Commit 21be756e authored by Nicolas Dufresne's avatar Nicolas Dufresne
Browse files

h264parse: Don't wait for next NAL if input is aligned

Waiting for the next NAL increases the latency. If alignment=nal/au
has been negotiated, assumes the the buffer contains a complete
NAL and don't except a second start-code. This way, nal -> nal,
au -> au and au -> nal no longer introduce latency.

As a side effect, the collect_pad() function was not able to poke at the
following NAL. This call is now moved before processing the NAL, so
it's looking at the current NAL before it's ingested into the parser
state in order to dermin if the end of an AU has been reached. The AUD
injection state as been adapted to support this.
parent 4a7d3974
......@@ -188,14 +188,13 @@ gst_h264_parse_reset_frame (GstH264Parse * h264parse)
/* done parsing; reset state */
h264parse->current_off = -1;
h264parse->picture_start = FALSE;
h264parse->update_caps = FALSE;
h264parse->idr_pos = -1;
h264parse->sei_pos = -1;
h264parse->keyframe = FALSE;
h264parse->header = FALSE;
h264parse->frame_start = FALSE;
h264parse->aud_insert = TRUE;
h264parse->aud_insert = FALSE;
gst_adapter_clear (h264parse->frame_out);
}
......@@ -821,6 +820,10 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
GST_H264_PARSE_STATE_VALID_PICTURE_HEADERS))
return FALSE;
/* This is similar to the GOT_SLICE state, but is only reset when the
* AU is complete. This is used to keep track of AU */
h264parse->picture_start = TRUE;
/* don't need to parse the whole slice (header) here */
if (*(nalu->data + nalu->offset + nalu->header_bytes) & 0x80) {
/* means first_mb_in_slice == 0 */
......@@ -875,7 +878,7 @@ gst_h264_parse_process_nal (GstH264Parse * h264parse, GstH264NalUnit * nalu)
pres = gst_h264_parser_parse_nal (nalparser, nalu);
if (pres != GST_H264_PARSER_OK)
return FALSE;
h264parse->aud_insert = FALSE;
h264parse->aud_needed = FALSE;
break;
default:
/* drop anything before the initial SPS */
......@@ -907,24 +910,12 @@ static inline gboolean
gst_h264_parse_collect_nal (GstH264Parse * h264parse, const guint8 * data,
guint size, GstH264NalUnit * nalu)
{
gboolean complete;
GstH264ParserResult parse_res;
GstH264NalUnitType nal_type = nalu->type;
GstH264NalUnit nnalu;
GST_DEBUG_OBJECT (h264parse, "parsing collected nal");
parse_res = gst_h264_parser_identify_nalu_unchecked (h264parse->nalparser,
data, nalu->offset + nalu->size, size, &nnalu);
if (parse_res != GST_H264_PARSER_OK)
return FALSE;
gboolean complete;
/* determine if AU complete */
GST_LOG_OBJECT (h264parse, "nal type: %d %s", nal_type, _nal_name (nal_type));
/* coded slice NAL starts a picture,
* i.e. other types become aggregated in front of it */
h264parse->picture_start |= (nal_type == GST_H264_NAL_SLICE ||
nal_type == GST_H264_NAL_SLICE_DPA || nal_type == GST_H264_NAL_SLICE_IDR);
GST_LOG_OBJECT (h264parse, "next nal type: %d %s (picture started %i)",
nal_type, _nal_name (nal_type), h264parse->picture_start);
/* consider a coded slices (IDR or not) to start a picture,
* (so ending the previous one) if first_mb_in_slice == 0
......@@ -933,21 +924,20 @@ gst_h264_parse_collect_nal (GstH264Parse * h264parse, const guint8 * data,
* but in practice it works in sane cases, needs not much parsing,
* and also works with broken frame_num in NAL
* (where spec-wise would fail) */
nal_type = nnalu.type;
complete = h264parse->picture_start && ((nal_type >= GST_H264_NAL_SEI &&
nal_type <= GST_H264_NAL_AU_DELIMITER) ||
(nal_type >= 14 && nal_type <= 18));
GST_LOG_OBJECT (h264parse, "next nal type: %d %s", nal_type,
_nal_name (nal_type));
complete |= h264parse->picture_start && (nal_type == GST_H264_NAL_SLICE
|| nal_type == GST_H264_NAL_SLICE_DPA
|| nal_type == GST_H264_NAL_SLICE_IDR) &&
/* first_mb_in_slice == 0 considered start of frame */
(nnalu.data[nnalu.offset + nnalu.header_bytes] & 0x80);
(nalu->data[nalu->offset + nalu->header_bytes] & 0x80);
GST_LOG_OBJECT (h264parse, "au complete: %d", complete);
if (complete)
h264parse->picture_start = FALSE;
return complete;
}
......@@ -989,6 +979,10 @@ gst_h264_parse_handle_frame_packetized (GstBaseParse * parse,
parse_res = gst_h264_parser_identify_nalu_avc (h264parse->nalparser,
map.data, 0, map.size, nl, &nalu);
/* there is no AUD in AVC, always enable insertion, the pre_push function
* will only add it once, and will only add it for byte-stream output. */
h264parse->aud_insert = TRUE;
while (parse_res == GST_H264_PARSER_OK) {
GST_DEBUG_OBJECT (h264parse, "AVC nal offset %d", nalu.offset + nalu.size);
......@@ -1067,7 +1061,6 @@ gst_h264_parse_handle_frame (GstBaseParse * parse,
GstH264ParserResult pres;
gint framesize;
GstFlowReturn ret;
gboolean au_complete;
if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (frame->buffer,
GST_BUFFER_FLAG_DISCONT))) {
......@@ -1163,6 +1156,13 @@ gst_h264_parse_handle_frame (GstBaseParse * parse,
nalu.offset, nalu.size);
break;
case GST_H264_PARSER_NO_NAL_END:
/* In NAL alignment, assume the NAL is complete */
if (h264parse->in_align == GST_H264_PARSE_ALIGN_NAL ||
h264parse->in_align == GST_H264_PARSE_ALIGN_AU) {
nonext = TRUE;
nalu.size = size - nalu.offset;
break;
}
GST_DEBUG_OBJECT (h264parse, "not a complete nal found at offset %u",
nalu.offset);
/* if draining, accept it as complete nal */
......@@ -1202,7 +1202,6 @@ gst_h264_parse_handle_frame (GstBaseParse * parse,
if (current_off == 0) {
GST_DEBUG_OBJECT (h264parse, "skipping broken nal");
*skipsize = nalu.offset;
h264parse->aud_needed = TRUE;
goto skip;
} else {
GST_DEBUG_OBJECT (h264parse, "terminating au");
......@@ -1219,15 +1218,13 @@ gst_h264_parse_handle_frame (GstBaseParse * parse,
GST_DEBUG_OBJECT (h264parse, "%p complete nal found. Off: %u, Size: %u",
data, nalu.offset, nalu.size);
if (!nonext) {
if (nalu.offset + nalu.size + 4 + 2 > size) {
GST_DEBUG_OBJECT (h264parse, "not enough data for next NALU");
if (drain) {
GST_DEBUG_OBJECT (h264parse, "but draining anyway");
nonext = TRUE;
} else {
goto more;
}
if (gst_h264_parse_collect_nal (h264parse, data, size, &nalu)) {
h264parse->aud_needed = TRUE;
/* complete current frame, if it exist */
if (current_off > 0) {
nalu.size = 0;
nalu.offset = nalu.sc_offset;
break;
}
}
......@@ -1236,30 +1233,33 @@ gst_h264_parse_handle_frame (GstBaseParse * parse,
"broken/invalid nal Type: %d %s, Size: %u will be dropped",
nalu.type, _nal_name (nalu.type), nalu.size);
*skipsize = nalu.size;
h264parse->aud_needed = TRUE;
goto skip;
}
/* Judge whether or not to insert AU Delimiter in case of byte-stream
* If we're in the middle of au, we don't need to insert aud.
* Otherwise, we honor the result in gst_h264_parse_process_nal.
* Note that this should be done until draining if it's happening.
*/
if (h264parse->align == GST_H264_PARSE_ALIGN_NAL && !h264parse->aud_needed)
h264parse->aud_insert = FALSE;
/* Make sure the next buffer will contain an AUD */
if (h264parse->aud_needed) {
h264parse->aud_insert = TRUE;
h264parse->aud_needed = FALSE;
}
if (nonext)
break;
/* if no next nal, we reached the end of this buffer */
if (nonext) {
/* If there is a marker flag, or input is AU, we know this is complete */
if (GST_BUFFER_FLAG_IS_SET (frame->buffer, GST_BUFFER_FLAG_MARKER) ||
h264parse->in_align == GST_H264_PARSE_ALIGN_AU) {
break;
}
/* if no next nal, we know it's complete here */
au_complete = gst_h264_parse_collect_nal (h264parse, data, size, &nalu);
/* or if we are draining */
if (drain || h264parse->align == GST_H264_PARSE_ALIGN_NAL)
break;
if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) {
h264parse->aud_needed = au_complete;
break;
current_off = nalu.offset + nalu.size;
goto more;
}
if (au_complete)
/* If the output is NAL, we are done */
if (h264parse->align == GST_H264_PARSE_ALIGN_NAL)
break;
GST_DEBUG_OBJECT (h264parse, "Looking for more");
......@@ -2434,6 +2434,7 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
/* In case of byte-stream, insert au delimeter by default
* if it doesn't exist */
if (h264parse->aud_insert && h264parse->format == GST_H264_PARSE_FORMAT_BYTE) {
GST_DEBUG_OBJECT (h264parse, "Inserting AUD into the stream.");
if (h264parse->align == GST_H264_PARSE_ALIGN_AU) {
GstMemory *mem =
gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, (guint8 *) au_delim,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment