add MPEG-2 intra vlc support
[libav.git] / libavformat / movenc.c
CommitLineData
1cb5f7fd
MN
1/*
2 * MOV, 3GP, MP4 encoder.
3 * Copyright (c) 2003 Thomas Raivio.
69dde1ad 4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>.
1cb5f7fd
MN
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
5509bffa 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1cb5f7fd
MN
19 */
20#include "avformat.h"
f578f938 21#include "avi.h"
1cb5f7fd 22#include "avio.h"
e60b4ced 23#include "mov.h"
1cb5f7fd 24
6e6d6dc0
MN
25#undef NDEBUG
26#include <assert.h>
27
1cb5f7fd
MN
28#define MOV_INDEX_CLUSTER_SIZE 16384
29#define globalTimescale 1000
30
69dde1ad
GB
31#define MODE_MP4 0
32#define MODE_MOV 1
33#define MODE_3GP 2
115329f1 34#define MODE_PSP 3 // example working PSP command line:
8af18154 35// ffmpeg -i testinput.avi -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4
8536ab89 36#define MODE_3G2 4
69dde1ad 37
1cb5f7fd 38typedef struct MOVIentry {
b29af723
MN
39 unsigned int flags, size;
40 uint64_t pos;
e45ccf79 41 unsigned int samplesInChunk;
f578f938 42 char key_frame;
1cb5f7fd 43 unsigned int entries;
b4712e3c 44 int64_t cts;
1cb5f7fd
MN
45} MOVIentry;
46
47typedef struct MOVIndex {
69dde1ad 48 int mode;
1cb5f7fd 49 int entry;
b29af723 50 uint64_t mdat_size;
1cb5f7fd
MN
51 int ents_allocated;
52 long timescale;
53 long time;
a3a80ddc 54 int64_t trackDuration;
e45ccf79
GB
55 long sampleCount;
56 long sampleDuration;
f578f938 57 int hasKeyframes;
b4712e3c 58 int hasBframes;
ab561df9 59 int language;
1cb5f7fd
MN
60 int trackID;
61 AVCodecContext *enc;
62
63 int vosLen;
6e6d6dc0 64 uint8_t *vosData;
1cb5f7fd
MN
65 MOVIentry** cluster;
66} MOVTrack;
67
8af18154 68typedef struct MOVContext {
69dde1ad 69 int mode;
a3a80ddc 70 int64_t time;
1cb5f7fd 71 int nb_streams;
f578f938 72 offset_t mdat_pos;
1cb5f7fd
MN
73 long timescale;
74 MOVTrack tracks[MAX_STREAMS];
75} MOVContext;
76
e45ccf79
GB
77static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track);
78
6e6d6dc0 79//FIXME supprt 64bit varaint with wide placeholders
b29af723 80static offset_t updateSize (ByteIOContext *pb, offset_t pos)
1cb5f7fd 81{
b29af723 82 offset_t curpos = url_ftell(pb);
1cb5f7fd 83 url_fseek(pb, pos, SEEK_SET);
6e6d6dc0 84 put_be32(pb, curpos - pos); /* rewrite size */
1cb5f7fd 85 url_fseek(pb, curpos, SEEK_SET);
6e6d6dc0
MN
86
87 return curpos - pos;
1cb5f7fd
MN
88}
89
e45ccf79 90/* Chunk offset atom */
6e6d6dc0 91static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
92{
93 int i;
ed06cf6d 94 int mode64 = 0; // use 32 bit size variant if possible
b29af723 95 offset_t pos = url_ftell(pb);
f578f938 96 put_be32(pb, 0); /* size */
b29af723
MN
97 if (pos > UINT32_MAX) {
98 mode64 = 1;
99 put_tag(pb, "co64");
100 } else
101 put_tag(pb, "stco");
1cb5f7fd
MN
102 put_be32(pb, 0); /* version & flags */
103 put_be32(pb, track->entry); /* entry count */
104 for (i=0; i<track->entry; i++) {
105 int cl = i / MOV_INDEX_CLUSTER_SIZE;
106 int id = i % MOV_INDEX_CLUSTER_SIZE;
b29af723
MN
107 if(mode64 == 1)
108 put_be64(pb, track->cluster[cl][id].pos);
109 else
110 put_be32(pb, track->cluster[cl][id].pos);
1cb5f7fd 111 }
f578f938 112 return updateSize (pb, pos);
1cb5f7fd
MN
113}
114
e45ccf79 115/* Sample size atom */
6e6d6dc0 116static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 117{
f578f938 118 int equalChunks = 1;
e45ccf79 119 int i, j, entries = 0, tst = -1, oldtst = -1;
1cb5f7fd 120
b29af723 121 offset_t pos = url_ftell(pb);
f578f938 122 put_be32(pb, 0); /* size */
1cb5f7fd
MN
123 put_tag(pb, "stsz");
124 put_be32(pb, 0); /* version & flags */
125
f578f938
TR
126 for (i=0; i<track->entry; i++) {
127 int cl = i / MOV_INDEX_CLUSTER_SIZE;
128 int id = i % MOV_INDEX_CLUSTER_SIZE;
e45ccf79
GB
129 tst = track->cluster[cl][id].size/track->cluster[cl][id].entries;
130 if(oldtst != -1 && tst != oldtst) {
131 equalChunks = 0;
f578f938
TR
132 }
133 oldtst = tst;
e45ccf79 134 entries += track->cluster[cl][id].entries;
f578f938 135 }
e45ccf79
GB
136 if (equalChunks) {
137 int sSize = track->cluster[0][0].size/track->cluster[0][0].entries;
115329f1 138 put_be32(pb, sSize); // sample size
e45ccf79 139 put_be32(pb, entries); // sample count
1cb5f7fd 140 }
f578f938 141 else {
115329f1
DB
142 put_be32(pb, 0); // sample size
143 put_be32(pb, entries); // sample count
f578f938 144 for (i=0; i<track->entry; i++) {
1cb5f7fd
MN
145 int cl = i / MOV_INDEX_CLUSTER_SIZE;
146 int id = i % MOV_INDEX_CLUSTER_SIZE;
e45ccf79
GB
147 for ( j=0; j<track->cluster[cl][id].entries; j++) {
148 put_be32(pb, track->cluster[cl][id].size /
149 track->cluster[cl][id].entries);
150 }
1cb5f7fd
MN
151 }
152 }
f578f938 153 return updateSize (pb, pos);
1cb5f7fd
MN
154}
155
e45ccf79 156/* Sample to chunk atom */
6e6d6dc0 157static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 158{
b29af723
MN
159 int index = 0, oldval = -1, i;
160 offset_t entryPos, curpos;
f578f938 161
b29af723 162 offset_t pos = url_ftell(pb);
f578f938 163 put_be32(pb, 0); /* size */
1cb5f7fd 164 put_tag(pb, "stsc");
115329f1 165 put_be32(pb, 0); // version & flags
f578f938 166 entryPos = url_ftell(pb);
115329f1 167 put_be32(pb, track->entry); // entry count
f578f938
TR
168 for (i=0; i<track->entry; i++) {
169 int cl = i / MOV_INDEX_CLUSTER_SIZE;
170 int id = i % MOV_INDEX_CLUSTER_SIZE;
e45ccf79 171 if(oldval != track->cluster[cl][id].samplesInChunk)
f578f938 172 {
115329f1 173 put_be32(pb, i+1); // first chunk
e45ccf79 174 put_be32(pb, track->cluster[cl][id].samplesInChunk); // samples per chunk
115329f1 175 put_be32(pb, 0x1); // sample description index
e45ccf79 176 oldval = track->cluster[cl][id].samplesInChunk;
f578f938 177 index++;
1cb5f7fd
MN
178 }
179 }
f578f938
TR
180 curpos = url_ftell(pb);
181 url_fseek(pb, entryPos, SEEK_SET);
115329f1 182 put_be32(pb, index); // rewrite size
f578f938 183 url_fseek(pb, curpos, SEEK_SET);
1cb5f7fd 184
f578f938 185 return updateSize (pb, pos);
1cb5f7fd
MN
186}
187
e45ccf79 188/* Sync sample atom */
f578f938 189static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 190{
b29af723
MN
191 offset_t curpos, entryPos;
192 int i, index = 0;
193 offset_t pos = url_ftell(pb);
115329f1 194 put_be32(pb, 0); // size
1cb5f7fd 195 put_tag(pb, "stss");
115329f1 196 put_be32(pb, 0); // version & flags
f578f938 197 entryPos = url_ftell(pb);
115329f1 198 put_be32(pb, track->entry); // entry count
f578f938
TR
199 for (i=0; i<track->entry; i++) {
200 int cl = i / MOV_INDEX_CLUSTER_SIZE;
201 int id = i % MOV_INDEX_CLUSTER_SIZE;
202 if(track->cluster[cl][id].key_frame == 1) {
203 put_be32(pb, i+1);
204 index++;
205 }
206 }
207 curpos = url_ftell(pb);
208 url_fseek(pb, entryPos, SEEK_SET);
115329f1 209 put_be32(pb, index); // rewrite size
f578f938
TR
210 url_fseek(pb, curpos, SEEK_SET);
211 return updateSize (pb, pos);
1cb5f7fd
MN
212}
213
6e6d6dc0 214static int mov_write_damr_tag(ByteIOContext *pb)
1cb5f7fd
MN
215{
216 put_be32(pb, 0x11); /* size */
217 put_tag(pb, "damr");
218 put_tag(pb, "FFMP");
219 put_byte(pb, 0);
f578f938 220
9c09db54
BC
221 //put_be16(pb, 0x80); /* Mode set (all modes for AMR_NB) */
222 //put_be16(pb, 0xa); /* Mode change period (no restriction) */
223 put_be16(pb, 0x81ff); /* Mode set (all modes for AMR_NB) */
224 put_be16(pb, 1); /* Mode change period (no restriction) */
1cb5f7fd
MN
225 return 0x11;
226}
227
69dde1ad
GB
228static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track)
229{
b29af723 230 offset_t pos = url_ftell(pb);
69dde1ad
GB
231
232 put_be32(pb, 0); /* size */
233 put_tag(pb, "wave");
234
235 put_be32(pb, 12); /* size */
236 put_tag(pb, "frma");
237 put_tag(pb, "mp4a");
238
239 put_be32(pb, 12); /* size */
240 put_tag(pb, "mp4a");
241 put_be32(pb, 0);
242
243 mov_write_esds_tag(pb, track);
244
245 put_be32(pb, 12); /* size */
246 put_tag(pb, "srcq");
247 put_be32(pb, 0x40);
248
249 put_be32(pb, 8); /* size */
250 put_be32(pb, 0); /* null tag */
251
252 return updateSize (pb, pos);
253}
254
0c1e0bab 255static const CodecTag codec_movaudio_tags[] = {
8cc7a34d
AB
256 { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') },
257 { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') },
258 { CODEC_ID_ADPCM_IMA_QT, MKTAG('i', 'm', 'a', '4') },
259 { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') },
260 { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') },
261 { CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
262 { CODEC_ID_AMR_NB, MKTAG('s', 'a', 'm', 'r') },
11bec294 263 { CODEC_ID_AMR_WB, MKTAG('s', 'a', 'w', 'b') },
8cc7a34d
AB
264 { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') },
265 { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') },
266 { CODEC_ID_MP3, MKTAG('.', 'm', 'p', '3') },
8e321619 267 { CODEC_ID_NONE, 0 },
8cc7a34d
AB
268};
269
f578f938 270static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 271{
b29af723 272 offset_t pos = url_ftell(pb);
ffdd57d4 273 int tag;
115329f1 274
1cb5f7fd 275 put_be32(pb, 0); /* size */
f578f938 276
caacd4de
RG
277 tag = track->enc->codec_tag;
278 if (!tag)
8cc7a34d
AB
279 tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id);
280 // if no mac fcc found, try with Microsoft tags
281 if (!tag)
282 {
bb270c08 283 int tmp = codec_get_tag(codec_wav_tags, track->enc->codec_id);
ffdd57d4 284 tag = MKTAG('m', 's', ((tmp >> 8) & 0xff), (tmp & 0xff));
8cc7a34d 285 }
ffdd57d4 286 put_le32(pb, tag); // store it byteswapped
f578f938 287
1cb5f7fd
MN
288 put_be32(pb, 0); /* Reserved */
289 put_be16(pb, 0); /* Reserved */
290 put_be16(pb, 1); /* Data-reference index, XXX == 1 */
69dde1ad 291
e45ccf79 292 /* SoundDescription */
69dde1ad
GB
293 if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
294 put_be16(pb, 1); /* Version 1 */
295 else
296 put_be16(pb, 0); /* Version 0 */
e45ccf79 297 put_be16(pb, 0); /* Revision level */
1cb5f7fd
MN
298 put_be32(pb, 0); /* Reserved */
299
f578f938
TR
300 put_be16(pb, track->enc->channels); /* Number of channels */
301 /* TODO: Currently hard-coded to 16-bit, there doesn't seem
e45ccf79 302 to be a good way to get number of bits of audio */
1cb5f7fd 303 put_be16(pb, 0x10); /* Reserved */
ef19c7eb
GB
304
305 if(track->enc->codec_id == CODEC_ID_AAC ||
306 track->enc->codec_id == CODEC_ID_MP3)
307 {
308 put_be16(pb, 0xfffe); /* compression ID (vbr)*/
309 }
310 else
311 {
312 put_be16(pb, 0); /* compression ID (= 0) */
313 }
9a4d9388 314 put_be16(pb, 0); /* packet size (= 0) */
1cb5f7fd
MN
315 put_be16(pb, track->timescale); /* Time scale */
316 put_be16(pb, 0); /* Reserved */
317
69dde1ad
GB
318 if(track->mode == MODE_MOV && track->enc->codec_id == CODEC_ID_AAC)
319 {
320 /* SoundDescription V1 extended info */
321 put_be32(pb, track->enc->frame_size); /* Samples per packet */
322 put_be32(pb, 1536); /* Bytes per packet */
323 put_be32(pb, 2); /* Bytes per frame */
324 put_be32(pb, 2); /* Bytes per sample */
325 }
326
327 if(track->enc->codec_id == CODEC_ID_AAC) {
328 if( track->mode == MODE_MOV ) mov_write_wave_tag(pb, track);
329 else mov_write_esds_tag(pb, track);
330 }
f578f938
TR
331 if(track->enc->codec_id == CODEC_ID_AMR_NB)
332 mov_write_damr_tag(pb);
6e6d6dc0 333 return updateSize (pb, pos);
1cb5f7fd
MN
334}
335
6e6d6dc0 336static int mov_write_d263_tag(ByteIOContext *pb)
1cb5f7fd
MN
337{
338 put_be32(pb, 0xf); /* size */
339 put_tag(pb, "d263");
340 put_tag(pb, "FFMP");
341 put_be16(pb, 0x0a);
342 put_byte(pb, 0);
343 return 0xf;
344}
345
f578f938
TR
346/* TODO: No idea about these values */
347static int mov_write_svq3_tag(ByteIOContext *pb)
1cb5f7fd 348{
f578f938
TR
349 put_be32(pb, 0x15);
350 put_tag(pb, "SMI ");
351 put_tag(pb, "SEQH");
352 put_be32(pb, 0x5);
353 put_be32(pb, 0xe2c0211d);
354 put_be32(pb, 0xc0000000);
115329f1 355 put_byte(pb, 0);
f578f938 356 return 0x15;
1cb5f7fd
MN
357}
358
c1b8e6d8
BC
359static uint8_t *avc_find_startcode( uint8_t *p, uint8_t *end )
360{
361 uint8_t *a = p + 4 - ((int)p & 3);
362
363 for( end -= 3; p < a && p < end; p++ ) {
364 if( p[0] == 0 && p[1] == 0 && p[2] == 1 )
365 return p;
366 }
367
368 for( end -= 3; p < end; p += 4 ) {
369 uint32_t x = *(uint32_t*)p;
370// if( (x - 0x01000100) & (~x) & 0x80008000 ) // little endian
371// if( (x - 0x00010001) & (~x) & 0x00800080 ) // big endian
372 if( (x - 0x01010101) & (~x) & 0x80808080 ) { // generic
373 if( p[1] == 0 ) {
374 if( p[0] == 0 && p[2] == 1 )
375 return p;
376 if( p[2] == 0 && p[3] == 1 )
377 return p+1;
378 }
379 if( p[3] == 0 ) {
380 if( p[2] == 0 && p[4] == 1 )
381 return p+2;
382 if( p[4] == 0 && p[5] == 1 )
383 return p+3;
384 }
385 }
386 }
387
388 for( end += 3; p < end; p++ ) {
389 if( p[0] == 0 && p[1] == 0 && p[2] == 1 )
390 return p;
391 }
392
393 return end + 3;
394}
395
396static void avc_parse_nal_units(uint8_t **buf, int *size)
397{
398 ByteIOContext pb;
399 uint8_t *p = *buf;
400 uint8_t *end = p + *size;
401 uint8_t *nal_start, *nal_end;
402
403 url_open_dyn_buf(&pb);
404 nal_start = avc_find_startcode(p, end);
405 while (nal_start < end) {
406 while(!*(nal_start++));
407 nal_end = avc_find_startcode(nal_start, end);
408 put_be32(&pb, nal_end - nal_start);
409 put_buffer(&pb, nal_start, nal_end - nal_start);
410 nal_start = nal_end;
411 }
412 av_freep(buf);
413 *size = url_close_dyn_buf(&pb, buf);
414}
415
416static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track)
417{
418 offset_t pos = url_ftell(pb);
419
420 put_be32(pb, 0);
421 put_tag(pb, "avcC");
422 if (track->vosLen > 6) {
423 /* check for h264 start code */
424 if (BE_32(track->vosData) == 0x00000001) {
425 uint8_t *buf, *end;
426 uint32_t sps_size=0, pps_size=0;
427 uint8_t *sps=0, *pps=0;
428
429 avc_parse_nal_units(&track->vosData, &track->vosLen);
430 buf = track->vosData;
431 end = track->vosData + track->vosLen;
432
c1b8e6d8
BC
433 /* look for sps and pps */
434 while (buf < end) {
435 unsigned int size;
436 uint8_t nal_type;
437 size = BE_32(buf);
438 nal_type = buf[4] & 0x1f;
439 if (nal_type == 7) { /* SPS */
440 sps = buf + 4;
441 sps_size = size;
442 } else if (nal_type == 8) { /* PPS */
443 pps = buf + 4;
444 pps_size = size;
445 }
446 buf += size + 4;
447 }
448 assert(sps);
449 assert(pps);
611fd605
BC
450
451 put_byte(pb, 1); /* version */
452 put_byte(pb, sps[1]); /* profile */
453 put_byte(pb, sps[2]); /* profile compat */
454 put_byte(pb, sps[3]); /* level */
455 put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
456 put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */
457
c1b8e6d8
BC
458 put_be16(pb, sps_size);
459 put_buffer(pb, sps, sps_size);
460 put_byte(pb, 1); /* number of pps */
461 put_be16(pb, pps_size);
462 put_buffer(pb, pps, pps_size);
463 } else {
464 put_buffer(pb, track->vosData, track->vosLen);
465 }
466 }
467 return updateSize(pb, pos);
468}
469
e45ccf79
GB
470static unsigned int descrLength(unsigned int len)
471{
472 if (len < 0x00000080)
473 return 2 + len;
474 else if (len < 0x00004000)
475 return 3 + len;
476 else if(len < 0x00200000)
477 return 4 + len;
478 else
479 return 5 + len;
480}
481
482static void putDescr(ByteIOContext *pb, int tag, int size)
1cb5f7fd 483{
e45ccf79
GB
484 uint32_t len;
485 uint8_t vals[4];
486
487 len = size;
488 vals[3] = (uint8_t)(len & 0x7f);
489 len >>= 7;
115329f1 490 vals[2] = (uint8_t)((len & 0x7f) | 0x80);
e45ccf79 491 len >>= 7;
115329f1 492 vals[1] = (uint8_t)((len & 0x7f) | 0x80);
e45ccf79
GB
493 len >>= 7;
494 vals[0] = (uint8_t)((len & 0x7f) | 0x80);
495
496 put_byte(pb, tag); // DescriptorTag
497
498 if (size < 0x00000080)
499 {
500 put_byte(pb, vals[3]);
501 }
502 else if (size < 0x00004000)
503 {
504 put_byte(pb, vals[2]);
505 put_byte(pb, vals[3]);
506 }
507 else if (size < 0x00200000)
508 {
509 put_byte(pb, vals[1]);
510 put_byte(pb, vals[2]);
511 put_byte(pb, vals[3]);
512 }
513 else if (size < 0x10000000)
514 {
515 put_byte(pb, vals[0]);
516 put_byte(pb, vals[1]);
517 put_byte(pb, vals[2]);
518 put_byte(pb, vals[3]);
519 }
1cb5f7fd
MN
520}
521
6e6d6dc0 522static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
1cb5f7fd 523{
46103f6b 524 int decoderSpecificInfoLen;
b29af723 525 offset_t pos = url_ftell(pb);
e45ccf79 526
46103f6b
FR
527 decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
528
e45ccf79 529 put_be32(pb, 0); // size
1cb5f7fd 530 put_tag(pb, "esds");
e45ccf79 531 put_be32(pb, 0); // Version
1cb5f7fd 532
e45ccf79
GB
533 // ES descriptor
534 putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
535 descrLength(1));
6c13c880 536 put_be16(pb, track->trackID);
1cb5f7fd
MN
537 put_byte(pb, 0x00); // flags (= no flags)
538
e45ccf79
GB
539 // DecoderConfig descriptor
540 putDescr(pb, 0x04, 13 + decoderSpecificInfoLen);
541
6c13c880
MN
542 // Object type indication
543 put_byte(pb, codec_get_tag(ff_mov_obj_type, track->enc->codec_id));
e45ccf79 544
5cad192d
NS
545 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
546 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
e45ccf79
GB
547 if(track->enc->codec_type == CODEC_TYPE_AUDIO)
548 put_byte(pb, 0x15); // flags (= Audiostream)
549 else
550 put_byte(pb, 0x11); // flags (= Visualstream)
551
6c13c880
MN
552 put_byte(pb, track->enc->rc_buffer_size>>(3+16)); // Buffersize DB (24 bits)
553 put_be16(pb, (track->enc->rc_buffer_size>>3)&0xFFFF); // Buffersize DB
1cb5f7fd 554
6c13c880
MN
555 put_be32(pb, FFMAX(track->enc->bit_rate, track->enc->rc_max_rate)); // maxbitrate (FIXME should be max rate in any 1 sec window)
556 if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0)
557 put_be32(pb, 0); // vbr
558 else
559 put_be32(pb, track->enc->rc_max_rate); // avg bitrate
1cb5f7fd 560
e45ccf79
GB
561 if (track->vosLen)
562 {
563 // DecoderSpecific info descriptor
564 putDescr(pb, 0x05, track->vosLen);
565 put_buffer(pb, track->vosData, track->vosLen);
566 }
567
8af18154 568
e45ccf79 569 // SL descriptor
4bfc029f 570 putDescr(pb, 0x06, 1);
1cb5f7fd 571 put_byte(pb, 0x02);
e45ccf79 572 return updateSize (pb, pos);
1cb5f7fd
MN
573}
574
0c1e0bab 575static const CodecTag codec_movvideo_tags[] = {
8cc7a34d
AB
576 { CODEC_ID_SVQ1, MKTAG('S', 'V', 'Q', '1') },
577 { CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') },
578 { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
579 { CODEC_ID_H263, MKTAG('s', '2', '6', '3') },
0c1e0bab 580 { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
8e321619
BC
581 /* special handling in mov_find_video_codec_tag */
582 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, /* DV NTSC */
583 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 'p') }, /* DV PAL */
584 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'p', 'p') }, /* DVCPRO PAL */
585 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'n') }, /* DVCPRO50 NTSC */
586 { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'p') }, /* DVCPRO50 PAL */
587 { CODEC_ID_NONE, 0 },
8cc7a34d
AB
588};
589
8e321619
BC
590static int mov_find_video_codec_tag(MOVTrack* track)
591{
592 int tag;
593
594 tag = track->enc->codec_tag;
595 if (!tag) {
596 if (track->enc->codec_id == CODEC_ID_DVVIDEO) {
597 if (track->enc->height == 480) { /* NTSC */
598 if (track->enc->pix_fmt == PIX_FMT_YUV422P)
599 tag = MKTAG('d', 'v', '5', 'n');
600 else
601 tag = MKTAG('d', 'v', 'c', ' ');
602 } else { /* assume PAL */
603 if (track->enc->pix_fmt == PIX_FMT_YUV422P)
604 tag = MKTAG('d', 'v', '5', 'p');
605 else if (track->enc->pix_fmt == PIX_FMT_YUV420P)
8e321619 606 tag = MKTAG('d', 'v', 'c', 'p');
3cdc7eb4
BC
607 else
608 tag = MKTAG('d', 'v', 'p', 'p');
8e321619
BC
609 }
610 } else {
611 tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id);
612 }
613 }
614 // if no mac fcc found, try with Microsoft tags
615 if (!tag)
616 tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id);
617 assert(tag);
618 return tag;
619}
620
f578f938 621static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 622{
b29af723 623 offset_t pos = url_ftell(pb);
53ffdd14 624 char compressor_name[32];
ffdd57d4 625 int tag;
8cc7a34d 626
f578f938 627 put_be32(pb, 0); /* size */
8cc7a34d 628
8e321619 629 tag = mov_find_video_codec_tag(track);
ffdd57d4 630 put_le32(pb, tag); // store it byteswapped
6e6d6dc0 631
f578f938
TR
632 put_be32(pb, 0); /* Reserved */
633 put_be16(pb, 0); /* Reserved */
634 put_be16(pb, 1); /* Data-reference index */
635
53ffdd14
RG
636 put_be16(pb, 0); /* Codec stream version */
637 put_be16(pb, 0); /* Codec stream revision (=0) */
638 put_tag(pb, "FFMP"); /* Vendor */
639 if(track->enc->codec_id == CODEC_ID_RAWVIDEO) {
640 put_be32(pb, 0); /* Temporal Quality */
641 put_be32(pb, 0x400); /* Spatial Quality = lossless*/
642 } else {
643 put_be32(pb, 0x200); /* Temporal Quality = normal */
644 put_be32(pb, 0x200); /* Spatial Quality = normal */
645 }
f578f938
TR
646 put_be16(pb, track->enc->width); /* Video width */
647 put_be16(pb, track->enc->height); /* Video height */
53ffdd14
RG
648 put_be32(pb, 0x00480000); /* Horizontal resolution 72dpi */
649 put_be32(pb, 0x00480000); /* Vertical resolution 72dpi */
9a4d9388
RS
650 put_be32(pb, 0); /* Data size (= 0) */
651 put_be16(pb, 1); /* Frame count (= 1) */
115329f1 652
53ffdd14 653 memset(compressor_name,0,32);
25cf9062 654 if (track->enc->codec && track->enc->codec->name)
53ffdd14 655 strncpy(compressor_name,track->enc->codec->name,31);
25cf9062 656 put_byte(pb, strlen(compressor_name));
53ffdd14 657 put_buffer(pb, compressor_name, 31);
115329f1 658
f578f938
TR
659 put_be16(pb, 0x18); /* Reserved */
660 put_be16(pb, 0xffff); /* Reserved */
661 if(track->enc->codec_id == CODEC_ID_MPEG4)
662 mov_write_esds_tag(pb, track);
663 else if(track->enc->codec_id == CODEC_ID_H263)
664 mov_write_d263_tag(pb);
665 else if(track->enc->codec_id == CODEC_ID_SVQ3)
115329f1 666 mov_write_svq3_tag(pb);
c1b8e6d8
BC
667 else if(track->enc->codec_id == CODEC_ID_H264)
668 mov_write_avcc_tag(pb, track);
f578f938
TR
669
670 return updateSize (pb, pos);
1cb5f7fd
MN
671}
672
6e6d6dc0 673static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 674{
b29af723 675 offset_t pos = url_ftell(pb);
1cb5f7fd
MN
676 put_be32(pb, 0); /* size */
677 put_tag(pb, "stsd");
678 put_be32(pb, 0); /* version & flags */
679 put_be32(pb, 1); /* entry count */
f578f938
TR
680 if (track->enc->codec_type == CODEC_TYPE_VIDEO)
681 mov_write_video_tag(pb, track);
682 else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
683 mov_write_audio_tag(pb, track);
6e6d6dc0 684 return updateSize(pb, pos);
1cb5f7fd
MN
685}
686
b4712e3c
BC
687static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack* track)
688{
689 Time2Sample *ctts_entries;
690 uint32_t entries = 0;
691 uint32_t atom_size;
692 int i;
693
694 ctts_entries = av_malloc((track->entry + 1) * sizeof(*ctts_entries)); /* worst case */
695 ctts_entries[0].count = 1;
696 ctts_entries[0].duration = track->cluster[0][0].cts;
697 for (i=1; i<track->entry; i++) {
698 int cl = i / MOV_INDEX_CLUSTER_SIZE;
699 int id = i % MOV_INDEX_CLUSTER_SIZE;
700 if (track->cluster[cl][id].cts == ctts_entries[entries].duration) {
701 ctts_entries[entries].count++; /* compress */
702 } else {
703 entries++;
704 ctts_entries[entries].duration = track->cluster[cl][id].cts;
705 ctts_entries[entries].count = 1;
706 }
707 }
708 entries++; /* last one */
709 atom_size = 16 + (entries * 8);
710 put_be32(pb, atom_size); /* size */
711 put_tag(pb, "ctts");
712 put_be32(pb, 0); /* version & flags */
713 put_be32(pb, entries); /* entry count */
714 for (i=0; i<entries; i++) {
715 put_be32(pb, ctts_entries[i].count);
716 put_be32(pb, ctts_entries[i].duration);
717 }
718 av_free(ctts_entries);
719 return atom_size;
720}
721
0078e9b9 722/* TODO: */
e45ccf79 723/* Time to sample atom */
6e6d6dc0 724static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
725{
726 put_be32(pb, 0x18); /* size */
727 put_tag(pb, "stts");
728 put_be32(pb, 0); /* version & flags */
729 put_be32(pb, 1); /* entry count */
730
e45ccf79
GB
731 put_be32(pb, track->sampleCount); /* sample count */
732 put_be32(pb, track->sampleDuration); /* sample duration */
1cb5f7fd
MN
733 return 0x18;
734}
735
6e6d6dc0 736static int mov_write_dref_tag(ByteIOContext *pb)
1cb5f7fd
MN
737{
738 put_be32(pb, 28); /* size */
739 put_tag(pb, "dref");
740 put_be32(pb, 0); /* version & flags */
741 put_be32(pb, 1); /* entry count */
742
743 put_be32(pb, 0xc); /* size */
744 put_tag(pb, "url ");
745 put_be32(pb, 1); /* version & flags */
746
747 return 28;
748}
749
6e6d6dc0 750static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 751{
b29af723 752 offset_t pos = url_ftell(pb);
1cb5f7fd
MN
753 put_be32(pb, 0); /* size */
754 put_tag(pb, "stbl");
6e6d6dc0
MN
755 mov_write_stsd_tag(pb, track);
756 mov_write_stts_tag(pb, track);
f578f938 757 if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
32ba6fb1 758 track->hasKeyframes < track->entry)
f578f938 759 mov_write_stss_tag(pb, track);
b4712e3c
BC
760 if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
761 track->hasBframes)
762 mov_write_ctts_tag(pb, track);
6e6d6dc0
MN
763 mov_write_stsc_tag(pb, track);
764 mov_write_stsz_tag(pb, track);
765 mov_write_stco_tag(pb, track);
766 return updateSize(pb, pos);
1cb5f7fd
MN
767}
768
6e6d6dc0 769static int mov_write_dinf_tag(ByteIOContext *pb)
1cb5f7fd 770{
b29af723 771 offset_t pos = url_ftell(pb);
1cb5f7fd
MN
772 put_be32(pb, 0); /* size */
773 put_tag(pb, "dinf");
6e6d6dc0
MN
774 mov_write_dref_tag(pb);
775 return updateSize(pb, pos);
1cb5f7fd
MN
776}
777
6e6d6dc0 778static int mov_write_smhd_tag(ByteIOContext *pb)
1cb5f7fd
MN
779{
780 put_be32(pb, 16); /* size */
781 put_tag(pb, "smhd");
782 put_be32(pb, 0); /* version & flags */
783 put_be16(pb, 0); /* reserved (balance, normally = 0) */
784 put_be16(pb, 0); /* reserved */
785 return 16;
786}
787
6e6d6dc0 788static int mov_write_vmhd_tag(ByteIOContext *pb)
1cb5f7fd
MN
789{
790 put_be32(pb, 0x14); /* size (always 0x14) */
791 put_tag(pb, "vmhd");
792 put_be32(pb, 0x01); /* version & flags */
793 put_be64(pb, 0); /* reserved (graphics mode = copy) */
794 return 0x14;
795}
796
6e6d6dc0 797static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 798{
9a4d9388 799 char *descr, *hdlr, *hdlr_type;
b29af723 800 offset_t pos = url_ftell(pb);
115329f1 801
9a4d9388 802 if (!track) { /* no media --> data handler */
bb270c08
DB
803 hdlr = "dhlr";
804 hdlr_type = "url ";
805 descr = "DataHandler";
9a4d9388 806 } else {
bb270c08
DB
807 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
808 if (track->enc->codec_type == CODEC_TYPE_VIDEO) {
809 hdlr_type = "vide";
810 descr = "VideoHandler";
811 } else {
812 hdlr_type = "soun";
813 descr = "SoundHandler";
814 }
9a4d9388 815 }
115329f1 816
f578f938 817 put_be32(pb, 0); /* size */
1cb5f7fd
MN
818 put_tag(pb, "hdlr");
819 put_be32(pb, 0); /* Version & flags */
906b578f 820 put_buffer(pb, hdlr, 4); /* handler */
9a4d9388 821 put_tag(pb, hdlr_type); /* handler type */
f578f938
TR
822 put_be32(pb ,0); /* reserved */
823 put_be32(pb ,0); /* reserved */
824 put_be32(pb ,0); /* reserved */
9a4d9388
RS
825 put_byte(pb, strlen(descr)); /* string counter */
826 put_buffer(pb, descr, strlen(descr)); /* handler description */
827 return updateSize(pb, pos);
828}
829
830static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
831{
b29af723 832 offset_t pos = url_ftell(pb);
9a4d9388
RS
833 put_be32(pb, 0); /* size */
834 put_tag(pb, "minf");
1cb5f7fd 835 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
9a4d9388 836 mov_write_vmhd_tag(pb);
1cb5f7fd 837 else
9a4d9388
RS
838 mov_write_smhd_tag(pb);
839 if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
840 mov_write_hdlr_tag(pb, NULL);
841 mov_write_dinf_tag(pb);
842 mov_write_stbl_tag(pb, track);
f578f938 843 return updateSize(pb, pos);
1cb5f7fd
MN
844}
845
6e6d6dc0 846static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 847{
a3a80ddc
BC
848 int version = track->trackDuration < INT32_MAX ? 0 : 1;
849
850 (version == 1) ? put_be32(pb, 44) : put_be32(pb, 32); /* size */
1cb5f7fd 851 put_tag(pb, "mdhd");
a3a80ddc
BC
852 put_byte(pb, version);
853 put_be24(pb, 0); /* flags */
854 if (version == 1) {
855 put_be64(pb, track->time);
856 put_be64(pb, track->time);
857 } else {
858 put_be32(pb, track->time); /* creation time */
859 put_be32(pb, track->time); /* modification time */
860 }
115329f1 861 put_be32(pb, track->timescale); /* time scale (sample rate for audio) */
a3a80ddc 862 (version == 1) ? put_be64(pb, track->trackDuration) : put_be32(pb, track->trackDuration); /* duration */
ab561df9 863 put_be16(pb, track->language); /* language */
1cb5f7fd
MN
864 put_be16(pb, 0); /* reserved (quality) */
865 return 32;
866}
867
6e6d6dc0 868static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 869{
b29af723 870 offset_t pos = url_ftell(pb);
1cb5f7fd
MN
871 put_be32(pb, 0); /* size */
872 put_tag(pb, "mdia");
6e6d6dc0
MN
873 mov_write_mdhd_tag(pb, track);
874 mov_write_hdlr_tag(pb, track);
875 mov_write_minf_tag(pb, track);
876 return updateSize(pb, pos);
1cb5f7fd
MN
877}
878
6e6d6dc0 879static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 880{
a3a80ddc
BC
881 int64_t duration = av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP);
882 int version = duration < INT32_MAX ? 0 : 1;
883
884 (version == 1) ? put_be32(pb, 104) : put_be32(pb, 92); /* size */
1cb5f7fd 885 put_tag(pb, "tkhd");
a3a80ddc
BC
886 put_byte(pb, version);
887 put_be24(pb, 0xf); /* flags (track enabled) */
888 if (version == 1) {
889 put_be64(pb, track->time);
890 put_be64(pb, track->time);
891 } else {
892 put_be32(pb, track->time); /* creation time */
893 put_be32(pb, track->time); /* modification time */
894 }
1cb5f7fd
MN
895 put_be32(pb, track->trackID); /* track-id */
896 put_be32(pb, 0); /* reserved */
a3a80ddc 897 (version == 1) ? put_be64(pb, duration) : put_be32(pb, duration);
1cb5f7fd
MN
898
899 put_be32(pb, 0); /* reserved */
900 put_be32(pb, 0); /* reserved */
901 put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
902 /* Volume, only for audio */
903 if(track->enc->codec_type == CODEC_TYPE_AUDIO)
904 put_be16(pb, 0x0100);
905 else
906 put_be16(pb, 0);
907 put_be16(pb, 0); /* reserved */
908
909 /* Matrix structure */
910 put_be32(pb, 0x00010000); /* reserved */
911 put_be32(pb, 0x0); /* reserved */
912 put_be32(pb, 0x0); /* reserved */
913 put_be32(pb, 0x0); /* reserved */
914 put_be32(pb, 0x00010000); /* reserved */
915 put_be32(pb, 0x0); /* reserved */
916 put_be32(pb, 0x0); /* reserved */
917 put_be32(pb, 0x0); /* reserved */
918 put_be32(pb, 0x40000000); /* reserved */
919
920 /* Track width and height, for visual only */
921 if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
69dde1ad
GB
922 double sample_aspect_ratio = av_q2d(track->enc->sample_aspect_ratio);
923 if( !sample_aspect_ratio ) sample_aspect_ratio = 1;
924 put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000);
f578f938 925 put_be32(pb, track->enc->height*0x10000);
1cb5f7fd
MN
926 }
927 else {
928 put_be32(pb, 0);
929 put_be32(pb, 0);
930 }
931 return 0x5c;
932}
933
8af18154 934// This box seems important for the psp playback ... without it the movie seems to hang
935static int mov_write_edts_tag(ByteIOContext *pb, MOVTrack *track)
936{
8af18154 937 put_be32(pb, 0x24); /* size */
938 put_tag(pb, "edts");
939 put_be32(pb, 0x1c); /* size */
940 put_tag(pb, "elst");
941 put_be32(pb, 0x0);
942 put_be32(pb, 0x1);
943
83fa2ef8 944 put_be32(pb, av_rescale_rnd(track->trackDuration, globalTimescale, track->timescale, AV_ROUND_UP)); /* duration ... doesn't seem to effect psp */
8af18154 945
a336965e
BC
946 if (track->hasBframes)
947 put_be32(pb, track->sampleDuration); /* first pts is 1 */
948 else
949 put_be32(pb, 0);
8af18154 950 put_be32(pb, 0x00010000);
951 return 0x24;
952}
953
954// goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
955static int mov_write_uuid_tag_psp(ByteIOContext *pb, MOVTrack *mov)
956{
957 put_be32(pb, 0x34); /* size ... reports as 28 in mp4box! */
958 put_tag(pb, "uuid");
959 put_tag(pb, "USMT");
960 put_be32(pb, 0x21d24fce);
961 put_be32(pb, 0xbb88695c);
962 put_be32(pb, 0xfac9c740);
963 put_be32(pb, 0x1c); // another size here!
964 put_tag(pb, "MTDT");
965 put_be32(pb, 0x00010012);
966 put_be32(pb, 0x0a);
967 put_be32(pb, 0x55c40000);
968 put_be32(pb, 0x1);
969 put_be32(pb, 0x0);
970 return 0x34;
971}
972
6e6d6dc0 973static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 974{
b29af723 975 offset_t pos = url_ftell(pb);
1cb5f7fd
MN
976 put_be32(pb, 0); /* size */
977 put_tag(pb, "trak");
6e6d6dc0 978 mov_write_tkhd_tag(pb, track);
c6e722e5 979 if (track->mode == MODE_PSP || track->hasBframes)
8af18154 980 mov_write_edts_tag(pb, track); // PSP Movies require edts box
6e6d6dc0 981 mov_write_mdia_tag(pb, track);
115329f1 982 if (track->mode == MODE_PSP)
8af18154 983 mov_write_uuid_tag_psp(pb,track); // PSP Movies require this uuid box
6e6d6dc0 984 return updateSize(pb, pos);
1cb5f7fd
MN
985}
986
88730be6 987#if 0
1cb5f7fd 988/* TODO: Not sorted out, but not necessary either */
6e6d6dc0 989static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd
MN
990{
991 put_be32(pb, 0x15); /* size */
992 put_tag(pb, "iods");
993 put_be32(pb, 0); /* version & flags */
994 put_be16(pb, 0x1007);
995 put_byte(pb, 0);
996 put_be16(pb, 0x4fff);
997 put_be16(pb, 0xfffe);
998 put_be16(pb, 0x01ff);
999 return 0x15;
1000}
88730be6 1001#endif
1cb5f7fd 1002
6e6d6dc0 1003static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd 1004{
b29af723
MN
1005 int maxTrackID = 1, i;
1006 int64_t maxTrackLenTemp, maxTrackLen = 0;
a3a80ddc 1007 int version;
1cb5f7fd 1008
1cb5f7fd
MN
1009 for (i=0; i<MAX_STREAMS; i++) {
1010 if(mov->tracks[i].entry > 0) {
83fa2ef8 1011 maxTrackLenTemp = av_rescale_rnd(mov->tracks[i].trackDuration, globalTimescale, mov->tracks[i].timescale, AV_ROUND_UP);
f578f938
TR
1012 if(maxTrackLen < maxTrackLenTemp)
1013 maxTrackLen = maxTrackLenTemp;
1cb5f7fd
MN
1014 if(maxTrackID < mov->tracks[i].trackID)
1015 maxTrackID = mov->tracks[i].trackID;
1016 }
1017 }
a3a80ddc
BC
1018
1019 version = maxTrackLen < UINT32_MAX ? 0 : 1;
1020 (version == 1) ? put_be32(pb, 120) : put_be32(pb, 108); /* size */
1021 put_tag(pb, "mvhd");
1022 put_byte(pb, version);
1023 put_be24(pb, 0); /* flags */
1024 if (version == 1) {
1025 put_be64(pb, mov->time);
1026 put_be64(pb, mov->time);
1027 } else {
1028 put_be32(pb, mov->time); /* creation time */
1029 put_be32(pb, mov->time); /* modification time */
1030 }
1031 put_be32(pb, mov->timescale); /* timescale */
1032 (version == 1) ? put_be64(pb, maxTrackLen) : put_be32(pb, maxTrackLen); /* duration of longest track */
1cb5f7fd
MN
1033
1034 put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
1035 put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
1036 put_be16(pb, 0); /* reserved */
1037 put_be32(pb, 0); /* reserved */
1038 put_be32(pb, 0); /* reserved */
1039
1040 /* Matrix structure */
1041 put_be32(pb, 0x00010000); /* reserved */
1042 put_be32(pb, 0x0); /* reserved */
1043 put_be32(pb, 0x0); /* reserved */
1044 put_be32(pb, 0x0); /* reserved */
1045 put_be32(pb, 0x00010000); /* reserved */
1046 put_be32(pb, 0x0); /* reserved */
1047 put_be32(pb, 0x0); /* reserved */
1048 put_be32(pb, 0x0); /* reserved */
1049 put_be32(pb, 0x40000000); /* reserved */
1050
1051 put_be32(pb, 0); /* reserved (preview time) */
1052 put_be32(pb, 0); /* reserved (preview duration) */
1053 put_be32(pb, 0); /* reserved (poster time) */
1054 put_be32(pb, 0); /* reserved (selection time) */
1055 put_be32(pb, 0); /* reserved (selection duration) */
1056 put_be32(pb, 0); /* reserved (current time) */
1057 put_be32(pb, maxTrackID+1); /* Next track id */
1058 return 0x6c;
1059}
1060
b6c50eb1
PB
1061static int mov_write_itunes_hdlr_tag(ByteIOContext *pb, MOVContext* mov,
1062 AVFormatContext *s)
1063{
b29af723 1064 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1065 put_be32(pb, 0); /* size */
1066 put_tag(pb, "hdlr");
1067 put_be32(pb, 0);
1068 put_be32(pb, 0);
1069 put_tag(pb, "mdir");
1070 put_tag(pb, "appl");
1071 put_be32(pb, 0);
1072 put_be32(pb, 0);
1073 put_be16(pb, 0);
1074 return updateSize(pb, pos);
1075}
1076
1077/* helper function to write a data tag with the specified string as data */
1078static int mov_write_string_data_tag(ByteIOContext *pb, MOVContext* mov,
1079 AVFormatContext *s, const char *data)
1080{
b29af723 1081 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1082 put_be32(pb, 0); /* size */
1083 put_tag(pb, "data");
1084 put_be32(pb, 1);
1085 put_be32(pb, 0);
1086 put_buffer(pb, data, strlen(data));
1087 return updateSize(pb, pos);
1088}
1089
1090/* iTunes name of the song/movie */
1091static int mov_write_nam_tag(ByteIOContext *pb, MOVContext* mov,
1092 AVFormatContext *s)
1093{
1094 int size = 0;
1095 if ( s->title[0] ) {
b29af723 1096 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1097 put_be32(pb, 0); /* size */
1098 put_tag(pb, "\251nam");
1099 mov_write_string_data_tag(pb, mov, s, s->title);
1100 size = updateSize(pb, pos);
1101 }
1102 return size;
1103}
1104
1105/* iTunes name of the artist/performer */
1106static int mov_write_ART_tag(ByteIOContext *pb, MOVContext* mov,
1107 AVFormatContext *s)
1108{
1109 int size = 0;
1110 if ( s->author[0] ) {
b29af723 1111 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1112 put_be32(pb, 0); /* size */
1113 put_tag(pb, "\251ART");
1114 // we use the author here as this is the only thing that we have...
1115 mov_write_string_data_tag(pb, mov, s, s->author);
1116 size = updateSize(pb, pos);
1117 }
1118 return size;
1119}
1120
1121/* iTunes name of the writer */
1122static int mov_write_wrt_tag(ByteIOContext *pb, MOVContext* mov,
1123 AVFormatContext *s)
1124{
1125 int size = 0;
1126 if ( s->author[0] ) {
b29af723 1127 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1128 put_be32(pb, 0); /* size */
1129 put_tag(pb, "\251wrt");
1130 mov_write_string_data_tag(pb, mov, s, s->author);
1131 size = updateSize(pb, pos);
1132 }
1133 return size;
1134}
1135
1136/* iTunes name of the album */
1137static int mov_write_alb_tag(ByteIOContext *pb, MOVContext* mov,
1138 AVFormatContext *s)
1139{
1140 int size = 0;
1141 if ( s->album[0] ) {
b29af723 1142 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1143 put_be32(pb, 0); /* size */
1144 put_tag(pb, "\251alb");
1145 mov_write_string_data_tag(pb, mov, s, s->album);
1146 size = updateSize(pb, pos);
1147 }
1148 return size;
1149}
1150
1151/* iTunes year */
1152static int mov_write_day_tag(ByteIOContext *pb, MOVContext* mov,
1153 AVFormatContext *s)
1154{
1155 char year[5];
1156 int size = 0;
1157 if ( s->year ) {
b29af723 1158 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1159 put_be32(pb, 0); /* size */
1160 put_tag(pb, "\251day");
1161 snprintf(year, 5, "%04d", s->year);
1162 mov_write_string_data_tag(pb, mov, s, year);
1163 size = updateSize(pb, pos);
1164 }
1165 return size;
1166}
1167
1168/* iTunes tool used to create the file */
1169static int mov_write_too_tag(ByteIOContext *pb, MOVContext* mov,
1170 AVFormatContext *s)
1171{
b29af723 1172 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1173 put_be32(pb, 0); /* size */
1174 put_tag(pb, "\251too");
1175 mov_write_string_data_tag(pb, mov, s, LIBAVFORMAT_IDENT);
1176 return updateSize(pb, pos);
1177}
1178
1179/* iTunes comment */
1180static int mov_write_cmt_tag(ByteIOContext *pb, MOVContext* mov,
1181 AVFormatContext *s)
1182{
1183 int size = 0;
1184 if ( s->comment[0] ) {
b29af723 1185 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1186 put_be32(pb, 0); /* size */
1187 put_tag(pb, "\251cmt");
1188 mov_write_string_data_tag(pb, mov, s, s->comment);
1189 size = updateSize(pb, pos);
1190 }
1191 return size;
1192}
1193
1194/* iTunes custom genre */
1195static int mov_write_gen_tag(ByteIOContext *pb, MOVContext* mov,
1196 AVFormatContext *s)
1197{
1198 int size = 0;
1199 if ( s->genre[0] ) {
b29af723 1200 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1201 put_be32(pb, 0); /* size */
1202 put_tag(pb, "\251gen");
1203 mov_write_string_data_tag(pb, mov, s, s->genre);
1204 size = updateSize(pb, pos);
1205 }
1206 return size;
1207}
1208
1209/* iTunes track number */
1210static int mov_write_trkn_tag(ByteIOContext *pb, MOVContext* mov,
1211 AVFormatContext *s)
1212{
1213 int size = 0;
1214 if ( s->track ) {
b29af723 1215 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1216 put_be32(pb, 0); /* size */
1217 put_tag(pb, "trkn");
1218 {
b29af723 1219 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1220 put_be32(pb, 0); /* size */
1221 put_tag(pb, "data");
1222 put_be32(pb, 0); // 8 bytes empty
1223 put_be32(pb, 0);
1224 put_be16(pb, 0); // empty
1225 put_be16(pb, s->track); // track number
1226 put_be16(pb, 0); // total track number
1227 put_be16(pb, 0); // empty
1228 updateSize(pb, pos);
1229 }
1230 size = updateSize(pb, pos);
1231 }
1232 return size;
1233}
1234
1235/* iTunes meta data list */
1236static int mov_write_ilst_tag(ByteIOContext *pb, MOVContext* mov,
1237 AVFormatContext *s)
1238{
b29af723 1239 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1240 put_be32(pb, 0); /* size */
1241 put_tag(pb, "ilst");
1242 mov_write_nam_tag(pb, mov, s);
1243 mov_write_ART_tag(pb, mov, s);
1244 mov_write_wrt_tag(pb, mov, s);
1245 mov_write_alb_tag(pb, mov, s);
1246 mov_write_day_tag(pb, mov, s);
1247 mov_write_too_tag(pb, mov, s);
1248 mov_write_cmt_tag(pb, mov, s);
1249 mov_write_gen_tag(pb, mov, s);
1250 mov_write_trkn_tag(pb, mov, s);
1251 return updateSize(pb, pos);
1252}
1253
1254/* iTunes meta data tag */
1255static int mov_write_meta_tag(ByteIOContext *pb, MOVContext* mov,
1256 AVFormatContext *s)
1257{
1258 int size = 0;
1259
1260 // only save meta tag if required
115329f1 1261 if ( s->title[0] || s->author[0] || s->album[0] || s->year ||
b6c50eb1 1262 s->comment[0] || s->genre[0] || s->track ) {
b29af723 1263 offset_t pos = url_ftell(pb);
b6c50eb1
PB
1264 put_be32(pb, 0); /* size */
1265 put_tag(pb, "meta");
1266 put_be32(pb, 0);
1267 mov_write_itunes_hdlr_tag(pb, mov, s);
1268 mov_write_ilst_tag(pb, mov, s);
1269 size = updateSize(pb, pos);
1270 }
1271 return size;
1272}
115329f1 1273
69dde1ad
GB
1274static int mov_write_udta_tag(ByteIOContext *pb, MOVContext* mov,
1275 AVFormatContext *s)
1276{
b29af723 1277 offset_t pos = url_ftell(pb);
69dde1ad
GB
1278 int i;
1279
1280 put_be32(pb, 0); /* size */
1281 put_tag(pb, "udta");
1282
b6c50eb1
PB
1283 /* iTunes meta data */
1284 mov_write_meta_tag(pb, mov, s);
1285
69dde1ad
GB
1286 /* Requirements */
1287 for (i=0; i<MAX_STREAMS; i++) {
1288 if(mov->tracks[i].entry <= 0) continue;
1289 if (mov->tracks[i].enc->codec_id == CODEC_ID_AAC ||
1290 mov->tracks[i].enc->codec_id == CODEC_ID_MPEG4) {
b29af723 1291 offset_t pos = url_ftell(pb);
69dde1ad
GB
1292 put_be32(pb, 0); /* size */
1293 put_tag(pb, "\251req");
1294 put_be16(pb, sizeof("QuickTime 6.0 or greater") - 1);
1295 put_be16(pb, 0);
1296 put_buffer(pb, "QuickTime 6.0 or greater",
1297 sizeof("QuickTime 6.0 or greater") - 1);
1298 updateSize(pb, pos);
1299 break;
1300 }
1301 }
1302
1303 /* Encoder */
501866a1 1304 if(mov->tracks[0].enc && !(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT))
69dde1ad 1305 {
b29af723 1306 offset_t pos = url_ftell(pb);
69dde1ad
GB
1307 put_be32(pb, 0); /* size */
1308 put_tag(pb, "\251enc");
1309 put_be16(pb, sizeof(LIBAVFORMAT_IDENT) - 1); /* string length */
1310 put_be16(pb, 0);
1311 put_buffer(pb, LIBAVFORMAT_IDENT, sizeof(LIBAVFORMAT_IDENT) - 1);
1312 updateSize(pb, pos);
1313 }
1314
1315 if( s->title[0] )
1316 {
b29af723 1317 offset_t pos = url_ftell(pb);
69dde1ad
GB
1318 put_be32(pb, 0); /* size */
1319 put_tag(pb, "\251nam");
1320 put_be16(pb, strlen(s->title)); /* string length */
1321 put_be16(pb, 0);
1322 put_buffer(pb, s->title, strlen(s->title));
1323 updateSize(pb, pos);
1324 }
1325
1326 if( s->author[0] )
1327 {
b29af723 1328 offset_t pos = url_ftell(pb);
69dde1ad
GB
1329 put_be32(pb, 0); /* size */
1330 put_tag(pb, /*"\251aut"*/ "\251day" );
1331 put_be16(pb, strlen(s->author)); /* string length */
1332 put_be16(pb, 0);
1333 put_buffer(pb, s->author, strlen(s->author));
1334 updateSize(pb, pos);
1335 }
1336
1337 if( s->comment[0] )
1338 {
b29af723 1339 offset_t pos = url_ftell(pb);
69dde1ad
GB
1340 put_be32(pb, 0); /* size */
1341 put_tag(pb, "\251des");
1342 put_be16(pb, strlen(s->comment)); /* string length */
1343 put_be16(pb, 0);
1344 put_buffer(pb, s->comment, strlen(s->comment));
1345 updateSize(pb, pos);
1346 }
1347
1348 return updateSize(pb, pos);
1349}
1350
dcfdb046
BL
1351
1352static size_t ascii_to_wc (ByteIOContext *pb, char *b, size_t n)
1353{
1354 size_t i;
1355 unsigned char c;
1356 for (i = 0; i < n - 1; i++) {
1357 c = b[i];
1358 if (! (0x20 <= c && c <= 0x7f ))
1359 c = 0x3f; /* '?' */
1360 put_be16(pb, c);
1361 }
1362 put_be16(pb, 0x00);
1363 return 2*n;
1364}
1365
1366static uint16_t language_code (char *str)
1367{
1368 return ((((str[0]-'a') & 0x1F)<<10) + (((str[1]-'a') & 0x1F)<<5) + ((str[2]-'a') & 0x1F));
1369}
1370
1371static int mov_write_uuidusmt_tag (ByteIOContext *pb, AVFormatContext *s)
1372{
1373 size_t len, size;
1374 offset_t pos, curpos;
1375
1376 size = 0;
1377 if (s->title[0]) {
1378 pos = url_ftell(pb);
1379 put_be32(pb, 0); /* size placeholder*/
1380 put_tag(pb, "uuid");
1381 put_tag(pb, "USMT");
1382 put_be32(pb, 0x21d24fce ); /* 96 bit UUID */
1383 put_be32(pb, 0xbb88695c );
1384 put_be32(pb, 0xfac9c740 );
1385 size += 24;
1386
1387 put_be32(pb, 0); /* size placeholder*/
1388 put_tag(pb, "MTDT");
1389 put_be16(pb, 1);
1390 size += 10;
1391
1392 // Title
1393 len = strlen(s->title)+1;
1394 put_be16(pb, len*2+10); /* size */
1395 put_be32(pb, 0x01); /* type */
1396 put_be16(pb, language_code("und")); /* language */
1397 put_be16(pb, 0x01); /* ? */
1398 ascii_to_wc (pb, s->title, len);
1399 size += len*2+10;
1400
1401 // size
1402 curpos = url_ftell(pb);
1403 url_fseek(pb, pos, SEEK_SET);
1404 put_be32(pb, size);
1405 url_fseek(pb, pos+24, SEEK_SET);
1406 put_be32(pb, size-24);
1407 url_fseek(pb, curpos, SEEK_SET);
1408 }
1409
1410 return size;
1411}
1412
69dde1ad
GB
1413static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov,
1414 AVFormatContext *s)
1cb5f7fd 1415{
b29af723
MN
1416 int i;
1417 offset_t pos = url_ftell(pb);
1cb5f7fd
MN
1418 put_be32(pb, 0); /* size placeholder*/
1419 put_tag(pb, "moov");
1420 mov->timescale = globalTimescale;
1421
1422 for (i=0; i<MAX_STREAMS; i++) {
e45ccf79
GB
1423 if(mov->tracks[i].entry <= 0) continue;
1424
1425 if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) {
c0df9d75
MN
1426 mov->tracks[i].timescale = mov->tracks[i].enc->time_base.den;
1427 mov->tracks[i].sampleDuration = mov->tracks[i].enc->time_base.num;
b451719e
BC
1428 } else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
1429 mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate;
1430 mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_size;
1cb5f7fd 1431 }
e45ccf79 1432
115329f1 1433 mov->tracks[i].trackDuration =
a3a80ddc 1434 (int64_t)mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration;
e45ccf79
GB
1435 mov->tracks[i].time = mov->time;
1436 mov->tracks[i].trackID = i+1;
1cb5f7fd
MN
1437 }
1438
6e6d6dc0
MN
1439 mov_write_mvhd_tag(pb, mov);
1440 //mov_write_iods_tag(pb, mov);
1cb5f7fd
MN
1441 for (i=0; i<MAX_STREAMS; i++) {
1442 if(mov->tracks[i].entry > 0) {
6e6d6dc0 1443 mov_write_trak_tag(pb, &(mov->tracks[i]));
1cb5f7fd
MN
1444 }
1445 }
1446
dcfdb046
BL
1447 if (mov->mode == MODE_PSP)
1448 mov_write_uuidusmt_tag(pb, s);
1449 else
69dde1ad
GB
1450 mov_write_udta_tag(pb, mov, s);
1451
6e6d6dc0 1452 return updateSize(pb, pos);
1cb5f7fd
MN
1453}
1454
f578f938 1455int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov)
1cb5f7fd 1456{
b29af723
MN
1457 put_be32(pb, 8); // placeholder for extended size field (64 bit)
1458 put_tag(pb, "wide");
1459
115329f1 1460 mov->mdat_pos = url_ftell(pb);
1cb5f7fd
MN
1461 put_be32(pb, 0); /* size placeholder*/
1462 put_tag(pb, "mdat");
1463 return 0;
1464}
1465
1466/* TODO: This needs to be more general */
dcfdb046 1467static void mov_write_ftyp_tag (ByteIOContext *pb, AVFormatContext *s)
1cb5f7fd 1468{
69dde1ad
GB
1469 MOVContext *mov = s->priv_data;
1470
1cb5f7fd
MN
1471 put_be32(pb, 0x14 ); /* size */
1472 put_tag(pb, "ftyp");
e45ccf79 1473
69dde1ad 1474 if ( mov->mode == MODE_3GP )
e45ccf79 1475 put_tag(pb, "3gp4");
8536ab89 1476 else if ( mov->mode == MODE_3G2 )
1477 put_tag(pb, "3g2a");
8af18154 1478 else if ( mov->mode == MODE_PSP )
1479 put_tag(pb, "MSNV");
26f86eaf 1480 else if ( mov->mode == MODE_MP4 )
e45ccf79 1481 put_tag(pb, "isom");
26f86eaf
BC
1482 else
1483 put_tag(pb, "qt ");
e45ccf79 1484
1cb5f7fd 1485 put_be32(pb, 0x200 );
e45ccf79 1486
69dde1ad 1487 if ( mov->mode == MODE_3GP )
e45ccf79 1488 put_tag(pb, "3gp4");
8536ab89 1489 else if ( mov->mode == MODE_3G2 )
1490 put_tag(pb, "3g2a");
8af18154 1491 else if ( mov->mode == MODE_PSP )
1492 put_tag(pb, "MSNV");
26f86eaf 1493 else if ( mov->mode == MODE_MP4 )
e45ccf79 1494 put_tag(pb, "mp41");
26f86eaf
BC
1495 else
1496 put_tag(pb, "qt ");
1cb5f7fd
MN
1497}
1498
0c716ab7 1499static void mov_write_uuidprof_tag(ByteIOContext *pb, AVFormatContext *s)
8af18154 1500{
dcfdb046
BL
1501 AVCodecContext *VideoCodec = s->streams[0]->codec;
1502 AVCodecContext *AudioCodec = s->streams[1]->codec;
1503 int AudioRate = AudioCodec->sample_rate;
1504 int FrameRate = ((VideoCodec->time_base.den) * (0x10000))/ (VideoCodec->time_base.num);
9e282ba3
MN
1505 int audio_kbitrate= AudioCodec->bit_rate / 1000;
1506 int video_kbitrate= FFMIN(VideoCodec->bit_rate / 1000, 800 - audio_kbitrate);
8af18154 1507
1508 put_be32(pb, 0x94 ); /* size */
1509 put_tag(pb, "uuid");
1510 put_tag(pb, "PROF");
1511
1512 put_be32(pb, 0x21d24fce ); /* 96 bit UUID */
1513 put_be32(pb, 0xbb88695c );
1514 put_be32(pb, 0xfac9c740 );
1515
1516 put_be32(pb, 0x0 ); /* ? */
1517 put_be32(pb, 0x3 ); /* 3 sections ? */
1518
1519 put_be32(pb, 0x14 ); /* size */
1520 put_tag(pb, "FPRF");
1521 put_be32(pb, 0x0 ); /* ? */
1522 put_be32(pb, 0x0 ); /* ? */
1523 put_be32(pb, 0x0 ); /* ? */
1524
1525 put_be32(pb, 0x2c ); /* size */
1526 put_tag(pb, "APRF"); /* audio */
1527 put_be32(pb, 0x0 );
dcfdb046 1528 put_be32(pb, 0x2 ); /* TrackID */
8af18154 1529 put_tag(pb, "mp4a");
1530 put_be32(pb, 0x20f );
1531 put_be32(pb, 0x0 );
9e282ba3
MN
1532 put_be32(pb, audio_kbitrate);
1533 put_be32(pb, audio_kbitrate);
dcfdb046
BL
1534 put_be32(pb, AudioRate );
1535 put_be32(pb, AudioCodec->channels );
8af18154 1536
1537 put_be32(pb, 0x34 ); /* size */
1538 put_tag(pb, "VPRF"); /* video */
1539 put_be32(pb, 0x0 );
dcfdb046 1540 put_be32(pb, 0x1 ); /* TrackID */
87b041e0
MN
1541 if (VideoCodec->codec_id == CODEC_ID_H264) {
1542 put_tag(pb, "avc1");
1543 put_be16(pb, 0x014D );
1544 put_be16(pb, 0x0015 );
1545 } else {
1546 put_tag(pb, "mp4v");
1547 put_be16(pb, 0x0000 );
1548 put_be16(pb, 0x0103 );
1549 }
8af18154 1550 put_be32(pb, 0x0 );
9e282ba3
MN
1551 put_be32(pb, video_kbitrate);
1552 put_be32(pb, video_kbitrate);
dcfdb046
BL
1553 put_be32(pb, FrameRate);
1554 put_be32(pb, FrameRate);
1555 put_be16(pb, VideoCodec->width);
1556 put_be16(pb, VideoCodec->height);
1557 put_be32(pb, 0x010001); /* ? */
8af18154 1558}
1559
1cb5f7fd
MN
1560static int mov_write_header(AVFormatContext *s)
1561{
1562 ByteIOContext *pb = &s->pb;
69dde1ad
GB
1563 MOVContext *mov = s->priv_data;
1564 int i;
1cb5f7fd 1565
1522767d
BC
1566 /* Default mode == MP4 */
1567 mov->mode = MODE_MP4;
1568
1569 if (s->oformat != NULL) {
1570 if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP;
1571 else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3G2;
1572 else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV;
1573 else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP;
1574
26f86eaf 1575 mov_write_ftyp_tag(pb,s);
1522767d
BC
1576 if ( mov->mode == MODE_PSP ) {
1577 if ( s->nb_streams != 2 ) {
1578 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
1579 return -1;
1580 }
1581 mov_write_uuidprof_tag(pb,s);
1582 }
1583 }
1584
ffdd57d4 1585 for(i=0; i<s->nb_streams; i++){
01f4895c 1586 AVCodecContext *c= s->streams[i]->codec;
ffdd57d4 1587
b4712e3c
BC
1588 if(c->codec_type == CODEC_TYPE_VIDEO){
1589 av_set_pts_info(s->streams[i], 64, 1, c->time_base.den);
ffdd57d4
MN
1590 if (!codec_get_tag(codec_movvideo_tags, c->codec_id)){
1591 if(!codec_get_tag(codec_bmp_tags, c->codec_id))
1592 return -1;
1593 else
1594 av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, the file may be unplayable!\n");
1595 }
1596 }else if(c->codec_type == CODEC_TYPE_AUDIO){
b4712e3c 1597 av_set_pts_info(s->streams[i], 64, 1, c->sample_rate);
ffdd57d4
MN
1598 if (!codec_get_tag(codec_movaudio_tags, c->codec_id)){
1599 if(!codec_get_tag(codec_wav_tags, c->codec_id))
1600 return -1;
1601 else
1602 av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, the file may be unplayable!\n");
1603 }
1604 }
1522767d 1605 mov->tracks[i].language = ff_mov_iso639_to_lang(s->streams[i]->language, mov->mode != MODE_MOV);
69dde1ad
GB
1606 }
1607
1608 for (i=0; i<MAX_STREAMS; i++) {
1609 mov->tracks[i].mode = mov->mode;
f578f938
TR
1610 }
1611
18c697ac
BC
1612 mov_write_mdat_tag(pb, mov);
1613 mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based
1614
1cb5f7fd
MN
1615 put_flush_packet(pb);
1616
1617 return 0;
1618}
1619
e928649b 1620static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
1cb5f7fd
MN
1621{
1622 MOVContext *mov = s->priv_data;
1623 ByteIOContext *pb = &s->pb;
01f4895c 1624 AVCodecContext *enc = s->streams[pkt->stream_index]->codec;
e928649b 1625 MOVTrack* trk = &mov->tracks[pkt->stream_index];
1a31840c 1626 int cl, id;
e45ccf79 1627 unsigned int samplesInChunk = 0;
e928649b 1628 int size= pkt->size;
1cb5f7fd 1629
e45ccf79
GB
1630 if (url_is_streamed(&s->pb)) return 0; /* Can't handle that */
1631 if (!size) return 0; /* Discard 0 sized packets */
1cb5f7fd 1632
5616f85d
BC
1633 if (enc->codec_type == CODEC_TYPE_AUDIO) {
1634 switch (enc->codec_id) {
1635 case CODEC_ID_AMR_NB:
1636 { /* We must find out how many AMR blocks there are in one packet */
1637 static uint16_t packed_size[16] =
1638 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
1639 int len = 0;
1640
1641 while (len < size && samplesInChunk < 100) {
1642 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
1643 samplesInChunk++;
1644 }
f578f938 1645 }
5616f85d
BC
1646 break;
1647 case CODEC_ID_PCM_ALAW:
e45ccf79 1648 samplesInChunk = size/enc->channels;
5616f85d
BC
1649 break;
1650 case CODEC_ID_PCM_S16BE:
1651 case CODEC_ID_PCM_S16LE:
bb270c08 1652 samplesInChunk = size/(2*enc->channels);
5616f85d
BC
1653 break;
1654 default:
e45ccf79 1655 samplesInChunk = 1;
1cb5f7fd 1656 }
5616f85d
BC
1657 } else {
1658 samplesInChunk = 1;
e45ccf79
GB
1659 }
1660
5616f85d
BC
1661 /* copy extradata if it exists */
1662 if (trk->vosLen == 0 && enc->extradata_size > 0) {
e45ccf79
GB
1663 trk->vosLen = enc->extradata_size;
1664 trk->vosData = av_malloc(trk->vosLen);
1665 memcpy(trk->vosData, enc->extradata, trk->vosLen);
1666 }
1667
5616f85d
BC
1668 if (enc->codec_id == CODEC_ID_H264 && trk->vosLen > 0 && *(uint8_t *)trk->vosData != 1) {
1669 /* from x264 or from bytestream h264 */
1670 /* nal reformating needed */
1671 avc_parse_nal_units(&pkt->data, &pkt->size);
1672 assert(pkt->size);
1673 size = pkt->size;
c1b8e6d8
BC
1674 }
1675
e45ccf79
GB
1676 cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
1677 id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
1678
1679 if (trk->ents_allocated <= trk->entry) {
115329f1 1680 trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*));
e45ccf79
GB
1681 if (!trk->cluster)
1682 return -1;
1683 trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
1684 if (!trk->cluster[cl])
1685 return -1;
1686 trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
1687 }
e45ccf79 1688
69dde1ad 1689 trk->cluster[cl][id].pos = url_ftell(pb);
e45ccf79
GB
1690 trk->cluster[cl][id].samplesInChunk = samplesInChunk;
1691 trk->cluster[cl][id].size = size;
1692 trk->cluster[cl][id].entries = samplesInChunk;
1693 if(enc->codec_type == CODEC_TYPE_VIDEO) {
b4712e3c
BC
1694 if (pkt->dts != pkt->pts)
1695 trk->hasBframes = 1;
1696 trk->cluster[cl][id].cts = pkt->pts - pkt->dts;
e928649b
MN
1697 trk->cluster[cl][id].key_frame = !!(pkt->flags & PKT_FLAG_KEY);
1698 if(trk->cluster[cl][id].key_frame)
32ba6fb1 1699 trk->hasKeyframes++;
1cb5f7fd 1700 }
e45ccf79
GB
1701 trk->enc = enc;
1702 trk->entry++;
1703 trk->sampleCount += samplesInChunk;
1704 trk->mdat_size += size;
1705
e928649b 1706 put_buffer(pb, pkt->data, size);
1cb5f7fd
MN
1707
1708 put_flush_packet(pb);
1709 return 0;
1710}
1711
1712static int mov_write_trailer(AVFormatContext *s)
1713{
1714 MOVContext *mov = s->priv_data;
1715 ByteIOContext *pb = &s->pb;
1716 int res = 0;
b29af723
MN
1717 int i;
1718 uint64_t j;
1cb5f7fd 1719
69dde1ad 1720 offset_t moov_pos = url_ftell(pb);
1cb5f7fd
MN
1721
1722 /* Write size of mdat tag */
69dde1ad 1723 for (i=0, j=0; i<MAX_STREAMS; i++) {
1cb5f7fd
MN
1724 if(mov->tracks[i].ents_allocated > 0) {
1725 j += mov->tracks[i].mdat_size;
1726 }
1727 }
b29af723
MN
1728 if (j+8 <= UINT32_MAX) {
1729 url_fseek(pb, mov->mdat_pos, SEEK_SET);
1730 put_be32(pb, j+8);
1731 } else {
1732 /* overwrite 'wide' placeholder atom */
1733 url_fseek(pb, mov->mdat_pos - 8, SEEK_SET);
1734 put_be32(pb, 1); /* special value: real atom size will be 64 bit value after tag field */
1735 put_tag(pb, "mdat");
1736 put_be64(pb, j+16);
1737 }
69dde1ad 1738 url_fseek(pb, moov_pos, SEEK_SET);
1cb5f7fd 1739
69dde1ad 1740 mov_write_moov_tag(pb, mov, s);
1cb5f7fd
MN
1741
1742 for (i=0; i<MAX_STREAMS; i++) {
1743 for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
1744 av_free(mov->tracks[i].cluster[j]);
1745 }
1746 av_free(mov->tracks[i].cluster);
ec7d0d2e
GB
1747 if( mov->tracks[i].vosLen ) av_free( mov->tracks[i].vosData );
1748
1cb5f7fd
MN
1749 mov->tracks[i].cluster = NULL;
1750 mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
1751 }
69dde1ad 1752
1cb5f7fd
MN
1753 put_flush_packet(pb);
1754
1755 return res;
1756}
1757
1758static AVOutputFormat mov_oformat = {
1759 "mov",
1760 "mov format",
1761 NULL,
1762 "mov",
1763 sizeof(MOVContext),
69dde1ad 1764 CODEC_ID_AAC,
2187d948 1765 CODEC_ID_MPEG4,
1cb5f7fd
MN
1766 mov_write_header,
1767 mov_write_packet,
1768 mov_write_trailer,
c64d476c 1769 .flags = AVFMT_GLOBALHEADER,
1cb5f7fd
MN
1770};
1771
1772static AVOutputFormat _3gp_oformat = {
1773 "3gp",
1774 "3gp format",
1775 NULL,
1776 "3gp",
1777 sizeof(MOVContext),
1778 CODEC_ID_AMR_NB,
1779 CODEC_ID_H263,
1780 mov_write_header,
1781 mov_write_packet,
1782 mov_write_trailer,
c64d476c 1783 .flags = AVFMT_GLOBALHEADER,
1cb5f7fd
MN
1784};
1785
1786static AVOutputFormat mp4_oformat = {
1787 "mp4",
1788 "mp4 format",
4cb3f3b6
DC
1789 "application/mp4",
1790 "mp4,m4a",
1cb5f7fd
MN
1791 sizeof(MOVContext),
1792 CODEC_ID_AAC,
1793 CODEC_ID_MPEG4,
1794 mov_write_header,
1795 mov_write_packet,
1796 mov_write_trailer,
c64d476c 1797 .flags = AVFMT_GLOBALHEADER,
1cb5f7fd
MN
1798};
1799
8af18154 1800static AVOutputFormat psp_oformat = {
1801 "psp",
1802 "psp mp4 format",
1803 NULL,
1804 "mp4,psp",
1805 sizeof(MOVContext),
1806 CODEC_ID_AAC,
1807 CODEC_ID_MPEG4,
1808 mov_write_header,
1809 mov_write_packet,
1810 mov_write_trailer,
dcfdb046 1811 .flags = AVFMT_GLOBALHEADER,
8af18154 1812};
1813
8536ab89 1814static AVOutputFormat _3g2_oformat = {
1815 "3g2",
1816 "3gp2 format",
1817 NULL,
1818 "3g2",
1819 sizeof(MOVContext),
1820 CODEC_ID_AMR_NB,
1821 CODEC_ID_H263,
1822 mov_write_header,
1823 mov_write_packet,
1824 mov_write_trailer,
c64d476c 1825 .flags = AVFMT_GLOBALHEADER,
8536ab89 1826};
1827
1cb5f7fd
MN
1828int movenc_init(void)
1829{
1830 av_register_output_format(&mov_oformat);
1831 av_register_output_format(&_3gp_oformat);
1832 av_register_output_format(&mp4_oformat);
8af18154 1833 av_register_output_format(&psp_oformat);
8536ab89 1834 av_register_output_format(&_3g2_oformat);
1cb5f7fd
MN
1835 return 0;
1836}