2nd attempt at OS/X shared/mdynamicnopic fix by ("Steven M. Schultz" <sms at 2BSD...
[libav.git] / libavformat / movenc.c
CommitLineData
1cb5f7fd
MN
1/*
2 * MOV, 3GP, MP4 encoder.
3 * Copyright (c) 2003 Thomas Raivio.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include "avformat.h"
f578f938 20#include "avi.h"
1cb5f7fd
MN
21#include "avio.h"
22#include <time.h>
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 {
31 unsigned int flags, pos, len;
f578f938
TR
32 unsigned int chunkSize;
33 char key_frame;
1cb5f7fd
MN
34 unsigned int entries;
35} MOVIentry;
36
37typedef struct MOVIndex {
38 int entry;
39 int samples;
40 int mdat_size;
1cb5f7fd
MN
41 int ents_allocated;
42 long timescale;
43 long time;
f578f938
TR
44 long frameCount;
45 long trackDuration;
1cb5f7fd 46 long sampleDelta;
f578f938 47 int hasKeyframes;
1cb5f7fd
MN
48 int trackID;
49 AVCodecContext *enc;
50
51 int vosLen;
6e6d6dc0 52 uint8_t *vosData;
1cb5f7fd
MN
53 MOVIentry** cluster;
54} MOVTrack;
55
56typedef struct {
57 long time;
58 int nb_streams;
f578f938
TR
59 int mdat_written;
60 offset_t mdat_pos;
1cb5f7fd
MN
61 offset_t movi_list;
62 long timescale;
63 MOVTrack tracks[MAX_STREAMS];
64} MOVContext;
65
6e6d6dc0
MN
66//FIXME supprt 64bit varaint with wide placeholders
67static int updateSize (ByteIOContext *pb, int pos)
1cb5f7fd
MN
68{
69 long curpos = url_ftell(pb);
70 url_fseek(pb, pos, SEEK_SET);
6e6d6dc0 71 put_be32(pb, curpos - pos); /* rewrite size */
1cb5f7fd 72 url_fseek(pb, curpos, SEEK_SET);
6e6d6dc0
MN
73
74 return curpos - pos;
1cb5f7fd
MN
75}
76
6e6d6dc0 77static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
78{
79 int i;
f578f938
TR
80 int pos = url_ftell(pb);
81 put_be32(pb, 0); /* size */
1cb5f7fd
MN
82 put_tag(pb, "stco");
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);
89 }
f578f938 90 return updateSize (pb, pos);
1cb5f7fd
MN
91}
92
6e6d6dc0 93static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 94{
f578f938
TR
95 int equalChunks = 1;
96 int i, tst = -1, oldtst = -1;
1cb5f7fd 97
f578f938
TR
98 int pos = url_ftell(pb);
99 put_be32(pb, 0); /* size */
1cb5f7fd
MN
100 put_tag(pb, "stsz");
101 put_be32(pb, 0); /* version & flags */
102
f578f938
TR
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) {
108 equalChunks = 0;
109 break;
110 }
111 oldtst = tst;
112 }
113 if(equalChunks ||
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
1cb5f7fd 119 }
f578f938
TR
120 else {
121 put_be32(pb, 0); // sample size
122 put_be32(pb, track->entry); // sample count
123 for (i=0; i<track->entry; i++) {
1cb5f7fd
MN
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);
127 }
128 }
f578f938 129 return updateSize (pb, pos);
1cb5f7fd
MN
130}
131
6e6d6dc0 132static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 133{
f578f938
TR
134 int index = 0, oldval = -1, i, entryPos, curpos;
135
136 int pos = url_ftell(pb);
137 put_be32(pb, 0); /* size */
1cb5f7fd
MN
138 put_tag(pb, "stsc");
139 put_be32(pb, 0); // version & flags
f578f938
TR
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)
146 {
1cb5f7fd 147 put_be32(pb, i+1); // first chunk
f578f938 148 put_be32(pb, track->cluster[cl][id].chunkSize);
1cb5f7fd 149 put_be32(pb, 0x1); // sample description index
f578f938
TR
150 oldval = track->cluster[cl][id].chunkSize;
151 index++;
1cb5f7fd
MN
152 }
153 }
f578f938
TR
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);
1cb5f7fd 158
f578f938 159 return updateSize (pb, pos);
1cb5f7fd
MN
160}
161
f578f938 162static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 163{
f578f938
TR
164 long curpos;
165 int i, index = 0, entryPos;
166 int pos = url_ftell(pb);
167 put_be32(pb, 0); // size
1cb5f7fd 168 put_tag(pb, "stss");
f578f938
TR
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) {
176 put_be32(pb, i+1);
177 index++;
178 }
179 }
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);
1cb5f7fd
MN
185}
186
6e6d6dc0 187static int mov_write_damr_tag(ByteIOContext *pb)
1cb5f7fd
MN
188{
189 put_be32(pb, 0x11); /* size */
190 put_tag(pb, "damr");
191 put_tag(pb, "FFMP");
192 put_byte(pb, 0);
f578f938
TR
193
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) */
1cb5f7fd
MN
198 return 0x11;
199}
200
f578f938 201static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 202{
6e6d6dc0 203 int pos = url_ftell(pb);
1cb5f7fd 204 put_be32(pb, 0); /* size */
f578f938
TR
205
206 if(track->enc->codec_id == CODEC_ID_PCM_MULAW)
207 put_tag(pb, "ulaw");
208 else if(track->enc->codec_id == CODEC_ID_PCM_ALAW)
209 put_tag(pb, "alaw");
210 else if(track->enc->codec_id == CODEC_ID_ADPCM_IMA_QT)
211 put_tag(pb, "ima4");
212 else if(track->enc->codec_id == CODEC_ID_MACE3)
213 put_tag(pb, "MAC3");
214 else if(track->enc->codec_id == CODEC_ID_MACE6)
215 put_tag(pb, "MAC6");
216 else if(track->enc->codec_id == CODEC_ID_AAC)
217 put_tag(pb, "mp4a");
218 else if(track->enc->codec_id == CODEC_ID_AMR_NB)
219 put_tag(pb, "samr");
220 else
221 put_tag(pb, " ");
222
1cb5f7fd
MN
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 */
228
f578f938
TR
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 */
1cb5f7fd 232 put_be16(pb, 0x10); /* Reserved */
f578f938
TR
233 put_be16(pb, 0); /* compression ID (= 0) */
234 put_be16(pb, 0); /* packet size (= 0) */
1cb5f7fd
MN
235 put_be16(pb, track->timescale); /* Time scale */
236 put_be16(pb, 0); /* Reserved */
237
f578f938
TR
238 if(track->enc->codec_id == CODEC_ID_AMR_NB)
239 mov_write_damr_tag(pb);
6e6d6dc0 240 return updateSize (pb, pos);
1cb5f7fd
MN
241}
242
6e6d6dc0 243static int mov_write_d263_tag(ByteIOContext *pb)
1cb5f7fd
MN
244{
245 put_be32(pb, 0xf); /* size */
246 put_tag(pb, "d263");
247 put_tag(pb, "FFMP");
248 put_be16(pb, 0x0a);
249 put_byte(pb, 0);
250 return 0xf;
251}
252
f578f938
TR
253/* TODO: No idea about these values */
254static int mov_write_svq3_tag(ByteIOContext *pb)
1cb5f7fd 255{
f578f938
TR
256 put_be32(pb, 0x15);
257 put_tag(pb, "SMI ");
258 put_tag(pb, "SEQH");
259 put_be32(pb, 0x5);
260 put_be32(pb, 0xe2c0211d);
261 put_be32(pb, 0xc0000000);
262 put_byte(pb, 0);
263 return 0x15;
1cb5f7fd
MN
264}
265
266static unsigned int esdsLength(unsigned int len)
267{
268 unsigned int result = 0;
269 unsigned char b = len & 0x7f;
270 result += b;
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;
277 return result;
278}
279
6e6d6dc0 280static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic
1cb5f7fd
MN
281{
282 put_be32(pb, track->vosLen+18+14+17);
283 put_tag(pb, "esds");
284 put_be32(pb, 0); // Version
285
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)
290
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
298
299 // TODO: find real values for these
300 put_be32(pb, 0x0002e918); // maxbitrate
301 put_be32(pb, 0x00017e6b); // avg bitrate
302
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);
6e6d6dc0 307
1cb5f7fd
MN
308 put_byte(pb, 0x06);
309 put_be32(pb, esdsLength(1)); // length
310 put_byte(pb, 0x02);
311 return track->vosLen+18+14+17;
312}
313
f578f938 314static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 315{
6e6d6dc0 316 int pos = url_ftell(pb);
f578f938
TR
317 put_be32(pb, 0); /* size */
318 if(track->enc->codec_id == CODEC_ID_SVQ1)
319 put_tag(pb, "SVQ1");
320 else if(track->enc->codec_id == CODEC_ID_SVQ3)
321 put_tag(pb, "SVQ3");
322 else if(track->enc->codec_id == CODEC_ID_MPEG4)
323 put_tag(pb, "mp4v");
324 else if(track->enc->codec_id == CODEC_ID_H263)
325 put_tag(pb, "s263");
326 else
327 put_tag(pb, " "); /* Unknown tag */
6e6d6dc0 328
f578f938
TR
329 put_be32(pb, 0); /* Reserved */
330 put_be16(pb, 0); /* Reserved */
331 put_be16(pb, 1); /* Data-reference index */
332
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 */
347
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);
360
361 return updateSize (pb, pos);
1cb5f7fd
MN
362}
363
6e6d6dc0 364static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 365{
6e6d6dc0 366 int pos = url_ftell(pb);
1cb5f7fd
MN
367 put_be32(pb, 0); /* size */
368 put_tag(pb, "stsd");
369 put_be32(pb, 0); /* version & flags */
370 put_be32(pb, 1); /* entry count */
f578f938
TR
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);
6e6d6dc0 375 return updateSize(pb, pos);
1cb5f7fd
MN
376}
377
f578f938 378/* TODO?: Currently all samples/frames seem to have same duration */
6e6d6dc0 379static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
380{
381 put_be32(pb, 0x18); /* size */
382 put_tag(pb, "stts");
383 put_be32(pb, 0); /* version & flags */
384 put_be32(pb, 1); /* entry count */
385
f578f938 386 put_be32(pb, track->frameCount); /* sample count */
1cb5f7fd
MN
387 put_be32(pb, track->sampleDelta); /* sample delta */
388 return 0x18;
389}
390
6e6d6dc0 391static int mov_write_dref_tag(ByteIOContext *pb)
1cb5f7fd
MN
392{
393 put_be32(pb, 28); /* size */
394 put_tag(pb, "dref");
395 put_be32(pb, 0); /* version & flags */
396 put_be32(pb, 1); /* entry count */
397
398 put_be32(pb, 0xc); /* size */
399 put_tag(pb, "url ");
400 put_be32(pb, 1); /* version & flags */
401
402 return 28;
403}
404
6e6d6dc0 405static int mov_write_stbl_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 406{
6e6d6dc0 407 int pos = url_ftell(pb);
1cb5f7fd
MN
408 put_be32(pb, 0); /* size */
409 put_tag(pb, "stbl");
6e6d6dc0
MN
410 mov_write_stsd_tag(pb, track);
411 mov_write_stts_tag(pb, track);
f578f938
TR
412 if (track->enc->codec_type == CODEC_TYPE_VIDEO &&
413 track->hasKeyframes)
414 mov_write_stss_tag(pb, track);
6e6d6dc0
MN
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);
1cb5f7fd
MN
419}
420
6e6d6dc0 421static int mov_write_dinf_tag(ByteIOContext *pb)
1cb5f7fd 422{
6e6d6dc0 423 int pos = url_ftell(pb);
1cb5f7fd
MN
424 put_be32(pb, 0); /* size */
425 put_tag(pb, "dinf");
6e6d6dc0
MN
426 mov_write_dref_tag(pb);
427 return updateSize(pb, pos);
1cb5f7fd
MN
428}
429
6e6d6dc0 430static int mov_write_smhd_tag(ByteIOContext *pb)
1cb5f7fd
MN
431{
432 put_be32(pb, 16); /* size */
433 put_tag(pb, "smhd");
434 put_be32(pb, 0); /* version & flags */
435 put_be16(pb, 0); /* reserved (balance, normally = 0) */
436 put_be16(pb, 0); /* reserved */
437 return 16;
438}
439
6e6d6dc0 440static int mov_write_vmhd_tag(ByteIOContext *pb)
1cb5f7fd
MN
441{
442 put_be32(pb, 0x14); /* size (always 0x14) */
443 put_tag(pb, "vmhd");
444 put_be32(pb, 0x01); /* version & flags */
445 put_be64(pb, 0); /* reserved (graphics mode = copy) */
446 return 0x14;
447}
448
6e6d6dc0 449static int mov_write_minf_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 450{
6e6d6dc0 451 int pos = url_ftell(pb);
1cb5f7fd
MN
452 put_be32(pb, 0); /* size */
453 put_tag(pb, "minf");
454 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
6e6d6dc0 455 mov_write_vmhd_tag(pb);
1cb5f7fd 456 else
6e6d6dc0
MN
457 mov_write_smhd_tag(pb);
458 mov_write_dinf_tag(pb);
459 mov_write_stbl_tag(pb, track);
460 return updateSize(pb, pos);
1cb5f7fd
MN
461}
462
6e6d6dc0 463static int mov_write_hdlr_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 464{
f578f938
TR
465 char *str;
466 int pos = url_ftell(pb);
467 put_be32(pb, 0); /* size */
1cb5f7fd
MN
468 put_tag(pb, "hdlr");
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 */
473 else
474 put_tag(pb, "soun"); /* handler type */
f578f938
TR
475 put_be32(pb ,0); /* reserved */
476 put_be32(pb ,0); /* reserved */
477 put_be32(pb ,0); /* reserved */
1cb5f7fd 478 if(track->enc->codec_type == CODEC_TYPE_VIDEO)
f578f938 479 str = "VideoHandler";
1cb5f7fd 480 else
f578f938
TR
481 str = "SoundHandler";
482 put_byte(pb, strlen(str)); /* string counter */
483 put_buffer(pb, str, strlen(str));
484 return updateSize(pb, pos);
1cb5f7fd
MN
485}
486
6e6d6dc0 487static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd
MN
488{
489 put_be32(pb, 32); /* size */
490 put_tag(pb, "mdhd");
491 put_be32(pb, 0); /* Version & flags */
492 put_be32(pb, track->time); /* creation time */
493 put_be32(pb, track->time); /* modification time */
f578f938
TR
494 if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
495 int64_t rate = track->enc->frame_rate;
496 put_be32(pb, rate);
497 put_be32(pb, rate*(int64_t)track->trackDuration/(int64_t)globalTimescale); // duration
498 }
499 else {
500 put_be32(pb, track->timescale); /* time scale (sample rate for audio) */
501 put_be32(pb, track->trackDuration); /* duration */
502 }
1cb5f7fd
MN
503 put_be16(pb, 0); /* language, 0 = english */
504 put_be16(pb, 0); /* reserved (quality) */
505 return 32;
506}
507
6e6d6dc0 508static int mov_write_mdia_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 509{
6e6d6dc0 510 int pos = url_ftell(pb);
1cb5f7fd
MN
511 put_be32(pb, 0); /* size */
512 put_tag(pb, "mdia");
6e6d6dc0
MN
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);
1cb5f7fd
MN
517}
518
6e6d6dc0 519static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 520{
f578f938 521 int64_t maxTrackLenTemp;
1cb5f7fd
MN
522 put_be32(pb, 0x5c); /* size (always 0x5c) */
523 put_tag(pb, "tkhd");
f578f938 524 put_be32(pb, 0xf); /* version & flags (track enabled) */
1cb5f7fd
MN
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 */
f578f938
TR
529 maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)track->trackDuration)/(int64_t)track->timescale;
530 put_be32(pb, (long)maxTrackLenTemp); /* duration */
1cb5f7fd
MN
531
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);
538 else
539 put_be16(pb, 0);
540 put_be16(pb, 0); /* reserved */
541
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 */
552
553 /* Track width and height, for visual only */
554 if(track->enc->codec_type == CODEC_TYPE_VIDEO) {
f578f938
TR
555 put_be32(pb, track->enc->width*0x10000);
556 put_be32(pb, track->enc->height*0x10000);
1cb5f7fd
MN
557 }
558 else {
559 put_be32(pb, 0);
560 put_be32(pb, 0);
561 }
562 return 0x5c;
563}
564
6e6d6dc0 565static int mov_write_trak_tag(ByteIOContext *pb, MOVTrack* track)
1cb5f7fd 566{
6e6d6dc0 567 int pos = url_ftell(pb);
1cb5f7fd
MN
568 put_be32(pb, 0); /* size */
569 put_tag(pb, "trak");
6e6d6dc0
MN
570 mov_write_tkhd_tag(pb, track);
571 mov_write_mdia_tag(pb, track);
572 return updateSize(pb, pos);
1cb5f7fd
MN
573}
574
575/* TODO: Not sorted out, but not necessary either */
6e6d6dc0 576static int mov_write_iods_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd
MN
577{
578 put_be32(pb, 0x15); /* size */
579 put_tag(pb, "iods");
580 put_be32(pb, 0); /* version & flags */
581 put_be16(pb, 0x1007);
582 put_byte(pb, 0);
583 put_be16(pb, 0x4fff);
584 put_be16(pb, 0xfffe);
585 put_be16(pb, 0x01ff);
586 return 0x15;
587}
588
6e6d6dc0 589static int mov_write_mvhd_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd
MN
590{
591 int maxTrackID = 1, maxTrackLen = 0, i;
f578f938 592 int64_t maxTrackLenTemp;
1cb5f7fd
MN
593
594 put_be32(pb, 0x6c); /* size (always 0x6c) */
595 put_tag(pb, "mvhd");
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) {
f578f938
TR
602 maxTrackLenTemp = ((int64_t)globalTimescale*(int64_t)mov->tracks[i].trackDuration)/(int64_t)mov->tracks[i].timescale;
603 if(maxTrackLen < maxTrackLenTemp)
604 maxTrackLen = maxTrackLenTemp;
1cb5f7fd
MN
605 if(maxTrackID < mov->tracks[i].trackID)
606 maxTrackID = mov->tracks[i].trackID;
607 }
608 }
609 put_be32(pb, maxTrackLen); /* duration of longest track */
610
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 */
616
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 */
627
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 */
635 return 0x6c;
636}
637
6e6d6dc0 638static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov)
1cb5f7fd 639{
6e6d6dc0 640 int pos, i;
1cb5f7fd
MN
641 pos = url_ftell(pb);
642 put_be32(pb, 0); /* size placeholder*/
643 put_tag(pb, "moov");
644 mov->timescale = globalTimescale;
645
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;
f578f938
TR
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;
1cb5f7fd
MN
654 }
655 else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) {
f578f938 656 long trackDuration = 0;
1cb5f7fd
MN
657 /* If AMR, track timescale = 8000, AMR_WB = 16000 */
658 if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) {
f578f938
TR
659 int j;
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;
664 }
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
1cb5f7fd
MN
669 mov->tracks[i].timescale = 8000;
670 }
671 else {
f578f938
TR
672 int j;
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;
677 }
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;
1cb5f7fd
MN
682 }
683 }
684 mov->tracks[i].time = mov->time;
685 mov->tracks[i].trackID = i+1;
686 }
687 }
688
6e6d6dc0
MN
689 mov_write_mvhd_tag(pb, mov);
690 //mov_write_iods_tag(pb, mov);
1cb5f7fd
MN
691 for (i=0; i<MAX_STREAMS; i++) {
692 if(mov->tracks[i].entry > 0) {
6e6d6dc0 693 mov_write_trak_tag(pb, &(mov->tracks[i]));
1cb5f7fd
MN
694 }
695 }
696
6e6d6dc0 697 return updateSize(pb, pos);
1cb5f7fd
MN
698}
699
f578f938 700int mov_write_mdat_tag(ByteIOContext *pb, MOVContext* mov)
1cb5f7fd 701{
f578f938 702 mov->mdat_pos = url_ftell(pb);
1cb5f7fd
MN
703 put_be32(pb, 0); /* size placeholder*/
704 put_tag(pb, "mdat");
705 return 0;
706}
707
708/* TODO: This needs to be more general */
709int mov_write_ftyp_tag(ByteIOContext *pb)
710{
711 put_be32(pb, 0x14 ); /* size */
712 put_tag(pb, "ftyp");
713 put_tag(pb, "3gp4");
714 put_be32(pb, 0x200 );
715 put_tag(pb, "3gp4");
716 return 0x14;
717}
718
719static int mov_write_header(AVFormatContext *s)
720{
721 ByteIOContext *pb = &s->pb;
722
f578f938
TR
723 if(s->oformat != NULL) {
724 if(!strcmp("3gp", s->oformat->name))
725 mov_write_ftyp_tag(pb);
726 }
727
1cb5f7fd
MN
728 put_flush_packet(pb);
729
730 return 0;
731}
732
733static int Timestamp() {
734 time_t ltime;
735 time ( &ltime );
736 return ltime+(24107*86400);
737}
738
739static int mov_write_packet(AVFormatContext *s, int stream_index,
49057904 740 const uint8_t *buf, int size, int64_t pts)
1cb5f7fd
MN
741{
742 MOVContext *mov = s->priv_data;
743 ByteIOContext *pb = &s->pb;
744 AVCodecContext *enc;
1a31840c 745 int cl, id;
1cb5f7fd
MN
746
747 enc = &s->streams[stream_index]->codec;
748 if (!url_is_streamed(&s->pb)) {
749 MOVTrack* trk = &mov->tracks[stream_index];
750 int sampleCount = 0;
f578f938 751 unsigned int chunkSize = 0;
1cb5f7fd 752
f578f938
TR
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};
757 int len = 0;
1cb5f7fd 758
f578f938
TR
759 while(len < size && sampleCount < 100) {
760 len += packed_size[(buf[len] >> 3) & 0x0F];
761 sampleCount++;
762 }
763 chunkSize = 1;
764 }
765 else {
766 sampleCount = size;
767 chunkSize = size/enc->channels;
1cb5f7fd
MN
768 }
769 }
f578f938
TR
770 else if(enc->codec_type == CODEC_TYPE_VIDEO) {
771 if(enc->codec_id == CODEC_ID_MPEG4 &&
772 trk->vosLen == 0)
773 {
774 assert(enc->extradata_size);
775
776 trk->vosLen = enc->extradata_size;
777 trk->vosData = av_malloc(trk->vosLen);
778 memcpy(trk->vosData, enc->extradata, trk->vosLen);
779 }
780 chunkSize = 1;
1cb5f7fd
MN
781 }
782
1a31840c
MM
783 cl = trk->entry / MOV_INDEX_CLUSTER_SIZE;
784 id = trk->entry % MOV_INDEX_CLUSTER_SIZE;
1cb5f7fd
MN
785
786 if (trk->ents_allocated <= trk->entry) {
787 trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*));
788 if (!trk->cluster)
789 return -1;
790 trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry));
791 if (!trk->cluster[cl])
792 return -1;
793 trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE;
794 }
f578f938
TR
795 if(mov->mdat_written == 0) {
796 mov_write_mdat_tag(pb, mov);
797 mov->mdat_written = 1;
1cb5f7fd
MN
798 mov->time = Timestamp();
799 }
6e6d6dc0 800
1cb5f7fd 801 trk->cluster[cl][id].pos = url_ftell(pb) - mov->movi_list;
f578f938
TR
802 trk->cluster[cl][id].chunkSize = chunkSize;
803 if(enc->channels > 1)
804 trk->cluster[cl][id].len = size/enc->channels;
805 else
806 trk->cluster[cl][id].len = size;
1cb5f7fd 807 trk->cluster[cl][id].entries = sampleCount;
f578f938
TR
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;
812 }
1cb5f7fd
MN
813 trk->enc = enc;
814 trk->entry++;
815 if(sampleCount == 0)
816 trk->samples++;
817 else
818 trk->samples += sampleCount;
819 trk->mdat_size += size;
820 }
821 put_buffer(pb, buf, size);
822
823 put_flush_packet(pb);
824 return 0;
825}
826
827static int mov_write_trailer(AVFormatContext *s)
828{
829 MOVContext *mov = s->priv_data;
830 ByteIOContext *pb = &s->pb;
831 int res = 0;
832 int i, j;
833 offset_t file_size;
834
835 file_size = url_ftell(pb);
836 j = 0;
837
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;
842 }
843 }
f578f938 844 url_fseek(pb, mov->mdat_pos, SEEK_SET);
1cb5f7fd
MN
845 put_be32(pb, j+8);
846 url_fseek(pb, file_size, SEEK_SET);
847
848 mov_write_moov_tag(pb, mov);
849
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]);
853 }
854 av_free(mov->tracks[i].cluster);
855 mov->tracks[i].cluster = NULL;
856 mov->tracks[i].ents_allocated = mov->tracks[i].entry = 0;
857 }
858 put_flush_packet(pb);
859
860 return res;
861}
862
863static AVOutputFormat mov_oformat = {
864 "mov",
865 "mov format",
866 NULL,
867 "mov",
868 sizeof(MOVContext),
f578f938 869 CODEC_ID_PCM_ALAW,
2187d948 870 CODEC_ID_MPEG4,
1cb5f7fd
MN
871 mov_write_header,
872 mov_write_packet,
873 mov_write_trailer,
874};
875
876static AVOutputFormat _3gp_oformat = {
877 "3gp",
878 "3gp format",
879 NULL,
880 "3gp",
881 sizeof(MOVContext),
882 CODEC_ID_AMR_NB,
883 CODEC_ID_H263,
884 mov_write_header,
885 mov_write_packet,
886 mov_write_trailer,
887};
888
889static AVOutputFormat mp4_oformat = {
890 "mp4",
891 "mp4 format",
4cb3f3b6
DC
892 "application/mp4",
893 "mp4,m4a",
1cb5f7fd
MN
894 sizeof(MOVContext),
895 CODEC_ID_AAC,
896 CODEC_ID_MPEG4,
897 mov_write_header,
898 mov_write_packet,
899 mov_write_trailer,
900};
901
902int movenc_init(void)
903{
904 av_register_output_format(&mov_oformat);
905 av_register_output_format(&_3gp_oformat);
906 av_register_output_format(&mp4_oformat);
907 return 0;
908}