[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