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
This commit is contained in:
parent
c6b32b42de
commit
2271608c43
@ -636,7 +636,9 @@ mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end)
|
|||||||
/* Skip the start code */
|
/* Skip the start code */
|
||||||
data += 4;
|
data += 4;
|
||||||
|
|
||||||
|
hdr->temp_ref = (data[0] << 2) | (data[1] >> 6);
|
||||||
hdr->pic_type = (data[1] >> 3) & 0x07;
|
hdr->pic_type = (data[1] >> 3) & 0x07;
|
||||||
|
|
||||||
if (hdr->pic_type == 0 || hdr->pic_type > 4)
|
if (hdr->pic_type == 0 || hdr->pic_type > 4)
|
||||||
return FALSE; /* Corrupted picture packet */
|
return FALSE; /* Corrupted picture packet */
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ struct MPEGSeqHdr
|
|||||||
|
|
||||||
struct MPEGPictureHdr
|
struct MPEGPictureHdr
|
||||||
{
|
{
|
||||||
|
guint16 temp_ref;
|
||||||
guint8 pic_type;
|
guint8 pic_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,6 +92,10 @@ gst_mpegvideoparse_change_state (GstElement * element,
|
|||||||
|
|
||||||
static void mpv_send_pending_segs (MpegVideoParse * mpegvideoparse);
|
static void mpv_send_pending_segs (MpegVideoParse * mpegvideoparse);
|
||||||
static void mpv_clear_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;
|
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_n = mpegvideoparse->seq_hdr.par_w = 0;
|
||||||
mpegvideoparse->seq_hdr.fps_d = mpegvideoparse->seq_hdr.par_h = 1;
|
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);
|
mpv_clear_pending_segs (mpegvideoparse);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,6 +411,30 @@ picture_type_name (guint8 pct)
|
|||||||
}
|
}
|
||||||
#endif /* GST_DISABLE_GST_DEBUG */
|
#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
|
static gboolean
|
||||||
mpegvideoparse_handle_picture (MpegVideoParse * mpegvideoparse, GstBuffer * buf)
|
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",
|
GST_LOG_OBJECT (mpegvideoparse, "Picture type is %s",
|
||||||
picture_type_name (hdr.pic_type));
|
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);
|
cur = mpeg_util_find_start_code (&sync_word, cur, end);
|
||||||
}
|
}
|
||||||
@ -441,11 +507,10 @@ mpegvideoparse_handle_picture (MpegVideoParse * mpegvideoparse, GstBuffer * buf)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
static GstClockTime
|
||||||
static guint64
|
mpegvideoparse_get_time_code (guint8 * cur, MPEGSeqHdr * seq_hdr)
|
||||||
gst_mpegvideoparse_time_code (guchar * gop, MPEGSeqHdr * seq_hdr)
|
|
||||||
{
|
{
|
||||||
guint32 data = GST_READ_UINT32_BE (gop);
|
guint32 data = GST_READ_UINT32_BE (cur + 1);
|
||||||
guint64 seconds;
|
guint64 seconds;
|
||||||
guint8 frames;
|
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,
|
return seconds * GST_SECOND + gst_util_uint64_scale_int (frames * GST_SECOND,
|
||||||
seq_hdr->fps_d, seq_hdr->fps_n);
|
seq_hdr->fps_d, seq_hdr->fps_n);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_mpegvideoparse_flush (MpegVideoParse * mpegvideoparse)
|
gst_mpegvideoparse_flush (MpegVideoParse * mpegvideoparse)
|
||||||
|
@ -49,6 +49,11 @@ struct _MpegVideoParse {
|
|||||||
gint64 next_offset;
|
gint64 next_offset;
|
||||||
gboolean need_discont;
|
gboolean need_discont;
|
||||||
|
|
||||||
|
/* Timestamp calculation */
|
||||||
|
GstClockTime ref_ts;
|
||||||
|
guint16 temp_ref;
|
||||||
|
GstClockTime base_time_code;
|
||||||
|
|
||||||
/* Info from the Sequence Header */
|
/* Info from the Sequence Header */
|
||||||
MPEGSeqHdr seq_hdr;
|
MPEGSeqHdr seq_hdr;
|
||||||
GstBuffer *seq_hdr_buf;
|
GstBuffer *seq_hdr_buf;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user