ffmpeg / libavformat / movenc.c @ 6cc7f139
History | View | Annotate | Download (78.6 KB)
1 | 1cb5f7fd | Michael Niedermayer | /*
|
---|---|---|---|
2 | 7fbde343 | Aurelien Jacobs | * MOV, 3GP, MP4 muxer
|
3 | 406792e7 | Diego Biurrun | * Copyright (c) 2003 Thomas Raivio
|
4 | * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
|
||
5 | 7c4502c8 | Baptiste Coudurier | * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
|
6 | 1cb5f7fd | Michael Niedermayer | *
|
7 | 2912e87a | Mans Rullgard | * This file is part of Libav.
|
8 | b78e7197 | Diego Biurrun | *
|
9 | 2912e87a | Mans Rullgard | * Libav is free software; you can redistribute it and/or
|
10 | 1cb5f7fd | Michael Niedermayer | * modify it under the terms of the GNU Lesser General Public
|
11 | * License as published by the Free Software Foundation; either
|
||
12 | b78e7197 | Diego Biurrun | * version 2.1 of the License, or (at your option) any later version.
|
13 | 1cb5f7fd | Michael Niedermayer | *
|
14 | 2912e87a | Mans Rullgard | * Libav is distributed in the hope that it will be useful,
|
15 | 1cb5f7fd | Michael Niedermayer | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
17 | * Lesser General Public License for more details.
|
||
18 | *
|
||
19 | * You should have received a copy of the GNU Lesser General Public
|
||
20 | 2912e87a | Mans Rullgard | * License along with Libav; if not, write to the Free Software
|
21 | 5509bffa | Diego Biurrun | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
22 | 1cb5f7fd | Michael Niedermayer | */
|
23 | 4909e517 | Baptiste Coudurier | |
24 | f72dad41 | Martin Storsjö | #include "movenc.h" |
25 | 1cb5f7fd | Michael Niedermayer | #include "avformat.h" |
26 | 0abdb293 | Anton Khirnov | #include "avio_internal.h" |
27 | 9d9f4119 | Måns Rullgård | #include "riff.h" |
28 | 1cb5f7fd | Michael Niedermayer | #include "avio.h" |
29 | e40ee6a2 | Baptiste Coudurier | #include "isom.h" |
30 | 1bd2d763 | Aurelien Jacobs | #include "avc.h" |
31 | 9106a698 | Stefano Sabatini | #include "libavcodec/get_bits.h" |
32 | b2755007 | Stefano Sabatini | #include "libavcodec/put_bits.h" |
33 | e977af6f | Martin Storsjö | #include "internal.h" |
34 | #include "libavutil/avstring.h" |
||
35 | 1cb5f7fd | Michael Niedermayer | |
36 | 6e6d6dc0 | Michael Niedermayer | #undef NDEBUG
|
37 | #include <assert.h> |
||
38 | |||
39 | 90b5b51e | Diego Biurrun | //FIXME support 64 bit variant with wide placeholders
|
40 | ae628ec1 | Anton Khirnov | static int64_t updateSize(AVIOContext *pb, int64_t pos)
|
41 | 1cb5f7fd | Michael Niedermayer | { |
42 | a2704c97 | Anton Khirnov | int64_t curpos = avio_tell(pb); |
43 | 6b4aa5da | Anton Khirnov | avio_seek(pb, pos, SEEK_SET); |
44 | 77eb5504 | Anton Khirnov | avio_wb32(pb, curpos - pos); /* rewrite size */
|
45 | 6b4aa5da | Anton Khirnov | avio_seek(pb, curpos, SEEK_SET); |
46 | 6e6d6dc0 | Michael Niedermayer | |
47 | return curpos - pos;
|
||
48 | 1cb5f7fd | Michael Niedermayer | } |
49 | |||
50 | e45ccf79 | Gildas Bazin | /* Chunk offset atom */
|
51 | ae628ec1 | Anton Khirnov | static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track) |
52 | 1cb5f7fd | Michael Niedermayer | { |
53 | int i;
|
||
54 | ed06cf6d | Benjamin Larsson | int mode64 = 0; // use 32 bit size variant if possible |
55 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
56 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
57 | b29af723 | Michael Niedermayer | if (pos > UINT32_MAX) {
|
58 | mode64 = 1;
|
||
59 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "co64");
|
60 | b29af723 | Michael Niedermayer | } else
|
61 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "stco");
|
62 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version & flags */ |
63 | avio_wb32(pb, track->entry); /* entry count */
|
||
64 | 1cb5f7fd | Michael Niedermayer | for (i=0; i<track->entry; i++) { |
65 | b29af723 | Michael Niedermayer | if(mode64 == 1) |
66 | 77eb5504 | Anton Khirnov | avio_wb64(pb, track->cluster[i].pos); |
67 | b29af723 | Michael Niedermayer | else
|
68 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->cluster[i].pos); |
69 | 1cb5f7fd | Michael Niedermayer | } |
70 | f7635edb | Baptiste Coudurier | return updateSize(pb, pos);
|
71 | 1cb5f7fd | Michael Niedermayer | } |
72 | |||
73 | e45ccf79 | Gildas Bazin | /* Sample size atom */
|
74 | ae628ec1 | Anton Khirnov | static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track) |
75 | 1cb5f7fd | Michael Niedermayer | { |
76 | f578f938 | Thomas Raivio | int equalChunks = 1; |
77 | e45ccf79 | Gildas Bazin | int i, j, entries = 0, tst = -1, oldtst = -1; |
78 | 1cb5f7fd | Michael Niedermayer | |
79 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
80 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
81 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "stsz");
|
82 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version & flags */ |
83 | 1cb5f7fd | Michael Niedermayer | |
84 | f578f938 | Thomas Raivio | for (i=0; i<track->entry; i++) { |
85 | 0aec3c5c | Baptiste Coudurier | tst = track->cluster[i].size/track->cluster[i].entries; |
86 | e45ccf79 | Gildas Bazin | if(oldtst != -1 && tst != oldtst) { |
87 | equalChunks = 0;
|
||
88 | f578f938 | Thomas Raivio | } |
89 | oldtst = tst; |
||
90 | 0aec3c5c | Baptiste Coudurier | entries += track->cluster[i].entries; |
91 | f578f938 | Thomas Raivio | } |
92 | e45ccf79 | Gildas Bazin | if (equalChunks) {
|
93 | 0aec3c5c | Baptiste Coudurier | int sSize = track->cluster[0].size/track->cluster[0].entries; |
94 | 77eb5504 | Anton Khirnov | avio_wb32(pb, sSize); // sample size
|
95 | avio_wb32(pb, entries); // sample count
|
||
96 | 1cb5f7fd | Michael Niedermayer | } |
97 | f578f938 | Thomas Raivio | else {
|
98 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); // sample size |
99 | avio_wb32(pb, entries); // sample count
|
||
100 | f578f938 | Thomas Raivio | for (i=0; i<track->entry; i++) { |
101 | 91208916 | Baptiste Coudurier | for (j=0; j<track->cluster[i].entries; j++) { |
102 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->cluster[i].size / |
103 | 0aec3c5c | Baptiste Coudurier | track->cluster[i].entries); |
104 | e45ccf79 | Gildas Bazin | } |
105 | 1cb5f7fd | Michael Niedermayer | } |
106 | } |
||
107 | f7635edb | Baptiste Coudurier | return updateSize(pb, pos);
|
108 | 1cb5f7fd | Michael Niedermayer | } |
109 | |||
110 | e45ccf79 | Gildas Bazin | /* Sample to chunk atom */
|
111 | ae628ec1 | Anton Khirnov | static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track) |
112 | 1cb5f7fd | Michael Niedermayer | { |
113 | b29af723 | Michael Niedermayer | int index = 0, oldval = -1, i; |
114 | bc5c918e | Diego Biurrun | int64_t entryPos, curpos; |
115 | f578f938 | Thomas Raivio | |
116 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
117 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
118 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "stsc");
|
119 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); // version & flags |
120 | a2704c97 | Anton Khirnov | entryPos = avio_tell(pb); |
121 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->entry); // entry count
|
122 | f578f938 | Thomas Raivio | for (i=0; i<track->entry; i++) { |
123 | 0aec3c5c | Baptiste Coudurier | if(oldval != track->cluster[i].samplesInChunk)
|
124 | f578f938 | Thomas Raivio | { |
125 | 77eb5504 | Anton Khirnov | avio_wb32(pb, i+1); // first chunk |
126 | avio_wb32(pb, track->cluster[i].samplesInChunk); // samples per chunk
|
||
127 | avio_wb32(pb, 0x1); // sample description index |
||
128 | 0aec3c5c | Baptiste Coudurier | oldval = track->cluster[i].samplesInChunk; |
129 | f578f938 | Thomas Raivio | index++; |
130 | 1cb5f7fd | Michael Niedermayer | } |
131 | } |
||
132 | a2704c97 | Anton Khirnov | curpos = avio_tell(pb); |
133 | 6b4aa5da | Anton Khirnov | avio_seek(pb, entryPos, SEEK_SET); |
134 | 77eb5504 | Anton Khirnov | avio_wb32(pb, index); // rewrite size
|
135 | 6b4aa5da | Anton Khirnov | avio_seek(pb, curpos, SEEK_SET); |
136 | 1cb5f7fd | Michael Niedermayer | |
137 | f7635edb | Baptiste Coudurier | return updateSize(pb, pos);
|
138 | 1cb5f7fd | Michael Niedermayer | } |
139 | |||
140 | e45ccf79 | Gildas Bazin | /* Sync sample atom */
|
141 | ae628ec1 | Anton Khirnov | static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag) |
142 | 1cb5f7fd | Michael Niedermayer | { |
143 | bc5c918e | Diego Biurrun | int64_t curpos, entryPos; |
144 | b29af723 | Michael Niedermayer | int i, index = 0; |
145 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
146 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); // size |
147 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps"); |
148 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); // version & flags |
149 | a2704c97 | Anton Khirnov | entryPos = avio_tell(pb); |
150 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->entry); // entry count
|
151 | f578f938 | Thomas Raivio | for (i=0; i<track->entry; i++) { |
152 | e1316b19 | Baptiste Coudurier | if (track->cluster[i].flags & flag) {
|
153 | 77eb5504 | Anton Khirnov | avio_wb32(pb, i+1);
|
154 | f578f938 | Thomas Raivio | index++; |
155 | } |
||
156 | } |
||
157 | a2704c97 | Anton Khirnov | curpos = avio_tell(pb); |
158 | 6b4aa5da | Anton Khirnov | avio_seek(pb, entryPos, SEEK_SET); |
159 | 77eb5504 | Anton Khirnov | avio_wb32(pb, index); // rewrite size
|
160 | 6b4aa5da | Anton Khirnov | avio_seek(pb, curpos, SEEK_SET); |
161 | f7635edb | Baptiste Coudurier | return updateSize(pb, pos);
|
162 | 1cb5f7fd | Michael Niedermayer | } |
163 | |||
164 | ae628ec1 | Anton Khirnov | static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track) |
165 | 1cb5f7fd | Michael Niedermayer | { |
166 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x11); /* size */ |
167 | 0abdb293 | Anton Khirnov | if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr"); |
168 | else ffio_wfourcc(pb, "damr"); |
||
169 | ffio_wfourcc(pb, "FFMP");
|
||
170 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0); /* decoder version */ |
171 | 3a72cbd9 | Baptiste Coudurier | |
172 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */ |
173 | avio_w8(pb, 0x00); /* Mode change period (no restriction) */ |
||
174 | avio_w8(pb, 0x01); /* Frames per sample */ |
||
175 | 3a72cbd9 | Baptiste Coudurier | return 0x11; |
176 | } |
||
177 | |||
178 | ae628ec1 | Anton Khirnov | static int mov_write_ac3_tag(AVIOContext *pb, MOVTrack *track) |
179 | d4a240cb | Baptiste Coudurier | { |
180 | GetBitContext gbc; |
||
181 | PutBitContext pbc; |
||
182 | uint8_t buf[3];
|
||
183 | int fscod, bsid, bsmod, acmod, lfeon, frmsizecod;
|
||
184 | |||
185 | if (track->vosLen < 7) |
||
186 | return -1; |
||
187 | |||
188 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 11);
|
189 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "dac3");
|
190 | d4a240cb | Baptiste Coudurier | |
191 | 544a0f47 | Damiano Galassi | init_get_bits(&gbc, track->vosData+4, track->vosLen-4); |
192 | d4a240cb | Baptiste Coudurier | fscod = get_bits(&gbc, 2);
|
193 | frmsizecod = get_bits(&gbc, 6);
|
||
194 | bsid = get_bits(&gbc, 5);
|
||
195 | bsmod = get_bits(&gbc, 3);
|
||
196 | acmod = get_bits(&gbc, 3);
|
||
197 | if (acmod == 2) { |
||
198 | skip_bits(&gbc, 2); // dsurmod |
||
199 | } else {
|
||
200 | if ((acmod & 1) && acmod != 1) |
||
201 | skip_bits(&gbc, 2); // cmixlev |
||
202 | if (acmod & 4) |
||
203 | skip_bits(&gbc, 2); // surmixlev |
||
204 | } |
||
205 | lfeon = get_bits1(&gbc); |
||
206 | |||
207 | init_put_bits(&pbc, buf, sizeof(buf));
|
||
208 | put_bits(&pbc, 2, fscod);
|
||
209 | put_bits(&pbc, 5, bsid);
|
||
210 | put_bits(&pbc, 3, bsmod);
|
||
211 | put_bits(&pbc, 3, acmod);
|
||
212 | put_bits(&pbc, 1, lfeon);
|
||
213 | put_bits(&pbc, 5, frmsizecod>>1); // bit_rate_code |
||
214 | put_bits(&pbc, 5, 0); // reserved |
||
215 | |||
216 | flush_put_bits(&pbc); |
||
217 | 77eb5504 | Anton Khirnov | avio_write(pb, buf, sizeof(buf));
|
218 | d4a240cb | Baptiste Coudurier | |
219 | return 11; |
||
220 | } |
||
221 | |||
222 | 463e7afd | Baptiste Coudurier | /**
|
223 | * This function writes extradata "as is".
|
||
224 | * Extradata must be formated like a valid atom (with size and tag)
|
||
225 | */
|
||
226 | ae628ec1 | Anton Khirnov | static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track) |
227 | 463e7afd | Baptiste Coudurier | { |
228 | 77eb5504 | Anton Khirnov | avio_write(pb, track->enc->extradata, track->enc->extradata_size); |
229 | 463e7afd | Baptiste Coudurier | return track->enc->extradata_size;
|
230 | } |
||
231 | |||
232 | ae628ec1 | Anton Khirnov | static int mov_write_enda_tag(AVIOContext *pb) |
233 | fcef991a | Baptiste Coudurier | { |
234 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 10);
|
235 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "enda");
|
236 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 1); /* little endian */ |
237 | fcef991a | Baptiste Coudurier | return 10; |
238 | } |
||
239 | |||
240 | 039627cf | Baptiste Coudurier | static unsigned int descrLength(unsigned int len) |
241 | { |
||
242 | 08db8f18 | Michael Niedermayer | int i;
|
243 | for(i=1; len>>(7*i); i++); |
||
244 | return len + 1 + i; |
||
245 | 039627cf | Baptiste Coudurier | } |
246 | |||
247 | ae628ec1 | Anton Khirnov | static void putDescr(AVIOContext *pb, int tag, unsigned int size) |
248 | 039627cf | Baptiste Coudurier | { |
249 | 08db8f18 | Michael Niedermayer | int i= descrLength(size) - size - 2; |
250 | 77eb5504 | Anton Khirnov | avio_w8(pb, tag); |
251 | 08db8f18 | Michael Niedermayer | for(; i>0; i--) |
252 | 77eb5504 | Anton Khirnov | avio_w8(pb, (size>>(7*i)) | 0x80); |
253 | avio_w8(pb, size & 0x7F);
|
||
254 | 039627cf | Baptiste Coudurier | } |
255 | |||
256 | ae628ec1 | Anton Khirnov | static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic |
257 | 039627cf | Baptiste Coudurier | { |
258 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
259 | fcef991a | Baptiste Coudurier | int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0; |
260 | 039627cf | Baptiste Coudurier | |
261 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); // size |
262 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "esds");
|
263 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); // Version |
264 | 039627cf | Baptiste Coudurier | |
265 | // ES descriptor
|
||
266 | putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) + |
||
267 | descrLength(1));
|
||
268 | 77eb5504 | Anton Khirnov | avio_wb16(pb, track->trackID); |
269 | avio_w8(pb, 0x00); // flags (= no flags) |
||
270 | 039627cf | Baptiste Coudurier | |
271 | // DecoderConfig descriptor
|
||
272 | putDescr(pb, 0x04, 13 + decoderSpecificInfoLen); |
||
273 | |||
274 | // Object type indication
|
||
275 | dfce888f | Baptiste Coudurier | if ((track->enc->codec_id == CODEC_ID_MP2 ||
|
276 | track->enc->codec_id == CODEC_ID_MP3) && |
||
277 | c4e02d70 | Baptiste Coudurier | track->enc->sample_rate > 24000)
|
278 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0x6B); // 11172-3 |
279 | dfce888f | Baptiste Coudurier | else
|
280 | 77eb5504 | Anton Khirnov | avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id)); |
281 | 039627cf | Baptiste Coudurier | |
282 | // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
|
||
283 | // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
|
||
284 | 72415b2a | Stefano Sabatini | if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
|
285 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0x15); // flags (= Audiostream) |
286 | 039627cf | Baptiste Coudurier | else
|
287 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0x11); // flags (= Visualstream) |
288 | 039627cf | Baptiste Coudurier | |
289 | 77eb5504 | Anton Khirnov | avio_w8(pb, track->enc->rc_buffer_size>>(3+16)); // Buffersize DB (24 bits) |
290 | avio_wb16(pb, (track->enc->rc_buffer_size>>3)&0xFFFF); // Buffersize DB |
||
291 | 039627cf | Baptiste Coudurier | |
292 | 77eb5504 | Anton Khirnov | avio_wb32(pb, FFMAX(track->enc->bit_rate, track->enc->rc_max_rate)); // maxbitrate (FIXME should be max rate in any 1 sec window)
|
293 | 039627cf | Baptiste Coudurier | if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0) |
294 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); // vbr |
295 | 039627cf | Baptiste Coudurier | else
|
296 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->enc->rc_max_rate); // avg bitrate
|
297 | 039627cf | Baptiste Coudurier | |
298 | 287d6cfa | Baptiste Coudurier | if (track->vosLen) {
|
299 | 039627cf | Baptiste Coudurier | // DecoderSpecific info descriptor
|
300 | putDescr(pb, 0x05, track->vosLen);
|
||
301 | 77eb5504 | Anton Khirnov | avio_write(pb, track->vosData, track->vosLen); |
302 | 039627cf | Baptiste Coudurier | } |
303 | |||
304 | // SL descriptor
|
||
305 | putDescr(pb, 0x06, 1); |
||
306 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0x02);
|
307 | f7635edb | Baptiste Coudurier | return updateSize(pb, pos);
|
308 | 039627cf | Baptiste Coudurier | } |
309 | |||
310 | 7c4b7d0f | Baptiste Coudurier | static int mov_pcm_le_gt16(enum CodecID codec_id) |
311 | { |
||
312 | return codec_id == CODEC_ID_PCM_S24LE ||
|
||
313 | codec_id == CODEC_ID_PCM_S32LE || |
||
314 | codec_id == CODEC_ID_PCM_F32LE || |
||
315 | codec_id == CODEC_ID_PCM_F64LE; |
||
316 | } |
||
317 | |||
318 | ae628ec1 | Anton Khirnov | static int mov_write_ms_tag(AVIOContext *pb, MOVTrack *track) |
319 | f2589642 | Baptiste Coudurier | { |
320 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
321 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0);
|
322 | avio_wl32(pb, track->tag); // store it byteswapped
|
||
323 | 795ed278 | Janne Grunau | track->enc->codec_tag = av_bswap16(track->tag >> 16);
|
324 | f2589642 | Baptiste Coudurier | ff_put_wav_header(pb, track->enc); |
325 | return updateSize(pb, pos);
|
||
326 | } |
||
327 | |||
328 | ae628ec1 | Anton Khirnov | static int mov_write_wave_tag(AVIOContext *pb, MOVTrack *track) |
329 | 69dde1ad | Gildas Bazin | { |
330 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
331 | 69dde1ad | Gildas Bazin | |
332 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
333 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "wave");
|
334 | 69dde1ad | Gildas Bazin | |
335 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 12); /* size */ |
336 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "frma");
|
337 | 77eb5504 | Anton Khirnov | avio_wl32(pb, track->tag); |
338 | 69dde1ad | Gildas Bazin | |
339 | fcef991a | Baptiste Coudurier | if (track->enc->codec_id == CODEC_ID_AAC) {
|
340 | aa1c1c61 | Baptiste Coudurier | /* useless atom needed by mplayer, ipod, not needed by quicktime */
|
341 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 12); /* size */ |
342 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "mp4a");
|
343 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0);
|
344 | fcef991a | Baptiste Coudurier | mov_write_esds_tag(pb, track); |
345 | 7c4b7d0f | Baptiste Coudurier | } else if (mov_pcm_le_gt16(track->enc->codec_id)) { |
346 | fcef991a | Baptiste Coudurier | mov_write_enda_tag(pb); |
347 | 3a72cbd9 | Baptiste Coudurier | } else if (track->enc->codec_id == CODEC_ID_AMR_NB) { |
348 | b7d9da10 | Baptiste Coudurier | mov_write_amr_tag(pb, track); |
349 | d4a240cb | Baptiste Coudurier | } else if (track->enc->codec_id == CODEC_ID_AC3) { |
350 | mov_write_ac3_tag(pb, track); |
||
351 | 463e7afd | Baptiste Coudurier | } else if (track->enc->codec_id == CODEC_ID_ALAC) { |
352 | mov_write_extradata_tag(pb, track); |
||
353 | f2589642 | Baptiste Coudurier | } else if (track->enc->codec_id == CODEC_ID_ADPCM_MS || |
354 | track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) { |
||
355 | mov_write_ms_tag(pb, track); |
||
356 | fcef991a | Baptiste Coudurier | } |
357 | 69dde1ad | Gildas Bazin | |
358 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 8); /* size */ |
359 | avio_wb32(pb, 0); /* null tag */ |
||
360 | 69dde1ad | Gildas Bazin | |
361 | f7635edb | Baptiste Coudurier | return updateSize(pb, pos);
|
362 | 69dde1ad | Gildas Bazin | } |
363 | |||
364 | ae628ec1 | Anton Khirnov | static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track) |
365 | 79e42311 | Baptiste Coudurier | { |
366 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->vosLen+8);
|
367 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "glbl");
|
368 | 77eb5504 | Anton Khirnov | avio_write(pb, track->vosData, track->vosLen); |
369 | 79e42311 | Baptiste Coudurier | return 8+track->vosLen; |
370 | } |
||
371 | |||
372 | feaa8d11 | Baptiste Coudurier | /**
|
373 | * Compute flags for 'lpcm' tag.
|
||
374 | * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
|
||
375 | */
|
||
376 | static int mov_get_lpcm_flags(enum CodecID codec_id) |
||
377 | { |
||
378 | switch (codec_id) {
|
||
379 | case CODEC_ID_PCM_F32BE:
|
||
380 | case CODEC_ID_PCM_F64BE:
|
||
381 | return 11; |
||
382 | case CODEC_ID_PCM_F32LE:
|
||
383 | case CODEC_ID_PCM_F64LE:
|
||
384 | return 9; |
||
385 | case CODEC_ID_PCM_U8:
|
||
386 | return 10; |
||
387 | case CODEC_ID_PCM_S16BE:
|
||
388 | case CODEC_ID_PCM_S24BE:
|
||
389 | case CODEC_ID_PCM_S32BE:
|
||
390 | return 14; |
||
391 | case CODEC_ID_PCM_S8:
|
||
392 | case CODEC_ID_PCM_S16LE:
|
||
393 | case CODEC_ID_PCM_S24LE:
|
||
394 | case CODEC_ID_PCM_S32LE:
|
||
395 | return 12; |
||
396 | default:
|
||
397 | return 0; |
||
398 | } |
||
399 | } |
||
400 | |||
401 | ae628ec1 | Anton Khirnov | static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track) |
402 | 1cb5f7fd | Michael Niedermayer | { |
403 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
404 | feaa8d11 | Baptiste Coudurier | int version = 0; |
405 | uint32_t tag = track->tag; |
||
406 | |||
407 | if (track->mode == MODE_MOV) {
|
||
408 | if (track->timescale > UINT16_MAX) {
|
||
409 | if (mov_get_lpcm_flags(track->enc->codec_id))
|
||
410 | tag = AV_RL32("lpcm");
|
||
411 | version = 2;
|
||
412 | f2589642 | Baptiste Coudurier | } else if (track->audio_vbr || mov_pcm_le_gt16(track->enc->codec_id) || |
413 | track->enc->codec_id == CODEC_ID_ADPCM_MS || |
||
414 | track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) { |
||
415 | feaa8d11 | Baptiste Coudurier | version = 1;
|
416 | } |
||
417 | } |
||
418 | 115329f1 | Diego Biurrun | |
419 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
420 | avio_wl32(pb, tag); // store it byteswapped
|
||
421 | avio_wb32(pb, 0); /* Reserved */ |
||
422 | avio_wb16(pb, 0); /* Reserved */ |
||
423 | avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */ |
||
424 | 69dde1ad | Gildas Bazin | |
425 | e45ccf79 | Gildas Bazin | /* SoundDescription */
|
426 | 77eb5504 | Anton Khirnov | avio_wb16(pb, version); /* Version */
|
427 | avio_wb16(pb, 0); /* Revision level */ |
||
428 | avio_wb32(pb, 0); /* Reserved */ |
||
429 | 1cb5f7fd | Michael Niedermayer | |
430 | feaa8d11 | Baptiste Coudurier | if (version == 2) { |
431 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 3);
|
432 | avio_wb16(pb, 16);
|
||
433 | avio_wb16(pb, 0xfffe);
|
||
434 | avio_wb16(pb, 0);
|
||
435 | avio_wb32(pb, 0x00010000);
|
||
436 | avio_wb32(pb, 72);
|
||
437 | avio_wb64(pb, av_dbl2int(track->timescale)); |
||
438 | avio_wb32(pb, track->enc->channels); |
||
439 | avio_wb32(pb, 0x7F000000);
|
||
440 | avio_wb32(pb, av_get_bits_per_sample(track->enc->codec_id)); |
||
441 | avio_wb32(pb, mov_get_lpcm_flags(track->enc->codec_id)); |
||
442 | avio_wb32(pb, track->sampleSize); |
||
443 | avio_wb32(pb, track->enc->frame_size); |
||
444 | feaa8d11 | Baptiste Coudurier | } else {
|
445 | ba7c0ece | Baptiste Coudurier | if (track->mode == MODE_MOV) {
|
446 | 77eb5504 | Anton Khirnov | avio_wb16(pb, track->enc->channels); |
447 | ba7c0ece | Baptiste Coudurier | if (track->enc->codec_id == CODEC_ID_PCM_U8 ||
|
448 | track->enc->codec_id == CODEC_ID_PCM_S8) |
||
449 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 8); /* bits per sample */ |
450 | ba7c0ece | Baptiste Coudurier | else
|
451 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 16);
|
452 | avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */ |
||
453 | ba7c0ece | Baptiste Coudurier | } else { /* reserved for mp4/3gp */ |
454 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 2);
|
455 | avio_wb16(pb, 16);
|
||
456 | avio_wb16(pb, 0);
|
||
457 | ba7c0ece | Baptiste Coudurier | } |
458 | ef19c7eb | Gildas Bazin | |
459 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 0); /* packet size (= 0) */ |
460 | avio_wb16(pb, track->timescale); /* Time scale */
|
||
461 | avio_wb16(pb, 0); /* Reserved */ |
||
462 | feaa8d11 | Baptiste Coudurier | } |
463 | 1cb5f7fd | Michael Niedermayer | |
464 | 5cb49ca1 | Baptiste Coudurier | if(version == 1) { /* SoundDescription V1 extended info */ |
465 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->enc->frame_size); /* Samples per packet */
|
466 | avio_wb32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */
|
||
467 | avio_wb32(pb, track->sampleSize); /* Bytes per frame */
|
||
468 | avio_wb32(pb, 2); /* Bytes per sample */ |
||
469 | 69dde1ad | Gildas Bazin | } |
470 | |||
471 | 6dd19fff | Baptiste Coudurier | if(track->mode == MODE_MOV &&
|
472 | (track->enc->codec_id == CODEC_ID_AAC || |
||
473 | 4ed19420 | Kurtnoise | track->enc->codec_id == CODEC_ID_AC3 || |
474 | 6dd19fff | Baptiste Coudurier | track->enc->codec_id == CODEC_ID_AMR_NB || |
475 | 7c4b7d0f | Baptiste Coudurier | track->enc->codec_id == CODEC_ID_ALAC || |
476 | f2589642 | Baptiste Coudurier | track->enc->codec_id == CODEC_ID_ADPCM_MS || |
477 | track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV || |
||
478 | 7c4b7d0f | Baptiste Coudurier | mov_pcm_le_gt16(track->enc->codec_id))) |
479 | fcef991a | Baptiste Coudurier | mov_write_wave_tag(pb, track); |
480 | d0c0a29b | Baptiste Coudurier | else if(track->tag == MKTAG('m','p','4','a')) |
481 | 3a72cbd9 | Baptiste Coudurier | mov_write_esds_tag(pb, track); |
482 | else if(track->enc->codec_id == CODEC_ID_AMR_NB) |
||
483 | b7d9da10 | Baptiste Coudurier | mov_write_amr_tag(pb, track); |
484 | 4ed19420 | Kurtnoise | else if(track->enc->codec_id == CODEC_ID_AC3) |
485 | mov_write_ac3_tag(pb, track); |
||
486 | efa1fb39 | Baptiste Coudurier | else if(track->enc->codec_id == CODEC_ID_ALAC) |
487 | 709c9f8d | Baptiste Coudurier | mov_write_extradata_tag(pb, track); |
488 | 79e42311 | Baptiste Coudurier | else if(track->vosLen > 0) |
489 | mov_write_glbl_tag(pb, track); |
||
490 | 3a72cbd9 | Baptiste Coudurier | |
491 | f7635edb | Baptiste Coudurier | return updateSize(pb, pos);
|
492 | 1cb5f7fd | Michael Niedermayer | } |
493 | |||
494 | ae628ec1 | Anton Khirnov | static int mov_write_d263_tag(AVIOContext *pb) |
495 | 1cb5f7fd | Michael Niedermayer | { |
496 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0xf); /* size */ |
497 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "d263");
|
498 | ffio_wfourcc(pb, "FFMP");
|
||
499 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0); /* decoder version */ |
500 | 87494ea0 | Baptiste Coudurier | /* FIXME use AVCodecContext level/profile, when encoder will set values */
|
501 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0xa); /* level */ |
502 | avio_w8(pb, 0); /* profile */ |
||
503 | 1cb5f7fd | Michael Niedermayer | return 0xf; |
504 | } |
||
505 | |||
506 | f578f938 | Thomas Raivio | /* TODO: No idea about these values */
|
507 | ae628ec1 | Anton Khirnov | static int mov_write_svq3_tag(AVIOContext *pb) |
508 | 1cb5f7fd | Michael Niedermayer | { |
509 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x15);
|
510 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "SMI ");
|
511 | ffio_wfourcc(pb, "SEQH");
|
||
512 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x5);
|
513 | avio_wb32(pb, 0xe2c0211d);
|
||
514 | avio_wb32(pb, 0xc0000000);
|
||
515 | avio_w8(pb, 0);
|
||
516 | f578f938 | Thomas Raivio | return 0x15; |
517 | 1cb5f7fd | Michael Niedermayer | } |
518 | |||
519 | ae628ec1 | Anton Khirnov | static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track) |
520 | 6e6eebf9 | Aurelien Jacobs | { |
521 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
522 | 6e6eebf9 | Aurelien Jacobs | |
523 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0);
|
524 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "avcC");
|
525 | 9ab3f71b | Aurelien Jacobs | ff_isom_write_avcc(pb, track->vosData, track->vosLen); |
526 | c1b8e6d8 | Baptiste Coudurier | return updateSize(pb, pos);
|
527 | } |
||
528 | |||
529 | fc4cbc16 | Baptiste Coudurier | /* also used by all avid codecs (dv, imx, meridien) and their variants */
|
530 | ae628ec1 | Anton Khirnov | static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track) |
531 | fc4cbc16 | Baptiste Coudurier | { |
532 | int i;
|
||
533 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 24); /* size */ |
534 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "ACLR");
|
535 | ffio_wfourcc(pb, "ACLR");
|
||
536 | ffio_wfourcc(pb, "0001");
|
||
537 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 1); /* yuv 1 / rgb 2 ? */ |
538 | avio_wb32(pb, 0); /* unknown */ |
||
539 | fc4cbc16 | Baptiste Coudurier | |
540 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 24); /* size */ |
541 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "APRG");
|
542 | ffio_wfourcc(pb, "APRG");
|
||
543 | ffio_wfourcc(pb, "0001");
|
||
544 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 1); /* unknown */ |
545 | avio_wb32(pb, 0); /* unknown */ |
||
546 | fc4cbc16 | Baptiste Coudurier | |
547 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 120); /* size */ |
548 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "ARES");
|
549 | ffio_wfourcc(pb, "ARES");
|
||
550 | ffio_wfourcc(pb, "0001");
|
||
551 | 77eb5504 | Anton Khirnov | avio_wb32(pb, AV_RB32(track->vosData + 0x28)); /* dnxhd cid, some id ? */ |
552 | avio_wb32(pb, track->enc->width); |
||
553 | fc4cbc16 | Baptiste Coudurier | /* values below are based on samples created with quicktime and avid codecs */
|
554 | if (track->vosData[5] & 2) { // interlaced |
||
555 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->enc->height/2);
|
556 | avio_wb32(pb, 2); /* unknown */ |
||
557 | avio_wb32(pb, 0); /* unknown */ |
||
558 | avio_wb32(pb, 4); /* unknown */ |
||
559 | fc4cbc16 | Baptiste Coudurier | } else {
|
560 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->enc->height); |
561 | avio_wb32(pb, 1); /* unknown */ |
||
562 | avio_wb32(pb, 0); /* unknown */ |
||
563 | 44fb8ebb | Baptiste Coudurier | if (track->enc->height == 1080) |
564 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 5); /* unknown */ |
565 | 44fb8ebb | Baptiste Coudurier | else
|
566 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 6); /* unknown */ |
567 | fc4cbc16 | Baptiste Coudurier | } |
568 | /* padding */
|
||
569 | for (i = 0; i < 10; i++) |
||
570 | 77eb5504 | Anton Khirnov | avio_wb64(pb, 0);
|
571 | fc4cbc16 | Baptiste Coudurier | |
572 | /* extra padding for stsd needed */
|
||
573 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0);
|
574 | fc4cbc16 | Baptiste Coudurier | return 0; |
575 | } |
||
576 | |||
577 | 6b600285 | Baptiste Coudurier | static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track) |
578 | 8e321619 | Baptiste Coudurier | { |
579 | 039627cf | Baptiste Coudurier | int tag = track->enc->codec_tag;
|
580 | 2ab57c04 | Baptiste Coudurier | |
581 | 1a40491e | Daniel Verkamp | if (!ff_codec_get_tag(ff_mp4_obj_type, track->enc->codec_id))
|
582 | 2ab57c04 | Baptiste Coudurier | return 0; |
583 | |||
584 | if (track->enc->codec_id == CODEC_ID_H264) tag = MKTAG('a','v','c','1'); |
||
585 | else if (track->enc->codec_id == CODEC_ID_AC3) tag = MKTAG('a','c','-','3'); |
||
586 | else if (track->enc->codec_id == CODEC_ID_DIRAC) tag = MKTAG('d','r','a','c'); |
||
587 | else if (track->enc->codec_id == CODEC_ID_MOV_TEXT) tag = MKTAG('t','x','3','g'); |
||
588 | 72415b2a | Stefano Sabatini | else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) tag = MKTAG('m','p','4','v'); |
589 | else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) tag = MKTAG('m','p','4','a'); |
||
590 | 6b600285 | Baptiste Coudurier | |
591 | return tag;
|
||
592 | } |
||
593 | |||
594 | 3c8d1447 | Baptiste Coudurier | static const AVCodecTag codec_ipod_tags[] = { |
595 | { CODEC_ID_H264, MKTAG('a','v','c','1') }, |
||
596 | { CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, |
||
597 | { CODEC_ID_AAC, MKTAG('m','p','4','a') }, |
||
598 | { CODEC_ID_ALAC, MKTAG('a','l','a','c') }, |
||
599 | { CODEC_ID_AC3, MKTAG('a','c','-','3') }, |
||
600 | { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') }, |
||
601 | { CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') }, |
||
602 | { CODEC_ID_NONE, 0 },
|
||
603 | }; |
||
604 | |||
605 | 6b600285 | Baptiste Coudurier | static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track) |
606 | { |
||
607 | int tag = track->enc->codec_tag;
|
||
608 | |||
609 | 130ba4b1 | Baptiste Coudurier | // keep original tag for subs, ipod supports both formats
|
610 | 72415b2a | Stefano Sabatini | if (!(track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE &&
|
611 | 2ab57c04 | Baptiste Coudurier | (tag == MKTAG('t','x','3','g') || |
612 | b6cb9946 | Baptiste Coudurier | tag == MKTAG('t','e','x','t')))) |
613 | 1a40491e | Daniel Verkamp | tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id); |
614 | 0872acc4 | Baptiste Coudurier | |
615 | ade5b91d | Stefano Sabatini | if (!av_match_ext(s->filename, "m4a") && !av_match_ext(s->filename, "m4v")) |
616 | 2ab57c04 | Baptiste Coudurier | av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
|
617 | "Quicktime/Ipod might not play the file\n");
|
||
618 | 6b600285 | Baptiste Coudurier | |
619 | return tag;
|
||
620 | } |
||
621 | |||
622 | static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track) |
||
623 | { |
||
624 | int tag;
|
||
625 | |||
626 | 06ed4873 | Baptiste Coudurier | if (track->enc->width == 720) /* SD */ |
627 | if (track->enc->height == 480) /* NTSC */ |
||
628 | if (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n'); |
||
629 | else tag = MKTAG('d','v','c',' '); |
||
630 | else if (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p'); |
||
631 | else if (track->enc->pix_fmt == PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p'); |
||
632 | else tag = MKTAG('d','v','p','p'); |
||
633 | else if (track->enc->height == 720) /* HD 720 line */ |
||
634 | if (track->enc->time_base.den == 50) tag = MKTAG('d','v','h','q'); |
||
635 | else tag = MKTAG('d','v','h','p'); |
||
636 | else if (track->enc->height == 1080) /* HD 1080 line */ |
||
637 | if (track->enc->time_base.den == 25) tag = MKTAG('d','v','h','5'); |
||
638 | else tag = MKTAG('d','v','h','6'); |
||
639 | else {
|
||
640 | av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
|
||
641 | return 0; |
||
642 | } |
||
643 | 6b600285 | Baptiste Coudurier | |
644 | return tag;
|
||
645 | } |
||
646 | |||
647 | 3c8d1447 | Baptiste Coudurier | static const struct { |
648 | enum PixelFormat pix_fmt;
|
||
649 | uint32_t tag; |
||
650 | unsigned bps;
|
||
651 | } mov_pix_fmt_tags[] = { |
||
652 | { PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 }, |
||
653 | { PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 }, |
||
654 | a7cc89e2 | Baptiste Coudurier | { PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 }, |
655 | f65aad95 | Baptiste Coudurier | { PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 }, |
656 | { PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 }, |
||
657 | { PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 }, |
||
658 | 9a191b3a | Baptiste Coudurier | { PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 }, |
659 | 3c8d1447 | Baptiste Coudurier | { PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 }, |
660 | f65aad95 | Baptiste Coudurier | { PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 }, |
661 | dfb0471f | Baptiste Coudurier | { PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 }, |
662 | 5b50b8f5 | Baptiste Coudurier | { PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 }, |
663 | ed88074a | Baptiste Coudurier | { PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 }, |
664 | a7cc89e2 | Baptiste Coudurier | { PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 }, |
665 | 9a191b3a | Baptiste Coudurier | { PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 }, |
666 | 3c8d1447 | Baptiste Coudurier | }; |
667 | |||
668 | 6b600285 | Baptiste Coudurier | static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track) |
669 | { |
||
670 | int tag = track->enc->codec_tag;
|
||
671 | 2ab57c04 | Baptiste Coudurier | int i;
|
672 | |||
673 | for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) { |
||
674 | if (track->enc->pix_fmt == mov_pix_fmt_tags[i].pix_fmt) {
|
||
675 | tag = mov_pix_fmt_tags[i].tag; |
||
676 | track->enc->bits_per_coded_sample = mov_pix_fmt_tags[i].bps; |
||
677 | break;
|
||
678 | } |
||
679 | } |
||
680 | 6b600285 | Baptiste Coudurier | |
681 | return tag;
|
||
682 | } |
||
683 | |||
684 | static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track) |
||
685 | { |
||
686 | int tag = track->enc->codec_tag;
|
||
687 | |||
688 | if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
|
||
689 | a2b7ed32 | Baptiste Coudurier | (track->enc->codec_id == CODEC_ID_DVVIDEO || |
690 | 6b600285 | Baptiste Coudurier | track->enc->codec_id == CODEC_ID_RAWVIDEO || |
691 | 10d8eac9 | Baptiste Coudurier | track->enc->codec_id == CODEC_ID_H263 || |
692 | 6b600285 | Baptiste Coudurier | av_get_bits_per_sample(track->enc->codec_id)))) { // pcm audio
|
693 | 0872acc4 | Baptiste Coudurier | if (track->enc->codec_id == CODEC_ID_DVVIDEO)
|
694 | 6b600285 | Baptiste Coudurier | tag = mov_get_dv_codec_tag(s, track); |
695 | 0872acc4 | Baptiste Coudurier | else if (track->enc->codec_id == CODEC_ID_RAWVIDEO) |
696 | 6b600285 | Baptiste Coudurier | tag = mov_get_rawvideo_codec_tag(s, track); |
697 | 72415b2a | Stefano Sabatini | else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) { |
698 | 1a40491e | Daniel Verkamp | tag = ff_codec_get_tag(codec_movvideo_tags, track->enc->codec_id); |
699 | 08680ab8 | Baptiste Coudurier | if (!tag) { // if no mac fcc found, try with Microsoft tags |
700 | 1a40491e | Daniel Verkamp | tag = ff_codec_get_tag(ff_codec_bmp_tags, track->enc->codec_id); |
701 | 08680ab8 | Baptiste Coudurier | if (tag)
|
702 | av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, "
|
||
703 | "the file may be unplayable!\n");
|
||
704 | } |
||
705 | 72415b2a | Stefano Sabatini | } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) { |
706 | 1a40491e | Daniel Verkamp | tag = ff_codec_get_tag(codec_movaudio_tags, track->enc->codec_id); |
707 | 08680ab8 | Baptiste Coudurier | if (!tag) { // if no mac fcc found, try with Microsoft tags |
708 | 1a40491e | Daniel Verkamp | int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->enc->codec_id);
|
709 | 08680ab8 | Baptiste Coudurier | if (ms_tag) {
|
710 | tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff)); |
||
711 | av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, "
|
||
712 | "the file may be unplayable!\n");
|
||
713 | d97f2144 | Baptiste Coudurier | } |
714 | 08680ab8 | Baptiste Coudurier | } |
715 | 72415b2a | Stefano Sabatini | } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) |
716 | 1a40491e | Daniel Verkamp | tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id); |
717 | a23c9c4a | Baptiste Coudurier | } |
718 | 2ab57c04 | Baptiste Coudurier | |
719 | 8e321619 | Baptiste Coudurier | return tag;
|
720 | } |
||
721 | |||
722 | 3c8d1447 | Baptiste Coudurier | static const AVCodecTag codec_3gp_tags[] = { |
723 | { CODEC_ID_H263, MKTAG('s','2','6','3') }, |
||
724 | { CODEC_ID_H264, MKTAG('a','v','c','1') }, |
||
725 | { CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, |
||
726 | { CODEC_ID_AAC, MKTAG('m','p','4','a') }, |
||
727 | { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') }, |
||
728 | { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') }, |
||
729 | { CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') }, |
||
730 | { CODEC_ID_NONE, 0 },
|
||
731 | }; |
||
732 | |||
733 | 6b600285 | Baptiste Coudurier | static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track) |
734 | { |
||
735 | int tag = track->enc->codec_tag;
|
||
736 | |||
737 | if (track->mode == MODE_MP4 || track->mode == MODE_PSP)
|
||
738 | tag = mp4_get_codec_tag(s, track); |
||
739 | else if (track->mode == MODE_IPOD) |
||
740 | tag = ipod_get_codec_tag(s, track); |
||
741 | else if (track->mode & MODE_3GP) |
||
742 | 1a40491e | Daniel Verkamp | tag = ff_codec_get_tag(codec_3gp_tags, track->enc->codec_id); |
743 | 6b600285 | Baptiste Coudurier | else
|
744 | tag = mov_get_codec_tag(s, track); |
||
745 | |||
746 | return tag;
|
||
747 | } |
||
748 | |||
749 | aa9f4208 | Baptiste Coudurier | /** Write uuid atom.
|
750 | * Needed to make file play in iPods running newest firmware
|
||
751 | * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
|
||
752 | */
|
||
753 | ae628ec1 | Anton Khirnov | static int mov_write_uuid_tag_ipod(AVIOContext *pb) |
754 | aa9f4208 | Baptiste Coudurier | { |
755 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 28);
|
756 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "uuid");
|
757 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x6b6840f2);
|
758 | avio_wb32(pb, 0x5f244fc5);
|
||
759 | avio_wb32(pb, 0xba39a51b);
|
||
760 | avio_wb32(pb, 0xcf0323f3);
|
||
761 | avio_wb32(pb, 0x0);
|
||
762 | aa9f4208 | Baptiste Coudurier | return 28; |
763 | } |
||
764 | |||
765 | ae628ec1 | Anton Khirnov | static int mov_write_subtitle_tag(AVIOContext *pb, MOVTrack *track) |
766 | f6204886 | David Conrad | { |
767 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
768 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
769 | avio_wl32(pb, track->tag); // store it byteswapped
|
||
770 | avio_wb32(pb, 0); /* Reserved */ |
||
771 | avio_wb16(pb, 0); /* Reserved */ |
||
772 | avio_wb16(pb, 1); /* Data-reference index */ |
||
773 | f6204886 | David Conrad | |
774 | if (track->enc->extradata_size)
|
||
775 | 77eb5504 | Anton Khirnov | avio_write(pb, track->enc->extradata, track->enc->extradata_size); |
776 | f6204886 | David Conrad | |
777 | return updateSize(pb, pos);
|
||
778 | } |
||
779 | |||
780 | ae628ec1 | Anton Khirnov | static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track) |
781 | b015be21 | Baptiste Coudurier | { |
782 | AVRational sar; |
||
783 | av_reduce(&sar.num, &sar.den, track->enc->sample_aspect_ratio.num, |
||
784 | track->enc->sample_aspect_ratio.den, INT_MAX); |
||
785 | |||
786 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 16);
|
787 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "pasp");
|
788 | 77eb5504 | Anton Khirnov | avio_wb32(pb, sar.num); |
789 | avio_wb32(pb, sar.den); |
||
790 | b015be21 | Baptiste Coudurier | return 16; |
791 | } |
||
792 | |||
793 | ae628ec1 | Anton Khirnov | static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) |
794 | 1cb5f7fd | Michael Niedermayer | { |
795 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
796 | 53ffdd14 | Roine Gustafsson | char compressor_name[32]; |
797 | 8cc7a34d | Alex Beregszaszi | |
798 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
799 | avio_wl32(pb, track->tag); // store it byteswapped
|
||
800 | avio_wb32(pb, 0); /* Reserved */ |
||
801 | avio_wb16(pb, 0); /* Reserved */ |
||
802 | avio_wb16(pb, 1); /* Data-reference index */ |
||
803 | f578f938 | Thomas Raivio | |
804 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 0); /* Codec stream version */ |
805 | avio_wb16(pb, 0); /* Codec stream revision (=0) */ |
||
806 | 5997ed78 | Baptiste Coudurier | if (track->mode == MODE_MOV) {
|
807 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "FFMP"); /* Vendor */ |
808 | 915282e5 | Baptiste Coudurier | if(track->enc->codec_id == CODEC_ID_RAWVIDEO) {
|
809 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* Temporal Quality */ |
810 | avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/ |
||
811 | 915282e5 | Baptiste Coudurier | } else {
|
812 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x200); /* Temporal Quality = normal */ |
813 | avio_wb32(pb, 0x200); /* Spatial Quality = normal */ |
||
814 | 915282e5 | Baptiste Coudurier | } |
815 | 5997ed78 | Baptiste Coudurier | } else {
|
816 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* Reserved */ |
817 | avio_wb32(pb, 0); /* Reserved */ |
||
818 | avio_wb32(pb, 0); /* Reserved */ |
||
819 | 5997ed78 | Baptiste Coudurier | } |
820 | 77eb5504 | Anton Khirnov | avio_wb16(pb, track->enc->width); /* Video width */
|
821 | avio_wb16(pb, track->height); /* Video height */
|
||
822 | avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */ |
||
823 | avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */ |
||
824 | avio_wb32(pb, 0); /* Data size (= 0) */ |
||
825 | avio_wb16(pb, 1); /* Frame count (= 1) */ |
||
826 | 115329f1 | Diego Biurrun | |
827 | 53ffdd14 | Roine Gustafsson | memset(compressor_name,0,32); |
828 | 5997ed78 | Baptiste Coudurier | /* FIXME not sure, ISO 14496-1 draft where it shall be set to 0 */
|
829 | if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name)
|
||
830 | 53ffdd14 | Roine Gustafsson | strncpy(compressor_name,track->enc->codec->name,31);
|
831 | 77eb5504 | Anton Khirnov | avio_w8(pb, strlen(compressor_name)); |
832 | avio_write(pb, compressor_name, 31);
|
||
833 | 115329f1 | Diego Biurrun | |
834 | dd1c8f3e | Luca Abeni | if (track->mode == MODE_MOV && track->enc->bits_per_coded_sample)
|
835 | 77eb5504 | Anton Khirnov | avio_wb16(pb, track->enc->bits_per_coded_sample); |
836 | ccac8438 | Baptiste Coudurier | else
|
837 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 0x18); /* Reserved */ |
838 | avio_wb16(pb, 0xffff); /* Reserved */ |
||
839 | d0c0a29b | Baptiste Coudurier | if(track->tag == MKTAG('m','p','4','v')) |
840 | f578f938 | Thomas Raivio | mov_write_esds_tag(pb, track); |
841 | else if(track->enc->codec_id == CODEC_ID_H263) |
||
842 | mov_write_d263_tag(pb); |
||
843 | else if(track->enc->codec_id == CODEC_ID_SVQ3) |
||
844 | 115329f1 | Diego Biurrun | mov_write_svq3_tag(pb); |
845 | 7b0f4c9a | Baptiste Coudurier | else if(track->enc->codec_id == CODEC_ID_DNXHD) |
846 | mov_write_avid_tag(pb, track); |
||
847 | aa9f4208 | Baptiste Coudurier | else if(track->enc->codec_id == CODEC_ID_H264) { |
848 | c1b8e6d8 | Baptiste Coudurier | mov_write_avcc_tag(pb, track); |
849 | aa9f4208 | Baptiste Coudurier | if(track->mode == MODE_IPOD)
|
850 | mov_write_uuid_tag_ipod(pb); |
||
851 | b64518e9 | Baptiste Coudurier | } else if(track->vosLen > 0) |
852 | 79e42311 | Baptiste Coudurier | mov_write_glbl_tag(pb, track); |
853 | f578f938 | Thomas Raivio | |
854 | d184c86c | Maksym Veremeyenko | if (track->enc->sample_aspect_ratio.den && track->enc->sample_aspect_ratio.num &&
|
855 | b015be21 | Baptiste Coudurier | track->enc->sample_aspect_ratio.den != track->enc->sample_aspect_ratio.num) { |
856 | mov_write_pasp_tag(pb, track); |
||
857 | } |
||
858 | |||
859 | f7635edb | Baptiste Coudurier | return updateSize(pb, pos);
|
860 | 1cb5f7fd | Michael Niedermayer | } |
861 | |||
862 | ae628ec1 | Anton Khirnov | static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track) |
863 | e977af6f | Martin Storsjö | { |
864 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
865 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
866 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "rtp ");
|
867 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* Reserved */ |
868 | avio_wb16(pb, 0); /* Reserved */ |
||
869 | avio_wb16(pb, 1); /* Data-reference index */ |
||
870 | e977af6f | Martin Storsjö | |
871 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 1); /* Hint track version */ |
872 | avio_wb16(pb, 1); /* Highest compatible version */ |
||
873 | avio_wb32(pb, track->max_packet_size); /* Max packet size */
|
||
874 | e977af6f | Martin Storsjö | |
875 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 12); /* size */ |
876 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "tims");
|
877 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->timescale); |
878 | e977af6f | Martin Storsjö | |
879 | return updateSize(pb, pos);
|
||
880 | } |
||
881 | |||
882 | ae628ec1 | Anton Khirnov | static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track) |
883 | 1cb5f7fd | Michael Niedermayer | { |
884 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
885 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
886 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "stsd");
|
887 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version & flags */ |
888 | avio_wb32(pb, 1); /* entry count */ |
||
889 | 72415b2a | Stefano Sabatini | if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO)
|
890 | f578f938 | Thomas Raivio | mov_write_video_tag(pb, track); |
891 | 72415b2a | Stefano Sabatini | else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) |
892 | f578f938 | Thomas Raivio | mov_write_audio_tag(pb, track); |
893 | 72415b2a | Stefano Sabatini | else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) |
894 | f6204886 | David Conrad | mov_write_subtitle_tag(pb, track); |
895 | e977af6f | Martin Storsjö | else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) |
896 | mov_write_rtp_tag(pb, track); |
||
897 | 6e6d6dc0 | Michael Niedermayer | return updateSize(pb, pos);
|
898 | 1cb5f7fd | Michael Niedermayer | } |
899 | |||
900 | ae628ec1 | Anton Khirnov | static int mov_write_ctts_tag(AVIOContext *pb, MOVTrack *track) |
901 | b4712e3c | Baptiste Coudurier | { |
902 | c3e92a6c | Baptiste Coudurier | MOVStts *ctts_entries; |
903 | b4712e3c | Baptiste Coudurier | uint32_t entries = 0;
|
904 | uint32_t atom_size; |
||
905 | int i;
|
||
906 | |||
907 | ctts_entries = av_malloc((track->entry + 1) * sizeof(*ctts_entries)); /* worst case */ |
||
908 | ctts_entries[0].count = 1; |
||
909 | 0aec3c5c | Baptiste Coudurier | ctts_entries[0].duration = track->cluster[0].cts; |
910 | b4712e3c | Baptiste Coudurier | for (i=1; i<track->entry; i++) { |
911 | 0aec3c5c | Baptiste Coudurier | if (track->cluster[i].cts == ctts_entries[entries].duration) {
|
912 | b4712e3c | Baptiste Coudurier | ctts_entries[entries].count++; /* compress */
|
913 | } else {
|
||
914 | entries++; |
||
915 | 0aec3c5c | Baptiste Coudurier | ctts_entries[entries].duration = track->cluster[i].cts; |
916 | b4712e3c | Baptiste Coudurier | ctts_entries[entries].count = 1;
|
917 | } |
||
918 | } |
||
919 | entries++; /* last one */
|
||
920 | atom_size = 16 + (entries * 8); |
||
921 | 77eb5504 | Anton Khirnov | avio_wb32(pb, atom_size); /* size */
|
922 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "ctts");
|
923 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version & flags */ |
924 | avio_wb32(pb, entries); /* entry count */
|
||
925 | b4712e3c | Baptiste Coudurier | for (i=0; i<entries; i++) { |
926 | 77eb5504 | Anton Khirnov | avio_wb32(pb, ctts_entries[i].count); |
927 | avio_wb32(pb, ctts_entries[i].duration); |
||
928 | b4712e3c | Baptiste Coudurier | } |
929 | av_free(ctts_entries); |
||
930 | return atom_size;
|
||
931 | } |
||
932 | |||
933 | e45ccf79 | Gildas Bazin | /* Time to sample atom */
|
934 | ae628ec1 | Anton Khirnov | static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track) |
935 | 1cb5f7fd | Michael Niedermayer | { |
936 | c3e92a6c | Baptiste Coudurier | MOVStts *stts_entries; |
937 | aa90239f | Baptiste Coudurier | uint32_t entries = -1;
|
938 | uint32_t atom_size; |
||
939 | int i;
|
||
940 | |||
941 | 72415b2a | Stefano Sabatini | if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
|
942 | aa90239f | Baptiste Coudurier | stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */ |
943 | stts_entries[0].count = track->sampleCount;
|
||
944 | stts_entries[0].duration = 1; |
||
945 | entries = 1;
|
||
946 | } else {
|
||
947 | stts_entries = av_malloc(track->entry * sizeof(*stts_entries)); /* worst case */ |
||
948 | for (i=0; i<track->entry; i++) { |
||
949 | int64_t duration = i + 1 == track->entry ?
|
||
950 | track->trackDuration - track->cluster[i].dts + track->cluster[0].dts : /* readjusting */ |
||
951 | track->cluster[i+1].dts - track->cluster[i].dts;
|
||
952 | if (i && duration == stts_entries[entries].duration) {
|
||
953 | stts_entries[entries].count++; /* compress */
|
||
954 | } else {
|
||
955 | entries++; |
||
956 | stts_entries[entries].duration = duration; |
||
957 | stts_entries[entries].count = 1;
|
||
958 | } |
||
959 | } |
||
960 | entries++; /* last one */
|
||
961 | } |
||
962 | atom_size = 16 + (entries * 8); |
||
963 | 77eb5504 | Anton Khirnov | avio_wb32(pb, atom_size); /* size */
|
964 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "stts");
|
965 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version & flags */ |
966 | avio_wb32(pb, entries); /* entry count */
|
||
967 | aa90239f | Baptiste Coudurier | for (i=0; i<entries; i++) { |
968 | 77eb5504 | Anton Khirnov | avio_wb32(pb, stts_entries[i].count); |
969 | avio_wb32(pb, stts_entries[i].duration); |
||
970 | aa90239f | Baptiste Coudurier | } |
971 | av_free(stts_entries); |
||
972 | return atom_size;
|
||
973 | 1cb5f7fd | Michael Niedermayer | } |
974 | |||
975 | ae628ec1 | Anton Khirnov | static int mov_write_dref_tag(AVIOContext *pb) |
976 | 1cb5f7fd | Michael Niedermayer | { |
977 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 28); /* size */ |
978 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "dref");
|
979 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version & flags */ |
980 | avio_wb32(pb, 1); /* entry count */ |
||
981 | 1cb5f7fd | Michael Niedermayer | |
982 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0xc); /* size */ |
983 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "url ");
|
984 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 1); /* version & flags */ |
985 | 1cb5f7fd | Michael Niedermayer | |
986 | return 28; |
||
987 | } |
||
988 | |||
989 | ae628ec1 | Anton Khirnov | static int mov_write_stbl_tag(AVIOContext *pb, MOVTrack *track) |
990 | 1cb5f7fd | Michael Niedermayer | { |
991 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
992 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
993 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "stbl");
|
994 | 6e6d6dc0 | Michael Niedermayer | mov_write_stsd_tag(pb, track); |
995 | mov_write_stts_tag(pb, track); |
||
996 | e977af6f | Martin Storsjö | if ((track->enc->codec_type == AVMEDIA_TYPE_VIDEO ||
|
997 | track->enc->codec_tag == MKTAG('r','t','p',' ')) && |
||
998 | b371539a | Baptiste Coudurier | track->hasKeyframes && track->hasKeyframes < track->entry) |
999 | e1316b19 | Baptiste Coudurier | mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE); |
1000 | if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
|
||
1001 | mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE); |
||
1002 | 72415b2a | Stefano Sabatini | if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO &&
|
1003 | e1316b19 | Baptiste Coudurier | track->flags & MOV_TRACK_CTTS) |
1004 | b4712e3c | Baptiste Coudurier | mov_write_ctts_tag(pb, track); |
1005 | 6e6d6dc0 | Michael Niedermayer | mov_write_stsc_tag(pb, track); |
1006 | mov_write_stsz_tag(pb, track); |
||
1007 | mov_write_stco_tag(pb, track); |
||
1008 | return updateSize(pb, pos);
|
||
1009 | 1cb5f7fd | Michael Niedermayer | } |
1010 | |||
1011 | ae628ec1 | Anton Khirnov | static int mov_write_dinf_tag(AVIOContext *pb) |
1012 | 1cb5f7fd | Michael Niedermayer | { |
1013 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1014 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
1015 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "dinf");
|
1016 | 6e6d6dc0 | Michael Niedermayer | mov_write_dref_tag(pb); |
1017 | return updateSize(pb, pos);
|
||
1018 | 1cb5f7fd | Michael Niedermayer | } |
1019 | |||
1020 | ae628ec1 | Anton Khirnov | static int mov_write_nmhd_tag(AVIOContext *pb) |
1021 | f6204886 | David Conrad | { |
1022 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 12);
|
1023 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "nmhd");
|
1024 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0);
|
1025 | f6204886 | David Conrad | return 12; |
1026 | } |
||
1027 | |||
1028 | ae628ec1 | Anton Khirnov | static int mov_write_gmhd_tag(AVIOContext *pb) |
1029 | f6204886 | David Conrad | { |
1030 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x20); /* size */ |
1031 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "gmhd");
|
1032 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x18); /* gmin size */ |
1033 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "gmin");/* generic media info */ |
1034 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version & flags */ |
1035 | avio_wb16(pb, 0x40); /* graphics mode = */ |
||
1036 | avio_wb16(pb, 0x8000); /* opColor (r?) */ |
||
1037 | avio_wb16(pb, 0x8000); /* opColor (g?) */ |
||
1038 | avio_wb16(pb, 0x8000); /* opColor (b?) */ |
||
1039 | avio_wb16(pb, 0); /* balance */ |
||
1040 | avio_wb16(pb, 0); /* reserved */ |
||
1041 | f6204886 | David Conrad | return 0x20; |
1042 | } |
||
1043 | |||
1044 | ae628ec1 | Anton Khirnov | static int mov_write_smhd_tag(AVIOContext *pb) |
1045 | 1cb5f7fd | Michael Niedermayer | { |
1046 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 16); /* size */ |
1047 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "smhd");
|
1048 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version & flags */ |
1049 | avio_wb16(pb, 0); /* reserved (balance, normally = 0) */ |
||
1050 | avio_wb16(pb, 0); /* reserved */ |
||
1051 | 1cb5f7fd | Michael Niedermayer | return 16; |
1052 | } |
||
1053 | |||
1054 | ae628ec1 | Anton Khirnov | static int mov_write_vmhd_tag(AVIOContext *pb) |
1055 | 1cb5f7fd | Michael Niedermayer | { |
1056 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x14); /* size (always 0x14) */ |
1057 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "vmhd");
|
1058 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x01); /* version & flags */ |
1059 | avio_wb64(pb, 0); /* reserved (graphics mode = copy) */ |
||
1060 | 1cb5f7fd | Michael Niedermayer | return 0x14; |
1061 | } |
||
1062 | |||
1063 | ae628ec1 | Anton Khirnov | static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track) |
1064 | 1cb5f7fd | Michael Niedermayer | { |
1065 | 985688b8 | Baptiste Coudurier | const char *hdlr, *descr = NULL, *hdlr_type = NULL; |
1066 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1067 | 115329f1 | Diego Biurrun | |
1068 | 9a4d9388 | Roman Shaposhnik | if (!track) { /* no media --> data handler */ |
1069 | bb270c08 | Diego Biurrun | hdlr = "dhlr";
|
1070 | hdlr_type = "url ";
|
||
1071 | descr = "DataHandler";
|
||
1072 | 9a4d9388 | Roman Shaposhnik | } else {
|
1073 | bb270c08 | Diego Biurrun | hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0"; |
1074 | 72415b2a | Stefano Sabatini | if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
|
1075 | bb270c08 | Diego Biurrun | hdlr_type = "vide";
|
1076 | descr = "VideoHandler";
|
||
1077 | 72415b2a | Stefano Sabatini | } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) { |
1078 | bb270c08 | Diego Biurrun | hdlr_type = "soun";
|
1079 | descr = "SoundHandler";
|
||
1080 | 72415b2a | Stefano Sabatini | } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) { |
1081 | 9f520554 | Baptiste Coudurier | if (track->tag == MKTAG('t','x','3','g')) hdlr_type = "sbtl"; |
1082 | 80357cfc | Baptiste Coudurier | else hdlr_type = "text"; |
1083 | f6204886 | David Conrad | descr = "SubtitleHandler";
|
1084 | e977af6f | Martin Storsjö | } else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) { |
1085 | hdlr_type = "hint";
|
||
1086 | descr = "HintHandler";
|
||
1087 | bb270c08 | Diego Biurrun | } |
1088 | 9a4d9388 | Roman Shaposhnik | } |
1089 | 115329f1 | Diego Biurrun | |
1090 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
1091 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "hdlr");
|
1092 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* Version & flags */ |
1093 | avio_write(pb, hdlr, 4); /* handler */ |
||
1094 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, hdlr_type); /* handler type */
|
1095 | 77eb5504 | Anton Khirnov | avio_wb32(pb ,0); /* reserved */ |
1096 | avio_wb32(pb ,0); /* reserved */ |
||
1097 | avio_wb32(pb ,0); /* reserved */ |
||
1098 | 606d48ce | Larbi Joubala | if (!track || track->mode == MODE_MOV)
|
1099 | 77eb5504 | Anton Khirnov | avio_w8(pb, strlen(descr)); /* pascal string */
|
1100 | avio_write(pb, descr, strlen(descr)); /* handler description */
|
||
1101 | 606d48ce | Larbi Joubala | if (track && track->mode != MODE_MOV)
|
1102 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0); /* c string */ |
1103 | 9a4d9388 | Roman Shaposhnik | return updateSize(pb, pos);
|
1104 | } |
||
1105 | |||
1106 | ae628ec1 | Anton Khirnov | static int mov_write_hmhd_tag(AVIOContext *pb) |
1107 | e977af6f | Martin Storsjö | { |
1108 | /* This atom must be present, but leaving the values at zero
|
||
1109 | * seems harmless. */
|
||
1110 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 28); /* size */ |
1111 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "hmhd");
|
1112 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version, flags */ |
1113 | avio_wb16(pb, 0); /* maxPDUsize */ |
||
1114 | avio_wb16(pb, 0); /* avgPDUsize */ |
||
1115 | avio_wb32(pb, 0); /* maxbitrate */ |
||
1116 | avio_wb32(pb, 0); /* avgbitrate */ |
||
1117 | avio_wb32(pb, 0); /* reserved */ |
||
1118 | e977af6f | Martin Storsjö | return 28; |
1119 | } |
||
1120 | |||
1121 | ae628ec1 | Anton Khirnov | static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track) |
1122 | 9a4d9388 | Roman Shaposhnik | { |
1123 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1124 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
1125 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "minf");
|
1126 | 72415b2a | Stefano Sabatini | if(track->enc->codec_type == AVMEDIA_TYPE_VIDEO)
|
1127 | 9a4d9388 | Roman Shaposhnik | mov_write_vmhd_tag(pb); |
1128 | 72415b2a | Stefano Sabatini | else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) |
1129 | 9a4d9388 | Roman Shaposhnik | mov_write_smhd_tag(pb); |
1130 | 72415b2a | Stefano Sabatini | else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) { |
1131 | 9f520554 | Baptiste Coudurier | if (track->tag == MKTAG('t','e','x','t')) mov_write_gmhd_tag(pb); |
1132 | 80357cfc | Baptiste Coudurier | else mov_write_nmhd_tag(pb);
|
1133 | e977af6f | Martin Storsjö | } else if (track->tag == MKTAG('r','t','p',' ')) { |
1134 | mov_write_hmhd_tag(pb); |
||
1135 | f6204886 | David Conrad | } |
1136 | 9a4d9388 | Roman Shaposhnik | if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */ |
1137 | mov_write_hdlr_tag(pb, NULL);
|
||
1138 | mov_write_dinf_tag(pb); |
||
1139 | mov_write_stbl_tag(pb, track); |
||
1140 | f578f938 | Thomas Raivio | return updateSize(pb, pos);
|
1141 | 1cb5f7fd | Michael Niedermayer | } |
1142 | |||
1143 | ae628ec1 | Anton Khirnov | static int mov_write_mdhd_tag(AVIOContext *pb, MOVTrack *track) |
1144 | 1cb5f7fd | Michael Niedermayer | { |
1145 | a3a80ddc | Baptiste Coudurier | int version = track->trackDuration < INT32_MAX ? 0 : 1; |
1146 | |||
1147 | 77eb5504 | Anton Khirnov | (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */ |
1148 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "mdhd");
|
1149 | 77eb5504 | Anton Khirnov | avio_w8(pb, version); |
1150 | avio_wb24(pb, 0); /* flags */ |
||
1151 | a3a80ddc | Baptiste Coudurier | if (version == 1) { |
1152 | 77eb5504 | Anton Khirnov | avio_wb64(pb, track->time); |
1153 | avio_wb64(pb, track->time); |
||
1154 | a3a80ddc | Baptiste Coudurier | } else {
|
1155 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->time); /* creation time */
|
1156 | avio_wb32(pb, track->time); /* modification time */
|
||
1157 | a3a80ddc | Baptiste Coudurier | } |
1158 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
|
1159 | (version == 1) ? avio_wb64(pb, track->trackDuration) : avio_wb32(pb, track->trackDuration); /* duration */ |
||
1160 | avio_wb16(pb, track->language); /* language */
|
||
1161 | avio_wb16(pb, 0); /* reserved (quality) */ |
||
1162 | db8f4a92 | Michael Niedermayer | |
1163 | if(version!=0 && track->mode == MODE_MOV){ |
||
1164 | av_log(NULL, AV_LOG_ERROR,
|
||
1165 | "FATAL error, file duration too long for timebase, this file will not be\n"
|
||
1166 | b1b64c23 | Aurelien Jacobs | "playable with quicktime. Choose a different timebase or a different\n"
|
1167 | db8f4a92 | Michael Niedermayer | "container format\n");
|
1168 | } |
||
1169 | |||
1170 | 1cb5f7fd | Michael Niedermayer | return 32; |
1171 | } |
||
1172 | |||
1173 | ae628ec1 | Anton Khirnov | static int mov_write_mdia_tag(AVIOContext *pb, MOVTrack *track) |
1174 | 1cb5f7fd | Michael Niedermayer | { |
1175 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1176 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
1177 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "mdia");
|
1178 | 6e6d6dc0 | Michael Niedermayer | mov_write_mdhd_tag(pb, track); |
1179 | mov_write_hdlr_tag(pb, track); |
||
1180 | mov_write_minf_tag(pb, track); |
||
1181 | return updateSize(pb, pos);
|
||
1182 | 1cb5f7fd | Michael Niedermayer | } |
1183 | |||
1184 | ae628ec1 | Anton Khirnov | static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) |
1185 | 1cb5f7fd | Michael Niedermayer | { |
1186 | 729ef3ba | Baptiste Coudurier | int64_t duration = av_rescale_rnd(track->trackDuration, MOV_TIMESCALE, |
1187 | track->timescale, AV_ROUND_UP); |
||
1188 | a3a80ddc | Baptiste Coudurier | int version = duration < INT32_MAX ? 0 : 1; |
1189 | |||
1190 | 77eb5504 | Anton Khirnov | (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */ |
1191 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "tkhd");
|
1192 | 77eb5504 | Anton Khirnov | avio_w8(pb, version); |
1193 | avio_wb24(pb, 0xf); /* flags (track enabled) */ |
||
1194 | a3a80ddc | Baptiste Coudurier | if (version == 1) { |
1195 | 77eb5504 | Anton Khirnov | avio_wb64(pb, track->time); |
1196 | avio_wb64(pb, track->time); |
||
1197 | a3a80ddc | Baptiste Coudurier | } else {
|
1198 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->time); /* creation time */
|
1199 | avio_wb32(pb, track->time); /* modification time */
|
||
1200 | a3a80ddc | Baptiste Coudurier | } |
1201 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->trackID); /* track-id */
|
1202 | avio_wb32(pb, 0); /* reserved */ |
||
1203 | (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
|
||
1204 | 1cb5f7fd | Michael Niedermayer | |
1205 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* reserved */ |
1206 | avio_wb32(pb, 0); /* reserved */ |
||
1207 | avio_wb32(pb, 0x0); /* reserved (Layer & Alternate group) */ |
||
1208 | 1cb5f7fd | Michael Niedermayer | /* Volume, only for audio */
|
1209 | 72415b2a | Stefano Sabatini | if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
|
1210 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 0x0100);
|
1211 | 1cb5f7fd | Michael Niedermayer | else
|
1212 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 0);
|
1213 | avio_wb16(pb, 0); /* reserved */ |
||
1214 | 1cb5f7fd | Michael Niedermayer | |
1215 | /* Matrix structure */
|
||
1216 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x00010000); /* reserved */ |
1217 | avio_wb32(pb, 0x0); /* reserved */ |
||
1218 | avio_wb32(pb, 0x0); /* reserved */ |
||
1219 | avio_wb32(pb, 0x0); /* reserved */ |
||
1220 | avio_wb32(pb, 0x00010000); /* reserved */ |
||
1221 | avio_wb32(pb, 0x0); /* reserved */ |
||
1222 | avio_wb32(pb, 0x0); /* reserved */ |
||
1223 | avio_wb32(pb, 0x0); /* reserved */ |
||
1224 | avio_wb32(pb, 0x40000000); /* reserved */ |
||
1225 | 1cb5f7fd | Michael Niedermayer | |
1226 | /* Track width and height, for visual only */
|
||
1227 | ddb63017 | David Conrad | if(st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO ||
|
1228 | track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) { |
||
1229 | ea1afa12 | Maksym Veremeyenko | if(track->mode == MODE_MOV) {
|
1230 | avio_wb32(pb, track->enc->width << 16);
|
||
1231 | fffdee89 | Baptiste Coudurier | avio_wb32(pb, track->height << 16);
|
1232 | ea1afa12 | Maksym Veremeyenko | } else {
|
1233 | 77d207cb | Maksym Veremeyenko | double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
|
1234 | if(!sample_aspect_ratio || track->height != track->enc->height)
|
||
1235 | sample_aspect_ratio = 1;
|
||
1236 | avio_wb32(pb, sample_aspect_ratio * track->enc->width*0x10000);
|
||
1237 | avio_wb32(pb, track->height*0x10000);
|
||
1238 | ea1afa12 | Maksym Veremeyenko | } |
1239 | 1cb5f7fd | Michael Niedermayer | } |
1240 | else {
|
||
1241 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0);
|
1242 | avio_wb32(pb, 0);
|
||
1243 | 1cb5f7fd | Michael Niedermayer | } |
1244 | return 0x5c; |
||
1245 | } |
||
1246 | |||
1247 | 13ff92d1 | Ronald S. Bultje | static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track) |
1248 | ea1afa12 | Maksym Veremeyenko | { |
1249 | int32_t width = av_rescale(track->enc->sample_aspect_ratio.num, track->enc->width, |
||
1250 | track->enc->sample_aspect_ratio.den); |
||
1251 | |||
1252 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1253 | ea1afa12 | Maksym Veremeyenko | |
1254 | avio_wb32(pb, 0); /* size */ |
||
1255 | 13ff92d1 | Ronald S. Bultje | ffio_wfourcc(pb, "tapt");
|
1256 | ea1afa12 | Maksym Veremeyenko | |
1257 | avio_wb32(pb, 20);
|
||
1258 | 13ff92d1 | Ronald S. Bultje | ffio_wfourcc(pb, "clef");
|
1259 | ea1afa12 | Maksym Veremeyenko | avio_wb32(pb, 0);
|
1260 | avio_wb32(pb, width << 16);
|
||
1261 | avio_wb32(pb, track->enc->height << 16);
|
||
1262 | |||
1263 | avio_wb32(pb, 20);
|
||
1264 | 13ff92d1 | Ronald S. Bultje | ffio_wfourcc(pb, "enof");
|
1265 | ea1afa12 | Maksym Veremeyenko | avio_wb32(pb, 0);
|
1266 | avio_wb32(pb, track->enc->width << 16);
|
||
1267 | avio_wb32(pb, track->enc->height << 16);
|
||
1268 | |||
1269 | return updateSize(pb, pos);
|
||
1270 | }; |
||
1271 | |||
1272 | 8af18154 | tjcannell@blueyonder.co.uk | // This box seems important for the psp playback ... without it the movie seems to hang
|
1273 | ae628ec1 | Anton Khirnov | static int mov_write_edts_tag(AVIOContext *pb, MOVTrack *track) |
1274 | 8af18154 | tjcannell@blueyonder.co.uk | { |
1275 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x24); /* size */ |
1276 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "edts");
|
1277 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x1c); /* size */ |
1278 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "elst");
|
1279 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x0);
|
1280 | avio_wb32(pb, 0x1);
|
||
1281 | 8af18154 | tjcannell@blueyonder.co.uk | |
1282 | 729ef3ba | Baptiste Coudurier | /* duration ... doesn't seem to effect psp */
|
1283 | 77eb5504 | Anton Khirnov | avio_wb32(pb, av_rescale_rnd(track->trackDuration, MOV_TIMESCALE, |
1284 | 729ef3ba | Baptiste Coudurier | track->timescale, AV_ROUND_UP)); |
1285 | 8af18154 | tjcannell@blueyonder.co.uk | |
1286 | 77eb5504 | Anton Khirnov | avio_wb32(pb, track->cluster[0].cts); /* first pts is cts since dts is 0 */ |
1287 | avio_wb32(pb, 0x00010000);
|
||
1288 | 8af18154 | tjcannell@blueyonder.co.uk | return 0x24; |
1289 | } |
||
1290 | |||
1291 | ae628ec1 | Anton Khirnov | static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track) |
1292 | ddb63017 | David Conrad | { |
1293 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 20); // size |
1294 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "tref");
|
1295 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 12); // size (subatom) |
1296 | avio_wl32(pb, track->tref_tag); |
||
1297 | avio_wb32(pb, track->tref_id); |
||
1298 | ddb63017 | David Conrad | return 20; |
1299 | } |
||
1300 | |||
1301 | 8af18154 | tjcannell@blueyonder.co.uk | // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
|
1302 | ae628ec1 | Anton Khirnov | static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov) |
1303 | 8af18154 | tjcannell@blueyonder.co.uk | { |
1304 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */ |
1305 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "uuid");
|
1306 | ffio_wfourcc(pb, "USMT");
|
||
1307 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x21d24fce);
|
1308 | avio_wb32(pb, 0xbb88695c);
|
||
1309 | avio_wb32(pb, 0xfac9c740);
|
||
1310 | avio_wb32(pb, 0x1c); // another size here! |
||
1311 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "MTDT");
|
1312 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x00010012);
|
1313 | avio_wb32(pb, 0x0a);
|
||
1314 | avio_wb32(pb, 0x55c40000);
|
||
1315 | avio_wb32(pb, 0x1);
|
||
1316 | avio_wb32(pb, 0x0);
|
||
1317 | 8af18154 | tjcannell@blueyonder.co.uk | return 0x34; |
1318 | } |
||
1319 | |||
1320 | ae628ec1 | Anton Khirnov | static int mov_write_udta_sdp(AVIOContext *pb, AVCodecContext *ctx, int index) |
1321 | e977af6f | Martin Storsjö | { |
1322 | char buf[1000] = ""; |
||
1323 | int len;
|
||
1324 | |||
1325 | 7ad1dc54 | Martin Storsjö | ff_sdp_write_media(buf, sizeof(buf), ctx, NULL, NULL, 0, 0); |
1326 | e977af6f | Martin Storsjö | av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", index); |
1327 | len = strlen(buf); |
||
1328 | |||
1329 | 77eb5504 | Anton Khirnov | avio_wb32(pb, len + 24);
|
1330 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "udta");
|
1331 | 77eb5504 | Anton Khirnov | avio_wb32(pb, len + 16);
|
1332 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "hnti");
|
1333 | 77eb5504 | Anton Khirnov | avio_wb32(pb, len + 8);
|
1334 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "sdp ");
|
1335 | 77eb5504 | Anton Khirnov | avio_write(pb, buf, len); |
1336 | e977af6f | Martin Storsjö | return len + 24; |
1337 | } |
||
1338 | |||
1339 | ae628ec1 | Anton Khirnov | static int mov_write_trak_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) |
1340 | 1cb5f7fd | Michael Niedermayer | { |
1341 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1342 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
1343 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "trak");
|
1344 | 59729451 | Aurelien Jacobs | mov_write_tkhd_tag(pb, track, st); |
1345 | e1316b19 | Baptiste Coudurier | if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS)
|
1346 | 8af18154 | tjcannell@blueyonder.co.uk | mov_write_edts_tag(pb, track); // PSP Movies require edts box
|
1347 | ddb63017 | David Conrad | if (track->tref_tag)
|
1348 | mov_write_tref_tag(pb, track); |
||
1349 | 6e6d6dc0 | Michael Niedermayer | mov_write_mdia_tag(pb, track); |
1350 | 115329f1 | Diego Biurrun | if (track->mode == MODE_PSP)
|
1351 | 8af18154 | tjcannell@blueyonder.co.uk | mov_write_uuid_tag_psp(pb,track); // PSP Movies require this uuid box
|
1352 | e977af6f | Martin Storsjö | if (track->tag == MKTAG('r','t','p',' ')) |
1353 | mov_write_udta_sdp(pb, track->rtp_ctx->streams[0]->codec, track->trackID);
|
||
1354 | ea1afa12 | Maksym Veremeyenko | if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO && track->mode == MODE_MOV) {
|
1355 | double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
|
||
1356 | if (0.0 != sample_aspect_ratio && 1.0 != sample_aspect_ratio) |
||
1357 | mov_write_tapt_tag(pb, track); |
||
1358 | }; |
||
1359 | 6e6d6dc0 | Michael Niedermayer | return updateSize(pb, pos);
|
1360 | 1cb5f7fd | Michael Niedermayer | } |
1361 | |||
1362 | 88730be6 | Måns Rullgård | #if 0
|
1363 | 1cb5f7fd | Michael Niedermayer | /* TODO: Not sorted out, but not necessary either */
|
1364 | ae628ec1 | Anton Khirnov | static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
|
1365 | 1cb5f7fd | Michael Niedermayer | {
|
1366 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x15); /* size */
|
1367 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "iods");
|
1368 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version & flags */
|
1369 | avio_wb16(pb, 0x1007);
|
||
1370 | avio_w8(pb, 0);
|
||
1371 | avio_wb16(pb, 0x4fff);
|
||
1372 | avio_wb16(pb, 0xfffe);
|
||
1373 | avio_wb16(pb, 0x01ff);
|
||
1374 | 1cb5f7fd | Michael Niedermayer | return 0x15;
|
1375 | }
|
||
1376 | 88730be6 | Måns Rullgård | #endif
|
1377 | 1cb5f7fd | Michael Niedermayer | |
1378 | ae628ec1 | Anton Khirnov | static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov) |
1379 | 1cb5f7fd | Michael Niedermayer | { |
1380 | b29af723 | Michael Niedermayer | int maxTrackID = 1, i; |
1381 | int64_t maxTrackLenTemp, maxTrackLen = 0;
|
||
1382 | a3a80ddc | Baptiste Coudurier | int version;
|
1383 | 1cb5f7fd | Michael Niedermayer | |
1384 | 42fb4148 | Baptiste Coudurier | for (i=0; i<mov->nb_streams; i++) { |
1385 | 1cb5f7fd | Michael Niedermayer | if(mov->tracks[i].entry > 0) { |
1386 | 729ef3ba | Baptiste Coudurier | maxTrackLenTemp = av_rescale_rnd(mov->tracks[i].trackDuration, |
1387 | MOV_TIMESCALE, |
||
1388 | mov->tracks[i].timescale, |
||
1389 | AV_ROUND_UP); |
||
1390 | f578f938 | Thomas Raivio | if(maxTrackLen < maxTrackLenTemp)
|
1391 | maxTrackLen = maxTrackLenTemp; |
||
1392 | 1cb5f7fd | Michael Niedermayer | if(maxTrackID < mov->tracks[i].trackID)
|
1393 | maxTrackID = mov->tracks[i].trackID; |
||
1394 | } |
||
1395 | } |
||
1396 | a3a80ddc | Baptiste Coudurier | |
1397 | version = maxTrackLen < UINT32_MAX ? 0 : 1; |
||
1398 | 77eb5504 | Anton Khirnov | (version == 1) ? avio_wb32(pb, 120) : avio_wb32(pb, 108); /* size */ |
1399 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "mvhd");
|
1400 | 77eb5504 | Anton Khirnov | avio_w8(pb, version); |
1401 | avio_wb24(pb, 0); /* flags */ |
||
1402 | a3a80ddc | Baptiste Coudurier | if (version == 1) { |
1403 | 77eb5504 | Anton Khirnov | avio_wb64(pb, mov->time); |
1404 | avio_wb64(pb, mov->time); |
||
1405 | a3a80ddc | Baptiste Coudurier | } else {
|
1406 | 77eb5504 | Anton Khirnov | avio_wb32(pb, mov->time); /* creation time */
|
1407 | avio_wb32(pb, mov->time); /* modification time */
|
||
1408 | a3a80ddc | Baptiste Coudurier | } |
1409 | 77eb5504 | Anton Khirnov | avio_wb32(pb, MOV_TIMESCALE); |
1410 | (version == 1) ? avio_wb64(pb, maxTrackLen) : avio_wb32(pb, maxTrackLen); /* duration of longest track */ |
||
1411 | 1cb5f7fd | Michael Niedermayer | |
1412 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */ |
1413 | avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */ |
||
1414 | avio_wb16(pb, 0); /* reserved */ |
||
1415 | avio_wb32(pb, 0); /* reserved */ |
||
1416 | avio_wb32(pb, 0); /* reserved */ |
||
1417 | 1cb5f7fd | Michael Niedermayer | |
1418 | /* Matrix structure */
|
||
1419 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x00010000); /* reserved */ |
1420 | avio_wb32(pb, 0x0); /* reserved */ |
||
1421 | avio_wb32(pb, 0x0); /* reserved */ |
||
1422 | avio_wb32(pb, 0x0); /* reserved */ |
||
1423 | avio_wb32(pb, 0x00010000); /* reserved */ |
||
1424 | avio_wb32(pb, 0x0); /* reserved */ |
||
1425 | avio_wb32(pb, 0x0); /* reserved */ |
||
1426 | avio_wb32(pb, 0x0); /* reserved */ |
||
1427 | avio_wb32(pb, 0x40000000); /* reserved */ |
||
1428 | |||
1429 | avio_wb32(pb, 0); /* reserved (preview time) */ |
||
1430 | avio_wb32(pb, 0); /* reserved (preview duration) */ |
||
1431 | avio_wb32(pb, 0); /* reserved (poster time) */ |
||
1432 | avio_wb32(pb, 0); /* reserved (selection time) */ |
||
1433 | avio_wb32(pb, 0); /* reserved (selection duration) */ |
||
1434 | avio_wb32(pb, 0); /* reserved (current time) */ |
||
1435 | avio_wb32(pb, maxTrackID+1); /* Next track id */ |
||
1436 | 1cb5f7fd | Michael Niedermayer | return 0x6c; |
1437 | } |
||
1438 | |||
1439 | ae628ec1 | Anton Khirnov | static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov, |
1440 | b6c50eb1 | Patrice Bensoussan | AVFormatContext *s) |
1441 | { |
||
1442 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 33); /* size */ |
1443 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "hdlr");
|
1444 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0);
|
1445 | avio_wb32(pb, 0);
|
||
1446 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "mdir");
|
1447 | ffio_wfourcc(pb, "appl");
|
||
1448 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0);
|
1449 | avio_wb32(pb, 0);
|
||
1450 | avio_w8(pb, 0);
|
||
1451 | 6b174197 | Tomas Härdin | return 33; |
1452 | b6c50eb1 | Patrice Bensoussan | } |
1453 | |||
1454 | /* helper function to write a data tag with the specified string as data */
|
||
1455 | ae628ec1 | Anton Khirnov | static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style) |
1456 | b6c50eb1 | Patrice Bensoussan | { |
1457 | efda3395 | Michael Niedermayer | if(long_style){
|
1458 | 6b174197 | Tomas Härdin | int size = 16 + strlen(data); |
1459 | 77eb5504 | Anton Khirnov | avio_wb32(pb, size); /* size */
|
1460 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "data");
|
1461 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 1);
|
1462 | avio_wb32(pb, 0);
|
||
1463 | avio_write(pb, data, strlen(data)); |
||
1464 | 6b174197 | Tomas Härdin | return size;
|
1465 | efda3395 | Michael Niedermayer | }else{
|
1466 | fe3ab8ad | Baptiste Coudurier | if (!lang)
|
1467 | lang = ff_mov_iso639_to_lang("und", 1); |
||
1468 | 77eb5504 | Anton Khirnov | avio_wb16(pb, strlen(data)); /* string length */
|
1469 | avio_wb16(pb, lang); |
||
1470 | avio_write(pb, data, strlen(data)); |
||
1471 | efda3395 | Michael Niedermayer | return strlen(data) + 4; |
1472 | b6c50eb1 | Patrice Bensoussan | } |
1473 | } |
||
1474 | |||
1475 | ae628ec1 | Anton Khirnov | static int mov_write_string_tag(AVIOContext *pb, const char *name, const char *value, int lang, int long_style){ |
1476 | b6c50eb1 | Patrice Bensoussan | int size = 0; |
1477 | 91208916 | Baptiste Coudurier | if (value && value[0]) { |
1478 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1479 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
1480 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, name); |
1481 | d9fc9ff3 | Aurelien Jacobs | mov_write_string_data_tag(pb, value, lang, long_style); |
1482 | efda3395 | Michael Niedermayer | size= updateSize(pb, pos); |
1483 | b6c50eb1 | Patrice Bensoussan | } |
1484 | return size;
|
||
1485 | } |
||
1486 | |||
1487 | ae628ec1 | Anton Khirnov | static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb, |
1488 | 1ee2d448 | Aurelien Jacobs | const char *name, const char *tag, |
1489 | int long_style)
|
||
1490 | b6c50eb1 | Patrice Bensoussan | { |
1491 | d9fc9ff3 | Aurelien Jacobs | int l, lang = 0, len, len2; |
1492 | AVMetadataTag *t, *t2 = NULL;
|
||
1493 | char tag2[16]; |
||
1494 | 1ee2d448 | Aurelien Jacobs | |
1495 | if (!(t = av_metadata_get(s->metadata, tag, NULL, 0))) |
||
1496 | efda3395 | Michael Niedermayer | return 0; |
1497 | 1ee2d448 | Aurelien Jacobs | |
1498 | d9fc9ff3 | Aurelien Jacobs | len = strlen(t->key); |
1499 | snprintf(tag2, sizeof(tag2), "%s-", tag); |
||
1500 | while ((t2 = av_metadata_get(s->metadata, tag2, t2, AV_METADATA_IGNORE_SUFFIX))) {
|
||
1501 | len2 = strlen(t2->key); |
||
1502 | if (len2 == len+4 && !strcmp(t->value, t2->value) |
||
1503 | cc255afe | Baptiste Coudurier | && (l=ff_mov_iso639_to_lang(&t2->key[len2-3], 1)) >= 0) { |
1504 | d9fc9ff3 | Aurelien Jacobs | lang = l; |
1505 | break;
|
||
1506 | } |
||
1507 | } |
||
1508 | return mov_write_string_tag(pb, name, t->value, lang, long_style);
|
||
1509 | b6c50eb1 | Patrice Bensoussan | } |
1510 | |||
1511 | /* iTunes track number */
|
||
1512 | ae628ec1 | Anton Khirnov | static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov, |
1513 | b6c50eb1 | Patrice Bensoussan | AVFormatContext *s) |
1514 | { |
||
1515 | 1ee2d448 | Aurelien Jacobs | AVMetadataTag *t = av_metadata_get(s->metadata, "track", NULL, 0); |
1516 | int size = 0, track = t ? atoi(t->value) : 0; |
||
1517 | if (track) {
|
||
1518 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 32); /* size */ |
1519 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "trkn");
|
1520 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 24); /* size */ |
1521 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "data");
|
1522 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); // 8 bytes empty |
1523 | avio_wb32(pb, 0);
|
||
1524 | avio_wb16(pb, 0); // empty |
||
1525 | avio_wb16(pb, track); // track number
|
||
1526 | avio_wb16(pb, 0); // total track number |
||
1527 | avio_wb16(pb, 0); // empty |
||
1528 | 6b174197 | Tomas Härdin | size = 32;
|
1529 | b6c50eb1 | Patrice Bensoussan | } |
1530 | return size;
|
||
1531 | } |
||
1532 | |||
1533 | /* iTunes meta data list */
|
||
1534 | ae628ec1 | Anton Khirnov | static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, |
1535 | b6c50eb1 | Patrice Bensoussan | AVFormatContext *s) |
1536 | { |
||
1537 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1538 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
1539 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "ilst");
|
1540 | 1ee2d448 | Aurelien Jacobs | mov_write_string_metadata(s, pb, "\251nam", "title" , 1); |
1541 | ea4c4d7f | Baptiste Coudurier | mov_write_string_metadata(s, pb, "\251ART", "artist" , 1); |
1542 | 2cf9c7ef | Mike Melanson | mov_write_string_metadata(s, pb, "aART", "album_artist", 1); |
1543 | 620af1a1 | David Conrad | mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1); |
1544 | 1ee2d448 | Aurelien Jacobs | mov_write_string_metadata(s, pb, "\251alb", "album" , 1); |
1545 | ca76a119 | Anton Khirnov | mov_write_string_metadata(s, pb, "\251day", "date" , 1); |
1546 | d9fc9ff3 | Aurelien Jacobs | mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1); |
1547 | 1ee2d448 | Aurelien Jacobs | mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1); |
1548 | mov_write_string_metadata(s, pb, "\251gen", "genre" , 1); |
||
1549 | mov_write_string_metadata(s, pb, "\251cpy", "copyright", 1); |
||
1550 | 2cf9c7ef | Mike Melanson | mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1); |
1551 | mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1); |
||
1552 | 7382902b | David Conrad | mov_write_string_metadata(s, pb, "desc", "description",1); |
1553 | mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1); |
||
1554 | mov_write_string_metadata(s, pb, "tvsh", "show" , 1); |
||
1555 | mov_write_string_metadata(s, pb, "tven", "episode_id",1); |
||
1556 | mov_write_string_metadata(s, pb, "tvnn", "network" , 1); |
||
1557 | b6c50eb1 | Patrice Bensoussan | mov_write_trkn_tag(pb, mov, s); |
1558 | return updateSize(pb, pos);
|
||
1559 | } |
||
1560 | |||
1561 | /* iTunes meta data tag */
|
||
1562 | ae628ec1 | Anton Khirnov | static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov, |
1563 | b6c50eb1 | Patrice Bensoussan | AVFormatContext *s) |
1564 | { |
||
1565 | int size = 0; |
||
1566 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1567 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
1568 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "meta");
|
1569 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0);
|
1570 | b97fb809 | Aurelien Jacobs | mov_write_itunes_hdlr_tag(pb, mov, s); |
1571 | mov_write_ilst_tag(pb, mov, s); |
||
1572 | size = updateSize(pb, pos); |
||
1573 | b6c50eb1 | Patrice Bensoussan | return size;
|
1574 | } |
||
1575 | 115329f1 | Diego Biurrun | |
1576 | 07b7b06d | Baptiste Coudurier | static int utf8len(const uint8_t *b) |
1577 | { |
||
1578 | int len=0; |
||
1579 | int val;
|
||
1580 | while(*b){
|
||
1581 | GET_UTF8(val, *b++, return -1;) |
||
1582 | len++; |
||
1583 | } |
||
1584 | return len;
|
||
1585 | } |
||
1586 | |||
1587 | ae628ec1 | Anton Khirnov | static int ascii_to_wc(AVIOContext *pb, const uint8_t *b) |
1588 | 07b7b06d | Baptiste Coudurier | { |
1589 | int val;
|
||
1590 | while(*b){
|
||
1591 | GET_UTF8(val, *b++, return -1;) |
||
1592 | 77eb5504 | Anton Khirnov | avio_wb16(pb, val); |
1593 | 07b7b06d | Baptiste Coudurier | } |
1594 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 0x00);
|
1595 | 07b7b06d | Baptiste Coudurier | return 0; |
1596 | } |
||
1597 | |||
1598 | static uint16_t language_code(const char *str) |
||
1599 | { |
||
1600 | return (((str[0]-0x60) & 0x1F) << 10) + (((str[1]-0x60) & 0x1F) << 5) + ((str[2]-0x60) & 0x1F); |
||
1601 | } |
||
1602 | |||
1603 | ae628ec1 | Anton Khirnov | static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s, |
1604 | c6e2c6c9 | Baptiste Coudurier | const char *tag, const char *str) |
1605 | { |
||
1606 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1607 | 1ee2d448 | Aurelien Jacobs | AVMetadataTag *t = av_metadata_get(s->metadata, str, NULL, 0); |
1608 | if (!t || !utf8len(t->value))
|
||
1609 | c6e2c6c9 | Baptiste Coudurier | return 0; |
1610 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
1611 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, tag); /* type */
|
1612 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* version + flags */ |
1613 | c6e2c6c9 | Baptiste Coudurier | if (!strcmp(tag, "yrrc")) |
1614 | 77eb5504 | Anton Khirnov | avio_wb16(pb, atoi(t->value)); |
1615 | c6e2c6c9 | Baptiste Coudurier | else {
|
1616 | 77eb5504 | Anton Khirnov | avio_wb16(pb, language_code("eng")); /* language */ |
1617 | avio_write(pb, t->value, strlen(t->value)+1); /* UTF8 string value */ |
||
1618 | 1ee2d448 | Aurelien Jacobs | if (!strcmp(tag, "albm") && |
1619 | 221ed486 | Baptiste Coudurier | (t = av_metadata_get(s->metadata, "track", NULL, 0))) |
1620 | 77eb5504 | Anton Khirnov | avio_w8(pb, atoi(t->value)); |
1621 | c6e2c6c9 | Baptiste Coudurier | } |
1622 | return updateSize(pb, pos);
|
||
1623 | } |
||
1624 | |||
1625 | ae628ec1 | Anton Khirnov | static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s) |
1626 | dc75e4e3 | David Conrad | { |
1627 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1628 | dc75e4e3 | David Conrad | int i, nb_chapters = FFMIN(s->nb_chapters, 255); |
1629 | |||
1630 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); // size |
1631 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "chpl");
|
1632 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x01000000); // version + flags |
1633 | avio_wb32(pb, 0); // unknown |
||
1634 | avio_w8(pb, nb_chapters); |
||
1635 | dc75e4e3 | David Conrad | |
1636 | for (i = 0; i < nb_chapters; i++) { |
||
1637 | AVChapter *c = s->chapters[i]; |
||
1638 | AVMetadataTag *t; |
||
1639 | 77eb5504 | Anton Khirnov | avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000})); |
1640 | dc75e4e3 | David Conrad | |
1641 | if ((t = av_metadata_get(c->metadata, "title", NULL, 0))) { |
||
1642 | int len = FFMIN(strlen(t->value), 255); |
||
1643 | 77eb5504 | Anton Khirnov | avio_w8(pb, len); |
1644 | avio_write(pb, t->value, len); |
||
1645 | dc75e4e3 | David Conrad | } else
|
1646 | 77eb5504 | Anton Khirnov | avio_w8(pb, 0);
|
1647 | dc75e4e3 | David Conrad | } |
1648 | return updateSize(pb, pos);
|
||
1649 | } |
||
1650 | |||
1651 | ae628ec1 | Anton Khirnov | static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, |
1652 | 69dde1ad | Gildas Bazin | AVFormatContext *s) |
1653 | { |
||
1654 | ae628ec1 | Anton Khirnov | AVIOContext *pb_buf; |
1655 | 1ee2d448 | Aurelien Jacobs | int i, ret, size;
|
1656 | uint8_t *buf; |
||
1657 | 89a0d790 | Benoit Fouet | |
1658 | d1d87dfb | Baptiste Coudurier | for (i = 0; i < s->nb_streams; i++) |
1659 | if (mov->tracks[i].enc->flags & CODEC_FLAG_BITEXACT) {
|
||
1660 | 1ee2d448 | Aurelien Jacobs | return 0; |
1661 | d1d87dfb | Baptiste Coudurier | } |
1662 | |||
1663 | b92c5452 | Anton Khirnov | ret = avio_open_dyn_buf(&pb_buf); |
1664 | 1ee2d448 | Aurelien Jacobs | if(ret < 0) |
1665 | return ret;
|
||
1666 | 69dde1ad | Gildas Bazin | |
1667 | a04aec6d | Michael Niedermayer | if (mov->mode & MODE_3GP) {
|
1668 | a4de2b6e | Baptiste Coudurier | mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist"); |
1669 | 1ee2d448 | Aurelien Jacobs | mov_write_3gp_udta_tag(pb_buf, s, "titl", "title"); |
1670 | mov_write_3gp_udta_tag(pb_buf, s, "auth", "author"); |
||
1671 | mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre"); |
||
1672 | mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment"); |
||
1673 | mov_write_3gp_udta_tag(pb_buf, s, "albm", "album"); |
||
1674 | mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright"); |
||
1675 | ca76a119 | Anton Khirnov | mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date"); |
1676 | ce072b2d | Baptiste Coudurier | } else if (mov->mode == MODE_MOV) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4 |
1677 | 96d1e75a | Baptiste Coudurier | mov_write_string_metadata(s, pb_buf, "\251ART", "artist" , 0); |
1678 | 1ee2d448 | Aurelien Jacobs | mov_write_string_metadata(s, pb_buf, "\251nam", "title" , 0); |
1679 | mov_write_string_metadata(s, pb_buf, "\251aut", "author" , 0); |
||
1680 | mov_write_string_metadata(s, pb_buf, "\251alb", "album" , 0); |
||
1681 | ca76a119 | Anton Khirnov | mov_write_string_metadata(s, pb_buf, "\251day", "date" , 0); |
1682 | edd33cb6 | Baptiste Coudurier | mov_write_string_metadata(s, pb_buf, "\251swr", "encoder" , 0); |
1683 | 1ee2d448 | Aurelien Jacobs | mov_write_string_metadata(s, pb_buf, "\251des", "comment" , 0); |
1684 | mov_write_string_metadata(s, pb_buf, "\251gen", "genre" , 0); |
||
1685 | mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright" , 0); |
||
1686 | c6e2c6c9 | Baptiste Coudurier | } else {
|
1687 | 283c9a8e | Baptiste Coudurier | /* iTunes meta data */
|
1688 | 1ee2d448 | Aurelien Jacobs | mov_write_meta_tag(pb_buf, mov, s); |
1689 | c6e2c6c9 | Baptiste Coudurier | } |
1690 | 1ee2d448 | Aurelien Jacobs | |
1691 | dc75e4e3 | David Conrad | if (s->nb_chapters)
|
1692 | mov_write_chpl_tag(pb_buf, s); |
||
1693 | |||
1694 | 6dc7d80d | Anton Khirnov | if ((size = avio_close_dyn_buf(pb_buf, &buf)) > 0) { |
1695 | 77eb5504 | Anton Khirnov | avio_wb32(pb, size+8);
|
1696 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "udta");
|
1697 | 77eb5504 | Anton Khirnov | avio_write(pb, buf, size); |
1698 | 89a0d790 | Benoit Fouet | } |
1699 | 8b6e0aec | Martin Storsjö | av_free(buf); |
1700 | 89a0d790 | Benoit Fouet | |
1701 | return 0; |
||
1702 | 69dde1ad | Gildas Bazin | } |
1703 | |||
1704 | ae628ec1 | Anton Khirnov | static void mov_write_psp_udta_tag(AVIOContext *pb, |
1705 | 20e22af8 | Baptiste Coudurier | const char *str, const char *lang, int type) |
1706 | { |
||
1707 | int len = utf8len(str)+1; |
||
1708 | if(len<=0) |
||
1709 | d32d6def | Baptiste Coudurier | return;
|
1710 | 77eb5504 | Anton Khirnov | avio_wb16(pb, len*2+10); /* size */ |
1711 | avio_wb32(pb, type); /* type */
|
||
1712 | avio_wb16(pb, language_code(lang)); /* language */
|
||
1713 | avio_wb16(pb, 0x01); /* ? */ |
||
1714 | 20e22af8 | Baptiste Coudurier | ascii_to_wc(pb, str); |
1715 | } |
||
1716 | |||
1717 | ae628ec1 | Anton Khirnov | static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s) |
1718 | dcfdb046 | Benjamin Larsson | { |
1719 | 1ee2d448 | Aurelien Jacobs | AVMetadataTag *title = av_metadata_get(s->metadata, "title", NULL, 0); |
1720 | bc5c918e | Diego Biurrun | int64_t pos, pos2; |
1721 | dcfdb046 | Benjamin Larsson | |
1722 | 1ee2d448 | Aurelien Jacobs | if (title) {
|
1723 | a2704c97 | Anton Khirnov | pos = avio_tell(pb); |
1724 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size placeholder*/ |
1725 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "uuid");
|
1726 | ffio_wfourcc(pb, "USMT");
|
||
1727 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */ |
1728 | avio_wb32(pb, 0xbb88695c);
|
||
1729 | avio_wb32(pb, 0xfac9c740);
|
||
1730 | dcfdb046 | Benjamin Larsson | |
1731 | a2704c97 | Anton Khirnov | pos2 = avio_tell(pb); |
1732 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size placeholder*/ |
1733 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "MTDT");
|
1734 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 4);
|
1735 | dcfdb046 | Benjamin Larsson | |
1736 | 7cf0e16f | Michael Niedermayer | // ?
|
1737 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 0x0C); /* size */ |
1738 | avio_wb32(pb, 0x0B); /* type */ |
||
1739 | avio_wb16(pb, language_code("und")); /* language */ |
||
1740 | avio_wb16(pb, 0x0); /* ? */ |
||
1741 | avio_wb16(pb, 0x021C); /* data */ |
||
1742 | 7cf0e16f | Michael Niedermayer | |
1743 | d32d6def | Baptiste Coudurier | mov_write_psp_udta_tag(pb, LIBAVCODEC_IDENT, "eng", 0x04); |
1744 | 1ee2d448 | Aurelien Jacobs | mov_write_psp_udta_tag(pb, title->value, "eng", 0x01); |
1745 | 7cf0e16f | Michael Niedermayer | // snprintf(dt,32,"%04d/%02d/%02d %02d:%02d:%02d",t_st->tm_year+1900,t_st->tm_mon+1,t_st->tm_mday,t_st->tm_hour,t_st->tm_min,t_st->tm_sec);
|
1746 | d32d6def | Baptiste Coudurier | mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03); |
1747 | |||
1748 | updateSize(pb, pos2); |
||
1749 | return updateSize(pb, pos);
|
||
1750 | dcfdb046 | Benjamin Larsson | } |
1751 | |||
1752 | d32d6def | Baptiste Coudurier | return 0; |
1753 | dcfdb046 | Benjamin Larsson | } |
1754 | |||
1755 | ae628ec1 | Anton Khirnov | static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov, |
1756 | 69dde1ad | Gildas Bazin | AVFormatContext *s) |
1757 | 1cb5f7fd | Michael Niedermayer | { |
1758 | b29af723 | Michael Niedermayer | int i;
|
1759 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1760 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size placeholder*/ |
1761 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "moov");
|
1762 | 1cb5f7fd | Michael Niedermayer | |
1763 | 42fb4148 | Baptiste Coudurier | for (i=0; i<mov->nb_streams; i++) { |
1764 | e45ccf79 | Gildas Bazin | if(mov->tracks[i].entry <= 0) continue; |
1765 | |||
1766 | mov->tracks[i].time = mov->time; |
||
1767 | mov->tracks[i].trackID = i+1;
|
||
1768 | 1cb5f7fd | Michael Niedermayer | } |
1769 | |||
1770 | ddb63017 | David Conrad | if (mov->chapter_track)
|
1771 | for (i=0; i<s->nb_streams; i++) { |
||
1772 | mov->tracks[i].tref_tag = MKTAG('c','h','a','p'); |
||
1773 | mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].trackID; |
||
1774 | } |
||
1775 | e977af6f | Martin Storsjö | for (i = 0; i < mov->nb_streams; i++) { |
1776 | if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) { |
||
1777 | mov->tracks[i].tref_tag = MKTAG('h','i','n','t'); |
||
1778 | mov->tracks[i].tref_id = |
||
1779 | mov->tracks[mov->tracks[i].src_track].trackID; |
||
1780 | } |
||
1781 | } |
||
1782 | ddb63017 | David Conrad | |
1783 | 6e6d6dc0 | Michael Niedermayer | mov_write_mvhd_tag(pb, mov); |
1784 | //mov_write_iods_tag(pb, mov);
|
||
1785 | 42fb4148 | Baptiste Coudurier | for (i=0; i<mov->nb_streams; i++) { |
1786 | 1cb5f7fd | Michael Niedermayer | if(mov->tracks[i].entry > 0) { |
1787 | ddb63017 | David Conrad | mov_write_trak_tag(pb, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL);
|
1788 | 1cb5f7fd | Michael Niedermayer | } |
1789 | } |
||
1790 | |||
1791 | dcfdb046 | Benjamin Larsson | if (mov->mode == MODE_PSP)
|
1792 | mov_write_uuidusmt_tag(pb, s); |
||
1793 | c6e2c6c9 | Baptiste Coudurier | else
|
1794 | e344c1ea | Steve L'Homme | mov_write_udta_tag(pb, mov, s); |
1795 | 69dde1ad | Gildas Bazin | |
1796 | 6e6d6dc0 | Michael Niedermayer | return updateSize(pb, pos);
|
1797 | 1cb5f7fd | Michael Niedermayer | } |
1798 | |||
1799 | ae628ec1 | Anton Khirnov | static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov) |
1800 | 1cb5f7fd | Michael Niedermayer | { |
1801 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 8); // placeholder for extended size field (64 bit) |
1802 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free"); |
1803 | b29af723 | Michael Niedermayer | |
1804 | a2704c97 | Anton Khirnov | mov->mdat_pos = avio_tell(pb); |
1805 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size placeholder*/ |
1806 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "mdat");
|
1807 | 1cb5f7fd | Michael Niedermayer | return 0; |
1808 | } |
||
1809 | |||
1810 | /* TODO: This needs to be more general */
|
||
1811 | ae628ec1 | Anton Khirnov | static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) |
1812 | 1cb5f7fd | Michael Niedermayer | { |
1813 | 2d243fb3 | Ronald S. Bultje | MOVMuxContext *mov = s->priv_data; |
1814 | a2704c97 | Anton Khirnov | int64_t pos = avio_tell(pb); |
1815 | cd70d17f | Baptiste Coudurier | int has_h264 = 0, has_video = 0; |
1816 | 40f8675c | Baptiste Coudurier | int minor = 0x200; |
1817 | c55cc074 | Baptiste Coudurier | int i;
|
1818 | 69dde1ad | Gildas Bazin | |
1819 | 83579084 | Baptiste Coudurier | for (i = 0; i < s->nb_streams; i++) { |
1820 | AVStream *st = s->streams[i]; |
||
1821 | 72415b2a | Stefano Sabatini | if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
|
1822 | cd70d17f | Baptiste Coudurier | has_video = 1;
|
1823 | 83579084 | Baptiste Coudurier | if (st->codec->codec_id == CODEC_ID_H264)
|
1824 | has_h264 = 1;
|
||
1825 | } |
||
1826 | |||
1827 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0); /* size */ |
1828 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "ftyp");
|
1829 | e45ccf79 | Gildas Bazin | |
1830 | 40f8675c | Baptiste Coudurier | if (mov->mode == MODE_3GP) {
|
1831 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4"); |
1832 | 40f8675c | Baptiste Coudurier | minor = has_h264 ? 0x100 : 0x200; |
1833 | } else if (mov->mode & MODE_3G2) { |
||
1834 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a"); |
1835 | 40f8675c | Baptiste Coudurier | minor = has_h264 ? 0x20000 : 0x10000; |
1836 | }else if (mov->mode == MODE_PSP) |
||
1837 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "MSNV");
|
1838 | c55cc074 | Baptiste Coudurier | else if (mov->mode == MODE_MP4) |
1839 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "isom");
|
1840 | cd70d17f | Baptiste Coudurier | else if (mov->mode == MODE_IPOD) |
1841 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, has_video ? "M4V ":"M4A "); |
1842 | cd70d17f | Baptiste Coudurier | else
|
1843 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "qt ");
|
1844 | e45ccf79 | Gildas Bazin | |
1845 | 77eb5504 | Anton Khirnov | avio_wb32(pb, minor); |
1846 | e45ccf79 | Gildas Bazin | |
1847 | 6ba9ed95 | Baptiste Coudurier | if(mov->mode == MODE_MOV)
|
1848 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "qt ");
|
1849 | 6ba9ed95 | Baptiste Coudurier | else{
|
1850 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "isom");
|
1851 | ffio_wfourcc(pb, "iso2");
|
||
1852 | 83579084 | Baptiste Coudurier | if(has_h264)
|
1853 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "avc1");
|
1854 | 6ba9ed95 | Baptiste Coudurier | } |
1855 | ed6e47c2 | Michael Niedermayer | |
1856 | 91208916 | Baptiste Coudurier | if (mov->mode == MODE_3GP)
|
1857 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, has_h264 ? "3gp6":"3gp4"); |
1858 | a04aec6d | Michael Niedermayer | else if (mov->mode & MODE_3G2) |
1859 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, has_h264 ? "3g2b":"3g2a"); |
1860 | 91208916 | Baptiste Coudurier | else if (mov->mode == MODE_PSP) |
1861 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "MSNV");
|
1862 | c55cc074 | Baptiste Coudurier | else if (mov->mode == MODE_MP4) |
1863 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "mp41");
|
1864 | 1560b667 | Michael Niedermayer | return updateSize(pb, pos);
|
1865 | 1cb5f7fd | Michael Niedermayer | } |
1866 | |||
1867 | ae628ec1 | Anton Khirnov | static void mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s) |
1868 | 8af18154 | tjcannell@blueyonder.co.uk | { |
1869 | dcfdb046 | Benjamin Larsson | AVCodecContext *VideoCodec = s->streams[0]->codec;
|
1870 | AVCodecContext *AudioCodec = s->streams[1]->codec;
|
||
1871 | int AudioRate = AudioCodec->sample_rate;
|
||
1872 | int FrameRate = ((VideoCodec->time_base.den) * (0x10000))/ (VideoCodec->time_base.num); |
||
1873 | 9e282ba3 | Michael Niedermayer | int audio_kbitrate= AudioCodec->bit_rate / 1000; |
1874 | int video_kbitrate= FFMIN(VideoCodec->bit_rate / 1000, 800 - audio_kbitrate); |
||
1875 | 8af18154 | tjcannell@blueyonder.co.uk | |
1876 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x94); /* size */ |
1877 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "uuid");
|
1878 | ffio_wfourcc(pb, "PROF");
|
||
1879 | 8af18154 | tjcannell@blueyonder.co.uk | |
1880 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */ |
1881 | avio_wb32(pb, 0xbb88695c);
|
||
1882 | avio_wb32(pb, 0xfac9c740);
|
||
1883 | 8af18154 | tjcannell@blueyonder.co.uk | |
1884 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x0); /* ? */ |
1885 | avio_wb32(pb, 0x3); /* 3 sections ? */ |
||
1886 | 8af18154 | tjcannell@blueyonder.co.uk | |
1887 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x14); /* size */ |
1888 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "FPRF");
|
1889 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x0); /* ? */ |
1890 | avio_wb32(pb, 0x0); /* ? */ |
||
1891 | avio_wb32(pb, 0x0); /* ? */ |
||
1892 | 8af18154 | tjcannell@blueyonder.co.uk | |
1893 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x2c); /* size */ |
1894 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "APRF");/* audio */ |
1895 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x0);
|
1896 | avio_wb32(pb, 0x2); /* TrackID */ |
||
1897 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "mp4a");
|
1898 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x20f);
|
1899 | avio_wb32(pb, 0x0);
|
||
1900 | avio_wb32(pb, audio_kbitrate); |
||
1901 | avio_wb32(pb, audio_kbitrate); |
||
1902 | avio_wb32(pb, AudioRate); |
||
1903 | avio_wb32(pb, AudioCodec->channels); |
||
1904 | |||
1905 | avio_wb32(pb, 0x34); /* size */ |
||
1906 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "VPRF"); /* video */ |
1907 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x0);
|
1908 | avio_wb32(pb, 0x1); /* TrackID */ |
||
1909 | 87b041e0 | Michael Niedermayer | if (VideoCodec->codec_id == CODEC_ID_H264) {
|
1910 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "avc1");
|
1911 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 0x014D);
|
1912 | avio_wb16(pb, 0x0015);
|
||
1913 | 87b041e0 | Michael Niedermayer | } else {
|
1914 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "mp4v");
|
1915 | 77eb5504 | Anton Khirnov | avio_wb16(pb, 0x0000);
|
1916 | avio_wb16(pb, 0x0103);
|
||
1917 | 87b041e0 | Michael Niedermayer | } |
1918 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 0x0);
|
1919 | avio_wb32(pb, video_kbitrate); |
||
1920 | avio_wb32(pb, video_kbitrate); |
||
1921 | avio_wb32(pb, FrameRate); |
||
1922 | avio_wb32(pb, FrameRate); |
||
1923 | avio_wb16(pb, VideoCodec->width); |
||
1924 | avio_wb16(pb, VideoCodec->height); |
||
1925 | avio_wb32(pb, 0x010001); /* ? */ |
||
1926 | 8af18154 | tjcannell@blueyonder.co.uk | } |
1927 | |||
1928 | e1316b19 | Baptiste Coudurier | static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags) |
1929 | { |
||
1930 | uint32_t c = -1;
|
||
1931 | int i, closed_gop = 0; |
||
1932 | |||
1933 | for (i = 0; i < pkt->size - 4; i++) { |
||
1934 | c = (c<<8) + pkt->data[i];
|
||
1935 | if (c == 0x1b8) { // gop |
||
1936 | closed_gop = pkt->data[i+4]>>6 & 0x01; |
||
1937 | } else if (c == 0x100) { // pic |
||
1938 | int temp_ref = (pkt->data[i+1]<<2) | (pkt->data[i+2]>>6); |
||
1939 | if (!temp_ref || closed_gop) // I picture is not reordered |
||
1940 | *flags = MOV_SYNC_SAMPLE; |
||
1941 | else
|
||
1942 | *flags = MOV_PARTIAL_SYNC_SAMPLE; |
||
1943 | break;
|
||
1944 | } |
||
1945 | } |
||
1946 | return 0; |
||
1947 | } |
||
1948 | |||
1949 | 27a826c9 | Martin Storsjö | int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
|
1950 | 1cb5f7fd | Michael Niedermayer | { |
1951 | 2d243fb3 | Ronald S. Bultje | MOVMuxContext *mov = s->priv_data; |
1952 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
1953 | 039627cf | Baptiste Coudurier | MOVTrack *trk = &mov->tracks[pkt->stream_index]; |
1954 | AVCodecContext *enc = trk->enc; |
||
1955 | e45ccf79 | Gildas Bazin | unsigned int samplesInChunk = 0; |
1956 | e928649b | Michael Niedermayer | int size= pkt->size;
|
1957 | 1cb5f7fd | Michael Niedermayer | |
1958 | 8978feda | Anton Khirnov | if (!s->pb->seekable) return 0; /* Can't handle that */ |
1959 | e45ccf79 | Gildas Bazin | if (!size) return 0; /* Discard 0 sized packets */ |
1960 | 1cb5f7fd | Michael Niedermayer | |
1961 | 06fcf56c | Baptiste Coudurier | if (enc->codec_id == CODEC_ID_AMR_NB) {
|
1962 | 5cb49ca1 | Baptiste Coudurier | /* We must find out how many AMR blocks there are in one packet */
|
1963 | static uint16_t packed_size[16] = |
||
1964 | {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0}; |
||
1965 | int len = 0; |
||
1966 | |||
1967 | while (len < size && samplesInChunk < 100) { |
||
1968 | len += packed_size[(pkt->data[len] >> 3) & 0x0F]; |
||
1969 | samplesInChunk++; |
||
1970 | 1cb5f7fd | Michael Niedermayer | } |
1971 | 2111e3f9 | Michael Niedermayer | if(samplesInChunk > 1){ |
1972 | 89938d29 | Ramiro Polla | av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
|
1973 | 2111e3f9 | Michael Niedermayer | return -1; |
1974 | } |
||
1975 | f2589642 | Baptiste Coudurier | } else if (enc->codec_id == CODEC_ID_ADPCM_MS || |
1976 | enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) { |
||
1977 | samplesInChunk = enc->frame_size; |
||
1978 | 5cb49ca1 | Baptiste Coudurier | } else if (trk->sampleSize) |
1979 | samplesInChunk = size/trk->sampleSize; |
||
1980 | else
|
||
1981 | 5616f85d | Baptiste Coudurier | samplesInChunk = 1;
|
1982 | e45ccf79 | Gildas Bazin | |
1983 | 5616f85d | Baptiste Coudurier | /* copy extradata if it exists */
|
1984 | if (trk->vosLen == 0 && enc->extradata_size > 0) { |
||
1985 | e45ccf79 | Gildas Bazin | trk->vosLen = enc->extradata_size; |
1986 | trk->vosData = av_malloc(trk->vosLen); |
||
1987 | memcpy(trk->vosData, enc->extradata, trk->vosLen); |
||
1988 | } |
||
1989 | |||
1990 | 5d2160a0 | Baptiste Coudurier | if (enc->codec_id == CODEC_ID_H264 && trk->vosLen > 0 && *(uint8_t *)trk->vosData != 1) { |
1991 | /* from x264 or from bytestream h264 */
|
||
1992 | /* nal reformating needed */
|
||
1993 | size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size); |
||
1994 | } else {
|
||
1995 | 77eb5504 | Anton Khirnov | avio_write(pb, pkt->data, size); |
1996 | 5d2160a0 | Baptiste Coudurier | } |
1997 | |||
1998 | 0a63a676 | Luca Abeni | if ((enc->codec_id == CODEC_ID_DNXHD ||
|
1999 | 1fbbedff | Baptiste Coudurier | enc->codec_id == CODEC_ID_AC3) && !trk->vosLen) { |
2000 | db568c07 | Baptiste Coudurier | /* copy frame to create needed atoms */
|
2001 | trk->vosLen = size; |
||
2002 | trk->vosData = av_malloc(size); |
||
2003 | e8c4df40 | Baptiste Coudurier | if (!trk->vosData)
|
2004 | return AVERROR(ENOMEM);
|
||
2005 | db568c07 | Baptiste Coudurier | memcpy(trk->vosData, pkt->data, size); |
2006 | c1b8e6d8 | Baptiste Coudurier | } |
2007 | |||
2008 | 0aec3c5c | Baptiste Coudurier | if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) {
|
2009 | trk->cluster = av_realloc(trk->cluster, (trk->entry + MOV_INDEX_CLUSTER_SIZE) * sizeof(*trk->cluster));
|
||
2010 | e45ccf79 | Gildas Bazin | if (!trk->cluster)
|
2011 | return -1; |
||
2012 | } |
||
2013 | |||
2014 | a2704c97 | Anton Khirnov | trk->cluster[trk->entry].pos = avio_tell(pb) - size; |
2015 | 0aec3c5c | Baptiste Coudurier | trk->cluster[trk->entry].samplesInChunk = samplesInChunk; |
2016 | trk->cluster[trk->entry].size = size; |
||
2017 | trk->cluster[trk->entry].entries = samplesInChunk; |
||
2018 | aa90239f | Baptiste Coudurier | trk->cluster[trk->entry].dts = pkt->dts; |
2019 | trk->trackDuration = pkt->dts - trk->cluster[0].dts + pkt->duration;
|
||
2020 | |||
2021 | 96f69e0d | Baptiste Coudurier | if (pkt->pts == AV_NOPTS_VALUE) {
|
2022 | av_log(s, AV_LOG_WARNING, "pts has no value\n");
|
||
2023 | pkt->pts = pkt->dts; |
||
2024 | } |
||
2025 | c4f078ff | Baptiste Coudurier | if (pkt->dts != pkt->pts)
|
2026 | e1316b19 | Baptiste Coudurier | trk->flags |= MOV_TRACK_CTTS; |
2027 | c4f078ff | Baptiste Coudurier | trk->cluster[trk->entry].cts = pkt->pts - pkt->dts; |
2028 | e1316b19 | Baptiste Coudurier | trk->cluster[trk->entry].flags = 0;
|
2029 | cc947f04 | Jean-Daniel Dupas | if (pkt->flags & AV_PKT_FLAG_KEY) {
|
2030 | 44b11207 | Takashi Mochizuki | if (mov->mode == MODE_MOV && enc->codec_id == CODEC_ID_MPEG2VIDEO &&
|
2031 | trk->entry > 0) { // force sync sample for the first key frame |
||
2032 | e1316b19 | Baptiste Coudurier | mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags); |
2033 | if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
|
||
2034 | trk->flags |= MOV_TRACK_STPS; |
||
2035 | } else {
|
||
2036 | trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE; |
||
2037 | } |
||
2038 | if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
|
||
2039 | trk->hasKeyframes++; |
||
2040 | ab4752e3 | Baptiste Coudurier | } |
2041 | e45ccf79 | Gildas Bazin | trk->entry++; |
2042 | trk->sampleCount += samplesInChunk; |
||
2043 | 039627cf | Baptiste Coudurier | mov->mdat_size += size; |
2044 | e45ccf79 | Gildas Bazin | |
2045 | b7f2fdde | Anton Khirnov | avio_flush(pb); |
2046 | e977af6f | Martin Storsjö | |
2047 | if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) |
||
2048 | ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry); |
||
2049 | 1cb5f7fd | Michael Niedermayer | return 0; |
2050 | } |
||
2051 | |||
2052 | ddb63017 | David Conrad | // QuickTime chapters involve an additional text track with the chapter names
|
2053 | // as samples, and a tref pointing from the other tracks to the chapter one.
|
||
2054 | static void mov_create_chapter_track(AVFormatContext *s, int tracknum) |
||
2055 | { |
||
2056 | MOVMuxContext *mov = s->priv_data; |
||
2057 | MOVTrack *track = &mov->tracks[tracknum]; |
||
2058 | AVPacket pkt = { .stream_index = tracknum, .flags = AV_PKT_FLAG_KEY }; |
||
2059 | int i, len;
|
||
2060 | |||
2061 | track->mode = mov->mode; |
||
2062 | track->tag = MKTAG('t','e','x','t'); |
||
2063 | track->timescale = MOV_TIMESCALE; |
||
2064 | track->enc = avcodec_alloc_context(); |
||
2065 | track->enc->codec_type = AVMEDIA_TYPE_SUBTITLE; |
||
2066 | |||
2067 | for (i = 0; i < s->nb_chapters; i++) { |
||
2068 | AVChapter *c = s->chapters[i]; |
||
2069 | AVMetadataTag *t; |
||
2070 | |||
2071 | int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,MOV_TIMESCALE});
|
||
2072 | pkt.pts = pkt.dts = av_rescale_q(c->start, c->time_base, (AVRational){1,MOV_TIMESCALE});
|
||
2073 | pkt.duration = end - pkt.dts; |
||
2074 | |||
2075 | if ((t = av_metadata_get(c->metadata, "title", NULL, 0))) { |
||
2076 | len = strlen(t->value); |
||
2077 | pkt.size = len+2;
|
||
2078 | pkt.data = av_malloc(pkt.size); |
||
2079 | AV_WB16(pkt.data, len); |
||
2080 | memcpy(pkt.data+2, t->value, len);
|
||
2081 | 27a826c9 | Martin Storsjö | ff_mov_write_packet(s, &pkt); |
2082 | ddb63017 | David Conrad | av_freep(&pkt.data); |
2083 | } |
||
2084 | } |
||
2085 | } |
||
2086 | |||
2087 | 1b206f62 | David Conrad | static int mov_write_header(AVFormatContext *s) |
2088 | { |
||
2089 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
2090 | 1b206f62 | David Conrad | MOVMuxContext *mov = s->priv_data; |
2091 | e977af6f | Martin Storsjö | int i, hint_track = 0; |
2092 | 1b206f62 | David Conrad | |
2093 | 8978feda | Anton Khirnov | if (!s->pb->seekable) {
|
2094 | 1b206f62 | David Conrad | av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
|
2095 | return -1; |
||
2096 | } |
||
2097 | |||
2098 | /* Default mode == MP4 */
|
||
2099 | mov->mode = MODE_MP4; |
||
2100 | |||
2101 | if (s->oformat != NULL) { |
||
2102 | if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP; |
||
2103 | else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3GP|MODE_3G2; |
||
2104 | else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV; |
||
2105 | else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP; |
||
2106 | else if (!strcmp("ipod",s->oformat->name)) mov->mode = MODE_IPOD; |
||
2107 | |||
2108 | mov_write_ftyp_tag(pb,s); |
||
2109 | if (mov->mode == MODE_PSP) {
|
||
2110 | if (s->nb_streams != 2) { |
||
2111 | av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
|
||
2112 | return -1; |
||
2113 | } |
||
2114 | mov_write_uuidprof_tag(pb,s); |
||
2115 | } |
||
2116 | } |
||
2117 | |||
2118 | ddb63017 | David Conrad | mov->nb_streams = s->nb_streams; |
2119 | if (mov->mode & (MODE_MOV|MODE_IPOD) && s->nb_chapters)
|
||
2120 | mov->chapter_track = mov->nb_streams++; |
||
2121 | |||
2122 | e977af6f | Martin Storsjö | if (s->flags & AVFMT_FLAG_RTP_HINT) {
|
2123 | /* Add hint tracks for each audio and video stream */
|
||
2124 | hint_track = mov->nb_streams; |
||
2125 | for (i = 0; i < s->nb_streams; i++) { |
||
2126 | AVStream *st = s->streams[i]; |
||
2127 | if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
|
||
2128 | st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { |
||
2129 | mov->nb_streams++; |
||
2130 | } |
||
2131 | } |
||
2132 | } |
||
2133 | |||
2134 | ddb63017 | David Conrad | mov->tracks = av_mallocz(mov->nb_streams*sizeof(*mov->tracks));
|
2135 | 1b206f62 | David Conrad | if (!mov->tracks)
|
2136 | return AVERROR(ENOMEM);
|
||
2137 | |||
2138 | for(i=0; i<s->nb_streams; i++){ |
||
2139 | AVStream *st= s->streams[i]; |
||
2140 | MOVTrack *track= &mov->tracks[i]; |
||
2141 | AVMetadataTag *lang = av_metadata_get(st->metadata, "language", NULL,0); |
||
2142 | |||
2143 | track->enc = st->codec; |
||
2144 | track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
|
||
2145 | if (track->language < 0) |
||
2146 | track->language = 0;
|
||
2147 | track->mode = mov->mode; |
||
2148 | track->tag = mov_find_codec_tag(s, track); |
||
2149 | if (!track->tag) {
|
||
2150 | av_log(s, AV_LOG_ERROR, "track %d: could not find tag, "
|
||
2151 | "codec not currently supported in container\n", i);
|
||
2152 | goto error;
|
||
2153 | } |
||
2154 | e977af6f | Martin Storsjö | /* If hinting of this track is enabled by a later hint track,
|
2155 | * this is updated. */
|
||
2156 | track->hint_track = -1;
|
||
2157 | 1b206f62 | David Conrad | if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){
|
2158 | if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') || |
||
2159 | track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') || |
||
2160 | track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) { |
||
2161 | if (st->codec->width != 720 || (st->codec->height != 608 && st->codec->height != 512)) { |
||
2162 | av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
|
||
2163 | goto error;
|
||
2164 | } |
||
2165 | track->height = track->tag>>24 == 'n' ? 486 : 576; |
||
2166 | } |
||
2167 | track->timescale = st->codec->time_base.den; |
||
2168 | if (track->mode == MODE_MOV && track->timescale > 100000) |
||
2169 | av_log(s, AV_LOG_WARNING, |
||
2170 | "WARNING codec timebase is very high. If duration is too long,\n"
|
||
2171 | "file may not be playable by quicktime. Specify a shorter timebase\n"
|
||
2172 | "or choose different container.\n");
|
||
2173 | }else if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO){ |
||
2174 | track->timescale = st->codec->sample_rate; |
||
2175 | if(!st->codec->frame_size && !av_get_bits_per_sample(st->codec->codec_id)) {
|
||
2176 | av_log(s, AV_LOG_ERROR, "track %d: codec frame size is not set\n", i);
|
||
2177 | goto error;
|
||
2178 | f2589642 | Baptiste Coudurier | }else if(st->codec->codec_id == CODEC_ID_ADPCM_MS || |
2179 | st->codec->codec_id == CODEC_ID_ADPCM_IMA_WAV){ |
||
2180 | if (!st->codec->block_align) {
|
||
2181 | av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
|
||
2182 | goto error;
|
||
2183 | } |
||
2184 | track->sampleSize = st->codec->block_align; |
||
2185 | 1b206f62 | David Conrad | }else if(st->codec->frame_size > 1){ /* assume compressed audio */ |
2186 | track->audio_vbr = 1;
|
||
2187 | }else{
|
||
2188 | st->codec->frame_size = 1;
|
||
2189 | track->sampleSize = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels;
|
||
2190 | } |
||
2191 | if (track->mode != MODE_MOV) {
|
||
2192 | if (track->timescale > UINT16_MAX) {
|
||
2193 | av_log(s, AV_LOG_ERROR, "track %d: output format does not support "
|
||
2194 | "sample rate %dhz\n", i, track->timescale);
|
||
2195 | goto error;
|
||
2196 | } |
||
2197 | if (track->enc->codec_id == CODEC_ID_MP3 && track->timescale < 16000) { |
||
2198 | av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not supported\n",
|
||
2199 | i, track->enc->sample_rate); |
||
2200 | goto error;
|
||
2201 | } |
||
2202 | } |
||
2203 | }else if(st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE){ |
||
2204 | track->timescale = st->codec->time_base.den; |
||
2205 | } |
||
2206 | if (!track->height)
|
||
2207 | track->height = st->codec->height; |
||
2208 | |||
2209 | av_set_pts_info(st, 64, 1, track->timescale); |
||
2210 | } |
||
2211 | |||
2212 | mov_write_mdat_tag(pb, mov); |
||
2213 | mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based |
||
2214 | ddb63017 | David Conrad | |
2215 | if (mov->chapter_track)
|
||
2216 | mov_create_chapter_track(s, mov->chapter_track); |
||
2217 | 1b206f62 | David Conrad | |
2218 | e977af6f | Martin Storsjö | if (s->flags & AVFMT_FLAG_RTP_HINT) {
|
2219 | /* Initialize the hint tracks for each audio and video stream */
|
||
2220 | for (i = 0; i < s->nb_streams; i++) { |
||
2221 | AVStream *st = s->streams[i]; |
||
2222 | if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
|
||
2223 | st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { |
||
2224 | ff_mov_init_hinting(s, hint_track, i); |
||
2225 | hint_track++; |
||
2226 | } |
||
2227 | } |
||
2228 | } |
||
2229 | |||
2230 | b7f2fdde | Anton Khirnov | avio_flush(pb); |
2231 | 1b206f62 | David Conrad | |
2232 | return 0; |
||
2233 | error:
|
||
2234 | av_freep(&mov->tracks); |
||
2235 | return -1; |
||
2236 | } |
||
2237 | |||
2238 | 1cb5f7fd | Michael Niedermayer | static int mov_write_trailer(AVFormatContext *s) |
2239 | { |
||
2240 | 2d243fb3 | Ronald S. Bultje | MOVMuxContext *mov = s->priv_data; |
2241 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
2242 | 1cb5f7fd | Michael Niedermayer | int res = 0; |
2243 | 0aec3c5c | Baptiste Coudurier | int i;
|
2244 | 1cb5f7fd | Michael Niedermayer | |
2245 | a2704c97 | Anton Khirnov | int64_t moov_pos = avio_tell(pb); |
2246 | 1cb5f7fd | Michael Niedermayer | |
2247 | /* Write size of mdat tag */
|
||
2248 | 039627cf | Baptiste Coudurier | if (mov->mdat_size+8 <= UINT32_MAX) { |
2249 | 6b4aa5da | Anton Khirnov | avio_seek(pb, mov->mdat_pos, SEEK_SET); |
2250 | 77eb5504 | Anton Khirnov | avio_wb32(pb, mov->mdat_size+8);
|
2251 | b29af723 | Michael Niedermayer | } else {
|
2252 | /* overwrite 'wide' placeholder atom */
|
||
2253 | 6b4aa5da | Anton Khirnov | avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
|
2254 | 77eb5504 | Anton Khirnov | avio_wb32(pb, 1); /* special value: real atom size will be 64 bit value after tag field */ |
2255 | 0abdb293 | Anton Khirnov | ffio_wfourcc(pb, "mdat");
|
2256 | 77eb5504 | Anton Khirnov | avio_wb64(pb, mov->mdat_size+16);
|
2257 | b29af723 | Michael Niedermayer | } |
2258 | 6b4aa5da | Anton Khirnov | avio_seek(pb, moov_pos, SEEK_SET); |
2259 | 1cb5f7fd | Michael Niedermayer | |
2260 | 69dde1ad | Gildas Bazin | mov_write_moov_tag(pb, mov, s); |
2261 | 1cb5f7fd | Michael Niedermayer | |
2262 | ddb63017 | David Conrad | if (mov->chapter_track)
|
2263 | av_freep(&mov->tracks[mov->chapter_track].enc); |
||
2264 | |||
2265 | 42fb4148 | Baptiste Coudurier | for (i=0; i<mov->nb_streams; i++) { |
2266 | e977af6f | Martin Storsjö | if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) |
2267 | ff_mov_close_hinting(&mov->tracks[i]); |
||
2268 | 0aec3c5c | Baptiste Coudurier | av_freep(&mov->tracks[i].cluster); |
2269 | |||
2270 | 91208916 | Baptiste Coudurier | if(mov->tracks[i].vosLen) av_free(mov->tracks[i].vosData);
|
2271 | ec7d0d2e | Gildas Bazin | |
2272 | 1cb5f7fd | Michael Niedermayer | } |
2273 | 69dde1ad | Gildas Bazin | |
2274 | b7f2fdde | Anton Khirnov | avio_flush(pb); |
2275 | 1cb5f7fd | Michael Niedermayer | |
2276 | 5c5776e1 | Baptiste Coudurier | av_freep(&mov->tracks); |
2277 | |||
2278 | 1cb5f7fd | Michael Niedermayer | return res;
|
2279 | } |
||
2280 | |||
2281 | b250f9c6 | Aurelien Jacobs | #if CONFIG_MOV_MUXER
|
2282 | c6610a21 | Diego Elio Pettenò | AVOutputFormat ff_mov_muxer = { |
2283 | 1cb5f7fd | Michael Niedermayer | "mov",
|
2284 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("MOV format"),
|
2285 | 1cb5f7fd | Michael Niedermayer | NULL,
|
2286 | "mov",
|
||
2287 | 2d243fb3 | Ronald S. Bultje | sizeof(MOVMuxContext),
|
2288 | 69dde1ad | Gildas Bazin | CODEC_ID_AAC, |
2289 | 2187d948 | Michael Niedermayer | CODEC_ID_MPEG4, |
2290 | 1cb5f7fd | Michael Niedermayer | mov_write_header, |
2291 | 27a826c9 | Martin Storsjö | ff_mov_write_packet, |
2292 | 1cb5f7fd | Michael Niedermayer | mov_write_trailer, |
2293 | 91360ce6 | Baptiste Coudurier | .flags = AVFMT_GLOBALHEADER, |
2294 | c1854592 | Reimar Döffinger | .codec_tag = (const AVCodecTag* const []){codec_movvideo_tags, codec_movaudio_tags, 0}, |
2295 | 1cb5f7fd | Michael Niedermayer | }; |
2296 | ff70e601 | Måns Rullgård | #endif
|
2297 | b250f9c6 | Aurelien Jacobs | #if CONFIG_TGP_MUXER
|
2298 | c6610a21 | Diego Elio Pettenò | AVOutputFormat ff_tgp_muxer = { |
2299 | 1cb5f7fd | Michael Niedermayer | "3gp",
|
2300 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("3GP format"),
|
2301 | 1cb5f7fd | Michael Niedermayer | NULL,
|
2302 | "3gp",
|
||
2303 | 2d243fb3 | Ronald S. Bultje | sizeof(MOVMuxContext),
|
2304 | 1cb5f7fd | Michael Niedermayer | CODEC_ID_AMR_NB, |
2305 | CODEC_ID_H263, |
||
2306 | mov_write_header, |
||
2307 | 27a826c9 | Martin Storsjö | ff_mov_write_packet, |
2308 | 1cb5f7fd | Michael Niedermayer | mov_write_trailer, |
2309 | c64d476c | Calcium | .flags = AVFMT_GLOBALHEADER, |
2310 | c1854592 | Reimar Döffinger | .codec_tag = (const AVCodecTag* const []){codec_3gp_tags, 0}, |
2311 | 1cb5f7fd | Michael Niedermayer | }; |
2312 | ff70e601 | Måns Rullgård | #endif
|
2313 | b250f9c6 | Aurelien Jacobs | #if CONFIG_MP4_MUXER
|
2314 | c6610a21 | Diego Elio Pettenò | AVOutputFormat ff_mp4_muxer = { |
2315 | 1cb5f7fd | Michael Niedermayer | "mp4",
|
2316 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("MP4 format"),
|
2317 | 4cb3f3b6 | Dan Christiansen | "application/mp4",
|
2318 | ccec1b69 | Baptiste Coudurier | "mp4",
|
2319 | 2d243fb3 | Ronald S. Bultje | sizeof(MOVMuxContext),
|
2320 | 1cb5f7fd | Michael Niedermayer | CODEC_ID_AAC, |
2321 | CODEC_ID_MPEG4, |
||
2322 | mov_write_header, |
||
2323 | 27a826c9 | Martin Storsjö | ff_mov_write_packet, |
2324 | 1cb5f7fd | Michael Niedermayer | mov_write_trailer, |
2325 | 91360ce6 | Baptiste Coudurier | .flags = AVFMT_GLOBALHEADER, |
2326 | c1854592 | Reimar Döffinger | .codec_tag = (const AVCodecTag* const []){ff_mp4_obj_type, 0}, |
2327 | 1cb5f7fd | Michael Niedermayer | }; |
2328 | ff70e601 | Måns Rullgård | #endif
|
2329 | b250f9c6 | Aurelien Jacobs | #if CONFIG_PSP_MUXER
|
2330 | c6610a21 | Diego Elio Pettenò | AVOutputFormat ff_psp_muxer = { |
2331 | 8af18154 | tjcannell@blueyonder.co.uk | "psp",
|
2332 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("PSP MP4 format"),
|
2333 | 8af18154 | tjcannell@blueyonder.co.uk | NULL,
|
2334 | "mp4,psp",
|
||
2335 | 2d243fb3 | Ronald S. Bultje | sizeof(MOVMuxContext),
|
2336 | 8af18154 | tjcannell@blueyonder.co.uk | CODEC_ID_AAC, |
2337 | CODEC_ID_MPEG4, |
||
2338 | mov_write_header, |
||
2339 | 27a826c9 | Martin Storsjö | ff_mov_write_packet, |
2340 | 8af18154 | tjcannell@blueyonder.co.uk | mov_write_trailer, |
2341 | dcfdb046 | Benjamin Larsson | .flags = AVFMT_GLOBALHEADER, |
2342 | c1854592 | Reimar Döffinger | .codec_tag = (const AVCodecTag* const []){ff_mp4_obj_type, 0}, |
2343 | 8af18154 | tjcannell@blueyonder.co.uk | }; |
2344 | ff70e601 | Måns Rullgård | #endif
|
2345 | b250f9c6 | Aurelien Jacobs | #if CONFIG_TG2_MUXER
|
2346 | c6610a21 | Diego Elio Pettenò | AVOutputFormat ff_tg2_muxer = { |
2347 | 8536ab89 | tjraivio@cc.hut.fi | "3g2",
|
2348 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("3GP2 format"),
|
2349 | 8536ab89 | tjraivio@cc.hut.fi | NULL,
|
2350 | "3g2",
|
||
2351 | 2d243fb3 | Ronald S. Bultje | sizeof(MOVMuxContext),
|
2352 | 8536ab89 | tjraivio@cc.hut.fi | CODEC_ID_AMR_NB, |
2353 | CODEC_ID_H263, |
||
2354 | mov_write_header, |
||
2355 | 27a826c9 | Martin Storsjö | ff_mov_write_packet, |
2356 | 8536ab89 | tjraivio@cc.hut.fi | mov_write_trailer, |
2357 | c64d476c | Calcium | .flags = AVFMT_GLOBALHEADER, |
2358 | c1854592 | Reimar Döffinger | .codec_tag = (const AVCodecTag* const []){codec_3gp_tags, 0}, |
2359 | 8536ab89 | tjraivio@cc.hut.fi | }; |
2360 | ff70e601 | Måns Rullgård | #endif
|
2361 | b250f9c6 | Aurelien Jacobs | #if CONFIG_IPOD_MUXER
|
2362 | c6610a21 | Diego Elio Pettenò | AVOutputFormat ff_ipod_muxer = { |
2363 | aa9f4208 | Baptiste Coudurier | "ipod",
|
2364 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("iPod H.264 MP4 format"),
|
2365 | aa9f4208 | Baptiste Coudurier | "application/mp4",
|
2366 | ccec1b69 | Baptiste Coudurier | "m4v,m4a",
|
2367 | 2d243fb3 | Ronald S. Bultje | sizeof(MOVMuxContext),
|
2368 | aa9f4208 | Baptiste Coudurier | CODEC_ID_AAC, |
2369 | CODEC_ID_H264, |
||
2370 | mov_write_header, |
||
2371 | 27a826c9 | Martin Storsjö | ff_mov_write_packet, |
2372 | aa9f4208 | Baptiste Coudurier | mov_write_trailer, |
2373 | .flags = AVFMT_GLOBALHEADER, |
||
2374 | d1df4da0 | Baptiste Coudurier | .codec_tag = (const AVCodecTag* const []){codec_ipod_tags, 0}, |
2375 | aa9f4208 | Baptiste Coudurier | }; |
2376 | #endif |