[MPlayer-G2-dev] Re: mp-G2: play_frame()

Andriy N. Gritsenko andrej at lucky.net
Thu May 8 15:37:25 CEST 2003


    Hi!

    OOPS, sorry, I've forgotten to attach the file. :(

    It's only concept, not really workink subroutine. Sorry, I don't have
enough time now to do all researches on G2 streaming but someone here are
working on that problem too so I think it will be very useful to join our
thoughts. :)

    Yesterday's evening I've spent some time to write play_frame() a bit.
See it in attachment. It allows multiple play contexts and multiple audio
or video streams, has no static vars, and is independent of other parts
of G2 as much as possible. Some comments:

1) I didn't do some audio/video specific parts since I didn't get yet how
  to pull audio and video frames from chain, sorry.
2) I've changed skiplimit variable to float. Some time ago I wanted to
  run mplayer with -skiplimit 0.2 since it may allow me significally
  decrease number of dropped valuable frames despite of little A-V
  desync.
3) Many applications may have more than one play context (for example,
  player with multiscreen ability, video editor, streaming server, etc.)
  so have static variables (such as sh_audio or video_out) isn't good
  solution. So I've implemented struct play_context. :)
4) Since it's allowed to have more than one video or audio stream, each
  stream has to have his own sync mechanism, it dissalows to have static
  vars so I've moved statics for that into sh_audio and sh_video (may be,
  we will implement some struct chain_t instead of sh_audio_t/sh_video_t
  for unification later?). These variables are:
    double skipcnt; // counter how many skips are possible now
    double pts; // presentation timestamp of last gotten frame
    double corr; // correction time for this stream chain
    int skipped; // number of skipped (dropped) non-duplicate frames
    int dupped; // number of inserted duplicate frames
5) play_frame() will work in any application (player, encoder, etc.) with
  no changes and hacks. :)
6) Input chain (from source stream to play_frame subroutine) have not
  push frame to output chain (audio/video out or muxer) directly but
  play_frame() will do that instead. It's because only play_frame() may
  decide if frame has to be dropped or duplicated. Anyway each input
  chain must have appropriate output chain. :)

    Any questions/comments are welcomed but don't ask me wrote all missed
stuff - I have no enough time for researches on G2 streams now and they
are too complex to solve it without knowing the details. Sorry for that.

    With best wishes.
    Andriy.
-------------- next part --------------
#include "ctl.h"

float skiplimit = -1; // config variable!

typedef struct {
  sh_audio_t **sh_audio;
  ao_functions_t **audio_out;
  int audio_streams; // chains sh_audio and audio_out
  sh_video_t **sh_video;
  vo_instance_t **video_out;
  int video_streams; // chains sh_video and video_out
  double pts; // presentation timestamp at end of last played frame
} play_context;

/* play the frame at timestamp pts with frame duration duration */
int play_frame (play_context *ctx, double pts, double duration) {
  int i;
  //double seek = check_control();

  //pts += seek;
  // play all audio
  for (i = 0; i < ctx->audio_streams; i++) {
    sh_audio_t *sh_a = ctx->sh_audio[i];
    ao_functions_t *ao = ctx->audio_out[i];

    if (sh_a->ds->eof) continue; // input ended
    // since it multistreamed now, pts must be added into sh_audio_t!
    do {
      // do seek if pts and ctx->pts are too different (may be only in player)
      //...
      // decode audio
      //...
      // play audio
      //...
      // update sh_a->pts
      //...
    } while (sh_a->pts + sh_a->corr < pts+duration);
  }
  // play all video
  for (i = 0; i < ctx->video_streams; i++) {
    sh_video_t *sh_v = ctx->sh_video[i];
    vo_instance_t *vo = ctx->video_out[i];
    static struct mp_image_s *mpi = NULL;

    if (sh_v->ds->eof) continue; // input ended
    // do seek if pts and ctx->pts are too different (may be only in player)
    //...
    // check if we jumped past current frame
    if (sh_v->pts + sh_v->corr < pts) { // we have to skip that frame
      if (skiplimit > 0)
	sh_v->skipcnt += skiplimit;
      while (skiplimit < 0 || sh_v->skipcnt >= 1) { // skip frame(s) if possible
	// decode videoframe (just for dropping now)
	sh_v->vfilter->get_image(sh_v->vfilter, mpi);
	if (mpi) { // if it isn't duplicate/dropped
	  sh_v->skipcnt -= 1.0;
	  sh_v->skipped += 1;
	}
	// videoframe skipped!
	// update sh_v->pts
	//...
	// checks for success
	if (sh_v->ds->eof || sh_v->pts + sh_v->corr >= pts+duration)
	  break;
      }
      continue; // next video
    }
    // we can process that frame
    if (skiplimit > 0)
      sh_v->skipcnt -= skiplimit;
    // duplicate current frame if it's need and possible
    if ((skiplimit < 0 || sh_v->skipcnt <= -1) &&
	sh_v->pts + sh_v->corr >= pts+duration) {
      sh_v->dupped += 1;
      // push duplicate frame with duration duration
      //...
      sh_v->corr += duration;
      sh_v->skipcnt += 1.0;
    }
    // process videoframe(s)
    while (sh_v->pts + sh_v->corr < pts+duration) {
      double frametime; // frame duration

      // decode videoframe (for play, full process)
      sh_v->vfilter->get_image(sh_v->vfilter, mpi);
      // get frame duration
      //...
      if (!mpi && sh_v->corr > 0) { // if it is duplicate/dropped
	// update sh_v->pts and drop it if possible
	sh_v->pts += frametime;
	sh_v->corr -= frametime;
	continue;
      }
      if (!mpi)
	sh_v->dupped += 1;
      // play videoframe (even duplicate one)
      //...
      sh_v->pts += frametime;
      break; // we cannot play more than one frame once
    }
  }
  // update ctx->pts
  ctx->pts = pts + duration;
}


More information about the MPlayer-G2-dev mailing list