Home | History | Annotate | Download | only in src
      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 /*******************************************************************************/
    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 
    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 /*******************************************************************************/
    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 /*******************************************************************************/
    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 /*******************************************************************************/
   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 /*******************************************************************************/
   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 /*******************************************************************************/
   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 /*******************************************************************************/
   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 /*******************************************************************************/
   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         if ((M4MP4W_Time32)auPtr->CTS < mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS) {
   2490             // Do not report as error, it will abort the entire filewrite. Just skip this frame.
   2491             M4OSA_TRACE1_0("Skip frame. Video frame has too old timestamp.");
   2492             return M4NO_ERROR;
   2493         }
   2494 
   2495         mMp4FileDataPtr->videoTrackPtr->currentPos += auPtr->size;
   2496 
   2497         /* Warning: time conversion cast 64to32! */
   2498         delta = (M4MP4W_Time32)auPtr->CTS
   2499             - mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS;
   2500 
   2501         /* DEBUG stts entries which are equal to 0 */
   2502         M4OSA_TRACE2_1("V_DELTA = %ld\n", delta);
   2503 
   2504 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   2505 
   2506         if (2 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb + 3)
   2507             >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
   2508             *M4MP4W_STSZ_ALLOC_SIZE)
   2509         {
   2510             M4OSA_TRACE1_0("M4MP4W_processAU : video stsz table is full");
   2511             return M4WAR_MP4W_OVERSIZE;
   2512         }
   2513 
   2514         mMp4FileDataPtr->videoTrackPtr->
   2515             TABLE_STSZ[mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb] =
   2516             (M4OSA_UInt16)auPtr->size;
   2517         mMp4FileDataPtr->filesize += 4;
   2518 
   2519 #else
   2520 
   2521         if (4 *mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
   2522             >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
   2523             *M4MP4W_STSZ_ALLOC_SIZE)
   2524         {
   2525             mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks += 1;
   2526 
   2527             mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ =
   2528                 (M4OSA_UInt32 *)M4MP4W_realloc(
   2529                 (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
   2530                 ( mMp4FileDataPtr->videoTrackPtr->
   2531                 nbOfAllocatedStszBlocks
   2532                 - 1) * M4MP4W_STSZ_ALLOC_SIZE,
   2533                 mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStszBlocks
   2534                 * M4MP4W_STSZ_ALLOC_SIZE);
   2535 
   2536             ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ != M4OSA_NULL,
   2537                 M4ERR_ALLOC);
   2538         }
   2539 
   2540         mMp4FileDataPtr->videoTrackPtr->
   2541             TABLE_STSZ[mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb] =
   2542             auPtr->size;
   2543         mMp4FileDataPtr->filesize += 4;
   2544 
   2545 #endif
   2546 
   2547         if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
   2548             == 0) /*test if first AU*/
   2549         {
   2550 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   2551 
   2552             M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0], 1);
   2553             M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0], 0);
   2554 
   2555 #else
   2556 
   2557             mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0] = 1;
   2558             mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = 0;
   2559 
   2560 #endif
   2561 
   2562             mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb = 1;
   2563             mMp4FileDataPtr->filesize += 8;
   2564         }
   2565         else if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
   2566             == 1 ) /*test if second AU*/
   2567         {
   2568 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   2569 
   2570             M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[0],
   2571                 (M4OSA_UInt16)delta);
   2572 
   2573 #else
   2574 
   2575             mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = delta;
   2576 
   2577 #endif
   2578 
   2579         }
   2580         else
   2581         {
   2582             /*retrieve last sample delta*/
   2583 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   2584 
   2585             lastSampleDur = M4MP4W_get32_Hi(&mMp4FileDataPtr->videoTrackPtr->
   2586                 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
   2587                 CommonData.sttsTableEntryNb - 1]);
   2588 
   2589             if (4 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
   2590                 + 3) >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks
   2591                 *M4MP4W_STTS_ALLOC_SIZE)
   2592             {
   2593                 M4OSA_TRACE1_0("M4MP4W_processAU : video stts table is full");
   2594                 return M4WAR_MP4W_OVERSIZE;
   2595             }
   2596 
   2597 #else
   2598 
   2599             lastSampleDur = mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
   2600                 * (mMp4FileDataPtr->videoTrackPtr->
   2601                 CommonData.sttsTableEntryNb - 1) + 1];
   2602 
   2603             if (8 *mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
   2604                 >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks
   2605                 *M4MP4W_STTS_ALLOC_SIZE)
   2606             {
   2607                 mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedSttsBlocks += 1;
   2608                 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS =
   2609                     (M4OSA_UInt32 *)M4MP4W_realloc(
   2610                     (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
   2611                     TABLE_STTS, ( mMp4FileDataPtr->videoTrackPtr->
   2612                     nbOfAllocatedSttsBlocks
   2613                     - 1) * M4MP4W_STTS_ALLOC_SIZE,
   2614                     mMp4FileDataPtr->videoTrackPtr->
   2615                     nbOfAllocatedSttsBlocks
   2616                     * M4MP4W_STTS_ALLOC_SIZE);
   2617                 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STTS
   2618                     != M4OSA_NULL, M4ERR_ALLOC);
   2619             }
   2620 
   2621 #endif                                   /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
   2622 
   2623             if (delta != lastSampleDur) /*new entry in the table*/
   2624             {
   2625 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   2626 
   2627                 M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->
   2628                     TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
   2629                     CommonData.sttsTableEntryNb], 1);
   2630                 M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->
   2631                     TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
   2632                     CommonData.sttsTableEntryNb], (M4OSA_UInt16)delta);
   2633 
   2634 #else
   2635 
   2636                 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
   2637                     mMp4FileDataPtr->videoTrackPtr->
   2638                     CommonData.sttsTableEntryNb)] = 1;
   2639                 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
   2640                     *(mMp4FileDataPtr->videoTrackPtr->
   2641                     CommonData.sttsTableEntryNb)+1] = delta;
   2642 
   2643 #endif
   2644 
   2645                 mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb +=
   2646                     1;
   2647                 mMp4FileDataPtr->filesize += 8;
   2648             }
   2649             else
   2650             {
   2651                 /*increase of 1 the number of consecutive AUs with same duration*/
   2652 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   2653 
   2654                 mMp4FileDataPtr->videoTrackPtr->
   2655                     TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
   2656                     CommonData.sttsTableEntryNb - 1] += 1;
   2657 
   2658 #else
   2659 
   2660                 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
   2661                     mMp4FileDataPtr->videoTrackPtr->
   2662                     CommonData.sttsTableEntryNb - 1)] += 1;
   2663 
   2664 #endif
   2665 
   2666             }
   2667         }
   2668 
   2669         mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb += 1;
   2670 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   2671 
   2672         mMp4FileDataPtr->videoTrackPtr->
   2673             chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentStsc] +=
   2674             1;
   2675 
   2676 #else
   2677 
   2678         mMp4FileDataPtr->videoTrackPtr->
   2679             chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] +=
   2680             1;
   2681 
   2682 #endif
   2683 
   2684         if (auPtr->attribute == AU_RAP)
   2685         {
   2686 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   2687 
   2688             if (4 *(mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb + 3)
   2689                 >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks
   2690                 *M4MP4W_STSS_ALLOC_SIZE)
   2691             {
   2692                 M4OSA_TRACE1_0("M4MP4W_processAU : video stss table is full");
   2693                 return M4WAR_MP4W_OVERSIZE;
   2694             }
   2695 
   2696 #else
   2697 
   2698             if (4 *mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb
   2699                 >= mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks
   2700                 *M4MP4W_STSS_ALLOC_SIZE)
   2701             {
   2702                 mMp4FileDataPtr->videoTrackPtr->nbOfAllocatedStssBlocks += 1;
   2703                 mMp4FileDataPtr->videoTrackPtr->TABLE_STSS =
   2704                     (M4OSA_UInt32 *)M4MP4W_realloc(
   2705                     (M4OSA_MemAddr32)mMp4FileDataPtr->videoTrackPtr->
   2706                     TABLE_STSS, ( mMp4FileDataPtr->videoTrackPtr->
   2707                     nbOfAllocatedStssBlocks
   2708                     - 1) * M4MP4W_STSS_ALLOC_SIZE,
   2709                     mMp4FileDataPtr->videoTrackPtr->
   2710                     nbOfAllocatedStssBlocks
   2711                     * M4MP4W_STSS_ALLOC_SIZE);
   2712                 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->TABLE_STSS
   2713                     != M4OSA_NULL, M4ERR_ALLOC);
   2714             }
   2715 
   2716 #endif /*_M4MP4W_OPTIMIZE_FOR_PHONE*/
   2717 
   2718             mMp4FileDataPtr->videoTrackPtr->
   2719                 TABLE_STSS[mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb] =
   2720                 mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb;
   2721             mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb += 1;
   2722             mMp4FileDataPtr->filesize += 4;
   2723         }
   2724 
   2725         /* Warning: time conversion cast 64to32! */
   2726         mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS =
   2727             (M4MP4W_Time32)auPtr->CTS;
   2728     }
   2729     else
   2730         return M4ERR_BAD_STREAM_ID;
   2731 
   2732     /* I moved some state modification to after we know the sample has been written correctly. */
   2733     if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
   2734         && (streamID == VideoStreamID))
   2735     {
   2736         mMp4FileDataPtr->audioMsStopTime =
   2737             (M4MP4W_Time32)(auPtr->CTS * scale_video);
   2738     }
   2739 
   2740     if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_FALSE)
   2741         || (streamID == VideoStreamID))
   2742     {
   2743         /*update fileSize*/
   2744         mMp4FileDataPtr->filesize += auPtr->size;
   2745     }
   2746 
   2747     if ((mMp4FileDataPtr->estimateAudioSize == M4OSA_TRUE)
   2748         && (streamID == VideoStreamID))
   2749     {
   2750         /*update filesize with estimated audio data that will be added later.    */
   2751         /*Warning: Assumption is made that:                                     */
   2752         /* - audio samples have constant size (e.g. no sid).                    */
   2753         /* - max audio sample size has been set, and is the actual sample size. */
   2754 
   2755         ERR_CHECK(mMp4FileDataPtr->audioMsChunkDur != 0,
   2756             M4WAR_MP4W_NOT_EVALUABLE);
   2757         mMp4FileDataPtr->filesize -=
   2758             (M4OSA_UInt32)(( mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS
   2759             * scale_video) * (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         mMp4FileDataPtr->filesize += (M4OSA_UInt32)(( auPtr->CTS * scale_video)
   2765             * (0.05/*always 50 AMR samples per second*/
   2766             *(M4OSA_Double)mMp4FileDataPtr->audioTrackPtr->MaxAUSize
   2767             + 16/*additional data for a new chunk*/
   2768             / (M4OSA_Double)mMp4FileDataPtr->audioMsChunkDur));
   2769     }
   2770 
   2771     M4OSA_TRACE1_4("processAU : size 0x%x mode %d filesize %lu limit %lu",
   2772         auPtr->size, auPtr->attribute, mMp4FileDataPtr->filesize,
   2773         mMp4FileDataPtr->MaxFileSize);
   2774 
   2775     return err;
   2776 }
   2777 
   2778 /*******************************************************************************/
   2779 M4OSA_ERR M4MP4W_closeWrite( M4OSA_Context context )
   2780 /*******************************************************************************/
   2781 {
   2782     M4OSA_ERR err = M4NO_ERROR;
   2783     M4OSA_ERR err2 = M4NO_ERROR, err3 = M4NO_ERROR;
   2784 
   2785     /*Warning: test should be done here to ensure context->pContext is not M4OSA_NULL,
   2786      but C is not C++...*/
   2787     M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
   2788 
   2789     M4OSA_UChar camcoder_maj, camcoder_min, camcoder_rev; /*camcoder version*/
   2790     M4OSA_Bool bAudio =
   2791         (( mMp4FileDataPtr->hasAudio)
   2792         && (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb
   2793         != 0)); /*((mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL) &&
   2794                     (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb != 0));*/
   2795     M4OSA_Bool bVideo =
   2796         (( mMp4FileDataPtr->hasVideo)
   2797         && (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb
   2798         != 0)); /*((mMp4FileDataPtr->videoTrackPtr != M4OSA_NULL) &&
   2799                     (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb != 0));*/
   2800     M4OSA_Bool bH263 = M4OSA_FALSE;
   2801     M4OSA_Bool bH264 = M4OSA_FALSE;
   2802     M4OSA_Bool bMP4V = M4OSA_FALSE;
   2803     M4OSA_Bool bAAC = M4OSA_FALSE;
   2804     M4OSA_Bool bEVRC = M4OSA_FALSE;
   2805 
   2806     /*intermediate variables*/
   2807     M4OSA_UInt32 A, B, N, AB4N;
   2808 
   2809     /*Trak variables*/
   2810     M4OSA_UInt32 a_trakId = AudioStreamID; /*     (audio=1)*/
   2811     /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
   2812     M4OSA_UInt32 a_trakOffset = 32;
   2813     M4OSA_UInt32 a_sttsSize = 24;          /* A (audio=24)*/
   2814     M4OSA_UInt32 a_stszSize = 20;          /* B (audio=20)*/
   2815     M4OSA_UInt32 a_trakSize = 402;         /*     (audio=402)*/
   2816     M4OSA_UInt32 a_mdiaSize = 302;         /*     (audio=302)*/
   2817     M4OSA_UInt32 a_minfSize = 229;         /*     (audio=229)*/
   2818     M4OSA_UInt32 a_stblSize = 169;         /*     (audio=169)*/
   2819     M4OSA_UInt32 a_stsdSize = 69;          /*     (audio=69 )*/
   2820     M4OSA_UInt32 a_esdSize = 53;           /*     (audio=53 )*/
   2821     M4OSA_UInt32 a_dataSize = 0;           /* temp: At the end, = currentPos*/
   2822     M4MP4W_Time32 a_trakDuration = 0;      /* equals lastCTS*/
   2823     M4MP4W_Time32 a_msTrakDuration = 0;
   2824     M4OSA_UInt32 a_stscSize = 28;          /* 16+12*nbchunksaudio*/
   2825     M4OSA_UInt32 a_stcoSize = 20;          /* 16+4*nbchunksaudio*/
   2826 
   2827     M4OSA_UInt32 v_trakId = VideoStreamID; /* (video=2)*/
   2828     /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
   2829     M4OSA_UInt32 v_trakOffset = 32;
   2830     M4OSA_UInt32 v_sttsSize = 0;      /* A (video=16+8J)*/
   2831     M4OSA_UInt32 v_stszSize = 0;      /* B (video=20+4K)*/
   2832     M4OSA_UInt32 v_trakSize = 0; /* (h263=A+B+4N+426), (mp4v=A+B+dsi+4N+448) */
   2833     M4OSA_UInt32 v_mdiaSize = 0; /* (h263=A+B+4N+326), (mp4v=A+B+dsi+4N+348) */
   2834     M4OSA_UInt32 v_minfSize = 0; /* (h263=A+B+4N+253), (mp4v=A+B+dsi+4N+275) */
   2835     M4OSA_UInt32 v_stblSize = 0; /* (h263=A+B+4N+189), (mp4v=A+B+dsi+4N+211) */
   2836     M4OSA_UInt32 v_stsdSize = 0;      /* (h263=117)        , (mp4v=139+dsi    )*/
   2837     M4OSA_UInt32 v_esdSize = 0;       /* (h263=101)        , (mp4v=153+dsi    )*/
   2838     M4OSA_UInt32 v_dataSize = 0;      /* temp: At the end, = currentPos*/
   2839     M4MP4W_Time32 v_trakDuration = 0; /* equals lastCTS*/
   2840     M4MP4W_Time32 v_msTrakDuration = 0;
   2841     M4OSA_UInt32 v_stscSize = 28;     /* 16+12*nbchunksvideo*/
   2842     M4OSA_UInt32 v_stcoSize = 20;     /* 16+4*nbchunksvideo*/
   2843 
   2844     /*video variables*/
   2845     M4OSA_UInt32 v_stssSize = 0; /* 4*N+16     STSS*/
   2846 
   2847     /*aac & mp4v temp variable*/
   2848     M4OSA_UInt8 dsi = 0;
   2849 
   2850     /*H264 variables*/
   2851     M4OSA_UInt32 v_avcCSize = 0; /* dsi+15*/
   2852 
   2853     /*MP4V variables*/
   2854     M4OSA_UInt32 v_esdsSize = 0;        /* dsi+37*/
   2855     M4OSA_UInt8 v_ESDescriptorSize =
   2856         0; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
   2857     M4OSA_UInt8 v_DCDescriptorSize = 0; /* dsi+15*/
   2858 
   2859     /*AAC variables*/
   2860     M4OSA_UInt32 a_esdsSize = 0;        /* dsi+37*/
   2861     M4OSA_UInt8 a_ESDescriptorSize =
   2862         0; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
   2863     M4OSA_UInt8 a_DCDescriptorSize = 0; /* dsi+15*/
   2864 
   2865     /*General variables*/
   2866 
   2867     /* audio chunk size + video chunk size*/
   2868     M4OSA_UInt32 mdatSize = 8;
   2869     M4OSA_UInt32 moovSize = 116; /* 116 + 402(audio) +    (A+B+4N+426)(h263) or */
   2870     /*                        (A+B+dsi+4N+448)(mp4v)    */
   2871     M4OSA_UInt32 creationTime; /* C */
   2872 
   2873     /*flag to set up the chunk interleave strategy*/
   2874     M4OSA_Bool bInterleaveAV =
   2875         (bAudio && bVideo && (mMp4FileDataPtr->InterleaveDur != 0));
   2876 
   2877     M4OSA_Context fileWriterContext = mMp4FileDataPtr->fileWriterContext;
   2878 
   2879     M4OSA_UInt32 i;
   2880 
   2881     M4OSA_Double scale_audio = 0.0;
   2882     M4OSA_Double scale_video = 0.0;
   2883     M4MP4W_Time32 delta;
   2884 
   2885 #ifndef _M4MP4W_MOOV_FIRST
   2886 
   2887     M4OSA_FilePosition moovPos, mdatPos;
   2888 
   2889 #endif /*_M4MP4W_MOOV_FIRST*/
   2890 
   2891     ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
   2892 
   2893     /*macro state */
   2894     mMp4FileDataPtr->state = M4MP4W_closed;
   2895 
   2896     /*if no data !*/
   2897     if ((!bAudio) && (!bVideo))
   2898     {
   2899         err = M4NO_ERROR; /*would be better to return a warning ?*/
   2900         goto cleanup;
   2901     }
   2902 
   2903 #ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
   2904     /* Remove safety file to make room for what needs to be written out here
   2905     (chunk flushing and moov). */
   2906 
   2907     if (M4OSA_TRUE == mMp4FileDataPtr->cleanSafetyFile)
   2908     {
   2909         M4OSA_Context tempContext;
   2910         err = mMp4FileDataPtr->fileWriterFunctions->openWrite(&tempContext,
   2911             mMp4FileDataPtr->safetyFileUrl,
   2912             M4OSA_kFileWrite | M4OSA_kFileCreate);
   2913 
   2914         if (M4NO_ERROR != err)
   2915             goto cleanup;
   2916         err = mMp4FileDataPtr->fileWriterFunctions->closeWrite(tempContext);
   2917 
   2918         if (M4NO_ERROR != err)
   2919             goto cleanup;
   2920         mMp4FileDataPtr->safetyFileUrl = M4OSA_NULL;
   2921         mMp4FileDataPtr->cleanSafetyFile = M4OSA_FALSE;
   2922     }
   2923 
   2924 #endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
   2925 
   2926     if (bVideo)
   2927     {
   2928         if ((M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable)
   2929             || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->chunkSizeTable)
   2930             || (M4OSA_NULL
   2931             == mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable)
   2932             || (M4OSA_NULL
   2933             == mMp4FileDataPtr->videoTrackPtr->chunkTimeMsTable)
   2934             || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ)
   2935             || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STTS)
   2936             || (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->TABLE_STSS))
   2937         {
   2938             mMp4FileDataPtr->fileWriterFunctions->closeWrite(
   2939                 fileWriterContext); /**< close the stream anyway */
   2940             M4MP4W_freeContext(context); /**< Free the context content */
   2941             return M4ERR_ALLOC;
   2942         }
   2943 
   2944         /*video microstate*/
   2945         mMp4FileDataPtr->videoTrackPtr->microState = M4MP4W_closed;
   2946 
   2947         /*current chunk is the last one and gives the total number of video chunks (-1)*/
   2948         for ( i = 0; i < mMp4FileDataPtr->videoTrackPtr->currentChunk; i++ )
   2949         {
   2950             v_dataSize += mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
   2951         }
   2952 
   2953 #ifndef _M4MP4W_MOOV_FIRST
   2954 #ifndef _M4MP4W_UNBUFFERED_VIDEO
   2955         /*flush chunk*/
   2956 
   2957         if (mMp4FileDataPtr->videoTrackPtr->currentPos > 0)
   2958         {
   2959             err = M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[0],
   2960                 mMp4FileDataPtr->videoTrackPtr->currentPos,
   2961                 mMp4FileDataPtr->fileWriterFunctions,
   2962                 mMp4FileDataPtr->fileWriterContext);
   2963 
   2964             if (M4NO_ERROR != err)
   2965                 goto cleanup;
   2966         }
   2967 
   2968 #endif
   2969 
   2970         M4OSA_TRACE1_0("flush video | CLOSE");
   2971         M4OSA_TRACE1_3("current chunk = %d  offset = 0x%x size = 0x%08X",
   2972             mMp4FileDataPtr->videoTrackPtr->currentChunk,
   2973             mMp4FileDataPtr->absoluteCurrentPos,
   2974             mMp4FileDataPtr->videoTrackPtr->currentPos);
   2975 
   2976         /*update chunk offset*/
   2977         mMp4FileDataPtr->videoTrackPtr->
   2978             chunkOffsetTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
   2979             mMp4FileDataPtr->absoluteCurrentPos;
   2980 
   2981         /*add chunk size to absoluteCurrentPos*/
   2982         mMp4FileDataPtr->absoluteCurrentPos +=
   2983             mMp4FileDataPtr->videoTrackPtr->currentPos;
   2984 #endif /*_M4MP4W_MOOV_FIRST*/
   2985 
   2986         /*update last chunk size, and add this value to v_dataSize*/
   2987 
   2988         mMp4FileDataPtr->videoTrackPtr->
   2989             chunkSizeTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
   2990             mMp4FileDataPtr->videoTrackPtr->currentPos;
   2991         v_dataSize +=
   2992             mMp4FileDataPtr->videoTrackPtr->currentPos; /*add last chunk size*/
   2993 
   2994         v_trakDuration = mMp4FileDataPtr->videoTrackPtr->
   2995             CommonData.lastCTS; /* equals lastCTS*/
   2996 
   2997         /* bugfix: if a new chunk was just created, cancel it before to close */
   2998         if ((mMp4FileDataPtr->videoTrackPtr->currentChunk != 0)
   2999             && (mMp4FileDataPtr->videoTrackPtr->currentPos == 0))
   3000         {
   3001             mMp4FileDataPtr->videoTrackPtr->currentChunk--;
   3002         }
   3003 #ifdef _M4MP4W_UNBUFFERED_VIDEO
   3004 
   3005         if ((mMp4FileDataPtr->videoTrackPtr->
   3006             chunkSampleNbTable[mMp4FileDataPtr->videoTrackPtr->
   3007             currentStsc] & 0xFFF) == 0)
   3008         {
   3009             mMp4FileDataPtr->videoTrackPtr->currentStsc--;
   3010         }
   3011 
   3012 #endif /*_M4MP4W_UNBUFFERED_VIDEO*/
   3013 
   3014         /* Last sample duration */
   3015         /* If we have the file duration we use it, else we duplicate the last AU */
   3016 
   3017         if (mMp4FileDataPtr->MaxFileDuration > 0)
   3018         {
   3019             /* use max file duration to calculate delta of last AU */
   3020             delta = mMp4FileDataPtr->MaxFileDuration
   3021                 - mMp4FileDataPtr->videoTrackPtr->CommonData.lastCTS;
   3022             v_trakDuration = mMp4FileDataPtr->MaxFileDuration;
   3023 
   3024             if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb > 1)
   3025             {
   3026                 /* if more than 1 frame, create a new stts entry (else already created) */
   3027                 mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb++;
   3028             }
   3029 
   3030 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   3031 
   3032             M4MP4W_put32_Lo(&mMp4FileDataPtr->videoTrackPtr->
   3033                 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
   3034                 CommonData.sttsTableEntryNb - 1], 1);
   3035             M4MP4W_put32_Hi(&mMp4FileDataPtr->videoTrackPtr->
   3036                 TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
   3037                 CommonData.sttsTableEntryNb - 1], delta);
   3038 
   3039 #else
   3040 
   3041             mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
   3042                 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
   3043                 - 1)] = 1;
   3044             mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
   3045                 *(mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb
   3046                 - 1) + 1] = delta;
   3047 
   3048 #endif
   3049 
   3050         }
   3051         else
   3052         {
   3053             /* duplicate the delta of the previous frame */
   3054             if (mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb > 1)
   3055             {
   3056                 /* if more than 1 frame, duplicate the stts entry (else already exists) */
   3057 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   3058 
   3059                 v_trakDuration +=
   3060                     M4MP4W_get32_Hi(&mMp4FileDataPtr->videoTrackPtr->
   3061                     TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
   3062                     CommonData.sttsTableEntryNb - 1]);
   3063                 mMp4FileDataPtr->videoTrackPtr->
   3064                     TABLE_STTS[mMp4FileDataPtr->videoTrackPtr->
   3065                     CommonData.sttsTableEntryNb - 1] += 1;
   3066 
   3067 #else
   3068 
   3069                 v_trakDuration += mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2
   3070                     * (mMp4FileDataPtr->videoTrackPtr->
   3071                     CommonData.sttsTableEntryNb - 1) + 1];
   3072                 mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[2 *(
   3073                     mMp4FileDataPtr->videoTrackPtr->
   3074                     CommonData.sttsTableEntryNb - 1)] += 1;
   3075 
   3076 #endif
   3077 
   3078             }
   3079             else
   3080             {
   3081                 M4OSA_TRACE1_0("M4MP4W_closeWrite : ! videoTrackPtr,\
   3082                      cannot know the duration of the unique AU !");
   3083                 /* If there is an audio track, we use it as a file duration
   3084                 (and so, as AU duration...) */
   3085                 if (mMp4FileDataPtr->audioTrackPtr != M4OSA_NULL)
   3086                 {
   3087                     M4OSA_TRACE1_0(
   3088                         "M4MP4W_closeWrite : ! Let's use the audio track duration !");
   3089                     mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] =
   3090                         (M4OSA_UInt32)(
   3091                         mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS
   3092                         * (1000.0 / mMp4FileDataPtr->audioTrackPtr->
   3093                         CommonData.timescale));
   3094                     v_trakDuration =
   3095                         mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1];
   3096                 }
   3097                 /* Else, we use a MAGICAL value (66 ms) */
   3098                 else
   3099                 {
   3100                     M4OSA_TRACE1_0(
   3101                         "M4MP4W_closeWrite : ! No audio track -> use magical value (66) !"); /*    */
   3102                     mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[1] = 66;
   3103                     v_trakDuration = 66;
   3104                 }
   3105             }
   3106         }
   3107 
   3108         /* Calculate table sizes */
   3109         A = v_sttsSize = 16 + 8 * mMp4FileDataPtr->videoTrackPtr->
   3110             CommonData.sttsTableEntryNb; /* A (video=16+8J)*/
   3111         B = v_stszSize = 20 + 4 * mMp4FileDataPtr->videoTrackPtr->
   3112             CommonData.sampleNb; /* B (video=20+4K)*/
   3113         N = mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb;
   3114         AB4N = A + B + 4 * N;
   3115 
   3116         scale_video =
   3117             1000.0 / mMp4FileDataPtr->videoTrackPtr->CommonData.timescale;
   3118         v_msTrakDuration = (M4OSA_UInt32)(v_trakDuration * scale_video);
   3119 
   3120         /*Convert integers in the table from LE into BE*/
   3121 #ifndef _M4MP4W_OPTIMIZE_FOR_PHONE
   3122 
   3123         M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
   3124             mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb);
   3125         M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STTS,
   3126             2 * (mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb));
   3127 
   3128 #endif
   3129 
   3130         M4MP4W_table32ToBE(mMp4FileDataPtr->videoTrackPtr->TABLE_STSS,
   3131             mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb);
   3132 
   3133         if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
   3134             == M4SYS_kH263)
   3135         {
   3136             bH263 = M4OSA_TRUE;
   3137             v_trakSize = AB4N + 426; /* (h263=A+B+4N+426)*/
   3138             v_mdiaSize = AB4N + 326; /* (h263=A+B+4N+326)*/
   3139             v_minfSize = AB4N + 253; /* (h263=A+B+4N+253)*/
   3140             v_stblSize = AB4N + 189; /* (h263=A+B+4N+189)*/
   3141             v_stsdSize = 117;        /* (h263=117)*/
   3142             v_esdSize = 101;         /* (h263=101)*/
   3143 
   3144             moovSize += AB4N + 426;
   3145 
   3146             if (((M4OSA_Int32)mMp4FileDataPtr->videoTrackPtr->avgBitrate) != -1)
   3147             {
   3148                 /*the optional 'bitr' atom is appended to the dsi,so filesize is 16 bytes bigger*/
   3149                 v_trakSize += 16;
   3150                 v_mdiaSize += 16;
   3151                 v_minfSize += 16;
   3152                 v_stblSize += 16;
   3153                 v_stsdSize += 16;
   3154                 v_esdSize += 16;
   3155                 moovSize += 16;
   3156             }
   3157         }
   3158         else if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
   3159             == M4SYS_kH264)
   3160         {
   3161             bH264 = M4OSA_TRUE;
   3162             /* For H264 there is no default DSI, and its presence is mandatory,
   3163             so check the DSI has been set*/
   3164             if (0 == mMp4FileDataPtr->videoTrackPtr->dsiSize
   3165                 || M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
   3166             {
   3167                 M4OSA_TRACE1_0(
   3168                     "M4MP4W_closeWrite: error, no H264 DSI has been set!");
   3169                 err = M4ERR_STATE;
   3170                 goto cleanup;
   3171             }
   3172 
   3173             /*H264 sizes of the atom*/
   3174 
   3175             // Remove the hardcoded DSI values of H264Block2
   3176             // TODO: check bMULPPSSPS case
   3177             v_avcCSize = sizeof(M4OSA_UInt32) + sizeof(H264Block2) +
   3178                 mMp4FileDataPtr->videoTrackPtr->dsiSize;
   3179 
   3180             v_trakSize = AB4N + v_avcCSize + 411;
   3181             v_mdiaSize = AB4N + v_avcCSize + 311;
   3182             v_minfSize = AB4N + v_avcCSize + 238;
   3183             v_stblSize = AB4N + v_avcCSize + 174;
   3184             v_stsdSize =        v_avcCSize + 102;
   3185             v_esdSize  =        v_avcCSize + 86;
   3186 
   3187             moovSize   += AB4N + v_avcCSize + 411;
   3188 
   3189         }
   3190         else if (mMp4FileDataPtr->videoTrackPtr->CommonData.trackType
   3191             == M4SYS_kMPEG_4)
   3192         {
   3193             bMP4V = M4OSA_TRUE;
   3194             /* For MPEG4 there is no default DSI, and its presence is mandatory,
   3195             so check the DSI has been set*/
   3196             if (0 == mMp4FileDataPtr->videoTrackPtr->dsiSize
   3197                 || M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
   3198             {
   3199                 M4OSA_TRACE1_0(
   3200                     "M4MP4W_closeWrite: error, no MPEG4 DSI has been set!");
   3201                 err = M4ERR_STATE;
   3202                 goto cleanup;
   3203             }
   3204 
   3205             /*MP4V variables*/
   3206             dsi = mMp4FileDataPtr->videoTrackPtr->dsiSize;
   3207             v_esdsSize = 37 + dsi;         /* dsi+37*/
   3208             v_ESDescriptorSize =
   3209                 23
   3210                 + dsi; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
   3211             v_DCDescriptorSize = 15 + dsi; /* dsi+15*/
   3212 
   3213             v_trakSize = AB4N + dsi + 448; /* (mp4v=A+B+dsi+4N+448)    */
   3214             v_mdiaSize = AB4N + dsi + 348; /* (mp4v=A+B+dsi+4N+348)    */
   3215             v_minfSize = AB4N + dsi + 275; /* (mp4v=A+B+dsi+4N+275)    */
   3216             v_stblSize = AB4N + dsi + 211; /* (mp4v=A+B+dsi+4N+211)    */
   3217             v_stsdSize = dsi + 139;        /* (mp4v=139+dsi)*/
   3218             v_esdSize = dsi + 123;         /* (mp4v=123+dsi)*/
   3219 
   3220             moovSize += AB4N + dsi + 448;
   3221         }
   3222 
   3223         /*video variables*/
   3224         v_stssSize = 16 + 4 * N; /* 4*N+16     STSS*/
   3225 
   3226 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   3227         /* stsc update */
   3228 
   3229         v_stscSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
   3230         v_stblSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
   3231         v_minfSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
   3232         v_mdiaSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
   3233         v_trakSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
   3234         moovSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentStsc;
   3235 
   3236         /* stco update */
   3237         v_stcoSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3238         v_stblSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3239         v_minfSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3240         v_mdiaSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3241         v_trakSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3242         moovSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3243 
   3244 #else
   3245         /*stsc/stco update*/
   3246 
   3247         v_stscSize += 12 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3248         v_stcoSize += 4 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3249         v_stblSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3250         v_minfSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3251         v_mdiaSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3252         v_trakSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3253         moovSize += 16 * mMp4FileDataPtr->videoTrackPtr->currentChunk;
   3254 
   3255 #endif
   3256 
   3257         /*update last chunk time*/
   3258 
   3259         mMp4FileDataPtr->videoTrackPtr->
   3260             chunkTimeMsTable[mMp4FileDataPtr->videoTrackPtr->currentChunk] =
   3261             v_msTrakDuration;
   3262     }
   3263 
   3264     if (bAudio)
   3265     {
   3266         if ((M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable)
   3267             || (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->chunkSizeTable)
   3268             || (M4OSA_NULL
   3269             == mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable)
   3270             || (M4OSA_NULL
   3271             == mMp4FileDataPtr->audioTrackPtr->chunkTimeMsTable)
   3272             || (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->TABLE_STTS))
   3273         {
   3274             mMp4FileDataPtr->fileWriterFunctions->closeWrite(
   3275                 fileWriterContext); /**< close the stream anyway */
   3276             M4MP4W_freeContext(context); /**< Free the context content */
   3277             return M4ERR_ALLOC;
   3278         }
   3279 
   3280         /*audio microstate*/
   3281         mMp4FileDataPtr->audioTrackPtr->microState = M4MP4W_closed;
   3282 
   3283         if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType == M4SYS_kAAC)
   3284         {
   3285             bAAC =
   3286                 M4OSA_TRUE; /*else, audio is implicitely amr in the following*/
   3287             dsi = mMp4FileDataPtr->audioTrackPtr->dsiSize; /*variable size*/
   3288 
   3289             a_esdsSize = 37 + dsi;                         /* dsi+37*/
   3290             a_ESDescriptorSize =
   3291                 23
   3292                 + dsi; /* dsi+23 (warning: check dsi<105 for coding size on 1 byte)*/
   3293             a_DCDescriptorSize = 15 + dsi;                 /* dsi+15*/
   3294 
   3295             a_esdSize = dsi + 73; /*overwrite a_esdSize with aac value*/
   3296             /*add dif. between amr & aac sizes: (- 53 + dsi + 37)*/
   3297             a_stsdSize += dsi + 20;
   3298             a_stblSize += dsi + 20;
   3299             a_minfSize += dsi + 20;
   3300             a_mdiaSize += dsi + 20;
   3301             a_trakSize += dsi + 20;
   3302             moovSize += dsi + 20;
   3303         }
   3304 
   3305         if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType
   3306             == M4SYS_kEVRC)
   3307         {
   3308             bEVRC =
   3309                 M4OSA_TRUE; /*else, audio is implicitely amr in the following*/
   3310 
   3311             /* evrc dsi is only 6 bytes while amr dsi is 9 bytes,all other blocks are unchanged */
   3312             a_esdSize -= 3;
   3313             a_stsdSize -= 3;
   3314             a_stblSize -= 3;
   3315             a_minfSize -= 3;
   3316             a_mdiaSize -= 3;
   3317             a_trakSize -= 3;
   3318             moovSize -= 3;
   3319         }
   3320 
   3321         if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize == 0)
   3322         {
   3323             if (M4OSA_NULL == mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ)
   3324             {
   3325                 mMp4FileDataPtr->fileWriterFunctions->closeWrite(
   3326                     fileWriterContext); /**< close the stream anyway */
   3327                 M4MP4W_freeContext(context); /**< Free the context content */
   3328                 return M4ERR_ALLOC;
   3329             }
   3330             /*Convert integers in the table from LE into BE*/
   3331             M4MP4W_table32ToBE(mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ,
   3332                 mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb);
   3333             a_stszSize +=
   3334                 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
   3335             a_stblSize +=
   3336                 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
   3337             a_minfSize +=
   3338                 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
   3339             a_mdiaSize +=
   3340                 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
   3341             a_trakSize +=
   3342                 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
   3343             moovSize += 4 * mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb;
   3344         }
   3345 
   3346         moovSize += 402;
   3347 
   3348         /*current chunk is the last one and gives the total number of audio chunks (-1)*/
   3349         for ( i = 0; i < mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
   3350         {
   3351             a_dataSize += mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
   3352         }
   3353 
   3354 #ifndef _M4MP4W_MOOV_FIRST
   3355         /*flush chunk*/
   3356 
   3357         if (mMp4FileDataPtr->audioTrackPtr->currentPos > 0)
   3358         {
   3359             err = M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[0],
   3360                 mMp4FileDataPtr->audioTrackPtr->currentPos,
   3361                 mMp4FileDataPtr->fileWriterFunctions,
   3362                 mMp4FileDataPtr->fileWriterContext);
   3363 
   3364             if (M4NO_ERROR != err)
   3365                 goto cleanup;
   3366         }
   3367 
   3368         M4OSA_TRACE1_0("flush audio | CLOSE");
   3369         M4OSA_TRACE1_2("current chunk = %d  offset = 0x%x",
   3370             mMp4FileDataPtr->audioTrackPtr->currentChunk,
   3371             mMp4FileDataPtr->absoluteCurrentPos);
   3372 
   3373         /*update chunk offset*/
   3374         mMp4FileDataPtr->audioTrackPtr->
   3375             chunkOffsetTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
   3376             mMp4FileDataPtr->absoluteCurrentPos;
   3377 
   3378         /*add chunk size to absoluteCurrentPos*/
   3379         mMp4FileDataPtr->absoluteCurrentPos +=
   3380             mMp4FileDataPtr->audioTrackPtr->currentPos;
   3381 
   3382 #endif /*_M4MP4W_MOOV_FIRST*/
   3383 
   3384         /*update last chunk size, and add this value to a_dataSize*/
   3385 
   3386         mMp4FileDataPtr->audioTrackPtr->
   3387             chunkSizeTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
   3388             mMp4FileDataPtr->audioTrackPtr->currentPos;
   3389         a_dataSize +=
   3390             mMp4FileDataPtr->audioTrackPtr->currentPos; /*add last chunk size*/
   3391 
   3392         /* bugfix: if a new chunk was just created, cancel it before to close */
   3393         if ((mMp4FileDataPtr->audioTrackPtr->currentChunk != 0)
   3394             && (mMp4FileDataPtr->audioTrackPtr->currentPos == 0))
   3395         {
   3396             mMp4FileDataPtr->audioTrackPtr->currentChunk--;
   3397         }
   3398 #ifdef _M4MP4W_UNBUFFERED_VIDEO
   3399 
   3400         if ((mMp4FileDataPtr->audioTrackPtr->
   3401             chunkSampleNbTable[mMp4FileDataPtr->audioTrackPtr->
   3402             currentStsc] & 0xFFF) == 0)
   3403         {
   3404             mMp4FileDataPtr->audioTrackPtr->currentStsc--;
   3405         }
   3406 
   3407 #endif                                                          /*_M4MP4W_UNBUFFERED_VIDEO*/
   3408 
   3409         a_trakDuration = mMp4FileDataPtr->audioTrackPtr->
   3410             CommonData.lastCTS; /* equals lastCTS*/
   3411         /* add last sample dur */
   3412 
   3413         if (mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb != 1)
   3414         {
   3415 #ifdef DUPLICATE_STTS_IN_LAST_AU
   3416             /*increase of 1 the number of consecutive AUs with same duration*/
   3417 
   3418             mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2
   3419                 *(mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
   3420                 - 1) - 2] += 1;
   3421 
   3422 #endif /*DUPLICATE_STTS_IN_LAST_AU*/
   3423 
   3424             a_trakDuration += mMp4FileDataPtr->audioTrackPtr->TABLE_STTS[2
   3425                 * (mMp4FileDataPtr->audioTrackPtr->
   3426                 CommonData.sttsTableEntryNb - 1) - 1];
   3427         }
   3428         else if (0 == mMp4FileDataPtr->audioTrackPtr->CommonData.lastCTS)
   3429         {
   3430             if (mMp4FileDataPtr->audioTrackPtr->CommonData.trackType
   3431                 == M4SYS_kAMR)
   3432             {
   3433                 if (12200 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
   3434                 {
   3435                     a_trakDuration = a_dataSize / 32
   3436                         * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
   3437                 }
   3438                 else if (10200 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
   3439                 {
   3440                     a_trakDuration = a_dataSize / 27
   3441                         * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
   3442                 }
   3443                 else if (7950 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
   3444                 {
   3445                     a_trakDuration = a_dataSize / 21
   3446                         * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
   3447                 }
   3448                 else if (7400 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
   3449                 {
   3450                     a_trakDuration = a_dataSize / 20
   3451                         * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
   3452                 }
   3453                 else if (6700 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
   3454                 {
   3455                     a_trakDuration = a_dataSize / 18
   3456                         * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
   3457                 }
   3458                 else if (5900 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
   3459                 {
   3460                     a_trakDuration = a_dataSize / 16
   3461                         * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
   3462                 }
   3463                 else if (5150 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
   3464                 {
   3465                     a_trakDuration = a_dataSize / 14
   3466                         * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
   3467                 }
   3468                 else if (4750 == mMp4FileDataPtr->audioTrackPtr->avgBitrate)
   3469                 {
   3470                     a_trakDuration = a_dataSize / 13
   3471                         * mMp4FileDataPtr->audioTrackPtr->sampleDuration;
   3472                 }
   3473             }
   3474         }
   3475 
   3476         scale_audio =
   3477             1000.0 / mMp4FileDataPtr->audioTrackPtr->CommonData.timescale;
   3478         a_msTrakDuration = (M4OSA_UInt32)(a_trakDuration * scale_audio);
   3479 
   3480 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   3481         /* stsc update */
   3482 
   3483         a_stscSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
   3484         a_stblSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
   3485         a_minfSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
   3486         a_mdiaSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
   3487         a_trakSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
   3488         moovSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentStsc;
   3489 
   3490         /* stso update */
   3491         a_stcoSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3492         a_stblSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3493         a_minfSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3494         a_mdiaSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3495         a_trakSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3496         moovSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3497 
   3498 #else
   3499         /*stsc/stco update*/
   3500 
   3501         a_stscSize += 12 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3502         a_stcoSize += 4 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3503         a_stblSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3504         a_minfSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3505         a_mdiaSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3506         a_trakSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3507         moovSize += 16 * mMp4FileDataPtr->audioTrackPtr->currentChunk;
   3508 
   3509 #endif
   3510 
   3511         /* compute the new size of stts*/
   3512 
   3513         a_sttsSize = 16 + 8 * (mMp4FileDataPtr->audioTrackPtr->
   3514             CommonData.sttsTableEntryNb - 1);
   3515 
   3516         moovSize += a_sttsSize - 24;
   3517         a_mdiaSize += a_sttsSize - 24;
   3518         a_minfSize += a_sttsSize - 24;
   3519         a_stblSize += a_sttsSize - 24;
   3520         a_trakSize += a_sttsSize - 24;
   3521 
   3522         /*update last chunk time*/
   3523         mMp4FileDataPtr->audioTrackPtr->
   3524             chunkTimeMsTable[mMp4FileDataPtr->audioTrackPtr->currentChunk] =
   3525             a_msTrakDuration;
   3526     }
   3527 
   3528     /* changing the way the mdat size is computed.
   3529     The real purpose of the mdat size is to know the amount to skip to get to the next
   3530     atom, which is the moov; the size of media in the mdat is almost secondary. Therefore,
   3531     it is of utmost importance that the mdat size "points" to where the moov actually
   3532     begins. Now, the moov begins right after the last data we wrote, so how could the sum
   3533     of all chunk sizes be different from the total size of what has been written? Well, it
   3534     can happen when the writing was unexpectedly stopped (because of lack of disk space,
   3535     for instance), in this case a chunk may be partially written (the partial write is not
   3536     necessarily erased) but it may not be reflected in the chunk size list (which may
   3537     believe it hasn't been written or on the contrary that it has been fully written). In
   3538     the case of such a mismatch, there is either unused data in the mdat (not very good,
   3539     but tolerable) or when reading the last chunk it will read the beginning of the moov
   3540     as part of the chunk (which means the last chunk won't be correctly decoded), both of
   3541     which are still better than losing the whole recording. In the long run it'll probably
   3542     be attempted to always clean up back to a consistent state, but at any rate it is
   3543     always safer to have the mdat size be computed using the position where the moov
   3544     actually begins, rather than using the size it is thought the mdat has.
   3545 
   3546     Therefore, I will record where we are just before writing the moov, to serve when
   3547     updating the mdat size. */
   3548 
   3549     /* mdatSize += a_dataSize + v_dataSize; *//*TODO allow for multiple chunks*/
   3550 
   3551     /* End of Pierre Lebeaupin 19/12/2007: changing the way the mdat size is computed. */
   3552 
   3553     /* first trak offset is 32+moovSize, second equals 32+moovSize+1st_track_size*/
   3554     a_trakOffset += moovSize;
   3555     v_trakOffset += moovSize/*+ a_dataSize*/;
   3556 
   3557     if (bInterleaveAV == M4OSA_FALSE)
   3558         v_trakOffset += a_dataSize;
   3559 
   3560     /*system time since 1970 */
   3561 #ifndef _M4MP4W_DONT_USE_TIME_H
   3562 
   3563     time((time_t *)&creationTime);
   3564     /*convert into time since 1/1/1904 00h00 (normative)*/
   3565     creationTime += 2082841761; /*nb of sec between 1904 and 1970*/
   3566 
   3567 #else                                            /*_M4MP4W_DONT_USE_TIME_H*/
   3568 
   3569     creationTime =
   3570         0xBBD09100; /* = 7/11/2003 00h00 ; in hexa because of code scrambler limitation with
   3571                                            large integers */
   3572 
   3573 #endif                                           /*_M4MP4W_DONT_USE_TIME_H*/
   3574 
   3575     mMp4FileDataPtr->duration =
   3576         max(a_msTrakDuration, v_msTrakDuration); /*max audio/video*/
   3577 
   3578 #ifdef _M4MP4W_MOOV_FIRST
   3579     /*open file in write binary mode*/
   3580 
   3581     err = mMp4FileDataPtr->fileWriterFunctions->openWrite(&fileWriterContext,
   3582         mMp4FileDataPtr->url, 0x22);
   3583     ERR_CHECK(err == M4NO_ERROR, err);
   3584 
   3585     /*ftyp atom*/
   3586     if (mMp4FileDataPtr->ftyp.major_brand != 0)
   3587     {
   3588         M4OSA_UInt32 i;
   3589 
   3590         /* Put customized ftyp box */
   3591         CLEANUPonERR(M4MP4W_putBE32(16
   3592             + (mMp4FileDataPtr->ftyp.nbCompatibleBrands * 4),
   3593             mMp4FileDataPtr->fileWriterFunctions,
   3594             mMp4FileDataPtr->fileWriterContext));
   3595         CLEANUPonERR(M4MP4W_putBE32(M4MPAC_FTYP_TAG,
   3596             mMp4FileDataPtr->fileWriterFunctions,
   3597             mMp4FileDataPtr->fileWriterContext));
   3598         CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->ftyp.major_brand,
   3599             mMp4FileDataPtr->fileWriterFunctions,
   3600             mMp4FileDataPtr->fileWriterContext));
   3601         CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->ftyp.minor_version,
   3602             mMp4FileDataPtr->fileWriterFunctions,
   3603             mMp4FileDataPtr->fileWriterContext));
   3604 
   3605         for ( i = 0; i < mMp4FileDataPtr->ftyp.nbCompatibleBrands; i++ )
   3606         {
   3607             CLEANUPonERR(
   3608                 M4MP4W_putBE32(mMp4FileDataPtr->ftyp.compatible_brands[i],
   3609                 mMp4FileDataPtr->fileWriterFunctions,
   3610                 mMp4FileDataPtr->fileWriterContext));
   3611         }
   3612     }
   3613     else
   3614     {
   3615         /* Put default ftyp box */
   3616         CLEANUPonERR(M4MP4W_putBlock(Default_ftyp, sizeof(Default_ftyp),
   3617             mMp4FileDataPtr->fileWriterFunctions,
   3618             mMp4FileDataPtr->fileWriterContext));
   3619     }
   3620 
   3621 #endif /*_M4MP4W_MOOV_FIRST*/
   3622 
   3623 #ifndef _M4MP4W_MOOV_FIRST
   3624     /* seek is used to get the current position relative to the start of the file. */
   3625     /* ... or rather, seek used to be used for that, but it has been found this functionality
   3626     is not reliably, or sometimes not at all, implemented in the various OSALs, so we now avoid
   3627     using it. */
   3628     /* Notice this new method assumes we're at the end of the file, this will break if ever we
   3629     are overwriting a larger file. */
   3630 
   3631     CLEANUPonERR(mMp4FileDataPtr->fileWriterFunctions->getOption(
   3632         mMp4FileDataPtr->fileWriterContext,
   3633         M4OSA_kFileWriteGetFileSize, (M4OSA_DataOption *) &moovPos));
   3634     /* moovPos will be used after writing the moov. */
   3635 
   3636 #endif /*_M4MP4W_MOOV_FIRST*/
   3637 
   3638     CLEANUPonERR(M4MP4W_putBE32(moovSize, mMp4FileDataPtr->fileWriterFunctions,
   3639         fileWriterContext));
   3640     CLEANUPonERR(M4MP4W_putBlock(CommonBlock3, sizeof(CommonBlock3),
   3641         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3642     CLEANUPonERR(M4MP4W_putBE32(creationTime,
   3643         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3644     CLEANUPonERR(M4MP4W_putBE32(creationTime,
   3645         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3646     CLEANUPonERR(M4MP4W_putBlock(CommonBlock4, sizeof(CommonBlock4),
   3647         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3648     CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->duration,
   3649         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3650     CLEANUPonERR(M4MP4W_putBlock(CommonBlock5, sizeof(CommonBlock5),
   3651         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3652 
   3653     if (bAudio)
   3654     {
   3655         CLEANUPonERR(M4MP4W_putBE32(a_trakSize,
   3656             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3657         CLEANUPonERR(M4MP4W_putBlock(CommonBlock6, sizeof(CommonBlock6),
   3658             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3659         CLEANUPonERR(M4MP4W_putBE32(creationTime,
   3660             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3661         CLEANUPonERR(M4MP4W_putBE32(creationTime,
   3662             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3663         CLEANUPonERR(M4MP4W_putBE32(a_trakId,
   3664             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3665         CLEANUPonERR(M4MP4W_putBlock(CommonBlock7, sizeof(CommonBlock7),
   3666             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3667         CLEANUPonERR(M4MP4W_putBE32(a_msTrakDuration,
   3668             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3669         CLEANUPonERR(M4MP4W_putBlock(CommonBlock7bis, sizeof(CommonBlock7bis),
   3670             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3671         CLEANUPonERR(M4MP4W_putBlock(AMRBlock1, sizeof(AMRBlock1),
   3672             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
   3673         CLEANUPonERR(M4MP4W_putBE32(a_mdiaSize,
   3674             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3675         CLEANUPonERR(M4MP4W_putBlock(CommonBlock8, sizeof(CommonBlock8),
   3676             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3677         CLEANUPonERR(M4MP4W_putBE32(creationTime,
   3678             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3679         CLEANUPonERR(M4MP4W_putBE32(creationTime,
   3680             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3681         CLEANUPonERR(
   3682             M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.timescale,
   3683             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3684         CLEANUPonERR(M4MP4W_putBE32(a_trakDuration,
   3685             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3686         CLEANUPonERR(M4MP4W_putBlock(CommonBlock9, sizeof(CommonBlock9),
   3687             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3688         CLEANUPonERR(M4MP4W_putBlock(AMRBlock1_1, sizeof(AMRBlock1_1),
   3689             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
   3690         CLEANUPonERR(M4MP4W_putBE32(a_minfSize,
   3691             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3692         CLEANUPonERR(M4MP4W_putBlock(CommonBlock10, sizeof(CommonBlock10),
   3693             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3694         CLEANUPonERR(M4MP4W_putBE32(a_stblSize,
   3695             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3696         CLEANUPonERR(M4MP4W_putBlock(CommonBlock11, sizeof(CommonBlock11),
   3697             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3698         CLEANUPonERR(M4MP4W_putBE32(a_sttsSize,
   3699             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3700         CLEANUPonERR(M4MP4W_putBlock(CommonBlock12, sizeof(CommonBlock12),
   3701             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3702 
   3703         CLEANUPonERR(M4MP4W_putBE32(
   3704             mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb - 1,
   3705             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3706         /*invert the table data to bigendian*/
   3707         M4MP4W_table32ToBE(mMp4FileDataPtr->audioTrackPtr->TABLE_STTS,
   3708             2 * (mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb
   3709             - 1));
   3710         CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
   3711             *)mMp4FileDataPtr->audioTrackPtr->TABLE_STTS,
   3712             ( mMp4FileDataPtr->audioTrackPtr->CommonData.sttsTableEntryNb - 1)
   3713             * 8,
   3714             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
   3715 
   3716         /* stsd */
   3717         CLEANUPonERR(M4MP4W_putBE32(a_stsdSize,
   3718             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3719         CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionHeader,
   3720             sizeof(SampleDescriptionHeader),
   3721             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3722         CLEANUPonERR(M4MP4W_putBE32(a_esdSize,
   3723             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3724 
   3725         /* sample desc entry inside stsd */
   3726         if (bAAC)
   3727         {
   3728             CLEANUPonERR(M4MP4W_putBlock(AACBlock1, sizeof(AACBlock1),
   3729                 mMp4FileDataPtr->fileWriterFunctions,
   3730                 fileWriterContext)); /*aac*/
   3731         }
   3732         else if (bEVRC)
   3733         {
   3734             CLEANUPonERR(M4MP4W_putBlock(EVRC8Block1, sizeof(EVRC8Block1),
   3735                 mMp4FileDataPtr->fileWriterFunctions,
   3736                 fileWriterContext)); /*evrc*/
   3737         }
   3738         else                         /*AMR8*/
   3739         {
   3740             CLEANUPonERR(M4MP4W_putBlock(AMR8Block1, sizeof(AMR8Block1),
   3741                 mMp4FileDataPtr->fileWriterFunctions,
   3742                 fileWriterContext)); /*amr8*/
   3743         }
   3744         CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryStart,
   3745             sizeof(SampleDescriptionEntryStart),
   3746             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3747         CLEANUPonERR(M4MP4W_putBlock(AudioSampleDescEntryBoilerplate,
   3748             sizeof(AudioSampleDescEntryBoilerplate),
   3749             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
   3750         CLEANUPonERR(
   3751             M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.timescale
   3752             << 16,
   3753             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3754 
   3755         /* DSI inside sample desc entry */
   3756         if (bAAC)
   3757         {
   3758             CLEANUPonERR(M4MP4W_putBE32(a_esdsSize,
   3759                 mMp4FileDataPtr->fileWriterFunctions,
   3760                 fileWriterContext)); /*aac*/
   3761             CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock0,
   3762                 sizeof(MPEGConfigBlock0), mMp4FileDataPtr->fileWriterFunctions,
   3763                 fileWriterContext)); /*aac*/
   3764             CLEANUPonERR(M4MP4W_putByte(a_ESDescriptorSize,
   3765                 mMp4FileDataPtr->fileWriterFunctions,
   3766                 fileWriterContext)); /*aac*/
   3767             CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock1,
   3768                 sizeof(MPEGConfigBlock1), mMp4FileDataPtr->fileWriterFunctions,
   3769                 fileWriterContext)); /*aac*/
   3770             CLEANUPonERR(M4MP4W_putByte(a_DCDescriptorSize,
   3771                 mMp4FileDataPtr->fileWriterFunctions,
   3772                 fileWriterContext)); /*aac*/
   3773             CLEANUPonERR(M4MP4W_putBlock(AACBlock2, sizeof(AACBlock2),
   3774                 mMp4FileDataPtr->fileWriterFunctions,
   3775                 fileWriterContext)); /*aac*/
   3776             CLEANUPonERR(
   3777                 M4MP4W_putBE24(mMp4FileDataPtr->audioTrackPtr->avgBitrate * 5,
   3778                 mMp4FileDataPtr->fileWriterFunctions,
   3779                 fileWriterContext)); /*aac*/
   3780             CLEANUPonERR(
   3781                 M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->maxBitrate,
   3782                 mMp4FileDataPtr->fileWriterFunctions,
   3783                 fileWriterContext)); /*aac*/
   3784             CLEANUPonERR(
   3785                 M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->avgBitrate,
   3786                 mMp4FileDataPtr->fileWriterFunctions,
   3787                 fileWriterContext)); /*aac*/
   3788             CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock2,
   3789                 sizeof(MPEGConfigBlock2), mMp4FileDataPtr->fileWriterFunctions,
   3790                 fileWriterContext)); /*aac*/
   3791             CLEANUPonERR(M4MP4W_putByte(mMp4FileDataPtr->audioTrackPtr->dsiSize,
   3792                 mMp4FileDataPtr->fileWriterFunctions,
   3793                 fileWriterContext)); /*aac*/
   3794             CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->DSI,
   3795                 mMp4FileDataPtr->audioTrackPtr->dsiSize,
   3796                 mMp4FileDataPtr->fileWriterFunctions,
   3797                 fileWriterContext)); /*aac*/
   3798             CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock3,
   3799                 sizeof(MPEGConfigBlock3), mMp4FileDataPtr->fileWriterFunctions,
   3800                 fileWriterContext)); /*aac*/
   3801         }
   3802         else if (bEVRC)
   3803         {
   3804             M4OSA_UInt8 localDsi[6];
   3805             M4OSA_UInt32 localI;
   3806 
   3807             CLEANUPonERR(M4MP4W_putBlock(EVRCBlock3_1, sizeof(EVRCBlock3_1),
   3808                 mMp4FileDataPtr->fileWriterFunctions,
   3809                 fileWriterContext)); /*audio*/
   3810 
   3811             /* copy the default block in a local variable*/
   3812             for ( localI = 0; localI < 6; localI++ )
   3813             {
   3814                 localDsi[localI] = EVRCBlock3_2[localI];
   3815             }
   3816             /* computes the number of sample per au */
   3817             /* and stores it in the DSI*/
   3818             /* assumes a char is enough to store the data*/
   3819             localDsi[5] =
   3820                 (M4OSA_UInt8)(mMp4FileDataPtr->audioTrackPtr->sampleDuration
   3821                 / 160)/*EVRC 1 frame duration*/;
   3822 
   3823             if (mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL)
   3824             {
   3825                 /* copy vendor name */
   3826                 for ( localI = 0; localI < 4; localI++ )
   3827                 {
   3828                     localDsi[localI] = (M4OSA_UInt8)(
   3829                         mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
   3830                 }
   3831             }
   3832             CLEANUPonERR(M4MP4W_putBlock(localDsi, 6,
   3833                 mMp4FileDataPtr->fileWriterFunctions,
   3834                 fileWriterContext)); /*audio*/
   3835         }
   3836         else                         /*AMR8*/
   3837         {
   3838             M4OSA_UInt8 localDsi[9];
   3839             M4OSA_UInt32 localI;
   3840 
   3841             CLEANUPonERR(M4MP4W_putBlock(AMRDSIHeader, sizeof(AMRDSIHeader),
   3842                 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3843 
   3844             /* copy the default block in a local variable*/
   3845             for ( localI = 0; localI < 9; localI++ )
   3846             {
   3847                 localDsi[localI] = AMRDefaultDSI[localI];
   3848             }
   3849             /* computes the number of sample per au */
   3850             /* and stores it in the DSI*/
   3851             /* assumes a char is enough to store the data*/
   3852             /* ALERT! The potential of the following line of code to explode in our face
   3853             is enormous when anything (sample rate or whatever) will change. This
   3854             calculation would be MUCH better handled by the VES or whatever deals with
   3855             the encoder more directly. */
   3856             localDsi[8] =
   3857                 (M4OSA_UInt8)(mMp4FileDataPtr->audioTrackPtr->sampleDuration
   3858                 / 160)/*AMR NB 1 frame duration*/;
   3859 
   3860             if (mMp4FileDataPtr->audioTrackPtr->DSI != M4OSA_NULL)
   3861             {
   3862                 /* copy vendor name */
   3863                 for ( localI = 0; localI < 4; localI++ )
   3864                 {
   3865                     localDsi[localI] = (M4OSA_UInt8)(
   3866                         mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
   3867                 }
   3868 
   3869                 /* copy the Mode Set */
   3870                 for ( localI = 5; localI < 7; localI++ )
   3871                 {
   3872                     localDsi[localI] = (M4OSA_UInt8)(
   3873                         mMp4FileDataPtr->audioTrackPtr->DSI[localI]);
   3874                 }
   3875             }
   3876             CLEANUPonERR(M4MP4W_putBlock(localDsi, 9,
   3877                 mMp4FileDataPtr->fileWriterFunctions,
   3878                 fileWriterContext)); /*audio*/
   3879         }
   3880 
   3881         /*end trak*/
   3882         CLEANUPonERR(M4MP4W_putBE32(a_stszSize,
   3883             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3884         CLEANUPonERR(M4MP4W_putBlock(CommonBlock15, sizeof(CommonBlock15),
   3885             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3886         CLEANUPonERR(M4MP4W_putBE32(
   3887             mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize,
   3888             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3889         CLEANUPonERR(
   3890             M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb,
   3891             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3892 
   3893         /*0 value for samplesize means not constant AU size*/
   3894         if (mMp4FileDataPtr->audioTrackPtr->CommonData.sampleSize == 0)
   3895         {
   3896             CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
   3897                 *)mMp4FileDataPtr->audioTrackPtr->TABLE_STSZ,
   3898                 mMp4FileDataPtr->audioTrackPtr->CommonData.sampleNb * 4,
   3899                 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3900         }
   3901 
   3902         CLEANUPonERR(M4MP4W_putBE32(a_stscSize,
   3903             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3904         CLEANUPonERR(M4MP4W_putBlock(CommonBlock16, sizeof(CommonBlock16),
   3905             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3906 
   3907 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   3908 
   3909         CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentStsc
   3910             + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3911 
   3912         for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentStsc; i++ )
   3913         {
   3914             CLEANUPonERR(M4MP4W_putBE32(
   3915                 ( mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable[i]
   3916             >> 12) + 1, mMp4FileDataPtr->fileWriterFunctions,
   3917                 fileWriterContext));
   3918             CLEANUPonERR(M4MP4W_putBE32((mMp4FileDataPtr->audioTrackPtr->
   3919                 chunkSampleNbTable[i] & 0xFFF),
   3920                 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3921             CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
   3922                 fileWriterContext));
   3923         }
   3924 
   3925 #else
   3926 
   3927         CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentChunk
   3928             + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3929 
   3930         for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
   3931         {
   3932             CLEANUPonERR(M4MP4W_putBE32(i + 1,
   3933                 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3934             CLEANUPonERR(M4MP4W_putBE32(
   3935                 mMp4FileDataPtr->audioTrackPtr->chunkSampleNbTable[i],
   3936                 mMp4FileDataPtr->fileWriterFunctions,
   3937                 fileWriterContext));
   3938             CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
   3939                 fileWriterContext));
   3940         }
   3941 
   3942 #endif
   3943 
   3944         CLEANUPonERR(M4MP4W_putBE32(a_stcoSize,
   3945             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3946         CLEANUPonERR(M4MP4W_putBlock(CommonBlock17, sizeof(CommonBlock17),
   3947             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3948         CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->audioTrackPtr->currentChunk
   3949             + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3950 
   3951 #ifdef _M4MP4W_MOOV_FIRST
   3952 
   3953         for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
   3954         {
   3955             CLEANUPonERR(M4MP4W_putBE32(a_trakOffset,
   3956                 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3957             a_trakOffset += mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
   3958 
   3959             if (( bInterleaveAV == M4OSA_TRUE)
   3960                 && (mMp4FileDataPtr->videoTrackPtr->currentChunk >= i))
   3961             {
   3962                 a_trakOffset +=
   3963                     mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
   3964             }
   3965         }
   3966 
   3967 #else
   3968 
   3969         for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk; i++ )
   3970         {
   3971             CLEANUPonERR(M4MP4W_putBE32(
   3972                 mMp4FileDataPtr->audioTrackPtr->chunkOffsetTable[i],
   3973                 mMp4FileDataPtr->fileWriterFunctions,
   3974                 fileWriterContext));
   3975         }
   3976 
   3977 #endif                                                                 /*_M4MP4W_MOOV_FIRST*/
   3978 
   3979         CLEANUPonERR(M4MP4W_putBlock(AMRBlock4, sizeof(AMRBlock4),
   3980             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*audio*/
   3981     }
   3982 
   3983     if (bVideo)
   3984     {
   3985         /*trak*/
   3986         CLEANUPonERR(M4MP4W_putBE32(v_trakSize,
   3987             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3988         CLEANUPonERR(M4MP4W_putBlock(CommonBlock6, sizeof(CommonBlock6),
   3989             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3990         CLEANUPonERR(M4MP4W_putBE32(creationTime,
   3991             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3992         CLEANUPonERR(M4MP4W_putBE32(creationTime,
   3993             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3994         CLEANUPonERR(M4MP4W_putBE32(v_trakId,
   3995             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3996         CLEANUPonERR(M4MP4W_putBlock(CommonBlock7, sizeof(CommonBlock7),
   3997             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   3998         CLEANUPonERR(M4MP4W_putBE32(v_msTrakDuration,
   3999             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4000         CLEANUPonERR(M4MP4W_putBlock(CommonBlock7bis, sizeof(CommonBlock7bis),
   4001             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4002 
   4003         /* In the track header width and height are 16.16 fixed point values,
   4004         so shift left the regular integer value by 16. */
   4005         CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->width << 16,
   4006             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4007         CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->height
   4008             << 16,
   4009             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4010 
   4011         CLEANUPonERR(M4MP4W_putBE32(v_mdiaSize,
   4012             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4013         CLEANUPonERR(M4MP4W_putBlock(CommonBlock8, sizeof(CommonBlock8),
   4014             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4015         CLEANUPonERR(M4MP4W_putBE32(creationTime,
   4016             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4017         CLEANUPonERR(M4MP4W_putBE32(creationTime,
   4018             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4019         CLEANUPonERR(
   4020             M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->CommonData.timescale,
   4021             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4022         CLEANUPonERR(M4MP4W_putBE32(v_trakDuration,
   4023             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4024         CLEANUPonERR(M4MP4W_putBlock(CommonBlock9, sizeof(CommonBlock9),
   4025             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4026         CLEANUPonERR(M4MP4W_putBlock(VideoBlock1_1, sizeof(VideoBlock1_1),
   4027             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4028         CLEANUPonERR(M4MP4W_putBE32(v_minfSize,
   4029             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4030         CLEANUPonERR(M4MP4W_putBlock(CommonBlock10, sizeof(CommonBlock10),
   4031             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4032         CLEANUPonERR(M4MP4W_putBE32(v_stblSize,
   4033             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4034         CLEANUPonERR(M4MP4W_putBlock(CommonBlock11, sizeof(CommonBlock11),
   4035             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4036         CLEANUPonERR(M4MP4W_putBE32(v_sttsSize,
   4037             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4038         CLEANUPonERR(M4MP4W_putBlock(CommonBlock12, sizeof(CommonBlock12),
   4039             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4040         CLEANUPonERR(M4MP4W_putBE32(
   4041             mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb,
   4042             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4043 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   4044 
   4045         for ( i = 0;
   4046             i < mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb;
   4047             i++ )
   4048         {
   4049             CLEANUPonERR(M4MP4W_putBE32(M4MP4W_get32_Lo(
   4050                 &mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[i]),
   4051                 mMp4FileDataPtr->fileWriterFunctions,
   4052                 fileWriterContext)); /*video*/
   4053             CLEANUPonERR(M4MP4W_putBE32(M4MP4W_get32_Hi(
   4054                 &mMp4FileDataPtr->videoTrackPtr->TABLE_STTS[i]),
   4055                 mMp4FileDataPtr->fileWriterFunctions,
   4056                 fileWriterContext)); /*video*/
   4057         }
   4058 
   4059 #else
   4060 
   4061         CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
   4062             *)mMp4FileDataPtr->videoTrackPtr->TABLE_STTS,
   4063             ( mMp4FileDataPtr->videoTrackPtr->CommonData.sttsTableEntryNb) * 8,
   4064             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4065 
   4066 #endif
   4067 
   4068         /* stsd */
   4069 
   4070         CLEANUPonERR(M4MP4W_putBE32(v_stsdSize,
   4071             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4072         CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionHeader,
   4073             sizeof(SampleDescriptionHeader),
   4074             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4075         CLEANUPonERR(M4MP4W_putBE32(v_esdSize,
   4076             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4077 
   4078         /* sample desc entry inside stsd */
   4079         if (bMP4V)
   4080         {
   4081             CLEANUPonERR(M4MP4W_putBlock(Mp4vBlock1, sizeof(Mp4vBlock1),
   4082                 mMp4FileDataPtr->fileWriterFunctions,
   4083                 fileWriterContext)); /*mp4v*/
   4084         }
   4085 
   4086         if (bH263)
   4087         {
   4088             CLEANUPonERR(M4MP4W_putBlock(H263Block1, sizeof(H263Block1),
   4089                 mMp4FileDataPtr->fileWriterFunctions,
   4090                 fileWriterContext)); /*h263*/
   4091         }
   4092 
   4093         if (bH264)
   4094         {
   4095             CLEANUPonERR(M4MP4W_putBlock(H264Block1, sizeof(H264Block1),
   4096                 mMp4FileDataPtr->fileWriterFunctions,
   4097                 fileWriterContext)); /*h264*/
   4098         }
   4099         CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryStart,
   4100             sizeof(SampleDescriptionEntryStart),
   4101             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4102         CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryVideoBoilerplate1,
   4103             sizeof(SampleDescriptionEntryVideoBoilerplate1),
   4104             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4105         CLEANUPonERR(M4MP4W_putBE16(mMp4FileDataPtr->videoTrackPtr->width,
   4106             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4107         CLEANUPonERR(M4MP4W_putBE16(mMp4FileDataPtr->videoTrackPtr->height,
   4108             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4109         CLEANUPonERR(M4MP4W_putBlock(VideoResolutions, sizeof(VideoResolutions),
   4110             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*mp4v*/
   4111         CLEANUPonERR(M4MP4W_putBlock(SampleDescriptionEntryVideoBoilerplate2,
   4112             sizeof(SampleDescriptionEntryVideoBoilerplate2),
   4113             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4114 
   4115         /* DSI inside sample desc entry */
   4116         if (bH263)
   4117         {
   4118             /* The h263 dsi given through the api must be 7 bytes, that is, it shall not include
   4119              the optional bitrate box. However, if the bitrate information is set in the stream
   4120              handler, a bitrate box is appended here to the dsi */
   4121             if (((M4OSA_Int32)mMp4FileDataPtr->videoTrackPtr->avgBitrate) != -1)
   4122             {
   4123                 CLEANUPonERR(M4MP4W_putBlock(H263Block2_bitr,
   4124                     sizeof(H263Block2_bitr),
   4125                     mMp4FileDataPtr->fileWriterFunctions,
   4126                     fileWriterContext)); /* d263 box with bitr atom */
   4127 
   4128                 if (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
   4129                 {
   4130                     CLEANUPonERR(M4MP4W_putBlock(H263Block3, sizeof(H263Block3),
   4131                         mMp4FileDataPtr->fileWriterFunctions,
   4132                         fileWriterContext)); /*h263*/
   4133                 }
   4134                 else
   4135                 {
   4136                     CLEANUPonERR(
   4137                         M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
   4138                         mMp4FileDataPtr->videoTrackPtr->dsiSize,
   4139                         mMp4FileDataPtr->fileWriterFunctions,
   4140                         fileWriterContext));
   4141                 }
   4142 
   4143                 CLEANUPonERR(M4MP4W_putBlock(H263Block4, sizeof(H263Block4),
   4144                     mMp4FileDataPtr->fileWriterFunctions,
   4145                     fileWriterContext)); /*h263*/
   4146                 /* Pierre Lebeaupin 2008/04/29: the two following lines used to be swapped;
   4147                 I changed to this order in order to conform to 3GPP. */
   4148                 CLEANUPonERR(
   4149                     M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->avgBitrate,
   4150                     mMp4FileDataPtr->fileWriterFunctions,
   4151                     fileWriterContext)); /*h263*/
   4152                 CLEANUPonERR(
   4153                     M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->maxBitrate,
   4154                     mMp4FileDataPtr->fileWriterFunctions,
   4155                     fileWriterContext)); /*h263*/
   4156             }
   4157             else
   4158             {
   4159                 CLEANUPonERR(M4MP4W_putBlock(H263Block2, sizeof(H263Block2),
   4160                     mMp4FileDataPtr->fileWriterFunctions,
   4161                     fileWriterContext)); /* d263 box */
   4162 
   4163                 if (M4OSA_NULL == mMp4FileDataPtr->videoTrackPtr->DSI)
   4164                 {
   4165                     CLEANUPonERR(M4MP4W_putBlock(H263Block3, sizeof(H263Block3),
   4166                         mMp4FileDataPtr->fileWriterFunctions,
   4167                         fileWriterContext)); /*h263*/
   4168                 }
   4169                 else
   4170                 {
   4171                     CLEANUPonERR(
   4172                         M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
   4173                         mMp4FileDataPtr->videoTrackPtr->dsiSize,
   4174                         mMp4FileDataPtr->fileWriterFunctions,
   4175                         fileWriterContext));
   4176                 }
   4177             }
   4178         }
   4179 
   4180         if (bMP4V)
   4181         {
   4182             M4OSA_UInt32 bufferSizeDB = 5 * mMp4FileDataPtr->videoTrackPtr->
   4183                 avgBitrate; /*bufferSizeDB set to 5 times the bitrate*/
   4184 
   4185             CLEANUPonERR(M4MP4W_putBE32(v_esdsSize,
   4186                 mMp4FileDataPtr->fileWriterFunctions,
   4187                 fileWriterContext)); /*mp4v*/
   4188             CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock0,
   4189                 sizeof(MPEGConfigBlock0), mMp4FileDataPtr->fileWriterFunctions,
   4190                 fileWriterContext)); /*mp4v*/
   4191             CLEANUPonERR(M4MP4W_putByte(v_ESDescriptorSize,
   4192                 mMp4FileDataPtr->fileWriterFunctions,
   4193                 fileWriterContext)); /*mp4v*/
   4194             CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock1,
   4195                 sizeof(MPEGConfigBlock1), mMp4FileDataPtr->fileWriterFunctions,
   4196                 fileWriterContext)); /*mp4v*/
   4197             CLEANUPonERR(M4MP4W_putByte(v_DCDescriptorSize,
   4198                 mMp4FileDataPtr->fileWriterFunctions,
   4199                 fileWriterContext)); /*mp4v*/
   4200             CLEANUPonERR(M4MP4W_putBlock(Mp4vBlock3, sizeof(Mp4vBlock3),
   4201                 mMp4FileDataPtr->fileWriterFunctions,
   4202                 fileWriterContext)); /*mp4v*/
   4203             CLEANUPonERR(M4MP4W_putBE24(bufferSizeDB,
   4204                 mMp4FileDataPtr->fileWriterFunctions,
   4205                 fileWriterContext)); /*mp4v*/
   4206             CLEANUPonERR(
   4207                 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->maxBitrate,
   4208                 mMp4FileDataPtr->fileWriterFunctions,
   4209                 fileWriterContext)); /*mp4v*/
   4210             CLEANUPonERR(
   4211                 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->avgBitrate,
   4212                 mMp4FileDataPtr->fileWriterFunctions,
   4213                 fileWriterContext)); /*mp4v*/
   4214             CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock2,
   4215                 sizeof(MPEGConfigBlock2), mMp4FileDataPtr->fileWriterFunctions,
   4216                 fileWriterContext)); /*mp4v*/
   4217             CLEANUPonERR(M4MP4W_putByte(mMp4FileDataPtr->videoTrackPtr->dsiSize,
   4218                 mMp4FileDataPtr->fileWriterFunctions,
   4219                 fileWriterContext)); /*mp4v*/
   4220             CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
   4221                 mMp4FileDataPtr->videoTrackPtr->dsiSize,
   4222                 mMp4FileDataPtr->fileWriterFunctions,
   4223                 fileWriterContext)); /*mp4v*/
   4224             CLEANUPonERR(M4MP4W_putBlock(MPEGConfigBlock3,
   4225                 sizeof(MPEGConfigBlock3), mMp4FileDataPtr->fileWriterFunctions,
   4226                 fileWriterContext)); /*mp4v*/
   4227         }
   4228 
   4229         if (bH264)
   4230         {
   4231             M4OSA_UInt16 ppsLentgh = 0; /* PPS length */
   4232             M4OSA_UInt16 spsLentgh = 0; /* SPS length */
   4233             M4OSA_UChar *tmpDSI = mMp4FileDataPtr->videoTrackPtr->DSI; /* DSI */
   4234             M4OSA_UInt16 NumberOfPPS;
   4235             M4OSA_UInt16 lCntPPS;
   4236 
   4237             /* Put the avcC (header + DSI) size */
   4238             CLEANUPonERR(M4MP4W_putBE32(v_avcCSize,
   4239                 mMp4FileDataPtr->fileWriterFunctions,
   4240                 fileWriterContext)); /*h264*/
   4241             /* Put the avcC header */
   4242             CLEANUPonERR(M4MP4W_putBlock(H264Block2, sizeof(H264Block2),
   4243                 mMp4FileDataPtr->fileWriterFunctions,
   4244                 fileWriterContext)); /*h264*/
   4245             /* Put the DSI (SPS + PPS) int the 3gp format*/
   4246             /* SPS length in BE */
   4247 
   4248             if ((0x01 != mMp4FileDataPtr->videoTrackPtr->DSI[0]) ||
   4249                  (0x42 != mMp4FileDataPtr->videoTrackPtr->DSI[1]))
   4250             {
   4251                 M4OSA_TRACE1_2("!!! M4MP4W_closeWrite ERROR : invalid AVCC 0x%X 0x%X",
   4252                     mMp4FileDataPtr->videoTrackPtr->DSI[0],
   4253                     mMp4FileDataPtr->videoTrackPtr->DSI[1]);
   4254                 return M4ERR_PARAMETER;
   4255             }
   4256             // Do not strip the DSI
   4257             CLEANUPonERR( M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->DSI,
   4258                 mMp4FileDataPtr->videoTrackPtr->dsiSize,
   4259                 mMp4FileDataPtr->fileWriterFunctions,
   4260                 fileWriterContext) );/*h264*/
   4261 
   4262         }
   4263 
   4264         /*end trak*/
   4265         CLEANUPonERR(M4MP4W_putBE32(v_stszSize,
   4266             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4267         CLEANUPonERR(M4MP4W_putBlock(CommonBlock15, sizeof(CommonBlock15),
   4268             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4269         CLEANUPonERR(M4MP4W_putBE32(
   4270             mMp4FileDataPtr->videoTrackPtr->CommonData.sampleSize,
   4271             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4272         CLEANUPonERR(
   4273             M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb,
   4274             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4275 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   4276 
   4277         for ( i = 0; i < mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb;
   4278             i++ )
   4279         {
   4280             CLEANUPonERR(
   4281                 M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ[i],
   4282                 mMp4FileDataPtr->fileWriterFunctions,
   4283                 fileWriterContext)); /*video*/
   4284         }
   4285 
   4286 #else
   4287 
   4288         CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
   4289             *)mMp4FileDataPtr->videoTrackPtr->TABLE_STSZ,
   4290             mMp4FileDataPtr->videoTrackPtr->CommonData.sampleNb * 4,
   4291             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4292 
   4293 #endif
   4294 
   4295         CLEANUPonERR(M4MP4W_putBE32(v_stscSize,
   4296             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4297         CLEANUPonERR(M4MP4W_putBlock(CommonBlock16, sizeof(CommonBlock16),
   4298             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4299 
   4300 #ifdef _M4MP4W_OPTIMIZE_FOR_PHONE
   4301 
   4302         CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentStsc
   4303             + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4304 
   4305         for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentStsc; i++ )
   4306         {
   4307             CLEANUPonERR(M4MP4W_putBE32(
   4308                 ( mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable[i]
   4309             >> 12) + 1, mMp4FileDataPtr->fileWriterFunctions,
   4310                 fileWriterContext));
   4311             CLEANUPonERR(M4MP4W_putBE32((mMp4FileDataPtr->videoTrackPtr->
   4312                 chunkSampleNbTable[i] & 0xFFF),
   4313                 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4314             CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
   4315                 fileWriterContext));
   4316         }
   4317 
   4318 #else
   4319 
   4320         CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentChunk
   4321             + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4322 
   4323         for (i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++)
   4324         {
   4325             CLEANUPonERR(M4MP4W_putBE32(i + 1,
   4326                 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4327             CLEANUPonERR(M4MP4W_putBE32(
   4328                 mMp4FileDataPtr->videoTrackPtr->chunkSampleNbTable[i],
   4329                 mMp4FileDataPtr->fileWriterFunctions,
   4330                 fileWriterContext));
   4331             CLEANUPonERR(M4MP4W_putBE32(1, mMp4FileDataPtr->fileWriterFunctions,
   4332                 fileWriterContext));
   4333         }
   4334 
   4335 #endif
   4336 
   4337         CLEANUPonERR(M4MP4W_putBE32(v_stcoSize,
   4338             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4339         CLEANUPonERR(M4MP4W_putBlock(CommonBlock17, sizeof(CommonBlock17),
   4340             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4341         CLEANUPonERR(M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->currentChunk
   4342             + 1, mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4343 
   4344 #ifdef _M4MP4W_MOOV_FIRST
   4345 
   4346         for (i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++)
   4347         {
   4348             if (( bInterleaveAV == M4OSA_TRUE)
   4349                 && (mMp4FileDataPtr->audioTrackPtr->currentChunk >= i))
   4350             {
   4351                 v_trakOffset +=
   4352                     mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i];
   4353             }
   4354             CLEANUPonERR(M4MP4W_putBE32(v_trakOffset,
   4355                 mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4356             v_trakOffset += mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i];
   4357         }
   4358 
   4359 #else
   4360 
   4361         for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk; i++ )
   4362         {
   4363             CLEANUPonERR(M4MP4W_putBE32(
   4364                 mMp4FileDataPtr->videoTrackPtr->chunkOffsetTable[i],
   4365                 mMp4FileDataPtr->fileWriterFunctions,
   4366                 fileWriterContext));
   4367         }
   4368 
   4369 #endif                                                                 /*_M4MP4W_MOOV_FIRST*/
   4370 
   4371         CLEANUPonERR(M4MP4W_putBE32(v_stssSize,
   4372             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4373         CLEANUPonERR(M4MP4W_putBlock(VideoBlock4, sizeof(VideoBlock4),
   4374             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4375         CLEANUPonERR(
   4376             M4MP4W_putBE32(mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb,
   4377             mMp4FileDataPtr->fileWriterFunctions,
   4378             fileWriterContext)); /*video*/
   4379         CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar
   4380             *)mMp4FileDataPtr->videoTrackPtr->TABLE_STSS,
   4381             mMp4FileDataPtr->videoTrackPtr->stssTableEntryNb * 4,
   4382             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4383         CLEANUPonERR(M4MP4W_putBlock(VideoBlock5, sizeof(VideoBlock5),
   4384             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext)); /*video*/
   4385     }
   4386 #ifdef _M4MP4W_MOOV_FIRST
   4387     /*mdat*/
   4388 
   4389     CLEANUPonERR(M4MP4W_putBE32(mdatSize, mMp4FileDataPtr->fileWriterFunctions,
   4390         fileWriterContext));
   4391     CLEANUPonERR(M4MP4W_putBlock(CommonBlock2, sizeof(CommonBlock2),
   4392         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4393 
   4394     /*write data, according to the interleave mode (default is not interleaved)*/
   4395     if (bInterleaveAV == M4OSA_FALSE)
   4396     {
   4397         if (bAudio)
   4398         {
   4399             for ( i = 0; i <= mMp4FileDataPtr->audioTrackPtr->currentChunk;
   4400                 i++ )
   4401             {
   4402                 CLEANUPonERR(
   4403                     M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[i],
   4404                     mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i],
   4405                     mMp4FileDataPtr->fileWriterFunctions,
   4406                     fileWriterContext)); /*audio (previously a_dataSize)*/
   4407             }
   4408         }
   4409 
   4410         if (bVideo)
   4411         {
   4412             for ( i = 0; i <= mMp4FileDataPtr->videoTrackPtr->currentChunk;
   4413                 i++ )
   4414             {
   4415                 CLEANUPonERR(
   4416                     M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[i],
   4417                     mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i],
   4418                     mMp4FileDataPtr->fileWriterFunctions,
   4419                     fileWriterContext)); /*video (previously a_dataSize)*/
   4420             }
   4421         }
   4422     }
   4423     else /*in this mode, we have audio and video to interleave*/
   4424     {
   4425         for ( i = 0; i <= max(mMp4FileDataPtr->audioTrackPtr->currentChunk,
   4426             mMp4FileDataPtr->videoTrackPtr->currentChunk); i++ )
   4427         {
   4428             if (i <= mMp4FileDataPtr->audioTrackPtr->currentChunk)
   4429             {
   4430                 CLEANUPonERR(
   4431                     M4MP4W_putBlock(mMp4FileDataPtr->audioTrackPtr->Chunk[i],
   4432                     mMp4FileDataPtr->audioTrackPtr->chunkSizeTable[i],
   4433                     mMp4FileDataPtr->fileWriterFunctions,
   4434                     fileWriterContext)); /*audio (previously a_dataSize)*/
   4435             }
   4436 
   4437             if (i <= mMp4FileDataPtr->videoTrackPtr->currentChunk)
   4438             {
   4439                 CLEANUPonERR(
   4440                     M4MP4W_putBlock(mMp4FileDataPtr->videoTrackPtr->Chunk[i],
   4441                     mMp4FileDataPtr->videoTrackPtr->chunkSizeTable[i],
   4442                     mMp4FileDataPtr->fileWriterFunctions,
   4443                     fileWriterContext)); /*video (previously a_dataSize)*/
   4444             }
   4445         }
   4446     }
   4447 
   4448 #endif /*_M4MP4W_MOOV_FIRST*/
   4449 
   4450     /*skip*/
   4451 
   4452     CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipHeader,
   4453         sizeof(BlockSignatureSkipHeader), mMp4FileDataPtr->fileWriterFunctions,
   4454         fileWriterContext));
   4455 
   4456     /* Write embedded string */
   4457     if (mMp4FileDataPtr->embeddedString == M4OSA_NULL)
   4458     {
   4459         CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipDefaultEmbeddedString,
   4460             sizeof(BlockSignatureSkipDefaultEmbeddedString),
   4461             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4462     }
   4463     else
   4464     {
   4465         CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->embeddedString, 16,
   4466             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4467     }
   4468 
   4469     /* Write ves core version */
   4470     camcoder_maj = (M4OSA_UChar)(mMp4FileDataPtr->camcoderVersion / 100);
   4471     camcoder_min =
   4472         (M4OSA_UChar)(( mMp4FileDataPtr->camcoderVersion - 100 * camcoder_maj)
   4473         / 10);
   4474     camcoder_rev =
   4475         (M4OSA_UChar)(mMp4FileDataPtr->camcoderVersion - 100 * camcoder_maj - 10
   4476         * camcoder_min);
   4477 
   4478     CLEANUPonERR(M4MP4W_putByte(' ', mMp4FileDataPtr->fileWriterFunctions,
   4479         fileWriterContext));
   4480     CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_maj + '0'),
   4481         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4482     CLEANUPonERR(M4MP4W_putByte('.', mMp4FileDataPtr->fileWriterFunctions,
   4483         fileWriterContext));
   4484     CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_min + '0'),
   4485         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4486     CLEANUPonERR(M4MP4W_putByte('.', mMp4FileDataPtr->fileWriterFunctions,
   4487         fileWriterContext));
   4488     CLEANUPonERR(M4MP4W_putByte((M4OSA_UChar)(camcoder_rev + '0'),
   4489         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4490 
   4491     /* Write integration tag */
   4492     CLEANUPonERR(M4MP4W_putBlock((const M4OSA_UChar *)" -- ", 4,
   4493         mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4494 
   4495     if (mMp4FileDataPtr->integrationTag == M4OSA_NULL)
   4496     {
   4497         CLEANUPonERR(M4MP4W_putBlock(BlockSignatureSkipDefaultIntegrationTag,
   4498             sizeof(BlockSignatureSkipDefaultIntegrationTag),
   4499             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4500     }
   4501     else
   4502     {
   4503         CLEANUPonERR(M4MP4W_putBlock(mMp4FileDataPtr->integrationTag, 60,
   4504             mMp4FileDataPtr->fileWriterFunctions, fileWriterContext));
   4505     }
   4506 
   4507 #ifndef _M4MP4W_MOOV_FIRST
   4508     /*overwrite mdat size*/
   4509 
   4510     if (mMp4FileDataPtr->ftyp.major_brand != 0)
   4511         mdatPos= 16 + mMp4FileDataPtr->ftyp.nbCompatibleBrands * 4;
   4512     else
   4513         mdatPos = 24;
   4514 
   4515     moovPos = moovPos - mdatPos;
   4516     mdatSize = moovPos;
   4517 
   4518     CLEANUPonERR(mMp4FileDataPtr->fileWriterFunctions->seek(fileWriterContext,
   4519         M4OSA_kFileSeekBeginning, &mdatPos)); /*seek after ftyp...*/
   4520     CLEANUPonERR(M4MP4W_putBE32(mdatSize, mMp4FileDataPtr->fileWriterFunctions,
   4521         fileWriterContext));
   4522 
   4523 #endif                                        /*_M4MP4W_MOOV_FIRST*/
   4524 
   4525 cleanup:
   4526 
   4527     /**
   4528     * Close the file even if an error occured */
   4529     if (M4OSA_NULL != mMp4FileDataPtr->fileWriterContext)
   4530     {
   4531         err2 =
   4532             mMp4FileDataPtr->fileWriterFunctions->closeWrite(mMp4FileDataPtr->
   4533             fileWriterContext); /**< close the stream anyway */
   4534 
   4535         if (M4NO_ERROR != err2)
   4536         {
   4537             M4OSA_TRACE1_1(
   4538                 "M4MP4W_closeWrite: fileWriterFunctions->closeWrite returns 0x%x",
   4539                 err2);
   4540         }
   4541         mMp4FileDataPtr->fileWriterContext = M4OSA_NULL;
   4542     }
   4543 
   4544 #ifdef _M4MP4W_RESERVED_MOOV_DISK_SPACE
   4545     /* Remove safety file if still present (here it is cleanup in case of error and NOT the normal
   4546     removal of the safety file to free emergency space for the moov). */
   4547 
   4548     if (M4OSA_TRUE == mMp4FileDataPtr->cleanSafetyFile)
   4549     {
   4550         M4OSA_Context tempContext;
   4551         err3 = mMp4FileDataPtr->fileWriterFunctions->openWrite(&tempContext,
   4552             mMp4FileDataPtr->safetyFileUrl,
   4553             M4OSA_kFileWrite | M4OSA_kFileCreate);
   4554 
   4555         if (M4NO_ERROR != err2)
   4556             err2 = err3;
   4557 
   4558         if (M4NO_ERROR
   4559             != err3) /* No sense closing if we couldn't open in the first place. */
   4560         {
   4561             err3 =
   4562                 mMp4FileDataPtr->fileWriterFunctions->closeWrite(tempContext);
   4563 
   4564             if (M4NO_ERROR != err2)
   4565                 err2 = err3;
   4566         }
   4567         mMp4FileDataPtr->safetyFileUrl = M4OSA_NULL;
   4568         mMp4FileDataPtr->cleanSafetyFile = M4OSA_FALSE;
   4569     }
   4570 
   4571 #endif /* _M4MP4W_RESERVED_MOOV_DISK_SPACE */
   4572 
   4573     /* Delete embedded string */
   4574 
   4575     if (M4OSA_NULL != mMp4FileDataPtr->embeddedString)
   4576     {
   4577         free(mMp4FileDataPtr->embeddedString);
   4578         mMp4FileDataPtr->embeddedString = M4OSA_NULL;
   4579     }
   4580 
   4581     /* Delete integration tag */
   4582     if (M4OSA_NULL != mMp4FileDataPtr->integrationTag)
   4583     {
   4584         free(mMp4FileDataPtr->integrationTag);
   4585         mMp4FileDataPtr->integrationTag = M4OSA_NULL;
   4586     }
   4587 
   4588     /**
   4589     * M4MP4W_freeContext() is now a private method, called only from here*/
   4590     err3 = M4MP4W_freeContext(context);
   4591 
   4592     if (M4NO_ERROR != err3)
   4593     {
   4594         M4OSA_TRACE1_1("M4MP4W_closeWrite: M4MP4W_freeContext returns 0x%x",
   4595             err3);
   4596     }
   4597 
   4598     /**
   4599     * Choose which error code to return */
   4600     if (M4NO_ERROR != err)
   4601     {
   4602         /**
   4603         * We give priority to main error */
   4604         M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err=0x%x", err);
   4605         return err;
   4606     }
   4607     else if (M4NO_ERROR != err2)
   4608     {
   4609         /**
   4610         * Error from closeWrite is returned if there is no main error */
   4611         M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err2=0x%x", err2);
   4612         return err2;
   4613     }
   4614     else
   4615     {
   4616         /**
   4617         * Error from M4MP4W_freeContext is returned only if there is no main error and
   4618           no close error */
   4619         M4OSA_TRACE1_1("M4MP4W_closeWrite: returning err3=0x%x", err3);
   4620         return err3;
   4621     }
   4622 }
   4623 
   4624 /*******************************************************************************/
   4625 M4OSA_ERR M4MP4W_getOption( M4OSA_Context context, M4OSA_OptionID option,
   4626                            M4OSA_DataOption *valuePtr )
   4627 /*******************************************************************************/
   4628 {
   4629     M4OSA_ERR err = M4NO_ERROR;
   4630 
   4631     M4SYS_StreamIDValue *streamIDvaluePtr = M4OSA_NULL;
   4632     M4MP4W_StreamIDsize *streamIDsizePtr = M4OSA_NULL;
   4633     M4MP4W_memAddr *memAddrPtr = M4OSA_NULL;
   4634     /*    M4MP4W_WriteCallBack*    callBackPtr = M4OSA_NULL;*/
   4635 
   4636     M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
   4637     ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
   4638 
   4639     ERR_CHECK(( mMp4FileDataPtr->state == M4MP4W_opened)
   4640         || (mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
   4641 
   4642     switch( option )
   4643     {
   4644         case (M4MP4W_maxAUperChunk):
   4645             return M4ERR_NOT_IMPLEMENTED;
   4646 
   4647         case (M4MP4W_maxChunkSize):
   4648 
   4649             streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
   4650 
   4651             switch( streamIDvaluePtr->streamID )
   4652             {
   4653                 case (AudioStreamID):
   4654                     if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
   4655                         return M4ERR_BAD_STREAM_ID;
   4656                     else
   4657                         streamIDvaluePtr->value =
   4658                         mMp4FileDataPtr->audioTrackPtr->MaxChunkSize;
   4659                     break;
   4660 
   4661                 case (VideoStreamID):
   4662                     if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
   4663                         return M4ERR_BAD_STREAM_ID;
   4664                     else
   4665                         streamIDvaluePtr->value =
   4666                         mMp4FileDataPtr->videoTrackPtr->MaxChunkSize;
   4667                     break;
   4668 
   4669                 case (0): /*all streams*/
   4670                     streamIDvaluePtr->value = mMp4FileDataPtr->MaxChunkSize;
   4671                     break;
   4672 
   4673                 default:
   4674                     return M4ERR_BAD_STREAM_ID;
   4675         }
   4676 
   4677         break;
   4678 
   4679     case (M4MP4W_maxChunkInter):
   4680 
   4681         streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
   4682 
   4683         switch( streamIDvaluePtr->streamID )
   4684         {
   4685             case (0): /*all streams*/
   4686                 streamIDvaluePtr->value = (M4OSA_UInt32)mMp4FileDataPtr->
   4687                     InterleaveDur; /*time conversion !*/
   4688                 break;
   4689 
   4690             default:
   4691                 return M4ERR_BAD_STREAM_ID;
   4692         }
   4693         break;
   4694 
   4695     case (M4MP4W_embeddedString):
   4696         memAddrPtr = (M4MP4W_memAddr *)(*valuePtr);
   4697         /*memAddrPtr must have been already allocated by the caller
   4698         and memAddrPtr->size initialized with the max possible length in bytes*/
   4699         ERR_CHECK(memAddrPtr->size >= 16, M4ERR_PARAMETER);
   4700         ERR_CHECK(memAddrPtr->addr != M4OSA_NULL, M4ERR_PARAMETER);
   4701         /*memAddrPtr->size is updated with the actual size of the string*/
   4702         memAddrPtr->size = 16;
   4703         /*if no value was set, return the default string */
   4704         if (mMp4FileDataPtr->embeddedString != M4OSA_NULL)
   4705             memcpy((void *)memAddrPtr->addr,
   4706             (void *)mMp4FileDataPtr->embeddedString, 16);
   4707         else
   4708             memcpy((void *)memAddrPtr->addr,
   4709             (void *)BlockSignatureSkipDefaultEmbeddedString,
   4710             16);
   4711         break;
   4712 
   4713     case (M4MP4W_integrationTag):
   4714         memAddrPtr = (M4MP4W_memAddr *)(*valuePtr);
   4715         /*memAddrPtr must have been already allocated by the caller
   4716         and memAddrPtr->size initialized with the max possible length in bytes*/
   4717         ERR_CHECK(memAddrPtr->size >= 60, M4ERR_PARAMETER);
   4718         ERR_CHECK(memAddrPtr->addr != M4OSA_NULL, M4ERR_PARAMETER);
   4719         /*memAddrPtr->size is updated with the actual size of the string*/
   4720         memAddrPtr->size = 60;
   4721         /*if no value was set, return the default string 0 */
   4722         if (mMp4FileDataPtr->integrationTag != M4OSA_NULL)
   4723             memcpy((void *)memAddrPtr->addr,
   4724             (void *)mMp4FileDataPtr->integrationTag, 60);
   4725         else
   4726             memcpy((void *)memAddrPtr->addr,
   4727             (void *)BlockSignatureSkipDefaultIntegrationTag,
   4728             60);
   4729         break;
   4730 
   4731     case (M4MP4W_CamcoderVersion):
   4732 
   4733         streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
   4734 
   4735         switch( streamIDvaluePtr->streamID )
   4736         {
   4737             case (0): /*all streams*/
   4738                 streamIDvaluePtr->value = mMp4FileDataPtr->camcoderVersion;
   4739                 break;
   4740 
   4741             default:
   4742                 return M4ERR_BAD_STREAM_ID;
   4743         }
   4744         break;
   4745 
   4746     case (M4MP4W_preWriteCallBack):
   4747         return M4ERR_NOT_IMPLEMENTED;
   4748         /*callBackPtr = (M4MP4W_WriteCallBack*)(*valuePtr);
   4749         *callBackPtr = mMp4FileDataPtr->PreWriteCallBack;
   4750         break;*/
   4751 
   4752     case (M4MP4W_postWriteCallBack):
   4753         return M4ERR_NOT_IMPLEMENTED;
   4754         /*callBackPtr = (M4MP4W_WriteCallBack*)(*valuePtr);
   4755         *callBackPtr = mMp4FileDataPtr->PostWriteCallBack;
   4756         break;*/
   4757 
   4758     case (M4MP4W_maxAUsize):
   4759 
   4760         streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
   4761 
   4762         switch( streamIDvaluePtr->streamID )
   4763         {
   4764             case (AudioStreamID):
   4765                 if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
   4766                     return M4ERR_BAD_STREAM_ID;
   4767                 else
   4768                     streamIDvaluePtr->value =
   4769                     mMp4FileDataPtr->audioTrackPtr->MaxAUSize;
   4770                 break;
   4771 
   4772             case (VideoStreamID):
   4773                 if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
   4774                     return M4ERR_BAD_STREAM_ID;
   4775                 else
   4776                     streamIDvaluePtr->value =
   4777                     mMp4FileDataPtr->videoTrackPtr->MaxAUSize;
   4778                 break;
   4779 
   4780             case (0): /*all streams*/
   4781                 streamIDvaluePtr->value = mMp4FileDataPtr->MaxAUSize;
   4782                 break;
   4783 
   4784             default:
   4785                 return M4ERR_BAD_STREAM_ID;
   4786         }
   4787 
   4788         break;
   4789 
   4790     case (M4MP4W_IOD):
   4791         return M4ERR_NOT_IMPLEMENTED;
   4792 
   4793     case (M4MP4W_ESD):
   4794         return M4ERR_NOT_IMPLEMENTED;
   4795 
   4796     case (M4MP4W_SDP):
   4797         return M4ERR_NOT_IMPLEMENTED;
   4798 
   4799     case (M4MP4W_trackSize):
   4800         streamIDsizePtr = (M4MP4W_StreamIDsize *)(*valuePtr);
   4801         streamIDsizePtr->width = mMp4FileDataPtr->videoTrackPtr->width;
   4802         streamIDsizePtr->height = mMp4FileDataPtr->videoTrackPtr->height;
   4803         break;
   4804 
   4805     case (M4MP4W_estimateAudioSize):
   4806         streamIDvaluePtr = (M4SYS_StreamIDValue *)(*valuePtr);
   4807         streamIDvaluePtr->value =
   4808             (M4OSA_UInt32)mMp4FileDataPtr->estimateAudioSize;
   4809         break;
   4810 
   4811     case (M4MP4W_MOOVfirst):
   4812         return M4ERR_NOT_IMPLEMENTED;
   4813 
   4814     case (M4MP4W_V2_MOOF):
   4815         return M4ERR_NOT_IMPLEMENTED;
   4816 
   4817     case (M4MP4W_V2_tblCompres):
   4818         return M4ERR_NOT_IMPLEMENTED;
   4819 
   4820     default:
   4821         return M4ERR_BAD_OPTION_ID;
   4822     }
   4823 
   4824     return err;
   4825 }
   4826 
   4827 /*******************************************************************************/
   4828 M4OSA_ERR M4MP4W_setOption( M4OSA_Context context, M4OSA_OptionID option,
   4829                            M4OSA_DataOption value )
   4830 /*******************************************************************************/
   4831 {
   4832     M4OSA_ERR err = M4NO_ERROR;
   4833 
   4834     M4SYS_StreamIDValue *streamIDvaluePtr = M4OSA_NULL;
   4835     M4MP4W_StreamIDsize *streamIDsizePtr = M4OSA_NULL;
   4836     M4MP4W_memAddr *memAddrPtr = M4OSA_NULL;
   4837     M4SYS_StreamIDmemAddr *streamIDmemAddrPtr;
   4838 
   4839     M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
   4840     ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
   4841 
   4842     /* Verify state */
   4843     switch( option )
   4844     {
   4845         case M4MP4W_maxFileDuration:
   4846         case M4MP4W_DSI:
   4847             /* this param can be set at the end of a recording */
   4848             ERR_CHECK((mMp4FileDataPtr->state != M4MP4W_closed), M4ERR_STATE);
   4849             break;
   4850 
   4851         case M4MP4W_setFtypBox:
   4852             /* this param can only be set before starting any write */
   4853             ERR_CHECK(mMp4FileDataPtr->state == M4MP4W_opened, M4ERR_STATE);
   4854             break;
   4855 
   4856         default:
   4857             /* in general params can be set at open or ready stage */
   4858             ERR_CHECK(( mMp4FileDataPtr->state == M4MP4W_opened)
   4859                 || (mMp4FileDataPtr->state == M4MP4W_ready), M4ERR_STATE);
   4860     }
   4861 
   4862     /* Set option */
   4863     switch( option )
   4864     {
   4865         case (M4MP4W_maxAUperChunk):
   4866             return M4ERR_NOT_IMPLEMENTED;
   4867 
   4868         case (M4MP4W_maxChunkSize):
   4869 
   4870             streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
   4871 
   4872             switch( streamIDvaluePtr->streamID )
   4873             {
   4874                 case (AudioStreamID):
   4875                     if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
   4876                         return
   4877                         M4ERR_BAD_STREAM_ID; /*maybe the stream has not been added yet*/
   4878                     else
   4879                     {
   4880                         mMp4FileDataPtr->audioTrackPtr->MaxChunkSize =
   4881                             streamIDvaluePtr->value;
   4882                     }
   4883 
   4884                     break;
   4885 
   4886                 case (VideoStreamID):
   4887                     if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
   4888                         return
   4889                         M4ERR_BAD_STREAM_ID; /*maybe the stream has not been added yet*/
   4890                     else
   4891                     {
   4892                         mMp4FileDataPtr->videoTrackPtr->MaxChunkSize =
   4893                             streamIDvaluePtr->value;
   4894                     }
   4895                     break;
   4896 
   4897                 case (0): /*all streams*/
   4898 
   4899                     /*In M4MP4W_opened state, no stream is present yet, so only global value
   4900                     needs to be updated.*/
   4901                     mMp4FileDataPtr->MaxChunkSize = streamIDvaluePtr->value;
   4902 
   4903                     if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
   4904                     {
   4905                         mMp4FileDataPtr->audioTrackPtr->MaxChunkSize =
   4906                             streamIDvaluePtr->value;
   4907                     }
   4908 
   4909                     if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
   4910                     {
   4911                         mMp4FileDataPtr->videoTrackPtr->MaxChunkSize =
   4912                             streamIDvaluePtr->value;
   4913                     }
   4914                     break;
   4915 
   4916                 default:
   4917                     return M4ERR_BAD_STREAM_ID;
   4918             }
   4919             break;
   4920 
   4921         case (M4MP4W_maxChunkInter):
   4922 
   4923             streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
   4924 
   4925             switch( streamIDvaluePtr->streamID )
   4926             {
   4927                 case (0):                                       /*all streams*/
   4928                     mMp4FileDataPtr->InterleaveDur =
   4929                         (M4MP4W_Time32)streamIDvaluePtr->
   4930                         value; /*time conversion!*/
   4931                     break;
   4932 
   4933                 default:
   4934                     return M4ERR_BAD_STREAM_ID;
   4935                     /*not meaningfull to set this parameter on a streamID basis*/
   4936             }
   4937             break;
   4938 
   4939         case (M4MP4W_maxFileSize):
   4940             mMp4FileDataPtr->MaxFileSize = *(M4OSA_UInt32 *)value;
   4941             break;
   4942 
   4943         case (M4MP4W_embeddedString):
   4944             memAddrPtr = (M4MP4W_memAddr *)value;
   4945             /*
   4946             * If memAddrPtr->size > 16 bytes, then the string will be truncated.
   4947             * If memAddrPtr->size < 16 bytes, then return M4ERR_PARAMETER
   4948             */
   4949             ERR_CHECK(memAddrPtr->size >= 16, M4ERR_PARAMETER);
   4950 
   4951             if (mMp4FileDataPtr->embeddedString == M4OSA_NULL)
   4952             {
   4953                 mMp4FileDataPtr->embeddedString =
   4954                     (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(16, M4MP4_WRITER,
   4955                     (M4OSA_Char *)"embeddedString");
   4956                 ERR_CHECK(mMp4FileDataPtr->embeddedString != M4OSA_NULL,
   4957                     M4ERR_ALLOC);
   4958             }
   4959             /*else, just overwrite the previously set string*/
   4960             memcpy((void *)mMp4FileDataPtr->embeddedString,
   4961                 (void *)memAddrPtr->addr, 16);
   4962             break;
   4963 
   4964         case (M4MP4W_integrationTag):
   4965             memAddrPtr = (M4MP4W_memAddr *)value;
   4966             /*
   4967             * If memAddrPtr->size > 60 bytes, then the string will be truncated.
   4968             * If memAddrPtr->size < 60 bytes, then pad with 0
   4969             */
   4970             if (mMp4FileDataPtr->integrationTag == M4OSA_NULL)
   4971             {
   4972                 mMp4FileDataPtr->integrationTag =
   4973                     (M4OSA_UChar *)M4OSA_32bitAlignedMalloc(60, M4MP4_WRITER,
   4974                     (M4OSA_Char *)"integrationTag");
   4975                 ERR_CHECK(mMp4FileDataPtr->integrationTag != M4OSA_NULL,
   4976                     M4ERR_ALLOC);
   4977             }
   4978             /*else, just overwrite the previously set string*/
   4979             if (memAddrPtr->size < 60)
   4980             {
   4981                 memcpy((void *)mMp4FileDataPtr->integrationTag,
   4982                     (void *)BlockSignatureSkipDefaultIntegrationTag,
   4983                     60);
   4984                 memcpy((void *)mMp4FileDataPtr->integrationTag,
   4985                     (void *)memAddrPtr->addr, memAddrPtr->size);
   4986             }
   4987             else
   4988             {
   4989                 memcpy((void *)mMp4FileDataPtr->integrationTag,
   4990                     (void *)memAddrPtr->addr, 60);
   4991             }
   4992             break;
   4993 
   4994         case (M4MP4W_CamcoderVersion):
   4995 
   4996             streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
   4997 
   4998             switch( streamIDvaluePtr->streamID )
   4999             {
   5000                 case (0): /*all streams*/
   5001                     mMp4FileDataPtr->camcoderVersion = streamIDvaluePtr->value;
   5002                     break;
   5003 
   5004                 default:
   5005                     return M4ERR_BAD_STREAM_ID;
   5006                     /*not meaningfull to set this parameter on a streamID basis*/
   5007             }
   5008             break;
   5009 
   5010         case (M4MP4W_preWriteCallBack):
   5011             return M4ERR_NOT_IMPLEMENTED;
   5012             /*mMp4FileDataPtr->PreWriteCallBack = *(M4MP4W_WriteCallBack*)value;
   5013             break;*/
   5014 
   5015         case (M4MP4W_postWriteCallBack):
   5016             return M4ERR_NOT_IMPLEMENTED;
   5017             /*mMp4FileDataPtr->PostWriteCallBack = *(M4MP4W_WriteCallBack*)value;
   5018             break;*/
   5019 
   5020         case (M4MP4W_maxAUsize):
   5021 
   5022             streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
   5023 
   5024             switch( streamIDvaluePtr->streamID )
   5025             {
   5026                 case (AudioStreamID):
   5027 
   5028                     /*if (mMp4FileDataPtr->audioTrackPtr == M4OSA_NULL)*/
   5029                     if (mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
   5030                         return M4ERR_BAD_STREAM_ID;
   5031                     else
   5032                         mMp4FileDataPtr->audioTrackPtr->MaxAUSize =
   5033                         streamIDvaluePtr->value;
   5034                     break;
   5035 
   5036                 case (VideoStreamID):
   5037 
   5038                     /*if (mMp4FileDataPtr->videoTrackPtr == M4OSA_NULL)*/
   5039                     if (mMp4FileDataPtr->hasVideo == M4OSA_FALSE)
   5040                         return M4ERR_BAD_STREAM_ID;
   5041                     else
   5042                         mMp4FileDataPtr->videoTrackPtr->MaxAUSize =
   5043                         streamIDvaluePtr->value;
   5044                     break;
   5045 
   5046                 case (0): /*all streams*/
   5047 
   5048                     mMp4FileDataPtr->MaxAUSize = streamIDvaluePtr->value;
   5049 
   5050                     if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
   5051                         mMp4FileDataPtr->audioTrackPtr->MaxAUSize =
   5052                         streamIDvaluePtr->value;
   5053 
   5054                     if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
   5055                         mMp4FileDataPtr->videoTrackPtr->MaxAUSize =
   5056                         streamIDvaluePtr->value;
   5057 
   5058                     break;
   5059 
   5060                 default:
   5061                     return M4ERR_BAD_STREAM_ID;
   5062             }
   5063             break;
   5064 
   5065         case (M4MP4W_IOD):
   5066             return M4ERR_NOT_IMPLEMENTED;
   5067 
   5068         case (M4MP4W_ESD):
   5069             return M4ERR_NOT_IMPLEMENTED;
   5070 
   5071         case (M4MP4W_SDP):
   5072             return M4ERR_NOT_IMPLEMENTED;
   5073 
   5074         case (M4MP4W_trackSize):
   5075 
   5076             streamIDsizePtr = (M4MP4W_StreamIDsize *)value;
   5077 
   5078             if ((streamIDsizePtr->streamID != VideoStreamID)
   5079                 || (mMp4FileDataPtr->hasVideo == M4OSA_FALSE))
   5080                 return M4ERR_BAD_STREAM_ID;
   5081             else
   5082             {
   5083                 mMp4FileDataPtr->videoTrackPtr->width = streamIDsizePtr->width;
   5084                 mMp4FileDataPtr->videoTrackPtr->height =
   5085                     streamIDsizePtr->height;
   5086             }
   5087             break;
   5088 
   5089         case (M4MP4W_estimateAudioSize):
   5090 
   5091             streamIDvaluePtr = (M4SYS_StreamIDValue *)value;
   5092 
   5093             /*shall not set this option before audio and video streams were added*/
   5094             /*nonsense to set this option if not in case audio+video*/
   5095             if ((mMp4FileDataPtr->hasAudio == M4OSA_FALSE)
   5096                 || (mMp4FileDataPtr->hasVideo == M4OSA_FALSE))
   5097                 return M4ERR_STATE;
   5098 
   5099             mMp4FileDataPtr->estimateAudioSize =
   5100                 (M4OSA_Bool)streamIDvaluePtr->value;
   5101             break;
   5102 
   5103         case (M4MP4W_MOOVfirst):
   5104             return M4ERR_NOT_IMPLEMENTED;
   5105 
   5106         case (M4MP4W_V2_MOOF):
   5107             return M4ERR_NOT_IMPLEMENTED;
   5108 
   5109         case (M4MP4W_V2_tblCompres):
   5110             return M4ERR_NOT_IMPLEMENTED;
   5111 
   5112         case (M4MP4W_maxFileDuration):
   5113             mMp4FileDataPtr->MaxFileDuration = *(M4OSA_UInt32 *)value;
   5114             break;
   5115 
   5116         case (M4MP4W_setFtypBox):
   5117             {
   5118                 M4OSA_UInt32 size;
   5119 
   5120                 ERR_CHECK(( (M4MP4C_FtypBox *)value)->major_brand != 0,
   5121                     M4ERR_PARAMETER);
   5122 
   5123                 /* Copy structure */
   5124                 mMp4FileDataPtr->ftyp = *(M4MP4C_FtypBox *)value;
   5125 
   5126                 /* Update global position variables with the difference between common and
   5127                  user block */
   5128                 size =
   5129                     mMp4FileDataPtr->ftyp.nbCompatibleBrands * sizeof(M4OSA_UInt32);
   5130 
   5131                 mMp4FileDataPtr->absoluteCurrentPos = 8/*mdat*/ + 16 + size;
   5132                 mMp4FileDataPtr->filesize = 218/*mdat+moov+skip*/ + 16 + size;
   5133             }
   5134             break;
   5135 
   5136         case (M4MP4W_DSI):
   5137             {
   5138                 streamIDmemAddrPtr = (M4SYS_StreamIDmemAddr *)value;
   5139 
   5140                 /* Nested switch! Whee! */
   5141                 switch( streamIDmemAddrPtr->streamID )
   5142                 {
   5143                     case (AudioStreamID):
   5144                         return M4ERR_NOT_IMPLEMENTED;
   5145 
   5146                     case (VideoStreamID):
   5147 
   5148                         /* Protect DSI setting : only once allowed on a given stream */
   5149 
   5150                         switch( mMp4FileDataPtr->videoTrackPtr->
   5151                             CommonData.trackType )
   5152                         {
   5153                             case M4SYS_kH263:
   5154                                 if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
   5155                                     || (M4OSA_NULL
   5156                                     != mMp4FileDataPtr->videoTrackPtr->DSI))
   5157                                 {
   5158                                     M4OSA_TRACE1_0(
   5159                                         "M4MP4W_setOption: dsi already set !");
   5160                                     return M4ERR_STATE;
   5161                                 }
   5162 
   5163                                 if ((0 == streamIDmemAddrPtr->size)
   5164                                     || (M4OSA_NULL == streamIDmemAddrPtr->addr))
   5165                                 {
   5166                                     M4OSA_TRACE1_0(
   5167                                         "M4MP4W_setOption: Bad H263 dsi!");
   5168                                     return M4ERR_PARAMETER;
   5169                                 }
   5170 
   5171                                 /*decoder specific info size is supposed to be always 7
   5172                                  bytes long */
   5173                                 ERR_CHECK(streamIDmemAddrPtr->size == 7,
   5174                                     M4ERR_PARAMETER);
   5175                                 mMp4FileDataPtr->videoTrackPtr->dsiSize =
   5176                                     (M4OSA_UInt8)streamIDmemAddrPtr->size;
   5177                                 mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
   5178                                     *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
   5179                                     M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
   5180                                 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
   5181                                     != M4OSA_NULL, M4ERR_ALLOC);
   5182                                 memcpy(
   5183                                     (void *)mMp4FileDataPtr->videoTrackPtr->
   5184                                     DSI,
   5185                                     (void *)streamIDmemAddrPtr->addr,
   5186                                     streamIDmemAddrPtr->size);
   5187 
   5188                                 break;
   5189 
   5190                             case M4SYS_kMPEG_4:
   5191                                 if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
   5192                                     || (M4OSA_NULL
   5193                                     != mMp4FileDataPtr->videoTrackPtr->DSI))
   5194                                 {
   5195                                     M4OSA_TRACE1_0(
   5196                                         "M4MP4W_setOption: dsi already set !");
   5197                                     return M4ERR_STATE;
   5198                                 }
   5199 
   5200                                 if ((0 == streamIDmemAddrPtr->size)
   5201                                     || (M4OSA_NULL == streamIDmemAddrPtr->addr))
   5202                                 {
   5203                                     M4OSA_TRACE1_0(
   5204                                         "M4MP4W_setOption: Bad MPEG4 dsi!");
   5205                                     return M4ERR_PARAMETER;
   5206                                 }
   5207 
   5208                                 /*MP4V specific*/
   5209                                 ERR_CHECK(streamIDmemAddrPtr->size < 105,
   5210                                     M4ERR_PARAMETER);
   5211                                 mMp4FileDataPtr->videoTrackPtr->dsiSize =
   5212                                     (M4OSA_UInt8)streamIDmemAddrPtr->size;
   5213                                 mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
   5214                                     *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
   5215                                     M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
   5216                                 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
   5217                                     != M4OSA_NULL, M4ERR_ALLOC);
   5218                                 memcpy(
   5219                                     (void *)mMp4FileDataPtr->videoTrackPtr->
   5220                                     DSI,
   5221                                     (void *)streamIDmemAddrPtr->addr,
   5222                                     streamIDmemAddrPtr->size);
   5223                                 mMp4FileDataPtr->filesize +=
   5224                                     streamIDmemAddrPtr->size;
   5225 
   5226                                 break;
   5227 
   5228                             case M4SYS_kH264:
   5229                                 if ((0 != mMp4FileDataPtr->videoTrackPtr->dsiSize)
   5230                                     || (M4OSA_NULL
   5231                                     != mMp4FileDataPtr->videoTrackPtr->DSI))
   5232                                 {
   5233                                     /* + H.264 trimming */
   5234                                     if (M4OSA_TRUE == mMp4FileDataPtr->bMULPPSSPS)
   5235                                     {
   5236                                         free(mMp4FileDataPtr->videoTrackPtr->DSI);
   5237 
   5238                                         // Do not strip the DSI
   5239                                         /* Store the DSI size */
   5240                                         mMp4FileDataPtr->videoTrackPtr->dsiSize =
   5241                                             (M4OSA_UInt8)streamIDmemAddrPtr->size;
   5242                                              M4OSA_TRACE1_1("M4MP4W_setOption: in set option DSI size =%d"\
   5243                                             ,mMp4FileDataPtr->videoTrackPtr->dsiSize);
   5244                                         /* Copy the DSI (SPS + PPS) */
   5245                                         mMp4FileDataPtr->videoTrackPtr->DSI =
   5246                                             (M4OSA_UChar*)M4OSA_32bitAlignedMalloc(
   5247                                             streamIDmemAddrPtr->size, M4MP4_WRITER,
   5248                                             (M4OSA_Char *)"videoTrackPtr->DSI");
   5249                                         ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI !=
   5250                                              M4OSA_NULL, M4ERR_ALLOC);
   5251                                         memcpy(
   5252                                             (void *)mMp4FileDataPtr->videoTrackPtr->DSI,
   5253                                             (void *)streamIDmemAddrPtr->addr,
   5254                                             streamIDmemAddrPtr->size);
   5255 
   5256                                         break;
   5257                                         /* - H.264 trimming */
   5258                                     }
   5259                                     else
   5260                                     {
   5261                                         M4OSA_TRACE1_0(
   5262                                             "M4MP4W_setOption: dsi already set !");
   5263                                         return M4ERR_STATE;
   5264                                     }
   5265                                 }
   5266 
   5267                                 if (( 0 == streamIDmemAddrPtr->size)
   5268                                     || (M4OSA_NULL == streamIDmemAddrPtr->addr))
   5269                                 {
   5270                                     M4OSA_TRACE1_0(
   5271                                         "M4MP4W_setOption: Bad H264 dsi!");
   5272                                     return M4ERR_PARAMETER;
   5273                                 }
   5274 
   5275                                 /* Store the DSI size */
   5276                                 mMp4FileDataPtr->videoTrackPtr->dsiSize =
   5277                                     (M4OSA_UInt8)streamIDmemAddrPtr->size;
   5278 
   5279                                 /* Copy the DSI (SPS + PPS) */
   5280                                 mMp4FileDataPtr->videoTrackPtr->DSI = (M4OSA_UChar
   5281                                     *)M4OSA_32bitAlignedMalloc(streamIDmemAddrPtr->size,
   5282                                     M4MP4_WRITER, (M4OSA_Char *)"videoTrackPtr->DSI");
   5283                                 ERR_CHECK(mMp4FileDataPtr->videoTrackPtr->DSI
   5284                                     != M4OSA_NULL, M4ERR_ALLOC);
   5285                                 memcpy(
   5286                                     (void *)mMp4FileDataPtr->videoTrackPtr->
   5287                                     DSI,
   5288                                     (void *)streamIDmemAddrPtr->addr,
   5289                                     streamIDmemAddrPtr->size);
   5290                                 break;
   5291 
   5292                             default:
   5293                                 return M4ERR_BAD_STREAM_ID;
   5294                         }
   5295                     break;
   5296 
   5297                 default:
   5298                     return M4ERR_BAD_STREAM_ID;
   5299                 }
   5300             }
   5301             break;
   5302             /* H.264 Trimming  */
   5303         case M4MP4W_MUL_PPS_SPS:
   5304             mMp4FileDataPtr->bMULPPSSPS = *(M4OSA_Int8 *)value;
   5305             /* H.264 Trimming  */
   5306             break;
   5307 
   5308         default:
   5309             return M4ERR_BAD_OPTION_ID;
   5310     }
   5311 
   5312     return err;
   5313 }
   5314 
   5315 /*******************************************************************************/
   5316 M4OSA_ERR M4MP4W_getState( M4OSA_Context context, M4MP4W_State *state,
   5317                           M4SYS_StreamID streamID )
   5318 /*******************************************************************************/
   5319 {
   5320     M4OSA_ERR err = M4NO_ERROR;
   5321 
   5322     M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
   5323     ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
   5324 
   5325     switch( streamID )
   5326     {
   5327         case (0):
   5328             *state = mMp4FileDataPtr->state;
   5329             break;
   5330 
   5331         case (AudioStreamID):
   5332             if (mMp4FileDataPtr->hasAudio == M4OSA_TRUE)
   5333             {
   5334                 *state = mMp4FileDataPtr->audioTrackPtr->microState;
   5335             }
   5336             else
   5337             {
   5338                 return M4ERR_BAD_STREAM_ID;
   5339             }
   5340             break;
   5341 
   5342         case (VideoStreamID):
   5343             if (mMp4FileDataPtr->hasVideo == M4OSA_TRUE)
   5344             {
   5345                 *state = mMp4FileDataPtr->videoTrackPtr->microState;
   5346             }
   5347             else
   5348             {
   5349                 return M4ERR_BAD_STREAM_ID;
   5350             }
   5351             break;
   5352 
   5353         default:
   5354             return M4ERR_BAD_STREAM_ID;
   5355     }
   5356 
   5357     return err;
   5358 }
   5359 
   5360 /*******************************************************************************/
   5361 M4OSA_ERR M4MP4W_getCurrentFileSize( M4OSA_Context context,
   5362                                     M4OSA_UInt32 *pCurrentFileSize )
   5363 /*******************************************************************************/
   5364 {
   5365     M4OSA_ERR err = M4NO_ERROR;
   5366 
   5367     M4MP4W_Mp4FileData *mMp4FileDataPtr = (M4MP4W_Mp4FileData *)context;
   5368     ERR_CHECK(context != M4OSA_NULL, M4ERR_PARAMETER);
   5369 
   5370     ERR_CHECK(pCurrentFileSize != M4OSA_NULL, M4ERR_PARAMETER);
   5371     *pCurrentFileSize = mMp4FileDataPtr->filesize;
   5372 
   5373     return err;
   5374 }
   5375 
   5376 #endif /* _M4MP4W_USE_CST_MEMORY_WRITER */
   5377