[MPlayer-dev-eng] [PATCH] Timestamp-based mpg seeking

Michael Behrisch behrisch at informatik.hu-berlin.de
Mon Oct 4 12:07:16 CEST 2004


This is "proof of concept"-patch which enables seeking based
on the largest timestamp in an mpg stream. It is often more 
accurate than the current seeking and it has the additional 
benefit of giving the (almost) precise total time of the movie.

It includes a guess on whether the timestamps are correct.

This it not ready to be included beacuse it does not free 
all the memory allocated, it is not documented and tested
with three files only. But beforing doing more work,
I wanted to know whether a patch like that might get accepted.
If so, I will fix the issues mentioned and improve seeking
further with some kind of "iterative search" just as in demux_ogg.

Michael

-------------- next part --------------
--- libmpdemux/demuxer.old	2004-09-24 12:41:20.000000000 +0200
+++ libmpdemux/demuxer.c	2004-10-02 14:09:04.432251416 +0200
@@ -616,6 +616,7 @@
 extern void demux_open_nuv(demuxer_t *demuxer);
 extern int demux_audio_open(demuxer_t* demuxer);
 extern int demux_ogg_open(demuxer_t* demuxer);
+extern int demux_mpg_open(demuxer_t* demuxer);
 extern int demux_rawaudio_open(demuxer_t* demuxer);
 extern int demux_rawvideo_open(demuxer_t* demuxer);
 extern int smjpeg_check_file(demuxer_t *demuxer);
@@ -985,7 +986,7 @@
   num_h264_pps=0;
   num_mp3audio_packets=0;
 
-  if(ds_fill_buffer(demuxer->video)){
+  if(demux_mpg_open(demuxer)){
     if(!pes)
       mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_Detected_XXX_FileFormat,"MPEG-PES");
     else
--- libmpdemux/demux_mpg.old	2004-09-24 12:41:20.000000000 +0200
+++ libmpdemux/demux_mpg.c	2004-10-02 14:10:35.658382936 +0200
@@ -17,8 +17,47 @@
 //#define MAX_PS_PACKETSIZE 2048
 #define MAX_PS_PACKETSIZE (224*1024)
 
+typedef struct mpg_demuxer {
+  float last_pts;
+  float final_pts;
+} mpg_demuxer_t;
+
 static int mpeg_pts_error=0;
 
+/// Open an mpg physical stream
+int demux_mpg_open(demuxer_t* demuxer) {
+  off_t pos = stream_tell(demuxer->stream);
+  if (!ds_fill_buffer(demuxer->video)) return 0;
+  mpg_demuxer_t* mpg_d = (mpg_demuxer_t*)calloc(1,sizeof(mpg_demuxer_t));
+  demuxer->priv = mpg_d;
+  mpg_d->final_pts = 0.0;
+  // 500000 is a wild guess
+  off_t end_seq_start = demuxer->movi_end-500000;
+  if (demuxer->seekable && stream_tell(demuxer->stream) < end_seq_start) {
+    stream_t *s = demuxer->stream;
+    float half_pts = 0.0;
+    stream_seek(s,(pos + end_seq_start / 2));
+    while ((!s->eof) && ds_fill_buffer(demuxer->video) && half_pts == 0.0) {
+      half_pts = mpg_d->last_pts;
+    }
+    stream_seek(s,end_seq_start);
+    while ((!s->eof) && ds_fill_buffer(demuxer->video) && mpg_d->final_pts == 0.0) {
+      mpg_d->final_pts = mpg_d->last_pts;
+    }
+    // educated guess about validity of timestamps
+    if (mpg_d->final_pts > 3 * half_pts || mpg_d->final_pts < 1.5 * half_pts) {
+      mpg_d->final_pts = 0.0;
+    }
+    ds_free_packs(demuxer->audio);
+    ds_free_packs(demuxer->video);
+    
+    stream_seek(s,pos);
+    ds_fill_buffer(demuxer->video);
+  }
+  return 1;
+}
+
+
 static unsigned int read_mpeg_timestamp(stream_t *s,int c){
   int d,e;
   unsigned int pts;
@@ -222,6 +261,7 @@
     mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_MPG: Read %d data bytes from packet %04X\n",len,id);
 //    printf("packet start = 0x%X  \n",stream_tell(demux->stream)-packet_start_pos);
     ds_read_packet(ds,demux->stream,len,pts/90000.0f,demux->filepos,0);
+    if (demux-> priv != NULL) ((mpg_demuxer_t*)demux->priv)->last_pts = pts/90000.0f;
 //    if(ds==demux->sub) parse_dvdsub(ds->last->buffer,ds->last->len);
     return 1;
   }
@@ -357,7 +397,8 @@
     demux_stream_t *d_video=demuxer->video;
     sh_audio_t *sh_audio=d_audio->sh;
     sh_video_t *sh_video=d_video->sh;
-
+    mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demuxer->priv;
+    
   //================= seek in MPEG ==========================
     off_t newpos=(flags&1)?demuxer->movi_start:demuxer->filepos;
 	
@@ -365,8 +406,10 @@
 	// float seek 0..1
 	newpos+=(demuxer->movi_end-demuxer->movi_start)*rel_seek_secs;
     } else {
+        if (mpg_d != NULL && mpg_d->final_pts > 0.0)
+          newpos += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) / mpg_d->final_pts;
 	// time seek (secs)
-        if(!sh_video || !sh_video->i_bps) // unspecified or VBR
+        else if(!sh_video || !sh_video->i_bps) // unspecified or VBR
           newpos+=2324*75*rel_seek_secs; // 174.3 kbyte/sec
         else
           newpos+=sh_video->i_bps*rel_seek_secs;
@@ -414,9 +457,14 @@
     demux_stream_t *d_video=demuxer->video;
 /*    sh_audio_t *sh_audio=d_audio->sh;*/
     sh_video_t *sh_video=d_video->sh;
+    mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demuxer->priv;
 
     switch(cmd) {
 	case DEMUXER_CTRL_GET_TIME_LENGTH:
+            if (mpg_d != NULL && mpg_d->final_pts > 0.0) {
+              *((unsigned long *)arg)=(long)mpg_d->final_pts;
+              return DEMUXER_CTRL_GUESS;
+            }
 	    if(!sh_video->i_bps)  // unspecified or VBR 
     		return DEMUXER_CTRL_DONTKNOW;
 	    *((unsigned long *)arg)=(demuxer->movi_end-demuxer->movi_start)/sh_video->i_bps;


More information about the MPlayer-dev-eng mailing list