h265parse: Wait for SEI before exposing src caps
Similar to h264parse, this makes sure 'lcevc=false' src caps are not set before parsing SEI. It is needed for decodebin2 to work properly with the LCEVC decoder. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/9427>
This commit is contained in:
parent
98d3228fc2
commit
b904ac195f
@ -3376,19 +3376,7 @@ gst_h265_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
|
||||
}
|
||||
|
||||
if (format == h265parse->format && align == h265parse->align) {
|
||||
/* do not set CAPS and passthrough mode if SPS/PPS have not been parsed */
|
||||
if (h265parse->have_sps && h265parse->have_pps) {
|
||||
/* Don't enable passthrough here. This element will parse various
|
||||
* SEI messages which would be very important/useful for downstream
|
||||
* (HDR, timecode for example)
|
||||
*/
|
||||
#if 0
|
||||
gst_base_parse_set_passthrough (parse, TRUE);
|
||||
#endif
|
||||
|
||||
/* we did parse codec-data and might supplement src caps */
|
||||
gst_h265_parse_update_src_caps (h265parse, caps);
|
||||
}
|
||||
h265parse->have_vps = TRUE;
|
||||
} else if (format == GST_H265_PARSE_FORMAT_HVC1
|
||||
|| format == GST_H265_PARSE_FORMAT_HEV1) {
|
||||
/* if input != output, and input is hevc, must split before anything else */
|
||||
|
@ -345,70 +345,6 @@ GST_START_TEST (test_parse_detect_stream_with_hdr_sei)
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
/* 8bits 4:4:4 encoded stream, and profile-level-tier is not spec compliant.
|
||||
* extracted from the file reported at
|
||||
* https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1009
|
||||
*/
|
||||
static const guint8 broken_profile_codec_data[] = {
|
||||
0x01, 0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x99, 0xf0, 0x00, 0xfc, 0xff, 0xf8, 0xf8, 0x00, 0x00, 0x0f, 0x03, 0x20,
|
||||
0x00, 0x01, 0x00, 0x18, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x24, 0x08,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x99, 0xac, 0x09, 0x21, 0x00, 0x01, 0x00, 0x2c, 0x42, 0x01, 0x01,
|
||||
0x24, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x99, 0x90, 0x00, 0x3c, 0x04, 0x00, 0x44, 0x0f, 0x84,
|
||||
0x72, 0xd6, 0x94, 0x84, 0xb2, 0x5c, 0x40, 0x20, 0x00, 0x00, 0x03, 0x00,
|
||||
0x20, 0x00, 0x00, 0x07, 0x81, 0x22, 0x00, 0x01, 0x00, 0x08, 0x44, 0x01,
|
||||
0xc0, 0xf7, 0x18, 0x30, 0x0c, 0xc9
|
||||
};
|
||||
|
||||
GST_START_TEST (test_parse_fallback_profile)
|
||||
{
|
||||
GstHarness *h = gst_harness_new ("h265parse");
|
||||
GstCaps *caps;
|
||||
GstBuffer *codec_data;
|
||||
GstEvent *event;
|
||||
|
||||
codec_data = gst_buffer_new_memdup (broken_profile_codec_data,
|
||||
sizeof (broken_profile_codec_data));
|
||||
|
||||
caps = gst_caps_from_string ("video/x-h265, stream-format=(string)hvc1, "
|
||||
"alignment=(string)au");
|
||||
gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
|
||||
gst_buffer_unref (codec_data);
|
||||
|
||||
gst_harness_set_src_caps (h, caps);
|
||||
while ((event = gst_harness_pull_event (h)) != NULL) {
|
||||
GstStructure *s;
|
||||
const gchar *profile;
|
||||
|
||||
if (GST_EVENT_TYPE (event) != GST_EVENT_CAPS) {
|
||||
gst_event_unref (event);
|
||||
continue;
|
||||
}
|
||||
|
||||
gst_event_parse_caps (event, &caps);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
profile = gst_structure_get_string (s, "profile");
|
||||
|
||||
/* h265parse must provide profile */
|
||||
fail_unless (profile);
|
||||
|
||||
/* must not be main profile at least.
|
||||
* main-444 is expected but we might update the profile parsing
|
||||
* logic later. At least it should not be main profile
|
||||
*/
|
||||
fail_if (g_strcmp0 (profile, "main") == 0);
|
||||
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
}
|
||||
|
||||
gst_harness_teardown (h);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
h265parse_suite (void)
|
||||
{
|
||||
@ -421,7 +357,6 @@ h265parse_suite (void)
|
||||
tcase_add_test (tc_chain, test_parse_split);
|
||||
tcase_add_test (tc_chain, test_parse_detect_stream);
|
||||
tcase_add_test (tc_chain, test_parse_detect_stream_with_hdr_sei);
|
||||
tcase_add_test (tc_chain, test_parse_fallback_profile);
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -1187,6 +1122,9 @@ GST_START_TEST (test_invalid_sei_in_hvcc)
|
||||
GstHarness *h;
|
||||
GstCaps *caps;
|
||||
GstBuffer *codec_data;
|
||||
GstBuffer *buf, *bufout;
|
||||
GstMapInfo mapout;
|
||||
|
||||
/* Consists of 4 arrays (VPS, SPS, PPS, SEI -> broken) and each array contains
|
||||
* single nalu
|
||||
* Captured from the log at
|
||||
@ -1215,7 +1153,18 @@ GST_START_TEST (test_invalid_sei_in_hvcc)
|
||||
|
||||
h = gst_harness_new ("h265parse");
|
||||
gst_harness_set_src_caps (h, caps);
|
||||
gst_harness_push_event (h, gst_event_new_eos ());
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Send idr to trigger caps event */
|
||||
buf = composite_buffer (100, 0, 1, h265_idr_hvcc, sizeof (h265_idr));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
while (TRUE) {
|
||||
GstEvent *event = gst_harness_pull_event (h);
|
||||
@ -1240,6 +1189,103 @@ GST_START_TEST (test_invalid_sei_in_hvcc)
|
||||
gst_event_unref (event);
|
||||
}
|
||||
|
||||
/* Verify IDR */
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
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);
|
||||
|
||||
gst_harness_teardown (h);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
/* 8bits 4:4:4 encoded stream, and profile-level-tier is not spec compliant.
|
||||
* extracted from the file reported at
|
||||
* https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1009
|
||||
*/
|
||||
static const guint8 broken_profile_codec_data[] = {
|
||||
0x01, 0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x99, 0xf0, 0x00, 0xfc, 0xff, 0xf8, 0xf8, 0x00, 0x00, 0x0f, 0x03, 0x20,
|
||||
0x00, 0x01, 0x00, 0x18, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x24, 0x08,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x99, 0xac, 0x09, 0x21, 0x00, 0x01, 0x00, 0x2c, 0x42, 0x01, 0x01,
|
||||
0x24, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x99, 0x90, 0x00, 0x3c, 0x04, 0x00, 0x44, 0x0f, 0x84,
|
||||
0x72, 0xd6, 0x94, 0x84, 0xb2, 0x5c, 0x40, 0x20, 0x00, 0x00, 0x03, 0x00,
|
||||
0x20, 0x00, 0x00, 0x07, 0x81, 0x22, 0x00, 0x01, 0x00, 0x08, 0x44, 0x01,
|
||||
0xc0, 0xf7, 0x18, 0x30, 0x0c, 0xc9
|
||||
};
|
||||
|
||||
GST_START_TEST (test_parse_fallback_profile)
|
||||
{
|
||||
GstHarness *h = gst_harness_new ("h265parse");
|
||||
GstCaps *caps;
|
||||
GstBuffer *codec_data;
|
||||
GstEvent *event;
|
||||
GstBuffer *buf, *bufout;
|
||||
GstMapInfo mapout;
|
||||
|
||||
codec_data = gst_buffer_new_memdup (broken_profile_codec_data,
|
||||
sizeof (broken_profile_codec_data));
|
||||
|
||||
caps = gst_caps_from_string ("video/x-h265, stream-format=(string)hvc1, "
|
||||
"alignment=(string)au");
|
||||
gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
|
||||
gst_buffer_unref (codec_data);
|
||||
|
||||
gst_harness_set_src_caps (h, 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);
|
||||
|
||||
/* Send idr to trigger caps event */
|
||||
buf = composite_buffer (100, 0, 1, h265_idr_hvcc, sizeof (h265_idr));
|
||||
fail_unless_equals_int (gst_harness_push (h, buf), GST_FLOW_OK);
|
||||
|
||||
while ((event = gst_harness_pull_event (h)) != NULL) {
|
||||
GstStructure *s;
|
||||
const gchar *profile;
|
||||
|
||||
if (GST_EVENT_TYPE (event) != GST_EVENT_CAPS) {
|
||||
gst_event_unref (event);
|
||||
continue;
|
||||
}
|
||||
|
||||
gst_event_parse_caps (event, &caps);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
profile = gst_structure_get_string (s, "profile");
|
||||
|
||||
/* h265parse must provide profile */
|
||||
fail_unless (profile);
|
||||
|
||||
/* must not be main profile at least.
|
||||
* main-444 is expected but we might update the profile parsing
|
||||
* logic later. At least it should not be main profile
|
||||
*/
|
||||
fail_if (g_strcmp0 (profile, "main") == 0);
|
||||
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Verify IDR */
|
||||
bufout = gst_harness_pull (h);
|
||||
fail_unless (bufout != NULL);
|
||||
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);
|
||||
|
||||
gst_harness_teardown (h);
|
||||
}
|
||||
|
||||
@ -1386,6 +1432,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_parse_fallback_profile);
|
||||
tcase_add_test (tc_chain, test_packetized_hvcc_drop_corrupt);
|
||||
return s;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user