From e7ae593993af5dcc4b7c46dee25aae23c63864ce Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Mon, 7 Nov 2011 18:43:26 +0000 Subject: [PATCH 01/10] v4l2: Set pixel-aspect-ratio to 1/1 We don't currently support setting the pixel-aspect-ratio from V4L2. So simply set it to be 1/1 in the caps to prevent negotiation failures when fixating to weird values (e.g. when the downstream caps has pixel-aspect-ratio = [ MIN, MAX ] ) https://bugzilla.gnome.org/show_bug.cgi?id=663580 --- sys/v4l2/gstv4l2object.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index 903e63a9da..76ac677823 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -1719,7 +1719,8 @@ return_data: s = gst_structure_copy (template); gst_structure_set (s, "width", G_TYPE_INT, (gint) width, "height", G_TYPE_INT, (gint) height, - "interlaced", G_TYPE_BOOLEAN, interlaced, NULL); + "interlaced", G_TYPE_BOOLEAN, interlaced, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL); if (G_IS_VALUE (&rates)) { /* only change the framerate on the template when we have a valid probed new @@ -1980,6 +1981,8 @@ default_frame_sizes: gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL); gst_structure_set (tmp, "interlaced", G_TYPE_BOOLEAN, interlaced, NULL); + gst_structure_set (tmp, "pixel-aspect-ratio", + GST_TYPE_FRACTION, 1, 1, NULL); gst_caps_append_structure (ret, tmp); From 0ad78db0a30bda6b9be9b674c4b1ecf90a8a69c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 30 Aug 2011 19:06:13 -0400 Subject: [PATCH 02/10] rtpsession: Process received Full Intra Requests Process FIR requests according to RFC 5104 https://bugzilla.gnome.org/show_bug.cgi?id=658419 --- gst/rtpmanager/rtpsession.c | 96 +++++++++++++++++++++++++++++-------- gst/rtpmanager/rtpsession.h | 1 + 2 files changed, 76 insertions(+), 21 deletions(-) diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index fe73e99e7d..1a651e08b7 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -2158,45 +2158,93 @@ rtp_session_process_app (RTPSession * sess, GstRTCPPacket * packet, GST_DEBUG ("received APP"); } +static gboolean +rtp_session_request_local_key_unit (RTPSession * sess, RTPSource * src, + gboolean fir, GstClockTime current_time) +{ + guint32 round_trip = 0; + + rtp_source_get_last_rb (src, NULL, NULL, NULL, NULL, NULL, NULL, &round_trip); + + if (sess->last_keyframe_request != GST_CLOCK_TIME_NONE && round_trip) { + GstClockTime round_trip_in_ns = gst_util_uint64_scale (round_trip, + GST_SECOND, 65536); + + if (sess->last_keyframe_request != GST_CLOCK_TIME_NONE && + current_time - sess->last_keyframe_request < 2 * round_trip_in_ns) { + GST_DEBUG ("Ignoring %s request because one was send without one " + "RTT (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")", + fir ? "FIR" : "PLI", + GST_TIME_ARGS (current_time - sess->last_keyframe_request), + GST_TIME_ARGS (round_trip_in_ns));; + return FALSE; + } + } + + sess->last_keyframe_request = current_time; + + GST_LOG ("received %s request from %X %p(%p)", fir ? "FIR" : "PLI", + rtp_source_get_ssrc (src), sess->callbacks.process_rtp, + sess->callbacks.request_key_unit); + + sess->callbacks.request_key_unit (sess, fir, + sess->request_key_unit_user_data); + + return TRUE; +} + static void rtp_session_process_pli (RTPSession * sess, guint32 sender_ssrc, guint32 media_ssrc, GstClockTime current_time) { RTPSource *src; - guint32 round_trip = 0; if (!sess->callbacks.request_key_unit) return; + src = g_hash_table_lookup (sess->ssrcs[sess->mask_idx], + GINT_TO_POINTER (sender_ssrc)); + if (!src) + return; + + rtp_session_request_local_key_unit (sess, src, FALSE, current_time); +} + +static void +rtp_session_process_fir (RTPSession * sess, guint32 sender_ssrc, + guint8 * fci_data, guint fci_length, GstClockTime current_time) +{ + RTPSource *src; + guint32 ssrc; + guint position = 0; + gboolean our_request = FALSE; + + if (!sess->callbacks.request_key_unit) + return; + + if (fci_length < 8) + return; + src = g_hash_table_lookup (sess->ssrcs[sess->mask_idx], GINT_TO_POINTER (sender_ssrc)); if (!src) return; - if (sess->last_keyframe_request != GST_CLOCK_TIME_NONE && - rtp_source_get_last_rb (src, NULL, NULL, NULL, NULL, NULL, NULL, - &round_trip)) { - GstClockTime round_trip_in_ns = gst_util_uint64_scale (round_trip, - GST_SECOND, 65536); + for (position = 0; position < fci_length; position += 8) { + guint8 *data = fci_data + position; - if (sess->last_keyframe_request != GST_CLOCK_TIME_NONE && - current_time - sess->last_keyframe_request < round_trip_in_ns) { - GST_DEBUG ("Ignoring PLI because one was send without one RTT (%" - GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")", - GST_TIME_ARGS (current_time - sess->last_keyframe_request), - GST_TIME_ARGS (round_trip_in_ns));; - return; + ssrc = GST_READ_UINT32_BE (data); + + if (ssrc == rtp_source_get_ssrc (sess->source)) { + our_request = TRUE; + break; } } + if (!our_request) + return; - sess->last_keyframe_request = current_time; - - GST_LOG ("received PLI from %X %p(%p)", sender_ssrc, - sess->callbacks.process_rtp, sess->callbacks.request_key_unit); - - sess->callbacks.request_key_unit (sess, FALSE, - sess->request_key_unit_user_data); + rtp_session_request_local_key_unit (sess, src, TRUE, current_time); } static void @@ -2240,7 +2288,9 @@ rtp_session_process_feedback (RTPSession * sess, GstRTCPPacket * packet, rtp_source_retain_rtcp_packet (src, packet, arrival->running_time); } - if (rtp_source_get_ssrc (sess->source) == media_ssrc) { + if (rtp_source_get_ssrc (sess->source) == media_ssrc || + /* PSFB FIR puts the media ssrc inside the FCI */ + (type == GST_RTCP_TYPE_PSFB && fbtype == GST_RTCP_PSFB_TYPE_FIR)) { switch (type) { case GST_RTCP_TYPE_PSFB: switch (fbtype) { @@ -2248,6 +2298,10 @@ rtp_session_process_feedback (RTPSession * sess, GstRTCPPacket * packet, rtp_session_process_pli (sess, sender_ssrc, media_ssrc, current_time); break; + case GST_RTCP_PSFB_TYPE_FIR: + rtp_session_process_fir (sess, sender_ssrc, fci_data, fci_length, + current_time); + break; default: break; } diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h index 6b827f60a1..617737554c 100644 --- a/gst/rtpmanager/rtpsession.h +++ b/gst/rtpmanager/rtpsession.h @@ -237,6 +237,7 @@ struct _RTPSession { GArray *rtcp_pli_requests; GstClockTime last_keyframe_request; + gboolean last_keyframe_all_headers; }; /** From 59c028a4ceb96a71e7d37c965ff72d9bc2cc4641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 31 Aug 2011 14:35:33 -0400 Subject: [PATCH 03/10] rtpsession: Hack to FIR because Google doesn't set the sender ssrc correctly https://bugzilla.gnome.org/show_bug.cgi?id=658419 --- gst/rtpmanager/rtpsession.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index 1a651e08b7..9a7d2da6b5 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -2228,6 +2228,23 @@ rtp_session_process_fir (RTPSession * sess, guint32 sender_ssrc, src = g_hash_table_lookup (sess->ssrcs[sess->mask_idx], GINT_TO_POINTER (sender_ssrc)); + /* Hack because Google fails to set the sender_ssrc correctly */ + if (!src && sender_ssrc == 1) { + GHashTableIter iter; + + if (sess->stats.sender_sources > + RTP_SOURCE_IS_SENDER (sess->source) ? 2 : 1) + return; + + g_hash_table_iter_init (&iter, sess->ssrcs[sess->mask_idx]); + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) & src)) { + if (src != sess->source && rtp_source_is_sender (src)) + break; + src = NULL; + } + } + if (!src) return; From 12a6b9613bd081f16719734a1706c8f2b9d6b36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Thu, 1 Sep 2011 16:25:21 -0400 Subject: [PATCH 04/10] rtpsession: Put the PLI requests in each RTPSource Also refactor a bit and put all the keyframe request code in one place inside rtpsession.c https://bugzilla.gnome.org/show_bug.cgi?id=658419 --- gst/rtpmanager/gstrtpsession.c | 12 ++++------ gst/rtpmanager/rtpsession.c | 40 ++++++++++++++++++---------------- gst/rtpmanager/rtpsession.h | 6 ++--- gst/rtpmanager/rtpsource.h | 2 ++ 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c index 030a9e4bc1..fd5944aeb7 100644 --- a/gst/rtpmanager/gstrtpsession.c +++ b/gst/rtpmanager/gstrtpsession.c @@ -1389,7 +1389,6 @@ gst_rtp_session_request_remote_key_unit (GstRtpSession * rtpsession, guint32 ssrc, guint payload, gboolean all_headers) { GstCaps *caps; - gboolean requested = FALSE; caps = gst_rtp_session_get_caps_for_pt (rtpsession, payload); @@ -1401,15 +1400,12 @@ gst_rtp_session_request_remote_key_unit (GstRtpSession * rtpsession, gst_caps_unref (caps); - if (pli) { - rtp_session_request_key_unit (rtpsession->priv->session, ssrc); - rtp_session_request_early_rtcp (rtpsession->priv->session, - gst_clock_get_time (rtpsession->priv->sysclock), 200 * GST_MSECOND); - requested = TRUE; - } + if (pli) + return rtp_session_request_key_unit (rtpsession->priv->session, ssrc, + gst_clock_get_time (rtpsession->priv->sysclock)); } - return requested; + return FALSE; } static gboolean diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index 9a7d2da6b5..17b1b02741 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -568,7 +568,6 @@ rtp_session_init (RTPSession * sess) sess->rtcp_immediate_feedback_threshold = DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD; - sess->rtcp_pli_requests = g_array_new (FALSE, FALSE, sizeof (guint32)); sess->last_keyframe_request = GST_CLOCK_TIME_NONE; GST_DEBUG ("%p: session using SSRC: %08x", sess, sess->source->ssrc); @@ -591,8 +590,6 @@ rtp_session_finalize (GObject * object) g_hash_table_destroy (sess->cnames); g_object_unref (sess->source); - g_array_free (sess->rtcp_pli_requests, TRUE); - G_OBJECT_CLASS (rtp_session_parent_class)->finalize (object); } @@ -3301,19 +3298,22 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time, dont_send: RTP_SESSION_UNLOCK (sess); - } -void -rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc) +gboolean +rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc, GstClockTime now) { - guint i; + RTPSource *src = g_hash_table_lookup (sess->ssrcs[sess->mask_idx], + GUINT_TO_POINTER (ssrc)); - for (i = 0; i < sess->rtcp_pli_requests->len; i++) - if (ssrc == g_array_index (sess->rtcp_pli_requests, guint32, i)) - return; + if (!src) + return FALSE; - g_array_append_val (sess->rtcp_pli_requests, ssrc); + src->send_pli = TRUE; + + rtp_session_request_early_rtcp (sess, now, 200 * GST_MSECOND); + + return TRUE; } static gboolean @@ -3336,16 +3336,19 @@ rtp_session_on_sending_rtcp (RTPSession * sess, GstBuffer * buffer, gboolean early) { gboolean ret = FALSE; + GHashTableIter iter; + gpointer key, value; RTP_SESSION_LOCK (sess); - while (sess->rtcp_pli_requests->len) { - GstRTCPPacket rtcppacket; - guint media_ssrc = g_array_index (sess->rtcp_pli_requests, guint32, 0); - RTPSource *media_src = g_hash_table_lookup (sess->ssrcs[sess->mask_idx], - GUINT_TO_POINTER (media_ssrc)); + g_hash_table_iter_init (&iter, sess->ssrcs[sess->mask_idx]); - if (media_src && !rtp_source_has_retained (media_src, + while (g_hash_table_iter_next (&iter, &key, &value)) { + guint media_ssrc = GPOINTER_TO_UINT (key); + RTPSource *media_src = value; + GstRTCPPacket rtcppacket; + + if (media_src->send_pli && !rtp_source_has_retained (media_src, has_pli_compare_func, NULL)) { if (gst_rtcp_buffer_add_packet (buffer, GST_RTCP_TYPE_PSFB, &rtcppacket)) { gst_rtcp_packet_fb_set_type (&rtcppacket, GST_RTCP_PSFB_TYPE_PLI); @@ -3360,8 +3363,7 @@ rtp_session_on_sending_rtcp (RTPSession * sess, GstBuffer * buffer, break; } } - - g_array_remove_index (sess->rtcp_pli_requests, 0); + media_src->send_pli = FALSE; } RTP_SESSION_UNLOCK (sess); diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h index 617737554c..741d54beb4 100644 --- a/gst/rtpmanager/rtpsession.h +++ b/gst/rtpmanager/rtpsession.h @@ -235,7 +235,6 @@ struct _RTPSession { GstClockTime rtcp_feedback_retention_window; guint rtcp_immediate_feedback_threshold; - GArray *rtcp_pli_requests; GstClockTime last_keyframe_request; gboolean last_keyframe_all_headers; }; @@ -350,7 +349,8 @@ void rtp_session_request_early_rtcp (RTPSession * sess, GstClockT GstClockTimeDiff max_delay); /* Notify session of a request for a new key unit */ -void rtp_session_request_key_unit (RTPSession * sess, - guint32 ssrc); +gboolean rtp_session_request_key_unit (RTPSession * sess, + guint32 ssrc, + GstClockTime now); #endif /* __RTP_SESSION_H__ */ diff --git a/gst/rtpmanager/rtpsource.h b/gst/rtpmanager/rtpsource.h index 6db0a6a678..861ffdeccf 100644 --- a/gst/rtpmanager/rtpsource.h +++ b/gst/rtpmanager/rtpsource.h @@ -172,6 +172,8 @@ struct _RTPSource { GList *conflicting_addresses; GQueue *retained_feedback; + + gboolean send_pli; }; struct _RTPSourceClass { From 79a9564c688773aae3ed1df006f82beb6e2d038e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Thu, 1 Sep 2011 17:47:38 -0400 Subject: [PATCH 05/10] rtpsession: Send FIR requests in response to key unit requests with all-headers=TRUE https://bugzilla.gnome.org/show_bug.cgi?id=658419 --- gst/rtpmanager/gstrtpsession.c | 13 +++++-- gst/rtpmanager/rtpsession.c | 69 ++++++++++++++++++++++++++++++---- gst/rtpmanager/rtpsession.h | 4 +- gst/rtpmanager/rtpsource.h | 3 ++ 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c index fd5944aeb7..881dc4beed 100644 --- a/gst/rtpmanager/gstrtpsession.c +++ b/gst/rtpmanager/gstrtpsession.c @@ -1386,7 +1386,7 @@ gst_rtp_session_event_recv_rtp_sink (GstPad * pad, GstEvent * event) static gboolean gst_rtp_session_request_remote_key_unit (GstRtpSession * rtpsession, - guint32 ssrc, guint payload, gboolean all_headers) + guint32 ssrc, guint payload, gboolean all_headers, gint count) { GstCaps *caps; @@ -1395,14 +1395,16 @@ gst_rtp_session_request_remote_key_unit (GstRtpSession * rtpsession, if (caps) { const GstStructure *s = gst_caps_get_structure (caps, 0); gboolean pli; + gboolean fir; pli = gst_structure_has_field (s, "rtcp-fb-nack-pli"); + fir = gst_structure_has_field (s, "rtcp-fb-ccm-fir") && all_headers; gst_caps_unref (caps); - if (pli) + if (pli || fir) return rtp_session_request_key_unit (rtpsession->priv->session, ssrc, - gst_clock_get_time (rtpsession->priv->sysclock)); + gst_clock_get_time (rtpsession->priv->sysclock), fir, count); } return FALSE; @@ -1431,10 +1433,13 @@ gst_rtp_session_event_recv_rtp_src (GstPad * pad, GstEvent * event) gst_structure_get_uint (s, "ssrc", &ssrc) && gst_structure_get_uint (s, "payload", &pt)) { gboolean all_headers = FALSE; + gint count = -1; gst_structure_get_boolean (s, "all-headers", &all_headers); + if (gst_structure_get_int (s, "count", &count) && count < 0) + count += G_MAXINT; /* Make sure count is positive if present */ if (gst_rtp_session_request_remote_key_unit (rtpsession, ssrc, pt, - all_headers)) + all_headers, count)) forward = FALSE; } break; diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index 17b1b02741..f499106f26 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -2184,8 +2184,10 @@ rtp_session_request_local_key_unit (RTPSession * sess, RTPSource * src, rtp_source_get_ssrc (src), sess->callbacks.process_rtp, sess->callbacks.request_key_unit); + RTP_SESSION_UNLOCK (sess); sess->callbacks.request_key_unit (sess, fir, sess->request_key_unit_user_data); + RTP_SESSION_LOCK (sess); return TRUE; } @@ -3301,7 +3303,8 @@ dont_send: } gboolean -rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc, GstClockTime now) +rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc, GstClockTime now, + gboolean fir, gint count) { RTPSource *src = g_hash_table_lookup (sess->ssrcs[sess->mask_idx], GUINT_TO_POINTER (ssrc)); @@ -3309,7 +3312,16 @@ rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc, GstClockTime now) if (!src) return FALSE; - src->send_pli = TRUE; + if (fir) { + src->send_pli = FALSE; + src->send_fir = TRUE; + + if (count == -1 || count != src->last_fir_count) + src->current_send_fir_seqnum++; + src->last_fir_count = count; + } else if (!src->send_fir) { + src->send_pli = TRUE; + } rtp_session_request_early_rtcp (sess, now, 200 * GST_MSECOND); @@ -3338,23 +3350,64 @@ rtp_session_on_sending_rtcp (RTPSession * sess, GstBuffer * buffer, gboolean ret = FALSE; GHashTableIter iter; gpointer key, value; + gboolean started_fir = FALSE; + GstRTCPPacket fir_rtcppacket; RTP_SESSION_LOCK (sess); g_hash_table_iter_init (&iter, sess->ssrcs[sess->mask_idx]); - while (g_hash_table_iter_next (&iter, &key, &value)) { guint media_ssrc = GPOINTER_TO_UINT (key); RTPSource *media_src = value; - GstRTCPPacket rtcppacket; + guint8 *fci_data; + + if (media_src->send_fir) { + if (!started_fir) { + if (!gst_rtcp_buffer_add_packet (buffer, GST_RTCP_TYPE_PSFB, + &fir_rtcppacket)) + break; + gst_rtcp_packet_fb_set_type (&fir_rtcppacket, GST_RTCP_PSFB_TYPE_FIR); + gst_rtcp_packet_fb_set_sender_ssrc (&fir_rtcppacket, + rtp_source_get_ssrc (sess->source)); + gst_rtcp_packet_fb_set_media_ssrc (&fir_rtcppacket, 0); + + if (!gst_rtcp_packet_fb_set_fci_length (&fir_rtcppacket, 2)) { + gst_rtcp_packet_remove (&fir_rtcppacket); + break; + } + ret = TRUE; + started_fir = TRUE; + } else { + if (!gst_rtcp_packet_fb_set_fci_length (&fir_rtcppacket, + !gst_rtcp_packet_fb_get_fci_length (&fir_rtcppacket) + 2)) + break; + } + + fci_data = gst_rtcp_packet_fb_get_fci (&fir_rtcppacket) - + ((gst_rtcp_packet_fb_get_fci_length (&fir_rtcppacket) - 2) * 4); + + GST_WRITE_UINT32_BE (fci_data, media_ssrc); + fci_data += 4; + fci_data[0] = media_src->current_send_fir_seqnum; + fci_data[1] = fci_data[2] = fci_data[3] = 0; + media_src->send_fir = FALSE; + } + } + + g_hash_table_iter_init (&iter, sess->ssrcs[sess->mask_idx]); + while (g_hash_table_iter_next (&iter, &key, &value)) { + guint media_ssrc = GPOINTER_TO_UINT (key); + RTPSource *media_src = value; + GstRTCPPacket pli_rtcppacket; if (media_src->send_pli && !rtp_source_has_retained (media_src, has_pli_compare_func, NULL)) { - if (gst_rtcp_buffer_add_packet (buffer, GST_RTCP_TYPE_PSFB, &rtcppacket)) { - gst_rtcp_packet_fb_set_type (&rtcppacket, GST_RTCP_PSFB_TYPE_PLI); - gst_rtcp_packet_fb_set_sender_ssrc (&rtcppacket, + if (gst_rtcp_buffer_add_packet (buffer, GST_RTCP_TYPE_PSFB, + &pli_rtcppacket)) { + gst_rtcp_packet_fb_set_type (&pli_rtcppacket, GST_RTCP_PSFB_TYPE_PLI); + gst_rtcp_packet_fb_set_sender_ssrc (&pli_rtcppacket, rtp_source_get_ssrc (sess->source)); - gst_rtcp_packet_fb_set_media_ssrc (&rtcppacket, media_ssrc); + gst_rtcp_packet_fb_set_media_ssrc (&pli_rtcppacket, media_ssrc); ret = TRUE; } else { /* Break because the packet is full, will put next request in a diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h index 741d54beb4..ecc0b98f31 100644 --- a/gst/rtpmanager/rtpsession.h +++ b/gst/rtpmanager/rtpsession.h @@ -351,6 +351,8 @@ void rtp_session_request_early_rtcp (RTPSession * sess, GstClockT /* Notify session of a request for a new key unit */ gboolean rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc, - GstClockTime now); + GstClockTime now, + gboolean fir, + gint count); #endif /* __RTP_SESSION_H__ */ diff --git a/gst/rtpmanager/rtpsource.h b/gst/rtpmanager/rtpsource.h index 861ffdeccf..fc204aeedd 100644 --- a/gst/rtpmanager/rtpsource.h +++ b/gst/rtpmanager/rtpsource.h @@ -174,6 +174,9 @@ struct _RTPSource { GQueue *retained_feedback; gboolean send_pli; + gboolean send_fir; + guint8 current_send_fir_seqnum; + gint last_fir_count; }; struct _RTPSourceClass { From 1169bb05af25d6f0902a8d29c067b237ebfd6849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 2 Sep 2011 19:20:07 -0400 Subject: [PATCH 06/10] gstrtpsession: Add special mode to use FIR as repair as Google does https://bugzilla.gnome.org/show_bug.cgi?id=658419 --- gst/rtpmanager/gstrtpsession.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c index 881dc4beed..5fe3bec6e5 100644 --- a/gst/rtpmanager/gstrtpsession.c +++ b/gst/rtpmanager/gstrtpsession.c @@ -1400,6 +1400,12 @@ gst_rtp_session_request_remote_key_unit (GstRtpSession * rtpsession, pli = gst_structure_has_field (s, "rtcp-fb-nack-pli"); fir = gst_structure_has_field (s, "rtcp-fb-ccm-fir") && all_headers; + /* Google Talk uses FIR for repair, so send it even if we just want a + * regular PLI */ + if (!pli && + gst_structure_has_field (s, "rtcp-fb-x-gstreamer-fir-as-repair")) + fir = TRUE; + gst_caps_unref (caps); if (pli || fir) From 011c33e91ec56c64e26312cf5cdb60890a84d32e Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 14 Nov 2011 15:34:57 +0000 Subject: [PATCH 07/10] flacparse: detect when a file lies about fixed block size If the sample/block number happens to be the same as the block size, we assume variable block size, and thus counters in samples in the headers. This can only get us a false positive for a block size of 1, which is invalid. We can get false negatives more often though (eg, if not starting at the start of the stream), but then that's already GIGO. --- gst/audioparsers/gstflacparse.c | 12 ++++++++++++ gst/audioparsers/gstflacparse.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index 05bfd0e0f1..637319f621 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -399,6 +399,8 @@ gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse, /* 0 == fixed block size, 1 == variable block size */ blocking_strategy = gst_bit_reader_get_bits_uint8_unchecked (&reader, 1); + if (flacparse->force_variable_block_size) + blocking_strategy = 1; /* block size index, calculation of the real blocksize below */ block_size = gst_bit_reader_get_bits_uint16_unchecked (&reader, 4); @@ -532,6 +534,16 @@ gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse, if (actual_crc != expected_crc) goto error; + /* Sanity check sample number against blocking strategy, as it seems + some files claim fixed block size but supply sample numbers, + rather than block numbers. */ + if (set && blocking_strategy == 0 && block_size == sample_number) { + GST_WARNING_OBJECT (flacparse, "This file claims fixed block size, " + "but seems to be lying: assuming variable block size"); + flacparse->force_variable_block_size = TRUE; + blocking_strategy = 1; + } + /* The FLAC format documentation says: The "blocking strategy" bit determines how to calculate the sample number diff --git a/gst/audioparsers/gstflacparse.h b/gst/audioparsers/gstflacparse.h index 1c6db0e581..282755244c 100644 --- a/gst/audioparsers/gstflacparse.h +++ b/gst/audioparsers/gstflacparse.h @@ -79,6 +79,8 @@ struct _GstFlacParse { GList *headers; GstBuffer *seektable; + + gboolean force_variable_block_size; }; struct _GstFlacParseClass { From 413f445455fd0b246ba8142931d1f03c651dda5e Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 16 Nov 2011 18:57:21 +0100 Subject: [PATCH 08/10] flacenc: reset tag setter interface when appropriate --- ext/flac/gstflacenc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c index 1cf721c6b6..42c4921041 100644 --- a/ext/flac/gstflacenc.c +++ b/ext/flac/gstflacenc.c @@ -477,6 +477,8 @@ gst_flac_enc_stop (GstAudioEncoder * enc) g_list_free (flacenc->headers); flacenc->headers = NULL; + gst_tag_setter_reset_tags (GST_TAG_SETTER (enc)); + return TRUE; } From c0d86fd26f863ff0257440bb87ebd2944ab6e0da Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 16 Nov 2011 18:57:38 +0100 Subject: [PATCH 09/10] speexenc: reset tag setter interface when appropriate --- ext/speex/gstspeexenc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/speex/gstspeexenc.c b/ext/speex/gstspeexenc.c index 3d0bec27e9..6f792623cc 100644 --- a/ext/speex/gstspeexenc.c +++ b/ext/speex/gstspeexenc.c @@ -282,6 +282,8 @@ gst_speex_enc_stop (GstAudioEncoder * benc) g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL); enc->headers = NULL; + gst_tag_setter_reset_tags (GST_TAG_SETTER (enc)); + return TRUE; } From 7df81223220600b7e27f1fdc1be25891dc63bdba Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 16 Nov 2011 19:08:05 +0100 Subject: [PATCH 10/10] speexenc: ensure to free allocated padded data --- ext/speex/gstspeexenc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/speex/gstspeexenc.c b/ext/speex/gstspeexenc.c index 6f792623cc..89672f2b09 100644 --- a/ext/speex/gstspeexenc.c +++ b/ext/speex/gstspeexenc.c @@ -547,7 +547,7 @@ gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf) gint frame_size = enc->frame_size; gint bytes = frame_size * 2 * enc->channels, samples, size; gint outsize, written, dtx_ret = 0; - guint8 *data; + guint8 *data, *data0 = NULL; GstBuffer *outbuf; GstFlowReturn ret = GST_FLOW_OK; @@ -558,7 +558,7 @@ gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf) if (G_UNLIKELY (size % bytes)) { GST_DEBUG_OBJECT (enc, "draining; adding silence samples"); size = ((size / bytes) + 1) * bytes; - data = g_malloc0 (size); + data0 = data = g_malloc0 (size); memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); } } else { @@ -610,6 +610,7 @@ gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf) outbuf, samples); done: + g_free (data0); return ret; }