Commit 40ad4931 authored by Nicolas Dufresne's avatar Nicolas Dufresne
Browse files

h265parse: 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 d3f15f2e
......@@ -178,7 +178,6 @@ gst_h265_parse_reset_frame (GstH265Parse * h265parse)
/* done parsing; reset state */
h265parse->current_off = -1;
h265parse->picture_start = FALSE;
h265parse->update_caps = FALSE;
h265parse->idr_pos = -1;
h265parse->sei_pos = -1;
......@@ -672,6 +671,10 @@ gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu)
GST_H265_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 */
h265parse->picture_start = TRUE;
pres = gst_h265_parser_parse_slice_hdr (nalparser, nalu, &slice);
if (pres == GST_H265_PARSER_OK) {
......@@ -753,47 +756,33 @@ static inline gboolean
gst_h265_parse_collect_nal (GstH265Parse * h265parse, const guint8 * data,
guint size, GstH265NalUnit * nalu)
{
gboolean complete;
GstH265ParserResult parse_res;
GstH265NalUnitType nal_type = nalu->type;
GstH265NalUnit nnalu;
GST_DEBUG_OBJECT (h265parse, "parsing collected nal");
parse_res = gst_h265_parser_identify_nalu_unchecked (h265parse->nalparser,
data, nalu->offset + nalu->size, size, &nnalu);
if (parse_res != GST_H265_PARSER_OK)
return FALSE;
gboolean complete;
/* determine if AU complete */
GST_LOG_OBJECT (h265parse, "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 */
h265parse->picture_start |= ((nal_type >= GST_H265_NAL_SLICE_TRAIL_N
&& nal_type <= GST_H265_NAL_SLICE_RASL_R)
|| (nal_type >= GST_H265_NAL_SLICE_BLA_W_LP
&& nal_type <= RESERVED_IRAP_NAL_TYPE_MAX));
GST_LOG_OBJECT (h265parse, "next nal type: %d %s (picture started %i)",
nal_type, _nal_name (nal_type), h265parse->picture_start);
/* consider a coded slices (IRAP or not) to start a picture,
* (so ending the previous one) if first_slice_segment_in_pic_flag == 1*/
nal_type = nnalu.type;
complete = h265parse->picture_start && ((nal_type >= GST_H265_NAL_VPS
&& nal_type <= GST_H265_NAL_AUD)
|| nal_type == GST_H265_NAL_PREFIX_SEI || (nal_type >= 41
&& nal_type <= 44) || (nal_type >= 48 && nal_type <= 55));
GST_LOG_OBJECT (h265parse, "next nal type: %d %s", nal_type,
_nal_name (nal_type));
/* Any VCL Nal unit with first_slice_segment_in_pic_flag == 1 considered start of frame */
complete |= h265parse->picture_start
&& (((nal_type >= GST_H265_NAL_SLICE_TRAIL_N
&& nal_type <= GST_H265_NAL_SLICE_RASL_R)
|| (nal_type >= GST_H265_NAL_SLICE_BLA_W_LP
&& nal_type <= RESERVED_IRAP_NAL_TYPE_MAX))
&& (nnalu.data[nnalu.offset + 2] & 0x80));
&& (nalu->data[nalu->offset + 2] & 0x80));
GST_LOG_OBJECT (h265parse, "au complete: %d", complete);
if (complete)
h265parse->picture_start = FALSE;
return complete;
}
......@@ -939,7 +928,9 @@ gst_h265_parse_handle_frame (GstBaseParse * parse,
GST_LOG_OBJECT (h265parse, "resuming frame parsing");
}
drain = GST_BASE_PARSE_DRAINING (parse);
/* Always consume the entire input buffer when in_align == ALIGN_AU */
drain = GST_BASE_PARSE_DRAINING (parse)
|| h265parse->in_align == GST_H265_PARSE_ALIGN_AU;
nonext = FALSE;
current_off = h265parse->current_off;
......@@ -982,6 +973,13 @@ gst_h265_parse_handle_frame (GstBaseParse * parse,
nalu.offset, nalu.size);
break;
case GST_H265_PARSER_NO_NAL_END:
/* In NAL alignment, assume the NAL is complete */
if (h265parse->in_align == GST_H265_PARSE_ALIGN_NAL ||
h265parse->in_align == GST_H265_PARSE_ALIGN_AU) {
nonext = TRUE;
nalu.size = size - nalu.offset;
break;
}
GST_DEBUG_OBJECT (h265parse, "not a complete nal found at offset %u",
nalu.offset);
/* if draining, accept it as complete nal */
......@@ -1036,18 +1034,12 @@ gst_h265_parse_handle_frame (GstBaseParse * parse,
GST_DEBUG_OBJECT (h265parse, "%p complete nal found. Off: %u, Size: %u",
data, nalu.offset, nalu.size);
/* simulate no next nal if none needed */
nonext = nonext || (h265parse->align == GST_H265_PARSE_ALIGN_NAL);
if (!nonext) {
if (nalu.offset + nalu.size + 5 + 2 > size) {
GST_DEBUG_OBJECT (h265parse, "not enough data for next NALU");
if (drain) {
GST_DEBUG_OBJECT (h265parse, "but draining anyway");
nonext = TRUE;
} else {
goto more;
}
if (gst_h265_parse_collect_nal (h265parse, data, size, &nalu)) {
/* complete current frame, if it exist */
if (current_off > 0) {
nalu.size = 0;
nalu.offset = nalu.sc_offset;
break;
}
}
......@@ -1059,11 +1051,23 @@ gst_h265_parse_handle_frame (GstBaseParse * parse,
goto skip;
}
if (nonext)
break;
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) ||
h265parse->in_align == GST_H265_PARSE_ALIGN_AU) {
break;
}
/* or if we are draining or producing NALs */
if (drain || h265parse->align == GST_H265_PARSE_ALIGN_NAL)
break;
/* if no next nal, we know it's complete here */
if (gst_h265_parse_collect_nal (h265parse, data, size, &nalu))
current_off = nalu.offset + nalu.size;
goto more;
}
/* If the output is NAL, we are done */
if (h265parse->align == GST_H265_PARSE_ALIGN_NAL)
break;
GST_DEBUG_OBJECT (h265parse, "Looking for more");
......@@ -2315,6 +2319,8 @@ gst_h265_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
h265parse->packetized = TRUE;
}
h265parse->in_align = align;
return TRUE;
/* ERRORS */
......
......@@ -63,6 +63,7 @@ struct _GstH265Parse
/* state */
GstH265Parser *nalparser;
guint in_align;
guint state;
guint align;
guint format;
......
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