Mercurial > libavformat.hg
comparison movenc.c @ 201:85def00971c3 libavformat
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
author | michaelni |
---|---|
date | Tue, 26 Aug 2003 20:23:13 +0000 |
parents | |
children | d755254e8797 |
comparison
equal
deleted
inserted
replaced
200:c0d49b5d246c | 201:85def00971c3 |
---|---|
1 /* | |
2 * MOV, 3GP, MP4 encoder. | |
3 * Copyright (c) 2003 Thomas Raivio. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 #include "avformat.h" | |
20 #include "avio.h" | |
21 #include <time.h> | |
22 | |
23 /* | |
24 * Limitations | |
25 * - Currently supports h.263, MPEG4 video codecs, and AMR audio codec. | |
26 */ | |
27 | |
28 #define MOV_INDEX_CLUSTER_SIZE 16384 | |
29 #define globalTimescale 1000 | |
30 | |
31 typedef struct MOVIentry { | |
32 unsigned int flags, pos, len; | |
33 unsigned int entries; | |
34 } MOVIentry; | |
35 | |
36 typedef struct MOVIndex { | |
37 int entry; | |
38 int samples; | |
39 int mdat_size; | |
40 offset_t mdat_pos; | |
41 int ents_allocated; | |
42 long timescale; | |
43 long time; | |
44 long frameDuration; | |
45 long sampleDelta; | |
46 int trackID; | |
47 AVCodecContext *enc; | |
48 | |
49 int vosLen; | |
50 char *vosData; | |
51 MOVIentry** cluster; | |
52 } MOVTrack; | |
53 | |
54 typedef struct { | |
55 long time; | |
56 int nb_streams; | |
57 offset_t movi_list; | |
58 long timescale; | |
59 MOVTrack tracks[MAX_STREAMS]; | |
60 } MOVContext; | |
61 | |
62 void writeSize (ByteIOContext *pb, int pos, int size) | |
63 { | |
64 long curpos = url_ftell(pb); | |
65 url_fseek(pb, pos, SEEK_SET); | |
66 put_be32(pb, size); /* rewrite size */ | |
67 url_fseek(pb, curpos, SEEK_SET); | |
68 } | |
69 | |
70 int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track) | |
71 { | |
72 int i; | |
73 put_be32(pb, 16+track->entry*4); /* size */ | |
74 put_tag(pb, "stco"); | |
75 put_be32(pb, 0); /* version & flags */ | |
76 put_be32(pb, track->entry); /* entry count */ | |
77 for (i=0; i<track->entry; i++) { | |
78 int cl = i / MOV_INDEX_CLUSTER_SIZE; | |
79 int id = i % MOV_INDEX_CLUSTER_SIZE; | |
80 put_be32(pb, track->cluster[cl][id].pos); | |
81 } | |
82 return 16+track->entry*4; | |
83 } | |
84 | |
85 int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track) | |
86 { | |
87 int i, size; | |
88 | |
89 if(track->cluster[0][0].entries != 0) | |
90 size = 20; | |
91 else | |
92 size = 20+track->samples*4; | |
93 put_be32(pb, size); /* size */ | |
94 put_tag(pb, "stsz"); | |
95 put_be32(pb, 0); /* version & flags */ | |
96 | |
97 /* TODO: Ugly (and false) assumption: if we have a chunk of samples, assume | |
98 * all sizes are same */ | |
99 if(track->cluster[0][0].entries != 0) { | |
100 int sSize = track->cluster[0][0].len/track->cluster[0][0].entries; | |
101 put_be32(pb, sSize); /* sample size */ | |
102 put_be32(pb, track->samples); /* sample count */ | |
103 } | |
104 else | |
105 { | |
106 put_be32(pb, 0); /* sample size */ | |
107 put_be32(pb, track->samples); /* sample count */ | |
108 for (i=0; i<track->samples; i++) { | |
109 int cl = i / MOV_INDEX_CLUSTER_SIZE; | |
110 int id = i % MOV_INDEX_CLUSTER_SIZE; | |
111 put_be32(pb, track->cluster[cl][id].len); | |
112 } | |
113 } | |
114 return size; | |
115 } | |
116 | |
117 int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track) | |
118 { | |
119 int size; | |
120 if(track->cluster[0][0].entries != 0) | |
121 size = 16+track->entry*4*3; | |
122 else | |
123 size = 0x1c; | |
124 put_be32(pb, size); // size | |
125 put_tag(pb, "stsc"); | |
126 put_be32(pb, 0); // version & flags | |
127 if(track->cluster[0][0].entries != 0) { | |
128 int i; | |
129 put_be32(pb, track->entry); // entry count | |
130 for (i=0; i<track->entry; i++) { | |
131 int cl = i / MOV_INDEX_CLUSTER_SIZE; | |
132 int id = i % MOV_INDEX_CLUSTER_SIZE; | |
133 put_be32(pb, i+1); // first chunk | |
134 put_be32(pb, track->cluster[cl][id].entries); | |
135 put_be32(pb, 0x1); // sample description index | |
136 } | |
137 } | |
138 else { | |
139 put_be32(pb, 1); // entry count | |
140 put_be32(pb, 0x1); // first chunk | |
141 put_be32(pb, 0x1); // samples per chunk | |
142 put_be32(pb, 0x1); // sample description index | |
143 } | |
144 | |
145 return size; | |
146 } | |
147 | |
148 int mov_write_stss_tag(ByteIOContext *pb) //TRA OK | |
149 { | |
150 put_be32(pb, 0x14); /* size */ | |
151 put_tag(pb, "stss"); | |
152 put_be32(pb, 0); /* version & flags */ | |
153 put_be32(pb, 1); /* entry count */ | |
154 put_be32(pb, 0x1); /* sample number */ | |
155 return 0x14; | |
156 } | |
157 | |
158 int mov_write_damr_tag(ByteIOContext *pb) | |
159 { | |
160 put_be32(pb, 0x11); /* size */ | |
161 put_tag(pb, "damr"); | |
162 put_tag(pb, "FFMP"); | |
163 put_byte(pb, 0); | |
164 put_be16(pb, 0x81ff); /* Mode set (all modes for AMR_NB) */ | |
165 put_be16(pb, 1); /* Mode change period (no restriction) */ | |
166 return 0x11; | |
167 } | |
168 | |
169 int mov_write_samr_tag(ByteIOContext *pb, MOVTrack* track) | |
170 { | |
171 int size = 0x24; | |
172 int pos; | |
173 pos = url_ftell(pb); | |
174 put_be32(pb, 0); /* size */ | |
175 /* "samr" for AMR NB, "sawb" for AMR WB */ | |
176 put_tag(pb, "samr"); | |
177 put_be32(pb, 0); /* Reserved */ | |
178 put_be16(pb, 0); /* Reserved */ | |
179 put_be16(pb, 1); /* Data-reference index, XXX == 1 */ | |
180 put_be32(pb, 0); /* Reserved */ | |
181 put_be32(pb, 0); /* Reserved */ | |
182 | |
183 put_be16(pb, 2); /* Reserved */ | |
184 put_be16(pb, 0x10); /* Reserved */ | |
185 put_be32(pb, 0); /* Reserved */ | |
186 put_be16(pb, track->timescale); /* Time scale */ | |
187 put_be16(pb, 0); /* Reserved */ | |
188 | |
189 size += mov_write_damr_tag(pb); | |
190 writeSize (pb, pos, size); | |
191 return size; | |
192 } | |
193 | |
194 int mov_write_d263_tag(ByteIOContext *pb) | |
195 { | |
196 put_be32(pb, 0xf); /* size */ | |
197 put_tag(pb, "d263"); | |
198 put_tag(pb, "FFMP"); | |
199 put_be16(pb, 0x0a); | |
200 put_byte(pb, 0); | |
201 return 0xf; | |
202 } | |
203 | |
204 int mov_write_s263_tag(ByteIOContext *pb, MOVTrack* track) | |
205 { | |
206 int size = 0x56; | |
207 int pos; | |
208 pos = url_ftell(pb); | |
209 put_be32(pb, 0); /* size */ | |
210 put_tag(pb, "s263"); | |
211 put_be32(pb, 0); /* Reserved */ | |
212 put_be16(pb, 0); /* Reserved */ | |
213 put_be16(pb, 1); /* Data-reference index */ | |
214 put_be32(pb, 0); /* Reserved */ | |
215 put_be32(pb, 0); /* Reserved */ | |
216 put_be32(pb, 0); /* Reserved */ | |
217 put_be32(pb, 0); /* Reserved */ | |
218 put_be16(pb, track->enc->width); /* Video width */ | |
219 put_be16(pb, track->enc->height); /* Video height */ | |
220 put_be32(pb, 0x00480000); /* Reserved */ | |
221 put_be32(pb, 0x00480000); /* Reserved */ | |
222 put_be32(pb, 0); /* Reserved */ | |
223 put_be16(pb, 1); /* Reserved */ | |
224 put_be32(pb, 0); /* Reserved */ | |
225 put_be32(pb, 0); /* Reserved */ | |
226 put_be32(pb, 0); /* Reserved */ | |
227 put_be32(pb, 0); /* Reserved */ | |
228 put_be32(pb, 0); /* Reserved */ | |
229 put_be32(pb, 0); /* Reserved */ | |
230 put_be32(pb, 0); /* Reserved */ | |
231 put_be32(pb, 0); /* Reserved */ | |
232 put_be16(pb, 0x18); /* Reserved */ | |
233 put_be16(pb, 0xffff); /* Reserved */ | |
234 size += mov_write_d263_tag(pb); | |
235 writeSize (pb, pos, size); | |
236 return size; | |
237 } | |
238 | |
239 static unsigned int esdsLength(unsigned int len) | |
240 { | |
241 unsigned int result = 0; | |
242 unsigned char b = len & 0x7f; | |
243 result += b; | |
244 b = (len >> 8) & 0x7f; | |
245 result += (b + 0x80) << 8; | |
246 b = (len >> 16) & 0x7f; | |
247 result += (b + 0x80) << 16; | |
248 b = (len >> 24) & 0x7f; | |
249 result += (b + 0x80) << 24; | |
250 return result; | |
251 } | |
252 | |
253 int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic | |
254 { | |
255 put_be32(pb, track->vosLen+18+14+17); | |
256 put_tag(pb, "esds"); | |
257 put_be32(pb, 0); // Version | |
258 | |
259 put_byte(pb, 0x03); // tag = ES_DescriptorTag | |
260 put_be32(pb, esdsLength(track->vosLen+18+14)); // Length | |
261 put_be16(pb, 0x0001); // ID (= 1) | |
262 put_byte(pb, 0x00); // flags (= no flags) | |
263 | |
264 // Decoderconfigdescriptor = 4 | |
265 put_byte(pb, 0x04); // tag = DecoderConfigDescriptor | |
266 put_be32(pb, esdsLength(track->vosLen+18)); // Length | |
267 put_byte(pb, 0x20); // Object type indication (Visual 14496-2) | |
268 put_byte(pb, 0x11); // flags (= Visualstream) | |
269 put_byte(pb, 0x0); // Buffersize DB (24 bits) | |
270 put_be16(pb, 0x0dd2); // Buffersize DB | |
271 | |
272 // TODO: find real values for these | |
273 put_be32(pb, 0x0002e918); // maxbitrate | |
274 put_be32(pb, 0x00017e6b); // avg bitrate | |
275 | |
276 // Decoderspecific info Tag = 5 | |
277 put_byte(pb, 0x05); // tag = Decoderspecific info | |
278 put_be32(pb, esdsLength(track->vosLen)); // length | |
279 put_buffer(pb, track->vosData, track->vosLen); | |
280 | |
281 put_byte(pb, 0x06); | |
282 put_be32(pb, esdsLength(1)); // length | |
283 put_byte(pb, 0x02); | |
284 return track->vosLen+18+14+17; | |
285 } | |
286 | |
287 int mov_write_mp4v_tag(ByteIOContext *pb, MOVTrack* track) // Basic | |
288 { | |
289 put_be32(pb, 194); | |
290 put_tag(pb, "mp4v"); | |
291 put_be32(pb, 0); // Reserved | |
292 put_be16(pb, 0); // Reserved | |
293 put_be16(pb, 1); // Data-reference index | |
294 put_be32(pb, 0); // Reserved | |
295 put_be32(pb, 0); // Reserved | |
296 put_be32(pb, 0); // Reserved | |
297 put_be32(pb, 0); // Reserved | |
298 put_be16(pb, track->enc->width); // Width | |
299 put_be16(pb, track->enc->height); // Height | |
300 put_be32(pb, 0x00480000); // Reserved | |
301 put_be32(pb, 0x00480000); // Reserved | |
302 put_be32(pb, 0); // Reserved | |
303 put_be16(pb, 1); // Reserved | |
304 put_be32(pb, 0); // Reserved | |
305 put_be32(pb, 0); // Reserved | |
306 put_be32(pb, 0); // Reserved | |
307 put_be32(pb, 0); // Reserved | |
308 put_be32(pb, 0); // Reserved | |
309 put_be32(pb, 0); // Reserved | |
310 put_be32(pb, 0); // Reserved | |
311 put_be32(pb, 0); // Reserved | |
312 put_be16(pb, 24); // Reserved | |
313 put_be16(pb, 0xFFFF); // Reserved | |
314 mov_write_esds_tag(pb, track); | |
315 return 194; | |
316 } | |
317 | |
318 int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track) | |
319 { | |
320 int size = 16; | |
321 int pos; | |
322 pos = url_ftell(pb); | |
323 put_be32(pb, 0); /* size */ | |
324 put_tag(pb, "stsd"); | |
325 put_be32(pb, 0); /* version & flags */ | |
326 put_be32(pb, 1); /* entry count */ | |
327 if (track->enc->codec_type == CODEC_TYPE_VIDEO) { | |
328 if (track->enc->codec_id == CODEC_ID_H263) | |
329 size += mov_write_s263_tag(pb, track); | |
330 else if (track->enc->codec_id == CODEC_ID_MPEG4) | |
331 size += mov_write_mp4v_tag(pb, track); | |
332 } | |
333 else if (track->enc->codec_type == CODEC_TYPE_AUDIO) { | |
334 if (track->enc->codec_id == CODEC_ID_AMR_NB) | |
335 size += mov_write_samr_tag(pb, track); | |
336 } | |
337 writeSize (pb, pos, size); | |
338 return size; | |
339 } | |
340 | |
341 int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track) | |
342 { | |
343 put_be32(pb, 0x18); /* size */ | |
344 put_tag(pb, "stts"); | |
345 put_be32(pb, 0); /* version & flags */ | |
346 put_be32(pb, 1); /* entry count */ | |
347 | |
348 put_be32(pb, track->samples); /* sample count */ | |
349 put_be32(pb, track->sampleDelta); /* sample delta */ | |
350 return 0x18; | |
351 } | |
352 | |
353 int mov_write_dref_tag(ByteIOContext *pb) | |
354 { | |
355 put_be32(pb, 28); /* size */ | |
356 put_tag(pb, "dref"); | |
357 put_be32(pb, 0); /* version & flags */ | |
358 put_be32(pb, 1); /* entry count */ | |
359 | |
360 put_be32(pb, 0xc); /* size */ | |
361 put_tag(pb, "url "); | |
362 put_be32(pb, 1); /* version & flags */ | |
363 | |
364 return 28; | |
365 } | |
366 | |
367 int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track) | |
368 { | |
369 int size = 8; | |
370 int pos; | |
371 pos = url_ftell(pb); | |
372 put_be32(pb, 0); /* size */ | |
373 put_tag(pb, "stbl"); | |
374 size += mov_write_stsd_tag(pb, track); | |
375 size += mov_write_stts_tag(pb, track); | |
376 if (track->enc->codec_type == CODEC_TYPE_VIDEO) | |
377 size += mov_write_stss_tag(pb); | |
378 size += mov_write_stsc_tag(pb, track); | |
379 size += mov_write_stsz_tag(pb, track); | |
380 size += mov_write_stco_tag(pb, track); | |
381 writeSize (pb, pos, size); | |
382 return size; | |
383 } | |
384 | |
385 int mov_write_dinf_tag(ByteIOContext *pb) | |
386 { | |
387 int size = 8; | |
388 int pos; | |
389 pos = url_ftell(pb); | |
390 put_be32(pb, 0); /* size */ | |
391 put_tag(pb, "dinf"); | |
392 size += mov_write_dref_tag(pb); | |
393 writeSize (pb, pos, size); | |
394 return size; | |
395 } | |
396 | |
397 int mov_write_smhd_tag(ByteIOContext *pb) | |
398 { | |
399 put_be32(pb, 16); /* size */ | |
400 put_tag(pb, "smhd"); | |
401 put_be32(pb, 0); /* version & flags */ | |
402 put_be16(pb, 0); /* reserved (balance, normally = 0) */ | |
403 put_be16(pb, 0); /* reserved */ | |
404 return 16; | |
405 } | |
406 | |
407 int mov_write_vmhd_tag(ByteIOContext *pb) | |
408 { | |
409 put_be32(pb, 0x14); /* size (always 0x14) */ | |
410 put_tag(pb, "vmhd"); | |
411 put_be32(pb, 0x01); /* version & flags */ | |
412 put_be64(pb, 0); /* reserved (graphics mode = copy) */ | |
413 return 0x14; | |
414 } | |
415 | |
416 int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track) | |
417 { | |
418 int size = 8; | |
419 int pos; | |
420 pos = url_ftell(pb); | |
421 put_be32(pb, 0); /* size */ | |
422 put_tag(pb, "minf"); | |
423 if(track->enc->codec_type == CODEC_TYPE_VIDEO) | |
424 size += mov_write_vmhd_tag(pb); | |
425 else | |
426 size += mov_write_smhd_tag(pb); | |
427 size += mov_write_dinf_tag(pb); | |
428 size += mov_write_stbl_tag(pb, track); | |
429 writeSize (pb, pos, size); | |
430 return size; | |
431 } | |
432 | |
433 int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track) | |
434 { | |
435 int size = 0; | |
436 size = 45; | |
437 put_be32(pb, size); /* size */ | |
438 put_tag(pb, "hdlr"); | |
439 put_be32(pb, 0); /* Version & flags */ | |
440 put_be32(pb, 0); /* reserved */ | |
441 if(track->enc->codec_type == CODEC_TYPE_VIDEO) | |
442 put_tag(pb, "vide"); /* handler type */ | |
443 else | |
444 put_tag(pb, "soun"); /* handler type */ | |
445 put_byte(pb, 0); /* reserved */ | |
446 put_byte(pb, 0); /* reserved */ | |
447 put_byte(pb, 0); /* reserved */ | |
448 put_byte(pb, 0); /* reserved */ | |
449 put_byte(pb, 0); /* reserved */ | |
450 put_byte(pb, 0); /* reserved */ | |
451 put_byte(pb, 0); /* reserved */ | |
452 put_byte(pb, 0); /* reserved */ | |
453 put_byte(pb, 0); /* reserved */ | |
454 put_byte(pb, 0); /* reserved */ | |
455 put_byte(pb, 0); /* reserved */ | |
456 put_byte(pb, 0); /* reserved */ | |
457 if(track->enc->codec_type == CODEC_TYPE_VIDEO) | |
458 put_buffer(pb, "VideoHandler", 13); | |
459 else | |
460 put_buffer(pb, "SoundHandler", 13); | |
461 return size; | |
462 } | |
463 | |
464 int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track) | |
465 { | |
466 put_be32(pb, 32); /* size */ | |
467 put_tag(pb, "mdhd"); | |
468 put_be32(pb, 0); /* Version & flags */ | |
469 put_be32(pb, track->time); /* creation time */ | |
470 put_be32(pb, track->time); /* modification time */ | |
471 put_be32(pb, track->timescale); /* time scale */ | |
472 | |
473 put_be32(pb, track->timescale*track->entry*track->frameDuration/globalTimescale); /* duration */ | |
474 put_be16(pb, 0); /* language, 0 = english */ | |
475 put_be16(pb, 0); /* reserved (quality) */ | |
476 return 32; | |
477 } | |
478 | |
479 int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track) | |
480 { | |
481 int size = 8; | |
482 int pos; | |
483 pos = url_ftell(pb); | |
484 put_be32(pb, 0); /* size */ | |
485 put_tag(pb, "mdia"); | |
486 size += mov_write_mdhd_tag(pb, track); | |
487 size += mov_write_hdlr_tag(pb, track); | |
488 size += mov_write_minf_tag(pb, track); | |
489 writeSize (pb, pos, size); | |
490 return size; | |
491 } | |
492 | |
493 int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track) | |
494 { | |
495 put_be32(pb, 0x5c); /* size (always 0x5c) */ | |
496 put_tag(pb, "tkhd"); | |
497 put_be32(pb, 1); /* version & flags (track enabled) */ | |
498 put_be32(pb, track->time); /* creation time */ | |
499 put_be32(pb, track->time); /* modification time */ | |
500 put_be32(pb, track->trackID); /* track-id */ | |
501 put_be32(pb, 0); /* reserved */ | |
502 put_be32(pb, track->entry*track->frameDuration); /* duration */ | |
503 | |
504 put_be32(pb, 0); /* reserved */ | |
505 put_be32(pb, 0); /* reserved */ | |
506 put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */ | |
507 /* Volume, only for audio */ | |
508 if(track->enc->codec_type == CODEC_TYPE_AUDIO) | |
509 put_be16(pb, 0x0100); | |
510 else | |
511 put_be16(pb, 0); | |
512 put_be16(pb, 0); /* reserved */ | |
513 | |
514 /* Matrix structure */ | |
515 put_be32(pb, 0x00010000); /* reserved */ | |
516 put_be32(pb, 0x0); /* reserved */ | |
517 put_be32(pb, 0x0); /* reserved */ | |
518 put_be32(pb, 0x0); /* reserved */ | |
519 put_be32(pb, 0x00010000); /* reserved */ | |
520 put_be32(pb, 0x0); /* reserved */ | |
521 put_be32(pb, 0x0); /* reserved */ | |
522 put_be32(pb, 0x0); /* reserved */ | |
523 put_be32(pb, 0x40000000); /* reserved */ | |
524 | |
525 /* Track width and height, for visual only */ | |
526 if(track->enc->codec_type == CODEC_TYPE_VIDEO) { | |
527 put_be32(pb, 0x01400000); | |
528 put_be32(pb, 0x00f00000); | |
529 } | |
530 else { | |
531 put_be32(pb, 0); | |
532 put_be32(pb, 0); | |
533 } | |
534 return 0x5c; | |
535 } | |
536 | |
537 int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track) | |
538 { | |
539 int size = 8; | |
540 int pos; | |
541 pos = url_ftell(pb); | |
542 put_be32(pb, 0); /* size */ | |
543 put_tag(pb, "trak"); | |
544 size += mov_write_tkhd_tag(pb, track); | |
545 size += mov_write_mdia_tag(pb, track); | |
546 writeSize (pb, pos, size); | |
547 return size; | |
548 } | |
549 | |
550 /* TODO: Not sorted out, but not necessary either */ | |
551 int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov) | |
552 { | |
553 put_be32(pb, 0x15); /* size */ | |
554 put_tag(pb, "iods"); | |
555 put_be32(pb, 0); /* version & flags */ | |
556 put_be16(pb, 0x1007); | |
557 put_byte(pb, 0); | |
558 put_be16(pb, 0x4fff); | |
559 put_be16(pb, 0xfffe); | |
560 put_be16(pb, 0x01ff); | |
561 return 0x15; | |
562 } | |
563 | |
564 int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov) | |
565 { | |
566 int maxTrackID = 1, maxTrackLen = 0, i; | |
567 | |
568 put_be32(pb, 0x6c); /* size (always 0x6c) */ | |
569 put_tag(pb, "mvhd"); | |
570 put_be32(pb, 0); /* version & flags */ | |
571 put_be32(pb, mov->time); /* creation time */ | |
572 put_be32(pb, mov->time); /* modification time */ | |
573 put_be32(pb, mov->timescale); /* timescale */ | |
574 for (i=0; i<MAX_STREAMS; i++) { | |
575 if(mov->tracks[i].entry > 0) { | |
576 if(maxTrackLen < mov->tracks[i].entry*mov->tracks[i].frameDuration) | |
577 maxTrackLen = mov->tracks[i].entry*mov->tracks[i].frameDuration; | |
578 if(maxTrackID < mov->tracks[i].trackID) | |
579 maxTrackID = mov->tracks[i].trackID; | |
580 } | |
581 } | |
582 put_be32(pb, maxTrackLen); /* duration of longest track */ | |
583 | |
584 put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */ | |
585 put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */ | |
586 put_be16(pb, 0); /* reserved */ | |
587 put_be32(pb, 0); /* reserved */ | |
588 put_be32(pb, 0); /* reserved */ | |
589 | |
590 /* Matrix structure */ | |
591 put_be32(pb, 0x00010000); /* reserved */ | |
592 put_be32(pb, 0x0); /* reserved */ | |
593 put_be32(pb, 0x0); /* reserved */ | |
594 put_be32(pb, 0x0); /* reserved */ | |
595 put_be32(pb, 0x00010000); /* reserved */ | |
596 put_be32(pb, 0x0); /* reserved */ | |
597 put_be32(pb, 0x0); /* reserved */ | |
598 put_be32(pb, 0x0); /* reserved */ | |
599 put_be32(pb, 0x40000000); /* reserved */ | |
600 | |
601 put_be32(pb, 0); /* reserved (preview time) */ | |
602 put_be32(pb, 0); /* reserved (preview duration) */ | |
603 put_be32(pb, 0); /* reserved (poster time) */ | |
604 put_be32(pb, 0); /* reserved (selection time) */ | |
605 put_be32(pb, 0); /* reserved (selection duration) */ | |
606 put_be32(pb, 0); /* reserved (current time) */ | |
607 put_be32(pb, maxTrackID+1); /* Next track id */ | |
608 return 0x6c; | |
609 } | |
610 | |
611 int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov) | |
612 { | |
613 int pos, size = 8, i; | |
614 pos = url_ftell(pb); | |
615 put_be32(pb, 0); /* size placeholder*/ | |
616 put_tag(pb, "moov"); | |
617 mov->timescale = globalTimescale; | |
618 | |
619 for (i=0; i<MAX_STREAMS; i++) { | |
620 if(mov->tracks[i].entry > 0) { | |
621 if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) { | |
622 mov->tracks[i].timescale = globalTimescale; | |
623 mov->tracks[i].sampleDelta = mov->tracks[i].frameDuration = | |
624 globalTimescale*mov->tracks[i].enc->frame_rate_base/mov->tracks[i].enc->frame_rate; | |
625 } | |
626 else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) { | |
627 /* If AMR, track timescale = 8000, AMR_WB = 16000 */ | |
628 if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) { | |
629 mov->tracks[i].frameDuration = 20; | |
630 mov->tracks[i].sampleDelta = 160; | |
631 mov->tracks[i].timescale = 8000; | |
632 } | |
633 else { | |
634 mov->tracks[i].timescale = globalTimescale; | |
635 mov->tracks[i].frameDuration = | |
636 globalTimescale*mov->tracks[i].enc->frame_rate_base/mov->tracks[i].enc->frame_rate; | |
637 } | |
638 } | |
639 mov->tracks[i].time = mov->time; | |
640 mov->tracks[i].trackID = i+1; | |
641 } | |
642 } | |
643 | |
644 size += mov_write_mvhd_tag(pb, mov); | |
645 //size += mov_write_iods_tag(pb, mov); | |
646 for (i=0; i<MAX_STREAMS; i++) { | |
647 if(mov->tracks[i].entry > 0) { | |
648 size += mov_write_trak_tag(pb, &(mov->tracks[i])); | |
649 } | |
650 } | |
651 | |
652 writeSize (pb, pos, size); | |
653 | |
654 return size; | |
655 } | |
656 | |
657 int mov_write_mdat_tag(ByteIOContext *pb, MOVTrack* track) | |
658 { | |
659 track->mdat_pos = url_ftell(pb); | |
660 put_be32(pb, 0); /* size placeholder*/ | |
661 put_tag(pb, "mdat"); | |
662 return 0; | |
663 } | |
664 | |
665 /* TODO: This needs to be more general */ | |
666 int mov_write_ftyp_tag(ByteIOContext *pb) | |
667 { | |
668 put_be32(pb, 0x14 ); /* size */ | |
669 put_tag(pb, "ftyp"); | |
670 put_tag(pb, "3gp4"); | |
671 put_be32(pb, 0x200 ); | |
672 put_tag(pb, "3gp4"); | |
673 return 0x14; | |
674 } | |
675 | |
676 static int mov_write_header(AVFormatContext *s) | |
677 { | |
678 ByteIOContext *pb = &s->pb; | |
679 | |
680 /* write ftyp */ | |
681 mov_write_ftyp_tag(pb); | |
682 | |
683 put_flush_packet(pb); | |
684 | |
685 return 0; | |
686 } | |
687 | |
688 static int Timestamp() { | |
689 time_t ltime; | |
690 time ( <ime ); | |
691 return ltime+(24107*86400); | |
692 } | |
693 | |
694 static int mov_write_packet(AVFormatContext *s, int stream_index, | |
695 uint8_t *buf, int size, int force_pts) | |
696 { | |
697 MOVContext *mov = s->priv_data; | |
698 ByteIOContext *pb = &s->pb; | |
699 AVCodecContext *enc; | |
700 | |
701 enc = &s->streams[stream_index]->codec; | |
702 if (!url_is_streamed(&s->pb)) { | |
703 MOVTrack* trk = &mov->tracks[stream_index]; | |
704 int sampleCount = 0; | |
705 | |
706 /* We must find out how many AMR blocks there are in one packet */ | |
707 if(enc->codec_type == CODEC_TYPE_AUDIO && | |
708 enc->codec_id == CODEC_ID_AMR_NB) { | |
709 static uint16_t packed_size[16] = {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0}; | |
710 int len = 0; | |
711 | |
712 while(len < size && sampleCount < 100) { | |
713 len += packed_size[(buf[len] >> 3) & 0x0F]; | |
714 sampleCount++; | |
715 } | |
716 } | |
717 /* TODO: Is there some other way to get VOS block from MPEG4 stream? */ | |
718 if(enc->codec_type == CODEC_TYPE_VIDEO && | |
719 enc->codec_id == CODEC_ID_MPEG4 && | |
720 trk->vosLen == 0) | |
721 { | |
722 int index = 0; | |
723 int vosStart = 0; | |
724 while(index < size) { | |
725 if(buf[index] == 0 && buf[index+1] == 0 && buf[index+2] == 1) { | |
726 index+=3; | |
727 if(buf[index] == 0xB6) { | |
728 if(vosStart != 0) { | |
729 trk->vosLen = index-3 - (vosStart-3); | |
730 trk->vosData = av_malloc(trk->vosLen+2); | |
731 memcpy(trk->vosData, (char *)&buf[vosStart-3], trk->vosLen); | |
732 break; | |
733 } | |
734 } | |
735 else if(buf[index] == 0xb0) { | |
736 vosStart = index; | |
737 } | |
738 } | |
739 index++; | |
740 } | |
741 } | |
742 | |
743 int cl = trk->entry / MOV_INDEX_CLUSTER_SIZE; | |
744 int id = trk->entry % MOV_INDEX_CLUSTER_SIZE; | |
745 | |
746 if (trk->ents_allocated <= trk->entry) { | |
747 trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*)); | |
748 if (!trk->cluster) | |
749 return -1; | |
750 trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry)); | |
751 if (!trk->cluster[cl]) | |
752 return -1; | |
753 trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE; | |
754 } | |
755 if(stream_index == 0 && trk->entry == 0) { | |
756 mov_write_mdat_tag(pb, trk); | |
757 mov->time = Timestamp(); | |
758 } | |
759 trk->cluster[cl][id].pos = url_ftell(pb) - mov->movi_list; | |
760 trk->cluster[cl][id].len = size; | |
761 trk->cluster[cl][id].entries = sampleCount; | |
762 trk->enc = enc; | |
763 trk->entry++; | |
764 if(sampleCount == 0) | |
765 trk->samples++; | |
766 else | |
767 trk->samples += sampleCount; | |
768 trk->mdat_size += size; | |
769 } | |
770 put_buffer(pb, buf, size); | |
771 | |
772 put_flush_packet(pb); | |
773 return 0; | |
774 } | |
775 | |
776 static int mov_write_trailer(AVFormatContext *s) | |
777 { | |
778 MOVContext *mov = s->priv_data; | |
779 ByteIOContext *pb = &s->pb; | |
780 int res = 0; | |
781 int i, j; | |
782 offset_t file_size; | |
783 | |
784 file_size = url_ftell(pb); | |
785 j = 0; | |
786 | |
787 /* Write size of mdat tag */ | |
788 for (i=0; i<MAX_STREAMS; i++) { | |
789 if(mov->tracks[i].ents_allocated > 0) { | |
790 j += mov->tracks[i].mdat_size; | |
791 } | |
792 } | |
793 url_fseek(pb, mov->tracks[0].mdat_pos, SEEK_SET); | |
794 put_be32(pb, j+8); | |
795 url_fseek(pb, file_size, SEEK_SET); | |
796 | |
797 mov_write_moov_tag(pb, mov); | |
798 | |
799 for (i=0; i<MAX_STREAMS; i++) { | |
800 for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) { | |
801 av_free(mov->tracks[i].cluster[j]); | |
802 } | |
803 av_free(mov->tracks[i].cluster); | |
804 mov->tracks[i].cluster = NULL; | |
805 mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0; | |
806 } | |
807 put_flush_packet(pb); | |
808 | |
809 return res; | |
810 } | |
811 | |
812 static AVOutputFormat mov_oformat = { | |
813 "mov", | |
814 "mov format", | |
815 NULL, | |
816 "mov", | |
817 sizeof(MOVContext), | |
818 CODEC_ID_MP2, | |
819 CODEC_ID_SVQ1, | |
820 mov_write_header, | |
821 mov_write_packet, | |
822 mov_write_trailer, | |
823 }; | |
824 | |
825 static AVOutputFormat _3gp_oformat = { | |
826 "3gp", | |
827 "3gp format", | |
828 NULL, | |
829 "3gp", | |
830 sizeof(MOVContext), | |
831 CODEC_ID_AMR_NB, | |
832 CODEC_ID_H263, | |
833 mov_write_header, | |
834 mov_write_packet, | |
835 mov_write_trailer, | |
836 }; | |
837 | |
838 static AVOutputFormat mp4_oformat = { | |
839 "mp4", | |
840 "mp4 format", | |
841 NULL, | |
842 "mp4", | |
843 sizeof(MOVContext), | |
844 CODEC_ID_AAC, | |
845 CODEC_ID_MPEG4, | |
846 mov_write_header, | |
847 mov_write_packet, | |
848 mov_write_trailer, | |
849 }; | |
850 | |
851 int movenc_init(void) | |
852 { | |
853 av_register_output_format(&mov_oformat); | |
854 av_register_output_format(&_3gp_oformat); | |
855 av_register_output_format(&mp4_oformat); | |
856 return 0; | |
857 } |