summaryrefslogtreecommitdiffstats
path: root/audio/decode/ad_lavc.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2012-12-09 18:53:24 +0100
committerwm4 <wm4@nowhere>2012-12-11 00:37:54 +0100
commit2dd2d9bcfcf57b9921c9ef360746dd59c45574fd (patch)
treefc470ed6d914e9b04e8b0fb33f51ce0346b86804 /audio/decode/ad_lavc.c
parent58f3b7548588c224099fa059868116be003678bd (diff)
downloadmpv-2dd2d9bcfcf57b9921c9ef360746dd59c45574fd.tar.bz2
mpv-2dd2d9bcfcf57b9921c9ef360746dd59c45574fd.tar.xz
audio/decode: remove ad_pcm and use ad_lavc for PCM
Since libavcodec doesn't have a "generic" PCM decoder, we have to go out of out way to make it look like ad_lavc provides one: make it provide a pseudo "pcm" decoder, which maps some format tags manually to the individual libavcodec PCM decoders. Format tags which uniquely map to one libavcodec could be mapped via codecs.conf. Since defining these in tag_map[] is much shorter (one line vs. a full codec entry in codecs.conf), and since we need tag_map[] anyway, we don't use codecs.conf for these. ad_pcm is evil because it still does partial packet reads (with demux_read_data()), and it's redundant to libavcodec anyway.
Diffstat (limited to 'audio/decode/ad_lavc.c')
-rw-r--r--audio/decode/ad_lavc.c99
1 files changed, 95 insertions, 4 deletions
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index 8553e93cf1..e0e39e1e7d 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -59,6 +59,86 @@ struct priv {
int previous_data_left; // input demuxer packet data
};
+struct pcm_map
+{
+ int tag;
+ const char *codecs[5]; // {any, 1byte, 2bytes, 3bytes, 4bytes}
+};
+
+// NOTE: some of these are needed to make rawaudio with demux_mkv and others
+// work. ffmpeg does similar mapping internally, not part of the public
+// API. Some of these might be dead leftovers for demux_mov support.
+static const struct pcm_map tag_map[] = {
+ // Microsoft PCM
+ {0x0, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
+ {0x1, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
+ // MS PCM, Extended
+ {0xfffe, {NULL, "pcm_u8", "pcm_s16le", "pcm_s24le", "pcm_s32le"}},
+ // IEEE float
+ {0x3, {"pcm_f32le"}},
+ // 'raw '
+ {0x20776172, {"pcm_s16be", [1] = "pcm_u8"}},
+ // 'twos'/'sowt'
+ {0x736F7774, {"pcm_s16be", [1] = "pcm_s8"}},
+ {0x74776F73, {"pcm_s16be", [1] = "pcm_s8"}},
+ // 'fl32'/'FL32'
+ {0x32336c66, {"pcm_f32be"}},
+ {0x32334C46, {"pcm_f32be"}},
+ // '23lf'/'lpcm'
+ {0x666c3332, {"pcm_f32le"}},
+ {0x6D63706C, {"pcm_f32le"}},
+ // 'in24', bigendian int24
+ {0x34326e69, {"pcm_s24be"}},
+ // '42ni', little endian int24, MPlayer internal fourCC
+ {0x696e3234, {"pcm_s24le"}},
+ // 'in32', bigendian int32
+ {0x32336e69, {"pcm_s32be"}},
+ // '23ni', little endian int32, MPlayer internal fourCC
+ {0x696e3332, {"pcm_s32le"}},
+ {-1},
+};
+
+// For demux_rawaudio.c; needed because ffmpeg doesn't have these sample
+// formats natively.
+static const struct pcm_map af_map[] = {
+ {AF_FORMAT_U8, {"pcm_u8"}},
+ {AF_FORMAT_S8, {"pcm_u8"}},
+ {AF_FORMAT_U16_LE, {"pcm_u16le"}},
+ {AF_FORMAT_U16_BE, {"pcm_u16be"}},
+ {AF_FORMAT_S16_LE, {"pcm_s16le"}},
+ {AF_FORMAT_S16_BE, {"pcm_s16be"}},
+ {AF_FORMAT_U24_LE, {"pcm_u24le"}},
+ {AF_FORMAT_U24_BE, {"pcm_u24be"}},
+ {AF_FORMAT_S24_LE, {"pcm_s24le"}},
+ {AF_FORMAT_S24_BE, {"pcm_s24be"}},
+ {AF_FORMAT_U32_LE, {"pcm_u32le"}},
+ {AF_FORMAT_U32_BE, {"pcm_u32be"}},
+ {AF_FORMAT_S32_LE, {"pcm_s32le"}},
+ {AF_FORMAT_S32_BE, {"pcm_s32be"}},
+ {AF_FORMAT_FLOAT_LE, {"pcm_f32le"}},
+ {AF_FORMAT_FLOAT_BE, {"pcm_f32be"}},
+ {-1},
+};
+
+static const char *find_pcm_decoder(const struct pcm_map *map, int format,
+ int bits_per_sample)
+{
+ int bytes = (bits_per_sample + 7) / 8;
+ for (int n = 0; map[n].tag != -1; n++) {
+ const struct pcm_map *entry = &map[n];
+ if (entry->tag == format) {
+ const char *dec = NULL;
+ if (bytes >= 1 && bytes <= 4)
+ dec = entry->codecs[bytes];
+ if (!dec)
+ dec = entry->codecs[0];
+ if (dec)
+ return dec;
+ }
+ }
+ return NULL;
+}
+
static int preinit(sh_audio_t *sh)
{
return 1;
@@ -115,12 +195,23 @@ static int init(sh_audio_t *sh_audio)
AVCodecContext *lavc_context;
AVCodec *lavc_codec;
- if (sh_audio->codec->dll) {
- lavc_codec = avcodec_find_decoder_by_name(sh_audio->codec->dll);
+ const char *dll = sh_audio->codec->dll;
+
+ if (sh_audio->wf && dll && strcmp(dll, "pcm") == 0) {
+ if (sh_audio->format == MKTAG('M', 'P', 'a', 'f')) {
+ // demuxer_rawaudio convenience (abuses wFormatTag)
+ dll = find_pcm_decoder(af_map, sh_audio->wf->wFormatTag, 0);
+ } else {
+ dll = find_pcm_decoder(tag_map, sh_audio->format,
+ sh_audio->wf->wBitsPerSample);
+ }
+ }
+
+ if (dll) {
+ lavc_codec = avcodec_find_decoder_by_name(dll);
if (!lavc_codec) {
mp_tmsg(MSGT_DECAUDIO, MSGL_ERR,
- "Cannot find codec '%s' in libavcodec...\n",
- sh_audio->codec->dll);
+ "Cannot find codec '%s' in libavcodec...\n", dll);
return 0;
}
} else if (!sh_audio->libav_codec_id) {