diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c index be34ad63c0..0ccd3dc5ee 100644 --- a/gst/rtp/gstrtph264pay.c +++ b/gst/rtp/gstrtph264pay.c @@ -45,8 +45,34 @@ GST_DEBUG_CATEGORY_STATIC (rtph264pay_debug); #define GST_CAT_DEFAULT (rtph264pay_debug) +#define GST_TYPE_RTP_H264_AGGREGATE_MODE \ + (gst_rtp_h264_aggregate_mode_get_type ()) + + +static GType +gst_rtp_h264_aggregate_mode_get_type (void) +{ + static GType type = 0; + static const GEnumValue values[] = { + {GST_RTP_H264_AGGREGATE_NONE, "Do not aggregate NAL units", "none"}, + {GST_RTP_H264_AGGREGATE_ZERO_LATENCY, "Aggregate all that arrive together", + "zero-latency"}, + {GST_RTP_H264_AGGREGATE_MAX_STAP, + "Aggregate all NAL units with the same timestamp (adds one frame of" + " latency)", "max-stap"}, + {0, NULL, NULL}, + }; + + if (!type) { + type = g_enum_register_static ("GstRtpH264AggregateMode", values); + } + return type; +} + + + /* references: - * +* * RFC 3984 */ @@ -72,14 +98,14 @@ GST_STATIC_PAD_TEMPLATE ("src", #define DEFAULT_SPROP_PARAMETER_SETS NULL #define DEFAULT_CONFIG_INTERVAL 0 -#define DEFAULT_DO_AGGREGATE TRUE +#define DEFAULT_AGGREGATE_MODE GST_RTP_H264_AGGREGATE_ZERO_LATENCY enum { PROP_0, PROP_SPROP_PARAMETER_SETS, PROP_CONFIG_INTERVAL, - PROP_DO_AGGREGATE, + PROP_AGGREGATE_MODE, }; static void gst_rtp_h264_pay_finalize (GObject * object); @@ -139,12 +165,13 @@ gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass) ); g_object_class_install_property (G_OBJECT_CLASS (klass), - PROP_DO_AGGREGATE, - g_param_spec_boolean ("do-aggregate", + PROP_AGGREGATE_MODE, + g_param_spec_enum ("aggregate-mode", "Attempt to use aggregate packets", "Bundle suitable SPS/PPS NAL units into STAP-A " "aggregate packets. ", - FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) + GST_TYPE_RTP_H264_AGGREGATE_MODE, + DEFAULT_AGGREGATE_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) ); gobject_class->finalize = gst_rtp_h264_pay_finalize; @@ -182,7 +209,7 @@ gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay) (GDestroyNotify) gst_buffer_unref); rtph264pay->last_spspps = -1; rtph264pay->spspps_interval = DEFAULT_CONFIG_INTERVAL; - rtph264pay->do_aggregate = DEFAULT_DO_AGGREGATE; + rtph264pay->aggregate_mode = DEFAULT_AGGREGATE_MODE; rtph264pay->delta_unit = FALSE; rtph264pay->discont = FALSE; @@ -915,7 +942,7 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload, discont = FALSE; } - if (rtph264pay->do_aggregate) + if (rtph264pay->aggregate_mode != GST_RTP_H264_AGGREGATE_NONE) return gst_rtp_h264_pay_payload_nal_bundle (basepayload, paybuf, dts, pts, end_of_au, delta_unit, discont, nal_header); @@ -1066,6 +1093,7 @@ gst_rtp_h264_pay_reset_bundle (GstRtpH264Pay * rtph264pay) { g_clear_pointer (&rtph264pay->bundle, gst_buffer_list_unref); rtph264pay->bundle_size = 0; + rtph264pay->bundle_contains_vcl = FALSE; } static GstFlowReturn @@ -1175,9 +1203,6 @@ gst_rtp_h264_pay_payload_nal_bundle (GstRTPBasePayload * basepayload, } else if (discont) { GST_DEBUG_OBJECT (rtph264pay, "found discont"); start_of_au = TRUE; - } else if (!delta_unit) { - GST_DEBUG_OBJECT (rtph264pay, "found !delta_unit"); - start_of_au = TRUE; } else if (GST_BUFFER_PTS (first) != pts || GST_BUFFER_DTS (first) != dts) { GST_DEBUG_OBJECT (rtph264pay, "found timestamp mismatch"); start_of_au = TRUE; @@ -1225,6 +1250,7 @@ gst_rtp_h264_pay_payload_nal_bundle (GstRTPBasePayload * basepayload, GST_DEBUG_OBJECT (rtph264pay, "creating new STAP-A aggregate"); bundle = rtph264pay->bundle = gst_buffer_list_new (); bundle_size = rtph264pay->bundle_size = 1; + rtph264pay->bundle_contains_vcl = FALSE; } GST_DEBUG_OBJECT (rtph264pay, @@ -1249,6 +1275,10 @@ gst_rtp_h264_pay_payload_nal_bundle (GstRTPBasePayload * basepayload, rtph264pay->bundle_size += pay_size; ret = GST_FLOW_OK; + if ((nal_type >= 1 && nal_type <= 5) || nal_type == 14 || + (nal_type >= 20 && nal_type <= 23)) + rtph264pay->bundle_contains_vcl = TRUE; + if (end_of_au) { GST_DEBUG_OBJECT (rtph264pay, "sending bundle at end of AU"); ret = gst_rtp_h264_pay_send_bundle (rtph264pay, TRUE); @@ -1554,6 +1584,13 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload, g_array_set_size (nal_queue, 0); } + if (ret == GST_FLOW_OK && + rtph264pay->aggregate_mode == GST_RTP_H264_AGGREGATE_ZERO_LATENCY) { + GST_DEBUG_OBJECT (rtph264pay, "sending bundle at end incoming packet"); + ret = gst_rtp_h264_pay_send_bundle (rtph264pay, FALSE); + } + + done: if (avc) { gst_buffer_unmap (buffer, &map); @@ -1669,8 +1706,8 @@ gst_rtp_h264_pay_set_property (GObject * object, guint prop_id, case PROP_CONFIG_INTERVAL: rtph264pay->spspps_interval = g_value_get_int (value); break; - case PROP_DO_AGGREGATE: - rtph264pay->do_aggregate = g_value_get_boolean (value); + case PROP_AGGREGATE_MODE: + rtph264pay->aggregate_mode = g_value_get_enum (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1693,8 +1730,8 @@ gst_rtp_h264_pay_get_property (GObject * object, guint prop_id, case PROP_CONFIG_INTERVAL: g_value_set_int (value, rtph264pay->spspps_interval); break; - case PROP_DO_AGGREGATE: - g_value_set_boolean (value, rtph264pay->do_aggregate); + case PROP_AGGREGATE_MODE: + g_value_set_enum (value, rtph264pay->aggregate_mode); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/gst/rtp/gstrtph264pay.h b/gst/rtp/gstrtph264pay.h index 36cee344a7..e6cce4ceb3 100644 --- a/gst/rtp/gstrtph264pay.h +++ b/gst/rtp/gstrtph264pay.h @@ -54,6 +54,13 @@ typedef enum GST_H264_ALIGNMENT_AU } GstH264Alignment; +typedef enum +{ + GST_RTP_H264_AGGREGATE_NONE, + GST_RTP_H264_AGGREGATE_ZERO_LATENCY, + GST_RTP_H264_AGGREGATE_MAX_STAP, +} GstRTPH264AggregateMode; + struct _GstRtpH264Pay { GstRTPBasePayload payload; @@ -83,7 +90,8 @@ struct _GstRtpH264Pay /* aggregate buffers with STAP-A */ GstBufferList *bundle; guint bundle_size; - gboolean do_aggregate; + gboolean bundle_contains_vcl; + GstRTPH264AggregateMode aggregate_mode; }; struct _GstRtpH264PayClass diff --git a/tests/check/elements/rtph264.c b/tests/check/elements/rtph264.c index 83f7ddc5e4..fb6d5471c5 100644 --- a/tests/check/elements/rtph264.c +++ b/tests/check/elements/rtph264.c @@ -539,8 +539,6 @@ GST_START_TEST (test_rtph264pay_reserved_nals) guint8 nal_27[sizeof (h264_aud)]; GstFlowReturn ret; - g_object_set (h->element, "do-aggregate", FALSE, NULL); - gst_harness_set_src_caps_str (h, "video/x-h264,alignment=nal,stream-format=byte-stream"); @@ -605,8 +603,6 @@ GST_START_TEST (test_rtph264pay_two_slices_timestamp) sizeof (h264_idr_slice_2), GST_SECOND)); fail_unless_equals_int (ret, GST_FLOW_OK); - gst_harness_push_event (h, gst_event_new_eos ()); - fail_unless_equals_int (gst_harness_buffers_in_queue (h), 4); buffer = gst_harness_pull (h); @@ -644,8 +640,7 @@ GST_END_TEST; GST_START_TEST (test_rtph264pay_marker_for_flag) { - GstHarness *h = - gst_harness_new_parse ("rtph264pay timestamp-offset=123 do-aggregate=0"); + GstHarness *h = gst_harness_new_parse ("rtph264pay timestamp-offset=123"); GstFlowReturn ret; GstBuffer *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; @@ -685,7 +680,8 @@ GST_END_TEST; GST_START_TEST (test_rtph264pay_marker_for_au) { GstHarness *h = - gst_harness_new_parse ("rtph264pay timestamp-offset=123 do-aggregate=0"); + gst_harness_new_parse + ("rtph264pay timestamp-offset=123 aggregate-mode=none"); GstFlowReturn ret; GstBuffer *slice1, *slice2, *buffer; GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;