From 1ccf82cfd85ce870297599c18292484004d2145f Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Fri, 21 Dec 2012 16:31:26 -0500 Subject: [PATCH 1/4] lavr: cosmetics: reindent --- libavresample/audio_convert.c | 53 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/libavresample/audio_convert.c b/libavresample/audio_convert.c index b57d2fa650..371617cc25 100644 --- a/libavresample/audio_convert.c +++ b/libavresample/audio_convert.c @@ -378,32 +378,35 @@ int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) } } } else { - switch (ac->func_type) { - case CONV_FUNC_TYPE_FLAT: { - if (!in->is_planar) - len *= in->channels; - if (use_generic) { - for (p = 0; p < ac->planes; p++) - ac->conv_flat_generic(out->data[p], in->data[p], len); - } else { - for (p = 0; p < ac->planes; p++) - ac->conv_flat(out->data[p], in->data[p], len); + switch (ac->func_type) { + case CONV_FUNC_TYPE_FLAT: { + if (!in->is_planar) + len *= in->channels; + if (use_generic) { + for (p = 0; p < ac->planes; p++) + ac->conv_flat_generic(out->data[p], in->data[p], len); + } else { + for (p = 0; p < ac->planes; p++) + ac->conv_flat(out->data[p], in->data[p], len); + } + break; + } + case CONV_FUNC_TYPE_INTERLEAVE: + if (use_generic) + ac->conv_interleave_generic(out->data[0], in->data, len, + ac->channels); + else + ac->conv_interleave(out->data[0], in->data, len, ac->channels); + break; + case CONV_FUNC_TYPE_DEINTERLEAVE: + if (use_generic) + ac->conv_deinterleave_generic(out->data, in->data[0], len, + ac->channels); + else + ac->conv_deinterleave(out->data, in->data[0], len, + ac->channels); + break; } - break; - } - case CONV_FUNC_TYPE_INTERLEAVE: - if (use_generic) - ac->conv_interleave_generic(out->data[0], in->data, len, ac->channels); - else - ac->conv_interleave(out->data[0], in->data, len, ac->channels); - break; - case CONV_FUNC_TYPE_DEINTERLEAVE: - if (use_generic) - ac->conv_deinterleave_generic(out->data, in->data[0], len, ac->channels); - else - ac->conv_deinterleave(out->data, in->data[0], len, ac->channels); - break; - } } out->nb_samples = in->nb_samples; From 4164b0e8d38bc579cef777d7971c90c72a0600e7 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Fri, 28 Dec 2012 16:58:55 -0500 Subject: [PATCH 2/4] lavr: mix: reduce the mixing matrix when possible If the matrix results in an output channel not getting a contribution from any input channel and the corresponding input channel does not contribute to any outputs, we can skip the channel during mixing and silence it after mixing. If the matrix results in an input channel not contributing to any output channels and it is not in the output mix, or if the input channel only contributes fully to the same output channel, we can skip the channel during mixing. If the matrix results in an output channel only getting full contribution from the corresponding input channel and that input channel does not contribute to any other output channels, we can skip the channel during mixing. --- libavresample/audio_mix.c | 216 ++++++++++++++++++++++++++++++++------ 1 file changed, 186 insertions(+), 30 deletions(-) diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c index 2b3d9f1f7a..8df8a0223b 100644 --- a/libavresample/audio_mix.c +++ b/libavresample/audio_mix.c @@ -47,6 +47,11 @@ struct AudioMix { mix_func *mix; mix_func *mix_generic; + int in_matrix_channels; + int out_matrix_channels; + int output_zero[AVRESAMPLE_MAX_CHANNELS]; + int input_skip[AVRESAMPLE_MAX_CHANNELS]; + int output_skip[AVRESAMPLE_MAX_CHANNELS]; int16_t *matrix_q8[AVRESAMPLE_MAX_CHANNELS]; int32_t *matrix_q15[AVRESAMPLE_MAX_CHANNELS]; float *matrix_flt[AVRESAMPLE_MAX_CHANNELS]; @@ -59,8 +64,8 @@ void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt, const char *descr, void *mix_func) { if (fmt == am->fmt && coeff_type == am->coeff_type && - ( in_channels == am->in_channels || in_channels == 0) && - (out_channels == am->out_channels || out_channels == 0)) { + ( in_channels == am->in_matrix_channels || in_channels == 0) && + (out_channels == am->out_matrix_channels || out_channels == 0)) { char chan_str[16]; am->mix = mix_func; am->func_descr = descr; @@ -278,6 +283,12 @@ static void mix_2_to_6_fltp_flt_c(float **samples, float **matrix, int len, static int mix_function_init(AudioMix *am) { + /* no need to set a mix function when we're skipping mixing */ + if (!am->in_matrix_channels || !am->out_matrix_channels) { + am->func_descr = "n/a"; + return 0; + } + /* any-to-any C versions */ ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, @@ -379,25 +390,34 @@ AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr) goto error; } + ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels); + if (ret < 0) { + av_log(avr, AV_LOG_ERROR, "error setting mix matrix\n"); + av_free(matrix_dbl); + goto error; + } + av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name), avr->in_channels, avr->in_channel_layout); av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name), avr->out_channels, avr->out_channel_layout); av_log(avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n", in_layout_name, out_layout_name); + av_log(avr, AV_LOG_DEBUG, "matrix size: %d x %d\n", + am->in_matrix_channels, am->out_matrix_channels); for (i = 0; i < avr->out_channels; i++) { for (j = 0; j < avr->in_channels; j++) { - av_log(avr, AV_LOG_DEBUG, " %0.3f ", - matrix_dbl[i * avr->in_channels + j]); + if (am->output_zero[i]) + av_log(avr, AV_LOG_DEBUG, " (ZERO)"); + else if (am->input_skip[j] || am->output_skip[i]) + av_log(avr, AV_LOG_DEBUG, " (SKIP)"); + else + av_log(avr, AV_LOG_DEBUG, " %0.3f ", + matrix_dbl[i * avr->in_channels + j]); } av_log(avr, AV_LOG_DEBUG, "\n"); } - ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels); - if (ret < 0) { - av_free(matrix_dbl); - goto error; - } av_free(matrix_dbl); } @@ -435,6 +455,7 @@ int ff_audio_mix(AudioMix *am, AudioData *src) { int use_generic = 1; int len = src->nb_samples; + int i, j; /* determine whether to use the optimized function based on pointer and samples alignment in both the input and output */ @@ -450,11 +471,35 @@ int ff_audio_mix(AudioMix *am, AudioData *src) src->nb_samples, am->in_channels, am->out_channels, use_generic ? am->func_descr_generic : am->func_descr); - if (use_generic) - am->mix_generic(src->data, am->matrix, len, am->out_channels, - am->in_channels); - else - am->mix(src->data, am->matrix, len, am->out_channels, am->in_channels); + if (am->in_matrix_channels && am->out_matrix_channels) { + uint8_t **data; + uint8_t *data0[AVRESAMPLE_MAX_CHANNELS]; + + if (am->out_matrix_channels < am->out_channels || + am->in_matrix_channels < am->in_channels) { + for (i = 0, j = 0; i < FFMAX(am->in_channels, am->out_channels); i++) { + if (am->input_skip[i] || am->output_skip[i] || am->output_zero[i]) + continue; + data0[j++] = src->data[i]; + } + data = data0; + } else { + data = src->data; + } + + if (use_generic) + am->mix_generic(data, am->matrix, len, am->out_matrix_channels, + am->in_matrix_channels); + else + am->mix(data, am->matrix, len, am->out_matrix_channels, + am->in_matrix_channels); + } + + if (am->out_matrix_channels < am->out_channels) { + for (i = 0; i < am->out_channels; i++) + if (am->output_zero[i]) + av_samples_set_silence(&src->data[i], 0, len, 1, am->fmt); + } ff_audio_data_set_channels(src, am->out_channels); @@ -463,7 +508,7 @@ int ff_audio_mix(AudioMix *am, AudioData *src) int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride) { - int i, o; + int i, o, i0, o0; if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS || am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) { @@ -476,9 +521,19 @@ int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride) av_log(am->avr, AV_LOG_ERROR, "matrix is not set\n"); \ return AVERROR(EINVAL); \ } \ - for (o = 0; o < am->out_channels; o++) \ - for (i = 0; i < am->in_channels; i++) \ - matrix[o * stride + i] = am->matrix_ ## suffix[o][i] * (scale); + for (o = 0, o0 = 0; o < am->out_channels; o++) { \ + for (i = 0, i0 = 0; i < am->in_channels; i++) { \ + if (am->input_skip[i] || am->output_zero[o]) \ + matrix[o * stride + i] = 0.0; \ + else \ + matrix[o * stride + i] = am->matrix_ ## suffix[o0][i0] * \ + (scale); \ + if (!am->input_skip[i]) \ + i0++; \ + } \ + if (!am->output_zero[o]) \ + o0++; \ + } switch (am->coeff_type) { case AV_MIX_COEFF_TYPE_Q8: @@ -500,7 +555,7 @@ int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride) int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride) { - int i, o; + int i, o, i0, o0; if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS || am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) { @@ -513,19 +568,123 @@ int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride) am->matrix = NULL; } + memset(am->output_zero, 0, sizeof(am->output_zero)); + memset(am->input_skip, 0, sizeof(am->input_skip)); + memset(am->output_skip, 0, sizeof(am->output_zero)); + am->in_matrix_channels = am->in_channels; + am->out_matrix_channels = am->out_channels; + + /* exclude output channels if they can be zeroed instead of mixed */ + for (o = 0; o < am->out_channels; o++) { + int zero = 1; + + /* check if the output is always silent */ + for (i = 0; i < am->in_channels; i++) { + if (matrix[o * stride + i] != 0.0) { + zero = 0; + break; + } + } + /* check if the corresponding input channel makes a contribution to + any output channel */ + if (o < am->in_channels) { + for (i = 0; i < am->out_channels; i++) { + if (matrix[i * stride + o] != 0.0) { + zero = 0; + break; + } + } + } + if (zero) { + am->output_zero[o] = 1; + am->out_matrix_channels--; + } + } + if (am->out_matrix_channels == 0) { + am->in_matrix_channels = 0; + return 0; + } + + /* skip input channels that contribute fully only to the corresponding + output channel */ + for (i = 0; i < FFMIN(am->in_channels, am->out_channels); i++) { + int skip = 1; + + for (o = 0; o < am->out_channels; o++) { + if ((o != i && matrix[o * stride + i] != 0.0) || + (o == i && matrix[o * stride + i] != 1.0)) { + skip = 0; + break; + } + } + if (skip) { + am->input_skip[i] = 1; + am->in_matrix_channels--; + } + } + /* skip input channels that do not contribute to any output channel */ + for (; i < am->in_channels; i++) { + int contrib = 0; + + for (o = 0; o < am->out_channels; o++) { + if (matrix[o * stride + i] != 0.0) { + contrib = 1; + break; + } + } + if (!contrib) { + am->input_skip[i] = 1; + am->in_matrix_channels--; + } + } + if (am->in_matrix_channels == 0) { + am->out_matrix_channels = 0; + return 0; + } + + /* skip output channels that only get full contribution from the + corresponding input channel */ + for (o = 0; o < FFMIN(am->in_channels, am->out_channels); o++) { + int skip = 1; + + for (i = 0; i < am->in_channels; i++) { + if ((o != i && matrix[o * stride + i] != 0.0) || + (o == i && matrix[o * stride + i] != 1.0)) { + skip = 0; + break; + } + } + if (skip) { + am->output_skip[o] = 1; + am->out_matrix_channels--; + } + } + if (am->out_matrix_channels == 0) { + am->in_matrix_channels = 0; + return 0; + } + #define CONVERT_MATRIX(type, expr) \ - am->matrix_## type[0] = av_mallocz(am->out_channels * am->in_channels * \ + am->matrix_## type[0] = av_mallocz(am->out_matrix_channels * \ + am->in_matrix_channels * \ sizeof(*am->matrix_## type[0])); \ if (!am->matrix_## type[0]) \ return AVERROR(ENOMEM); \ - for (o = 0; o < am->out_channels; o++) { \ - if (o > 0) \ - am->matrix_## type[o] = am->matrix_## type[o - 1] + \ - am->in_channels; \ - for (i = 0; i < am->in_channels; i++) { \ - double v = matrix[o * stride + i]; \ - am->matrix_## type[o][i] = expr; \ + for (o = 0, o0 = 0; o < am->out_channels; o++) { \ + if (am->output_zero[o] || am->output_skip[o]) \ + continue; \ + if (o0 > 0) \ + am->matrix_## type[o0] = am->matrix_## type[o0 - 1] + \ + am->in_matrix_channels; \ + for (i = 0, i0 = 0; i < am->in_channels; i++) { \ + double v; \ + if (am->input_skip[i]) \ + continue; \ + v = matrix[o * stride + i]; \ + am->matrix_## type[o0][i0] = expr; \ + i0++; \ } \ + o0++; \ } \ am->matrix = (void **)am->matrix_## type; @@ -544,8 +703,5 @@ int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride) return AVERROR(EINVAL); } - /* TODO: detect situations where we can just swap around pointers - instead of doing matrix multiplications with 0.0 and 1.0 */ - return 0; } From 7ff3fd7ae4d6b178501f2f98ff64cbaad02752cc Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Sat, 29 Dec 2012 14:22:55 -0500 Subject: [PATCH 3/4] lavr: log channel conversion description for any-to-any functions --- libavresample/audio_mix.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c index 8df8a0223b..12f5d24ba0 100644 --- a/libavresample/audio_mix.c +++ b/libavresample/audio_mix.c @@ -87,11 +87,12 @@ void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt, } else if (out_channels) { snprintf(chan_str, sizeof(chan_str), "[any to %d] ", out_channels); + } else { + snprintf(chan_str, sizeof(chan_str), "[any to any] "); } av_log(am->avr, AV_LOG_DEBUG, "audio_mix: found function: [fmt=%s] " "[c=%s] %s(%s)\n", av_get_sample_fmt_name(fmt), - coeff_type_names[coeff_type], - (in_channels || out_channels) ? chan_str : "", descr); + coeff_type_names[coeff_type], chan_str, descr); } } From 8729698d50739524665090e083d1bfdf28235724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Mon, 7 Jan 2013 18:39:04 +0200 Subject: [PATCH 4/4] rtsp: Recheck the reordering queue if getting a new packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we timed out and consumed a packet from the reordering queue, but didn't return a packet to the caller, recheck the queue status. Otherwise, we could end up in an infinite loop, trying to consume a queued packet that has already been consumed. CC: libav-stable@libav.org Signed-off-by: Martin Storsjö --- libavformat/rtsp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 134b3223e4..b3e54442af 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -1867,6 +1867,7 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt) rt->cur_transport_priv = NULL; } +redo: if (rt->transport == RTSP_TRANSPORT_RTP) { int i; int64_t first_queue_time = 0; @@ -1882,12 +1883,15 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt) first_queue_st = rt->rtsp_streams[i]; } } - if (first_queue_time) + if (first_queue_time) { wait_end = first_queue_time + s->max_delay; + } else { + wait_end = 0; + first_queue_st = NULL; + } } /* read next RTP packet */ - redo: if (!rt->recvbuf) { rt->recvbuf = av_malloc(RECVBUF_SIZE); if (!rt->recvbuf)