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 ( &ltime );
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 }