1/* 2 * AIFF/AIFF-C muxer 3 * Copyright (c) 2006 Patrick Guimond 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include <stdint.h> 23 24#include "libavutil/intfloat.h" 25#include "libavutil/opt.h" 26#include "libavcodec/packet_internal.h" 27#include "avformat.h" 28#include "internal.h" 29#include "aiff.h" 30#include "avio_internal.h" 31#include "isom.h" 32#include "id3v2.h" 33 34typedef struct AIFFOutputContext { 35 const AVClass *class; 36 int64_t form; 37 int64_t frames; 38 int64_t ssnd; 39 int audio_stream_idx; 40 PacketList pict_list; 41 int write_id3v2; 42 int id3v2_version; 43} AIFFOutputContext; 44 45static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff) 46{ 47 int ret; 48 uint64_t pos, end, size; 49 ID3v2EncContext id3v2 = { 0 }; 50 AVIOContext *pb = s->pb; 51 PacketListEntry *list_entry = aiff->pict_list.head; 52 53 if (!s->metadata && !s->nb_chapters && !list_entry) 54 return 0; 55 56 avio_wl32(pb, MKTAG('I', 'D', '3', ' ')); 57 avio_wb32(pb, 0); 58 pos = avio_tell(pb); 59 60 ff_id3v2_start(&id3v2, pb, aiff->id3v2_version, ID3v2_DEFAULT_MAGIC); 61 ff_id3v2_write_metadata(s, &id3v2); 62 while (list_entry) { 63 if ((ret = ff_id3v2_write_apic(s, &id3v2, &list_entry->pkt)) < 0) 64 return ret; 65 list_entry = list_entry->next; 66 } 67 ff_id3v2_finish(&id3v2, pb, s->metadata_header_padding); 68 69 end = avio_tell(pb); 70 size = end - pos; 71 72 /* Update chunk size */ 73 avio_seek(pb, pos - 4, SEEK_SET); 74 avio_wb32(pb, size); 75 avio_seek(pb, end, SEEK_SET); 76 77 if (size & 1) 78 avio_w8(pb, 0); 79 80 return 0; 81} 82 83static void put_meta(AVFormatContext *s, const char *key, uint32_t id) 84{ 85 AVDictionaryEntry *tag; 86 AVIOContext *pb = s->pb; 87 88 if (tag = av_dict_get(s->metadata, key, NULL, 0)) { 89 int size = strlen(tag->value); 90 91 avio_wl32(pb, id); 92 avio_wb32(pb, FFALIGN(size, 2)); 93 avio_write(pb, tag->value, size); 94 if (size & 1) 95 avio_w8(pb, 0); 96 } 97} 98 99static int aiff_write_header(AVFormatContext *s) 100{ 101 AIFFOutputContext *aiff = s->priv_data; 102 AVIOContext *pb = s->pb; 103 AVCodecParameters *par; 104 uint64_t sample_rate; 105 int i, aifc = 0; 106 107 aiff->audio_stream_idx = -1; 108 for (i = 0; i < s->nb_streams; i++) { 109 AVStream *st = s->streams[i]; 110 if (aiff->audio_stream_idx < 0 && st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { 111 aiff->audio_stream_idx = i; 112 } else if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { 113 av_log(s, AV_LOG_ERROR, "AIFF allows only one audio stream and a picture.\n"); 114 return AVERROR(EINVAL); 115 } 116 } 117 if (aiff->audio_stream_idx < 0) { 118 av_log(s, AV_LOG_ERROR, "No audio stream present.\n"); 119 return AVERROR(EINVAL); 120 } 121 122 par = s->streams[aiff->audio_stream_idx]->codecpar; 123 124 /* First verify if format is ok */ 125 if (!par->codec_tag) 126 return AVERROR(EINVAL); 127 if (par->codec_tag != MKTAG('N','O','N','E')) 128 aifc = 1; 129 130 /* FORM AIFF header */ 131 ffio_wfourcc(pb, "FORM"); 132 aiff->form = avio_tell(pb); 133 avio_wb32(pb, 0); /* file length */ 134 ffio_wfourcc(pb, aifc ? "AIFC" : "AIFF"); 135 136 if (aifc) { // compressed audio 137 if (!par->block_align) { 138 av_log(s, AV_LOG_ERROR, "block align not set\n"); 139 return AVERROR(EINVAL); 140 } 141 /* Version chunk */ 142 ffio_wfourcc(pb, "FVER"); 143 avio_wb32(pb, 4); 144 avio_wb32(pb, 0xA2805140); 145 } 146 147 if (par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE && par->ch_layout.nb_channels > 2) { 148 ffio_wfourcc(pb, "CHAN"); 149 avio_wb32(pb, 12); 150 ff_mov_write_chan(pb, par->ch_layout.u.mask); 151 } 152 153 put_meta(s, "title", MKTAG('N', 'A', 'M', 'E')); 154 put_meta(s, "author", MKTAG('A', 'U', 'T', 'H')); 155 put_meta(s, "copyright", MKTAG('(', 'c', ')', ' ')); 156 put_meta(s, "comment", MKTAG('A', 'N', 'N', 'O')); 157 158 /* Common chunk */ 159 ffio_wfourcc(pb, "COMM"); 160 avio_wb32(pb, aifc ? 24 : 18); /* size */ 161 avio_wb16(pb, par->ch_layout.nb_channels); /* Number of channels */ 162 163 aiff->frames = avio_tell(pb); 164 avio_wb32(pb, 0); /* Number of frames */ 165 166 if (!par->bits_per_coded_sample) 167 par->bits_per_coded_sample = av_get_bits_per_sample(par->codec_id); 168 if (!par->bits_per_coded_sample) { 169 av_log(s, AV_LOG_ERROR, "could not compute bits per sample\n"); 170 return AVERROR(EINVAL); 171 } 172 if (!par->block_align) 173 par->block_align = (par->bits_per_coded_sample * par->ch_layout.nb_channels) >> 3; 174 175 avio_wb16(pb, par->bits_per_coded_sample); /* Sample size */ 176 177 sample_rate = av_double2int(par->sample_rate); 178 avio_wb16(pb, (sample_rate >> 52) + (16383 - 1023)); 179 avio_wb64(pb, UINT64_C(1) << 63 | sample_rate << 11); 180 181 if (aifc) { 182 avio_wl32(pb, par->codec_tag); 183 avio_wb16(pb, 0); 184 } 185 186 if ( (par->codec_tag == MKTAG('Q','D','M','2') 187 || par->codec_tag == MKTAG('Q','c','l','p')) && par->extradata_size) { 188 ffio_wfourcc(pb, "wave"); 189 avio_wb32(pb, par->extradata_size); 190 avio_write(pb, par->extradata, par->extradata_size); 191 } 192 193 /* Sound data chunk */ 194 ffio_wfourcc(pb, "SSND"); 195 aiff->ssnd = avio_tell(pb); /* Sound chunk size */ 196 avio_wb32(pb, 0); /* Sound samples data size */ 197 avio_wb32(pb, 0); /* Data offset */ 198 avio_wb32(pb, 0); /* Block-size (block align) */ 199 200 avpriv_set_pts_info(s->streams[aiff->audio_stream_idx], 64, 1, 201 s->streams[aiff->audio_stream_idx]->codecpar->sample_rate); 202 203 return 0; 204} 205 206static int aiff_write_packet(AVFormatContext *s, AVPacket *pkt) 207{ 208 AIFFOutputContext *aiff = s->priv_data; 209 AVIOContext *pb = s->pb; 210 if (pkt->stream_index == aiff->audio_stream_idx) 211 avio_write(pb, pkt->data, pkt->size); 212 else { 213 /* warn only once for each stream */ 214 if (s->streams[pkt->stream_index]->nb_frames == 1) { 215 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d," 216 " ignoring.\n", pkt->stream_index); 217 } 218 if (s->streams[pkt->stream_index]->nb_frames >= 1) 219 return 0; 220 221 return avpriv_packet_list_put(&aiff->pict_list, pkt, NULL, 0); 222 } 223 224 return 0; 225} 226 227static int aiff_write_trailer(AVFormatContext *s) 228{ 229 int ret = 0; 230 AVIOContext *pb = s->pb; 231 AIFFOutputContext *aiff = s->priv_data; 232 AVCodecParameters *par = s->streams[aiff->audio_stream_idx]->codecpar; 233 234 /* Chunks sizes must be even */ 235 int64_t file_size, data_size; 236 data_size = avio_tell(pb); 237 if (data_size & 1) 238 avio_w8(pb, 0); 239 240 if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { 241 /* Write ID3 tags */ 242 if (aiff->write_id3v2) 243 if ((ret = put_id3v2_tags(s, aiff)) < 0) 244 return ret; 245 246 /* File length */ 247 file_size = avio_tell(pb); 248 avio_seek(pb, aiff->form, SEEK_SET); 249 avio_wb32(pb, file_size - aiff->form - 4); 250 251 /* Number of sample frames */ 252 avio_seek(pb, aiff->frames, SEEK_SET); 253 avio_wb32(pb, (data_size - aiff->ssnd - 12) / par->block_align); 254 255 /* Sound Data chunk size */ 256 avio_seek(pb, aiff->ssnd, SEEK_SET); 257 avio_wb32(pb, data_size - aiff->ssnd - 4); 258 } 259 260 return ret; 261} 262 263static void aiff_deinit(AVFormatContext *s) 264{ 265 AIFFOutputContext *aiff = s->priv_data; 266 267 avpriv_packet_list_free(&aiff->pict_list); 268} 269 270#define OFFSET(x) offsetof(AIFFOutputContext, x) 271#define ENC AV_OPT_FLAG_ENCODING_PARAM 272static const AVOption options[] = { 273 { "write_id3v2", "Enable ID3 tags writing.", 274 OFFSET(write_id3v2), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, ENC }, 275 { "id3v2_version", "Select ID3v2 version to write. Currently 3 and 4 are supported.", 276 OFFSET(id3v2_version), AV_OPT_TYPE_INT, {.i64 = 4}, 3, 4, ENC }, 277 { NULL }, 278}; 279 280static const AVClass aiff_muxer_class = { 281 .class_name = "AIFF muxer", 282 .item_name = av_default_item_name, 283 .option = options, 284 .version = LIBAVUTIL_VERSION_INT, 285}; 286 287const AVOutputFormat ff_aiff_muxer = { 288 .name = "aiff", 289 .long_name = NULL_IF_CONFIG_SMALL("Audio IFF"), 290 .mime_type = "audio/aiff", 291 .extensions = "aif,aiff,afc,aifc", 292 .priv_data_size = sizeof(AIFFOutputContext), 293 .audio_codec = AV_CODEC_ID_PCM_S16BE, 294 .video_codec = AV_CODEC_ID_PNG, 295 .write_header = aiff_write_header, 296 .write_packet = aiff_write_packet, 297 .write_trailer = aiff_write_trailer, 298 .deinit = aiff_deinit, 299 .codec_tag = ff_aiff_codec_tags_list, 300 .priv_class = &aiff_muxer_class, 301}; 302