00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavutil/intfloat.h"
00023 #include "avformat.h"
00024 #include "internal.h"
00025 #include "aiff.h"
00026 #include "avio_internal.h"
00027 #include "isom.h"
00028
00029 typedef struct {
00030 int64_t form;
00031 int64_t frames;
00032 int64_t ssnd;
00033 } AIFFOutputContext;
00034
00035 static int aiff_write_header(AVFormatContext *s)
00036 {
00037 AIFFOutputContext *aiff = s->priv_data;
00038 AVIOContext *pb = s->pb;
00039 AVCodecContext *enc = s->streams[0]->codec;
00040 uint64_t sample_rate;
00041 int aifc = 0;
00042
00043
00044 if (!enc->codec_tag)
00045 return -1;
00046 if (enc->codec_tag != MKTAG('N','O','N','E'))
00047 aifc = 1;
00048
00049
00050 ffio_wfourcc(pb, "FORM");
00051 aiff->form = avio_tell(pb);
00052 avio_wb32(pb, 0);
00053 ffio_wfourcc(pb, aifc ? "AIFC" : "AIFF");
00054
00055 if (aifc) {
00056 enc->bits_per_coded_sample = 16;
00057 if (!enc->block_align) {
00058 av_log(s, AV_LOG_ERROR, "block align not set\n");
00059 return -1;
00060 }
00061
00062 ffio_wfourcc(pb, "FVER");
00063 avio_wb32(pb, 4);
00064 avio_wb32(pb, 0xA2805140);
00065 }
00066
00067 if (enc->channels > 2 && enc->channel_layout) {
00068 ffio_wfourcc(pb, "CHAN");
00069 avio_wb32(pb, 12);
00070 ff_mov_write_chan(pb, enc->channel_layout);
00071 }
00072
00073
00074 ffio_wfourcc(pb, "COMM");
00075 avio_wb32(pb, aifc ? 24 : 18);
00076 avio_wb16(pb, enc->channels);
00077
00078 aiff->frames = avio_tell(pb);
00079 avio_wb32(pb, 0);
00080
00081 if (!enc->bits_per_coded_sample)
00082 enc->bits_per_coded_sample = av_get_bits_per_sample(enc->codec_id);
00083 if (!enc->bits_per_coded_sample) {
00084 av_log(s, AV_LOG_ERROR, "could not compute bits per sample\n");
00085 return -1;
00086 }
00087 if (!enc->block_align)
00088 enc->block_align = (enc->bits_per_coded_sample * enc->channels) >> 3;
00089
00090 avio_wb16(pb, enc->bits_per_coded_sample);
00091
00092 sample_rate = av_double2int(enc->sample_rate);
00093 avio_wb16(pb, (sample_rate >> 52) + (16383 - 1023));
00094 avio_wb64(pb, UINT64_C(1) << 63 | sample_rate << 11);
00095
00096 if (aifc) {
00097 avio_wl32(pb, enc->codec_tag);
00098 avio_wb16(pb, 0);
00099 }
00100
00101
00102 ffio_wfourcc(pb, "SSND");
00103 aiff->ssnd = avio_tell(pb);
00104 avio_wb32(pb, 0);
00105 avio_wb32(pb, 0);
00106 avio_wb32(pb, 0);
00107
00108 avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
00109
00110
00111 avio_flush(pb);
00112
00113 return 0;
00114 }
00115
00116 static int aiff_write_packet(AVFormatContext *s, AVPacket *pkt)
00117 {
00118 AVIOContext *pb = s->pb;
00119 avio_write(pb, pkt->data, pkt->size);
00120 return 0;
00121 }
00122
00123 static int aiff_write_trailer(AVFormatContext *s)
00124 {
00125 AVIOContext *pb = s->pb;
00126 AIFFOutputContext *aiff = s->priv_data;
00127 AVCodecContext *enc = s->streams[0]->codec;
00128
00129
00130 int64_t file_size, end_size;
00131 end_size = file_size = avio_tell(pb);
00132 if (file_size & 1) {
00133 avio_w8(pb, 0);
00134 end_size++;
00135 }
00136
00137 if (s->pb->seekable) {
00138
00139 avio_seek(pb, aiff->form, SEEK_SET);
00140 avio_wb32(pb, file_size - aiff->form - 4);
00141
00142
00143 avio_seek(pb, aiff->frames, SEEK_SET);
00144 avio_wb32(pb, (file_size-aiff->ssnd-12)/enc->block_align);
00145
00146
00147 avio_seek(pb, aiff->ssnd, SEEK_SET);
00148 avio_wb32(pb, file_size - aiff->ssnd - 4);
00149
00150
00151 avio_seek(pb, end_size, SEEK_SET);
00152
00153 avio_flush(pb);
00154 }
00155
00156 return 0;
00157 }
00158
00159 AVOutputFormat ff_aiff_muxer = {
00160 .name = "aiff",
00161 .long_name = NULL_IF_CONFIG_SMALL("Audio IFF"),
00162 .mime_type = "audio/aiff",
00163 .extensions = "aif,aiff,afc,aifc",
00164 .priv_data_size = sizeof(AIFFOutputContext),
00165 .audio_codec = CODEC_ID_PCM_S16BE,
00166 .video_codec = CODEC_ID_NONE,
00167 .write_header = aiff_write_header,
00168 .write_packet = aiff_write_packet,
00169 .write_trailer = aiff_write_trailer,
00170 .codec_tag = (const AVCodecTag* const []){ ff_codec_aiff_tags, 0 },
00171 };