1
0
mirror of https://github.com/mpv-player/mpv synced 2025-04-01 00:07:33 +00:00

Merge branch 'audio_changes'

Conflicts:
	audio/out/ao_lavc.c
This commit is contained in:
wm4 2013-05-12 21:47:55 +02:00
commit e6e5a7b221
79 changed files with 3311 additions and 3584 deletions

View File

@ -30,15 +30,15 @@ filter list.
Available filters are:
lavrresample[=option1:option2:...]
Changes the sample rate of the audio stream to an integer <srate> in Hz.
Can be used if you have a fixed frequency sound card or if you are stuck
with an old sound card that is only capable of max 44.1kHz.
This filter uses libavresample (or libswresample, depending on the build)
to change sample rate, sample format, or channel layout of the audio stream.
This filter is automatically enabled if the audio output doesn't support
the audio configuration of the file being played.
This filter is automatically enabled if necessary. It only supports the
16-bit integer native-endian format.
It supports only the following sample formats: u8, s16ne, s32ne, floatne.
srate=<srate>
the output sample rate (defaut: 44100)
the output sample rate
length=<length>
length of the filter with respect to the lower sampling rate (default:
16)
@ -50,6 +50,11 @@ lavrresample[=option1:option2:...]
linear
if set then filters will be linearly interpolated between polyphase
entries (default: no)
no-detach
don't detach if input and output audio format/rate/channels are the
same. You should add this option if you specify additional parameters,
as automatically inserted lavrresample instances will use the
default settings.
lavcac3enc[=tospdif[:bitrate[:minchn]]]
Encode multi-channel audio to AC-3 at runtime using libavcodec. Supports
@ -205,6 +210,34 @@ channels=nch[:nr:from1:to1:from2:to2:from3:to3:...]
Would change the number of channels to 6 and set up 4 routes that copy
channel 0 to channels 0 to 3. Channel 4 and 5 will contain silence.
force=in-format:in-srate:in-channels:out-format:out-srate:out-channels
Force a specific audio format/configuration without actually changing the
audio data. Keep in mind that the filter system might auto-insert actual
conversion filters before or after this filter if needed.
All parameters are optional. The ``in-`` variants restrict what the filter
accepts as input. The ``out-`` variants change the audio format, without
actually doing a conversion. The data will be 'reinterpreted' by the
filters or audio outputs following this filter.
<in-format>
Force conversion to this format. See ``format`` filter for valid audio
format values.
<in-srate>
Force conversion to a specific sample rate. The rate is an integer,
48000 for example.
<in-channels>
Force mixing to a specific channel layout. See ``--channels`` option
for possible values.
<out-format>
<out-srate>
<out-channels>
format[=format]
Convert between different sample formats. Automatically enabled when
needed by the sound card or another filter. See also ``--format``.
@ -219,7 +252,7 @@ format[=format]
rule that are also valid format specifiers: u8, s8, floatle, floatbe,
floatne, mpeg2, and ac3.
volume[=v[:sc]]
volume[=v[:sc[:fast]]]
Implements software volume control. Use this filter with caution since it
can reduce the signal to noise ratio of the sound. In most cases it is
best to set the level for the PCM sound to max, leave this filter out and
@ -233,8 +266,7 @@ volume[=v[:sc]]
This filter has a second feature: It measures the overall maximum sound
level and prints out that level when mpv exits. This feature currently
only works with floating-point data, use e.g. ``--af-adv=force=5``, or use
``--af=stats``.
only works with floating-point data.
*NOTE*: This filter is not reentrant and can therefore only be enabled
once for every audio stream.
@ -250,6 +282,9 @@ volume[=v[:sc]]
*WARNING*: This feature creates distortion and should be considered a
last resort.
<fast>
Force S16 sample format if set to 1. Lower quality, but might be faster
in some situations.
*EXAMPLE*:
@ -286,6 +321,11 @@ pan=n[:L00:L01:L02:...L10:L11:L12:...Ln0:Ln1:Ln2:...]
channels 0 and 1 into output channel 2 (which could be sent to a
subwoofer for example).
*NOTE*: if you just want to force remixing to a certain output channel
layout, it's easier to use the ``force`` filter. For example,
``mpv '--af=force=channels=5.1' '--channels=5.1'`` would always force
remixing audio to 5.1 and output it like this.
sub[=fc:ch]
Adds a subwoofer channel to the audio stream. The audio data used for
creating the subwoofer channel is an average of the sound in channel 0 and

View File

@ -124,6 +124,7 @@ Command line switches
-afm hwac3 --ad=spdif:ac3,spdif:dts
-x W, -y H --geometry=WxH + --no-keepaspect
-xy W --autofit=W
-a52drc level --ad-lavc-ac3drc=level
=================================== ===================================
*NOTE*: ``-opt val`` becomes ``--opt=val``.

View File

@ -1,11 +1,3 @@
--a52drc=<level>
Select the Dynamic Range Compression level for AC-3 audio streams. <level>
is a float value ranging from 0 to 1, where 0 means no compression and 1
(which is the default) means full compression (make loud passages more
silent and vice versa). Values up to 2 are also accepted, but are purely
experimental. This option only shows an effect if the AC-3 stream contains
the required range compression information.
--abs=<value>
(``--ao=oss`` only) (OBSOLETE)
Override audio driver/card buffer size detection.
@ -37,6 +29,25 @@
``--ad=help``
List all available decoders.
--ad-lavc-ac3drc=<level>
Select the Dynamic Range Compression level for AC-3 audio streams. <level>
is a float value ranging from 0 to 1, where 0 means no compression and 1
(which is the default) means full compression (make loud passages more
silent and vice versa). Values up to 2 are also accepted, but are purely
experimental. This option only shows an effect if the AC-3 stream contains
the required range compression information.
--ad-lavc-downmix=<yes|no>
Whether to request audio channel downmixing from the decoder (default: yes).
Some decoders, like AC-3, AAC and DTS, can remix audio on decoding. The
requested number of output channels is set with the ``--channels`` option.
Useful for playing surround audio on a stereo system.
--ad-lavc-o=<key>=<value>[,<key>=<value>[,...]]
Pass AVOptions to libavcodec decoder. Note, a patch to make the o=
unneeded and pass all unknown options through the AVOption system is
welcome. A full list of AVOptions can be found in the FFmpeg manual.
--af=<filter1[=parameter1:parameter2:...],filter2,...>
Specify a list of audio filters to apply to the audio stream. See
`audio_filters` for details and descriptions of the available filters.
@ -44,40 +55,6 @@
``--af-clr`` exist to modify a previously specified list, but you
shouldn't need these for typical use.
--af-adv=<force=(0-7):list=(filters)>
See also ``--af``.
Specify advanced audio filter options:
force=<0-7>
Forces the insertion of audio filters to one of the following:
0
Use completely automatic filter insertion (currently identical to
1).
1
Optimize for accuracy (default).
2
Optimize for speed. *Warning*: Some features in the audio filters
may silently fail, and the sound quality may drop.
3
Use no automatic insertion of filters and no optimization.
*Warning*: It may be possible to crash mpv using this setting.
4
Use automatic insertion of filters according to 0 above, but use
floating point processing when possible.
5
Use automatic insertion of filters according to 1 above, but use
floating point processing when possible.
6
Use automatic insertion of filters according to 2 above, but use
floating point processing when possible.
7
Use no automatic insertion of filters according to 3 above, and
use floating point processing when possible.
list=<filters>
Same as ``--af``.
--aid=<ID|auto|no>
Select audio channel. ``auto`` selects the default, ``no`` disables audio.
See also ``--alang``.
@ -381,25 +358,24 @@
--cdrom-device=<path>
Specify the CD-ROM device (default: ``/dev/cdrom``).
--channels=<number>
--channels=<number|layout>
Request the number of playback channels (default: 2). mpv asks the
decoder to decode the audio into as many channels as specified. Then it is
up to the decoder to fulfill the requirement. This is usually only
important when playing videos with AC-3 audio (like DVDs). In that case
liba52 does the decoding by default and correctly downmixes the audio into
the requested number of channels. To directly control the number of output
channels independently of how many channels are decoded, use the channels
filter (``--af=channels``).
important when playing videos with AC-3, AAC or DTS audio. In that case
libavcodec downmixes the audio into the requested number of channels if
possible.
*NOTE*: This option is honored by codecs (AC-3 only), filters (surround)
and audio output drivers (OSS at least).
Available options are:
The ``--channels`` option either takes a channel number or an explicit
channel layout. Channel numbers refer to default layouts, e.g. 2 channels
refer to stereo, 6 refers to 5.1.
:2: stereo
:4: surround
:6: full 5.1
:8: full 7.1
See ``--channels=help`` output for defined default layouts. This also
lists speaker names, which can be used to express arbitrary channel
layouts (e.g. ``fl-fr-lfe`` is 2.1).
--chapter=<start[-end]>
Specify which chapter to start playing at. Optionally specify which
@ -1985,9 +1961,8 @@
--srate=<Hz>
Select the output sample rate to be used (of course sound cards have
limits on this). If the sample frequency selected is different from that
of the current media, the resample or lavcresample audio filter will be
inserted into the audio filter layer to compensate for the difference. The
type of resampling can be controlled by the ``--af-adv`` option.
of the current media, the lavrresample audio filter will be
inserted into the audio filter layer to compensate for the difference.
--start=<relative time>
Seek to given time position.

View File

@ -124,6 +124,10 @@ ifeq ($(HAVE_AVUTIL_REFCOUNTING),no)
endif
SOURCES = talloc.c \
audio/audio.c \
audio/chmap.c \
audio/chmap_sel.c \
audio/fmt-conversion.c \
audio/format.c \
audio/mixer.c \
audio/reorder_ch.c \
@ -138,6 +142,7 @@ SOURCES = talloc.c \
audio/filter/af_dummy.c \
audio/filter/af_equalizer.c \
audio/filter/af_extrastereo.c \
audio/filter/af_force.c \
audio/filter/af_format.c \
audio/filter/af_hrtf.c \
audio/filter/af_karaoke.c \

View File

@ -1,3 +1,10 @@
# Usage:
# uncrustify -l C -c TOOLS/uncrustify.cfg --no-backup --replace file.c
#
# Keep in mind that this uncrustify configuration still produces some
# bad/broken formatting.
#
code_width=80
indent_align_string=false
indent_braces=false

76
audio/audio.c Normal file
View File

@ -0,0 +1,76 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "core/mp_talloc.h"
#include "audio.h"
void mp_audio_set_format(struct mp_audio *mpa, int format)
{
mpa->format = format;
mpa->bps = af_fmt2bits(format) / 8;
}
void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels)
{
struct mp_chmap map;
mp_chmap_from_channels(&map, num_channels);
mp_audio_set_channels(mpa, &map);
}
// Use old MPlayer/ALSA channel layout.
void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels)
{
struct mp_chmap map;
mp_chmap_from_channels_alsa(&map, num_channels);
mp_audio_set_channels(mpa, &map);
}
void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap)
{
assert(mp_chmap_is_empty(chmap) || mp_chmap_is_valid(chmap));
mpa->channels = *chmap;
mpa->nch = mpa->channels.num;
}
void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src)
{
mp_audio_set_format(dst, src->format);
mp_audio_set_channels(dst, &src->channels);
dst->rate = src->rate;
}
bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b)
{
return a->format == b->format && a->rate == b->rate &&
mp_chmap_equals(&a->channels, &b->channels);
}
char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format)
{
char *chstr = mp_chmap_to_str(chmap);
char *res = talloc_asprintf(NULL, "%dHz %s %dch %s", srate, chstr,
chmap->num, af_fmt2str_short(format));
talloc_free(chstr);
return res;
}
char *mp_audio_config_to_str(struct mp_audio *mpa)
{
return mp_audio_fmt_to_str(mpa->rate, &mpa->channels, mpa->format);
}

46
audio/audio.h Normal file
View File

@ -0,0 +1,46 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MP_AUDIO_H
#define MP_AUDIO_H
#include "format.h"
#include "chmap.h"
// Audio data chunk
struct mp_audio {
void *audio; // data buffer
int len; // buffer length (in bytes)
int rate; // sample rate
struct mp_chmap channels; // channel layout, use mp_audio_set_*() to set
int format; // format (AF_FORMAT_...), use mp_audio_set_format() to set
// Redundant fields, for convenience
int nch; // number of channels (redundant with chmap)
int bps; // bytes per sample (redundant with format)
};
void mp_audio_set_format(struct mp_audio *mpa, int format);
void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels);
void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels);
void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap);
void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src);
bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b);
char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format);
char *mp_audio_config_to_str(struct mp_audio *mpa);
#endif

486
audio/chmap.c Normal file
View File

@ -0,0 +1,486 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <assert.h>
#include "core/mp_msg.h"
#include "chmap.h"
// Names taken from libavutil/channel_layout.c (Not accessible by API.)
// Use of these names is hard-coded in some places (e.g. ao_alsa.c)
static const char *speaker_names[MP_SPEAKER_ID_COUNT][2] = {
[MP_SPEAKER_ID_FL] = {"fl", "front left"},
[MP_SPEAKER_ID_FR] = {"fr", "front right"},
[MP_SPEAKER_ID_FC] = {"fc", "front center"},
[MP_SPEAKER_ID_LFE] = {"lfe", "low frequency"},
[MP_SPEAKER_ID_BL] = {"bl", "back left"},
[MP_SPEAKER_ID_BR] = {"br", "back right"},
[MP_SPEAKER_ID_FLC] = {"flc", "front left-of-center"},
[MP_SPEAKER_ID_FRC] = {"frc", "front right-of-center"},
[MP_SPEAKER_ID_BC] = {"bc", "back center"},
[MP_SPEAKER_ID_SL] = {"sl", "side left"},
[MP_SPEAKER_ID_SR] = {"sr", "side right"},
[MP_SPEAKER_ID_TC] = {"tc", "top center"},
[MP_SPEAKER_ID_TFL] = {"tfl", "top front left"},
[MP_SPEAKER_ID_TFC] = {"tfc", "top front center"},
[MP_SPEAKER_ID_TFR] = {"tfr", "top front right"},
[MP_SPEAKER_ID_TBL] = {"tbl", "top back left"},
[MP_SPEAKER_ID_TBC] = {"tbc", "top back center"},
[MP_SPEAKER_ID_TBR] = {"tbr", "top back right"},
[MP_SPEAKER_ID_DL] = {"dl", "downmix left"},
[MP_SPEAKER_ID_DR] = {"dr", "downmix right"},
[MP_SPEAKER_ID_WL] = {"wl", "wide left"},
[MP_SPEAKER_ID_WR] = {"wr", "wide right"},
[MP_SPEAKER_ID_SDL] = {"sdl", "surround direct left"},
[MP_SPEAKER_ID_SDR] = {"sdr", "surround direct right"},
[MP_SPEAKER_ID_LFE2] = {"lfe2", "low frequency 2"},
};
// Names taken from libavutil/channel_layout.c (Not accessible by API.)
// Channel order corresponds to lavc/waveex, except for the alsa entries.
static const char *std_layout_names[][2] = {
{"empty", ""}, // not in lavc
{"mono", "fc"},
{"stereo", "fl-fr"},
{"2.1", "fl-fr-lfe"},
{"3.0", "fl-fr-fc"},
{"3.0(back)", "fl-fr-bc"},
{"4.0", "fl-fr-fc-bc"},
{"quad", "fl-fr-bl-br"},
{"quad(side)", "fl-fr-sl-sr"},
{"3.1", "fl-fr-fc-lfe"},
{"5.0", "fl-fr-fc-bl-br"},
{"5.0(alsa)", "fl-fr-bl-br-fc"}, // not in lavc
{"5.0(side)", "fl-fr-fc-sl-sr"},
{"4.1", "fl-fr-fc-lfe-bc"},
{"4.1(alsa)", "fl-fr-bl-br-lfe"}, // not in lavc
{"5.1", "fl-fr-fc-lfe-bl-br"},
{"5.1(alsa)", "fl-fr-bl-br-fc-lfe"}, // not in lavc
{"5.1(side)", "fl-fr-fc-lfe-sl-sr"},
{"6.0", "fl-fr-fc-bc-sl-sr"},
{"6.0(front)", "fl-fr-flc-frc-sl-sr"},
{"hexagonal", "fl-fr-fc-bl-br-bc"},
{"6.1", "fl-fr-fc-lfe-bl-br-bc"},
{"6.1(front)", "fl-fr-lfe-flc-frc-sl-sr"},
{"7.0", "fl-fr-fc-bl-br-sl-sr"},
{"7.0(front)", "fl-fr-fc-flc-frc-sl-sr"},
{"7.1", "fl-fr-fc-lfe-bl-br-sl-sr"},
{"7.1(alsa)", "fl-fr-bl-br-fc-lfe-sl-sr"}, // not in lavc
{"7.1(wide)", "fl-fr-fc-lfe-bl-br-flc-frc"},
{"7.1(wide-side)", "fl-fr-fc-lfe-flc-frc-sl-sr"},
{"octagonal", "fl-fr-fc-bl-br-bc-sl-sr"},
{"downmix", "dl-dr"},
{0}
};
static const struct mp_chmap default_layouts[MP_NUM_CHANNELS + 1] = {
{0}, // empty
MP_CHMAP_INIT_MONO, // mono
MP_CHMAP2(FL, FR), // stereo
MP_CHMAP3(FL, FR, LFE), // 2.1
MP_CHMAP4(FL, FR, FC, BC), // 4.0
MP_CHMAP5(FL, FR, FC, BL, BR), // 5.0
MP_CHMAP6(FL, FR, FC, LFE, BL, BR), // 5.1
MP_CHMAP7(FL, FR, FC, LFE, BL, BR, BC), // 6.1
MP_CHMAP8(FL, FR, FC, LFE, BL, BR, SL, SR), // 7.1
};
// The channel order was lavc/waveex, but differs from lavc for 5, 6 and 8
// channels. 3 and 7 channels were likely undefined (no ALSA support).
static const char *mplayer_layouts[MP_NUM_CHANNELS + 1] = {
[1] = "mono",
[2] = "stereo",
[4] = "4.0",
[5] = "5.0(alsa)",
[6] = "5.1(alsa)",
[8] = "7.1(alsa)",
};
// Returns true if speakers are mapped uniquely, and there's at least 1 channel.
bool mp_chmap_is_valid(const struct mp_chmap *src)
{
bool mapped[MP_SPEAKER_ID_COUNT] = {0};
for (int n = 0; n < src->num; n++) {
int sp = src->speaker[n];
if (sp >= MP_SPEAKER_ID_COUNT || mapped[sp])
return false;
mapped[sp] = true;
}
return src->num > 0;
}
bool mp_chmap_is_empty(const struct mp_chmap *src)
{
return src->num == 0;
}
// Return true if the channel map defines the number of the channels only, and
// the channels have to meaning associated with them.
bool mp_chmap_is_unknown(const struct mp_chmap *src)
{
for (int n = 0; n < src->num; n++) {
int speaker = src->speaker[n];
if (speaker >= MP_SPEAKER_ID_UNKNOWN0 &&
speaker <= MP_SPEAKER_ID_UNKNOWN_LAST)
return true;
}
return false;
}
// Note: empty channel maps compare as equal. Invalid ones can equal too.
bool mp_chmap_equals(const struct mp_chmap *a, const struct mp_chmap *b)
{
if (a->num != b->num)
return false;
for (int n = 0; n < a->num; n++) {
if (a->speaker[n] != b->speaker[n])
return false;
}
return true;
}
// Whether they use the same speakers (even if in different order).
bool mp_chmap_equals_reordered(const struct mp_chmap *a, const struct mp_chmap *b)
{
struct mp_chmap t1 = *a, t2 = *b;
mp_chmap_reorder_norm(&t1);
mp_chmap_reorder_norm(&t2);
return mp_chmap_equals(&t1, &t2);
}
bool mp_chmap_is_compatible(const struct mp_chmap *a, const struct mp_chmap *b)
{
if (mp_chmap_equals(a, b))
return true;
if (a->num == b->num && (mp_chmap_is_unknown(a) || mp_chmap_is_unknown(b)))
return true;
return false;
}
bool mp_chmap_is_stereo(const struct mp_chmap *src)
{
static const struct mp_chmap stereo = MP_CHMAP_INIT_STEREO;
return mp_chmap_equals(src, &stereo);
}
static int comp_uint8(const void *a, const void *b)
{
return *(const uint8_t *)a - *(const uint8_t *)b;
}
// Reorder channels to normal order, with monotonically increasing speaker IDs.
// We define this order as the same order used with waveex.
void mp_chmap_reorder_norm(struct mp_chmap *map)
{
uint8_t *arr = &map->speaker[0];
qsort(arr, map->num, 1, comp_uint8);
}
// Set *dst to a standard layout with the given number of channels.
// If the number of channels is invalid, an invalid map is set, and
// mp_chmap_is_valid(dst) will return false.
void mp_chmap_from_channels(struct mp_chmap *dst, int num_channels)
{
if (num_channels < 0 || num_channels > MP_NUM_CHANNELS) {
*dst = (struct mp_chmap) {0};
} else {
*dst = default_layouts[num_channels];
}
}
// Try to do what mplayer/mplayer2/mpv did before channel layouts were
// introduced, i.e. get the old default channel order.
void mp_chmap_from_channels_alsa(struct mp_chmap *dst, int num_channels)
{
if (num_channels < 0 || num_channels > MP_NUM_CHANNELS) {
*dst = (struct mp_chmap) {0};
} else {
mp_chmap_from_str(dst, bstr0(mplayer_layouts[num_channels]));
if (!dst->num)
mp_chmap_from_channels(dst, num_channels);
}
}
// Set *dst to an unknown layout for the given numbers of channels.
// If the number of channels is invalid, an invalid map is set, and
// mp_chmap_is_valid(dst) will return false.
void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels)
{
if (num_channels < 0 || num_channels > MP_NUM_CHANNELS) {
*dst = (struct mp_chmap) {0};
} else {
dst->num = num_channels;
for (int n = 0; n < dst->num; n++)
dst->speaker[n] = MP_SPEAKER_ID_UNKNOWN0 + n;
}
}
// Return channel index of the given speaker, or -1.
static int mp_chmap_find_speaker(const struct mp_chmap *map, int speaker)
{
for (int n = 0; n < map->num; n++) {
if (map->speaker[n] == speaker)
return n;
}
return -1;
}
static void mp_chmap_remove_speaker(struct mp_chmap *map, int speaker)
{
int index = mp_chmap_find_speaker(map, speaker);
if (index >= 0) {
for (int n = index; n < map->num - 1; n++)
map->speaker[n] = map->speaker[n + 1];
map->num--;
}
}
// Some decoders output additional, redundant channels, which are usually
// useless and will mess up proper audio output channel handling.
// map: channel map from which the channels should be removed
// requested: if not NULL, and if it contains any of the "useless" channels,
// don't remove them (this is for convenience)
void mp_chmap_remove_useless_channels(struct mp_chmap *map,
const struct mp_chmap *requested)
{
if (requested &&
mp_chmap_find_speaker(requested, MP_SPEAKER_ID_DL) >= 0)
return;
if (map->num > 2) {
mp_chmap_remove_speaker(map, MP_SPEAKER_ID_DL);
mp_chmap_remove_speaker(map, MP_SPEAKER_ID_DR);
}
}
// Return the ffmpeg/libav channel layout as in <libavutil/channel_layout.h>.
// Warning: this ignores the order of the channels, and will return a channel
// mask even if the order is different from libavcodec's.
uint64_t mp_chmap_to_lavc_unchecked(const struct mp_chmap *src)
{
// lavc has no concept for unknown layouts yet, so pick a default
struct mp_chmap t = *src;
if (mp_chmap_is_unknown(&t))
mp_chmap_from_channels(&t, t.num);
uint64_t mask = 0;
for (int n = 0; n < t.num; n++)
mask |= 1ULL << t.speaker[n];
return mask;
}
// Return the ffmpeg/libav channel layout as in <libavutil/channel_layout.h>.
// Returns 0 if the channel order doesn't match lavc's or if it's invalid.
uint64_t mp_chmap_to_lavc(const struct mp_chmap *src)
{
if (!mp_chmap_is_lavc(src))
return 0;
return mp_chmap_to_lavc_unchecked(src);
}
// Set channel map from the ffmpeg/libav channel layout as in
// <libavutil/channel_layout.h>.
// If the number of channels exceed MP_NUM_CHANNELS, set dst to empty.
void mp_chmap_from_lavc(struct mp_chmap *dst, uint64_t src)
{
dst->num = 0;
for (int n = 0; n < 64; n++) {
if (src & (1ULL << n)) {
if (dst->num >= MP_NUM_CHANNELS) {
dst->num = 0;
return;
}
dst->speaker[dst->num] = n;
dst->num++;
}
}
}
bool mp_chmap_is_lavc(const struct mp_chmap *src)
{
if (!mp_chmap_is_valid(src))
return false;
if (mp_chmap_is_unknown(src))
return true;
// lavc's channel layout is a bit mask, and channels are always ordered
// from LSB to MSB speaker bits, so speaker IDs have to increase.
assert(src->num > 0);
for (int n = 1; n < src->num; n++) {
if (src->speaker[n - 1] >= src->speaker[n])
return false;
}
for (int n = 0; n < src->num; n++) {
if (src->speaker[n] >= 64)
return false;
}
return true;
}
void mp_chmap_reorder_to_lavc(struct mp_chmap *map)
{
if (!mp_chmap_is_valid(map))
return;
uint64_t mask = mp_chmap_to_lavc_unchecked(map);
mp_chmap_from_lavc(map, mask);
}
// Get reordering array for from->to reordering. from->to must have the same set
// of speakers (i.e. same number and speaker IDs, just different order). Then,
// for each speaker n, dst[n] will be set such that:
// to->speaker[dst[n]] = from->speaker[n]
// (dst[n] gives the source channel for destination channel n)
void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
const struct mp_chmap *to)
{
assert(from->num == to->num);
if (mp_chmap_is_unknown(from) || mp_chmap_is_unknown(to)) {
for (int n = 0; n < from->num; n++)
dst[n] = n;
return;
}
// Same set of speakers required
assert(mp_chmap_equals_reordered(from, to));
for (int n = 0; n < from->num; n++) {
int src = from->speaker[n];
dst[n] = -1;
for (int i = 0; i < to->num; i++) {
if (src == to->speaker[i]) {
dst[n] = i;
break;
}
}
assert(dst[n] != -1);
}
for (int n = 0; n < from->num; n++)
assert(to->speaker[dst[n]] == from->speaker[n]);
}
// Returns something like "fl-fr-fc". If there's a standard layout in lavc
// order, return that, e.g. "3.0" instead of "fl-fr-fc".
// Unassigned but valid speakers get names like "sp28".
char *mp_chmap_to_str(const struct mp_chmap *src)
{
char *res = talloc_strdup(NULL, "");
if (mp_chmap_is_unknown(src))
return talloc_asprintf_append_buffer(res, "unknown%d", src->num);
for (int n = 0; n < src->num; n++) {
int sp = src->speaker[n];
const char *s = sp < MP_SPEAKER_ID_COUNT ? speaker_names[sp][0] : NULL;
char buf[10];
if (!s) {
snprintf(buf, sizeof(buf), "sp%d", sp);
s = buf;
}
res = talloc_asprintf_append_buffer(res, "%s%s", n > 0 ? "-" : "", s);
}
// To standard layout name
for (int n = 0; std_layout_names[n][0]; n++) {
if (res && strcmp(res, std_layout_names[n][1]) == 0) {
talloc_free(res);
res = talloc_strdup(NULL, std_layout_names[n][0]);
break;
}
}
return res;
}
// If src can be parsed as channel map (as produced by mp_chmap_to_str()),
// return true and set *dst. Otherwise, return false and don't change *dst.
// Note: call mp_chmap_is_valid() to test whether the returned map is valid
// the map could be empty, or contain multiply mapped channels
bool mp_chmap_from_str(struct mp_chmap *dst, bstr src)
{
// Single number corresponds to mp_chmap_from_channels()
if (src.len > 0) {
bstr t = src;
bool unknown = bstr_eatstart0(&t, "unknown");
bstr rest;
long long count = bstrtoll(t, &rest, 10);
if (rest.len == 0) {
struct mp_chmap res;
if (unknown) {
mp_chmap_set_unknown(&res, count);
} else {
mp_chmap_from_channels(&res, count);
}
if (mp_chmap_is_valid(&res)) {
*dst = res;
return true;
}
}
}
// From standard layout name
for (int n = 0; std_layout_names[n][0]; n++) {
if (bstr_equals0(src, std_layout_names[n][0])) {
src = bstr0(std_layout_names[n][1]);
break;
}
}
// Explicit speaker list (separated by "-")
struct mp_chmap res = {0};
while (src.len) {
bstr s;
bstr_split_tok(src, "-", &s, &src);
int speaker = -1;
for (int n = 0; n < MP_SPEAKER_ID_COUNT; n++) {
const char *name = speaker_names[n][0];
if (name && bstr_equals0(s, name)) {
speaker = n;
break;
}
}
if (speaker < 0) {
if (bstr_eatstart0(&s, "sp")) {
long long sp = bstrtoll(s, &s, 0);
if (s.len == 0 && sp >= 0 && sp < MP_SPEAKER_ID_COUNT)
speaker = sp;
}
if (speaker < 0)
return false;
}
if (res.num >= MP_NUM_CHANNELS)
return false;
res.speaker[res.num] = speaker;
res.num++;
}
*dst = res;
return true;
}
void mp_chmap_print_help(int msgt, int msgl)
{
mp_msg(msgt, msgl, "Speakers:\n");
for (int n = 0; n < MP_SPEAKER_ID_COUNT; n++) {
if (speaker_names[n][0])
mp_msg(msgt, msgl, " %-16s (%s)\n",
speaker_names[n][0], speaker_names[n][1]);
}
mp_msg(msgt, msgl, "Standard layouts:\n");
for (int n = 0; std_layout_names[n][0]; n++) {
mp_msg(msgt, msgl, " %-16s (%s)\n",
std_layout_names[n][0], std_layout_names[n][1]);
}
for (int n = 0; n < MP_NUM_CHANNELS; n++)
mp_msg(msgt, msgl, " unknown%d\n", n);
}

132
audio/chmap.h Normal file
View File

@ -0,0 +1,132 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MP_CHMAP_H
#define MP_CHMAP_H
#include <inttypes.h>
#include <stdbool.h>
#include "core/bstr.h"
#define MP_NUM_CHANNELS 8
// Speaker a channel can be assigned to.
// This corresponds to WAVEFORMATEXTENSIBLE channel mask bit indexes.
// E.g. channel_mask = (1 << MP_SPEAKER_ID_FL) | ...
enum {
// Official WAVEFORMATEXTENSIBLE (shortened names)
MP_SPEAKER_ID_FL = 0, // FRONT_LEFT
MP_SPEAKER_ID_FR, // FRONT_RIGHT
MP_SPEAKER_ID_FC, // FRONT_CENTER
MP_SPEAKER_ID_LFE, // LOW_FREQUENCY
MP_SPEAKER_ID_BL, // BACK_LEFT
MP_SPEAKER_ID_BR, // BACK_RIGHT
MP_SPEAKER_ID_FLC, // FRONT_LEFT_OF_CENTER
MP_SPEAKER_ID_FRC, // FRONT_RIGHT_OF_CENTER
MP_SPEAKER_ID_BC, // BACK_CENTER
MP_SPEAKER_ID_SL, // SIDE_LEFT
MP_SPEAKER_ID_SR, // SIDE_RIGHT
MP_SPEAKER_ID_TC, // TOP_CENTER
MP_SPEAKER_ID_TFL, // TOP_FRONT_LEFT
MP_SPEAKER_ID_TFC, // TOP_FRONT_CENTER
MP_SPEAKER_ID_TFR, // TOP_FRONT_RIGHT
MP_SPEAKER_ID_TBL, // TOP_BACK_LEFT
MP_SPEAKER_ID_TBC, // TOP_BACK_CENTER
MP_SPEAKER_ID_TBR, // TOP_BACK_RIGHT
// Inofficial/libav* extensions
MP_SPEAKER_ID_DL = 29, // STEREO_LEFT (stereo downmix special speakers)
MP_SPEAKER_ID_DR, // STEREO_RIGHT
MP_SPEAKER_ID_WL, // WIDE_LEFT
MP_SPEAKER_ID_WR, // WIDE_RIGHT
MP_SPEAKER_ID_SDL, // SURROUND_DIRECT_LEFT
MP_SPEAKER_ID_SDR, // SURROUND_DIRECT_RIGHT
MP_SPEAKER_ID_LFE2, // LOW_FREQUENCY_2
// Special mpv-specific speaker entries reserved for channels which have no
// known meaning.
MP_SPEAKER_ID_UNKNOWN0 = 64,
MP_SPEAKER_ID_UNKNOWN_LAST = MP_SPEAKER_ID_UNKNOWN0 + MP_NUM_CHANNELS - 1,
// Including the unassigned IDs in between. This is not a valid ID anymore.
MP_SPEAKER_ID_COUNT,
};
struct mp_chmap {
uint8_t num; // number of channels
// Given a channel n, speaker[n] is the speaker ID driven by that channel.
// Entries after speaker[num - 1] are undefined.
uint8_t speaker[MP_NUM_CHANNELS];
};
#define MP_SP(speaker) MP_SPEAKER_ID_ ## speaker
#define MP_CHMAP2(a, b) \
{2, {MP_SP(a), MP_SP(b)}}
#define MP_CHMAP3(a, b, c) \
{3, {MP_SP(a), MP_SP(b), MP_SP(c)}}
#define MP_CHMAP4(a, b, c, d) \
{4, {MP_SP(a), MP_SP(b), MP_SP(c), MP_SP(d)}}
#define MP_CHMAP5(a, b, c, d, e) \
{5, {MP_SP(a), MP_SP(b), MP_SP(c), MP_SP(d), MP_SP(e)}}
#define MP_CHMAP6(a, b, c, d, e, f) \
{6, {MP_SP(a), MP_SP(b), MP_SP(c), MP_SP(d), MP_SP(e), MP_SP(f)}}
#define MP_CHMAP7(a, b, c, d, e, f, g) \
{7, {MP_SP(a), MP_SP(b), MP_SP(c), MP_SP(d), MP_SP(e), MP_SP(f), MP_SP(g)}}
#define MP_CHMAP8(a, b, c, d, e, f, g, h) \
{8, {MP_SP(a), MP_SP(b), MP_SP(c), MP_SP(d), MP_SP(e), MP_SP(f), MP_SP(g), MP_SP(h)}}
#define MP_CHMAP_INIT_MONO {1, {MP_SPEAKER_ID_FC}}
#define MP_CHMAP_INIT_STEREO MP_CHMAP2(FL, FR)
bool mp_chmap_is_valid(const struct mp_chmap *src);
bool mp_chmap_is_empty(const struct mp_chmap *src);
bool mp_chmap_is_unknown(const struct mp_chmap *src);
bool mp_chmap_equals(const struct mp_chmap *a, const struct mp_chmap *b);
bool mp_chmap_equals_reordered(const struct mp_chmap *a, const struct mp_chmap *b);
bool mp_chmap_is_compatible(const struct mp_chmap *a, const struct mp_chmap *b);
bool mp_chmap_is_stereo(const struct mp_chmap *src);
void mp_chmap_reorder_norm(struct mp_chmap *map);
void mp_chmap_from_channels(struct mp_chmap *dst, int num_channels);
void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels);
void mp_chmap_from_channels_alsa(struct mp_chmap *dst, int num_channels);
void mp_chmap_remove_useless_channels(struct mp_chmap *map,
const struct mp_chmap *requested);
uint64_t mp_chmap_to_lavc(const struct mp_chmap *src);
uint64_t mp_chmap_to_lavc_unchecked(const struct mp_chmap *src);
void mp_chmap_from_lavc(struct mp_chmap *dst, uint64_t src);
bool mp_chmap_is_lavc(const struct mp_chmap *src);
void mp_chmap_reorder_to_lavc(struct mp_chmap *map);
void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
const struct mp_chmap *to);
char *mp_chmap_to_str(const struct mp_chmap *src);
bool mp_chmap_from_str(struct mp_chmap *dst, bstr src);
void mp_chmap_print_help(int msgt, int msgl);
// Use these to avoid chaos in case lavc's definition should diverge from MS.
#define mp_chmap_to_waveext mp_chmap_to_lavc
#define mp_chmap_from_waveext mp_chmap_from_lavc
#define mp_chmap_is_waveext mp_chmap_is_lavc
#define mp_chmap_reorder_to_waveext mp_chmap_reorder_to_lavc
#endif

210
audio/chmap_sel.c Normal file
View File

@ -0,0 +1,210 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <assert.h>
#include "chmap_sel.h"
// 5.1 and 5.1(side) are practically the same. It doesn't make much sense to
// reject either of them.
static const int replaceable_speakers[][2] = {
{MP_SPEAKER_ID_SL, MP_SPEAKER_ID_BL},
{MP_SPEAKER_ID_SR, MP_SPEAKER_ID_BR},
{-1},
};
// list[] contains a list of speaker pairs, with each pair indicating how
// a speaker can be swapped for another speaker. Try to replace speakers from
// the left of the list with the ones on the right, or the other way around.
static bool replace_speakers(struct mp_chmap *map, const int list[][2])
{
if (!mp_chmap_is_valid(map))
return false;
for (int dir = 0; dir < 2; dir++) {
int from = dir ? 0 : 1;
int to = dir ? 1 : 0;
bool replaced = false;
struct mp_chmap t = *map;
for (int n = 0; n < t.num; n++) {
for (int i = 0; list[i][0] != -1; i++) {
if (t.speaker[n] == list[i][from]) {
t.speaker[n] = list[i][to];
replaced = true;
break;
}
}
}
if (replaced && mp_chmap_is_valid(&t)) {
*map = t;
return true;
}
}
return false;
}
// Allow all channel layouts that can be expressed with mp_chmap.
// (By default, all layouts are rejected.)
void mp_chmap_sel_add_any(struct mp_chmap_sel *s)
{
s->allow_any = true;
}
// Allow all waveext formats, and force waveext channel order.
void mp_chmap_sel_add_waveext(struct mp_chmap_sel *s)
{
s->allow_waveext = true;
}
void mp_chmap_sel_add_alsa_def(struct mp_chmap_sel *s)
{
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
struct mp_chmap t;
mp_chmap_from_channels_alsa(&t, n);
if (t.num)
mp_chmap_sel_add_map(s, &t);
}
}
#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0]))
// Add a channel map that should be allowed.
void mp_chmap_sel_add_map(struct mp_chmap_sel *s, const struct mp_chmap *map)
{
assert(s->num_chmaps < ARRAY_LEN(s->chmaps));
if (mp_chmap_is_valid(map))
s->chmaps[s->num_chmaps++] = *map;
}
// Allow all waveext formats in default order.
void mp_chmap_sel_add_waveext_def(struct mp_chmap_sel *s)
{
for (int n = 1; n < MP_NUM_CHANNELS; n++) {
struct mp_chmap map;
mp_chmap_from_channels(&map, n);
mp_chmap_sel_add_map(s, &map);
}
}
// Whitelist a speaker (MP_SPEAKER_ID_...). All layouts that contain whitelisted
// speakers are allowed.
void mp_chmap_sel_add_speaker(struct mp_chmap_sel *s, int id)
{
assert(id >= 0 && id < MP_SPEAKER_ID_COUNT);
s->speakers[id] = true;
}
static bool test_speakers(const struct mp_chmap_sel *s, struct mp_chmap *map)
{
for (int n = 0; n < map->num; n++) {
if (!s->speakers[map->speaker[n]])
return false;
}
return true;
}
static bool test_maps(const struct mp_chmap_sel *s, struct mp_chmap *map)
{
for (int n = 0; n < s->num_chmaps; n++) {
if (mp_chmap_equals_reordered(&s->chmaps[n], map)) {
*map = s->chmaps[n];
return true;
}
}
return false;
}
static bool test_waveext(const struct mp_chmap_sel *s, struct mp_chmap *map)
{
if (s->allow_waveext) {
struct mp_chmap t = *map;
mp_chmap_reorder_to_waveext(&t);
if (mp_chmap_is_waveext(&t)) {
*map = t;
return true;
}
}
return false;
}
static bool test_layout(const struct mp_chmap_sel *s, struct mp_chmap *map)
{
if (!mp_chmap_is_valid(map))
return false;
return s->allow_any || test_waveext(s, map) || test_speakers(s, map) ||
test_maps(s, map);
}
// Determine which channel map to use given a source channel map, and various
// parameters restricting possible choices. If the map doesn't match, select
// a fallback and set it.
// If no matching layout is found, a reordered layout may be returned.
// If that is not possible, a fallback for up/downmixing may be returned.
// If no choice is possible, set *map to empty.
bool mp_chmap_sel_adjust(const struct mp_chmap_sel *s, struct mp_chmap *map)
{
if (test_layout(s, map))
return true;
if (mp_chmap_is_unknown(map)) {
struct mp_chmap t = {0};
if (mp_chmap_sel_get_def(s, &t, map->num) && test_layout(s, &t)) {
*map = t;
return true;
}
}
// 5.1 <-> 5.1(side)
if (replace_speakers(map, replaceable_speakers) && test_layout(s, map))
return true;
// Fallback to mono/stereo as last resort
if (map->num == 1) {
*map = (struct mp_chmap) MP_CHMAP_INIT_MONO;
} else if (map->num >= 2) {
*map = (struct mp_chmap) MP_CHMAP_INIT_STEREO;
}
if (test_layout(s, map))
return true;
*map = (struct mp_chmap) {0};
return false;
}
// Set map to a default layout with num channels. Used for audio APIs that
// return a channel count as part of format negotiation, but give no
// information about the channel layout.
// If the channel count is correct, do nothing and leave *map untouched.
bool mp_chmap_sel_get_def(const struct mp_chmap_sel *s, struct mp_chmap *map,
int num)
{
if (map->num != num) {
*map = (struct mp_chmap) {0};
// Set of speakers or waveext might allow it.
struct mp_chmap t;
mp_chmap_from_channels(&t, num);
mp_chmap_reorder_to_waveext(&t);
if (test_layout(s, &t)) {
*map = t;
} else {
for (int n = 0; n < s->num_chmaps; n++) {
if (s->chmaps[n].num == num) {
*map = s->chmaps[n];
break;
}
}
}
}
return map->num > 0;
}

43
audio/chmap_sel.h Normal file
View File

@ -0,0 +1,43 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MP_CHMAP_SEL_H
#define MP_CHMAP_SEL_H
#include <stdbool.h>
#include "chmap.h"
struct mp_chmap_sel {
// should be considered opaque
bool allow_any, allow_waveext;
bool speakers[MP_SPEAKER_ID_COUNT];
struct mp_chmap chmaps[20];
int num_chmaps;
};
void mp_chmap_sel_add_any(struct mp_chmap_sel *s);
void mp_chmap_sel_add_waveext(struct mp_chmap_sel *s);
void mp_chmap_sel_add_waveext_def(struct mp_chmap_sel *s);
void mp_chmap_sel_add_alsa_def(struct mp_chmap_sel *s);
void mp_chmap_sel_add_map(struct mp_chmap_sel *s, const struct mp_chmap *map);
void mp_chmap_sel_add_speaker(struct mp_chmap_sel *s, int id);
bool mp_chmap_sel_adjust(const struct mp_chmap_sel *s, struct mp_chmap *map);
bool mp_chmap_sel_get_def(const struct mp_chmap_sel *s, struct mp_chmap *map,
int num);
#endif

View File

@ -48,10 +48,4 @@ extern const ad_functions_t * const mpcodecs_ad_drivers[];
// fallback if ADCTRL_SKIP not implemented: ds_fill_buffer(sh_audio->ds);
#define ADCTRL_SKIP_FRAME 2 // skip block/frame, called while seeking
// fallback if ADCTRL_QUERY_FORMAT not implemented: sh_audio->sample_format
#define ADCTRL_QUERY_FORMAT 3 // test for availabilty of a format
// fallback: use hw mixer in libao
#define ADCTRL_SET_VOLUME 4 // not used at the moment
#endif /* MPLAYER_AD_H */

View File

@ -32,9 +32,11 @@
#include "core/codecs.h"
#include "core/mp_msg.h"
#include "core/options.h"
#include "core/av_opts.h"
#include "ad_internal.h"
#include "audio/reorder_ch.h"
#include "audio/fmt-conversion.h"
#include "compat/mpbswap.h"
#include "compat/libav.h"
@ -49,6 +51,16 @@ struct priv {
int output_left;
int unitsize;
int previous_data_left; // input demuxer packet data
bool force_channel_map;
};
#define OPT_BASE_STRUCT struct MPOpts
const m_option_t ad_lavc_decode_opts_conf[] = {
OPT_FLOATRANGE("ac3drc", ad_lavc_param.ac3drc, 0, 0, 2),
OPT_FLAG("downmix", ad_lavc_param.downmix, 0),
OPT_STRING("o", ad_lavc_param.avopt, 0),
{0}
};
struct pcm_map
@ -144,17 +156,9 @@ static int preinit(sh_audio_t *sh)
static int setup_format(sh_audio_t *sh_audio,
const AVCodecContext *lavc_context)
{
int sample_format = sh_audio->sample_format;
switch (av_get_packed_sample_fmt(lavc_context->sample_fmt)) {
case AV_SAMPLE_FMT_U8: sample_format = AF_FORMAT_U8; break;
case AV_SAMPLE_FMT_S16: sample_format = AF_FORMAT_S16_NE; break;
case AV_SAMPLE_FMT_S32: sample_format = AF_FORMAT_S32_NE; break;
case AV_SAMPLE_FMT_FLT: sample_format = AF_FORMAT_FLOAT_NE; break;
default:
mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "Unsupported sample format\n");
sample_format = AF_FORMAT_UNKNOWN;
}
struct priv *priv = sh_audio->context;
int sample_format =
af_from_avformat(av_get_packed_sample_fmt(lavc_context->sample_fmt));
bool broken_srate = false;
int samplerate = lavc_context->sample_rate;
int container_samplerate = sh_audio->container_out_samplerate;
@ -166,10 +170,20 @@ 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 (priv->force_channel_map) {
if (lavc_chmap.num == sh_audio->channels.num)
lavc_chmap = sh_audio->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;
@ -198,41 +212,59 @@ static void set_from_wf(AVCodecContext *avctx, WAVEFORMATEX *wf)
static int init(sh_audio_t *sh_audio, const char *decoder)
{
struct MPOpts *opts = sh_audio->opts;
struct MPOpts *mpopts = sh_audio->opts;
struct ad_lavc_param *opts = &mpopts->ad_lavc_param;
AVCodecContext *lavc_context;
AVCodec *lavc_codec;
struct priv *ctx = talloc_zero(NULL, struct priv);
sh_audio->context = ctx;
if (sh_audio->wf && strcmp(decoder, "pcm") == 0) {
decoder = find_pcm_decoder(tag_map, sh_audio->format,
sh_audio->wf->wBitsPerSample);
} else if (sh_audio->wf && strcmp(decoder, "mp-pcm") == 0) {
decoder = find_pcm_decoder(af_map, sh_audio->format, 0);
ctx->force_channel_map = true;
}
lavc_codec = avcodec_find_decoder_by_name(decoder);
if (!lavc_codec) {
mp_tmsg(MSGT_DECAUDIO, MSGL_ERR,
"Cannot find codec '%s' in libavcodec...\n", decoder);
uninit(sh_audio);
return 0;
}
struct priv *ctx = talloc_zero(NULL, struct priv);
sh_audio->context = ctx;
lavc_context = avcodec_alloc_context3(lavc_codec);
ctx->avctx = lavc_context;
ctx->avframe = avcodec_alloc_frame();
lavc_context->codec_type = AVMEDIA_TYPE_AUDIO;
lavc_context->codec_id = lavc_codec->id;
lavc_context->request_channels = opts->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->drc_level,
av_opt_set_double(lavc_context, "drc_scale", opts->ac3drc,
AV_OPT_SEARCH_CHILDREN);
if (opts->avopt) {
if (parse_avopts(lavc_context, opts->avopt) < 0) {
mp_msg(MSGT_DECVIDEO, MSGL_ERR,
"ad_lavc: setting AVOptions '%s' failed.\n", opts->avopt);
uninit(sh_audio);
return 0;
}
}
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);
@ -279,13 +311,9 @@ static int init(sh_audio_t *sh_audio, const char *decoder)
if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec)
sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec;
switch (av_get_packed_sample_fmt(lavc_context->sample_fmt)) {
case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S32:
case AV_SAMPLE_FMT_FLT:
break;
default:
int af_sample_fmt =
af_from_avformat(av_get_packed_sample_fmt(lavc_context->sample_fmt));
if (af_sample_fmt == AF_FORMAT_UNKNOWN) {
uninit(sh_audio);
return 0;
}
@ -442,13 +470,6 @@ static int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen,
memcpy(buf, priv->output, size);
priv->output += size;
priv->output_left -= size;
if (avctx->channels >= 5) {
int samplesize = av_get_bytes_per_sample(avctx->sample_fmt);
reorder_channel_nch(buf, AF_CHANNEL_LAYOUT_LAVC_DEFAULT,
AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
avctx->channels,
size / samplesize, samplesize);
}
if (len < 0)
len = size;
else

View File

@ -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.

View File

@ -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;

View File

@ -41,22 +41,14 @@
int fakemono = 0;
struct af_cfg af_cfg = {1, NULL}; // Configuration for audio filters
struct af_cfg af_cfg = {0}; // Configuration for audio filters
static int init_audio_codec(sh_audio_t *sh_audio, const char *decoder)
{
assert(!sh_audio->initialized);
resync_audio_stream(sh_audio);
sh_audio->samplesize = 2;
sh_audio->sample_format = AF_FORMAT_S16_NE;
if ((af_cfg.force & AF_INIT_FORMAT_MASK) == AF_INIT_FLOAT) {
int fmt = AF_FORMAT_FLOAT_NE;
if (sh_audio->ad_driver->control(sh_audio, ADCTRL_QUERY_FORMAT,
&fmt) == CONTROL_TRUE) {
sh_audio->sample_format = fmt;
sh_audio->samplesize = 4;
}
}
sh_audio->samplesize = 4;
sh_audio->sample_format = AF_FORMAT_FLOAT_NE;
sh_audio->audio_out_minsize = 8192; // default, preinit() may change it
if (!sh_audio->ad_driver->preinit(sh_audio)) {
mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder preinit failed.\n");
@ -94,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
@ -102,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;
}
@ -168,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",
@ -191,7 +183,7 @@ void uninit_audio(sh_audio_t *sh_audio)
if (sh_audio->afilter) {
mp_msg(MSGT_DECAUDIO, MSGL_V, "Uninit audio filters...\n");
af_uninit(sh_audio->afilter);
free(sh_audio->afilter);
af_destroy(sh_audio->afilter);
sh_audio->afilter = NULL;
}
if (sh_audio->initialized) {
@ -207,43 +199,41 @@ void uninit_audio(sh_audio_t *sh_audio)
int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
int *out_samplerate, int *out_channels, int *out_format)
int *out_samplerate, struct mp_chmap *out_channels,
int *out_format)
{
struct af_stream *afs = sh_audio->afilter;
if (!afs) {
afs = calloc(1, sizeof(struct af_stream));
afs->opts = sh_audio->opts;
}
if (!afs)
afs = af_new(sh_audio->opts);
// input format: same as codec's output format:
afs->input.rate = in_samplerate;
afs->input.nch = sh_audio->channels;
afs->input.format = sh_audio->sample_format;
af_fix_parameters(&(afs->input));
afs->input.rate = in_samplerate;
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)
afs->output.rate = *out_samplerate;
afs->output.nch = *out_channels;
afs->output.format = *out_format;
af_fix_parameters(&(afs->output));
afs->output.rate = *out_samplerate;
mp_audio_set_channels(&afs->output, out_channels);
mp_audio_set_format(&afs->output, *out_format);
// filter config:
memcpy(&afs->cfg, &af_cfg, sizeof(struct af_cfg));
char *s_from = mp_audio_config_to_str(&afs->input);
char *s_to = mp_audio_config_to_str(&afs->output);
mp_tmsg(MSGT_DECAUDIO, MSGL_V,
"Building audio filter chain for %dHz/%dch/%s -> %dHz/%dch/%s...\n",
afs->input.rate, afs->input.nch,
af_fmt2str_short(afs->input.format), afs->output.rate,
afs->output.nch, af_fmt2str_short(afs->output.format));
"Building audio filter chain for %s -> %s...\n", s_from, s_to);
talloc_free(s_from);
talloc_free(s_to);
// let's autoprobe it!
if (0 != af_init(afs)) {
sh_audio->afilter = NULL;
free(afs);
af_destroy(afs);
return 0; // failed :(
}
*out_samplerate = afs->output.rate;
*out_channels = afs->output.nch;
*out_channels = afs->output.channels;
*out_format = afs->output.format;
// ok!
@ -270,7 +260,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;
@ -278,7 +268,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;
@ -294,10 +284,10 @@ static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len)
.audio = sh->a_buffer,
.len = len,
.rate = sh->samplerate,
.nch = sh->channels,
.format = sh->sample_format
};
af_fix_parameters(&filter_input);
mp_audio_set_format(&filter_input, sh->sample_format);
mp_audio_set_channels(&filter_input, &sh->channels);
struct mp_audio *filter_output = af_play(sh->afilter, &filter_input);
if (!filter_output)
return -1;
@ -325,7 +315,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

View File

@ -19,6 +19,7 @@
#ifndef MPLAYER_DEC_AUDIO_H
#define MPLAYER_DEC_AUDIO_H
#include "audio/chmap.h"
#include "demux/stheader.h"
struct bstr;
@ -33,6 +34,7 @@ void skip_audio_frame(sh_audio_t *sh_audio);
void uninit_audio(sh_audio_t *sh_audio);
int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
int *out_samplerate, int *out_channels, int *out_format);
int *out_samplerate, struct mp_chmap *out_channels,
int *out_format);
#endif /* MPLAYER_DEC_AUDIO_H */

File diff suppressed because it is too large Load Diff

View File

@ -20,31 +20,21 @@
#define MPLAYER_AF_H
#include <stdio.h>
#include <stdbool.h>
#include "config.h"
#include "core/options.h"
#include "audio/format.h"
#include "audio/chmap.h"
#include "audio/audio.h"
#include "control.h"
#include "core/mp_msg.h"
struct af_instance;
// Number of channels
#ifndef AF_NCH
#define AF_NCH 8
#endif
// Audio data chunk
struct mp_audio {
void *audio; // data buffer
int len; // buffer length
int rate; // sample rate
int nch; // number of channels
int format; // format
int bps; // bytes per sample
};
#define AF_NCH MP_NUM_CHANNELS
// Flags used for defining the behavior of an audio filter
#define AF_FLAGS_REENTRANT 0x00000000
@ -59,6 +49,7 @@ struct af_info {
const char *comment;
const int flags;
int (*open)(struct af_instance *vf);
bool (*test_conversion)(int src_format, int dst_format);
};
// Linked list of audio filters
@ -75,29 +66,11 @@ struct af_instance {
* corresponding output */
double mul; /* length multiplier: how much does this instance change
the length of the buffer. */
bool auto_inserted; // inserted by af.c, such as conversion filters
};
// Initialization flags
extern int *af_cpu_speed;
#define AF_INIT_AUTO 0x00000000
#define AF_INIT_SLOW 0x00000001
#define AF_INIT_FAST 0x00000002
#define AF_INIT_FORCE 0x00000003
#define AF_INIT_TYPE_MASK 0x00000003
#define AF_INIT_INT 0x00000000
#define AF_INIT_FLOAT 0x00000004
#define AF_INIT_FORMAT_MASK 0x00000004
// Default init type
#ifndef AF_INIT_TYPE
#define AF_INIT_TYPE (af_cpu_speed ? *af_cpu_speed : AF_INIT_SLOW)
#endif
// Configuration switches
struct af_cfg {
int force; // Initialization type
char **list; /* list of names of filters that are added to filter
list during first initialization of stream */
};
@ -107,9 +80,12 @@ struct af_stream {
// The first and last filter in the list
struct af_instance *first;
struct af_instance *last;
// Storage for input and output data formats
// The user sets the input format (what the decoder outputs), and sets some
// or all fields in output to the output format the AO accepts.
// See fixup_output_format().
struct mp_audio input;
struct mp_audio output;
struct mp_audio filter_output;
// Configuration for this stream
struct af_cfg cfg;
struct MPOpts *opts;
@ -139,6 +115,9 @@ struct af_stream {
* \param s filter chain
*/
struct af_stream *af_new(struct MPOpts *opts);
void af_destroy(struct af_stream *s);
/**
* \brief Initialize the stream "s".
* \return 0 on success, -1 on failure
@ -161,10 +140,10 @@ void af_uninit(struct af_stream *s);
/**
* \brief Reinit the filter list from the given filter on downwards
* \param Filter instance to begin the reinit from
* See af.c.
* \return AF_OK on success or AF_ERROR on failure
*/
int af_reinit(struct af_stream *s, struct af_instance *af);
int af_reinit(struct af_stream *s);
/**
* \brief This function adds the filter "name" to the stream s.
@ -306,23 +285,13 @@ float af_softclip(float a);
/** Print a list of all available audio filters */
void af_help(void);
/**
* \brief fill the missing parameters in the struct mp_audio structure
* \param data structure to fill
* \ingroup af_filter
*
* Currently only sets bps based on format
*/
void af_fix_parameters(struct mp_audio *data);
/** Memory reallocation macro: if a local buffer is used (i.e. if the
filter doesn't operate on the incoming buffer this macro must be
called to ensure the buffer is big enough.
* \ingroup af_filter
*/
#define RESIZE_LOCAL_BUFFER(a, d) \
((a->data->len < \
af_lencalc(a->mul, d)) ? af_resize_local_buffer(a, d) : AF_OK)
((a->data->len < af_lencalc(a->mul, d)) ? af_resize_local_buffer(a, d) : AF_OK)
/* Some other useful macro definitions*/
#ifndef min

View File

@ -105,9 +105,8 @@ static int control(struct af_instance *af, int cmd, void *arg)
format = ((struct mp_audio*)arg)->format;
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = 2; // bs2b is useful only for 2ch audio
af->data->bps = ((struct mp_audio*)arg)->bps;
af->data->format = format;
mp_audio_set_num_channels(af->data, 2); // bs2b is useful only for 2ch audio
mp_audio_set_format(af->data, format);
/* check for formats supported by libbs2b
and assign corresponding handlers */
@ -162,8 +161,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
break;
default:
af->play = play_f;
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
break;
}

View File

@ -48,9 +48,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = max(s->ch+1,((struct mp_audio*)arg)->nch);
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
mp_audio_set_channels_old(af->data, max(s->ch+1,((struct mp_audio*)arg)->nch));
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
return af_test_output(af,(struct mp_audio*)arg);
}

View File

@ -164,8 +164,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
}
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->format = ((struct mp_audio*)arg)->format;
af->data->bps = ((struct mp_audio*)arg)->bps;
mp_audio_set_format(af->data, ((struct mp_audio*)arg)->format);
af->mul = (double)af->data->nch / ((struct mp_audio*)arg)->nch;
return check_routes(s,((struct mp_audio*)arg)->nch,af->data->nch);
case AF_CONTROL_COMMAND_LINE:{
@ -194,54 +193,20 @@ static int control(struct af_instance* af, int cmd, void* arg)
}
}
if(AF_OK != af->control(af,AF_CONTROL_CHANNELS | AF_CONTROL_SET ,&nch))
struct mp_chmap chmap;
mp_chmap_from_channels(&chmap, nch);
if (AF_OK != af->control(af, AF_CONTROL_CHANNELS | AF_CONTROL_SET, &chmap))
return AF_ERROR;
return AF_OK;
}
case AF_CONTROL_CHANNELS | AF_CONTROL_SET:
// Reinit must be called after this function has been called
// Sanity check
if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){
mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] The number of output channels must be"
" between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
return AF_ERROR;
}
af->data->nch=((int*)arg)[0];
mp_audio_set_channels(af->data, (struct mp_chmap *)arg);
if(!s->router)
mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Changing number of channels"
" to %i\n",af->data->nch);
return AF_OK;
case AF_CONTROL_CHANNELS | AF_CONTROL_GET:
*(int*)arg = af->data->nch;
return AF_OK;
case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_SET:{
int ch = ((af_control_ext_t*)arg)->ch;
int* route = ((af_control_ext_t*)arg)->arg;
s->route[ch][FR] = route[FR];
s->route[ch][TO] = route[TO];
return AF_OK;
}
case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_GET:{
int ch = ((af_control_ext_t*)arg)->ch;
int* route = ((af_control_ext_t*)arg)->arg;
route[FR] = s->route[ch][FR];
route[TO] = s->route[ch][TO];
return AF_OK;
}
case AF_CONTROL_CHANNELS_NR | AF_CONTROL_SET:
s->nr = *(int*)arg;
return AF_OK;
case AF_CONTROL_CHANNELS_NR | AF_CONTROL_GET:
*(int*)arg = s->nr;
return AF_OK;
case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_SET:
s->router = *(int*)arg;
return AF_OK;
case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_GET:
*(int*)arg = s->router;
return AF_OK;
}
return AF_UNKNOWN;
}
@ -277,7 +242,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
// Set output data
c->audio = l->audio;
c->len = c->len / c->nch * l->nch;
c->nch = l->nch;
mp_audio_set_channels(c, &l->channels);
return c;
}

View File

@ -52,10 +52,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
for(i=0;i<af->data->nch;i++)
free(s->q[i]);
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = ((struct mp_audio*)arg)->nch;
af->data->format = ((struct mp_audio*)arg)->format;
af->data->bps = ((struct mp_audio*)arg)->bps;
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
// Allocate new delay queues
for(i=0;i<af->data->nch;i++){

View File

@ -87,15 +87,10 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = ((struct mp_audio*)arg)->nch;
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
if(((struct mp_audio*)arg)->format == (AF_FORMAT_S16_NE)){
af->data->format = AF_FORMAT_S16_NE;
af->data->bps = 2;
}else{
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
if(((struct mp_audio*)arg)->format != (AF_FORMAT_S16_NE)){
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
}
return af_test_output(af,(struct mp_audio*)arg);
case AF_CONTROL_COMMAND_LINE:{

View File

@ -29,8 +29,8 @@
static int control(struct af_instance* af, int cmd, void* arg)
{
switch(cmd){
case AF_CONTROL_REINIT:
memcpy(af->data,(struct mp_audio*)arg,sizeof(struct mp_audio));
case AF_CONTROL_REINIT: ;
*af->data = *(struct mp_audio*)arg;
mp_msg(MSGT_AFILTER, MSGL_V, "[dummy] Was reinitialized: %iHz/%ich/%s\n",
af->data->rate,af->data->nch,af_fmt2str_short(af->data->format));
return AF_OK;

View File

@ -96,10 +96,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = ((struct mp_audio*)arg)->nch;
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
// Calculate number of active filters
s->K=KM;
@ -150,30 +148,6 @@ static int control(struct af_instance* af, int cmd, void* arg)
}
return AF_OK;
}
case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_SET:{
float* gain = ((af_control_ext_t*)arg)->arg;
int ch = ((af_control_ext_t*)arg)->ch;
int k;
if(ch >= AF_NCH || ch < 0)
return AF_ERROR;
for(k = 0 ; k<KM ; k++)
s->g[ch][k] = pow(10.0,clamp(gain[k],G_MIN,G_MAX)/20.0)-1.0;
return AF_OK;
}
case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_GET:{
float* gain = ((af_control_ext_t*)arg)->arg;
int ch = ((af_control_ext_t*)arg)->ch;
int k;
if(ch >= AF_NCH || ch < 0)
return AF_ERROR;
for(k = 0 ; k<KM ; k++)
gain[k] = log10(s->g[ch][k]+1.0) * 20.0;
return AF_OK;
}
}
return AF_UNKNOWN;
}

View File

@ -85,10 +85,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
close(s->fd);
// Accept only int16_t as input format (which sucks)
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = ((struct mp_audio*)arg)->nch;
af->data->format = AF_FORMAT_S16_NE;
af->data->bps = 2;
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
// If buffer length isn't set, set it to the default value
if(s->sz == 0)

View File

@ -47,17 +47,14 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = 2;
if (((struct mp_audio*)arg)->format == AF_FORMAT_FLOAT_NE)
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
mp_audio_set_num_channels(af->data, 2);
if (af->data->format == AF_FORMAT_FLOAT_NE)
{
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
af->play = play_float;
}// else
{
af->data->format = AF_FORMAT_S16_NE;
af->data->bps = 2;
mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
af->play = play_s16;
}
@ -69,12 +66,6 @@ static int control(struct af_instance* af, int cmd, void* arg)
s->mul = f;
return AF_OK;
}
case AF_CONTROL_ES_MUL | AF_CONTROL_SET:
s->mul = *(float*)arg;
return AF_OK;
case AF_CONTROL_ES_MUL | AF_CONTROL_GET:
*(float*)arg = s->mul;
return AF_OK;
}
return AF_UNKNOWN;
}

146
audio/filter/af_force.c Normal file
View File

@ -0,0 +1,146 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <libavutil/common.h>
#include "core/m_config.h"
#include "core/m_option.h"
#include "audio/format.h"
#include "af.h"
struct priv {
struct m_config *config;
int in_format;
int in_srate;
struct mp_chmap in_channels;
int out_format;
int out_srate;
struct mp_chmap out_channels;
struct mp_audio data;
struct mp_audio temp;
};
static const struct priv defaults = {
.in_format = AF_FORMAT_UNKNOWN,
.out_format = AF_FORMAT_UNKNOWN,
};
#define OPT_BASE_STRUCT struct priv
static const struct m_option options[] = {
OPT_AUDIOFORMAT("format", in_format, 0),
OPT_INTRANGE("srate", in_srate, 0, 1000, 8*48000),
OPT_CHMAP("channels", in_channels, CONF_MIN, .min = 0),
OPT_AUDIOFORMAT("out-format", out_format, 0),
OPT_INTRANGE("out-srate", out_srate, 0, 1000, 8*48000),
OPT_CHMAP("out-channels", out_channels, CONF_MIN, .min = 0),
{0}
};
static int control(struct af_instance *af, int cmd, void *arg)
{
struct priv *priv = af->setup;
switch (cmd) {
case AF_CONTROL_REINIT: {
struct mp_audio *in = arg;
struct mp_audio orig_in = *in;
struct mp_audio *out = af->data;
if (priv->in_format != AF_FORMAT_UNKNOWN)
mp_audio_set_format(in, priv->in_format);
if (priv->in_channels.num)
mp_audio_set_channels(in, &priv->in_channels);
if (priv->in_srate)
in->rate = priv->in_srate;
mp_audio_copy_config(out, in);
if (priv->out_format != AF_FORMAT_UNKNOWN)
mp_audio_set_format(out, priv->out_format);
if (priv->out_channels.num)
mp_audio_set_channels(out, &priv->out_channels);
if (priv->out_srate)
out->rate = priv->out_srate;
if (in->nch != out->nch || in->bps != out->bps) {
mp_msg(MSGT_AFILTER, MSGL_ERR,
"[af_force] Forced input/output format are incompatible.\n");
return AF_ERROR;
}
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
}
case AF_CONTROL_COMMAND_LINE: {
if (m_config_parse_suboptions(priv->config, "af_force", (char *)arg) < 0)
return AF_ERROR;
return AF_OK;
}
}
return AF_UNKNOWN;
}
static struct mp_audio *play(struct af_instance *af, struct mp_audio *data)
{
struct priv *priv = af->setup;
struct mp_audio *r = &priv->temp;
*r = *af->data;
r->audio = data->audio;
r->len = data->len;
return r;
}
static void uninit(struct af_instance *af)
{
talloc_free(af->setup);
}
static int af_open(struct af_instance *af)
{
af->control = control;
af->uninit = uninit;
af->play = play;
af->mul = 1;
struct priv *priv = talloc(NULL, struct priv);
af->setup = priv;
*priv = defaults;
priv->config = m_config_simple(priv);
talloc_steal(priv, priv->config);
m_config_register_options(priv->config, options);
af->data = &priv->data;
return AF_OK;
}
struct af_info af_info_force = {
"Force audio format",
"force",
"",
"",
0,
af_open
};

