rle_code can overflow when multiplied by 4
[libav.git] / libavformat / movenc.c
CommitLineData
1cb5f7fd
MN
1/*
2 * MOV, 3GP, MP4 encoder.
3 * Copyright (c) 2003 Thomas Raivio.
e45ccf79 4 * Enhancements by Gildas Bazin <gbazin@netcourrier.com>
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
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include "avformat.h"
f578f938 21#include "avi.h"
1cb5f7fd 22#include "avio.h"
1cb5f7fd 23
6e6d6dc0
MN
24#undef NDEBUG
25#include <assert.h>
26
1cb5f7fd
MN
27#define MOV_INDEX_CLUSTER_SIZE 16384
28#define globalTimescale 1000
29
30typedef struct MOVIentry {
e45ccf79
GB
31 unsigned int flags, pos, size;
32 unsigned int samplesInChunk;
f578f938 33 char key_frame;
1cb5f7fd
MN
34 unsigned int entries;
35} MOVIentry;
36
37typedef struct MOVIndex {
38 int entry;
1cb5f7fd 39 int mdat_size;
1cb5f7fd
MN
40 int ents_allocated;
41 long timescale;
42 long time;
f578f938 43 long trackDuration;
e45ccf79
GB
44 long sampleCount;
45 long sampleDuration;
f578f938 46 int hasKeyframes;
1cb5f7fd
MN
47 int trackID;
48 AVCodecContext *enc;
49
50 int vosLen;
6e6d6dc0 51 uint8_t *vosData;
1cb5f7fd
MN
52 MOVIentry** cluster;
53} MOVTrack;
54
55typedef struct {
56 long time;
57 int nb_streams;
f578f938
TR
58 int mdat_written;
59 offset_t mdat_pos;
1cb5f7fd
MN
60 offset_t movi_list;
61 long timescale;
62 MOVTrack tracks[MAX_STREAMS];
63} MOVContext;
64
e45ccf79
GB
65static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track);
66
6e6d6dc0
MN
67//FIXME supprt 64bit varaint with wide placeholders
68static int updateSize (ByteIOContext *pb, int pos)
1cb5f7fd
MN
69{
70 long curpos = url_ftell(pb);
71 url_fseek(pb, pos, SEEK_SET);
6e6d6dc0 72 put_be32(pb, curpos - pos); /* rewrite size */
1cb5f7fd 73 url_fseek(pb, curpos, SEEK_SET);
6e6d6dc0
MN
74
75 return curpos - pos;
1cb5f7fd
MN
76}
77
e45ccf79 78/* Chunk offset atom */
6e6d6dc0 79static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
80{
81 int i;
f578f938
TR
82 int pos = url_ftell(pb);
83 put_be32(pb, 0); /* size */
1cb5f7fd
MN
84 put_tag(pb, "stco");
85 put_be32(pb, 0); /* version & flags */
86 put_be32(pb, track->entry); /* entry count */
87 for (i=0; i<track->entry; i++) {
88 int cl = i / MOV_INDEX_CLUSTER_SIZE;
89 int id = i % MOV_INDEX_CLUSTER_SIZE;
90 put_be32(pb, track->cluster[cl][id].pos);
91 }
f578f938 92 return updateSize (pb, pos);
1cb5f7fd
MN
93}
94
e45ccf79 95/* Sample size atom */
6e6d6dc0 96static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 97{
f578f938 98 int equalChunks = 1;
e45ccf79 99 int i, j, entries = 0, tst = -1, oldtst = -1;
1cb5f7fd 100
f578f938
TR
101 int pos = url_ftell(pb);
102 put_be32(pb, 0); /* size */
1cb5f7fd
MN
103 put_tag(pb, "stsz");
104 put_be32(pb, 0); /* version & flags */
105
f578f938
TR
106 for (i=0; i<track->entry; i++) {
107 int cl = i / MOV_INDEX_CLUSTER_SIZE;
108 int id = i % MOV_INDEX_CLUSTER_SIZE;
e45ccf79
GB
109 tst = track->cluster[cl][id].size/track->cluster[cl][id].entries;
110 if(oldtst != -1 && tst != oldtst) {
111 equalChunks = 0;
f578f938
TR
112 }
113 oldtst = tst;
e45ccf79 114 entries += track->cluster[cl][id].entries;
f578f938 115 }
e45ccf79
GB
116 if (equalChunks) {
117 int sSize = track->cluster[0][0].size/track->cluster[0][0].entries;
f578f938 118 put_be32(pb, sSize); // sample size
e45ccf79 119 put_be32(pb, entries); // sample count
1cb5f7fd 120 }
f578f938
TR
121 else {
122 put_be32(pb, 0); // sample size
e45ccf79 123 put_be32(pb, entries); // sample count
f578f938 124 for (i=0; i<track->entry; i++) {
1cb5f7fd
MN
125 int cl = i / MOV_INDEX_CLUSTER_SIZE;
126 int id = i % MOV_INDEX_CLUSTER_SIZE;
e45ccf79
GB
127 for ( j=0; j<track->cluster[cl][id].entries; j++) {
128 put_be32(pb, track->cluster[cl][id].size /
129 track->cluster[cl][id].entries);
130 }
1cb5f7fd
MN
131 }
132 }
f578f938 133 return updateSize (pb, pos);
1cb5f7fd
MN
134}
135
e45ccf79 136/* Sample to chunk atom */
6e6d6dc0 137static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 138{
f578f938
TR
139 int index = 0, oldval = -1, i, entryPos, curpos;
140
141 int pos = url_ftell(pb);
142 put_be32(pb, 0); /* size */
1cb5f7fd
MN
143 put_tag(pb, "stsc");
144 put_be32(pb, 0); // version & flags
f578f938
TR
145 entryPos = url_ftell(pb);
146 put_be32(pb, track->entry); // entry count
147 for (i=0; i<track->entry; i++) {
148 int cl = i / MOV_INDEX_CLUSTER_SIZE;
149 int id = i % MOV_INDEX_CLUSTER_SIZE;
e45ccf79 150 if(oldval != track->cluster[cl][id].samplesInChunk)
f578f938 151 {
1cb5f7fd 152 put_be32(pb, i+1); // first chunk
e45ccf79 153 put_be32(pb, track->cluster[cl][id].samplesInChunk); // samples per chunk
1cb5f7fd 154 put_be32(pb, 0x1); // sample description index
e45ccf79 155 oldval = track->cluster[cl][id].samplesInChunk;
f578f938 156 index++;
1cb5f7fd
MN
157 }
158 }
f578f938
TR
159 curpos = url_ftell(pb);
160 url_fseek(pb, entryPos, SEEK_SET);
161 put_be32(pb, index); // rewrite size
162 url_fseek(pb, curpos, SEEK_SET);
1cb5f7fd 163
f578f938 164 return updateSize (pb, pos);
1cb5f7fd
MN
165}
166
e45ccf79 167/* Sync sample atom */
f578f938 168static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 169{
f578f938
TR
170 long curpos;
171 int i, index = 0, entryPos;
172 int pos = url_ftell(pb);
173 put_be32(pb, 0); // size
1cb5f7fd 174 put_tag(pb, "stss");
f578f938
TR
175 put_be32(pb, 0); // version & flags
176 entryPos = url_ftell(pb);
177 put_be32(pb, track->entry); // entry count
178 for (i=0; i<track->entry; i++) {
179 int cl = i / MOV_INDEX_CLUSTER_SIZE;
180 int id = i % MOV_INDEX_CLUSTER_SIZE;
181 if(track->cluster[cl][id].key_frame == 1) {
182 put_be32(pb, i+1);
183 index++;
184 }
185 }
186 curpos = url_ftell(pb);
187 url_fseek(pb, entryPos, SEEK_SET);
188 put_be32(pb, index); // rewrite size
189 url_fseek(pb, curpos, SEEK_SET);
190 return updateSize (pb, pos);
1cb5f7fd
MN
191}
192
6e6d6dc0 193static int mov_write_damr_tag(ByteIOContext *pb)
1cb5f7fd
MN
194{
195 put_be32(pb, 0x11); /* size */
196 put_tag(pb, "damr");
197 put_tag(pb, "FFMP");
198 put_byte(pb, 0);
f578f938
TR
199
200 put_be16(pb, 0x80); /* Mode set (all modes for AMR_NB) */
201 put_be16(pb, 0xa); /* Mode change period (no restriction) */
202 //put_be16(pb, 0x81ff); /* Mode set (all modes for AMR_NB) */
203 //put_be16(pb, 1); /* Mode change period (no restriction) */
1cb5f7fd
MN
204 return 0x11;
205}
206
f578f938 207static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 208{
6e6d6dc0 209 int pos = url_ftell(pb);
1cb5f7fd 210 put_be32(pb, 0); /* size */
f578f938
TR
211
212 if(track->enc->codec_id == CODEC_ID_PCM_MULAW)
213 put_tag(pb, "ulaw");
214 else if(track->enc->codec_id == CODEC_ID_PCM_ALAW)
215 put_tag(pb, "alaw");
216 else if(track->enc->codec_id == CODEC_ID_ADPCM_IMA_QT)
217 put_tag(pb, "ima4");
218 else if(track->enc->codec_id == CODEC_ID_MACE3)
219 put_tag(pb, "MAC3");
220 else if(track->enc->codec_id == CODEC_ID_MACE6)
221 put_tag(pb, "MAC6");
222 else if(track->enc->codec_id == CODEC_ID_AAC)
223 put_tag(pb, "mp4a");
224 else if(track->enc->codec_id == CODEC_ID_AMR_NB)
225 put_tag(pb, "samr");
226 else
227 put_tag(pb, " ");
228
1cb5f7fd
MN
229 put_be32(pb, 0); /* Reserved */
230 put_be16(pb, 0); /* Reserved */
231 put_be16(pb, 1); /* Data-reference index, XXX == 1 */
e45ccf79
GB
232 /* SoundDescription */
233 put_be16(pb, 0); /* Version */
234 put_be16(pb, 0); /* Revision level */
1cb5f7fd
MN
235 put_be32(pb, 0); /* Reserved */
236
f578f938
TR
237 put_be16(pb, track->enc->channels); /* Number of channels */
238 /* TODO: Currently hard-coded to 16-bit, there doesn't seem
e45ccf79 239 to be a good way to get number of bits of audio */
1cb5f7fd 240 put_be16(pb, 0x10); /* Reserved */
f578f938
TR
241 put_be16(pb, 0); /* compression ID (= 0) */
242 put_be16(pb, 0); /* packet size (= 0) */
1cb5f7fd
MN
243 put_be16(pb, track->timescale); /* Time scale */
244 put_be16(pb, 0); /* Reserved */
245
e45ccf79
GB
246 if(track->enc->codec_id == CODEC_ID_AAC)
247 mov_write_esds_tag(pb, track);
f578f938
TR
248 if(track->enc->codec_id == CODEC_ID_AMR_NB)
249 mov_write_damr_tag(pb);
6e6d6dc0 250 return updateSize (pb, pos);
1cb5f7fd
MN
251}
252
6e6d6dc0 253static int mov_write_d263_tag(ByteIOContext *pb)
1cb5f7fd
MN
254{
255 put_be32(pb, 0xf); /* size */
256 put_tag(pb, "d263");
257 put_tag(pb, "FFMP");
258 put_be16(pb, 0x0a);
259 put_byte(pb, 0);
260 return 0xf;
261}
262
f578f938
TR
263/* TODO: No idea about these values */
264static int mov_write_svq3_tag(ByteIOContext *pb)
1cb5f7fd 265{
f578f938
TR
266 put_be32(pb, 0x15);
267 put_tag(pb, "SMI ");
268 put_tag(pb, "SEQH");
269 put_be32(pb, 0x5);
270 put_be32(pb, 0xe2c0211d);
271 put_be32(pb, 0xc0000000);
272 put_byte(pb, 0);
273 return 0x15;
1cb5f7fd
MN
274}
275
e45ccf79
GB
276static unsigned int descrLength(unsigned int len)
277{
278 if (len < 0x00000080)
279 return 2 + len;
280 else if (len < 0x00004000)
281 return 3 + len;
282 else if(len < 0x00200000)
283 return 4 + len;
284 else
285 return 5 + len;
286}
287
288static void putDescr(ByteIOContext *pb, int tag, int size)
1cb5f7fd 289{
e45ccf79
GB
290 uint32_t len;
291 uint8_t vals[4];
292
293 len = size;
294 vals[3] = (uint8_t)(len & 0x7f);
295 len >>= 7;
296 vals[2] = (uint8_t)((len & 0x7f) | 0x80);
297 len >>= 7;
298 vals[1] = (uint8_t)((len & 0x7f) | 0x80);
299 len >>= 7;
300 vals[0] = (uint8_t)((len & 0x7f) | 0x80);
301
302 put_byte(pb, tag); // DescriptorTag
303
304 if (size < 0x00000080)
305 {
306 put_byte(pb, vals[3]);
307 }
308 else if (size < 0x00004000)
309 {
310 put_byte(pb, vals[2]);
311 put_byte(pb, vals[3]);
312 }
313 else if (size < 0x00200000)
314 {
315 put_byte(pb, vals[1]);
316 put_byte(pb, vals[2]);
317 put_byte(pb, vals[3]);
318 }
319 else if (size < 0x10000000)
320 {
321 put_byte(pb, vals[0]);
322 put_byte(pb, vals[1]);
323 put_byte(pb, vals[2]);
324 put_byte(pb, vals[3]);
325 }
1cb5f7fd
MN
326}
327
6e6d6dc0 328static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
1cb5f7fd 329{
e45ccf79
GB
330 int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0;
331 int pos = url_ftell(pb);
332
333 put_be32(pb, 0); // size
1cb5f7fd 334 put_tag(pb, "esds");
e45ccf79 335 put_be32(pb, 0); // Version
1cb5f7fd 336
e45ccf79
GB
337 // ES descriptor
338 putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) +
339 descrLength(1));
340 put_be16(pb, 0x0001); // ID (= 1)
1cb5f7fd
MN
341 put_byte(pb, 0x00); // flags (= no flags)
342
e45ccf79
GB
343 // DecoderConfig descriptor
344 putDescr(pb, 0x04, 13 + decoderSpecificInfoLen);
345
346 if(track->enc->codec_id == CODEC_ID_AAC)
347 put_byte(pb, 0x40); // Object type indication
348 else if(track->enc->codec_id == CODEC_ID_MPEG4)
349 put_byte(pb, 0x20); // Object type indication (Visual 14496-2)
350
351 if(track->enc->codec_type == CODEC_TYPE_AUDIO)
352 put_byte(pb, 0x15); // flags (= Audiostream)
353 else
354 put_byte(pb, 0x11); // flags (= Visualstream)
355
1cb5f7fd
MN
356 put_byte(pb, 0x0); // Buffersize DB (24 bits)
357 put_be16(pb, 0x0dd2); // Buffersize DB
358
359 // TODO: find real values for these
360 put_be32(pb, 0x0002e918); // maxbitrate
361 put_be32(pb, 0x00017e6b); // avg bitrate
362
e45ccf79
GB
363 if (track->vosLen)
364 {
365 // DecoderSpecific info descriptor
366 putDescr(pb, 0x05, track->vosLen);
367 put_buffer(pb, track->vosData, track->vosLen);
368 }
369
370 // SL descriptor
371 putDescr(pb, 0x06, descrLength(1));
1cb5f7fd 372 put_byte(pb, 0x02);
e45ccf79 373 return updateSize (pb, pos);
1cb5f7fd
MN
374}
375
f578f938 376static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 377{
6e6d6dc0 378 int pos = url_ftell(pb);
f578f938
TR
379 put_be32(pb, 0); /* size */
380 if(track->enc->codec_id == CODEC_ID_SVQ1)
381 put_tag(pb, "SVQ1");
382 else if(track->enc->codec_id == CODEC_ID_SVQ3)
383 put_tag(pb, "SVQ3");
384 else if(track->enc->codec_id == CODEC_ID_MPEG4)
385 put_tag(pb, "mp4v");
386 else if(track->enc->codec_id == CODEC_ID_H263)
387 put_tag(pb, "s263");
388 else
389 put_tag(pb, " "); /* Unknown tag */
6e6d6dc0 390
f578f938
TR
391 put_be32(pb, 0); /* Reserved */
392 put_be16(pb, 0); /* Reserved */
393 put_be16(pb, 1); /* Data-reference index */
394
395 put_be32(pb, 0); /* Reserved (= 02000c) */
396 put_be32(pb, 0); /* Reserved ("SVis")*/
397 put_be32(pb, 0); /* Reserved */
398 put_be32(pb, 0); /* Reserved (400)*/
399 put_be16(pb, track->enc->width); /* Video width */
400 put_be16(pb, track->enc->height); /* Video height */
401 put_be32(pb, 0x00480000); /* Reserved */
402 put_be32(pb, 0x00480000); /* Reserved */
403 put_be32(pb, 0); /* Reserved */
404 put_be32(pb, 0); /* Reserved */
405 put_be32(pb, 0); /* Reserved */
406 put_be32(pb, 0); /* Reserved */
407 put_be32(pb, 0); /* Reserved */
408 put_be32(pb, 0); /* Reserved */
409
410 put_be16(pb, 0); /* Reserved */
411 put_be32(pb, 0); /* Reserved */
412 put_be32(pb, 0); /* Reserved */
413 put_be32(pb, 0); /* Reserved */
414 put_be16(pb, 0x18); /* Reserved */
415 put_be16(pb, 0xffff); /* Reserved */
416 if(track->enc->codec_id == CODEC_ID_MPEG4)
417 mov_write_esds_tag(pb, track);
418 else if(track->enc->codec_id == CODEC_ID_H263)
419 mov_write_d263_tag(pb);
420 else if(track->enc->codec_id == CODEC_ID_SVQ3)
421 mov_write_svq3_tag(pb);
422
423 return updateSize (pb, pos);
1cb5f7fd
MN
424}
425
6e6d6dc0 426static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 427{
6e6d6dc0 428 int pos = url_ftell(pb);
1cb5f7fd
MN
429 put_be32(pb, 0); /* size */
430 put_tag(pb, "stsd");
431 put_be32(pb, 0); /* version & flags */
432 put_be32(pb, 1); /* entry count */
f578f938
TR
433 if (track->enc->codec_type == CODEC_TYPE_VIDEO)
434 mov_write_video_tag(pb, track);
435 else if (track->enc->codec_type == CODEC_TYPE_AUDIO)
436 mov_write_audio_tag(pb, track);
6e6d6dc0 437 return updateSize(pb, pos);
1cb5f7fd
MN
438}
439
f578f938 440/* TODO?: Currently all samples/frames seem to have same duration */
e45ccf79 441/* Time to sample atom */
6e6d6dc0 442static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
443{
444 put_be32(pb, 0x18); /* size */
445 put_tag(pb, "stts");
446 put_be32(pb, 0); /* version & flags */
447 put_be32(pb, 1); /* entry count */
448
e45ccf79
GB
449 put_be32(pb, track->sampleCount); /* sample count */
450 put_be32(pb, track->sampleDuration); /* sample duration */
1cb5f7fd
MN
451 return 0x18;
452}
453
6e6d6dc0 454static int mov_write_dref_tag(ByteIOContext *pb)
1cb5f7fd
MN
455{
456 put_be32(pb, 28); /* size */
457 put_tag(pb, "dref");
458 put_be32(pb, 0); /* version & flags */
459 put_be32(pb, 1); /* entry count */
460
461 put_be32(pb, 0xc); /* size */
462 put_tag(pb, "url ");
463 put_be32(pb, 1); /* version & flags */
464
465 return 28;
466}
467
6e6d6dc0 468static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 469{
6e6d6dc0 470 int pos = url_ftell(pb);
1cb5f7fd
MN
471 put_be32(pb, 0); /* size */
472 put_tag(pb, "stbl");
6e6d6dc0
MN
473 mov_write_stsd_tag(pb, track);
474 mov_write_stts_tag(pb, track);
f578f938
TR
475 if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
476 track->hasKeyframes)
477 mov_write_stss_tag(pb, track);
6e6d6dc0
MN
478 mov_write_stsc_tag(pb, track);
479 mov_write_stsz_tag(pb, track);
480 mov_write_stco_tag(pb, track);
481 return updateSize(pb, pos);
1cb5f7fd
MN
482}
483
6e6d6dc0 484static int mov_write_dinf_tag(ByteIOContext *pb)
1cb5f7fd 485{
6e6d6dc0 486 int pos = url_ftell(pb);
1cb5f7fd
MN
487 put_be32(pb, 0); /* size */
488 put_tag(pb, "dinf");
6e6d6dc0
MN
489 mov_write_dref_tag(pb);
490 return updateSize(pb, pos);
1cb5f7fd
MN
491}
492
6e6d6dc0 493static int mov_write_smhd_tag(ByteIOContext *pb)
1cb5f7fd
MN
494{
495 put_be32(pb, 16); /* size */
496 put_tag(pb, "smhd");
497 put_be32(pb, 0); /* version & flags */
498 put_be16(pb, 0); /* reserved (balance, normally = 0) */
499 put_be16(pb, 0); /* reserved */
500 return 16;
501}
502
6e6d6dc0 503static int mov_write_vmhd_tag(ByteIOContext *pb)
1cb5f7fd
MN
504{
505 put_be32(pb, 0x14); /* size (always 0x14) */
506 put_tag(pb, "vmhd");
507 put_be32(pb, 0x01); /* version & flags */
508 put_be64(pb, 0); /* reserved (graphics mode = copy) */
509 return 0x14;
510}
511
6e6d6dc0 512static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 513{
6e6d6dc0 514 int pos = url_ftell(pb);
1cb5f7fd
MN
515 put_be32(pb, 0); /* size */
516 put_tag(pb, "minf");
517 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
6e6d6dc0 518 mov_write_vmhd_tag(pb);
1cb5f7fd 519 else
6e6d6dc0
MN
520 mov_write_smhd_tag(pb);
521 mov_write_dinf_tag(pb);
522 mov_write_stbl_tag(pb, track);
523 return updateSize(pb, pos);
1cb5f7fd
MN
524}
525
6e6d6dc0 526static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 527{
f578f938
TR
528 char *str;
529 int pos = url_ftell(pb);
530 put_be32(pb, 0); /* size */
1cb5f7fd
MN
531 put_tag(pb, "hdlr");
532 put_be32(pb, 0); /* Version & flags */
533 put_be32(pb, 0); /* reserved */
534 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
535 put_tag(pb, "vide"); /* handler type */
536 else
537 put_tag(pb, "soun"); /* handler type */
f578f938
TR
538 put_be32(pb ,0); /* reserved */
539 put_be32(pb ,0); /* reserved */
540 put_be32(pb ,0); /* reserved */
1cb5f7fd 541 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
f578f938 542 str = "VideoHandler";
1cb5f7fd 543 else
f578f938
TR
544 str = "SoundHandler";
545 put_byte(pb, strlen(str)); /* string counter */
546 put_buffer(pb, str, strlen(str));
547 return updateSize(pb, pos);
1cb5f7fd
MN
548}
549
6e6d6dc0 550static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
551{
552 put_be32(pb, 32); /* size */
553 put_tag(pb, "mdhd");
554 put_be32(pb, 0); /* Version & flags */
555 put_be32(pb, track->time); /* creation time */
556 put_be32(pb, track->time); /* modification time */
e45ccf79
GB
557 put_be32(pb, track->timescale); /* time scale (sample rate for audio) */
558 put_be32(pb, track->trackDuration); /* duration */
1cb5f7fd
MN
559 put_be16(pb, 0); /* language, 0 = english */
560 put_be16(pb, 0); /* reserved (quality) */
561 return 32;
562}
563
6e6d6dc0 564static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 565{
6e6d6dc0 566 int pos = url_ftell(pb);
1cb5f7fd
MN
567 put_be32(pb, 0); /* size */
568 put_tag(pb, "mdia");
6e6d6dc0
MN
569 mov_write_mdhd_tag(pb, track);
570 mov_write_hdlr_tag(pb, track);
571 mov_write_minf_tag(pb, track);
572 return updateSize(pb, pos);
1cb5f7fd
MN
573}
574
6e6d6dc0 575static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 576{
f578f938 577 int64_t maxTrackLenTemp;
1cb5f7fd
MN
578 put_be32(pb, 0x5c); /* size (always 0x5c) */
579 put_tag(pb, "tkhd");
f578f938 580 put_be32(pb, 0xf); /* version & flags (track enabled) */
1cb5f7fd
MN
581 put_be32(pb, track->time); /* creation time */
582 put_be32(pb, track->time); /* modification time */
583 put_be32(pb, track->trackID); /* track-id */
584 put_be32(pb, 0); /* reserved */
f578f938
TR
585 maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)track->trackDuration)/(int64_t)track->timescale;
586 put_be32(pb, (long)maxTrackLenTemp); /* duration */
1cb5f7fd
MN
587
588 put_be32(pb, 0); /* reserved */
589 put_be32(pb, 0); /* reserved */
590 put_be32(pb, 0x0); /* reserved (Layer & Alternate group) */
591 /* Volume, only for audio */
592 if(track->enc->codec_type == CODEC_TYPE_AUDIO)
593 put_be16(pb, 0x0100);
594 else
595 put_be16(pb, 0);
596 put_be16(pb, 0); /* reserved */
597
598 /* Matrix structure */
599 put_be32(pb, 0x00010000); /* reserved */
600 put_be32(pb, 0x0); /* reserved */
601 put_be32(pb, 0x0); /* reserved */
602 put_be32(pb, 0x0); /* reserved */
603 put_be32(pb, 0x00010000); /* reserved */
604 put_be32(pb, 0x0); /* reserved */
605 put_be32(pb, 0x0); /* reserved */
606 put_be32(pb, 0x0); /* reserved */
607 put_be32(pb, 0x40000000); /* reserved */
608
609 /* Track width and height, for visual only */
610 if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
f578f938
TR
611 put_be32(pb, track->enc->width*0x10000);
612 put_be32(pb, track->enc->height*0x10000);
1cb5f7fd
MN
613 }
614 else {
615 put_be32(pb, 0);
616 put_be32(pb, 0);
617 }
618 return 0x5c;
619}
620
6e6d6dc0 621static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 622{
6e6d6dc0 623 int pos = url_ftell(pb);
1cb5f7fd
MN
624 put_be32(pb, 0); /* size */
625 put_tag(pb, "trak");
6e6d6dc0
MN
626 mov_write_tkhd_tag(pb, track);
627 mov_write_mdia_tag(pb, track);
628 return updateSize(pb, pos);
1cb5f7fd
MN
629}
630
631/* TODO: Not sorted out, but not necessary either */
6e6d6dc0 632static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd
MN
633{
634 put_be32(pb, 0x15); /* size */
635 put_tag(pb, "iods");
636 put_be32(pb, 0); /* version & flags */
637 put_be16(pb, 0x1007);
638 put_byte(pb, 0);
639 put_be16(pb, 0x4fff);
640 put_be16(pb, 0xfffe);
641 put_be16(pb, 0x01ff);
642 return 0x15;
643}
644
6e6d6dc0 645static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd
MN
646{
647 int maxTrackID = 1, maxTrackLen = 0, i;
f578f938 648 int64_t maxTrackLenTemp;
1cb5f7fd
MN
649
650 put_be32(pb, 0x6c); /* size (always 0x6c) */
651 put_tag(pb, "mvhd");
652 put_be32(pb, 0); /* version & flags */
653 put_be32(pb, mov->time); /* creation time */
654 put_be32(pb, mov->time); /* modification time */
655 put_be32(pb, mov->timescale); /* timescale */
656 for (i=0; i<MAX_STREAMS; i++) {
657 if(mov->tracks[i].entry > 0) {
f578f938
TR
658 maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)mov->tracks[i].trackDuration)/(int64_t)mov->tracks[i].timescale;
659 if(maxTrackLen < maxTrackLenTemp)
660 maxTrackLen = maxTrackLenTemp;
1cb5f7fd
MN
661 if(maxTrackID < mov->tracks[i].trackID)
662 maxTrackID = mov->tracks[i].trackID;
663 }
664 }
665 put_be32(pb, maxTrackLen); /* duration of longest track */
666
667 put_be32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
668 put_be16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
669 put_be16(pb, 0); /* reserved */
670 put_be32(pb, 0); /* reserved */
671 put_be32(pb, 0); /* reserved */
672
673 /* Matrix structure */
674 put_be32(pb, 0x00010000); /* reserved */
675 put_be32(pb, 0x0); /* reserved */
676 put_be32(pb, 0x0); /* reserved */
677 put_be32(pb, 0x0); /* reserved */
678 put_be32(pb, 0x00010000); /* reserved */
679 put_be32(pb, 0x0); /* reserved */
680 put_be32(pb, 0x0); /* reserved */
681 put_be32(pb, 0x0); /* reserved */
682 put_be32(pb, 0x40000000); /* reserved */
683
684 put_be32(pb, 0); /* reserved (preview time) */
685 put_be32(pb, 0); /* reserved (preview duration) */
686 put_be32(pb, 0); /* reserved (poster time) */
687 put_be32(pb, 0); /* reserved (selection time) */
688 put_be32(pb, 0); /* reserved (selection duration) */
689 put_be32(pb, 0); /* reserved (current time) */
690 put_be32(pb, maxTrackID+1); /* Next track id */
691 return 0x6c;
692}
693
6e6d6dc0 694static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd 695{
6e6d6dc0 696 int pos, i;
1cb5f7fd
MN
697 pos = url_ftell(pb);
698 put_be32(pb, 0); /* size placeholder*/
699 put_tag(pb, "moov");
700 mov->timescale = globalTimescale;
701
702 for (i=0; i<MAX_STREAMS; i++) {
e45ccf79
GB
703 if(mov->tracks[i].entry <= 0) continue;
704
705 if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) {
706 mov->tracks[i].timescale = mov->tracks[i].enc->frame_rate;
707 mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_rate_base;
708 }
709 else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
710 /* If AMR, track timescale = 8000, AMR_WB = 16000 */
711 if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) {
712 mov->tracks[i].sampleDuration = 160; // Bytes per chunk
713 mov->tracks[i].timescale = 8000;
1cb5f7fd 714 }
e45ccf79
GB
715 else {
716 mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate;
717 mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_size;
1cb5f7fd 718 }
1cb5f7fd 719 }
e45ccf79
GB
720
721 mov->tracks[i].trackDuration =
722 mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration;
723 mov->tracks[i].time = mov->time;
724 mov->tracks[i].trackID = i+1;
1cb5f7fd
MN
725 }
726
6e6d6dc0
MN
727 mov_write_mvhd_tag(pb, mov);
728 //mov_write_iods_tag(pb, mov);
1cb5f7fd
MN
729 for (i=0; i<MAX_STREAMS; i++) {
730 if(mov->tracks[i].entry > 0) {
6e6d6dc0 731 mov_write_trak_tag(pb, &(mov->tracks[i]));
1cb5f7fd
MN
732 }
733 }
734
6e6d6dc0 735 return updateSize(pb, pos);
1cb5f7fd
MN
736}
737
f578f938 738int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov)
1cb5f7fd 739{
f578f938 740 mov->mdat_pos = url_ftell(pb);
1cb5f7fd
MN
741 put_be32(pb, 0); /* size placeholder*/
742 put_tag(pb, "mdat");
743 return 0;
744}
745
746/* TODO: This needs to be more general */
e45ccf79 747int mov_write_ftyp_tag(ByteIOContext *pb, AVFormatContext *s)
1cb5f7fd
MN
748{
749 put_be32(pb, 0x14 ); /* size */
750 put_tag(pb, "ftyp");
e45ccf79
GB
751
752 if (!strcmp("3gp", s->oformat->name))
753 put_tag(pb, "3gp4");
754 else
755 put_tag(pb, "isom");
756
1cb5f7fd 757 put_be32(pb, 0x200 );
e45ccf79
GB
758
759 if (!strcmp("3gp", s->oformat->name))
760 put_tag(pb, "3gp4");
761 else
762 put_tag(pb, "mp41");
763
1cb5f7fd
MN
764 return 0x14;
765}
766
767static int mov_write_header(AVFormatContext *s)
768{
769 ByteIOContext *pb = &s->pb;
770
f578f938 771 if(s->oformat != NULL) {
e45ccf79
GB
772 if(!strcmp("3gp", s->oformat->name) || !strcmp("mp4", s->oformat->name))
773 mov_write_ftyp_tag(pb,s);
f578f938
TR
774 }
775
1cb5f7fd
MN
776 put_flush_packet(pb);
777
778 return 0;
779}
780
781static int Timestamp() {
dd0003fa 782 return 1067949799U+(24107*86400); //its the modification time of this line :)
1cb5f7fd
MN
783}
784
785static int mov_write_packet(AVFormatContext *s, int stream_index,
49057904 786 const uint8_t *buf, int size, int64_t pts)
1cb5f7fd
MN
787{
788 MOVContext *mov = s->priv_data;
789 ByteIOContext *pb = &s->pb;
e45ccf79
GB
790 AVCodecContext *enc = &s->streams[stream_index]->codec;
791 MOVTrack* trk = &mov->tracks[stream_index];
1a31840c 792 int cl, id;
e45ccf79 793 unsigned int samplesInChunk = 0;
1cb5f7fd 794
e45ccf79
GB
795 if (url_is_streamed(&s->pb)) return 0; /* Can't handle that */
796 if (!size) return 0; /* Discard 0 sized packets */
1cb5f7fd 797
e45ccf79
GB
798 if (enc->codec_type == CODEC_TYPE_VIDEO ) {
799 samplesInChunk = 1;
800 }
801 else if (enc->codec_type == CODEC_TYPE_AUDIO ) {
802 if( enc->codec_id == CODEC_ID_AMR_NB) {
f578f938 803 /* We must find out how many AMR blocks there are in one packet */
e45ccf79
GB
804 static uint16_t packed_size[16] =
805 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0};
806 int len = 0;
807
808 while (len < size && samplesInChunk < 100) {
809 len += packed_size[(buf[len] >> 3) & 0x0F];
810 samplesInChunk++;
f578f938 811 }
1cb5f7fd 812 }
e45ccf79
GB
813 else if(enc->codec_id == CODEC_ID_PCM_ALAW) {
814 samplesInChunk = size/enc->channels;
1cb5f7fd 815 }
e45ccf79
GB
816 else {
817 samplesInChunk = 1;
1cb5f7fd 818 }
e45ccf79
GB
819 }
820
821 if ((enc->codec_id == CODEC_ID_MPEG4 || enc->codec_id == CODEC_ID_AAC)
822 && trk->vosLen == 0) {
823 assert(enc->extradata_size);
824
825 trk->vosLen = enc->extradata_size;
826 trk->vosData = av_malloc(trk->vosLen);
827 memcpy(trk->vosData, enc->extradata, trk->vosLen);
828 }
829
830 cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
831 id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
832
833 if (trk->ents_allocated <= trk->entry) {
834 trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*));
835 if (!trk->cluster)
836 return -1;
837 trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
838 if (!trk->cluster[cl])
839 return -1;
840 trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
841 }
842 if (mov->mdat_written == 0) {
843 mov_write_mdat_tag(pb, mov);
844 mov->mdat_written = 1;
845 mov->time = Timestamp();
846 }
847
848 trk->cluster[cl][id].pos = url_ftell(pb) - mov->movi_list;
849 trk->cluster[cl][id].samplesInChunk = samplesInChunk;
850 trk->cluster[cl][id].size = size;
851 trk->cluster[cl][id].entries = samplesInChunk;
852 if(enc->codec_type == CODEC_TYPE_VIDEO) {
853 trk->cluster[cl][id].key_frame = enc->coded_frame->key_frame;
854 if(enc->coded_frame->pict_type == FF_I_TYPE)
f578f938 855 trk->hasKeyframes = 1;
1cb5f7fd 856 }
e45ccf79
GB
857 trk->enc = enc;
858 trk->entry++;
859 trk->sampleCount += samplesInChunk;
860 trk->mdat_size += size;
861
1cb5f7fd
MN
862 put_buffer(pb, buf, size);
863
864 put_flush_packet(pb);
865 return 0;
866}
867
868static int mov_write_trailer(AVFormatContext *s)
869{
870 MOVContext *mov = s->priv_data;
871 ByteIOContext *pb = &s->pb;
872 int res = 0;
873 int i, j;
874 offset_t file_size;
875
876 file_size = url_ftell(pb);
877 j = 0;
878
879 /* Write size of mdat tag */
880 for (i=0; i<MAX_STREAMS; i++) {
881 if(mov->tracks[i].ents_allocated > 0) {
882 j += mov->tracks[i].mdat_size;
883 }
884 }
f578f938 885 url_fseek(pb, mov->mdat_pos, SEEK_SET);
1cb5f7fd
MN
886 put_be32(pb, j+8);
887 url_fseek(pb, file_size, SEEK_SET);
888
889 mov_write_moov_tag(pb, mov);
890
891 for (i=0; i<MAX_STREAMS; i++) {
892 for (j=0; j<mov->tracks[i].ents_allocated/MOV_INDEX_CLUSTER_SIZE; j++) {
893 av_free(mov->tracks[i].cluster[j]);
894 }
895 av_free(mov->tracks[i].cluster);
ec7d0d2e
GB
896 if( mov->tracks[i].vosLen ) av_free( mov->tracks[i].vosData );
897
1cb5f7fd
MN
898 mov->tracks[i].cluster = NULL;
899 mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
900 }
901 put_flush_packet(pb);
902
903 return res;
904}
905
906static AVOutputFormat mov_oformat = {
907 "mov",
908 "mov format",
909 NULL,
910 "mov",
911 sizeof(MOVContext),
f578f938 912 CODEC_ID_PCM_ALAW,
2187d948 913 CODEC_ID_MPEG4,
1cb5f7fd
MN
914 mov_write_header,
915 mov_write_packet,
916 mov_write_trailer,
917};
918
919static AVOutputFormat _3gp_oformat = {
920 "3gp",
921 "3gp format",
922 NULL,
923 "3gp",
924 sizeof(MOVContext),
925 CODEC_ID_AMR_NB,
926 CODEC_ID_H263,
927 mov_write_header,
928 mov_write_packet,
929 mov_write_trailer,
930};
931
932static AVOutputFormat mp4_oformat = {
933 "mp4",
934 "mp4 format",
4cb3f3b6
DC
935 "application/mp4",
936 "mp4,m4a",
1cb5f7fd
MN
937 sizeof(MOVContext),
938 CODEC_ID_AAC,
939 CODEC_ID_MPEG4,
940 mov_write_header,
941 mov_write_packet,
942 mov_write_trailer,
943};
944
945int movenc_init(void)
946{
947 av_register_output_format(&mov_oformat);
948 av_register_output_format(&_3gp_oformat);
949 av_register_output_format(&mp4_oformat);
950 return 0;
951}