diff --git a/doc/utils.texi b/doc/utils.texi index 44ce285d26..1818f107d6 100644 --- a/doc/utils.texi +++ b/doc/utils.texi @@ -721,20 +721,28 @@ FL+FR+FC+BL+BR+BC+SL+SR+WL+WR+TBL+TBR+TBC+TFC+TFL+TFR DL+DR @end table -A custom channel layout can be specified as a sequence of terms, separated by -'+' or '|'. Each term can be: +A custom channel layout can be specified as a sequence of terms, separated by '+'. +Each term can be: @itemize +@item +the name of a single channel (e.g. @samp{FL}, @samp{FR}, @samp{FC}, @samp{LFE}, etc.), +each optionally containing a custom name after a '@@', (e.g. @samp{FL@@Left}, +@samp{FR@@Right}, @samp{FC@@Center}, @samp{LFE@@Low_Frequency}, etc.) +@end itemize + +A standard channel layout can be specified by the following: +@itemize +@item +the name of a single channel (e.g. @samp{FL}, @samp{FR}, @samp{FC}, @samp{LFE}, etc.) + @item the name of a standard channel layout (e.g. @samp{mono}, @samp{stereo}, @samp{4.0}, @samp{quad}, @samp{5.0}, etc.) -@item -the name of a single channel (e.g. @samp{FL}, @samp{FR}, @samp{FC}, @samp{LFE}, etc.) - @item a number of channels, in decimal, followed by 'c', yielding the default channel layout for that number of channels (see the function -@code{av_get_default_channel_layout}). Note that not all channel counts have a +@code{av_channel_layout_default}). Note that not all channel counts have a default layout. @item @@ -751,7 +759,7 @@ Before libavutil version 53 the trailing character "c" to specify a number of channels was optional, but now it is required, while a channel layout mask can also be specified as a decimal number (if and only if not followed by "c" or "C"). -See also the function @code{av_get_channel_layout} defined in +See also the function @code{av_channel_layout_from_string} defined in @file{libavutil/channel_layout.h}. @c man end SYNTAX diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index 4b50e15eef..55cdbfb7a7 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -1470,8 +1470,19 @@ static void print_codec(const AVCodec *c) GET_SAMPLE_RATE_NAME); PRINT_CODEC_SUPPORTED(c, sample_fmts, enum AVSampleFormat, "sample formats", AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME); - PRINT_CODEC_SUPPORTED(c, channel_layouts, uint64_t, "channel layouts", - 0, GET_CH_LAYOUT_DESC); + + if (c->ch_layouts) { + const AVChannelLayout *p = c->ch_layouts; + + printf(" Supported channel layouts:"); + while (p->nb_channels) { + char name[128]; + av_channel_layout_describe(p, name, sizeof(name)); + printf(" %s", name); + p++; + } + printf("\n"); + } if (c->priv_class) { show_help_children(c->priv_class, @@ -1784,29 +1795,30 @@ int show_pix_fmts(void *optctx, const char *opt, const char *arg) int show_layouts(void *optctx, const char *opt, const char *arg) { + const AVChannelLayout *ch_layout; + void *iter = NULL; + char buf[128], buf2[128]; int i = 0; - uint64_t layout, j; - const char *name, *descr; printf("Individual channels:\n" "NAME DESCRIPTION\n"); for (i = 0; i < 63; i++) { - name = av_get_channel_name((uint64_t)1 << i); - if (!name) + av_channel_name(buf, sizeof(buf), i); + if (!strcmp(buf, "?")) continue; - descr = av_get_channel_description((uint64_t)1 << i); - printf("%-14s %s\n", name, descr); + av_channel_description(buf2, sizeof(buf2), i); + printf("%-14s %s\n", buf, buf2); } printf("\nStandard channel layouts:\n" "NAME DECOMPOSITION\n"); - for (i = 0; !av_get_standard_channel_layout(i, &layout, &name); i++) { - if (name) { - printf("%-14s ", name); - for (j = 1; j; j <<= 1) - if ((layout & j)) - printf("%s%s", (layout & (j - 1)) ? "+" : "", av_get_channel_name(j)); + while (ch_layout = av_channel_layout_standard(&iter)) { + av_channel_layout_describe(ch_layout, buf, sizeof(buf)); + av_channel_name(buf2, sizeof(buf2), i); + printf("%-14s ", buf); + for (i = 0; i < 63; i++) + if (av_channel_layout_index_from_channel(ch_layout, i) >= 0) + printf("%s%s", i ? "+" : "", buf2); printf("\n"); - } } return 0; } diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h index 50eed9b13a..274d2e5b14 100644 --- a/fftools/cmdutils.h +++ b/fftools/cmdutils.h @@ -663,14 +663,6 @@ void *allocate_array_elem(void *array, size_t elem_size, int *nb_elems); char name[16];\ snprintf(name, sizeof(name), "%d", rate); -#define GET_CH_LAYOUT_NAME(ch_layout)\ - char name[16];\ - snprintf(name, sizeof(name), "0x%"PRIx64, ch_layout); - -#define GET_CH_LAYOUT_DESC(ch_layout)\ - char name[128];\ - av_get_channel_layout_string(name, sizeof(name), 0, ch_layout); - double get_rotation(int32_t *displaymatrix); #endif /* FFTOOLS_CMDUTILS_H */ diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 9a3fdc636d..a98e49b775 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -551,6 +551,7 @@ static void ffmpeg_cleanup(int ret) avfilter_inout_free(&ofilter->out_tmp); av_freep(&ofilter->name); + av_channel_layout_uninit(&ofilter->ch_layout); av_freep(&fg->outputs[j]); } av_freep(&fg->outputs); @@ -1532,7 +1533,7 @@ static int reap_filters(int flush) break; case AVMEDIA_TYPE_AUDIO: if (!(enc->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) && - enc->channels != filtered_frame->channels) { + enc->ch_layout.nb_channels != filtered_frame->ch_layout.nb_channels) { av_log(NULL, AV_LOG_ERROR, "Audio filter graph output is not normalized and encoder does not support parameter changes\n"); break; @@ -1878,17 +1879,22 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti print_final_stats(total_size); } -static void ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par) +static int ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par) { + int ret; + // We never got any input. Set a fake format, which will // come from libavformat. ifilter->format = par->format; ifilter->sample_rate = par->sample_rate; - ifilter->channels = par->channels; - ifilter->channel_layout = par->channel_layout; ifilter->width = par->width; ifilter->height = par->height; ifilter->sample_aspect_ratio = par->sample_aspect_ratio; + ret = av_channel_layout_copy(&ifilter->ch_layout, &par->ch_layout); + if (ret < 0) + return ret; + + return 0; } static void flush_encoders(void) @@ -1916,8 +1922,11 @@ static void flush_encoders(void) int x; for (x = 0; x < fg->nb_inputs; x++) { InputFilter *ifilter = fg->inputs[x]; - if (ifilter->format < 0) - ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar); + if (ifilter->format < 0 && + ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar) < 0) { + av_log(NULL, AV_LOG_ERROR, "Error copying paramerets from input stream\n"); + exit_program(1); + } } if (!ifilter_has_all_input_formats(fg)) @@ -2093,16 +2102,15 @@ int guess_input_channel_layout(InputStream *ist) { AVCodecContext *dec = ist->dec_ctx; - if (!dec->channel_layout) { + if (dec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) { char layout_name[256]; - if (dec->channels > ist->guess_layout_max) + if (dec->ch_layout.nb_channels > ist->guess_layout_max) return 0; - dec->channel_layout = av_get_default_channel_layout(dec->channels); - if (!dec->channel_layout) + av_channel_layout_default(&dec->ch_layout, dec->ch_layout.nb_channels); + if (dec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) return 0; - av_get_channel_layout_string(layout_name, sizeof(layout_name), - dec->channels, dec->channel_layout); + av_channel_layout_describe(&dec->ch_layout, layout_name, sizeof(layout_name)); av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream " "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name); } @@ -2155,8 +2163,7 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_ref switch (ifilter->ist->st->codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: need_reinit |= ifilter->sample_rate != frame->sample_rate || - ifilter->channels != frame->channels || - ifilter->channel_layout != frame->channel_layout; + av_channel_layout_compare(&ifilter->ch_layout, &frame->ch_layout); break; case AVMEDIA_TYPE_VIDEO: need_reinit |= ifilter->width != frame->width || @@ -2232,8 +2239,11 @@ static int ifilter_send_eof(InputFilter *ifilter, int64_t pts) return ret; } else { // the filtergraph was never configured - if (ifilter->format < 0) - ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar); + if (ifilter->format < 0) { + ret = ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar); + if (ret < 0) + return ret; + } if (ifilter->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) { av_log(NULL, AV_LOG_ERROR, "Cannot determine format of input stream %d:%d after EOF\n", ifilter->ist->file_index, ifilter->ist->st->index); return AVERROR_INVALIDDATA; @@ -3306,8 +3316,9 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) case AVMEDIA_TYPE_AUDIO: enc_ctx->sample_fmt = av_buffersink_get_format(ost->filter->filter); enc_ctx->sample_rate = av_buffersink_get_sample_rate(ost->filter->filter); - enc_ctx->channel_layout = av_buffersink_get_channel_layout(ost->filter->filter); - enc_ctx->channels = av_buffersink_get_channels(ost->filter->filter); + ret = av_buffersink_get_ch_layout(ost->filter->filter, &enc_ctx->ch_layout); + if (ret < 0) + return ret; if (ost->bits_per_raw_sample) enc_ctx->bits_per_raw_sample = ost->bits_per_raw_sample; diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index cc8f767e5d..6a19dc9c7c 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -250,8 +250,7 @@ typedef struct InputFilter { AVRational sample_aspect_ratio; int sample_rate; - int channels; - uint64_t channel_layout; + AVChannelLayout ch_layout; AVBufferRef *hw_frames_ctx; int32_t *displaymatrix; @@ -274,12 +273,12 @@ typedef struct OutputFilter { AVRational frame_rate; int format; int sample_rate; - uint64_t channel_layout; + AVChannelLayout ch_layout; // those are only set if no format is specified and the encoder gives us multiple options // They point directly to the relevant lists of the encoder. const int *formats; - const uint64_t *channel_layouts; + const AVChannelLayout *ch_layouts; const int *sample_rates; } OutputFilter; diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index b80d7189db..0845c631a5 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -153,8 +153,25 @@ DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats, DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0, "%d", ) -DEF_CHOOSE_FORMAT(channel_layouts, uint64_t, channel_layout, channel_layouts, 0, - "0x%"PRIx64, ) +static void choose_channel_layouts(OutputFilter *ofilter, AVBPrint *bprint) +{ + if (av_channel_layout_check(&ofilter->ch_layout)) { + av_bprintf(bprint, "channel_layouts="); + av_channel_layout_describe_bprint(&ofilter->ch_layout, bprint); + } else if (ofilter->ch_layouts) { + const AVChannelLayout *p; + + av_bprintf(bprint, "channel_layouts="); + for (p = ofilter->ch_layouts; p->nb_channels; p++) { + av_channel_layout_describe_bprint(p, bprint); + av_bprintf(bprint, "|"); + } + if (bprint->len > 0) + bprint->str[--bprint->len] = '\0'; + } else + return; + av_bprint_chars(bprint, ':', 1); +} int init_simple_filtergraph(InputStream *ist, OutputStream *ost) { @@ -542,9 +559,10 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, } while (0) av_bprint_init(&args, 0, AV_BPRINT_SIZE_UNLIMITED); if (ost->audio_channels_mapped) { + AVChannelLayout mapped_layout = { 0 }; int i; - av_bprintf(&args, "0x%"PRIx64, - av_get_default_channel_layout(ost->audio_channels_mapped)); + av_channel_layout_default(&mapped_layout, ost->audio_channels_mapped); + av_channel_layout_describe_bprint(&mapped_layout, &args); for (i = 0; i < ost->audio_channels_mapped; i++) if (ost->audio_channels_map[i] != -1) av_bprintf(&args, "|c%d=c%d", i, ost->audio_channels_map[i]); @@ -553,8 +571,8 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, av_bprint_clear(&args); } - if (codec->channels && !codec->channel_layout) - codec->channel_layout = av_get_default_channel_layout(codec->channels); + if (codec->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) + av_channel_layout_default(&codec->ch_layout, codec->ch_layout.nb_channels); choose_sample_fmts(ofilter, &args); choose_sample_rates(ofilter, &args); @@ -833,11 +851,12 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, 1, ifilter->sample_rate, ifilter->sample_rate, av_get_sample_fmt_name(ifilter->format)); - if (ifilter->channel_layout) - av_bprintf(&args, ":channel_layout=0x%"PRIx64, - ifilter->channel_layout); - else - av_bprintf(&args, ":channels=%d", ifilter->channels); + if (av_channel_layout_check(&ifilter->ch_layout) && + ifilter->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) { + av_bprintf(&args, ":channel_layout="); + av_channel_layout_describe_bprint(&ifilter->ch_layout, &args); + } else + av_bprintf(&args, ":channels=%d", ifilter->ch_layout.nb_channels); snprintf(name, sizeof(name), "graph_%d_in_%d_%d", fg->index, ist->file_index, ist->st->index); @@ -1085,7 +1104,10 @@ int configure_filtergraph(FilterGraph *fg) ofilter->height = av_buffersink_get_h(sink); ofilter->sample_rate = av_buffersink_get_sample_rate(sink); - ofilter->channel_layout = av_buffersink_get_channel_layout(sink); + av_channel_layout_uninit(&ofilter->ch_layout); + ret = av_buffersink_get_ch_layout(sink, &ofilter->ch_layout); + if (ret < 0) + goto fail; } fg->reconfiguration = 1; @@ -1147,6 +1169,7 @@ fail: int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame) { AVFrameSideData *sd; + int ret; av_buffer_unref(&ifilter->hw_frames_ctx); @@ -1157,8 +1180,9 @@ int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame) ifilter->sample_aspect_ratio = frame->sample_aspect_ratio; ifilter->sample_rate = frame->sample_rate; - ifilter->channels = frame->channels; - ifilter->channel_layout = frame->channel_layout; + ret = av_channel_layout_copy(&ifilter->ch_layout, &frame->ch_layout); + if (ret < 0) + return ret; av_freep(&ifilter->displaymatrix); sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX); diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index f983c74a66..70e6502f22 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -507,7 +507,7 @@ static int opt_map_channel(void *optctx, const char *opt, const char *arg) /* allow trailing ? to map_channel */ if (allow_unused = strchr(mapchan, '?')) *allow_unused = 0; - if (m->channel_idx < 0 || m->channel_idx >= st->codecpar->channels || + if (m->channel_idx < 0 || m->channel_idx >= st->codecpar->ch_layout.nb_channels || input_streams[input_files[m->file_idx]->ist_index + m->stream_idx]->user_set_discard == AVDISCARD_ALL) { if (allow_unused) { av_log(NULL, AV_LOG_VERBOSE, "mapchan: invalid audio channel #%d.%d.%d\n", @@ -1945,9 +1945,14 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st); if (!ost->stream_copy) { + int channels = 0; char *sample_fmt = NULL; - MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st); + MATCH_PER_STREAM_OPT(audio_channels, i, channels, oc, st); + if (channels) { + audio_enc->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; + audio_enc->ch_layout.nb_channels = channels; + } MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st); if (sample_fmt && @@ -2367,7 +2372,7 @@ static int open_output_file(OptionsContext *o, const char *filename) for (i = 0; i < ifile->nb_streams; i++) { int score; ist = input_streams[ifile->ist_index + i]; - score = ist->st->codecpar->channels + score = ist->st->codecpar->ch_layout.nb_channels + 100000000 * !!(ist->st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS) + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT); if (ist->user_set_discard == AVDISCARD_ALL) @@ -2644,10 +2649,10 @@ loop_end: } else { f->sample_rates = ost->enc->supported_samplerates; } - if (ost->enc_ctx->channels) { - f->channel_layout = av_get_default_channel_layout(ost->enc_ctx->channels); - } else { - f->channel_layouts = ost->enc->channel_layouts; + if (ost->enc_ctx->ch_layout.nb_channels) { + av_channel_layout_default(&f->ch_layout, ost->enc_ctx->ch_layout.nb_channels); + } else if (ost->enc->ch_layouts) { + f->ch_layouts = ost->enc->ch_layouts; } break; } @@ -3236,22 +3241,34 @@ static int opt_channel_layout(void *optctx, const char *opt, const char *arg) char layout_str[32]; char *stream_str; char *ac_str; - int ret, channels, ac_str_size; - uint64_t layout; + int ret, ac_str_size; + AVChannelLayout layout = { 0 }; - layout = av_get_channel_layout(arg); - if (!layout) { + ret = av_channel_layout_from_string(&layout, arg); + if (ret < 0) { +#if FF_API_OLD_CHANNEL_LAYOUT + uint64_t mask; + AV_NOWARN_DEPRECATED({ + mask = av_get_channel_layout(arg); + }) + if (!mask) { +#endif av_log(NULL, AV_LOG_ERROR, "Unknown channel layout: %s\n", arg); return AVERROR(EINVAL); +#if FF_API_OLD_CHANNEL_LAYOUT + } + av_log(NULL, AV_LOG_WARNING, "Channel layout '%s' uses a deprecated syntax.\n", + arg); + av_channel_layout_from_mask(&layout, mask); +#endif } - snprintf(layout_str, sizeof(layout_str), "%"PRIu64, layout); - ret = opt_default_new(o, opt, layout_str); + + ret = opt_default_new(o, opt, arg); if (ret < 0) return ret; /* set 'ac' option based on channel layout */ - channels = av_get_channel_layout_nb_channels(layout); - snprintf(layout_str, sizeof(layout_str), "%d", channels); + snprintf(layout_str, sizeof(layout_str), "%d", layout.nb_channels); stream_str = strchr(opt, ':'); ac_str_size = 3 + (stream_str ? strlen(stream_str) : 0); ac_str = av_mallocz(ac_str_size);