2 * MOV, 3GP, MP4 encoder.
3 * Copyright (c) 2003 Thomas Raivio.
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.
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.
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
27 #define MOV_INDEX_CLUSTER_SIZE 16384
28 #define globalTimescale 1000
30 typedef struct MOVIentry {
31 unsigned int flags, pos, len;
32 unsigned int chunkSize;
37 typedef struct MOVIndex {
63 MOVTrack tracks[MAX_STREAMS];
66 //FIXME supprt 64bit varaint with wide placeholders
67 static int updateSize (ByteIOContext *pb, int pos)
69 long curpos = url_ftell(pb);
70 url_fseek(pb, pos, SEEK_SET);
71 put_be32(pb, curpos - pos); /* rewrite size */
72 url_fseek(pb, curpos, SEEK_SET);
77 static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track)
80 int pos = url_ftell(pb);
81 put_be32(pb, 0); /* size */
83 put_be32(pb, 0); /* version & flags */
84 put_be32(pb, track->entry); /* entry count */
85 for (i=0; i<track->entry; i++) {
86 int cl = i / MOV_INDEX_CLUSTER_SIZE;
87 int id = i % MOV_INDEX_CLUSTER_SIZE;
88 put_be32(pb, track->cluster[cl][id].pos);
90 return updateSize (pb, pos);
93 static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
96 int i, tst = -1, oldtst = -1;
98 int pos = url_ftell(pb);
99 put_be32(pb, 0); /* size */
101 put_be32(pb, 0); /* version & flags */
103 for (i=0; i<track->entry; i++) {
104 int cl = i / MOV_INDEX_CLUSTER_SIZE;
105 int id = i % MOV_INDEX_CLUSTER_SIZE;
106 tst = track->cluster[cl][id].len;
107 if(oldtst != -1 && tst != oldtst) {
114 track->enc->codec_type == CODEC_TYPE_AUDIO) {
115 //int sSize = track->cluster[0][0].len/track->cluster[0][0].entries;
116 int sSize = track->cluster[0][0].len;
117 put_be32(pb, sSize); // sample size
118 put_be32(pb, track->samples/track->enc->channels); // sample count
121 put_be32(pb, 0); // sample size
122 put_be32(pb, track->entry); // sample count
123 for (i=0; i<track->entry; i++) {
124 int cl = i / MOV_INDEX_CLUSTER_SIZE;
125 int id = i % MOV_INDEX_CLUSTER_SIZE;
126 put_be32(pb, track->cluster[cl][id].len);
129 return updateSize (pb, pos);
132 static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
134 int index = 0, oldval = -1, i, entryPos, curpos;
136 int pos = url_ftell(pb);
137 put_be32(pb, 0); /* size */
139 put_be32(pb, 0); // version & flags
140 entryPos = url_ftell(pb);
141 put_be32(pb, track->entry); // entry count
142 for (i=0; i<track->entry; i++) {
143 int cl = i / MOV_INDEX_CLUSTER_SIZE;
144 int id = i % MOV_INDEX_CLUSTER_SIZE;
145 if(oldval != track->cluster[cl][id].chunkSize)
147 put_be32(pb, i+1); // first chunk
148 put_be32(pb, track->cluster[cl][id].chunkSize);
149 put_be32(pb, 0x1); // sample description index
150 oldval = track->cluster[cl][id].chunkSize;
154 curpos = url_ftell(pb);
155 url_fseek(pb, entryPos, SEEK_SET);
156 put_be32(pb, index); // rewrite size
157 url_fseek(pb, curpos, SEEK_SET);
159 return updateSize (pb, pos);
162 static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track)
165 int i, index = 0, entryPos;
166 int pos = url_ftell(pb);
167 put_be32(pb, 0); // size
169 put_be32(pb, 0); // version & flags
170 entryPos = url_ftell(pb);
171 put_be32(pb, track->entry); // entry count
172 for (i=0; i<track->entry; i++) {
173 int cl = i / MOV_INDEX_CLUSTER_SIZE;
174 int id = i % MOV_INDEX_CLUSTER_SIZE;
175 if(track->cluster[cl][id].key_frame == 1) {
180 curpos = url_ftell(pb);
181 url_fseek(pb, entryPos, SEEK_SET);
182 put_be32(pb, index); // rewrite size
183 url_fseek(pb, curpos, SEEK_SET);
184 return updateSize (pb, pos);
187 static int mov_write_damr_tag(ByteIOContext *pb)
189 put_be32(pb, 0x11); /* size */
194 put_be16(pb, 0x80); /* Mode set (all modes for AMR_NB) */
195 put_be16(pb, 0xa); /* Mode change period (no restriction) */
196 //put_be16(pb, 0x81ff); /* Mode set (all modes for AMR_NB) */
197 //put_be16(pb, 1); /* Mode change period (no restriction) */
201 static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
203 int pos = url_ftell(pb);
204 put_be32(pb, 0); /* size */
206 if(track->enc->codec_id == CODEC_ID_PCM_MULAW)
208 else if(track->enc->codec_id == CODEC_ID_PCM_ALAW)
210 else if(track->enc->codec_id == CODEC_ID_ADPCM_IMA_QT)
212 else if(track->enc->codec_id == CODEC_ID_MACE3)
214 else if(track->enc->codec_id == CODEC_ID_MACE6)
216 else if(track->enc->codec_id == CODEC_ID_AAC)
218 else if(track->enc->codec_id == CODEC_ID_AMR_NB)
223 put_be32(pb, 0); /* Reserved */
224 put_be16(pb, 0); /* Reserved */
225 put_be16(pb, 1); /* Data-reference index, XXX == 1 */
226 put_be32(pb, 0); /* Reserved */
227 put_be32(pb, 0); /* Reserved */
229 put_be16(pb, track->enc->channels); /* Number of channels */
230 /* TODO: Currently hard-coded to 16-bit, there doesn't seem
231 to be a good way to get number of bits of audio */
232 put_be16(pb, 0x10); /* Reserved */
233 put_be16(pb, 0); /* compression ID (= 0) */
234 put_be16(pb, 0); /* packet size (= 0) */
235 put_be16(pb, track->timescale); /* Time scale */
236 put_be16(pb, 0); /* Reserved */
238 if(track->enc->codec_id == CODEC_ID_AMR_NB)
239 mov_write_damr_tag(pb);
240 return updateSize (pb, pos);
243 static int mov_write_d263_tag(ByteIOContext *pb)
245 put_be32(pb, 0xf); /* size */
253 /* TODO: No idea about these values */
254 static int mov_write_svq3_tag(ByteIOContext *pb)
260 put_be32(pb, 0xe2c0211d);
261 put_be32(pb, 0xc0000000);
266 static unsigned int esdsLength(unsigned int len)
268 unsigned int result = 0;
269 unsigned char b = len & 0x7f;
271 b = (len >> 8) & 0x7f;
272 result += (b + 0x80) << 8;
273 b = (len >> 16) & 0x7f;
274 result += (b + 0x80) << 16;
275 b = (len >> 24) & 0x7f;
276 result += (b + 0x80) << 24;
280 static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
282 put_be32(pb, track->vosLen+18+14+17);
284 put_be32(pb, 0); // Version
286 put_byte(pb, 0x03); // tag = ES_DescriptorTag
287 put_be32(pb, esdsLength(track->vosLen+18+14)); // Length
288 put_be16(pb, 0x0001); // ID (= 1)
289 put_byte(pb, 0x00); // flags (= no flags)
291 // Decoderconfigdescriptor = 4
292 put_byte(pb, 0x04); // tag = DecoderConfigDescriptor
293 put_be32(pb, esdsLength(track->vosLen+18)); // Length
294 put_byte(pb, 0x20); // Object type indication (Visual 14496-2)
295 put_byte(pb, 0x11); // flags (= Visualstream)
296 put_byte(pb, 0x0); // Buffersize DB (24 bits)
297 put_be16(pb, 0x0dd2); // Buffersize DB
299 // TODO: find real values for these
300 put_be32(pb, 0x0002e918); // maxbitrate
301 put_be32(pb, 0x00017e6b); // avg bitrate
303 // Decoderspecific info Tag = 5
304 put_byte(pb, 0x05); // tag = Decoderspecific info
305 put_be32(pb, esdsLength(track->vosLen)); // length
306 put_buffer(pb, track->vosData, track->vosLen);
309 put_be32(pb, esdsLength(1)); // length
311 return track->vosLen+18+14+17;
314 static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
316 int pos = url_ftell(pb);
317 put_be32(pb, 0); /* size */
318 if(track->enc->codec_id == CODEC_ID_SVQ1)
320 else if(track->enc->codec_id == CODEC_ID_SVQ3)
322 else if(track->enc->codec_id == CODEC_ID_MPEG4)
324 else if(track->enc->codec_id == CODEC_ID_H263)
327 put_tag(pb, " "); /* Unknown tag */
329 put_be32(pb, 0); /* Reserved */
330 put_be16(pb, 0); /* Reserved */
331 put_be16(pb, 1); /* Data-reference index */
333 put_be32(pb, 0); /* Reserved (= 02000c) */
334 put_be32(pb, 0); /* Reserved ("SVis")*/
335 put_be32(pb, 0); /* Reserved */
336 put_be32(pb, 0); /* Reserved (400)*/
337 put_be16(pb, track->enc->width); /* Video width */
338 put_be16(pb, track->enc->height); /* Video height */
339 put_be32(pb, 0x00480000); /* Reserved */
340 put_be32(pb, 0x00480000); /* Reserved */
341 put_be32(pb, 0); /* Reserved */
342 put_be32(pb, 0); /* Reserved */
343 put_be32(pb, 0); /* Reserved */
344 put_be32(pb, 0); /* Reserved */
345 put_be32(pb, 0); /* Reserved */
346 put_be32(pb, 0); /* Reserved */
348 put_be16(pb, 0); /* Reserved */
349 put_be32(pb, 0); /* Reserved */
350 put_be32(pb, 0); /* Reserved */
351 put_be32(pb, 0); /* Reserved */
352 put_be16(pb, 0x18); /* Reserved */
353 put_be16(pb, 0xffff); /* Reserved */
354 if(track->enc->codec_id == CODEC_ID_MPEG4)
355 mov_write_esds_tag(pb, track);
356 else if(track->enc->codec_id == CODEC_ID_H263)
357 mov_write_d263_tag(pb);
358 else if(track->enc->codec_id == CODEC_ID_SVQ3)
359 mov_write_svq3_tag(pb);
361 return updateSize (pb, pos);
364 static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
366 int pos = url_ftell(pb);
367 put_be32(pb, 0); /* size */
369 put_be32(pb, 0); /* version & flags */
370 put_be32(pb, 1); /* entry count */
371 if (track->enc->codec_type == CODEC_TYPE_VIDEO)
372 mov_write_video_tag(pb, track);
373 else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
374 mov_write_audio_tag(pb, track);
375 return updateSize(pb, pos);
378 /* TODO?: Currently all samples/frames seem to have same duration */
379 static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
381 put_be32(pb, 0x18); /* size */
383 put_be32(pb, 0); /* version & flags */
384 put_be32(pb, 1); /* entry count */
386 put_be32(pb, track->frameCount); /* sample count */
387 put_be32(pb, track->sampleDelta); /* sample delta */
391 static int mov_write_dref_tag(ByteIOContext *pb)
393 put_be32(pb, 28); /* size */
395 put_be32(pb, 0); /* version & flags */
396 put_be32(pb, 1); /* entry count */
398 put_be32(pb, 0xc); /* size */
400 put_be32(pb, 1); /* version & flags */
405 static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
407 int pos = url_ftell(pb);
408 put_be32(pb, 0); /* size */
410 mov_write_stsd_tag(pb, track);
411 mov_write_stts_tag(pb, track);
412 if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
414 mov_write_stss_tag(pb, track);
415 mov_write_stsc_tag(pb, track);
416 mov_write_stsz_tag(pb, track);
417 mov_write_stco_tag(pb, track);
418 return updateSize(pb, pos);
421 static int mov_write_dinf_tag(ByteIOContext *pb)
423 int pos = url_ftell(pb);
424 put_be32(pb, 0); /* size */
426 mov_write_dref_tag(pb);
427 return updateSize(pb, pos);
430 static int mov_write_smhd_tag(ByteIOContext *pb)
432 put_be32(pb, 16); /* size */
434 put_be32(pb, 0); /* version & flags */
435 put_be16(pb, 0); /* reserved (balance, normally = 0) */
436 put_be16(pb, 0); /* reserved */
440 static int mov_write_vmhd_tag(ByteIOContext *pb)
442 put_be32(pb, 0x14); /* size (always 0x14) */
444 put_be32(pb, 0x01); /* version & flags */
445 put_be64(pb, 0); /* reserved (graphics mode = copy) */
449 static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
451 int pos = url_ftell(pb);
452 put_be32(pb, 0); /* size */
454 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
455 mov_write_vmhd_tag(pb);
457 mov_write_smhd_tag(pb);
458 mov_write_dinf_tag(pb);
459 mov_write_stbl_tag(pb, track);
460 return updateSize(pb, pos);
463 static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
466 int pos = url_ftell(pb);
467 put_be32(pb, 0); /* size */
469 put_be32(pb, 0); /* Version & flags */
470 put_be32(pb, 0); /* reserved */
471 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
472 put_tag(pb, "vide"); /* handler type */
474 put_tag(pb, "soun"); /* handler type */
475 put_be32(pb ,0); /* reserved */
476 put_be32(pb ,0); /* reserved */
477 put_be32(pb ,0); /* reserved */
478 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
479 str = "VideoHandler";
481 str = "SoundHandler";
482 put_byte(pb, strlen(str)); /* string counter */
483 put_buffer(pb, str, strlen(str));
484 return updateSize(pb, pos);
487 static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
489 put_be32(pb, 32); /* size */
491 put_be32(pb, 0); /* Version & flags */
492 put_be32(pb, track->time); /* creation time */
493 put_be32(pb, track->time); /* modification time */
494 if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
495 int64_t rate = track->enc->frame_rate;
497 put_be32(pb, rate*(int64_t)track->trackDuration/(int64_t)globalTimescale); // duration
500 put_be32(pb, track->timescale); /* time scale (sample rate for audio) */
501 put_be32(pb, track->trackDuration); /* duration */
503 put_be16(pb, 0); /* language, 0 = english */
504 put_be16(pb, 0); /* reserved (quality) */
508 static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
510 int pos = url_ftell(pb);
511 put_be32(pb, 0); /* size */
513 mov_write_mdhd_tag(pb, track);
514 mov_write_hdlr_tag(pb, track);
515 mov_write_minf_tag(pb, track);
516 return updateSize(pb, pos);
519 static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
521 int64_t maxTrackLenTemp;
522 put_be32(pb, 0x5c); /* size (always 0x5c) */
524 put_be32(pb, 0xf); /* version & flags (track enabled) */
525 put_be32(pb, track->time); /* creation time */
526 put_be32(pb, track->time); /* modification time */
527 put_be32(pb, track->trackID); /* track-id */
528 put_be32(pb, 0); /* reserved */
529 maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)track->trackDuration)/(int64_t)track->timescale;
530 put_be32(pb, (long)maxTrackLenTemp); /* duration */
532 put_be32(pb, 0); /* reserved */
533 put_be32(pb, 0); /* reserved */
534 put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
535 /* Volume, only for audio */
536 if(track->enc->codec_type == CODEC_TYPE_AUDIO)
537 put_be16(pb, 0x0100);
540 put_be16(pb, 0); /* reserved */
542 /* Matrix structure */
543 put_be32(pb, 0x00010000); /* reserved */
544 put_be32(pb, 0x0); /* reserved */
545 put_be32(pb, 0x0); /* reserved */
546 put_be32(pb, 0x0); /* reserved */
547 put_be32(pb, 0x00010000); /* reserved */
548 put_be32(pb, 0x0); /* reserved */
549 put_be32(pb, 0x0); /* reserved */
550 put_be32(pb, 0x0); /* reserved */
551 put_be32(pb, 0x40000000); /* reserved */
553 /* Track width and height, for visual only */
554 if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
555 put_be32(pb, track->enc->width*0x10000);
556 put_be32(pb, track->enc->height*0x10000);
565 static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
567 int pos = url_ftell(pb);
568 put_be32(pb, 0); /* size */
570 mov_write_tkhd_tag(pb, track);
571 mov_write_mdia_tag(pb, track);
572 return updateSize(pb, pos);
575 /* TODO: Not sorted out, but not necessary either */
576 static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
578 put_be32(pb, 0x15); /* size */
580 put_be32(pb, 0); /* version & flags */
581 put_be16(pb, 0x1007);
583 put_be16(pb, 0x4fff);
584 put_be16(pb, 0xfffe);
585 put_be16(pb, 0x01ff);
589 static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
591 int maxTrackID = 1, maxTrackLen = 0, i;
592 int64_t maxTrackLenTemp;
594 put_be32(pb, 0x6c); /* size (always 0x6c) */
596 put_be32(pb, 0); /* version & flags */
597 put_be32(pb, mov->time); /* creation time */
598 put_be32(pb, mov->time); /* modification time */
599 put_be32(pb, mov->timescale); /* timescale */
600 for (i=0; i<MAX_STREAMS; i++) {
601 if(mov->tracks[i].entry > 0) {
602 maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)mov->tracks[i].trackDuration)/(int64_t)mov->tracks[i].timescale;
603 if(maxTrackLen < maxTrackLenTemp)
604 maxTrackLen = maxTrackLenTemp;
605 if(maxTrackID < mov->tracks[i].trackID)
606 maxTrackID = mov->tracks[i].trackID;
609 put_be32(pb, maxTrackLen); /* duration of longest track */
611 put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
612 put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
613 put_be16(pb, 0); /* reserved */
614 put_be32(pb, 0); /* reserved */
615 put_be32(pb, 0); /* reserved */
617 /* Matrix structure */
618 put_be32(pb, 0x00010000); /* reserved */
619 put_be32(pb, 0x0); /* reserved */
620 put_be32(pb, 0x0); /* reserved */
621 put_be32(pb, 0x0); /* reserved */
622 put_be32(pb, 0x00010000); /* reserved */
623 put_be32(pb, 0x0); /* reserved */
624 put_be32(pb, 0x0); /* reserved */
625 put_be32(pb, 0x0); /* reserved */
626 put_be32(pb, 0x40000000); /* reserved */
628 put_be32(pb, 0); /* reserved (preview time) */
629 put_be32(pb, 0); /* reserved (preview duration) */
630 put_be32(pb, 0); /* reserved (poster time) */
631 put_be32(pb, 0); /* reserved (selection time) */
632 put_be32(pb, 0); /* reserved (selection duration) */
633 put_be32(pb, 0); /* reserved (current time) */
634 put_be32(pb, maxTrackID+1); /* Next track id */
638 static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov)
642 put_be32(pb, 0); /* size placeholder*/
644 mov->timescale = globalTimescale;
646 for (i=0; i<MAX_STREAMS; i++) {
647 if(mov->tracks[i].entry > 0) {
648 if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) {
649 mov->tracks[i].timescale = globalTimescale;
650 mov->tracks[i].sampleDelta = mov->tracks[i].enc->frame_rate_base;
651 mov->tracks[i].frameCount = mov->tracks[i].samples;
652 mov->tracks[i].trackDuration = (int64_t)((int64_t)mov->tracks[i].entry*
653 (int64_t)globalTimescale*(int64_t)mov->tracks[i].enc->frame_rate_base)/(int64_t)mov->tracks[i].enc->frame_rate;
655 else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
656 long trackDuration = 0;
657 /* If AMR, track timescale = 8000, AMR_WB = 16000 */
658 if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) {
660 for (j=0; j<mov->tracks[i].samples; j++) {
661 int cl = j / MOV_INDEX_CLUSTER_SIZE;
662 int id = j % MOV_INDEX_CLUSTER_SIZE;
663 trackDuration += mov->tracks[i].cluster[cl][id].entries;
665 mov->tracks[i].sampleDelta = 160; // Bytes per chunk
666 mov->tracks[i].frameCount = mov->tracks[i].samples;
667 mov->tracks[i].trackDuration =
668 mov->tracks[i].samples * mov->tracks[i].sampleDelta; //trackDuration
669 mov->tracks[i].timescale = 8000;
673 for (j=0; j<=mov->tracks[i].entry; j++) {
674 int cl = j / MOV_INDEX_CLUSTER_SIZE;
675 int id = j % MOV_INDEX_CLUSTER_SIZE;
676 trackDuration += mov->tracks[i].cluster[cl][id].len;
678 mov->tracks[i].frameCount = trackDuration;
679 mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate;
680 mov->tracks[i].sampleDelta = 1;
681 mov->tracks[i].trackDuration = trackDuration;
684 mov->tracks[i].time = mov->time;
685 mov->tracks[i].trackID = i+1;
689 mov_write_mvhd_tag(pb, mov);
690 //mov_write_iods_tag(pb, mov);
691 for (i=0; i<MAX_STREAMS; i++) {
692 if(mov->tracks[i].entry > 0) {
693 mov_write_trak_tag(pb, &(mov->tracks[i]));
697 return updateSize(pb, pos);
700 int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov)
702 mov->mdat_pos = url_ftell(pb);
703 put_be32(pb, 0); /* size placeholder*/
708 /* TODO: This needs to be more general */
709 int mov_write_ftyp_tag(ByteIOContext *pb)
711 put_be32(pb, 0x14 ); /* size */
714 put_be32(pb, 0x200 );
719 static int mov_write_header(AVFormatContext *s)
721 ByteIOContext *pb = &s->pb;
723 if(s->oformat != NULL) {
724 if(!strcmp("3gp", s->oformat->name))
725 mov_write_ftyp_tag(pb);
728 put_flush_packet(pb);
733 static int Timestamp() {
736 return ltime+(24107*86400);
739 static int mov_write_packet(AVFormatContext *s, int stream_index,
740 const uint8_t *buf, int size, int64_t pts)
742 MOVContext *mov = s->priv_data;
743 ByteIOContext *pb = &s->pb;
747 enc = &s->streams[stream_index]->codec;
748 if (!url_is_streamed(&s->pb)) {
749 MOVTrack* trk = &mov->tracks[stream_index];
751 unsigned int chunkSize = 0;
753 if(enc->codec_type == CODEC_TYPE_AUDIO) {
754 /* We must find out how many AMR blocks there are in one packet */
755 if(enc->codec_id == CODEC_ID_AMR_NB) {
756 static uint16_t packed_size[16] = {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
759 while(len < size && sampleCount < 100) {
760 len += packed_size[(buf[len] >> 3) & 0x0F];
767 chunkSize = size/enc->channels;
770 else if(enc->codec_type == CODEC_TYPE_VIDEO) {
771 if(enc->codec_id == CODEC_ID_MPEG4 &&
774 assert(enc->extradata_size);
776 trk->vosLen = enc->extradata_size;
777 trk->vosData = av_malloc(trk->vosLen);
778 memcpy(trk->vosData, enc->extradata, trk->vosLen);
783 cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
784 id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
786 if (trk->ents_allocated <= trk->entry) {
787 trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*));
790 trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
791 if (!trk->cluster[cl])
793 trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
795 if(mov->mdat_written == 0) {
796 mov_write_mdat_tag(pb, mov);
797 mov->mdat_written = 1;
798 mov->time = Timestamp();
801 trk->cluster[cl][id].pos = url_ftell(pb) - mov->movi_list;
802 trk->cluster[cl][id].chunkSize = chunkSize;
803 if(enc->channels > 1)
804 trk->cluster[cl][id].len = size/enc->channels;
806 trk->cluster[cl][id].len = size;
807 trk->cluster[cl][id].entries = sampleCount;
808 if(enc->codec_type == CODEC_TYPE_VIDEO) {
809 trk->cluster[cl][id].key_frame = enc->coded_frame->key_frame;
810 if(enc->coded_frame->pict_type == FF_I_TYPE)
811 trk->hasKeyframes = 1;
818 trk->samples += sampleCount;
819 trk->mdat_size += size;
821 put_buffer(pb, buf, size);
823 put_flush_packet(pb);
827 static int mov_write_trailer(AVFormatContext *s)
829 MOVContext *mov = s->priv_data;
830 ByteIOContext *pb = &s->pb;
835 file_size = url_ftell(pb);
838 /* Write size of mdat tag */
839 for (i=0; i<MAX_STREAMS; i++) {
840 if(mov->tracks[i].ents_allocated > 0) {
841 j += mov->tracks[i].mdat_size;
844 url_fseek(pb, mov->mdat_pos, SEEK_SET);
846 url_fseek(pb, file_size, SEEK_SET);
848 mov_write_moov_tag(pb, mov);
850 for (i=0; i<MAX_STREAMS; i++) {
851 for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
852 av_free(mov->tracks[i].cluster[j]);
854 av_free(mov->tracks[i].cluster);
855 mov->tracks[i].cluster = NULL;
856 mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
858 put_flush_packet(pb);
863 static AVOutputFormat mov_oformat = {
876 static AVOutputFormat _3gp_oformat = {
889 static AVOutputFormat mp4_oformat = {
902 int movenc_init(void)
904 av_register_output_format(&mov_oformat);
905 av_register_output_format(&_3gp_oformat);
906 av_register_output_format(&mp4_oformat);