diff --git a/gst-libs/gst/rtp/gstrtpbasepayload.c b/gst-libs/gst/rtp/gstrtpbasepayload.c index 393d8c6751..7efbf11589 100644 --- a/gst-libs/gst/rtp/gstrtpbasepayload.c +++ b/gst-libs/gst/rtp/gstrtpbasepayload.c @@ -60,6 +60,7 @@ struct _GstRTPBasePayloadPrivate GstEvent *pending_segment; GstCaps *subclass_srccaps; + GstCaps *sinkcaps; }; /* RTPBasePayload signals and args */ @@ -403,6 +404,7 @@ gst_rtp_base_payload_finalize (GObject * object) rtpbasepayload->encoding_name = NULL; gst_caps_replace (&rtpbasepayload->priv->subclass_srccaps, NULL); + gst_caps_replace (&rtpbasepayload->priv->sinkcaps, NULL); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -450,6 +452,8 @@ gst_rtp_base_payload_sink_event_default (GstRTPBasePayload * rtpbasepayload, gst_event_parse_caps (event, &caps); GST_DEBUG_OBJECT (rtpbasepayload, "setting caps %" GST_PTR_FORMAT, caps); + gst_caps_replace (&rtpbasepayload->priv->sinkcaps, caps); + rtpbasepayload_class = GST_RTP_BASE_PAYLOAD_GET_CLASS (rtpbasepayload); if (rtpbasepayload_class->set_caps) res = rtpbasepayload_class->set_caps (rtpbasepayload, caps); @@ -775,6 +779,7 @@ static gboolean gst_rtp_base_payload_negotiate (GstRTPBasePayload * payload) { GstCaps *templ, *peercaps, *srccaps; + GstStructure *s, *d; gboolean res; payload->priv->caps_max_ptime = DEFAULT_MAX_PTIME; @@ -806,7 +811,6 @@ gst_rtp_base_payload_negotiate (GstRTPBasePayload * payload) GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps); } else { GstCaps *temp; - GstStructure *s, *d; const GValue *value; gboolean have_pt = FALSE; gboolean have_ts_offset = FALSE; @@ -1029,6 +1033,35 @@ gst_rtp_base_payload_negotiate (GstRTPBasePayload * payload) GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps); } + if (payload->priv->sinkcaps != NULL) { + s = gst_caps_get_structure (payload->priv->sinkcaps, 0); + if (g_str_has_prefix (gst_structure_get_name (s), "video")) { + gboolean has_framerate; + gint num, denom; + + GST_DEBUG_OBJECT (payload, "video caps: %" GST_PTR_FORMAT, + payload->priv->sinkcaps); + + has_framerate = gst_structure_get_fraction (s, "framerate", &num, &denom); + if (has_framerate && num == 0 && denom == 1) { + has_framerate = + gst_structure_get_fraction (s, "max-framerate", &num, &denom); + } + + if (has_framerate) { + gchar str[G_ASCII_DTOSTR_BUF_SIZE]; + gdouble framerate; + + gst_util_fraction_to_double (num, denom, &framerate); + g_ascii_dtostr (str, G_ASCII_DTOSTR_BUF_SIZE, framerate); + d = gst_caps_get_structure (srccaps, 0); + gst_structure_set (d, "a-framerate", G_TYPE_STRING, str, NULL); + } + + GST_DEBUG_OBJECT (payload, "with video caps: %" GST_PTR_FORMAT, srccaps); + } + } + update_max_ptime (payload); res = gst_pad_set_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), srccaps); @@ -1493,6 +1526,7 @@ gst_rtp_base_payload_change_state (GstElement * element, priv->base_offset = GST_BUFFER_OFFSET_NONE; priv->negotiated = FALSE; gst_caps_replace (&rtpbasepayload->priv->subclass_srccaps, NULL); + gst_caps_replace (&rtpbasepayload->priv->sinkcaps, NULL); break; default: break; diff --git a/tests/check/libs/rtpbasepayload.c b/tests/check/libs/rtpbasepayload.c index 900b0b96bd..cb38be38bf 100644 --- a/tests/check/libs/rtpbasepayload.c +++ b/tests/check/libs/rtpbasepayload.c @@ -287,6 +287,14 @@ validate_event (guint index, const gchar * name, const gchar * field, ...) fail_unless (gst_structure_get_uint (gst_caps_get_structure (caps, 0), "ssrc", &ssrc)); fail_unless_equals_int (ssrc, expected); + } else if (!g_strcmp0 (field, "a-framerate")) { + const gchar *expected = va_arg (var_args, const gchar *); + GstCaps *caps; + const gchar *framerate; + gst_event_parse_caps (event, &caps); + framerate = gst_structure_get_string (gst_caps_get_structure (caps, 0), + "a-framerate"); + fail_unless_equals_string (framerate, expected); } else { fail ("test cannot validate unknown event field '%s'", field); } @@ -1764,6 +1772,90 @@ GST_START_TEST (rtp_base_payload_property_stats_test) GST_END_TEST; +/* push a single buffer to the payloader which should successfully payload it + * into an RTP packet. besides the payloaded RTP packet there should be the + * three events initial events: stream-start, caps and segment. because of that + * the input caps has framerate this will be propagated to an a-framerate field + * on the output caps. + */ +GST_START_TEST (rtp_base_payload_framerate_attribute) +{ + State *state; + + state = create_payloader ("video/x-raw,framerate=(fraction)1/4", &sinktmpl, + "perfect-rtptime", FALSE, + NULL); + + set_state (state, GST_STATE_PLAYING); + + push_buffer (state, + "pts", 0 * GST_SECOND, + NULL); + + set_state (state, GST_STATE_NULL); + + validate_buffers_received (1); + + validate_buffer (0, + "pts", 0 * GST_SECOND, + NULL); + + validate_events_received (3); + + validate_normal_start_events (0); + + validate_event (1, "caps", + "a-framerate", "0.25", + NULL); + + destroy_payloader (state); +} + +GST_END_TEST; + +/* push a single buffer to the payloader which should successfully payload it + * into an RTP packet. besides the payloaded RTP packet there should be the + * three events initial events: stream-start, caps and segment. because of that + * the input caps has both framerate and max-framerate set the a-framerate field + * on the output caps will correspond to the value of the max-framerate field. + */ +GST_START_TEST (rtp_base_payload_max_framerate_attribute) +{ + State *state; + + state = create_payloader ( + "video/x-raw,framerate=(fraction)0/1,max-framerate=(fraction)1/8", + &sinktmpl, + "perfect-rtptime", FALSE, + NULL); + + set_state (state, GST_STATE_PLAYING); + + push_buffer (state, + "pts", 0 * GST_SECOND, + NULL); + + set_state (state, GST_STATE_NULL); + + validate_buffers_received (1); + + validate_buffer (0, + "pts", 0 * GST_SECOND, + NULL); + + validate_events_received (3); + + validate_normal_start_events (0); + + validate_event (1, "caps", + "a-framerate", "0.125", + NULL); + + destroy_payloader (state); +} + +GST_END_TEST; + static Suite * rtp_basepayloading_suite (void) { @@ -1798,6 +1890,9 @@ rtp_basepayloading_suite (void) tcase_add_test (tc_chain, rtp_base_payload_property_ptime_multiple_test); tcase_add_test (tc_chain, rtp_base_payload_property_stats_test); + tcase_add_test (tc_chain, rtp_base_payload_framerate_attribute); + tcase_add_test (tc_chain, rtp_base_payload_max_framerate_attribute); + return s; }