diff --git a/configure b/configure index 467ab16ce5..53972de6a3 100755 --- a/configure +++ b/configure @@ -1574,6 +1574,7 @@ CONFIG_EXTRA=" mpegvideoenc nettle rangecoder + riffdec riffenc rtpdec rtpenc_chain @@ -2025,13 +2026,18 @@ libutvideo_encoder_deps="libutvideo" # demuxers / muxers ac3_demuxer_select="ac3_parser" +asf_demuxer_select="riffdec" asf_muxer_select="riffenc" asf_stream_muxer_select="asf_muxer" +avi_demuxer_select="riffdec" avi_muxer_select="riffenc" avisynth_demuxer_deps="avisynth" +avisynth_demuxer_select="riffdec" +caf_demuxer_select="riffdec" dirac_demuxer_select="dirac_parser" dts_demuxer_select="dca_parser" dtshd_demuxer_select="dca_parser" +dxa_demuxer_select="riffdec" eac3_demuxer_select="ac3_parser" f4v_muxer_select="mov_muxer" flac_demuxer_select="flac_parser" @@ -2040,9 +2046,11 @@ ismv_muxer_select="mov_muxer" libnut_demuxer_deps="libnut" libnut_muxer_deps="libnut" matroska_audio_muxer_select="matroska_muxer" +matroska_demuxer_select="riffdec" matroska_demuxer_suggest="bzlib lzo zlib" matroska_muxer_select="riffenc" mmf_muxer_select="riffenc" +mov_demuxer_select="riffdec" mov_demuxer_suggest="zlib" mov_muxer_select="riffenc rtpenc_chain" mp3_demuxer_select="mpegaudio_parser" @@ -2051,6 +2059,7 @@ mpegts_muxer_select="adts_muxer latm_muxer" mpegtsraw_demuxer_select="mpegts_demuxer" mxf_d10_muxer_select="mxf_muxer" nut_muxer_select="riffenc" +nuv_demuxer_select="riffdec" ogg_demuxer_select="golomb" psp_muxer_select="mov_muxer" rtp_demuxer_select="sdp_demuxer" @@ -2068,8 +2077,12 @@ tgp_muxer_select="mov_muxer" vobsub_demuxer_select="mpegps_demuxer" w64_demuxer_deps="wav_demuxer" w64_muxer_deps="wav_muxer" +wav_demuxer_select="riffdec" wav_muxer_select="riffenc" webm_muxer_select="riffenc" +wtv_demuxer_select="riffdec" +xmv_demuxer_select="riffdec" +xwma_demuxer_select="riffdec" # indevs / outdevs alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp" diff --git a/libavformat/Makefile b/libavformat/Makefile index b0e42b3b5a..b8872b336b 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -25,6 +25,7 @@ OBJS = allformats.o \ utils.o \ OBJS-$(CONFIG_NETWORK) += network.o +OBJS-$(CONFIG_RIFFDEC) += riffdec.o OBJS-$(CONFIG_RIFFENC) += riffenc.o OBJS-$(CONFIG_RTPDEC) += rdt.o \ rtp.o \ diff --git a/libavformat/riff.c b/libavformat/riff.c index 0896d22c5c..84d97ed5c2 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -20,13 +20,9 @@ */ #include "libavutil/error.h" -#include "libavutil/log.h" #include "libavcodec/avcodec.h" #include "avformat.h" -#include "avio_internal.h" #include "riff.h" -#include "libavcodec/bytestream.h" -#include "libavutil/avassert.h" /* Note: When encoding, the first matching tag is used, so order is * important if multiple tags are possible for a given codec. @@ -422,14 +418,6 @@ const AVCodecTag ff_codec_wav_tags[] = { { AV_CODEC_ID_NONE, 0 }, }; -const AVCodecGuid ff_codec_wav_guids[] = { - { AV_CODEC_ID_AC3, { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } }, - { AV_CODEC_ID_ATRAC3P, { 0xBF, 0xAA, 0x23, 0xE9, 0x58, 0xCB, 0x71, 0x44, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62 } }, - { AV_CODEC_ID_EAC3, { 0xAF, 0x87, 0xFB, 0xA7, 0x02, 0x2D, 0xFB, 0x42, 0xA4, 0xD4, 0x05, 0xCD, 0x93, 0x84, 0x3B, 0xDD } }, - { AV_CODEC_ID_MP2, { 0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } }, - { AV_CODEC_ID_NONE } -}; - const AVMetadataConv ff_riff_info_conv[] = { { "IART", "artist" }, { "ICMT", "comment" }, @@ -447,22 +435,6 @@ const AVMetadataConv ff_riff_info_conv[] = { { 0 }, }; -void ff_get_guid(AVIOContext *s, ff_asf_guid *g) -{ - av_assert0(sizeof(*g) == 16); //compiler will optimize this out - if (avio_read(s, *g, sizeof(*g)) < (int)sizeof(*g)) - memset(*g, 0, sizeof(*g)); -} - -enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid) -{ - int i; - for (i = 0; guids[i].id != AV_CODEC_ID_NONE; i++) - if (!ff_guidcmp(guids[i].guid, guid)) - return guids[i].id; - return AV_CODEC_ID_NONE; -} - const struct AVCodecTag *avformat_get_riff_video_tags(void) { return ff_codec_bmp_tags; @@ -472,198 +444,3 @@ const struct AVCodecTag *avformat_get_riff_audio_tags(void) { return ff_codec_wav_tags; } - -#if CONFIG_DEMUXERS -/* We could be given one of the three possible structures here: - * WAVEFORMAT, PCMWAVEFORMAT or WAVEFORMATEX. Each structure - * is an expansion of the previous one with the fields added - * at the bottom. PCMWAVEFORMAT adds 'WORD wBitsPerSample' and - * WAVEFORMATEX adds 'WORD cbSize' and basically makes itself - * an openended structure. - */ - -static void parse_waveformatex(AVIOContext *pb, AVCodecContext *c) -{ - ff_asf_guid subformat; - int bps = avio_rl16(pb); - if (bps) - c->bits_per_coded_sample = bps; - - c->channel_layout = avio_rl32(pb); /* dwChannelMask */ - - ff_get_guid(pb, &subformat); - if (!memcmp(subformat + 4, - (const uint8_t[]){ FF_MEDIASUBTYPE_BASE_GUID }, 12)) { - c->codec_tag = AV_RL32(subformat); - c->codec_id = ff_wav_codec_get_id(c->codec_tag, - c->bits_per_coded_sample); - } else { - c->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subformat); - if (!c->codec_id) - av_log(c, AV_LOG_WARNING, - "unknown subformat:"FF_PRI_GUID"\n", - FF_ARG_GUID(subformat)); - } -} - -int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) -{ - int id; - - id = avio_rl16(pb); - codec->codec_type = AVMEDIA_TYPE_AUDIO; - codec->channels = avio_rl16(pb); - codec->sample_rate = avio_rl32(pb); - codec->bit_rate = avio_rl32(pb) * 8; - codec->block_align = avio_rl16(pb); - if (size == 14) { /* We're dealing with plain vanilla WAVEFORMAT */ - codec->bits_per_coded_sample = 8; - } else - codec->bits_per_coded_sample = avio_rl16(pb); - if (id == 0xFFFE) { - codec->codec_tag = 0; - } else { - codec->codec_tag = id; - codec->codec_id = ff_wav_codec_get_id(id, - codec->bits_per_coded_sample); - } - if (size >= 18) { /* We're obviously dealing with WAVEFORMATEX */ - int cbSize = avio_rl16(pb); /* cbSize */ - size -= 18; - cbSize = FFMIN(size, cbSize); - if (cbSize >= 22 && id == 0xfffe) { /* WAVEFORMATEXTENSIBLE */ - parse_waveformatex(pb, codec); - cbSize -= 22; - size -= 22; - } - codec->extradata_size = cbSize; - if (cbSize > 0) { - av_free(codec->extradata); - codec->extradata = av_mallocz(codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); - if (!codec->extradata) - return AVERROR(ENOMEM); - avio_read(pb, codec->extradata, codec->extradata_size); - size -= cbSize; - } - - /* It is possible for the chunk to contain garbage at the end */ - if (size > 0) - avio_skip(pb, size); - } - if (codec->codec_id == AV_CODEC_ID_AAC_LATM) { - /* Channels and sample_rate values are those prior to applying SBR - * and/or PS. */ - codec->channels = 0; - codec->sample_rate = 0; - } - /* override bits_per_coded_sample for G.726 */ - if (codec->codec_id == AV_CODEC_ID_ADPCM_G726 && codec->sample_rate) - codec->bits_per_coded_sample = codec->bit_rate / codec->sample_rate; - - return 0; -} - -enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps) -{ - enum AVCodecID id; - id = ff_codec_get_id(ff_codec_wav_tags, tag); - if (id <= 0) - return id; - - 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; -} - -int ff_get_bmp_header(AVIOContext *pb, AVStream *st, unsigned *esize) -{ - int tag1; - if(esize) *esize = avio_rl32(pb); - else avio_rl32(pb); - st->codec->width = avio_rl32(pb); - st->codec->height = (int32_t)avio_rl32(pb); - avio_rl16(pb); /* planes */ - st->codec->bits_per_coded_sample = avio_rl16(pb); /* depth */ - tag1 = avio_rl32(pb); - avio_rl32(pb); /* ImageSize */ - avio_rl32(pb); /* XPelsPerMeter */ - avio_rl32(pb); /* YPelsPerMeter */ - avio_rl32(pb); /* ClrUsed */ - avio_rl32(pb); /* ClrImportant */ - return tag1; -} - -int ff_read_riff_info(AVFormatContext *s, int64_t size) -{ - int64_t start, end, cur; - AVIOContext *pb = s->pb; - - start = avio_tell(pb); - end = start + size; - - while ((cur = avio_tell(pb)) >= 0 && - cur <= end - 8 /* = tag + size */) { - uint32_t chunk_code; - int64_t chunk_size; - char key[5] = { 0 }; - char *value; - - chunk_code = avio_rl32(pb); - chunk_size = avio_rl32(pb); - if (url_feof(pb)) { - if (chunk_code || chunk_size) { - av_log(s, AV_LOG_WARNING, "INFO subchunk truncated\n"); - return AVERROR_INVALIDDATA; - } - return AVERROR_EOF; - } - if (chunk_size > end || - end - chunk_size < cur || - chunk_size == UINT_MAX) { - avio_seek(pb, -9, SEEK_CUR); - chunk_code = avio_rl32(pb); - chunk_size = avio_rl32(pb); - if (chunk_size > end || end - chunk_size < cur || chunk_size == UINT_MAX) { - av_log(s, AV_LOG_WARNING, "too big INFO subchunk\n"); - return AVERROR_INVALIDDATA; - } - } - - chunk_size += (chunk_size & 1); - - if (!chunk_code) { - if (chunk_size) - avio_skip(pb, chunk_size); - else if (pb->eof_reached) { - av_log(s, AV_LOG_WARNING, "truncated file\n"); - return AVERROR_EOF; - } - continue; - } - - value = av_mallocz(chunk_size + 1); - if (!value) { - av_log(s, AV_LOG_ERROR, - "out of memory, unable to read INFO tag\n"); - return AVERROR(ENOMEM); - } - - AV_WL32(key, chunk_code); - - if (avio_read(pb, value, chunk_size) != chunk_size) { - av_log(s, AV_LOG_WARNING, - "premature end of file while reading INFO tag\n"); - } - - av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL); - } - - return 0; -} -#endif /* CONFIG_DEMUXERS */ diff --git a/libavformat/riffdec.c b/libavformat/riffdec.c new file mode 100644 index 0000000000..973f3fada9 --- /dev/null +++ b/libavformat/riffdec.c @@ -0,0 +1,247 @@ +/* + * RIFF demuxing functions and data + * Copyright (c) 2000 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/dict.h" +#include "libavutil/error.h" +#include "libavutil/log.h" +#include "libavutil/mathematics.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/bytestream.h" +#include "avformat.h" +#include "avio_internal.h" +#include "riff.h" + +const AVCodecGuid ff_codec_wav_guids[] = { + { AV_CODEC_ID_AC3, { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } }, + { AV_CODEC_ID_ATRAC3P, { 0xBF, 0xAA, 0x23, 0xE9, 0x58, 0xCB, 0x71, 0x44, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62 } }, + { AV_CODEC_ID_EAC3, { 0xAF, 0x87, 0xFB, 0xA7, 0x02, 0x2D, 0xFB, 0x42, 0xA4, 0xD4, 0x05, 0xCD, 0x93, 0x84, 0x3B, 0xDD } }, + { AV_CODEC_ID_MP2, { 0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } }, + { AV_CODEC_ID_NONE } +}; + +void ff_get_guid(AVIOContext *s, ff_asf_guid *g) +{ + av_assert0(sizeof(*g) == 16); //compiler will optimize this out + if (avio_read(s, *g, sizeof(*g)) < (int)sizeof(*g)) + memset(*g, 0, sizeof(*g)); +} + +enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid) +{ + int i; + for (i = 0; guids[i].id != AV_CODEC_ID_NONE; i++) + if (!ff_guidcmp(guids[i].guid, guid)) + return guids[i].id; + return AV_CODEC_ID_NONE; +} + +/* We could be given one of the three possible structures here: + * WAVEFORMAT, PCMWAVEFORMAT or WAVEFORMATEX. Each structure + * is an expansion of the previous one with the fields added + * at the bottom. PCMWAVEFORMAT adds 'WORD wBitsPerSample' and + * WAVEFORMATEX adds 'WORD cbSize' and basically makes itself + * an openended structure. + */ + +static void parse_waveformatex(AVIOContext *pb, AVCodecContext *c) +{ + ff_asf_guid subformat; + int bps = avio_rl16(pb); + if (bps) + c->bits_per_coded_sample = bps; + + c->channel_layout = avio_rl32(pb); /* dwChannelMask */ + + ff_get_guid(pb, &subformat); + if (!memcmp(subformat + 4, + (const uint8_t[]){ FF_MEDIASUBTYPE_BASE_GUID }, 12)) { + c->codec_tag = AV_RL32(subformat); + c->codec_id = ff_wav_codec_get_id(c->codec_tag, + c->bits_per_coded_sample); + } else { + c->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subformat); + if (!c->codec_id) + av_log(c, AV_LOG_WARNING, + "unknown subformat:"FF_PRI_GUID"\n", + FF_ARG_GUID(subformat)); + } +} + +int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) +{ + int id; + + id = avio_rl16(pb); + codec->codec_type = AVMEDIA_TYPE_AUDIO; + codec->channels = avio_rl16(pb); + codec->sample_rate = avio_rl32(pb); + codec->bit_rate = avio_rl32(pb) * 8; + codec->block_align = avio_rl16(pb); + if (size == 14) { /* We're dealing with plain vanilla WAVEFORMAT */ + codec->bits_per_coded_sample = 8; + } else + codec->bits_per_coded_sample = avio_rl16(pb); + if (id == 0xFFFE) { + codec->codec_tag = 0; + } else { + codec->codec_tag = id; + codec->codec_id = ff_wav_codec_get_id(id, + codec->bits_per_coded_sample); + } + if (size >= 18) { /* We're obviously dealing with WAVEFORMATEX */ + int cbSize = avio_rl16(pb); /* cbSize */ + size -= 18; + cbSize = FFMIN(size, cbSize); + if (cbSize >= 22 && id == 0xfffe) { /* WAVEFORMATEXTENSIBLE */ + parse_waveformatex(pb, codec); + cbSize -= 22; + size -= 22; + } + codec->extradata_size = cbSize; + if (cbSize > 0) { + av_free(codec->extradata); + codec->extradata = av_mallocz(codec->extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE); + if (!codec->extradata) + return AVERROR(ENOMEM); + avio_read(pb, codec->extradata, codec->extradata_size); + size -= cbSize; + } + + /* It is possible for the chunk to contain garbage at the end */ + if (size > 0) + avio_skip(pb, size); + } + if (codec->codec_id == AV_CODEC_ID_AAC_LATM) { + /* Channels and sample_rate values are those prior to applying SBR + * and/or PS. */ + codec->channels = 0; + codec->sample_rate = 0; + } + /* override bits_per_coded_sample for G.726 */ + if (codec->codec_id == AV_CODEC_ID_ADPCM_G726 && codec->sample_rate) + codec->bits_per_coded_sample = codec->bit_rate / codec->sample_rate; + + return 0; +} + +enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps) +{ + enum AVCodecID id; + id = ff_codec_get_id(ff_codec_wav_tags, tag); + if (id <= 0) + return id; + + 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; +} + +int ff_get_bmp_header(AVIOContext *pb, AVStream *st, unsigned *esize) +{ + int tag1; + if(esize) *esize = avio_rl32(pb); + else avio_rl32(pb); + st->codec->width = avio_rl32(pb); + st->codec->height = (int32_t)avio_rl32(pb); + avio_rl16(pb); /* planes */ + st->codec->bits_per_coded_sample = avio_rl16(pb); /* depth */ + tag1 = avio_rl32(pb); + avio_rl32(pb); /* ImageSize */ + avio_rl32(pb); /* XPelsPerMeter */ + avio_rl32(pb); /* YPelsPerMeter */ + avio_rl32(pb); /* ClrUsed */ + avio_rl32(pb); /* ClrImportant */ + return tag1; +} + +int ff_read_riff_info(AVFormatContext *s, int64_t size) +{ + int64_t start, end, cur; + AVIOContext *pb = s->pb; + + start = avio_tell(pb); + end = start + size; + + while ((cur = avio_tell(pb)) >= 0 && + cur <= end - 8 /* = tag + size */) { + uint32_t chunk_code; + int64_t chunk_size; + char key[5] = { 0 }; + char *value; + + chunk_code = avio_rl32(pb); + chunk_size = avio_rl32(pb); + if (url_feof(pb)) { + if (chunk_code || chunk_size) { + av_log(s, AV_LOG_WARNING, "INFO subchunk truncated\n"); + return AVERROR_INVALIDDATA; + } + return AVERROR_EOF; + } + if (chunk_size > end || + end - chunk_size < cur || + chunk_size == UINT_MAX) { + avio_seek(pb, -9, SEEK_CUR); + chunk_code = avio_rl32(pb); + chunk_size = avio_rl32(pb); + if (chunk_size > end || end - chunk_size < cur || chunk_size == UINT_MAX) { + av_log(s, AV_LOG_WARNING, "too big INFO subchunk\n"); + return AVERROR_INVALIDDATA; + } + } + + chunk_size += (chunk_size & 1); + + if (!chunk_code) { + if (chunk_size) + avio_skip(pb, chunk_size); + else if (pb->eof_reached) { + av_log(s, AV_LOG_WARNING, "truncated file\n"); + return AVERROR_EOF; + } + continue; + } + + value = av_mallocz(chunk_size + 1); + if (!value) { + av_log(s, AV_LOG_ERROR, + "out of memory, unable to read INFO tag\n"); + return AVERROR(ENOMEM); + } + + AV_WL32(key, chunk_code); + + if (avio_read(pb, value, chunk_size) != chunk_size) { + av_log(s, AV_LOG_WARNING, + "premature end of file while reading INFO tag\n"); + } + + av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL); + } + + return 0; +}