Merge branch 'master' into 0.11

Conflicts:
	ext/speex/gstspeexenc.c
	gst/rtpmanager/rtpsession.c
This commit is contained in:
Wim Taymans 2011-11-17 17:17:11 +01:00
commit 07cc855b24
9 changed files with 231 additions and 72 deletions

View file

@ -462,6 +462,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;
}

View file

@ -270,6 +270,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;
}
@ -530,7 +532,7 @@ gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
gint frame_size = enc->frame_size;
gint bytes = frame_size * 2 * enc->channels, samples;
gint outsize, written, dtx_ret = 0;
guint8 *data, *bdata, *outdata;
guint8 *data, *data0 = NULL, *bdata, *outdata;
gsize bsize, size;
GstBuffer *outbuf;
GstFlowReturn ret = GST_FLOW_OK;
@ -542,7 +544,7 @@ gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
size = ((bsize / bytes) + 1) * bytes;
data = g_malloc0 (size);
data0 = data = g_malloc0 (size);
memcpy (data, bdata, bsize);
gst_buffer_unmap (buf, bdata, bsize);
bdata = NULL;
@ -606,6 +608,7 @@ gst_speex_enc_encode (GstSpeexEnc * enc, GstBuffer * buf)
outbuf, samples);
done:
g_free (data0);
return ret;
}

View file

@ -394,6 +394,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);
@ -527,6 +529,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

View file

@ -79,6 +79,8 @@ struct _GstFlacParse {
GList *headers;
GstBuffer *seektable;
gboolean force_variable_block_size;
};
struct _GstFlacParseClass {

View file

@ -1375,30 +1375,34 @@ gst_rtp_session_event_recv_rtp_sink (GstPad * pad, GstObject * parent,
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;
gboolean requested = FALSE;
caps = gst_rtp_session_get_caps_for_pt (rtpsession, payload);
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;
/* 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) {
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 || fir)
return rtp_session_request_key_unit (rtpsession->priv->session, ssrc,
gst_clock_get_time (rtpsession->priv->sysclock), fir, count);
}
return requested;
return FALSE;
}
static gboolean
@ -1421,10 +1425,13 @@ gst_rtp_session_event_recv_rtp_src (GstPad * pad, GstObject * parent,
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;

View file

@ -567,7 +567,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);
@ -590,8 +589,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);
}
@ -2169,45 +2166,112 @@ 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);
RTP_SESSION_UNLOCK (sess);
sess->callbacks.request_key_unit (sess, fir,
sess->request_key_unit_user_data);
RTP_SESSION_LOCK (sess);
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));
/* 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;
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
@ -2251,7 +2315,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) {
@ -2259,6 +2325,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;
}
@ -3262,19 +3332,32 @@ 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,
gboolean fir, gint count)
{
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);
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);
return TRUE;
}
static gboolean
@ -3302,39 +3385,78 @@ rtp_session_on_sending_rtcp (RTPSession * sess, GstBuffer * buffer,
gboolean early)
{
gboolean ret = FALSE;
GHashTableIter iter;
gpointer key, value;
gboolean started_fir = FALSE;
GstRTCPPacket fir_rtcppacket;
GstRTCPBuffer rtcp;
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));
gst_rtcp_buffer_map (buffer, GST_MAP_WRITE, &rtcp);
if (media_src && !rtp_source_has_retained (media_src,
has_pli_compare_func, NULL)) {
GstRTCPBuffer rtcp;
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;
guint8 *fci_data;
gst_rtcp_buffer_map (buffer, GST_MAP_WRITE, &rtcp);
if (gst_rtcp_buffer_add_packet (&rtcp, 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 (media_src->send_fir) {
if (!started_fir) {
if (!gst_rtcp_buffer_add_packet (&rtcp, 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 (&rtcppacket, media_ssrc);
ret = TRUE;
gst_rtcp_buffer_unmap (&rtcp);
} else {
/* Break because the packet is full, will put next request in a
* further packet
*/
gst_rtcp_buffer_unmap (&rtcp);
break;
}
}
gst_rtcp_packet_fb_set_media_ssrc (&fir_rtcppacket, 0);
g_array_remove_index (sess->rtcp_pli_requests, 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 (&rtcp, GST_RTCP_TYPE_PSFB,
&pli_rtcppacket))
/* Break because the packet is full, will put next request in a
* further packet */
break;
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 (&pli_rtcppacket, media_ssrc);
ret = TRUE;
}
media_src->send_pli = FALSE;
}
gst_rtcp_buffer_unmap (&rtcp);
RTP_SESSION_UNLOCK (sess);
return ret;

View file

@ -234,8 +234,8 @@ 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;
};
/**
@ -348,7 +348,10 @@ 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,
gboolean fir,
gint count);
#endif /* __RTP_SESSION_H__ */

View file

@ -172,6 +172,11 @@ struct _RTPSource {
GList *conflicting_addresses;
GQueue *retained_feedback;
gboolean send_pli;
gboolean send_fir;
guint8 current_send_fir_seqnum;
gint last_fir_count;
};
struct _RTPSourceClass {

View file

@ -1729,7 +1729,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
@ -1990,6 +1991,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);