Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * Core Audio Format muxer |
||
3 | * Copyright (c) 2011 Carl Eugen Hoyos |
||
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 "avformat.h" |
||
23 | #include "caf.h" |
||
24 | #include "isom.h" |
||
25 | #include "avio_internal.h" |
||
26 | #include "libavutil/intfloat.h" |
||
27 | #include "libavutil/dict.h" |
||
28 | |||
29 | typedef struct { |
||
30 | int64_t data; |
||
31 | uint8_t *pkt_sizes; |
||
32 | int size_buffer_size; |
||
33 | int size_entries_used; |
||
34 | int packets; |
||
35 | } CAFContext; |
||
36 | |||
37 | static uint32_t codec_flags(enum AVCodecID codec_id) { |
||
38 | switch (codec_id) { |
||
39 | case AV_CODEC_ID_PCM_F32BE: |
||
40 | case AV_CODEC_ID_PCM_F64BE: |
||
41 | return 1; //< kCAFLinearPCMFormatFlagIsFloat |
||
42 | case AV_CODEC_ID_PCM_S16LE: |
||
43 | case AV_CODEC_ID_PCM_S24LE: |
||
44 | case AV_CODEC_ID_PCM_S32LE: |
||
45 | return 2; //< kCAFLinearPCMFormatFlagIsLittleEndian |
||
46 | case AV_CODEC_ID_PCM_F32LE: |
||
47 | case AV_CODEC_ID_PCM_F64LE: |
||
48 | return 3; //< kCAFLinearPCMFormatFlagIsFloat | kCAFLinearPCMFormatFlagIsLittleEndian |
||
49 | default: |
||
50 | return 0; |
||
51 | } |
||
52 | } |
||
53 | |||
54 | static uint32_t samples_per_packet(enum AVCodecID codec_id, int channels) { |
||
55 | switch (codec_id) { |
||
56 | case AV_CODEC_ID_PCM_S8: |
||
57 | case AV_CODEC_ID_PCM_S16LE: |
||
58 | case AV_CODEC_ID_PCM_S16BE: |
||
59 | case AV_CODEC_ID_PCM_S24LE: |
||
60 | case AV_CODEC_ID_PCM_S24BE: |
||
61 | case AV_CODEC_ID_PCM_S32LE: |
||
62 | case AV_CODEC_ID_PCM_S32BE: |
||
63 | case AV_CODEC_ID_PCM_F32LE: |
||
64 | case AV_CODEC_ID_PCM_F32BE: |
||
65 | case AV_CODEC_ID_PCM_F64LE: |
||
66 | case AV_CODEC_ID_PCM_F64BE: |
||
67 | case AV_CODEC_ID_PCM_ALAW: |
||
68 | case AV_CODEC_ID_PCM_MULAW: |
||
69 | return 1; |
||
70 | case AV_CODEC_ID_MACE3: |
||
71 | case AV_CODEC_ID_MACE6: |
||
72 | return 6; |
||
73 | case AV_CODEC_ID_ADPCM_IMA_QT: |
||
74 | return 64; |
||
75 | case AV_CODEC_ID_AMR_NB: |
||
76 | case AV_CODEC_ID_GSM: |
||
77 | case AV_CODEC_ID_ILBC: |
||
78 | case AV_CODEC_ID_QCELP: |
||
79 | return 160; |
||
80 | case AV_CODEC_ID_GSM_MS: |
||
81 | return 320; |
||
82 | case AV_CODEC_ID_MP1: |
||
83 | return 384; |
||
84 | case AV_CODEC_ID_MP2: |
||
85 | case AV_CODEC_ID_MP3: |
||
86 | return 1152; |
||
87 | case AV_CODEC_ID_AC3: |
||
88 | return 1536; |
||
89 | case AV_CODEC_ID_QDM2: |
||
90 | return 2048 * channels; |
||
91 | case AV_CODEC_ID_ALAC: |
||
92 | return 4096; |
||
93 | case AV_CODEC_ID_ADPCM_IMA_WAV: |
||
94 | return (1024 - 4 * channels) * 8 / (4 * channels) + 1; |
||
95 | case AV_CODEC_ID_ADPCM_MS: |
||
96 | return (1024 - 7 * channels) * 2 / channels + 2; |
||
97 | default: |
||
98 | return 0; |
||
99 | } |
||
100 | } |
||
101 | |||
102 | static int caf_write_header(AVFormatContext *s) |
||
103 | { |
||
104 | AVIOContext *pb = s->pb; |
||
105 | AVCodecContext *enc = s->streams[0]->codec; |
||
106 | CAFContext *caf = s->priv_data; |
||
107 | AVDictionaryEntry *t = NULL; |
||
108 | unsigned int codec_tag = ff_codec_get_tag(ff_codec_caf_tags, enc->codec_id); |
||
109 | int64_t chunk_size = 0; |
||
110 | |||
111 | switch (enc->codec_id) { |
||
112 | case AV_CODEC_ID_AAC: |
||
113 | case AV_CODEC_ID_AC3: |
||
114 | av_log(s, AV_LOG_ERROR, "muxing codec currently unsupported\n"); |
||
115 | return AVERROR_PATCHWELCOME; |
||
116 | } |
||
117 | |||
118 | switch (enc->codec_id) { |
||
119 | case AV_CODEC_ID_PCM_S8: |
||
120 | case AV_CODEC_ID_PCM_S16LE: |
||
121 | case AV_CODEC_ID_PCM_S16BE: |
||
122 | case AV_CODEC_ID_PCM_S24LE: |
||
123 | case AV_CODEC_ID_PCM_S24BE: |
||
124 | case AV_CODEC_ID_PCM_S32LE: |
||
125 | case AV_CODEC_ID_PCM_S32BE: |
||
126 | case AV_CODEC_ID_PCM_F32LE: |
||
127 | case AV_CODEC_ID_PCM_F32BE: |
||
128 | case AV_CODEC_ID_PCM_F64LE: |
||
129 | case AV_CODEC_ID_PCM_F64BE: |
||
130 | case AV_CODEC_ID_PCM_ALAW: |
||
131 | case AV_CODEC_ID_PCM_MULAW: |
||
132 | codec_tag = MKTAG('l','p','c','m'); |
||
133 | } |
||
134 | |||
135 | if (!codec_tag) { |
||
136 | av_log(s, AV_LOG_ERROR, "unsupported codec\n"); |
||
137 | return AVERROR_INVALIDDATA; |
||
138 | } |
||
139 | |||
140 | if (!enc->block_align && !pb->seekable) { |
||
141 | av_log(s, AV_LOG_ERROR, "Muxing variable packet size not supported on non seekable output\n"); |
||
142 | return AVERROR_INVALIDDATA; |
||
143 | } |
||
144 | |||
145 | ffio_wfourcc(pb, "caff"); //< mFileType |
||
146 | avio_wb16(pb, 1); //< mFileVersion |
||
147 | avio_wb16(pb, 0); //< mFileFlags |
||
148 | |||
149 | ffio_wfourcc(pb, "desc"); //< Audio Description chunk |
||
150 | avio_wb64(pb, 32); //< mChunkSize |
||
151 | avio_wb64(pb, av_double2int(enc->sample_rate)); //< mSampleRate |
||
152 | avio_wl32(pb, codec_tag); //< mFormatID |
||
153 | avio_wb32(pb, codec_flags(enc->codec_id)); //< mFormatFlags |
||
154 | avio_wb32(pb, enc->block_align); //< mBytesPerPacket |
||
155 | avio_wb32(pb, samples_per_packet(enc->codec_id, enc->channels)); //< mFramesPerPacket |
||
156 | avio_wb32(pb, enc->channels); //< mChannelsPerFrame |
||
157 | avio_wb32(pb, av_get_bits_per_sample(enc->codec_id)); //< mBitsPerChannel |
||
158 | |||
159 | if (enc->channel_layout) { |
||
160 | ffio_wfourcc(pb, "chan"); |
||
161 | avio_wb64(pb, 12); |
||
162 | ff_mov_write_chan(pb, enc->channel_layout); |
||
163 | } |
||
164 | |||
165 | if (enc->codec_id == AV_CODEC_ID_ALAC) { |
||
166 | ffio_wfourcc(pb, "kuki"); |
||
167 | avio_wb64(pb, 12 + enc->extradata_size); |
||
168 | avio_write(pb, "\0\0\0\14frmaalac", 12); |
||
169 | avio_write(pb, enc->extradata, enc->extradata_size); |
||
170 | } else if (enc->codec_id == AV_CODEC_ID_AMR_NB) { |
||
171 | ffio_wfourcc(pb, "kuki"); |
||
172 | avio_wb64(pb, 29); |
||
173 | avio_write(pb, "\0\0\0\14frmasamr", 12); |
||
174 | avio_wb32(pb, 0x11); /* size */ |
||
175 | avio_write(pb, "samrFFMP", 8); |
||
176 | avio_w8(pb, 0); /* decoder version */ |
||
177 | |||
178 | avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */ |
||
179 | avio_w8(pb, 0x00); /* Mode change period (no restriction) */ |
||
180 | avio_w8(pb, 0x01); /* Frames per sample */ |
||
181 | } else if (enc->codec_id == AV_CODEC_ID_QDM2) { |
||
182 | ffio_wfourcc(pb, "kuki"); |
||
183 | avio_wb64(pb, enc->extradata_size); |
||
184 | avio_write(pb, enc->extradata, enc->extradata_size); |
||
185 | } |
||
186 | |||
187 | if (av_dict_count(s->metadata)) { |
||
188 | ffio_wfourcc(pb, "info"); //< Information chunk |
||
189 | while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { |
||
190 | chunk_size += strlen(t->key) + strlen(t->value) + 2; |
||
191 | } |
||
192 | avio_wb64(pb, chunk_size + 4); |
||
193 | avio_wb32(pb, av_dict_count(s->metadata)); |
||
194 | t = NULL; |
||
195 | while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { |
||
196 | avio_put_str(pb, t->key); |
||
197 | avio_put_str(pb, t->value); |
||
198 | } |
||
199 | } |
||
200 | |||
201 | ffio_wfourcc(pb, "data"); //< Audio Data chunk |
||
202 | caf->data = avio_tell(pb); |
||
203 | avio_wb64(pb, -1); //< mChunkSize |
||
204 | avio_wb32(pb, 0); //< mEditCount |
||
205 | |||
206 | avio_flush(pb); |
||
207 | return 0; |
||
208 | } |
||
209 | |||
210 | static int caf_write_packet(AVFormatContext *s, AVPacket *pkt) |
||
211 | { |
||
212 | CAFContext *caf = s->priv_data; |
||
213 | |||
214 | avio_write(s->pb, pkt->data, pkt->size); |
||
215 | if (!s->streams[0]->codec->block_align) { |
||
216 | void *pkt_sizes = caf->pkt_sizes; |
||
217 | int i, alloc_size = caf->size_entries_used + 5; |
||
218 | if (alloc_size < 0) { |
||
219 | caf->pkt_sizes = NULL; |
||
220 | } else { |
||
221 | caf->pkt_sizes = av_fast_realloc(caf->pkt_sizes, |
||
222 | &caf->size_buffer_size, |
||
223 | alloc_size); |
||
224 | } |
||
225 | if (!caf->pkt_sizes) { |
||
226 | av_free(pkt_sizes); |
||
227 | return AVERROR(ENOMEM); |
||
228 | } |
||
229 | for (i = 4; i > 0; i--) { |
||
230 | unsigned top = pkt->size >> i * 7; |
||
231 | if (top) |
||
232 | caf->pkt_sizes[caf->size_entries_used++] = 128 | top; |
||
233 | } |
||
234 | caf->pkt_sizes[caf->size_entries_used++] = pkt->size & 127; |
||
235 | caf->packets++; |
||
236 | } |
||
237 | return 0; |
||
238 | } |
||
239 | |||
240 | static int caf_write_trailer(AVFormatContext *s) |
||
241 | { |
||
242 | CAFContext *caf = s->priv_data; |
||
243 | AVIOContext *pb = s->pb; |
||
244 | AVCodecContext *enc = s->streams[0]->codec; |
||
245 | |||
246 | if (pb->seekable) { |
||
247 | int64_t file_size = avio_tell(pb); |
||
248 | |||
249 | avio_seek(pb, caf->data, SEEK_SET); |
||
250 | avio_wb64(pb, file_size - caf->data - 8); |
||
251 | avio_seek(pb, file_size, SEEK_SET); |
||
252 | if (!enc->block_align) { |
||
253 | ffio_wfourcc(pb, "pakt"); |
||
254 | avio_wb64(pb, caf->size_entries_used + 24); |
||
255 | avio_wb64(pb, caf->packets); ///< mNumberPackets |
||
256 | avio_wb64(pb, caf->packets * samples_per_packet(enc->codec_id, enc->channels)); ///< mNumberValidFrames |
||
257 | avio_wb32(pb, 0); ///< mPrimingFrames |
||
258 | avio_wb32(pb, 0); ///< mRemainderFrames |
||
259 | avio_write(pb, caf->pkt_sizes, caf->size_entries_used); |
||
260 | caf->size_buffer_size = 0; |
||
261 | } |
||
262 | avio_flush(pb); |
||
263 | } |
||
264 | av_freep(&caf->pkt_sizes); |
||
265 | return 0; |
||
266 | } |
||
267 | |||
268 | AVOutputFormat ff_caf_muxer = { |
||
269 | .name = "caf", |
||
270 | .long_name = NULL_IF_CONFIG_SMALL("Apple CAF (Core Audio Format)"), |
||
271 | .mime_type = "audio/x-caf", |
||
272 | .extensions = "caf", |
||
273 | .priv_data_size = sizeof(CAFContext), |
||
274 | .audio_codec = AV_CODEC_ID_PCM_S16BE, |
||
275 | .video_codec = AV_CODEC_ID_NONE, |
||
276 | .write_header = caf_write_header, |
||
277 | .write_packet = caf_write_packet, |
||
278 | .write_trailer = caf_write_trailer, |
||
279 | .codec_tag = (const AVCodecTag* const []){ff_codec_caf_tags, 0}, |
||
280 | };>>>>>>>>>>>>>>>>>>>>>>>> |