diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c index 7c6c821a5f..c7089effb6 100644 --- a/gst/rtp/gstrtph264pay.c +++ b/gst/rtp/gstrtph264pay.c @@ -166,6 +166,7 @@ gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay) (GDestroyNotify) gst_buffer_unref); rtph264pay->last_spspps = -1; rtph264pay->spspps_interval = DEFAULT_CONFIG_INTERVAL; + rtph264pay->delta_unit = FALSE; rtph264pay->adapter = gst_adapter_new (); } @@ -704,7 +705,8 @@ gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader, static GstFlowReturn gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload, - GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au); + GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au, + gboolean delta_unit); static GstFlowReturn gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload, @@ -721,7 +723,7 @@ gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload, GST_DEBUG_OBJECT (rtph264pay, "inserting SPS in the stream"); /* resend SPS */ ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (sps_buf), - dts, pts, FALSE); + dts, pts, FALSE, FALSE); /* Not critical here; but throw a warning */ if (ret != GST_FLOW_OK) { sent_all_sps_pps = FALSE; @@ -735,7 +737,7 @@ gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload, GST_DEBUG_OBJECT (rtph264pay, "inserting PPS in the stream"); /* resend PPS */ ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (pps_buf), - dts, pts, FALSE); + dts, pts, FALSE, FALSE); /* Not critical here; but throw a warning */ if (ret != GST_FLOW_OK) { sent_all_sps_pps = FALSE; @@ -749,9 +751,12 @@ gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload, return ret; } +/* @delta_unit: if %FALSE the first packet sent won't have the + * GST_BUFFER_FLAG_DELTA_UNIT flag. */ static GstFlowReturn gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload, - GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au) + GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au, + gboolean delta_unit) { GstRtpH264Pay *rtph264pay; GstFlowReturn ret; @@ -843,6 +848,12 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload, GST_BUFFER_PTS (outbuf) = pts; GST_BUFFER_DTS (outbuf) = dts; + if (!delta_unit) + /* Only the first packet sent should not have the flag */ + delta_unit = TRUE; + else + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); + gst_rtp_buffer_unmap (&rtp); /* insert payload memory block */ @@ -909,6 +920,12 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload, gst_buffer_copy_region (paybuf, GST_BUFFER_COPY_MEMORY, pos, limitedSize)); + if (!delta_unit) + /* Only the first packet sent should not have the flag */ + delta_unit = TRUE; + else + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); + /* add the buffer to the buffer list */ gst_buffer_list_add (list, outbuf); @@ -940,6 +957,7 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, gboolean avc; GstBuffer *paybuf = NULL; gsize skip; + gboolean delayed_not_delta_unit = FALSE; rtph264pay = GST_RTP_H264_PAY (basepayload); @@ -956,11 +974,23 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, size = map.size; pts = GST_BUFFER_PTS (buffer); dts = GST_BUFFER_DTS (buffer); + rtph264pay->delta_unit = GST_BUFFER_FLAG_IS_SET (buffer, + GST_BUFFER_FLAG_DELTA_UNIT); GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size); } else { dts = gst_adapter_prev_dts (rtph264pay->adapter, NULL); pts = gst_adapter_prev_pts (rtph264pay->adapter, NULL); if (buffer) { + if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) { + if (gst_adapter_available (rtph264pay->adapter) == 0) + rtph264pay->delta_unit = FALSE; + else + /* This buffer contains a key frame but the adapter isn't empty. So + * we'll purge it first by sending a first packet and then the second + * one won't have the DELTA_UNIT flag. */ + delayed_not_delta_unit = TRUE; + } + if (!GST_CLOCK_TIME_IS_VALID (dts)) dts = GST_BUFFER_DTS (buffer); if (!GST_CLOCK_TIME_IS_VALID (pts)) @@ -1024,7 +1054,12 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, nal_len); ret = gst_rtp_h264_pay_payload_nal (basepayload, paybuf, dts, pts, - end_of_au); + end_of_au, rtph264pay->delta_unit); + + if (!rtph264pay->delta_unit) + /* Only the first outgoing packet doesn't have the DELTA_UNIT flag */ + rtph264pay->delta_unit = TRUE; + if (ret != GST_FLOW_OK) break; @@ -1155,7 +1190,16 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, /* put the data in one or more RTP packets */ ret = gst_rtp_h264_pay_payload_nal (basepayload, paybuf, dts, pts, - end_of_au); + end_of_au, rtph264pay->delta_unit); + + if (delayed_not_delta_unit) { + rtph264pay->delta_unit = FALSE; + delayed_not_delta_unit = FALSE; + } else { + /* Only the first outgoing packet doesn't have the DELTA_UNIT flag */ + rtph264pay->delta_unit = TRUE; + } + if (ret != GST_FLOW_OK) { break; } diff --git a/gst/rtp/gstrtph264pay.h b/gst/rtp/gstrtph264pay.h index e1f6c7f1a9..5881a5a0b5 100644 --- a/gst/rtp/gstrtph264pay.h +++ b/gst/rtp/gstrtph264pay.h @@ -74,6 +74,9 @@ struct _GstRtpH264Pay guint spspps_interval; gboolean send_spspps; GstClockTime last_spspps; + + /* TRUE if the next NALU processed should have the DELTA_UNIT flag */ + gboolean delta_unit; }; struct _GstRtpH264PayClass