diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index 8177d9cde6..4997a66bc4 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -168,10 +168,16 @@ static int setup_format(sh_audio_t *sh_audio, else if (container_samplerate) samplerate = container_samplerate; - if (lavc_context->channels != sh_audio->channels || + struct mp_chmap lavc_chmap; + mp_chmap_from_lavc(&lavc_chmap, lavc_context->channel_layout); + // No channel layout or layout disagrees with channel count + if (lavc_chmap.num != lavc_context->channels) + mp_chmap_from_channels(&lavc_chmap, lavc_context->channels); + + if (!mp_chmap_equals(&lavc_chmap, &sh_audio->channels) || samplerate != sh_audio->samplerate || sample_format != sh_audio->sample_format) { - sh_audio->channels = lavc_context->channels; + sh_audio->channels = lavc_chmap; sh_audio->samplerate = samplerate; sh_audio->sample_format = sample_format; sh_audio->samplesize = af_fmt2bits(sh_audio->sample_format) / 8; @@ -227,8 +233,11 @@ static int init(sh_audio_t *sh_audio, const char *decoder) lavc_context->codec_type = AVMEDIA_TYPE_AUDIO; lavc_context->codec_id = lavc_codec->id; - if (opts->downmix) - lavc_context->request_channels = mpopts->audio_output_channels; + if (opts->downmix) { + lavc_context->request_channels = mpopts->audio_output_channels.num; + lavc_context->request_channel_layout = + mp_chmap_to_lavc(&mpopts->audio_output_channels); + } // Always try to set - option only exists for AC3 at the moment av_opt_set_double(lavc_context, "drc_scale", opts->ac3drc, @@ -246,6 +255,7 @@ static int init(sh_audio_t *sh_audio, const char *decoder) lavc_context->codec_tag = sh_audio->format; lavc_context->sample_rate = sh_audio->samplerate; lavc_context->bit_rate = sh_audio->i_bps * 8; + lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels); if (sh_audio->wf) set_from_wf(lavc_context, sh_audio->wf); diff --git a/audio/decode/ad_mpg123.c b/audio/decode/ad_mpg123.c index 999dc2fbba..45538f42f6 100644 --- a/audio/decode/ad_mpg123.c +++ b/audio/decode/ad_mpg123.c @@ -358,7 +358,7 @@ static int init(sh_audio_t *sh, const char *decoder) con->mean_count = 0; #endif con->vbr = (finfo.vbr != MPG123_CBR); - sh->channels = channels; + mp_chmap_from_channels(&sh->channels, channels); sh->samplerate = rate; /* Without external force, mpg123 will always choose signed encoding, * and non-16-bit only on builds that don't support it. diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c index ad735dde7d..a6f41932e9 100644 --- a/audio/decode/ad_spdif.c +++ b/audio/decode/ad_spdif.c @@ -148,19 +148,20 @@ static int init(sh_audio_t *sh, const char *decoder) } sh->ds->buffer_pos -= in_size; + int num_channels = 0; switch (lavf_ctx->streams[0]->codec->codec_id) { case AV_CODEC_ID_AAC: spdif_ctx->iec61937_packet_size = 16384; sh->sample_format = AF_FORMAT_IEC61937_LE; sh->samplerate = srate; - sh->channels = 2; + num_channels = 2; sh->i_bps = bps; break; case AV_CODEC_ID_AC3: spdif_ctx->iec61937_packet_size = 6144; sh->sample_format = AF_FORMAT_AC3_LE; sh->samplerate = srate; - sh->channels = 2; + num_channels = 2; sh->i_bps = bps; break; case AV_CODEC_ID_DTS: @@ -175,13 +176,13 @@ static int init(sh_audio_t *sh, const char *decoder) spdif_ctx->iec61937_packet_size = 32768; sh->sample_format = AF_FORMAT_IEC61937_LE; sh->samplerate = 192000; // DTS core require 48000 - sh->channels = 2*4; + num_channels = 2*4; sh->i_bps = bps; } else { spdif_ctx->iec61937_packet_size = 32768; sh->sample_format = AF_FORMAT_AC3_LE; sh->samplerate = srate; - sh->channels = 2; + num_channels = 2; sh->i_bps = bps; } break; @@ -189,26 +190,28 @@ static int init(sh_audio_t *sh, const char *decoder) spdif_ctx->iec61937_packet_size = 24576; sh->sample_format = AF_FORMAT_IEC61937_LE; sh->samplerate = 192000; - sh->channels = 2; + num_channels = 2; sh->i_bps = bps; break; case AV_CODEC_ID_MP3: spdif_ctx->iec61937_packet_size = 4608; sh->sample_format = AF_FORMAT_MPEG2; sh->samplerate = srate; - sh->channels = 2; + num_channels = 2; sh->i_bps = bps; break; case AV_CODEC_ID_TRUEHD: spdif_ctx->iec61937_packet_size = 61440; sh->sample_format = AF_FORMAT_IEC61937_LE; sh->samplerate = 192000; - sh->channels = 8; + num_channels = 8; sh->i_bps = bps; break; default: break; } + if (num_channels) + mp_chmap_from_channels(&sh->channels, num_channels); return 1; diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index 11232f9271..999a96a10b 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -86,7 +86,7 @@ static int init_audio_codec(sh_audio_t *sh_audio, const char *decoder) sh_audio->initialized = 1; - if (!sh_audio->channels || !sh_audio->samplerate) { + if (mp_chmap_is_empty(&sh_audio->channels) || !sh_audio->samplerate) { mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder did not specify " "audio format!\n"); uninit_audio(sh_audio); // free buffers @@ -94,7 +94,7 @@ static int init_audio_codec(sh_audio_t *sh_audio, const char *decoder) } if (!sh_audio->o_bps) - sh_audio->o_bps = sh_audio->channels * sh_audio->samplerate + sh_audio->o_bps = sh_audio->channels.num * sh_audio->samplerate * sh_audio->samplesize; return 1; } @@ -160,14 +160,14 @@ int init_best_audio_codec(sh_audio_t *sh_audio, char *audio_decoders) sh_audio->gsh->decoder_desc); mp_msg(MSGT_DECAUDIO, MSGL_V, "AUDIO: %d Hz, %d ch, %s, %3.1f kbit/%3.2f%% (ratio: %d->%d)\n", - sh_audio->samplerate, sh_audio->channels, + sh_audio->samplerate, sh_audio->channels.num, af_fmt2str_short(sh_audio->sample_format), sh_audio->i_bps * 8 * 0.001, ((float) sh_audio->i_bps / sh_audio->o_bps) * 100.0, sh_audio->i_bps, sh_audio->o_bps); mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n", - sh_audio->i_bps * 8, sh_audio->samplerate, sh_audio->channels); + sh_audio->i_bps * 8, sh_audio->samplerate, sh_audio->channels.num); } else { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Failed to initialize an audio decoder for codec '%s'.\n", @@ -207,7 +207,7 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate, afs = af_new(sh_audio->opts); // input format: same as codec's output format: afs->input.rate = in_samplerate; - mp_audio_set_num_channels(&afs->input, sh_audio->channels); + mp_audio_set_channels(&afs->input, &sh_audio->channels); mp_audio_set_format(&afs->input, sh_audio->sample_format); // output format: same as ao driver's input format (if missing, fallback to input) @@ -259,7 +259,7 @@ static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len) // Decode more bytes if needed int old_samplerate = sh->samplerate; - int old_channels = sh->channels; + struct mp_chmap old_channels = sh->channels; int old_sample_format = sh->sample_format; while (sh->a_buffer_len < len) { unsigned char *buf = sh->a_buffer + sh->a_buffer_len; @@ -267,7 +267,7 @@ static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len) int maxlen = sh->a_buffer_size - sh->a_buffer_len; int ret = sh->ad_driver->decode_audio(sh, buf, minlen, maxlen); int format_change = sh->samplerate != old_samplerate - || sh->channels != old_channels + || !mp_chmap_equals(&sh->channels, &old_channels) || sh->sample_format != old_sample_format; if (ret <= 0 || format_change) { error = format_change ? -2 : -1; @@ -285,7 +285,7 @@ static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len) .rate = sh->samplerate, }; mp_audio_set_format(&filter_input, sh->sample_format); - mp_audio_set_num_channels(&filter_input, sh->channels); + mp_audio_set_channels(&filter_input, &sh->channels); struct mp_audio *filter_output = af_play(sh->afilter, &filter_input); if (!filter_output) @@ -314,7 +314,7 @@ int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen) // Indicates that a filter seems to be buffering large amounts of data int huge_filter_buffer = 0; // Decoded audio must be cut at boundaries of this many bytes - int unitsize = sh_audio->channels * sh_audio->samplesize * 16; + int unitsize = sh_audio->channels.num * sh_audio->samplesize * 16; /* Filter output size will be about filter_multiplier times input size. * If some filter buffers audio in big blocks this might only hold diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index 6e776f6598..5994f24056 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -415,7 +415,7 @@ const m_option_t common_opts[] = { // force video/audio rate: OPT_DOUBLE("fps", force_fps, CONF_MIN, 0), OPT_INTRANGE("srate", force_srate, 0, 1000, 8*48000), - OPT_INTRANGE("channels", audio_output_channels, 0, 1, 8), + OPT_CHMAP("channels", audio_output_channels, CONF_MIN, .min = 1), OPT_AUDIOFORMAT("format", audio_output_format, 0), OPT_FLOATRANGE("speed", playback_speed, 0, 0.01, 100.0), diff --git a/core/command.c b/core/command.c index 641dfb80e0..115ea9236f 100644 --- a/core/command.c +++ b/core/command.c @@ -667,20 +667,10 @@ static int mp_property_channels(m_option_t *prop, int action, void *arg, return M_PROPERTY_UNAVAILABLE; switch (action) { case M_PROPERTY_PRINT: - switch (mpctx->sh_audio->channels) { - case 1: - *(char **) arg = talloc_strdup(NULL, "mono"); - break; - case 2: - *(char **) arg = talloc_strdup(NULL, "stereo"); - break; - default: - *(char **) arg = talloc_asprintf(NULL, "%d channels", - mpctx->sh_audio->channels); - } + *(char **) arg = mp_chmap_to_str(&mpctx->sh_audio->channels); return M_PROPERTY_OK; case M_PROPERTY_GET: - *(int *)arg = mpctx->sh_audio->channels; + *(int *)arg = mpctx->sh_audio->channels.num; return M_PROPERTY_OK; } return M_PROPERTY_NOT_IMPLEMENTED; diff --git a/core/defaultopts.c b/core/defaultopts.c index 75a3b8d226..f1778f2fff 100644 --- a/core/defaultopts.c +++ b/core/defaultopts.c @@ -4,6 +4,7 @@ #include "defaultopts.h" #include "core/options.h" #include "audio/mixer.h" +#include "audio/chmap.h" void set_default_mplayer_options(struct MPOpts *opts) { @@ -71,7 +72,7 @@ void set_default_mplayer_options(struct MPOpts *opts) .audio_display = 1, .sub_visibility = 1, .extension_parsing = 1, - .audio_output_channels = 2, + .audio_output_channels = MP_CHMAP_INIT_STEREO, .audio_output_format = -1, // AF_FORMAT_UNKNOWN .playback_speed = 1., .movie_aspect = -1., diff --git a/core/m_option.h b/core/m_option.h index 66e7208801..e365b3eedc 100644 --- a/core/m_option.h +++ b/core/m_option.h @@ -25,6 +25,7 @@ #include "config.h" #include "core/bstr.h" +#include "audio/chmap.h" // m_option allows to parse, print and copy data of various types. @@ -210,6 +211,7 @@ union m_option_value { struct m_color color; struct m_geometry geometry; struct m_geometry size_box; + struct mp_chmap chmap; }; //////////////////////////////////////////////////////////////////////////// diff --git a/core/mplayer.c b/core/mplayer.c index 3f7df8ef36..665216921e 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -324,7 +324,7 @@ static void print_file_properties(struct MPContext *mpctx, const char *filename) mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_RATE=%d\n", mpctx->sh_audio->samplerate); mp_msg(MSGT_IDENTIFY, MSGL_INFO, - "ID_AUDIO_NCH=%d\n", mpctx->sh_audio->channels); + "ID_AUDIO_NCH=%d\n", mpctx->sh_audio->channels.num); start_pts = ds_get_next_pts(mpctx->sh_audio->ds); } if (video_start_pts != MP_NOPTS_VALUE) { @@ -1563,8 +1563,11 @@ void reinit_audio_chain(struct MPContext *mpctx) mpctx->ao->samplerate = opts->force_srate; mpctx->ao->format = opts->audio_output_format; // Automatic downmix - if (opts->audio_output_channels == 2 && mpctx->sh_audio->channels != 2) + if (mp_chmap_is_stereo(&opts->audio_output_channels) && + !mp_chmap_is_stereo(&mpctx->sh_audio->channels)) + { mp_chmap_from_channels(&mpctx->ao->channels, 2); + } } ao = mpctx->ao; diff --git a/core/options.h b/core/options.h index e72778dbde..2af8479316 100644 --- a/core/options.h +++ b/core/options.h @@ -150,7 +150,7 @@ typedef struct MPOpts { double force_fps; - int audio_output_channels; + struct mp_chmap audio_output_channels; int audio_output_format; int force_srate; int dtshd; diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index ba34e7acfa..9bfafe3257 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -341,7 +341,9 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i) sh_audio->format = codec->codec_tag; // probably unneeded - sh_audio->channels = codec->channels; + mp_chmap_from_channels(&sh_audio->channels, codec->channels); + if (codec->channel_layout) + mp_chmap_from_lavc(&sh_audio->channels, codec->channel_layout); sh_audio->samplerate = codec->sample_rate; sh_audio->i_bps = codec->bit_rate / 8; diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index ee39038c77..4452aa9929 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1393,7 +1393,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track, sh_a->format = track->a_formattag; sh_a->wf->wFormatTag = track->a_formattag; - sh_a->channels = track->a_channels; + mp_chmap_from_channels(&sh_a->channels, track->a_channels); sh_a->wf->nChannels = track->a_channels; sh_a->samplerate = (uint32_t) track->a_sfreq; sh_a->container_out_samplerate = track->a_osfreq; @@ -1411,7 +1411,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track, free(sh_a->wf); sh_a->wf = NULL; } else if (track->a_formattag == 0x0001) { /* PCM || PCM_BE */ - sh_a->wf->nAvgBytesPerSec = sh_a->channels * sh_a->samplerate * 2; + sh_a->wf->nAvgBytesPerSec = sh_a->channels.num * sh_a->samplerate * 2; sh_a->wf->nBlockAlign = sh_a->wf->nAvgBytesPerSec; if (!strcmp(track->codec_id, MKV_A_PCM_BE)) sh_a->format = mmioFOURCC('t', 'w', 'o', 's'); @@ -1583,7 +1583,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track, char *data = sh_a->codecdata; memcpy(data + 0, "TTA1", 4); AV_WL16(data + 4, 1); - AV_WL16(data + 6, sh_a->channels); + AV_WL16(data + 6, sh_a->channels.num); AV_WL16(data + 8, sh_a->wf->wBitsPerSample); AV_WL32(data + 10, sh_a->samplerate); // Bogus: last frame won't be played. diff --git a/demux/demux_rawaudio.c b/demux/demux_rawaudio.c index c6aad60806..3cd2500e03 100644 --- a/demux/demux_rawaudio.c +++ b/demux/demux_rawaudio.c @@ -31,12 +31,12 @@ #include "audio/format.h" -static int channels = 2; +static struct mp_chmap channels = MP_CHMAP_INIT_STEREO; static int samplerate = 44100; static int format = AF_FORMAT_S16_NE; const m_option_t demux_rawaudio_opts[] = { - { "channels", &channels, CONF_TYPE_INT,CONF_RANGE,1,8, NULL }, + { "channels", &channels, &m_option_type_chmap, CONF_MIN, 1 }, { "rate", &samplerate, CONF_TYPE_INT,CONF_RANGE,1000,8*48000, NULL }, { "format", &format, CONF_TYPE_AFMT, 0, 0, 0, NULL }, {NULL, NULL, 0, 0, 0, 0, NULL} @@ -55,11 +55,12 @@ static demuxer_t* demux_rawaudio_open(demuxer_t* demuxer) { sh_audio->format = format; sh_audio->wf = w = malloc(sizeof(*w)); w->wFormatTag = 0; - w->nChannels = sh_audio->channels = channels; + sh_audio->channels = channels; + w->nChannels = sh_audio->channels.num; w->nSamplesPerSec = sh_audio->samplerate = samplerate; int samplesize = (af_fmt2bits(format) + 7) / 8; - w->nAvgBytesPerSec = samplerate * samplesize * channels; - w->nBlockAlign = channels * samplesize; + w->nAvgBytesPerSec = samplerate * samplesize * w->nChannels; + w->nBlockAlign = w->nChannels * samplesize; w->wBitsPerSample = 8 * samplesize; w->cbSize = 0; @@ -105,7 +106,7 @@ static void demux_rawaudio_seek(demuxer_t *demuxer,float rel_seek_secs,float aud else pos = base + (rel_seek_secs*sh_audio->i_bps); - pos -= (pos % (sh_audio->channels * sh_audio->samplesize) ); + pos -= (pos % (sh_audio->channels.num * sh_audio->samplesize) ); stream_seek(s,pos); // printf("demux_rawaudio: streamtell=%d\n",(int)stream_tell(demuxer->stream)); } diff --git a/demux/stheader.h b/demux/stheader.h index 8d1822c99f..488d94c114 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -23,6 +23,7 @@ #include "codec_tags.h" +#include "audio/chmap.h" #include "aviheader.h" #include "ms_hdr.h" struct MPOpts; @@ -108,8 +109,8 @@ typedef struct sh_audio { int samplerate; int container_out_samplerate; int samplesize; - int channels; - int o_bps; // == samplerate*samplesize*channels (uncompr. bytes/sec) + struct mp_chmap channels; + int o_bps; // == samplerate*samplesize*channels.num (uncompr. bytes/sec) int i_bps; // == bitrate (compressed bytes/sec) // in buffers: int audio_in_minsize; // initial size to allocate for a_in_buffer if any diff --git a/stream/tv.c b/stream/tv.c index 80dd53e6a1..38368d4925 100644 --- a/stream/tv.c +++ b/stream/tv.c @@ -792,23 +792,25 @@ static demuxer_t* demux_open_tv(demuxer_t *demuxer) &sh_audio->samplerate); funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLESIZE, &sh_audio->samplesize); + int nchannels = sh_audio->channels.num; funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_CHANNELS, - &sh_audio->channels); + &nchannels); + mp_chmap_from_channels(&sh_audio->channels, nchannels); sh_audio->gsh->codec = "mp-pcm"; sh_audio->format = audio_format; sh_audio->i_bps = sh_audio->o_bps = sh_audio->samplerate * sh_audio->samplesize * - sh_audio->channels; + sh_audio->channels.num; // emulate WF for win32 codecs: sh_audio->wf = malloc(sizeof(*sh_audio->wf)); sh_audio->wf->wFormatTag = sh_audio->format; - sh_audio->wf->nChannels = sh_audio->channels; + sh_audio->wf->nChannels = sh_audio->channels.num; sh_audio->wf->wBitsPerSample = sh_audio->samplesize * 8; sh_audio->wf->nSamplesPerSec = sh_audio->samplerate; - sh_audio->wf->nBlockAlign = sh_audio->samplesize * sh_audio->channels; + sh_audio->wf->nBlockAlign = sh_audio->samplesize * sh_audio->channels.num; sh_audio->wf->nAvgBytesPerSec = sh_audio->i_bps; mp_tmsg(MSGT_DECVIDEO, MSGL_V, " TV audio: %d channels, %d bits, %d Hz\n",