From 2271608c4314d6d0a685c18c5c47d55495586159 Mon Sep 17 00:00:00 2001 From: Thijs Vermeir Date: Mon, 18 Oct 2010 15:32:14 +0200 Subject: [PATCH] mpegvideoparse: fix timestamp generation Use information from the gop header and picture header to calculate the picture timestamp. (time_code and temporal_reference) and adapt to upstream timestamps if provided. https://bugzilla.gnome.org/show_bug.cgi?id=632222 --- gst/mpegvideoparse/mpegpacketiser.c | 2 + gst/mpegvideoparse/mpegpacketiser.h | 1 + gst/mpegvideoparse/mpegvideoparse.c | 78 +++++++++++++++++++++++++++++++++---- gst/mpegvideoparse/mpegvideoparse.h | 5 +++ 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/gst/mpegvideoparse/mpegpacketiser.c b/gst/mpegvideoparse/mpegpacketiser.c index 694c476..b3be15a 100644 --- a/gst/mpegvideoparse/mpegpacketiser.c +++ b/gst/mpegvideoparse/mpegpacketiser.c @@ -636,7 +636,9 @@ mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end) /* Skip the start code */ data += 4; + hdr->temp_ref = (data[0] << 2) | (data[1] >> 6); hdr->pic_type = (data[1] >> 3) & 0x07; + if (hdr->pic_type == 0 || hdr->pic_type > 4) return FALSE; /* Corrupted picture packet */ diff --git a/gst/mpegvideoparse/mpegpacketiser.h b/gst/mpegvideoparse/mpegpacketiser.h index 88b1ca5..d82018e 100644 --- a/gst/mpegvideoparse/mpegpacketiser.h +++ b/gst/mpegvideoparse/mpegpacketiser.h @@ -86,6 +86,7 @@ struct MPEGSeqHdr struct MPEGPictureHdr { + guint16 temp_ref; guint8 pic_type; }; diff --git a/gst/mpegvideoparse/mpegvideoparse.c b/gst/mpegvideoparse/mpegvideoparse.c index 70fdc89..6bff373 100644 --- a/gst/mpegvideoparse/mpegvideoparse.c +++ b/gst/mpegvideoparse/mpegvideoparse.c @@ -92,6 +92,10 @@ gst_mpegvideoparse_change_state (GstElement * element, static void mpv_send_pending_segs (MpegVideoParse * mpegvideoparse); static void mpv_clear_pending_segs (MpegVideoParse * mpegvideoparse); +static GstClockTime mpegvideoparse_get_timestamp_from_reference (MPEGSeqHdr * + seq_hdr, GstClockTime ref_ts, gint32 ref); +static GstClockTime mpegvideoparse_get_time_code (guint8 * cur, + MPEGSeqHdr * seq_hdr); static GstElementClass *parent_class = NULL; @@ -163,6 +167,9 @@ mpv_parse_reset (MpegVideoParse * mpegvideoparse) mpegvideoparse->seq_hdr.fps_n = mpegvideoparse->seq_hdr.par_w = 0; mpegvideoparse->seq_hdr.fps_d = mpegvideoparse->seq_hdr.par_h = 1; + mpegvideoparse->ref_ts = GST_CLOCK_TIME_NONE; + mpegvideoparse->base_time_code = GST_CLOCK_TIME_NONE; + mpv_clear_pending_segs (mpegvideoparse); } @@ -404,6 +411,30 @@ picture_type_name (guint8 pct) } #endif /* GST_DISABLE_GST_DEBUG */ +static GstClockTime +mpegvideoparse_get_timestamp_from_reference (MPEGSeqHdr * seq_hdr, + GstClockTime ref_ts, gint32 ref) +{ + + if (ref < 0) { + GstClockTime duration; + + duration = gst_util_uint64_scale_int (ref * GST_SECOND * -1, + seq_hdr->fps_d, seq_hdr->fps_n); + + if (duration > ref_ts) + return ref_ts; + else + return ref_ts - duration; + } + + if (ref == 0) + return ref_ts; + + return ref_ts + gst_util_uint64_scale_int (ref * GST_SECOND, + seq_hdr->fps_d, seq_hdr->fps_n); +} + static gboolean mpegvideoparse_handle_picture (MpegVideoParse * mpegvideoparse, GstBuffer * buf) { @@ -432,8 +463,43 @@ mpegvideoparse_handle_picture (MpegVideoParse * mpegvideoparse, GstBuffer * buf) GST_LOG_OBJECT (mpegvideoparse, "Picture type is %s", picture_type_name (hdr.pic_type)); - /* FIXME: Can use the picture type and number of fields to track a - * timestamp */ + + if (GST_BUFFER_TIMESTAMP (buf) == GST_CLOCK_TIME_NONE) { + if (mpegvideoparse->ref_ts != GST_CLOCK_TIME_NONE) { + GST_BUFFER_TIMESTAMP (buf) = + mpegvideoparse_get_timestamp_from_reference + (&mpegvideoparse->seq_hdr, mpegvideoparse->ref_ts, + hdr.temp_ref - mpegvideoparse->temp_ref); + } + } else { + /* we got a timestamp from upstream, use this timestamp as our reference now */ + mpegvideoparse->ref_ts = GST_BUFFER_TIMESTAMP (buf); + mpegvideoparse->temp_ref = hdr.temp_ref; + } + + GST_DEBUG_OBJECT (mpegvideoparse, + "Picture timestamp %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + } else if (cur[0] == MPEG_PACKET_GOP) { + if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) { + mpegvideoparse->base_time_code = + mpegvideoparse_get_time_code (cur, + &mpegvideoparse->seq_hdr) - GST_BUFFER_TIMESTAMP (buf); + mpegvideoparse->ref_ts = GST_BUFFER_TIMESTAMP (buf); + mpegvideoparse->temp_ref = 0; + } else { + if (mpegvideoparse->base_time_code == GST_CLOCK_TIME_NONE) { + mpegvideoparse->base_time_code = + mpegvideoparse_get_time_code (cur, &mpegvideoparse->seq_hdr); + mpegvideoparse->ref_ts = 0; + mpegvideoparse->temp_ref = 0; + } else { + mpegvideoparse->ref_ts = + mpegvideoparse_get_time_code (cur, + &mpegvideoparse->seq_hdr) - mpegvideoparse->base_time_code; + mpegvideoparse->temp_ref = 0; + } + } } cur = mpeg_util_find_start_code (&sync_word, cur, end); } @@ -441,11 +507,10 @@ mpegvideoparse_handle_picture (MpegVideoParse * mpegvideoparse, GstBuffer * buf) return TRUE; } -#if 0 -static guint64 -gst_mpegvideoparse_time_code (guchar * gop, MPEGSeqHdr * seq_hdr) +static GstClockTime +mpegvideoparse_get_time_code (guint8 * cur, MPEGSeqHdr * seq_hdr) { - guint32 data = GST_READ_UINT32_BE (gop); + guint32 data = GST_READ_UINT32_BE (cur + 1); guint64 seconds; guint8 frames; @@ -458,7 +523,6 @@ gst_mpegvideoparse_time_code (guchar * gop, MPEGSeqHdr * seq_hdr) return seconds * GST_SECOND + gst_util_uint64_scale_int (frames * GST_SECOND, seq_hdr->fps_d, seq_hdr->fps_n); } -#endif static void gst_mpegvideoparse_flush (MpegVideoParse * mpegvideoparse) diff --git a/gst/mpegvideoparse/mpegvideoparse.h b/gst/mpegvideoparse/mpegvideoparse.h index b514863..fa5cfd4 100644 --- a/gst/mpegvideoparse/mpegvideoparse.h +++ b/gst/mpegvideoparse/mpegvideoparse.h @@ -49,6 +49,11 @@ struct _MpegVideoParse { gint64 next_offset; gboolean need_discont; + /* Timestamp calculation */ + GstClockTime ref_ts; + guint16 temp_ref; + GstClockTime base_time_code; + /* Info from the Sequence Header */ MPEGSeqHdr seq_hdr; GstBuffer *seq_hdr_buf; -- 2.7.4