diff options
author | Carl Eugen Hoyos <cehoyos@ag.or.at> | 2011-05-15 03:25:27 +0200 |
---|---|---|
committer | Carl Eugen Hoyos <cehoyos@ag.or.at> | 2011-05-15 03:25:57 +0200 |
commit | 2c4ad1a37b7980b40d6875daea4f87b154509c2e (patch) | |
tree | e9e103e6aa67211ba61658809836be185f59c92d /libavformat | |
parent | 0c3803f6bb50038970ee40daa25cfb3ea484febd (diff) | |
download | ffmpeg-2c4ad1a37b7980b40d6875daea4f87b154509c2e.tar.gz |
Initial caf muxer.
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/Makefile | 1 | ||||
-rw-r--r-- | libavformat/allformats.c | 2 | ||||
-rw-r--r-- | libavformat/cafenc.c | 182 | ||||
-rw-r--r-- | libavformat/isom.c | 29 | ||||
-rw-r--r-- | libavformat/isom.h | 2 |
5 files changed, 215 insertions, 1 deletions
diff --git a/libavformat/Makefile b/libavformat/Makefile index 739decfd9f..26c094cbfc 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -48,6 +48,7 @@ OBJS-$(CONFIG_BFI_DEMUXER) += bfi.o OBJS-$(CONFIG_BINK_DEMUXER) += bink.o OBJS-$(CONFIG_C93_DEMUXER) += c93.o vocdec.o voc.o OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o riff.o isom.o +OBJS-$(CONFIG_CAF_MUXER) += cafenc.o caf.o riff.o isom.o OBJS-$(CONFIG_CAVSVIDEO_DEMUXER) += cavsvideodec.o rawdec.o OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index d08f2f742a..a9fa117243 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -71,7 +71,7 @@ void av_register_all(void) REGISTER_DEMUXER (BFI, bfi); REGISTER_DEMUXER (BINK, bink); REGISTER_DEMUXER (C93, c93); - REGISTER_DEMUXER (CAF, caf); + REGISTER_MUXDEMUX (CAF, caf); REGISTER_MUXDEMUX (CAVSVIDEO, cavsvideo); REGISTER_DEMUXER (CDG, cdg); REGISTER_MUXER (CRC, crc); diff --git a/libavformat/cafenc.c b/libavformat/cafenc.c new file mode 100644 index 0000000000..0f33c6b592 --- /dev/null +++ b/libavformat/cafenc.c @@ -0,0 +1,182 @@ +/* + * Core Audio Format muxer + * Copyright (c) 2011 Carl Eugen Hoyos + * + * 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 "avformat.h" +#include "caf.h" +#include "riff.h" +#include "isom.h" +#include "avio_internal.h" + +typedef struct { + int64_t data; +} CAFContext; + +static uint32_t codec_flags(enum CodecID codec_id) { + switch (codec_id) { + case CODEC_ID_PCM_F32BE: + case CODEC_ID_PCM_F64BE: + return 1; //< kCAFLinearPCMFormatFlagIsFloat + case CODEC_ID_PCM_S16LE: + case CODEC_ID_PCM_S24LE: + case CODEC_ID_PCM_S32LE: + return 2; //< kCAFLinearPCMFormatFlagIsLittleEndian + case CODEC_ID_PCM_F32LE: + case CODEC_ID_PCM_F64LE: + return 3; //< kCAFLinearPCMFormatFlagIsFloat | kCAFLinearPCMFormatFlagIsLittleEndian + default: + return 0; + } +} + +static uint32_t samples_per_packet(enum CodecID codec_id) { + switch (codec_id) { + case CODEC_ID_PCM_S8: + case CODEC_ID_PCM_S16LE: + case CODEC_ID_PCM_S16BE: + case CODEC_ID_PCM_S24LE: + case CODEC_ID_PCM_S24BE: + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_S32BE: + case CODEC_ID_PCM_F32LE: + case CODEC_ID_PCM_F32BE: + case CODEC_ID_PCM_F64LE: + case CODEC_ID_PCM_F64BE: + case CODEC_ID_PCM_ALAW: + case CODEC_ID_PCM_MULAW: + return 1; + case CODEC_ID_MACE3: + case CODEC_ID_MACE6: + return 6; + case CODEC_ID_ADPCM_IMA_QT: + return 64; + case CODEC_ID_AMR_NB: + case CODEC_ID_GSM: + case CODEC_ID_QCELP: + return 160; + case CODEC_ID_MP1: + return 384; + case CODEC_ID_MP2: + case CODEC_ID_MP3: + return 1152; + case CODEC_ID_AC3: + return 1536; + case CODEC_ID_ALAC: + case CODEC_ID_QDM2: + return 4096; + default: + return 0; + } +} + +static int caf_write_header(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + AVCodecContext *enc = s->streams[0]->codec; + CAFContext *caf = s->priv_data; + unsigned int codec_tag = ff_codec_get_tag(ff_codec_caf_tags, enc->codec_id); + + switch (enc->codec_id) { + case CODEC_ID_PCM_S8: + case CODEC_ID_PCM_S16LE: + case CODEC_ID_PCM_S16BE: + case CODEC_ID_PCM_S24LE: + case CODEC_ID_PCM_S24BE: + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_S32BE: + case CODEC_ID_PCM_F32LE: + case CODEC_ID_PCM_F32BE: + case CODEC_ID_PCM_F64LE: + case CODEC_ID_PCM_F64BE: + case CODEC_ID_PCM_ALAW: + case CODEC_ID_PCM_MULAW: + codec_tag = MKBETAG('l','p','c','m'); + } + + if (!codec_tag) { + av_log(s, AV_LOG_ERROR, "unsupported codec\n"); + return AVERROR_INVALIDDATA; + } + + if (!enc->block_align) { + av_log(s, AV_LOG_ERROR, "muxing with unknown or variable packet size not yet supported\n"); + return AVERROR_PATCHWELCOME; + } + + ffio_wfourcc(pb, "caff"); //< mFileType + avio_wb16(pb, 1); //< mFileVersion + avio_wb16(pb, 0); //< mFileFlags + + ffio_wfourcc(pb, "desc"); //< Audio Description chunk + avio_wb64(pb, 32); //< mChunkSize + avio_wb64(pb, av_dbl2int(enc->sample_rate)); //< mSampleRate + avio_wb32(pb, codec_tag); //< mFormatID + avio_wb32(pb, codec_flags(enc->codec_id)); //< mFormatFlags + avio_wb32(pb, enc->block_align); //< mBytesPerPacket + avio_wb32(pb, samples_per_packet(enc->codec_id)); //< mFramesPerPacket + avio_wb32(pb, enc->channels); //< mChannelsPerFrame + avio_wb32(pb, enc->bits_per_coded_sample); //< mBitsPerChannel + + ff_mov_write_chan(s, enc->channel_layout, "chan"); + + ffio_wfourcc(pb, "data"); //< Audio Data chunk + caf->data = avio_tell(pb); + avio_wb64(pb, -1); //< mChunkSize + avio_wb32(pb, 0); //< mEditCount + + avio_flush(pb); + return 0; +} + +static int caf_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + avio_write(s->pb, pkt->data, pkt->size); + return 0; +} + +static int caf_write_trailer(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + + if (pb->seekable) { + CAFContext *caf = s->priv_data; + int64_t file_size = avio_tell(pb); + + avio_seek(pb, caf->data, SEEK_SET); + avio_wb64(pb, file_size - caf->data - 8); + avio_seek(pb, file_size, SEEK_SET); + avio_flush(pb); + } + return 0; +} + +AVOutputFormat ff_caf_muxer = { + "caf", + NULL_IF_CONFIG_SMALL("Apple Core Audio Format"), + "audio/x-caf", + "caf", + sizeof(CAFContext), + CODEC_ID_PCM_S16BE, + CODEC_ID_NONE, + caf_write_header, + caf_write_packet, + caf_write_trailer, + .codec_tag= (const AVCodecTag* const []){ff_codec_caf_tags, 0}, +}; diff --git a/libavformat/isom.c b/libavformat/isom.c index 1713aa89b7..3259128d3a 100644 --- a/libavformat/isom.c +++ b/libavformat/isom.c @@ -27,6 +27,7 @@ #include "internal.h" #include "isom.h" #include "riff.h" +#include "avio_internal.h" #include "libavcodec/mpeg4audio.h" #include "libavcodec/mpegaudiodata.h" @@ -483,3 +484,31 @@ void ff_mov_read_chan(AVFormatContext *s, int64_t size, AVCodecContext *codec) avio_skip(pb, 8); } +void ff_mov_write_chan(AVFormatContext *s, int64_t channel_layout, + const char *chunk_type) +{ + AVIOContext *pb = s->pb; + const MovChannelLayout *layouts; + uint32_t layout_tag = 0; + + if (!channel_layout) + return; + + for (layouts = mov_channel_layout; layouts->channel_layout; layouts++) + if (channel_layout == layouts->channel_layout) { + layout_tag = layouts->layout_tag; + break; + } + + ffio_wfourcc(pb, chunk_type); + avio_wb64(pb, 12); //< mChunkSize + if (layout_tag) { + avio_wb32(pb, layout_tag); //< mChannelLayoutTag + avio_wb32(pb, 0); //< mChannelBitmap + } else { + avio_wb32(pb, 0x10000); //< kCAFChannelLayoutTag_UseChannelBitmap + avio_wb32(pb, channel_layout); + } + avio_wb32(pb, 0); //< mNumberChannelDescriptions +} + diff --git a/libavformat/isom.h b/libavformat/isom.h index 99de0c860a..6649d85739 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -157,5 +157,7 @@ enum CodecID ff_mov_get_lpcm_codec_id(int bps, int flags); int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries); void ff_mov_read_chan(AVFormatContext *s, int64_t size, AVCodecContext *codec); +void ff_mov_write_chan(AVFormatContext *s, int64_t channel_layout, + const char *chunk_type); #endif /* AVFORMAT_ISOM_H */ |