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