From b40b4ffb81fe295b7db661d3960c6da761a62a84 Mon Sep 17 00:00:00 2001 From: Peter Stensson Date: Thu, 22 Jun 2023 11:06:02 +0200 Subject: [PATCH] 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: --- .../gst-plugins-good/gst/rtp/gstrtph265pay.c | 34 ++++---- .../tests/check/elements/rtph265.c | 84 +++++++++++++++++++ 2 files changed, 103 insertions(+), 15 deletions(-) diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph265pay.c b/subprojects/gst-plugins-good/gst/rtp/gstrtph265pay.c index e06c928e4a..5a08f8bbe2 100644 --- a/subprojects/gst-plugins-good/gst/rtp/gstrtph265pay.c +++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph265pay.c @@ -922,8 +922,7 @@ gst_rtp_h265_pay_decode_nal (GstRtpH265Pay * payloader, } static GstFlowReturn gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * - basepayload, GPtrArray * paybufs, GstClockTime dts, GstClockTime pts, - gboolean delta_unit); + basepayload, GPtrArray * paybufs, GstClockTime dts, GstClockTime pts); static GstFlowReturn gst_rtp_h265_pay_payload_nal_single (GstRTPBasePayload * basepayload, GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, 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)); } - 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) { /* not critical but warn */ GST_WARNING_OBJECT (basepayload, "failed pushing VPS/SPS/PPS"); @@ -996,8 +995,7 @@ gst_rtp_h265_pay_reset_bundle (GstRtpH265Pay * rtph265pay) static GstFlowReturn gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload, - GPtrArray * paybufs, GstClockTime dts, GstClockTime pts, - gboolean delta_unit) + GPtrArray * paybufs, GstClockTime dts, GstClockTime pts) { GstRtpH265Pay *rtph265pay; guint mtu; @@ -1023,6 +1021,7 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload, gboolean send_ps; guint size; gboolean marker; + gboolean delta_unit; 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); + delta_unit = GST_BUFFER_FLAG_IS_SET (paybuf, GST_BUFFER_FLAG_DELTA_UNIT); size = gst_buffer_get_size (paybuf); gst_buffer_extract (paybuf, 0, nal_header, 2); @@ -1583,6 +1583,14 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, 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 * advance_bytes () will switch to the correct GstMemory. The payloader * 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; remaining_buffer_size -= nal_len; } - ret = - 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; + ret = gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts); gst_buffer_memory_unmap (&memory); gst_buffer_unref (buffer); @@ -1713,6 +1715,10 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload, 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) { rtph265pay->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); } /* put the data in one or more RTP packets */ - ret = - gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts, - rtph265pay->delta_unit); + ret = gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts); g_array_set_size (nal_queue, 0); } diff --git a/subprojects/gst-plugins-good/tests/check/elements/rtph265.c b/subprojects/gst-plugins-good/tests/check/elements/rtph265.c index c35d05c52a..d5474b5045 100644 --- a/subprojects/gst-plugins-good/tests/check/elements/rtph265.c +++ b/subprojects/gst-plugins-good/tests/check/elements/rtph265.c @@ -1181,6 +1181,87 @@ GST_START_TEST (test_rtph265pay_delta_unit_flag) 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) { 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_verify_nalu_hdr); 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); return s;