rtph265pay: Only mark first NAL as non delta-unit

When the input buffer contained multiple NAL's the second one would keep
the non delta-unit flag for a key frame.

The delta-unit flag will now be set per NAL when preparing the buffer
list to payload.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4937>
This commit is contained in:
Peter Stensson 2023-06-22 11:06:02 +02:00 committed by GStreamer Marge Bot
parent 1c4de219e4
commit b40b4ffb81
2 changed files with 103 additions and 15 deletions

View file

@ -922,8 +922,7 @@ gst_rtp_h265_pay_decode_nal (GstRtpH265Pay * payloader,
} }
static GstFlowReturn gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * static GstFlowReturn gst_rtp_h265_pay_payload_nal (GstRTPBasePayload *
basepayload, GPtrArray * paybufs, GstClockTime dts, GstClockTime pts, basepayload, GPtrArray * paybufs, GstClockTime dts, GstClockTime pts);
gboolean delta_unit);
static GstFlowReturn gst_rtp_h265_pay_payload_nal_single (GstRTPBasePayload * static GstFlowReturn gst_rtp_h265_pay_payload_nal_single (GstRTPBasePayload *
basepayload, GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, basepayload, GstBuffer * paybuf, GstClockTime dts, GstClockTime pts,
gboolean marker, gboolean delta_unit); gboolean marker, gboolean delta_unit);
@ -970,7 +969,7 @@ gst_rtp_h265_pay_send_vps_sps_pps (GstRTPBasePayload * basepayload,
g_ptr_array_add (bufs, gst_buffer_ref (pps_buf)); g_ptr_array_add (bufs, gst_buffer_ref (pps_buf));
} }
ret = gst_rtp_h265_pay_payload_nal (basepayload, bufs, dts, pts, FALSE); ret = gst_rtp_h265_pay_payload_nal (basepayload, bufs, dts, pts);
if (ret != GST_FLOW_OK) { if (ret != GST_FLOW_OK) {
/* not critical but warn */ /* not critical but warn */
GST_WARNING_OBJECT (basepayload, "failed pushing VPS/SPS/PPS"); GST_WARNING_OBJECT (basepayload, "failed pushing VPS/SPS/PPS");
@ -996,8 +995,7 @@ gst_rtp_h265_pay_reset_bundle (GstRtpH265Pay * rtph265pay)
static GstFlowReturn static GstFlowReturn
gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload, gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
GPtrArray * paybufs, GstClockTime dts, GstClockTime pts, GPtrArray * paybufs, GstClockTime dts, GstClockTime pts)
gboolean delta_unit)
{ {
GstRtpH265Pay *rtph265pay; GstRtpH265Pay *rtph265pay;
guint mtu; guint mtu;
@ -1023,6 +1021,7 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
gboolean send_ps; gboolean send_ps;
guint size; guint size;
gboolean marker; gboolean marker;
gboolean delta_unit;
paybuf = g_ptr_array_index (paybufs, i); paybuf = g_ptr_array_index (paybufs, i);
@ -1033,6 +1032,7 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
} }
marker = GST_BUFFER_FLAG_IS_SET (paybuf, GST_BUFFER_FLAG_MARKER); marker = GST_BUFFER_FLAG_IS_SET (paybuf, GST_BUFFER_FLAG_MARKER);
delta_unit = GST_BUFFER_FLAG_IS_SET (paybuf, GST_BUFFER_FLAG_DELTA_UNIT);
size = gst_buffer_get_size (paybuf); size = gst_buffer_get_size (paybuf);
gst_buffer_extract (paybuf, 0, nal_header, 2); gst_buffer_extract (paybuf, 0, nal_header, 2);
@ -1583,6 +1583,14 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
discont = FALSE; discont = FALSE;
} }
GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_DELTA_UNIT);
if (!rtph265pay->delta_unit)
GST_BUFFER_FLAG_UNSET (paybuf, GST_BUFFER_FLAG_DELTA_UNIT);
if (!rtph265pay->delta_unit)
/* only the first outgoing packet doesn't have the DELTA_UNIT flag */
rtph265pay->delta_unit = TRUE;
/* Skip current nal. If it is split over multiple GstMemory /* Skip current nal. If it is split over multiple GstMemory
* advance_bytes () will switch to the correct GstMemory. The payloader * advance_bytes () will switch to the correct GstMemory. The payloader
* does not access those bytes directly but uses gst_buffer_copy_region () * does not access those bytes directly but uses gst_buffer_copy_region ()
@ -1592,13 +1600,7 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
offset += nal_len; offset += nal_len;
remaining_buffer_size -= nal_len; remaining_buffer_size -= nal_len;
} }
ret = ret = gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts);
gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts,
rtph265pay->delta_unit);
if (!rtph265pay->delta_unit)
/* only the first outgoing packet doesn't have the DELTA_UNIT flag */
rtph265pay->delta_unit = TRUE;
gst_buffer_memory_unmap (&memory); gst_buffer_memory_unmap (&memory);
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
@ -1713,6 +1715,10 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
discont = FALSE; discont = FALSE;
} }
GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_DELTA_UNIT);
if (!rtph265pay->delta_unit)
GST_BUFFER_FLAG_UNSET (paybuf, GST_BUFFER_FLAG_DELTA_UNIT);
if (delayed_not_delta_unit) { if (delayed_not_delta_unit) {
rtph265pay->delta_unit = FALSE; rtph265pay->delta_unit = FALSE;
delayed_not_delta_unit = FALSE; delayed_not_delta_unit = FALSE;
@ -1726,9 +1732,7 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
gst_adapter_flush (rtph265pay->adapter, nal_len - size); gst_adapter_flush (rtph265pay->adapter, nal_len - size);
} }
/* put the data in one or more RTP packets */ /* put the data in one or more RTP packets */
ret = ret = gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts);
gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts,
rtph265pay->delta_unit);
g_array_set_size (nal_queue, 0); g_array_set_size (nal_queue, 0);
} }

