h26xparse: Drop NAL units that can't be parsed using AU alignment
Change so that the handling of NAL unit that can't be parsed when using AU alignment is the same as when using NAL alignment, ie drop the data if it can't be parsed. If the AU contains more than one NAL unit any correctly parsed NAL unit in the AU is kept. Fixes #4436 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8976>
This commit is contained in:
parent
a58fd15c91
commit
38f5ab75fd
@ -1317,7 +1317,6 @@ gst_h264_parse_handle_frame_packetized (GstBaseParse * parse,
|
||||
* a replacement output buffer is provided anyway. */
|
||||
gst_h264_parse_parse_frame (parse, &tmp_frame);
|
||||
ret = gst_base_parse_finish_frame (parse, &tmp_frame, nl + nalu.size);
|
||||
left -= nl + nalu.size;
|
||||
|
||||
/* Bail out if we get a flow error. */
|
||||
if (ret != GST_FLOW_OK) {
|
||||
@ -1326,6 +1325,7 @@ gst_h264_parse_handle_frame_packetized (GstBaseParse * parse,
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
left -= nl + nalu.size;
|
||||
|
||||
parse_res = gst_h264_parser_identify_nalu_avc (h264parse->nalparser,
|
||||
map.data, nalu.offset + nalu.size, map.size, nl, &nalu);
|
||||
@ -1334,17 +1334,53 @@ gst_h264_parse_handle_frame_packetized (GstBaseParse * parse,
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
|
||||
if (!h264parse->split_packetized) {
|
||||
h264parse->marker = TRUE;
|
||||
gst_h264_parse_parse_frame (parse, frame);
|
||||
ret = gst_base_parse_finish_frame (parse, frame, map.size);
|
||||
gint parsed = map.size - left;
|
||||
|
||||
/* Nothing to do if no NAL unit was parsed, the whole AU will be dropped
|
||||
* below. */
|
||||
if (parsed > 0) {
|
||||
if (G_UNLIKELY (left)) {
|
||||
/* Only part of the AU could be parsed, split out that part the rest
|
||||
* will be dropped below. Should not be happening for nice AVC. */
|
||||
GST_WARNING_OBJECT (parse, "Problem parsing part of AU, keep part that "
|
||||
"has been correctly parsed (%d bytes).", parsed);
|
||||
buffer = gst_buffer_copy (frame->buffer);
|
||||
GstBaseParseFrame tmp_frame;
|
||||
|
||||
gst_base_parse_frame_init (&tmp_frame);
|
||||
tmp_frame.flags |= frame->flags;
|
||||
tmp_frame.offset = frame->offset;
|
||||
tmp_frame.overhead = frame->overhead;
|
||||
tmp_frame.buffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL,
|
||||
0, parsed);
|
||||
|
||||
h264parse->marker = TRUE;
|
||||
gst_h264_parse_parse_frame (parse, &tmp_frame);
|
||||
ret = gst_base_parse_finish_frame (parse, &tmp_frame, parsed);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
/* Bail out if we get a flow error. */
|
||||
if (ret != GST_FLOW_OK) {
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
gst_buffer_unref (buffer);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* The whole AU succesfully parsed. */
|
||||
h264parse->marker = TRUE;
|
||||
gst_h264_parse_parse_frame (parse, frame);
|
||||
ret = gst_base_parse_finish_frame (parse, frame, map.size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gst_buffer_unref (buffer);
|
||||
if (G_UNLIKELY (left)) {
|
||||
/* should not be happening for nice AVC */
|
||||
GST_WARNING_OBJECT (parse, "skipping leftover AVC data %d", left);
|
||||
frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
|
||||
ret = gst_base_parse_finish_frame (parse, frame, left);
|
||||
}
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (left)) {
|
||||
/* should not be happening for nice AVC */
|
||||
GST_WARNING_OBJECT (parse, "skipping leftover AVC data %d", left);
|
||||
frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
|
||||
ret = gst_base_parse_finish_frame (parse, frame, left);
|
||||
}
|
||||
|
||||
if (parse_res == GST_H264_PARSER_NO_NAL_END ||
|
||||
|
@ -1113,7 +1113,6 @@ gst_h265_parse_handle_frame_packetized (GstBaseParse * parse,
|
||||
* a replacement output buffer is provided anyway. */
|
||||
gst_h265_parse_parse_frame (parse, &tmp_frame);
|
||||
ret = gst_base_parse_finish_frame (parse, &tmp_frame, nl + nalu.size);
|
||||
left -= nl + nalu.size;
|
||||
|
||||
/* Bail out if we get a flow error. */
|
||||
if (ret != GST_FLOW_OK) {
|
||||
@ -1122,6 +1121,7 @@ gst_h265_parse_handle_frame_packetized (GstBaseParse * parse,
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
left -= nl + nalu.size;
|
||||
|
||||
parse_res = gst_h265_parser_identify_nalu_hevc (h265parse->nalparser,
|
||||
map.data, nalu.offset + nalu.size, map.size, nl, &nalu);
|
||||
@ -1130,17 +1130,53 @@ gst_h265_parse_handle_frame_packetized (GstBaseParse * parse,
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
|
||||
if (!h265parse->split_packetized) {
|
||||
h265parse->marker = TRUE;
|
||||
gst_h265_parse_parse_frame (parse, frame);
|
||||
ret = gst_base_parse_finish_frame (parse, frame, map.size);
|
||||
gint parsed = map.size - left;
|
||||
|
||||
/* Nothing to do if no NAL unit was parsed, the whole AU will be dropped
|
||||
* below. */
|
||||
if (parsed > 0) {
|
||||
if (G_UNLIKELY (left)) {
|
||||
/* Only part of the AU could be parsed, split out that part the rest
|
||||
* will be dropped below. Should not be happening for nice HEVC. */
|
||||
GST_WARNING_OBJECT (parse, "Problem parsing part of AU, keep part that "
|
||||
"has been correctly parsed (%d bytes).", parsed);
|
||||
buffer = gst_buffer_copy (frame->buffer);
|
||||
GstBaseParseFrame tmp_frame;
|
||||
|
||||
gst_base_parse_frame_init (&tmp_frame);
|
||||
tmp_frame.flags |= frame->flags;
|
||||
tmp_frame.offset = frame->offset;
|
||||
tmp_frame.overhead = frame->overhead;
|
||||
tmp_frame.buffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL,
|
||||
0, parsed);
|
||||
|
||||
h265parse->marker = TRUE;
|
||||
gst_h265_parse_parse_frame (parse, &tmp_frame);
|
||||
ret = gst_base_parse_finish_frame (parse, &tmp_frame, parsed);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
/* Bail out if we get a flow error. */
|
||||
if (ret != GST_FLOW_OK) {
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
gst_buffer_unref (buffer);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* The whole AU succesfully parsed. */
|
||||
h265parse->marker = TRUE;
|
||||
gst_h265_parse_parse_frame (parse, frame);
|
||||
ret = gst_base_parse_finish_frame (parse, frame, map.size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gst_buffer_unref (buffer);
|
||||
if (G_UNLIKELY (left)) {
|
||||
/* should not be happening for nice HEVC */
|
||||
GST_WARNING_OBJECT (parse, "skipping leftover HEVC data %d", left);
|
||||
frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
|
||||
ret = gst_base_parse_finish_frame (parse, frame, left);
|
||||
}
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (left)) {
|
||||
/* should not be happening for nice HEVC */
|
||||
GST_WARNING_OBJECT (parse, "skipping leftover HEVC data %d", left);
|
||||
frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
|
||||
ret = gst_base_parse_finish_frame (parse, frame, left);
|
||||
}
|
||||
|
||||
if (parse_res == GST_H265_PARSER_NO_NAL_END ||
|
||||
|
@ -1050,7 +1050,6 @@ gst_h266_parse_handle_frame_packetized (GstBaseParse * parse,
|
||||
* a replacement output buffer is provided anyway. */
|
||||
gst_h266_parse_parse_frame (parse, &tmp_frame);
|
||||
ret = gst_base_parse_finish_frame (parse, &tmp_frame, nl + nalu.size);
|
||||
left -= nl + nalu.size;
|
||||
|
||||
/* Bail out if we get a flow error. */
|
||||
if (ret != GST_FLOW_OK) {
|
||||
@ -1059,6 +1058,7 @@ gst_h266_parse_handle_frame_packetized (GstBaseParse * parse,
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
left -= nl + nalu.size;
|
||||
|
||||
parse_res = gst_h266_parser_identify_nalu_vvc (h266parse->nalparser,
|
||||
map.data, nalu.offset + nalu.size, map.size, nl, &nalu);
|
||||
@ -1067,17 +1067,53 @@ gst_h266_parse_handle_frame_packetized (GstBaseParse * parse,
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
|
||||
if (!h266parse->split_packetized) {
|
||||
h266parse->marker = TRUE;
|
||||
gst_h266_parse_parse_frame (parse, frame);
|
||||
ret = gst_base_parse_finish_frame (parse, frame, map.size);
|
||||
gint parsed = map.size - left;
|
||||
|
||||
/* Nothing to do if no NAL unit was parsed, the whole AU will be dropped
|
||||
* below. */
|
||||
if (parsed > 0) {
|
||||
if (G_UNLIKELY (left)) {
|
||||
/* Only part of the AU could be parsed, split out that part the rest
|
||||
* will be dropped below. Should not be happening for nice VVC. */
|
||||
GST_WARNING_OBJECT (parse, "Problem parsing part of AU, keep part that "
|
||||
"has been correctly parsed (%d bytes).", parsed);
|
||||
buffer = gst_buffer_copy (frame->buffer);
|
||||
GstBaseParseFrame tmp_frame;
|
||||
|
||||
gst_base_parse_frame_init (&tmp_frame);
|
||||
tmp_frame.flags |= frame->flags;
|
||||
tmp_frame.offset = frame->offset;
|
||||
tmp_frame.overhead = frame->overhead;
|
||||
tmp_frame.buffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL,
|
||||
0, parsed);
|
||||
|
||||
h266parse->marker = TRUE;
|
||||
gst_h266_parse_parse_frame (parse, &tmp_frame);
|
||||
ret = gst_base_parse_finish_frame (parse, &tmp_frame, parsed);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
/* Bail out if we get a flow error. */
|
||||
if (ret != GST_FLOW_OK) {
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
gst_buffer_unref (buffer);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* The whole AU succesfully parsed. */
|
||||
h266parse->marker = TRUE;
|
||||
gst_h266_parse_parse_frame (parse, frame);
|
||||
ret = gst_base_parse_finish_frame (parse, frame, map.size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gst_buffer_unref (buffer);
|
||||
if (G_UNLIKELY (left)) {
|
||||
/* should not be happening for nice VVC */
|
||||
GST_WARNING_OBJECT (parse, "skipping leftover VVC data %d", left);
|
||||
frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
|
||||
ret = gst_base_parse_finish_frame (parse, frame, left);
|
||||
}
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (left)) {
|
||||
/* should not be happening for nice VVC */
|
||||
GST_WARNING_OBJECT (parse, "skipping leftover VVC data %d", left);
|
||||
frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
|
||||
ret = gst_base_parse_finish_frame (parse, frame, left);
|
||||
}
|
||||
|
||||
if (parse_res == GST_H266_PARSER_NO_NAL_END ||
|
||||
|
@ -1593,6 +1593,110 @@ GST_START_TEST (test_parse_to_avc3_without_sps)
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_packetized_avc_drop_corrupt)
|
||||
{
|
||||
GstBuffer *cdata;
|
||||
GstCaps *in_caps, *out_caps;
|
||||
GstHarness *h = gst_harness_new ("h264parse");
|
||||
GstBuffer *buf, *bufout;
|
||||
GstMapInfo mapout;
|
||||
|
||||
in_caps = gst_caps_from_string (stream_type_to_caps_str (PACKETIZED_AU));
|
||||
cdata =
|
||||
gst_buffer_new_memdup (h264_avc_codec_data, sizeof (h264_avc_codec_data));
|
||||
gst_caps_set_simple (in_caps, "codec_data", GST_TYPE_BUFFER, cdata,
|
||||
"stream-format", G_TYPE_STRING, "avc", NULL);
|
||||
gst_buffer_unref (cdata);
|
||||
out_caps = gst_caps_from_string (stream_type_to_caps_str (PACKETIZED_AU));
|
||||
|
||||
gst_harness_set_caps (h, in_caps, out_caps);
|
||||
|
||||
/* avc idr frame nal */
|
||||
static guint8 *h264_idr_avc;
|
||||
|
||||
/* make avc idr frame NAL */
|
||||
h264_idr_avc = g_malloc (sizeof (h264_idrframe));
|
||||
GST_WRITE_UINT32_BE (h264_idr_avc, sizeof (h264_idrframe) - 4);
|
||||
memcpy (h264_idr_avc + 4, h264_idrframe + 4, sizeof (h264_idrframe) - 4);
|
||||
|
||||
static guint8 h264_garbage_avc[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x05
|
||||
};
|
||||
|
||||
/* Send all => drop garbage end but keep correct frame. */
|
||||
buf = composite_buffer (100, 0, 2, h264_idr_avc, sizeof (h264_idrframe),
|
||||
h264_garbage_avc, sizeof (h264_garbage_avc));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Send 3 IDR frames => all should be kept. */
|
||||
buf = composite_buffer (200, 0, 3, h264_idr_avc, sizeof (h264_idrframe),
|
||||
h264_idr_avc, sizeof (h264_idrframe), h264_idr_avc,
|
||||
sizeof (h264_idrframe));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Send 2 IDR and one garbage => keep the first two and drop garabage. */
|
||||
buf = composite_buffer (300, 0, 3, h264_idr_avc, sizeof (h264_idrframe),
|
||||
h264_idr_avc, sizeof (h264_idrframe), h264_garbage_avc,
|
||||
sizeof (h264_garbage_avc));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Only send part of correct frame => drop everything */
|
||||
buf = wrap_buffer (h264_idr_avc, sizeof (h264_idrframe) - 10, 400, 0);
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Send garbage frame => drop everything */
|
||||
buf = wrap_buffer (h264_garbage_avc, sizeof (h264_garbage_avc), 500, 0);
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* EOS for pending buffers to be drained if any */
|
||||
gst_harness_push_event (h, gst_event_new_eos ());
|
||||
|
||||
fail_unless_equals_int (gst_harness_buffers_received (h), 3);
|
||||
|
||||
/* Verify IDR + garbage. */
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
|
||||
gsize sps_pps_sz = sizeof (h264_sps) + sizeof (h264_pps);
|
||||
gst_buffer_map (bufout, &mapout, GST_MAP_READ);
|
||||
fail_unless_equals_int (mapout.size, sps_pps_sz + sizeof (h264_idrframe));
|
||||
fail_unless (memcmp (mapout.data + sps_pps_sz,
|
||||
h264_idr_avc, sizeof (h264_idrframe)) == 0);
|
||||
gst_buffer_unmap (bufout, &mapout);
|
||||
gst_buffer_unref (bufout);
|
||||
|
||||
/* Verify 3 * IDR. */
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
|
||||
gst_buffer_map (bufout, &mapout, GST_MAP_READ);
|
||||
fail_unless_equals_int (mapout.size, 3 * sizeof (h264_idrframe));
|
||||
fail_unless (memcmp (mapout.data, h264_idr_avc, sizeof (h264_idrframe)) == 0);
|
||||
fail_unless (memcmp (mapout.data + sizeof (h264_idrframe), h264_idr_avc,
|
||||
sizeof (h264_idrframe)) == 0);
|
||||
fail_unless (memcmp (mapout.data + 2 * sizeof (h264_idrframe), h264_idr_avc,
|
||||
sizeof (h264_idrframe)) == 0);
|
||||
gst_buffer_unmap (bufout, &mapout);
|
||||
gst_buffer_unref (bufout);
|
||||
|
||||
/* Verify 2 * IDR + garbage. */
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
|
||||
gst_buffer_map (bufout, &mapout, GST_MAP_READ);
|
||||
fail_unless_equals_int (mapout.size, 2 * sizeof (h264_idrframe));
|
||||
fail_unless (memcmp (mapout.data, h264_idr_avc, sizeof (h264_idrframe)) == 0);
|
||||
fail_unless (memcmp (mapout.data + sizeof (h264_idrframe), h264_idr_avc,
|
||||
sizeof (h264_idrframe)) == 0);
|
||||
gst_buffer_unmap (bufout, &mapout);
|
||||
gst_buffer_unref (bufout);
|
||||
|
||||
gst_harness_teardown (h);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - Both push- and pull-modes need to be tested
|
||||
@ -1707,6 +1811,7 @@ main (int argc, char **argv)
|
||||
tcase_add_test (tc_chain, test_parse_aud_insert);
|
||||
tcase_add_test (tc_chain, test_parse_sei_userdefinedunregistered);
|
||||
tcase_add_test (tc_chain, test_parse_to_avc3_without_sps);
|
||||
tcase_add_test (tc_chain, test_packetized_avc_drop_corrupt);
|
||||
nf += gst_check_run_suite (s, "h264parse", __FILE__);
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,18 @@ GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
*
|
||||
*/
|
||||
|
||||
static const guint8 h265_hvcc_codec_data[] = {
|
||||
0x01, 0x04, 0x08, 0x00, 0x00, 0x00, 0x98, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3f,
|
||||
0xf0, 0x00, 0xfc, 0xff, 0xfc, 0xfc, 0x00, 0x00, 0x0f, 0x03, 0x20, 0x00, 0x01,
|
||||
0x00, 0x17, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x04, 0x08, 0x00, 0x00, 0x03,
|
||||
0x00, 0x98, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x3f, 0x95, 0x98, 0x09, 0x21,
|
||||
0x00, 0x01, 0x00, 0x2f, 0x42, 0x01, 0x01, 0x04, 0x08, 0x00, 0x00, 0x03, 0x00,
|
||||
0x98, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x3f, 0x90, 0x11, 0x08, 0x8a, 0x52,
|
||||
0xca, 0xcd, 0x57, 0x95, 0xff, 0xe0, 0x00, 0x20, 0x00, 0x2d, 0x41, 0x81, 0x81,
|
||||
0x81, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x1e, 0x08, 0x22,
|
||||
0x00, 0x01, 0x00, 0x06, 0x44, 0x01, 0xc1, 0x73, 0xd0, 0x89
|
||||
};
|
||||
|
||||
static const guint8 h265_vps[] = {
|
||||
0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, 0x00,
|
||||
0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x3f, 0x95,
|
||||
@ -1233,6 +1245,109 @@ GST_START_TEST (test_invalid_sei_in_hvcc)
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_packetized_hvcc_drop_corrupt)
|
||||
{
|
||||
GstBuffer *cdata;
|
||||
GstCaps *in_caps, *out_caps;
|
||||
GstHarness *h = gst_harness_new ("h265parse");
|
||||
GstBuffer *buf, *bufout;
|
||||
GstMapInfo mapout;
|
||||
const gchar *in_caps_str =
|
||||
"video/x-h265, stream-format=(string)hvc1, alignment=(string)au";
|
||||
const gchar *out_caps_str =
|
||||
"video/x-h265, stream-format=(string)hvc1, alignment=(string)au";
|
||||
|
||||
in_caps = gst_caps_from_string (in_caps_str);
|
||||
cdata = gst_buffer_new_memdup (h265_hvcc_codec_data,
|
||||
sizeof (h265_hvcc_codec_data));
|
||||
gst_caps_set_simple (in_caps, "codec_data", GST_TYPE_BUFFER, cdata, NULL);
|
||||
gst_buffer_unref (cdata);
|
||||
out_caps = gst_caps_from_string (out_caps_str);
|
||||
gst_harness_set_caps (h, in_caps, out_caps);
|
||||
|
||||
/* hvcc idr frame nal */
|
||||
static guint8 *h265_idr_hvcc;
|
||||
|
||||
/* make hvcc frame NAL */
|
||||
h265_idr_hvcc = g_malloc (sizeof (h265_idr));
|
||||
GST_WRITE_UINT32_BE (h265_idr_hvcc, sizeof (h265_idr) - 4);
|
||||
memcpy (h265_idr_hvcc + 4, h265_idr + 4, sizeof (h265_idr) - 4);
|
||||
|
||||
static guint8 h265_garbage_hvcc[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x05
|
||||
};
|
||||
|
||||
/* Send all => drop garbage end but keep correct frame. */
|
||||
buf = composite_buffer (100, 0, 2, h265_idr_hvcc, sizeof (h265_idr),
|
||||
h265_garbage_hvcc, sizeof (h265_garbage_hvcc));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Send 3 IDR frames => all should be kept. */
|
||||
buf = composite_buffer (200, 0, 3, h265_idr_hvcc, sizeof (h265_idr),
|
||||
h265_idr_hvcc, sizeof (h265_idr), h265_idr_hvcc, sizeof (h265_idr));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Send 2 IDR and one garbage => keep the first two and drop garabage. */
|
||||
buf = composite_buffer (300, 0, 3, h265_idr_hvcc, sizeof (h265_idr),
|
||||
h265_idr_hvcc, sizeof (h265_idr), h265_garbage_hvcc,
|
||||
sizeof (h265_garbage_hvcc));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Only send part of correct frame => drop everything */
|
||||
buf = wrap_buffer (h265_idr_hvcc, sizeof (h265_idr) - 10, 400, 0);
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Send garbage frame => drop everything */
|
||||
buf = wrap_buffer (h265_garbage_hvcc, sizeof (h265_garbage_hvcc), 500, 0);
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* EOS for pending buffers to be drained if any */
|
||||
gst_harness_push_event (h, gst_event_new_eos ());
|
||||
|
||||
fail_unless_equals_int (gst_harness_buffers_received (h), 3);
|
||||
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
|
||||
/* Verify IDR + garbage. */
|
||||
gst_buffer_map (bufout, &mapout, GST_MAP_READ);
|
||||
fail_unless_equals_int (mapout.size, sizeof (h265_idr));
|
||||
fail_unless (memcmp (mapout.data, h265_idr_hvcc, sizeof (h265_idr)) == 0);
|
||||
gst_buffer_unmap (bufout, &mapout);
|
||||
gst_buffer_unref (bufout);
|
||||
|
||||
/* Verify 3 * IDR. */
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
|
||||
gst_buffer_map (bufout, &mapout, GST_MAP_READ);
|
||||
fail_unless_equals_int (mapout.size, 3 * sizeof (h265_idr));
|
||||
fail_unless (memcmp (mapout.data, h265_idr_hvcc, sizeof (h265_idr)) == 0);
|
||||
fail_unless (memcmp (mapout.data + sizeof (h265_idr), h265_idr_hvcc,
|
||||
sizeof (h265_idr)) == 0);
|
||||
fail_unless (memcmp (mapout.data + 2 * sizeof (h265_idr), h265_idr_hvcc,
|
||||
sizeof (h265_idr)) == 0);
|
||||
gst_buffer_unmap (bufout, &mapout);
|
||||
gst_buffer_unref (bufout);
|
||||
|
||||
/* Verify 2 * IDR + garbage. */
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
|
||||
gst_buffer_map (bufout, &mapout, GST_MAP_READ);
|
||||
fail_unless_equals_int (mapout.size, 2 * sizeof (h265_idr));
|
||||
fail_unless (memcmp (mapout.data, h265_idr_hvcc, sizeof (h265_idr)) == 0);
|
||||
fail_unless (memcmp (mapout.data + sizeof (h265_idr), h265_idr_hvcc,
|
||||
sizeof (h265_idr)) == 0);
|
||||
gst_buffer_unmap (bufout, &mapout);
|
||||
gst_buffer_unref (bufout);
|
||||
|
||||
g_free (h265_idr_hvcc);
|
||||
gst_harness_teardown (h);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
h265parse_harnessed_suite (void)
|
||||
{
|
||||
@ -1271,6 +1386,7 @@ h265parse_harnessed_suite (void)
|
||||
tcase_add_test (tc_chain, test_parse_sei_userdefinedunregistered);
|
||||
tcase_add_test (tc_chain, test_invalid_sei_in_hvcc);
|
||||
|
||||
tcase_add_test (tc_chain, test_packetized_hvcc_drop_corrupt);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -1230,6 +1230,112 @@ GST_START_TEST (test_drain)
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_packetized_vvc1_drop_corrupt)
|
||||
{
|
||||
GstBuffer *cdata;
|
||||
GstCaps *in_caps, *out_caps;
|
||||
GstHarness *h = gst_harness_new ("h266parse");
|
||||
GstBuffer *buf, *bufout;
|
||||
GstMapInfo mapout;
|
||||
const gchar *in_caps_str =
|
||||
"video/x-h266, parsed=(boolean)false, stream-format=vvc1, alignment=au";
|
||||
const gchar *out_caps_str =
|
||||
"video/x-h266, parsed=(boolean)true, stream-format=vvc1, alignment=au";
|
||||
|
||||
in_caps = gst_caps_from_string (in_caps_str);
|
||||
cdata = gst_buffer_new_memdup (h266_vvc1_codec_data,
|
||||
sizeof (h266_vvc1_codec_data));
|
||||
gst_caps_set_simple (in_caps, "codec_data", GST_TYPE_BUFFER, cdata,
|
||||
"stream-format", G_TYPE_STRING, "vvc1", NULL);
|
||||
gst_buffer_unref (cdata);
|
||||
out_caps = gst_caps_from_string (out_caps_str);
|
||||
gst_harness_set_caps (h, in_caps, out_caps);
|
||||
|
||||
/* vvc1 idr frame nal */
|
||||
static guint8 *h266_idr_vvc1;
|
||||
|
||||
/* make vvc1 idr frame NAL */
|
||||
h266_idr_vvc1 = g_malloc (sizeof (h266_idr));
|
||||
GST_WRITE_UINT32_BE (h266_idr_vvc1, sizeof (h266_idr) - 4);
|
||||
memcpy (h266_idr_vvc1 + 4, h266_idr + 4, sizeof (h266_idr) - 4);
|
||||
|
||||
static guint8 h266_garbage_vvc1[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x05
|
||||
};
|
||||
|
||||
/* Send all => drop garbage end but keep correct frame. */
|
||||
buf = composite_buffer (100, 0, 2, h266_idr_vvc1, sizeof (h266_idr),
|
||||
h266_garbage_vvc1, sizeof (h266_garbage_vvc1));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Send 3 IDR frames => all should be kept. */
|
||||
buf = composite_buffer (200, 0, 3, h266_idr_vvc1, sizeof (h266_idr),
|
||||
h266_idr_vvc1, sizeof (h266_idr), h266_idr_vvc1, sizeof (h266_idr));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Send 2 IDR and one garbage => keep the first two and drop garabage. */
|
||||
buf = composite_buffer (300, 0, 3, h266_idr_vvc1, sizeof (h266_idr),
|
||||
h266_idr_vvc1, sizeof (h266_idr), h266_garbage_vvc1,
|
||||
sizeof (h266_garbage_vvc1));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Only send part of correct frame => drop everything */
|
||||
buf = wrap_buffer (h266_idr_vvc1, sizeof (h266_idr) - 10, 300, 0);
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* Send garbage frame => drop everything */
|
||||
buf = wrap_buffer (h266_garbage_vvc1, sizeof (h266_garbage_vvc1), 400, 0);
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
/* EOS for pending buffers to be drained if any */
|
||||
gst_harness_push_event (h, gst_event_new_eos ());
|
||||
|
||||
fail_unless_equals_int (gst_harness_buffers_received (h), 3);
|
||||
|
||||
/* Verify IDR + garbage. */
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
|
||||
gsize vps_sps_pps_sz = sizeof (h266_vps) + sizeof (h266_sps) +
|
||||
sizeof (h266_pps);
|
||||
gst_buffer_map (bufout, &mapout, GST_MAP_READ);
|
||||
fail_unless_equals_int (mapout.size, vps_sps_pps_sz + sizeof (h266_idr));
|
||||
fail_unless (memcmp (mapout.data + vps_sps_pps_sz,
|
||||
h266_idr_vvc1, sizeof (h266_idr)) == 0);
|
||||
gst_buffer_unmap (bufout, &mapout);
|
||||
gst_buffer_unref (bufout);
|
||||
|
||||
/* Verify 3 * IDR. */
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
|
||||
gst_buffer_map (bufout, &mapout, GST_MAP_READ);
|
||||
fail_unless_equals_int (mapout.size, 3 * sizeof (h266_idr));
|
||||
fail_unless (memcmp (mapout.data, h266_idr_vvc1, sizeof (h266_idr)) == 0);
|
||||
fail_unless (memcmp (mapout.data + sizeof (h266_idr), h266_idr_vvc1,
|
||||
sizeof (h266_idr)) == 0);
|
||||
fail_unless (memcmp (mapout.data + 2 * sizeof (h266_idr), h266_idr_vvc1,
|
||||
sizeof (h266_idr)) == 0);
|
||||
gst_buffer_unmap (bufout, &mapout);
|
||||
gst_buffer_unref (bufout);
|
||||
|
||||
/* Verify 2 * IDR + garbage. */
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
|
||||
gst_buffer_map (bufout, &mapout, GST_MAP_READ);
|
||||
fail_unless_equals_int (mapout.size, 2 * sizeof (h266_idr));
|
||||
fail_unless (memcmp (mapout.data, h266_idr_vvc1, sizeof (h266_idr)) == 0);
|
||||
fail_unless (memcmp (mapout.data + sizeof (h266_idr), h266_idr_vvc1,
|
||||
sizeof (h266_idr)) == 0);
|
||||
gst_buffer_unmap (bufout, &mapout);
|
||||
gst_buffer_unref (bufout);
|
||||
|
||||
gst_harness_teardown (h);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
h266parse_harnessed_suite (void)
|
||||
{
|
||||
@ -1268,6 +1374,8 @@ h266parse_harnessed_suite (void)
|
||||
|
||||
tcase_add_test (tc_chain, test_drain);
|
||||
|
||||
tcase_add_test (tc_chain, test_packetized_vvc1_drop_corrupt);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user