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