mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-20 08:41:07 +00:00
rtph264pay: Don't insert SPS/PPS before the second image slice
Only the first slice, for which fist_mb_in_slice is set to 0, should trigger insertion of SPS and PPS buffers. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3402>
This commit is contained in:
parent
4067bbdd91
commit
c3e52d5c4f
2 changed files with 86 additions and 2 deletions
|
@ -924,6 +924,7 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
{
|
||||
GstRtpH264Pay *rtph264pay;
|
||||
guint8 nal_header, nal_type;
|
||||
gboolean first_slice = FALSE;
|
||||
gboolean send_spspps;
|
||||
guint size;
|
||||
|
||||
|
@ -960,8 +961,17 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
|
||||
send_spspps = FALSE;
|
||||
|
||||
if (nal_type == IDR_TYPE_ID) {
|
||||
guint8 first_mb_in_slice;
|
||||
gst_buffer_extract (paybuf, 1, &first_mb_in_slice, 1);
|
||||
/* 'first_mb_in_slice' specifies the address of the first macroblock
|
||||
* in the slice. if 'first_mb_in_slice' is 0 (note that it's exp golomb
|
||||
* code), the current slice is the first slice of the frame */
|
||||
first_slice = ((first_mb_in_slice >> 7) & 0x01) == 1;
|
||||
}
|
||||
|
||||
/* check if we need to emit an SPS/PPS now */
|
||||
if (nal_type == IDR_TYPE_ID && rtph264pay->spspps_interval > 0) {
|
||||
if (first_slice && nal_type == IDR_TYPE_ID && rtph264pay->spspps_interval > 0) {
|
||||
if (rtph264pay->last_spspps != -1) {
|
||||
guint64 diff;
|
||||
GstClockTime running_time =
|
||||
|
@ -993,7 +1003,8 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
GST_DEBUG_OBJECT (rtph264pay, "no previous SPS/PPS time, send now");
|
||||
send_spspps = TRUE;
|
||||
}
|
||||
} else if (nal_type == IDR_TYPE_ID && rtph264pay->spspps_interval == -1) {
|
||||
} else if (first_slice && nal_type == IDR_TYPE_ID
|
||||
&& rtph264pay->spspps_interval == -1) {
|
||||
GST_DEBUG_OBJECT (rtph264pay, "sending SPS/PPS before current IDR frame");
|
||||
/* send SPS/PPS before every IDR frame */
|
||||
send_spspps = TRUE;
|
||||
|
|
|
@ -1455,6 +1455,77 @@ GST_START_TEST (test_rtph264pay_avc_incomplete_nal)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
/* A buffer consists of two memory chunks: a primary slice with
|
||||
* fist_mb_in_slice set to 0 and a secondary one. Only the first slice
|
||||
* should trigger generation of SPS and PPS buffers */
|
||||
GST_START_TEST (test_rtph264pay_avc_two_slices_per_buffer_config_interval)
|
||||
{
|
||||
GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123"
|
||||
" name=p config-interval=-1");
|
||||
GstFlowReturn ret;
|
||||
GstBuffer *slice1;
|
||||
GstBuffer *slice2;
|
||||
GstBuffer *buffer;
|
||||
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
||||
guint8 *rest_of_image;
|
||||
gsize rest_of_slice_1_size;
|
||||
gsize rest_of_image_size;
|
||||
guint num_buffers;
|
||||
guint8 *payload = NULL;
|
||||
guint8 nal_type;
|
||||
|
||||
gst_harness_set_src_caps_str (h,
|
||||
"video/x-h264,alignment=au,stream-format=avc,"
|
||||
"codec_data=(buffer)01f4000dffe1001c67f4000d919b2884d80b50606064000003"
|
||||
"000400000300f23c50a65801000668ebec448440");
|
||||
|
||||
/* first slice */
|
||||
slice1 = wrap_static_buffer (h264_idr_slice_1_avc, 1);
|
||||
rest_of_slice_1_size = sizeof (h264_idr_slice_1_avc) - 1;
|
||||
|
||||
rest_of_image_size = rest_of_slice_1_size + sizeof (h264_idr_slice_2_avc);
|
||||
rest_of_image = g_malloc (rest_of_image_size);
|
||||
|
||||
memcpy (rest_of_image, h264_idr_slice_1_avc + 1, rest_of_slice_1_size);
|
||||
memcpy (rest_of_image + rest_of_slice_1_size, h264_idr_slice_2_avc,
|
||||
sizeof (h264_idr_slice_2_avc));
|
||||
|
||||
/* second slice */
|
||||
slice2 =
|
||||
wrap_static_buffer_full (rest_of_image, rest_of_image_size,
|
||||
rest_of_image, g_free);
|
||||
buffer = gst_buffer_append (slice1, slice2);
|
||||
|
||||
ret = gst_harness_push (h, buffer);
|
||||
fail_unless_equals_int (ret, GST_FLOW_OK);
|
||||
/* SPS PPS IDR (Slice1) IDR (Slice2) */
|
||||
num_buffers = gst_harness_buffers_in_queue (h);
|
||||
fail_unless_equals_int (num_buffers, 4);
|
||||
|
||||
for (guint i = 0; i < num_buffers; i++) {
|
||||
buffer = gst_harness_pull (h);
|
||||
fail_unless (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp));
|
||||
payload = gst_rtp_buffer_get_payload (&rtp);
|
||||
gst_rtp_buffer_unmap (&rtp);
|
||||
nal_type = (GST_READ_UINT8 (payload)) & 0x1f;
|
||||
GST_INFO ("nal_type=%d", nal_type);
|
||||
if (i == 0) {
|
||||
fail_unless_equals_int (nal_type, 7);
|
||||
} else if (i == 1) {
|
||||
fail_unless_equals_int (nal_type, 8);
|
||||
} else if (i == 2) {
|
||||
fail_unless_equals_int (nal_type, 5);
|
||||
} else if (i == 3) {
|
||||
fail_unless_equals_int (nal_type, 5);
|
||||
}
|
||||
|
||||
gst_buffer_unref (buffer);
|
||||
}
|
||||
gst_harness_teardown (h);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
rtph264_suite (void)
|
||||
{
|
||||
|
@ -1486,6 +1557,8 @@ rtph264_suite (void)
|
|||
tcase_add_test (tc_chain, test_rtph264pay_avc);
|
||||
tcase_add_test (tc_chain, test_rtph264pay_avc_two_slices_per_buffer);
|
||||
tcase_add_test (tc_chain, test_rtph264pay_avc_incomplete_nal);
|
||||
tcase_add_test (tc_chain,
|
||||
test_rtph264pay_avc_two_slices_per_buffer_config_interval);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue