Mercurial > libavformat.hg
comparison movenc.c @ 298:0b2eed7b1210 libavformat
movenc patch by (Gildas Bazin <gbazin at altern dot org>)
author | michael |
---|---|
date | Mon, 03 Nov 2003 21:51:07 +0000 |
parents | eccf0c3e3289 |
children | 5ee1aa8cc0ea |
comparison
equal
deleted
inserted
replaced
297:85d558a18134 | 298:0b2eed7b1210 |
---|---|
1 /* | 1 /* |
2 * MOV, 3GP, MP4 encoder. | 2 * MOV, 3GP, MP4 encoder. |
3 * Copyright (c) 2003 Thomas Raivio. | 3 * Copyright (c) 2003 Thomas Raivio. |
4 * Enhancements by Gildas Bazin <gbazin@netcourrier.com> | |
4 * | 5 * |
5 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
6 * modify it under the terms of the GNU Lesser General Public | 7 * modify it under the terms of the GNU Lesser General Public |
7 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
8 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
26 | 27 |
27 #define MOV_INDEX_CLUSTER_SIZE 16384 | 28 #define MOV_INDEX_CLUSTER_SIZE 16384 |
28 #define globalTimescale 1000 | 29 #define globalTimescale 1000 |
29 | 30 |
30 typedef struct MOVIentry { | 31 typedef struct MOVIentry { |
31 unsigned int flags, pos, len; | 32 unsigned int flags, pos, size; |
32 unsigned int chunkSize; | 33 unsigned int samplesInChunk; |
33 char key_frame; | 34 char key_frame; |
34 unsigned int entries; | 35 unsigned int entries; |
35 } MOVIentry; | 36 } MOVIentry; |
36 | 37 |
37 typedef struct MOVIndex { | 38 typedef struct MOVIndex { |
38 int entry; | 39 int entry; |
39 int samples; | |
40 int mdat_size; | 40 int mdat_size; |
41 int ents_allocated; | 41 int ents_allocated; |
42 long timescale; | 42 long timescale; |
43 long time; | 43 long time; |
44 long frameCount; | |
45 long trackDuration; | 44 long trackDuration; |
46 long sampleDelta; | 45 long sampleCount; |
46 long sampleDuration; | |
47 int hasKeyframes; | 47 int hasKeyframes; |
48 int trackID; | 48 int trackID; |
49 AVCodecContext *enc; | 49 AVCodecContext *enc; |
50 | 50 |
51 int vosLen; | 51 int vosLen; |
61 offset_t movi_list; | 61 offset_t movi_list; |
62 long timescale; | 62 long timescale; |
63 MOVTrack tracks[MAX_STREAMS]; | 63 MOVTrack tracks[MAX_STREAMS]; |
64 } MOVContext; | 64 } MOVContext; |
65 | 65 |
66 static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track); | |
67 | |
66 //FIXME supprt 64bit varaint with wide placeholders | 68 //FIXME supprt 64bit varaint with wide placeholders |
67 static int updateSize (ByteIOContext *pb, int pos) | 69 static int updateSize (ByteIOContext *pb, int pos) |
68 { | 70 { |
69 long curpos = url_ftell(pb); | 71 long curpos = url_ftell(pb); |
70 url_fseek(pb, pos, SEEK_SET); | 72 url_fseek(pb, pos, SEEK_SET); |
72 url_fseek(pb, curpos, SEEK_SET); | 74 url_fseek(pb, curpos, SEEK_SET); |
73 | 75 |
74 return curpos - pos; | 76 return curpos - pos; |
75 } | 77 } |
76 | 78 |
79 /* Chunk offset atom */ | |
77 static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track) | 80 static int mov_write_stco_tag(ByteIOContext *pb, MOVTrack* track) |
78 { | 81 { |
79 int i; | 82 int i; |
80 int pos = url_ftell(pb); | 83 int pos = url_ftell(pb); |
81 put_be32(pb, 0); /* size */ | 84 put_be32(pb, 0); /* size */ |
88 put_be32(pb, track->cluster[cl][id].pos); | 91 put_be32(pb, track->cluster[cl][id].pos); |
89 } | 92 } |
90 return updateSize (pb, pos); | 93 return updateSize (pb, pos); |
91 } | 94 } |
92 | 95 |
96 /* Sample size atom */ | |
93 static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track) | 97 static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track) |
94 { | 98 { |
95 int equalChunks = 1; | 99 int equalChunks = 1; |
96 int i, tst = -1, oldtst = -1; | 100 int i, j, entries = 0, tst = -1, oldtst = -1; |
97 | 101 |
98 int pos = url_ftell(pb); | 102 int pos = url_ftell(pb); |
99 put_be32(pb, 0); /* size */ | 103 put_be32(pb, 0); /* size */ |
100 put_tag(pb, "stsz"); | 104 put_tag(pb, "stsz"); |
101 put_be32(pb, 0); /* version & flags */ | 105 put_be32(pb, 0); /* version & flags */ |
102 | 106 |
103 for (i=0; i<track->entry; i++) { | 107 for (i=0; i<track->entry; i++) { |
104 int cl = i / MOV_INDEX_CLUSTER_SIZE; | 108 int cl = i / MOV_INDEX_CLUSTER_SIZE; |
105 int id = i % MOV_INDEX_CLUSTER_SIZE; | 109 int id = i % MOV_INDEX_CLUSTER_SIZE; |
106 tst = track->cluster[cl][id].len; | 110 tst = track->cluster[cl][id].size/track->cluster[cl][id].entries; |
107 if(oldtst != -1 && tst != oldtst) { | 111 if(oldtst != -1 && tst != oldtst) { |
108 equalChunks = 0; | 112 equalChunks = 0; |
109 break; | |
110 } | 113 } |
111 oldtst = tst; | 114 oldtst = tst; |
112 } | 115 entries += track->cluster[cl][id].entries; |
113 if(equalChunks || | 116 } |
114 track->enc->codec_type == CODEC_TYPE_AUDIO) { | 117 if (equalChunks) { |
115 //int sSize = track->cluster[0][0].len/track->cluster[0][0].entries; | 118 int sSize = track->cluster[0][0].size/track->cluster[0][0].entries; |
116 int sSize = track->cluster[0][0].len; | |
117 put_be32(pb, sSize); // sample size | 119 put_be32(pb, sSize); // sample size |
118 put_be32(pb, track->samples/track->enc->channels); // sample count | 120 put_be32(pb, entries); // sample count |
119 } | 121 } |
120 else { | 122 else { |
121 put_be32(pb, 0); // sample size | 123 put_be32(pb, 0); // sample size |
122 put_be32(pb, track->entry); // sample count | 124 put_be32(pb, entries); // sample count |
123 for (i=0; i<track->entry; i++) { | 125 for (i=0; i<track->entry; i++) { |
124 int cl = i / MOV_INDEX_CLUSTER_SIZE; | 126 int cl = i / MOV_INDEX_CLUSTER_SIZE; |
125 int id = i % MOV_INDEX_CLUSTER_SIZE; | 127 int id = i % MOV_INDEX_CLUSTER_SIZE; |
126 put_be32(pb, track->cluster[cl][id].len); | 128 for ( j=0; j<track->cluster[cl][id].entries; j++) { |
129 put_be32(pb, track->cluster[cl][id].size / | |
130 track->cluster[cl][id].entries); | |
131 } | |
127 } | 132 } |
128 } | 133 } |
129 return updateSize (pb, pos); | 134 return updateSize (pb, pos); |
130 } | 135 } |
131 | 136 |
137 /* Sample to chunk atom */ | |
132 static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track) | 138 static int mov_write_stsc_tag(ByteIOContext *pb, MOVTrack* track) |
133 { | 139 { |
134 int index = 0, oldval = -1, i, entryPos, curpos; | 140 int index = 0, oldval = -1, i, entryPos, curpos; |
135 | 141 |
136 int pos = url_ftell(pb); | 142 int pos = url_ftell(pb); |
140 entryPos = url_ftell(pb); | 146 entryPos = url_ftell(pb); |
141 put_be32(pb, track->entry); // entry count | 147 put_be32(pb, track->entry); // entry count |
142 for (i=0; i<track->entry; i++) { | 148 for (i=0; i<track->entry; i++) { |
143 int cl = i / MOV_INDEX_CLUSTER_SIZE; | 149 int cl = i / MOV_INDEX_CLUSTER_SIZE; |
144 int id = i % MOV_INDEX_CLUSTER_SIZE; | 150 int id = i % MOV_INDEX_CLUSTER_SIZE; |
145 if(oldval != track->cluster[cl][id].chunkSize) | 151 if(oldval != track->cluster[cl][id].samplesInChunk) |
146 { | 152 { |
147 put_be32(pb, i+1); // first chunk | 153 put_be32(pb, i+1); // first chunk |
148 put_be32(pb, track->cluster[cl][id].chunkSize); | 154 put_be32(pb, track->cluster[cl][id].samplesInChunk); // samples per chunk |
149 put_be32(pb, 0x1); // sample description index | 155 put_be32(pb, 0x1); // sample description index |
150 oldval = track->cluster[cl][id].chunkSize; | 156 oldval = track->cluster[cl][id].samplesInChunk; |
151 index++; | 157 index++; |
152 } | 158 } |
153 } | 159 } |
154 curpos = url_ftell(pb); | 160 curpos = url_ftell(pb); |
155 url_fseek(pb, entryPos, SEEK_SET); | 161 url_fseek(pb, entryPos, SEEK_SET); |
157 url_fseek(pb, curpos, SEEK_SET); | 163 url_fseek(pb, curpos, SEEK_SET); |
158 | 164 |
159 return updateSize (pb, pos); | 165 return updateSize (pb, pos); |
160 } | 166 } |
161 | 167 |
168 /* Sync sample atom */ | |
162 static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track) | 169 static int mov_write_stss_tag(ByteIOContext *pb, MOVTrack* track) |
163 { | 170 { |
164 long curpos; | 171 long curpos; |
165 int i, index = 0, entryPos; | 172 int i, index = 0, entryPos; |
166 int pos = url_ftell(pb); | 173 int pos = url_ftell(pb); |
221 put_tag(pb, " "); | 228 put_tag(pb, " "); |
222 | 229 |
223 put_be32(pb, 0); /* Reserved */ | 230 put_be32(pb, 0); /* Reserved */ |
224 put_be16(pb, 0); /* Reserved */ | 231 put_be16(pb, 0); /* Reserved */ |
225 put_be16(pb, 1); /* Data-reference index, XXX == 1 */ | 232 put_be16(pb, 1); /* Data-reference index, XXX == 1 */ |
226 put_be32(pb, 0); /* Reserved */ | 233 /* SoundDescription */ |
234 put_be16(pb, 0); /* Version */ | |
235 put_be16(pb, 0); /* Revision level */ | |
227 put_be32(pb, 0); /* Reserved */ | 236 put_be32(pb, 0); /* Reserved */ |
228 | 237 |
229 put_be16(pb, track->enc->channels); /* Number of channels */ | 238 put_be16(pb, track->enc->channels); /* Number of channels */ |
230 /* TODO: Currently hard-coded to 16-bit, there doesn't seem | 239 /* TODO: Currently hard-coded to 16-bit, there doesn't seem |
231 to be a good way to get number of bits of audio */ | 240 to be a good way to get number of bits of audio */ |
232 put_be16(pb, 0x10); /* Reserved */ | 241 put_be16(pb, 0x10); /* Reserved */ |
233 put_be16(pb, 0); /* compression ID (= 0) */ | 242 put_be16(pb, 0); /* compression ID (= 0) */ |
234 put_be16(pb, 0); /* packet size (= 0) */ | 243 put_be16(pb, 0); /* packet size (= 0) */ |
235 put_be16(pb, track->timescale); /* Time scale */ | 244 put_be16(pb, track->timescale); /* Time scale */ |
236 put_be16(pb, 0); /* Reserved */ | 245 put_be16(pb, 0); /* Reserved */ |
237 | 246 |
247 if(track->enc->codec_id == CODEC_ID_AAC) | |
248 mov_write_esds_tag(pb, track); | |
238 if(track->enc->codec_id == CODEC_ID_AMR_NB) | 249 if(track->enc->codec_id == CODEC_ID_AMR_NB) |
239 mov_write_damr_tag(pb); | 250 mov_write_damr_tag(pb); |
240 return updateSize (pb, pos); | 251 return updateSize (pb, pos); |
241 } | 252 } |
242 | 253 |
261 put_be32(pb, 0xc0000000); | 272 put_be32(pb, 0xc0000000); |
262 put_byte(pb, 0); | 273 put_byte(pb, 0); |
263 return 0x15; | 274 return 0x15; |
264 } | 275 } |
265 | 276 |
266 static unsigned int esdsLength(unsigned int len) | 277 static unsigned int descrLength(unsigned int len) |
267 { | 278 { |
268 unsigned int result = 0; | 279 if (len < 0x00000080) |
269 unsigned char b = len & 0x7f; | 280 return 2 + len; |
270 result += b; | 281 else if (len < 0x00004000) |
271 b = (len >> 8) & 0x7f; | 282 return 3 + len; |
272 result += (b + 0x80) << 8; | 283 else if(len < 0x00200000) |
273 b = (len >> 16) & 0x7f; | 284 return 4 + len; |
274 result += (b + 0x80) << 16; | 285 else |
275 b = (len >> 24) & 0x7f; | 286 return 5 + len; |
276 result += (b + 0x80) << 24; | 287 } |
277 return result; | 288 |
289 static void putDescr(ByteIOContext *pb, int tag, int size) | |
290 { | |
291 uint32_t len; | |
292 uint8_t vals[4]; | |
293 | |
294 len = size; | |
295 vals[3] = (uint8_t)(len & 0x7f); | |
296 len >>= 7; | |
297 vals[2] = (uint8_t)((len & 0x7f) | 0x80); | |
298 len >>= 7; | |
299 vals[1] = (uint8_t)((len & 0x7f) | 0x80); | |
300 len >>= 7; | |
301 vals[0] = (uint8_t)((len & 0x7f) | 0x80); | |
302 | |
303 put_byte(pb, tag); // DescriptorTag | |
304 | |
305 if (size < 0x00000080) | |
306 { | |
307 put_byte(pb, vals[3]); | |
308 } | |
309 else if (size < 0x00004000) | |
310 { | |
311 put_byte(pb, vals[2]); | |
312 put_byte(pb, vals[3]); | |
313 } | |
314 else if (size < 0x00200000) | |
315 { | |
316 put_byte(pb, vals[1]); | |
317 put_byte(pb, vals[2]); | |
318 put_byte(pb, vals[3]); | |
319 } | |
320 else if (size < 0x10000000) | |
321 { | |
322 put_byte(pb, vals[0]); | |
323 put_byte(pb, vals[1]); | |
324 put_byte(pb, vals[2]); | |
325 put_byte(pb, vals[3]); | |
326 } | |
278 } | 327 } |
279 | 328 |
280 static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic | 329 static int mov_write_esds_tag(ByteIOContext *pb, MOVTrack* track) // Basic |
281 { | 330 { |
282 put_be32(pb, track->vosLen+18+14+17); | 331 int decoderSpecificInfoLen = track->vosLen ? descrLength(track->vosLen):0; |
332 int pos = url_ftell(pb); | |
333 | |
334 put_be32(pb, 0); // size | |
283 put_tag(pb, "esds"); | 335 put_tag(pb, "esds"); |
284 put_be32(pb, 0); // Version | 336 put_be32(pb, 0); // Version |
285 | 337 |
286 put_byte(pb, 0x03); // tag = ES_DescriptorTag | 338 // ES descriptor |
287 put_be32(pb, esdsLength(track->vosLen+18+14)); // Length | 339 putDescr(pb, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) + |
288 put_be16(pb, 0x0001); // ID (= 1) | 340 descrLength(1)); |
341 put_be16(pb, 0x0001); // ID (= 1) | |
289 put_byte(pb, 0x00); // flags (= no flags) | 342 put_byte(pb, 0x00); // flags (= no flags) |
290 | 343 |
291 // Decoderconfigdescriptor = 4 | 344 // DecoderConfig descriptor |
292 put_byte(pb, 0x04); // tag = DecoderConfigDescriptor | 345 putDescr(pb, 0x04, 13 + decoderSpecificInfoLen); |
293 put_be32(pb, esdsLength(track->vosLen+18)); // Length | 346 |
294 put_byte(pb, 0x20); // Object type indication (Visual 14496-2) | 347 if(track->enc->codec_id == CODEC_ID_AAC) |
295 put_byte(pb, 0x11); // flags (= Visualstream) | 348 put_byte(pb, 0x40); // Object type indication |
349 else if(track->enc->codec_id == CODEC_ID_MPEG4) | |
350 put_byte(pb, 0x20); // Object type indication (Visual 14496-2) | |
351 | |
352 if(track->enc->codec_type == CODEC_TYPE_AUDIO) | |
353 put_byte(pb, 0x15); // flags (= Audiostream) | |
354 else | |
355 put_byte(pb, 0x11); // flags (= Visualstream) | |
356 | |
296 put_byte(pb, 0x0); // Buffersize DB (24 bits) | 357 put_byte(pb, 0x0); // Buffersize DB (24 bits) |
297 put_be16(pb, 0x0dd2); // Buffersize DB | 358 put_be16(pb, 0x0dd2); // Buffersize DB |
298 | 359 |
299 // TODO: find real values for these | 360 // TODO: find real values for these |
300 put_be32(pb, 0x0002e918); // maxbitrate | 361 put_be32(pb, 0x0002e918); // maxbitrate |
301 put_be32(pb, 0x00017e6b); // avg bitrate | 362 put_be32(pb, 0x00017e6b); // avg bitrate |
302 | 363 |
303 // Decoderspecific info Tag = 5 | 364 if (track->vosLen) |
304 put_byte(pb, 0x05); // tag = Decoderspecific info | 365 { |
305 put_be32(pb, esdsLength(track->vosLen)); // length | 366 // DecoderSpecific info descriptor |
306 put_buffer(pb, track->vosData, track->vosLen); | 367 putDescr(pb, 0x05, track->vosLen); |
307 | 368 put_buffer(pb, track->vosData, track->vosLen); |
308 put_byte(pb, 0x06); | 369 } |
309 put_be32(pb, esdsLength(1)); // length | 370 |
371 // SL descriptor | |
372 putDescr(pb, 0x06, descrLength(1)); | |
310 put_byte(pb, 0x02); | 373 put_byte(pb, 0x02); |
311 return track->vosLen+18+14+17; | 374 return updateSize (pb, pos); |
312 } | 375 } |
313 | 376 |
314 static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track) | 377 static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track) |
315 { | 378 { |
316 int pos = url_ftell(pb); | 379 int pos = url_ftell(pb); |
374 mov_write_audio_tag(pb, track); | 437 mov_write_audio_tag(pb, track); |
375 return updateSize(pb, pos); | 438 return updateSize(pb, pos); |
376 } | 439 } |
377 | 440 |
378 /* TODO?: Currently all samples/frames seem to have same duration */ | 441 /* TODO?: Currently all samples/frames seem to have same duration */ |
442 /* Time to sample atom */ | |
379 static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track) | 443 static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track) |
380 { | 444 { |
381 put_be32(pb, 0x18); /* size */ | 445 put_be32(pb, 0x18); /* size */ |
382 put_tag(pb, "stts"); | 446 put_tag(pb, "stts"); |
383 put_be32(pb, 0); /* version & flags */ | 447 put_be32(pb, 0); /* version & flags */ |
384 put_be32(pb, 1); /* entry count */ | 448 put_be32(pb, 1); /* entry count */ |
385 | 449 |
386 put_be32(pb, track->frameCount); /* sample count */ | 450 put_be32(pb, track->sampleCount); /* sample count */ |
387 put_be32(pb, track->sampleDelta); /* sample delta */ | 451 put_be32(pb, track->sampleDuration); /* sample duration */ |
388 return 0x18; | 452 return 0x18; |
389 } | 453 } |
390 | 454 |
391 static int mov_write_dref_tag(ByteIOContext *pb) | 455 static int mov_write_dref_tag(ByteIOContext *pb) |
392 { | 456 { |
489 put_be32(pb, 32); /* size */ | 553 put_be32(pb, 32); /* size */ |
490 put_tag(pb, "mdhd"); | 554 put_tag(pb, "mdhd"); |
491 put_be32(pb, 0); /* Version & flags */ | 555 put_be32(pb, 0); /* Version & flags */ |
492 put_be32(pb, track->time); /* creation time */ | 556 put_be32(pb, track->time); /* creation time */ |
493 put_be32(pb, track->time); /* modification time */ | 557 put_be32(pb, track->time); /* modification time */ |
494 if(track->enc->codec_type == CODEC_TYPE_VIDEO) { | 558 put_be32(pb, track->timescale); /* time scale (sample rate for audio) */ |
495 int64_t rate = track->enc->frame_rate; | 559 put_be32(pb, track->trackDuration); /* duration */ |
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 } | |
503 put_be16(pb, 0); /* language, 0 = english */ | 560 put_be16(pb, 0); /* language, 0 = english */ |
504 put_be16(pb, 0); /* reserved (quality) */ | 561 put_be16(pb, 0); /* reserved (quality) */ |
505 return 32; | 562 return 32; |
506 } | 563 } |
507 | 564 |
642 put_be32(pb, 0); /* size placeholder*/ | 699 put_be32(pb, 0); /* size placeholder*/ |
643 put_tag(pb, "moov"); | 700 put_tag(pb, "moov"); |
644 mov->timescale = globalTimescale; | 701 mov->timescale = globalTimescale; |
645 | 702 |
646 for (i=0; i<MAX_STREAMS; i++) { | 703 for (i=0; i<MAX_STREAMS; i++) { |
647 if(mov->tracks[i].entry > 0) { | 704 if(mov->tracks[i].entry <= 0) continue; |
648 if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) { | 705 |
649 mov->tracks[i].timescale = globalTimescale; | 706 if(mov->tracks[i].enc->codec_type == CODEC_TYPE_VIDEO) { |
650 mov->tracks[i].sampleDelta = mov->tracks[i].enc->frame_rate_base; | 707 mov->tracks[i].timescale = mov->tracks[i].enc->frame_rate; |
651 mov->tracks[i].frameCount = mov->tracks[i].samples; | 708 mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_rate_base; |
652 mov->tracks[i].trackDuration = (int64_t)((int64_t)mov->tracks[i].entry* | 709 } |
653 (int64_t)globalTimescale*(int64_t)mov->tracks[i].enc->frame_rate_base)/(int64_t)mov->tracks[i].enc->frame_rate; | 710 else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) { |
711 /* If AMR, track timescale = 8000, AMR_WB = 16000 */ | |
712 if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) { | |
713 mov->tracks[i].sampleDuration = 160; // Bytes per chunk | |
714 mov->tracks[i].timescale = 8000; | |
654 } | 715 } |
655 else if(mov->tracks[i].enc->codec_type == CODEC_TYPE_AUDIO) { | 716 else { |
656 long trackDuration = 0; | 717 mov->tracks[i].timescale = mov->tracks[i].enc->sample_rate; |
657 /* If AMR, track timescale = 8000, AMR_WB = 16000 */ | 718 mov->tracks[i].sampleDuration = mov->tracks[i].enc->frame_size; |
658 if(mov->tracks[i].enc->codec_id == CODEC_ID_AMR_NB) { | |
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 | |
669 mov->tracks[i].timescale = 8000; | |
670 } | |
671 else { | |
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; | |
682 } | |
683 } | 719 } |
684 mov->tracks[i].time = mov->time; | 720 } |
685 mov->tracks[i].trackID = i+1; | 721 |
686 } | 722 mov->tracks[i].trackDuration = |
723 mov->tracks[i].sampleCount * mov->tracks[i].sampleDuration; | |
724 mov->tracks[i].time = mov->time; | |
725 mov->tracks[i].trackID = i+1; | |
687 } | 726 } |
688 | 727 |
689 mov_write_mvhd_tag(pb, mov); | 728 mov_write_mvhd_tag(pb, mov); |
690 //mov_write_iods_tag(pb, mov); | 729 //mov_write_iods_tag(pb, mov); |
691 for (i=0; i<MAX_STREAMS; i++) { | 730 for (i=0; i<MAX_STREAMS; i++) { |
704 put_tag(pb, "mdat"); | 743 put_tag(pb, "mdat"); |
705 return 0; | 744 return 0; |
706 } | 745 } |
707 | 746 |
708 /* TODO: This needs to be more general */ | 747 /* TODO: This needs to be more general */ |
709 int mov_write_ftyp_tag(ByteIOContext *pb) | 748 int mov_write_ftyp_tag(ByteIOContext *pb, AVFormatContext *s) |
710 { | 749 { |
711 put_be32(pb, 0x14 ); /* size */ | 750 put_be32(pb, 0x14 ); /* size */ |
712 put_tag(pb, "ftyp"); | 751 put_tag(pb, "ftyp"); |
713 put_tag(pb, "3gp4"); | 752 |
753 if (!strcmp("3gp", s->oformat->name)) | |
754 put_tag(pb, "3gp4"); | |
755 else | |
756 put_tag(pb, "isom"); | |
757 | |
714 put_be32(pb, 0x200 ); | 758 put_be32(pb, 0x200 ); |
715 put_tag(pb, "3gp4"); | 759 |
760 if (!strcmp("3gp", s->oformat->name)) | |
761 put_tag(pb, "3gp4"); | |
762 else | |
763 put_tag(pb, "mp41"); | |
764 | |
716 return 0x14; | 765 return 0x14; |
717 } | 766 } |
718 | 767 |
719 static int mov_write_header(AVFormatContext *s) | 768 static int mov_write_header(AVFormatContext *s) |
720 { | 769 { |
721 ByteIOContext *pb = &s->pb; | 770 ByteIOContext *pb = &s->pb; |
722 | 771 |
723 if(s->oformat != NULL) { | 772 if(s->oformat != NULL) { |
724 if(!strcmp("3gp", s->oformat->name)) | 773 if(!strcmp("3gp", s->oformat->name) || !strcmp("mp4", s->oformat->name)) |
725 mov_write_ftyp_tag(pb); | 774 mov_write_ftyp_tag(pb,s); |
726 } | 775 } |
727 | 776 |
728 put_flush_packet(pb); | 777 put_flush_packet(pb); |
729 | 778 |
730 return 0; | 779 return 0; |
739 static int mov_write_packet(AVFormatContext *s, int stream_index, | 788 static int mov_write_packet(AVFormatContext *s, int stream_index, |
740 const uint8_t *buf, int size, int64_t pts) | 789 const uint8_t *buf, int size, int64_t pts) |
741 { | 790 { |
742 MOVContext *mov = s->priv_data; | 791 MOVContext *mov = s->priv_data; |
743 ByteIOContext *pb = &s->pb; | 792 ByteIOContext *pb = &s->pb; |
744 AVCodecContext *enc; | 793 AVCodecContext *enc = &s->streams[stream_index]->codec; |
794 MOVTrack* trk = &mov->tracks[stream_index]; | |
745 int cl, id; | 795 int cl, id; |
746 | 796 unsigned int samplesInChunk = 0; |
747 enc = &s->streams[stream_index]->codec; | 797 |
748 if (!url_is_streamed(&s->pb)) { | 798 if (url_is_streamed(&s->pb)) return 0; /* Can't handle that */ |
749 MOVTrack* trk = &mov->tracks[stream_index]; | 799 if (!size) return 0; /* Discard 0 sized packets */ |
750 int sampleCount = 0; | 800 |
751 unsigned int chunkSize = 0; | 801 if (enc->codec_type == CODEC_TYPE_VIDEO ) { |
752 | 802 samplesInChunk = 1; |
753 if(enc->codec_type == CODEC_TYPE_AUDIO) { | 803 } |
804 else if (enc->codec_type == CODEC_TYPE_AUDIO ) { | |
805 if( enc->codec_id == CODEC_ID_AMR_NB) { | |
754 /* We must find out how many AMR blocks there are in one packet */ | 806 /* We must find out how many AMR blocks there are in one packet */ |
755 if(enc->codec_id == CODEC_ID_AMR_NB) { | 807 static uint16_t packed_size[16] = |
756 static uint16_t packed_size[16] = {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0}; | 808 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 0}; |
757 int len = 0; | 809 int len = 0; |
758 | 810 |
759 while(len < size && sampleCount < 100) { | 811 while (len < size && samplesInChunk < 100) { |
760 len += packed_size[(buf[len] >> 3) & 0x0F]; | 812 len += packed_size[(buf[len] >> 3) & 0x0F]; |
761 sampleCount++; | 813 samplesInChunk++; |
762 } | |
763 chunkSize = 1; | |
764 } | 814 } |
765 else { | 815 } |
766 sampleCount = size; | 816 else if(enc->codec_id == CODEC_ID_PCM_ALAW) { |
767 chunkSize = size/enc->channels; | 817 samplesInChunk = size/enc->channels; |
768 } | 818 } |
769 } | 819 else { |
770 else if(enc->codec_type == CODEC_TYPE_VIDEO) { | 820 samplesInChunk = 1; |
771 if(enc->codec_id == CODEC_ID_MPEG4 && | 821 } |
772 trk->vosLen == 0) | 822 } |
773 { | 823 |
774 assert(enc->extradata_size); | 824 if ((enc->codec_id == CODEC_ID_MPEG4 || enc->codec_id == CODEC_ID_AAC) |
775 | 825 && trk->vosLen == 0) { |
776 trk->vosLen = enc->extradata_size; | 826 assert(enc->extradata_size); |
777 trk->vosData = av_malloc(trk->vosLen); | 827 |
778 memcpy(trk->vosData, enc->extradata, trk->vosLen); | 828 trk->vosLen = enc->extradata_size; |
779 } | 829 trk->vosData = av_malloc(trk->vosLen); |
780 chunkSize = 1; | 830 memcpy(trk->vosData, enc->extradata, trk->vosLen); |
781 } | 831 } |
782 | 832 |
783 cl = trk->entry / MOV_INDEX_CLUSTER_SIZE; | 833 cl = trk->entry / MOV_INDEX_CLUSTER_SIZE; |
784 id = trk->entry % MOV_INDEX_CLUSTER_SIZE; | 834 id = trk->entry % MOV_INDEX_CLUSTER_SIZE; |
785 | 835 |
786 if (trk->ents_allocated <= trk->entry) { | 836 if (trk->ents_allocated <= trk->entry) { |
787 trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*)); | 837 trk->cluster = av_realloc(trk->cluster, (cl+1)*sizeof(void*)); |
788 if (!trk->cluster) | 838 if (!trk->cluster) |
789 return -1; | 839 return -1; |
790 trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry)); | 840 trk->cluster[cl] = av_malloc(MOV_INDEX_CLUSTER_SIZE*sizeof(MOVIentry)); |
791 if (!trk->cluster[cl]) | 841 if (!trk->cluster[cl]) |
792 return -1; | 842 return -1; |
793 trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE; | 843 trk->ents_allocated += MOV_INDEX_CLUSTER_SIZE; |
794 } | 844 } |
795 if(mov->mdat_written == 0) { | 845 if (mov->mdat_written == 0) { |
796 mov_write_mdat_tag(pb, mov); | 846 mov_write_mdat_tag(pb, mov); |
797 mov->mdat_written = 1; | 847 mov->mdat_written = 1; |
798 mov->time = Timestamp(); | 848 mov->time = Timestamp(); |
799 } | 849 } |
800 | 850 |
801 trk->cluster[cl][id].pos = url_ftell(pb) - mov->movi_list; | 851 trk->cluster[cl][id].pos = url_ftell(pb) - mov->movi_list; |
802 trk->cluster[cl][id].chunkSize = chunkSize; | 852 trk->cluster[cl][id].samplesInChunk = samplesInChunk; |
803 if(enc->channels > 1) | 853 trk->cluster[cl][id].size = size; |
804 trk->cluster[cl][id].len = size/enc->channels; | 854 trk->cluster[cl][id].entries = samplesInChunk; |
805 else | 855 if(enc->codec_type == CODEC_TYPE_VIDEO) { |
806 trk->cluster[cl][id].len = size; | 856 trk->cluster[cl][id].key_frame = enc->coded_frame->key_frame; |
807 trk->cluster[cl][id].entries = sampleCount; | 857 if(enc->coded_frame->pict_type == FF_I_TYPE) |
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; | 858 trk->hasKeyframes = 1; |
812 } | 859 } |
813 trk->enc = enc; | 860 trk->enc = enc; |
814 trk->entry++; | 861 trk->entry++; |
815 if(sampleCount == 0) | 862 trk->sampleCount += samplesInChunk; |
816 trk->samples++; | 863 trk->mdat_size += size; |
817 else | 864 |
818 trk->samples += sampleCount; | |
819 trk->mdat_size += size; | |
820 } | |
821 put_buffer(pb, buf, size); | 865 put_buffer(pb, buf, size); |
822 | 866 |
823 put_flush_packet(pb); | 867 put_flush_packet(pb); |
824 return 0; | 868 return 0; |
825 } | 869 } |