mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
rtph265pay: Fix handling of config-interval
Insert VPS/SPS/PPS before the first NAL unit containing an I-frame in an access unit only. If an access unit consists of several such NAL units (tiles) VPS/SPS/PPS should only be inserted before the first of them so that parameters are only updated between frames. Do not insert VPS/SPS/PPS before P-frames when config-interval is -1. https://bugzilla.gnome.org/show_bug.cgi?id=775817
This commit is contained in:
parent
c08a0493ff
commit
494246f75c
1 changed files with 216 additions and 214 deletions
|
@ -808,7 +808,7 @@ gst_rtp_h265_pay_decode_nal (GstRtpH265Pay * payloader,
|
|||
|
||||
static GstFlowReturn
|
||||
gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
|
||||
GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au);
|
||||
GPtrArray * paybufs, GstClockTime dts, GstClockTime pts);
|
||||
|
||||
static GstFlowReturn
|
||||
gst_rtp_h265_pay_send_vps_sps_pps (GstRTPBasePayload * basepayload,
|
||||
|
@ -817,48 +817,38 @@ gst_rtp_h265_pay_send_vps_sps_pps (GstRTPBasePayload * basepayload,
|
|||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
gboolean sent_all_vps_sps_pps = TRUE;
|
||||
guint i;
|
||||
GPtrArray *bufs;
|
||||
|
||||
bufs = g_ptr_array_new ();
|
||||
|
||||
for (i = 0; i < rtph265pay->vps->len; i++) {
|
||||
GstBuffer *vps_buf =
|
||||
GST_BUFFER_CAST (g_ptr_array_index (rtph265pay->vps, i));
|
||||
|
||||
GST_DEBUG_OBJECT (rtph265pay, "inserting VPS in the stream");
|
||||
/* resend VPS */
|
||||
ret = gst_rtp_h265_pay_payload_nal (basepayload, gst_buffer_ref (vps_buf),
|
||||
dts, pts, FALSE);
|
||||
/* Not critical here; but throw a warning */
|
||||
if (ret != GST_FLOW_OK) {
|
||||
sent_all_vps_sps_pps = FALSE;
|
||||
GST_WARNING_OBJECT (basepayload, "Problem pushing VPS");
|
||||
}
|
||||
g_ptr_array_add (bufs, gst_buffer_ref (vps_buf));
|
||||
}
|
||||
for (i = 0; i < rtph265pay->sps->len; i++) {
|
||||
GstBuffer *sps_buf =
|
||||
GST_BUFFER_CAST (g_ptr_array_index (rtph265pay->sps, i));
|
||||
|
||||
GST_DEBUG_OBJECT (rtph265pay, "inserting SPS in the stream");
|
||||
/* resend SPS */
|
||||
ret = gst_rtp_h265_pay_payload_nal (basepayload, gst_buffer_ref (sps_buf),
|
||||
dts, pts, FALSE);
|
||||
/* Not critical here; but throw a warning */
|
||||
if (ret != GST_FLOW_OK) {
|
||||
sent_all_vps_sps_pps = FALSE;
|
||||
GST_WARNING_OBJECT (basepayload, "Problem pushing SPS");
|
||||
}
|
||||
g_ptr_array_add (bufs, gst_buffer_ref (sps_buf));
|
||||
}
|
||||
for (i = 0; i < rtph265pay->pps->len; i++) {
|
||||
GstBuffer *pps_buf =
|
||||
GST_BUFFER_CAST (g_ptr_array_index (rtph265pay->pps, i));
|
||||
|
||||
GST_DEBUG_OBJECT (rtph265pay, "inserting PPS in the stream");
|
||||
/* resend PPS */
|
||||
ret = gst_rtp_h265_pay_payload_nal (basepayload, gst_buffer_ref (pps_buf),
|
||||
dts, pts, FALSE);
|
||||
/* Not critical here; but throw a warning */
|
||||
if (ret != GST_FLOW_OK) {
|
||||
sent_all_vps_sps_pps = FALSE;
|
||||
GST_WARNING ("Problem pushing PPS");
|
||||
g_ptr_array_add (bufs, gst_buffer_ref (pps_buf));
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
sent_all_vps_sps_pps = FALSE;
|
||||
}
|
||||
|
||||
if (pts != -1 && sent_all_vps_sps_pps)
|
||||
|
@ -869,35 +859,53 @@ gst_rtp_h265_pay_send_vps_sps_pps (GstRTPBasePayload * basepayload,
|
|||
|
||||
static GstFlowReturn
|
||||
gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
|
||||
GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au)
|
||||
GPtrArray * paybufs, GstClockTime dts, GstClockTime pts)
|
||||
{
|
||||
GstRtpH265Pay *rtph265pay;
|
||||
guint mtu;
|
||||
GstFlowReturn ret;
|
||||
guint8 nalHeader[2];
|
||||
guint8 nalType;
|
||||
guint packet_len, payload_len, mtu;
|
||||
GstBuffer *outbuf;
|
||||
guint8 *payload;
|
||||
GstBufferList *list = NULL;
|
||||
gboolean send_vps_sps_pps;
|
||||
GstRTPBuffer rtp = { NULL };
|
||||
guint size = gst_buffer_get_size (paybuf);
|
||||
gint i;
|
||||
gboolean sent_ps;
|
||||
|
||||
rtph265pay = GST_RTP_H265_PAY (basepayload);
|
||||
mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph265pay);
|
||||
|
||||
gst_buffer_extract (paybuf, 0, nalHeader, 2);
|
||||
nalType = (nalHeader[0] >> 1) & 0x3f;
|
||||
|
||||
GST_DEBUG_OBJECT (rtph265pay, "Processing Buffer with NAL TYPE=%d", nalType);
|
||||
|
||||
/* should set src caps before pushing stuff,
|
||||
* and if we did not see enough VPS/SPS/PPS, that may not be the case */
|
||||
if (G_UNLIKELY (!gst_pad_has_current_caps (GST_RTP_BASE_PAYLOAD_SRCPAD
|
||||
(basepayload))))
|
||||
gst_rtp_h265_pay_set_vps_sps_pps (basepayload);
|
||||
|
||||
send_vps_sps_pps = FALSE;
|
||||
ret = GST_FLOW_OK;
|
||||
sent_ps = FALSE;
|
||||
for (i = 0; i < paybufs->len; i++) {
|
||||
guint8 nalHeader[2];
|
||||
guint8 nalType;
|
||||
guint packet_len, payload_len;
|
||||
GstBuffer *paybuf;
|
||||
GstBuffer *outbuf;
|
||||
guint8 *payload;
|
||||
GstBufferList *outlist = NULL;
|
||||
gboolean send_ps;
|
||||
GstRTPBuffer rtp = { NULL };
|
||||
guint size;
|
||||
|
||||
paybuf = g_ptr_array_index (paybufs, i);
|
||||
|
||||
if (ret != GST_FLOW_OK) {
|
||||
/* unref buffers that will not be payloaded after a flow error */
|
||||
gst_buffer_unref (paybuf);
|
||||
continue;
|
||||
}
|
||||
|
||||
size = gst_buffer_get_size (paybuf);
|
||||
gst_buffer_extract (paybuf, 0, nalHeader, 2);
|
||||
nalType = (nalHeader[0] >> 1) & 0x3f;
|
||||
|
||||
GST_DEBUG_OBJECT (rtph265pay, "Processing Buffer with NAL TYPE=%d",
|
||||
nalType);
|
||||
|
||||
send_ps = FALSE;
|
||||
|
||||
/* check if we need to emit an VPS/SPS/PPS now */
|
||||
if ((nalType == GST_H265_NAL_SLICE_TRAIL_N)
|
||||
|
@ -920,7 +928,8 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
|
||||
GST_LOG_OBJECT (rtph265pay,
|
||||
"now %" GST_TIME_FORMAT ", last VPS/SPS/PPS %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (pts), GST_TIME_ARGS (rtph265pay->last_vps_sps_pps));
|
||||
GST_TIME_ARGS (pts),
|
||||
GST_TIME_ARGS (rtph265pay->last_vps_sps_pps));
|
||||
|
||||
/* calculate diff between last SPS/PPS in milliseconds */
|
||||
if (pts > rtph265pay->last_vps_sps_pps)
|
||||
|
@ -935,29 +944,34 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
/* bigger than interval, queue SPS/PPS */
|
||||
if (GST_TIME_AS_SECONDS (diff) >= rtph265pay->vps_sps_pps_interval) {
|
||||
GST_DEBUG_OBJECT (rtph265pay, "time to send VPS/SPS/PPS");
|
||||
send_vps_sps_pps = TRUE;
|
||||
send_ps = TRUE;
|
||||
}
|
||||
} else {
|
||||
/* no known previous SPS/PPS time, send now */
|
||||
GST_DEBUG_OBJECT (rtph265pay, "no previous VPS/SPS/PPS time, send now");
|
||||
send_vps_sps_pps = TRUE;
|
||||
}
|
||||
} else if (rtph265pay->vps_sps_pps_interval == -1) {
|
||||
GST_DEBUG_OBJECT (rtph265pay,
|
||||
"sending VPS/SPS/PPS before current IDR frame");
|
||||
"no previous VPS/SPS/PPS time, send now");
|
||||
send_ps = TRUE;
|
||||
}
|
||||
} else if (rtph265pay->vps_sps_pps_interval == -1
|
||||
&& (nalType == GST_H265_NAL_SLICE_IDR_W_RADL
|
||||
|| nalType == GST_H265_NAL_SLICE_IDR_N_LP)) {
|
||||
/* send VPS/SPS/PPS before every IDR frame */
|
||||
send_vps_sps_pps = TRUE;
|
||||
send_ps = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (send_vps_sps_pps || rtph265pay->send_vps_sps_pps) {
|
||||
if (!sent_ps && (send_ps || rtph265pay->send_vps_sps_pps)) {
|
||||
/* we need to send SPS/PPS now first. FIXME, don't use the pts for
|
||||
* checking when we need to send SPS/PPS but convert to running_time first. */
|
||||
* checking when we need to send SPS/PPS but convert to running_time
|
||||
* first */
|
||||
rtph265pay->send_vps_sps_pps = FALSE;
|
||||
ret = gst_rtp_h265_pay_send_vps_sps_pps (basepayload, rtph265pay, dts, pts);
|
||||
sent_ps = TRUE;
|
||||
GST_DEBUG_OBJECT (rtph265pay, "sending VPS/SPS/PPS before current frame");
|
||||
ret =
|
||||
gst_rtp_h265_pay_send_vps_sps_pps (basepayload, rtph265pay, dts, pts);
|
||||
if (ret != GST_FLOW_OK) {
|
||||
gst_buffer_unref (paybuf);
|
||||
return ret;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -976,7 +990,9 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
|
||||
|
||||
/* only set the marker bit on packets containing access units */
|
||||
if (IS_ACCESS_UNIT (nalType) && end_of_au) {
|
||||
if (i == paybufs->len - 1
|
||||
&& rtph265pay->alignment == GST_H265_ALIGNMENT_AU
|
||||
&& IS_ACCESS_UNIT (nalType)) {
|
||||
gst_rtp_buffer_set_marker (&rtp, 1);
|
||||
}
|
||||
|
||||
|
@ -989,15 +1005,15 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
g_quark_from_static_string (GST_META_TAG_VIDEO_STR));
|
||||
outbuf = gst_buffer_append (outbuf, paybuf);
|
||||
|
||||
list = gst_buffer_list_new ();
|
||||
outlist = gst_buffer_list_new ();
|
||||
|
||||
/* add the buffer to the buffer list */
|
||||
gst_buffer_list_add (list, outbuf);
|
||||
gst_buffer_list_add (outlist, outbuf);
|
||||
|
||||
gst_rtp_buffer_unmap (&rtp);
|
||||
|
||||
/* push the list to the next element in the pipe */
|
||||
ret = gst_rtp_base_payload_push_list (basepayload, list);
|
||||
ret = gst_rtp_base_payload_push_list (basepayload, outlist);
|
||||
} else {
|
||||
/* fragmentation Units */
|
||||
guint limitedSize;
|
||||
|
@ -1015,7 +1031,7 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
/* We keep 3 bytes for PayloadHdr and FU Header */
|
||||
payload_len = gst_rtp_buffer_calc_payload_len (mtu - 3, 0, 0);
|
||||
|
||||
list = gst_buffer_list_new ();
|
||||
outlist = gst_buffer_list_new ();
|
||||
|
||||
while (end == 0) {
|
||||
limitedSize = size < payload_len ? size : payload_len;
|
||||
|
@ -1045,7 +1061,9 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
|
||||
/* set the marker bit on the last packet of an access unit */
|
||||
if (IS_ACCESS_UNIT (nalType)) {
|
||||
gst_rtp_buffer_set_marker (&rtp, end && end_of_au);
|
||||
gst_rtp_buffer_set_marker (&rtp,
|
||||
end && i == paybufs->len - 1
|
||||
&& rtph265pay->alignment == GST_H265_ALIGNMENT_AU);
|
||||
}
|
||||
|
||||
/* FU Header */
|
||||
|
@ -1059,7 +1077,7 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
gst_buffer_copy_into (outbuf, paybuf, GST_BUFFER_COPY_MEMORY, pos,
|
||||
limitedSize);
|
||||
/* add the buffer to the buffer list */
|
||||
gst_buffer_list_add (list, outbuf);
|
||||
gst_buffer_list_add (outlist, outbuf);
|
||||
|
||||
size -= limitedSize;
|
||||
pos += limitedSize;
|
||||
|
@ -1067,9 +1085,13 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
|
|||
start = 0;
|
||||
}
|
||||
|
||||
ret = gst_rtp_base_payload_push_list (basepayload, list);
|
||||
ret = gst_rtp_base_payload_push_list (basepayload, outlist);
|
||||
gst_buffer_unref (paybuf);
|
||||
}
|
||||
}
|
||||
|
||||
g_ptr_array_free (paybufs, TRUE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1136,12 +1158,13 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
|||
if (hevc) {
|
||||
guint nal_length_size;
|
||||
gsize offset = 0;
|
||||
GPtrArray *paybufs;
|
||||
|
||||
paybufs = g_ptr_array_new ();
|
||||
nal_length_size = rtph265pay->nal_length_size;
|
||||
|
||||
while (size > nal_length_size) {
|
||||
gint i;
|
||||
gboolean end_of_au = FALSE;
|
||||
|
||||
nal_len = 0;
|
||||
for (i = 0; i < nal_length_size; i++) {
|
||||
|
@ -1161,30 +1184,19 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
|||
nal_len);
|
||||
}
|
||||
|
||||
/* If we're at the end of the buffer, then we're at the end of the
|
||||
* access unit
|
||||
*/
|
||||
if (rtph265pay->alignment == GST_H265_ALIGNMENT_AU
|
||||
&& size - nal_len <= nal_length_size) {
|
||||
end_of_au = TRUE;
|
||||
}
|
||||
|
||||
paybuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset,
|
||||
nal_len);
|
||||
|
||||
ret =
|
||||
gst_rtp_h265_pay_payload_nal (basepayload, paybuf, dts, pts,
|
||||
end_of_au);
|
||||
if (ret != GST_FLOW_OK)
|
||||
break;
|
||||
g_ptr_array_add (paybufs, paybuf);
|
||||
|
||||
data += nal_len;
|
||||
offset += nal_len;
|
||||
size -= nal_len;
|
||||
}
|
||||
ret = gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts);
|
||||
} else {
|
||||
guint next;
|
||||
gboolean update = FALSE;
|
||||
GPtrArray *paybufs;
|
||||
|
||||
/* get offset of first start code */
|
||||
next = next_start_code (data, size);
|
||||
|
@ -1202,6 +1214,8 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
|||
GST_DEBUG_OBJECT (basepayload,
|
||||
"found first start at %u, bytes left %" G_GSIZE_FORMAT, next, size);
|
||||
|
||||
paybufs = g_ptr_array_new ();
|
||||
|
||||
/* first pass to locate NALs and parse VPS/SPS/PPS */
|
||||
while (size > 4) {
|
||||
/* skip start code */
|
||||
|
@ -1254,7 +1268,6 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
|||
|
||||
for (i = 0; i < nal_queue->len; i++) {
|
||||
guint size;
|
||||
gboolean end_of_au = FALSE;
|
||||
|
||||
nal_len = g_array_index (nal_queue, guint, i);
|
||||
/* skip start code */
|
||||
|
@ -1270,32 +1283,21 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
|
|||
for (; size > 1 && data[size - 1] == 0x0; size--)
|
||||
/* skip */ ;
|
||||
|
||||
|
||||
/* If it's the last nal unit we have in non-bytestream mode, we can
|
||||
* assume it's the end of an access-unit
|
||||
*
|
||||
* FIXME: We need to wait until the next packet or EOS to
|
||||
/* FIXME: We need to wait until the next packet or EOS to
|
||||
* actually payload the NAL so we can know if the current NAL is
|
||||
* the last one of an access unit or not if we are in bytestream mode
|
||||
*/
|
||||
if ((rtph265pay->alignment == GST_H265_ALIGNMENT_AU || buffer == NULL) &&
|
||||
i == nal_queue->len - 1)
|
||||
end_of_au = TRUE;
|
||||
|
||||
paybuf = gst_adapter_take_buffer (rtph265pay->adapter, size);
|
||||
g_assert (paybuf);
|
||||
|
||||
/* put the data in one or more RTP packets */
|
||||
ret =
|
||||
gst_rtp_h265_pay_payload_nal (basepayload, paybuf, dts, pts,
|
||||
end_of_au);
|
||||
if (ret != GST_FLOW_OK) {
|
||||
break;
|
||||
}
|
||||
g_ptr_array_add (paybufs, paybuf);
|
||||
|
||||
/* move to next NAL packet */
|
||||
/* Skips the trailing zeros */
|
||||
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);
|
||||
g_array_set_size (nal_queue, 0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue