summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-09-24 22:55:50 +0200
committerwm4 <wm4@nowhere>2014-09-24 22:55:50 +0200
commit9ac86d9e994aeb764207f4d0279b3d37266f79e6 (patch)
treee1d7ca4e241e8dbe551e9a65eb7dd1e0b4008876
parent8a8f65d73d7009b13571293d1de6284d42a318e8 (diff)
downloadmpv-9ac86d9e994aeb764207f4d0279b3d37266f79e6.tar.bz2
mpv-9ac86d9e994aeb764207f4d0279b3d37266f79e6.tar.xz
audio: decouple demux and audio decoder/filter sample formats
For a while, we used this to transfer PCM from demuxer to the filter chain. We had a special "codec" that mapped what MPlayer used to do (MPlayer passes the AF sample format over an extra field to ad_pcm, which specially interprets it). Do this by providing a mp_set_pcm_codec() function, which describes a sample format in a generic way, and sets the appropriate demuxer header fields so that libavcodec interprets it correctly. We use the fact that libavcodec has separate PCM decoders for each format. These are systematically named, so we can easily map them. This has the advantage that we can change the audio filter chain as we like, without losing features from the "rawaudio" demuxer. In fact, this commit also gets rid of the audio filter chain formats completely. Instead have an explicit list of PCM formats. (We could even just have the user pass libavcodec PCM decoder names directly, but that would be annoying in other ways.)
-rw-r--r--DOCS/man/options.rst1
-rw-r--r--audio/decode/ad_lavc.c37
-rw-r--r--demux/codec_tags.c16
-rw-r--r--demux/codec_tags.h4
-rw-r--r--demux/demux_raw.c61
-rw-r--r--demux/demux_tv.c30
-rw-r--r--demux/stheader.h2
7 files changed, 66 insertions, 85 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index 70a11e7cc3..b61484ccfe 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -2005,6 +2005,7 @@ Demuxer
``--demuxer-rawaudio-format=<value>``
Sample format for ``--demuxer=rawaudio`` (default: s16le).
+ Use ``--demuxer-rawaudio-format=help`` to get a list of all formats.
``--demuxer-rawaudio-rate=<value>``
Sample rate for ``--demuxer=rawaudio`` (default: 44 kHz).
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index 443cfdad54..56d68bbd90 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -94,35 +94,6 @@ static const struct pcm_map tag_map[] = {
{-1},
};
-// For demux_rawaudio.c; needed because ffmpeg doesn't have these sample
-// formats natively.
-static const struct pcm_map af_map_le[] = {
- {AF_FORMAT_U8, {"pcm_u8"}},
- {AF_FORMAT_S8, {"pcm_u8"}},
- {AF_FORMAT_U16, {"pcm_u16le"}},
- {AF_FORMAT_S16, {"pcm_s16le"}},
- {AF_FORMAT_U24, {"pcm_u24le"}},
- {AF_FORMAT_S24, {"pcm_s24le"}},
- {AF_FORMAT_U32, {"pcm_u32le"}},
- {AF_FORMAT_S32, {"pcm_s32le"}},
- {AF_FORMAT_FLOAT, {"pcm_f32le"}},
- {AF_FORMAT_DOUBLE, {"pcm_f64le"}},
- {-1},
-};
-static const struct pcm_map af_map_be[] = {
- {AF_FORMAT_U8, {"pcm_u8"}},
- {AF_FORMAT_S8, {"pcm_u8"}},
- {AF_FORMAT_U16, {"pcm_u16be"}},
- {AF_FORMAT_S16, {"pcm_s16be"}},
- {AF_FORMAT_U24, {"pcm_u24be"}},
- {AF_FORMAT_S24, {"pcm_s24be"}},
- {AF_FORMAT_U32, {"pcm_u32be"}},
- {AF_FORMAT_S32, {"pcm_s32be"}},
- {AF_FORMAT_FLOAT, {"pcm_f32be"}},
- {AF_FORMAT_DOUBLE, {"pcm_f64be"}},
- {-1},
-};
-
static const char *find_pcm_decoder(const struct pcm_map *map, int format,
int bits_per_sample)
{
@@ -202,12 +173,10 @@ static int init(struct dec_audio *da, const char *decoder)
if (sh_audio->wf && strcmp(decoder, "pcm") == 0) {
decoder = find_pcm_decoder(tag_map, sh->format,
sh_audio->wf->wBitsPerSample);
- } else if (sh_audio->wf && strcmp(decoder, "mp-pcm") == 0) {
- const struct pcm_map *map = sh_audio->big_endian ? af_map_be : af_map_le;
- decoder = find_pcm_decoder(map, sh->format, 0);
- ctx->force_channel_map = true;
}
+ ctx->force_channel_map = sh_audio->force_channels;
+
lavc_codec = avcodec_find_decoder_by_name(decoder);
if (!lavc_codec) {
MP_ERR(da, "Cannot find codec '%s' in libavcodec...\n", decoder);
@@ -236,6 +205,7 @@ static int init(struct dec_audio *da, const char *decoder)
lavc_context->codec_tag = sh->format;
lavc_context->sample_rate = sh_audio->samplerate;
lavc_context->bit_rate = sh_audio->bitrate;
+ lavc_context->channels = sh_audio->channels.num;
lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
if (sh_audio->wf)
@@ -367,7 +337,6 @@ static void add_decoders(struct mp_decoder_list *list)
{
mp_add_lavc_decoders(list, AVMEDIA_TYPE_AUDIO);
mp_add_decoder(list, "lavc", "pcm", "pcm", "Raw PCM");
- mp_add_decoder(list, "lavc", "mp-pcm", "mp-pcm", "Raw PCM");
}
const struct ad_functions ad_lavc = {
diff --git a/demux/codec_tags.c b/demux/codec_tags.c
index 3f5a3e0922..23e1935dba 100644
--- a/demux/codec_tags.c
+++ b/demux/codec_tags.c
@@ -383,3 +383,19 @@ uint32_t mp_video_fourcc_alias(uint32_t fourcc)
}
return fourcc;
}
+
+void mp_set_pcm_codec(struct sh_stream *sh, bool sign, bool is_float, int bits,
+ bool is_be)
+{
+ // This uses libavcodec pcm codec names, e.g. "pcm_u16le".
+ char codec[64] = "pcm_";
+ if (is_float) {
+ mp_snprintf_cat(codec, sizeof(codec), "f");
+ } else {
+ mp_snprintf_cat(codec, sizeof(codec), sign ? "s" : "u");
+ }
+ mp_snprintf_cat(codec, sizeof(codec), "%d", bits);
+ if (bits != 8)
+ mp_snprintf_cat(codec, sizeof(codec), is_be ? "be" : "le");
+ sh->codec = talloc_strdup(sh->audio, codec);
+}
diff --git a/demux/codec_tags.h b/demux/codec_tags.h
index d8c63800b1..b65b68792a 100644
--- a/demux/codec_tags.h
+++ b/demux/codec_tags.h
@@ -19,6 +19,7 @@
#define MP_CODEC_TAGS_H
#include <stdint.h>
+#include <stdbool.h>
uint32_t mp_video_fourcc_alias(uint32_t fourcc);
@@ -26,4 +27,7 @@ struct sh_stream;
void mp_set_codec_from_tag(struct sh_stream *sh);
+void mp_set_pcm_codec(struct sh_stream *sh, bool sign, bool is_float, int bits,
+ bool is_be);
+
#endif
diff --git a/demux/demux_raw.c b/demux/demux_raw.c
index 552c74a2a3..6faea6e61d 100644
--- a/demux/demux_raw.c
+++ b/demux/demux_raw.c
@@ -29,7 +29,7 @@
#include "stream/stream.h"
#include "demux.h"
#include "stheader.h"
-#include "audio/format.h"
+#include "codec_tags.h"
#include "video/img_format.h"
#include "video/img_fourcc.h"
@@ -40,16 +40,37 @@ struct demux_rawaudio_opts {
struct mp_chmap channels;
int samplerate;
int aformat;
- int endian;
};
+// Ad-hoc schema to systematically encode the format as int
+#define PCM(sign, is_float, bits, is_be) \
+ ((sign) | ((is_float) << 1) | ((is_be) << 2) | ((bits) << 3))
+#define NE (BYTE_ORDER == BIG_ENDIAN)
+
#define OPT_BASE_STRUCT struct demux_rawaudio_opts
const struct m_sub_options demux_rawaudio_conf = {
.opts = (const m_option_t[]) {
OPT_CHMAP("channels", channels, CONF_MIN, .min = 1),
OPT_INTRANGE("rate", samplerate, 0, 1000, 8 * 48000),
- OPT_AUDIOFORMAT("format", aformat, 0),
- OPT_CHOICE("endian", endian, 0, ({"native", 0}, {"le", 1}, {"be", 2})),
+ OPT_CHOICE("format", aformat, 0,
+ ({"u8", PCM(0, 0, 8, 0)},
+ {"s8", PCM(1, 0, 8, 0)},
+ {"u16le", PCM(0, 0, 16, 0)}, {"u16be", PCM(0, 0, 16, 1)},
+ {"s16le", PCM(1, 0, 16, 0)}, {"u16be", PCM(1, 0, 16, 1)},
+ {"u24le", PCM(0, 0, 24, 0)}, {"u24be", PCM(0, 0, 24, 1)},
+ {"s24le", PCM(1, 0, 24, 0)}, {"s24be", PCM(1, 0, 24, 1)},
+ {"u32le", PCM(0, 0, 32, 0)}, {"u32be", PCM(0, 0, 32, 1)},
+ {"s32le", PCM(1, 0, 32, 0)}, {"s32be", PCM(1, 0, 32, 1)},
+ {"floatle", PCM(0, 1, 32, 0)}, {"floatbe", PCM(0, 1, 32, 1)},
+ {"doublele",PCM(0, 1, 64, 0)}, {"doublebe", PCM(0, 1, 64, 1)},
+ {"u16", PCM(0, 0, 16, NE)},
+ {"s16", PCM(1, 0, 16, NE)},
+ {"u24", PCM(0, 0, 24, NE)},
+ {"s24", PCM(1, 0, 24, NE)},
+ {"u32", PCM(0, 0, 32, NE)},
+ {"s32", PCM(1, 0, 32, NE)},
+ {"float", PCM(0, 1, 32, NE)},
+ {"double", PCM(0, 1, 64, NE)})),
{0}
},
.size = sizeof(struct demux_rawaudio_opts),
@@ -57,11 +78,13 @@ const struct m_sub_options demux_rawaudio_conf = {
// Note that currently, stream_cdda expects exactly these parameters!
.channels = MP_CHMAP_INIT_STEREO,
.samplerate = 44100,
- .aformat = AF_FORMAT_S16,
- .endian = 0,
+ .aformat = PCM(1, 0, 16, NE), // s16
},
};
+#undef PCM
+#undef NE
+
struct demux_rawvideo_opts {
int vformat;
int mp_format;
@@ -105,32 +128,20 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check)
struct demux_rawaudio_opts *opts = demuxer->opts->demux_rawaudio;
struct sh_stream *sh;
sh_audio_t *sh_audio;
- MP_WAVEFORMATEX *w;
if (check != DEMUX_CHECK_REQUEST && check != DEMUX_CHECK_FORCE)
return -1;
- if (AF_FORMAT_IS_SPECIAL(opts->aformat))
- return -1;
-
sh = new_sh_stream(demuxer, STREAM_AUDIO);
sh_audio = sh->audio;
- sh->codec = "mp-pcm";
- sh->format = opts->aformat;
- sh_audio->wf = w = talloc_zero(sh, MP_WAVEFORMATEX);
- w->wFormatTag = 0;
sh_audio->channels = opts->channels;
- w->nChannels = sh_audio->channels.num;
- w->nSamplesPerSec = sh_audio->samplerate = opts->samplerate;
- int samplesize = af_fmt2bps(opts->aformat);
- w->nAvgBytesPerSec = sh_audio->samplerate * samplesize * w->nChannels;
- w->nBlockAlign = w->nChannels * samplesize;
- w->wBitsPerSample = 8 * samplesize;
- w->cbSize = 0;
- int machine_endian = BYTE_ORDER == BIG_ENDIAN ? 2 : 1;
- int endian = opts->endian ? opts->endian : machine_endian;
- // wav usually implies little endian
- sh_audio->big_endian = endian == 2;
+ sh_audio->force_channels = true;
+ sh_audio->samplerate = opts->samplerate;
+
+ int f = opts->aformat;
+ // See PCM(): sign float bits endian
+ mp_set_pcm_codec(sh, f & 1, f & 2, f >> 3, f & 4);
+ int samplesize = ((f >> 3) + 7) / 8;
struct priv *p = talloc_ptrtype(demuxer, p);
demuxer->priv = p;
diff --git a/demux/demux_tv.c b/demux/demux_tv.c
index a4421a86cf..198ca922e5 100644
--- a/demux/demux_tv.c
+++ b/demux/demux_tv.c
@@ -8,6 +8,7 @@
#include "options/options.h"
#include "demux.h"
+#include "codec_tags.h"
#include "audio/format.h"
#include "video/img_fourcc.h"
@@ -105,11 +106,8 @@ static int demux_open_tv(demuxer_t *demuxer, enum demux_check check)
switch(audio_format)
{
- case AF_FORMAT_U8:
- case AF_FORMAT_S8:
- case AF_FORMAT_U16:
+ // This is the only format any of the current inputs generate.
case AF_FORMAT_S16:
- case AF_FORMAT_S32:
break;
default:
MP_ERR(tvh, "Audio type '%s' unsupported!\n",
@@ -127,29 +125,11 @@ static int demux_open_tv(demuxer_t *demuxer, enum demux_check check)
&nchannels);
mp_chmap_from_channels(&sh_audio->channels, nchannels);
- sh_a->codec = "mp-pcm";
- sh_a->format = audio_format;
-
- int samplesize = af_fmt2bps(audio_format);
- int block_align = samplesize * sh_audio->channels.num;
- int bytes_per_second = sh_audio->samplerate * block_align;
-
- sh_audio->bitrate = bytes_per_second * 8;
-
- // emulate WF for win32 codecs:
- sh_audio->wf = talloc_zero(sh_audio, MP_WAVEFORMATEX);
- sh_audio->wf->wFormatTag = sh_a->format;
- sh_audio->wf->nChannels = sh_audio->channels.num;
- sh_audio->wf->wBitsPerSample = samplesize * 8;
- sh_audio->wf->nSamplesPerSec = sh_audio->samplerate;
- sh_audio->wf->nBlockAlign = block_align;
- sh_audio->wf->nAvgBytesPerSec = bytes_per_second;
- // wav header usually implies little endian
- sh_audio->big_endian = BYTE_ORDER == BIG_ENDIAN;
+ // s16ne
+ mp_set_pcm_codec(sh_a, true, false, 16, BYTE_ORDER == BIG_ENDIAN);
MP_VERBOSE(tvh, " TV audio: %d channels, %d bits, %d Hz\n",
- sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample,
- sh_audio->wf->nSamplesPerSec);
+ nchannels, 16, sh_audio->samplerate);
}
no_audio:
diff --git a/demux/stheader.h b/demux/stheader.h
index 806f7d9c5a..a2740f0189 100644
--- a/demux/stheader.h
+++ b/demux/stheader.h
@@ -67,10 +67,10 @@ struct sh_stream {
typedef struct sh_audio {
int samplerate;
struct mp_chmap channels;
+ bool force_channels;
int bitrate; // compressed bits/sec
// win32-compatible codec parameters:
MP_WAVEFORMATEX *wf;
- bool big_endian; // endianess with wf and mp-pcm
// note codec extradata may be either under "wf" or "codecdata"
unsigned char *codecdata;
int codecdata_len;