diff --git a/libavformat/internal.h b/libavformat/internal.h index 4f740c99d1..14f4cdbdf1 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -359,6 +359,21 @@ unsigned int ff_codec_get_tag(const AVCodecTag *tags, enum AVCodecID id); enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag); +/** + * Select a PCM codec based on the given parameters. + * + * @param bps bits-per-sample + * @param flt floating-point + * @param be big-endian + * @param sflags signed flags. each bit corresponds to one byte of bit depth. + * e.g. the 1st bit indicates if 8-bit should be signed or + * unsigned, the 2nd bit indicates if 16-bit should be signed or + * unsigned, etc... This is useful for formats such as WAVE where + * only 8-bit is unsigned and all other bit depths are signed. + * @return a PCM codec id or AV_CODEC_ID_NONE + */ +enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags); + /** * Chooses a timebase for muxing the specified stream. * diff --git a/libavformat/mov.c b/libavformat/mov.c index 1a8a5a7182..149bd20954 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -1170,33 +1170,12 @@ static int mov_read_stco(MOVContext *c, AVIOContext *pb, MOVAtom atom) */ enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags) { - if (flags & 1) { // floating point - if (flags & 2) { // big endian - if (bps == 32) return AV_CODEC_ID_PCM_F32BE; - else if (bps == 64) return AV_CODEC_ID_PCM_F64BE; - } else { - if (bps == 32) return AV_CODEC_ID_PCM_F32LE; - else if (bps == 64) return AV_CODEC_ID_PCM_F64LE; - } - } else { - if (flags & 2) { - if (bps == 8) { - // signed integer - if (flags & 4) return AV_CODEC_ID_PCM_S8; - else return AV_CODEC_ID_PCM_U8; - }else if (bps == 16) return AV_CODEC_ID_PCM_S16BE; - else if (bps == 24) return AV_CODEC_ID_PCM_S24BE; - else if (bps == 32) return AV_CODEC_ID_PCM_S32BE; - } else { - if (bps == 8) { - if (flags & 4) return AV_CODEC_ID_PCM_S8; - else return AV_CODEC_ID_PCM_U8; - }else if (bps == 16) return AV_CODEC_ID_PCM_S16LE; - else if (bps == 24) return AV_CODEC_ID_PCM_S24LE; - else if (bps == 32) return AV_CODEC_ID_PCM_S32LE; - } - } - return AV_CODEC_ID_NONE; + /* lpcm flags: + * 0x1 = float + * 0x2 = big-endian + * 0x4 = signed + */ + return ff_get_pcm_codec_id(bps, flags & 1, flags & 2, flags & 4 ? -1 : 0); } int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) diff --git a/libavformat/nuv.c b/libavformat/nuv.c index c67c1fa695..37d92e284f 100644 --- a/libavformat/nuv.c +++ b/libavformat/nuv.c @@ -26,6 +26,12 @@ #include "internal.h" #include "riff.h" +static const AVCodecTag nuv_audio_tags[] = { + { AV_CODEC_ID_PCM_S16LE, MKTAG('R', 'A', 'W', 'A') }, + { AV_CODEC_ID_MP3, MKTAG('L', 'A', 'M', 'E') }, + { AV_CODEC_ID_NONE, 0 }, +}; + typedef struct { int v_id; int a_id; @@ -96,14 +102,25 @@ static int get_codec_data(AVIOContext *pb, AVStream *vst, avio_skip(pb, 4); if (ast) { + int id; + ast->codec->codec_tag = avio_rl32(pb); ast->codec->sample_rate = avio_rl32(pb); ast->codec->bits_per_coded_sample = avio_rl32(pb); ast->codec->channels = avio_rl32(pb); ast->codec->channel_layout = 0; - ast->codec->codec_id = - ff_wav_codec_get_id(ast->codec->codec_tag, - ast->codec->bits_per_coded_sample); + + id = ff_wav_codec_get_id(ast->codec->codec_tag, + ast->codec->bits_per_coded_sample); + if (id == AV_CODEC_ID_NONE) { + id = ff_codec_get_id(nuv_audio_tags, + ast->codec->codec_tag); + if (id == AV_CODEC_ID_PCM_S16LE) + id = ff_get_pcm_codec_id(ast->codec->bits_per_coded_sample, + 0, 0, ~1); + } + ast->codec->codec_id = id; + ast->need_parsing = AVSTREAM_PARSE_FULL; } else avio_skip(pb, 4 * 4); diff --git a/libavformat/riff.c b/libavformat/riff.c index cddbec477c..57d6ca68df 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -384,11 +384,6 @@ const AVCodecTag ff_codec_wav_tags[] = { { AV_CODEC_ID_FLAC, 0xF1AC }, { AV_CODEC_ID_ADPCM_SWF, ('S'<<8)+'F' }, { AV_CODEC_ID_VORBIS, ('V'<<8)+'o' }, //HACK/FIXME, does vorbis in WAV/AVI have an (in)official id? - - /* FIXME: All of the IDs below are not 16 bit and thus illegal. */ - // for NuppelVideo (nuv.c) - { AV_CODEC_ID_PCM_S16LE, MKTAG('R', 'A', 'W', 'A') }, - { AV_CODEC_ID_MP3, MKTAG('L', 'A', 'M', 'E') }, { AV_CODEC_ID_NONE, 0 }, }; @@ -757,16 +752,12 @@ enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps) id = ff_codec_get_id(ff_codec_wav_tags, tag); if (id <= 0) return id; - /* handle specific u8 codec */ - if (id == AV_CODEC_ID_PCM_S16LE && bps == 8) - id = AV_CODEC_ID_PCM_U8; - if (id == AV_CODEC_ID_PCM_S16LE && bps == 20 || - id == AV_CODEC_ID_PCM_S16LE && bps == 24) - id = AV_CODEC_ID_PCM_S24LE; - if (id == AV_CODEC_ID_PCM_S16LE && bps == 32) - id = AV_CODEC_ID_PCM_S32LE; - if (id == AV_CODEC_ID_PCM_F32LE && bps == 64) - id = AV_CODEC_ID_PCM_F64LE; + + if (id == AV_CODEC_ID_PCM_S16LE) + id = ff_get_pcm_codec_id(bps, 0, 0, ~1); + else if (id == AV_CODEC_ID_PCM_F32LE) + id = ff_get_pcm_codec_id(bps, 1, 0, 0); + if (id == AV_CODEC_ID_ADPCM_IMA_WAV && bps == 8) id = AV_CODEC_ID_PCM_ZORK; return id; diff --git a/libavformat/utils.c b/libavformat/utils.c index 3e87dbc76e..b7506dea98 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -2440,6 +2440,37 @@ enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag) return AV_CODEC_ID_NONE; } +enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags) +{ + if (flt) { + switch (bps) { + case 32: return be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE; + case 64: return be ? AV_CODEC_ID_PCM_F64BE : AV_CODEC_ID_PCM_F64LE; + default: return AV_CODEC_ID_NONE; + } + } else { + bps += 7; + bps >>= 3; + if (sflags & (1 << (bps - 1))) { + switch (bps) { + case 1: return AV_CODEC_ID_PCM_S8; + case 2: return be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE; + case 3: return be ? AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE; + case 4: return be ? AV_CODEC_ID_PCM_S32BE : AV_CODEC_ID_PCM_S32LE; + default: return AV_CODEC_ID_NONE; + } + } else { + switch (bps) { + case 1: return AV_CODEC_ID_PCM_U8; + case 2: return be ? AV_CODEC_ID_PCM_U16BE : AV_CODEC_ID_PCM_U16LE; + case 3: return be ? AV_CODEC_ID_PCM_U24BE : AV_CODEC_ID_PCM_U24LE; + case 4: return be ? AV_CODEC_ID_PCM_U32BE : AV_CODEC_ID_PCM_U32LE; + default: return AV_CODEC_ID_NONE; + } + } + } +} + unsigned int av_codec_get_tag(const AVCodecTag * const *tags, enum AVCodecID id) { int i;