VideoEditor3gpReader.cpp revision 694816d7291f17364502ac5d3319684a0b180860
1/* 2 * Copyright (C) 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 VideoEditor3gpReader.cpp 20* @brief StageFright shell 3GP Reader 21************************************************************************* 22*/ 23 24#define LOG_NDEBUG 1 25#define LOG_TAG "VIDEOEDITOR_3GPREADER" 26 27/** 28 * HEADERS 29 * 30 */ 31#define VIDEOEDITOR_BITSTREAM_PARSER 32 33#include "M4OSA_Debug.h" 34#include "VideoEditor3gpReader.h" 35#include "M4SYS_AccessUnit.h" 36#include "VideoEditorUtils.h" 37#include "M4READER_3gpCom.h" 38#include "M4_Common.h" 39#include "M4OSA_FileWriter.h" 40 41#ifdef VIDEOEDITOR_BITSTREAM_PARSER 42#include "M4OSA_CoreID.h" 43#include "M4OSA_Error.h" 44#include "M4OSA_Memory.h" 45#include "M4_Utils.h" 46#endif 47 48#include "ESDS.h" 49#include "utils/Log.h" 50#include <media/stagefright/MediaBufferGroup.h> 51#include <media/stagefright/DataSource.h> 52#include <media/stagefright/FileSource.h> 53#include <media/stagefright/MediaBuffer.h> 54#include <media/stagefright/MediaDefs.h> 55#include <media/stagefright/MediaExtractor.h> 56#include <media/stagefright/MediaDebug.h> 57#include <media/stagefright/MediaSource.h> 58#include <media/stagefright/MetaData.h> 59 60/** 61 * SOURCE CLASS 62 */ 63namespace android { 64/** 65 * ENGINE INTERFACE 66 */ 67 68/** 69 ************************************************************************ 70 * @brief Array of AMR NB/WB bitrates 71 * @note Array to match the mode and the bit rate 72 ************************************************************************ 73*/ 74const M4OSA_UInt32 VideoEditor3gpReader_AmrBitRate [2 /* 8kHz / 16kHz */] 75 [9 /* the bitrate mode */] = 76{ 77 {4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200, 0}, 78 {6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850} 79}; 80 81/** 82 ******************************************************************************* 83 * structure VideoEditor3gpReader_Context 84 * @brief:This structure defines the context of the StageFright 3GP shell Reader 85 ******************************************************************************* 86*/ 87typedef struct { 88 sp<DataSource> mDataSource; 89 sp<MediaExtractor> mExtractor; 90 sp<MediaSource> mAudioSource; 91 sp<MediaSource> mVideoSource; 92 M4_StreamHandler* mAudioStreamHandler; 93 M4_StreamHandler* mVideoStreamHandler; 94 M4SYS_AccessUnit mAudioAu; 95 M4SYS_AccessUnit mVideoAu; 96 M4OSA_Time mMaxDuration; 97 int32_t mFileSize; 98 M4_StreamType mStreamType; 99 M4OSA_UInt32 mStreamId; 100 int32_t mTracks; 101 int32_t mCurrTrack; 102 M4OSA_Bool mAudioSeeking; 103 M4OSA_Time mAudioSeekTime; 104 M4OSA_Bool mVideoSeeking; 105 M4OSA_Time mVideoSeekTime; 106 107} VideoEditor3gpReader_Context; 108 109#ifdef VIDEOEDITOR_BITSTREAM_PARSER 110/** 111 ************************************************************************ 112 * structure VideoEditor3gpReader_BitStreamParserContext 113 * @brief Internal BitStreamParser context 114 ************************************************************************ 115*/ 116typedef struct { 117 M4OSA_UInt32* mPbitStream; /**< bitstream pointer (32bits aligned) */ 118 M4OSA_Int32 mSize; /**< bitstream size in bytes */ 119 M4OSA_Int32 mIndex; /**< byte index */ 120 M4OSA_Int32 mBitIndex; /**< bit index */ 121 M4OSA_Int32 mStructSize; /**< size of structure */ 122} VideoEditor3gpReader_BitStreamParserContext; 123 124/** 125 ******************************************************************************* 126 * @brief Allocates the context and initializes internal data. 127 * @param pContext (OUT) Pointer to the BitStreamParser context to create. 128 * @param bitStream A pointer to the bitstream 129 * @param size The size of the bitstream in bytes 130 ******************************************************************************* 131*/ 132static void VideoEditor3gpReader_BitStreamParserInit(void** pContext, 133 void* pBitStream, M4OSA_Int32 size) { 134 VideoEditor3gpReader_BitStreamParserContext* pStreamContext; 135 136 *pContext=M4OSA_NULL; 137 pStreamContext = (VideoEditor3gpReader_BitStreamParserContext*)M4OSA_32bitAlignedMalloc( 138 sizeof(VideoEditor3gpReader_BitStreamParserContext), M4READER_3GP, 139 (M4OSA_Char*)"3GP BitStreamParser Context"); 140 if (M4OSA_NULL == pStreamContext) { 141 return; 142 } 143 pStreamContext->mPbitStream=(M4OSA_UInt32*)pBitStream; 144 pStreamContext->mSize=size; 145 pStreamContext->mIndex=0; 146 pStreamContext->mBitIndex=0; 147 pStreamContext->mStructSize = 148 sizeof(VideoEditor3gpReader_BitStreamParserContext); 149 150 *pContext=pStreamContext; 151} 152/** 153 ********************************************************************** 154 * @brief Clean up context 155 * @param pContext (IN/OUT) BitStreamParser context. 156 ********************************************************************** 157*/ 158static void VideoEditor3gpReader_BitStreamParserCleanUp(void* pContext) { 159 free((M4OSA_Int32*)pContext); 160} 161/** 162 ***************************************************************************** 163 * @brief Read the next <length> bits in the bitstream. 164 * @note The function does not update the bitstream pointer. 165 * @param pContext (IN/OUT) BitStreamParser context. 166 * @param length (IN) The number of bits to extract from the bitstream 167 * @return the read bits 168 ***************************************************************************** 169*/ 170static M4OSA_UInt32 VideoEditor3gpReader_BitStreamParserShowBits(void* pContext, 171 M4OSA_Int32 length) { 172 VideoEditor3gpReader_BitStreamParserContext* pStreamContext = 173 (VideoEditor3gpReader_BitStreamParserContext*)pContext; 174 175 M4OSA_UInt32 u_mask; 176 M4OSA_UInt32 retval; 177 M4OSA_Int32 i_ovf; 178 179 M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0, 180 "VideoEditor3gpReader_BitStreamParserShowBits:invalid context pointer"); 181 182 retval=(M4OSA_UInt32)GET_MEMORY32(pStreamContext->\ 183 mPbitStream[ pStreamContext->mIndex ]); 184 i_ovf = pStreamContext->mBitIndex + length - 32; 185 u_mask = (length >= 32) ? 0xffffffff: (1 << length) - 1; 186 187 /* do we have enough bits availble in the current word(32bits)*/ 188 if (i_ovf <= 0) { 189 retval=(retval >> (- i_ovf)) & u_mask; 190 } else { 191 M4OSA_UInt32 u_nextword = (M4OSA_UInt32)GET_MEMORY32( 192 pStreamContext->mPbitStream[ pStreamContext->mIndex + 1 ]); 193 M4OSA_UInt32 u_msb_mask, u_msb_value, u_lsb_mask, u_lsb_value; 194 195 u_msb_mask = ((1 << (32 - pStreamContext->mBitIndex)) - 1) << i_ovf; 196 u_msb_value = retval << i_ovf; 197 u_lsb_mask = (1 << i_ovf) - 1; 198 u_lsb_value = u_nextword >> (32 - i_ovf); 199 retval= (u_msb_value & u_msb_mask ) | (u_lsb_value & u_lsb_mask); 200 } 201 /* return the bits...*/ 202 return retval; 203} 204/** 205 ************************************************************************ 206 * @brief Increment the bitstream pointer of <length> bits. 207 * @param pContext (IN/OUT) BitStreamParser context. 208 * @param length (IN) The number of bit to shift the bitstream 209 ************************************************************************ 210*/ 211static void VideoEditor3gpReader_BitStreamParserFlushBits(void* pContext, 212 M4OSA_Int32 length) { 213 VideoEditor3gpReader_BitStreamParserContext* pStreamContext=( 214 VideoEditor3gpReader_BitStreamParserContext*)pContext; 215 M4OSA_Int32 val; 216 217 if (M4OSA_NULL == pStreamContext) { 218 return; 219 } 220 val=pStreamContext->mBitIndex + length; 221 /* update the bits...*/ 222 pStreamContext->mBitIndex += length; 223 224 if (val - 32 >= 0) { 225 /* update the bits...*/ 226 pStreamContext->mBitIndex -= 32; 227 /* update the words*/ 228 pStreamContext->mIndex++; 229 } 230} 231 232static M4OSA_UInt32 VideoEditor3gpReader_BitStreamParserGetBits( 233 void* pContext,M4OSA_Int32 bitPos, M4OSA_Int32 bitLength) { 234 VideoEditor3gpReader_BitStreamParserContext* pStreamContext = 235 (VideoEditor3gpReader_BitStreamParserContext*)pContext; 236 237 M4OSA_Int32 bitLocation, bitIndex; 238 M4OSA_UInt32 retval=0; 239 240 M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0, 241 "VideoEditor3gpReader_BitStreamParserGetBits: invalid context pointer"); 242 243 /* computes the word location*/ 244 bitLocation=bitPos/32; 245 bitIndex=(bitPos) % 32; 246 247 if (bitLocation < pStreamContext->mSize) { 248 M4OSA_UInt32 u_mask; 249 M4OSA_Int32 i_ovf = bitIndex + bitLength - 32; 250 retval=(M4OSA_UInt32)GET_MEMORY32( 251 pStreamContext->mPbitStream[ bitLocation ]); 252 253 u_mask = (bitLength >= 32) ? 0xffffffff: (1 << bitLength) - 1; 254 255 if (i_ovf <= 0) { 256 retval=(retval >> (- i_ovf)) & u_mask; 257 } else { 258 M4OSA_UInt32 u_nextword = (M4OSA_UInt32)GET_MEMORY32( 259 pStreamContext->mPbitStream[ bitLocation + 1 ]); 260 M4OSA_UInt32 u_msb_mask, u_msb_value, u_lsb_mask, u_lsb_value; 261 262 u_msb_mask = ((1 << (32 - bitIndex)) - 1) << i_ovf; 263 u_msb_value = retval << i_ovf; 264 u_lsb_mask = (1 << i_ovf) - 1; 265 u_lsb_value = u_nextword >> (32 - i_ovf); 266 retval= (u_msb_value & u_msb_mask ) | (u_lsb_value & u_lsb_mask); 267 } 268 } 269 return retval; 270} 271 272static void VideoEditor3gpReader_BitStreamParserRestart(void* pContext) { 273 VideoEditor3gpReader_BitStreamParserContext* pStreamContext = 274 (VideoEditor3gpReader_BitStreamParserContext*)pContext; 275 276 if (M4OSA_NULL == pStreamContext) { 277 return; 278 } 279 /* resets the bitstream pointers*/ 280 pStreamContext->mIndex=0; 281 pStreamContext->mBitIndex=0; 282} 283/** 284 ******************************************************************************* 285 * @brief Get a pointer to the current byte pointed by the bitstream pointer. 286 * @note It should be used carefully as the pointer is in the bitstream itself 287 * and no copy is made. 288 * @param pContext (IN/OUT) BitStreamParser context. 289 * @return Pointer to the current location in the bitstream 290 ******************************************************************************* 291*/ 292static M4OSA_UInt8* VideoEditor3gpReader_GetCurrentbitStreamPointer( 293 void* pContext) { 294 VideoEditor3gpReader_BitStreamParserContext* pStreamContext = 295 (VideoEditor3gpReader_BitStreamParserContext*)pContext; 296 M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0, "invalid context pointer"); 297 298 return (M4OSA_UInt8*)((M4OSA_UInt8*)pStreamContext->mPbitStream + \ 299 pStreamContext->mIndex * sizeof(M4OSA_UInt32) + \ 300 pStreamContext->mBitIndex/8) ; 301} 302 303static M4OSA_Int32 VideoEditor3gpReader_BitStreamParserGetSize(void* pContext) { 304 VideoEditor3gpReader_BitStreamParserContext* pStreamContext = 305 (VideoEditor3gpReader_BitStreamParserContext*)pContext; 306 M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0, "invalid context pointer"); 307 308 return pStreamContext->mSize; 309} 310 311 312static void VideoEditor3gpReader_MPEG4BitStreamParserInit(void** pContext, 313 void* pBitStream, M4OSA_Int32 size) { 314 VideoEditor3gpReader_BitStreamParserInit(pContext, pBitStream, size); 315} 316static M4OSA_Int32 VideoEditor3gpReader_GetMpegLengthFromInteger(void* pContext, 317 M4OSA_UInt32 val) { 318 M4OSA_UInt32 length=0; 319 M4OSA_UInt32 numBytes=0; 320 M4OSA_UInt32 b=0; 321 322 M4OSA_DEBUG_IF1((M4OSA_NULL==pContext), 0, "invalid context pointer"); 323 324 /* the length is encoded as a sequence of bytes. The highest bit is used 325 to indicate that the length continues on the next byte. 326 327 The length can be: 0x80 0x80 0x80 0x22 328 of just 0x22 (highest bit not set) 329 330 */ 331 332 do { 333 b=(val & ((0xff)<< (8 * numBytes)))>> (8 * numBytes); 334 length=(length << 7) | (b & 0x7f); 335 numBytes++; 336 } while ((b & 0x80) && numBytes < 4); 337 338 return length; 339} 340 341/** 342 ******************************************************************************* 343 * @brief Decode an MPEG4 Systems descriptor size from an encoded SDL size data 344 * @note The value is read from the current bitstream location. 345 * @param pContext (IN/OUT) BitStreamParser context. 346 * @return Size in a human readable form 347 ******************************************************************************* 348*/ 349static M4OSA_Int32 VideoEditor3gpReader_GetMpegLengthFromStream(void* pContext){ 350 M4OSA_UInt32 length=0; 351 M4OSA_UInt32 numBytes=0; 352 M4OSA_UInt32 b=0; 353 354 M4OSA_DEBUG_IF1((M4OSA_NULL==pContext), 0, "invalid context pointer"); 355 356 /* the length is encoded as a sequence of bytes. The highest bit is used 357 to indicate that the length continues on the next byte. 358 359 The length can be: 0x80 0x80 0x80 0x22 360 of just 0x22 (highest bit not set) 361 */ 362 363 do { 364 b=VideoEditor3gpReader_BitStreamParserShowBits(pContext, 8); 365 VideoEditor3gpReader_BitStreamParserFlushBits(pContext, 8); 366 length=(length << 7) | (b & 0x7f); 367 numBytes++; 368 } while ((b & 0x80) && numBytes < 4); 369 370 return length; 371} 372#endif /* VIDEOEDITOR_BITSTREAM_PARSER */ 373/** 374************************************************************************ 375* @brief create an instance of the 3gp reader 376 * @note allocates the context 377 * 378 * @param pContext: (OUT) pointer on a reader context 379 * 380 * @return M4NO_ERROR there is no error 381 * @return M4ERR_ALLOC a memory allocation has failed 382 * @return M4ERR_PARAMETER at least one parameter is not valid 383************************************************************************ 384*/ 385 386M4OSA_ERR VideoEditor3gpReader_create(M4OSA_Context *pContext) { 387 VideoEditor3gpReader_Context* pC = NULL; 388 M4OSA_ERR err = M4NO_ERROR; 389 VIDEOEDITOR_CHECK(M4OSA_NULL != pContext , M4ERR_PARAMETER); 390 391 LOGV("VideoEditor3gpReader_create begin"); 392 393 /* Context allocation & initialization */ 394 SAFE_MALLOC(pC, VideoEditor3gpReader_Context, 1, "VideoEditor3gpReader"); 395 396 memset(pC, sizeof(VideoEditor3gpReader_Context), 0); 397 398 pC->mAudioStreamHandler = M4OSA_NULL; 399 pC->mAudioAu.dataAddress = M4OSA_NULL; 400 pC->mVideoStreamHandler = M4OSA_NULL; 401 pC->mVideoAu.dataAddress = M4OSA_NULL; 402 403 pC->mAudioSeeking = M4OSA_FALSE; 404 pC->mAudioSeekTime = 0; 405 406 pC->mVideoSeeking = M4OSA_FALSE; 407 pC->mVideoSeekTime = 0; 408 409 M4OSA_INT64_FROM_INT32(pC->mMaxDuration, 0); 410 *pContext=pC; 411 412cleanUp: 413 if ( M4NO_ERROR == err ) { 414 LOGV("VideoEditor3gpReader_create no error"); 415 } else { 416 LOGV("VideoEditor3gpReader_create ERROR 0x%X", err); 417 } 418 LOGV("VideoEditor3gpReader_create end "); 419 return err; 420} 421 422/** 423************************************************************************** 424* @brief destroy the instance of the 3gp reader 425* @note after this call the context is invalid 426* @param context: (IN) Context of the reader 427* @return M4NO_ERROR there is no error 428* @return M4ERR_PARAMETER pContext parameter is not properly set 429************************************************************************** 430*/ 431 432M4OSA_ERR VideoEditor3gpReader_destroy(M4OSA_Context pContext) { 433 M4OSA_ERR err = M4NO_ERROR; 434 VideoEditor3gpReader_Context* pC = M4OSA_NULL; 435 436 LOGV("VideoEditor3gpReader_destroy begin"); 437 438 VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER); 439 pC = (VideoEditor3gpReader_Context*)pContext; 440 441 SAFE_FREE(pC->mAudioAu.dataAddress); 442 pC->mAudioAu.dataAddress = M4OSA_NULL; 443 SAFE_FREE(pC->mVideoAu.dataAddress); 444 pC->mVideoAu.dataAddress = M4OSA_NULL; 445 SAFE_FREE(pC); 446 pContext = M4OSA_NULL; 447 448cleanUp: 449 if( M4NO_ERROR == err ) { 450 LOGV("VideoEditor3gpReader_destroy no error"); 451 } 452 else 453 { 454 LOGV("VideoEditor3gpReader_destroy ERROR 0x%X", err); 455 } 456 457 LOGV("VideoEditor3gpReader_destroy end "); 458 return err; 459} 460 461/** 462************************************************************************ 463* @brief open the reader and initializes its created instance 464* @note this function open the media file 465* @param context: (IN) Context of the reader 466* @param pFileDescriptor: (IN) Pointer to proprietary data identifying 467* the media to open 468* @return M4NO_ERROR there is no error 469* @return M4ERR_PARAMETER the context is NULL 470* @return M4ERR_UNSUPPORTED_MEDIA_TYPE 471* the media is DRM protected 472************************************************************************ 473*/ 474 475M4OSA_ERR VideoEditor3gpReader_open(M4OSA_Context pContext, 476 M4OSA_Void* pFileDescriptor) { 477 VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)pContext; 478 M4OSA_ERR err = M4NO_ERROR; 479 480 LOGV("VideoEditor3gpReader_open start "); 481 M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER, 482 "VideoEditor3gpReader_open: invalid context pointer"); 483 M4OSA_DEBUG_IF1((M4OSA_NULL == pFileDescriptor), M4ERR_PARAMETER, 484 "VideoEditor3gpReader_open: invalid pointer pFileDescriptor"); 485 486 LOGV("VideoEditor3gpReader_open Datasource start %s", 487 (char*)pFileDescriptor); 488 //pC->mDataSource = DataSource::CreateFromURI((char*)pFileDescriptor); 489 pC->mDataSource = new FileSource ((char*)pFileDescriptor); 490 491 if (pC->mDataSource == NULL) { 492 LOGV("VideoEditor3gpReader_open Datasource error"); 493 return M4ERR_PARAMETER; 494 } 495 496 pC->mExtractor = MediaExtractor::Create(pC->mDataSource, 497 MEDIA_MIMETYPE_CONTAINER_MPEG4); 498 499 if (pC->mExtractor == NULL) { 500 LOGV("VideoEditor3gpReader_open extractor error"); 501 return M4ERR_PARAMETER; 502 } 503 504 int32_t isDRMProtected = 0; 505 sp<MetaData> meta = pC->mExtractor->getMetaData(); 506 meta->findInt32(kKeyIsDRM, &isDRMProtected); 507 if (isDRMProtected) { 508 LOGV("VideoEditorMp3Reader_open error - DRM Protected"); 509 return M4ERR_UNSUPPORTED_MEDIA_TYPE; 510 } 511 512 LOGV("VideoEditor3gpReader_open end "); 513 return err; 514} 515 516/** 517************************************************************************ 518* @brief close the reader 519* @note close the 3GP file 520* @param context: (IN) Context of the reader 521* @return M4NO_ERROR there is no error 522* @return M4ERR_PARAMETER the context is NULL 523* @return M4ERR_BAD_CONTEXT provided context is not a valid one 524************************************************************************ 525*/ 526M4OSA_ERR VideoEditor3gpReader_close(M4OSA_Context context) { 527 VideoEditor3gpReader_Context *pC = (VideoEditor3gpReader_Context*)context; 528 M4READER_AudioSbrUserdata *pAudioSbrUserData; 529 M4_AccessUnit *pAU; 530 M4OSA_ERR err = M4NO_ERROR; 531 532 LOGV("VideoEditor3gpReader_close begin"); 533 534 M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER, 535 "VideoEditor3gpReader_close: invalid context pointer"); 536 537 if (pC->mAudioStreamHandler) { 538 LOGV("VideoEditor3gpReader_close Audio"); 539 540 if (M4OSA_NULL != pC->mAudioStreamHandler->m_pDecoderSpecificInfo) { 541 free(pC->mAudioStreamHandler->\ 542 m_pDecoderSpecificInfo); 543 pC->mAudioStreamHandler->m_decoderSpecificInfoSize = 0; 544 pC->mAudioStreamHandler->m_pDecoderSpecificInfo = M4OSA_NULL; 545 } 546 547 if ((M4DA_StreamTypeAudioAac == pC->mAudioStreamHandler->m_streamType) 548 && (M4OSA_NULL != pC->mAudioStreamHandler->m_pUserData)) { 549 pAudioSbrUserData = (M4READER_AudioSbrUserdata*)(\ 550 pC->mAudioStreamHandler->m_pUserData); 551 552 pAU = (M4_AccessUnit*)pAudioSbrUserData->m_pFirstAU; 553 if (M4OSA_NULL != pAU) { 554 free(pAU); 555 } 556 557 if (M4OSA_NULL != pAudioSbrUserData->m_pAacDecoderUserConfig) { 558 free(pAudioSbrUserData->\ 559 m_pAacDecoderUserConfig); 560 } 561 free(pAudioSbrUserData); 562 pC->mAudioStreamHandler->m_pUserData = M4OSA_NULL; 563 } 564 565 if (pC->mAudioStreamHandler->m_pESDSInfo != M4OSA_NULL) { 566 free(pC->mAudioStreamHandler->m_pESDSInfo); 567 pC->mAudioStreamHandler->m_pESDSInfo = M4OSA_NULL; 568 pC->mAudioStreamHandler->m_ESDSInfoSize = 0; 569 } 570 /* Finally destroy the stream handler */ 571 free(pC->mAudioStreamHandler); 572 pC->mAudioStreamHandler = M4OSA_NULL; 573 574 pC->mAudioSource->stop(); 575 pC->mAudioSource.clear(); 576 } 577 if (pC->mVideoStreamHandler) { 578 LOGV("VideoEditor3gpReader_close Video "); 579 580 if(M4OSA_NULL != pC->mVideoStreamHandler->m_pDecoderSpecificInfo) { 581 free(pC->mVideoStreamHandler->\ 582 m_pDecoderSpecificInfo); 583 pC->mVideoStreamHandler->m_decoderSpecificInfoSize = 0; 584 pC->mVideoStreamHandler->m_pDecoderSpecificInfo = M4OSA_NULL; 585 } 586 587 if(M4OSA_NULL != pC->mVideoStreamHandler->m_pH264DecoderSpecificInfo) { 588 free(pC->mVideoStreamHandler->\ 589 m_pH264DecoderSpecificInfo); 590 pC->mVideoStreamHandler->m_H264decoderSpecificInfoSize = 0; 591 pC->mVideoStreamHandler->m_pH264DecoderSpecificInfo = M4OSA_NULL; 592 } 593 594 if(pC->mVideoStreamHandler->m_pESDSInfo != M4OSA_NULL) { 595 free(pC->mVideoStreamHandler->m_pESDSInfo); 596 pC->mVideoStreamHandler->m_pESDSInfo = M4OSA_NULL; 597 pC->mVideoStreamHandler->m_ESDSInfoSize = 0; 598 } 599 600 /* Finally destroy the stream handler */ 601 free(pC->mVideoStreamHandler); 602 pC->mVideoStreamHandler = M4OSA_NULL; 603 604 pC->mVideoSource->stop(); 605 pC->mVideoSource.clear(); 606 } 607 pC->mExtractor.clear(); 608 pC->mDataSource.clear(); 609 610 LOGV("VideoEditor3gpReader_close end"); 611 return err; 612} 613 614/** 615************************************************************************ 616* @brief get an option from the 3gp reader 617* @note it allows the caller to retrieve a property value: 618* 619* @param context: (IN) Context of the reader 620* @param optionId: (IN) indicates the option to get 621* @param pValue: (OUT) pointer to structure or value (allocated 622* by user) where option is stored 623* 624* @return M4NO_ERROR there is no error 625* @return M4ERR_BAD_CONTEXT provided context is not a valid one 626* @return M4ERR_PARAMETER at least one parameter is not properly set 627* @return M4ERR_BAD_OPTION_ID when the option ID is not a valid one 628* @return M4ERR_VIDEO_NOT_H263 No video stream H263 in file. 629* @return M4ERR_NO_VIDEO_STREAM_RETRIEVED_YET 630* Function 3gpReader_getNextStreamHandler must be called before 631************************************************************************ 632*/ 633M4OSA_ERR VideoEditor3gpReader_getOption(M4OSA_Context context, 634 M4OSA_OptionID optionId, M4OSA_DataOption pValue) { 635 VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context; 636 M4OSA_ERR err = M4NO_ERROR; 637 638 LOGV("VideoEditor3gpReader_getOption begin %d", optionId); 639 640 M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER, 641 "invalid context pointer"); 642 M4OSA_DEBUG_IF1((M4OSA_NULL == pValue), M4ERR_PARAMETER, 643 "VideoEditor3gpReader_getOption: invalid pointer on value"); 644 645 switch (optionId) { 646 case M4READER_kOptionID_Duration: 647 { 648 LOGV("VideoEditor3gpReader_getOption duration %d",pC->mMaxDuration); 649 M4OSA_TIME_SET(*(M4OSA_Time*)pValue, pC->mMaxDuration); 650 } 651 break; 652 case M4READER_kOptionID_Version: 653 /* not used */ 654 LOGV("VideoEditor3gpReader_getOption: M4READER_kOptionID_Version"); 655 break; 656 657 case M4READER_kOptionID_Copyright: 658 /* not used */ 659 LOGV(">>>>>>> M4READER_kOptionID_Copyright"); 660 break; 661 662 case M4READER_kOptionID_CreationTime: 663 /* not used */ 664 LOGV("VideoEditor3gpReader_getOption M4READER_kOptionID_CreationTime"); 665 break; 666 667 case M4READER_kOptionID_Bitrate: 668 { 669 M4OSA_UInt32* pBitrate = (M4OSA_UInt32*)pValue; 670 671 if (pC->mMaxDuration != 0) { 672 M4OSA_UInt32 ui32Tmp = (M4OSA_UInt32)pC->mMaxDuration; 673 *pBitrate = (M4OSA_UInt32)((M4OSA_Double)pC->mFileSize * \ 674 8000.0 / (M4OSA_Double)ui32Tmp); 675 LOGV("3gpReader_getOption bitrate: %d", *pBitrate); 676 } 677 *pBitrate = 384000; //check 678 LOGV("VideoEditor3gpReader_getOption bitrate %ld", *pBitrate); 679 } 680 break; 681 case M4READER_3GP_kOptionID_H263Properties: 682 { 683 if(M4OSA_NULL == pC->mVideoStreamHandler) { 684 LOGV("VideoEditor3gpReader_getOption no videoStream retrieved"); 685 686 err = M4ERR_NO_VIDEO_STREAM_RETRIEVED_YET; 687 break; 688 } 689 if((M4DA_StreamTypeVideoH263 != pC->mVideoStreamHandler->\ 690 m_streamType) || (pC->mVideoStreamHandler->\ 691 m_decoderSpecificInfoSize < 7)) { 692 LOGV("VideoEditor3gpReader_getOption DSI Size %d", 693 pC->mVideoStreamHandler->m_decoderSpecificInfoSize); 694 695 err = M4ERR_VIDEO_NOT_H263; 696 break; 697 } 698 699 /* MAGICAL in the decoder confi H263: the 7th byte is the profile 700 * number, 6th byte is the level number */ 701 ((M4READER_3GP_H263Properties *)pValue)->uiProfile = 702 pC->mVideoStreamHandler->m_pDecoderSpecificInfo[6]; 703 ((M4READER_3GP_H263Properties *)pValue)->uiLevel = 704 pC->mVideoStreamHandler->m_pDecoderSpecificInfo[5]; 705 LOGV("VideoEditor3gpReader_getOption M4READER_3GP_kOptionID_\ 706 H263Properties end"); 707 } 708 break; 709 case M4READER_3GP_kOptionID_PurpleLabsDrm: 710 LOGV("VideoEditor3gpReaderOption M4READER_3GP_kOptionID_PurpleLabsDrm"); 711 /* not used */ 712 break; 713 714 case M4READER_kOptionID_GetNumberOfAudioAu: 715 /* not used */ 716 LOGV("VideoEditor3gpReadeOption M4READER_kOptionID_GetNumberOfAudioAu"); 717 break; 718 719 case M4READER_kOptionID_GetNumberOfVideoAu: 720 /* not used */ 721 LOGV("VideoEditor3gpReader_getOption :GetNumberOfVideoAu"); 722 break; 723 724 case M4READER_kOptionID_GetMetadata: 725 /* not used */ 726 LOGV("VideoEditor3gpReader_getOption M4READER_kOptionID_GetMetadata"); 727 break; 728 729 case M4READER_kOptionID_3gpFtypBox: 730 /* used only for SEMC */ 731 LOGV("VideoEditor3gpReader_getOption M4READER_kOptionID_3gpFtypBox"); 732 err = M4ERR_BAD_OPTION_ID; //check this 733 break; 734 735#ifdef OPTIONID_GET_NEXT_VIDEO_CTS 736 case M4READER_3GP_kOptionID_getNextVideoCTS: 737 /* not used */ 738 LOGV("VideoEditor3gpReader_getOption: getNextVideoCTS"); 739 break; 740#endif 741 default: 742 { 743 err = M4ERR_BAD_OPTION_ID; 744 LOGV("VideoEditor3gpReader_getOption M4ERR_BAD_OPTION_ID"); 745 } 746 break; 747 } 748 LOGV("VideoEditor3gpReader_getOption end: optionID: x%x", optionId); 749 return err; 750} 751/** 752************************************************************************ 753* @brief set an option on the 3gp reader 754* @note No option can be set yet. 755* @param context: (IN) Context of the reader 756* @param optionId: (IN) indicates the option to set 757* @param pValue: (IN) pointer to structure or value (allocated 758* by user) where option is stored 759* @return M4NO_ERROR there is no error 760* @return M4ERR_BAD_CONTEXT provided context is not a valid one 761* @return M4ERR_PARAMETER at least one parameter is not properly set 762* @return M4ERR_BAD_OPTION_ID when the option ID is not a valid one 763************************************************************************ 764*/ 765M4OSA_ERR VideoEditor3gpReader_setOption(M4OSA_Context context, 766 M4OSA_OptionID optionId, M4OSA_DataOption pValue) { 767 VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context; 768 M4OSA_ERR err = M4NO_ERROR; 769 770 /* Check function parameters */ 771 M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER, 772 "invalid context pointer"); 773 M4OSA_DEBUG_IF1((M4OSA_NULL == pValue), M4ERR_PARAMETER, 774 "invalid value pointer"); 775 776 LOGV("VideoEditor3gpReader_setOption begin %d",optionId); 777 778 switch(optionId) { 779 case M4READER_kOptionID_SetOsaFileReaderFctsPtr: 780 break; 781 782 case M4READER_3GP_kOptionID_AudioOnly: 783 break; 784 785 case M4READER_3GP_kOptionID_VideoOnly: 786 break; 787 788 case M4READER_3GP_kOptionID_FastOpenMode: 789 break; 790 791 case M4READER_kOptionID_MaxMetadataSize: 792 break; 793 794 default: 795 { 796 LOGV("VideoEditor3gpReader_setOption: returns M4ERR_BAD_OPTION_ID"); 797 err = M4ERR_BAD_OPTION_ID; 798 } 799 break; 800 } 801 LOGV("VideoEditor3gpReader_setOption end "); 802 return err; 803} 804/** 805 ************************************************************************ 806 * @brief fill the access unit structure with initialization values 807 * @param context: (IN) Context of the reader 808 * @param pStreamHandler: (IN) pointer to the stream handler to which 809 * the access unit will be associated 810 * @param pAccessUnit: (IN/OUT) pointer to the access unit (allocated 811 * by the caller) to initialize 812 * @return M4NO_ERROR there is no error 813 * @return M4ERR_PARAMETER at least one parameter is not properly set 814 ************************************************************************ 815*/ 816M4OSA_ERR VideoEditor3gpReader_fillAuStruct(M4OSA_Context context, 817 M4_StreamHandler *pStreamHandler, M4_AccessUnit *pAccessUnit) { 818 VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context; 819 M4OSA_ERR err= M4NO_ERROR; 820 821 M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER, 822 "VideoEditor3gpReader_fillAuStruct: invalid context"); 823 M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, 824 "VideoEditor3gpReader_fillAuStruc invalid pointer to M4_StreamHandler"); 825 M4OSA_DEBUG_IF1((pAccessUnit == 0), M4ERR_PARAMETER, 826 "VideoEditor3gpReader_fillAuStruct: invalid pointer to M4_AccessUnit"); 827 828 LOGV("VideoEditor3gpReader_fillAuStruct begin"); 829 830 /* Initialize pAccessUnit structure */ 831 pAccessUnit->m_size = 0; 832 pAccessUnit->m_CTS = 0; 833 pAccessUnit->m_DTS = 0; 834 pAccessUnit->m_attribute = 0; 835 pAccessUnit->m_dataAddress = M4OSA_NULL; 836 pAccessUnit->m_maxsize = pStreamHandler->m_maxAUSize; 837 pAccessUnit->m_streamID = pStreamHandler->m_streamId; 838 pAccessUnit->m_structSize = sizeof(M4_AccessUnit); 839 840 LOGV("VideoEditor3gpReader_fillAuStruct end"); 841 return M4NO_ERROR; 842} 843 844/** 845******************************************************************************** 846* @brief jump into the stream at the specified time 847* @note 848* @param context: (IN) Context of the reader 849* @param pStreamHandler (IN) the stream handler of the stream to make jump 850* @param pTime (I/O)IN the time to jump to (in ms) 851* OUT the time to which the stream really jumped 852* @return M4NO_ERROR there is no error 853* @return M4ERR_PARAMETER at least one parameter is not properly set 854******************************************************************************** 855*/ 856M4OSA_ERR VideoEditor3gpReader_jump(M4OSA_Context context, 857 M4_StreamHandler *pStreamHandler, M4OSA_Int32* pTime) { 858 VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context; 859 M4OSA_ERR err = M4NO_ERROR; 860 M4SYS_AccessUnit* pAu; 861 M4OSA_Time time64; 862 M4OSA_Double timeDouble; 863 864 M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER, 865 "VideoEditor3gpReader_jump: invalid context"); 866 M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, 867 "VideoEditor3gpReader_jump: invalid pointer to M4_StreamHandler"); 868 M4OSA_DEBUG_IF1((pTime == 0), M4ERR_PARAMETER, 869 "VideoEditor3gpReader_jump: invalid time pointer"); 870 871 LOGV("VideoEditor3gpReader_jump begin"); 872 873 if (*pTime == (pStreamHandler->m_duration)) { 874 *pTime -= 1; 875 } 876 M4OSA_INT64_FROM_INT32(time64, *pTime); 877 878 LOGV("VideoEditor3gpReader_jump time us %ld ", time64); 879 880 if ((pC->mAudioStreamHandler != M4OSA_NULL) && 881 (pStreamHandler->m_streamId == pC->mAudioStreamHandler->m_streamId)) 882 { 883 pAu = &pC->mAudioAu; 884 pAu->CTS = time64; 885 pAu->DTS = time64; 886 887 time64 = time64 * 1000; /* Convert the time into micro sec */ 888 pC->mAudioSeeking = M4OSA_TRUE; 889 pC->mAudioSeekTime = time64; 890 LOGV("VideoEditor3gpReader_jump AUDIO time us %ld ", time64); 891 } else if ((pC->mVideoStreamHandler != M4OSA_NULL) && 892 (pStreamHandler->m_streamId == pC->mVideoStreamHandler->m_streamId)) 893 { 894 pAu = &pC->mVideoAu; 895 pAu->CTS = time64; 896 pAu->DTS = time64; 897 898 time64 = time64 * 1000; /* Convert the time into micro sec */ 899 pC->mVideoSeeking = M4OSA_TRUE; 900 pC->mVideoSeekTime = time64; 901 LOGV("VideoEditor3gpReader_jump VIDEO time us %ld ", time64); 902 } else { 903 LOGV("VideoEditor3gpReader_jump passed StreamHandler is not known\n"); 904 return M4ERR_PARAMETER; 905 } 906 time64 = time64 / 1000; /* Convert the time into milli sec */ 907 LOGV("VideoEditor3gpReader_jump time ms before seekset %ld ", time64); 908 909 M4OSA_INT64_TO_DOUBLE(timeDouble, time64); 910 *pTime = (M4OSA_Int32)timeDouble; 911 912 LOGV("VideoEditor3gpReader_jump end"); 913 err = M4NO_ERROR; 914 return err; 915} 916/** 917******************************************************************************** 918* @brief reset the stream, that is seek it to beginning and make it ready 919* @note 920* @param context: (IN) Context of the reader 921* @param pStreamHandler (IN) The stream handler of the stream to reset 922* @return M4NO_ERROR there is no error 923* @return M4ERR_PARAMETER at least one parameter is not properly set 924******************************************************************************** 925*/ 926M4OSA_ERR VideoEditor3gpReader_reset(M4OSA_Context context, 927 M4_StreamHandler *pStreamHandler) { 928 VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context; 929 M4OSA_ERR err = M4NO_ERROR; 930 M4SYS_StreamID streamIdArray[2]; 931 M4SYS_AccessUnit* pAu; 932 M4OSA_Time time64; 933 934 M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER, 935 "VideoEditor3gpReader_reset: invalid context"); 936 M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, 937 "VideoEditor3gpReader_reset: invalid pointer to M4_StreamHandler"); 938 939 M4OSA_INT64_FROM_INT32(time64, 0); 940 941 LOGV("VideoEditor3gpReader_reset begin"); 942 943 if (pStreamHandler == (M4_StreamHandler*)pC->mAudioStreamHandler) { 944 pAu = &pC->mAudioAu; 945 } else if (pStreamHandler == (M4_StreamHandler*)pC->mVideoStreamHandler) { 946 pAu = &pC->mVideoAu; 947 } else { 948 LOGV("VideoEditor3gpReader_reset passed StreamHandler is not known\n"); 949 return M4ERR_PARAMETER; 950 } 951 952 pAu->CTS = time64; 953 pAu->DTS = time64; 954 955 LOGV("VideoEditor3gpReader_reset end"); 956 return err; 957} 958 959/** 960******************************************************************************** 961* @brief Gets an access unit (AU) from the stream handler source. 962* @note An AU is the smallest possible amount of data to be decoded by decoder 963* 964* @param context: (IN) Context of the reader 965* @param pStreamHandler (IN) The stream handler of the stream to make jump 966* @param pAccessUnit (IO) Pointer to access unit to fill with read data 967* @return M4NO_ERROR there is no error 968* @return M4ERR_PARAMETER at least one parameter is not properly set 969* @returns M4ERR_ALLOC memory allocation failed 970* @returns M4WAR_NO_MORE_AU there are no more access unit in the stream 971******************************************************************************** 972*/ 973M4OSA_ERR VideoEditor3gpReader_getNextAu(M4OSA_Context context, 974 M4_StreamHandler *pStreamHandler, M4_AccessUnit *pAccessUnit) { 975 VideoEditor3gpReader_Context* pC=(VideoEditor3gpReader_Context*)context; 976 M4OSA_ERR err = M4NO_ERROR; 977 M4SYS_AccessUnit* pAu; 978 int64_t tempTime64 = 0; 979 MediaBuffer *mMediaBuffer = NULL; 980 MediaSource::ReadOptions options; 981 M4OSA_Bool flag = M4OSA_FALSE; 982 status_t error; 983 int32_t i32Tmp = 0; 984 985 M4OSA_DEBUG_IF1((pReaderContext == 0), M4ERR_PARAMETER, 986 "VideoEditor3gpReader_getNextAu: invalid context"); 987 M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, 988 "VideoEditor3gpReader_getNextAu: invalid pointer to M4_StreamHandler"); 989 M4OSA_DEBUG_IF1((pAccessUnit == 0), M4ERR_PARAMETER, 990 "VideoEditor3gpReader_getNextAu: invalid pointer to M4_AccessUnit"); 991 992 LOGV("VideoEditor3gpReader_getNextAu begin"); 993 994 if (pStreamHandler == (M4_StreamHandler*)pC->mAudioStreamHandler) { 995 LOGV("VideoEditor3gpReader_getNextAu audio stream"); 996 pAu = &pC->mAudioAu; 997 if (pC->mAudioSeeking == M4OSA_TRUE) { 998 LOGV("VideoEditor3gpReader_getNextAu audio seek time: %ld", 999 pC->mAudioSeekTime); 1000 options.setSeekTo(pC->mAudioSeekTime); 1001 pC->mAudioSource->read(&mMediaBuffer, &options); 1002 1003 mMediaBuffer->meta_data()->findInt64(kKeyTime, 1004 (int64_t*)&tempTime64); 1005 options.clearSeekTo(); 1006 pC->mAudioSeeking = M4OSA_FALSE; 1007 flag = M4OSA_TRUE; 1008 } else { 1009 LOGV("VideoEditor3gpReader_getNextAu audio no seek:"); 1010 pC->mAudioSource->read(&mMediaBuffer, &options); 1011 if (mMediaBuffer != NULL) { 1012 mMediaBuffer->meta_data()->findInt64(kKeyTime, 1013 (int64_t*)&tempTime64); 1014 } 1015 } 1016 } else if (pStreamHandler == (M4_StreamHandler*)pC->mVideoStreamHandler) { 1017 LOGV("VideoEditor3gpReader_getNextAu video steram "); 1018 pAu = &pC->mVideoAu; 1019 if(pC->mVideoSeeking == M4OSA_TRUE) { 1020 flag = M4OSA_TRUE; 1021 LOGV("VideoEditor3gpReader_getNextAu seek: %ld",pC->mVideoSeekTime); 1022 options.setSeekTo(pC->mVideoSeekTime, 1023 MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 1024 do 1025 { 1026 if (mMediaBuffer != NULL) { 1027 LOGV("VideoEditor3gpReader_getNextAu free the MediaBuffer"); 1028 mMediaBuffer->release(); 1029 } 1030 error = pC->mVideoSource->read(&mMediaBuffer, &options); 1031 LOGV("VE3gpReader_getNextAu MediaBuffer %x , error %d", 1032 mMediaBuffer, error); 1033 if (mMediaBuffer != NULL) 1034 { 1035 if (mMediaBuffer->meta_data()->findInt32(kKeyIsSyncFrame, 1036 &i32Tmp) && i32Tmp) { 1037 LOGV("SYNC FRAME FOUND--%d", i32Tmp); 1038 pAu->attribute = AU_RAP; 1039 } 1040 else { 1041 pAu->attribute = AU_P_Frame; 1042 } 1043 mMediaBuffer->meta_data()->findInt64(kKeyTime, 1044 (int64_t*)&tempTime64); 1045 } else { 1046 break; 1047 } 1048 options.clearSeekTo(); 1049 } while(tempTime64 < pC->mVideoSeekTime); 1050 1051 LOGV("VE3gpReader_getNextAu: video time with seek = %lld:", 1052 tempTime64); 1053 pC->mVideoSeeking = M4OSA_FALSE; 1054 } else { 1055 LOGV("VideoEditor3gpReader_getNextAu video no seek:"); 1056 pC->mVideoSource->read(&mMediaBuffer, &options); 1057 1058 if(mMediaBuffer != NULL) { 1059 if (mMediaBuffer->meta_data()->findInt32(kKeyIsSyncFrame, 1060 &i32Tmp) && i32Tmp) { 1061 LOGV("SYNC FRAME FOUND--%d", i32Tmp); 1062 pAu->attribute = AU_RAP; 1063 } 1064 else { 1065 pAu->attribute = AU_P_Frame; 1066 } 1067 mMediaBuffer->meta_data()->findInt64(kKeyTime, 1068 (int64_t*)&tempTime64); 1069 LOGV("VE3gpReader_getNextAu: video no seek time = %lld:", 1070 tempTime64); 1071 }else { 1072 LOGV("VE3gpReader_getNextAu:video no seek time buffer is NULL"); 1073 } 1074 } 1075 } else { 1076 LOGV("VideoEditor3gpReader_getNextAu M4ERR_PARAMETER"); 1077 return M4ERR_PARAMETER; 1078 } 1079 1080 if (mMediaBuffer != NULL) { 1081 if( (pAu->dataAddress == NULL) || (pAu->size < \ 1082 mMediaBuffer->range_length())) { 1083 if(pAu->dataAddress != NULL) { 1084 free((M4OSA_Int32*)pAu->dataAddress); 1085 pAu->dataAddress = NULL; 1086 } 1087 LOGV("Buffer lenght = %d ,%d",(mMediaBuffer->range_length() +\ 1088 3) & ~0x3,(mMediaBuffer->range_length())); 1089 1090 pAu->dataAddress = (M4OSA_Int32*)M4OSA_32bitAlignedMalloc( 1091 (mMediaBuffer->range_length() + 3) & ~0x3,M4READER_3GP, 1092 (M4OSA_Char*)"pAccessUnit->m_dataAddress" ); 1093 if(pAu->dataAddress == NULL) { 1094 LOGV("VideoEditor3gpReader_getNextAu malloc failed"); 1095 return M4ERR_ALLOC; 1096 } 1097 } 1098 pAu->size = mMediaBuffer->range_length(); 1099 1100 memcpy((void *)pAu->dataAddress, 1101 (void *)((const char *)mMediaBuffer->data() + mMediaBuffer->range_offset()), 1102 mMediaBuffer->range_length()); 1103 1104 if( (pStreamHandler == (M4_StreamHandler*)pC->mVideoStreamHandler) && 1105 (pStreamHandler->m_streamType == M4DA_StreamTypeVideoMpeg4Avc) ) { 1106 M4OSA_UInt32 size = mMediaBuffer->range_length(); 1107 M4OSA_UInt8 *lbuffer; 1108 1109 lbuffer = (M4OSA_UInt8 *) pAu->dataAddress; 1110 LOGV("pAccessUnit->m_dataAddress size = %x",size); 1111 1112 lbuffer[0] = (size >> 24) & 0xFF; 1113 lbuffer[1] = (size >> 16) & 0xFF; 1114 lbuffer[2] = (size >> 8) & 0xFF; 1115 lbuffer[3] = (size) & 0xFF; 1116 } 1117 1118 pAu->CTS = tempTime64; 1119 1120 pAu->CTS = pAu->CTS / 1000; //converting the microsec to millisec 1121 LOGV("VideoEditor3gpReader_getNextAu CTS = %ld",pAu->CTS); 1122 1123 pAu->DTS = pAu->CTS; 1124 if (pStreamHandler == (M4_StreamHandler*)pC->mAudioStreamHandler) { 1125 pAu->attribute = M4SYS_kFragAttrOk; 1126 } 1127 mMediaBuffer->release(); 1128 1129 pAccessUnit->m_dataAddress = (M4OSA_Int8*) pAu->dataAddress; 1130 pAccessUnit->m_size = pAu->size; 1131 pAccessUnit->m_maxsize = pAu->size; 1132 pAccessUnit->m_CTS = pAu->CTS; 1133 pAccessUnit->m_DTS = pAu->DTS; 1134 pAccessUnit->m_attribute = pAu->attribute; 1135 1136 } else { 1137 LOGV("VideoEditor3gpReader_getNextAu: M4WAR_NO_MORE_AU (EOS) reached"); 1138 pAccessUnit->m_size = 0; 1139 err = M4WAR_NO_MORE_AU; 1140 } 1141 options.clearSeekTo(); 1142 1143 pAu->nbFrag = 0; 1144 mMediaBuffer = NULL; 1145 LOGV("VideoEditor3gpReader_getNextAu end "); 1146 1147 return err; 1148} 1149/** 1150 ******************************************************************************* 1151 * @brief Split the AVC DSI in its different components and write it in 1152 * ONE memory buffer 1153 * @note 1154 * @param pStreamHandler: (IN/OUT) The MPEG4-AVC stream 1155 * @param pDecoderConfigLocal: (IN) The DSI buffer 1156 * @param decoderConfigSizeLocal: (IN) The DSI buffer size 1157 * @return M4NO_ERROR there is no error 1158 * @return ERR_FILE_SYNTAX_ERROR pDecoderConfigLocal is NULL 1159 ******************************************************************************* 1160*/ 1161static M4OSA_ERR VideoEditor3gpReader_AnalyseAvcDsi( 1162 M4_StreamHandler *pStreamHandler, M4OSA_Int32* pDecoderConfigLocal, 1163 M4OSA_Int32 decoderConfigSizeLocal) { 1164 struct _avcSpecificInfo *pAvcSpecInfo = M4OSA_NULL; 1165 M4OSA_UInt32 uiSpecInfoSize; 1166 M4OSA_Context pBitParserContext = M4OSA_NULL; 1167 M4OSA_MemAddr8 pPos; 1168 1169 /** 1170 * First parsing to get the total allocation size (we must not do 1171 * multiple malloc, but only one instead) */ 1172 { 1173 M4OSA_Int32 val; 1174 M4OSA_UInt32 i,j; 1175 M4OSA_UInt8 nalUnitLength; 1176 M4OSA_UInt8 numOfSequenceParameterSets; 1177 M4OSA_UInt32 uiTotalSizeOfSPS = 0; 1178 M4OSA_UInt8 numOfPictureParameterSets; 1179 M4OSA_UInt32 uiTotalSizeOfPPS = 0; 1180 M4OSA_UInt32 uiSize; 1181 struct _avcSpecificInfo avcSpIf; 1182 1183 avcSpIf.m_nalUnitLength = 0; 1184 1185 if (M4OSA_NULL == pDecoderConfigLocal) { 1186 return M4ERR_READER3GP_DECODER_CONFIG_ERROR; 1187 } 1188 1189 VideoEditor3gpReader_MPEG4BitStreamParserInit(&pBitParserContext, 1190 pDecoderConfigLocal, decoderConfigSizeLocal); 1191 1192 if (M4OSA_NULL == pBitParserContext) { 1193 return M4ERR_ALLOC; 1194 } 1195 1196 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1197 /* 8 bits -- configuration version */ 1198 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1199 /* 8 bits -- avc profile indication*/ 1200 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1201 /* 8 bits -- profile compatibility */ 1202 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1203 /* 8 bits -- avc level indication*/ 1204 val=VideoEditor3gpReader_BitStreamParserShowBits(pBitParserContext, 8); 1205 /* 6 bits reserved 111111b 2 bits length Size minus one*/ 1206 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1207 /* m_nalUnitLength */ 1208 1209 nalUnitLength = (M4OSA_UInt8)((val & 0x03) + 1);/*0b11111100*/ 1210 if (nalUnitLength > 4) { 1211 pStreamHandler->m_decoderSpecificInfoSize = 0; 1212 pStreamHandler->m_pDecoderSpecificInfo = M4OSA_NULL; 1213 VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext); 1214 } else { 1215 /** 1216 * SPS table */ 1217 val=VideoEditor3gpReader_BitStreamParserShowBits(pBitParserContext, 1218 8);/* 3 bits-reserved 111b-5 bits number of sequence parameter set*/ 1219 numOfSequenceParameterSets = val & 0x1F; 1220 /*1F instead of E0*/ /*0b11100000*/ /*Number of seq parameter sets*/ 1221 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1222 for (i=0; i < numOfSequenceParameterSets; i++) { 1223 /** 1224 * Get the size of this element */ 1225 uiSize = 1226 (M4OSA_UInt32)VideoEditor3gpReader_BitStreamParserShowBits( 1227 pBitParserContext, 16); 1228 uiTotalSizeOfSPS += uiSize; 1229 VideoEditor3gpReader_BitStreamParserFlushBits( 1230 pBitParserContext, 16); 1231 /** 1232 *Read the element(dont keep it, we only want size right now) */ 1233 for (j=0; j<uiSize; j++) { 1234 VideoEditor3gpReader_BitStreamParserFlushBits( 1235 pBitParserContext, 8); 1236 } 1237 } 1238 1239 /** 1240 * SPS table */ 1241 numOfPictureParameterSets=(M4OSA_UInt8)\ 1242 VideoEditor3gpReader_BitStreamParserShowBits(pBitParserContext, 1243 8); 1244 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1245 for (i=0; i < numOfPictureParameterSets; i++) { 1246 /** 1247 * Get the size of this element */ 1248 uiSize = (M4OSA_UInt32) 1249 VideoEditor3gpReader_BitStreamParserShowBits( 1250 pBitParserContext, 16); 1251 uiTotalSizeOfPPS += uiSize; 1252 VideoEditor3gpReader_BitStreamParserFlushBits( 1253 pBitParserContext, 16); 1254 /** 1255 *Read the element(dont keep it,we only want size right now)*/ 1256 for (j=0; j<uiSize; j++) { 1257 VideoEditor3gpReader_BitStreamParserFlushBits( 1258 pBitParserContext, 8); 1259 } 1260 } 1261 1262 /** 1263 * Compute the size of the full buffer */ 1264 uiSpecInfoSize = sizeof(struct _avcSpecificInfo) + 1265 numOfSequenceParameterSets * sizeof(struct _parameterSet) 1266 + /**< size of the table of SPS elements */ 1267 numOfPictureParameterSets * sizeof(struct _parameterSet) 1268 + /**< size of the table of PPS elements */ 1269 uiTotalSizeOfSPS + 1270 uiTotalSizeOfPPS; 1271 /** 1272 * Allocate the buffer */ 1273 pAvcSpecInfo =(struct _avcSpecificInfo*)M4OSA_32bitAlignedMalloc(uiSpecInfoSize, 1274 M4READER_3GP, (M4OSA_Char*)"MPEG-4 AVC DecoderSpecific"); 1275 if (M4OSA_NULL == pAvcSpecInfo) { 1276 VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext); 1277 return M4ERR_ALLOC; 1278 } 1279 1280 /** 1281 * Set the pointers to the correct part of the buffer */ 1282 pAvcSpecInfo->m_nalUnitLength = nalUnitLength; 1283 pAvcSpecInfo->m_numOfSequenceParameterSets = 1284 numOfSequenceParameterSets; 1285 pAvcSpecInfo->m_numOfPictureParameterSets = 1286 numOfPictureParameterSets; 1287 1288 /* We place the SPS param sets table after m_pPictureParameterSet */ 1289 pAvcSpecInfo->m_pSequenceParameterSet= (struct _parameterSet*)( 1290 (M4OSA_MemAddr8)(&pAvcSpecInfo->m_pPictureParameterSet) + 1291 sizeof(pAvcSpecInfo->m_pPictureParameterSet)); 1292 /*We place the PPS param sets table after the SPS param sets table*/ 1293 pAvcSpecInfo->m_pPictureParameterSet = (struct _parameterSet*)( 1294 (M4OSA_MemAddr8)(pAvcSpecInfo->m_pSequenceParameterSet) + 1295 (numOfSequenceParameterSets * sizeof(struct _parameterSet))); 1296 /**< The data will be placed after the PPS param sets table */ 1297 pPos = (M4OSA_MemAddr8)pAvcSpecInfo->m_pPictureParameterSet + 1298 (numOfPictureParameterSets * sizeof(struct _parameterSet)); 1299 1300 /** 1301 * reset the bit parser */ 1302 VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext); 1303 } 1304 } 1305 1306 /** 1307 * Second parsing to copy the data */ 1308 if (M4OSA_NULL != pAvcSpecInfo) { 1309 M4OSA_Int32 i,j; 1310 1311 VideoEditor3gpReader_MPEG4BitStreamParserInit(&pBitParserContext, 1312 pDecoderConfigLocal, decoderConfigSizeLocal); 1313 1314 if (M4OSA_NULL == pBitParserContext) { 1315 free(pAvcSpecInfo); 1316 return M4ERR_ALLOC; 1317 } 1318 1319 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1320 /* 8 bits -- configuration version */ 1321 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1322 /* 8 bits -- avc profile indication*/ 1323 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1324 /* 8 bits -- profile compatibility */ 1325 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1326 /* 8 bits -- avc level indication*/ 1327 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1328 /* m_nalUnitLength */ 1329 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1330 /* 3 bits -- reserved 111b -- 5 bits number of sequence parameter set*/ 1331 1332 for (i=0; i < pAvcSpecInfo->m_numOfSequenceParameterSets; i++) { 1333 pAvcSpecInfo->m_pSequenceParameterSet[i].m_length = 1334 (M4OSA_UInt16)VideoEditor3gpReader_BitStreamParserShowBits( 1335 pBitParserContext, 16); 1336 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext,16); 1337 1338 pAvcSpecInfo->m_pSequenceParameterSet[i].m_pParameterSetUnit = 1339 (M4OSA_UInt8*)pPos; /**< current position in the buffer */ 1340 pPos += pAvcSpecInfo->m_pSequenceParameterSet[i].m_length; 1341 /**< increment the position in the buffer */ 1342 for (j=0; j<pAvcSpecInfo->m_pSequenceParameterSet[i].m_length;j++){ 1343 pAvcSpecInfo->m_pSequenceParameterSet[i].m_pParameterSetUnit[j]= 1344 (M4OSA_UInt8)VideoEditor3gpReader_BitStreamParserShowBits( 1345 pBitParserContext, 8); 1346 VideoEditor3gpReader_BitStreamParserFlushBits( 1347 pBitParserContext, 8); 1348 } 1349 } 1350 1351 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8); 1352 /* number of pîcture parameter set*/ 1353 1354 for (i=0; i < pAvcSpecInfo->m_numOfPictureParameterSets; i++) { 1355 pAvcSpecInfo->m_pPictureParameterSet[i].m_length = 1356 (M4OSA_UInt16)VideoEditor3gpReader_BitStreamParserShowBits( 1357 pBitParserContext, 16); 1358 VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext,16); 1359 1360 pAvcSpecInfo->m_pPictureParameterSet[i].m_pParameterSetUnit = 1361 (M4OSA_UInt8*)pPos; /**< current position in the buffer */ 1362 pPos += pAvcSpecInfo->m_pPictureParameterSet[i].m_length; 1363 /**< increment the position in the buffer */ 1364 for (j=0; j<pAvcSpecInfo->m_pPictureParameterSet[i].m_length; j++) { 1365 pAvcSpecInfo->m_pPictureParameterSet[i].m_pParameterSetUnit[j] = 1366 (M4OSA_UInt8)VideoEditor3gpReader_BitStreamParserShowBits( 1367 pBitParserContext, 8); 1368 VideoEditor3gpReader_BitStreamParserFlushBits( 1369 pBitParserContext, 8); 1370 } 1371 } 1372 VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext); 1373 pStreamHandler->m_decoderSpecificInfoSize = uiSpecInfoSize; 1374 pStreamHandler->m_pDecoderSpecificInfo = (M4OSA_UInt8*)pAvcSpecInfo; 1375 } 1376 pStreamHandler->m_H264decoderSpecificInfoSize = decoderConfigSizeLocal; 1377 pStreamHandler->m_pH264DecoderSpecificInfo = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( 1378 decoderConfigSizeLocal, M4READER_3GP, 1379 (M4OSA_Char*)"MPEG-4 AVC DecoderSpecific"); 1380 if (M4OSA_NULL == pStreamHandler->m_pH264DecoderSpecificInfo) { 1381 goto cleanup; 1382 } 1383 1384 memcpy((void * ) pStreamHandler->m_pH264DecoderSpecificInfo, 1385 (void * )pDecoderConfigLocal, 1386 pStreamHandler->m_H264decoderSpecificInfoSize); 1387 return M4NO_ERROR; 1388cleanup: 1389 VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext); 1390 return M4ERR_READER3GP_DECODER_CONFIG_ERROR; 1391} 1392/** 1393******************************************************************************** 1394* @brief Get the next stream found in the 3gp file 1395* @note 1396* @param context: (IN) Context of the reader 1397* @param pMediaFamily: OUT) pointer to a user allocated 1398* M4READER_MediaFamily that will be filled 1399* with the media family of the found stream 1400* @param pStreamHandler:(OUT) pointer to StreamHandler that will be allocated 1401* and filled with the found stream description 1402* @return M4NO_ERROR there is no error 1403* @return M4ERR_BAD_CONTEXT provided context is not a valid one 1404* @return M4ERR_PARAMETER at least one parameter is not properly set 1405* @return M4WAR_NO_MORE_STREAM no more available stream in the media 1406******************************************************************************** 1407*/ 1408M4OSA_ERR VideoEditor3gpReader_getNextStreamHandler(M4OSA_Context context, 1409 M4READER_MediaFamily *pMediaFamily, 1410 M4_StreamHandler **pStreamHandler) { 1411 VideoEditor3gpReader_Context* pC=(VideoEditor3gpReader_Context*)context; 1412 M4OSA_ERR err = M4NO_ERROR; 1413 M4SYS_StreamID streamIdArray[2]; 1414 M4SYS_StreamDescription streamDesc; 1415 M4_AudioStreamHandler* pAudioStreamHandler; 1416 M4_VideoStreamHandler* pVideoStreamHandler; 1417 M4OSA_Int8 *DecoderSpecificInfo = M4OSA_NULL; 1418 M4OSA_Int32 decoderSpecificInfoSize =0, maxAUSize = 0; 1419 1420 M4_StreamType streamType = M4DA_StreamTypeUnknown; 1421 M4OSA_UInt8 temp, i, trackCount; 1422 M4OSA_Bool haveAudio = M4OSA_FALSE; 1423 M4OSA_Bool haveVideo = M4OSA_FALSE; 1424 sp<MetaData> meta = NULL; 1425 int64_t Duration = 0; 1426 M4OSA_UInt8* DecoderSpecific = M4OSA_NULL ; 1427 uint32_t type; 1428 const void *data; 1429 size_t size; 1430 const void *codec_specific_data; 1431 size_t codec_specific_data_size; 1432 M4OSA_Int32 ptempTime; 1433 M4OSA_Int32 avgFPS=0; 1434 1435 LOGV("VideoEditor3gpReader_getNextStreamHandler begin"); 1436 1437 M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER, 1438 "VideoEditor3gpReader_getNextStreamHandler: invalid context"); 1439 M4OSA_DEBUG_IF1((pMediaFamily == 0), M4ERR_PARAMETER, 1440 "getNextStreamHandler: invalid pointer to MediaFamily"); 1441 M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, 1442 "getNextStreamHandler: invalid pointer to StreamHandler"); 1443 1444 trackCount = pC->mExtractor->countTracks(); 1445 temp = pC->mCurrTrack; 1446 1447 if(temp >= trackCount) { 1448 LOGV("VideoEditor3gpReader_getNextStreamHandler error = %d", 1449 M4WAR_NO_MORE_STREAM); 1450 return (M4WAR_NO_MORE_STREAM); 1451 } else { 1452 const char *mime; 1453 meta = pC->mExtractor->getTrackMetaData(temp); 1454 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1455 1456 if (!haveVideo && !strncasecmp(mime, "video/", 6)) { 1457 pC->mVideoSource = pC->mExtractor->getTrack(temp); 1458 pC->mVideoSource->start(); 1459 1460 *pMediaFamily = M4READER_kMediaFamilyVideo; 1461 haveVideo = true; 1462 LOGV("VideoEditor3gpReader_getNextStreamHandler getTrack called"); 1463 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { 1464 streamType = M4DA_StreamTypeVideoMpeg4Avc; 1465 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) { 1466 streamType = M4DA_StreamTypeVideoH263; 1467 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) { 1468 streamType = M4DA_StreamTypeVideoMpeg4; 1469 } else { 1470 LOGV("VideoEditor3gpReaderGetNextStreamHandler streamTypeNONE"); 1471 } 1472 LOGV("VideoEditor3gpReader_getNextStreamHandler: stream type: %d ", 1473 streamType); 1474 1475 if(streamType != M4DA_StreamTypeUnknown) { 1476 pC->mStreamType = streamType; 1477 pC->mStreamId = pC->mCurrTrack; 1478 1479 pVideoStreamHandler = (M4_VideoStreamHandler*)M4OSA_32bitAlignedMalloc 1480 (sizeof(M4_VideoStreamHandler), M4READER_3GP, 1481 (M4OSA_Char*)"M4_VideoStreamHandler"); 1482 if (M4OSA_NULL == pVideoStreamHandler) { 1483 return M4ERR_ALLOC; 1484 } 1485 pVideoStreamHandler->m_structSize=sizeof(M4_VideoStreamHandler); 1486 1487 meta->findInt32(kKeyWidth, 1488 (int32_t*)&(pVideoStreamHandler->m_videoWidth)); 1489 meta->findInt32(kKeyHeight, 1490 (int32_t*)&(pVideoStreamHandler->m_videoHeight)); 1491 1492 (*pStreamHandler) = (M4_StreamHandler*)(pVideoStreamHandler); 1493 meta->findInt64(kKeyDuration, 1494 (int64_t*)&(Duration)); 1495 ((*pStreamHandler)->m_duration) = 1496 (int32_t)((Duration)/1000); // conversion to mS 1497 pC->mMaxDuration = ((*pStreamHandler)->m_duration); 1498 LOGV("VideoEditor3gpReader_getNextStreamHandler m_duration %d", 1499 (*pStreamHandler)->m_duration); 1500 1501 pC->mFileSize = 0; 1502 1503 meta->findInt32(kKeyMaxInputSize, (int32_t*)&(maxAUSize)); 1504 if(maxAUSize == 0) { 1505 maxAUSize = 70000; 1506 } 1507 (*pStreamHandler)->m_maxAUSize = maxAUSize; 1508 LOGV("<<<<<<<<<< video: mMaxAUSize from MP4 extractor: %d", 1509 (*pStreamHandler)->m_maxAUSize); 1510 1511 if( (M4DA_StreamTypeVideoH263 == streamType) || 1512 (M4DA_StreamTypeVideoMpeg4Avc == streamType)){ 1513 ((M4_StreamHandler*)pVideoStreamHandler)->m_averageBitRate = 1514 384000; 1515 } 1516 1517 meta->findInt32(kKeyFrameRate, 1518 (int32_t*)&(avgFPS)); 1519 LOGV("<<<<<<<<<< video: Average FPS from MP4 extractor: %d", 1520 avgFPS); 1521 1522 pVideoStreamHandler->m_averageFrameRate =(M4OSA_Float) avgFPS; 1523 LOGV("<<<<<<<<<< video: Average FPS from MP4 extractor in FLOAT: %f", 1524 pVideoStreamHandler->m_averageFrameRate); 1525 1526 pC->mVideoStreamHandler = 1527 (M4_StreamHandler*)(pVideoStreamHandler); 1528 1529 /* Get the DSI info */ 1530 if(M4DA_StreamTypeVideoH263 == streamType) { 1531 if (meta->findData(kKeyD263, &type, &data, &size)) { 1532 (*pStreamHandler)->m_decoderSpecificInfoSize = size; 1533 if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) { 1534 DecoderSpecific = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( 1535 (*pStreamHandler)->m_decoderSpecificInfoSize, 1536 M4READER_3GP,(M4OSA_Char*)"H263 DSI"); 1537 if (M4OSA_NULL == DecoderSpecific) { 1538 return M4ERR_ALLOC; 1539 } 1540 memcpy((void *)DecoderSpecific, 1541 (void *)data, size); 1542 (*pStreamHandler)->m_pDecoderSpecificInfo = 1543 DecoderSpecific; 1544 } 1545 else { 1546 (*pStreamHandler)->m_pDecoderSpecificInfo = 1547 M4OSA_NULL; 1548 (*pStreamHandler)->m_decoderSpecificInfoSize = 0; 1549 } 1550 (*pStreamHandler)->m_pESDSInfo = M4OSA_NULL; 1551 (*pStreamHandler)->m_ESDSInfoSize = 0; 1552 (*pStreamHandler)->m_pH264DecoderSpecificInfo = M4OSA_NULL; 1553 (*pStreamHandler)->m_H264decoderSpecificInfoSize = 0; 1554 } else { 1555 LOGV("VE_getNextStreamHandler: H263 dsi not found"); 1556 (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL; 1557 (*pStreamHandler)->m_decoderSpecificInfoSize = 0; 1558 (*pStreamHandler)->m_H264decoderSpecificInfoSize = 0; 1559 (*pStreamHandler)->m_pH264DecoderSpecificInfo = 1560 M4OSA_NULL; 1561 (*pStreamHandler)->m_pESDSInfo = M4OSA_NULL; 1562 (*pStreamHandler)->m_ESDSInfoSize = 0; 1563 } 1564 } 1565 else if(M4DA_StreamTypeVideoMpeg4Avc == streamType) { 1566 if(meta->findData(kKeyAVCC, &type, &data, &size)) { 1567 decoderSpecificInfoSize = size; 1568 if (decoderSpecificInfoSize != 0) { 1569 DecoderSpecificInfo = (M4OSA_Int8*)M4OSA_32bitAlignedMalloc( 1570 decoderSpecificInfoSize, M4READER_3GP, 1571 (M4OSA_Char*)"H264 DecoderSpecific" ); 1572 if (M4OSA_NULL == DecoderSpecificInfo) { 1573 LOGV("VideoEditor3gp_getNextStream is NULL "); 1574 return M4ERR_ALLOC; 1575 } 1576 memcpy((void *)DecoderSpecificInfo, 1577 (void *)data, decoderSpecificInfoSize); 1578 } else { 1579 LOGV("DSI Size %d", decoderSpecificInfoSize); 1580 DecoderSpecificInfo = M4OSA_NULL; 1581 } 1582 } 1583 (*pStreamHandler)->m_pESDSInfo = M4OSA_NULL; 1584 (*pStreamHandler)->m_ESDSInfoSize = 0; 1585 1586 err = VideoEditor3gpReader_AnalyseAvcDsi(*pStreamHandler, 1587 (M4OSA_Int32*)DecoderSpecificInfo, decoderSpecificInfoSize); 1588 1589 if (M4NO_ERROR != err) { 1590 return err; 1591 } 1592 LOGV("decsize %d, h264decsize %d: %d", (*pStreamHandler)->\ 1593 m_decoderSpecificInfoSize, (*pStreamHandler)->\ 1594 m_H264decoderSpecificInfoSize); 1595 1596 if(M4OSA_NULL != DecoderSpecificInfo) { 1597 free(DecoderSpecificInfo); 1598 DecoderSpecificInfo = M4OSA_NULL; 1599 } 1600 } else if( (M4DA_StreamTypeVideoMpeg4 == streamType) ) { 1601 if (meta->findData(kKeyESDS, &type, &data, &size)) { 1602 ESDS esds((const char *)data, size); 1603 CHECK_EQ(esds.InitCheck(), OK); 1604 1605 (*pStreamHandler)->m_ESDSInfoSize = size; 1606 (*pStreamHandler)->m_pESDSInfo = (M4OSA_UInt8*)\ 1607 M4OSA_32bitAlignedMalloc((*pStreamHandler)->m_ESDSInfoSize, 1608 M4READER_3GP, (M4OSA_Char*)"H263 DecoderSpecific" ); 1609 if (M4OSA_NULL == (*pStreamHandler)->m_pESDSInfo) { 1610 return M4ERR_ALLOC; 1611 } 1612 memcpy((void *)(*pStreamHandler)->\ 1613 m_pESDSInfo, (void *)data, size); 1614 1615 esds.getCodecSpecificInfo(&codec_specific_data, 1616 &codec_specific_data_size); 1617 LOGV("VE MP4 dsisize: %d, %x", codec_specific_data_size, 1618 codec_specific_data); 1619 1620 (*pStreamHandler)->m_decoderSpecificInfoSize = 1621 codec_specific_data_size; 1622 if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) { 1623 DecoderSpecific = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( 1624 (*pStreamHandler)->m_decoderSpecificInfoSize, 1625 M4READER_3GP, (M4OSA_Char*)" DecoderSpecific" ); 1626 if (M4OSA_NULL == DecoderSpecific) { 1627 return M4ERR_ALLOC; 1628 } 1629 memcpy((void *)DecoderSpecific, 1630 (void *)codec_specific_data, 1631 codec_specific_data_size); 1632 (*pStreamHandler)->m_pDecoderSpecificInfo = 1633 DecoderSpecific; 1634 } 1635 else { 1636 (*pStreamHandler)->m_pDecoderSpecificInfo = 1637 M4OSA_NULL; 1638 } 1639 (*pStreamHandler)->m_pH264DecoderSpecificInfo = 1640 M4OSA_NULL; 1641 (*pStreamHandler)->m_H264decoderSpecificInfoSize = 0; 1642 } 1643 } else { 1644 LOGV("VideoEditor3gpReader_getNextStream NO video stream"); 1645 return M4ERR_READER_UNKNOWN_STREAM_TYPE; 1646 } 1647 } 1648 else { 1649 LOGV("VideoEditor3gpReader_getNextStream NO video stream"); 1650 return M4ERR_READER_UNKNOWN_STREAM_TYPE; 1651 } 1652 1653 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { 1654 LOGV("VideoEditor3gpReader_getNextStream audio getTrack called"); 1655 pC->mAudioSource = pC->mExtractor->getTrack(pC->mCurrTrack); 1656 pC->mAudioSource->start(); 1657 *pMediaFamily = M4READER_kMediaFamilyAudio; 1658 1659 if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) { 1660 streamType = M4DA_StreamTypeAudioAmrNarrowBand; 1661 } else if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) { 1662 streamType = M4DA_StreamTypeAudioAmrWideBand; 1663 } 1664 else if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { 1665 streamType = M4DA_StreamTypeAudioAac; 1666 } else { 1667 LOGV("VideoEditor3gpReader_getNextStrea streamtype Unknown "); 1668 } 1669 if(streamType != M4DA_StreamTypeUnknown) { 1670 pC->mStreamType = streamType; 1671 pC->mStreamId = pC->mCurrTrack; 1672 1673 LOGV("VE streamtype %d ,id %d", streamType, pC->mCurrTrack); 1674 1675 pAudioStreamHandler = (M4_AudioStreamHandler*)M4OSA_32bitAlignedMalloc 1676 (sizeof(M4_AudioStreamHandler), M4READER_3GP, 1677 (M4OSA_Char*)"M4_AudioStreamHandler"); 1678 if (M4OSA_NULL == pAudioStreamHandler) { 1679 return M4ERR_ALLOC; 1680 } 1681 pAudioStreamHandler->m_structSize=sizeof(M4_AudioStreamHandler); 1682 pAudioStreamHandler->m_byteSampleSize = 0; 1683 pAudioStreamHandler->m_nbChannels = 0; 1684 pAudioStreamHandler->m_samplingFrequency= 0; 1685 pAudioStreamHandler->m_byteFrameLength = 0; 1686 1687 (*pStreamHandler) = (M4_StreamHandler*)(pAudioStreamHandler); 1688 pC->mAudioStreamHandler = 1689 (M4_StreamHandler*)(pAudioStreamHandler); 1690 (*pStreamHandler)->m_averageBitRate = 0; 1691 haveAudio = true; 1692 pC->mAudioStreamHandler=(M4_StreamHandler*)pAudioStreamHandler; 1693 pC->mAudioStreamHandler->m_pESDSInfo = M4OSA_NULL; 1694 pC->mAudioStreamHandler->m_ESDSInfoSize = 0; 1695 1696 meta->findInt32(kKeyMaxInputSize, (int32_t*)&(maxAUSize)); 1697 if(maxAUSize == 0) { 1698 maxAUSize = 70000; 1699 } 1700 (*pStreamHandler)->m_maxAUSize = maxAUSize; 1701 LOGV("VE Audio mMaxAUSize from MP4 extractor: %d", maxAUSize); 1702 } 1703 if((M4DA_StreamTypeAudioAmrNarrowBand == streamType) || 1704 (M4DA_StreamTypeAudioAmrWideBand == streamType)) { 1705 M4OSA_UInt32 freqIndex = 0; /**< AMR NB */ 1706 M4OSA_UInt32 modeSet; 1707 M4OSA_UInt32 i; 1708 M4OSA_Context pBitParserContext = M4OSA_NULL; 1709 1710 if(M4DA_StreamTypeAudioAmrWideBand == streamType) { 1711 freqIndex = 1; /**< AMR WB */ 1712 } 1713 1714 if (meta->findData(kKeyESDS, &type, &data, &size)) { 1715 ESDS esds((const char *)data, size); 1716 CHECK_EQ(esds.InitCheck(), OK); 1717 1718 esds.getCodecSpecificInfo(&codec_specific_data, 1719 &codec_specific_data_size); 1720 (*pStreamHandler)->m_decoderSpecificInfoSize = 1721 codec_specific_data_size; 1722 1723 if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) { 1724 DecoderSpecific = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( 1725 (*pStreamHandler)->m_decoderSpecificInfoSize, 1726 M4READER_3GP, (M4OSA_Char*)"H263 DecoderSpecific" ); 1727 if (M4OSA_NULL == DecoderSpecific) { 1728 return M4ERR_ALLOC; 1729 } 1730 memcpy((void *)DecoderSpecific, 1731 (void *)codec_specific_data, 1732 codec_specific_data_size); 1733 (*pStreamHandler)->m_pDecoderSpecificInfo = 1734 DecoderSpecific; 1735 } else { 1736 (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL; 1737 } 1738 } else { 1739 M4OSA_UChar AmrDsi[] = 1740 {'P','H','L','P',0x00, 0x00, 0x80, 0x00, 0x01,}; 1741 (*pStreamHandler)->m_decoderSpecificInfoSize = 9; 1742 DecoderSpecific = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( 1743 (*pStreamHandler)->m_decoderSpecificInfoSize, 1744 M4READER_3GP, (M4OSA_Char*)"H263 DecoderSpecific" ); 1745 if (M4OSA_NULL == DecoderSpecific) { 1746 return M4ERR_ALLOC; 1747 } 1748 if(freqIndex ==0) { 1749 AmrDsi[8] = 0x01; 1750 } else { 1751 AmrDsi[8] = 0x02; 1752 } 1753 for(i = 0; i< 9; i++) { 1754 DecoderSpecific[i] = AmrDsi[i]; 1755 } 1756 (*pStreamHandler)->m_pDecoderSpecificInfo = DecoderSpecific; 1757 } 1758 (*pStreamHandler)->m_averageBitRate = 1759 VideoEditor3gpReader_AmrBitRate[freqIndex][7]; 1760 } else if((M4DA_StreamTypeAudioAac == streamType)) { 1761 if (meta->findData(kKeyESDS, &type, &data, &size)) { 1762 ESDS esds((const char *)data, size); 1763 CHECK_EQ(esds.InitCheck(), OK); 1764 1765 (*pStreamHandler)->m_ESDSInfoSize = size; 1766 (*pStreamHandler)->m_pESDSInfo = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( 1767 (*pStreamHandler)->m_ESDSInfoSize, M4READER_3GP, 1768 (M4OSA_Char*)"H263 DecoderSpecific" ); 1769 if (M4OSA_NULL == (*pStreamHandler)->m_pESDSInfo) { 1770 return M4ERR_ALLOC; 1771 } 1772 memcpy((void *)(*pStreamHandler)->m_pESDSInfo, 1773 (void *)data, size); 1774 esds.getCodecSpecificInfo(&codec_specific_data, 1775 &codec_specific_data_size); 1776 1777 LOGV("VEdsi %d,%x",codec_specific_data_size, 1778 codec_specific_data); 1779 1780 (*pStreamHandler)->m_decoderSpecificInfoSize = 1781 codec_specific_data_size; 1782 if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) { 1783 DecoderSpecific = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc( 1784 (*pStreamHandler)->m_decoderSpecificInfoSize, 1785 M4READER_3GP, (M4OSA_Char*)"H263 DecoderSpecific" ); 1786 if (M4OSA_NULL == DecoderSpecific) { 1787 return M4ERR_ALLOC; 1788 } 1789 memcpy((void *)DecoderSpecific, 1790 (void *)codec_specific_data, 1791 codec_specific_data_size); 1792 (*pStreamHandler)->m_pDecoderSpecificInfo = 1793 DecoderSpecific; 1794 } else { 1795 (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL; 1796 } 1797 } 1798 } else { 1799 LOGV("VideoEditor3gpReader_getNextStream mStreamType: none "); 1800 return M4ERR_READER_UNKNOWN_STREAM_TYPE; 1801 } 1802 } else { 1803 LOGV("VE noaudio-video stream:pC->mCurrTrack = %d ",pC->mCurrTrack); 1804 pC->mCurrTrack++; //Increment current track to get the next track 1805 return M4ERR_READER_UNKNOWN_STREAM_TYPE; 1806 } 1807 LOGV("VE StreamType: %d, stremhandler %x",streamType, *pStreamHandler ); 1808 (*pStreamHandler)->m_streamType = streamType; 1809 (*pStreamHandler)->m_streamId = pC->mStreamId; 1810 (*pStreamHandler)->m_pUserData = M4OSA_NULL; 1811 (*pStreamHandler)->m_structSize = sizeof(M4_StreamHandler); 1812 (*pStreamHandler)->m_bStreamIsOK = M4OSA_TRUE; 1813 1814 meta->findInt64(kKeyDuration, 1815 (int64_t*)&(Duration)); 1816 1817 (*pStreamHandler)->m_duration = (int32_t)(Duration / 1000); 1818 1819 pC->mMaxDuration = ((*pStreamHandler)->m_duration); 1820 LOGV("VE str duration duration: %d ", (*pStreamHandler)->m_duration); 1821 1822 /* In AAC case: Put the first AU in pAudioStreamHandler->m_pUserData 1823 *since decoder has to know if stream contains SBR data(Implicit sig) */ 1824 if(M4DA_StreamTypeAudioAac == (*pStreamHandler)->m_streamType) { 1825 M4READER_AudioSbrUserdata* pAudioSbrUserdata; 1826 1827 pAudioSbrUserdata = (M4READER_AudioSbrUserdata*)M4OSA_32bitAlignedMalloc( 1828 sizeof(M4READER_AudioSbrUserdata),M4READER_3GP, 1829 (M4OSA_Char*)"M4READER_AudioSbrUserdata"); 1830 if (M4OSA_NULL == pAudioSbrUserdata) { 1831 err = M4ERR_ALLOC; 1832 goto Error; 1833 } 1834 (*pStreamHandler)->m_pUserData = pAudioSbrUserdata; 1835 pAudioSbrUserdata->m_bIsSbrEnabled = M4OSA_FALSE; 1836 1837 pAudioSbrUserdata->m_pFirstAU = (M4_AccessUnit*)M4OSA_32bitAlignedMalloc( 1838 sizeof(M4_AccessUnit),M4READER_3GP, (M4OSA_Char*)"1st AAC AU"); 1839 if (M4OSA_NULL == pAudioSbrUserdata->m_pFirstAU) { 1840 pAudioSbrUserdata->m_pAacDecoderUserConfig = M4OSA_NULL; 1841 err = M4ERR_ALLOC; 1842 goto Error; 1843 } 1844 pAudioSbrUserdata->m_pAacDecoderUserConfig = (M4_AacDecoderConfig*)\ 1845 M4OSA_32bitAlignedMalloc(sizeof(M4_AacDecoderConfig),M4READER_3GP, 1846 (M4OSA_Char*)"m_pAacDecoderUserConfig"); 1847 if (M4OSA_NULL == pAudioSbrUserdata->m_pAacDecoderUserConfig) { 1848 err = M4ERR_ALLOC; 1849 goto Error; 1850 } 1851 } 1852 if(M4DA_StreamTypeAudioAac == (*pStreamHandler)->m_streamType) { 1853 M4_AudioStreamHandler* pAudioStreamHandler = 1854 (M4_AudioStreamHandler*)(*pStreamHandler); 1855 M4READER_AudioSbrUserdata* pUserData = (M4READER_AudioSbrUserdata*)\ 1856 (pAudioStreamHandler->m_basicProperties.m_pUserData); 1857 1858 err = VideoEditor3gpReader_fillAuStruct(pC, (*pStreamHandler), 1859 (M4_AccessUnit*)pUserData->m_pFirstAU); 1860 if (M4NO_ERROR != err) { 1861 goto Error; 1862 } 1863 err = VideoEditor3gpReader_getNextAu(pC, (*pStreamHandler), 1864 (M4_AccessUnit*)pUserData->m_pFirstAU); 1865 if (M4NO_ERROR != err) { 1866 goto Error; 1867 } 1868 err = VideoEditor3gpReader_reset(pC, (*pStreamHandler)); 1869 if (M4NO_ERROR != err) { 1870 goto Error; 1871 } 1872 } 1873 } 1874 pC->mCurrTrack++; //Increment the current track to get next track 1875 LOGV("pC->mCurrTrack = %d",pC->mCurrTrack); 1876 1877 if (!haveAudio && !haveVideo) { 1878 *pMediaFamily=M4READER_kMediaFamilyUnknown; 1879 return M4ERR_READER_UNKNOWN_STREAM_TYPE; 1880 } 1881Error: 1882 LOGV("VideoEditor3gpReader_getNextStreamHandler end error = %d",err); 1883 return err; 1884} 1885 1886M4OSA_ERR VideoEditor3gpReader_getPrevRapTime(M4OSA_Context context, 1887 M4_StreamHandler *pStreamHandler, M4OSA_Int32* pTime) 1888{ 1889 VideoEditor3gpReader_Context *pC = (VideoEditor3gpReader_Context*)context; 1890 M4OSA_ERR err = M4NO_ERROR; 1891 MediaBuffer *mMediaBuffer = M4OSA_NULL; 1892 MediaSource::ReadOptions options; 1893 M4OSA_Time time64; 1894 int64_t tempTime64 = 0; 1895 status_t error; 1896 1897 LOGV("VideoEditor3gpReader_getPrevRapTime begin"); 1898 1899 M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER, 1900 "VideoEditor3gpReader_getPrevRapTime: invalid context"); 1901 M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER, 1902 "VideoEditor3gpReader_getPrevRapTime invalid pointer to StreamHandler"); 1903 M4OSA_DEBUG_IF1((pTime == 0), M4ERR_PARAMETER, 1904 "VideoEditor3gpReader_getPrevRapTime: invalid time pointer"); 1905 if (*pTime == (pStreamHandler->m_duration)) { 1906 *pTime -= 1; 1907 } 1908 M4OSA_INT64_FROM_INT32(time64, *pTime); 1909 time64 = time64 * 1000; 1910 1911 LOGV("VideoEditor3gpReader_getPrevRapTime seek time: %ld",time64); 1912 options.setSeekTo(time64, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 1913 error = pC->mVideoSource->read(&mMediaBuffer, &options); 1914 if (error != OK) { 1915 //Can not get the previous Sync. 1916 //Must be end of stream. 1917 return M4WAR_NO_MORE_AU; 1918 } 1919 1920 mMediaBuffer->meta_data()->findInt64(kKeyTime, (int64_t*)&tempTime64); 1921 LOGV("VideoEditor3gpReader_getPrevRapTime read time %ld, %x", tempTime64, 1922 mMediaBuffer); 1923 1924 (*pTime) = (tempTime64) / 1000; 1925 1926 if(mMediaBuffer != M4OSA_NULL) { 1927 LOGV(" mMediaBuffer size = %d length %d", mMediaBuffer->size(), 1928 mMediaBuffer->range_length()); 1929 mMediaBuffer->release(); 1930 mMediaBuffer = M4OSA_NULL; 1931 } 1932 options.clearSeekTo(); 1933 1934 if(error != OK) { 1935 LOGV("VideoEditor3gpReader_getPrevRapTime end \ 1936 M4WAR_READER_INFORMATION_NOT_PRESENT"); 1937 return M4WAR_READER_INFORMATION_NOT_PRESENT; 1938 } else { 1939 LOGV("VideoEditor3gpReader_getPrevRapTime end: err %x", err); 1940 err = M4NO_ERROR; 1941 return err; 1942 } 1943} 1944 1945extern "C" { 1946M4OSA_ERR VideoEditor3gpReader_getInterface(M4READER_MediaType *pMediaType, 1947 M4READER_GlobalInterface **pRdrGlobalInterface, 1948 M4READER_DataInterface **pRdrDataInterface) { 1949 1950 M4OSA_ERR err = M4NO_ERROR; 1951 1952 VIDEOEDITOR_CHECK(M4OSA_NULL != pMediaType, M4ERR_PARAMETER); 1953 VIDEOEDITOR_CHECK(M4OSA_NULL != pRdrGlobalInterface, M4ERR_PARAMETER); 1954 VIDEOEDITOR_CHECK(M4OSA_NULL != pRdrDataInterface, M4ERR_PARAMETER); 1955 1956 LOGV("VideoEditor3gpReader_getInterface begin"); 1957 LOGV("VideoEditor3gpReader_getInterface %d 0x%x 0x%x", *pMediaType, 1958 *pRdrGlobalInterface,*pRdrDataInterface); 1959 1960 SAFE_MALLOC(*pRdrGlobalInterface, M4READER_GlobalInterface, 1, 1961 "VideoEditor3gpReader_getInterface"); 1962 SAFE_MALLOC(*pRdrDataInterface, M4READER_DataInterface, 1, 1963 "VideoEditor3gpReader_getInterface"); 1964 1965 *pMediaType = M4READER_kMediaType3GPP; 1966 1967 (*pRdrGlobalInterface)->m_pFctCreate = VideoEditor3gpReader_create; 1968 (*pRdrGlobalInterface)->m_pFctDestroy = VideoEditor3gpReader_destroy; 1969 (*pRdrGlobalInterface)->m_pFctOpen = VideoEditor3gpReader_open; 1970 (*pRdrGlobalInterface)->m_pFctClose = VideoEditor3gpReader_close; 1971 (*pRdrGlobalInterface)->m_pFctGetOption = VideoEditor3gpReader_getOption; 1972 (*pRdrGlobalInterface)->m_pFctSetOption = VideoEditor3gpReader_setOption; 1973 (*pRdrGlobalInterface)->m_pFctGetNextStream = 1974 VideoEditor3gpReader_getNextStreamHandler; 1975 (*pRdrGlobalInterface)->m_pFctFillAuStruct = 1976 VideoEditor3gpReader_fillAuStruct; 1977 (*pRdrGlobalInterface)->m_pFctStart = M4OSA_NULL; 1978 (*pRdrGlobalInterface)->m_pFctStop = M4OSA_NULL; 1979 (*pRdrGlobalInterface)->m_pFctJump = VideoEditor3gpReader_jump; 1980 (*pRdrGlobalInterface)->m_pFctReset = VideoEditor3gpReader_reset; 1981 (*pRdrGlobalInterface)->m_pFctGetPrevRapTime = 1982 VideoEditor3gpReader_getPrevRapTime; 1983 (*pRdrDataInterface)->m_pFctGetNextAu = VideoEditor3gpReader_getNextAu; 1984 (*pRdrDataInterface)->m_readerContext = M4OSA_NULL; 1985 1986cleanUp: 1987 if( M4NO_ERROR == err ) { 1988 LOGV("VideoEditor3gpReader_getInterface no error"); 1989 } else { 1990 SAFE_FREE(*pRdrGlobalInterface); 1991 SAFE_FREE(*pRdrDataInterface); 1992 1993 LOGV("VideoEditor3gpReader_getInterface ERROR 0x%X", err); 1994 } 1995 LOGV("VideoEditor3gpReader_getInterface end"); 1996 return err; 1997} 1998 1999} /* extern "C" */ 2000 2001} /* namespace android */ 2002 2003 2004