diff --git a/demux/codec_tags.c b/demux/codec_tags.c index e520161b87..c74f66f30c 100644 --- a/demux/codec_tags.c +++ b/demux/codec_tags.c @@ -18,6 +18,8 @@ #include #include #include +#include + #include "codec_tags.h" #include "stheader.h" #include "common/av_common.h" @@ -48,14 +50,50 @@ static const char *lookup_tag(int type, uint32_t tag) return id == AV_CODEC_ID_NONE ? NULL : mp_codec_from_av_codec_id(id); } +static const unsigned char guid_pcm[16] = + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}; +static const unsigned char guid_float[16] = + {0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}; +// Corresponds to FF_MEDIASUBTYPE_BASE_GUID (plus 4 bytes of padding). +static const unsigned char guid_ffext[16] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}; + static void map_audio_pcm_tag(struct mp_codec_params *c) { + // MS PCM, Extended + if (c->codec_tag == 0xfffe && c->extradata_size >= 22) { + // WAVEFORMATEXTENSIBLE.dwChannelMask + uint64_t chmask = AV_RL32(c->extradata + 2); + struct mp_chmap chmap; + mp_chmap_from_waveext(&chmap, chmask); + if (c->channels.num == chmap.num) + c->channels = chmap; + + // WAVEFORMATEXTENSIBLE.SubFormat + unsigned char *subformat = c->extradata + 6; + if (memcmp(subformat + 4, guid_ffext + 4, 12) == 0) { + // libavformat extension. + c->codec_tag = AV_RL32(subformat); + c->codec = lookup_tag(c->type, c->codec_tag); + } + if (memcmp(subformat, guid_pcm, 16) == 0) + c->codec_tag = 0x0; + if (memcmp(subformat, guid_float, 16) == 0) + c->codec_tag = 0x3; + + // Compressed formats might use this. + c->extradata += 22; + c->extradata_size += 22; + } + int bits = c->bits_per_coded_sample; int bytes = (bits + 7) / 8; switch (c->codec_tag) { case 0x0: // Microsoft PCM case 0x1: - case 0xfffe: // MS PCM, Extended if (bytes >= 1 && bytes <= 4) mp_set_pcm_codec(c, bytes > 1, false, bytes * 8, false); break; diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 9515cd10c5..97c7d3e09b 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1549,12 +1549,12 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) unsigned char *extradata = track->private_data; unsigned int extradata_len = track->private_size; - uint64_t chmask = 0; if (!track->a_osfreq) track->a_osfreq = track->a_sfreq; sh_a->bits_per_coded_sample = track->a_bps ? track->a_bps : 16; sh_a->samplerate = (uint32_t) track->a_osfreq; + mp_chmap_set_unknown(&sh_a->channels, track->a_channels); for (int i = 0; mkv_audio_tags[i][0]; i++) { if (!strcmp(mkv_audio_tags[i][0], track->codec_id)) { @@ -1581,10 +1581,11 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) extradata = track->private_data + 18; extradata_len = track->private_size - 18; sh_a->bits_per_coded_sample = track->a_bps; + sh_a->extradata = extradata; + sh_a->extradata_size = extradata_len; mp_set_codec_from_tag(sh_a); - // WAVEFORMATEXTENSIBLE.dwChannelMask - if (sh_a->codec_tag == 0xfffe && extradata_len >= 6) - chmask = AV_RL32(extradata + 2); + extradata = sh_a->extradata; + extradata_len = sh_a->extradata_size; } else if (!strcmp(track->codec_id, "A_PCM/INT/LIT")) { bool sign = sh_a->bits_per_coded_sample > 8; mp_set_pcm_codec(sh_a, sign, false, sh_a->bits_per_coded_sample, false); @@ -1704,10 +1705,6 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) if (!sh_a->codec) goto error; - mp_chmap_from_waveext(&sh_a->channels, chmask); - if (sh_a->channels.num != track->a_channels) - mp_chmap_set_unknown(&sh_a->channels, track->a_channels); - const char *codec = sh_a->codec; if (!strcmp(codec, "mp2") || !strcmp(codec, "mp3") || !strcmp(codec, "truehd"))