mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 06:46:38 +00:00
h264parse: compute timestamp
This commit is contained in:
parent
9c08ece157
commit
d520e426b0
1 changed files with 125 additions and 5 deletions
|
@ -1001,22 +1001,20 @@ gst_h264_parse_chain_forward (GstH264Parse * h264parse, gboolean discont,
|
||||||
{
|
{
|
||||||
GstFlowReturn res = GST_FLOW_OK;
|
GstFlowReturn res = GST_FLOW_OK;
|
||||||
const guint8 *data;
|
const guint8 *data;
|
||||||
GstClockTime timestamp;
|
|
||||||
|
|
||||||
if (discont) {
|
if (discont) {
|
||||||
gst_adapter_clear (h264parse->adapter);
|
gst_adapter_clear (h264parse->adapter);
|
||||||
h264parse->discont = TRUE;
|
h264parse->discont = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
|
||||||
|
|
||||||
gst_adapter_push (h264parse->adapter, buffer);
|
gst_adapter_push (h264parse->adapter, buffer);
|
||||||
|
|
||||||
while (res == GST_FLOW_OK) {
|
while (res == GST_FLOW_OK) {
|
||||||
gint i;
|
gint i;
|
||||||
gint next_nalu_pos = -1;
|
gint next_nalu_pos = -1;
|
||||||
gint avail;
|
gint avail;
|
||||||
gboolean delta_unit = TRUE;
|
gboolean delta_unit = FALSE;
|
||||||
|
gboolean got_frame = FALSE;
|
||||||
|
|
||||||
avail = gst_adapter_available (h264parse->adapter);
|
avail = gst_adapter_available (h264parse->adapter);
|
||||||
if (avail < h264parse->nal_length_size + 1)
|
if (avail < h264parse->nal_length_size + 1)
|
||||||
|
@ -1146,8 +1144,131 @@ gst_h264_parse_chain_forward (GstH264Parse * h264parse, gboolean discont,
|
||||||
/* we have a packet */
|
/* we have a packet */
|
||||||
if (next_nalu_pos > 0) {
|
if (next_nalu_pos > 0) {
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
|
GstClockTime outbuf_dts = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
outbuf = gst_adapter_take_buffer (h264parse->adapter, next_nalu_pos);
|
outbuf = gst_adapter_take_buffer (h264parse->adapter, next_nalu_pos);
|
||||||
|
outbuf_dts = gst_adapter_prev_timestamp (h264parse->adapter, NULL); /* Better value for the second parameter? */
|
||||||
|
|
||||||
|
/* Ignore upstream dts that stalls or goes backward. Upstream elements
|
||||||
|
* like filesrc would keep on writing timestamp=0. XXX: is this correct?
|
||||||
|
* TODO: better way to detect whether upstream timstamps are useful */
|
||||||
|
if (h264parse->last_outbuf_dts != GST_CLOCK_TIME_NONE
|
||||||
|
&& outbuf_dts != GST_CLOCK_TIME_NONE
|
||||||
|
&& outbuf_dts <= h264parse->last_outbuf_dts)
|
||||||
|
outbuf_dts = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
|
if (got_frame || delta_unit) {
|
||||||
|
GstH264Sps *sps = h264parse->sps;
|
||||||
|
gint duration = 1;
|
||||||
|
|
||||||
|
if (!sps) {
|
||||||
|
GST_DEBUG_OBJECT (h264parse, "referred SPS invalid");
|
||||||
|
goto TIMESTAMP_FINISH;
|
||||||
|
} else if (!sps->timing_info_present_flag) {
|
||||||
|
GST_DEBUG_OBJECT (h264parse,
|
||||||
|
"unable to compute timestamp: timing info not present");
|
||||||
|
goto TIMESTAMP_FINISH;
|
||||||
|
} else if (sps->time_scale == 0) {
|
||||||
|
GST_DEBUG_OBJECT (h264parse,
|
||||||
|
"unable to compute timestamp: time_scale = 0 "
|
||||||
|
"(this is forbidden in spec; bitstream probably contains error)");
|
||||||
|
goto TIMESTAMP_FINISH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sps->pic_struct_present_flag
|
||||||
|
&& h264parse->sei_pic_struct != (guint8) - 1) {
|
||||||
|
/* Note that when h264parse->sei_pic_struct == -1 (unspecified), there
|
||||||
|
* are ways to infer its value. This is related to computing the
|
||||||
|
* TopFieldOrderCnt and BottomFieldOrderCnt, which looks
|
||||||
|
* complicated and thus not implemented for the time being. Yet
|
||||||
|
* the value we have here is correct for many applications
|
||||||
|
*/
|
||||||
|
switch (h264parse->sei_pic_struct) {
|
||||||
|
case SEI_PIC_STRUCT_TOP_FIELD:
|
||||||
|
case SEI_PIC_STRUCT_BOTTOM_FIELD:
|
||||||
|
duration = 1;
|
||||||
|
break;
|
||||||
|
case SEI_PIC_STRUCT_FRAME:
|
||||||
|
case SEI_PIC_STRUCT_TOP_BOTTOM:
|
||||||
|
case SEI_PIC_STRUCT_BOTTOM_TOP:
|
||||||
|
duration = 2;
|
||||||
|
break;
|
||||||
|
case SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
|
||||||
|
case SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:
|
||||||
|
duration = 3;
|
||||||
|
break;
|
||||||
|
case SEI_PIC_STRUCT_FRAME_DOUBLING:
|
||||||
|
duration = 4;
|
||||||
|
break;
|
||||||
|
case SEI_PIC_STRUCT_FRAME_TRIPLING:
|
||||||
|
duration = 6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GST_DEBUG_OBJECT (h264parse,
|
||||||
|
"h264parse->sei_pic_struct of unknown value %d. Not parsed",
|
||||||
|
h264parse->sei_pic_struct);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
duration = h264parse->field_pic_flag ? 1 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* h264parse.264 C.1.2 Timing of coded picture removal (equivalent to DTS):
|
||||||
|
* Tr,n(0) = initial_cpb_removal_delay[ SchedSelIdx ] / 90000
|
||||||
|
* Tr,n(n) = Tr,n(nb) + Tc * cpb_removal_delay(n)
|
||||||
|
* where
|
||||||
|
* Tc = num_units_in_tick / time_scale
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (h264parse->ts_trn_nb != GST_CLOCK_TIME_NONE) {
|
||||||
|
/* buffering period is present */
|
||||||
|
if (outbuf_dts != GST_CLOCK_TIME_NONE) {
|
||||||
|
/* If upstream timestamp is valid, we respect it and adjust current
|
||||||
|
* reference point */
|
||||||
|
h264parse->ts_trn_nb = outbuf_dts -
|
||||||
|
(GstClockTime) gst_util_uint64_scale_int
|
||||||
|
(h264parse->sei_cpb_removal_delay * GST_SECOND,
|
||||||
|
sps->num_units_in_tick, sps->time_scale);
|
||||||
|
} else {
|
||||||
|
/* If no upstream timestamp is given, we write in new timestamp */
|
||||||
|
h264parse->dts = h264parse->ts_trn_nb +
|
||||||
|
(GstClockTime) gst_util_uint64_scale_int
|
||||||
|
(h264parse->sei_cpb_removal_delay * GST_SECOND,
|
||||||
|
sps->num_units_in_tick, sps->time_scale);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* naive method: no removal delay specified, use best guess (add prev
|
||||||
|
* frame duration) */
|
||||||
|
if (outbuf_dts != GST_CLOCK_TIME_NONE)
|
||||||
|
h264parse->dts = outbuf_dts;
|
||||||
|
else if (h264parse->dts != GST_CLOCK_TIME_NONE)
|
||||||
|
h264parse->dts +=
|
||||||
|
(GstClockTime) gst_util_uint64_scale_int (h264parse->
|
||||||
|
cur_duration * GST_SECOND, sps->num_units_in_tick,
|
||||||
|
sps->time_scale);
|
||||||
|
else
|
||||||
|
h264parse->dts = 0; /* initialization */
|
||||||
|
|
||||||
|
/* TODO: better approach: construct a buffer queue and put all these
|
||||||
|
* NALs into the buffer. Wait until we are able to get any valid dts
|
||||||
|
* or such like, and dump the buffer and estimate the timestamps of
|
||||||
|
* the NALs by their duration.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
h264parse->cur_duration = duration;
|
||||||
|
h264parse->frame_cnt += 1;
|
||||||
|
if (outbuf_dts != GST_CLOCK_TIME_NONE)
|
||||||
|
h264parse->last_outbuf_dts = outbuf_dts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outbuf_dts == GST_CLOCK_TIME_NONE)
|
||||||
|
outbuf_dts = h264parse->dts;
|
||||||
|
else
|
||||||
|
h264parse->dts = outbuf_dts;
|
||||||
|
|
||||||
|
TIMESTAMP_FINISH:
|
||||||
|
GST_BUFFER_TIMESTAMP (outbuf) = outbuf_dts;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (h264parse,
|
GST_DEBUG_OBJECT (h264parse,
|
||||||
"pushing buffer %p, size %u, ts %" GST_TIME_FORMAT, outbuf,
|
"pushing buffer %p, size %u, ts %" GST_TIME_FORMAT, outbuf,
|
||||||
|
@ -1164,7 +1285,6 @@ gst_h264_parse_chain_forward (GstH264Parse * h264parse, gboolean discont,
|
||||||
GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
|
GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||||
|
|
||||||
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (h264parse->srcpad));
|
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (h264parse->srcpad));
|
||||||
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
|
||||||
res = gst_pad_push (h264parse->srcpad, outbuf);
|
res = gst_pad_push (h264parse->srcpad, outbuf);
|
||||||
} else {
|
} else {
|
||||||
/* NALU can not be parsed yet, we wait for more data in the adapter. */
|
/* NALU can not be parsed yet, we wait for more data in the adapter. */
|
||||||
|
|
Loading…
Reference in a new issue