• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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