removed warnings
[libav.git] / libavformat / movenc.c
CommitLineData
1cb5f7fd
MN
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
31typedef struct MOVIentry {
32 unsigned int flags, pos, len;
33 unsigned int entries;
34} MOVIentry;
35
36typedef 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
54typedef struct {
55 long time;
56 int nb_streams;
57 offset_t movi_list;
58 long timescale;
59 MOVTrack tracks[MAX_STREAMS];
60} MOVContext;
61
62void 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
70int 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
85int 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
117int 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
148int 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
158int 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
169int 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
194int 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
204int 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
239static 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
253int 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
287int 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
318int 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
341int 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
353int 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
367int 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
385int 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
397int 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
407int 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
416int 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
433int 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
464int 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
479int 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
493int 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
537int 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 */
551int 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
564int 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
611int 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
657int 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 */
666int 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
676static 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
688static int Timestamp() {
689 time_t ltime;
690 time ( &ltime );
691 return ltime+(24107*86400);
692}
693
694static 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;
1a31840c 700 int cl, id;
1cb5f7fd
MN
701
702 enc = &s->streams[stream_index]->codec;
703 if (!url_is_streamed(&s->pb)) {
704 MOVTrack* trk = &mov->tracks[stream_index];
705 int sampleCount = 0;
706
707 /* We must find out how many AMR blocks there are in one packet */
708 if(enc->codec_type == CODEC_TYPE_AUDIO &&
709 enc->codec_id == CODEC_ID_AMR_NB) {
710 static uint16_t packed_size[16] = {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
711 int len = 0;
712
713 while(len < size && sampleCount < 100) {
714 len += packed_size[(buf[len] >> 3) & 0x0F];
715 sampleCount++;
716 }
717 }
718 /* TODO: Is there some other way to get VOS block from MPEG4 stream? */
719 if(enc->codec_type == CODEC_TYPE_VIDEO &&
720 enc->codec_id == CODEC_ID_MPEG4 &&
721 trk->vosLen == 0)
722 {
723 int index = 0;
724 int vosStart = 0;
725 while(index < size) {
726 if(buf[index] == 0 && buf[index+1] == 0 && buf[index+2] == 1) {
727 index+=3;
728 if(buf[index] == 0xB6) {
729 if(vosStart != 0) {
730 trk->vosLen = index-3 - (vosStart-3);
731 trk->vosData = av_malloc(trk->vosLen+2);
732 memcpy(trk->vosData, (char *)&buf[vosStart-3], trk->vosLen);
733 break;
734 }
735 }
736 else if(buf[index] == 0xb0) {
737 vosStart = index;
738 }
739 }
740 index++;
741 }
742 }
743
1a31840c
MM
744 cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
745 id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
1cb5f7fd
MN
746
747 if (trk->ents_allocated <= trk->entry) {
748 trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*));
749 if (!trk->cluster)
750 return -1;
751 trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
752 if (!trk->cluster[cl])
753 return -1;
754 trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
755 }
756 if(stream_index == 0 && trk->entry == 0) {
757 mov_write_mdat_tag(pb, trk);
758 mov->time = Timestamp();
759 }
760 trk->cluster[cl][id].pos = url_ftell(pb) - mov->movi_list;
761 trk->cluster[cl][id].len = size;
762 trk->cluster[cl][id].entries = sampleCount;
763 trk->enc = enc;
764 trk->entry++;
765 if(sampleCount == 0)
766 trk->samples++;
767 else
768 trk->samples += sampleCount;
769 trk->mdat_size += size;
770 }
771 put_buffer(pb, buf, size);
772
773 put_flush_packet(pb);
774 return 0;
775}
776
777static int mov_write_trailer(AVFormatContext *s)
778{
779 MOVContext *mov = s->priv_data;
780 ByteIOContext *pb = &s->pb;
781 int res = 0;
782 int i, j;
783 offset_t file_size;
784
785 file_size = url_ftell(pb);
786 j = 0;
787
788 /* Write size of mdat tag */
789 for (i=0; i<MAX_STREAMS; i++) {
790 if(mov->tracks[i].ents_allocated > 0) {
791 j += mov->tracks[i].mdat_size;
792 }
793 }
794 url_fseek(pb, mov->tracks[0].mdat_pos, SEEK_SET);
795 put_be32(pb, j+8);
796 url_fseek(pb, file_size, SEEK_SET);
797
798 mov_write_moov_tag(pb, mov);
799
800 for (i=0; i<MAX_STREAMS; i++) {
801 for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
802 av_free(mov->tracks[i].cluster[j]);
803 }
804 av_free(mov->tracks[i].cluster);
805 mov->tracks[i].cluster = NULL;
806 mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
807 }
808 put_flush_packet(pb);
809
810 return res;
811}
812
813static AVOutputFormat mov_oformat = {
814 "mov",
815 "mov format",
816 NULL,
817 "mov",
818 sizeof(MOVContext),
819 CODEC_ID_MP2,
820 CODEC_ID_SVQ1,
821 mov_write_header,
822 mov_write_packet,
823 mov_write_trailer,
824};
825
826static AVOutputFormat _3gp_oformat = {
827 "3gp",
828 "3gp format",
829 NULL,
830 "3gp",
831 sizeof(MOVContext),
832 CODEC_ID_AMR_NB,
833 CODEC_ID_H263,
834 mov_write_header,
835 mov_write_packet,
836 mov_write_trailer,
837};
838
839static AVOutputFormat mp4_oformat = {
840 "mp4",
841 "mp4 format",
842 NULL,
843 "mp4",
844 sizeof(MOVContext),
845 CODEC_ID_AAC,
846 CODEC_ID_MPEG4,
847 mov_write_header,
848 mov_write_packet,
849 mov_write_trailer,
850};
851
852int movenc_init(void)
853{
854 av_register_output_format(&mov_oformat);
855 av_register_output_format(&_3gp_oformat);
856 av_register_output_format(&mp4_oformat);
857 return 0;
858}