1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 /**
17 ******************************************************************************
18 * @file M4MP4W_Writer.c
19 * @brief Implementation of the core MP4 writer
20 ******************************************************************************
21 */
22
23 #include "NXPSW_CompilerSwitches.h"
24
25 #ifndef _M4MP4W_USE_CST_MEMORY_WRITER
26
27 #include "M4OSA_Error.h"
28 #include "M4OSA_Debug.h"
29 #include "M4MP4W_Writer.h"
30 #include "M4MP4W_Utils.h"
31
32 /* Check optimisation flags : BEGIN */
33 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
34 #ifdef _M4MP4W_MOOV_FIRST
35 #error "_M4MP4W_OPTIMIZE_FOR_PHONE should not be used with _M4MP4W_MOOV_FIRST"
36
37 #endif
38
39 #endif
40
41 #ifdef _M4MP4W_UNBUFFERED_VIDEO
42 #ifndef _M4MP4W_OPTIMIZE_FOR_PHONE
43 #error "_M4MP4W_UNBUFFERED_VIDEO should be used with _M4MP4W_OPTIMIZE_FOR_PHONE"
44
45 #endif
46
47 #endif
48 /* Check optimisation flags : END */
49
50 #ifndef _M4MP4W_DONT_USE_TIME_H
51 #include <time.h>
52
53 #endif /*_M4MP4W_DONT_USE_TIME_H*/
54
55 /*MACROS*/
56 #define MAJOR_VERSION 3
57 #define MINOR_VERSION 3
58 #define REVISION 0
59
60 #define ERR_CHECK(exp, err) if (!(exp)) { return err; }
61 #define CLEANUPonERR(func) if ((err = func) != M4NO_ERROR) goto cleanup
62
63 #define max(a,b) (((a) > (b)) ? (a) : (b))
64
65 /***************/
66 /*Static blocks*/
67 /***************/
68
69 /*CommonBlocks*/
70
71 const M4OSA_UChar Default_ftyp [] =
72 {
73 0x00, 0x00, 0x00, 0x18, 'f', 't', 'y', 'p', '3', 'g', 'p', '7', 0x00, 0x00,
74 0x03, 0x00, '3', 'g', 'p', '7', 'i', 's', 'o', 'm'
75 };
76
77 const M4OSA_UChar CommonBlock2 [] =
78 {
79 'm', 'd', 'a', 't'
80 };
81
82 const M4OSA_UChar CommonBlock3 [] =
83 {
84 'm', 'o', 'o', 'v', 0x00, 0x00, 0x00, 0x6C, 'm', 'v', 'h', 'd', 0x00,
85 0x00, 0x00, 0x00
86 };
87
88 const M4OSA_UChar CommonBlock4 [] =
89 {
90 0x00, 0x00, 0x03, 0xE8
91 };
92
93 const M4OSA_UChar CommonBlock5 [] =
94 {
95 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03
102 };
103
104 const M4OSA_UChar CommonBlock6 [] =
105 {
106 't', 'r', 'a', 'k', 0x00, 0x00, 0x00, 0x5C, 't', 'k', 'h', 'd', 0x00,
107 0x00, 0x00, 0x01
108 };
109
110 const M4OSA_UChar CommonBlock7 [] =
111 {
112 0x00, 0x00, 0x00, 0x00
113 };
114
115 const M4OSA_UChar CommonBlock7bis [] =
116 {
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x40, 0x00, 0x00, 0x00
122 };
123
124 const M4OSA_UChar CommonBlock8 [] =
125 {
126 'm', 'd', 'i', 'a', 0x00, 0x00, 0x00, 0x20, 'm', 'd', 'h', 'd', 0x00,
127 0x00, 0x00, 0x00
128 };
129
130 const M4OSA_UChar CommonBlock9 [] =
131 {
132 0x55, 0xC4, 0x00, 0x00
133 };
134
135 const M4OSA_UChar CommonBlock10 [] =
136 {
137 'm', 'i', 'n', 'f', 0x00, 0x00, 0x00, 0x24, 'd', 'i', 'n', 'f', 0x00,
138 0x00, 0x00, 0x1C, 'd', 'r', 'e', 'f', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 'u', 'r', 'l', ' ', 0x00, 0x00, 0x00,
140 0x01
141 };
142
143 const M4OSA_UChar CommonBlock11 [] =
144 {
145 's', 't', 'b', 'l'
146 };
147
148 const M4OSA_UChar CommonBlock12 [] =
149 {
150 's', 't', 't', 's', 0x00, 0x00, 0x00, 0x00
151 };
152
153 const M4OSA_UChar SampleDescriptionHeader [] =
154 {
155 's', 't', 's', 'd', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
156 };
157
158 const M4OSA_UChar SampleDescriptionEntryStart [] =
159 {
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00
162 };
163
164 const M4OSA_UChar CommonBlock15 [] =
165 {
166 's', 't', 's', 'z', 0x00, 0x00, 0x00, 0x00
167 };
168
169 const M4OSA_UChar CommonBlock16 [] =
170 {
171 's', 't', 's', 'c', 0x00, 0x00, 0x00, 0x00
172 };
173
174 const M4OSA_UChar CommonBlock17 [] =
175 {
176 's', 't', 'c', 'o', 0x00, 0x00, 0x00, 0x00
177 };
178
179 const M4OSA_UChar BlockSignatureSkipHeader [] =
180 {
181 0x00, 0x00, 0x00, 0x5E, 's', 'k', 'i', 'p'
182 };
183 /* due to current limitations, size must be 16 */
184 const M4OSA_UChar BlockSignatureSkipDefaultEmbeddedString [] =
185 {
186 'N', 'X', 'P', 'S', 'W', ' ', 'C', 'A', 'M', 'C', 'O', 'R', 'D', 'E',
187 'R', ' '
188 };
189 /* follows the version (like " 3.0.2"), then " -- " */
190 /* due to current limitations, size must be 60 */
191 const M4OSA_UChar BlockSignatureSkipDefaultIntegrationTag [] =
192 {
193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
194 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
195 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
196 };
197
198 /*VideoBlocks*/
199 /* 320*240, now no longer hardcoded */
200 /* const M4OSA_UChar VideoBlock1[] =
201 { 0x01, 0x40, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00 }; */
202 const M4OSA_UChar VideoBlock1_1 [] =
203 {
204 0x00, 0x00, 0x00, 0x21, 'h', 'd', 'l', 'r', 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00, 0x00, 0x00, 'v', 'i', 'd', 'e', 0x00, 0x00, 0x00, 0x00, 0x00,
206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
207 };
208
209 const M4OSA_UChar SampleDescriptionEntryVideoBoilerplate1 [] =
210 {
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
212 };
213
214 const M4OSA_UChar SampleDescriptionEntryVideoBoilerplate2 [] =
215 {
216 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x00, 0x00, 0x18, 0xFF, 0xFF
220 };
221
222 const M4OSA_UChar VideoBlock4 [] =
223 {
224 's', 't', 's', 's', 0x00, 0x00, 0x00, 0x00
225 }; /*STSS*/
226
227 const M4OSA_UChar VideoBlock5 [] =
228 {
229 0x00, 0x00, 0x00, 0x14, 'v', 'm', 'h', 'd', 0x00, 0x00, 0x00, 0x00, 0x00,
230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
231 };
232
233 const M4OSA_UChar VideoResolutions [] =
234 {
235 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00
236 };
237
238 /*Mp4vBlocks*/
239 const M4OSA_UChar Mp4vBlock1 [] =
240 {
241 'm', 'p', '4', 'v'
242 };
243
244 const M4OSA_UChar Mp4vBlock3 [] =
245 {
246 0x20, 0x11
247 };
248
249 /*H263Blocks*/
250 const M4OSA_UChar H263Block1 [] =
251 {
252 's', '2', '6', '3'
253 };
254
255 const M4OSA_UChar H263Block2 [] =
256 {
257 0x00, 0x00, 0x00, 0x0F, 'd', '2', '6', '3'
258 };
259
260 const M4OSA_UChar H263Block2_bitr [] =
261 {
262 0x00, 0x00, 0x00, 0x1F, 'd', '2', '6', '3'
263 };
264
265 const M4OSA_UChar H263Block3 [] =
266 {
267 'P', 'H', 'L', 'P', 0x00, 0x0A, 0x00
268 };
269
270 const M4OSA_UChar H263Block4 [] =
271 {
272 0x00, 0x00, 0x00, 0x10, 'b', 'i', 't', 'r'
273 };
274
275 /*H264Blocks*/
276 const M4OSA_UChar H264Block1 [] =
277 {
278 'a', 'v', 'c', '1'
279 };
280
281 /* Store the avcC field, the version (=1),
282 the profile (=66), the compatibility (=0), */
283
284 /* the level (=10),111111 + NAL field Size (= 4 - 1),
285 111 + number of PPS (=1) */
286
287 const M4OSA_UChar H264Block2 [] =
288 {
289 // Remove the hardcoded DSI values of H264Block2
290 'a' , 'v' , 'c' , 'C'
291 };
292
293 /*AMRBlocks*/
294 const M4OSA_UChar AMRBlock1 [] =
295 {
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
297 };
298
299 const M4OSA_UChar AMRBlock1_1 [] =
300 {
301 0x00, 0x00, 0x00, 0x21, 'h', 'd', 'l', 'r', 0x00, 0x00, 0x00, 0x00, 0x00,
302 0x00, 0x00, 0x00, 's', 'o', 'u', 'n', 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
304 };
305
306 const M4OSA_UChar AudioSampleDescEntryBoilerplate [] =
307 {
308 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00
309 };
310
311 const M4OSA_UChar AMRDSIHeader [] =
312 {
313 0x00, 0x00, 0x00, 0x11, 'd', 'a', 'm', 'r'
314 };
315
316 const M4OSA_UChar AMRDefaultDSI [] =
317 {
318 'P', 'H', 'L', 'P', 0x00, 0x00, 0x80, 0x00, 0x01
319 };
320
321 const M4OSA_UChar AMRBlock4 [] =
322 {
323 0x00, 0x00, 0x00, 0x10, 's', 'm', 'h', 'd', 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00
325 };
326
327 /*AMR8Blocks*/
328 const M4OSA_UChar AMR8Block1 [] =
329 {
330 's', 'a', 'm', 'r'
331 };
332
333 /*AMR16Blocks*/
334 /*const M4OSA_UChar AMR16Block1[] = { 's', 'a', 'w', 'b'};*/
335
336 /*AACBlocks*/
337 const M4OSA_UChar AACBlock1 [] =
338 {
339 'm', 'p', '4', 'a'
340 };
341
342 const M4OSA_UChar AACBlock2 [] =
343 {
344 0x40, 0x15
345 };
346
347 /*MPEGConfigBlocks (AAC & MP4V)*/
348 const M4OSA_UChar MPEGConfigBlock0 [] =
349 {
350 'e', 's', 'd', 's', 0x00, 0x00, 0x00, 0x00, 0x03
351 };
352
353 const M4OSA_UChar MPEGConfigBlock1 [] =
354 {
355 0x00, 0x00, 0x00, 0x04
356 };
357
358 const M4OSA_UChar MPEGConfigBlock2 [] = { 0x05 };
359 const M4OSA_UChar MPEGConfigBlock3 [] =
360 {
361 0x06, 0x01, 0x02
362 };
363
364 /*EVRCBlocks*/
365 const M4OSA_UChar EVRCBlock3_1 [] =
366 {
367 0x00, 0x00, 0x00, 0x0E, 'd', 'e', 'v', 'c'
368 };
369
370 const M4OSA_UChar EVRCBlock3_2 [] =
371 {
372 'P', 'H', 'L', 'P', 0x00, 0x00
373 };
374
375 /*EVRC8Blocks*/
376 const M4OSA_UChar EVRC8Block1 [] =
377 {
378 's', 'e', 'v', 'c'
379 };
380
381 /***********/
382 /* Methods */
383 /***********/
384
385 /*******************************************************************************/
M4MP4W_getVersion(M4OSA_UInt8 * major,M4OSA_UInt8 * minor,M4OSA_UInt8 * revision)386 M4OSA_ERR M4MP4W_getVersion(M4OSA_UInt8 *major, M4OSA_UInt8 *minor,
387 M4OSA_UInt8 *revision )
388 /*******************************************************************************/
389 {
390 ERR_CHECK(M4OSA_NULL != major, M4ERR_PARAMETER);
391 ERR_CHECK(M4OSA_NULL != minor, M4ERR_PARAMETER);
392 ERR_CHECK(M4OSA_NULL != revision, M4ERR_PARAMETER);
393
394 *major = MAJOR_VERSION;
395 *minor = MINOR_VERSION;
396 *revision = REVISION;
397
398 return M4NO_ERROR;
399 }
400
401 static M4OSA_UInt32 M4MP4W_STTS_ALLOC_SIZE;
402 static M4OSA_UInt32 M4MP4W_STSZ_ALLOC_SIZE;
403 static M4OSA_UInt32 M4MP4W_STSS_ALLOC_SIZE;
404 static M4OSA_UInt32 M4MP4W_CHUNK_ALLOC_NB;
405 static M4OSA_UInt32 M4MP4W_STTS_AUDIO_ALLOC_SIZE;
406 static M4OSA_UInt32 M4MP4W_STSZ_AUDIO_ALLOC_SIZE;
407 static M4OSA_UInt32 M4MP4W_CHUNK_AUDIO_ALLOC_NB;
408
409 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
410 #ifdef _M4MP4W_UNBUFFERED_VIDEO
411 /* stsc[ ] table is splitted at 12 bits */
412 #define M4MP4W_VIDEO_MAX_AU_PER_CHUNK 4095 /* 0=notused */
413
414 #else
415 #define M4MP4W_VIDEO_MAX_AU_PER_CHUNK 10 /* 0=notused */
416
417 #endif
418
419 #endif
420
421 /*******************************************************************************/
422
M4MP4W_initializeAllocationParameters(M4MP4W_Mp4FileData * Ptr)423 M4OSA_ERR M4MP4W_initializeAllocationParameters(M4MP4W_Mp4FileData *Ptr )
424 /*******************************************************************************/
425 {
426 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
427
428 M4OSA_UInt32 maxMemory, vesMemory;
429 M4OSA_UInt32 nbVideoFrames, nbAudioFrames;
430 M4OSA_UInt32 averageVideoChunk;
431
432 /*-----------*/
433 /* NB_FRAMES */
434 /*-----------*/
435
436 /* magical formula : memory = vesMemory + 12 * framerate * duration */
437
438 #ifdef _M4MP4W_UNBUFFERED_VIDEO
439
440 vesMemory = 0x32000; /* 200 kB */
441
442 #else
443
444 vesMemory = 0x3E800; /* 250 kB */
445
446 #endif
447
448 #define VIDEO_POOL_MEMORY 1000000
449
450 maxMemory = VIDEO_POOL_MEMORY;
451
452 if (maxMemory < vesMemory) {
453 return M4ERR_ALLOC;
454 }
455
456 nbVideoFrames = ( maxMemory - vesMemory) / 12;
457
458 M4OSA_TRACE1_1("M4MP4W: %d images max", nbVideoFrames);
459
460 /* VIDEO */
461 #ifdef _M4MP4W_UNBUFFERED_VIDEO
462 /* assume an average of 25 fpc : reference = 15 fps * 2s * 0.8 */
463
464 averageVideoChunk = 2500;
465
466 #else
467
468 if (M4MP4W_VIDEO_MAX_AU_PER_CHUNK > 0)
469 {
470 averageVideoChunk = 100 * M4MP4W_VIDEO_MAX_AU_PER_CHUNK - 20
471 * (M4MP4W_VIDEO_MAX_AU_PER_CHUNK - 1); /* margin 20% */
472 }
473 else
474 {
475 /* assume an average of 50 fpc */
476 averageVideoChunk = 5000;
477 }
478
479 #endif
480
481 M4MP4W_STTS_ALLOC_SIZE = nbVideoFrames * sizeof(M4OSA_UInt32);
482 M4MP4W_STSZ_ALLOC_SIZE = nbVideoFrames * sizeof(M4OSA_UInt16);
483 M4MP4W_STSS_ALLOC_SIZE = nbVideoFrames * sizeof(
484 M4OSA_UInt32); /* very conservative (all images are intra) */
485
486 M4MP4W_CHUNK_ALLOC_NB = ( nbVideoFrames * 100) / averageVideoChunk + 1;
487
488 /* AUDIO */
489
490 nbAudioFrames = nbVideoFrames;
491 /* audio is 5 fps, which is the smallest framerate for video */
492
493 M4MP4W_STTS_AUDIO_ALLOC_SIZE = 100; /* compressed */
494 M4MP4W_STSZ_AUDIO_ALLOC_SIZE = 100; /* compressed */
495
496 #ifdef _M4MP4W_UNBUFFERED_VIDEO
497
498 M4MP4W_CHUNK_AUDIO_ALLOC_NB = nbAudioFrames / 10 + 1;
499
500 #else
501
502 M4MP4W_CHUNK_AUDIO_ALLOC_NB = nbAudioFrames / 38 + 1;
503
504 #endif
505
506 return M4NO_ERROR;
507
508 #else
509
510 /* VIDEO 5 min at 25 fps null-enc */
511
512 M4MP4W_STTS_ALLOC_SIZE = 20000;
513 M4MP4W_STSZ_ALLOC_SIZE = 18000;
514 M4MP4W_STSS_ALLOC_SIZE = 5000;
515 M4MP4W_CHUNK_ALLOC_NB = 500;
516
517 /* AUDIO 2 min aac+ null-enc */
518
519 M4MP4W_STTS_AUDIO_ALLOC_SIZE = 32000;
520 M4MP4W_STSZ_AUDIO_ALLOC_SIZE = 20000;
521 M4MP4W_CHUNK_AUDIO_ALLOC_NB = 1000;
522
523 return M4NO_ERROR;
524
525 #endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
526
527 }
528
529 /*******************************************************************************/
M4MP4W_openWrite(M4OSA_Context * contextPtr,void * outputFileDescriptor,M4OSA_FileWriterPointer * fileWriterFunction,void * tempFileDescriptor,M4OSA_FileReadPointer * fileReaderFunction)530 M4OSA_ERR M4MP4W_openWrite(M4OSA_Context *contextPtr,
531 void *outputFileDescriptor,
532 M4OSA_FileWriterPointer *fileWriterFunction,
533 void *tempFileDescriptor,
534 M4OSA_FileReadPointer *fileReaderFunction )
535 /*******************************************************************************/
536 {
537 M4OSA_ERR err = M4NO_ERROR;
538 M4MP4W_Mp4FileData *mMp4FileDataPtr = M4OSA_NULL;
539
540 ERR_CHECK(M4OSA_NULL != contextPtr, M4ERR_PARAMETER);
541 ERR_CHECK(M4OSA_NULL != outputFileDescriptor, M4ERR_PARAMETER);
542 ERR_CHECK(M4OSA_NULL != fileWriterFunction, M4ERR_PARAMETER);
543 #ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
544 /* Optional, feature won't be used if NULL */
545
546 M4OSA_TRACE2_1("tempFileDescriptor = %p", tempFileDescriptor);
547
548 if (M4OSA_NULL == tempFileDescriptor)
549 {
550 M4OSA_TRACE1_0(
551 "tempFileDescriptor is NULL, RESERVED_MOOV_DISK_SPACE feature not used");
552 }
553
554 #else /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
555 /* Not used : ERR_CHECK(M4OSA_NULL != tempFileDescriptor, M4ERR_PARAMETER); */
556 #endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
557 /* Not used : ERR_CHECK(M4OSA_NULL != fileReaderFunction, M4ERR_PARAMETER); */
558
559 /* The context reuse mode was suppressed*/
560
561 mMp4FileDataPtr =
562 (M4MP4W_Mp4FileData *)M4OSA_32bitAlignedMalloc(sizeof(M4MP4W_Mp4FileData),
563 M4MP4_WRITER, (M4OSA_Char *)"MP4 writer context");
564 ERR_CHECK(mMp4FileDataPtr != M4OSA_NULL, M4ERR_ALLOC);
565 mMp4FileDataPtr->url = outputFileDescriptor;
566 mMp4FileDataPtr->audioTrackPtr = M4OSA_NULL;
567 mMp4FileDataPtr->videoTrackPtr = M4OSA_NULL;
568 mMp4FileDataPtr->MaxChunkSize = M4MP4W_DefaultMaxChunkSize; /*default */
569 mMp4FileDataPtr->MaxAUSize = M4MP4W_DefaultMaxAuSize; /*default */
570 mMp4FileDataPtr->InterleaveDur =
571 M4MP4W_DefaultInterleaveDur; /*default = 0, i.e. not used*/
572 mMp4FileDataPtr->MaxFileSize = 0; /*default = 0, i.e. not used*/
573 mMp4FileDataPtr->camcoderVersion = 0; /*default is " 0.0.0"*/
574 mMp4FileDataPtr->embeddedString =
575 M4OSA_NULL; /*default is in BlockSignatureSkipDefaultEmbeddedString */
576 mMp4FileDataPtr->integrationTag = M4OSA_NULL; /*default is 0 */
577 mMp4FileDataPtr->MaxFileDuration = 0; /*default = 0, i.e. not used*/
578
579 mMp4FileDataPtr->fileWriterFunctions = fileWriterFunction;
580 mMp4FileDataPtr->hasAudio = M4OSA_FALSE;
581 mMp4FileDataPtr->hasVideo = M4OSA_FALSE;
582 mMp4FileDataPtr->state = M4MP4W_opened;
583 mMp4FileDataPtr->duration = 0; /*i*/
584 /*patch for integrationTag 174 -> 238 (+64)*/
585 mMp4FileDataPtr->filesize =
586 238; /*initialization with constant part in ftyp+mdat+moov+skip*/
587
588 mMp4FileDataPtr->estimateAudioSize = M4OSA_FALSE;
589 mMp4FileDataPtr->audioMsChunkDur =
590 0; /*set and used only when estimateAudioSize is true*/
591 mMp4FileDataPtr->audioMsStopTime =
592 0; /*set and used only when estimateAudioSize is true*/
593
594 mMp4FileDataPtr->fileWriterContext = M4OSA_NULL;
595 /* + CRLV6775 -H.264 trimming */
596 mMp4FileDataPtr->bMULPPSSPS = M4OSA_FALSE;
597 /* - CRLV6775 -H.264 trimming */
598
599 #ifndef _M4MP4W_MOOV_FIRST
600
601 mMp4FileDataPtr->absoluteCurrentPos =
602 32; /*init with ftyp + beginning of mdat size*/
603
604 #endif
605
606 #ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
607
608 mMp4FileDataPtr->safetyFileUrl = tempFileDescriptor;
609 mMp4FileDataPtr->cleanSafetyFile =
610 M4OSA_FALSE; /* No need to clean it just yet. */
611
612 #endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
613
614 /* ftyp atom */
615
616 memset((void *) &mMp4FileDataPtr->ftyp,0,
617 sizeof(mMp4FileDataPtr->ftyp));
618
619 *contextPtr = mMp4FileDataPtr;
620
621 M4MP4W_initializeAllocationParameters(mMp4FileDataPtr);
622
623 return err;
624 }
625
626 /*******************************************************************************/
M4MP4W_addStream(M4OSA_Context context,M4SYS_StreamDescription * streamDescPtr)627 M4OSA_ERR M4MP4W_addStream(M4OSA_Context context,
628 M4SYS_StreamDescription *streamDescPtr )
629 /*******************************************************************************/
630 {
631 M4OSA_ERR err = M4NO_ERROR;
632
633 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
634
635 ERR_CHECK(M4OSA_NULL != context, M4ERR_PARAMETER);
636
637 ERR_CHECK(( mMp4FileDataPtr->state == M4MP4W_opened)
638 || (mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
639 mMp4FileDataPtr->state = M4MP4W_ready;
640
641 switch (streamDescPtr->streamType)
642 {
643 case M4SYS_kAMR:
644 case M4SYS_kAAC:
645 case M4SYS_kEVRC:
646 /*Audio*/
647 ERR_CHECK(streamDescPtr->streamID == AudioStreamID,
648 M4ERR_PARAMETER);
649
650 /*check if an audio track has already been added*/
651 ERR_CHECK(mMp4FileDataPtr->hasAudio == M4OSA_FALSE,
652 M4ERR_BAD_CONTEXT);
653
654 /*check if alloc need to be done*/
655 if (mMp4FileDataPtr->audioTrackPtr == M4OSA_NULL)
656 {
657 mMp4FileDataPtr->audioTrackPtr = (M4MP4W_AudioTrackData
658 *)M4OSA_32bitAlignedMalloc(sizeof(M4MP4W_AudioTrackData),
659 M4MP4_WRITER, (M4OSA_Char *)"M4MP4W_AudioTrackData");
660 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL,
661 M4ERR_ALLOC);
662
663 /**
664 * We must init these pointers in case an alloc bellow fails */
665 mMp4FileDataPtr->audioTrackPtr->Chunk = M4OSA_NULL;
666 mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable = M4OSA_NULL;
667 mMp4FileDataPtr->audioTrackPtr->chunkSizeTable = M4OSA_NULL;
668 mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable = M4OSA_NULL;
669 mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable = M4OSA_NULL;
670 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS = M4OSA_NULL;
671 mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ = M4OSA_NULL;
672 mMp4FileDataPtr->audioTrackPtr->DSI = M4OSA_NULL;
673
674 /*now dynamic*/
675
676 #ifdef _M4MP4W_MOOV_FIRST
677
678 mMp4FileDataPtr->audioTrackPtr->Chunk =
679 (M4OSA_UChar ** )M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_AUDIO_ALLOC_NB
680 * sizeof(M4OSA_UChar *),
681 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->Chunk");
682 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->Chunk != M4OSA_NULL,
683 M4ERR_ALLOC);
684
685 #else
686
687 mMp4FileDataPtr->audioTrackPtr->Chunk =
688 (M4OSA_UChar ** )M4OSA_32bitAlignedMalloc(sizeof(M4OSA_UChar *),
689 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->Chunk");
690 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->Chunk != M4OSA_NULL,
691 M4ERR_ALLOC);
692 mMp4FileDataPtr->audioTrackPtr->Chunk[0] = M4OSA_NULL;
693
694 mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable =
695 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_AUDIO_ALLOC_NB
696 * sizeof(M4OSA_UInt32),
697 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->chunkOffsetTable");
698 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable
699 != M4OSA_NULL, M4ERR_ALLOC);
700
701 #endif /*_M4MP4W_MOOV_FIRST*/
702
703 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS =
704 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_STTS_AUDIO_ALLOC_SIZE,
705 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->TABLE_STTS");
706 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->TABLE_STTS
707 != M4OSA_NULL, M4ERR_ALLOC);
708 mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedSttsBlocks = 1;
709
710 mMp4FileDataPtr->audioTrackPtr->chunkSizeTable =
711 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_AUDIO_ALLOC_NB
712 * sizeof(M4OSA_UInt32),
713 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->chunkSizeTable");
714 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkSizeTable
715 != M4OSA_NULL, M4ERR_ALLOC);
716 mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable =
717 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_AUDIO_ALLOC_NB
718 * sizeof(M4OSA_UInt32),
719 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->chunkSampleNbTable");
720 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable
721 != M4OSA_NULL, M4ERR_ALLOC);
722 mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable =
723 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_AUDIO_ALLOC_NB
724 * sizeof(M4OSA_UInt32),
725 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->chunkTimeMsTable");
726 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable
727 != M4OSA_NULL, M4ERR_ALLOC);
728
729 mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk = 0;
730 }
731 mMp4FileDataPtr->hasAudio = M4OSA_TRUE;
732 mMp4FileDataPtr->filesize += 402;
733 mMp4FileDataPtr->audioTrackPtr->MaxChunkSize =
734 mMp4FileDataPtr->MaxChunkSize; /* init value */
735 mMp4FileDataPtr->audioTrackPtr->MaxAUSize =
736 mMp4FileDataPtr->MaxAUSize;
737 mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS = 0;
738 mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb = 0;
739 mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize = 0;
740 mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb = 1;
741 mMp4FileDataPtr->audioTrackPtr->CommonData.timescale =
742 streamDescPtr->timeScale;
743 mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[0] = 0; /*init*/
744 mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable[0] = 0; /*init*/
745 mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable[0] = 0; /*init*/
746 mMp4FileDataPtr->audioTrackPtr->currentChunk =
747 0; /*1st chunk is Chunk[0]*/
748 mMp4FileDataPtr->audioTrackPtr->currentPos = 0;
749 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
750
751 mMp4FileDataPtr->audioTrackPtr->currentStsc = 0;
752
753 #endif
754
755 mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_ready;
756 mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedStszBlocks = 0;
757 mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ = M4OSA_NULL;
758
759 mMp4FileDataPtr->audioTrackPtr->avgBitrate =
760 streamDescPtr->averageBitrate;
761 mMp4FileDataPtr->audioTrackPtr->maxBitrate =
762 streamDescPtr->maxBitrate;
763
764 if (streamDescPtr->streamType == M4SYS_kAMR)
765 {
766
767 mMp4FileDataPtr->audioTrackPtr->CommonData.trackType =
768 M4SYS_kAMR;
769 ERR_CHECK(streamDescPtr->timeScale == 8000, M4ERR_PARAMETER);
770 mMp4FileDataPtr->audioTrackPtr->sampleDuration =
771 160; /*AMR8+timescale=8000 => sample duration 160 constant*/
772
773 /*Use given DSI if passed, else use default value*/
774 if (streamDescPtr->decoderSpecificInfoSize != 0)
775 {
776 /*amr DSI is 9 bytes long !*/
777 mMp4FileDataPtr->audioTrackPtr->dsiSize =
778 9; /*always 9 for amr*/
779 ERR_CHECK(streamDescPtr->decoderSpecificInfoSize == 9,
780 M4ERR_PARAMETER);
781 mMp4FileDataPtr->audioTrackPtr->DSI =
782 (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(9, M4MP4_WRITER,
783 (M4OSA_Char *)"audioTrackPtr->DSI");
784 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL,
785 M4ERR_ALLOC);
786 memcpy(
787 (void *)mMp4FileDataPtr->audioTrackPtr->DSI,
788 (void *)streamDescPtr->decoderSpecificInfo,
789 9);
790 }
791 else
792 {
793 mMp4FileDataPtr->audioTrackPtr->DSI =
794 M4OSA_NULL; /*default static block will be used*/
795 mMp4FileDataPtr->audioTrackPtr->dsiSize =
796 0; /*but the actual static dsi is 9 bytes !*/
797 }
798 }
799 else if (streamDescPtr->streamType == M4SYS_kEVRC)
800 {
801
802 mMp4FileDataPtr->audioTrackPtr->CommonData.trackType =
803 M4SYS_kEVRC;
804 ERR_CHECK(streamDescPtr->timeScale == 8000, M4ERR_PARAMETER);
805 mMp4FileDataPtr->audioTrackPtr->sampleDuration =
806 160; /*EVRC+timescale=8000 => sample duration 160 constant*/
807
808 /*Use given DSI if passed, else use default value*/
809 if (streamDescPtr->decoderSpecificInfoSize != 0)
810 {
811 /*evrc DSI is 6 bytes long !*/
812 mMp4FileDataPtr->audioTrackPtr->dsiSize =
813 6; /*always 6 for evrc*/
814 ERR_CHECK(streamDescPtr->decoderSpecificInfoSize == 6,
815 M4ERR_PARAMETER);
816 mMp4FileDataPtr->audioTrackPtr->DSI =
817 (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(6, M4MP4_WRITER,
818 (M4OSA_Char *)"audioTrackPtr->DSI");
819 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL,
820 M4ERR_ALLOC);
821 memcpy(
822 (void *)mMp4FileDataPtr->audioTrackPtr->DSI,
823 (void *)streamDescPtr->decoderSpecificInfo,
824 6);
825 }
826 else
827 {
828 mMp4FileDataPtr->audioTrackPtr->DSI =
829 M4OSA_NULL; /*default static block will be used*/
830 mMp4FileDataPtr->audioTrackPtr->dsiSize =
831 0; /*but the actual static dsi is 6 bytes !*/
832 }
833 }
834 else /*M4SYS_kAAC*/
835 {
836 /*avg bitrate should be set*/
837 ERR_CHECK(streamDescPtr->averageBitrate != -1, M4ERR_PARAMETER);
838 ERR_CHECK(streamDescPtr->maxBitrate != -1, M4ERR_PARAMETER);
839
840 mMp4FileDataPtr->audioTrackPtr->CommonData.trackType =
841 M4SYS_kAAC;
842 mMp4FileDataPtr->audioTrackPtr->sampleDuration =
843 0; /*don't know for aac, so set 0*/
844
845 mMp4FileDataPtr->audioTrackPtr->dsiSize =
846 (M4OSA_UInt8)streamDescPtr->decoderSpecificInfoSize;
847
848 if (mMp4FileDataPtr->audioTrackPtr->dsiSize != 0)
849 {
850 mMp4FileDataPtr->audioTrackPtr->DSI =
851 (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(
852 streamDescPtr->decoderSpecificInfoSize,
853 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->DSI");
854 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL,
855 M4ERR_ALLOC);
856 memcpy(
857 (void *)mMp4FileDataPtr->audioTrackPtr->DSI,
858 (void *)streamDescPtr->decoderSpecificInfo,
859 streamDescPtr->decoderSpecificInfoSize);
860 }
861 else
862 {
863 /*no dsi: return bad parameter ?*/
864 return M4ERR_PARAMETER;
865 }
866 }
867
868 break;
869
870 case (M4SYS_kMPEG_4):
871 case (M4SYS_kH264):
872 case (M4SYS_kH263):
873 /*Video*/
874 ERR_CHECK(streamDescPtr->streamID == VideoStreamID,
875 M4ERR_PARAMETER);
876
877 /*check if a video track has already been added*/
878 ERR_CHECK(mMp4FileDataPtr->hasVideo == M4OSA_FALSE,
879 M4ERR_BAD_CONTEXT);
880
881 /*check if alloc need to be done*/
882 if (mMp4FileDataPtr->videoTrackPtr == M4OSA_NULL)
883 {
884 mMp4FileDataPtr->videoTrackPtr = (M4MP4W_VideoTrackData
885 *)M4OSA_32bitAlignedMalloc(sizeof(M4MP4W_VideoTrackData),
886 M4MP4_WRITER, (M4OSA_Char *)"M4MP4W_VideoTrackData");
887 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr != M4OSA_NULL,
888 M4ERR_ALLOC);
889
890 /**
891 * We must init these pointers in case an alloc bellow fails */
892 mMp4FileDataPtr->videoTrackPtr->Chunk = M4OSA_NULL;
893 mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable = M4OSA_NULL;
894 mMp4FileDataPtr->videoTrackPtr->chunkSizeTable = M4OSA_NULL;
895 mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable = M4OSA_NULL;
896 mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable = M4OSA_NULL;
897 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS = M4OSA_NULL;
898 mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ = M4OSA_NULL;
899 mMp4FileDataPtr->videoTrackPtr->TABLE_STSS = M4OSA_NULL;
900 mMp4FileDataPtr->videoTrackPtr->DSI = M4OSA_NULL;
901
902 /*now dynamic*/
903
904 #ifdef _M4MP4W_MOOV_FIRST
905
906 mMp4FileDataPtr->videoTrackPtr->Chunk =
907 (M4OSA_UChar ** )M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_ALLOC_NB
908 * sizeof(M4OSA_UChar *),
909 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->Chunk");
910 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->Chunk != M4OSA_NULL,
911 M4ERR_ALLOC);
912
913 #else
914 /*re-use the same chunk and flush it when full*/
915
916 mMp4FileDataPtr->videoTrackPtr->Chunk =
917 (M4OSA_UChar ** )M4OSA_32bitAlignedMalloc(sizeof(M4OSA_UChar *),
918 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->Chunk");
919 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->Chunk != M4OSA_NULL,
920 M4ERR_ALLOC);
921 mMp4FileDataPtr->videoTrackPtr->Chunk[0] = M4OSA_NULL;
922
923 mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable =
924 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_ALLOC_NB
925 * sizeof(M4OSA_UInt32),
926 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->chunkOffsetTable");
927 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable
928 != M4OSA_NULL, M4ERR_ALLOC);
929
930 #endif /*_M4MP4W_MOOV_FIRST*/
931
932 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->Chunk != M4OSA_NULL,
933 M4ERR_ALLOC);
934 mMp4FileDataPtr->videoTrackPtr->chunkSizeTable =
935 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_ALLOC_NB
936 * sizeof(M4OSA_UInt32),
937 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->chunkSizeTable");
938 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkSizeTable
939 != M4OSA_NULL, M4ERR_ALLOC);
940 mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable =
941 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_ALLOC_NB
942 * sizeof(M4OSA_UInt32),
943 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->chunkSampleNbTable");
944 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable
945 != M4OSA_NULL, M4ERR_ALLOC);
946 mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable =
947 (M4MP4W_Time32 *)M4OSA_32bitAlignedMalloc(M4MP4W_CHUNK_ALLOC_NB
948 * sizeof(M4MP4W_Time32),
949 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->chunkTimeMsTable");
950 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable
951 != M4OSA_NULL, M4ERR_ALLOC);
952
953 mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk = 0;
954 /*tables are now dynamic*/
955 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS =
956 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_STTS_ALLOC_SIZE,
957 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->TABLE_STTS");
958 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STTS
959 != M4OSA_NULL, M4ERR_ALLOC);
960 mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks = 1;
961 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
962
963 mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ =
964 (M4OSA_UInt16 *)M4OSA_32bitAlignedMalloc(M4MP4W_STSZ_ALLOC_SIZE,
965 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->TABLE_STSZ");
966
967 #else
968
969 mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ =
970 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_STSZ_ALLOC_SIZE,
971 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->TABLE_STSZ");
972
973 #endif
974
975 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ
976 != M4OSA_NULL, M4ERR_ALLOC);
977 mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks = 1;
978 mMp4FileDataPtr->videoTrackPtr->TABLE_STSS =
979 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(M4MP4W_STSS_ALLOC_SIZE,
980 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->TABLE_STSS");
981 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSS
982 != M4OSA_NULL, M4ERR_ALLOC);
983 mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks = 1;
984 }
985 mMp4FileDataPtr->hasVideo = M4OSA_TRUE;
986 mMp4FileDataPtr->filesize += 462;
987 mMp4FileDataPtr->videoTrackPtr->width = M4MP4W_DefaultWidth;
988 mMp4FileDataPtr->videoTrackPtr->height = M4MP4W_DefaultHeight;
989 mMp4FileDataPtr->videoTrackPtr->MaxAUSize =
990 mMp4FileDataPtr->MaxAUSize;
991 mMp4FileDataPtr->videoTrackPtr->CommonData.trackType =
992 streamDescPtr->streamType;
993 mMp4FileDataPtr->videoTrackPtr->MaxChunkSize =
994 mMp4FileDataPtr->MaxChunkSize; /* init value */
995 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
996
997 mMp4FileDataPtr->videoTrackPtr->MaxAUperChunk =
998 M4MP4W_VIDEO_MAX_AU_PER_CHUNK;
999
1000 #endif
1001
1002 ERR_CHECK(streamDescPtr->timeScale == 1000, M4ERR_PARAMETER);
1003 mMp4FileDataPtr->videoTrackPtr->CommonData.timescale = 1000;
1004 mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS = 0;
1005 mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb = 0;
1006 mMp4FileDataPtr->videoTrackPtr->CommonData.sampleSize = 0;
1007 mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb = 1;
1008 mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[0] = 0; /*init*/
1009 mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable[0] = 0; /*init*/
1010 mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable[0] = 0; /*init*/
1011 mMp4FileDataPtr->videoTrackPtr->currentChunk =
1012 0; /*1st chunk is Chunk[0]*/
1013 mMp4FileDataPtr->videoTrackPtr->currentPos = 0;
1014 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
1015
1016 mMp4FileDataPtr->videoTrackPtr->currentStsc = 0;
1017
1018 #endif
1019
1020 mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb = 0;
1021 mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_ready;
1022
1023 if (streamDescPtr->streamType == M4SYS_kH263)
1024 {
1025 if (( streamDescPtr->averageBitrate == -1)
1026 || (streamDescPtr->maxBitrate == -1))
1027 {
1028 /*the bitrate will not be written if the bitrate information
1029 is not fully set */
1030 mMp4FileDataPtr->videoTrackPtr->avgBitrate = -1;
1031 mMp4FileDataPtr->videoTrackPtr->maxBitrate = -1;
1032 }
1033 else
1034 {
1035 /*proprietary storage of h263 bitrate.
1036 Warning: not the actual bitrate (bit set to 1).*/
1037 mMp4FileDataPtr->videoTrackPtr->avgBitrate =
1038 streamDescPtr->averageBitrate;
1039 mMp4FileDataPtr->videoTrackPtr->maxBitrate =
1040 streamDescPtr->maxBitrate;
1041 }
1042
1043 if (( 0 != streamDescPtr->decoderSpecificInfoSize)
1044 && (M4OSA_NULL != streamDescPtr->decoderSpecificInfo))
1045 {
1046 /*decoder specific info size is supposed to be always 7 bytes long */
1047 ERR_CHECK(streamDescPtr->decoderSpecificInfoSize == 7,
1048 M4ERR_PARAMETER);
1049 mMp4FileDataPtr->videoTrackPtr->dsiSize =
1050 (M4OSA_UInt8)streamDescPtr->decoderSpecificInfoSize;
1051 mMp4FileDataPtr->videoTrackPtr->DSI =
1052 (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(
1053 streamDescPtr->decoderSpecificInfoSize,
1054 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
1055 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI != M4OSA_NULL,
1056 M4ERR_ALLOC);
1057 memcpy(
1058 (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
1059 (void *)streamDescPtr->decoderSpecificInfo,
1060 streamDescPtr->decoderSpecificInfoSize);
1061 }
1062 else
1063 {
1064 /*use the default dsi*/
1065 mMp4FileDataPtr->videoTrackPtr->DSI = M4OSA_NULL;
1066 mMp4FileDataPtr->videoTrackPtr->dsiSize = 0;
1067 }
1068 }
1069
1070 if (streamDescPtr->streamType == M4SYS_kMPEG_4)
1071 {
1072 mMp4FileDataPtr->filesize += 22; /*extra bytes (from h263)*/
1073 /* allow DSI to be M4OSA_NULL, in which case the actual DSI will be
1074 set by setOption. */
1075 if (( 0 == streamDescPtr->decoderSpecificInfoSize)
1076 || (M4OSA_NULL == streamDescPtr->decoderSpecificInfo))
1077 {
1078 mMp4FileDataPtr->videoTrackPtr->DSI = M4OSA_NULL;
1079 mMp4FileDataPtr->videoTrackPtr->dsiSize = 0;
1080 }
1081 else
1082 {
1083 /*MP4V specific*/
1084 /*decoder specific info size is supposed to be always <
1085 105 so that ESD size can be coded with 1 byte*/
1086 /*(this should not be restrictive because dsi is always shorter !)*/
1087 ERR_CHECK(streamDescPtr->decoderSpecificInfoSize < 105,
1088 M4ERR_PARAMETER);
1089 mMp4FileDataPtr->videoTrackPtr->dsiSize =
1090 (M4OSA_UInt8)streamDescPtr->decoderSpecificInfoSize;
1091 mMp4FileDataPtr->videoTrackPtr->DSI =
1092 (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(
1093 streamDescPtr->decoderSpecificInfoSize,
1094 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
1095 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI != M4OSA_NULL,
1096 M4ERR_ALLOC);
1097 memcpy(
1098 (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
1099 (void *)streamDescPtr->decoderSpecificInfo,
1100 streamDescPtr->decoderSpecificInfoSize);
1101 mMp4FileDataPtr->filesize +=
1102 streamDescPtr->decoderSpecificInfoSize;
1103 }
1104 /*avg bitrate should be set*/
1105 ERR_CHECK(streamDescPtr->averageBitrate != -1, M4ERR_PARAMETER);
1106 mMp4FileDataPtr->videoTrackPtr->avgBitrate =
1107 streamDescPtr->averageBitrate;
1108 mMp4FileDataPtr->videoTrackPtr->maxBitrate =
1109 streamDescPtr->averageBitrate;
1110 }
1111
1112 if (streamDescPtr->streamType == M4SYS_kH264)
1113 {
1114 /* H264 specific information */
1115 mMp4FileDataPtr->videoTrackPtr->avgBitrate =
1116 streamDescPtr->averageBitrate;
1117 mMp4FileDataPtr->videoTrackPtr->maxBitrate =
1118 streamDescPtr->maxBitrate;
1119
1120 if ((0 != streamDescPtr->decoderSpecificInfoSize)
1121 && (M4OSA_NULL != streamDescPtr->decoderSpecificInfo))
1122 {
1123 /* + H.264 trimming */
1124 if (M4OSA_TRUE == mMp4FileDataPtr->bMULPPSSPS)
1125 {
1126 M4OSA_UInt16 SPSLength, PPSLength;
1127 M4OSA_UInt16 *DSI;
1128 /* Store the DSI size */
1129 mMp4FileDataPtr->videoTrackPtr->dsiSize =
1130 (M4OSA_UInt8)streamDescPtr->decoderSpecificInfoSize
1131 - 24;
1132
1133 /* Copy the DSI (SPS + PPS) */
1134 mMp4FileDataPtr->videoTrackPtr->DSI =
1135 (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(
1136 streamDescPtr->decoderSpecificInfoSize,
1137 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
1138 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
1139 != M4OSA_NULL, M4ERR_ALLOC);
1140
1141 DSI =
1142 (M4OSA_UInt16 *)streamDescPtr->decoderSpecificInfo;
1143 SPSLength = DSI[6];
1144 PPSLength = DSI[10];
1145 memcpy(
1146 (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
1147 (void *)((streamDescPtr->
1148 decoderSpecificInfo)+12), 2);
1149 memcpy(
1150 (void *)((mMp4FileDataPtr->videoTrackPtr->
1151 DSI)+2), (void *)((streamDescPtr->
1152 decoderSpecificInfo)+28), SPSLength);
1153
1154 memcpy(
1155 (void *)((mMp4FileDataPtr->videoTrackPtr->
1156 DSI)+2 + SPSLength),
1157 (void *)((streamDescPtr->
1158 decoderSpecificInfo)+20), 2);
1159 memcpy(
1160 (void *)((mMp4FileDataPtr->videoTrackPtr->
1161 DSI)+4 + SPSLength),
1162 (void *)((streamDescPtr->
1163 decoderSpecificInfo)+28 + SPSLength),
1164 PPSLength);
1165 /* - H.264 trimming */
1166 }
1167 else
1168 {
1169 /* Store the DSI size */
1170 mMp4FileDataPtr->videoTrackPtr->dsiSize =
1171 (M4OSA_UInt8)streamDescPtr->decoderSpecificInfoSize;
1172
1173 /* Copy the DSI (SPS + PPS) */
1174 mMp4FileDataPtr->videoTrackPtr->DSI =
1175 (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(
1176 streamDescPtr->decoderSpecificInfoSize,
1177 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
1178 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
1179 != M4OSA_NULL, M4ERR_ALLOC);
1180 memcpy(
1181 (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
1182 (void *)streamDescPtr->
1183 decoderSpecificInfo,
1184 streamDescPtr->decoderSpecificInfoSize);
1185 }
1186 }
1187 else
1188 {
1189 /*use the default dsi*/
1190 mMp4FileDataPtr->videoTrackPtr->DSI = M4OSA_NULL;
1191 mMp4FileDataPtr->videoTrackPtr->dsiSize = 0;
1192 }
1193 }
1194 break;
1195
1196 default:
1197 err = M4ERR_PARAMETER;
1198 }
1199
1200 return err;
1201 }
1202
1203 /*******************************************************************************/
M4MP4W_startWriting(M4OSA_Context context)1204 M4OSA_ERR M4MP4W_startWriting( M4OSA_Context context )
1205 /*******************************************************************************/
1206 {
1207 M4OSA_ERR err = M4NO_ERROR;
1208 M4OSA_UInt32 fileModeAccess = M4OSA_kFileWrite | M4OSA_kFileCreate;
1209 M4OSA_UInt32 i;
1210 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
1211 ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
1212
1213 ERR_CHECK((mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
1214 mMp4FileDataPtr->state = M4MP4W_writing;
1215
1216 /*audio microstate */
1217 /* if (mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL)*/
1218 if (mMp4FileDataPtr->hasAudio)
1219 {
1220 ERR_CHECK((mMp4FileDataPtr->audioTrackPtr->microState == M4MP4W_ready),
1221 M4ERR_STATE);
1222 mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_writing;
1223
1224 /* First audio chunk allocation */
1225 mMp4FileDataPtr->audioTrackPtr->Chunk[0] = (M4OSA_UChar
1226 *)M4OSA_32bitAlignedMalloc(mMp4FileDataPtr->audioTrackPtr->MaxChunkSize,
1227 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->Chunk[0]");
1228 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->Chunk[0] != M4OSA_NULL,
1229 M4ERR_ALLOC);
1230 }
1231
1232 /*video microstate*/
1233 /* if (mMp4FileDataPtr->videoTrackPtr != M4OSA_NULL)*/
1234 if (mMp4FileDataPtr->hasVideo)
1235 {
1236 ERR_CHECK((mMp4FileDataPtr->videoTrackPtr->microState == M4MP4W_ready),
1237 M4ERR_STATE);
1238 mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_writing;
1239
1240 /* First video chunk allocation */
1241 mMp4FileDataPtr->videoTrackPtr->Chunk[0] = (M4OSA_UChar
1242 *)M4OSA_32bitAlignedMalloc(mMp4FileDataPtr->videoTrackPtr->MaxChunkSize,
1243 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->Chunk[0]");
1244 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->Chunk[0] != M4OSA_NULL,
1245 M4ERR_ALLOC);
1246 }
1247
1248 if (mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
1249 {
1250 /*set audioMsChunkDur (duration in ms before a new chunk is created)
1251 for audio size estimation*/
1252 ERR_CHECK(mMp4FileDataPtr->hasVideo, M4ERR_BAD_CONTEXT);
1253 ERR_CHECK(mMp4FileDataPtr->hasAudio, M4ERR_BAD_CONTEXT);
1254
1255 mMp4FileDataPtr->audioMsChunkDur =
1256 20 * mMp4FileDataPtr->audioTrackPtr->MaxChunkSize
1257 / mMp4FileDataPtr->audioTrackPtr->MaxAUSize;
1258
1259 if (( mMp4FileDataPtr->InterleaveDur != 0)
1260 && (mMp4FileDataPtr->InterleaveDur
1261 < 20 *mMp4FileDataPtr->audioTrackPtr->MaxChunkSize
1262 / mMp4FileDataPtr->audioTrackPtr->MaxAUSize))
1263 {
1264 mMp4FileDataPtr->audioMsChunkDur = mMp4FileDataPtr->InterleaveDur;
1265 }
1266 }
1267
1268 #ifndef _M4MP4W_MOOV_FIRST
1269
1270 /*open file in write binary mode*/
1271
1272 err = mMp4FileDataPtr->fileWriterFunctions->openWrite(
1273 &mMp4FileDataPtr->fileWriterContext,
1274 mMp4FileDataPtr->url, fileModeAccess);
1275 ERR_CHECK((M4NO_ERROR == err), err);
1276
1277 /*ftyp atom*/
1278 if (mMp4FileDataPtr->ftyp.major_brand != 0)
1279 {
1280 /* Put customized ftyp box */
1281 err =
1282 M4MP4W_putBE32(16 + (mMp4FileDataPtr->ftyp.nbCompatibleBrands * 4),
1283 mMp4FileDataPtr->fileWriterFunctions,
1284 mMp4FileDataPtr->fileWriterContext);
1285 ERR_CHECK((M4NO_ERROR == err), err);
1286 err = M4MP4W_putBE32(M4MPAC_FTYP_TAG,
1287 mMp4FileDataPtr->fileWriterFunctions,
1288 mMp4FileDataPtr->fileWriterContext);
1289 ERR_CHECK((M4NO_ERROR == err), err);
1290 err = M4MP4W_putBE32(mMp4FileDataPtr->ftyp.major_brand,
1291 mMp4FileDataPtr->fileWriterFunctions,
1292 mMp4FileDataPtr->fileWriterContext);
1293 ERR_CHECK((M4NO_ERROR == err), err);
1294 err = M4MP4W_putBE32(mMp4FileDataPtr->ftyp.minor_version,
1295 mMp4FileDataPtr->fileWriterFunctions,
1296 mMp4FileDataPtr->fileWriterContext);
1297 ERR_CHECK((M4NO_ERROR == err), err);
1298
1299 for ( i = 0; i < mMp4FileDataPtr->ftyp.nbCompatibleBrands; i++ )
1300 {
1301 err = M4MP4W_putBE32(mMp4FileDataPtr->ftyp.compatible_brands[i],
1302 mMp4FileDataPtr->fileWriterFunctions,
1303 mMp4FileDataPtr->fileWriterContext);
1304 ERR_CHECK((M4NO_ERROR == err), err);
1305 }
1306 }
1307 else
1308 {
1309 /* Put default ftyp box */
1310 err = M4MP4W_putBlock(Default_ftyp, sizeof(Default_ftyp),
1311 mMp4FileDataPtr->fileWriterFunctions,
1312 mMp4FileDataPtr->fileWriterContext);
1313 ERR_CHECK((M4NO_ERROR == err), err);
1314 }
1315
1316 /*init mdat value with 0 but the right value is set just before the file is closed*/
1317 err = M4MP4W_putBE32(0, mMp4FileDataPtr->fileWriterFunctions,
1318 mMp4FileDataPtr->fileWriterContext);
1319 ERR_CHECK((M4NO_ERROR == err), err);
1320 err = M4MP4W_putBlock(CommonBlock2, sizeof(CommonBlock2),
1321 mMp4FileDataPtr->fileWriterFunctions,
1322 mMp4FileDataPtr->fileWriterContext);
1323 ERR_CHECK((M4NO_ERROR == err), err);
1324
1325 #endif /*_M4MP4W_MOOV_FIRST*/
1326
1327 #ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
1328
1329 if (0 != mMp4FileDataPtr->MaxFileSize
1330 && M4OSA_NULL != mMp4FileDataPtr->safetyFileUrl)
1331 {
1332 M4OSA_ERR err2 = M4NO_ERROR;
1333 M4OSA_Context safetyFileContext = M4OSA_NULL;
1334 M4OSA_UInt32 safetyFileSize = 0, addendum = 0;
1335 M4OSA_UChar dummyData[100]; /* To fill the safety file with */
1336
1337 err =
1338 mMp4FileDataPtr->fileWriterFunctions->openWrite(&safetyFileContext,
1339 mMp4FileDataPtr->safetyFileUrl, fileModeAccess);
1340 ERR_CHECK((M4NO_ERROR == err), err);
1341
1342 mMp4FileDataPtr->cleanSafetyFile = M4OSA_TRUE;
1343
1344 /* 10% seems to be a reasonable worst case, but also provision for 1kb of moov overhead.*/
1345 safetyFileSize = 1000 + (mMp4FileDataPtr->MaxFileSize * 10 + 99) / 100;
1346
1347 /* Here we add space to take into account the fact we have to flush any pending
1348 chunk in closeWrite, this space is the sum of the maximum chunk sizes, for each
1349 track. */
1350
1351 #ifndef _M4MP4W_UNBUFFERED_VIDEO
1352
1353 if (mMp4FileDataPtr->hasVideo)
1354 {
1355 safetyFileSize += mMp4FileDataPtr->videoTrackPtr->MaxChunkSize;
1356 }
1357
1358 #endif
1359
1360 if (mMp4FileDataPtr->hasAudio)
1361 {
1362 safetyFileSize += mMp4FileDataPtr->audioTrackPtr->MaxChunkSize;
1363 }
1364
1365 memset((void *)dummyData, 0xCA,sizeof(dummyData)); /* For extra safety. */
1366
1367 for ( i = 0;
1368 i < (safetyFileSize + sizeof(dummyData) - 1) / sizeof(dummyData);
1369 i++ )
1370 {
1371 err = mMp4FileDataPtr->fileWriterFunctions->writeData(
1372 safetyFileContext, dummyData, sizeof(dummyData));
1373
1374 if (M4NO_ERROR != err)
1375 break;
1376 /* Don't return from the function yet, as we need to close the file first. */
1377 }
1378
1379 /* I don't need to keep it open. */
1380 err2 =
1381 mMp4FileDataPtr->fileWriterFunctions->closeWrite(safetyFileContext);
1382
1383 if (M4NO_ERROR != err)
1384 {
1385 return err;
1386 }
1387 else
1388 ERR_CHECK((M4NO_ERROR == err2), err2);
1389
1390 M4OSA_TRACE1_0("Safety file correctly created");
1391 }
1392 #endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
1393
1394 return err;
1395 }
1396
1397 /*******************************************************************************/
M4MP4W_newAudioChunk(M4OSA_Context context,M4OSA_UInt32 * leftSpaceInChunk)1398 M4OSA_ERR M4MP4W_newAudioChunk( M4OSA_Context context,
1399 M4OSA_UInt32 *leftSpaceInChunk )
1400 /*******************************************************************************/
1401 {
1402 M4OSA_ERR err = M4NO_ERROR;
1403
1404 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
1405 M4OSA_Double scale_audio;
1406
1407 #ifndef _M4MP4W_OPTIMIZE_FOR_PHONE
1408
1409 M4OSA_UInt32 reallocNb;
1410
1411 #endif
1412
1413 /* video only */
1414
1415 if (mMp4FileDataPtr->audioTrackPtr == M4OSA_NULL)
1416 return M4NO_ERROR;
1417
1418 M4OSA_TRACE1_0(" M4MP4W_newAudioChunk - flush audio");
1419 M4OSA_TRACE1_2("current chunk = %d offset = 0x%x",
1420 mMp4FileDataPtr->audioTrackPtr->currentChunk,
1421 mMp4FileDataPtr->absoluteCurrentPos);
1422
1423 scale_audio = 1000.0 / mMp4FileDataPtr->audioTrackPtr->CommonData.timescale;
1424
1425 #ifndef _M4MP4W_MOOV_FIRST
1426 /*flush chunk*/
1427
1428 err = M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[0],
1429 mMp4FileDataPtr->audioTrackPtr->currentPos,
1430 mMp4FileDataPtr->fileWriterFunctions,
1431 mMp4FileDataPtr->fileWriterContext);
1432
1433 if (M4NO_ERROR != err)
1434 {
1435 M4OSA_FilePosition temp = mMp4FileDataPtr->absoluteCurrentPos;
1436 M4OSA_TRACE2_1(
1437 "M4MP4W_newAudioChunk: putBlock error when flushing chunk: %#X",
1438 err);
1439 /* Ouch, we got an error writing to the file, but we need to properly react so that the
1440 state is still consistent and we can properly close the file so that what has been
1441 recorded so far is not lost. Yay error recovery! */
1442
1443 /* First, we do not know where we are in the file. Put us back at where we were before
1444 attempting to write the data. That way, we're consistent with the chunk state data. */
1445 err = mMp4FileDataPtr->fileWriterFunctions->seek(
1446 mMp4FileDataPtr->fileWriterContext,
1447 M4OSA_kFileSeekBeginning, &temp);
1448
1449 M4OSA_TRACE2_3(
1450 "Backtracking to position 0x%08X, seek returned %d and position %08X",
1451 mMp4FileDataPtr->absoluteCurrentPos, err, temp);
1452
1453 /* Then, do not update any info whatsoever in the writing state. This will have the
1454 consequence that it will be as if the chunk has not been flushed yet, and therefore
1455 it will be done as part of closeWrite (where there could be room to do so,
1456 if some emergency room is freed for that purpose). */
1457
1458 /* And lastly (for here), return that we've reached the limit of available space. */
1459
1460 return M4WAR_MP4W_OVERSIZE;
1461 }
1462
1463 /*update chunk offset*/
1464 mMp4FileDataPtr->audioTrackPtr->
1465 chunkOffsetTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
1466 mMp4FileDataPtr->absoluteCurrentPos;
1467
1468 /*add chunk size to absoluteCurrentPos*/
1469 mMp4FileDataPtr->absoluteCurrentPos +=
1470 mMp4FileDataPtr->audioTrackPtr->currentPos;
1471
1472 #endif /*_M4MP4W_MOOV_FIRST*/
1473
1474 /*update chunk info */
1475
1476 mMp4FileDataPtr->audioTrackPtr->
1477 chunkSizeTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
1478 mMp4FileDataPtr->audioTrackPtr->currentPos;
1479 mMp4FileDataPtr->audioTrackPtr->
1480 chunkTimeMsTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
1481 mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS;
1482
1483 mMp4FileDataPtr->audioTrackPtr->currentChunk += 1;
1484 /*if audio amount of data is not estimated*/
1485 if (mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
1486 mMp4FileDataPtr->filesize += 16;
1487
1488 /*alloc new chunk*/
1489 /*only if not already allocated*/
1490 if (mMp4FileDataPtr->audioTrackPtr->currentChunk
1491 > mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk)
1492 {
1493 /*update LastAllocatedChunk ( -> = currentChunk)*/
1494 mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk += 1;
1495
1496 /*max nb of chunk is now dynamic*/
1497 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
1498
1499 if (mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk
1500 + 3 > M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1501 {
1502 M4OSA_TRACE1_0("M4MP4W_newAudioChunk : audio chunk table is full");
1503 return M4WAR_MP4W_OVERSIZE;
1504 }
1505
1506 #else
1507
1508 if (((mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk)
1509 % M4MP4W_CHUNK_AUDIO_ALLOC_NB) == 0)
1510 {
1511 reallocNb = mMp4FileDataPtr->audioTrackPtr->LastAllocatedChunk
1512 + M4MP4W_CHUNK_AUDIO_ALLOC_NB;
1513
1514 #ifdef _M4MP4W_MOOV_FIRST
1515
1516 mMp4FileDataPtr->audioTrackPtr->Chunk =
1517 (M4OSA_UChar ** )M4MP4W_realloc(
1518 (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->Chunk,
1519 ( reallocNb - M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1520 * sizeof(M4OSA_UChar *),
1521 reallocNb * sizeof(M4OSA_UChar *));
1522 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->Chunk != M4OSA_NULL,
1523 M4ERR_ALLOC);
1524
1525 #else
1526
1527 mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable =
1528 (M4OSA_UInt32 *)M4MP4W_realloc(
1529 (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
1530 chunkOffsetTable,
1531 ( reallocNb - M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1532 * sizeof(M4OSA_UInt32),
1533 reallocNb * sizeof(M4OSA_UInt32));
1534 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable
1535 != M4OSA_NULL, M4ERR_ALLOC);
1536
1537 #endif /*_M4MP4W_MOOV_FIRST*/
1538
1539 mMp4FileDataPtr->audioTrackPtr->chunkSizeTable =
1540 (M4OSA_UInt32 *)M4MP4W_realloc(
1541 (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
1542 chunkSizeTable,
1543 ( reallocNb - M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1544 * sizeof(M4OSA_UInt32),
1545 reallocNb * sizeof(M4OSA_UInt32));
1546 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkSizeTable
1547 != M4OSA_NULL, M4ERR_ALLOC);
1548
1549 mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable =
1550 (M4OSA_UInt32 *)M4MP4W_realloc(
1551 (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
1552 chunkSampleNbTable,
1553 ( reallocNb - M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1554 * sizeof(M4OSA_UInt32),
1555 reallocNb * sizeof(M4OSA_UInt32));
1556 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable
1557 != M4OSA_NULL, M4ERR_ALLOC);
1558
1559 mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable =
1560 (M4MP4W_Time32 *)M4MP4W_realloc(
1561 (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
1562 chunkTimeMsTable,
1563 ( reallocNb - M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1564 * sizeof(M4MP4W_Time32),
1565 reallocNb * sizeof(M4MP4W_Time32));
1566 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable
1567 != M4OSA_NULL, M4ERR_ALLOC);
1568 }
1569 #endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
1570
1571 #ifdef _M4MP4W_MOOV_FIRST
1572
1573 mMp4FileDataPtr->audioTrackPtr->
1574 Chunk[mMp4FileDataPtr->audioTrackPtr->currentChunk] = (M4OSA_UChar
1575 *)M4OSA_32bitAlignedMalloc(mMp4FileDataPtr->audioTrackPtr->MaxChunkSize,
1576 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->currentChunk");
1577 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->
1578 Chunk[mMp4FileDataPtr->audioTrackPtr->currentChunk]
1579 != M4OSA_NULL, M4ERR_ALLOC);
1580
1581 #endif /*_M4MP4W_MOOV_FIRST*/
1582
1583 }
1584
1585 /*update leftSpaceInChunk, currentPos and currentChunkDur*/
1586 *leftSpaceInChunk = mMp4FileDataPtr->audioTrackPtr->MaxChunkSize;
1587 mMp4FileDataPtr->audioTrackPtr->currentPos = 0;
1588
1589 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
1590 /* check wether to use a new stsc or not */
1591
1592 if (mMp4FileDataPtr->audioTrackPtr->currentStsc > 0)
1593 {
1594 if (( mMp4FileDataPtr->audioTrackPtr->
1595 chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->
1596 currentStsc] & 0xFFF) != (mMp4FileDataPtr->audioTrackPtr->
1597 chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->currentStsc
1598 - 1] & 0xFFF))
1599 mMp4FileDataPtr->audioTrackPtr->currentStsc += 1;
1600 }
1601 else
1602 mMp4FileDataPtr->audioTrackPtr->currentStsc += 1;
1603
1604 /* max nb of chunk is now dynamic */
1605 if (mMp4FileDataPtr->audioTrackPtr->currentStsc
1606 + 3 > M4MP4W_CHUNK_AUDIO_ALLOC_NB)
1607 {
1608 M4OSA_TRACE1_0("M4MP4W_newAudioChunk : audio stsc table is full");
1609 return M4WAR_MP4W_OVERSIZE;
1610 }
1611
1612 /* set nb of samples in the new chunk to 0 */
1613 mMp4FileDataPtr->audioTrackPtr->
1614 chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->currentStsc] =
1615 0 + (mMp4FileDataPtr->audioTrackPtr->currentChunk << 12);
1616
1617 #else
1618 /*set nb of samples in the new chunk to 0*/
1619
1620 mMp4FileDataPtr->audioTrackPtr->
1621 chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] = 0;
1622
1623 #endif
1624
1625 /*set time of the new chunk to lastCTS (for initialization, but updated further to the
1626 CTS of the last sample in the chunk)*/
1627
1628 mMp4FileDataPtr->audioTrackPtr->
1629 chunkTimeMsTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
1630 (M4OSA_UInt32)(mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS
1631 * scale_audio);
1632
1633 return err;
1634 }
1635
1636 /*******************************************************************************/
M4MP4W_newVideoChunk(M4OSA_Context context,M4OSA_UInt32 * leftSpaceInChunk)1637 M4OSA_ERR M4MP4W_newVideoChunk( M4OSA_Context context,
1638 M4OSA_UInt32 *leftSpaceInChunk )
1639 /*******************************************************************************/
1640 {
1641 M4OSA_ERR err = M4NO_ERROR;
1642
1643 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
1644 M4OSA_Double scale_video;
1645
1646 #ifndef _M4MP4W_OPTIMIZE_FOR_PHONE
1647
1648 M4OSA_UInt32 reallocNb;
1649
1650 #endif
1651
1652 /* audio only */
1653
1654 if (mMp4FileDataPtr->videoTrackPtr == M4OSA_NULL)
1655 return M4NO_ERROR;
1656
1657 M4OSA_TRACE1_0("M4MP4W_newVideoChunk - flush video");
1658 M4OSA_TRACE1_2("current chunk = %d offset = 0x%x",
1659 mMp4FileDataPtr->videoTrackPtr->currentChunk,
1660 mMp4FileDataPtr->absoluteCurrentPos);
1661
1662 scale_video = 1000.0 / mMp4FileDataPtr->videoTrackPtr->CommonData.timescale;
1663
1664 #ifndef _M4MP4W_MOOV_FIRST
1665
1666 #ifdef _M4MP4W_UNBUFFERED_VIDEO
1667 /* samples are already written to file */
1668 #else
1669 /*flush chunk*/
1670
1671 err = M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[0],
1672 mMp4FileDataPtr->videoTrackPtr->currentPos,
1673 mMp4FileDataPtr->fileWriterFunctions,
1674 mMp4FileDataPtr->fileWriterContext);
1675
1676 if (M4NO_ERROR != err)
1677 {
1678 M4OSA_FilePosition temp = mMp4FileDataPtr->absoluteCurrentPos;
1679 M4OSA_TRACE2_1(
1680 "M4MP4W_newVideoChunk: putBlock error when flushing chunk: %#X",
1681 err);
1682 /* Ouch, we got an error writing to the file, but we need to properly react so that the
1683 state is still consistent and we can properly close the file so that what has been
1684 recorded so far is not lost. Yay error recovery! */
1685
1686 /* First, we do not know where we are in the file. Put us back at where we were before
1687 attempting to write the data. That way, we're consistent with the chunk state data. */
1688 err = mMp4FileDataPtr->fileWriterFunctions->seek(
1689 mMp4FileDataPtr->fileWriterContext,
1690 M4OSA_kFileSeekBeginning, &temp);
1691
1692 M4OSA_TRACE2_3(
1693 "Backtracking to position 0x%08X, seek returned %d and position %08X",
1694 mMp4FileDataPtr->absoluteCurrentPos, err, temp);
1695 /* Then, do not update any info whatsoever in the writing state. This will have the
1696 consequence that it will be as if the chunk has not been flushed yet, and therefore it
1697 will be done as part of closeWrite (where there could be room to do so, if some
1698 emergency room is freed for that purpose). */
1699
1700 /* And lastly (for here), return that we've reached the limit of available space.
1701 We don't care about the error originally returned by putBlock. */
1702
1703 return M4WAR_MP4W_OVERSIZE;
1704 }
1705
1706 #endif
1707
1708 /*update chunk offset*/
1709
1710 mMp4FileDataPtr->videoTrackPtr->
1711 chunkOffsetTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
1712 mMp4FileDataPtr->absoluteCurrentPos;
1713
1714 /*add chunk size to absoluteCurrentPos*/
1715 mMp4FileDataPtr->absoluteCurrentPos +=
1716 mMp4FileDataPtr->videoTrackPtr->currentPos;
1717
1718 #endif /*_M4MP4W_MOOV_FIRST*/
1719
1720 /*update chunk info before to go for a new one*/
1721
1722 mMp4FileDataPtr->videoTrackPtr->
1723 chunkSizeTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
1724 mMp4FileDataPtr->videoTrackPtr->currentPos;
1725 mMp4FileDataPtr->videoTrackPtr->
1726 chunkTimeMsTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
1727 (M4OSA_UInt32)(mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS
1728 * scale_video);
1729
1730 mMp4FileDataPtr->videoTrackPtr->currentChunk += 1;
1731 mMp4FileDataPtr->filesize += 16;
1732
1733 /*alloc new chunk*/
1734 /*only if not already allocated*/
1735 if (mMp4FileDataPtr->videoTrackPtr->currentChunk
1736 > mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk)
1737 {
1738 /*update LastAllocatedChunk ( -> = currentChunk)*/
1739 mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk += 1;
1740
1741 /*max nb of chunk is now dynamic*/
1742 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
1743
1744 if ( mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk
1745 + 3 > M4MP4W_CHUNK_ALLOC_NB)
1746 {
1747 M4OSA_TRACE1_0("M4MP4W_newVideoChunk : video chunk table is full");
1748 return M4WAR_MP4W_OVERSIZE;
1749 }
1750
1751 #else
1752
1753 if (((mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk)
1754 % M4MP4W_CHUNK_ALLOC_NB) == 0)
1755 {
1756 reallocNb = mMp4FileDataPtr->videoTrackPtr->LastAllocatedChunk
1757 + M4MP4W_CHUNK_ALLOC_NB;
1758
1759 #ifdef _M4MP4W_MOOV_FIRST
1760
1761 mMp4FileDataPtr->videoTrackPtr->Chunk =
1762 (M4OSA_UChar ** )M4MP4W_realloc(
1763 (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->Chunk,
1764 ( reallocNb
1765 - M4MP4W_CHUNK_ALLOC_NB) * sizeof(M4OSA_UChar *),
1766 reallocNb * sizeof(M4OSA_UChar *));
1767 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->Chunk != M4OSA_NULL,
1768 M4ERR_ALLOC);
1769
1770 #else
1771
1772 mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable =
1773 (M4OSA_UInt32 *)M4MP4W_realloc(
1774 (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
1775 chunkOffsetTable, ( reallocNb - M4MP4W_CHUNK_ALLOC_NB)
1776 * sizeof(M4OSA_UInt32),
1777 reallocNb * sizeof(M4OSA_UInt32));
1778 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable
1779 != M4OSA_NULL, M4ERR_ALLOC);
1780
1781 #endif /*_M4MP4W_MOOV_FIRST*/
1782
1783 mMp4FileDataPtr->videoTrackPtr->chunkSizeTable =
1784 (M4OSA_UInt32 *)M4MP4W_realloc(
1785 (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
1786 chunkSizeTable, ( reallocNb - M4MP4W_CHUNK_ALLOC_NB)
1787 * sizeof(M4OSA_UInt32),
1788 reallocNb * sizeof(M4OSA_UInt32));
1789 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkSizeTable
1790 != M4OSA_NULL, M4ERR_ALLOC);
1791
1792 mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable =
1793 (M4OSA_UInt32 *)M4MP4W_realloc(
1794 (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
1795 chunkSampleNbTable, ( reallocNb - M4MP4W_CHUNK_ALLOC_NB)
1796 * sizeof(M4OSA_UInt32),
1797 reallocNb * sizeof(M4OSA_UInt32));
1798 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable
1799 != M4OSA_NULL, M4ERR_ALLOC);
1800
1801 mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable =
1802 (M4MP4W_Time32 *)M4MP4W_realloc(
1803 (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
1804 chunkTimeMsTable, ( reallocNb
1805 - M4MP4W_CHUNK_ALLOC_NB) * sizeof(M4MP4W_Time32),
1806 reallocNb * sizeof(M4MP4W_Time32));
1807 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable
1808 != M4OSA_NULL, M4ERR_ALLOC);
1809 }
1810 #endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
1811
1812 #ifdef _M4MP4W_MOOV_FIRST
1813
1814 mMp4FileDataPtr->videoTrackPtr->
1815 Chunk[mMp4FileDataPtr->videoTrackPtr->currentChunk] = (M4OSA_UChar
1816 *)M4OSA_32bitAlignedMalloc(mMp4FileDataPtr->videoTrackPtr->MaxChunkSize,
1817 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->MaxChunkSize");
1818 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->
1819 Chunk[mMp4FileDataPtr->videoTrackPtr->currentChunk]
1820 != M4OSA_NULL, M4ERR_ALLOC);
1821
1822 #endif /*_M4MP4W_MOOV_FIRST*/
1823
1824 }
1825
1826 /*update leftSpaceInChunk, currentPos and currentChunkDur*/
1827 *leftSpaceInChunk = mMp4FileDataPtr->videoTrackPtr->MaxChunkSize;
1828 mMp4FileDataPtr->videoTrackPtr->currentPos = 0;
1829
1830 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
1831 /* check wether to use a new stsc or not */
1832
1833 if (mMp4FileDataPtr->videoTrackPtr->currentStsc > 0)
1834 {
1835 if ((mMp4FileDataPtr->videoTrackPtr->
1836 chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->
1837 currentStsc] & 0xFFF) != (mMp4FileDataPtr->videoTrackPtr->
1838 chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentStsc
1839 - 1] & 0xFFF))
1840 mMp4FileDataPtr->videoTrackPtr->currentStsc += 1;
1841 }
1842 else
1843 mMp4FileDataPtr->videoTrackPtr->currentStsc += 1;
1844
1845 /* max nb of chunk is now dynamic */
1846 if (mMp4FileDataPtr->videoTrackPtr->currentStsc
1847 + 3 > M4MP4W_CHUNK_ALLOC_NB)
1848 {
1849 M4OSA_TRACE1_0("M4MP4W_newVideoChunk : video stsc table is full");
1850 return M4WAR_MP4W_OVERSIZE;
1851 }
1852
1853 /* set nb of samples in the new chunk to 0 */
1854 mMp4FileDataPtr->videoTrackPtr->
1855 chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentStsc] =
1856 0 + (mMp4FileDataPtr->videoTrackPtr->currentChunk << 12);
1857
1858 #else
1859 /*set nb of samples in the new chunk to 0*/
1860
1861 mMp4FileDataPtr->videoTrackPtr->
1862 chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] = 0;
1863
1864 #endif
1865
1866 /*set time of the new chunk to lastCTS (for initialization, but updated further to the
1867 CTS of the last sample in the chunk)*/
1868
1869 mMp4FileDataPtr->videoTrackPtr->
1870 chunkTimeMsTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
1871 (M4OSA_UInt32)(mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS
1872 * scale_video);
1873
1874 return err;
1875 }
1876
1877 /*******************************************************************************/
M4MP4W_startAU(M4OSA_Context context,M4SYS_StreamID streamID,M4SYS_AccessUnit * auPtr)1878 M4OSA_ERR M4MP4W_startAU( M4OSA_Context context, M4SYS_StreamID streamID,
1879 M4SYS_AccessUnit *auPtr )
1880 /*******************************************************************************/
1881 {
1882 M4OSA_ERR err = M4NO_ERROR;
1883
1884 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
1885
1886 M4OSA_UInt32 leftSpaceInChunk;
1887 M4MP4W_Time32 chunkDurMs;
1888
1889 M4OSA_Double scale_audio;
1890 M4OSA_Double scale_video;
1891
1892 ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
1893 ERR_CHECK(auPtr != M4OSA_NULL, M4ERR_PARAMETER);
1894
1895 M4OSA_TRACE2_0("----- M4MP4W_startAU -----");
1896
1897 /*check macro state*/
1898 ERR_CHECK((mMp4FileDataPtr->state == M4MP4W_writing), M4ERR_STATE);
1899
1900 if (streamID == AudioStreamID) /*audio stream*/
1901 {
1902 M4OSA_TRACE2_0("M4MP4W_startAU -> audio");
1903
1904 scale_audio =
1905 1000.0 / mMp4FileDataPtr->audioTrackPtr->CommonData.timescale;
1906
1907 /*audio microstate*/
1908 ERR_CHECK((mMp4FileDataPtr->audioTrackPtr->microState
1909 == M4MP4W_writing), M4ERR_STATE);
1910 mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_writing_startAU;
1911
1912 leftSpaceInChunk = mMp4FileDataPtr->audioTrackPtr->MaxChunkSize
1913 - mMp4FileDataPtr->audioTrackPtr->currentPos;
1914
1915 M4OSA_TRACE2_2("audio %d %d",
1916 mMp4FileDataPtr->audioTrackPtr->currentPos, leftSpaceInChunk);
1917
1918 chunkDurMs =
1919 (M4OSA_UInt32)(( mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS
1920 * scale_audio) - mMp4FileDataPtr->audioTrackPtr->
1921 chunkTimeMsTable[mMp4FileDataPtr->audioTrackPtr->
1922 currentChunk]);
1923
1924 if ((leftSpaceInChunk < mMp4FileDataPtr->audioTrackPtr->MaxAUSize)
1925 || (( mMp4FileDataPtr->InterleaveDur != 0)
1926 && (chunkDurMs >= mMp4FileDataPtr->InterleaveDur)))
1927 {
1928 #ifdef _M4MP4W_UNBUFFERED_VIDEO
1929 /* only if there is at least 1 video sample in the chunk */
1930
1931 if ((mMp4FileDataPtr->videoTrackPtr != M4OSA_NULL)
1932 && (mMp4FileDataPtr->videoTrackPtr->currentPos > 0))
1933 {
1934 /* close the opened video chunk before creating a new audio one */
1935 err = M4MP4W_newVideoChunk(context, &leftSpaceInChunk);
1936
1937 if (err != M4NO_ERROR)
1938 return err;
1939 }
1940
1941 #endif
1942 /* not enough space in current chunk: create a new one */
1943
1944 err = M4MP4W_newAudioChunk(context, &leftSpaceInChunk);
1945
1946 if (err != M4NO_ERROR)
1947 return err;
1948 }
1949
1950 auPtr->size = leftSpaceInChunk;
1951
1952 #ifdef _M4MP4W_MOOV_FIRST
1953
1954 auPtr->dataAddress = (M4OSA_MemAddr32)(mMp4FileDataPtr->audioTrackPtr->
1955 Chunk[mMp4FileDataPtr->audioTrackPtr->currentChunk]
1956 + mMp4FileDataPtr->audioTrackPtr->currentPos);
1957
1958 #else
1959
1960 auPtr->dataAddress =
1961 (M4OSA_MemAddr32)(mMp4FileDataPtr->audioTrackPtr->Chunk[0]
1962 + mMp4FileDataPtr->audioTrackPtr->currentPos);
1963
1964 #endif /*_M4MP4W_MOOV_FIRST*/
1965
1966 }
1967 else if (streamID == VideoStreamID) /*video stream*/
1968 {
1969 M4OSA_TRACE2_0("M4MP4W_startAU -> video");
1970
1971 scale_video =
1972 1000.0 / mMp4FileDataPtr->videoTrackPtr->CommonData.timescale;
1973
1974 /*video microstate*/
1975 ERR_CHECK((mMp4FileDataPtr->videoTrackPtr->microState
1976 == M4MP4W_writing), M4ERR_STATE);
1977 mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_writing_startAU;
1978
1979 leftSpaceInChunk = mMp4FileDataPtr->videoTrackPtr->MaxChunkSize
1980 - mMp4FileDataPtr->videoTrackPtr->currentPos;
1981
1982 chunkDurMs =
1983 (M4OSA_UInt32)(( mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS
1984 * scale_video) - mMp4FileDataPtr->videoTrackPtr->
1985 chunkTimeMsTable[mMp4FileDataPtr->videoTrackPtr->
1986 currentChunk]);
1987
1988 #ifdef _M4MP4W_UNBUFFERED_VIDEO
1989
1990 leftSpaceInChunk = mMp4FileDataPtr->videoTrackPtr->MaxChunkSize;
1991
1992 #endif
1993
1994 M4OSA_TRACE2_2("video %d %d",
1995 mMp4FileDataPtr->videoTrackPtr->currentPos, leftSpaceInChunk);
1996
1997 if (( leftSpaceInChunk < mMp4FileDataPtr->videoTrackPtr->MaxAUSize)
1998 || (( mMp4FileDataPtr->InterleaveDur != 0)
1999 && (chunkDurMs >= mMp4FileDataPtr->InterleaveDur))
2000 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2001
2002 || (( mMp4FileDataPtr->videoTrackPtr->MaxAUperChunk != 0)
2003 && (( mMp4FileDataPtr->videoTrackPtr->
2004 chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->
2005 currentStsc] & 0xFFF)
2006 == mMp4FileDataPtr->videoTrackPtr->MaxAUperChunk))
2007
2008 #endif
2009
2010 )
2011 {
2012 /*not enough space in current chunk: create a new one*/
2013 err = M4MP4W_newVideoChunk(context, &leftSpaceInChunk);
2014
2015 if (err != M4NO_ERROR)
2016 return err;
2017 }
2018
2019 M4OSA_TRACE2_3("startAU: size 0x%x pos 0x%x chunk %u", auPtr->size,
2020 mMp4FileDataPtr->videoTrackPtr->currentPos,
2021 mMp4FileDataPtr->videoTrackPtr->currentChunk);
2022
2023 M4OSA_TRACE3_1("adr = 0x%p", auPtr->dataAddress);
2024
2025 if (auPtr->dataAddress)
2026 {
2027 M4OSA_TRACE3_3(" data = %08X %08X %08X", auPtr->dataAddress[0],
2028 auPtr->dataAddress[1], auPtr->dataAddress[2]);
2029 }
2030
2031 auPtr->size = leftSpaceInChunk;
2032 #ifdef _M4MP4W_MOOV_FIRST
2033
2034 if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
2035 == M4SYS_kH264)
2036 auPtr->dataAddress =
2037 (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->
2038 Chunk[mMp4FileDataPtr->videoTrackPtr->currentChunk]
2039 + mMp4FileDataPtr->videoTrackPtr->currentPos + 4);
2040 else
2041 auPtr->dataAddress =
2042 (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->
2043 Chunk[mMp4FileDataPtr->videoTrackPtr->currentChunk]
2044 + mMp4FileDataPtr->videoTrackPtr->currentPos);
2045
2046 #else
2047 #ifdef _M4MP4W_UNBUFFERED_VIDEO
2048
2049 if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
2050 == M4SYS_kH264)
2051 auPtr->dataAddress =
2052 (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->Chunk[0] + 4);
2053 else
2054 auPtr->dataAddress =
2055 (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->Chunk[0]);
2056
2057 #else
2058
2059 if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
2060 == M4SYS_kH264)
2061 auPtr->dataAddress =
2062 (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->Chunk[0]
2063 + mMp4FileDataPtr->videoTrackPtr->currentPos
2064 + 4); /* In H264, we must start by the length of the NALU, coded in 4 bytes */
2065 else
2066 auPtr->dataAddress =
2067 (M4OSA_MemAddr32)(mMp4FileDataPtr->videoTrackPtr->Chunk[0]
2068 + mMp4FileDataPtr->videoTrackPtr->currentPos);
2069
2070 #endif /*_M4MP4W_UNBUFFERED_VIDEO*/
2071
2072 #endif /*_M4MP4W_MOOV_FIRST*/
2073
2074 }
2075 else
2076 return M4ERR_BAD_STREAM_ID;
2077
2078 M4OSA_TRACE1_3("M4MPW_startAU: start address:%p, size:%lu, stream:%d",
2079 auPtr->dataAddress, auPtr->size, streamID);
2080
2081 return err;
2082 }
2083
2084 /*******************************************************************************/
M4MP4W_processAU(M4OSA_Context context,M4SYS_StreamID streamID,M4SYS_AccessUnit * auPtr)2085 M4OSA_ERR M4MP4W_processAU( M4OSA_Context context, M4SYS_StreamID streamID,
2086 M4SYS_AccessUnit *auPtr )
2087 /*******************************************************************************/
2088 {
2089 M4OSA_ERR err = M4NO_ERROR;
2090 M4MP4W_Time32 delta;
2091 M4MP4W_Time32 lastSampleDur;
2092 M4OSA_UInt32 i;
2093 /*expectedSize is the max filesize to forecast when adding a new AU:*/
2094 M4OSA_UInt32 expectedSize =
2095 32; /*initialized with an estimation of the max metadata space needed for an AU.*/
2096 M4OSA_Double scale_audio = 0.0;
2097 M4OSA_Double scale_video = 0.0;
2098
2099 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
2100 ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
2101
2102 /*check macro state*/
2103 ERR_CHECK((mMp4FileDataPtr->state == M4MP4W_writing), M4ERR_STATE);
2104
2105 M4OSA_TRACE2_0("M4MP4W_processAU");
2106
2107 if (streamID == AudioStreamID)
2108 scale_audio =
2109 1000.0 / mMp4FileDataPtr->audioTrackPtr->CommonData.timescale;
2110
2111 if (streamID == VideoStreamID)
2112 scale_video =
2113 1000.0 / mMp4FileDataPtr->videoTrackPtr->CommonData.timescale;
2114
2115 /* PL 27/10/2008: after the resurgence of the AAC 128 bug, I added a debug check that
2116 the encoded data didn't overflow the available space in the AU */
2117
2118 switch( streamID )
2119 {
2120 case AudioStreamID:
2121 M4OSA_DEBUG_IF1(auPtr->size
2122 + mMp4FileDataPtr->audioTrackPtr->currentPos
2123 > mMp4FileDataPtr->audioTrackPtr->MaxChunkSize,
2124 M4ERR_CONTEXT_FAILED,
2125 "Uh oh. Buffer overflow in the writer. Abandon ship!");
2126 M4OSA_DEBUG_IF2(auPtr->size
2127 > mMp4FileDataPtr->audioTrackPtr->MaxAUSize,
2128 M4ERR_CONTEXT_FAILED,
2129 "Oops. An AU went over the declared Max AU size.\
2130 You might wish to investigate that.");
2131 break;
2132
2133 case VideoStreamID:
2134 M4OSA_DEBUG_IF1(auPtr->size
2135 + mMp4FileDataPtr->videoTrackPtr->currentPos
2136 > mMp4FileDataPtr->videoTrackPtr->MaxChunkSize,
2137 M4ERR_CONTEXT_FAILED,
2138 "Uh oh. Buffer overflow in the writer. Abandon ship!");
2139 M4OSA_DEBUG_IF2(auPtr->size
2140 > mMp4FileDataPtr->videoTrackPtr->MaxAUSize,
2141 M4ERR_CONTEXT_FAILED,
2142 "Oops. An AU went over the declared Max AU size.\
2143 You might wish to investigate that.");
2144 break;
2145 }
2146
2147 /*only if not in the case audio with estimateAudioSize
2148 (else, size already estimated at this point)*/
2149 if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
2150 || (streamID == VideoStreamID))
2151 {
2152 /*check filesize if needed*/
2153 if (mMp4FileDataPtr->MaxFileSize != 0)
2154 {
2155 expectedSize += mMp4FileDataPtr->filesize + auPtr->size;
2156
2157 if ((streamID == VideoStreamID)
2158 && (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
2159 == M4SYS_kH264))
2160 {
2161 expectedSize += 4;
2162 }
2163
2164 if (expectedSize > mMp4FileDataPtr->MaxFileSize)
2165 {
2166 M4OSA_TRACE1_0("processAU : !! FILESIZE EXCEEDED !!");
2167
2168 /* patch for autostop is MaxFileSize exceeded */
2169 M4OSA_TRACE1_0("M4MP4W_processAU : stop at targeted filesize");
2170 return M4WAR_MP4W_OVERSIZE;
2171 }
2172 }
2173 }
2174
2175 /*case audioMsStopTime has already been set during video processing,
2176 and now check it for audio*/
2177 if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
2178 && (streamID == AudioStreamID))
2179 {
2180 if (mMp4FileDataPtr->audioMsStopTime <= (auPtr->CTS *scale_audio))
2181 {
2182 /* bugfix: if a new chunk was just created, cancel it before to close */
2183 if ((mMp4FileDataPtr->audioTrackPtr->currentChunk != 0)
2184 && (mMp4FileDataPtr->audioTrackPtr->currentPos == 0))
2185 {
2186 mMp4FileDataPtr->audioTrackPtr->currentChunk--;
2187 }
2188 M4OSA_TRACE1_0("M4MP4W_processAU : audio stop time reached");
2189 return M4WAR_MP4W_OVERSIZE;
2190 }
2191 }
2192
2193 if (streamID == AudioStreamID) /*audio stream*/
2194 {
2195 M4OSA_TRACE2_0("M4MP4W_processAU -> audio");
2196
2197 /*audio microstate*/
2198 ERR_CHECK((mMp4FileDataPtr->audioTrackPtr->microState
2199 == M4MP4W_writing_startAU), M4ERR_STATE);
2200 mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_writing;
2201
2202 mMp4FileDataPtr->audioTrackPtr->currentPos += auPtr->size;
2203 /* Warning: time conversion cast 64to32! */
2204 delta = (M4MP4W_Time32)auPtr->CTS
2205 - mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS;
2206
2207 /* DEBUG stts entries which are equal to 0 */
2208 M4OSA_TRACE2_1("A_DELTA = %ld\n", delta);
2209
2210 if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2211 == 0) /*test if first AU*/
2212 {
2213 /*set au size*/
2214 mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize = auPtr->size;
2215
2216 /*sample duration is a priori constant in audio case, */
2217 /*but if an Au at least has different size, a stsz table will be created */
2218
2219 /*mMp4FileDataPtr->audioTrackPtr->sampleDuration = delta; */
2220 /*TODO test sample duration? (should be 20ms in AMR8, 160 tics with timescale 8000) */
2221 }
2222 else
2223 {
2224 /*check if au size is constant (audio) */
2225 /*0 sample size means non constant size*/
2226 if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize != 0)
2227 {
2228 if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize
2229 != auPtr->size)
2230 {
2231 /*first AU with different size => non constant size => STSZ table needed*/
2232 /*computation of the nb of block of size M4MP4W_STSZ_ALLOC_SIZE to allocate*/
2233 mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedStszBlocks =
2234 1 + mMp4FileDataPtr->audioTrackPtr->
2235 CommonData.sampleNb
2236 * 4 / M4MP4W_STSZ_AUDIO_ALLOC_SIZE;
2237 mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ =
2238 (M4OSA_UInt32 *)M4OSA_32bitAlignedMalloc(
2239 mMp4FileDataPtr->audioTrackPtr->
2240 nbOfAllocatedStszBlocks
2241 * M4MP4W_STSZ_AUDIO_ALLOC_SIZE,
2242 M4MP4_WRITER, (M4OSA_Char *)"audioTrackPtr->TABLE_STSZ");
2243 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ
2244 != M4OSA_NULL, M4ERR_ALLOC);
2245
2246 for ( i = 0;
2247 i < mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
2248 i++ )
2249 {
2250 mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ[i] =
2251 mMp4FileDataPtr->audioTrackPtr->
2252 CommonData.sampleSize;
2253 }
2254 mMp4FileDataPtr->audioTrackPtr->
2255 TABLE_STSZ[mMp4FileDataPtr->audioTrackPtr->
2256 CommonData.sampleNb] = auPtr->size;
2257 mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize =
2258 0; /*used as a flag in that case*/
2259 /*more bytes in the file in that case:*/
2260 if (mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
2261 mMp4FileDataPtr->filesize +=
2262 4 * mMp4FileDataPtr->audioTrackPtr->
2263 CommonData.sampleNb;
2264 }
2265 }
2266 /*else table already exists*/
2267 else
2268 {
2269 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2270
2271 if (4 *(mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb + 3)
2272 >= mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedStszBlocks
2273 *M4MP4W_STSZ_AUDIO_ALLOC_SIZE)
2274 {
2275 M4OSA_TRACE1_0(
2276 "M4MP4W_processAU : audio stsz table is full");
2277 return M4WAR_MP4W_OVERSIZE;
2278 }
2279
2280 #else
2281
2282 if (4 *mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2283 >= mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedStszBlocks
2284 *M4MP4W_STSZ_AUDIO_ALLOC_SIZE)
2285 {
2286 mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedStszBlocks +=
2287 1;
2288 mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ =
2289 (M4OSA_UInt32 *)M4MP4W_realloc(
2290 (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
2291 TABLE_STSZ, ( mMp4FileDataPtr->audioTrackPtr->
2292 nbOfAllocatedStszBlocks - 1)
2293 * M4MP4W_STSZ_AUDIO_ALLOC_SIZE,
2294 mMp4FileDataPtr->audioTrackPtr->
2295 nbOfAllocatedStszBlocks
2296 * M4MP4W_STSZ_AUDIO_ALLOC_SIZE);
2297 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ
2298 != M4OSA_NULL, M4ERR_ALLOC);
2299 }
2300
2301 #endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
2302
2303 mMp4FileDataPtr->audioTrackPtr->
2304 TABLE_STSZ[mMp4FileDataPtr->audioTrackPtr->
2305 CommonData.sampleNb] = auPtr->size;
2306
2307 if (mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
2308 mMp4FileDataPtr->filesize += 4;
2309 }
2310 }
2311
2312 if (delta > mMp4FileDataPtr->audioTrackPtr->sampleDuration)
2313 {
2314 /* keep track of real sample duration*/
2315 mMp4FileDataPtr->audioTrackPtr->sampleDuration = delta;
2316 }
2317
2318 if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2319 == 0) /*test if first AU*/
2320 {
2321 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[0] = 1;
2322 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[1] = 0;
2323 mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb = 1;
2324 mMp4FileDataPtr->filesize += 8;
2325 }
2326 else if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2327 == 1) /*test if second AU*/
2328 {
2329 #ifndef DUPLICATE_STTS_IN_LAST_AU
2330
2331 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[0] += 1;
2332
2333 #endif /*DUPLICATE_STTS_IN_LAST_AU*/
2334
2335 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[1] = delta;
2336 mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb += 1;
2337 mMp4FileDataPtr->filesize += 8;
2338 }
2339 else
2340 {
2341 /*retrieve last sample delta*/
2342 lastSampleDur = mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2
2343 * (mMp4FileDataPtr->audioTrackPtr->
2344 CommonData.sttsTableEntryNb - 1) - 1];
2345
2346 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2347
2348 if (8 *(mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
2349 + 3) >= mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedSttsBlocks
2350 *M4MP4W_STTS_AUDIO_ALLOC_SIZE)
2351 {
2352 M4OSA_TRACE1_0("M4MP4W_processAU : audio stts table is full");
2353 return M4WAR_MP4W_OVERSIZE;
2354 }
2355
2356 #else
2357
2358 if (8 *mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
2359 >= mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedSttsBlocks
2360 *M4MP4W_STTS_AUDIO_ALLOC_SIZE)
2361 {
2362 mMp4FileDataPtr->audioTrackPtr->nbOfAllocatedSttsBlocks += 1;
2363 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS =
2364 (M4OSA_UInt32 *)M4MP4W_realloc(
2365 (M4OSA_MemAddr32)mMp4FileDataPtr->audioTrackPtr->
2366 TABLE_STTS, ( mMp4FileDataPtr->audioTrackPtr->
2367 nbOfAllocatedSttsBlocks
2368 - 1) * M4MP4W_STTS_AUDIO_ALLOC_SIZE,
2369 mMp4FileDataPtr->audioTrackPtr->
2370 nbOfAllocatedSttsBlocks
2371 * M4MP4W_STTS_AUDIO_ALLOC_SIZE);
2372 ERR_CHECK(mMp4FileDataPtr->audioTrackPtr->TABLE_STTS
2373 != M4OSA_NULL, M4ERR_ALLOC);
2374 }
2375
2376 #endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
2377
2378 if (delta != lastSampleDur) /*new entry in the table*/
2379 {
2380 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2 *(
2381 mMp4FileDataPtr->audioTrackPtr->
2382 CommonData.sttsTableEntryNb - 1)] = 1;
2383 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2 *(
2384 mMp4FileDataPtr->audioTrackPtr->
2385 CommonData.sttsTableEntryNb - 1) + 1] = delta;
2386 mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb +=
2387 1;
2388 mMp4FileDataPtr->filesize += 8;
2389 }
2390 else
2391 {
2392 /*increase of 1 the number of consecutive AUs with same duration*/
2393 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2 *(
2394 mMp4FileDataPtr->audioTrackPtr->
2395 CommonData.sttsTableEntryNb - 1) - 2] += 1;
2396 }
2397 }
2398 mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb += 1;
2399 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2400
2401 mMp4FileDataPtr->audioTrackPtr->
2402 chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->currentStsc] +=
2403 1;
2404
2405 #else
2406
2407 mMp4FileDataPtr->audioTrackPtr->
2408 chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] +=
2409 1;
2410
2411 #endif
2412 /* Warning: time conversion cast 64to32! */
2413
2414 mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS =
2415 (M4MP4W_Time32)auPtr->CTS;
2416 }
2417 else if (streamID == VideoStreamID) /*video stream*/
2418 {
2419 M4OSA_TRACE2_0("M4MP4W_processAU -> video");
2420
2421 /* In h264, the size of the AU must be added to the data */
2422 if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
2423 == M4SYS_kH264)
2424 {
2425 /* Add the size of the NALU in BE */
2426 M4OSA_MemAddr8 pTmpDataAddress = M4OSA_NULL;
2427 auPtr->dataAddress -= 1;
2428 pTmpDataAddress = (M4OSA_MemAddr8)auPtr->dataAddress;
2429
2430 // bit manipulation
2431 *pTmpDataAddress++ = (M4OSA_UInt8)((auPtr->size >> 24) & 0x000000FF);
2432 *pTmpDataAddress++ = (M4OSA_UInt8)((auPtr->size >> 16) & 0x000000FF);
2433 *pTmpDataAddress++ = (M4OSA_UInt8)((auPtr->size >> 8) & 0x000000FF);
2434 *pTmpDataAddress++ = (M4OSA_UInt8)((auPtr->size) & 0x000000FF);
2435
2436 auPtr->size += 4;
2437 }
2438
2439 /*video microstate*/
2440 ERR_CHECK((mMp4FileDataPtr->videoTrackPtr->microState
2441 == M4MP4W_writing_startAU), M4ERR_STATE);
2442 mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_writing;
2443
2444 #ifdef _M4MP4W_UNBUFFERED_VIDEO
2445 /* samples are written to file now */
2446
2447 err = M4MP4W_putBlock((M4OSA_UChar *)auPtr->dataAddress, auPtr->size,
2448 mMp4FileDataPtr->fileWriterFunctions,
2449 mMp4FileDataPtr->fileWriterContext);
2450
2451 if (err != M4NO_ERROR)
2452 {
2453 M4OSA_FilePosition temp = mMp4FileDataPtr->absoluteCurrentPos
2454 + mMp4FileDataPtr->videoTrackPtr->currentPos;
2455 M4OSA_TRACE2_1(
2456 "M4MP4W_processAU: putBlock error when writing unbuffered video sample: %#X",
2457 err);
2458 /* Ouch, we got an error writing to the file, but we need to properly react so that
2459 the state is still consistent and we can properly close the file so that what has
2460 been recorded so far is not lost. Yay error recovery! */
2461
2462 /* First, we do not know where we are in the file. Put us back at where we were before
2463 attempting to write the data. That way, we're consistent with the chunk and sample
2464 state data.absoluteCurrentPos is only updated for chunks, it points to the beginning
2465 of the chunk,therefore we need to add videoTrackPtr->currentPos to know where we
2466 were in the file. */
2467 err = mMp4FileDataPtr->fileWriterFunctions->seek(
2468 mMp4FileDataPtr->fileWriterContext,
2469 M4OSA_kFileSeekBeginning, &temp);
2470
2471 M4OSA_TRACE2_3(
2472 "Backtracking to position 0x%08X, seek returned %d and position %08X",
2473 mMp4FileDataPtr->absoluteCurrentPos
2474 + mMp4FileDataPtr->videoTrackPtr->currentPos, err, temp);
2475
2476 /* Then, do not update any info whatsoever in the writing state. This will have the
2477 consequence that it will be as if the sample has never been written, so the chunk
2478 will be merely closed after the previous sample (the sample we attempted to write
2479 here is lost). */
2480
2481 /* And lastly (for here), return that we've reached the limit of available space.
2482 We don't care about the error originally returned by putBlock. */
2483
2484 return M4WAR_MP4W_OVERSIZE;
2485 }
2486
2487 #endif
2488
2489 mMp4FileDataPtr->videoTrackPtr->currentPos += auPtr->size;
2490
2491 /* Warning: time conversion cast 64to32! */
2492 delta = (M4MP4W_Time32)auPtr->CTS
2493 - mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS;
2494
2495 /* DEBUG stts entries which are equal to 0 */
2496 M4OSA_TRACE2_1("V_DELTA = %ld\n", delta);
2497
2498 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2499
2500 if (2 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb + 3)
2501 >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
2502 *M4MP4W_STSZ_ALLOC_SIZE)
2503 {
2504 M4OSA_TRACE1_0("M4MP4W_processAU : video stsz table is full");
2505 return M4WAR_MP4W_OVERSIZE;
2506 }
2507
2508 mMp4FileDataPtr->videoTrackPtr->
2509 TABLE_STSZ[mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb] =
2510 (M4OSA_UInt16)auPtr->size;
2511 mMp4FileDataPtr->filesize += 4;
2512
2513 #else
2514
2515 if (4 *mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2516 >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
2517 *M4MP4W_STSZ_ALLOC_SIZE)
2518 {
2519 mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks += 1;
2520
2521 mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ =
2522 (M4OSA_UInt32 *)M4MP4W_realloc(
2523 (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
2524 ( mMp4FileDataPtr->videoTrackPtr->
2525 nbOfAllocatedStszBlocks
2526 - 1) * M4MP4W_STSZ_ALLOC_SIZE,
2527 mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
2528 * M4MP4W_STSZ_ALLOC_SIZE);
2529
2530 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ != M4OSA_NULL,
2531 M4ERR_ALLOC);
2532 }
2533
2534 mMp4FileDataPtr->videoTrackPtr->
2535 TABLE_STSZ[mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb] =
2536 auPtr->size;
2537 mMp4FileDataPtr->filesize += 4;
2538
2539 #endif
2540
2541 if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2542 == 0) /*test if first AU*/
2543 {
2544 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2545
2546 M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0], 1);
2547 M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0], 0);
2548
2549 #else
2550
2551 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0] = 1;
2552 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = 0;
2553
2554 #endif
2555
2556 mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb = 1;
2557 mMp4FileDataPtr->filesize += 8;
2558 }
2559 else if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2560 == 1 ) /*test if second AU*/
2561 {
2562 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2563
2564 M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0],
2565 (M4OSA_UInt16)delta);
2566
2567 #else
2568
2569 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = delta;
2570
2571 #endif
2572
2573 }
2574 else
2575 {
2576 /*retrieve last sample delta*/
2577 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2578
2579 lastSampleDur = M4MP4W_get32_Hi(&mMp4FileDataPtr->videoTrackPtr->
2580 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2581 CommonData.sttsTableEntryNb - 1]);
2582
2583 if (4 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
2584 + 3) >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks
2585 *M4MP4W_STTS_ALLOC_SIZE)
2586 {
2587 M4OSA_TRACE1_0("M4MP4W_processAU : video stts table is full");
2588 return M4WAR_MP4W_OVERSIZE;
2589 }
2590
2591 #else
2592
2593 lastSampleDur = mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
2594 * (mMp4FileDataPtr->videoTrackPtr->
2595 CommonData.sttsTableEntryNb - 1) + 1];
2596
2597 if (8 *mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
2598 >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks
2599 *M4MP4W_STTS_ALLOC_SIZE)
2600 {
2601 mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks += 1;
2602 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS =
2603 (M4OSA_UInt32 *)M4MP4W_realloc(
2604 (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
2605 TABLE_STTS, ( mMp4FileDataPtr->videoTrackPtr->
2606 nbOfAllocatedSttsBlocks
2607 - 1) * M4MP4W_STTS_ALLOC_SIZE,
2608 mMp4FileDataPtr->videoTrackPtr->
2609 nbOfAllocatedSttsBlocks
2610 * M4MP4W_STTS_ALLOC_SIZE);
2611 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STTS
2612 != M4OSA_NULL, M4ERR_ALLOC);
2613 }
2614
2615 #endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
2616
2617 if (delta != lastSampleDur) /*new entry in the table*/
2618 {
2619 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2620
2621 M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->
2622 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2623 CommonData.sttsTableEntryNb], 1);
2624 M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->
2625 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2626 CommonData.sttsTableEntryNb], (M4OSA_UInt16)delta);
2627
2628 #else
2629
2630 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
2631 mMp4FileDataPtr->videoTrackPtr->
2632 CommonData.sttsTableEntryNb)] = 1;
2633 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
2634 *(mMp4FileDataPtr->videoTrackPtr->
2635 CommonData.sttsTableEntryNb)+1] = delta;
2636
2637 #endif
2638
2639 mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb +=
2640 1;
2641 mMp4FileDataPtr->filesize += 8;
2642 }
2643 else
2644 {
2645 /*increase of 1 the number of consecutive AUs with same duration*/
2646 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2647
2648 mMp4FileDataPtr->videoTrackPtr->
2649 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
2650 CommonData.sttsTableEntryNb - 1] += 1;
2651
2652 #else
2653
2654 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
2655 mMp4FileDataPtr->videoTrackPtr->
2656 CommonData.sttsTableEntryNb - 1)] += 1;
2657
2658 #endif
2659
2660 }
2661 }
2662
2663 mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb += 1;
2664 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2665
2666 mMp4FileDataPtr->videoTrackPtr->
2667 chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentStsc] +=
2668 1;
2669
2670 #else
2671
2672 mMp4FileDataPtr->videoTrackPtr->
2673 chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] +=
2674 1;
2675
2676 #endif
2677
2678 if (auPtr->attribute == AU_RAP)
2679 {
2680 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
2681
2682 if (4 *(mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb + 3)
2683 >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks
2684 *M4MP4W_STSS_ALLOC_SIZE)
2685 {
2686 M4OSA_TRACE1_0("M4MP4W_processAU : video stss table is full");
2687 return M4WAR_MP4W_OVERSIZE;
2688 }
2689
2690 #else
2691
2692 if (4 *mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb
2693 >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks
2694 *M4MP4W_STSS_ALLOC_SIZE)
2695 {
2696 mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks += 1;
2697 mMp4FileDataPtr->videoTrackPtr->TABLE_STSS =
2698 (M4OSA_UInt32 *)M4MP4W_realloc(
2699 (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
2700 TABLE_STSS, ( mMp4FileDataPtr->videoTrackPtr->
2701 nbOfAllocatedStssBlocks
2702 - 1) * M4MP4W_STSS_ALLOC_SIZE,
2703 mMp4FileDataPtr->videoTrackPtr->
2704 nbOfAllocatedStssBlocks
2705 * M4MP4W_STSS_ALLOC_SIZE);
2706 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSS
2707 != M4OSA_NULL, M4ERR_ALLOC);
2708 }
2709
2710 #endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
2711
2712 mMp4FileDataPtr->videoTrackPtr->
2713 TABLE_STSS[mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb] =
2714 mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb;
2715 mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb += 1;
2716 mMp4FileDataPtr->filesize += 4;
2717 }
2718
2719 /* Warning: time conversion cast 64to32! */
2720 mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS =
2721 (M4MP4W_Time32)auPtr->CTS;
2722 }
2723 else
2724 return M4ERR_BAD_STREAM_ID;
2725
2726 /* I moved some state modification to after we know the sample has been written correctly. */
2727 if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
2728 && (streamID == VideoStreamID))
2729 {
2730 mMp4FileDataPtr->audioMsStopTime =
2731 (M4MP4W_Time32)(auPtr->CTS * scale_video);
2732 }
2733
2734 if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
2735 || (streamID == VideoStreamID))
2736 {
2737 /*update fileSize*/
2738 mMp4FileDataPtr->filesize += auPtr->size;
2739 }
2740
2741 if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
2742 && (streamID == VideoStreamID))
2743 {
2744 /*update filesize with estimated audio data that will be added later. */
2745 /*Warning: Assumption is made that: */
2746 /* - audio samples have constant size (e.g. no sid). */
2747 /* - max audio sample size has been set, and is the actual sample size. */
2748
2749 ERR_CHECK(mMp4FileDataPtr->audioMsChunkDur != 0,
2750 M4WAR_MP4W_NOT_EVALUABLE);
2751 mMp4FileDataPtr->filesize -=
2752 (M4OSA_UInt32)(( mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS
2753 * scale_video) * (0.05/*always 50 AMR samples per second*/
2754 *(M4OSA_Double)mMp4FileDataPtr->audioTrackPtr->MaxAUSize
2755 + 16/*additional data for a new chunk*/
2756 / (M4OSA_Double)mMp4FileDataPtr->audioMsChunkDur));
2757
2758 mMp4FileDataPtr->filesize += (M4OSA_UInt32)(( auPtr->CTS * scale_video)
2759 * (0.05/*always 50 AMR samples per second*/
2760 *(M4OSA_Double)mMp4FileDataPtr->audioTrackPtr->MaxAUSize
2761 + 16/*additional data for a new chunk*/
2762 / (M4OSA_Double)mMp4FileDataPtr->audioMsChunkDur));
2763 }
2764
2765 M4OSA_TRACE1_4("processAU : size 0x%x mode %d filesize %lu limit %lu",
2766 auPtr->size, auPtr->attribute, mMp4FileDataPtr->filesize,
2767 mMp4FileDataPtr->MaxFileSize);
2768
2769 return err;
2770 }
2771
2772 /*******************************************************************************/
M4MP4W_closeWrite(M4OSA_Context context)2773 M4OSA_ERR M4MP4W_closeWrite( M4OSA_Context context )
2774 /*******************************************************************************/
2775 {
2776 M4OSA_ERR err = M4NO_ERROR;
2777 M4OSA_ERR err2 = M4NO_ERROR, err3 = M4NO_ERROR;
2778
2779 /*Warning: test should be done here to ensure context->pContext is not M4OSA_NULL,
2780 but C is not C++...*/
2781 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
2782
2783 M4OSA_UChar camcoder_maj, camcoder_min, camcoder_rev; /*camcoder version*/
2784 M4OSA_Bool bAudio =
2785 (( mMp4FileDataPtr->hasAudio)
2786 && (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
2787 != 0)); /*((mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL) &&
2788 (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb != 0));*/
2789 M4OSA_Bool bVideo =
2790 (( mMp4FileDataPtr->hasVideo)
2791 && (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
2792 != 0)); /*((mMp4FileDataPtr->videoTrackPtr != M4OSA_NULL) &&
2793 (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb != 0));*/
2794 M4OSA_Bool bH263 = M4OSA_FALSE;
2795 M4OSA_Bool bH264 = M4OSA_FALSE;
2796 M4OSA_Bool bMP4V = M4OSA_FALSE;
2797 M4OSA_Bool bAAC = M4OSA_FALSE;
2798 M4OSA_Bool bEVRC = M4OSA_FALSE;
2799
2800 /*intermediate variables*/
2801 M4OSA_UInt32 A, B, N, AB4N;
2802
2803 /*Trak variables*/
2804 M4OSA_UInt32 a_trakId = AudioStreamID; /* (audio=1)*/
2805 /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
2806 M4OSA_UInt32 a_trakOffset = 32;
2807 M4OSA_UInt32 a_sttsSize = 24; /* A (audio=24)*/
2808 M4OSA_UInt32 a_stszSize = 20; /* B (audio=20)*/
2809 M4OSA_UInt32 a_trakSize = 402; /* (audio=402)*/
2810 M4OSA_UInt32 a_mdiaSize = 302; /* (audio=302)*/
2811 M4OSA_UInt32 a_minfSize = 229; /* (audio=229)*/
2812 M4OSA_UInt32 a_stblSize = 169; /* (audio=169)*/
2813 M4OSA_UInt32 a_stsdSize = 69; /* (audio=69 )*/
2814 M4OSA_UInt32 a_esdSize = 53; /* (audio=53 )*/
2815 M4OSA_UInt32 a_dataSize = 0; /* temp: At the end, = currentPos*/
2816 M4MP4W_Time32 a_trakDuration = 0; /* equals lastCTS*/
2817 M4MP4W_Time32 a_msTrakDuration = 0;
2818 M4OSA_UInt32 a_stscSize = 28; /* 16+12*nbchunksaudio*/
2819 M4OSA_UInt32 a_stcoSize = 20; /* 16+4*nbchunksaudio*/
2820
2821 M4OSA_UInt32 v_trakId = VideoStreamID; /* (video=2)*/
2822 /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
2823 M4OSA_UInt32 v_trakOffset = 32;
2824 M4OSA_UInt32 v_sttsSize = 0; /* A (video=16+8J)*/
2825 M4OSA_UInt32 v_stszSize = 0; /* B (video=20+4K)*/
2826 M4OSA_UInt32 v_trakSize = 0; /* (h263=A+B+4N+426), (mp4v=A+B+dsi+4N+448) */
2827 M4OSA_UInt32 v_mdiaSize = 0; /* (h263=A+B+4N+326), (mp4v=A+B+dsi+4N+348) */
2828 M4OSA_UInt32 v_minfSize = 0; /* (h263=A+B+4N+253), (mp4v=A+B+dsi+4N+275) */
2829 M4OSA_UInt32 v_stblSize = 0; /* (h263=A+B+4N+189), (mp4v=A+B+dsi+4N+211) */
2830 M4OSA_UInt32 v_stsdSize = 0; /* (h263=117) , (mp4v=139+dsi )*/
2831 M4OSA_UInt32 v_esdSize = 0; /* (h263=101) , (mp4v=153+dsi )*/
2832 M4OSA_UInt32 v_dataSize = 0; /* temp: At the end, = currentPos*/
2833 M4MP4W_Time32 v_trakDuration = 0; /* equals lastCTS*/
2834 M4MP4W_Time32 v_msTrakDuration = 0;
2835 M4OSA_UInt32 v_stscSize = 28; /* 16+12*nbchunksvideo*/
2836 M4OSA_UInt32 v_stcoSize = 20; /* 16+4*nbchunksvideo*/
2837
2838 /*video variables*/
2839 M4OSA_UInt32 v_stssSize = 0; /* 4*N+16 STSS*/
2840
2841 /*aac & mp4v temp variable*/
2842 M4OSA_UInt8 dsi = 0;
2843
2844 /*H264 variables*/
2845 M4OSA_UInt32 v_avcCSize = 0; /* dsi+15*/
2846
2847 /*MP4V variables*/
2848 M4OSA_UInt32 v_esdsSize = 0; /* dsi+37*/
2849 M4OSA_UInt8 v_ESDescriptorSize =
2850 0; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
2851 M4OSA_UInt8 v_DCDescriptorSize = 0; /* dsi+15*/
2852
2853 /*AAC variables*/
2854 M4OSA_UInt32 a_esdsSize = 0; /* dsi+37*/
2855 M4OSA_UInt8 a_ESDescriptorSize =
2856 0; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
2857 M4OSA_UInt8 a_DCDescriptorSize = 0; /* dsi+15*/
2858
2859 /*General variables*/
2860
2861 /* audio chunk size + video chunk size*/
2862 M4OSA_UInt32 mdatSize = 8;
2863 M4OSA_UInt32 moovSize = 116; /* 116 + 402(audio) + (A+B+4N+426)(h263) or */
2864 /* (A+B+dsi+4N+448)(mp4v) */
2865 M4OSA_UInt32 creationTime; /* C */
2866
2867 /*flag to set up the chunk interleave strategy*/
2868 M4OSA_Bool bInterleaveAV =
2869 (bAudio && bVideo && (mMp4FileDataPtr->InterleaveDur != 0));
2870
2871 M4OSA_Context fileWriterContext = mMp4FileDataPtr->fileWriterContext;
2872
2873 M4OSA_UInt32 i;
2874
2875 M4OSA_Double scale_audio = 0.0;
2876 M4OSA_Double scale_video = 0.0;
2877 M4MP4W_Time32 delta;
2878
2879 #ifndef _M4MP4W_MOOV_FIRST
2880
2881 M4OSA_FilePosition moovPos, mdatPos;
2882
2883 #endif /*_M4MP4W_MOOV_FIRST*/
2884
2885 ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
2886
2887 /*macro state */
2888 mMp4FileDataPtr->state = M4MP4W_closed;
2889
2890 /*if no data !*/
2891 if ((!bAudio) && (!bVideo))
2892 {
2893 err = M4NO_ERROR; /*would be better to return a warning ?*/
2894 goto cleanup;
2895 }
2896
2897 #ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
2898 /* Remove safety file to make room for what needs to be written out here
2899 (chunk flushing and moov). */
2900
2901 if (M4OSA_TRUE == mMp4FileDataPtr->cleanSafetyFile)
2902 {
2903 M4OSA_Context tempContext;
2904 err = mMp4FileDataPtr->fileWriterFunctions->openWrite(&tempContext,
2905 mMp4FileDataPtr->safetyFileUrl,
2906 M4OSA_kFileWrite | M4OSA_kFileCreate);
2907
2908 if (M4NO_ERROR != err)
2909 goto cleanup;
2910 err = mMp4FileDataPtr->fileWriterFunctions->closeWrite(tempContext);
2911
2912 if (M4NO_ERROR != err)
2913 goto cleanup;
2914 mMp4FileDataPtr->safetyFileUrl = M4OSA_NULL;
2915 mMp4FileDataPtr->cleanSafetyFile = M4OSA_FALSE;
2916 }
2917
2918 #endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
2919
2920 if (bVideo)
2921 {
2922 if ((M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable)
2923 || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->chunkSizeTable)
2924 || (M4OSA_NULL
2925 == mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable)
2926 || (M4OSA_NULL
2927 == mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable)
2928 || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ)
2929 || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STTS)
2930 || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STSS))
2931 {
2932 mMp4FileDataPtr->fileWriterFunctions->closeWrite(
2933 fileWriterContext); /**< close the stream anyway */
2934 M4MP4W_freeContext(context); /**< Free the context content */
2935 return M4ERR_ALLOC;
2936 }
2937
2938 /*video microstate*/
2939 mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_closed;
2940
2941 /*current chunk is the last one and gives the total number of video chunks (-1)*/
2942 for ( i = 0; i < mMp4FileDataPtr->videoTrackPtr->currentChunk; i++ )
2943 {
2944 v_dataSize += mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
2945 }
2946
2947 #ifndef _M4MP4W_MOOV_FIRST
2948 #ifndef _M4MP4W_UNBUFFERED_VIDEO
2949 /*flush chunk*/
2950
2951 if (mMp4FileDataPtr->videoTrackPtr->currentPos > 0)
2952 {
2953 err = M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[0],
2954 mMp4FileDataPtr->videoTrackPtr->currentPos,
2955 mMp4FileDataPtr->fileWriterFunctions,
2956 mMp4FileDataPtr->fileWriterContext);
2957
2958 if (M4NO_ERROR != err)
2959 goto cleanup;
2960 }
2961
2962 #endif
2963
2964 M4OSA_TRACE1_0("flush video | CLOSE");
2965 M4OSA_TRACE1_3("current chunk = %d offset = 0x%x size = 0x%08X",
2966 mMp4FileDataPtr->videoTrackPtr->currentChunk,
2967 mMp4FileDataPtr->absoluteCurrentPos,
2968 mMp4FileDataPtr->videoTrackPtr->currentPos);
2969
2970 /*update chunk offset*/
2971 mMp4FileDataPtr->videoTrackPtr->
2972 chunkOffsetTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
2973 mMp4FileDataPtr->absoluteCurrentPos;
2974
2975 /*add chunk size to absoluteCurrentPos*/
2976 mMp4FileDataPtr->absoluteCurrentPos +=
2977 mMp4FileDataPtr->videoTrackPtr->currentPos;
2978 #endif /*_M4MP4W_MOOV_FIRST*/
2979
2980 /*update last chunk size, and add this value to v_dataSize*/
2981
2982 mMp4FileDataPtr->videoTrackPtr->
2983 chunkSizeTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
2984 mMp4FileDataPtr->videoTrackPtr->currentPos;
2985 v_dataSize +=
2986 mMp4FileDataPtr->videoTrackPtr->currentPos; /*add last chunk size*/
2987
2988 v_trakDuration = mMp4FileDataPtr->videoTrackPtr->
2989 CommonData.lastCTS; /* equals lastCTS*/
2990
2991 /* bugfix: if a new chunk was just created, cancel it before to close */
2992 if ((mMp4FileDataPtr->videoTrackPtr->currentChunk != 0)
2993 && (mMp4FileDataPtr->videoTrackPtr->currentPos == 0))
2994 {
2995 mMp4FileDataPtr->videoTrackPtr->currentChunk--;
2996 }
2997 #ifdef _M4MP4W_UNBUFFERED_VIDEO
2998
2999 if ((mMp4FileDataPtr->videoTrackPtr->
3000 chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->
3001 currentStsc] & 0xFFF) == 0)
3002 {
3003 mMp4FileDataPtr->videoTrackPtr->currentStsc--;
3004 }
3005
3006 #endif /*_M4MP4W_UNBUFFERED_VIDEO*/
3007
3008 /* Last sample duration */
3009 /* If we have the file duration we use it, else we duplicate the last AU */
3010
3011 if (mMp4FileDataPtr->MaxFileDuration > 0)
3012 {
3013 /* use max file duration to calculate delta of last AU */
3014 delta = mMp4FileDataPtr->MaxFileDuration
3015 - mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS;
3016 v_trakDuration = mMp4FileDataPtr->MaxFileDuration;
3017
3018 if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb > 1)
3019 {
3020 /* if more than 1 frame, create a new stts entry (else already created) */
3021 mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb++;
3022 }
3023
3024 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3025
3026 M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->
3027 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3028 CommonData.sttsTableEntryNb - 1], 1);
3029 M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->
3030 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3031 CommonData.sttsTableEntryNb - 1], delta);
3032
3033 #else
3034
3035 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
3036 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
3037 - 1)] = 1;
3038 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
3039 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
3040 - 1) + 1] = delta;
3041
3042 #endif
3043
3044 }
3045 else
3046 {
3047 /* duplicate the delta of the previous frame */
3048 if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb > 1)
3049 {
3050 /* if more than 1 frame, duplicate the stts entry (else already exists) */
3051 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3052
3053 v_trakDuration +=
3054 M4MP4W_get32_Hi(&mMp4FileDataPtr->videoTrackPtr->
3055 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3056 CommonData.sttsTableEntryNb - 1]);
3057 mMp4FileDataPtr->videoTrackPtr->
3058 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
3059 CommonData.sttsTableEntryNb - 1] += 1;
3060
3061 #else
3062
3063 v_trakDuration += mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
3064 * (mMp4FileDataPtr->videoTrackPtr->
3065 CommonData.sttsTableEntryNb - 1) + 1];
3066 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
3067 mMp4FileDataPtr->videoTrackPtr->
3068 CommonData.sttsTableEntryNb - 1)] += 1;
3069
3070 #endif
3071
3072 }
3073 else
3074 {
3075 M4OSA_TRACE1_0("M4MP4W_closeWrite : ! videoTrackPtr,\
3076 cannot know the duration of the unique AU !");
3077 /* If there is an audio track, we use it as a file duration
3078 (and so, as AU duration...) */
3079 if (mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL)
3080 {
3081 M4OSA_TRACE1_0(
3082 "M4MP4W_closeWrite : ! Let's use the audio track duration !");
3083 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] =
3084 (M4OSA_UInt32)(
3085 mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS
3086 * (1000.0 / mMp4FileDataPtr->audioTrackPtr->
3087 CommonData.timescale));
3088 v_trakDuration =
3089 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1];
3090 }
3091 /* Else, we use a MAGICAL value (66 ms) */
3092 else
3093 {
3094 M4OSA_TRACE1_0(
3095 "M4MP4W_closeWrite : ! No audio track -> use magical value (66) !"); /* */
3096 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = 66;
3097 v_trakDuration = 66;
3098 }
3099 }
3100 }
3101
3102 /* Calculate table sizes */
3103 A = v_sttsSize = 16 + 8 * mMp4FileDataPtr->videoTrackPtr->
3104 CommonData.sttsTableEntryNb; /* A (video=16+8J)*/
3105 B = v_stszSize = 20 + 4 * mMp4FileDataPtr->videoTrackPtr->
3106 CommonData.sampleNb; /* B (video=20+4K)*/
3107 N = mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb;
3108 AB4N = A + B + 4 * N;
3109
3110 scale_video =
3111 1000.0 / mMp4FileDataPtr->videoTrackPtr->CommonData.timescale;
3112 v_msTrakDuration = (M4OSA_UInt32)(v_trakDuration * scale_video);
3113
3114 /*Convert integers in the table from LE into BE*/
3115 #ifndef _M4MP4W_OPTIMIZE_FOR_PHONE
3116
3117 M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
3118 mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb);
3119 M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STTS,
3120 2 * (mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb));
3121
3122 #endif
3123
3124 M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STSS,
3125 mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb);
3126
3127 if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
3128 == M4SYS_kH263)
3129 {
3130 bH263 = M4OSA_TRUE;
3131 v_trakSize = AB4N + 426; /* (h263=A+B+4N+426)*/
3132 v_mdiaSize = AB4N + 326; /* (h263=A+B+4N+326)*/
3133 v_minfSize = AB4N + 253; /* (h263=A+B+4N+253)*/
3134 v_stblSize = AB4N + 189; /* (h263=A+B+4N+189)*/
3135 v_stsdSize = 117; /* (h263=117)*/
3136 v_esdSize = 101; /* (h263=101)*/
3137
3138 moovSize += AB4N + 426;
3139
3140 if (((M4OSA_Int32)mMp4FileDataPtr->videoTrackPtr->avgBitrate) != -1)
3141 {
3142 /*the optional 'bitr' atom is appended to the dsi,so filesize is 16 bytes bigger*/
3143 v_trakSize += 16;
3144 v_mdiaSize += 16;
3145 v_minfSize += 16;
3146 v_stblSize += 16;
3147 v_stsdSize += 16;
3148 v_esdSize += 16;
3149 moovSize += 16;
3150 }
3151 }
3152 else if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
3153 == M4SYS_kH264)
3154 {
3155 bH264 = M4OSA_TRUE;
3156 /* For H264 there is no default DSI, and its presence is mandatory,
3157 so check the DSI has been set*/
3158 if (0 == mMp4FileDataPtr->videoTrackPtr->dsiSize
3159 || M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
3160 {
3161 M4OSA_TRACE1_0(
3162 "M4MP4W_closeWrite: error, no H264 DSI has been set!");
3163 err = M4ERR_STATE;
3164 goto cleanup;
3165 }
3166
3167 /*H264 sizes of the atom*/
3168
3169 // Remove the hardcoded DSI values of H264Block2
3170 // TODO: check bMULPPSSPS case
3171 v_avcCSize = sizeof(M4OSA_UInt32) + sizeof(H264Block2) +
3172 mMp4FileDataPtr->videoTrackPtr->dsiSize;
3173
3174 v_trakSize = AB4N + v_avcCSize + 411;
3175 v_mdiaSize = AB4N + v_avcCSize + 311;
3176 v_minfSize = AB4N + v_avcCSize + 238;
3177 v_stblSize = AB4N + v_avcCSize + 174;
3178 v_stsdSize = v_avcCSize + 102;
3179 v_esdSize = v_avcCSize + 86;
3180
3181 moovSize += AB4N + v_avcCSize + 411;
3182
3183 }
3184 else if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
3185 == M4SYS_kMPEG_4)
3186 {
3187 bMP4V = M4OSA_TRUE;
3188 /* For MPEG4 there is no default DSI, and its presence is mandatory,
3189 so check the DSI has been set*/
3190 if (0 == mMp4FileDataPtr->videoTrackPtr->dsiSize
3191 || M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
3192 {
3193 M4OSA_TRACE1_0(
3194 "M4MP4W_closeWrite: error, no MPEG4 DSI has been set!");
3195 err = M4ERR_STATE;
3196 goto cleanup;
3197 }
3198
3199 /*MP4V variables*/
3200 dsi = mMp4FileDataPtr->videoTrackPtr->dsiSize;
3201 v_esdsSize = 37 + dsi; /* dsi+37*/
3202 v_ESDescriptorSize =
3203 23
3204 + dsi; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
3205 v_DCDescriptorSize = 15 + dsi; /* dsi+15*/
3206
3207 v_trakSize = AB4N + dsi + 448; /* (mp4v=A+B+dsi+4N+448) */
3208 v_mdiaSize = AB4N + dsi + 348; /* (mp4v=A+B+dsi+4N+348) */
3209 v_minfSize = AB4N + dsi + 275; /* (mp4v=A+B+dsi+4N+275) */
3210 v_stblSize = AB4N + dsi + 211; /* (mp4v=A+B+dsi+4N+211) */
3211 v_stsdSize = dsi + 139; /* (mp4v=139+dsi)*/
3212 v_esdSize = dsi + 123; /* (mp4v=123+dsi)*/
3213
3214 moovSize += AB4N + dsi + 448;
3215 }
3216
3217 /*video variables*/
3218 v_stssSize = 16 + 4 * N; /* 4*N+16 STSS*/
3219
3220 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3221 /* stsc update */
3222
3223 v_stscSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3224 v_stblSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3225 v_minfSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3226 v_mdiaSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3227 v_trakSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3228 moovSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
3229
3230 /* stco update */
3231 v_stcoSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3232 v_stblSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3233 v_minfSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3234 v_mdiaSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3235 v_trakSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3236 moovSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3237
3238 #else
3239 /*stsc/stco update*/
3240
3241 v_stscSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3242 v_stcoSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3243 v_stblSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3244 v_minfSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3245 v_mdiaSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3246 v_trakSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3247 moovSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
3248
3249 #endif
3250
3251 /*update last chunk time*/
3252
3253 mMp4FileDataPtr->videoTrackPtr->
3254 chunkTimeMsTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
3255 v_msTrakDuration;
3256 }
3257
3258 if (bAudio)
3259 {
3260 if ((M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable)
3261 || (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->chunkSizeTable)
3262 || (M4OSA_NULL
3263 == mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable)
3264 || (M4OSA_NULL
3265 == mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable)
3266 || (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->TABLE_STTS))
3267 {
3268 mMp4FileDataPtr->fileWriterFunctions->closeWrite(
3269 fileWriterContext); /**< close the stream anyway */
3270 M4MP4W_freeContext(context); /**< Free the context content */
3271 return M4ERR_ALLOC;
3272 }
3273
3274 /*audio microstate*/
3275 mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_closed;
3276
3277 if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType == M4SYS_kAAC)
3278 {
3279 bAAC =
3280 M4OSA_TRUE; /*else, audio is implicitely amr in the following*/
3281 dsi = mMp4FileDataPtr->audioTrackPtr->dsiSize; /*variable size*/
3282
3283 a_esdsSize = 37 + dsi; /* dsi+37*/
3284 a_ESDescriptorSize =
3285 23
3286 + dsi; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
3287 a_DCDescriptorSize = 15 + dsi; /* dsi+15*/
3288
3289 a_esdSize = dsi + 73; /*overwrite a_esdSize with aac value*/
3290 /*add dif. between amr & aac sizes: (- 53 + dsi + 37)*/
3291 a_stsdSize += dsi + 20;
3292 a_stblSize += dsi + 20;
3293 a_minfSize += dsi + 20;
3294 a_mdiaSize += dsi + 20;
3295 a_trakSize += dsi + 20;
3296 moovSize += dsi + 20;
3297 }
3298
3299 if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType
3300 == M4SYS_kEVRC)
3301 {
3302 bEVRC =
3303 M4OSA_TRUE; /*else, audio is implicitely amr in the following*/
3304
3305 /* evrc dsi is only 6 bytes while amr dsi is 9 bytes,all other blocks are unchanged */
3306 a_esdSize -= 3;
3307 a_stsdSize -= 3;
3308 a_stblSize -= 3;
3309 a_minfSize -= 3;
3310 a_mdiaSize -= 3;
3311 a_trakSize -= 3;
3312 moovSize -= 3;
3313 }
3314
3315 if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize == 0)
3316 {
3317 if (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ)
3318 {
3319 mMp4FileDataPtr->fileWriterFunctions->closeWrite(
3320 fileWriterContext); /**< close the stream anyway */
3321 M4MP4W_freeContext(context); /**< Free the context content */
3322 return M4ERR_ALLOC;
3323 }
3324 /*Convert integers in the table from LE into BE*/
3325 M4MP4W_table32ToBE(mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ,
3326 mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb);
3327 a_stszSize +=
3328 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3329 a_stblSize +=
3330 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3331 a_minfSize +=
3332 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3333 a_mdiaSize +=
3334 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3335 a_trakSize +=
3336 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3337 moovSize += 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
3338 }
3339
3340 moovSize += 402;
3341
3342 /*current chunk is the last one and gives the total number of audio chunks (-1)*/
3343 for ( i = 0; i < mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3344 {
3345 a_dataSize += mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
3346 }
3347
3348 #ifndef _M4MP4W_MOOV_FIRST
3349 /*flush chunk*/
3350
3351 if (mMp4FileDataPtr->audioTrackPtr->currentPos > 0)
3352 {
3353 err = M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[0],
3354 mMp4FileDataPtr->audioTrackPtr->currentPos,
3355 mMp4FileDataPtr->fileWriterFunctions,
3356 mMp4FileDataPtr->fileWriterContext);
3357
3358 if (M4NO_ERROR != err)
3359 goto cleanup;
3360 }
3361
3362 M4OSA_TRACE1_0("flush audio | CLOSE");
3363 M4OSA_TRACE1_2("current chunk = %d offset = 0x%x",
3364 mMp4FileDataPtr->audioTrackPtr->currentChunk,
3365 mMp4FileDataPtr->absoluteCurrentPos);
3366
3367 /*update chunk offset*/
3368 mMp4FileDataPtr->audioTrackPtr->
3369 chunkOffsetTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
3370 mMp4FileDataPtr->absoluteCurrentPos;
3371
3372 /*add chunk size to absoluteCurrentPos*/
3373 mMp4FileDataPtr->absoluteCurrentPos +=
3374 mMp4FileDataPtr->audioTrackPtr->currentPos;
3375
3376 #endif /*_M4MP4W_MOOV_FIRST*/
3377
3378 /*update last chunk size, and add this value to a_dataSize*/
3379
3380 mMp4FileDataPtr->audioTrackPtr->
3381 chunkSizeTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
3382 mMp4FileDataPtr->audioTrackPtr->currentPos;
3383 a_dataSize +=
3384 mMp4FileDataPtr->audioTrackPtr->currentPos; /*add last chunk size*/
3385
3386 /* bugfix: if a new chunk was just created, cancel it before to close */
3387 if ((mMp4FileDataPtr->audioTrackPtr->currentChunk != 0)
3388 && (mMp4FileDataPtr->audioTrackPtr->currentPos == 0))
3389 {
3390 mMp4FileDataPtr->audioTrackPtr->currentChunk--;
3391 }
3392 #ifdef _M4MP4W_UNBUFFERED_VIDEO
3393
3394 if ((mMp4FileDataPtr->audioTrackPtr->
3395 chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->
3396 currentStsc] & 0xFFF) == 0)
3397 {
3398 mMp4FileDataPtr->audioTrackPtr->currentStsc--;
3399 }
3400
3401 #endif /*_M4MP4W_UNBUFFERED_VIDEO*/
3402
3403 a_trakDuration = mMp4FileDataPtr->audioTrackPtr->
3404 CommonData.lastCTS; /* equals lastCTS*/
3405 /* add last sample dur */
3406
3407 if (mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb != 1)
3408 {
3409 #ifdef DUPLICATE_STTS_IN_LAST_AU
3410 /*increase of 1 the number of consecutive AUs with same duration*/
3411
3412 mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2
3413 *(mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
3414 - 1) - 2] += 1;
3415
3416 #endif /*DUPLICATE_STTS_IN_LAST_AU*/
3417
3418 a_trakDuration += mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2
3419 * (mMp4FileDataPtr->audioTrackPtr->
3420 CommonData.sttsTableEntryNb - 1) - 1];
3421 }
3422 else if (0 == mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS)
3423 {
3424 if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType
3425 == M4SYS_kAMR)
3426 {
3427 if (12200 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3428 {
3429 a_trakDuration = a_dataSize / 32
3430 * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3431 }
3432 else if (10200 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3433 {
3434 a_trakDuration = a_dataSize / 27
3435 * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3436 }
3437 else if (7950 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3438 {
3439 a_trakDuration = a_dataSize / 21
3440 * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3441 }
3442 else if (7400 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3443 {
3444 a_trakDuration = a_dataSize / 20
3445 * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3446 }
3447 else if (6700 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3448 {
3449 a_trakDuration = a_dataSize / 18
3450 * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3451 }
3452 else if (5900 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3453 {
3454 a_trakDuration = a_dataSize / 16
3455 * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3456 }
3457 else if (5150 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3458 {
3459 a_trakDuration = a_dataSize / 14
3460 * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3461 }
3462 else if (4750 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
3463 {
3464 a_trakDuration = a_dataSize / 13
3465 * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
3466 }
3467 }
3468 }
3469
3470 scale_audio =
3471 1000.0 / mMp4FileDataPtr->audioTrackPtr->CommonData.timescale;
3472 a_msTrakDuration = (M4OSA_UInt32)(a_trakDuration * scale_audio);
3473
3474 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3475 /* stsc update */
3476
3477 a_stscSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3478 a_stblSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3479 a_minfSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3480 a_mdiaSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3481 a_trakSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3482 moovSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
3483
3484 /* stso update */
3485 a_stcoSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3486 a_stblSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3487 a_minfSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3488 a_mdiaSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3489 a_trakSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3490 moovSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3491
3492 #else
3493 /*stsc/stco update*/
3494
3495 a_stscSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3496 a_stcoSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3497 a_stblSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3498 a_minfSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3499 a_mdiaSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3500 a_trakSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3501 moovSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
3502
3503 #endif
3504
3505 /* compute the new size of stts*/
3506
3507 a_sttsSize = 16 + 8 * (mMp4FileDataPtr->audioTrackPtr->
3508 CommonData.sttsTableEntryNb - 1);
3509
3510 moovSize += a_sttsSize - 24;
3511 a_mdiaSize += a_sttsSize - 24;
3512 a_minfSize += a_sttsSize - 24;
3513 a_stblSize += a_sttsSize - 24;
3514 a_trakSize += a_sttsSize - 24;
3515
3516 /*update last chunk time*/
3517 mMp4FileDataPtr->audioTrackPtr->
3518 chunkTimeMsTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
3519 a_msTrakDuration;
3520 }
3521
3522 /* changing the way the mdat size is computed.
3523 The real purpose of the mdat size is to know the amount to skip to get to the next
3524 atom, which is the moov; the size of media in the mdat is almost secondary. Therefore,
3525 it is of utmost importance that the mdat size "points" to where the moov actually
3526 begins. Now, the moov begins right after the last data we wrote, so how could the sum
3527 of all chunk sizes be different from the total size of what has been written? Well, it
3528 can happen when the writing was unexpectedly stopped (because of lack of disk space,
3529 for instance), in this case a chunk may be partially written (the partial write is not
3530 necessarily erased) but it may not be reflected in the chunk size list (which may
3531 believe it hasn't been written or on the contrary that it has been fully written). In
3532 the case of such a mismatch, there is either unused data in the mdat (not very good,
3533 but tolerable) or when reading the last chunk it will read the beginning of the moov
3534 as part of the chunk (which means the last chunk won't be correctly decoded), both of
3535 which are still better than losing the whole recording. In the long run it'll probably
3536 be attempted to always clean up back to a consistent state, but at any rate it is
3537 always safer to have the mdat size be computed using the position where the moov
3538 actually begins, rather than using the size it is thought the mdat has.
3539
3540 Therefore, I will record where we are just before writing the moov, to serve when
3541 updating the mdat size. */
3542
3543 /* mdatSize += a_dataSize + v_dataSize; *//*TODO allow for multiple chunks*/
3544
3545 /* End of Pierre Lebeaupin 19/12/2007: changing the way the mdat size is computed. */
3546
3547 /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
3548 a_trakOffset += moovSize;
3549 v_trakOffset += moovSize/*+ a_dataSize*/;
3550
3551 if (bInterleaveAV == M4OSA_FALSE)
3552 v_trakOffset += a_dataSize;
3553
3554 /*system time since 1970 */
3555 #ifndef _M4MP4W_DONT_USE_TIME_H
3556
3557 time((time_t *)&creationTime);
3558 /*convert into time since 1/1/1904 00h00 (normative)*/
3559 creationTime += 2082841761; /*nb of sec between 1904 and 1970*/
3560
3561 #else /*_M4MP4W_DONT_USE_TIME_H*/
3562
3563 creationTime =
3564 0xBBD09100; /* = 7/11/2003 00h00 ; in hexa because of code scrambler limitation with
3565 large integers */
3566
3567 #endif /*_M4MP4W_DONT_USE_TIME_H*/
3568
3569 mMp4FileDataPtr->duration =
3570 max(a_msTrakDuration, v_msTrakDuration); /*max audio/video*/
3571
3572 #ifdef _M4MP4W_MOOV_FIRST
3573 /*open file in write binary mode*/
3574
3575 err = mMp4FileDataPtr->fileWriterFunctions->openWrite(&fileWriterContext,
3576 mMp4FileDataPtr->url, 0x22);
3577 ERR_CHECK(err == M4NO_ERROR, err);
3578
3579 /*ftyp atom*/
3580 if (mMp4FileDataPtr->ftyp.major_brand != 0)
3581 {
3582 M4OSA_UInt32 i;
3583
3584 /* Put customized ftyp box */
3585 CLEANUPonERR(M4MP4W_putBE32(16
3586 + (mMp4FileDataPtr->ftyp.nbCompatibleBrands * 4),
3587 mMp4FileDataPtr->fileWriterFunctions,
3588 mMp4FileDataPtr->fileWriterContext));
3589 CLEANUPonERR(M4MP4W_putBE32(M4MPAC_FTYP_TAG,
3590 mMp4FileDataPtr->fileWriterFunctions,
3591 mMp4FileDataPtr->fileWriterContext));
3592 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->ftyp.major_brand,
3593 mMp4FileDataPtr->fileWriterFunctions,
3594 mMp4FileDataPtr->fileWriterContext));
3595 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->ftyp.minor_version,
3596 mMp4FileDataPtr->fileWriterFunctions,
3597 mMp4FileDataPtr->fileWriterContext));
3598
3599 for ( i = 0; i < mMp4FileDataPtr->ftyp.nbCompatibleBrands; i++ )
3600 {
3601 CLEANUPonERR(
3602 M4MP4W_putBE32(mMp4FileDataPtr->ftyp.compatible_brands[i],
3603 mMp4FileDataPtr->fileWriterFunctions,
3604 mMp4FileDataPtr->fileWriterContext));
3605 }
3606 }
3607 else
3608 {
3609 /* Put default ftyp box */
3610 CLEANUPonERR(M4MP4W_putBlock(Default_ftyp, sizeof(Default_ftyp),
3611 mMp4FileDataPtr->fileWriterFunctions,
3612 mMp4FileDataPtr->fileWriterContext));
3613 }
3614
3615 #endif /*_M4MP4W_MOOV_FIRST*/
3616
3617 #ifndef _M4MP4W_MOOV_FIRST
3618 /* seek is used to get the current position relative to the start of the file. */
3619 /* ... or rather, seek used to be used for that, but it has been found this functionality
3620 is not reliably, or sometimes not at all, implemented in the various OSALs, so we now avoid
3621 using it. */
3622 /* Notice this new method assumes we're at the end of the file, this will break if ever we
3623 are overwriting a larger file. */
3624
3625 CLEANUPonERR(mMp4FileDataPtr->fileWriterFunctions->getOption(
3626 mMp4FileDataPtr->fileWriterContext,
3627 M4OSA_kFileWriteGetFileSize, (M4OSA_DataOption *) &moovPos));
3628 /* moovPos will be used after writing the moov. */
3629
3630 #endif /*_M4MP4W_MOOV_FIRST*/
3631
3632 CLEANUPonERR(M4MP4W_putBE32(moovSize, mMp4FileDataPtr->fileWriterFunctions,
3633 fileWriterContext));
3634 CLEANUPonERR(M4MP4W_putBlock(CommonBlock3, sizeof(CommonBlock3),
3635 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3636 CLEANUPonERR(M4MP4W_putBE32(creationTime,
3637 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3638 CLEANUPonERR(M4MP4W_putBE32(creationTime,
3639 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3640 CLEANUPonERR(M4MP4W_putBlock(CommonBlock4, sizeof(CommonBlock4),
3641 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3642 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->duration,
3643 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3644 CLEANUPonERR(M4MP4W_putBlock(CommonBlock5, sizeof(CommonBlock5),
3645 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3646
3647 if (bAudio)
3648 {
3649 CLEANUPonERR(M4MP4W_putBE32(a_trakSize,
3650 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3651 CLEANUPonERR(M4MP4W_putBlock(CommonBlock6, sizeof(CommonBlock6),
3652 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3653 CLEANUPonERR(M4MP4W_putBE32(creationTime,
3654 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3655 CLEANUPonERR(M4MP4W_putBE32(creationTime,
3656 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3657 CLEANUPonERR(M4MP4W_putBE32(a_trakId,
3658 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3659 CLEANUPonERR(M4MP4W_putBlock(CommonBlock7, sizeof(CommonBlock7),
3660 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3661 CLEANUPonERR(M4MP4W_putBE32(a_msTrakDuration,
3662 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3663 CLEANUPonERR(M4MP4W_putBlock(CommonBlock7bis, sizeof(CommonBlock7bis),
3664 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3665 CLEANUPonERR(M4MP4W_putBlock(AMRBlock1, sizeof(AMRBlock1),
3666 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3667 CLEANUPonERR(M4MP4W_putBE32(a_mdiaSize,
3668 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3669 CLEANUPonERR(M4MP4W_putBlock(CommonBlock8, sizeof(CommonBlock8),
3670 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3671 CLEANUPonERR(M4MP4W_putBE32(creationTime,
3672 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3673 CLEANUPonERR(M4MP4W_putBE32(creationTime,
3674 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3675 CLEANUPonERR(
3676 M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.timescale,
3677 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3678 CLEANUPonERR(M4MP4W_putBE32(a_trakDuration,
3679 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3680 CLEANUPonERR(M4MP4W_putBlock(CommonBlock9, sizeof(CommonBlock9),
3681 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3682 CLEANUPonERR(M4MP4W_putBlock(AMRBlock1_1, sizeof(AMRBlock1_1),
3683 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3684 CLEANUPonERR(M4MP4W_putBE32(a_minfSize,
3685 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3686 CLEANUPonERR(M4MP4W_putBlock(CommonBlock10, sizeof(CommonBlock10),
3687 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3688 CLEANUPonERR(M4MP4W_putBE32(a_stblSize,
3689 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3690 CLEANUPonERR(M4MP4W_putBlock(CommonBlock11, sizeof(CommonBlock11),
3691 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3692 CLEANUPonERR(M4MP4W_putBE32(a_sttsSize,
3693 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3694 CLEANUPonERR(M4MP4W_putBlock(CommonBlock12, sizeof(CommonBlock12),
3695 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3696
3697 CLEANUPonERR(M4MP4W_putBE32(
3698 mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb - 1,
3699 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3700 /*invert the table data to bigendian*/
3701 M4MP4W_table32ToBE(mMp4FileDataPtr->audioTrackPtr->TABLE_STTS,
3702 2 * (mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
3703 - 1));
3704 CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
3705 *)mMp4FileDataPtr->audioTrackPtr->TABLE_STTS,
3706 ( mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb - 1)
3707 * 8,
3708 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3709
3710 /* stsd */
3711 CLEANUPonERR(M4MP4W_putBE32(a_stsdSize,
3712 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3713 CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionHeader,
3714 sizeof(SampleDescriptionHeader),
3715 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3716 CLEANUPonERR(M4MP4W_putBE32(a_esdSize,
3717 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3718
3719 /* sample desc entry inside stsd */
3720 if (bAAC)
3721 {
3722 CLEANUPonERR(M4MP4W_putBlock(AACBlock1, sizeof(AACBlock1),
3723 mMp4FileDataPtr->fileWriterFunctions,
3724 fileWriterContext)); /*aac*/
3725 }
3726 else if (bEVRC)
3727 {
3728 CLEANUPonERR(M4MP4W_putBlock(EVRC8Block1, sizeof(EVRC8Block1),
3729 mMp4FileDataPtr->fileWriterFunctions,
3730 fileWriterContext)); /*evrc*/
3731 }
3732 else /*AMR8*/
3733 {
3734 CLEANUPonERR(M4MP4W_putBlock(AMR8Block1, sizeof(AMR8Block1),
3735 mMp4FileDataPtr->fileWriterFunctions,
3736 fileWriterContext)); /*amr8*/
3737 }
3738 CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryStart,
3739 sizeof(SampleDescriptionEntryStart),
3740 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3741 CLEANUPonERR(M4MP4W_putBlock(AudioSampleDescEntryBoilerplate,
3742 sizeof(AudioSampleDescEntryBoilerplate),
3743 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3744 CLEANUPonERR(
3745 M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.timescale
3746 << 16,
3747 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3748
3749 /* DSI inside sample desc entry */
3750 if (bAAC)
3751 {
3752 CLEANUPonERR(M4MP4W_putBE32(a_esdsSize,
3753 mMp4FileDataPtr->fileWriterFunctions,
3754 fileWriterContext)); /*aac*/
3755 CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock0,
3756 sizeof(MPEGConfigBlock0), mMp4FileDataPtr->fileWriterFunctions,
3757 fileWriterContext)); /*aac*/
3758 CLEANUPonERR(M4MP4W_putByte(a_ESDescriptorSize,
3759 mMp4FileDataPtr->fileWriterFunctions,
3760 fileWriterContext)); /*aac*/
3761 CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock1,
3762 sizeof(MPEGConfigBlock1), mMp4FileDataPtr->fileWriterFunctions,
3763 fileWriterContext)); /*aac*/
3764 CLEANUPonERR(M4MP4W_putByte(a_DCDescriptorSize,
3765 mMp4FileDataPtr->fileWriterFunctions,
3766 fileWriterContext)); /*aac*/
3767 CLEANUPonERR(M4MP4W_putBlock(AACBlock2, sizeof(AACBlock2),
3768 mMp4FileDataPtr->fileWriterFunctions,
3769 fileWriterContext)); /*aac*/
3770 CLEANUPonERR(
3771 M4MP4W_putBE24(mMp4FileDataPtr->audioTrackPtr->avgBitrate * 5,
3772 mMp4FileDataPtr->fileWriterFunctions,
3773 fileWriterContext)); /*aac*/
3774 CLEANUPonERR(
3775 M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->maxBitrate,
3776 mMp4FileDataPtr->fileWriterFunctions,
3777 fileWriterContext)); /*aac*/
3778 CLEANUPonERR(
3779 M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->avgBitrate,
3780 mMp4FileDataPtr->fileWriterFunctions,
3781 fileWriterContext)); /*aac*/
3782 CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock2,
3783 sizeof(MPEGConfigBlock2), mMp4FileDataPtr->fileWriterFunctions,
3784 fileWriterContext)); /*aac*/
3785 CLEANUPonERR(M4MP4W_putByte(mMp4FileDataPtr->audioTrackPtr->dsiSize,
3786 mMp4FileDataPtr->fileWriterFunctions,
3787 fileWriterContext)); /*aac*/
3788 CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->DSI,
3789 mMp4FileDataPtr->audioTrackPtr->dsiSize,
3790 mMp4FileDataPtr->fileWriterFunctions,
3791 fileWriterContext)); /*aac*/
3792 CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock3,
3793 sizeof(MPEGConfigBlock3), mMp4FileDataPtr->fileWriterFunctions,
3794 fileWriterContext)); /*aac*/
3795 }
3796 else if (bEVRC)
3797 {
3798 M4OSA_UInt8 localDsi[6];
3799 M4OSA_UInt32 localI;
3800
3801 CLEANUPonERR(M4MP4W_putBlock(EVRCBlock3_1, sizeof(EVRCBlock3_1),
3802 mMp4FileDataPtr->fileWriterFunctions,
3803 fileWriterContext)); /*audio*/
3804
3805 /* copy the default block in a local variable*/
3806 for ( localI = 0; localI < 6; localI++ )
3807 {
3808 localDsi[localI] = EVRCBlock3_2[localI];
3809 }
3810 /* computes the number of sample per au */
3811 /* and stores it in the DSI*/
3812 /* assumes a char is enough to store the data*/
3813 localDsi[5] =
3814 (M4OSA_UInt8)(mMp4FileDataPtr->audioTrackPtr->sampleDuration
3815 / 160)/*EVRC 1 frame duration*/;
3816
3817 if (mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL)
3818 {
3819 /* copy vendor name */
3820 for ( localI = 0; localI < 4; localI++ )
3821 {
3822 localDsi[localI] = (M4OSA_UInt8)(
3823 mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
3824 }
3825 }
3826 CLEANUPonERR(M4MP4W_putBlock(localDsi, 6,
3827 mMp4FileDataPtr->fileWriterFunctions,
3828 fileWriterContext)); /*audio*/
3829 }
3830 else /*AMR8*/
3831 {
3832 M4OSA_UInt8 localDsi[9];
3833 M4OSA_UInt32 localI;
3834
3835 CLEANUPonERR(M4MP4W_putBlock(AMRDSIHeader, sizeof(AMRDSIHeader),
3836 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3837
3838 /* copy the default block in a local variable*/
3839 for ( localI = 0; localI < 9; localI++ )
3840 {
3841 localDsi[localI] = AMRDefaultDSI[localI];
3842 }
3843 /* computes the number of sample per au */
3844 /* and stores it in the DSI*/
3845 /* assumes a char is enough to store the data*/
3846 /* ALERT! The potential of the following line of code to explode in our face
3847 is enormous when anything (sample rate or whatever) will change. This
3848 calculation would be MUCH better handled by the VES or whatever deals with
3849 the encoder more directly. */
3850 localDsi[8] =
3851 (M4OSA_UInt8)(mMp4FileDataPtr->audioTrackPtr->sampleDuration
3852 / 160)/*AMR NB 1 frame duration*/;
3853
3854 if (mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL)
3855 {
3856 /* copy vendor name */
3857 for ( localI = 0; localI < 4; localI++ )
3858 {
3859 localDsi[localI] = (M4OSA_UInt8)(
3860 mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
3861 }
3862
3863 /* copy the Mode Set */
3864 for ( localI = 5; localI < 7; localI++ )
3865 {
3866 localDsi[localI] = (M4OSA_UInt8)(
3867 mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
3868 }
3869 }
3870 CLEANUPonERR(M4MP4W_putBlock(localDsi, 9,
3871 mMp4FileDataPtr->fileWriterFunctions,
3872 fileWriterContext)); /*audio*/
3873 }
3874
3875 /*end trak*/
3876 CLEANUPonERR(M4MP4W_putBE32(a_stszSize,
3877 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3878 CLEANUPonERR(M4MP4W_putBlock(CommonBlock15, sizeof(CommonBlock15),
3879 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3880 CLEANUPonERR(M4MP4W_putBE32(
3881 mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize,
3882 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3883 CLEANUPonERR(
3884 M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb,
3885 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3886
3887 /*0 value for samplesize means not constant AU size*/
3888 if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize == 0)
3889 {
3890 CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
3891 *)mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ,
3892 mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb * 4,
3893 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3894 }
3895
3896 CLEANUPonERR(M4MP4W_putBE32(a_stscSize,
3897 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3898 CLEANUPonERR(M4MP4W_putBlock(CommonBlock16, sizeof(CommonBlock16),
3899 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3900
3901 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
3902
3903 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentStsc
3904 + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3905
3906 for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentStsc; i++ )
3907 {
3908 CLEANUPonERR(M4MP4W_putBE32(
3909 ( mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable[i]
3910 >> 12) + 1, mMp4FileDataPtr->fileWriterFunctions,
3911 fileWriterContext));
3912 CLEANUPonERR(M4MP4W_putBE32((mMp4FileDataPtr->audioTrackPtr->
3913 chunkSampleNbTable[i] & 0xFFF),
3914 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3915 CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
3916 fileWriterContext));
3917 }
3918
3919 #else
3920
3921 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentChunk
3922 + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3923
3924 for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3925 {
3926 CLEANUPonERR(M4MP4W_putBE32(i + 1,
3927 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3928 CLEANUPonERR(M4MP4W_putBE32(
3929 mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable[i],
3930 mMp4FileDataPtr->fileWriterFunctions,
3931 fileWriterContext));
3932 CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
3933 fileWriterContext));
3934 }
3935
3936 #endif
3937
3938 CLEANUPonERR(M4MP4W_putBE32(a_stcoSize,
3939 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3940 CLEANUPonERR(M4MP4W_putBlock(CommonBlock17, sizeof(CommonBlock17),
3941 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3942 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentChunk
3943 + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3944
3945 #ifdef _M4MP4W_MOOV_FIRST
3946
3947 for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3948 {
3949 CLEANUPonERR(M4MP4W_putBE32(a_trakOffset,
3950 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3951 a_trakOffset += mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
3952
3953 if (( bInterleaveAV == M4OSA_TRUE)
3954 && (mMp4FileDataPtr->videoTrackPtr->currentChunk >= i))
3955 {
3956 a_trakOffset +=
3957 mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
3958 }
3959 }
3960
3961 #else
3962
3963 for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
3964 {
3965 CLEANUPonERR(M4MP4W_putBE32(
3966 mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable[i],
3967 mMp4FileDataPtr->fileWriterFunctions,
3968 fileWriterContext));
3969 }
3970
3971 #endif /*_M4MP4W_MOOV_FIRST*/
3972
3973 CLEANUPonERR(M4MP4W_putBlock(AMRBlock4, sizeof(AMRBlock4),
3974 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
3975 }
3976
3977 if (bVideo)
3978 {
3979 /*trak*/
3980 CLEANUPonERR(M4MP4W_putBE32(v_trakSize,
3981 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3982 CLEANUPonERR(M4MP4W_putBlock(CommonBlock6, sizeof(CommonBlock6),
3983 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3984 CLEANUPonERR(M4MP4W_putBE32(creationTime,
3985 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3986 CLEANUPonERR(M4MP4W_putBE32(creationTime,
3987 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3988 CLEANUPonERR(M4MP4W_putBE32(v_trakId,
3989 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3990 CLEANUPonERR(M4MP4W_putBlock(CommonBlock7, sizeof(CommonBlock7),
3991 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3992 CLEANUPonERR(M4MP4W_putBE32(v_msTrakDuration,
3993 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3994 CLEANUPonERR(M4MP4W_putBlock(CommonBlock7bis, sizeof(CommonBlock7bis),
3995 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
3996
3997 /* In the track header width and height are 16.16 fixed point values,
3998 so shift left the regular integer value by 16. */
3999 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->width << 16,
4000 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4001 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->height
4002 << 16,
4003 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4004
4005 CLEANUPonERR(M4MP4W_putBE32(v_mdiaSize,
4006 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4007 CLEANUPonERR(M4MP4W_putBlock(CommonBlock8, sizeof(CommonBlock8),
4008 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4009 CLEANUPonERR(M4MP4W_putBE32(creationTime,
4010 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4011 CLEANUPonERR(M4MP4W_putBE32(creationTime,
4012 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4013 CLEANUPonERR(
4014 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->CommonData.timescale,
4015 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4016 CLEANUPonERR(M4MP4W_putBE32(v_trakDuration,
4017 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4018 CLEANUPonERR(M4MP4W_putBlock(CommonBlock9, sizeof(CommonBlock9),
4019 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4020 CLEANUPonERR(M4MP4W_putBlock(VideoBlock1_1, sizeof(VideoBlock1_1),
4021 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4022 CLEANUPonERR(M4MP4W_putBE32(v_minfSize,
4023 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4024 CLEANUPonERR(M4MP4W_putBlock(CommonBlock10, sizeof(CommonBlock10),
4025 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4026 CLEANUPonERR(M4MP4W_putBE32(v_stblSize,
4027 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4028 CLEANUPonERR(M4MP4W_putBlock(CommonBlock11, sizeof(CommonBlock11),
4029 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4030 CLEANUPonERR(M4MP4W_putBE32(v_sttsSize,
4031 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4032 CLEANUPonERR(M4MP4W_putBlock(CommonBlock12, sizeof(CommonBlock12),
4033 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4034 CLEANUPonERR(M4MP4W_putBE32(
4035 mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb,
4036 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4037 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
4038
4039 for ( i = 0;
4040 i < mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb;
4041 i++ )
4042 {
4043 CLEANUPonERR(M4MP4W_putBE32(M4MP4W_get32_Lo(
4044 &mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[i]),
4045 mMp4FileDataPtr->fileWriterFunctions,
4046 fileWriterContext)); /*video*/
4047 CLEANUPonERR(M4MP4W_putBE32(M4MP4W_get32_Hi(
4048 &mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[i]),
4049 mMp4FileDataPtr->fileWriterFunctions,
4050 fileWriterContext)); /*video*/
4051 }
4052
4053 #else
4054
4055 CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
4056 *)mMp4FileDataPtr->videoTrackPtr->TABLE_STTS,
4057 ( mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb) * 8,
4058 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4059
4060 #endif
4061
4062 /* stsd */
4063
4064 CLEANUPonERR(M4MP4W_putBE32(v_stsdSize,
4065 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4066 CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionHeader,
4067 sizeof(SampleDescriptionHeader),
4068 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4069 CLEANUPonERR(M4MP4W_putBE32(v_esdSize,
4070 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4071
4072 /* sample desc entry inside stsd */
4073 if (bMP4V)
4074 {
4075 CLEANUPonERR(M4MP4W_putBlock(Mp4vBlock1, sizeof(Mp4vBlock1),
4076 mMp4FileDataPtr->fileWriterFunctions,
4077 fileWriterContext)); /*mp4v*/
4078 }
4079
4080 if (bH263)
4081 {
4082 CLEANUPonERR(M4MP4W_putBlock(H263Block1, sizeof(H263Block1),
4083 mMp4FileDataPtr->fileWriterFunctions,
4084 fileWriterContext)); /*h263*/
4085 }
4086
4087 if (bH264)
4088 {
4089 CLEANUPonERR(M4MP4W_putBlock(H264Block1, sizeof(H264Block1),
4090 mMp4FileDataPtr->fileWriterFunctions,
4091 fileWriterContext)); /*h264*/
4092 }
4093 CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryStart,
4094 sizeof(SampleDescriptionEntryStart),
4095 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4096 CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryVideoBoilerplate1,
4097 sizeof(SampleDescriptionEntryVideoBoilerplate1),
4098 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4099 CLEANUPonERR(M4MP4W_putBE16(mMp4FileDataPtr->videoTrackPtr->width,
4100 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4101 CLEANUPonERR(M4MP4W_putBE16(mMp4FileDataPtr->videoTrackPtr->height,
4102 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4103 CLEANUPonERR(M4MP4W_putBlock(VideoResolutions, sizeof(VideoResolutions),
4104 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*mp4v*/
4105 CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryVideoBoilerplate2,
4106 sizeof(SampleDescriptionEntryVideoBoilerplate2),
4107 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4108
4109 /* DSI inside sample desc entry */
4110 if (bH263)
4111 {
4112 /* The h263 dsi given through the api must be 7 bytes, that is, it shall not include
4113 the optional bitrate box. However, if the bitrate information is set in the stream
4114 handler, a bitrate box is appended here to the dsi */
4115 if (((M4OSA_Int32)mMp4FileDataPtr->videoTrackPtr->avgBitrate) != -1)
4116 {
4117 CLEANUPonERR(M4MP4W_putBlock(H263Block2_bitr,
4118 sizeof(H263Block2_bitr),
4119 mMp4FileDataPtr->fileWriterFunctions,
4120 fileWriterContext)); /* d263 box with bitr atom */
4121
4122 if (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
4123 {
4124 CLEANUPonERR(M4MP4W_putBlock(H263Block3, sizeof(H263Block3),
4125 mMp4FileDataPtr->fileWriterFunctions,
4126 fileWriterContext)); /*h263*/
4127 }
4128 else
4129 {
4130 CLEANUPonERR(
4131 M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4132 mMp4FileDataPtr->videoTrackPtr->dsiSize,
4133 mMp4FileDataPtr->fileWriterFunctions,
4134 fileWriterContext));
4135 }
4136
4137 CLEANUPonERR(M4MP4W_putBlock(H263Block4, sizeof(H263Block4),
4138 mMp4FileDataPtr->fileWriterFunctions,
4139 fileWriterContext)); /*h263*/
4140 /* Pierre Lebeaupin 2008/04/29: the two following lines used to be swapped;
4141 I changed to this order in order to conform to 3GPP. */
4142 CLEANUPonERR(
4143 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->avgBitrate,
4144 mMp4FileDataPtr->fileWriterFunctions,
4145 fileWriterContext)); /*h263*/
4146 CLEANUPonERR(
4147 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->maxBitrate,
4148 mMp4FileDataPtr->fileWriterFunctions,
4149 fileWriterContext)); /*h263*/
4150 }
4151 else
4152 {
4153 CLEANUPonERR(M4MP4W_putBlock(H263Block2, sizeof(H263Block2),
4154 mMp4FileDataPtr->fileWriterFunctions,
4155 fileWriterContext)); /* d263 box */
4156
4157 if (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
4158 {
4159 CLEANUPonERR(M4MP4W_putBlock(H263Block3, sizeof(H263Block3),
4160 mMp4FileDataPtr->fileWriterFunctions,
4161 fileWriterContext)); /*h263*/
4162 }
4163 else
4164 {
4165 CLEANUPonERR(
4166 M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4167 mMp4FileDataPtr->videoTrackPtr->dsiSize,
4168 mMp4FileDataPtr->fileWriterFunctions,
4169 fileWriterContext));
4170 }
4171 }
4172 }
4173
4174 if (bMP4V)
4175 {
4176 M4OSA_UInt32 bufferSizeDB = 5 * mMp4FileDataPtr->videoTrackPtr->
4177 avgBitrate; /*bufferSizeDB set to 5 times the bitrate*/
4178
4179 CLEANUPonERR(M4MP4W_putBE32(v_esdsSize,
4180 mMp4FileDataPtr->fileWriterFunctions,
4181 fileWriterContext)); /*mp4v*/
4182 CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock0,
4183 sizeof(MPEGConfigBlock0), mMp4FileDataPtr->fileWriterFunctions,
4184 fileWriterContext)); /*mp4v*/
4185 CLEANUPonERR(M4MP4W_putByte(v_ESDescriptorSize,
4186 mMp4FileDataPtr->fileWriterFunctions,
4187 fileWriterContext)); /*mp4v*/
4188 CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock1,
4189 sizeof(MPEGConfigBlock1), mMp4FileDataPtr->fileWriterFunctions,
4190 fileWriterContext)); /*mp4v*/
4191 CLEANUPonERR(M4MP4W_putByte(v_DCDescriptorSize,
4192 mMp4FileDataPtr->fileWriterFunctions,
4193 fileWriterContext)); /*mp4v*/
4194 CLEANUPonERR(M4MP4W_putBlock(Mp4vBlock3, sizeof(Mp4vBlock3),
4195 mMp4FileDataPtr->fileWriterFunctions,
4196 fileWriterContext)); /*mp4v*/
4197 CLEANUPonERR(M4MP4W_putBE24(bufferSizeDB,
4198 mMp4FileDataPtr->fileWriterFunctions,
4199 fileWriterContext)); /*mp4v*/
4200 CLEANUPonERR(
4201 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->maxBitrate,
4202 mMp4FileDataPtr->fileWriterFunctions,
4203 fileWriterContext)); /*mp4v*/
4204 CLEANUPonERR(
4205 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->avgBitrate,
4206 mMp4FileDataPtr->fileWriterFunctions,
4207 fileWriterContext)); /*mp4v*/
4208 CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock2,
4209 sizeof(MPEGConfigBlock2), mMp4FileDataPtr->fileWriterFunctions,
4210 fileWriterContext)); /*mp4v*/
4211 CLEANUPonERR(M4MP4W_putByte(mMp4FileDataPtr->videoTrackPtr->dsiSize,
4212 mMp4FileDataPtr->fileWriterFunctions,
4213 fileWriterContext)); /*mp4v*/
4214 CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4215 mMp4FileDataPtr->videoTrackPtr->dsiSize,
4216 mMp4FileDataPtr->fileWriterFunctions,
4217 fileWriterContext)); /*mp4v*/
4218 CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock3,
4219 sizeof(MPEGConfigBlock3), mMp4FileDataPtr->fileWriterFunctions,
4220 fileWriterContext)); /*mp4v*/
4221 }
4222
4223 if (bH264)
4224 {
4225 M4OSA_UInt16 ppsLentgh = 0; /* PPS length */
4226 M4OSA_UInt16 spsLentgh = 0; /* SPS length */
4227 M4OSA_UChar *tmpDSI = mMp4FileDataPtr->videoTrackPtr->DSI; /* DSI */
4228 M4OSA_UInt16 NumberOfPPS;
4229 M4OSA_UInt16 lCntPPS;
4230
4231 /* Put the avcC (header + DSI) size */
4232 CLEANUPonERR(M4MP4W_putBE32(v_avcCSize,
4233 mMp4FileDataPtr->fileWriterFunctions,
4234 fileWriterContext)); /*h264*/
4235 /* Put the avcC header */
4236 CLEANUPonERR(M4MP4W_putBlock(H264Block2, sizeof(H264Block2),
4237 mMp4FileDataPtr->fileWriterFunctions,
4238 fileWriterContext)); /*h264*/
4239 /* Put the DSI (SPS + PPS) int the 3gp format*/
4240 /* SPS length in BE */
4241
4242 if ((0x01 != mMp4FileDataPtr->videoTrackPtr->DSI[0]) ||
4243 (0x42 != mMp4FileDataPtr->videoTrackPtr->DSI[1]))
4244 {
4245 M4OSA_TRACE1_2("!!! M4MP4W_closeWrite ERROR : invalid AVCC 0x%X 0x%X",
4246 mMp4FileDataPtr->videoTrackPtr->DSI[0],
4247 mMp4FileDataPtr->videoTrackPtr->DSI[1]);
4248 return M4ERR_PARAMETER;
4249 }
4250 // Do not strip the DSI
4251 CLEANUPonERR( M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
4252 mMp4FileDataPtr->videoTrackPtr->dsiSize,
4253 mMp4FileDataPtr->fileWriterFunctions,
4254 fileWriterContext) );/*h264*/
4255
4256 }
4257
4258 /*end trak*/
4259 CLEANUPonERR(M4MP4W_putBE32(v_stszSize,
4260 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4261 CLEANUPonERR(M4MP4W_putBlock(CommonBlock15, sizeof(CommonBlock15),
4262 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4263 CLEANUPonERR(M4MP4W_putBE32(
4264 mMp4FileDataPtr->videoTrackPtr->CommonData.sampleSize,
4265 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4266 CLEANUPonERR(
4267 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb,
4268 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4269 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
4270
4271 for ( i = 0; i < mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb;
4272 i++ )
4273 {
4274 CLEANUPonERR(
4275 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ[i],
4276 mMp4FileDataPtr->fileWriterFunctions,
4277 fileWriterContext)); /*video*/
4278 }
4279
4280 #else
4281
4282 CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
4283 *)mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
4284 mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb * 4,
4285 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4286
4287 #endif
4288
4289 CLEANUPonERR(M4MP4W_putBE32(v_stscSize,
4290 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4291 CLEANUPonERR(M4MP4W_putBlock(CommonBlock16, sizeof(CommonBlock16),
4292 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4293
4294 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
4295
4296 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentStsc
4297 + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4298
4299 for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentStsc; i++ )
4300 {
4301 CLEANUPonERR(M4MP4W_putBE32(
4302 ( mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable[i]
4303 >> 12) + 1, mMp4FileDataPtr->fileWriterFunctions,
4304 fileWriterContext));
4305 CLEANUPonERR(M4MP4W_putBE32((mMp4FileDataPtr->videoTrackPtr->
4306 chunkSampleNbTable[i] & 0xFFF),
4307 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4308 CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
4309 fileWriterContext));
4310 }
4311
4312 #else
4313
4314 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentChunk
4315 + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4316
4317 for (i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++)
4318 {
4319 CLEANUPonERR(M4MP4W_putBE32(i + 1,
4320 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4321 CLEANUPonERR(M4MP4W_putBE32(
4322 mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable[i],
4323 mMp4FileDataPtr->fileWriterFunctions,
4324 fileWriterContext));
4325 CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
4326 fileWriterContext));
4327 }
4328
4329 #endif
4330
4331 CLEANUPonERR(M4MP4W_putBE32(v_stcoSize,
4332 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4333 CLEANUPonERR(M4MP4W_putBlock(CommonBlock17, sizeof(CommonBlock17),
4334 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4335 CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentChunk
4336 + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4337
4338 #ifdef _M4MP4W_MOOV_FIRST
4339
4340 for (i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++)
4341 {
4342 if (( bInterleaveAV == M4OSA_TRUE)
4343 && (mMp4FileDataPtr->audioTrackPtr->currentChunk >= i))
4344 {
4345 v_trakOffset +=
4346 mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
4347 }
4348 CLEANUPonERR(M4MP4W_putBE32(v_trakOffset,
4349 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4350 v_trakOffset += mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
4351 }
4352
4353 #else
4354
4355 for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++ )
4356 {
4357 CLEANUPonERR(M4MP4W_putBE32(
4358 mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable[i],
4359 mMp4FileDataPtr->fileWriterFunctions,
4360 fileWriterContext));
4361 }
4362
4363 #endif /*_M4MP4W_MOOV_FIRST*/
4364
4365 CLEANUPonERR(M4MP4W_putBE32(v_stssSize,
4366 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4367 CLEANUPonERR(M4MP4W_putBlock(VideoBlock4, sizeof(VideoBlock4),
4368 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4369 CLEANUPonERR(
4370 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb,
4371 mMp4FileDataPtr->fileWriterFunctions,
4372 fileWriterContext)); /*video*/
4373 CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
4374 *)mMp4FileDataPtr->videoTrackPtr->TABLE_STSS,
4375 mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb * 4,
4376 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4377 CLEANUPonERR(M4MP4W_putBlock(VideoBlock5, sizeof(VideoBlock5),
4378 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
4379 }
4380 #ifdef _M4MP4W_MOOV_FIRST
4381 /*mdat*/
4382
4383 CLEANUPonERR(M4MP4W_putBE32(mdatSize, mMp4FileDataPtr->fileWriterFunctions,
4384 fileWriterContext));
4385 CLEANUPonERR(M4MP4W_putBlock(CommonBlock2, sizeof(CommonBlock2),
4386 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4387
4388 /*write data, according to the interleave mode (default is not interleaved)*/
4389 if (bInterleaveAV == M4OSA_FALSE)
4390 {
4391 if (bAudio)
4392 {
4393 for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk;
4394 i++ )
4395 {
4396 CLEANUPonERR(
4397 M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[i],
4398 mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i],
4399 mMp4FileDataPtr->fileWriterFunctions,
4400 fileWriterContext)); /*audio (previously a_dataSize)*/
4401 }
4402 }
4403
4404 if (bVideo)
4405 {
4406 for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk;
4407 i++ )
4408 {
4409 CLEANUPonERR(
4410 M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[i],
4411 mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i],
4412 mMp4FileDataPtr->fileWriterFunctions,
4413 fileWriterContext)); /*video (previously a_dataSize)*/
4414 }
4415 }
4416 }
4417 else /*in this mode, we have audio and video to interleave*/
4418 {
4419 for ( i = 0; i <= max(mMp4FileDataPtr->audioTrackPtr->currentChunk,
4420 mMp4FileDataPtr->videoTrackPtr->currentChunk); i++ )
4421 {
4422 if (i <= mMp4FileDataPtr->audioTrackPtr->currentChunk)
4423 {
4424 CLEANUPonERR(
4425 M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[i],
4426 mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i],
4427 mMp4FileDataPtr->fileWriterFunctions,
4428 fileWriterContext)); /*audio (previously a_dataSize)*/
4429 }
4430
4431 if (i <= mMp4FileDataPtr->videoTrackPtr->currentChunk)
4432 {
4433 CLEANUPonERR(
4434 M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[i],
4435 mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i],
4436 mMp4FileDataPtr->fileWriterFunctions,
4437 fileWriterContext)); /*video (previously a_dataSize)*/
4438 }
4439 }
4440 }
4441
4442 #endif /*_M4MP4W_MOOV_FIRST*/
4443
4444 /*skip*/
4445
4446 CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipHeader,
4447 sizeof(BlockSignatureSkipHeader), mMp4FileDataPtr->fileWriterFunctions,
4448 fileWriterContext));
4449
4450 /* Write embedded string */
4451 if (mMp4FileDataPtr->embeddedString == M4OSA_NULL)
4452 {
4453 CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipDefaultEmbeddedString,
4454 sizeof(BlockSignatureSkipDefaultEmbeddedString),
4455 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4456 }
4457 else
4458 {
4459 CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->embeddedString, 16,
4460 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4461 }
4462
4463 /* Write ves core version */
4464 camcoder_maj = (M4OSA_UChar)(mMp4FileDataPtr->camcoderVersion / 100);
4465 camcoder_min =
4466 (M4OSA_UChar)(( mMp4FileDataPtr->camcoderVersion - 100 * camcoder_maj)
4467 / 10);
4468 camcoder_rev =
4469 (M4OSA_UChar)(mMp4FileDataPtr->camcoderVersion - 100 * camcoder_maj - 10
4470 * camcoder_min);
4471
4472 CLEANUPonERR(M4MP4W_putByte(' ', mMp4FileDataPtr->fileWriterFunctions,
4473 fileWriterContext));
4474 CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_maj + '0'),
4475 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4476 CLEANUPonERR(M4MP4W_putByte('.', mMp4FileDataPtr->fileWriterFunctions,
4477 fileWriterContext));
4478 CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_min + '0'),
4479 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4480 CLEANUPonERR(M4MP4W_putByte('.', mMp4FileDataPtr->fileWriterFunctions,
4481 fileWriterContext));
4482 CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_rev + '0'),
4483 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4484
4485 /* Write integration tag */
4486 CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar *)" -- ", 4,
4487 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4488
4489 if (mMp4FileDataPtr->integrationTag == M4OSA_NULL)
4490 {
4491 CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipDefaultIntegrationTag,
4492 sizeof(BlockSignatureSkipDefaultIntegrationTag),
4493 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4494 }
4495 else
4496 {
4497 CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->integrationTag, 60,
4498 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
4499 }
4500
4501 #ifndef _M4MP4W_MOOV_FIRST
4502 /*overwrite mdat size*/
4503
4504 if (mMp4FileDataPtr->ftyp.major_brand != 0)
4505 mdatPos= 16 + mMp4FileDataPtr->ftyp.nbCompatibleBrands * 4;
4506 else
4507 mdatPos = 24;
4508
4509 moovPos = moovPos - mdatPos;
4510 mdatSize = moovPos;
4511
4512 CLEANUPonERR(mMp4FileDataPtr->fileWriterFunctions->seek(fileWriterContext,
4513 M4OSA_kFileSeekBeginning, &mdatPos)); /*seek after ftyp...*/
4514 CLEANUPonERR(M4MP4W_putBE32(mdatSize, mMp4FileDataPtr->fileWriterFunctions,
4515 fileWriterContext));
4516
4517 #endif /*_M4MP4W_MOOV_FIRST*/
4518
4519 cleanup:
4520
4521 /**
4522 * Close the file even if an error occured */
4523 if (M4OSA_NULL != mMp4FileDataPtr->fileWriterContext)
4524 {
4525 err2 =
4526 mMp4FileDataPtr->fileWriterFunctions->closeWrite(mMp4FileDataPtr->
4527 fileWriterContext); /**< close the stream anyway */
4528
4529 if (M4NO_ERROR != err2)
4530 {
4531 M4OSA_TRACE1_1(
4532 "M4MP4W_closeWrite: fileWriterFunctions->closeWrite returns 0x%x",
4533 err2);
4534 }
4535 mMp4FileDataPtr->fileWriterContext = M4OSA_NULL;
4536 }
4537
4538 #ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
4539 /* Remove safety file if still present (here it is cleanup in case of error and NOT the normal
4540 removal of the safety file to free emergency space for the moov). */
4541
4542 if (M4OSA_TRUE == mMp4FileDataPtr->cleanSafetyFile)
4543 {
4544 M4OSA_Context tempContext;
4545 err3 = mMp4FileDataPtr->fileWriterFunctions->openWrite(&tempContext,
4546 mMp4FileDataPtr->safetyFileUrl,
4547 M4OSA_kFileWrite | M4OSA_kFileCreate);
4548
4549 if (M4NO_ERROR != err2)
4550 err2 = err3;
4551
4552 if (M4NO_ERROR
4553 != err3) /* No sense closing if we couldn't open in the first place. */
4554 {
4555 err3 =
4556 mMp4FileDataPtr->fileWriterFunctions->closeWrite(tempContext);
4557
4558 if (M4NO_ERROR != err2)
4559 err2 = err3;
4560 }
4561 mMp4FileDataPtr->safetyFileUrl = M4OSA_NULL;
4562 mMp4FileDataPtr->cleanSafetyFile = M4OSA_FALSE;
4563 }
4564
4565 #endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
4566
4567 /* Delete embedded string */
4568
4569 if (M4OSA_NULL != mMp4FileDataPtr->embeddedString)
4570 {
4571 free(mMp4FileDataPtr->embeddedString);
4572 mMp4FileDataPtr->embeddedString = M4OSA_NULL;
4573 }
4574
4575 /* Delete integration tag */
4576 if (M4OSA_NULL != mMp4FileDataPtr->integrationTag)
4577 {
4578 free(mMp4FileDataPtr->integrationTag);
4579 mMp4FileDataPtr->integrationTag = M4OSA_NULL;
4580 }
4581
4582 /**
4583 * M4MP4W_freeContext() is now a private method, called only from here*/
4584 err3 = M4MP4W_freeContext(context);
4585
4586 if (M4NO_ERROR != err3)
4587 {
4588 M4OSA_TRACE1_1("M4MP4W_closeWrite: M4MP4W_freeContext returns 0x%x",
4589 err3);
4590 }
4591
4592 /**
4593 * Choose which error code to return */
4594 if (M4NO_ERROR != err)
4595 {
4596 /**
4597 * We give priority to main error */
4598 M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err=0x%x", err);
4599 return err;
4600 }
4601 else if (M4NO_ERROR != err2)
4602 {
4603 /**
4604 * Error from closeWrite is returned if there is no main error */
4605 M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err2=0x%x", err2);
4606 return err2;
4607 }
4608 else
4609 {
4610 /**
4611 * Error from M4MP4W_freeContext is returned only if there is no main error and
4612 no close error */
4613 M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err3=0x%x", err3);
4614 return err3;
4615 }
4616 }
4617
4618 /*******************************************************************************/
M4MP4W_getOption(M4OSA_Context context,M4OSA_OptionID option,M4OSA_DataOption * valuePtr)4619 M4OSA_ERR M4MP4W_getOption( M4OSA_Context context, M4OSA_OptionID option,
4620 M4OSA_DataOption *valuePtr )
4621 /*******************************************************************************/
4622 {
4623 M4OSA_ERR err = M4NO_ERROR;
4624
4625 M4SYS_StreamIDValue *streamIDvaluePtr = M4OSA_NULL;
4626 M4MP4W_StreamIDsize *streamIDsizePtr = M4OSA_NULL;
4627 M4MP4W_memAddr *memAddrPtr = M4OSA_NULL;
4628 /* M4MP4W_WriteCallBack* callBackPtr = M4OSA_NULL;*/
4629
4630 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
4631 ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
4632
4633 ERR_CHECK(( mMp4FileDataPtr->state == M4MP4W_opened)
4634 || (mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
4635
4636 switch( option )
4637 {
4638 case (M4MP4W_maxAUperChunk):
4639 return M4ERR_NOT_IMPLEMENTED;
4640
4641 case (M4MP4W_maxChunkSize):
4642
4643 streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4644
4645 switch( streamIDvaluePtr->streamID )
4646 {
4647 case (AudioStreamID):
4648 if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
4649 return M4ERR_BAD_STREAM_ID;
4650 else
4651 streamIDvaluePtr->value =
4652 mMp4FileDataPtr->audioTrackPtr->MaxChunkSize;
4653 break;
4654
4655 case (VideoStreamID):
4656 if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
4657 return M4ERR_BAD_STREAM_ID;
4658 else
4659 streamIDvaluePtr->value =
4660 mMp4FileDataPtr->videoTrackPtr->MaxChunkSize;
4661 break;
4662
4663 case (0): /*all streams*/
4664 streamIDvaluePtr->value = mMp4FileDataPtr->MaxChunkSize;
4665 break;
4666
4667 default:
4668 return M4ERR_BAD_STREAM_ID;
4669 }
4670
4671 break;
4672
4673 case (M4MP4W_maxChunkInter):
4674
4675 streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4676
4677 switch( streamIDvaluePtr->streamID )
4678 {
4679 case (0): /*all streams*/
4680 streamIDvaluePtr->value = (M4OSA_UInt32)mMp4FileDataPtr->
4681 InterleaveDur; /*time conversion !*/
4682 break;
4683
4684 default:
4685 return M4ERR_BAD_STREAM_ID;
4686 }
4687 break;
4688
4689 case (M4MP4W_embeddedString):
4690 memAddrPtr = (M4MP4W_memAddr *)(*valuePtr);
4691 /*memAddrPtr must have been already allocated by the caller
4692 and memAddrPtr->size initialized with the max possible length in bytes*/
4693 ERR_CHECK(memAddrPtr->size >= 16, M4ERR_PARAMETER);
4694 ERR_CHECK(memAddrPtr->addr != M4OSA_NULL, M4ERR_PARAMETER);
4695 /*memAddrPtr->size is updated with the actual size of the string*/
4696 memAddrPtr->size = 16;
4697 /*if no value was set, return the default string */
4698 if (mMp4FileDataPtr->embeddedString != M4OSA_NULL)
4699 memcpy((void *)memAddrPtr->addr,
4700 (void *)mMp4FileDataPtr->embeddedString, 16);
4701 else
4702 memcpy((void *)memAddrPtr->addr,
4703 (void *)BlockSignatureSkipDefaultEmbeddedString,
4704 16);
4705 break;
4706
4707 case (M4MP4W_integrationTag):
4708 memAddrPtr = (M4MP4W_memAddr *)(*valuePtr);
4709 /*memAddrPtr must have been already allocated by the caller
4710 and memAddrPtr->size initialized with the max possible length in bytes*/
4711 ERR_CHECK(memAddrPtr->size >= 60, M4ERR_PARAMETER);
4712 ERR_CHECK(memAddrPtr->addr != M4OSA_NULL, M4ERR_PARAMETER);
4713 /*memAddrPtr->size is updated with the actual size of the string*/
4714 memAddrPtr->size = 60;
4715 /*if no value was set, return the default string 0 */
4716 if (mMp4FileDataPtr->integrationTag != M4OSA_NULL)
4717 memcpy((void *)memAddrPtr->addr,
4718 (void *)mMp4FileDataPtr->integrationTag, 60);
4719 else
4720 memcpy((void *)memAddrPtr->addr,
4721 (void *)BlockSignatureSkipDefaultIntegrationTag,
4722 60);
4723 break;
4724
4725 case (M4MP4W_CamcoderVersion):
4726
4727 streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4728
4729 switch( streamIDvaluePtr->streamID )
4730 {
4731 case (0): /*all streams*/
4732 streamIDvaluePtr->value = mMp4FileDataPtr->camcoderVersion;
4733 break;
4734
4735 default:
4736 return M4ERR_BAD_STREAM_ID;
4737 }
4738 break;
4739
4740 case (M4MP4W_preWriteCallBack):
4741 return M4ERR_NOT_IMPLEMENTED;
4742 /*callBackPtr = (M4MP4W_WriteCallBack*)(*valuePtr);
4743 *callBackPtr = mMp4FileDataPtr->PreWriteCallBack;
4744 break;*/
4745
4746 case (M4MP4W_postWriteCallBack):
4747 return M4ERR_NOT_IMPLEMENTED;
4748 /*callBackPtr = (M4MP4W_WriteCallBack*)(*valuePtr);
4749 *callBackPtr = mMp4FileDataPtr->PostWriteCallBack;
4750 break;*/
4751
4752 case (M4MP4W_maxAUsize):
4753
4754 streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4755
4756 switch( streamIDvaluePtr->streamID )
4757 {
4758 case (AudioStreamID):
4759 if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
4760 return M4ERR_BAD_STREAM_ID;
4761 else
4762 streamIDvaluePtr->value =
4763 mMp4FileDataPtr->audioTrackPtr->MaxAUSize;
4764 break;
4765
4766 case (VideoStreamID):
4767 if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
4768 return M4ERR_BAD_STREAM_ID;
4769 else
4770 streamIDvaluePtr->value =
4771 mMp4FileDataPtr->videoTrackPtr->MaxAUSize;
4772 break;
4773
4774 case (0): /*all streams*/
4775 streamIDvaluePtr->value = mMp4FileDataPtr->MaxAUSize;
4776 break;
4777
4778 default:
4779 return M4ERR_BAD_STREAM_ID;
4780 }
4781
4782 break;
4783
4784 case (M4MP4W_IOD):
4785 return M4ERR_NOT_IMPLEMENTED;
4786
4787 case (M4MP4W_ESD):
4788 return M4ERR_NOT_IMPLEMENTED;
4789
4790 case (M4MP4W_SDP):
4791 return M4ERR_NOT_IMPLEMENTED;
4792
4793 case (M4MP4W_trackSize):
4794 streamIDsizePtr = (M4MP4W_StreamIDsize *)(*valuePtr);
4795 streamIDsizePtr->width = mMp4FileDataPtr->videoTrackPtr->width;
4796 streamIDsizePtr->height = mMp4FileDataPtr->videoTrackPtr->height;
4797 break;
4798
4799 case (M4MP4W_estimateAudioSize):
4800 streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
4801 streamIDvaluePtr->value =
4802 (M4OSA_UInt32)mMp4FileDataPtr->estimateAudioSize;
4803 break;
4804
4805 case (M4MP4W_MOOVfirst):
4806 return M4ERR_NOT_IMPLEMENTED;
4807
4808 case (M4MP4W_V2_MOOF):
4809 return M4ERR_NOT_IMPLEMENTED;
4810
4811 case (M4MP4W_V2_tblCompres):
4812 return M4ERR_NOT_IMPLEMENTED;
4813
4814 default:
4815 return M4ERR_BAD_OPTION_ID;
4816 }
4817
4818 return err;
4819 }
4820
4821 /*******************************************************************************/
M4MP4W_setOption(M4OSA_Context context,M4OSA_OptionID option,M4OSA_DataOption value)4822 M4OSA_ERR M4MP4W_setOption( M4OSA_Context context, M4OSA_OptionID option,
4823 M4OSA_DataOption value )
4824 /*******************************************************************************/
4825 {
4826 M4OSA_ERR err = M4NO_ERROR;
4827
4828 M4SYS_StreamIDValue *streamIDvaluePtr = M4OSA_NULL;
4829 M4MP4W_StreamIDsize *streamIDsizePtr = M4OSA_NULL;
4830 M4MP4W_memAddr *memAddrPtr = M4OSA_NULL;
4831 M4SYS_StreamIDmemAddr *streamIDmemAddrPtr;
4832
4833 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
4834 ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
4835
4836 /* Verify state */
4837 switch( option )
4838 {
4839 case M4MP4W_maxFileDuration:
4840 case M4MP4W_DSI:
4841 /* this param can be set at the end of a recording */
4842 ERR_CHECK((mMp4FileDataPtr->state != M4MP4W_closed), M4ERR_STATE);
4843 break;
4844
4845 case M4MP4W_setFtypBox:
4846 /* this param can only be set before starting any write */
4847 ERR_CHECK(mMp4FileDataPtr->state == M4MP4W_opened, M4ERR_STATE);
4848 break;
4849
4850 default:
4851 /* in general params can be set at open or ready stage */
4852 ERR_CHECK(( mMp4FileDataPtr->state == M4MP4W_opened)
4853 || (mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
4854 }
4855
4856 /* Set option */
4857 switch( option )
4858 {
4859 case (M4MP4W_maxAUperChunk):
4860 return M4ERR_NOT_IMPLEMENTED;
4861
4862 case (M4MP4W_maxChunkSize):
4863
4864 streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
4865
4866 switch( streamIDvaluePtr->streamID )
4867 {
4868 case (AudioStreamID):
4869 if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
4870 return
4871 M4ERR_BAD_STREAM_ID; /*maybe the stream has not been added yet*/
4872 else
4873 {
4874 mMp4FileDataPtr->audioTrackPtr->MaxChunkSize =
4875 streamIDvaluePtr->value;
4876 }
4877
4878 break;
4879
4880 case (VideoStreamID):
4881 if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
4882 return
4883 M4ERR_BAD_STREAM_ID; /*maybe the stream has not been added yet*/
4884 else
4885 {
4886 mMp4FileDataPtr->videoTrackPtr->MaxChunkSize =
4887 streamIDvaluePtr->value;
4888 }
4889 break;
4890
4891 case (0): /*all streams*/
4892
4893 /*In M4MP4W_opened state, no stream is present yet, so only global value
4894 needs to be updated.*/
4895 mMp4FileDataPtr->MaxChunkSize = streamIDvaluePtr->value;
4896
4897 if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
4898 {
4899 mMp4FileDataPtr->audioTrackPtr->MaxChunkSize =
4900 streamIDvaluePtr->value;
4901 }
4902
4903 if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
4904 {
4905 mMp4FileDataPtr->videoTrackPtr->MaxChunkSize =
4906 streamIDvaluePtr->value;
4907 }
4908 break;
4909
4910 default:
4911 return M4ERR_BAD_STREAM_ID;
4912 }
4913 break;
4914
4915 case (M4MP4W_maxChunkInter):
4916
4917 streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
4918
4919 switch( streamIDvaluePtr->streamID )
4920 {
4921 case (0): /*all streams*/
4922 mMp4FileDataPtr->InterleaveDur =
4923 (M4MP4W_Time32)streamIDvaluePtr->
4924 value; /*time conversion!*/
4925 break;
4926
4927 default:
4928 return M4ERR_BAD_STREAM_ID;
4929 /*not meaningfull to set this parameter on a streamID basis*/
4930 }
4931 break;
4932
4933 case (M4MP4W_maxFileSize):
4934 mMp4FileDataPtr->MaxFileSize = *(M4OSA_UInt32 *)value;
4935 break;
4936
4937 case (M4MP4W_embeddedString):
4938 memAddrPtr = (M4MP4W_memAddr *)value;
4939 /*
4940 * If memAddrPtr->size > 16 bytes, then the string will be truncated.
4941 * If memAddrPtr->size < 16 bytes, then return M4ERR_PARAMETER
4942 */
4943 ERR_CHECK(memAddrPtr->size >= 16, M4ERR_PARAMETER);
4944
4945 if (mMp4FileDataPtr->embeddedString == M4OSA_NULL)
4946 {
4947 mMp4FileDataPtr->embeddedString =
4948 (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(16, M4MP4_WRITER,
4949 (M4OSA_Char *)"embeddedString");
4950 ERR_CHECK(mMp4FileDataPtr->embeddedString != M4OSA_NULL,
4951 M4ERR_ALLOC);
4952 }
4953 /*else, just overwrite the previously set string*/
4954 memcpy((void *)mMp4FileDataPtr->embeddedString,
4955 (void *)memAddrPtr->addr, 16);
4956 break;
4957
4958 case (M4MP4W_integrationTag):
4959 memAddrPtr = (M4MP4W_memAddr *)value;
4960 /*
4961 * If memAddrPtr->size > 60 bytes, then the string will be truncated.
4962 * If memAddrPtr->size < 60 bytes, then pad with 0
4963 */
4964 if (mMp4FileDataPtr->integrationTag == M4OSA_NULL)
4965 {
4966 mMp4FileDataPtr->integrationTag =
4967 (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(60, M4MP4_WRITER,
4968 (M4OSA_Char *)"integrationTag");
4969 ERR_CHECK(mMp4FileDataPtr->integrationTag != M4OSA_NULL,
4970 M4ERR_ALLOC);
4971 }
4972 /*else, just overwrite the previously set string*/
4973 if (memAddrPtr->size < 60)
4974 {
4975 memcpy((void *)mMp4FileDataPtr->integrationTag,
4976 (void *)BlockSignatureSkipDefaultIntegrationTag,
4977 60);
4978 memcpy((void *)mMp4FileDataPtr->integrationTag,
4979 (void *)memAddrPtr->addr, memAddrPtr->size);
4980 }
4981 else
4982 {
4983 memcpy((void *)mMp4FileDataPtr->integrationTag,
4984 (void *)memAddrPtr->addr, 60);
4985 }
4986 break;
4987
4988 case (M4MP4W_CamcoderVersion):
4989
4990 streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
4991
4992 switch( streamIDvaluePtr->streamID )
4993 {
4994 case (0): /*all streams*/
4995 mMp4FileDataPtr->camcoderVersion = streamIDvaluePtr->value;
4996 break;
4997
4998 default:
4999 return M4ERR_BAD_STREAM_ID;
5000 /*not meaningfull to set this parameter on a streamID basis*/
5001 }
5002 break;
5003
5004 case (M4MP4W_preWriteCallBack):
5005 return M4ERR_NOT_IMPLEMENTED;
5006 /*mMp4FileDataPtr->PreWriteCallBack = *(M4MP4W_WriteCallBack*)value;
5007 break;*/
5008
5009 case (M4MP4W_postWriteCallBack):
5010 return M4ERR_NOT_IMPLEMENTED;
5011 /*mMp4FileDataPtr->PostWriteCallBack = *(M4MP4W_WriteCallBack*)value;
5012 break;*/
5013
5014 case (M4MP4W_maxAUsize):
5015
5016 streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
5017
5018 switch( streamIDvaluePtr->streamID )
5019 {
5020 case (AudioStreamID):
5021
5022 /*if (mMp4FileDataPtr->audioTrackPtr == M4OSA_NULL)*/
5023 if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
5024 return M4ERR_BAD_STREAM_ID;
5025 else
5026 mMp4FileDataPtr->audioTrackPtr->MaxAUSize =
5027 streamIDvaluePtr->value;
5028 break;
5029
5030 case (VideoStreamID):
5031
5032 /*if (mMp4FileDataPtr->videoTrackPtr == M4OSA_NULL)*/
5033 if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
5034 return M4ERR_BAD_STREAM_ID;
5035 else
5036 mMp4FileDataPtr->videoTrackPtr->MaxAUSize =
5037 streamIDvaluePtr->value;
5038 break;
5039
5040 case (0): /*all streams*/
5041
5042 mMp4FileDataPtr->MaxAUSize = streamIDvaluePtr->value;
5043
5044 if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
5045 mMp4FileDataPtr->audioTrackPtr->MaxAUSize =
5046 streamIDvaluePtr->value;
5047
5048 if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
5049 mMp4FileDataPtr->videoTrackPtr->MaxAUSize =
5050 streamIDvaluePtr->value;
5051
5052 break;
5053
5054 default:
5055 return M4ERR_BAD_STREAM_ID;
5056 }
5057 break;
5058
5059 case (M4MP4W_IOD):
5060 return M4ERR_NOT_IMPLEMENTED;
5061
5062 case (M4MP4W_ESD):
5063 return M4ERR_NOT_IMPLEMENTED;
5064
5065 case (M4MP4W_SDP):
5066 return M4ERR_NOT_IMPLEMENTED;
5067
5068 case (M4MP4W_trackSize):
5069
5070 streamIDsizePtr = (M4MP4W_StreamIDsize *)value;
5071
5072 if ((streamIDsizePtr->streamID != VideoStreamID)
5073 || (mMp4FileDataPtr->hasVideo == M4OSA_FALSE))
5074 return M4ERR_BAD_STREAM_ID;
5075 else
5076 {
5077 mMp4FileDataPtr->videoTrackPtr->width = streamIDsizePtr->width;
5078 mMp4FileDataPtr->videoTrackPtr->height =
5079 streamIDsizePtr->height;
5080 }
5081 break;
5082
5083 case (M4MP4W_estimateAudioSize):
5084
5085 streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
5086
5087 /*shall not set this option before audio and video streams were added*/
5088 /*nonsense to set this option if not in case audio+video*/
5089 if ((mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
5090 || (mMp4FileDataPtr->hasVideo == M4OSA_FALSE))
5091 return M4ERR_STATE;
5092
5093 mMp4FileDataPtr->estimateAudioSize =
5094 (M4OSA_Bool)streamIDvaluePtr->value;
5095 break;
5096
5097 case (M4MP4W_MOOVfirst):
5098 return M4ERR_NOT_IMPLEMENTED;
5099
5100 case (M4MP4W_V2_MOOF):
5101 return M4ERR_NOT_IMPLEMENTED;
5102
5103 case (M4MP4W_V2_tblCompres):
5104 return M4ERR_NOT_IMPLEMENTED;
5105
5106 case (M4MP4W_maxFileDuration):
5107 mMp4FileDataPtr->MaxFileDuration = *(M4OSA_UInt32 *)value;
5108 break;
5109
5110 case (M4MP4W_setFtypBox):
5111 {
5112 M4OSA_UInt32 size;
5113
5114 ERR_CHECK(( (M4MP4C_FtypBox *)value)->major_brand != 0,
5115 M4ERR_PARAMETER);
5116
5117 /* Copy structure */
5118 mMp4FileDataPtr->ftyp = *(M4MP4C_FtypBox *)value;
5119
5120 /* Update global position variables with the difference between common and
5121 user block */
5122 size =
5123 mMp4FileDataPtr->ftyp.nbCompatibleBrands * sizeof(M4OSA_UInt32);
5124
5125 mMp4FileDataPtr->absoluteCurrentPos = 8/*mdat*/ + 16 + size;
5126 mMp4FileDataPtr->filesize = 218/*mdat+moov+skip*/ + 16 + size;
5127 }
5128 break;
5129
5130 case (M4MP4W_DSI):
5131 {
5132 streamIDmemAddrPtr = (M4SYS_StreamIDmemAddr *)value;
5133
5134 /* Nested switch! Whee! */
5135 switch( streamIDmemAddrPtr->streamID )
5136 {
5137 case (AudioStreamID):
5138 return M4ERR_NOT_IMPLEMENTED;
5139
5140 case (VideoStreamID):
5141
5142 /* Protect DSI setting : only once allowed on a given stream */
5143
5144 switch( mMp4FileDataPtr->videoTrackPtr->
5145 CommonData.trackType )
5146 {
5147 case M4SYS_kH263:
5148 if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
5149 || (M4OSA_NULL
5150 != mMp4FileDataPtr->videoTrackPtr->DSI))
5151 {
5152 M4OSA_TRACE1_0(
5153 "M4MP4W_setOption: dsi already set !");
5154 return M4ERR_STATE;
5155 }
5156
5157 if ((0 == streamIDmemAddrPtr->size)
5158 || (M4OSA_NULL == streamIDmemAddrPtr->addr))
5159 {
5160 M4OSA_TRACE1_0(
5161 "M4MP4W_setOption: Bad H263 dsi!");
5162 return M4ERR_PARAMETER;
5163 }
5164
5165 /*decoder specific info size is supposed to be always 7
5166 bytes long */
5167 ERR_CHECK(streamIDmemAddrPtr->size == 7,
5168 M4ERR_PARAMETER);
5169 mMp4FileDataPtr->videoTrackPtr->dsiSize =
5170 (M4OSA_UInt8)streamIDmemAddrPtr->size;
5171 mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
5172 *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
5173 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
5174 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
5175 != M4OSA_NULL, M4ERR_ALLOC);
5176 memcpy(
5177 (void *)mMp4FileDataPtr->videoTrackPtr->
5178 DSI,
5179 (void *)streamIDmemAddrPtr->addr,
5180 streamIDmemAddrPtr->size);
5181
5182 break;
5183
5184 case M4SYS_kMPEG_4:
5185 if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
5186 || (M4OSA_NULL
5187 != mMp4FileDataPtr->videoTrackPtr->DSI))
5188 {
5189 M4OSA_TRACE1_0(
5190 "M4MP4W_setOption: dsi already set !");
5191 return M4ERR_STATE;
5192 }
5193
5194 if ((0 == streamIDmemAddrPtr->size)
5195 || (M4OSA_NULL == streamIDmemAddrPtr->addr))
5196 {
5197 M4OSA_TRACE1_0(
5198 "M4MP4W_setOption: Bad MPEG4 dsi!");
5199 return M4ERR_PARAMETER;
5200 }
5201
5202 /*MP4V specific*/
5203 ERR_CHECK(streamIDmemAddrPtr->size < 105,
5204 M4ERR_PARAMETER);
5205 mMp4FileDataPtr->videoTrackPtr->dsiSize =
5206 (M4OSA_UInt8)streamIDmemAddrPtr->size;
5207 mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
5208 *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
5209 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
5210 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
5211 != M4OSA_NULL, M4ERR_ALLOC);
5212 memcpy(
5213 (void *)mMp4FileDataPtr->videoTrackPtr->
5214 DSI,
5215 (void *)streamIDmemAddrPtr->addr,
5216 streamIDmemAddrPtr->size);
5217 mMp4FileDataPtr->filesize +=
5218 streamIDmemAddrPtr->size;
5219
5220 break;
5221
5222 case M4SYS_kH264:
5223 if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
5224 || (M4OSA_NULL
5225 != mMp4FileDataPtr->videoTrackPtr->DSI))
5226 {
5227 /* + H.264 trimming */
5228 if (M4OSA_TRUE == mMp4FileDataPtr->bMULPPSSPS)
5229 {
5230 free(mMp4FileDataPtr->videoTrackPtr->DSI);
5231
5232 // Do not strip the DSI
5233 /* Store the DSI size */
5234 mMp4FileDataPtr->videoTrackPtr->dsiSize =
5235 (M4OSA_UInt8)streamIDmemAddrPtr->size;
5236 M4OSA_TRACE1_1("M4MP4W_setOption: in set option DSI size =%d"\
5237 ,mMp4FileDataPtr->videoTrackPtr->dsiSize);
5238 /* Copy the DSI (SPS + PPS) */
5239 mMp4FileDataPtr->videoTrackPtr->DSI =
5240 (M4OSA_UChar*)M4OSA_32bitAlignedMalloc(
5241 streamIDmemAddrPtr->size, M4MP4_WRITER,
5242 (M4OSA_Char *)"videoTrackPtr->DSI");
5243 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI !=
5244 M4OSA_NULL, M4ERR_ALLOC);
5245 memcpy(
5246 (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
5247 (void *)streamIDmemAddrPtr->addr,
5248 streamIDmemAddrPtr->size);
5249
5250 break;
5251 /* - H.264 trimming */
5252 }
5253 else
5254 {
5255 M4OSA_TRACE1_0(
5256 "M4MP4W_setOption: dsi already set !");
5257 return M4ERR_STATE;
5258 }
5259 }
5260
5261 if (( 0 == streamIDmemAddrPtr->size)
5262 || (M4OSA_NULL == streamIDmemAddrPtr->addr))
5263 {
5264 M4OSA_TRACE1_0(
5265 "M4MP4W_setOption: Bad H264 dsi!");
5266 return M4ERR_PARAMETER;
5267 }
5268
5269 /* Store the DSI size */
5270 mMp4FileDataPtr->videoTrackPtr->dsiSize =
5271 (M4OSA_UInt8)streamIDmemAddrPtr->size;
5272
5273 /* Copy the DSI (SPS + PPS) */
5274 mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
5275 *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
5276 M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
5277 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
5278 != M4OSA_NULL, M4ERR_ALLOC);
5279 memcpy(
5280 (void *)mMp4FileDataPtr->videoTrackPtr->
5281 DSI,
5282 (void *)streamIDmemAddrPtr->addr,
5283 streamIDmemAddrPtr->size);
5284 break;
5285
5286 default:
5287 return M4ERR_BAD_STREAM_ID;
5288 }
5289 break;
5290
5291 default:
5292 return M4ERR_BAD_STREAM_ID;
5293 }
5294 }
5295 break;
5296 /* H.264 Trimming */
5297 case M4MP4W_MUL_PPS_SPS:
5298 mMp4FileDataPtr->bMULPPSSPS = *(M4OSA_Int8 *)value;
5299 /* H.264 Trimming */
5300 break;
5301
5302 default:
5303 return M4ERR_BAD_OPTION_ID;
5304 }
5305
5306 return err;
5307 }
5308
5309 /*******************************************************************************/
M4MP4W_getState(M4OSA_Context context,M4MP4W_State * state,M4SYS_StreamID streamID)5310 M4OSA_ERR M4MP4W_getState( M4OSA_Context context, M4MP4W_State *state,
5311 M4SYS_StreamID streamID )
5312 /*******************************************************************************/
5313 {
5314 M4OSA_ERR err = M4NO_ERROR;
5315
5316 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
5317 ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
5318
5319 switch( streamID )
5320 {
5321 case (0):
5322 *state = mMp4FileDataPtr->state;
5323 break;
5324
5325 case (AudioStreamID):
5326 if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
5327 {
5328 *state = mMp4FileDataPtr->audioTrackPtr->microState;
5329 }
5330 else
5331 {
5332 return M4ERR_BAD_STREAM_ID;
5333 }
5334 break;
5335
5336 case (VideoStreamID):
5337 if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
5338 {
5339 *state = mMp4FileDataPtr->videoTrackPtr->microState;
5340 }
5341 else
5342 {
5343 return M4ERR_BAD_STREAM_ID;
5344 }
5345 break;
5346
5347 default:
5348 return M4ERR_BAD_STREAM_ID;
5349 }
5350
5351 return err;
5352 }
5353
5354 /*******************************************************************************/
M4MP4W_getCurrentFileSize(M4OSA_Context context,M4OSA_UInt32 * pCurrentFileSize)5355 M4OSA_ERR M4MP4W_getCurrentFileSize( M4OSA_Context context,
5356 M4OSA_UInt32 *pCurrentFileSize )
5357 /*******************************************************************************/
5358 {
5359 M4OSA_ERR err = M4NO_ERROR;
5360
5361 M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
5362 ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
5363
5364 ERR_CHECK(pCurrentFileSize != M4OSA_NULL, M4ERR_PARAMETER);
5365 *pCurrentFileSize = mMp4FileDataPtr->filesize;
5366
5367 return err;
5368 }
5369
5370 #endif /* _M4MP4W_USE_CST_MEMORY_WRITER */
5371