View File

@ -75,6 +75,14 @@ static int check_format(int format)
return AF_ERROR;
}
static bool test_conversion(int src_format, int dst_format)
{
// This is the fallback conversion filter, so this filter is always
// inserted on format mismatches if no other filter can handle it.
// Initializing the filter might still fail.
return true;
}
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
@ -86,8 +94,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
int supported_ac3 = 0;
// Make sure this filter isn't redundant
if(af->data->format == data->format &&
af->data->bps == data->bps)
if(af->data->format == data->format)
return AF_DETACH;
// A bit complex because we can convert AC3
@ -113,7 +120,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
buf1, buf2);
af->data->rate = data->rate;
af->data->nch = data->nch;
mp_audio_set_channels(af->data, &data->channels);
af->mul = (double)af->data->bps / data->bps;
af->play = play; // set default
@ -147,7 +154,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
mp_msg(MSGT_AFILTER, MSGL_ERR, "[format] %s is not a valid format\n", (char *)arg);
return AF_ERROR;
}
if(AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format))
if(AF_OK != af->control(af, AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format))
return AF_ERROR;
return AF_OK;
}
@ -156,8 +163,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
if(!AF_FORMAT_IS_AC3(*(int*)arg) && AF_OK != check_format(*(int*)arg))
return AF_ERROR;
af->data->format = *(int*)arg;
af->data->bps = af_fmt2bits(af->data->format)/8;
mp_audio_set_format(af->data, *(int*)arg);
return AF_OK;
}
@ -186,7 +192,7 @@ static struct mp_audio* play_swapendian(struct af_instance* af, struct mp_audio*
endian(c->audio,l->audio,len,c->bps);
c->audio = l->audio;
c->format = l->format;
mp_audio_set_format(c, l->format);
return c;
}
@ -203,9 +209,8 @@ static struct mp_audio* play_float_s16(struct af_instance* af, struct mp_audio*
float2int(c->audio, l->audio, len, 2);
c->audio = l->audio;
mp_audio_set_format(c, l->format);
c->len = len*2;
c->bps = 2;
c->format = l->format;
return c;
}
@ -222,9 +227,8 @@ static struct mp_audio* play_s16_float(struct af_instance* af, struct mp_audio*
int2float(c->audio, l->audio, len, 2);
c->audio = l->audio;
mp_audio_set_format(c, l->format);
c->len = len*4;
c->bps = 4;
c->format = l->format;
return c;
}
@ -276,9 +280,8 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
// Set output data
c->audio = l->audio;
mp_audio_set_format(c, l->format);
c->len = len*l->bps;
c->bps = l->bps;
c->format = l->format;
return c;
}
@ -301,7 +304,8 @@ struct af_info af_info_format = {
"Anders",
"",
AF_FLAGS_REENTRANT,
af_open
af_open,
.test_conversion = test_conversion,
};
static inline uint32_t load24bit(void* data, int pos) {

View File

@ -299,7 +299,7 @@ static int control(struct af_instance *af, int cmd, void* arg)
af->data->rate);
return AF_ERROR;
}
af->data->nch = ((struct mp_audio*)arg)->nch;
mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch);
if(af->data->nch == 2) {
/* 2 channel input */
if(s->decode_mode != HRTF_MIX_MATRIX2CH) {
@ -308,13 +308,12 @@ static int control(struct af_instance *af, int cmd, void* arg)
}
}
else if (af->data->nch < 5)
af->data->nch = 5;
af->data->format = AF_FORMAT_S16_NE;
af->data->bps = 2;
mp_audio_set_channels_old(af->data, 5);
mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
test_output_res = af_test_output(af, (struct mp_audio*)arg);
af->mul = 2.0 / af->data->nch;
// after testing input set the real output format
af->data->nch = 2;
mp_audio_set_num_channels(af->data, 2);
s->print_flag = 1;
return test_output_res;
case AF_CONTROL_COMMAND_LINE:
@ -566,7 +565,7 @@ static struct mp_audio* play(struct af_instance *af, struct mp_audio *data)
/* Set output data */
data->audio = af->data->audio;
data->len = data->len / data->nch * 2;
data->nch = 2;
mp_audio_set_num_channels(data, 2);
return data;
}

View File