View file

@ -1181,6 +1181,87 @@ GST_START_TEST (test_rtph265pay_delta_unit_flag)
GST_END_TEST; GST_END_TEST;
GST_START_TEST (test_rtph265pay_delta_unit_multiple_nal)
{
GstHarness *h = gst_harness_new_parse ("rtph265pay mtu=28");
GstFlowReturn ret;
GstBuffer *buffer;
gst_harness_set_src_caps_str (h,
"video/x-h265,alignment=au,stream-format=hvc1,"
"codec_data=(buffer)0104080000009e28000000003ff000fcfff8f800000f032000"
"01001740010c01ffff0408000003009e2800000300003fba0240210001002f4201010"
"408000003009e2800000300003f90041020b2dd492657ff80008000b5060606040000"
"03000400000300782022000100074401c172b02240");
/* append two NAL's, each in separate memory blocks to the input buffer */
buffer = wrap_static_buffer (h265_hvc1_idr_data, sizeof (h265_hvc1_idr_data));
buffer = gst_buffer_append (buffer,
wrap_static_buffer (h265_hvc1_idr_data, sizeof (h265_hvc1_idr_data)));
ret = gst_harness_push (h, buffer);
fail_unless_equals_int (ret, GST_FLOW_OK);
/* each NAL should be split into two buffers and pushed as a buffer list,
* only the first buffer of the first buffer list should be marked as a
* non-delta unit */
buffer = gst_harness_pull (h);
fail_unless (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT));
gst_buffer_unref (buffer);
buffer = gst_harness_pull (h);
fail_unless (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT));
gst_buffer_unref (buffer);
buffer = gst_harness_pull (h);
fail_unless (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT));
gst_buffer_unref (buffer);
buffer = gst_harness_pull (h);
fail_unless (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT));
gst_buffer_unref (buffer);
gst_harness_teardown (h);
}
GST_END_TEST;
GST_START_TEST (test_rtph265pay_delta_unit_single_nal_multiple_memories)
{
GstHarness *h = gst_harness_new_parse ("rtph265pay mtu=28");
GstFlowReturn ret;
GstBuffer *buffer;
gst_harness_set_src_caps_str (h,
"video/x-h265,alignment=au,stream-format=hvc1,"
"codec_data=(buffer)0104080000009e28000000003ff000fcfff8f800000f032000"
"01001740010c01ffff0408000003009e2800000300003fba0240210001002f4201010"
"408000003009e2800000300003f90041020b2dd492657ff80008000b5060606040000"
"03000400000300782022000100074401c172b02240");
/* append one NAL spanning over two memory blocks to the input buffer */
gsize second_mem_size = 10;
gsize first_mem_size = sizeof (h265_hvc1_idr_data) - second_mem_size;
buffer = wrap_static_buffer (h265_hvc1_idr_data, first_mem_size);
buffer = gst_buffer_append (buffer,
wrap_static_buffer (h265_hvc1_idr_data + first_mem_size,
second_mem_size));
ret = gst_harness_push (h, buffer);
fail_unless_equals_int (ret, GST_FLOW_OK);
/* the NAL should be split into two buffers and pushed as a buffer list, only
* the first buffer in the buffer list should be marked as a non-delta unit */
buffer = gst_harness_pull (h);
fail_unless (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT));
gst_buffer_unref (buffer);
buffer = gst_harness_pull (h);
fail_unless (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT));
gst_buffer_unref (buffer);
gst_harness_teardown (h);
}
GST_END_TEST;
GST_START_TEST (test_rtph265pay_delta_unit_flag_config_interval) GST_START_TEST (test_rtph265pay_delta_unit_flag_config_interval)
{ {
GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123" GstHarness *h = gst_harness_new_parse ("rtph265pay timestamp-offset=123"
@ -1305,6 +1386,9 @@ rtph265_suite (void)
tcase_add_test (tc_chain, test_rtph265pay_aggregate_until_vcl); tcase_add_test (tc_chain, test_rtph265pay_aggregate_until_vcl);
tcase_add_test (tc_chain, test_rtph265pay_aggregate_verify_nalu_hdr); tcase_add_test (tc_chain, test_rtph265pay_aggregate_verify_nalu_hdr);
tcase_add_test (tc_chain, test_rtph265pay_delta_unit_flag); tcase_add_test (tc_chain, test_rtph265pay_delta_unit_flag);
tcase_add_test (tc_chain, test_rtph265pay_delta_unit_multiple_nal);
tcase_add_test (tc_chain,
test_rtph265pay_delta_unit_single_nal_multiple_memories);
tcase_add_test (tc_chain, test_rtph265pay_delta_unit_flag_config_interval); tcase_add_test (tc_chain, test_rtph265pay_delta_unit_flag_config_interval);
return s; return s;