summaryrefslogtreecommitdiffstats
path: root/libmpdemux
diff options
context:
space:
mode:
authornicodvb <nicodvb@b3059339-0415-0410-9bf9-f77b7e298cf2>2007-01-28 10:45:34 +0000
committernicodvb <nicodvb@b3059339-0415-0410-9bf9-f77b7e298cf2>2007-01-28 10:45:34 +0000
commit25918a8b310465bc0d8f42b9db0d6822cfff5947 (patch)
tree3b70d9bad8e71a97527a62926dba50de71f99bcc /libmpdemux
parentfec3b1e82edd31351f4db0ae6cd195ae8cd5dca3 (diff)
downloadmpv-25918a8b310465bc0d8f42b9db0d6822cfff5947.tar.bz2
mpv-25918a8b310465bc0d8f42b9db0d6822cfff5947.tar.xz
set has_valid_timestamps and corresponding first and final pts only after
having checked that at the beginning, at the middle and at the end of the stream timestamps don't reset and that they seem to progress (almost-) linearly; additionally probe those timestamps only when the stream type is file and it's seekable, so all other stream types (especially network ones) won't waste time trying to seek and possibly slowing down detection. Seeking is not negatively affected by these changes. Patch by Christian Aistleitner (zaek7q gmx net) reworked by me. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@22039 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpdemux')
-rw-r--r--libmpdemux/demux_mpg.c168
1 files changed, 122 insertions, 46 deletions
diff --git a/libmpdemux/demux_mpg.c b/libmpdemux/demux_mpg.c
index af888b4764..0bd53d8ce9 100644
--- a/libmpdemux/demux_mpg.c
+++ b/libmpdemux/demux_mpg.c
@@ -29,8 +29,10 @@
typedef struct mpg_demuxer {
float last_pts;
- float final_pts;
- int has_valid_timestamps;
+ float first_pts; // first pts found in stream
+ float first_to_final_pts_len; // difference between final pts and first pts
+ int has_valid_timestamps; // !=0 iff time stamps look linear
+ // (not necessarily starting with 0)
unsigned int es_map[0x40]; //es map of stream types (associated to the pes id) from 0xb0 to 0xef
int num_a_streams;
int a_stream_ids[MAX_A_STREAMS];
@@ -102,49 +104,123 @@ static int parse_psm(demuxer_t *demux, int len) {
// 500000 is a wild guess
#define TIMESTAMP_PROBE_LEN 500000
+//MAX_PTS_DIFF_FOR_CONSECUTIVE denotes the maximum difference
+//between two pts to consider them consecutive
+//1.0 is a wild guess
+#define MAX_PTS_DIFF_FOR_CONSECUTIVE 1.0
+
+//returns the first pts found within TIME_STAMP_PROBE_LEN bytes after stream_pos in demuxer's stream.
+//if no pts is found or an error occurs, -1.0 is returned.
+//Packs are freed.
+static float read_first_mpeg_pts_at_position(demuxer_t* demuxer, off_t stream_pos)
+{
+ stream_t *s = demuxer->stream;
+ mpg_demuxer_t *mpg_d = demuxer->priv;
+ float pts = -1.0; //the pts to return;
+ float found_pts1; //the most recently found pts
+ float found_pts2; //the pts found before found_pts1
+ float found_pts3; //the pts found before found_pts2
+ int found = 0;
+
+ if(!mpg_d || stream_pos < 0)
+ return pts;
+
+ found_pts3 = found_pts2 = found_pts1 = mpg_d->last_pts;
+ stream_seek(s, stream_pos);
+
+ //We look for pts.
+ //However, we do not stop at the first found one, as timestamps may reset
+ //Therefore, we seek until we found three consecutive
+ //pts within MAX_PTS_DIFF_FOR_CONSECUTIVE.
+
+ while(found<3 && !s->eof
+ && (fabsf(found_pts2-found_pts1) < MAX_PTS_DIFF_FOR_CONSECUTIVE)
+ && (fabsf(found_pts3-found_pts2) < MAX_PTS_DIFF_FOR_CONSECUTIVE)
+ && (stream_tell(s) < stream_pos + TIMESTAMP_PROBE_LEN)
+ && ds_fill_buffer(demuxer->video))
+ {
+ if(mpg_d->last_pts != found_pts1)
+ {
+ if(!found)
+ found_pts3 = found_pts2 = found_pts1 = mpg_d->last_pts; //the most recently found pts
+ else
+ {
+ found_pts3 = found_pts2;
+ found_pts2 = found_pts1;
+ found_pts1 = mpg_d->last_pts;
+ }
+ found++;
+ }
+ }
+
+ if(found == 3) pts = found_pts3;
+
+ //clean up from searching of first pts;
+ ds_free_packs(demuxer->audio);
+ ds_free_packs(demuxer->video);
+ ds_free_packs(demuxer->sub);
+
+ return pts;
+}
+
/// Open an mpg physical stream
static demuxer_t* demux_mpg_open(demuxer_t* demuxer) {
stream_t *s = demuxer->stream;
- off_t pos = stream_tell(s);
- off_t end_seq_start;
- float half_pts = 0.0;
mpg_demuxer_t* mpg_d;
if (!ds_fill_buffer(demuxer->video)) return 0;
- end_seq_start = demuxer->movi_end-TIMESTAMP_PROBE_LEN;
mpg_d = calloc(1,sizeof(mpg_demuxer_t));
- demuxer->priv = mpg_d;
- mpg_d->final_pts = 0.0;
- mpg_d->has_valid_timestamps = 1;
- mpg_d->num_a_streams = 0;
- if (demuxer->seekable && stream_tell(demuxer->stream) < end_seq_start) {
- off_t half_pos = pos + end_seq_start / 2;
- stream_seek(s, half_pos);
- while ((!s->eof) && ds_fill_buffer(demuxer->video) && half_pts == 0.0) {
- half_pts = mpg_d->last_pts;
- if (stream_tell(s) > half_pos + TIMESTAMP_PROBE_LEN)
- break;
- }
- stream_seek(s,end_seq_start);
- while ((!s->eof) && ds_fill_buffer(demuxer->video)) {
- if (mpg_d->final_pts < mpg_d->last_pts) mpg_d->final_pts = mpg_d->last_pts;
- if (stream_tell(s) > demuxer->movi_end)
- break;
- }
- // educated guess about validity of timestamps
- if (mpg_d->final_pts > 3 * half_pts || mpg_d->final_pts < 1.5 * half_pts) {
- mpg_d->has_valid_timestamps = 0;
- }
- ds_free_packs(demuxer->audio);
- ds_free_packs(demuxer->video);
- ds_free_packs(demuxer->sub);
- demuxer->stream->eof=0; // clear eof flag
- demuxer->video->eof=0;
- demuxer->audio->eof=0;
-
- stream_seek(s,pos);
- ds_fill_buffer(demuxer->video);
- }
+ if(mpg_d)
+ {
+ demuxer->priv = mpg_d;
+ mpg_d->last_pts = -1.0;
+ mpg_d->first_pts = -1.0;
+
+ //if seeking is allowed set has_valid_timestamps if appropriate
+ if(demuxer->seekable
+ && demuxer->stream->type == STREAMTYPE_FILE
+ && demuxer->movi_start != demuxer-> movi_end
+ )
+ {
+ //We seek to the beginning of the stream, to somewhere in the
+ //middle, and to the end of the stream, while remembering the pts
+ //at each of the three positions. With these pts, we check whether
+ //or not the pts are "linear enough" to justify seeking by the pts
+ //of the stream
+
+ //The position where the stream is now
+ off_t pos = stream_tell(s);
+ float first_pts = read_first_mpeg_pts_at_position(demuxer, demuxer->movi_start);
+ if(first_pts != -1.0)
+ {
+ float middle_pts = read_first_mpeg_pts_at_position(demuxer, (demuxer->movi_end - demuxer->movi_start)/2);
+ if(middle_pts != -1.0)
+ {
+ float final_pts = read_first_mpeg_pts_at_position(demuxer, demuxer->movi_end - TIMESTAMP_PROBE_LEN);
+ if(final_pts != -1.0)
+ {
+ // found proper first, middle, and final pts.
+ float proportion = (middle_pts-first_pts==0) ? -1 : (final_pts-middle_pts)/(middle_pts-first_pts);
+ // if they are linear enough set has_valid_timestamps
+ if((0.5 < proportion) && (proportion < 2))
+ {
+ mpg_d->first_pts = first_pts;
+ mpg_d->first_to_final_pts_len = final_pts - first_pts;
+ mpg_d->has_valid_timestamps = 1;
+ }
+ }
+ }
+ }
+
+ //Cleaning up from seeking in stream
+ demuxer->stream->eof=0;
+ demuxer->video->eof=0;
+ demuxer->audio->eof=0;
+
+ stream_seek(s,pos);
+ ds_fill_buffer(demuxer->video);
+ } // if ( demuxer->seekable )
+ } // if ( mpg_d )
return demuxer;
}
@@ -770,8 +846,8 @@ void demux_seek_mpg(demuxer_t *demuxer,float rel_seek_secs,float audio_delay, in
//================= seek in MPEG ==========================
//calculate the pts to seek to
if(flags & 2) {
- if (mpg_d && mpg_d->final_pts > 0.0)
- newpts += mpg_d->final_pts * rel_seek_secs;
+ if (mpg_d && mpg_d->first_to_final_pts_len > 0.0)
+ newpts += mpg_d->first_to_final_pts_len * rel_seek_secs;
else
newpts += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) * oldpts / oldpos;
} else
@@ -784,8 +860,8 @@ void demux_seek_mpg(demuxer_t *demuxer,float rel_seek_secs,float audio_delay, in
} else {
// time seek (secs)
if (mpg_d && mpg_d->has_valid_timestamps) {
- if (mpg_d->final_pts > 0.0)
- newpos += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) / mpg_d->final_pts;
+ if (mpg_d->first_to_final_pts_len > 0.0)
+ newpos += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) / mpg_d->first_to_final_pts_len;
else if (oldpts > 0.0)
newpos += rel_seek_secs * (oldpos - demuxer->movi_start) / oldpts;
} else if(!sh_video || !sh_video->i_bps) // unspecified or VBR
@@ -871,14 +947,14 @@ int demux_mpg_control(demuxer_t *demuxer,int cmd, void *arg){
return DEMUXER_CTRL_GUESS;
}
if (mpg_d && mpg_d->has_valid_timestamps) {
- *((double *)arg)=(double)mpg_d->final_pts;
- return DEMUXER_CTRL_GUESS;
+ *((double *)arg)=(double)mpg_d->first_to_final_pts_len;
+ return DEMUXER_CTRL_OK;
}
return DEMUXER_CTRL_DONTKNOW;
case DEMUXER_CTRL_GET_PERCENT_POS:
- if (mpg_d && mpg_d->has_valid_timestamps && mpg_d->final_pts > 0.0) {
- *((int *)arg)=(int)(100 * mpg_d->last_pts / mpg_d->final_pts);
+ if (mpg_d && mpg_d->has_valid_timestamps && mpg_d->first_to_final_pts_len > 0.0) {
+ *((int *)arg)=(int)(100 * (mpg_d->last_pts-mpg_d->first_pts) / mpg_d->first_to_final_pts_len);
return DEMUXER_CTRL_OK;
}
return DEMUXER_CTRL_DONTKNOW;