@ -34,10 +34,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
{
switch(cmd){
case AF_CONTROL_REINIT:
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = ((struct mp_audio*)arg)->nch;
af->data->format= AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
return af_test_output(af,(struct mp_audio*)arg);
}
return AF_UNKNOWN;

View File

@ -291,7 +291,7 @@ static int af_ladspa_parse_plugin(af_ladspa_t *setup) {
static void* mydlopen(const char *filename, int flag) {
char *buf;
const char *end, *start, *ladspapath;
int endsinso, needslash;
int endsinso;
size_t filenamelen;
void *result = NULL;
@ -324,9 +324,9 @@ static void* mydlopen(const char *filename, int flag) {
ladspapath=getenv("LADSPA_PATH");
if (ladspapath) {
start=ladspapath;
while (*start != '\0') {
int needslash;
end=start;
while ( (*end != ':') && (*end != '\0') )
end++;
@ -487,7 +487,6 @@ static int af_ladspa_malloc_failed(char *myname) {
static int control(struct af_instance *af, int cmd, void *arg) {
af_ladspa_t *setup = (af_ladspa_t*) af->setup;
int i, r;
float val;
switch(cmd) {
@ -498,10 +497,8 @@ static int control(struct af_instance *af, int cmd, void *arg) {
/* accept FLOAT, let af_format do conversion */
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = ((struct mp_audio*)arg)->nch;
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
/* arg->len is not set here yet, so init of buffers and connecting the
* filter, has to be done in play() :-/
@ -538,7 +535,10 @@ static int control(struct af_instance *af, int cmd, void *arg) {
}
line += strlen(buf);
setup->file = strdup(buf);
if (!setup->file) return af_ladspa_malloc_failed(setup->myname);
if (!setup->file) {
free(buf);
return af_ladspa_malloc_failed(setup->myname);
}
mp_msg(MSGT_AFILTER, MSGL_V, "%s: file --> %s\n", setup->myname,
setup->file);
if (*line != '\0') line++; /* read ':' */
@ -554,7 +554,10 @@ static int control(struct af_instance *af, int cmd, void *arg) {
}
line += strlen(buf);
setup->label = strdup(buf);
if (!setup->label) return af_ladspa_malloc_failed(setup->myname);
if (!setup->label) {
free(buf);
return af_ladspa_malloc_failed(setup->myname);
}
mp_msg(MSGT_AFILTER, MSGL_V, "%s: label --> %s\n", setup->myname,
setup->label);
/* if (*line != '0') line++; */ /* read ':' */
@ -581,15 +584,14 @@ static int control(struct af_instance *af, int cmd, void *arg) {
/* ninputcontrols is set by now, read control values from arg */
for(i=0; i<setup->ninputcontrols; i++) {
for (int i = 0; i < setup->ninputcontrols; i++) {
if (!line || *line != ':') {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("Not enough controls specified on the command line."));
return AF_ERROR;
}
line++;
r = sscanf(line, "%f", &val);
if (r!=1) {
if (sscanf(line, "%f", &val) != 1) {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("Not enough controls specified on the command line."));
return AF_ERROR;
@ -599,7 +601,7 @@ static int control(struct af_instance *af, int cmd, void *arg) {
}
mp_msg(MSGT_AFILTER, MSGL_V, "%s: input controls: ", setup->myname);
for(i=0; i<setup->ninputcontrols; i++) {
for (int i = 0; i < setup->ninputcontrols; i++) {
mp_msg(MSGT_AFILTER, MSGL_V, "%0.4f ",
setup->inputcontrols[setup->inputcontrolsmap[i]]);
}
@ -609,7 +611,7 @@ static int control(struct af_instance *af, int cmd, void *arg) {
mp_msg(MSGT_AFILTER, MSGL_V, "%s: checking boundaries of input controls\n",
setup->myname);
for(i=0; i<setup->ninputcontrols; i++) {
for (int i = 0; i < setup->ninputcontrols; i++) {
int p = setup->inputcontrolsmap[i];
LADSPA_PortRangeHint hint =
setup->plugin_descriptor->PortRangeHints[p];
@ -651,8 +653,6 @@ static int control(struct af_instance *af, int cmd, void *arg) {
*/
static void uninit(struct af_instance *af) {
int i;
free(af->data);
if (af->setup) {
af_ladspa_t *setup = (af_ladspa_t*) af->setup;
@ -664,7 +664,7 @@ static void uninit(struct af_instance *af) {
}
if (setup->chhandles) {
for(i=0; i<setup->nch; i+=setup->ninputs) {
for (int i = 0; i < setup->nch; i+=setup->ninputs) {
if (pdes->deactivate) pdes->deactivate(setup->chhandles[i]);
if (pdes->cleanup) pdes->cleanup(setup->chhandles[i]);
}
@ -681,13 +681,13 @@ static void uninit(struct af_instance *af) {
free(setup->outputs);
if (setup->inbufs) {
for(i=0; i<setup->nch; i++)
for(int i = 0; i < setup->nch; i++)
free(setup->inbufs[i]);
free(setup->inbufs);
}
if (setup->outbufs) {
for(i=0; i<setup->nch; i++)
for (int i = 0; i < setup->nch; i++)
free(setup->outbufs[i]);
free(setup->outbufs);
}

View File

@ -75,16 +75,16 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (AF_FORMAT_IS_AC3(data->format) || data->nch < s->min_channel_num)
return AF_DETACH;
af->data->format = s->in_sampleformat;
af->data->bps = af_fmt2bits(s->in_sampleformat) / 8;
mp_audio_set_format(af->data, s->in_sampleformat);
if (data->rate == 48000 || data->rate == 44100 || data->rate == 32000)
af->data->rate = data->rate;
else
af->data->rate = 48000;
if (data->nch > AC3_MAX_CHANNELS)
af->data->nch = AC3_MAX_CHANNELS;
mp_audio_set_num_channels(af->data, AC3_MAX_CHANNELS);
else
af->data->nch = data->nch;
mp_audio_set_channels(af->data, &data->channels);
mp_chmap_reorder_to_lavc(&af->data->channels);
test_output_res = af_test_output(af, data);
s->pending_len = 0;
@ -108,8 +108,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
// Put sample parameters
s->lavc_actx->channels = af->data->nch;
s->lavc_actx->channel_layout =
av_get_default_channel_layout(af->data->nch);
s->lavc_actx->channel_layout = mp_chmap_to_lavc(&af->data->channels);
s->lavc_actx->sample_rate = af->data->rate;
s->lavc_actx->bit_rate = bit_rate;
@ -123,9 +122,8 @@ static int control(struct af_instance *af, int cmd, void *arg)
"encoder frame size %d\n", s->lavc_actx->frame_size);
return AF_ERROR;
}
af->data->format = AF_FORMAT_AC3_BE;
af->data->bps = 2;
af->data->nch = 2;
mp_audio_set_format(af->data, AF_FORMAT_AC3_BE);
mp_audio_set_num_channels(af->data, 2);
return test_output_res;
case AF_CONTROL_COMMAND_LINE:
mp_msg(MSGT_AFILTER, MSGL_DBG2, "af_lavcac3enc cmdline: %s.\n", (char*)arg);
@ -235,15 +233,6 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
src2= s->pending_data;
}
if (c->nch >= 5) {
reorder_channel_nch(src2,
AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
AF_CHANNEL_LAYOUT_LAVC_DEFAULT,
c->nch,
s->expect_len / samplesize,
samplesize);
}
void *data = (void *) src2;
if (s->planarize) {
void *data2 = malloc(s->expect_len);
@ -316,8 +305,8 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
buf += len;
}
c->audio = l->audio;
c->nch = 2;
c->bps = 2;
mp_audio_set_num_channels(c, 2);
mp_audio_set_format(c, af->data->format);
c->len = outsize;
mp_msg(MSGT_AFILTER, MSGL_DBG2, "play return size %d, pending %d\n",
outsize, s->pending_len);

View File

@ -43,6 +43,7 @@
#define avresample_available(x) 0
#define avresample_convert(ctx, out, out_planesize, out_samples, in, in_planesize, in_samples) \
swr_convert(ctx, out, out_samples, (const uint8_t**)(in), in_samples)
#define avresample_set_channel_mapping swr_set_channel_mapping
#else
#error "config.h broken"
#endif
@ -50,6 +51,7 @@
#include "core/mp_msg.h"
#include "core/subopt-helper.h"
#include "audio/filter/af.h"
#include "audio/fmt-conversion.h"
struct af_resample_opts {
int filter_size;
@ -57,14 +59,24 @@ struct af_resample_opts {
int linear;
double cutoff;
int out_rate;
int in_rate;
int in_format;
struct mp_chmap in_channels;
int out_rate;
int out_format;
struct mp_chmap out_channels;
};
struct af_resample {
int allow_detach;
struct AVAudioResampleContext *avrctx;
struct AVAudioResampleContext *avrctx_out; // for output channel reordering
struct af_resample_opts ctx; // opts in the context
struct af_resample_opts opts; // opts requested by the user
// At least libswresample keeps a pointer around for this:
int reorder_in[MP_NUM_CHANNELS];
int reorder_out[MP_NUM_CHANNELS];
uint8_t *reorder_buffer;
};
#ifdef CONFIG_LIBAVRESAMPLE
@ -88,8 +100,12 @@ static bool needs_lavrctx_reconfigure(struct af_resample *s,
struct mp_audio *in,
struct mp_audio *out)
{
return s->ctx.out_rate != out->rate ||
s->ctx.in_rate != in->rate ||
return s->ctx.in_rate != in->rate ||
s->ctx.in_format != in->format ||
!mp_chmap_equals(&s->ctx.in_channels, &in->channels) ||
s->ctx.out_rate != out->rate ||
s->ctx.out_format != out->format ||
!mp_chmap_equals(&s->ctx.out_channels, &out->channels) ||
s->ctx.filter_size != s->opts.filter_size ||
s->ctx.phase_shift != s->opts.phase_shift ||
s->ctx.linear != s->opts.linear ||
@ -97,6 +113,12 @@ static bool needs_lavrctx_reconfigure(struct af_resample *s,
}
static bool test_conversion(int src_format, int dst_format)
{
return af_to_avformat(src_format) != AV_SAMPLE_FMT_NONE &&
af_to_avformat(dst_format) != AV_SAMPLE_FMT_NONE;
}
#define ctx_opt_set_int(a,b) av_opt_set_int(s->avrctx, (a), (b), 0)
#define ctx_opt_set_dbl(a,b) av_opt_set_double(s->avrctx, (a), (b), 0)
@ -108,36 +130,70 @@ static int control(struct af_instance *af, int cmd, void *arg)
switch (cmd) {
case AF_CONTROL_REINIT: {
if ((out->rate == in->rate) || (out->rate == 0))
struct mp_audio orig_in = *in;
if (((out->rate == in->rate) || (out->rate == 0)) &&
(out->format == in->format) &&
(mp_chmap_equals(&out->channels, &in->channels) || out->nch == 0) &&
s->allow_detach)
return AF_DETACH;
out->nch = FFMIN(in->nch, AF_NCH);
out->format = AF_FORMAT_S16_NE;
out->bps = 2;
af->mul = (double) out->rate / in->rate;
if (out->rate == 0)
out->rate = in->rate;
if (mp_chmap_is_empty(&out->channels))
mp_audio_set_channels(out, &in->channels);
enum AVSampleFormat in_samplefmt = af_to_avformat(in->format);
if (in_samplefmt == AV_SAMPLE_FMT_NONE) {
mp_audio_set_format(in, AF_FORMAT_FLOAT_NE);
in_samplefmt = af_to_avformat(in->format);
}
enum AVSampleFormat out_samplefmt = af_to_avformat(out->format);
if (out_samplefmt == AV_SAMPLE_FMT_NONE) {
mp_audio_set_format(out, in->format);
out_samplefmt = in_samplefmt;
}
af->mul = (double) (out->rate * out->nch) / (in->rate * in->nch);
af->delay = out->nch * s->opts.filter_size / FFMIN(af->mul, 1);
if (needs_lavrctx_reconfigure(s, in, out)) {
if (s->avrctx)
avresample_close(s->avrctx);
avresample_close(s->avrctx);
avresample_close(s->avrctx_out);
s->ctx.out_rate = out->rate;
s->ctx.in_rate = in->rate;
s->ctx.out_format = out->format;
s->ctx.in_format = in->format;
s->ctx.out_channels= out->channels;
s->ctx.in_channels = in->channels;
s->ctx.filter_size = s->opts.filter_size;
s->ctx.phase_shift = s->opts.phase_shift;
s->ctx.linear = s->opts.linear;
s->ctx.cutoff = s->opts.cutoff;
int ch_layout = av_get_default_channel_layout(out->nch);
struct mp_chmap map_in = in->channels;
struct mp_chmap map_out = out->channels;
ctx_opt_set_int("in_channel_layout", ch_layout);
ctx_opt_set_int("out_channel_layout", ch_layout);
// Try not to do any remixing if at least one is "unknown".
if (mp_chmap_is_unknown(&map_in) || mp_chmap_is_unknown(&map_out)) {
mp_chmap_set_unknown(&map_in, map_in.num);
mp_chmap_set_unknown(&map_out, map_out.num);
}
// unchecked: don't take any channel reordering into account
uint64_t in_ch_layout = mp_chmap_to_lavc_unchecked(&map_in);
uint64_t out_ch_layout = mp_chmap_to_lavc_unchecked(&map_out);
ctx_opt_set_int("in_channel_layout", in_ch_layout);
ctx_opt_set_int("out_channel_layout", out_ch_layout);
ctx_opt_set_int("in_sample_rate", s->ctx.in_rate);
ctx_opt_set_int("out_sample_rate", s->ctx.out_rate);
ctx_opt_set_int("in_sample_fmt", AV_SAMPLE_FMT_S16);
ctx_opt_set_int("out_sample_fmt", AV_SAMPLE_FMT_S16);
ctx_opt_set_int("in_sample_fmt", in_samplefmt);
ctx_opt_set_int("out_sample_fmt", out_samplefmt);
ctx_opt_set_int("filter_size", s->ctx.filter_size);
ctx_opt_set_int("phase_shift", s->ctx.phase_shift);
@ -145,20 +201,51 @@ static int control(struct af_instance *af, int cmd, void *arg)
ctx_opt_set_dbl("cutoff", s->ctx.cutoff);
if (avresample_open(s->avrctx) < 0) {
struct mp_chmap in_lavc;
mp_chmap_from_lavc(&in_lavc, in_ch_layout);
mp_chmap_get_reorder(s->reorder_in, &map_in, &in_lavc);
struct mp_chmap out_lavc;
mp_chmap_from_lavc(&out_lavc, out_ch_layout);
mp_chmap_get_reorder(s->reorder_out, &out_lavc, &map_out);
// Same configuration; we just reorder.
av_opt_set_int(s->avrctx_out, "in_channel_layout", out_ch_layout, 0);
av_opt_set_int(s->avrctx_out, "out_channel_layout", out_ch_layout, 0);
av_opt_set_int(s->avrctx_out, "in_sample_fmt", out_samplefmt, 0);
av_opt_set_int(s->avrctx_out, "out_sample_fmt", out_samplefmt, 0);
av_opt_set_int(s->avrctx_out, "in_sample_rate", s->ctx.out_rate, 0);
av_opt_set_int(s->avrctx_out, "out_sample_rate", s->ctx.out_rate, 0);
// API has weird requirements, quoting avresample.h:
// * This function can only be called when the allocated context is not open.
// * Also, the input channel layout must have already been set.
avresample_set_channel_mapping(s->avrctx, s->reorder_in);
avresample_set_channel_mapping(s->avrctx_out, s->reorder_out);
if (avresample_open(s->avrctx) < 0 ||
avresample_open(s->avrctx_out) < 0)
{
mp_msg(MSGT_AFILTER, MSGL_ERR, "[lavrresample] Cannot open "
"Libavresample Context. \n");
return AF_ERROR;
}
}
int out_rate, test_output_res;
// hack to make af_test_output ignore the samplerate change
out_rate = out->rate;
out->rate = in->rate;
test_output_res = af_test_output(af, in);
out->rate = out_rate;
return test_output_res;
return ((in->format == orig_in.format) &&
mp_chmap_equals(&in->channels, &orig_in.channels))
? AF_OK : AF_FALSE;
}
case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET: {
if (af_to_avformat(*(int*)arg) == AV_SAMPLE_FMT_NONE)
return AF_FALSE;
mp_audio_set_format(af->data, *(int*)arg);
return AF_OK;
}
case AF_CONTROL_CHANNELS | AF_CONTROL_SET: {
mp_audio_set_channels(af->data, (struct mp_chmap *)arg);
return AF_OK;
}
case AF_CONTROL_COMMAND_LINE: {
s->opts.cutoff = 0.0;
@ -169,6 +256,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
{"phase_shift", OPT_ARG_INT, &s->opts.phase_shift, NULL},
{"linear", OPT_ARG_BOOL, &s->opts.linear, NULL},
{"cutoff", OPT_ARG_FLOAT, &s->opts.cutoff, NULL},
{"detach", OPT_ARG_BOOL, &s->allow_detach, NULL},
{0}
};
@ -198,10 +286,21 @@ static void uninit(struct af_instance *af)
struct af_resample *s = af->setup;
if (s->avrctx)
avresample_close(s->avrctx);
if (s->avrctx_out)
avresample_close(s->avrctx_out);
talloc_free(af->setup);
}
}
static bool needs_reorder(int *reorder, int num_ch)
{
for (int n = 0; n < num_ch; n++) {
if (reorder[n] != n)
return true;
}
return false;
}
static struct mp_audio *play(struct af_instance *af, struct mp_audio *data)
{
struct af_resample *s = af->setup;
@ -227,10 +326,18 @@ static struct mp_audio *play(struct af_instance *af, struct mp_audio *data)
(uint8_t **) &out->audio, out_size, out_samples,
(uint8_t **) &in->audio, in_size, in_samples);
out_size = out->bps * out_samples * out->nch;
in->audio = out->audio;
in->len = out_size;
in->rate = s->ctx.out_rate;
*data = *out;
if (needs_reorder(s->reorder_out, out->nch)) {
if (talloc_get_size(s->reorder_buffer) < out_size)
s->reorder_buffer = talloc_realloc_size(s, s->reorder_buffer, out_size);
data->audio = s->reorder_buffer;
out_samples = avresample_convert(s->avrctx_out,
(uint8_t **) &data->audio, out_size, out_samples,
(uint8_t **) &out->audio, out_size, out_samples);
}
data->len = out->bps * out_samples * out->nch;
return data;
}
@ -244,7 +351,7 @@ static int af_open(struct af_instance *af)
af->mul = 1;
af->data = talloc_zero(s, struct mp_audio);
af->data->rate = 44100;
af->data->rate = 0;
int default_filter_size = 16;
s->opts = (struct af_resample_opts) {
@ -254,10 +361,13 @@ static int af_open(struct af_instance *af)
.phase_shift = 10,
};
s->allow_detach = 1;
s->avrctx = avresample_alloc_context();
s->avrctx_out = avresample_alloc_context();
af->setup = s;
if (s->avrctx) {
if (s->avrctx && s->avrctx_out) {
return AF_OK;
} else {
mp_msg(MSGT_AFILTER, MSGL_ERR, "[lavrresample] Cannot initialize "
@ -273,5 +383,6 @@ struct af_info af_info_lavrresample = {
"Stefano Pigozzi (based on Michael Niedermayer's lavcresample)",
"",
AF_FLAGS_REENTRANT,
af_open
af_open,
.test_conversion = test_conversion,
};

View File

@ -34,6 +34,15 @@ typedef struct af_pan_s
float level[AF_NCH][AF_NCH]; // Gain level for each channel
}af_pan_t;
static void set_channels(struct mp_audio *mpa, int num)
{
struct mp_chmap map;
// "unknown" channel layouts make it easier to pass through audio data,
// without triggering remixing.
mp_chmap_set_unknown(&map, num);
mp_audio_set_channels(mpa, &map);
}
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
@ -45,15 +54,13 @@ static int control(struct af_instance* af, int cmd, void* arg)
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
af->data->nch = s->nch ? s->nch: ((struct mp_audio*)arg)->nch;
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
set_channels(af->data, s->nch ? s->nch: ((struct mp_audio*)arg)->nch);
af->mul = (double)af->data->nch / ((struct mp_audio*)arg)->nch;
if((af->data->format != ((struct mp_audio*)arg)->format) ||
(af->data->bps != ((struct mp_audio*)arg)->bps)){
((struct mp_audio*)arg)->format = af->data->format;
((struct mp_audio*)arg)->bps = af->data->bps;
mp_audio_set_format((struct mp_audio*)arg, af->data->format);
return AF_FALSE;
}
return AF_OK;
@ -109,14 +116,11 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){
mp_msg(MSGT_AFILTER, MSGL_ERR, "[pan] The number of output channels must be"
" between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
" between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
return AF_ERROR;
}
s->nch=((int*)arg)[0];
return AF_OK;
case AF_CONTROL_PAN_NOUT | AF_CONTROL_GET:
*(int*)arg = af->data->nch;
return AF_OK;
case AF_CONTROL_PAN_BALANCE | AF_CONTROL_SET:{
float val = *(float*)arg;
if (s->nch)
@ -181,7 +185,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
// Set output data
c->audio = l->audio;
c->len = c->len / c->nch * l->nch;
c->nch = l->nch;
set_channels(c, l->nch);
return c;
}

View File

@ -302,26 +302,22 @@ static int control(struct af_instance* af, int cmd, void* arg)
"[scaletempo] %.3f speed * %.3f scale_nominal = %.3f\n",
s->speed, s->scale_nominal, s->scale);
mp_audio_copy_config(af->data, data);
if (s->scale == 1.0) {
if (s->speed_tempo && s->speed_pitch)
return AF_DETACH;
memcpy(af->data, data, sizeof(struct mp_audio));
af->delay = 0;
af->mul = 1;
return af_test_output(af, data);
}
af->data->rate = data->rate;
af->data->nch = data->nch;
if ( data->format == AF_FORMAT_S16_LE
|| data->format == AF_FORMAT_S16_BE ) {
if (data->format == AF_FORMAT_S16_NE) {
use_int = 1;
af->data->format = AF_FORMAT_S16_NE;
af->data->bps = bps = 2;
} else {
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = bps = 4;
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
}
bps = af->data->bps;
frames_stride = srate * s->ms_stride;
s->bytes_stride = frames_stride * bps * nch;

View File

@ -54,8 +54,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = 1;
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
mp_audio_set_num_channels(af->data, 1);
#if 0
if (((struct mp_audio*)arg)->format == AF_FORMAT_FLOAT_NE)
{
@ -65,8 +65,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
}// else
#endif
{
af->data->format = AF_FORMAT_S16_NE;
af->data->bps = 2;
mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
af->play = play_s16;
}
@ -79,18 +78,6 @@ static int control(struct af_instance* af, int cmd, void* arg)
s->decay = f2;
return AF_OK;
}
case AF_CONTROL_SS_FREQ | AF_CONTROL_SET:
s->freq = *(float*)arg;
return AF_OK;
case AF_CONTROL_SS_FREQ | AF_CONTROL_GET:
*(float*)arg = s->freq;
return AF_OK;
case AF_CONTROL_SS_DECAY | AF_CONTROL_SET:
s->decay = *(float*)arg;
return AF_OK;
case AF_CONTROL_SS_DECAY | AF_CONTROL_GET:
*(float*)arg = s->decay;
return AF_OK;
}
return AF_UNKNOWN;
}

View File

@ -70,9 +70,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = max(s->ch+1,((struct mp_audio*)arg)->nch);
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
mp_audio_set_channels_old(af->data, max(s->ch+1,((struct mp_audio*)arg)->nch));
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
// Design low-pass filter
s->k = 1.0;

View File

@ -92,10 +92,9 @@ static int control(struct af_instance* af, int cmd, void* arg)
switch(cmd){
case AF_CONTROL_REINIT:{
float fc;
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = ((struct mp_audio*)arg)->nch*2;
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch*2);
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
if (af->data->nch != 4){
mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Only stereo input is supported.\n");
@ -125,8 +124,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
if((af->data->format != ((struct mp_audio*)arg)->format) ||
(af->data->bps != ((struct mp_audio*)arg)->bps)){
((struct mp_audio*)arg)->format = af->data->format;
((struct mp_audio*)arg)->bps = af->data->bps;
mp_audio_set_format((struct mp_audio*)arg, af->data->format);
return AF_FALSE;
}
return AF_OK;
@ -244,7 +242,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data){
// Set output data
data->audio = af->data->audio;
data->len *= 2;
data->nch = af->data->nch;
mp_audio_set_channels_old(data, af->data->nch);
return data;
}

View File

@ -41,12 +41,10 @@ static int control(struct af_instance* af, int cmd, void* arg)
switch(cmd){
case AF_CONTROL_REINIT:
af->data->nch = data->nch;
af->data->format = AF_FORMAT_S16_NE;
af->data->bps = 2;
af->data->rate = data->rate;
mp_audio_copy_config(af->data, data);
mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
return AF_OK;
return af_test_output(af, data);
case AF_CONTROL_COMMAND_LINE:
sscanf((char*)arg,"%lf", &s->delta);
return AF_OK;

View File

@ -90,8 +90,8 @@ int af_test_output(struct af_instance* af, struct mp_audio* out)
if((af->data->format != out->format) ||
(af->data->bps != out->bps) ||
(af->data->rate != out->rate) ||
(af->data->nch != out->nch)){
memcpy(out,af->data,sizeof(struct mp_audio));
!mp_chmap_equals(&af->data->channels, &out->channels)){
*out = *af->data;
return AF_FALSE;
}
return AF_OK;

View File

@ -66,12 +66,10 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
af->data->nch = ((struct mp_audio*)arg)->nch;
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
if(s->fast && (((struct mp_audio*)arg)->format != (AF_FORMAT_FLOAT_NE))){
af->data->format = AF_FORMAT_S16_NE;
af->data->bps = 2;
mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
}
else{
// Cutoff set to 10Hz for forgetting factor
@ -79,42 +77,21 @@ static int control(struct af_instance* af, int cmd, void* arg)
float t = 2.0-cos(x);
s->time = 1.0 - (t - sqrt(t*t - 1));
mp_msg(MSGT_AFILTER, MSGL_DBG2, "[volume] Forgetting factor = %0.5f\n",s->time);
af->data->format = AF_FORMAT_FLOAT_NE;
af->data->bps = 4;
mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
}
return af_test_output(af,(struct mp_audio*)arg);
case AF_CONTROL_COMMAND_LINE:{
float v=0.0;
float vol[AF_NCH];
int i;
sscanf((char*)arg,"%f:%i", &v, &s->soft);
sscanf((char*)arg,"%f:%i:%i", &v, &s->soft, &s->fast);
for(i=0;i<AF_NCH;i++) vol[i]=v;
return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol);
}
case AF_CONTROL_POST_CREATE:
s->fast = ((((struct af_cfg*)arg)->force & AF_INIT_FORMAT_MASK) ==
AF_INIT_FLOAT) ? 0 : 1;
return AF_OK;
case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_SET:
memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int));
return AF_OK;
case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_GET:
memcpy((int*)arg,s->enable,AF_NCH*sizeof(int));
return AF_OK;
case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_SET:
s->soft = *(int*)arg;
return AF_OK;
case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_GET:
*(int*)arg = s->soft;
return AF_OK;
case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET:
return af_from_dB(AF_NCH,(float*)arg,s->level,20.0,-200.0,60.0);
case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET:
return af_to_dB(AF_NCH,s->level,(float*)arg,20.0);
case AF_CONTROL_VOLUME_PROBE | AF_CONTROL_GET:
return af_to_dB(AF_NCH,s->pow,(float*)arg,10.0);
case AF_CONTROL_VOLUME_PROBE_MAX | AF_CONTROL_GET:
return af_to_dB(AF_NCH,s->max,(float*)arg,10.0);
case AF_CONTROL_PRE_DESTROY:{
float m = 0.0;
int i;
@ -122,7 +99,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
for(i=0;i<AF_NCH;i++)
m=max(m,s->max[i]);
af_to_dB(1, &m, &m, 10.0);
mp_msg(MSGT_AFILTER, MSGL_INFO, "[volume] The maximum volume was %0.2fdB \n", m);
mp_msg(MSGT_AFILTER, MSGL_V, "[volume] The maximum volume was %0.2fdB \n", m);
}
return AF_OK;
}

View File

@ -21,48 +21,6 @@
#include <sys/types.h>
/*********************************************
// Control info struct.
//
// This struct is the argument in a info call to a filter.
*/
// Argument types
#define AF_CONTROL_TYPE_BOOL (0x0<<0)
#define AF_CONTROL_TYPE_CHAR (0x1<<0)
#define AF_CONTROL_TYPE_INT (0x2<<0)
#define AF_CONTROL_TYPE_FLOAT (0x3<<0)
#define AF_CONTROL_TYPE_STRUCT (0x4<<0)
#define AF_CONTROL_TYPE_SPECIAL (0x5<<0) // a pointer to a function for example
#define AF_CONTROL_TYPE_MASK (0x7<<0)
// Argument geometry
#define AF_CONTROL_GEOM_SCALAR (0x0<<3)
#define AF_CONTROL_GEOM_ARRAY (0x1<<3)
#define AF_CONTROL_GEOM_MATRIX (0x2<<3)
#define AF_CONTROL_GEOM_MASK (0x3<<3)
// Argument properties
#define AF_CONTROL_PROP_READ (0x0<<5) // The argument can be read
#define AF_CONTROL_PROP_WRITE (0x1<<5) // The argument can be written
#define AF_CONTROL_PROP_SAVE (0x2<<5) // Can be saved
#define AF_CONTROL_PROP_RUNTIME (0x4<<5) // Acessable during execution
#define AF_CONTROL_PROP_CHANNEL (0x8<<5) // Argument is set per channel
#define AF_CONTROL_PROP_MASK (0xF<<5)
typedef struct af_control_info_s{
int def; // Control enumrification
char* name; // Name of argument
char* info; // Description of what it does
int flags; // Flags as defined above
float max; // Max and min value
float min; // (only aplicable on float and int)
int xdim; // 1st dimension
int ydim; // 2nd dimension (=0 for everything except matrix)
size_t sz; // Size of argument in bytes
int ch; // Channel number (for future use)
void* arg; // Data (for future use)
}af_control_info_t;
/*********************************************
// Extended control used with arguments that operates on only one
// channel at the time
@ -98,11 +56,6 @@ typedef struct af_control_ext_s{
// OPTIONAL CALLS
/* Called just after creation with the af_cfg for the stream in which
the filter resides as input parameter this call can be used by the
filter to initialize itself */
#define AF_CONTROL_POST_CREATE 0x00000100 | AF_CONTROL_OPTIONAL
// Called just before destruction of a filter
#define AF_CONTROL_PRE_DESTROY 0x00000200 | AF_CONTROL_OPTIONAL
@ -119,20 +72,12 @@ typedef struct af_control_ext_s{
#define AF_CONTROL_SET 0x00000000
// Get argument
#define AF_CONTROL_GET 0x00000001
// Get info about the control, i.e fill in everything except argument
#define AF_CONTROL_INFO 0x00000002
// Resample
// Set output rate in resample
#define AF_CONTROL_RESAMPLE_RATE 0x00000100 | AF_CONTROL_FILTER_SPECIFIC
// Enable sloppy resampling
#define AF_CONTROL_RESAMPLE_SLOPPY 0x00000200 | AF_CONTROL_FILTER_SPECIFIC
// Set resampling accuracy
#define AF_CONTROL_RESAMPLE_ACCURACY 0x00000300 | AF_CONTROL_FILTER_SPECIFIC
// Format
#define AF_CONTROL_FORMAT_FMT 0x00000400 | AF_CONTROL_FILTER_SPECIFIC
@ -142,69 +87,11 @@ typedef struct af_control_ext_s{
// Set number of output channels in channels
#define AF_CONTROL_CHANNELS 0x00000600 | AF_CONTROL_FILTER_SPECIFIC
// Set number of channel routes
#define AF_CONTROL_CHANNELS_ROUTES 0x00000700 | AF_CONTROL_FILTER_SPECIFIC
// Set channel routing pair, arg is int[2] and ch is used
#define AF_CONTROL_CHANNELS_ROUTING 0x00000800 | AF_CONTROL_FILTER_SPECIFIC
// Set nuber of channel routing pairs, arg is int*
#define AF_CONTROL_CHANNELS_NR 0x00000900 | AF_CONTROL_FILTER_SPECIFIC
// Set make af_channels into a router
#define AF_CONTROL_CHANNELS_ROUTER 0x00000A00 | AF_CONTROL_FILTER_SPECIFIC
// Volume
// Turn volume control on and off, arg is int*
#define AF_CONTROL_VOLUME_ON_OFF 0x00000B00 | AF_CONTROL_FILTER_SPECIFIC
// Turn soft clipping of the volume on and off, arg is binary
#define AF_CONTROL_VOLUME_SOFTCLIP 0x00000C00 | AF_CONTROL_FILTER_SPECIFIC
// Set volume level, arg is a float* with the volume for all the channels
#define AF_CONTROL_VOLUME_LEVEL 0x00000D00 | AF_CONTROL_FILTER_SPECIFIC
// Probed power level for all channels, arg is a float*
#define AF_CONTROL_VOLUME_PROBE 0x00000E00 | AF_CONTROL_FILTER_SPECIFIC
// Maximum probed power level for all channels, arg is a float*
#define AF_CONTROL_VOLUME_PROBE_MAX 0x00000F00 | AF_CONTROL_FILTER_SPECIFIC
// Compressor/expander
// Turn compressor/expander on and off
#define AF_CONTROL_COMP_ON_OFF 0x00001000 | AF_CONTROL_FILTER_SPECIFIC
// Compression/expansion threshold [dB]
#define AF_CONTROL_COMP_THRESH 0x00001100 | AF_CONTROL_FILTER_SPECIFIC
// Compression/expansion attack time [ms]
#define AF_CONTROL_COMP_ATTACK 0x00001200 | AF_CONTROL_FILTER_SPECIFIC
// Compression/expansion release time [ms]
#define AF_CONTROL_COMP_RELEASE 0x00001300 | AF_CONTROL_FILTER_SPECIFIC
// Compression/expansion gain level [dB]
#define AF_CONTROL_COMP_RATIO 0x00001400 | AF_CONTROL_FILTER_SPECIFIC
// Noise gate
// Turn noise gate on an off
#define AF_CONTROL_GATE_ON_OFF 0x00001500 | AF_CONTROL_FILTER_SPECIFIC
// Noise gate threshold [dB]
#define AF_CONTROL_GATE_THRESH 0x00001600 | AF_CONTROL_FILTER_SPECIFIC
// Noise gate attack time [ms]
#define AF_CONTROL_GATE_ATTACK 0x00001700 | AF_CONTROL_FILTER_SPECIFIC
// Noise gate release time [ms]
#define AF_CONTROL_GATE_RELEASE 0x00001800 | AF_CONTROL_FILTER_SPECIFIC
// Noise gate release range level [dB]
#define AF_CONTROL_GATE_RANGE 0x00001900 | AF_CONTROL_FILTER_SPECIFIC
// Pan
// Pan levels, arg is a control_ext with a float*
@ -216,9 +103,6 @@ typedef struct af_control_ext_s{
// Balance, arg is float*; range -1 (left) to 1 (right), 0 center
#define AF_CONTROL_PAN_BALANCE 0x00001C00 | AF_CONTROL_FILTER_SPECIFIC
// Set equalizer gain, arg is a control_ext with a float*
#define AF_CONTROL_EQUALIZER_GAIN 0x00001D00 | AF_CONTROL_FILTER_SPECIFIC
// Delay length in ms, arg is a control_ext with a float*
#define AF_CONTROL_DELAY_LEN 0x00001E00 | AF_CONTROL_FILTER_SPECIFIC
@ -236,21 +120,10 @@ typedef struct af_control_ext_s{
// Export
#define AF_CONTROL_EXPORT_SZ 0x00003000 | AF_CONTROL_FILTER_SPECIFIC
// ExtraStereo Multiplier
#define AF_CONTROL_ES_MUL 0x00003100 | AF_CONTROL_FILTER_SPECIFIC
// Center
// Channel number which to inster the filtered data, arg in int*
#define AF_CONTROL_CENTER_CH 0x00003200 | AF_CONTROL_FILTER_SPECIFIC
// SineSuppress
#define AF_CONTROL_SS_FREQ 0x00003300 | AF_CONTROL_FILTER_SPECIFIC
#define AF_CONTROL_SS_DECAY 0x00003400 | AF_CONTROL_FILTER_SPECIFIC
#define AF_CONTROL_PLAYBACK_SPEED 0x00003500 | AF_CONTROL_FILTER_SPECIFIC
#define AF_CONTROL_SCALETEMPO_AMOUNT 0x00003600 | AF_CONTROL_FILTER_SPECIFIC

65
audio/fmt-conversion.c Normal file
View File

@ -0,0 +1,65 @@
/*
* This file is part of MPlayer.
*
* MPlayer is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* MPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "core/mp_msg.h"
#include <libavutil/avutil.h>
#include <libavutil/samplefmt.h>
#include "format.h"
#include "fmt-conversion.h"
static const struct {
enum AVSampleFormat sample_fmt;
int fmt;
} audio_conversion_map[] = {
{AV_SAMPLE_FMT_U8, AF_FORMAT_U8},
{AV_SAMPLE_FMT_S16, AF_FORMAT_S16_NE},
{AV_SAMPLE_FMT_S32, AF_FORMAT_S32_NE},
{AV_SAMPLE_FMT_FLT, AF_FORMAT_FLOAT_NE},
{AV_SAMPLE_FMT_DBL, AF_FORMAT_DOUBLE_NE},
{AV_SAMPLE_FMT_NONE, 0},
};
enum AVSampleFormat af_to_avformat(int fmt)
{
int i;
enum AVSampleFormat sample_fmt;
for (i = 0; audio_conversion_map[i].fmt; i++)
if (audio_conversion_map[i].fmt == fmt)
break;
sample_fmt = audio_conversion_map[i].sample_fmt;
if (sample_fmt == AF_FORMAT_UNKNOWN)
mp_msg(MSGT_GLOBAL, MSGL_V, "Unsupported sample format: %s\n",
af_fmt2str_short(fmt));
return sample_fmt;
}
int af_from_avformat(enum AVSampleFormat sample_fmt)
{
int i;
for (i = 0; audio_conversion_map[i].fmt; i++)
if (audio_conversion_map[i].sample_fmt == sample_fmt)
break;
int fmt = audio_conversion_map[i].fmt;
if (!fmt) {
const char *fmtname = av_get_sample_fmt_name(sample_fmt);
mp_msg(MSGT_GLOBAL, MSGL_ERR, "Unsupported AVSampleFormat %s (%d)\n",
fmtname ? fmtname : "INVALID", sample_fmt);
}
return fmt;
}

25
audio/fmt-conversion.h Normal file
View File

@ -0,0 +1,25 @@
/*
* This file is part of MPlayer.
*
* MPlayer is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* MPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPLAYER_SAMPLE_FMT_CONVERSION_H
#define MPLAYER_SAMPLE_FMT_CONVERSION_H
enum AVSampleFormat af_to_avformat(int fmt);
int af_from_avformat(enum AVSampleFormat sample_fmt);
#endif /* MPLAYER_SAMPLE_FMT_CONVERSION_H */

View File

@ -29,24 +29,17 @@
int af_fmt2bits(int format)
{
if (AF_FORMAT_IS_AC3(format)) return 16;
return (format & AF_FORMAT_BITS_MASK)+8;
// return (((format & AF_FORMAT_BITS_MASK)>>3)+1) * 8;
#if 0
if (format == AF_FORMAT_UNKNOWN)
return 0;
switch(format & AF_FORMAT_BITS_MASK)
{
case AF_FORMAT_8BIT: return 8;
case AF_FORMAT_16BIT: return 16;
case AF_FORMAT_24BIT: return 24;
case AF_FORMAT_32BIT: return 32;
case AF_FORMAT_48BIT: return 48;
case AF_FORMAT_64BIT: return 64;
}
#endif
return -1;
}
int af_bits2fmt(int bits)
{
return (bits/8 - 1) << 3;
return 0;
}
/* Convert format to str input str is a buffer for the
@ -94,6 +87,9 @@ const struct af_fmt_entry af_fmtstr_table[] = {
{ "floatle", AF_FORMAT_FLOAT_LE },
{ "floatbe", AF_FORMAT_FLOAT_BE },
{ "floatne", AF_FORMAT_FLOAT_NE },
{ "doublele", AF_FORMAT_DOUBLE_LE },
{ "doublebe", AF_FORMAT_DOUBLE_BE },
{ "doublene", AF_FORMAT_DOUBLE_NE },
{0}
};

View File

@ -53,8 +53,7 @@
#define AF_FORMAT_16BIT (1<<3)
#define AF_FORMAT_24BIT (2<<3)
#define AF_FORMAT_32BIT (3<<3)
#define AF_FORMAT_40BIT (4<<3)
#define AF_FORMAT_48BIT (5<<3)
#define AF_FORMAT_64BIT (4<<3)
#define AF_FORMAT_BITS_MASK (7<<3)
// Special flags refering to non pcm data (note: 1<<6, 2<<6, 5<<6 unused)
@ -85,6 +84,9 @@
#define AF_FORMAT_FLOAT_LE (AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_LE)
#define AF_FORMAT_FLOAT_BE (AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_BE)
#define AF_FORMAT_DOUBLE_LE (AF_FORMAT_F|AF_FORMAT_64BIT|AF_FORMAT_LE)
#define AF_FORMAT_DOUBLE_BE (AF_FORMAT_F|AF_FORMAT_64BIT|AF_FORMAT_BE)
#define AF_FORMAT_AC3_LE (AF_FORMAT_AC3|AF_FORMAT_16BIT|AF_FORMAT_LE)
#define AF_FORMAT_AC3_BE (AF_FORMAT_AC3|AF_FORMAT_16BIT|AF_FORMAT_BE)
@ -99,6 +101,7 @@
#define AF_FORMAT_U32_NE AF_FORMAT_U32_BE
#define AF_FORMAT_S32_NE AF_FORMAT_S32_BE
#define AF_FORMAT_FLOAT_NE AF_FORMAT_FLOAT_BE
#define AF_FORMAT_DOUBLE_NE AF_FORMAT_DOUBLE_BE
#define AF_FORMAT_AC3_NE AF_FORMAT_AC3_BE
#define AF_FORMAT_IEC61937_NE AF_FORMAT_IEC61937_BE
#else
@ -109,6 +112,7 @@
#define AF_FORMAT_U32_NE AF_FORMAT_U32_LE
#define AF_FORMAT_S32_NE AF_FORMAT_S32_LE
#define AF_FORMAT_FLOAT_NE AF_FORMAT_FLOAT_LE
#define AF_FORMAT_DOUBLE_NE AF_FORMAT_DOUBLE_LE
#define AF_FORMAT_AC3_NE AF_FORMAT_AC3_LE
#define AF_FORMAT_IEC61937_NE AF_FORMAT_IEC61937_LE
#endif
@ -127,7 +131,6 @@ extern const struct af_fmt_entry af_fmtstr_table[];
int af_str2fmt_short(bstr str);
int af_fmt2bits(int format);
int af_bits2fmt(int bits);
char* af_fmt2str(int format, char* str, int size);
const char* af_fmt2str_short(int format);

View File

@ -217,7 +217,7 @@ void mixer_setbalance(mixer_t *mixer, float val)
AF_CONTROL_PAN_BALANCE | AF_CONTROL_SET, &val))
return;
if (val == 0 || mixer->ao->channels < 2)
if (val == 0 || mixer->ao->channels.num < 2)
return;
if (!(af_pan_balance = af_add(mixer->afilter, "pan"))) {

View File

@ -250,14 +250,24 @@ void ao_resume(struct ao *ao)
ao->driver->resume(ao);
}
bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
struct mp_chmap *map)
{
return mp_chmap_sel_adjust(s, map);
}
bool ao_chmap_sel_get_def(struct ao *ao, const struct mp_chmap_sel *s,
struct mp_chmap *map, int num)
{
return mp_chmap_sel_get_def(s, map, num);
}
int old_ao_init(struct ao *ao, char *params)
{
assert(!global_ao);
global_ao = ao;
ao_subdevice = params ? talloc_strdup(ao, params) : NULL;
if (ao->driver->old_functions->init(ao->samplerate, ao->channels,
if (ao->driver->old_functions->init(ao->samplerate, &ao->channels,
ao->format, 0) == 0) {
global_ao = NULL;
return -1;

View File

@ -23,6 +23,8 @@
#include "core/bstr.h"
#include "core/mp_common.h"
#include "audio/chmap.h"
#include "audio/chmap_sel.h"
enum aocontrol {
// _VOLUME commands take struct ao_control_vol pointer for input/output.
@ -55,7 +57,7 @@ typedef struct ao_info {
/* interface towards mplayer and */
typedef struct ao_old_functions {
int (*control)(int cmd, void *arg);
int (*init)(int rate, int channels, int format, int flags);
int (*init)(int rate, const struct mp_chmap *channels, int format, int flags);
void (*uninit)(int immed);
void (*reset)(void);
int (*get_space)(void);
@ -68,7 +70,6 @@ typedef struct ao_old_functions {
struct ao;
struct ao_driver {
bool is_new;
bool encode;
const struct ao_info *info;
const struct ao_old_functions *old_functions;
@ -86,9 +87,9 @@ struct ao_driver {
/* global data used by mplayer and plugins */
struct ao {
int samplerate;
int channels;
struct mp_chmap channels;
int format;
int bps;
int bps; // bytes per second
int outburst;
int buffersize;
double pts;
@ -121,6 +122,11 @@ void ao_reset(struct ao *ao);
void ao_pause(struct ao *ao);
void ao_resume(struct ao *ao);
bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
struct mp_chmap *map);
bool ao_chmap_sel_get_def(struct ao *ao, const struct mp_chmap_sel *s,
struct mp_chmap *map, int num);
int old_ao_control(struct ao *ao, enum aocontrol cmd, void *arg);
int old_ao_init(struct ao *ao, char *params);
void old_ao_uninit(struct ao *ao, bool cut_audio);

File diff suppressed because it is too large Load Diff

View File

@ -412,7 +412,7 @@ static void print_help(void)
free(devids);
}
static int init(int rate,int channels,int format,int flags)
static int init(int rate,const struct mp_chmap *channels,int format,int flags)
{
AudioStreamBasicDescription inDesc;
AudioComponentDescription desc;
@ -439,7 +439,7 @@ int device_id, display_help = 0;
return 0;
}
ao_msg(MSGT_AO,MSGL_V, "init([%dHz][%dch][%s][%d])\n", rate, channels, af_fmt2str_short(format), flags);
ao_msg(MSGT_AO,MSGL_V, "init([%dHz][%dch][%s][%d])\n", rate, ao_data.channels.num, af_fmt2str_short(format), flags);
ao = calloc(1, sizeof(ao_coreaudio_t));
@ -499,10 +499,15 @@ int device_id, display_help = 0;
// Save selected device id
ao->i_selected_dev = devid_def;
struct mp_chmap_sel chmap_sel = {0};
mp_chmap_sel_add_waveext(&chmap_sel);
if (!ao_chmap_sel_adjust(&ao_data, &ao_data.channels, &chmap_sel))
goto err_out;
// Build Description for the input format
inDesc.mSampleRate=rate;
inDesc.mFormatID=ao->b_supports_digital ? kAudioFormat60958AC3 : kAudioFormatLinearPCM;
inDesc.mChannelsPerFrame=channels;
inDesc.mChannelsPerFrame=ao_data.channels.num;
inDesc.mBitsPerChannel=af_fmt2bits(format);
if((format&AF_FORMAT_POINT_MASK)==AF_FORMAT_F) {
@ -521,7 +526,7 @@ int device_id, display_help = 0;
inDesc.mFormatFlags |= kAudioFormatFlagIsBigEndian;
inDesc.mFramesPerPacket = 1;
ao->packetSize = inDesc.mBytesPerPacket = inDesc.mBytesPerFrame = inDesc.mFramesPerPacket*channels*(inDesc.mBitsPerChannel/8);
ao->packetSize = inDesc.mBytesPerPacket = inDesc.mBytesPerFrame = inDesc.mFramesPerPacket*ao_data.channels.num*(inDesc.mBitsPerChannel/8);
print_format(MSGL_V, "source:",&inDesc);
if (ao->b_supports_digital)
@ -605,7 +610,8 @@ int device_id, display_help = 0;
ao->chunk_size = maxFrames;//*inDesc.mBytesPerFrame;
ao_data.samplerate = inDesc.mSampleRate;
ao_data.channels = inDesc.mChannelsPerFrame;
if (!ao_chmap_sel_get_def(&ao_data, &chmap_sel, &ao_data.channels, inDesc.mChannelsPerFrame))
goto err_out2;
ao_data.bps = ao_data.samplerate * inDesc.mBytesPerFrame;
ao_data.outburst = ao->chunk_size;
ao_data.buffersize = ao_data.bps;
@ -837,7 +843,8 @@ static int OpenSPDIF(void)
ao->chunk_size = ao->stream_format.mBytesPerPacket;
ao_data.samplerate = ao->stream_format.mSampleRate;
ao_data.channels = ao->stream_format.mChannelsPerFrame;
// Applies default ordering; ok because AC3 data is always in mpv internal channel order
mp_chmap_from_channels(&ao_data.channels, ao->stream_format.mChannelsPerFrame);
ao_data.bps = ao_data.samplerate * (ao->stream_format.mBytesPerPacket/ao->stream_format.mFramesPerPacket);
ao_data.outburst = ao->chunk_size;
ao_data.buffersize = ao_data.bps;

View File

@ -64,26 +64,6 @@ LIBAO_EXTERN(dsound)
static const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x1,0x0000,0x0010, {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}};
#define SPEAKER_FRONT_LEFT 0x1
#define SPEAKER_FRONT_RIGHT 0x2
#define SPEAKER_FRONT_CENTER 0x4
#define SPEAKER_LOW_FREQUENCY 0x8
#define SPEAKER_BACK_LEFT 0x10
#define SPEAKER_BACK_RIGHT 0x20
#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
#define SPEAKER_BACK_CENTER 0x100
#define SPEAKER_SIDE_LEFT 0x200
#define SPEAKER_SIDE_RIGHT 0x400
#define SPEAKER_TOP_CENTER 0x800
#define SPEAKER_TOP_FRONT_LEFT 0x1000
#define SPEAKER_TOP_FRONT_CENTER 0x2000
#define SPEAKER_TOP_FRONT_RIGHT 0x4000
#define SPEAKER_TOP_BACK_LEFT 0x8000
#define SPEAKER_TOP_BACK_CENTER 0x10000
#define SPEAKER_TOP_BACK_RIGHT 0x20000
#define SPEAKER_RESERVED 0x80000000
#if 0
#define DSSPEAKER_HEADPHONE 0x00000001
#define DSSPEAKER_MONO 0x00000002
@ -107,28 +87,6 @@ typedef struct {
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
#endif
static const int channel_mask[] = {
/* 1 */ SPEAKER_FRONT_CENTER,
/* 2 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,
/* 3 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT
| SPEAKER_LOW_FREQUENCY,
/* 4 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT,
/* 5 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY,
/* 6 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY,
/* 7 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT | SPEAKER_BACK_CENTER | SPEAKER_BACK_RIGHT
| SPEAKER_LOW_FREQUENCY,
/* 8 */ SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT
| SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
| SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT
| SPEAKER_LOW_FREQUENCY,
};
static HINSTANCE hdsound_dll = NULL; ///handle to the dll
static LPDIRECTSOUND hds = NULL; ///direct sound object
static LPDIRECTSOUNDBUFFER hdspribuf = NULL; ///primary direct sound buffer
@ -349,22 +307,9 @@ static int write_buffer(unsigned char *data, int len)
if (SUCCEEDED(res))
{
if (!AF_FORMAT_IS_AC3(ao_data.format)) {
int sampsize = af_fmt2bits(ao_data.format) / 8;
reorder_channel_copy_nch(data,
AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
lpvPtr1,
AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT,
ao_data.channels,
dwBytes1 / sampsize,
sampsize);
memcpy(lpvPtr1, data, dwBytes1);
if (lpvPtr2 != NULL)
reorder_channel_copy_nch(data + dwBytes1,
AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
lpvPtr2,
AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT,
ao_data.channels,
dwBytes2 / sampsize,
sampsize);
memcpy(lpvPtr2, (char *)data + dwBytes1, dwBytes2);
write_offset+=dwBytes1+dwBytes2;
if(write_offset>=buffer_size)
@ -432,7 +377,7 @@ static int control(int cmd, void *arg)
\param flags unused
\return 1=success 0=fail
*/
static int init(int rate, int channels, int format, int flags)
static int init(int rate, const struct mp_chmap *channels, int format, int flags)
{
int res;
if (!InitDirectSound()) return 0;
@ -445,15 +390,14 @@ static int init(int rate, int channels, int format, int flags)
DSBUFFERDESC dsbpridesc;
DSBUFFERDESC dsbdesc;
//check if the channel count and format is supported in general
if (channels > FF_ARRAY_ELEMS(channel_mask)) {
UninitDirectSound();
mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: 8 channel audio not yet supported\n");
return 0;
}
if (AF_FORMAT_IS_AC3(format))
if (AF_FORMAT_IS_AC3(format)) {
format = AF_FORMAT_AC3_NE;
} else {
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext(&sel);
if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels))
return 0;
}
switch(format){
case AF_FORMAT_AC3_NE:
case AF_FORMAT_S24_LE:
@ -465,25 +409,24 @@ static int init(int rate, int channels, int format, int flags)
format=AF_FORMAT_S16_LE;
}
//fill global ao_data
ao_data.channels = channels;
ao_data.samplerate = rate;
ao_data.format = format;
ao_data.bps = channels * rate * (af_fmt2bits(format)>>3);
ao_data.bps = ao_data.channels.num * rate * (af_fmt2bits(format)>>3);
if(ao_data.buffersize==-1) ao_data.buffersize = ao_data.bps; // space for 1 sec
mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Samplerate:%iHz Channels:%i Format:%s\n", rate, channels, af_fmt2str_short(format));
mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Samplerate:%iHz Channels:%i Format:%s\n", rate, ao_data.channels.num, af_fmt2str_short(format));
mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Buffersize:%d bytes (%d msec)\n", ao_data.buffersize, ao_data.buffersize / ao_data.bps * 1000);
//fill waveformatex
ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE));
wformat.Format.cbSize = (channels > 2) ? sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) : 0;
wformat.Format.nChannels = channels;
wformat.Format.cbSize = (ao_data.channels.num > 2) ? sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) : 0;
wformat.Format.nChannels = ao_data.channels.num;
wformat.Format.nSamplesPerSec = rate;
if (AF_FORMAT_IS_AC3(format)) {
wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
wformat.Format.wBitsPerSample = 16;
wformat.Format.nBlockAlign = 4;
} else {
wformat.Format.wFormatTag = (channels > 2) ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM;
wformat.Format.wFormatTag = (ao_data.channels.num > 2) ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM;
wformat.Format.wBitsPerSample = af_fmt2bits(format);
wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3);
}
@ -503,8 +446,8 @@ static int init(int rate, int channels, int format, int flags)
| DSBCAPS_GLOBALFOCUS /** Allows background playing */
| DSBCAPS_CTRLVOLUME; /** volume control enabled */
if (channels > 2) {
wformat.dwChannelMask = channel_mask[channels - 1];
if (ao_data.channels.num > 2) {
wformat.dwChannelMask = mp_chmap_to_waveext(&ao_data.channels);
wformat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
wformat.Samples.wValidBitsPerSample = wformat.Format.wBitsPerSample;
// Needed for 5.1 on emu101k - shit soundblaster

View File

@ -50,7 +50,7 @@ static const ao_info_t info =
LIBAO_EXTERN(jack)
//! maximum number of channels supported, avoids lots of mallocs
#define MAX_CHANS 8
#define MAX_CHANS MP_NUM_CHANNELS
static jack_port_t *ports[MAX_CHANS];
static int num_ports; ///< Number of used ports == number of channels
static jack_client_t *client;
@ -202,7 +202,8 @@ static void print_help (void)
);
}
static int init(int rate, int channels, int format, int flags) {
static int init(int rate, const struct mp_chmap *channels, int format, int flags)
{
const char **matching_ports = NULL;
char *port_name = NULL;
char *client_name = NULL;
@ -222,10 +223,12 @@ static int init(int rate, int channels, int format, int flags) {
print_help();
return 0;
}
if (channels > MAX_CHANS) {
mp_msg(MSGT_AO, MSGL_FATAL, "[JACK] Invalid number of channels: %i\n", channels);
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext(&sel);
if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels))
goto err_out;
}
if (!client_name) {
client_name = malloc(40);
sprintf(client_name, "mpv [%d]", getpid());
@ -249,9 +252,9 @@ static int init(int rate, int channels, int format, int flags) {
goto err_out;
}
i = 1;
num_ports = ao_data.channels.num;
while (matching_ports[i]) i++;
if (channels > i) channels = i;
num_ports = channels;
if (num_ports > i) num_ports = i;
// create out output ports
for (i = 0; i < num_ports; i++) {
@ -281,10 +284,12 @@ static int init(int rate, int channels, int format, int flags) {
/ (float)rate;
callback_interval = 0;
ao_data.channels = channels;
if (!ao_chmap_sel_get_def(&ao_data, &sel, &ao_data.channels, num_ports))
goto err_out;
ao_data.samplerate = rate;
ao_data.format = AF_FORMAT_FLOAT_NE;
ao_data.bps = channels * rate * sizeof(float);
ao_data.bps = ao_data.channels.num * rate * sizeof(float);
ao_data.buffersize = CHUNK_SIZE * NUM_CHUNKS;
ao_data.outburst = CHUNK_SIZE;
free(matching_ports);

View File

@ -101,7 +101,14 @@ static int init(struct ao *ao, char *params)
ac->stream->codec->time_base.den = ao->samplerate;
ac->stream->codec->sample_rate = ao->samplerate;
ac->stream->codec->channels = ao->channels;
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_any(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;
mp_chmap_reorder_to_lavc(&ao->channels);
ac->stream->codec->channels = ao->channels.num;
ac->stream->codec->channel_layout = mp_chmap_to_lavc(&ao->channels);
ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_NONE;
@ -243,36 +250,6 @@ out_takefirst:
ac->stream->codec->bits_per_raw_sample = ac->sample_size * 8;
switch (ao->channels) {
case 1:
ac->stream->codec->channel_layout = AV_CH_LAYOUT_MONO;
break;
case 2:
ac->stream->codec->channel_layout = AV_CH_LAYOUT_STEREO;
break;
/* someone please check if these are what mplayer normally assumes
case 3:
ac->stream->codec->channel_layout = AV_CH_LAYOUT_SURROUND;
break;
case 4:
ac->stream->codec->channel_layout = AV_CH_LAYOUT_2_2;
break;
*/
case 5:
ac->stream->codec->channel_layout = AV_CH_LAYOUT_5POINT0;
break;
case 6:
ac->stream->codec->channel_layout = AV_CH_LAYOUT_5POINT1;
break;
case 8:
ac->stream->codec->channel_layout = AV_CH_LAYOUT_7POINT1;
break;
default:
mp_msg(MSGT_ENCODE, MSGL_ERR,
"ao-lavc: unknown channel layout; hoping for the best\n");
break;
}
if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->stream) < 0)
return -1;
@ -282,11 +259,12 @@ out_takefirst:
if (ac->pcmhack) {
ac->aframesize = 16384; // "enough"
ac->buffer_size = ac->aframesize * ac->pcmhack * ao->channels * 2 + 200;
ac->buffer_size =
ac->aframesize * ac->pcmhack * ao->channels.num * 2 + 200;
} else {
ac->aframesize = ac->stream->codec->frame_size;
ac->buffer_size = ac->aframesize * ac->sample_size * ao->channels * 2 +
200;
ac->buffer_size =
ac->aframesize * ac->sample_size * ao->channels.num * 2 + 200;
}
if (ac->buffer_size < FF_MIN_BUFFER_SIZE)
ac->buffer_size = FF_MIN_BUFFER_SIZE;
@ -304,10 +282,10 @@ out_takefirst:
ac->offset_left = ac->offset;
//fill_ao_data:
ao->outburst = ac->aframesize * ac->sample_size * ao->channels *
ac->framecount;
ao->outburst =
ac->aframesize * ac->sample_size * ao->channels.num * ac->framecount;
ao->buffersize = ao->outburst * 2;
ao->bps = ao->channels * ao->samplerate * ac->sample_size;
ao->bps = ao->channels.num * ao->samplerate * ac->sample_size;
ao->untimed = true;
ao->priv = ac;
@ -348,7 +326,7 @@ static void uninit(struct ao *ao, bool cut_audio)
// TRICK: append aframesize-1 samples to the end, then play() will
// encode all it can
size_t extralen =
(ac->aframesize - 1) * ao->channels * ac->sample_size;
(ac->aframesize - 1) * ao->channels.num * ac->sample_size;
void *paddingbuf = talloc_size(ao, ao->buffer.len + extralen);
memcpy(paddingbuf, ao->buffer.start, ao->buffer.len);
fill_with_padding((char *) paddingbuf + ao->buffer.len,
@ -392,12 +370,6 @@ static int encode(struct ao *ao, double apts, void *data)
int status, gotpacket;
ac->aframecount++;
if (data && (ao->channels == 5 || ao->channels == 6 || ao->channels == 8)) {
reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
AF_CHANNEL_LAYOUT_LAVC_DEFAULT,
ao->channels,
ac->aframesize * ao->channels, ac->sample_size);
}
if (data)
ectx->audio_pts_offset = realapts - apts;
@ -411,12 +383,18 @@ static int encode(struct ao *ao, double apts, void *data)
frame->nb_samples = ac->aframesize;
if (ac->planarize) {
void *data2 = talloc_size(ao, ac->aframesize * ao->channels * ac->sample_size);
reorder_to_planar(data2, data, ac->sample_size, ao->channels, ac->aframesize);
void *data2 = talloc_size(ao, ac->aframesize * ao->channels.num *
ac->sample_size);
reorder_to_planar(data2, data, ac->sample_size, ao->channels.num,
ac->aframesize);
data = data2;
}
if (avcodec_fill_audio_frame(frame, ao->channels, ac->stream->codec->sample_fmt, data, ac->aframesize * ao->channels * ac->sample_size, 1)) {
size_t audiolen = ac->aframesize * ao->channels.num * ac->sample_size;
if (avcodec_fill_audio_frame(frame, ao->channels.num,
ac->stream->codec->sample_fmt, data,
audiolen, 1))
{
mp_msg(MSGT_ENCODE, MSGL_ERR, "ao-lavc: error filling\n");
return -1;
}
@ -523,7 +501,7 @@ static int play(struct ao *ao, void *data, int len, int flags)
double pts = ao->pts;
double outpts;
len /= ac->sample_size * ao->channels;
len /= ac->sample_size * ao->channels.num;
if (!encode_lavc_start(ectx)) {
mp_msg(MSGT_ENCODE, MSGL_WARN,
@ -593,7 +571,7 @@ static int play(struct ao *ao, void *data, int len, int flags)
if (ac->offset_left <= -len) {
// skip whole frame
ac->offset_left += len;
return len * ac->sample_size * ao->channels;
return len * ac->sample_size * ao->channels.num;
} else {
// skip part of this frame, buffer/encode the rest
bufpos -= ac->offset_left;
@ -604,11 +582,11 @@ static int play(struct ao *ao, void *data, int len, int flags)
// make a temporary buffer, filled with zeroes at the start
// (don't worry, only happens once)
paddingbuf = talloc_size(ac, ac->sample_size * ao->channels *
paddingbuf = talloc_size(ac, ac->sample_size * ao->channels.num *
(ac->offset_left + len));
fill_with_padding(paddingbuf, ac->offset_left, ac->sample_size,
ac->sample_padding);
data = (char *) paddingbuf + ac->sample_size * ao->channels *
data = (char *) paddingbuf + ac->sample_size * ao->channels.num *
ac->offset_left;
bufpos -= ac->offset_left; // yes, negative!
ptsoffset += ac->offset_left;
@ -651,7 +629,7 @@ static int play(struct ao *ao, void *data, int len, int flags)
while (len - bufpos >= ac->aframesize) {
encode(ao,
outpts + (bufpos + ptsoffset) / (double) ao->samplerate + encode_lavc_getoffset(ectx, ac->stream),
(char *) data + ac->sample_size * bufpos * ao->channels);
(char *) data + ac->sample_size * bufpos * ao->channels.num);
bufpos += ac->aframesize;
}
@ -667,11 +645,10 @@ static int play(struct ao *ao, void *data, int len, int flags)
ectx->next_in_pts = nextpts;
}
return bufpos * ac->sample_size * ao->channels;
return bufpos * ac->sample_size * ao->channels.num;
}
const struct ao_driver audio_out_lavc = {
.is_new = true,
.encode = true,
.info = &(const struct ao_info) {
"audio encoding using libavcodec",

View File

@ -48,11 +48,17 @@ static int init(struct ao *ao, char *params)
{
struct priv *priv = talloc_zero(ao, struct priv);
ao->priv = priv;
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_any(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;
int samplesize = af_fmt2bits(ao->format) / 8;
ao->outburst = 256 * ao->channels * samplesize;
ao->outburst = 256 * ao->channels.num * samplesize;
// A "buffer" for about 0.2 seconds of audio
ao->buffersize = (int)(ao->samplerate * 0.2 / 256 + 1) * ao->outburst;
ao->bps = ao->channels * ao->samplerate * samplesize;
ao->bps = ao->channels.num * ao->samplerate * samplesize;
priv->last_time = GetTimer();
return 0;
@ -110,7 +116,6 @@ static float get_delay(struct ao *ao)
}
const struct ao_driver audio_out_null = {
.is_new = true,
.info = &(const struct ao_info) {
"Null audio output",
"null",

View File

@ -53,7 +53,7 @@ static const ao_info_t info =
LIBAO_EXTERN(openal)
#define MAX_CHANS 8
#define MAX_CHANS MP_NUM_CHANNELS
#define NUM_BUF 128
#define CHUNK_SIZE 512
static ALuint buffers[MAX_CHANS][NUM_BUF];
@ -109,15 +109,29 @@ static void list_devices(void) {
}
}
static int init(int rate, int channels, int format, int flags) {
struct speaker {
int id;
float pos[3];
};
static const struct speaker speaker_pos[] = {
{MP_SPEAKER_ID_FL, {-1, 0, 0.5}},
{MP_SPEAKER_ID_FR, { 1, 0, 0.5}},
{MP_SPEAKER_ID_FC, { 0, 0, 1}},
{MP_SPEAKER_ID_LFE, { 0, 0, 0.1}},
{MP_SPEAKER_ID_BL, {-1, 0, -1}},
{MP_SPEAKER_ID_BR, { 1, 0, -1}},
{MP_SPEAKER_ID_BC, { 0, 0, -1}},
{MP_SPEAKER_ID_SL, {-1, 0, 0}},
{MP_SPEAKER_ID_SR, { 1, 0, 0}},
{-1},
};
static int init(int rate, const struct mp_chmap *channels, int format,
int flags)
{
float position[3] = {0, 0, 0};
float direction[6] = {0, 0, 1, 0, -1, 0};
float sppos[MAX_CHANS][3] = {
{-1, 0, 0.5}, {1, 0, 0.5},
{-1, 0, -1}, {1, 0, -1},
{0, 0, 1}, {0, 0, 0.1},
{-1, 0, 0}, {1, 0, 0},
};
ALCdevice *dev = NULL;
ALCcontext *ctx = NULL;
ALCint freq = 0;
@ -137,9 +151,22 @@ static int init(int rate, int channels, int format, int flags) {
list_devices();
goto err_out;
}
if (channels > MAX_CHANS) {
mp_msg(MSGT_AO, MSGL_FATAL, "[OpenAL] Invalid number of channels: %i\n", channels);
struct mp_chmap_sel sel = {0};
for (i = 0; speaker_pos[i].id != -1; i++)
mp_chmap_sel_add_speaker(&sel, speaker_pos[i].id);
if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels))
goto err_out;
struct speaker speakers[MAX_CHANS];
for (i = 0; i < ao_data.channels.num; i++) {
speakers[i].id = -1;
for (int n = 0; speaker_pos[n].id >= 0; n++) {
if (speaker_pos[n].id == ao_data.channels.speaker[i])
speakers[i] = speaker_pos[n];
}
if (speakers[i].id < 0) {
mp_msg(MSGT_AO, MSGL_FATAL, "[OpenAL] Unknown channel layout\n");
goto err_out;
}
}
dev = alcOpenDevice(device);
if (!dev) {
@ -150,25 +177,22 @@ static int init(int rate, int channels, int format, int flags) {
alcMakeContextCurrent(ctx);
alListenerfv(AL_POSITION, position);
alListenerfv(AL_ORIENTATION, direction);
alGenSources(channels, sources);
for (i = 0; i < channels; i++) {
alGenSources(ao_data.channels.num, sources);
for (i = 0; i < ao_data.channels.num; i++) {
cur_buf[i] = 0;
unqueue_buf[i] = 0;
alGenBuffers(NUM_BUF, buffers[i]);
alSourcefv(sources[i], AL_POSITION, sppos[i]);
alSourcefv(sources[i], AL_POSITION, speakers[i].pos);
alSource3f(sources[i], AL_VELOCITY, 0, 0, 0);
}
if (channels == 1)
alSource3f(sources[0], AL_POSITION, 0, 0, 1);
ao_data.channels = channels;
alcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq);
if (alcGetError(dev) == ALC_NO_ERROR && freq)
rate = freq;
ao_data.samplerate = rate;
ao_data.format = AF_FORMAT_S16_NE;
ao_data.bps = channels * rate * 2;
ao_data.bps = ao_data.channels.num * rate * 2;
ao_data.buffersize = CHUNK_SIZE * NUM_BUF;
ao_data.outburst = channels * CHUNK_SIZE;
ao_data.outburst = ao_data.channels.num * CHUNK_SIZE;
tmpbuf = malloc(CHUNK_SIZE);
free(device);
return 1;
@ -200,7 +224,7 @@ static void uninit(int immed) {
static void unqueue_buffers(void) {
ALint p;
int s;
for (s = 0; s < ao_data.channels; s++) {
for (s = 0; s < ao_data.channels.num; s++) {
int till_wrap = NUM_BUF - unqueue_buf[s];
alGetSourcei(sources[s], AL_BUFFERS_PROCESSED, &p);
if (p >= till_wrap) {
@ -219,7 +243,7 @@ static void unqueue_buffers(void) {
* \brief stop playing and empty buffers (for seeking/pause)
*/
static void reset(void) {
alSourceStopv(ao_data.channels, sources);
alSourceStopv(ao_data.channels.num, sources);
unqueue_buffers();
}
@ -227,14 +251,14 @@ static void reset(void) {
* \brief stop playing, keep buffers (for pause)
*/
static void audio_pause(void) {
alSourcePausev(ao_data.channels, sources);
alSourcePausev(ao_data.channels.num, sources);
}
/**
* \brief resume playing, after audio_pause()
*/
static void audio_resume(void) {
alSourcePlayv(ao_data.channels, sources);
alSourcePlayv(ao_data.channels.num, sources);
}
static int get_space(void) {
@ -243,7 +267,7 @@ static int get_space(void) {
alGetSourcei(sources[0], AL_BUFFERS_QUEUED, &queued);
queued = NUM_BUF - queued - 3;
if (queued < 0) return 0;
return queued * CHUNK_SIZE * ao_data.channels;
return queued * CHUNK_SIZE * ao_data.channels.num;
}
/**
@ -254,22 +278,22 @@ static int play(void *data, int len, int flags) {
int i, j, k;
int ch;
int16_t *d = data;
len /= ao_data.channels * CHUNK_SIZE;
len /= ao_data.channels.num * CHUNK_SIZE;
for (i = 0; i < len; i++) {
for (ch = 0; ch < ao_data.channels; ch++) {
for (j = 0, k = ch; j < CHUNK_SIZE / 2; j++, k += ao_data.channels)
for (ch = 0; ch < ao_data.channels.num; ch++) {
for (j = 0, k = ch; j < CHUNK_SIZE / 2; j++, k += ao_data.channels.num)
tmpbuf[j] = d[k];
alBufferData(buffers[ch][cur_buf[ch]], AL_FORMAT_MONO16, tmpbuf,
CHUNK_SIZE, ao_data.samplerate);
alSourceQueueBuffers(sources[ch], 1, &buffers[ch][cur_buf[ch]]);
cur_buf[ch] = (cur_buf[ch] + 1) % NUM_BUF;
}
d += ao_data.channels * CHUNK_SIZE / 2;
d += ao_data.channels.num * CHUNK_SIZE / 2;
}
alGetSourcei(sources[0], AL_SOURCE_STATE, &state);
if (state != AL_PLAYING) // checked here in case of an underrun
alSourcePlayv(ao_data.channels, sources);
return len * ao_data.channels * CHUNK_SIZE;
alSourcePlayv(ao_data.channels.num, sources);
return len * ao_data.channels.num * CHUNK_SIZE;
}
static float get_delay(void) {

View File

@ -221,12 +221,12 @@ static int control(int cmd,void *arg){
// open & setup audio device
// return: 1=success 0=fail
static int init(int rate,int channels,int format,int flags){
static int init(int rate,const struct mp_chmap *channels,int format,int flags){
char *mixer_channels [SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
int oss_format;
char *mdev = mixer_device, *mchan = mixer_channel;
mp_msg(MSGT_AO,MSGL_V,"ao2: %d Hz %d chans %s\n",rate,channels,
mp_msg(MSGT_AO,MSGL_V,"ao2: %d Hz %d chans %s\n",rate,ao_data.channels.num,
af_fmt2str_short(format));
if (ao_subdevice) {
@ -339,25 +339,31 @@ ac3_retry:
mp_msg(MSGT_AO,MSGL_V,"audio_setup: sample format: %s (requested: %s)\n",
af_fmt2str_short(ao_data.format), af_fmt2str_short(format));
ao_data.channels = channels;
if(!AF_FORMAT_IS_AC3(format)) {
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_alsa_def(&sel);
if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels))
return 0;
int reqchannels = ao_data.channels.num;
// We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it
if (ao_data.channels > 2) {
if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels) == -1 ||
ao_data.channels != channels ) {
mp_tmsg(MSGT_AO,MSGL_ERR,"[AO OSS] audio_setup: Failed to set audio device to %d channels.\n", channels);
if (reqchannels > 2) {
int nchannels = reqchannels;
if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &nchannels) == -1 ||
nchannels != reqchannels ) {
mp_tmsg(MSGT_AO,MSGL_ERR,"[AO OSS] audio_setup: Failed to set audio device to %d channels.\n", reqchannels);
return 0;
}
}
else {
int c = ao_data.channels-1;
int c = reqchannels-1;
if (ioctl (audio_fd, SNDCTL_DSP_STEREO, &c) == -1) {
mp_tmsg(MSGT_AO,MSGL_ERR,"[AO OSS] audio_setup: Failed to set audio device to %d channels.\n", ao_data.channels);
mp_tmsg(MSGT_AO,MSGL_ERR,"[AO OSS] audio_setup: Failed to set audio device to %d channels.\n", reqchannels);
return 0;
}
ao_data.channels=c+1;
if (!ao_chmap_sel_get_def(&ao_data, &sel, &ao_data.channels, c + 1))
return 0;
}
mp_msg(MSGT_AO,MSGL_V,"audio_setup: using %d channels (requested: %d)\n", ao_data.channels, channels);
mp_msg(MSGT_AO,MSGL_V,"audio_setup: using %d channels (requested: %d)\n", ao_data.channels.num, reqchannels);
// set rate
ao_data.samplerate=rate;
ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate);
@ -403,7 +409,7 @@ ac3_retry:
#endif
}
ao_data.bps=ao_data.channels;
ao_data.bps=ao_data.channels.num;
switch (ao_data.format & AF_FORMAT_BITS_MASK) {
case AF_FORMAT_8BIT:
break;
@ -459,10 +465,10 @@ static void reset(void){
ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate);
ioctl (audio_fd, SNDCTL_DSP_SETFMT, &oss_format);
if(!AF_FORMAT_IS_AC3(ao_data.format)) {
if (ao_data.channels > 2)
ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels);
if (ao_data.channels.num > 2)
ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels.num);
else {
int c = ao_data.channels-1;
int c = ao_data.channels.num-1;
ioctl (audio_fd, SNDCTL_DSP_STEREO, &c);
}
ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate);

View File

@ -69,7 +69,7 @@ static void fput32le(uint32_t val, FILE *fp)
static void write_wave_header(struct ao *ao, FILE *fp, uint64_t data_length)
{
bool use_waveex = ao->channels >= 5 && ao->channels <= 8;
bool use_waveex = true;
uint16_t fmt = ao->format == AF_FORMAT_FLOAT_LE ?
WAV_ID_FLOAT_PCM : WAV_ID_PCM;
uint32_t fmt_chunk_size = use_waveex ? 40 : 16;
@ -86,30 +86,17 @@ static void write_wave_header(struct ao *ao, FILE *fp, uint64_t data_length)
fput32le(WAV_ID_FMT, fp);
fput32le(fmt_chunk_size, fp);
fput16le(use_waveex ? WAV_ID_FORMAT_EXTENSIBLE : fmt, fp);
fput16le(ao->channels, fp);
fput16le(ao->channels.num, fp);
fput32le(ao->samplerate, fp);
fput32le(ao->bps, fp);
fput16le(ao->channels * (bits / 8), fp);
fput16le(ao->channels.num * (bits / 8), fp);
fput16le(bits, fp);
if (use_waveex) {
// Extension chunk
fput16le(22, fp);
fput16le(bits, fp);
switch (ao->channels) {
case 5:
fput32le(0x0607, fp); // L R C Lb Rb
break;
case 6:
fput32le(0x060f, fp); // L R C Lb Rb LFE
break;
case 7:
fput32le(0x0727, fp); // L R C Cb Ls Rs LFE
break;
case 8:
fput32le(0x063f, fp); // L R C Lb Rb Ls Rs LFE
break;
}
fput32le(mp_chmap_to_waveext(&ao->channels), fp);
// 2 bytes format + 14 bytes guid
fput32le(fmt, fp);
fput32le(0x00100000, fp);
@ -159,14 +146,19 @@ static int init(struct ao *ao, char *params)
}
}
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;
ao->outburst = 65536;
ao->bps = ao->channels * ao->samplerate * (af_fmt2bits(ao->format) / 8);
ao->bps = ao->channels.num * ao->samplerate * (af_fmt2bits(ao->format) / 8);
mp_tmsg(MSGT_AO, MSGL_INFO, "[AO PCM] File: %s (%s)\n"
"PCM: Samplerate: %d Hz Channels: %d Format: %s\n",
priv->outputfilename,
priv->waveheader ? "WAVE" : "RAW PCM", ao->samplerate,
ao->channels, af_fmt2str_short(ao->format));
ao->channels.num, af_fmt2str_short(ao->format));
mp_tmsg(MSGT_AO, MSGL_INFO,
"[AO PCM] Info: Faster dumping is achieved with -no-video\n"
"[AO PCM] Info: To write WAVE files use -ao pcm:waveheader (default).\n");
@ -222,20 +214,12 @@ static int play(struct ao *ao, void *data, int len, int flags)
{
struct priv *priv = ao->priv;
if (ao->channels == 5 || ao->channels == 6 || ao->channels == 8) {
int frame_size = af_fmt2bits(ao->format) / 8;
len -= len % (frame_size * ao->channels);
reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT,
ao->channels, len / frame_size, frame_size);
}
fwrite(data, len, 1, priv->fp);
priv->data_length += len;
return len;
}
const struct ao_driver audio_out_pcm = {
.is_new = true,
.info = &(const struct ao_info) {
"RAW PCM/WAVE file writer audio output",
"pcm",

View File

@ -273,9 +273,15 @@ static int init(struct ao *ao, char *params)
if (pa_device == paNoDevice)
goto error_exit;
// The actual channel order probably depends on the platform.
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext_def(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
goto error_exit;
PaStreamParameters sp = {
.device = pa_device,
.channelCount = ao->channels,
.channelCount = ao->channels.num,
.suggestedLatency
= Pa_GetDeviceInfo(pa_device)->defaultHighOutputLatency,
};
@ -298,7 +304,7 @@ static int init(struct ao *ao, char *params)
ao->format = fmt->mp_format;
sp.sampleFormat = fmt->pa_format;
priv->framelen = ao->channels * (af_fmt2bits(ao->format) / 8);
priv->framelen = ao->channels.num * (af_fmt2bits(ao->format) / 8);
ao->bps = ao->samplerate * priv->framelen;
if (!check_pa_ret(Pa_IsFormatSupported(NULL, &sp, ao->samplerate)))
@ -413,7 +419,6 @@ static void resume(struct ao *ao)
}
const struct ao_driver audio_out_portaudio = {
.is_new = true,
.info = &(const struct ao_info) {
"PortAudio",
"portaudio",

View File

@ -143,6 +143,59 @@ static const struct format_map {
{AF_FORMAT_UNKNOWN, 0}
};
static const int speaker_map[][2] = {
{PA_CHANNEL_POSITION_MONO, MP_SPEAKER_ID_FC},
{PA_CHANNEL_POSITION_FRONT_LEFT, MP_SPEAKER_ID_FL},
{PA_CHANNEL_POSITION_FRONT_RIGHT, MP_SPEAKER_ID_FR},
{PA_CHANNEL_POSITION_FRONT_CENTER, MP_SPEAKER_ID_FC},
{PA_CHANNEL_POSITION_REAR_CENTER, MP_SPEAKER_ID_BC},
{PA_CHANNEL_POSITION_REAR_LEFT, MP_SPEAKER_ID_BL},
{PA_CHANNEL_POSITION_REAR_RIGHT, MP_SPEAKER_ID_BR},
{PA_CHANNEL_POSITION_LFE, MP_SPEAKER_ID_LFE},
{PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, MP_SPEAKER_ID_FLC},
{PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, MP_SPEAKER_ID_FRC},
{PA_CHANNEL_POSITION_SIDE_LEFT, MP_SPEAKER_ID_SL},
{PA_CHANNEL_POSITION_SIDE_RIGHT, MP_SPEAKER_ID_SR},
{PA_CHANNEL_POSITION_TOP_CENTER, MP_SPEAKER_ID_TC},
{PA_CHANNEL_POSITION_TOP_FRONT_LEFT, MP_SPEAKER_ID_TFL},
{PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, MP_SPEAKER_ID_TFR},
{PA_CHANNEL_POSITION_TOP_FRONT_CENTER, MP_SPEAKER_ID_TFC},
{PA_CHANNEL_POSITION_TOP_REAR_LEFT, MP_SPEAKER_ID_TBL},
{PA_CHANNEL_POSITION_TOP_REAR_RIGHT, MP_SPEAKER_ID_TBR},
{PA_CHANNEL_POSITION_TOP_REAR_CENTER, MP_SPEAKER_ID_TBC},
{PA_CHANNEL_POSITION_INVALID, -1}
};
static bool chmap_pa_from_mp(pa_channel_map *dst, struct mp_chmap *src)
{
if (src->num > PA_CHANNELS_MAX)
return false;
dst->channels = src->num;
for (int n = 0; n < src->num; n++) {
int mp_speaker = src->speaker[n];
int pa_speaker = PA_CHANNEL_POSITION_INVALID;
for (int i = 0; speaker_map[i][1] != -1; i++) {
if (speaker_map[i][1] == mp_speaker) {
pa_speaker = speaker_map[i][0];
break;
}
}
if (pa_speaker == PA_CHANNEL_POSITION_INVALID)
return false;
dst->map[n] = pa_speaker;
}
return true;
}
static bool select_chmap(struct ao *ao, pa_channel_map *dst)
{
struct mp_chmap_sel sel = {0};
for (int n = 0; speaker_map[n][1] != -1; n++)
mp_chmap_sel_add_speaker(&sel, speaker_map[n][1]);
return ao_chmap_sel_adjust(ao, &sel, &ao->channels) &&
chmap_pa_from_mp(dst, &ao->channels);
}
static void uninit(struct ao *ao, bool cut_audio)
{
struct priv *priv = ao->priv;
@ -209,30 +262,6 @@ static int init(struct ao *ao, char *params)
priv->broken_pause = true;
}
ss.channels = ao->channels;
ss.rate = ao->samplerate;
const struct format_map *fmt_map = format_maps;
while (fmt_map->mp_format != ao->format) {
if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) {
mp_msg(MSGT_AO, MSGL_V,
"AO: [pulse] Unsupported format, using default\n");
fmt_map = format_maps;
break;
}
fmt_map++;
}
ao->format = fmt_map->mp_format;
ss.format = fmt_map->pa_format;
if (!pa_sample_spec_valid(&ss)) {
mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Invalid sample spec\n");
goto fail;
}
pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
ao->bps = pa_bytes_per_second(&ss);
if (!(priv->mainloop = pa_threaded_mainloop_new())) {
mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate main loop\n");
goto fail;
@ -260,6 +289,32 @@ static int init(struct ao *ao, char *params)
if (pa_context_get_state(priv->context) != PA_CONTEXT_READY)
goto unlock_and_fail;
ss.channels = ao->channels.num;
ss.rate = ao->samplerate;
const struct format_map *fmt_map = format_maps;
while (fmt_map->mp_format != ao->format) {
if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) {
mp_msg(MSGT_AO, MSGL_V,
"AO: [pulse] Unsupported format, using default\n");
fmt_map = format_maps;
break;
}
fmt_map++;
}
ao->format = fmt_map->mp_format;
ss.format = fmt_map->pa_format;
if (!pa_sample_spec_valid(&ss)) {
mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Invalid sample spec\n");
goto fail;
}
if (!select_chmap(ao, &map))
goto fail;
ao->bps = pa_bytes_per_second(&ss);
if (!(priv->stream = pa_stream_new(priv->context, "audio stream", &ss,
&map)))
goto unlock_and_fail;
@ -495,7 +550,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
const ao_control_vol_t *vol = arg;
struct pa_cvolume volume;
pa_cvolume_reset(&volume, ao->channels);
pa_cvolume_reset(&volume, ao->channels.num);
if (volume.channels != 2)
pa_cvolume_set(&volume, volume.channels, VOL_MP2PA(vol->left));
else {
@ -533,7 +588,6 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
}
const struct ao_driver audio_out_pulse = {
.is_new = true,
.info = &(const struct ao_info) {
"PulseAudio audio output",
"pulse",

View File

@ -121,8 +121,16 @@ static int init(struct ao *ao, char *params)
free(port);
}
// Actual channel layout unknown.
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext_def(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) {
rsd_free(priv->rd);
return -1;
}
rsd_set_param(priv->rd, RSD_SAMPLERATE, &ao->samplerate);
rsd_set_param(priv->rd, RSD_CHANNELS, &ao->channels);
rsd_set_param(priv->rd, RSD_CHANNELS, &ao->channels.num);
int rsd_format = set_format(ao);
rsd_set_param(priv->rd, RSD_FORMAT, &rsd_format);
@ -132,7 +140,7 @@ static int init(struct ao *ao, char *params)
return -1;
}
ao->bps = ao->channels * ao->samplerate * af_fmt2bits(ao->format) / 8;
ao->bps = ao->channels.num * ao->samplerate * af_fmt2bits(ao->format) / 8;
return 0;
}
@ -189,7 +197,6 @@ static float get_delay(struct ao *ao)
}
const struct ao_driver audio_out_rsound = {
.is_new = true,
.info = &(const struct ao_info) {
.name = "RSound output driver",
.short_name = "rsound",

View File

@ -160,6 +160,13 @@ static int init(struct ao *ao, char *params)
return -1;
}
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext_def(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) {
uninit(ao, true);
return -1;
}
SDL_AudioSpec desired, obtained;
int bytes = 0;
@ -185,7 +192,7 @@ static int init(struct ao *ao, char *params)
#endif
}
desired.freq = ao->samplerate;
desired.channels = ao->channels;
desired.channels = ao->channels.num;
desired.samples = FFMIN(32768, ceil_power_of_two(ao->samplerate * buflen));
desired.callback = audio_callback;
desired.userdata = ao;
@ -236,9 +243,13 @@ static int init(struct ao *ao, char *params)
return -1;
}
if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, obtained.channels)) {
uninit(ao, true);
return -1;
}
ao->samplerate = obtained.freq;
ao->channels = obtained.channels;
ao->bps = ao->channels * ao->samplerate * bytes;
ao->bps = ao->channels.num * ao->samplerate * bytes;
ao->buffersize = obtained.size * bufcnt;
ao->outburst = obtained.size;
priv->buffer = av_fifo_alloc(ao->buffersize);
@ -362,7 +373,6 @@ static float get_delay(struct ao *ao)
}
const struct ao_driver audio_out_sdl = {
.is_new = true,
.info = &(const struct ao_info) {
"SDL Audio",
"sdl",

View File

@ -20,11 +20,12 @@
#define MPLAYER_AUDIO_OUT_INTERNAL_H
#include "core/options.h"
#include "ao.h"
// prototypes:
//static ao_info_t info;
static int control(int cmd, void *arg);
static int init(int rate,int channels,int format,int flags);
static int init(int rate,const struct mp_chmap *channels,int format,int flags);
static void uninit(int immed);
static void reset(void);
static int get_space(void);

File diff suppressed because it is too large Load Diff

View File

@ -25,114 +25,6 @@
#include <inttypes.h>
// L - Left
// R - Right
// C - Center
// Ls - Left Surround
// Rs - Right Surround
// Cs - Center Surround
// Rls - Rear Left Surround
// Rrs - Rear Right Surround
#define AF_LFE (1<<7)
#define AF_CHANNEL_LAYOUT_MONO ((100<<8)|1)
#define AF_CHANNEL_LAYOUT_STEREO ((101<<8)|2)
#define AF_CHANNEL_LAYOUT_1_0 AF_CHANNEL_LAYOUT_MONO // C
#define AF_CHANNEL_LAYOUT_2_0 AF_CHANNEL_LAYOUT_STEREO // L R
#define AF_CHANNEL_LAYOUT_2_1 ((102<<8)|3) // L R LFE
#define AF_CHANNEL_LAYOUT_3_0_A ((103<<8)|3) // L R C
#define AF_CHANNEL_LAYOUT_3_0_B ((104<<8)|3) // C L R
#define AF_CHANNEL_LAYOUT_4_0_A ((105<<8)|4) // L R C Cs
#define AF_CHANNEL_LAYOUT_4_0_B ((106<<8)|4) // C L R Cs
#define AF_CHANNEL_LAYOUT_4_0_C ((107<<8)|4) // L R Ls Rs
#define AF_CHANNEL_LAYOUT_5_0_A ((108<<8)|5) // L R C Ls Rs
#define AF_CHANNEL_LAYOUT_5_0_B ((109<<8)|5) // L R Ls Rs C
#define AF_CHANNEL_LAYOUT_5_0_C ((110<<8)|5) // L C R Ls Rs
#define AF_CHANNEL_LAYOUT_5_0_D ((111<<8)|5) // C L R Ls Rs
#define AF_CHANNEL_LAYOUT_5_1_A ((112<<8)|6|AF_LFE) // L R C LFE Ls Rs
#define AF_CHANNEL_LAYOUT_5_1_B ((113<<8)|6|AF_LFE) // L R Ls Rs C LFE
#define AF_CHANNEL_LAYOUT_5_1_C ((114<<8)|6|AF_LFE) // L C R Ls Rs LFE
#define AF_CHANNEL_LAYOUT_5_1_D ((115<<8)|6|AF_LFE) // C L R Ls Rs LFE
#define AF_CHANNEL_LAYOUT_5_1_E ((116<<8)|6|AF_LFE) // LFE L C R Ls Rs
#define AF_CHANNEL_LAYOUT_5_1_F ((117<<8)|6|AF_LFE) // C L R LFE Ls Rs
#define AF_CHANNEL_LAYOUT_6_1_A ((118<<8)|7|AF_LFE) // L R C LFE Ls Rs Cs
#define AF_CHANNEL_LAYOUT_7_1_A ((119<<8)|8|AF_LFE) // L R C LFE Ls Rs Rls Rrs
#define AF_CHANNEL_LAYOUT_7_1_B ((120<<8)|8|AF_LFE) // L R Ls Rs C LFE Rls Rrs
#define AF_CHANNEL_LAYOUT_7_1_C ((121<<8)|8|AF_LFE) // L C R Ls Rs LFE Rls Rrs
#define AF_CHANNEL_LAYOUT_7_1_D ((122<<8)|8|AF_LFE) // C L R Ls Rs Rls Rrs LFE
#define AF_CHANNEL_LAYOUT_7_1_F ((123<<8)|8|AF_LFE) // C L R LFE Ls Rs Rls Rrs
#define AF_CHANNEL_LAYOUT_ALSA_5CH_DEFAULT AF_CHANNEL_LAYOUT_5_0_B
#define AF_CHANNEL_LAYOUT_ALSA_6CH_DEFAULT AF_CHANNEL_LAYOUT_5_1_B
#define AF_CHANNEL_LAYOUT_ALSA_8CH_DEFAULT AF_CHANNEL_LAYOUT_7_1_B
#define AF_CHANNEL_LAYOUT_MPLAYER_5CH_DEFAULT AF_CHANNEL_LAYOUT_ALSA_5CH_DEFAULT
#define AF_CHANNEL_LAYOUT_MPLAYER_6CH_DEFAULT AF_CHANNEL_LAYOUT_ALSA_6CH_DEFAULT
#define AF_CHANNEL_LAYOUT_MPLAYER_8CH_DEFAULT AF_CHANNEL_LAYOUT_ALSA_8CH_DEFAULT
#define AF_CHANNEL_LAYOUT_AAC_5CH_DEFAULT AF_CHANNEL_LAYOUT_5_0_D
#define AF_CHANNEL_LAYOUT_AAC_6CH_DEFAULT AF_CHANNEL_LAYOUT_5_1_D
#define AF_CHANNEL_LAYOUT_AAC_8CH_DEFAULT AF_CHANNEL_LAYOUT_7_1_D
#define AF_CHANNEL_LAYOUT_WAVEEX_5CH_DEFAULT AF_CHANNEL_LAYOUT_5_0_A
#define AF_CHANNEL_LAYOUT_WAVEEX_6CH_DEFAULT AF_CHANNEL_LAYOUT_5_1_A
#define AF_CHANNEL_LAYOUT_WAVEEX_8CH_DEFAULT AF_CHANNEL_LAYOUT_7_1_A
#define AF_CHANNEL_LAYOUT_LAVC_5CH_DEFAULT AF_CHANNEL_LAYOUT_5_0_A
#define AF_CHANNEL_LAYOUT_LAVC_6CH_DEFAULT AF_CHANNEL_LAYOUT_5_1_A
#define AF_CHANNEL_LAYOUT_LAVC_8CH_DEFAULT AF_CHANNEL_LAYOUT_7_1_A
#define AF_CHANNEL_LAYOUT_VORBIS_5CH_DEFAULT AF_CHANNEL_LAYOUT_5_0_C
#define AF_CHANNEL_LAYOUT_VORBIS_6CH_DEFAULT AF_CHANNEL_LAYOUT_5_1_C
#define AF_CHANNEL_LAYOUT_VORBIS_8CH_DEFAULT AF_CHANNEL_LAYOUT_7_1_C
#define AF_CHANNEL_MASK 0xFF
#define AF_GET_CH_NUM(A) ((A)&0x7F)
#define AF_GET_CH_NUM_WITH_LFE(A) ((A)&0xFF)
#define AF_IS_SAME_CH_NUM(A,B) (((A)&0xFF)==((B)&0xFF))
#define AF_IS_LAYOUT_SPECIFIED(A) ((A)&0xFFFFF800)
#define AF_IS_LAYOUT_UNSPECIFIED(A) (!AF_IS_LAYOUT_SPECIFIED(A))
/// Optimized channel reorder between channel layouts with same channel number.
void reorder_channel_copy(void *src,
int src_layout,
void *dest,
int dest_layout,
int samples,
int samplesize);
/// Same with reorder_channel_copy, but works on single buffer.
void reorder_channel(void *buf,
int src_layout,
int dest_layout,
int samples,
int samplesize);
// Channel layout definitions for different audio sources or targets
// When specified channel number, they will be map to the specific layouts.
#define AF_CHANNEL_LAYOUT_ALSA_DEFAULT 0
#define AF_CHANNEL_LAYOUT_AAC_DEFAULT 1
#define AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT 2
#define AF_CHANNEL_LAYOUT_LAVC_DEFAULT 3
#define AF_CHANNEL_LAYOUT_VORBIS_DEFAULT 4
#define AF_CHANNEL_LAYOUT_SOURCE_NUM 5
#define AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT AF_CHANNEL_LAYOUT_ALSA_DEFAULT
/// Optimized channel reorder between different audio sources and targets.
void reorder_channel_copy_nch(void *src,
int src_layout,
void *dest,
int dest_layout,
int chnum,
int samples,
int samplesize);
/// Same with reorder_channel_copy_nch, but works on single buffer.
void reorder_channel_nch(void *buf,
int src_layout,
int dest_layout,
int chnum,
int samples,
int samplesize);
/// Utility function for planar audio conversions
void reorder_to_planar(void *restrict out, const void *restrict in,
size_t size, size_t nchan, size_t nmemb);
void reorder_to_packed(uint8_t *out, uint8_t **in,

View File

@ -175,11 +175,6 @@ const m_option_t mfopts_conf[]={
#include "audio/filter/af.h"
extern struct af_cfg af_cfg; // Audio filter configuration, defined in libmpcodecs/dec_audio.c
const m_option_t audio_filter_conf[]={
{"list", &af_cfg.list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL},
{"force", &af_cfg.force, CONF_TYPE_INT, CONF_RANGE, 0, 7, NULL},
{NULL, NULL, 0, 0, 0, 0, NULL}
};
extern int mp_msg_levels[MSGT_MAX];
extern int mp_msg_level_all;
@ -281,6 +276,7 @@ const m_option_t msgl_config[]={
};
extern const m_option_t lavc_decode_opts_conf[];
extern const m_option_t ad_lavc_decode_opts_conf[];
#define OPT_BASE_STRUCT struct MPOpts
@ -418,7 +414,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),
@ -428,15 +424,12 @@ const m_option_t common_opts[] = {
// ignore header-specified delay (dwStart)
OPT_FLAG("ignore-start", ignore_start, 0),
OPT_FLOATRANGE("a52drc", drc_level, 0, 0, 2),
// ------------------------- codec/vfilter options --------------------
// MP3-only: select stereo/left/right
{"stereo", &fakemono, CONF_TYPE_INT, CONF_RANGE, 0, 2, NULL},
{"af*", &af_cfg.list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL},
{"af-adv", (void *) audio_filter_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
OPT_SETTINGSLIST("vf*", vf_settings, 0, &vf_obj_list),
@ -472,6 +465,8 @@ const m_option_t common_opts[] = {
{"lavdopts", (void *) lavc_decode_opts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
{"lavfdopts", (void *) lavfdopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
{"ad-lavc", (void *) ad_lavc_decode_opts_conf, CONF_TYPE_SUBCONFIG},
// ------------------------- subtitles options --------------------
OPT_STRINGLIST("sub", sub_name, 0),

View File

@ -684,20 +684,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;
@ -2319,7 +2309,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
break;
}
af->control(af, AF_CONTROL_COMMAND_LINE, cmd->args[1].v.s);
af_reinit(sh_audio->afilter, af);
af_reinit(sh_audio->afilter);
}
break;
case MP_CMD_SHOW_CHAPTERS:

View File

@ -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)
{
@ -72,10 +73,9 @@ 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.,
.drc_level = 1.,
.movie_aspect = -1.,
.sub_auto = 1,
.osd_bar_visible = 1,
@ -93,6 +93,10 @@ void set_default_mplayer_options(struct MPOpts *opts)
.workaround_bugs = 1, // autodetect
.error_concealment = 3,
},
.ad_lavc_param = {
.ac3drc = 1.,
.downmix = 1,
},
.input = {
.key_fifo_size = 7,
.ar_delay = 200,

View File

@ -1604,6 +1604,48 @@ const m_option_type_t m_option_type_afmt = {
.copy = copy_opt,
};
#include "audio/chmap.h"
static int parse_chmap(const m_option_t *opt, struct bstr name,
struct bstr param, void *dst)
{
// min>0: at least min channels, min=0: empty ok, min=-1: invalid ok
int min_ch = (opt->flags & M_OPT_MIN) ? opt->min : 1;
if (bstr_equals0(param, "help")) {
mp_chmap_print_help(MSGT_CFGPARSER, MSGL_INFO);
return M_OPT_EXIT - 1;
}
if (param.len == 0 && min_ch >= 1)
return M_OPT_MISSING_PARAM;
struct mp_chmap res = {0};
if (!mp_chmap_from_str(&res, param)) {
mp_msg(MSGT_CFGPARSER, MSGL_ERR,
"Error parsing channel layout: %.*s\n", BSTR_P(param));
return M_OPT_INVALID;
}
if ((min_ch > 0 && !mp_chmap_is_valid(&res)) ||
(min_ch >= 0 && mp_chmap_is_empty(&res)))
{
mp_msg(MSGT_CFGPARSER, MSGL_ERR,
"Invalid channel layout: %.*s\n", BSTR_P(param));
return M_OPT_INVALID;
}
*(struct mp_chmap *)dst = res;
return 1;
}
const m_option_type_t m_option_type_chmap = {
.name = "Audio channels or channel map",
.size = sizeof(struct mp_chmap *),
.parse = parse_chmap,
.copy = copy_opt,
};
static int parse_timestring(struct bstr str, double *time, char endchar)
{

View File

@ -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.
@ -60,6 +61,7 @@ extern const m_option_type_t m_option_type_afmt;
extern const m_option_type_t m_option_type_color;
extern const m_option_type_t m_option_type_geometry;
extern const m_option_type_t m_option_type_size_box;
extern const m_option_type_t m_option_type_chmap;
// Callback used by m_option_type_print_func options.
typedef int (*m_opt_func_full_t)(const m_option_t *, const char *, const char *);
@ -194,6 +196,7 @@ union m_option_value {
struct m_color color;
struct m_geometry geometry;
struct m_geometry size_box;
struct mp_chmap chmap;
};
////////////////////////////////////////////////////////////////////////////
@ -568,6 +571,9 @@ int m_option_required_params(const m_option_t *opt);
#define OPT_AUDIOFORMAT(...) \
OPT_GENERAL(int, __VA_ARGS__, .type = &m_option_type_afmt)
#define OPT_CHMAP(...) \
OPT_GENERAL(struct mp_chmap, __VA_ARGS__, .type = &m_option_type_chmap)
#define M_CHOICES(choices) \
.priv = (void *)&(const struct m_opt_choice_alternatives[]){ \

View File

@ -330,7 +330,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) {
@ -1700,6 +1700,12 @@ void reinit_audio_chain(struct MPContext *mpctx)
mpctx->ao = ao_create(opts, mpctx->input);
mpctx->ao->samplerate = opts->force_srate;
mpctx->ao->format = opts->audio_output_format;
// Automatic downmix
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;
@ -1716,6 +1722,8 @@ void reinit_audio_chain(struct MPContext *mpctx)
if (!ao->initialized) {
ao->buffersize = opts->ao_buffersize;
ao->encode_lavc_ctx = mpctx->encode_lavc_ctx;
mp_chmap_remove_useless_channels(&ao->channels,
&opts->audio_output_channels);
ao_init(ao, opts->audio_driver_list);
if (!ao->initialized) {
mp_tmsg(MSGT_CPLAYER, MSGL_ERR,
@ -1723,12 +1731,10 @@ void reinit_audio_chain(struct MPContext *mpctx)
goto init_error;
}
ao->buffer.start = talloc_new(ao);
mp_msg(MSGT_CPLAYER, MSGL_INFO,
"AO: [%s] %dHz %dch %s (%d bytes per sample)\n",
ao->driver->info->short_name,
ao->samplerate, ao->channels,
af_fmt2str_short(ao->format),
af_fmt2bits(ao->format) / 8);
char *s = mp_audio_fmt_to_str(ao->samplerate, &ao->channels, ao->format);
mp_msg(MSGT_CPLAYER, MSGL_INFO, "AO: [%s] %s\n",
ao->driver->info->short_name, s);
talloc_free(s);
mp_msg(MSGT_CPLAYER, MSGL_V, "AO: Description: %s\nAO: Author: %s\n",
ao->driver->info->name, ao->driver->info->author);
if (strlen(ao->driver->info->comment) > 0)
@ -2295,7 +2301,7 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
ptsdiff = written_pts - mpctx->sh_video->pts - mpctx->delay
- mpctx->audio_delay;
bytes = ptsdiff * bps;
bytes -= bytes % (ao->channels * af_fmt2bits(ao->format) / 8);
bytes -= bytes % (ao->channels.num * af_fmt2bits(ao->format) / 8);
// ogg demuxers give packets without timing
if (written_pts <= 1 && sh_audio->pts == MP_NOPTS_VALUE) {
@ -2364,7 +2370,7 @@ static int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
bool partial_fill = false;
sh_audio_t * const sh_audio = mpctx->sh_audio;
bool modifiable_audio_format = !(ao->format & AF_FORMAT_SPECIAL_MASK);
int unitsize = ao->channels * af_fmt2bits(ao->format) / 8;
int unitsize = ao->channels.num * af_fmt2bits(ao->format) / 8;
if (mpctx->paused)
playsize = 1; // just initialize things (audio pts at least)

View File

@ -155,12 +155,11 @@ 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;
float playback_speed;
float drc_level;
struct m_obj_settings *vf_settings;
float movie_aspect;
int flip;
@ -210,6 +209,12 @@ typedef struct MPOpts {
char *avopt;
} lavc_param;
struct ad_lavc_param {
float ac3drc;
int downmix;
char *avopt;
} ad_lavc_param;
struct lavfdopts {
int probesize;
int probescore;

View File

@ -340,7 +340,9 @@ static void handle_stream(demuxer_t *demuxer, 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;

View File

@ -1349,7 +1349,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;
@ -1367,7 +1367,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');
@ -1539,7 +1539,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.

View File

@ -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));
}

View File

@ -23,6 +23,7 @@
#include "codec_tags.h"
#include "audio/chmap.h"
#include "aviheader.h"
#include "ms_hdr.h"
struct MPOpts;
@ -96,8 +97,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

View File

@ -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",