From 6ac9afd16e385fc450c58b8a3fb44baa99ea4af9 Mon Sep 17 00:00:00 2001 From: Lukasz Marek Date: Sat, 26 Oct 2013 01:19:31 +0200 Subject: [PATCH 01/10] lavd/alsa: fix timestamp calculation Current implementation didn't include duration of last processed packet. Device may return negative timestamps without this correction. Signed-off-by: Lukasz Marek --- libavdevice/alsa-audio-enc.c | 6 +++++- libavdevice/alsa-audio.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libavdevice/alsa-audio-enc.c b/libavdevice/alsa-audio-enc.c index 0f4e4a2c7a..5033a4894e 100644 --- a/libavdevice/alsa-audio-enc.c +++ b/libavdevice/alsa-audio-enc.c @@ -80,6 +80,10 @@ static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt) uint8_t *buf = pkt->data; size /= s->frame_size; + if (pkt->dts != AV_NOPTS_VALUE) + s->timestamp = pkt->dts; + s->timestamp += pkt->duration ? pkt->duration : size; + if (s->reorder_func) { if (size > s->reorder_buf_size) if (ff_alsa_extend_reorder_buf(s, size)) @@ -112,7 +116,7 @@ audio_get_output_timestamp(AVFormatContext *s1, int stream, snd_pcm_sframes_t delay = 0; *wall = av_gettime(); snd_pcm_delay(s->h, &delay); - *dts = s1->streams[0]->cur_dts - delay; + *dts = s->timestamp - delay; } AVOutputFormat ff_alsa_muxer = { diff --git a/libavdevice/alsa-audio.h b/libavdevice/alsa-audio.h index 44b7c72fc0..583c9119ac 100644 --- a/libavdevice/alsa-audio.h +++ b/libavdevice/alsa-audio.h @@ -57,6 +57,7 @@ typedef struct AlsaData { void (*reorder_func)(const void *, void *, int); void *reorder_buf; int reorder_buf_size; ///< in frames + int64_t timestamp; ///< current timestamp, without latency applied. } AlsaData; /** From e56d1a120324fa49a5367cbf22098c5c7eb23f91 Mon Sep 17 00:00:00 2001 From: Lukasz Marek Date: Sat, 26 Oct 2013 01:32:55 +0200 Subject: [PATCH 02/10] lavd/alsa: add stream validation Don't trust provided streams. Return with error when stream count is not 1 or provided stream is not an audio stream. Signed-off-by: Lukasz Marek --- libavdevice/alsa-audio-enc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libavdevice/alsa-audio-enc.c b/libavdevice/alsa-audio-enc.c index 5033a4894e..83e1d2f85f 100644 --- a/libavdevice/alsa-audio-enc.c +++ b/libavdevice/alsa-audio-enc.c @@ -47,12 +47,17 @@ static av_cold int audio_write_header(AVFormatContext *s1) { AlsaData *s = s1->priv_data; - AVStream *st; + AVStream *st = NULL; unsigned int sample_rate; enum AVCodecID codec_id; int res; + if (s1->nb_streams != 1 || s1->streams[0]->codec->codec_type != AVMEDIA_TYPE_AUDIO) { + av_log(s1, AV_LOG_ERROR, "Only a single audio stream is supported.\n"); + return AVERROR(EINVAL); + } st = s1->streams[0]; + sample_rate = st->codec->sample_rate; codec_id = st->codec->codec_id; res = ff_alsa_open(s1, SND_PCM_STREAM_PLAYBACK, &sample_rate, From eeb975f5cda31aff3deb8cb4925ea0bf3e897236 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Sat, 2 Nov 2013 16:23:26 +0100 Subject: [PATCH 03/10] lavf/wavenc: check for a single stream. Fix trac ticket #3110. --- libavformat/wavenc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c index fea38cf326..0067dfef29 100644 --- a/libavformat/wavenc.c +++ b/libavformat/wavenc.c @@ -116,6 +116,11 @@ static int wav_write_header(AVFormatContext *s) AVIOContext *pb = s->pb; int64_t fmt; + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "WAVE files have exactly one stream\n"); + return AVERROR(EINVAL); + } + if (wav->rf64 == RF64_ALWAYS) { ffio_wfourcc(pb, "RF64"); avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */ From 863fb11f63f7f60feec390f3c54dd13606e07d05 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Mon, 28 Oct 2013 11:50:09 +0100 Subject: [PATCH 04/10] lavd/lavfi: support unknown channel layouts. --- libavdevice/lavfi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libavdevice/lavfi.c b/libavdevice/lavfi.c index 559f721c8f..a177ad0271 100644 --- a/libavdevice/lavfi.c +++ b/libavdevice/lavfi.c @@ -248,6 +248,10 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx) ret = av_opt_set_int_list(sink, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN); if (ret < 0) goto end; + ret = av_opt_set_int(sink, "all_channel_counts", 1, + AV_OPT_SEARCH_CHILDREN); + if (ret < 0) + goto end; } lavfi->sinks[i] = sink; From f775eb3fb4c7b716107355e428e40cb63f71ee7a Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Tue, 3 Sep 2013 22:12:54 +0200 Subject: [PATCH 05/10] lavfi/avfiltergraph: suggest a solution when format selection fails. Format selection can fail if unknown channel layouts are used with filters that do not support it. --- libavfilter/avfiltergraph.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 506d79ec71..bcdcde06ce 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -654,6 +654,10 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) av_log(link->src, AV_LOG_ERROR, "Cannot select channel layout for" " the link between filters %s and %s.\n", link->src->name, link->dst->name); + if (!link->in_channel_layouts->all_counts) + av_log(link->src, AV_LOG_ERROR, "Unknown channel layouts not " + "supported, try specifying a channel layout using " + "'aformat=channel_layouts=something'.\n"); return AVERROR(EINVAL); } link->in_channel_layouts->nb_channel_layouts = 1; From d300f5f6f570659e4b58567b35c9e8600c9f2956 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Tue, 3 Sep 2013 22:13:49 +0200 Subject: [PATCH 06/10] lavfi/avfiltergraph: do not reduce incompatible lists. A list of "all channel layouts" but not "all channel counts" can not be reduced to a single unknown channel count. --- libavfilter/avfiltergraph.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index bcdcde06ce..1fb83c4877 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -741,7 +741,8 @@ static int reduce_formats_on_filter(AVFilterContext *filter) if (inlink->type != outlink->type || fmts->nb_channel_layouts == 1) continue; - if (fmts->all_layouts) { + if (fmts->all_layouts && + (!FF_LAYOUT2COUNT(fmt) || fmts->all_counts)) { /* Turn the infinite list into a singleton */ fmts->all_layouts = fmts->all_counts = 0; ff_add_channel_layout(&outlink->in_channel_layouts, fmt); From 6e2473edfda26a556c615ebc04d8aeba800bef7e Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Fri, 25 Oct 2013 15:07:40 +0200 Subject: [PATCH 07/10] lavfi: parsing helper for unknown channel layouts. Make ff_parse_channel_layout() accept unknown layouts too. --- libavfilter/af_aconvert.c | 2 +- libavfilter/af_pan.c | 2 +- libavfilter/asrc_aevalsrc.c | 2 +- libavfilter/asrc_anullsrc.c | 2 +- libavfilter/formats.c | 17 +++++++++++++++-- libavfilter/internal.h | 5 ++++- 6 files changed, 23 insertions(+), 7 deletions(-) diff --git a/libavfilter/af_aconvert.c b/libavfilter/af_aconvert.c index 10497aa787..19095cb7e6 100644 --- a/libavfilter/af_aconvert.c +++ b/libavfilter/af_aconvert.c @@ -66,7 +66,7 @@ static av_cold int init(AVFilterContext *ctx) (ret = ff_parse_sample_format(&aconvert->out_sample_fmt, aconvert->format_str, ctx)) < 0) return ret; if (aconvert->channel_layout_str && strcmp(aconvert->channel_layout_str, "auto")) - return ff_parse_channel_layout(&aconvert->out_chlayout, aconvert->channel_layout_str, ctx); + return ff_parse_channel_layout(&aconvert->out_chlayout, NULL, aconvert->channel_layout_str, ctx); return ret; } diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c index 1a01664675..e8c0a24db6 100644 --- a/libavfilter/af_pan.c +++ b/libavfilter/af_pan.c @@ -116,7 +116,7 @@ static av_cold int init(AVFilterContext *ctx) if (!args) return AVERROR(ENOMEM); arg = av_strtok(args, "|", &tokenizer); - ret = ff_parse_channel_layout(&pan->out_channel_layout, arg, ctx); + ret = ff_parse_channel_layout(&pan->out_channel_layout, NULL, arg, ctx); if (ret < 0) goto fail; pan->nb_output_channels = av_get_channel_layout_nb_channels(pan->out_channel_layout); diff --git a/libavfilter/asrc_aevalsrc.c b/libavfilter/asrc_aevalsrc.c index ded533d568..4c1bbdf1f8 100644 --- a/libavfilter/asrc_aevalsrc.c +++ b/libavfilter/asrc_aevalsrc.c @@ -109,7 +109,7 @@ static av_cold int init(AVFilterContext *ctx) if (eval->chlayout_str) { int n; - ret = ff_parse_channel_layout(&eval->chlayout, eval->chlayout_str, ctx); + ret = ff_parse_channel_layout(&eval->chlayout, NULL, eval->chlayout_str, ctx); if (ret < 0) goto end; diff --git a/libavfilter/asrc_anullsrc.c b/libavfilter/asrc_anullsrc.c index 26b32e1647..28d4500a25 100644 --- a/libavfilter/asrc_anullsrc.c +++ b/libavfilter/asrc_anullsrc.c @@ -68,7 +68,7 @@ static av_cold int init(AVFilterContext *ctx) null->sample_rate_str, ctx)) < 0) return ret; - if ((ret = ff_parse_channel_layout(&null->channel_layout, + if ((ret = ff_parse_channel_layout(&null->channel_layout, NULL, null->channel_layout_str, ctx)) < 0) return ret; diff --git a/libavfilter/formats.c b/libavfilter/formats.c index d51bf3c51d..5816032746 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -615,10 +615,21 @@ int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx) return 0; } -int ff_parse_channel_layout(int64_t *ret, const char *arg, void *log_ctx) +int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg, + void *log_ctx) { char *tail; - int64_t chlayout = av_get_channel_layout(arg); + int64_t chlayout, count; + + if (nret) { + count = strtol(arg, &tail, 10); + if (*tail == 'c' && !tail[1] && count > 0 && count < 63) { + *nret = count; + *ret = 0; + return 0; + } + } + chlayout = av_get_channel_layout(arg); if (chlayout == 0) { chlayout = strtol(arg, &tail, 10); if (*tail || chlayout == 0) { @@ -627,6 +638,8 @@ int ff_parse_channel_layout(int64_t *ret, const char *arg, void *log_ctx) } } *ret = chlayout; + if (nret) + *nret = av_get_channel_layout_nb_channels(chlayout); return 0; } diff --git a/libavfilter/internal.h b/libavfilter/internal.h index f8d0cce638..5e19698d07 100644 --- a/libavfilter/internal.h +++ b/libavfilter/internal.h @@ -207,11 +207,14 @@ int ff_parse_sample_format(int *ret, const char *arg, void *log_ctx); * Parse a channel layout or a corresponding integer representation. * * @param ret 64bit integer pointer to where the value should be written. + * @param nret integer pointer to the number of channels; + * if not NULL, then unknown channel layouts are accepted * @param arg string to parse * @param log_ctx log context * @return >= 0 in case of success, a negative AVERROR code on error */ -int ff_parse_channel_layout(int64_t *ret, const char *arg, void *log_ctx); +int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg, + void *log_ctx); void ff_update_link_current_pts(AVFilterLink *link, int64_t pts); From 4a640a6ac89099bfb02d6d3d3ada04e321a37476 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Fri, 25 Oct 2013 16:11:30 +0200 Subject: [PATCH 08/10] lswr: fix assert failure on unknown layouts. --- libswresample/rematrix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c index 5c98e68990..e146edfcf7 100644 --- a/libswresample/rematrix.c +++ b/libswresample/rematrix.c @@ -433,8 +433,8 @@ int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mus off = len1 * out->bps; } - av_assert0(out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout)); - av_assert0(in ->ch_count == av_get_channel_layout_nb_channels(s-> in_ch_layout)); + av_assert0(!s->out_ch_layout || out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout)); + av_assert0(!s-> in_ch_layout || in ->ch_count == av_get_channel_layout_nb_channels(s-> in_ch_layout)); for(out_i=0; out_ich_count; out_i++){ switch(s->matrix_ch[out_i][0]){ From 4e9adc9b7363cc336e3d47c98455e1508902fd29 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Fri, 25 Oct 2013 16:02:04 +0200 Subject: [PATCH 09/10] lavfi/af_pan: support unknown layouts on output. --- libavfilter/af_pan.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c index e8c0a24db6..9040c7a71a 100644 --- a/libavfilter/af_pan.c +++ b/libavfilter/af_pan.c @@ -116,10 +116,10 @@ static av_cold int init(AVFilterContext *ctx) if (!args) return AVERROR(ENOMEM); arg = av_strtok(args, "|", &tokenizer); - ret = ff_parse_channel_layout(&pan->out_channel_layout, NULL, arg, ctx); + ret = ff_parse_channel_layout(&pan->out_channel_layout, + &pan->nb_output_channels, arg, ctx); if (ret < 0) goto fail; - pan->nb_output_channels = av_get_channel_layout_nb_channels(pan->out_channel_layout); /* parse channel specifications */ while ((arg = arg0 = av_strtok(NULL, "|", &tokenizer))) { @@ -244,7 +244,9 @@ static int query_formats(AVFilterContext *ctx) // outlink supports only requested output channel layout layouts = NULL; - ff_add_channel_layout(&layouts, pan->out_channel_layout); + ff_add_channel_layout(&layouts, + pan->out_channel_layout ? pan->out_channel_layout : + FF_COUNT2LAYOUT(pan->nb_output_channels)); ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts); return 0; } @@ -286,6 +288,8 @@ static int config_props(AVFilterLink *link) 0, ctx); if (!pan->swr) return AVERROR(ENOMEM); + if (!pan->out_channel_layout) + av_opt_set_int(pan->swr, "och", pan->nb_output_channels, 0); // gains are pure, init the channel mapping if (pan->pure_gains) { From 7b0a587393e03dab552d66450d43ab82bda0a5a1 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Fri, 25 Oct 2013 16:12:06 +0200 Subject: [PATCH 10/10] lavfi/af_pan: support unknown layouts on input. Fix trac ticket #2899. --- libavfilter/af_pan.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c index 9040c7a71a..d28f382482 100644 --- a/libavfilter/af_pan.c +++ b/libavfilter/af_pan.c @@ -46,7 +46,6 @@ typedef struct PanContext { double gain[MAX_CHANNELS][MAX_CHANNELS]; int64_t need_renorm; int need_renumber; - int nb_input_channels; int nb_output_channels; int pure_gains; @@ -239,7 +238,7 @@ static int query_formats(AVFilterContext *ctx) ff_set_common_samplerates(ctx, formats); // inlink supports any channel layout - layouts = ff_all_channel_layouts(); + layouts = ff_all_channel_counts(); ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts); // outlink supports only requested output channel layout @@ -259,7 +258,6 @@ static int config_props(AVFilterLink *link) int i, j, k, r; double t; - pan->nb_input_channels = av_get_channel_layout_nb_channels(link->channel_layout); if (pan->need_renumber) { // input channels were given by their name: renumber them for (i = j = 0; i < MAX_CHANNELS; i++) { @@ -273,7 +271,7 @@ static int config_props(AVFilterLink *link) // sanity check; can't be done in query_formats since the inlink // channel layout is unknown at that time - if (pan->nb_input_channels > SWR_CH_MAX || + if (link->channels > SWR_CH_MAX || pan->nb_output_channels > SWR_CH_MAX) { av_log(ctx, AV_LOG_ERROR, "libswresample support a maximum of %d channels. " @@ -288,6 +286,8 @@ static int config_props(AVFilterLink *link) 0, ctx); if (!pan->swr) return AVERROR(ENOMEM); + if (!link->channel_layout) + av_opt_set_int(pan->swr, "ich", link->channels, 0); if (!pan->out_channel_layout) av_opt_set_int(pan->swr, "och", pan->nb_output_channels, 0); @@ -297,7 +297,7 @@ static int config_props(AVFilterLink *link) // get channel map from the pure gains for (i = 0; i < pan->nb_output_channels; i++) { int ch_id = -1; - for (j = 0; j < pan->nb_input_channels; j++) { + for (j = 0; j < link->channels; j++) { if (pan->gain[i][j]) { ch_id = j; break; @@ -315,7 +315,7 @@ static int config_props(AVFilterLink *link) if (!((pan->need_renorm >> i) & 1)) continue; t = 0; - for (j = 0; j < pan->nb_input_channels; j++) + for (j = 0; j < link->channels; j++) t += pan->gain[i][j]; if (t > -1E-5 && t < 1E-5) { // t is almost 0 but not exactly, this is probably a mistake @@ -324,7 +324,7 @@ static int config_props(AVFilterLink *link) "Degenerate coefficients while renormalizing\n"); continue; } - for (j = 0; j < pan->nb_input_channels; j++) + for (j = 0; j < link->channels; j++) pan->gain[i][j] /= t; } av_opt_set_int(pan->swr, "icl", link->channel_layout, 0); @@ -339,7 +339,7 @@ static int config_props(AVFilterLink *link) // summary for (i = 0; i < pan->nb_output_channels; i++) { cur = buf; - for (j = 0; j < pan->nb_input_channels; j++) { + for (j = 0; j < link->channels; j++) { r = snprintf(cur, buf + sizeof(buf) - cur, "%s%.3g i%d", j ? " + " : "", pan->gain[i][j], j); cur += FFMIN(buf + sizeof(buf) - cur, r);