mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
h264parse: unobfuscate frame parsing code
This commit is contained in:
parent
c835325536
commit
1cbd755a2c
2 changed files with 102 additions and 109 deletions
|
@ -177,11 +177,7 @@ gst_h264_parse_reset_frame (GstH264Parse * h264parse)
|
||||||
GST_DEBUG_OBJECT (h264parse, "reset frame");
|
GST_DEBUG_OBJECT (h264parse, "reset frame");
|
||||||
|
|
||||||
/* done parsing; reset state */
|
/* done parsing; reset state */
|
||||||
h264parse->nalu.valid = FALSE;
|
h264parse->current_off = -1;
|
||||||
h264parse->nalu.offset = 0;
|
|
||||||
h264parse->nalu.sc_offset = 0;
|
|
||||||
h264parse->nalu.size = 0;
|
|
||||||
h264parse->current_off = 0;
|
|
||||||
|
|
||||||
h264parse->picture_start = FALSE;
|
h264parse->picture_start = FALSE;
|
||||||
h264parse->update_caps = FALSE;
|
h264parse->update_caps = FALSE;
|
||||||
|
@ -656,10 +652,12 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
|
||||||
GstH264Parse *h264parse = GST_H264_PARSE (parse);
|
GstH264Parse *h264parse = GST_H264_PARSE (parse);
|
||||||
GstBuffer *buffer = frame->buffer;
|
GstBuffer *buffer = frame->buffer;
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
guint size, current_off = 0;
|
guint size;
|
||||||
gboolean drain;
|
gint current_off = 0;
|
||||||
|
gboolean drain, nonext;
|
||||||
GstH264NalParser *nalparser = h264parse->nalparser;
|
GstH264NalParser *nalparser = h264parse->nalparser;
|
||||||
GstH264NalUnit nalu;
|
GstH264NalUnit nalu;
|
||||||
|
GstH264ParserResult pres;
|
||||||
|
|
||||||
/* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */
|
/* expect at least 3 bytes startcode == sc, and 2 bytes NALU payload */
|
||||||
if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5))
|
if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 5))
|
||||||
|
@ -681,16 +679,38 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
|
||||||
data = GST_BUFFER_DATA (buffer);
|
data = GST_BUFFER_DATA (buffer);
|
||||||
size = GST_BUFFER_SIZE (buffer);
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
|
|
||||||
drain = FALSE;
|
drain = GST_BASE_PARSE_DRAINING (parse);
|
||||||
nalu = h264parse->nalu;
|
nonext = FALSE;
|
||||||
|
|
||||||
current_off = h264parse->current_off;
|
current_off = h264parse->current_off;
|
||||||
|
if (current_off < 0)
|
||||||
|
current_off = 0;
|
||||||
g_assert (current_off < size);
|
g_assert (current_off < size);
|
||||||
|
GST_DEBUG_OBJECT (h264parse, "last parse position %d", current_off);
|
||||||
|
|
||||||
|
/* check for initial skip */
|
||||||
|
if (h264parse->current_off == -1) {
|
||||||
|
pres =
|
||||||
|
gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off,
|
||||||
|
size, &nalu);
|
||||||
|
switch (pres) {
|
||||||
|
case GST_H264_PARSER_OK:
|
||||||
|
if (nalu.sc_offset > 0) {
|
||||||
|
*skipsize = nalu.sc_offset;
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_H264_PARSER_NO_NAL:
|
||||||
|
*skipsize = size - 3;
|
||||||
|
goto skip;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (h264parse, "last parse position %u", current_off);
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
GstH264ParserResult pres;
|
|
||||||
|
|
||||||
if (h264parse->packetized_chunked)
|
if (h264parse->packetized_chunked)
|
||||||
pres =
|
pres =
|
||||||
gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off,
|
gst_h264_parser_identify_nalu_unchecked (nalparser, data, current_off,
|
||||||
|
@ -702,99 +722,85 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
|
||||||
|
|
||||||
switch (pres) {
|
switch (pres) {
|
||||||
case GST_H264_PARSER_OK:
|
case GST_H264_PARSER_OK:
|
||||||
GST_DEBUG_OBJECT (h264parse, "complete nal found. "
|
GST_DEBUG_OBJECT (h264parse, "complete nal (offset, size): (%u, %u) ",
|
||||||
"current offset: %u, Nal offset: %u, Nal Size: %u",
|
nalu.offset, nalu.size);
|
||||||
current_off, nalu.offset, nalu.size);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (h264parse, "current off. %u",
|
|
||||||
nalu.offset + nalu.size);
|
|
||||||
|
|
||||||
if (!h264parse->nalu.size && !h264parse->nalu.valid)
|
|
||||||
h264parse->nalu = nalu;
|
|
||||||
|
|
||||||
/* need 2 bytes of next nal */
|
|
||||||
if (!h264parse->packetized_chunked &&
|
|
||||||
(nalu.offset + nalu.size + 4 + 2 > size)) {
|
|
||||||
if (GST_BASE_PARSE_DRAINING (parse)) {
|
|
||||||
drain = TRUE;
|
|
||||||
} else {
|
|
||||||
GST_DEBUG_OBJECT (h264parse, "need more bytes of next nal");
|
|
||||||
current_off = nalu.sc_offset;
|
|
||||||
goto more;
|
|
||||||
}
|
|
||||||
} else if (h264parse->packetized_chunked) {
|
|
||||||
/* normal next nal based collection not possible,
|
|
||||||
* _chain will have to tell us whether this was last one for AU */
|
|
||||||
drain = h264parse->packetized_last;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case GST_H264_PARSER_BROKEN_LINK:
|
|
||||||
return FALSE;
|
|
||||||
case GST_H264_PARSER_ERROR:
|
|
||||||
current_off = size - 3;
|
|
||||||
goto parsing_error;
|
|
||||||
case GST_H264_PARSER_NO_NAL:
|
|
||||||
/* don't expect to have found any NAL so far */
|
|
||||||
g_assert (h264parse->nalu.size == 0);
|
|
||||||
current_off = h264parse->nalu.sc_offset = size - 3;
|
|
||||||
goto more;
|
|
||||||
case GST_H264_PARSER_BROKEN_DATA:
|
|
||||||
GST_WARNING_OBJECT (h264parse, "input stream is corrupt; "
|
|
||||||
"it contains a NAL unit of length %d", nalu.size);
|
|
||||||
|
|
||||||
/* broken nal at start -> arrange to skip it,
|
|
||||||
* otherwise have it terminate current au
|
|
||||||
* (and so it will be skipped on next frame round) */
|
|
||||||
if (nalu.sc_offset == h264parse->nalu.sc_offset) {
|
|
||||||
*skipsize = nalu.offset;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (h264parse, "skipping broken nal");
|
|
||||||
goto invalid;
|
|
||||||
} else {
|
|
||||||
nalu.size = 0;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
case GST_H264_PARSER_NO_NAL_END:
|
case GST_H264_PARSER_NO_NAL_END:
|
||||||
GST_DEBUG_OBJECT (h264parse, "not a complete nal found at offset %u",
|
GST_DEBUG_OBJECT (h264parse, "not a complete nal found at offset %u",
|
||||||
nalu.offset);
|
nalu.offset);
|
||||||
|
/* if draining, accept it as complete nal */
|
||||||
current_off = nalu.sc_offset;
|
if (drain) {
|
||||||
/* We keep the reference to this nal so we start over the parsing
|
nonext = TRUE;
|
||||||
* here */
|
|
||||||
if (!h264parse->nalu.size && !h264parse->nalu.valid)
|
|
||||||
h264parse->nalu = nalu;
|
|
||||||
|
|
||||||
if (GST_BASE_PARSE_DRAINING (parse)) {
|
|
||||||
drain = TRUE;
|
|
||||||
GST_DEBUG_OBJECT (h264parse, "draining NAL %u %u %u", size,
|
|
||||||
h264parse->nalu.offset, h264parse->nalu.size);
|
|
||||||
/* Can't parse the nalu */
|
|
||||||
if (size - h264parse->nalu.offset < 2) {
|
|
||||||
*skipsize = nalu.offset;
|
|
||||||
goto invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We parse it anyway */
|
|
||||||
nalu.size = size - nalu.offset;
|
nalu.size = size - nalu.offset;
|
||||||
|
GST_DEBUG_OBJECT (h264parse, "draining, accepting with size %u",
|
||||||
|
nalu.size);
|
||||||
|
/* if it's not too short at least */
|
||||||
|
if (nalu.size < 2)
|
||||||
|
goto broken;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* otherwise need more */
|
||||||
goto more;
|
goto more;
|
||||||
|
case GST_H264_PARSER_BROKEN_LINK:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
case GST_H264_PARSER_ERROR:
|
||||||
|
/* should not really occur either */
|
||||||
|
GST_DEBUG_OBJECT (h264parse, "error parsing Nal Unit");
|
||||||
|
/* fall-through */
|
||||||
|
case GST_H264_PARSER_NO_NAL:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
case GST_H264_PARSER_BROKEN_DATA:
|
||||||
|
GST_WARNING_OBJECT (h264parse, "input stream is corrupt; "
|
||||||
|
"it contains a NAL unit of length %u", nalu.size);
|
||||||
|
broken:
|
||||||
|
/* broken nal at start -> arrange to skip it,
|
||||||
|
* otherwise have it terminate current au
|
||||||
|
* (and so it will be skipped on next frame round) */
|
||||||
|
if (current_off == 0) {
|
||||||
|
GST_DEBUG_OBJECT (h264parse, "skipping broken nal");
|
||||||
|
*skipsize = nalu.offset;
|
||||||
|
goto skip;
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (h264parse, "terminating au");
|
||||||
|
nalu.size = 0;
|
||||||
|
nalu.offset = nalu.sc_offset;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_off = nalu.offset + nalu.size;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (h264parse, "%p complete nal found. Off: %u, Size: %u",
|
GST_DEBUG_OBJECT (h264parse, "%p complete nal found. Off: %u, Size: %u",
|
||||||
data, nalu.offset, nalu.size);
|
data, nalu.offset, nalu.size);
|
||||||
|
|
||||||
|
/* simulate no next nal if none needed */
|
||||||
|
nonext = nonext || (h264parse->align == GST_H264_PARSE_ALIGN_NAL);
|
||||||
|
|
||||||
|
if (!nonext && !h264parse->packetized_chunked) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gst_h264_parse_process_nal (h264parse, &nalu);
|
gst_h264_parse_process_nal (h264parse, &nalu);
|
||||||
|
|
||||||
/* simulate no next nal if none needed */
|
if (nonext)
|
||||||
drain = drain || (h264parse->align == GST_H264_PARSE_ALIGN_NAL);
|
break;
|
||||||
|
|
||||||
/* In packetized mode we know there's only on NALU in each input packet,
|
/* In packetized mode we know there's only on NALU in each input packet,
|
||||||
* but we may not have seen the whole AU already, possibly need more */
|
* but we may not have seen the whole AU already, possibly need more */
|
||||||
if (h264parse->packetized_chunked) {
|
if (h264parse->packetized_chunked) {
|
||||||
if (drain)
|
if (h264parse->packetized_last)
|
||||||
break;
|
break;
|
||||||
/* next NALU expected at end of current data */
|
/* next NALU expected at end of current data */
|
||||||
current_off = size;
|
current_off = size;
|
||||||
|
@ -802,42 +808,30 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if no next nal, we know it's complete here */
|
/* if no next nal, we know it's complete here */
|
||||||
if (drain || gst_h264_parse_collect_nal (h264parse, data, size, &nalu))
|
if (gst_h264_parse_collect_nal (h264parse, data, size, &nalu))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (h264parse, "Looking for more");
|
GST_DEBUG_OBJECT (h264parse, "Looking for more");
|
||||||
|
current_off = nalu.offset + nalu.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
*skipsize = h264parse->nalu.sc_offset;
|
*framesize = nalu.offset + nalu.size;
|
||||||
*framesize = nalu.offset + nalu.size - h264parse->nalu.sc_offset;
|
|
||||||
h264parse->current_off = current_off;
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
parsing_error:
|
|
||||||
GST_DEBUG_OBJECT (h264parse, "error parsing Nal Unit");
|
|
||||||
|
|
||||||
more:
|
more:
|
||||||
/* ask for best next available */
|
/* ask for best next available */
|
||||||
*framesize = G_MAXUINT;
|
*framesize = G_MAXUINT;
|
||||||
if (!h264parse->nalu.size) {
|
|
||||||
/* skip up to initial startcode */
|
|
||||||
*skipsize = h264parse->nalu.sc_offset;
|
|
||||||
/* but mind some stuff will have been skipped */
|
|
||||||
g_assert (current_off >= *skipsize);
|
|
||||||
current_off -= *skipsize;
|
|
||||||
h264parse->nalu.sc_offset = 0;
|
|
||||||
} else {
|
|
||||||
*skipsize = 0;
|
*skipsize = 0;
|
||||||
}
|
|
||||||
|
|
||||||
/* Restart parsing from here next time */
|
/* Restart parsing from here next time */
|
||||||
|
if (current_off > 0)
|
||||||
h264parse->current_off = current_off;
|
h264parse->current_off = current_off;
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
invalid:
|
skip:
|
||||||
|
GST_DEBUG_OBJECT (h264parse, "skipping %d", *skipsize);
|
||||||
gst_h264_parse_reset_frame (h264parse);
|
gst_h264_parse_reset_frame (h264parse);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,10 +67,9 @@ struct _GstH264Parse
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
GstH264NalParser *nalparser;
|
GstH264NalParser *nalparser;
|
||||||
GstH264NalUnit nalu;
|
|
||||||
guint align;
|
guint align;
|
||||||
guint format;
|
guint format;
|
||||||
guint current_off;
|
gint current_off;
|
||||||
gboolean packetized_last;
|
gboolean packetized_last;
|
||||||
gboolean packetized_chunked;
|
gboolean packetized_chunked;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue