summaryrefslogtreecommitdiffstats
path: root/libvideoeditor/vss/stagefrightshells/src
diff options
context:
space:
mode:
authorDharmaray Kundargi <dharmaray@google.com>2011-01-16 15:59:43 -0800
committerDharmaray Kundargi <dharmaray@google.com>2011-01-17 09:59:01 -0800
commit7c9d8018755adf1857571125ba1b3598c96ea506 (patch)
tree6f97c14846692c0a7580c3a6019f7c91c669ffcf /libvideoeditor/vss/stagefrightshells/src
parent5358e878396e1c451e9f9ef07237c2e6ab662d49 (diff)
downloadframeworks_av-7c9d8018755adf1857571125ba1b3598c96ea506.zip
frameworks_av-7c9d8018755adf1857571125ba1b3598c96ea506.tar.gz
frameworks_av-7c9d8018755adf1857571125ba1b3598c96ea506.tar.bz2
Removed unwanted line in M4READER_Amr.h
vss core files upload on honeycomb Change-Id: I61206ae2398ce8ac544c6fb01a76fe8917bce75b
Diffstat (limited to 'libvideoeditor/vss/stagefrightshells/src')
-rwxr-xr-xlibvideoeditor/vss/stagefrightshells/src/Android.mk79
-rwxr-xr-xlibvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp1967
-rwxr-xr-xlibvideoeditor/vss/stagefrightshells/src/VideoEditorAudioDecoder.cpp907
-rwxr-xr-xlibvideoeditor/vss/stagefrightshells/src/VideoEditorAudioEncoder.cpp739
-rwxr-xr-xlibvideoeditor/vss/stagefrightshells/src/VideoEditorBuffer.c266
-rwxr-xr-xlibvideoeditor/vss/stagefrightshells/src/VideoEditorMp3Reader.cpp801
-rwxr-xr-xlibvideoeditor/vss/stagefrightshells/src/VideoEditorUtils.cpp444
-rwxr-xr-xlibvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp1404
-rwxr-xr-xlibvideoeditor/vss/stagefrightshells/src/VideoEditorVideoEncoder.cpp1288
9 files changed, 7895 insertions, 0 deletions
diff --git a/libvideoeditor/vss/stagefrightshells/src/Android.mk b/libvideoeditor/vss/stagefrightshells/src/Android.mk
new file mode 100755
index 0000000..297bfa7
--- /dev/null
+++ b/libvideoeditor/vss/stagefrightshells/src/Android.mk
@@ -0,0 +1,79 @@
+#
+# Copyright (C) 2011 NXP Software
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ VideoEditorVideoDecoder.cpp \
+ VideoEditorAudioDecoder.cpp \
+ VideoEditorMp3Reader.cpp \
+ VideoEditor3gpReader.cpp \
+ VideoEditorUtils.cpp \
+ VideoEditorBuffer.c \
+ VideoEditorVideoEncoder.cpp \
+ VideoEditorAudioEncoder.cpp
+
+LOCAL_C_INCLUDES += \
+ $(TOP)/frameworks/base/core/jni \
+ $(TOP)/frameworks/base/include \
+ $(TOP)/frameworks/base/include/media \
+ $(TOP)/frameworks/base/media/libmediaplayerservice \
+ $(TOP)/frameworks/base/media/libstagefright \
+ $(TOP)/frameworks/base/media/libstagefright/include \
+ $(TOP)/frameworks/base/media/libstagefright/rtsp \
+ $(JNI_H_INCLUDE) \
+ $(call include-path-for, corecg graphics) \
+ $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+ $(TOP)/external/opencore/android \
+ $(TOP)/vendor/qcom/proprietary/qdsp6/mm-core/omxcore/inc \
+ $(TOP)/frameworks/base/core/jni/mediaeditor \
+ $(TOP)/frameworks/media/libvideoeditor/vss/inc \
+ $(TOP)/frameworks/media/libvideoeditor/vss/common/inc \
+ $(TOP)/frameworks/media/libvideoeditor/vss/mcs/inc \
+ $(TOP)/frameworks/media/libvideoeditor/lvpp \
+ $(TOP)/frameworks/media/libvideoeditor/osal/inc \
+ $(TOP)/frameworks/media/libvideoeditor/vss/stagefrightshells/inc
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libandroid_runtime \
+ libnativehelper \
+ libmedia \
+ libbinder \
+ libstagefright \
+ libstagefright_omx \
+ libsurfaceflinger_client \
+ libvideoeditorplayer
+
+LOCAL_CFLAGS += \
+
+
+
+LOCAL_LDFLAGS += -fuse-ld=bfd
+
+LOCAL_STATIC_LIBRARIES := \
+ libvideoeditor_osal \
+ libstagefright_color_conversion
+
+
+LOCAL_MODULE:= libvideoeditor_stagefrightshells
+
+LOCAL_MODULE_TAGS := eng development
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp
new file mode 100755
index 0000000..70a5a81
--- /dev/null
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp
@@ -0,0 +1,1967 @@
+/*
+ * Copyright (C) 2011 NXP Software
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+*************************************************************************
+* @file VideoEditor3gpReader.cpp
+* @brief StageFright shell 3GP Reader
+*************************************************************************
+*/
+
+#define LOG_NDEBUG 1
+#define LOG_TAG "VIDEOEDITOR_3GPREADER"
+
+/**
+ * HEADERS
+ *
+ */
+#define VIDEOEDITOR_BITSTREAM_PARSER
+
+#include "M4OSA_Debug.h"
+#include "VideoEditor3gpReader.h"
+#include "M4SYS_AccessUnit.h"
+#include "VideoEditorUtils.h"
+#include "M4READER_3gpCom.h"
+#include "M4_Common.h"
+#include "M4OSA_FileWriter.h"
+
+#ifdef VIDEOEDITOR_BITSTREAM_PARSER
+#include "M4OSA_CoreID.h"
+#include "M4OSA_Error.h"
+#include "M4OSA_Memory.h"
+#include "M4_Utils.h"
+#endif
+
+#include "ESDS.h"
+#include "utils/Log.h"
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+/**
+ * SOURCE CLASS
+ */
+namespace android {
+/**
+ * ENGINE INTERFACE
+ */
+
+/**
+ ************************************************************************
+ * @brief Array of AMR NB/WB bitrates
+ * @note Array to match the mode and the bit rate
+ ************************************************************************
+*/
+const M4OSA_UInt32 VideoEditor3gpReader_AmrBitRate [2 /* 8kHz / 16kHz */]
+ [9 /* the bitrate mode */] =
+{
+ {4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200, 0},
+ {6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850}
+};
+
+/**
+ *******************************************************************************
+ * structure VideoEditor3gpReader_Context
+ * @brief:This structure defines the context of the StageFright 3GP shell Reader
+ *******************************************************************************
+*/
+typedef struct {
+ sp<DataSource> mDataSource;
+ sp<MediaExtractor> mExtractor;
+ sp<MediaSource> mAudioSource;
+ sp<MediaSource> mVideoSource;
+ M4_StreamHandler* mAudioStreamHandler;
+ M4_StreamHandler* mVideoStreamHandler;
+ M4SYS_AccessUnit mAudioAu;
+ M4SYS_AccessUnit mVideoAu;
+ M4OSA_Time mMaxDuration;
+ int32_t mFileSize;
+ M4_StreamType mStreamType;
+ M4OSA_UInt32 mStreamId;
+ int32_t mTracks;
+ int32_t mCurrTrack;
+ M4OSA_Bool mAudioSeeking;
+ M4OSA_Time mAudioSeekTime;
+ M4OSA_Bool mVideoSeeking;
+ M4OSA_Time mVideoSeekTime;
+
+} VideoEditor3gpReader_Context;
+
+#ifdef VIDEOEDITOR_BITSTREAM_PARSER
+/**
+ ************************************************************************
+ * structure VideoEditor3gpReader_BitStreamParserContext
+ * @brief Internal BitStreamParser context
+ ************************************************************************
+*/
+typedef struct {
+ M4OSA_UInt32* mPbitStream; /**< bitstream pointer (32bits aligned) */
+ M4OSA_Int32 mSize; /**< bitstream size in bytes */
+ M4OSA_Int32 mIndex; /**< byte index */
+ M4OSA_Int32 mBitIndex; /**< bit index */
+ M4OSA_Int32 mStructSize; /**< size of structure */
+} VideoEditor3gpReader_BitStreamParserContext;
+
+/**
+ *******************************************************************************
+ * @brief Allocates the context and initializes internal data.
+ * @param pContext (OUT) Pointer to the BitStreamParser context to create.
+ * @param bitStream A pointer to the bitstream
+ * @param size The size of the bitstream in bytes
+ *******************************************************************************
+*/
+static void VideoEditor3gpReader_BitStreamParserInit(void** pContext,
+ void* pBitStream, M4OSA_Int32 size) {
+ VideoEditor3gpReader_BitStreamParserContext* pStreamContext;
+
+ *pContext=M4OSA_NULL;
+ pStreamContext = (VideoEditor3gpReader_BitStreamParserContext*)M4OSA_malloc(
+ sizeof(VideoEditor3gpReader_BitStreamParserContext), M4READER_3GP,
+ (M4OSA_Char*)"3GP BitStreamParser Context");
+ if (M4OSA_NULL == pStreamContext) {
+ return;
+ }
+ pStreamContext->mPbitStream=(M4OSA_UInt32*)pBitStream;
+ pStreamContext->mSize=size;
+ pStreamContext->mIndex=0;
+ pStreamContext->mBitIndex=0;
+ pStreamContext->mStructSize =
+ sizeof(VideoEditor3gpReader_BitStreamParserContext);
+
+ *pContext=pStreamContext;
+}
+/**
+ **********************************************************************
+ * @brief Clean up context
+ * @param pContext (IN/OUT) BitStreamParser context.
+ **********************************************************************
+*/
+static void VideoEditor3gpReader_BitStreamParserCleanUp(void* pContext) {
+ M4OSA_free((M4OSA_Int32*)pContext);
+}
+/**
+ *****************************************************************************
+ * @brief Read the next <length> bits in the bitstream.
+ * @note The function does not update the bitstream pointer.
+ * @param pContext (IN/OUT) BitStreamParser context.
+ * @param length (IN) The number of bits to extract from the bitstream
+ * @return the read bits
+ *****************************************************************************
+*/
+static M4OSA_UInt32 VideoEditor3gpReader_BitStreamParserShowBits(void* pContext,
+ M4OSA_Int32 length) {
+ VideoEditor3gpReader_BitStreamParserContext* pStreamContext =
+ (VideoEditor3gpReader_BitStreamParserContext*)pContext;
+
+ M4OSA_UInt32 u_mask;
+ M4OSA_UInt32 retval;
+ M4OSA_Int32 i_ovf;
+
+ M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0,
+ "VideoEditor3gpReader_BitStreamParserShowBits:invalid context pointer");
+
+ retval=(M4OSA_UInt32)GET_MEMORY32(pStreamContext->\
+ mPbitStream[ pStreamContext->mIndex ]);
+ i_ovf = pStreamContext->mBitIndex + length - 32;
+ u_mask = (length >= 32) ? 0xffffffff: (1 << length) - 1;
+
+ /* do we have enough bits availble in the current word(32bits)*/
+ if (i_ovf <= 0) {
+ retval=(retval >> (- i_ovf)) & u_mask;
+ } else {
+ M4OSA_UInt32 u_nextword = (M4OSA_UInt32)GET_MEMORY32(
+ pStreamContext->mPbitStream[ pStreamContext->mIndex + 1 ]);
+ M4OSA_UInt32 u_msb_mask, u_msb_value, u_lsb_mask, u_lsb_value;
+
+ u_msb_mask = ((1 << (32 - pStreamContext->mBitIndex)) - 1) << i_ovf;
+ u_msb_value = retval << i_ovf;
+ u_lsb_mask = (1 << i_ovf) - 1;
+ u_lsb_value = u_nextword >> (32 - i_ovf);
+ retval= (u_msb_value & u_msb_mask ) | (u_lsb_value & u_lsb_mask);
+ }
+ /* return the bits...*/
+ return retval;
+}
+/**
+ ************************************************************************
+ * @brief Increment the bitstream pointer of <length> bits.
+ * @param pContext (IN/OUT) BitStreamParser context.
+ * @param length (IN) The number of bit to shift the bitstream
+ ************************************************************************
+*/
+static void VideoEditor3gpReader_BitStreamParserFlushBits(void* pContext,
+ M4OSA_Int32 length) {
+ VideoEditor3gpReader_BitStreamParserContext* pStreamContext=(
+ VideoEditor3gpReader_BitStreamParserContext*)pContext;
+ M4OSA_Int32 val;
+
+ if (M4OSA_NULL == pStreamContext) {
+ return;
+ }
+ val=pStreamContext->mBitIndex + length;
+ /* update the bits...*/
+ pStreamContext->mBitIndex += length;
+
+ if (val - 32 >= 0) {
+ /* update the bits...*/
+ pStreamContext->mBitIndex -= 32;
+ /* update the words*/
+ pStreamContext->mIndex++;
+ }
+}
+
+static M4OSA_UInt32 VideoEditor3gpReader_BitStreamParserGetBits(
+ void* pContext,M4OSA_Int32 bitPos, M4OSA_Int32 bitLength) {
+ VideoEditor3gpReader_BitStreamParserContext* pStreamContext =
+ (VideoEditor3gpReader_BitStreamParserContext*)pContext;
+
+ M4OSA_Int32 bitLocation, bitIndex;
+ M4OSA_UInt32 retval=0;
+
+ M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0,
+ "VideoEditor3gpReader_BitStreamParserGetBits: invalid context pointer");
+
+ /* computes the word location*/
+ bitLocation=bitPos/32;
+ bitIndex=(bitPos) % 32;
+
+ if (bitLocation < pStreamContext->mSize) {
+ M4OSA_UInt32 u_mask;
+ M4OSA_Int32 i_ovf = bitIndex + bitLength - 32;
+ retval=(M4OSA_UInt32)GET_MEMORY32(
+ pStreamContext->mPbitStream[ bitLocation ]);
+
+ u_mask = (bitLength >= 32) ? 0xffffffff: (1 << bitLength) - 1;
+
+ if (i_ovf <= 0) {
+ retval=(retval >> (- i_ovf)) & u_mask;
+ } else {
+ M4OSA_UInt32 u_nextword = (M4OSA_UInt32)GET_MEMORY32(
+ pStreamContext->mPbitStream[ bitLocation + 1 ]);
+ M4OSA_UInt32 u_msb_mask, u_msb_value, u_lsb_mask, u_lsb_value;
+
+ u_msb_mask = ((1 << (32 - bitIndex)) - 1) << i_ovf;
+ u_msb_value = retval << i_ovf;
+ u_lsb_mask = (1 << i_ovf) - 1;
+ u_lsb_value = u_nextword >> (32 - i_ovf);
+ retval= (u_msb_value & u_msb_mask ) | (u_lsb_value & u_lsb_mask);
+ }
+ }
+ return retval;
+}
+
+static void VideoEditor3gpReader_BitStreamParserRestart(void* pContext) {
+ VideoEditor3gpReader_BitStreamParserContext* pStreamContext =
+ (VideoEditor3gpReader_BitStreamParserContext*)pContext;
+
+ if (M4OSA_NULL == pStreamContext) {
+ return;
+ }
+ /* resets the bitstream pointers*/
+ pStreamContext->mIndex=0;
+ pStreamContext->mBitIndex=0;
+}
+/**
+ *******************************************************************************
+ * @brief Get a pointer to the current byte pointed by the bitstream pointer.
+ * @note It should be used carefully as the pointer is in the bitstream itself
+ * and no copy is made.
+ * @param pContext (IN/OUT) BitStreamParser context.
+ * @return Pointer to the current location in the bitstream
+ *******************************************************************************
+*/
+static M4OSA_UInt8* VideoEditor3gpReader_GetCurrentbitStreamPointer(
+ void* pContext) {
+ VideoEditor3gpReader_BitStreamParserContext* pStreamContext =
+ (VideoEditor3gpReader_BitStreamParserContext*)pContext;
+ M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0, "invalid context pointer");
+
+ return (M4OSA_UInt8*)((M4OSA_UInt8*)pStreamContext->mPbitStream + \
+ pStreamContext->mIndex * sizeof(M4OSA_UInt32) + \
+ pStreamContext->mBitIndex/8) ;
+}
+
+static M4OSA_Int32 VideoEditor3gpReader_BitStreamParserGetSize(void* pContext) {
+ VideoEditor3gpReader_BitStreamParserContext* pStreamContext =
+ (VideoEditor3gpReader_BitStreamParserContext*)pContext;
+ M4OSA_DEBUG_IF1((M4OSA_NULL==pStreamContext), 0, "invalid context pointer");
+
+ return pStreamContext->mSize;
+}
+
+
+static void VideoEditor3gpReader_MPEG4BitStreamParserInit(void** pContext,
+ void* pBitStream, M4OSA_Int32 size) {
+ VideoEditor3gpReader_BitStreamParserInit(pContext, pBitStream, size);
+}
+static M4OSA_Int32 VideoEditor3gpReader_GetMpegLengthFromInteger(void* pContext,
+ M4OSA_UInt32 val) {
+ M4OSA_UInt32 length=0;
+ M4OSA_UInt32 numBytes=0;
+ M4OSA_UInt32 b=0;
+
+ M4OSA_DEBUG_IF1((M4OSA_NULL==pContext), 0, "invalid context pointer");
+
+ /* the length is encoded as a sequence of bytes. The highest bit is used
+ to indicate that the length continues on the next byte.
+
+ The length can be: 0x80 0x80 0x80 0x22
+ of just 0x22 (highest bit not set)
+
+ */
+
+ do {
+ b=(val & ((0xff)<< (8 * numBytes)))>> (8 * numBytes);
+ length=(length << 7) | (b & 0x7f);
+ numBytes++;
+ } while ((b & 0x80) && numBytes < 4);
+
+ return length;
+}
+
+/**
+ *******************************************************************************
+ * @brief Decode an MPEG4 Systems descriptor size from an encoded SDL size data
+ * @note The value is read from the current bitstream location.
+ * @param pContext (IN/OUT) BitStreamParser context.
+ * @return Size in a human readable form
+ *******************************************************************************
+*/
+static M4OSA_Int32 VideoEditor3gpReader_GetMpegLengthFromStream(void* pContext){
+ M4OSA_UInt32 length=0;
+ M4OSA_UInt32 numBytes=0;
+ M4OSA_UInt32 b=0;
+
+ M4OSA_DEBUG_IF1((M4OSA_NULL==pContext), 0, "invalid context pointer");
+
+ /* the length is encoded as a sequence of bytes. The highest bit is used
+ to indicate that the length continues on the next byte.
+
+ The length can be: 0x80 0x80 0x80 0x22
+ of just 0x22 (highest bit not set)
+ */
+
+ do {
+ b=VideoEditor3gpReader_BitStreamParserShowBits(pContext, 8);
+ VideoEditor3gpReader_BitStreamParserFlushBits(pContext, 8);
+ length=(length << 7) | (b & 0x7f);
+ numBytes++;
+ } while ((b & 0x80) && numBytes < 4);
+
+ return length;
+}
+#endif /* VIDEOEDITOR_BITSTREAM_PARSER */
+/**
+************************************************************************
+* @brief create an instance of the 3gp reader
+ * @note allocates the context
+ *
+ * @param pContext: (OUT) pointer on a reader context
+ *
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_ALLOC a memory allocation has failed
+ * @return M4ERR_PARAMETER at least one parameter is not valid
+************************************************************************
+*/
+
+M4OSA_ERR VideoEditor3gpReader_create(M4OSA_Context *pContext) {
+ VideoEditor3gpReader_Context* pC = NULL;
+ M4OSA_ERR err = M4NO_ERROR;
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext , M4ERR_PARAMETER);
+
+ LOGV("VideoEditor3gpReader_create begin");
+
+ /* Context allocation & initialization */
+ SAFE_MALLOC(pC, VideoEditor3gpReader_Context, 1, "VideoEditor3gpReader");
+
+ memset(pC, sizeof(VideoEditor3gpReader_Context), 0);
+
+ pC->mAudioStreamHandler = M4OSA_NULL;
+ pC->mAudioAu.dataAddress = M4OSA_NULL;
+ pC->mVideoStreamHandler = M4OSA_NULL;
+ pC->mVideoAu.dataAddress = M4OSA_NULL;
+
+ pC->mAudioSeeking = M4OSA_FALSE;
+ pC->mAudioSeekTime = 0;
+
+ pC->mVideoSeeking = M4OSA_FALSE;
+ pC->mVideoSeekTime = 0;
+
+ M4OSA_INT64_FROM_INT32(pC->mMaxDuration, 0);
+ *pContext=pC;
+
+cleanUp:
+ if ( M4NO_ERROR == err ) {
+ LOGV("VideoEditor3gpReader_create no error");
+ } else {
+ LOGV("VideoEditor3gpReader_create ERROR 0x%X", err);
+ }
+ LOGV("VideoEditor3gpReader_create end ");
+ return err;
+}
+
+/**
+**************************************************************************
+* @brief destroy the instance of the 3gp reader
+* @note after this call the context is invalid
+* @param context: (IN) Context of the reader
+* @return M4NO_ERROR there is no error
+* @return M4ERR_PARAMETER pContext parameter is not properly set
+**************************************************************************
+*/
+
+M4OSA_ERR VideoEditor3gpReader_destroy(M4OSA_Context pContext) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditor3gpReader_Context* pC = M4OSA_NULL;
+
+ LOGV("VideoEditor3gpReader_destroy begin");
+
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ pC = (VideoEditor3gpReader_Context*)pContext;
+
+ SAFE_FREE(pC->mAudioAu.dataAddress);
+ pC->mAudioAu.dataAddress = M4OSA_NULL;
+ SAFE_FREE(pC->mVideoAu.dataAddress);
+ pC->mVideoAu.dataAddress = M4OSA_NULL;
+ SAFE_FREE(pC);
+ pContext = M4OSA_NULL;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditor3gpReader_destroy no error");
+ }
+ else
+ {
+ LOGV("VideoEditor3gpReader_destroy ERROR 0x%X", err);
+ }
+
+ LOGV("VideoEditor3gpReader_destroy end ");
+ return err;
+}
+
+/**
+************************************************************************
+* @brief open the reader and initializes its created instance
+* @note this function open the media file
+* @param context: (IN) Context of the reader
+* @param pFileDescriptor: (IN) Pointer to proprietary data identifying
+* the media to open
+* @return M4NO_ERROR there is no error
+* @return M4ERR_PARAMETER the context is NULL
+************************************************************************
+*/
+
+M4OSA_ERR VideoEditor3gpReader_open(M4OSA_Context pContext,
+ M4OSA_Void* pFileDescriptor) {
+ VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)pContext;
+ M4OSA_ERR err = M4NO_ERROR;
+
+ LOGV("VideoEditor3gpReader_open start ");
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_open: invalid context pointer");
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pFileDescriptor), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_open: invalid pointer pFileDescriptor");
+
+ LOGV("VideoEditor3gpReader_open Datasource start %s",
+ (char*)pFileDescriptor);
+ pC->mDataSource = DataSource::CreateFromURI((char*)pFileDescriptor);
+
+ if (pC->mDataSource == NULL) {
+ LOGV("VideoEditor3gpReader_open Datasource error");
+ return M4ERR_PARAMETER;
+ }
+
+ pC->mExtractor = MediaExtractor::Create(pC->mDataSource,
+ MEDIA_MIMETYPE_CONTAINER_MPEG4);
+
+ if (pC->mExtractor == NULL) {
+ LOGV("VideoEditor3gpReader_open extractor error");
+ return M4ERR_PARAMETER;
+ }
+
+ LOGV("VideoEditor3gpReader_open end ");
+ return err;
+}
+
+/**
+************************************************************************
+* @brief close the reader
+* @note close the 3GP file
+* @param context: (IN) Context of the reader
+* @return M4NO_ERROR there is no error
+* @return M4ERR_PARAMETER the context is NULL
+* @return M4ERR_BAD_CONTEXT provided context is not a valid one
+************************************************************************
+*/
+M4OSA_ERR VideoEditor3gpReader_close(M4OSA_Context context) {
+ VideoEditor3gpReader_Context *pC = (VideoEditor3gpReader_Context*)context;
+ M4READER_AudioSbrUserdata *pAudioSbrUserData;
+ M4_AccessUnit *pAU;
+ M4OSA_ERR err = M4NO_ERROR;
+
+ LOGV("VideoEditor3gpReader_close begin");
+
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_close: invalid context pointer");
+
+ if (pC->mAudioStreamHandler) {
+ LOGV("VideoEditor3gpReader_close Audio");
+
+ if (M4OSA_NULL != pC->mAudioStreamHandler->m_pDecoderSpecificInfo) {
+ M4OSA_free((M4OSA_MemAddr32)pC->mAudioStreamHandler->\
+ m_pDecoderSpecificInfo);
+ pC->mAudioStreamHandler->m_decoderSpecificInfoSize = 0;
+ pC->mAudioStreamHandler->m_pDecoderSpecificInfo = M4OSA_NULL;
+ }
+
+ if ((M4DA_StreamTypeAudioAac == pC->mAudioStreamHandler->m_streamType)
+ && (M4OSA_NULL != pC->mAudioStreamHandler->m_pUserData)) {
+ pAudioSbrUserData = (M4READER_AudioSbrUserdata*)(\
+ pC->mAudioStreamHandler->m_pUserData);
+
+ pAU = (M4_AccessUnit*)pAudioSbrUserData->m_pFirstAU;
+ if (M4OSA_NULL != pAU) {
+ M4OSA_free((M4OSA_MemAddr32)pAU);
+ }
+
+ if (M4OSA_NULL != pAudioSbrUserData->m_pAacDecoderUserConfig) {
+ M4OSA_free((M4OSA_MemAddr32)pAudioSbrUserData->\
+ m_pAacDecoderUserConfig);
+ }
+ M4OSA_free((M4OSA_MemAddr32)pAudioSbrUserData);
+ pC->mAudioStreamHandler->m_pUserData = M4OSA_NULL;
+ }
+
+ if (pC->mAudioStreamHandler->m_pESDSInfo != M4OSA_NULL) {
+ M4OSA_free((M4OSA_MemAddr32)pC->mAudioStreamHandler->m_pESDSInfo);
+ pC->mAudioStreamHandler->m_pESDSInfo = M4OSA_NULL;
+ pC->mAudioStreamHandler->m_ESDSInfoSize = 0;
+ }
+ /* Finally destroy the stream handler */
+ M4OSA_free((M4OSA_MemAddr32)pC->mAudioStreamHandler);
+ pC->mAudioStreamHandler = M4OSA_NULL;
+
+ pC->mAudioSource->stop();
+ pC->mAudioSource.clear();
+ }
+ if (pC->mVideoStreamHandler) {
+ LOGV("VideoEditor3gpReader_close Video ");
+
+ if(M4OSA_NULL != pC->mVideoStreamHandler->m_pDecoderSpecificInfo) {
+ M4OSA_free((M4OSA_MemAddr32)pC->mVideoStreamHandler->\
+ m_pDecoderSpecificInfo);
+ pC->mVideoStreamHandler->m_decoderSpecificInfoSize = 0;
+ pC->mVideoStreamHandler->m_pDecoderSpecificInfo = M4OSA_NULL;
+ }
+
+ if(M4OSA_NULL != pC->mVideoStreamHandler->m_pH264DecoderSpecificInfo) {
+ M4OSA_free((M4OSA_MemAddr32)pC->mVideoStreamHandler->\
+ m_pH264DecoderSpecificInfo);
+ pC->mVideoStreamHandler->m_H264decoderSpecificInfoSize = 0;
+ pC->mVideoStreamHandler->m_pH264DecoderSpecificInfo = M4OSA_NULL;
+ }
+
+ if(pC->mVideoStreamHandler->m_pESDSInfo != M4OSA_NULL) {
+ M4OSA_free((M4OSA_MemAddr32)pC->mVideoStreamHandler->m_pESDSInfo);
+ pC->mVideoStreamHandler->m_pESDSInfo = M4OSA_NULL;
+ pC->mVideoStreamHandler->m_ESDSInfoSize = 0;
+ }
+
+ /* Finally destroy the stream handler */
+ M4OSA_free((M4OSA_MemAddr32)pC->mVideoStreamHandler);
+ pC->mVideoStreamHandler = M4OSA_NULL;
+
+ pC->mVideoSource->stop();
+ pC->mVideoSource.clear();
+ }
+ pC->mDataSource.clear();
+
+ LOGV("VideoEditor3gpReader_close end");
+ return err;
+}
+
+/**
+************************************************************************
+* @brief get an option from the 3gp reader
+* @note it allows the caller to retrieve a property value:
+*
+* @param context: (IN) Context of the reader
+* @param optionId: (IN) indicates the option to get
+* @param pValue: (OUT) pointer to structure or value (allocated
+* by user) where option is stored
+*
+* @return M4NO_ERROR there is no error
+* @return M4ERR_BAD_CONTEXT provided context is not a valid one
+* @return M4ERR_PARAMETER at least one parameter is not properly set
+* @return M4ERR_BAD_OPTION_ID when the option ID is not a valid one
+* @return M4ERR_VIDEO_NOT_H263 No video stream H263 in file.
+* @return M4ERR_NO_VIDEO_STREAM_RETRIEVED_YET
+* Function 3gpReader_getNextStreamHandler must be called before
+************************************************************************
+*/
+M4OSA_ERR VideoEditor3gpReader_getOption(M4OSA_Context context,
+ M4OSA_OptionID optionId, M4OSA_DataOption pValue) {
+ VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+
+ LOGV("VideoEditor3gpReader_getOption begin %d", optionId);
+
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER,
+ "invalid context pointer");
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pValue), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_getOption: invalid pointer on value");
+
+ switch (optionId) {
+ case M4READER_kOptionID_Duration:
+ {
+ LOGV("VideoEditor3gpReader_getOption duration %d",pC->mMaxDuration);
+ M4OSA_TIME_SET(*(M4OSA_Time*)pValue, pC->mMaxDuration);
+ }
+ break;
+ case M4READER_kOptionID_Version:
+ /* not used */
+ LOGV("VideoEditor3gpReader_getOption: M4READER_kOptionID_Version");
+ break;
+
+ case M4READER_kOptionID_Copyright:
+ /* not used */
+ LOGV(">>>>>>> M4READER_kOptionID_Copyright");
+ break;
+
+ case M4READER_kOptionID_CreationTime:
+ /* not used */
+ LOGV("VideoEditor3gpReader_getOption M4READER_kOptionID_CreationTime");
+ break;
+
+ case M4READER_kOptionID_Bitrate:
+ {
+ M4OSA_UInt32* pBitrate = (M4OSA_UInt32*)pValue;
+
+ if (pC->mMaxDuration != 0) {
+ M4OSA_UInt32 ui32Tmp = (M4OSA_UInt32)pC->mMaxDuration;
+ *pBitrate = (M4OSA_UInt32)((M4OSA_Double)pC->mFileSize * \
+ 8000.0 / (M4OSA_Double)ui32Tmp);
+ LOGV("3gpReader_getOption bitrate: %d", *pBitrate);
+ }
+ *pBitrate = 384000; //check
+ LOGV("VideoEditor3gpReader_getOption bitrate %ld", *pBitrate);
+ }
+ break;
+ case M4READER_3GP_kOptionID_H263Properties:
+ {
+#if 0
+ if(M4OSA_NULL == pC->mVideoStreamHandler) {
+ LOGV("VideoEditor3gpReader_getOption no videoStream retrieved");
+
+ err = M4ERR_NO_VIDEO_STREAM_RETRIEVED_YET;
+ break;
+ }
+ if((M4DA_StreamTypeVideoH263 != pC->mVideoStreamHandler->\
+ mStreamType) || (pC->mVideoStreamHandler->\
+ m_decoderSpecificInfoSize < 7)) {
+ LOGV("VideoEditor3gpReader_getOption DSI Size %d",
+ pC->mVideoStreamHandler->m_decoderSpecificInfoSize);
+
+ err = M4ERR_VIDEO_NOT_H263;
+ break;
+ }
+
+ /* MAGICAL in the decoder confi H263: the 7th byte is the profile
+ * number, 6th byte is the level number */
+ ((M4READER_3GP_H263Properties *)pValue)->uiProfile =
+ pC->mVideoStreamHandler->m_pDecoderSpecificInfo[6];
+ ((M4READER_3GP_H263Properties *)pValue)->uiLevel =
+ pC->mVideoStreamHandler->m_pDecoderSpecificInfo[5];
+#endif
+ LOGV("VideoEditor3gpReader_getOption M4READER_3GP_kOptionID_\
+ H263Properties end");
+ }
+ break;
+ case M4READER_3GP_kOptionID_PurpleLabsDrm:
+ LOGV("VideoEditor3gpReaderOption M4READER_3GP_kOptionID_PurpleLabsDrm");
+ /* not used */
+ break;
+
+ case M4READER_kOptionID_GetNumberOfAudioAu:
+ /* not used */
+ LOGV("VideoEditor3gpReadeOption M4READER_kOptionID_GetNumberOfAudioAu");
+ break;
+
+ case M4READER_kOptionID_GetNumberOfVideoAu:
+ /* not used */
+ LOGV("VideoEditor3gpReader_getOption :GetNumberOfVideoAu");
+ break;
+
+ case M4READER_kOptionID_GetMetadata:
+ /* not used */
+ LOGV("VideoEditor3gpReader_getOption M4READER_kOptionID_GetMetadata");
+ break;
+
+ case M4READER_kOptionID_3gpFtypBox:
+ /* used only for SEMC */
+ LOGV("VideoEditor3gpReader_getOption M4READER_kOptionID_3gpFtypBox");
+ err = M4ERR_BAD_OPTION_ID; //check this
+ break;
+
+#ifdef OPTIONID_GET_NEXT_VIDEO_CTS
+ case M4READER_3GP_kOptionID_getNextVideoCTS:
+ /* not used */
+ LOGV("VideoEditor3gpReader_getOption: getNextVideoCTS");
+ break;
+#endif
+ default:
+ {
+ err = M4ERR_BAD_OPTION_ID;
+ LOGV("VideoEditor3gpReader_getOption M4ERR_BAD_OPTION_ID");
+ }
+ break;
+ }
+ LOGV("VideoEditor3gpReader_getOption end: optionID: x%x", optionId);
+ return err;
+}
+/**
+************************************************************************
+* @brief set an option on the 3gp reader
+* @note No option can be set yet.
+* @param context: (IN) Context of the reader
+* @param optionId: (IN) indicates the option to set
+* @param pValue: (IN) pointer to structure or value (allocated
+* by user) where option is stored
+* @return M4NO_ERROR there is no error
+* @return M4ERR_BAD_CONTEXT provided context is not a valid one
+* @return M4ERR_PARAMETER at least one parameter is not properly set
+* @return M4ERR_BAD_OPTION_ID when the option ID is not a valid one
+************************************************************************
+*/
+M4OSA_ERR VideoEditor3gpReader_setOption(M4OSA_Context context,
+ M4OSA_OptionID optionId, M4OSA_DataOption pValue) {
+ VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+
+ /* Check function parameters */
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pC), M4ERR_PARAMETER,
+ "invalid context pointer");
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pValue), M4ERR_PARAMETER,
+ "invalid value pointer");
+
+ LOGV("VideoEditor3gpReader_setOption begin %d",optionId);
+
+ switch(optionId) {
+ case M4READER_kOptionID_SetOsaFileReaderFctsPtr:
+ break;
+
+ case M4READER_3GP_kOptionID_AudioOnly:
+ break;
+
+ case M4READER_3GP_kOptionID_VideoOnly:
+ break;
+
+ case M4READER_3GP_kOptionID_FastOpenMode:
+ break;
+
+ case M4READER_kOptionID_MaxMetadataSize:
+ break;
+
+ default:
+ {
+ LOGV("VideoEditor3gpReader_setOption: returns M4ERR_BAD_OPTION_ID");
+ err = M4ERR_BAD_OPTION_ID;
+ }
+ break;
+ }
+ LOGV("VideoEditor3gpReader_setOption end ");
+ return err;
+}
+/**
+ ************************************************************************
+ * @brief fill the access unit structure with initialization values
+ * @param context: (IN) Context of the reader
+ * @param pStreamHandler: (IN) pointer to the stream handler to which
+ * the access unit will be associated
+ * @param pAccessUnit: (IN/OUT) pointer to the access unit (allocated
+ * by the caller) to initialize
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_PARAMETER at least one parameter is not properly set
+ ************************************************************************
+*/
+M4OSA_ERR VideoEditor3gpReader_fillAuStruct(M4OSA_Context context,
+ M4_StreamHandler *pStreamHandler, M4_AccessUnit *pAccessUnit) {
+ VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context;
+ M4OSA_ERR err= M4NO_ERROR;
+
+ M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_fillAuStruct: invalid context");
+ M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_fillAuStruc invalid pointer to M4_StreamHandler");
+ M4OSA_DEBUG_IF1((pAccessUnit == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_fillAuStruct: invalid pointer to M4_AccessUnit");
+
+ LOGV("VideoEditor3gpReader_fillAuStruct begin");
+
+ /* Initialize pAccessUnit structure */
+ pAccessUnit->m_size = 0;
+ pAccessUnit->m_CTS = 0;
+ pAccessUnit->m_DTS = 0;
+ pAccessUnit->m_attribute = 0;
+ pAccessUnit->m_dataAddress = M4OSA_NULL;
+ pAccessUnit->m_maxsize = pStreamHandler->m_maxAUSize;
+ pAccessUnit->m_streamID = pStreamHandler->m_streamId;
+ pAccessUnit->m_structSize = sizeof(M4_AccessUnit);
+
+ LOGV("VideoEditor3gpReader_fillAuStruct end");
+ return M4NO_ERROR;
+}
+
+/**
+********************************************************************************
+* @brief jump into the stream at the specified time
+* @note
+* @param context: (IN) Context of the reader
+* @param pStreamHandler (IN) the stream handler of the stream to make jump
+* @param pTime (I/O)IN the time to jump to (in ms)
+* OUT the time to which the stream really jumped
+* @return M4NO_ERROR there is no error
+* @return M4ERR_PARAMETER at least one parameter is not properly set
+********************************************************************************
+*/
+M4OSA_ERR VideoEditor3gpReader_jump(M4OSA_Context context,
+ M4_StreamHandler *pStreamHandler, M4OSA_Int32* pTime) {
+ VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+ M4SYS_AccessUnit* pAu;
+ M4OSA_Time time64;
+ M4OSA_Double timeDouble;
+
+ M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_jump: invalid context");
+ M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_jump: invalid pointer to M4_StreamHandler");
+ M4OSA_DEBUG_IF1((pTime == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_jump: invalid time pointer");
+
+ LOGV("VideoEditor3gpReader_jump begin");
+
+ if (*pTime == (pStreamHandler->m_duration)) {
+ *pTime -= 1;
+ }
+ M4OSA_INT64_FROM_INT32(time64, *pTime);
+
+ LOGV("VideoEditor3gpReader_jump time us %ld ", time64);
+
+ if ((pC->mAudioStreamHandler != M4OSA_NULL) &&
+ (pStreamHandler->m_streamId == pC->mAudioStreamHandler->m_streamId))
+ {
+ pAu = &pC->mAudioAu;
+ pAu->CTS = time64;
+ pAu->DTS = time64;
+
+ time64 = time64 * 1000; /* Convert the time into micro sec */
+ pC->mAudioSeeking = M4OSA_TRUE;
+ pC->mAudioSeekTime = time64;
+ LOGV("VideoEditor3gpReader_jump AUDIO time us %ld ", time64);
+ } else if ((pC->mVideoStreamHandler != M4OSA_NULL) &&
+ (pStreamHandler->m_streamId == pC->mVideoStreamHandler->m_streamId))
+ {
+ pAu = &pC->mVideoAu;
+ pAu->CTS = time64;
+ pAu->DTS = time64;
+
+ time64 = time64 * 1000; /* Convert the time into micro sec */
+ pC->mVideoSeeking = M4OSA_TRUE;
+ pC->mVideoSeekTime = time64;
+ LOGV("VideoEditor3gpReader_jump VIDEO time us %ld ", time64);
+ } else {
+ LOGV("VideoEditor3gpReader_jump passed StreamHandler is not known\n");
+ return M4ERR_PARAMETER;
+ }
+ time64 = time64 / 1000; /* Convert the time into milli sec */
+ LOGV("VideoEditor3gpReader_jump time ms before seekset %ld ", time64);
+
+ M4OSA_INT64_TO_DOUBLE(timeDouble, time64);
+ *pTime = (M4OSA_Int32)timeDouble;
+
+ LOGV("VideoEditor3gpReader_jump end");
+ err = M4NO_ERROR;
+ return err;
+}
+/**
+********************************************************************************
+* @brief reset the stream, that is seek it to beginning and make it ready
+* @note
+* @param context: (IN) Context of the reader
+* @param pStreamHandler (IN) The stream handler of the stream to reset
+* @return M4NO_ERROR there is no error
+* @return M4ERR_PARAMETER at least one parameter is not properly set
+********************************************************************************
+*/
+M4OSA_ERR VideoEditor3gpReader_reset(M4OSA_Context context,
+ M4_StreamHandler *pStreamHandler) {
+ VideoEditor3gpReader_Context* pC = (VideoEditor3gpReader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+ M4SYS_StreamID streamIdArray[2];
+ M4SYS_AccessUnit* pAu;
+ M4OSA_Time time64;
+
+ M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_reset: invalid context");
+ M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_reset: invalid pointer to M4_StreamHandler");
+
+ M4OSA_INT64_FROM_INT32(time64, 0);
+
+ LOGV("VideoEditor3gpReader_reset begin");
+
+ if (pStreamHandler == (M4_StreamHandler*)pC->mAudioStreamHandler) {
+ pAu = &pC->mAudioAu;
+ } else if (pStreamHandler == (M4_StreamHandler*)pC->mVideoStreamHandler) {
+ pAu = &pC->mVideoAu;
+ } else {
+ LOGV("VideoEditor3gpReader_reset passed StreamHandler is not known\n");
+ return M4ERR_PARAMETER;
+ }
+
+ pAu->CTS = time64;
+ pAu->DTS = time64;
+
+ LOGV("VideoEditor3gpReader_reset end");
+ return err;
+}
+
+/**
+********************************************************************************
+* @brief Gets an access unit (AU) from the stream handler source.
+* @note An AU is the smallest possible amount of data to be decoded by decoder
+*
+* @param context: (IN) Context of the reader
+* @param pStreamHandler (IN) The stream handler of the stream to make jump
+* @param pAccessUnit (IO) Pointer to access unit to fill with read data
+* @return M4NO_ERROR there is no error
+* @return M4ERR_PARAMETER at least one parameter is not properly set
+* @returns M4ERR_ALLOC memory allocation failed
+* @returns M4WAR_NO_MORE_AU there are no more access unit in the stream
+********************************************************************************
+*/
+M4OSA_ERR VideoEditor3gpReader_getNextAu(M4OSA_Context context,
+ M4_StreamHandler *pStreamHandler, M4_AccessUnit *pAccessUnit) {
+ VideoEditor3gpReader_Context* pC=(VideoEditor3gpReader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+ M4SYS_AccessUnit* pAu;
+ int64_t tempTime64 = 0;
+ MediaBuffer *mMediaBuffer = NULL;
+ MediaSource::ReadOptions options;
+ M4OSA_Bool flag = M4OSA_FALSE;
+ status_t error;
+
+ M4OSA_DEBUG_IF1((pReaderContext == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_getNextAu: invalid context");
+ M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_getNextAu: invalid pointer to M4_StreamHandler");
+ M4OSA_DEBUG_IF1((pAccessUnit == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_getNextAu: invalid pointer to M4_AccessUnit");
+
+ LOGV("VideoEditor3gpReader_getNextAu begin");
+
+ if (pStreamHandler == (M4_StreamHandler*)pC->mAudioStreamHandler) {
+ LOGV("VideoEditor3gpReader_getNextAu audio stream");
+ pAu = &pC->mAudioAu;
+ if (pC->mAudioSeeking == M4OSA_TRUE) {
+ LOGV("VideoEditor3gpReader_getNextAu audio seek time: %ld",
+ pC->mAudioSeekTime);
+ options.setSeekTo(pC->mAudioSeekTime);
+ pC->mAudioSource->read(&mMediaBuffer, &options);
+
+ mMediaBuffer->meta_data()->findInt64(kKeyTime,
+ (int64_t*)&tempTime64);
+ options.clearSeekTo();
+ pC->mAudioSeeking = M4OSA_FALSE;
+ flag = M4OSA_TRUE;
+ } else {
+ LOGV("VideoEditor3gpReader_getNextAu audio no seek:");
+ pC->mAudioSource->read(&mMediaBuffer, &options);
+ if (mMediaBuffer != NULL) {
+ mMediaBuffer->meta_data()->findInt64(kKeyTime,
+ (int64_t*)&tempTime64);
+ }
+ }
+ } else if (pStreamHandler == (M4_StreamHandler*)pC->mVideoStreamHandler) {
+ LOGV("VideoEditor3gpReader_getNextAu video steram ");
+ pAu = &pC->mVideoAu;
+ if(pC->mVideoSeeking == M4OSA_TRUE) {
+ flag = M4OSA_TRUE;
+ LOGV("VideoEditor3gpReader_getNextAu seek: %ld",pC->mVideoSeekTime);
+ options.setSeekTo(pC->mVideoSeekTime,
+ MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+ do
+ {
+ if (mMediaBuffer != NULL) {
+ LOGV("VideoEditor3gpReader_getNextAu free the MediaBuffer");
+ mMediaBuffer->release();
+ }
+ error = pC->mVideoSource->read(&mMediaBuffer, &options);
+ LOGV("VE3gpReader_getNextAu MediaBuffer %x , error %d",
+ mMediaBuffer, error);
+ if (mMediaBuffer != NULL)
+ {
+ mMediaBuffer->meta_data()->findInt64(kKeyTime,
+ (int64_t*)&tempTime64);
+ } else {
+ break;
+ }
+ options.clearSeekTo();
+ } while(tempTime64 < pC->mVideoSeekTime);
+
+ LOGV("VE3gpReader_getNextAu: video time with seek = %lld:",
+ tempTime64);
+ pC->mVideoSeeking = M4OSA_FALSE;
+ } else {
+ LOGV("VideoEditor3gpReader_getNextAu video no seek:");
+ pC->mVideoSource->read(&mMediaBuffer, &options);
+
+ if(mMediaBuffer != NULL) {
+ mMediaBuffer->meta_data()->findInt64(kKeyTime,
+ (int64_t*)&tempTime64);
+ LOGV("VE3gpReader_getNextAu: video no seek time = %lld:",
+ tempTime64);
+ }else {
+ LOGV("VE3gpReader_getNextAu:video no seek time buffer is NULL");
+ }
+ }
+ } else {
+ LOGV("VideoEditor3gpReader_getNextAu M4ERR_PARAMETER");
+ return M4ERR_PARAMETER;
+ }
+
+ if (mMediaBuffer != NULL) {
+ if( (pAu->dataAddress == NULL) || (pAu->size < \
+ mMediaBuffer->range_length())) {
+ if(pAu->dataAddress != NULL) {
+ M4OSA_free((M4OSA_Int32*)pAu->dataAddress);
+ pAu->dataAddress = NULL;
+ }
+ LOGV("Buffer lenght = %d ,%d",(mMediaBuffer->range_length() +\
+ 3) & ~0x3,(mMediaBuffer->range_length()));
+
+ pAu->dataAddress = (M4OSA_Int32*)M4OSA_malloc(
+ (mMediaBuffer->range_length() + 3) & ~0x3,M4READER_3GP,
+ (M4OSA_Char*)"pAccessUnit->m_dataAddress" );
+ if(pAu->dataAddress == NULL) {
+ LOGV("VideoEditor3gpReader_getNextAu malloc failed");
+ return M4ERR_ALLOC;
+ }
+ }
+ pAu->size = mMediaBuffer->range_length();
+
+ memcpy((M4OSA_MemAddr8)pAu->dataAddress,
+ (const char *)mMediaBuffer->data() + mMediaBuffer->range_offset(),
+ mMediaBuffer->range_length());
+
+ if( (pStreamHandler == (M4_StreamHandler*)pC->mVideoStreamHandler) &&
+ (pStreamHandler->m_streamType == M4DA_StreamTypeVideoMpeg4Avc) ) {
+ M4OSA_UInt32 size = mMediaBuffer->range_length();
+ M4OSA_UInt8 *lbuffer;
+
+ lbuffer = (M4OSA_UInt8 *) pAu->dataAddress;
+ LOGV("pAccessUnit->m_dataAddress size = %x",size);
+
+ lbuffer[0] = (size >> 24) & 0xFF;
+ lbuffer[1] = (size >> 16) & 0xFF;
+ lbuffer[2] = (size >> 8) & 0xFF;
+ lbuffer[3] = (size) & 0xFF;
+ }
+
+ pAu->CTS = tempTime64;
+
+ pAu->CTS = pAu->CTS / 1000; //converting the microsec to millisec
+ LOGV("VideoEditor3gpReader_getNextAu CTS = %ld",pAu->CTS);
+
+ pAu->DTS = pAu->CTS;
+ pAu->attribute = M4SYS_kFragAttrOk;
+ mMediaBuffer->release();
+
+ pAccessUnit->m_dataAddress = (M4OSA_Int8*) pAu->dataAddress;
+ pAccessUnit->m_size = pAu->size;
+ pAccessUnit->m_maxsize = pAu->size;
+ pAccessUnit->m_CTS = pAu->CTS;
+ pAccessUnit->m_DTS = pAu->DTS;
+ pAccessUnit->m_attribute = pAu->attribute;
+
+ } else {
+ LOGV("VideoEditor3gpReader_getNextAu: M4WAR_NO_MORE_AU (EOS) reached");
+ pAccessUnit->m_size = 0;
+ err = M4WAR_NO_MORE_AU;
+ }
+ options.clearSeekTo();
+
+ pAu->nbFrag = 0;
+ mMediaBuffer = NULL;
+ LOGV("VideoEditor3gpReader_getNextAu end ");
+
+ return err;
+}
+/**
+ *******************************************************************************
+ * @brief Split the AVC DSI in its different components and write it in
+ * ONE memory buffer
+ * @note
+ * @param pStreamHandler: (IN/OUT) The MPEG4-AVC stream
+ * @param pDecoderConfigLocal: (IN) The DSI buffer
+ * @param decoderConfigSizeLocal: (IN) The DSI buffer size
+ * @return M4NO_ERROR there is no error
+ * @return ERR_FILE_SYNTAX_ERROR pDecoderConfigLocal is NULL
+ *******************************************************************************
+*/
+static M4OSA_ERR VideoEditor3gpReader_AnalyseAvcDsi(
+ M4_StreamHandler *pStreamHandler, M4OSA_Int32* pDecoderConfigLocal,
+ M4OSA_Int32 decoderConfigSizeLocal) {
+ struct _avcSpecificInfo *pAvcSpecInfo = M4OSA_NULL;
+ M4OSA_UInt32 uiSpecInfoSize;
+ M4OSA_Context pBitParserContext = M4OSA_NULL;
+ M4OSA_MemAddr8 pPos;
+
+ /**
+ * First parsing to get the total allocation size (we must not do
+ * multiple malloc, but only one instead) */
+ {
+ M4OSA_Int32 val;
+ M4OSA_UInt32 i,j;
+ M4OSA_UInt8 nalUnitLength;
+ M4OSA_UInt8 numOfSequenceParameterSets;
+ M4OSA_UInt32 uiTotalSizeOfSPS = 0;
+ M4OSA_UInt8 numOfPictureParameterSets;
+ M4OSA_UInt32 uiTotalSizeOfPPS = 0;
+ M4OSA_UInt32 uiSize;
+ struct _avcSpecificInfo avcSpIf;
+
+ avcSpIf.m_nalUnitLength = 0;
+
+ if (M4OSA_NULL == pDecoderConfigLocal) {
+ return M4ERR_READER3GP_DECODER_CONFIG_ERROR;
+ }
+
+ VideoEditor3gpReader_MPEG4BitStreamParserInit(&pBitParserContext,
+ pDecoderConfigLocal, decoderConfigSizeLocal);
+
+ if (M4OSA_NULL == pBitParserContext) {
+ return M4ERR_ALLOC;
+ }
+
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* 8 bits -- configuration version */
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* 8 bits -- avc profile indication*/
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* 8 bits -- profile compatibility */
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* 8 bits -- avc level indication*/
+ val=VideoEditor3gpReader_BitStreamParserShowBits(pBitParserContext, 8);
+ /* 6 bits reserved 111111b 2 bits length Size minus one*/
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* m_nalUnitLength */
+
+ nalUnitLength = (M4OSA_UInt8)((val & 0x03) + 1);/*0b11111100*/
+ if (nalUnitLength > 4) {
+ pStreamHandler->m_decoderSpecificInfoSize = 0;
+ pStreamHandler->m_pDecoderSpecificInfo = M4OSA_NULL;
+ VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext);
+ } else {
+ /**
+ * SPS table */
+ val=VideoEditor3gpReader_BitStreamParserShowBits(pBitParserContext,
+ 8);/* 3 bits-reserved 111b-5 bits number of sequence parameter set*/
+ numOfSequenceParameterSets = val & 0x1F;
+ /*1F instead of E0*/ /*0b11100000*/ /*Number of seq parameter sets*/
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ for (i=0; i < numOfSequenceParameterSets; i++) {
+ /**
+ * Get the size of this element */
+ uiSize =
+ (M4OSA_UInt32)VideoEditor3gpReader_BitStreamParserShowBits(
+ pBitParserContext, 16);
+ uiTotalSizeOfSPS += uiSize;
+ VideoEditor3gpReader_BitStreamParserFlushBits(
+ pBitParserContext, 16);
+ /**
+ *Read the element(dont keep it, we only want size right now) */
+ for (j=0; j<uiSize; j++) {
+ VideoEditor3gpReader_BitStreamParserFlushBits(
+ pBitParserContext, 8);
+ }
+ }
+
+ /**
+ * SPS table */
+ numOfPictureParameterSets=(M4OSA_UInt8)\
+ VideoEditor3gpReader_BitStreamParserShowBits(pBitParserContext,
+ 8);
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ for (i=0; i < numOfPictureParameterSets; i++) {
+ /**
+ * Get the size of this element */
+ uiSize = (M4OSA_UInt32)
+ VideoEditor3gpReader_BitStreamParserShowBits(
+ pBitParserContext, 16);
+ uiTotalSizeOfPPS += uiSize;
+ VideoEditor3gpReader_BitStreamParserFlushBits(
+ pBitParserContext, 16);
+ /**
+ *Read the element(dont keep it,we only want size right now)*/
+ for (j=0; j<uiSize; j++) {
+ VideoEditor3gpReader_BitStreamParserFlushBits(
+ pBitParserContext, 8);
+ }
+ }
+
+ /**
+ * Compute the size of the full buffer */
+ uiSpecInfoSize = sizeof(struct _avcSpecificInfo) +
+ numOfSequenceParameterSets * sizeof(struct _parameterSet)
+ + /**< size of the table of SPS elements */
+ numOfPictureParameterSets * sizeof(struct _parameterSet)
+ + /**< size of the table of PPS elements */
+ uiTotalSizeOfSPS +
+ uiTotalSizeOfPPS;
+ /**
+ * Allocate the buffer */
+ pAvcSpecInfo =(struct _avcSpecificInfo*)M4OSA_malloc(uiSpecInfoSize,
+ M4READER_3GP, (M4OSA_Char*)"MPEG-4 AVC DecoderSpecific");
+ if (M4OSA_NULL == pAvcSpecInfo) {
+ VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext);
+ return M4ERR_ALLOC;
+ }
+
+ /**
+ * Set the pointers to the correct part of the buffer */
+ pAvcSpecInfo->m_nalUnitLength = nalUnitLength;
+ pAvcSpecInfo->m_numOfSequenceParameterSets =
+ numOfSequenceParameterSets;
+ pAvcSpecInfo->m_numOfPictureParameterSets =
+ numOfPictureParameterSets;
+
+ /* We place the SPS param sets table after m_pPictureParameterSet */
+ pAvcSpecInfo->m_pSequenceParameterSet= (struct _parameterSet*)(
+ (M4OSA_MemAddr8)(&pAvcSpecInfo->m_pPictureParameterSet) +
+ sizeof(pAvcSpecInfo->m_pPictureParameterSet));
+ /*We place the PPS param sets table after the SPS param sets table*/
+ pAvcSpecInfo->m_pPictureParameterSet = (struct _parameterSet*)(
+ (M4OSA_MemAddr8)(pAvcSpecInfo->m_pSequenceParameterSet) +
+ (numOfSequenceParameterSets * sizeof(struct _parameterSet)));
+ /**< The data will be placed after the PPS param sets table */
+ pPos = (M4OSA_MemAddr8)pAvcSpecInfo->m_pPictureParameterSet +
+ (numOfPictureParameterSets * sizeof(struct _parameterSet));
+
+ /**
+ * reset the bit parser */
+ VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext);
+ }
+ }
+
+ /**
+ * Second parsing to copy the data */
+ if (M4OSA_NULL != pAvcSpecInfo) {
+ M4OSA_Int32 i,j;
+
+ VideoEditor3gpReader_MPEG4BitStreamParserInit(&pBitParserContext,
+ pDecoderConfigLocal, decoderConfigSizeLocal);
+
+ if (M4OSA_NULL == pBitParserContext) {
+ M4OSA_free((M4OSA_MemAddr32)pAvcSpecInfo);
+ return M4ERR_ALLOC;
+ }
+
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* 8 bits -- configuration version */
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* 8 bits -- avc profile indication*/
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* 8 bits -- profile compatibility */
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* 8 bits -- avc level indication*/
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* m_nalUnitLength */
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* 3 bits -- reserved 111b -- 5 bits number of sequence parameter set*/
+
+ for (i=0; i < pAvcSpecInfo->m_numOfSequenceParameterSets; i++) {
+ pAvcSpecInfo->m_pSequenceParameterSet[i].m_length =
+ (M4OSA_UInt16)VideoEditor3gpReader_BitStreamParserShowBits(
+ pBitParserContext, 16);
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext,16);
+
+ pAvcSpecInfo->m_pSequenceParameterSet[i].m_pParameterSetUnit =
+ (M4OSA_UInt8*)pPos; /**< current position in the buffer */
+ pPos += pAvcSpecInfo->m_pSequenceParameterSet[i].m_length;
+ /**< increment the position in the buffer */
+ for (j=0; j<pAvcSpecInfo->m_pSequenceParameterSet[i].m_length;j++){
+ pAvcSpecInfo->m_pSequenceParameterSet[i].m_pParameterSetUnit[j]=
+ (M4OSA_UInt8)VideoEditor3gpReader_BitStreamParserShowBits(
+ pBitParserContext, 8);
+ VideoEditor3gpReader_BitStreamParserFlushBits(
+ pBitParserContext, 8);
+ }
+ }
+
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext, 8);
+ /* number of pîcture parameter set*/
+
+ for (i=0; i < pAvcSpecInfo->m_numOfPictureParameterSets; i++) {
+ pAvcSpecInfo->m_pPictureParameterSet[i].m_length =
+ (M4OSA_UInt16)VideoEditor3gpReader_BitStreamParserShowBits(
+ pBitParserContext, 16);
+ VideoEditor3gpReader_BitStreamParserFlushBits(pBitParserContext,16);
+
+ pAvcSpecInfo->m_pPictureParameterSet[i].m_pParameterSetUnit =
+ (M4OSA_UInt8*)pPos; /**< current position in the buffer */
+ pPos += pAvcSpecInfo->m_pPictureParameterSet[i].m_length;
+ /**< increment the position in the buffer */
+ for (j=0; j<pAvcSpecInfo->m_pPictureParameterSet[i].m_length; j++) {
+ pAvcSpecInfo->m_pPictureParameterSet[i].m_pParameterSetUnit[j] =
+ (M4OSA_UInt8)VideoEditor3gpReader_BitStreamParserShowBits(
+ pBitParserContext, 8);
+ VideoEditor3gpReader_BitStreamParserFlushBits(
+ pBitParserContext, 8);
+ }
+ }
+ VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext);
+ pStreamHandler->m_decoderSpecificInfoSize = uiSpecInfoSize;
+ pStreamHandler->m_pDecoderSpecificInfo = (M4OSA_UInt8*)pAvcSpecInfo;
+ }
+ pStreamHandler->m_H264decoderSpecificInfoSize = decoderConfigSizeLocal;
+ pStreamHandler->m_pH264DecoderSpecificInfo = (M4OSA_UInt8*)M4OSA_malloc(
+ decoderConfigSizeLocal, M4READER_3GP,
+ (M4OSA_Char*)"MPEG-4 AVC DecoderSpecific");
+ if (M4OSA_NULL == pStreamHandler->m_pH264DecoderSpecificInfo) {
+ goto cleanup;
+ }
+
+ M4OSA_memcpy((M4OSA_MemAddr8 ) pStreamHandler->m_pH264DecoderSpecificInfo,
+ (M4OSA_MemAddr8 )pDecoderConfigLocal,
+ pStreamHandler->m_H264decoderSpecificInfoSize);
+ return M4NO_ERROR;
+cleanup:
+ VideoEditor3gpReader_BitStreamParserCleanUp(pBitParserContext);
+ return M4ERR_READER3GP_DECODER_CONFIG_ERROR;
+}
+/**
+********************************************************************************
+* @brief Get the next stream found in the 3gp file
+* @note
+* @param context: (IN) Context of the reader
+* @param pMediaFamily: OUT) pointer to a user allocated
+* M4READER_MediaFamily that will be filled
+* with the media family of the found stream
+* @param pStreamHandler:(OUT) pointer to StreamHandler that will be allocated
+* and filled with the found stream description
+* @return M4NO_ERROR there is no error
+* @return M4ERR_BAD_CONTEXT provided context is not a valid one
+* @return M4ERR_PARAMETER at least one parameter is not properly set
+* @return M4WAR_NO_MORE_STREAM no more available stream in the media
+********************************************************************************
+*/
+M4OSA_ERR VideoEditor3gpReader_getNextStreamHandler(M4OSA_Context context,
+ M4READER_MediaFamily *pMediaFamily,
+ M4_StreamHandler **pStreamHandler) {
+ VideoEditor3gpReader_Context* pC=(VideoEditor3gpReader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+ M4SYS_StreamID streamIdArray[2];
+ M4SYS_StreamDescription streamDesc;
+ M4_AudioStreamHandler* pAudioStreamHandler;
+ M4_VideoStreamHandler* pVideoStreamHandler;
+ M4OSA_Int8 *DecoderSpecificInfo = M4OSA_NULL;
+ M4OSA_Int32 decoderSpecificInfoSize =0, maxAUSize = 0;
+
+ M4_StreamType streamType = M4DA_StreamTypeUnknown;
+ M4OSA_UInt8 temp, i, trackCount;
+ M4OSA_Bool haveAudio = M4OSA_FALSE;
+ M4OSA_Bool haveVideo = M4OSA_FALSE;
+ sp<MetaData> meta = NULL;
+ int64_t Duration = 0;
+ M4OSA_UInt8* DecoderSpecific = M4OSA_NULL ;
+ uint32_t type;
+ const void *data;
+ size_t size;
+ const void *codec_specific_data;
+ size_t codec_specific_data_size;
+ M4OSA_Int32 ptempTime;
+
+ LOGV("VideoEditor3gpReader_getNextStreamHandler begin");
+
+ M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_getNextStreamHandler: invalid context");
+ M4OSA_DEBUG_IF1((pMediaFamily == 0), M4ERR_PARAMETER,
+ "getNextStreamHandler: invalid pointer to MediaFamily");
+ M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER,
+ "getNextStreamHandler: invalid pointer to StreamHandler");
+
+ trackCount = pC->mExtractor->countTracks();
+ temp = pC->mCurrTrack;
+
+ if(temp >= trackCount) {
+ LOGV("VideoEditor3gpReader_getNextStreamHandler error = %d",
+ M4WAR_NO_MORE_STREAM);
+ return (M4WAR_NO_MORE_STREAM);
+ } else {
+ const char *mime;
+ meta = pC->mExtractor->getTrackMetaData(temp);
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
+ pC->mVideoSource = pC->mExtractor->getTrack(temp);
+ pC->mVideoSource->start();
+
+ *pMediaFamily = M4READER_kMediaFamilyVideo;
+ haveVideo = true;
+ LOGV("VideoEditor3gpReader_getNextStreamHandler getTrack called");
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ streamType = M4DA_StreamTypeVideoMpeg4Avc;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) {
+ streamType = M4DA_StreamTypeVideoH263;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) {
+ streamType = M4DA_StreamTypeVideoMpeg4;
+ } else {
+ LOGV("VideoEditor3gpReaderGetNextStreamHandler streamTypeNONE");
+ }
+ LOGV("VideoEditor3gpReader_getNextStreamHandler: stream type: %d ",
+ streamType);
+
+ if(streamType != M4DA_StreamTypeUnknown) {
+ pC->mStreamType = streamType;
+ pC->mStreamId = pC->mCurrTrack;
+
+ pVideoStreamHandler = (M4_VideoStreamHandler*)M4OSA_malloc
+ (sizeof(M4_VideoStreamHandler), M4READER_3GP,
+ (M4OSA_Char*)"M4_VideoStreamHandler");
+ if (M4OSA_NULL == pVideoStreamHandler) {
+ return M4ERR_ALLOC;
+ }
+ pVideoStreamHandler->m_structSize=sizeof(M4_VideoStreamHandler);
+
+ meta->findInt32(kKeyWidth,
+ (int32_t*)&(pVideoStreamHandler->m_videoWidth));
+ meta->findInt32(kKeyHeight,
+ (int32_t*)&(pVideoStreamHandler->m_videoHeight));
+
+ (*pStreamHandler) = (M4_StreamHandler*)(pVideoStreamHandler);
+ meta->findInt64(kKeyDuration,
+ (int64_t*)&(Duration));
+ ((*pStreamHandler)->m_duration) =
+ (int32_t)((Duration)/1000); // conversion to mS
+ pC->mMaxDuration = ((*pStreamHandler)->m_duration);
+ LOGV("VideoEditor3gpReader_getNextStreamHandler m_duration %d",
+ (*pStreamHandler)->m_duration);
+
+ pC->mFileSize = 0;
+
+ meta->findInt32(kKeyMaxInputSize, (int32_t*)&(maxAUSize));
+ if(maxAUSize == 0) {
+ maxAUSize = 70000;
+ }
+ (*pStreamHandler)->m_maxAUSize = maxAUSize;
+ LOGV("<<<<<<<<<< video: mMaxAUSize from MP4 extractor: %d",
+ (*pStreamHandler)->m_maxAUSize);
+
+ //check this
+ pVideoStreamHandler->m_averageFrameRate = 15;
+ if( (M4DA_StreamTypeVideoH263 == streamType) ||
+ (M4DA_StreamTypeVideoMpeg4Avc == streamType)){
+ ((M4_StreamHandler*)pVideoStreamHandler)->m_averageBitRate =
+ 384000;
+ }
+ pC->mVideoStreamHandler =
+ (M4_StreamHandler*)(pVideoStreamHandler);
+
+ /* Get the DSI info */
+ if(M4DA_StreamTypeVideoH263 == streamType) {
+ if (meta->findData(kKeyESDS, &type, &data, &size)) {
+ ESDS esds((const char *)data, size);
+ CHECK_EQ(esds.InitCheck(), OK);
+
+ esds.getCodecSpecificInfo(
+ &codec_specific_data, &codec_specific_data_size);
+ (*pStreamHandler)->m_decoderSpecificInfoSize =
+ codec_specific_data_size;
+ if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) {
+ DecoderSpecific = (M4OSA_UInt8*)M4OSA_malloc(
+ (*pStreamHandler)->m_decoderSpecificInfoSize,
+ M4READER_3GP,(M4OSA_Char*)"H263 DSI");
+ if (M4OSA_NULL == DecoderSpecific) {
+ return M4ERR_ALLOC;
+ }
+ M4OSA_memcpy((M4OSA_MemAddr8)DecoderSpecific,
+ (M4OSA_MemAddr8)codec_specific_data,
+ codec_specific_data_size);
+ (*pStreamHandler)->m_pDecoderSpecificInfo =
+ DecoderSpecific;
+ }
+ else {
+ (*pStreamHandler)->m_pDecoderSpecificInfo =
+ M4OSA_NULL;
+ }
+ } else {
+ LOGV("VE_getNextStreamHandler: H263 dsi not found");
+ (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL;
+ (*pStreamHandler)->m_decoderSpecificInfoSize = 0;
+ (*pStreamHandler)->m_H264decoderSpecificInfoSize = 0;
+ (*pStreamHandler)->m_pH264DecoderSpecificInfo =
+ M4OSA_NULL;
+ (*pStreamHandler)->m_pESDSInfo = M4OSA_NULL;
+ (*pStreamHandler)->m_ESDSInfoSize = 0;
+ }
+ }
+ else if(M4DA_StreamTypeVideoMpeg4Avc == streamType) {
+ if(meta->findData(kKeyAVCC, &type, &data, &size)) {
+ decoderSpecificInfoSize = size;
+ if (decoderSpecificInfoSize != 0) {
+ DecoderSpecificInfo = (M4OSA_Int8*)M4OSA_malloc(
+ decoderSpecificInfoSize, M4READER_3GP,
+ (M4OSA_Char*)"H264 DecoderSpecific" );
+ if (M4OSA_NULL == DecoderSpecificInfo) {
+ LOGV("VideoEditor3gp_getNextStream is NULL ");
+ return M4ERR_ALLOC;
+ }
+ M4OSA_memcpy((M4OSA_MemAddr8)DecoderSpecificInfo,
+ (M4OSA_MemAddr8)data, decoderSpecificInfoSize);
+ } else {
+ LOGV("DSI Size %d", decoderSpecificInfoSize);
+ DecoderSpecificInfo = M4OSA_NULL;
+ }
+ }
+ (*pStreamHandler)->m_pESDSInfo = M4OSA_NULL;
+ (*pStreamHandler)->m_ESDSInfoSize = 0;
+
+ err = VideoEditor3gpReader_AnalyseAvcDsi(*pStreamHandler,
+ (M4OSA_Int32*)DecoderSpecificInfo, decoderSpecificInfoSize);
+
+ if (M4NO_ERROR != err) {
+ return err;
+ }
+ LOGV("decsize %d, h264decsize %d: %d", (*pStreamHandler)->\
+ m_decoderSpecificInfoSize, (*pStreamHandler)->\
+ m_H264decoderSpecificInfoSize);
+
+ if(M4OSA_NULL != DecoderSpecificInfo) {
+ M4OSA_free((M4OSA_MemAddr32)DecoderSpecificInfo);
+ DecoderSpecificInfo = M4OSA_NULL;
+ }
+ } else if( (M4DA_StreamTypeVideoMpeg4 == streamType) ) {
+ if (meta->findData(kKeyESDS, &type, &data, &size)) {
+ ESDS esds((const char *)data, size);
+ CHECK_EQ(esds.InitCheck(), OK);
+
+ (*pStreamHandler)->m_ESDSInfoSize = size;
+ (*pStreamHandler)->m_pESDSInfo = (M4OSA_UInt8*)\
+ M4OSA_malloc((*pStreamHandler)->m_ESDSInfoSize,
+ M4READER_3GP, (M4OSA_Char*)"H263 DecoderSpecific" );
+ if (M4OSA_NULL == (*pStreamHandler)->m_pESDSInfo) {
+ return M4ERR_ALLOC;
+ }
+ M4OSA_memcpy((M4OSA_MemAddr8)(*pStreamHandler)->\
+ m_pESDSInfo, (M4OSA_MemAddr8)data, size);
+
+ esds.getCodecSpecificInfo(&codec_specific_data,
+ &codec_specific_data_size);
+ LOGV("VE MP4 dsisize: %d, %x", codec_specific_data_size,
+ codec_specific_data);
+
+ (*pStreamHandler)->m_decoderSpecificInfoSize =
+ codec_specific_data_size;
+ if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) {
+ DecoderSpecific = (M4OSA_UInt8*)M4OSA_malloc(
+ (*pStreamHandler)->m_decoderSpecificInfoSize,
+ M4READER_3GP, (M4OSA_Char*)" DecoderSpecific" );
+ if (M4OSA_NULL == DecoderSpecific) {
+ return M4ERR_ALLOC;
+ }
+ M4OSA_memcpy((M4OSA_MemAddr8)DecoderSpecific,
+ (M4OSA_MemAddr8)codec_specific_data,
+ codec_specific_data_size);
+ (*pStreamHandler)->m_pDecoderSpecificInfo =
+ DecoderSpecific;
+ }
+ else {
+ (*pStreamHandler)->m_pDecoderSpecificInfo =
+ M4OSA_NULL;
+ }
+ (*pStreamHandler)->m_pH264DecoderSpecificInfo =
+ M4OSA_NULL;
+ (*pStreamHandler)->m_H264decoderSpecificInfoSize = 0;
+ }
+ } else {
+ LOGV("VideoEditor3gpReader_getNextStream NO video stream");
+ return M4ERR_READER_UNKNOWN_STREAM_TYPE;
+ }
+ }
+ else {
+ LOGV("VideoEditor3gpReader_getNextStream NO video stream");
+ return M4ERR_READER_UNKNOWN_STREAM_TYPE;
+ }
+
+ } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
+ LOGV("VideoEditor3gpReader_getNextStream audio getTrack called");
+ pC->mAudioSource = pC->mExtractor->getTrack(pC->mCurrTrack);
+ pC->mAudioSource->start();
+ *pMediaFamily = M4READER_kMediaFamilyAudio;
+
+ if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
+ streamType = M4DA_StreamTypeAudioAmrNarrowBand;
+ } else if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
+ streamType = M4DA_StreamTypeAudioAmrWideBand;
+ }
+ else if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+ streamType = M4DA_StreamTypeAudioAac;
+ } else {
+ LOGV("VideoEditor3gpReader_getNextStrea streamtype Unknown ");
+ }
+ if(streamType != M4DA_StreamTypeUnknown) {
+ pC->mStreamType = streamType;
+ pC->mStreamId = pC->mCurrTrack;
+
+ LOGV("VE streamtype %d ,id %d", streamType, pC->mCurrTrack);
+
+ pAudioStreamHandler = (M4_AudioStreamHandler*)M4OSA_malloc
+ (sizeof(M4_AudioStreamHandler), M4READER_3GP,
+ (M4OSA_Char*)"M4_AudioStreamHandler");
+ if (M4OSA_NULL == pAudioStreamHandler) {
+ return M4ERR_ALLOC;
+ }
+ pAudioStreamHandler->m_structSize=sizeof(M4_AudioStreamHandler);
+ pAudioStreamHandler->m_byteSampleSize = 0;
+ pAudioStreamHandler->m_nbChannels = 0;
+ pAudioStreamHandler->m_samplingFrequency= 0;
+ pAudioStreamHandler->m_byteFrameLength = 0;
+
+ (*pStreamHandler) = (M4_StreamHandler*)(pAudioStreamHandler);
+ pC->mAudioStreamHandler =
+ (M4_StreamHandler*)(pAudioStreamHandler);
+ (*pStreamHandler)->m_averageBitRate = 0;
+ haveAudio = true;
+ pC->mAudioStreamHandler=(M4_StreamHandler*)pAudioStreamHandler;
+ pC->mAudioStreamHandler->m_pESDSInfo = M4OSA_NULL;
+ pC->mAudioStreamHandler->m_ESDSInfoSize = 0;
+
+ meta->findInt32(kKeyMaxInputSize, (int32_t*)&(maxAUSize));
+ if(maxAUSize == 0) {
+ maxAUSize = 70000;
+ }
+ (*pStreamHandler)->m_maxAUSize = maxAUSize;
+ LOGV("VE Audio mMaxAUSize from MP4 extractor: %d", maxAUSize);
+ }
+ if((M4DA_StreamTypeAudioAmrNarrowBand == streamType) ||
+ (M4DA_StreamTypeAudioAmrWideBand == streamType)) {
+ M4OSA_UInt32 freqIndex = 0; /**< AMR NB */
+ M4OSA_UInt32 modeSet;
+ M4OSA_UInt32 i;
+ M4OSA_Context pBitParserContext = M4OSA_NULL;
+
+ if(M4DA_StreamTypeAudioAmrWideBand == streamType) {
+ freqIndex = 1; /**< AMR WB */
+ }
+
+ if (meta->findData(kKeyESDS, &type, &data, &size)) {
+ ESDS esds((const char *)data, size);
+ CHECK_EQ(esds.InitCheck(), OK);
+
+ esds.getCodecSpecificInfo(&codec_specific_data,
+ &codec_specific_data_size);
+ (*pStreamHandler)->m_decoderSpecificInfoSize =
+ codec_specific_data_size;
+
+ if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) {
+ DecoderSpecific = (M4OSA_UInt8*)M4OSA_malloc(
+ (*pStreamHandler)->m_decoderSpecificInfoSize,
+ M4READER_3GP, (M4OSA_Char*)"H263 DecoderSpecific" );
+ if (M4OSA_NULL == DecoderSpecific) {
+ return M4ERR_ALLOC;
+ }
+ M4OSA_memcpy((M4OSA_MemAddr8)DecoderSpecific,
+ (M4OSA_MemAddr8)codec_specific_data,
+ codec_specific_data_size);
+ (*pStreamHandler)->m_pDecoderSpecificInfo =
+ DecoderSpecific;
+ } else {
+ (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL;
+ }
+ } else {
+ M4OSA_UChar AmrDsi[] =
+ {'P','H','L','P',0x00, 0x00, 0x80, 0x00, 0x01,};
+ (*pStreamHandler)->m_decoderSpecificInfoSize = 9;
+ DecoderSpecific = (M4OSA_UInt8*)M4OSA_malloc(
+ (*pStreamHandler)->m_decoderSpecificInfoSize,
+ M4READER_3GP, (M4OSA_Char*)"H263 DecoderSpecific" );
+ if (M4OSA_NULL == DecoderSpecific) {
+ return M4ERR_ALLOC;
+ }
+ if(freqIndex ==0) {
+ AmrDsi[8] = 0x01;
+ } else {
+ AmrDsi[8] = 0x02;
+ }
+ for(i = 0; i< 9; i++) {
+ DecoderSpecific[i] = AmrDsi[i];
+ }
+ (*pStreamHandler)->m_pDecoderSpecificInfo = DecoderSpecific;
+ }
+ (*pStreamHandler)->m_averageBitRate =
+ VideoEditor3gpReader_AmrBitRate[freqIndex][7];
+ } else if((M4DA_StreamTypeAudioAac == streamType)) {
+ if (meta->findData(kKeyESDS, &type, &data, &size)) {
+ ESDS esds((const char *)data, size);
+ CHECK_EQ(esds.InitCheck(), OK);
+
+ (*pStreamHandler)->m_ESDSInfoSize = size;
+ (*pStreamHandler)->m_pESDSInfo = (M4OSA_UInt8*)M4OSA_malloc(
+ (*pStreamHandler)->m_ESDSInfoSize, M4READER_3GP,
+ (M4OSA_Char*)"H263 DecoderSpecific" );
+ if (M4OSA_NULL == (*pStreamHandler)->m_pESDSInfo) {
+ return M4ERR_ALLOC;
+ }
+ M4OSA_memcpy((M4OSA_MemAddr8)(*pStreamHandler)->m_pESDSInfo,
+ (M4OSA_MemAddr8)data, size);
+ esds.getCodecSpecificInfo(&codec_specific_data,
+ &codec_specific_data_size);
+
+ LOGV("VEdsi %d,%x",codec_specific_data_size,
+ codec_specific_data);
+
+ (*pStreamHandler)->m_decoderSpecificInfoSize =
+ codec_specific_data_size;
+ if ((*pStreamHandler)->m_decoderSpecificInfoSize != 0) {
+ DecoderSpecific = (M4OSA_UInt8*)M4OSA_malloc(
+ (*pStreamHandler)->m_decoderSpecificInfoSize,
+ M4READER_3GP, (M4OSA_Char*)"H263 DecoderSpecific" );
+ if (M4OSA_NULL == DecoderSpecific) {
+ return M4ERR_ALLOC;
+ }
+ M4OSA_memcpy((M4OSA_MemAddr8)DecoderSpecific,
+ (M4OSA_MemAddr8)codec_specific_data,
+ codec_specific_data_size);
+ (*pStreamHandler)->m_pDecoderSpecificInfo =
+ DecoderSpecific;
+ } else {
+ (*pStreamHandler)->m_pDecoderSpecificInfo = M4OSA_NULL;
+ }
+ }
+ } else {
+ LOGV("VideoEditor3gpReader_getNextStream mStreamType: none ");
+ return M4ERR_READER_UNKNOWN_STREAM_TYPE;
+ }
+ } else {
+ LOGV("VE noaudio-video stream:pC->mCurrTrack = %d ",pC->mCurrTrack);
+ pC->mCurrTrack++; //Increment current track to get the next track
+ return M4ERR_READER_UNKNOWN_STREAM_TYPE;
+ }
+ LOGV("VE StreamType: %d, stremhandler %x",streamType, *pStreamHandler );
+ (*pStreamHandler)->m_streamType = streamType;
+ (*pStreamHandler)->m_streamId = pC->mStreamId;
+ (*pStreamHandler)->m_pUserData = M4OSA_NULL;
+ (*pStreamHandler)->m_structSize = sizeof(M4_StreamHandler);
+ (*pStreamHandler)->m_bStreamIsOK = M4OSA_TRUE;
+
+ meta->findInt64(kKeyDuration,
+ (int64_t*)&(Duration));
+
+ (*pStreamHandler)->m_duration = (int32_t)(Duration / 1000);
+
+ pC->mMaxDuration = ((*pStreamHandler)->m_duration);
+ LOGV("VE str duration duration: %d ", (*pStreamHandler)->m_duration);
+
+ /* In AAC case: Put the first AU in pAudioStreamHandler->m_pUserData
+ *since decoder has to know if stream contains SBR data(Implicit sig) */
+ if(M4DA_StreamTypeAudioAac == (*pStreamHandler)->m_streamType) {
+ M4READER_AudioSbrUserdata* pAudioSbrUserdata;
+
+ pAudioSbrUserdata = (M4READER_AudioSbrUserdata*)M4OSA_malloc(
+ sizeof(M4READER_AudioSbrUserdata),M4READER_3GP,
+ (M4OSA_Char*)"M4READER_AudioSbrUserdata");
+ if (M4OSA_NULL == pAudioSbrUserdata) {
+ err = M4ERR_ALLOC;
+ goto Error;
+ }
+ (*pStreamHandler)->m_pUserData = pAudioSbrUserdata;
+ pAudioSbrUserdata->m_bIsSbrEnabled = M4OSA_FALSE;
+
+ pAudioSbrUserdata->m_pFirstAU = (M4_AccessUnit*)M4OSA_malloc(
+ sizeof(M4_AccessUnit),M4READER_3GP, (M4OSA_Char*)"1st AAC AU");
+ if (M4OSA_NULL == pAudioSbrUserdata->m_pFirstAU) {
+ pAudioSbrUserdata->m_pAacDecoderUserConfig = M4OSA_NULL;
+ err = M4ERR_ALLOC;
+ goto Error;
+ }
+ pAudioSbrUserdata->m_pAacDecoderUserConfig = (M4_AacDecoderConfig*)\
+ M4OSA_malloc(sizeof(M4_AacDecoderConfig),M4READER_3GP,
+ (M4OSA_Char*)"m_pAacDecoderUserConfig");
+ if (M4OSA_NULL == pAudioSbrUserdata->m_pAacDecoderUserConfig) {
+ err = M4ERR_ALLOC;
+ goto Error;
+ }
+ }
+ if(M4DA_StreamTypeAudioAac == (*pStreamHandler)->m_streamType) {
+ M4_AudioStreamHandler* pAudioStreamHandler =
+ (M4_AudioStreamHandler*)(*pStreamHandler);
+ M4READER_AudioSbrUserdata* pUserData = (M4READER_AudioSbrUserdata*)\
+ (pAudioStreamHandler->m_basicProperties.m_pUserData);
+
+ err = VideoEditor3gpReader_fillAuStruct(pC, (*pStreamHandler),
+ (M4_AccessUnit*)pUserData->m_pFirstAU);
+ if (M4NO_ERROR != err) {
+ goto Error;
+ }
+ err = VideoEditor3gpReader_getNextAu(pC, (*pStreamHandler),
+ (M4_AccessUnit*)pUserData->m_pFirstAU);
+ if (M4NO_ERROR != err) {
+ goto Error;
+ }
+ err = VideoEditor3gpReader_reset(pC, (*pStreamHandler));
+ if (M4NO_ERROR != err) {
+ goto Error;
+ }
+ }
+ }
+ pC->mCurrTrack++; //Increment the current track to get next track
+ LOGV("pC->mCurrTrack = %d",pC->mCurrTrack);
+
+ if (!haveAudio && !haveVideo) {
+ *pMediaFamily=M4READER_kMediaFamilyUnknown;
+ return M4ERR_READER_UNKNOWN_STREAM_TYPE;
+ }
+Error:
+ LOGV("VideoEditor3gpReader_getNextStreamHandler end error = %d",err);
+ return err;
+}
+
+M4OSA_ERR VideoEditor3gpReader_getPrevRapTime(M4OSA_Context context,
+ M4_StreamHandler *pStreamHandler, M4OSA_Int32* pTime)
+{
+ VideoEditor3gpReader_Context *pC = (VideoEditor3gpReader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+ MediaBuffer *mMediaBuffer = M4OSA_NULL;
+ MediaSource::ReadOptions options;
+ M4OSA_Time time64;
+ int64_t tempTime64 = 0;
+ status_t error;
+
+ LOGV("VideoEditor3gpReader_getPrevRapTime begin");
+
+ M4OSA_DEBUG_IF1((pC == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_getPrevRapTime: invalid context");
+ M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_getPrevRapTime invalid pointer to StreamHandler");
+ M4OSA_DEBUG_IF1((pTime == 0), M4ERR_PARAMETER,
+ "VideoEditor3gpReader_getPrevRapTime: invalid time pointer");
+ if (*pTime == (pStreamHandler->m_duration)) {
+ *pTime -= 1;
+ }
+ M4OSA_INT64_FROM_INT32(time64, *pTime);
+ time64 = time64 * 1000;
+
+ LOGV("VideoEditor3gpReader_getPrevRapTime seek time: %ld",time64);
+ options.setSeekTo(time64, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+ error = pC->mVideoSource->read(&mMediaBuffer, &options);
+ if (error != OK) {
+ //Can not get the previous Sync.
+ //Must be end of stream.
+ return M4WAR_NO_MORE_AU;
+ }
+
+ mMediaBuffer->meta_data()->findInt64(kKeyTime, (int64_t*)&tempTime64);
+ LOGV("VideoEditor3gpReader_getPrevRapTime read time %ld, %x", tempTime64,
+ mMediaBuffer);
+
+ (*pTime) = (tempTime64) / 1000;
+
+ if(mMediaBuffer != M4OSA_NULL) {
+ LOGV(" mMediaBuffer size = %d length %d", mMediaBuffer->size(),
+ mMediaBuffer->range_length());
+ mMediaBuffer->release();
+ mMediaBuffer = M4OSA_NULL;
+ }
+ options.clearSeekTo();
+
+ if(error != OK) {
+ LOGV("VideoEditor3gpReader_getPrevRapTime end \
+ M4WAR_READER_INFORMATION_NOT_PRESENT");
+ return M4WAR_READER_INFORMATION_NOT_PRESENT;
+ } else {
+ LOGV("VideoEditor3gpReader_getPrevRapTime end: err %x", err);
+ err = M4NO_ERROR;
+ return err;
+ }
+}
+
+extern "C" {
+M4OSA_ERR VideoEditor3gpReader_getInterface(M4READER_MediaType *pMediaType,
+ M4READER_GlobalInterface **pRdrGlobalInterface,
+ M4READER_DataInterface **pRdrDataInterface) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pMediaType, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pRdrGlobalInterface, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pRdrDataInterface, M4ERR_PARAMETER);
+
+ LOGV("VideoEditor3gpReader_getInterface begin");
+ LOGV("VideoEditor3gpReader_getInterface %d 0x%x 0x%x", *pMediaType,
+ *pRdrGlobalInterface,*pRdrDataInterface);
+
+ SAFE_MALLOC(*pRdrGlobalInterface, M4READER_GlobalInterface, 1,
+ "VideoEditor3gpReader_getInterface");
+ SAFE_MALLOC(*pRdrDataInterface, M4READER_DataInterface, 1,
+ "VideoEditor3gpReader_getInterface");
+
+ *pMediaType = M4READER_kMediaType3GPP;
+
+ (*pRdrGlobalInterface)->m_pFctCreate = VideoEditor3gpReader_create;
+ (*pRdrGlobalInterface)->m_pFctDestroy = VideoEditor3gpReader_destroy;
+ (*pRdrGlobalInterface)->m_pFctOpen = VideoEditor3gpReader_open;
+ (*pRdrGlobalInterface)->m_pFctClose = VideoEditor3gpReader_close;
+ (*pRdrGlobalInterface)->m_pFctGetOption = VideoEditor3gpReader_getOption;
+ (*pRdrGlobalInterface)->m_pFctSetOption = VideoEditor3gpReader_setOption;
+ (*pRdrGlobalInterface)->m_pFctGetNextStream =
+ VideoEditor3gpReader_getNextStreamHandler;
+ (*pRdrGlobalInterface)->m_pFctFillAuStruct =
+ VideoEditor3gpReader_fillAuStruct;
+ (*pRdrGlobalInterface)->m_pFctStart = M4OSA_NULL;
+ (*pRdrGlobalInterface)->m_pFctStop = M4OSA_NULL;
+ (*pRdrGlobalInterface)->m_pFctJump = VideoEditor3gpReader_jump;
+ (*pRdrGlobalInterface)->m_pFctReset = VideoEditor3gpReader_reset;
+ (*pRdrGlobalInterface)->m_pFctGetPrevRapTime =
+ VideoEditor3gpReader_getPrevRapTime;
+ (*pRdrDataInterface)->m_pFctGetNextAu = VideoEditor3gpReader_getNextAu;
+ (*pRdrDataInterface)->m_readerContext = M4OSA_NULL;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditor3gpReader_getInterface no error");
+ } else {
+ SAFE_FREE(*pRdrGlobalInterface);
+ SAFE_FREE(*pRdrDataInterface);
+
+ LOGV("VideoEditor3gpReader_getInterface ERROR 0x%X", err);
+ }
+ LOGV("VideoEditor3gpReader_getInterface end");
+ return err;
+}
+
+} /* extern "C" */
+
+} /* namespace android */
+
+
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorAudioDecoder.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorAudioDecoder.cpp
new file mode 100755
index 0000000..2e88147
--- /dev/null
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorAudioDecoder.cpp
@@ -0,0 +1,907 @@
+/*
+ * Copyright (C) 2011 NXP Software
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+*************************************************************************
+* @file VideoEditorAudioDecoder.cpp
+* @brief StageFright shell Audio Decoder
+*************************************************************************
+*/
+
+#define LOG_NDEBUG 1
+#define LOG_TAG "VIDEOEDITOR_AUDIODECODER"
+
+#include "M4OSA_Debug.h"
+#include "VideoEditorAudioDecoder.h"
+#include "VideoEditorUtils.h"
+#include "M4MCS_InternalTypes.h"
+
+#include "utils/Log.h"
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+
+/********************
+ * DEFINITIONS *
+ ********************/
+// Version
+#define VIDEOEDITOR_AUDIO_DECODER_VERSION_MAJOR 1
+#define VIDEOEDITOR_AUDIO_DECODER_VERSION_MINOR 0
+#define VIDEOEDITOR_AUDIO_DECODER_VERSION_REV 0
+
+// Force using software decoder as engine does not support prefetch
+#define VIDEOEDITOR_FORCECODEC kSoftwareCodecsOnly
+
+namespace android {
+
+struct VideoEditorAudioDecoderSource : public MediaSource {
+ public:
+ static sp<VideoEditorAudioDecoderSource> Create(
+ const sp<MetaData>& format);
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+ virtual status_t read(MediaBuffer **buffer,
+ const ReadOptions *options = NULL);
+ virtual int32_t storeBuffer(MediaBuffer *buffer);
+
+ protected:
+ virtual ~VideoEditorAudioDecoderSource();
+
+ private:
+ struct MediaBufferChain {
+ MediaBuffer* buffer;
+ MediaBufferChain* nextLink;
+ };
+ enum State {
+ CREATED,
+ STARTED,
+ ERROR
+ };
+ VideoEditorAudioDecoderSource(const sp<MetaData>& format);
+ sp<MetaData> mFormat;
+ MediaBufferChain* mFirstBufferLink;
+ MediaBufferChain* mLastBufferLink;
+ int32_t mNbBuffer;
+ bool mIsEOS;
+ State mState;
+};
+
+sp<VideoEditorAudioDecoderSource> VideoEditorAudioDecoderSource::Create(
+ const sp<MetaData>& format) {
+
+ sp<VideoEditorAudioDecoderSource> aSource =
+ new VideoEditorAudioDecoderSource(format);
+
+ return aSource;
+}
+
+VideoEditorAudioDecoderSource::VideoEditorAudioDecoderSource(
+ const sp<MetaData>& format):
+ mFormat(format),
+ mFirstBufferLink(NULL),
+ mLastBufferLink(NULL),
+ mNbBuffer(0),
+ mIsEOS(false),
+ mState(CREATED) {
+}
+
+VideoEditorAudioDecoderSource::~VideoEditorAudioDecoderSource() {
+
+ if( STARTED == mState ) {
+ stop();
+ }
+}
+
+status_t VideoEditorAudioDecoderSource::start(MetaData *meta) {
+ status_t err = OK;
+
+ if( CREATED != mState ) {
+ LOGV("VideoEditorAudioDecoderSource::start: invalid state %d", mState);
+ return UNKNOWN_ERROR;
+ }
+
+ mState = STARTED;
+
+cleanUp:
+ LOGV("VideoEditorAudioDecoderSource::start END (0x%x)", err);
+ return err;
+}
+
+status_t VideoEditorAudioDecoderSource::stop() {
+ status_t err = OK;
+ int32_t i = 0;
+
+ LOGV("VideoEditorAudioDecoderSource::stop begin");
+
+ if( STARTED != mState ) {
+ LOGV("VideoEditorAudioDecoderSource::stop: invalid state %d", mState);
+ return UNKNOWN_ERROR;
+ }
+
+ // Release the buffer chain
+ MediaBufferChain* tmpLink = NULL;
+ while( mFirstBufferLink ) {
+ i++;
+ tmpLink = mFirstBufferLink;
+ mFirstBufferLink = mFirstBufferLink->nextLink;
+ delete tmpLink;
+ }
+ LOGV("VideoEditorAudioDecoderSource::stop : %d buffer remained", i);
+ mFirstBufferLink = NULL;
+ mLastBufferLink = NULL;
+
+ mState = CREATED;
+
+ LOGV("VideoEditorAudioDecoderSource::stop END (0x%x)", err);
+ return err;
+}
+
+sp<MetaData> VideoEditorAudioDecoderSource::getFormat() {
+
+ LOGV("VideoEditorAudioDecoderSource::getFormat");
+ return mFormat;
+}
+
+status_t VideoEditorAudioDecoderSource::read(MediaBuffer **buffer,
+ const ReadOptions *options) {
+ MediaSource::ReadOptions readOptions;
+ status_t err = OK;
+ MediaBufferChain* tmpLink = NULL;
+
+ LOGV("VideoEditorAudioDecoderSource::read begin");
+
+ if ( STARTED != mState ) {
+ LOGV("VideoEditorAudioDecoderSource::read invalid state %d", mState);
+ return UNKNOWN_ERROR;
+ }
+
+ // Get a buffer from the chain
+ if( NULL == mFirstBufferLink ) {
+ *buffer = NULL;
+ if( mIsEOS ) {
+ LOGV("VideoEditorAudioDecoderSource::read : EOS");
+ return ERROR_END_OF_STREAM;
+ } else {
+ LOGV("VideoEditorAudioDecoderSource::read : no buffer available");
+ return UNKNOWN_ERROR;
+ }
+ }
+ *buffer = mFirstBufferLink->buffer;
+
+ tmpLink = mFirstBufferLink;
+ mFirstBufferLink = mFirstBufferLink->nextLink;
+ if( NULL == mFirstBufferLink ) {
+ mLastBufferLink = NULL;
+ }
+ delete tmpLink;
+ mNbBuffer--;
+
+ LOGV("VideoEditorAudioDecoderSource::read END (0x%x)", err);
+ return err;
+}
+
+int32_t VideoEditorAudioDecoderSource::storeBuffer(MediaBuffer *buffer) {
+ status_t err = OK;
+
+ LOGV("VideoEditorAudioDecoderSource::storeBuffer begin");
+
+ // A NULL input buffer means that the end of stream was reached
+ if( NULL == buffer ) {
+ mIsEOS = true;
+ } else {
+ MediaBufferChain* newLink = new MediaBufferChain;
+ newLink->buffer = buffer;
+ newLink->nextLink = NULL;
+ if( NULL != mLastBufferLink ) {
+ mLastBufferLink->nextLink = newLink;
+ } else {
+ mFirstBufferLink = newLink;
+ }
+ mLastBufferLink = newLink;
+ mNbBuffer++;
+ }
+ LOGV("VideoEditorAudioDecoderSource::storeBuffer END");
+ return mNbBuffer;
+}
+
+/********************
+ * TOOLS *
+ ********************/
+
+M4OSA_ERR VideoEditorAudioDecoder_getBits(M4OSA_Int8* pData,
+ M4OSA_UInt32 dataSize, M4OSA_UInt8 nbBits, M4OSA_Int32* pResult,
+ M4OSA_UInt32* pOffset) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ M4OSA_UInt32 startByte = 0;
+ M4OSA_UInt32 startBit = 0;
+ M4OSA_UInt32 endByte = 0;
+ M4OSA_UInt32 endBit = 0;
+ M4OSA_UInt32 currentByte = 0;
+ M4OSA_UInt32 result = 0;
+ M4OSA_UInt32 ui32Tmp = 0;
+ M4OSA_UInt32 ui32Mask = 0;
+
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pData, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pOffset, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(32 >= nbBits, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK((*pOffset + nbBits) <= 8*dataSize, M4ERR_PARAMETER);
+
+ LOGV("VideoEditorAudioDecoder_getBits begin");
+
+ startByte = (*pOffset) >> 3;
+ endByte = (*pOffset + nbBits) >> 3;
+ startBit = (*pOffset) % 8;
+ endBit = (*pOffset + nbBits) % 8;
+ currentByte = startByte;
+
+ // Extract the requested nunber of bits from memory
+ while( currentByte <= endByte) {
+ ui32Mask = 0x000000FF;
+ if( currentByte == startByte ) {
+ ui32Mask >>= startBit;
+ }
+ ui32Tmp = ui32Mask & ((M4OSA_UInt32)pData[currentByte]);
+ if( currentByte == endByte ) {
+ ui32Tmp >>= (8-endBit);
+ result <<= endBit;
+ } else {
+ result <<= 8;
+ }
+ result |= ui32Tmp;
+ currentByte++;
+ }
+
+ *pResult = result;
+ *pOffset += nbBits;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioDecoder_getBits no error");
+ } else {
+ LOGV("VideoEditorAudioDecoder_getBits ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioDecoder_getBits end");
+ return err;
+}
+
+
+#define FREQ_TABLE_SIZE 16
+const M4OSA_UInt32 AD_AAC_FREQ_TABLE[FREQ_TABLE_SIZE] =
+ {96000, 88200, 64000, 48000, 44100,
+ 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0};
+
+
+M4OSA_ERR VideoEditorAudioDecoder_parse_AAC_DSI(M4OSA_Int8* pDSI,
+ M4OSA_UInt32 dsiSize, AAC_DEC_STREAM_PROPS* pProperties) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ M4OSA_UInt32 offset = 0;
+ M4OSA_Int32 result = 0;
+
+ LOGV("VideoEditorAudioDecoder_parse_AAC_DSI begin");
+
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pDSI, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pProperties, M4ERR_PARAMETER);
+
+ // Get the object type
+ err = VideoEditorAudioDecoder_getBits(pDSI, dsiSize, 5, &result, &offset);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+ switch( result ) {
+ case 2:
+ pProperties->aPSPresent = 0;
+ pProperties->aSBRPresent = 0;
+ break;
+ default:
+ LOGV("parse_AAC_DSI ERROR : object type %d is not supported",
+ result);
+ VIDEOEDITOR_CHECK(!"invalid AAC object type", M4ERR_BAD_OPTION_ID);
+ break;
+ }
+ pProperties->aAudioObjectType = (M4OSA_Int32)result;
+
+ // Get the frequency index
+ err = VideoEditorAudioDecoder_getBits(pDSI, dsiSize, 4, &result, &offset);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+ VIDEOEDITOR_CHECK((0 <= result) && (FREQ_TABLE_SIZE > result),
+ M4ERR_PARAMETER);
+ pProperties->aSampFreq = AD_AAC_FREQ_TABLE[result];
+ pProperties->aExtensionSampFreq = 0;
+
+ // Get the number of channels
+ err = VideoEditorAudioDecoder_getBits(pDSI, dsiSize, 4, &result, &offset);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+ pProperties->aNumChan = (M4OSA_UInt32)result;
+
+ // Set the max PCM samples per channel
+ pProperties->aMaxPCMSamplesPerCh = (pProperties->aSBRPresent) ? 2048 : 1024;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioDecoder_parse_AAC_DSI no error");
+ } else {
+ LOGV("VideoEditorAudioDecoder_parse_AAC_DSI ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioDecoder_parse_AAC_DSI end");
+ return err;
+}
+
+/********************
+ * ENGINE INTERFACE *
+ ********************/
+
+/**
+ ******************************************************************************
+ * structure VideoEditorAudioDecoder_Context
+ * @brief This structure defines the context of the StageFright audio decoder
+ * shell
+ ******************************************************************************
+*/
+typedef struct {
+ M4AD_Type mDecoderType;
+ M4_AudioStreamHandler* mAudioStreamHandler;
+ sp<VideoEditorAudioDecoderSource> mDecoderSource;
+ OMXClient mClient;
+ sp<MediaSource> mDecoder;
+ int32_t mNbOutputChannels;
+ uint32_t mNbInputFrames;
+ uint32_t mNbOutputFrames;
+} VideoEditorAudioDecoder_Context;
+
+M4OSA_ERR VideoEditorAudioDecoder_destroy(M4AD_Context pContext) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorAudioDecoder_destroy begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext;
+
+ // Stop the graph
+ if( M4OSA_NULL != pDecoderContext->mDecoder.get() ) {
+ pDecoderContext->mDecoder->stop();
+ }
+
+ // Destroy the graph
+ pDecoderContext->mDecoderSource.clear();
+ pDecoderContext->mDecoder.clear();
+ pDecoderContext->mClient.disconnect();
+
+ SAFE_FREE(pDecoderContext);
+ pContext = M4OSA_NULL;
+ LOGV("VideoEditorAudioDecoder_destroy : DONE");
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioDecoder_destroy no error");
+ } else {
+ LOGV("VideoEditorAudioDecoder_destroy ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioDecoder_destroy : end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_create(M4AD_Type decoderType,
+ M4AD_Context* pContext, M4_AudioStreamHandler* pStreamHandler,
+ void* pUserData) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL;
+ AAC_DEC_STREAM_PROPS aacProperties;
+ status_t result = OK;
+ sp<MetaData> decoderMetaData = NULL;
+ const char* mime = NULL;
+ uint32_t codecFlags = 0;
+
+ LOGV("VideoEditorAudioDecoder_create begin: decoderType %d", decoderType);
+
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pStreamHandler, M4ERR_PARAMETER);
+
+ // Context allocation & initialization
+ SAFE_MALLOC(pDecoderContext, VideoEditorAudioDecoder_Context, 1,
+ "AudioDecoder");
+ pDecoderContext->mDecoderType = decoderType;
+ pDecoderContext->mAudioStreamHandler = pStreamHandler;
+
+ pDecoderContext->mNbInputFrames = 0;
+ pDecoderContext->mNbOutputFrames = 0;
+
+ LOGV("VideoEditorAudioDecoder_create : maxAUSize %d",
+ pDecoderContext->mAudioStreamHandler->m_basicProperties.m_maxAUSize);
+
+ // Create the meta data for the decoder
+ decoderMetaData = new MetaData;
+ switch( pDecoderContext->mDecoderType ) {
+ case M4AD_kTypeAMRNB:
+ // StageFright parameters
+ mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+ // Engine parameters
+ pDecoderContext->mAudioStreamHandler->m_byteFrameLength = 160;
+ pDecoderContext->mAudioStreamHandler->m_byteSampleSize = 16;
+ pDecoderContext->mAudioStreamHandler->m_samplingFrequency = 8000;
+ pDecoderContext->mAudioStreamHandler->m_nbChannels = 1;
+ break;
+
+ case M4AD_kTypeAMRWB:
+ // StageFright parameters
+ mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+
+ pDecoderContext->mAudioStreamHandler->m_byteFrameLength = 160;
+ pDecoderContext->mAudioStreamHandler->m_byteSampleSize = 16;
+ pDecoderContext->mAudioStreamHandler->m_samplingFrequency = 16000;
+ pDecoderContext->mAudioStreamHandler->m_nbChannels = 1;
+ break;
+
+ case M4AD_kTypeAAC:
+ // Reject ADTS & ADIF (or any incorrect type)
+ VIDEOEDITOR_CHECK(M4DA_StreamTypeAudioAac ==
+ pDecoderContext->mAudioStreamHandler->\
+ m_basicProperties.m_streamType,M4ERR_PARAMETER);
+
+ // StageFright parameters
+ mime = MEDIA_MIMETYPE_AUDIO_AAC;
+
+ decoderMetaData->setData(kKeyESDS, kTypeESDS,
+ pStreamHandler->m_basicProperties.m_pESDSInfo,
+ pStreamHandler->m_basicProperties.m_ESDSInfoSize);
+
+ // Engine parameters
+ // Retrieve sampling frequency and number of channels from the DSI
+ err = VideoEditorAudioDecoder_parse_AAC_DSI(
+ (M4OSA_Int8*)pStreamHandler->m_basicProperties.\
+ m_pDecoderSpecificInfo,
+ pStreamHandler->m_basicProperties.m_decoderSpecificInfoSize,
+ &aacProperties);
+
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+ pDecoderContext->mAudioStreamHandler->m_byteFrameLength = 1024;
+ pDecoderContext->mAudioStreamHandler->m_byteSampleSize = 16;
+ pDecoderContext->mAudioStreamHandler->m_samplingFrequency =
+ aacProperties.aSampFreq;
+ pDecoderContext->mAudioStreamHandler->m_nbChannels =
+ aacProperties.aNumChan;
+
+ // Copy the stream properties into userdata
+ if( M4OSA_NULL != pUserData ) {
+ M4OSA_memcpy((M4OSA_MemAddr8)pUserData,
+ (M4OSA_MemAddr8)&aacProperties,
+ sizeof(AAC_DEC_STREAM_PROPS));
+ }
+ break;
+
+ case M4AD_kTypeMP3:
+ // StageFright parameters
+ mime = MEDIA_MIMETYPE_AUDIO_MPEG;
+ break;
+
+ default:
+ VIDEOEDITOR_CHECK(!"AudioDecoder_open : incorrect input format",
+ M4ERR_STATE);
+ break;
+ }
+ decoderMetaData->setCString(kKeyMIMEType, mime);
+ decoderMetaData->setInt32(kKeySampleRate,
+ (int32_t)pDecoderContext->mAudioStreamHandler->m_samplingFrequency);
+ decoderMetaData->setInt32(kKeyChannelCount,
+ pDecoderContext->mAudioStreamHandler->m_nbChannels);
+ decoderMetaData->setInt64(kKeyDuration,
+ (int64_t)pDecoderContext->mAudioStreamHandler->\
+ m_basicProperties.m_duration);
+
+ // Create the decoder source
+ pDecoderContext->mDecoderSource = VideoEditorAudioDecoderSource::Create(
+ decoderMetaData);
+ VIDEOEDITOR_CHECK(NULL != pDecoderContext->mDecoderSource.get(),
+ M4ERR_STATE);
+
+ // Connect to the OMX client
+ result = pDecoderContext->mClient.connect();
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+
+ // Create the OMX codec
+#ifdef VIDEOEDITOR_FORCECODEC
+ codecFlags |= OMXCodec::VIDEOEDITOR_FORCECODEC;
+#endif /* VIDEOEDITOR_FORCECODEC */
+
+ pDecoderContext->mDecoder = OMXCodec::Create(pDecoderContext->\
+ mClient.interface(),
+ decoderMetaData, false, pDecoderContext->mDecoderSource, NULL,
+ codecFlags);
+ VIDEOEDITOR_CHECK(NULL != pDecoderContext->mDecoder.get(), M4ERR_STATE);
+
+ // Get the output channels, the decoder might overwrite the input metadata
+ pDecoderContext->mDecoder->getFormat()->findInt32(kKeyChannelCount,
+ &pDecoderContext->mNbOutputChannels);
+ LOGV("VideoEditorAudioDecoder_create : output chan %d",
+ pDecoderContext->mNbOutputChannels);
+
+ // Start the decoder
+ result = pDecoderContext->mDecoder->start();
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+
+ *pContext = pDecoderContext;
+ LOGV("VideoEditorAudioDecoder_create : DONE");
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioDecoder_create no error");
+ } else {
+ VideoEditorAudioDecoder_destroy(pDecoderContext);
+ *pContext = M4OSA_NULL;
+ LOGV("VideoEditorAudioDecoder_create ERROR 0x%X", err);
+ }
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_create_AAC(M4AD_Context* pContext,
+ M4_AudioStreamHandler* pStreamHandler, void* pUserData) {
+
+ return VideoEditorAudioDecoder_create(
+ M4AD_kTypeAAC, pContext, pStreamHandler,pUserData);
+}
+
+
+M4OSA_ERR VideoEditorAudioDecoder_create_AMRNB(M4AD_Context* pContext,
+ M4_AudioStreamHandler* pStreamHandler, void* pUserData) {
+
+ return VideoEditorAudioDecoder_create(
+ M4AD_kTypeAMRNB, pContext, pStreamHandler, pUserData);
+}
+
+
+M4OSA_ERR VideoEditorAudioDecoder_create_AMRWB(M4AD_Context* pContext,
+ M4_AudioStreamHandler* pStreamHandler, void* pUserData) {
+
+ return VideoEditorAudioDecoder_create(
+ M4AD_kTypeAMRWB, pContext, pStreamHandler, pUserData);
+}
+
+
+M4OSA_ERR VideoEditorAudioDecoder_create_MP3(M4AD_Context* pContext,
+ M4_AudioStreamHandler* pStreamHandler, void* pUserData) {
+
+ return VideoEditorAudioDecoder_create(
+ M4AD_kTypeMP3, pContext, pStreamHandler, pUserData);
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_processInputBuffer(
+ M4AD_Context pContext, M4AD_Buffer* pInputBuffer) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL;
+ MediaBuffer* buffer = NULL;
+ int32_t nbBuffer = 0;
+
+ LOGV("VideoEditorAudioDecoder_processInputBuffer begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+
+ pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext;
+
+ if( M4OSA_NULL != pInputBuffer ) {
+ buffer = new MediaBuffer((size_t)pInputBuffer->m_bufferSize);
+ M4OSA_memcpy((M4OSA_Int8*)buffer->data() + buffer->range_offset(),
+ pInputBuffer->m_dataAddress, pInputBuffer->m_bufferSize);
+ }
+ nbBuffer = pDecoderContext->mDecoderSource->storeBuffer(buffer);
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioDecoder_processInputBuffer no error");
+ } else {
+ LOGV("VideoEditorAudioDecoder_processInputBuffer ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioDecoder_processInputBuffer end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_processOutputBuffer(M4AD_Context pContext,
+ MediaBuffer* buffer, M4AD_Buffer* pOuputBuffer) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL;
+ int32_t i32Tmp = 0;
+ int64_t i64Tmp = 0;
+ status_t result = OK;
+
+ LOGV("VideoEditorAudioDecoder_processOutputBuffer begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != buffer, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pOuputBuffer, M4ERR_PARAMETER);
+
+ pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext;
+
+ // Process the returned data
+ if( 0 == buffer->range_length() ) {
+ // Decoder has no data yet, nothing unusual
+ goto cleanUp;
+ }
+
+ pDecoderContext->mNbOutputFrames++;
+
+ if( pDecoderContext->mAudioStreamHandler->m_nbChannels ==
+ (M4OSA_UInt32)pDecoderContext->mNbOutputChannels ) {
+ // Just copy the PCMs
+ pOuputBuffer->m_bufferSize = (M4OSA_UInt32)buffer->range_length();
+ M4OSA_memcpy(pOuputBuffer->m_dataAddress,
+ ((M4OSA_MemAddr8)buffer->data())+buffer->range_offset(),
+ buffer->range_length());
+ } else if( pDecoderContext->mAudioStreamHandler->m_nbChannels <
+ (M4OSA_UInt32)pDecoderContext->mNbOutputChannels ) {
+ // The decoder forces stereo output, downsample
+ pOuputBuffer->m_bufferSize = (M4OSA_UInt32)(buffer->range_length()/2);
+ M4OSA_Int16* pDataIn = ((M4OSA_Int16*)buffer->data()) +
+ buffer->range_offset();
+ M4OSA_Int16* pDataOut = (M4OSA_Int16*)pOuputBuffer->m_dataAddress;
+ M4OSA_Int16* pDataEnd = pDataIn + \
+ (buffer->range_length()/sizeof(M4OSA_Int16));
+ while( pDataIn < pDataEnd ) {
+ *pDataOut = *pDataIn;
+ pDataIn+=2;
+ pDataOut++;
+ }
+ } else {
+ // The decoder forces mono output, not supported
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER);
+ }
+
+cleanUp:
+ // Release the buffer
+ buffer->release();
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioDecoder_processOutputBuffer no error");
+ } else {
+ pOuputBuffer->m_bufferSize = 0;
+ LOGV("VideoEditorAudioDecoder_processOutputBuffer ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioDecoder_processOutputBuffer end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_step(M4AD_Context pContext,
+ M4AD_Buffer* pInputBuffer, M4AD_Buffer* pOutputBuffer,
+ M4OSA_Bool bJump) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL;
+ status_t result = OK;
+ MediaBuffer* outputBuffer = NULL;
+
+ LOGV("VideoEditorAudioDecoder_step begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext;
+ pDecoderContext->mNbInputFrames++;
+
+ // Push the input buffer to the decoder source
+ err = VideoEditorAudioDecoder_processInputBuffer(pDecoderContext,
+ pInputBuffer);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+
+ // Read
+ result = pDecoderContext->mDecoder->read(&outputBuffer, NULL);
+ if(OK != result) {
+ LOGE("VideoEditorAudioDecoder_step result = %d",result);
+
+ }
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+
+ // Convert the PCM buffer
+ err = VideoEditorAudioDecoder_processOutputBuffer(pDecoderContext,
+ outputBuffer, pOutputBuffer);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioDecoder_step no error");
+ } else {
+ LOGV("VideoEditorAudioDecoder_step ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioDecoder_step end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_getVersion(M4_VersionInfo* pVersionInfo) {
+ M4OSA_ERR err = M4NO_ERROR;
+
+ LOGV("VideoEditorAudioDecoder_getVersion begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pVersionInfo, M4ERR_PARAMETER);
+
+ pVersionInfo->m_major = VIDEOEDITOR_AUDIO_DECODER_VERSION_MAJOR;
+ pVersionInfo->m_minor = VIDEOEDITOR_AUDIO_DECODER_VERSION_MINOR;
+ pVersionInfo->m_revision = VIDEOEDITOR_AUDIO_DECODER_VERSION_REV;
+ pVersionInfo->m_structSize = sizeof(M4_VersionInfo);
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioDecoder_getVersion no error");
+ } else {
+ LOGV("VideoEditorAudioDecoder_getVersion ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioDecoder_getVersion end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_setOption(M4AD_Context pContext,
+ M4OSA_UInt32 optionID, M4OSA_DataOption optionValue) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorAudioDecoder_setOption begin 0x%X", optionID);
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext;
+
+ switch( optionID ) {
+ case M4AD_kOptionID_UserParam:
+ LOGV("VideoEditorAudioDecodersetOption UserParam is not supported");
+ err = M4ERR_NOT_IMPLEMENTED;
+ break;
+ default:
+ LOGV("VideoEditorAudioDecoder_setOption unsupported optionId 0x%X",
+ optionID);
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID);
+ break;
+ }
+
+cleanUp:
+ if( ((M4OSA_UInt32)M4NO_ERROR == err) || ((M4OSA_UInt32)M4ERR_NOT_IMPLEMENTED == err) ) {
+ LOGV("VideoEditorAudioDecoder_setOption error 0x%X", err);
+ } else {
+ LOGV("VideoEditorAudioDecoder_setOption ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioDecoder_setOption end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_getOption(M4AD_Context pContext,
+ M4OSA_UInt32 optionID, M4OSA_DataOption optionValue) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorAudioDecoder_getOption begin: optionID 0x%X", optionID);
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext;
+
+ switch( optionID ) {
+ default:
+ LOGV("VideoEditorAudioDecoder_getOption unsupported optionId 0x%X",
+ optionID);
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID);
+ break;
+ }
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioDecoder_getOption no error");
+ } else {
+ LOGV("VideoEditorAudioDecoder_getOption ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioDecoder_getOption end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_getInterface(M4AD_Type decoderType,
+ M4AD_Type* pDecoderType, M4AD_Interface** pDecoderInterface) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pDecoderType, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pDecoderInterface, M4ERR_PARAMETER);
+
+ LOGV("VideoEditorAudioDecoder_getInterface begin %d 0x%x 0x%x",
+ decoderType, pDecoderType, pDecoderInterface);
+
+ SAFE_MALLOC(*pDecoderInterface, M4AD_Interface, 1,
+ "VideoEditorAudioDecoder");
+
+ *pDecoderType = decoderType;
+
+ switch( decoderType ) {
+ case M4AD_kTypeAMRNB:
+ (*pDecoderInterface)->m_pFctCreateAudioDec =
+ VideoEditorAudioDecoder_create_AMRNB;
+ break;
+ case M4AD_kTypeAMRWB:
+ (*pDecoderInterface)->m_pFctCreateAudioDec =
+ VideoEditorAudioDecoder_create_AMRWB;
+ break;
+ case M4AD_kTypeAAC:
+ (*pDecoderInterface)->m_pFctCreateAudioDec =
+ VideoEditorAudioDecoder_create_AAC;
+ break;
+ case M4AD_kTypeMP3:
+ (*pDecoderInterface)->m_pFctCreateAudioDec =
+ VideoEditorAudioDecoder_create_MP3;
+ break;
+ default:
+ LOGV("VEAD_getInterface ERROR: unsupported type %d", decoderType);
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER);
+ break;
+ }
+ (*pDecoderInterface)->m_pFctDestroyAudioDec =
+ VideoEditorAudioDecoder_destroy;
+ (*pDecoderInterface)->m_pFctResetAudioDec = M4OSA_NULL;
+ (*pDecoderInterface)->m_pFctStartAudioDec = M4OSA_NULL;
+ (*pDecoderInterface)->m_pFctStepAudioDec =
+ VideoEditorAudioDecoder_step;
+ (*pDecoderInterface)->m_pFctGetVersionAudioDec =
+ VideoEditorAudioDecoder_getVersion;
+ (*pDecoderInterface)->m_pFctSetOptionAudioDec =
+ VideoEditorAudioDecoder_setOption;
+ (*pDecoderInterface)->m_pFctGetOptionAudioDec =
+ VideoEditorAudioDecoder_getOption;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioDecoder_getInterface no error");
+ } else {
+ *pDecoderInterface = M4OSA_NULL;
+ LOGV("VideoEditorAudioDecoder_getInterface ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioDecoder_getInterface end");
+ return err;
+}
+
+
+extern "C" {
+
+M4OSA_ERR VideoEditorAudioDecoder_getInterface_AAC(M4AD_Type* pDecoderType,
+ M4AD_Interface** pDecoderInterface) {
+ LOGV("TEST: AAC VideoEditorAudioDecoder_getInterface no error");
+ return VideoEditorAudioDecoder_getInterface(
+ M4AD_kTypeAAC, pDecoderType, pDecoderInterface);
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_getInterface_AMRNB(M4AD_Type* pDecoderType,
+ M4AD_Interface** pDecoderInterface) {
+ LOGV("TEST: AMR VideoEditorAudioDecoder_getInterface no error");
+ return VideoEditorAudioDecoder_getInterface(
+ M4AD_kTypeAMRNB, pDecoderType, pDecoderInterface);
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_getInterface_AMRWB(M4AD_Type* pDecoderType,
+ M4AD_Interface** pDecoderInterface) {
+
+ return VideoEditorAudioDecoder_getInterface(
+ M4AD_kTypeAMRWB, pDecoderType, pDecoderInterface);
+}
+
+M4OSA_ERR VideoEditorAudioDecoder_getInterface_MP3(M4AD_Type* pDecoderType,
+ M4AD_Interface** pDecoderInterface) {
+
+ return VideoEditorAudioDecoder_getInterface(
+ M4AD_kTypeMP3, pDecoderType, pDecoderInterface);
+}
+
+} // extern "C"
+
+} // namespace android
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorAudioEncoder.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorAudioEncoder.cpp
new file mode 100755
index 0000000..718881f
--- /dev/null
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorAudioEncoder.cpp
@@ -0,0 +1,739 @@
+/*
+ * Copyright (C) 2011 NXP Software
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+*************************************************************************
+* @file VideoEditorAudioEncoder.cpp
+* @brief StageFright shell Audio Encoder
+*************************************************************************
+*/
+
+#define LOG_NDEBUG 1
+#define LOG_TAG "VIDEOEDITOR_AUDIOENCODER"
+
+#include "M4OSA_Debug.h"
+#include "VideoEditorAudioEncoder.h"
+#include "VideoEditorUtils.h"
+
+#include "utils/Log.h"
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+
+/*** DEFINITIONS ***/
+// Force using software encoder as engine does not support prefetch
+#define VIDEOEDITOR_FORCECODEC kSoftwareCodecsOnly
+
+namespace android {
+struct VideoEditorAudioEncoderSource : public MediaSource {
+ public:
+ static sp<VideoEditorAudioEncoderSource> Create();
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+ virtual status_t read(MediaBuffer **buffer,
+ const ReadOptions *options = NULL);
+ virtual int32_t storeBuffer(MediaBuffer *buffer);
+
+ protected:
+ virtual ~VideoEditorAudioEncoderSource();
+
+ private:
+ struct MediaBufferChain {
+ MediaBuffer* buffer;
+ MediaBufferChain* nextLink;
+ };
+ enum State {
+ CREATED,
+ STARTED,
+ ERROR
+ };
+ VideoEditorAudioEncoderSource();
+ MediaBufferChain* mFirstBufferLink;
+ MediaBufferChain* mLastBufferLink;
+ int32_t mNbBuffer;
+ State mState;
+};
+
+sp<VideoEditorAudioEncoderSource> VideoEditorAudioEncoderSource::Create() {
+
+ LOGV("VideoEditorAudioEncoderSource::Create");
+ sp<VideoEditorAudioEncoderSource> aSource =
+ new VideoEditorAudioEncoderSource();
+
+ return aSource;
+}
+
+VideoEditorAudioEncoderSource::VideoEditorAudioEncoderSource():
+ mFirstBufferLink(NULL),
+ mLastBufferLink(NULL),
+ mNbBuffer(0),
+ mState(CREATED) {
+ LOGV("VideoEditorAudioEncoderSource::VideoEditorAudioEncoderSource");
+}
+
+
+VideoEditorAudioEncoderSource::~VideoEditorAudioEncoderSource() {
+ LOGV("VideoEditorAudioEncoderSource::~VideoEditorAudioEncoderSource");
+
+ if( STARTED == mState ) {
+ stop();
+ }
+}
+
+status_t VideoEditorAudioEncoderSource::start(MetaData *meta) {
+ status_t err = OK;
+
+ LOGV("VideoEditorAudioEncoderSource::start");
+
+ if( CREATED != mState ) {
+ LOGV("VideoEditorAudioEncoderSource::start ERROR : invalid state %d",
+ mState);
+ return UNKNOWN_ERROR;
+ }
+
+ mState = STARTED;
+
+cleanUp:
+ LOGV("VideoEditorAudioEncoderSource::start END (0x%x)", err);
+ return err;
+}
+
+status_t VideoEditorAudioEncoderSource::stop() {
+ status_t err = OK;
+
+ LOGV("VideoEditorAudioEncoderSource::stop");
+
+ if( STARTED != mState ) {
+ LOGV("VideoEditorAudioEncoderSource::stop ERROR: invalid state %d",
+ mState);
+ return UNKNOWN_ERROR;
+ }
+
+ int32_t i = 0;
+ MediaBufferChain* tmpLink = NULL;
+ while( mFirstBufferLink ) {
+ i++;
+ tmpLink = mFirstBufferLink;
+ mFirstBufferLink = mFirstBufferLink->nextLink;
+ delete tmpLink;
+ }
+ LOGV("VideoEditorAudioEncoderSource::stop : %d buffer remained", i);
+ mFirstBufferLink = NULL;
+ mLastBufferLink = NULL;
+
+ mState = CREATED;
+
+ LOGV("VideoEditorAudioEncoderSource::stop END (0x%x)", err);
+ return err;
+}
+
+sp<MetaData> VideoEditorAudioEncoderSource::getFormat() {
+ LOGV("VideoEditorAudioEncoderSource::getFormat");
+
+ LOGV("VideoEditorAudioEncoderSource::getFormat :THIS IS NOT IMPLEMENTED");
+
+ return NULL;
+}
+
+status_t VideoEditorAudioEncoderSource::read(MediaBuffer **buffer,
+ const ReadOptions *options) {
+ MediaSource::ReadOptions readOptions;
+ status_t err = OK;
+ MediaBufferChain* tmpLink = NULL;
+
+ LOGV("VideoEditorAudioEncoderSource::read");
+
+ if ( STARTED != mState ) {
+ LOGV("VideoEditorAudioEncoderSource::read ERROR : invalid state %d",
+ mState);
+ return UNKNOWN_ERROR;
+ }
+
+ if( NULL == mFirstBufferLink ) {
+ *buffer = NULL;
+ LOGV("VideoEditorAudioEncoderSource::read : EOS");
+ return ERROR_END_OF_STREAM;
+ }
+ *buffer = mFirstBufferLink->buffer;
+
+ tmpLink = mFirstBufferLink;
+ mFirstBufferLink = mFirstBufferLink->nextLink;
+ if( NULL == mFirstBufferLink ) {
+ mLastBufferLink = NULL;
+ }
+ delete tmpLink;
+ mNbBuffer--;
+
+ LOGV("VideoEditorAudioEncoderSource::read END (0x%x)", err);
+ return err;
+}
+
+int32_t VideoEditorAudioEncoderSource::storeBuffer(MediaBuffer *buffer) {
+ status_t err = OK;
+
+ LOGV("VideoEditorAudioEncoderSource::storeBuffer");
+
+ MediaBufferChain* newLink = new MediaBufferChain;
+ newLink->buffer = buffer;
+ newLink->nextLink = NULL;
+ if( NULL != mLastBufferLink ) {
+ mLastBufferLink->nextLink = newLink;
+ } else {
+ mFirstBufferLink = newLink;
+ }
+ mLastBufferLink = newLink;
+ mNbBuffer++;
+
+ LOGV("VideoEditorAudioEncoderSource::storeBuffer END");
+ return mNbBuffer;
+}
+
+/********************
+ * ENGINE INTERFACE *
+ ********************/
+/**
+ ******************************************************************************
+ * structure VideoEditorAudioEncoder_Context
+ * @brief This structure defines the context of the StageFright audio
+ * encoder shell
+ ******************************************************************************
+*/
+typedef struct {
+ M4ENCODER_AudioFormat mFormat;
+ M4ENCODER_AudioParams* mCodecParams;
+ M4ENCODER_AudioDecSpecificInfo mDSI;
+ sp<VideoEditorAudioEncoderSource> mEncoderSource;
+ OMXClient mClient;
+ sp<MediaSource> mEncoder;
+ uint32_t mNbInputFrames;
+ uint32_t mNbOutputFrames;
+ int64_t mFirstOutputCts;
+ int64_t mLastOutputCts;
+} VideoEditorAudioEncoder_Context;
+
+M4OSA_ERR VideoEditorAudioEncoder_cleanup(M4OSA_Context pContext) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioEncoder_Context* pEncoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorAudioEncoder_cleanup begin");
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ pEncoderContext = (VideoEditorAudioEncoder_Context*)pContext;
+
+ SAFE_FREE(pEncoderContext->mDSI.pInfo);
+ SAFE_FREE(pEncoderContext);
+ pContext = M4OSA_NULL;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioEncoder_cleanup no error");
+ } else {
+ LOGV("VideoEditorAudioEncoder_cleanup ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioEncoder_cleanup end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_init(M4ENCODER_AudioFormat format,
+ M4OSA_Context* pContext, M4OSA_Void* pUserData) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioEncoder_Context* pEncoderContext = M4OSA_NULL;
+
+ LOGV(" VideoEditorAudioEncoder_init begin: format %d", format);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ SAFE_MALLOC(pEncoderContext, VideoEditorAudioEncoder_Context, 1,
+ "VideoEditorAudioEncoder");
+ pEncoderContext->mFormat = format;
+
+ *pContext = pEncoderContext;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioEncoder_init no error");
+ } else {
+ VideoEditorAudioEncoder_cleanup(pEncoderContext);
+ *pContext = M4OSA_NULL;
+ LOGV("VideoEditorAudioEncoder_init ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioEncoder_init end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_init_AAC(M4OSA_Context* pContext,
+ M4OSA_Void* pUserData) {
+ return VideoEditorAudioEncoder_init(M4ENCODER_kAAC, pContext, pUserData);
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_init_AMRNB(M4OSA_Context* pContext,
+ M4OSA_Void* pUserData) {
+ return VideoEditorAudioEncoder_init(M4ENCODER_kAMRNB, pContext, pUserData);
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_init_MP3(M4OSA_Context* pContext,
+ M4OSA_Void* pUserData) {
+ return VideoEditorAudioEncoder_init(M4ENCODER_kMP3, pContext, pUserData);
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_close(M4OSA_Context pContext) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioEncoder_Context* pEncoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorAudioEncoder_close begin");
+
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ pEncoderContext = (VideoEditorAudioEncoder_Context*)pContext;
+
+ SAFE_FREE(pEncoderContext->mCodecParams);
+
+ pEncoderContext->mEncoder->stop();
+ pEncoderContext->mEncoder.clear();
+ pEncoderContext->mClient.disconnect();
+ pEncoderContext->mEncoderSource.clear();
+
+ LOGV("AudioEncoder_close:IN %d frames,OUT %d frames from %lld to %lld",
+ pEncoderContext->mNbInputFrames,
+ pEncoderContext->mNbOutputFrames, pEncoderContext->mFirstOutputCts,
+ pEncoderContext->mLastOutputCts);
+
+ if( pEncoderContext->mNbInputFrames != pEncoderContext->mNbInputFrames ) {
+ LOGV("VideoEditorAudioEncoder_close:some frames were not encoded %d %d",
+ pEncoderContext->mNbInputFrames, pEncoderContext->mNbInputFrames);
+ }
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioEncoder_close no error");
+ } else {
+ LOGV("VideoEditorAudioEncoder_close ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioEncoder_close begin end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_open(M4OSA_Context pContext,
+ M4ENCODER_AudioParams *pParams, M4ENCODER_AudioDecSpecificInfo *pDSI,
+ M4OSA_Context pGrabberContext) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioEncoder_Context* pEncoderContext = M4OSA_NULL;
+ status_t result = OK;
+ sp<MetaData> encoderMetadata = NULL;
+ const char* mime = NULL;
+ int32_t iNbChannel = 0;
+ uint32_t codecFlags = 0;
+
+ LOGV("VideoEditorAudioEncoder_open begin");
+
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pParams, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pDSI, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorAudioEncoder_Context*)pContext;
+ pDSI->pInfo = M4OSA_NULL;
+ pDSI->infoSize = 0;
+
+ pEncoderContext->mNbInputFrames = 0;
+ pEncoderContext->mNbOutputFrames = 0;
+ pEncoderContext->mFirstOutputCts = -1;
+ pEncoderContext->mLastOutputCts = -1;
+
+ // Allocate & initialize the encoding parameters
+ LOGV("VideoEditorAudioEncoder_open : params F=%d CN=%d BR=%d F=%d",
+ pParams->Frequency, pParams->ChannelNum, pParams->Bitrate,
+ pParams->Format);
+ SAFE_MALLOC(pEncoderContext->mCodecParams, M4ENCODER_AudioParams, 1,
+ "VIDEOEDITOR CodecParams");
+ pEncoderContext->mCodecParams->Frequency = pParams->Frequency;
+ pEncoderContext->mCodecParams->ChannelNum = pParams->ChannelNum;
+ pEncoderContext->mCodecParams->Bitrate = pParams->Bitrate;
+ pEncoderContext->mCodecParams->Format = pParams->Format;
+
+ // Check output format consistency
+ VIDEOEDITOR_CHECK(pEncoderContext->mCodecParams->Format ==
+ pEncoderContext->mFormat, M4ERR_PARAMETER);
+
+ /**
+ * StageFright graph building
+ */
+ // Create the meta data for the encoder
+ encoderMetadata = new MetaData;
+ switch( pEncoderContext->mCodecParams->Format ) {
+ case M4ENCODER_kAAC:
+ {
+ mime = MEDIA_MIMETYPE_AUDIO_AAC;
+ break;
+ }
+ case M4ENCODER_kAMRNB:
+ {
+ mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+ break;
+ }
+ default:
+ {
+ VIDEOEDITOR_CHECK(!"AudioEncoder_open : incorrect input format",
+ M4ERR_PARAMETER);
+ break;
+ }
+ }
+ encoderMetadata->setCString(kKeyMIMEType, mime);
+ encoderMetadata->setInt32(kKeySampleRate,
+ (int32_t)pEncoderContext->mCodecParams->Frequency);
+ encoderMetadata->setInt32(kKeyBitRate,
+ (int32_t)pEncoderContext->mCodecParams->Bitrate);
+
+ switch( pEncoderContext->mCodecParams->ChannelNum ) {
+ case M4ENCODER_kMono:
+ {
+ iNbChannel = 1;
+ break;
+ }
+ case M4ENCODER_kStereo:
+ {
+ iNbChannel = 2;
+ break;
+ }
+ default:
+ {
+ VIDEOEDITOR_CHECK(!"AudioEncoder_open : incorrect channel number",
+ M4ERR_STATE);
+ break;
+ }
+ }
+ encoderMetadata->setInt32(kKeyChannelCount, iNbChannel);
+
+ // Create the encoder source
+ pEncoderContext->mEncoderSource = VideoEditorAudioEncoderSource::Create();
+ VIDEOEDITOR_CHECK(NULL != pEncoderContext->mEncoderSource.get(),
+ M4ERR_STATE);
+
+ // Connect to the OMX client
+ result = pEncoderContext->mClient.connect();
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+
+ // Create the OMX codec
+#ifdef VIDEOEDITOR_FORCECODEC
+ codecFlags |= OMXCodec::VIDEOEDITOR_FORCECODEC;
+#endif /* VIDEOEDITOR_FORCECODEC */
+ pEncoderContext->mEncoder = OMXCodec::Create(
+ pEncoderContext->mClient.interface(), encoderMetadata, true,
+ pEncoderContext->mEncoderSource, NULL, codecFlags);
+ VIDEOEDITOR_CHECK(NULL != pEncoderContext->mEncoder.get(), M4ERR_STATE);
+
+ // Start the graph
+ result = pEncoderContext->mEncoder->start();
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+
+ // Get AAC DSI, this code can only work with software encoder
+ if( M4ENCODER_kAAC == pEncoderContext->mCodecParams->Format ) {
+ int32_t isCodecConfig = 0;
+ MediaBuffer* buffer = NULL;
+
+ // Read once to get the DSI
+ result = pEncoderContext->mEncoder->read(&buffer, NULL);
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+ VIDEOEDITOR_CHECK(buffer->meta_data()->findInt32(kKeyIsCodecConfig,
+ &isCodecConfig) && isCodecConfig, M4ERR_STATE);
+
+ // Save the DSI
+ pEncoderContext->mDSI.infoSize = (M4OSA_UInt32)buffer->range_length();
+ SAFE_MALLOC(pEncoderContext->mDSI.pInfo, M4OSA_Int8,
+ pEncoderContext->mDSI.infoSize, "Encoder header");
+
+ M4OSA_memcpy(pEncoderContext->mDSI.pInfo,
+ (M4OSA_MemAddr8)(buffer->data())+buffer->range_offset(),
+ pEncoderContext->mDSI.infoSize);
+
+ buffer->release();
+ *pDSI = pEncoderContext->mDSI;
+ }
+ LOGV("VideoEditorAudioEncoder_open : DONE");
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioEncoder_open no error");
+ } else {
+ VideoEditorAudioEncoder_close(pEncoderContext);
+ LOGV("VideoEditorAudioEncoder_open ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioEncoder_open end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_processInputBuffer(M4OSA_Context pContext,
+ M4ENCODER_AudioBuffer* pInBuffer) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioEncoder_Context* pEncoderContext = M4OSA_NULL;
+ M4OSA_Int8* pData = M4OSA_NULL;
+ MediaBuffer* buffer = NULL;
+ int32_t nbBuffer = 0;
+
+ LOGV("VideoEditorAudioEncoder_processInputBuffer begin");
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorAudioEncoder_Context*)pContext;
+
+ switch( pEncoderContext->mCodecParams->ChannelNum ) {
+ case M4ENCODER_kMono:
+ case M4ENCODER_kStereo:
+ // Let the MediaBuffer own the data so we don't have to free it
+ buffer = new MediaBuffer((size_t)pInBuffer->pTableBufferSize[0]);
+ pData = (M4OSA_Int8*)buffer->data() + buffer->range_offset();
+ M4OSA_memcpy(pData, pInBuffer->pTableBuffer[0],
+ pInBuffer->pTableBufferSize[0]);
+ break;
+ default:
+ LOGV("VEAE_processInputBuffer unsupported channel configuration %d",
+ pEncoderContext->mCodecParams->ChannelNum);
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER);
+ break;
+ }
+
+ LOGV("VideoEditorAudioEncoder_processInputBuffer : store %d bytes",
+ buffer->range_length());
+ // Push the buffer to the source
+ nbBuffer = pEncoderContext->mEncoderSource->storeBuffer(buffer);
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioEncoder_processInputBuffer no error");
+ } else {
+ if( NULL != buffer ) {
+ buffer->release();
+ }
+ LOGV("VideoEditorAudioEncoder_processInputBuffer ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioEncoder_processInputBuffer end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_processOutputBuffer(M4OSA_Context pContext,
+ MediaBuffer* buffer, M4ENCODER_AudioBuffer* pOutBuffer) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioEncoder_Context* pEncoderContext = M4OSA_NULL;
+ M4OSA_UInt32 Cts = 0;
+ int32_t i32Tmp = 0;
+ int64_t i64Tmp = 0;
+ status_t result = OK;
+
+ LOGV("VideoEditorAudioEncoder_processOutputBuffer begin");
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != buffer, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pOutBuffer, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorAudioEncoder_Context*)pContext;
+
+ // Process the returned AU
+ if( 0 == buffer->range_length() ) {
+ // Encoder has no data yet, nothing unusual
+ LOGV("VideoEditorAudioEncoder_processOutputBuffer : buffer is empty");
+ pOutBuffer->pTableBufferSize[0] = 0;
+ goto cleanUp;
+ }
+ if( buffer->meta_data()->findInt32(kKeyIsCodecConfig, &i32Tmp) && i32Tmp ) {
+ /* This should not happen with software encoder,
+ * DSI was retrieved beforehand */
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_STATE);
+ } else {
+ // Check the CTS
+ VIDEOEDITOR_CHECK(buffer->meta_data()->findInt64(kKeyTime, &i64Tmp),
+ M4ERR_STATE);
+ Cts = (M4OSA_Int32)(i64Tmp/1000);
+
+ pEncoderContext->mNbOutputFrames++;
+ if( 0 > pEncoderContext->mFirstOutputCts ) {
+ pEncoderContext->mFirstOutputCts = i64Tmp;
+ }
+ pEncoderContext->mLastOutputCts = i64Tmp;
+
+ // Format the AU
+ M4OSA_memcpy(pOutBuffer->pTableBuffer[0],
+ (M4OSA_MemAddr8)(buffer->data())+buffer->range_offset(),
+ buffer->range_length());
+ pOutBuffer->pTableBufferSize[0] = (M4OSA_UInt32)buffer->range_length();
+ }
+
+cleanUp:
+ // Release the buffer
+ buffer->release();
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioEncoder_processOutputBuffer no error");
+ } else {
+ LOGV("VideoEditorAudioEncoder_processOutputBuffer ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioEncoder_processOutputBuffer end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_step(M4OSA_Context pContext,
+ M4ENCODER_AudioBuffer* pInBuffer, M4ENCODER_AudioBuffer* pOutBuffer) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioEncoder_Context* pEncoderContext = M4OSA_NULL;
+ status_t result = OK;
+ MediaBuffer* buffer = NULL;
+
+ LOGV("VideoEditorAudioEncoder_step begin");
+
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pInBuffer, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pOutBuffer, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorAudioEncoder_Context*)pContext;
+ pEncoderContext->mNbInputFrames++;
+
+ // Push the input buffer to the encoder source
+ err = VideoEditorAudioEncoder_processInputBuffer(pEncoderContext,pInBuffer);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+
+ // Read
+ result = pEncoderContext->mEncoder->read(&buffer, NULL);
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+
+ // Provide the encoded AU to the writer
+ err = VideoEditorAudioEncoder_processOutputBuffer(pEncoderContext, buffer,
+ pOutBuffer);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioEncoder_step no error");
+ } else {
+ LOGV("VideoEditorAudioEncoder_step ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioEncoder_step end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_getOption(M4OSA_Context pContext,
+ M4OSA_OptionID optionID, M4OSA_DataOption* optionValue) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorAudioEncoder_Context* pEncoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorAudioEncoder_getOption begin optionID 0x%X", optionID);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorAudioEncoder_Context*)pContext;
+
+ switch( optionID ) {
+ default:
+ LOGV("VideoEditorAudioEncoder_getOption: unsupported optionId 0x%X",
+ optionID);
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID);
+ break;
+ }
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioEncoder_getOption no error");
+ } else {
+ LOGV("VideoEditorAudioEncoder_getOption ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorAudioEncoder_getOption end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_getInterface(
+ M4ENCODER_AudioFormat format, M4ENCODER_AudioFormat* pFormat,
+ M4ENCODER_AudioGlobalInterface** pEncoderInterface) {
+ M4OSA_ERR err = M4NO_ERROR;
+
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pFormat, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pEncoderInterface, M4ERR_PARAMETER);
+
+ LOGV("VideoEditorAudioEncoder_getInterface 0x%x 0x%x",pFormat,
+ pEncoderInterface);
+ SAFE_MALLOC(*pEncoderInterface, M4ENCODER_AudioGlobalInterface, 1,
+ "AudioEncoder");
+
+ *pFormat = format;
+
+ switch( format ) {
+ case M4ENCODER_kAAC:
+ {
+ (*pEncoderInterface)->pFctInit = VideoEditorAudioEncoder_init_AAC;
+ break;
+ }
+ case M4ENCODER_kAMRNB:
+ {
+ (*pEncoderInterface)->pFctInit = VideoEditorAudioEncoder_init_AMRNB;
+ break;
+ }
+ case M4ENCODER_kMP3:
+ {
+ (*pEncoderInterface)->pFctInit = VideoEditorAudioEncoder_init_MP3;
+ break;
+ }
+ default:
+ {
+ LOGV("VideoEditorAudioEncoder_getInterface: unsupported format %d",
+ format);
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER);
+ break;
+ }
+ }
+ (*pEncoderInterface)->pFctCleanUp = VideoEditorAudioEncoder_cleanup;
+ (*pEncoderInterface)->pFctOpen = VideoEditorAudioEncoder_open;
+ (*pEncoderInterface)->pFctClose = VideoEditorAudioEncoder_close;
+ (*pEncoderInterface)->pFctStep = VideoEditorAudioEncoder_step;
+ (*pEncoderInterface)->pFctGetOption = VideoEditorAudioEncoder_getOption;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorAudioEncoder_getInterface no error");
+ } else {
+ *pEncoderInterface = M4OSA_NULL;
+ LOGV("VideoEditorAudioEncoder_getInterface ERROR 0x%X", err);
+ }
+ return err;
+}
+extern "C" {
+
+M4OSA_ERR VideoEditorAudioEncoder_getInterface_AAC(
+ M4ENCODER_AudioFormat* pFormat,
+ M4ENCODER_AudioGlobalInterface** pEncoderInterface) {
+ return VideoEditorAudioEncoder_getInterface(
+ M4ENCODER_kAAC, pFormat, pEncoderInterface);
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_getInterface_AMRNB(
+ M4ENCODER_AudioFormat* pFormat,
+ M4ENCODER_AudioGlobalInterface** pEncoderInterface) {
+
+ return VideoEditorAudioEncoder_getInterface(
+ M4ENCODER_kAMRNB, pFormat, pEncoderInterface);
+}
+
+M4OSA_ERR VideoEditorAudioEncoder_getInterface_MP3(
+ M4ENCODER_AudioFormat* pFormat,
+ M4ENCODER_AudioGlobalInterface** pEncoderInterface) {
+ LOGV("VideoEditorAudioEncoder_getInterface_MP3 no error");
+
+ return VideoEditorAudioEncoder_getInterface(
+ M4ENCODER_kMP3, pFormat, pEncoderInterface);
+}
+
+} // extern "C"
+
+} // namespace android
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorBuffer.c b/libvideoeditor/vss/stagefrightshells/src/VideoEditorBuffer.c
new file mode 100755
index 0000000..9f50a58
--- /dev/null
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorBuffer.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2011 NXP Software
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+*************************************************************************
+* @file VideoEditorBuffer.c
+* @brief StageFright shell Buffer
+*************************************************************************
+*/
+#undef M4OSA_TRACE_LEVEL
+#define M4OSA_TRACE_LEVEL 1
+
+#include "VideoEditorBuffer.h"
+#include "utils/Log.h"
+
+#define VIDEOEDITOR_BUFFEPOOL_MAX_NAME_SIZE 40
+
+#define VIDEOEDITOR_SAFE_FREE(p) \
+{ \
+ if(M4OSA_NULL != p) \
+ { \
+ M4OSA_free((M4OSA_MemAddr32)p); \
+ p = M4OSA_NULL; \
+ } \
+}
+
+/**
+ ************************************************************************
+ M4OSA_ERR VIDEOEDITOR_BUFFER_allocatePool(VIDEOEDITOR_BUFFER_Pool** ppool,
+ * M4OSA_UInt32 nbBuffers)
+ * @brief Allocate a pool of nbBuffers buffers
+ *
+ * @param ppool : IN The buffer pool to create
+ * @param nbBuffers : IN The number of buffers in the pool
+ * @param poolName : IN a name given to the pool
+ * @return Error code
+ ************************************************************************
+*/
+M4OSA_ERR VIDEOEDITOR_BUFFER_allocatePool(VIDEOEDITOR_BUFFER_Pool** ppool,
+ M4OSA_UInt32 nbBuffers, M4OSA_Char* poolName)
+{
+ M4OSA_ERR lerr = M4NO_ERROR;
+ VIDEOEDITOR_BUFFER_Pool* pool;
+
+ LOGV("VIDEOEDITOR_BUFFER_allocatePool : ppool = 0x%x nbBuffers = %d ",
+ ppool, nbBuffers);
+
+ pool = M4OSA_NULL;
+ pool = (VIDEOEDITOR_BUFFER_Pool*)M4OSA_malloc(
+ sizeof(VIDEOEDITOR_BUFFER_Pool), VIDEOEDITOR_BUFFER_EXTERNAL,
+ (M4OSA_Char*)("VIDEOEDITOR_BUFFER_allocatePool: pool"));
+ if (M4OSA_NULL == pool)
+ {
+ lerr = M4ERR_ALLOC;
+ goto VIDEOEDITOR_BUFFER_allocatePool_Cleanup;
+ }
+
+ LOGV("VIDEOEDITOR_BUFFER_allocatePool : Allocating Pool buffers");
+ pool->pNXPBuffer = M4OSA_NULL;
+ pool->pNXPBuffer = (VIDEOEDITOR_BUFFER_Buffer*)M4OSA_malloc(
+ sizeof(VIDEOEDITOR_BUFFER_Buffer)*nbBuffers,
+ VIDEOEDITOR_BUFFER_EXTERNAL,
+ (M4OSA_Char*)("BUFFER_allocatePool: pNXPBuffer"));
+ if(M4OSA_NULL == pool->pNXPBuffer)
+ {
+ lerr = M4ERR_ALLOC;
+ goto VIDEOEDITOR_BUFFER_allocatePool_Cleanup;
+ }
+
+ LOGV("VIDEOEDITOR_BUFFER_allocatePool : Allocating Pool name buffer");
+ pool->poolName = M4OSA_NULL;
+ pool->poolName = (M4OSA_Char*)M4OSA_malloc(
+ VIDEOEDITOR_BUFFEPOOL_MAX_NAME_SIZE,VIDEOEDITOR_BUFFER_EXTERNAL,
+ (M4OSA_Char*)("VIDEOEDITOR_BUFFER_allocatePool: poolname"));
+ if(pool->poolName == M4OSA_NULL)
+ {
+ lerr = M4ERR_ALLOC;
+ goto VIDEOEDITOR_BUFFER_allocatePool_Cleanup;
+ }
+
+ LOGV("VIDEOEDITOR_BUFFER_allocatePool : Assigning Pool name buffer");
+
+ M4OSA_memset(pool->poolName, VIDEOEDITOR_BUFFEPOOL_MAX_NAME_SIZE, 0);
+ M4OSA_memcpy(pool->poolName, poolName,
+ VIDEOEDITOR_BUFFEPOOL_MAX_NAME_SIZE-1);
+
+ pool->NB = nbBuffers;
+
+VIDEOEDITOR_BUFFER_allocatePool_Cleanup:
+ if(M4NO_ERROR != lerr)
+ {
+ VIDEOEDITOR_SAFE_FREE(pool->pNXPBuffer);
+ VIDEOEDITOR_SAFE_FREE(pool->poolName);
+ VIDEOEDITOR_SAFE_FREE(pool);
+ }
+ *ppool = pool;
+ LOGV("VIDEOEDITOR_BUFFER_allocatePool END");
+
+ return lerr;
+}
+
+/**
+ ************************************************************************
+ M4OSA_ERR VIDEOEDITOR_BUFFER_freePool(VIDEOEDITOR_BUFFER_Pool* ppool)
+ * @brief Deallocate a buffer pool
+ *
+ * @param ppool : IN The buffer pool to free
+ * @return Error code
+ ************************************************************************
+*/
+M4OSA_ERR VIDEOEDITOR_BUFFER_freePool(VIDEOEDITOR_BUFFER_Pool* ppool)
+{
+ M4OSA_ERR err;
+ M4OSA_UInt32 j = 0;
+
+ LOGV("VIDEOEDITOR_BUFFER_freePool : ppool = 0x%x", ppool);
+
+ err = M4NO_ERROR;
+
+ for (j = 0; j < ppool->NB; j++)
+ {
+ if(M4OSA_NULL != ppool->pNXPBuffer[j].pData)
+ {
+ M4OSA_free((M4OSA_MemAddr32)ppool->pNXPBuffer[j].pData);
+ ppool->pNXPBuffer[j].pData = M4OSA_NULL;
+ }
+ }
+
+ if(ppool != M4OSA_NULL)
+ {
+ SAFE_FREE(ppool->pNXPBuffer);
+ SAFE_FREE(ppool->poolName);
+ SAFE_FREE(ppool);
+ }
+
+ return(err);
+}
+
+/**
+ ************************************************************************
+ M4OSA_ERR VIDEOEDITOR_BUFFER_getBuffer(VIDEOEDITOR_BUFFER_Pool* ppool,
+ * VIDEOEDITOR_BUFFER_Buffer** pNXPBuffer)
+ * @brief Returns a buffer in a given state
+ *
+ * @param ppool : IN The buffer pool
+ * @param desiredState : IN The buffer state
+ * @param pNXPBuffer : IN The selected buffer
+ * @return Error code
+ ************************************************************************
+*/
+M4OSA_ERR VIDEOEDITOR_BUFFER_getBuffer(VIDEOEDITOR_BUFFER_Pool* ppool,
+ VIDEOEDITOR_BUFFER_State desiredState,
+ VIDEOEDITOR_BUFFER_Buffer** pNXPBuffer)
+{
+ M4OSA_ERR err = M4NO_ERROR;
+ M4OSA_Bool bFound = M4OSA_FALSE;
+ M4OSA_UInt32 i, ibuf;
+
+ LOGV("VIDEOEDITOR_BUFFER_getBuffer from %s in state=%d",
+ ppool->poolName, desiredState);
+
+ ibuf = 0;
+
+ for (i=0; i < ppool->NB; i++)
+ {
+ bFound = (ppool->pNXPBuffer[i].state == desiredState);
+ if (bFound)
+ {
+ ibuf = i;
+ break;
+ }
+ }
+
+ if(!bFound)
+ {
+ LOGV("VIDEOEDITOR_BUFFER_getBuffer No buffer available in state %d",
+ desiredState);
+ *pNXPBuffer = M4OSA_NULL;
+ return M4ERR_NO_BUFFER_AVAILABLE;
+ }
+
+ /* case where a buffer has been found */
+ *pNXPBuffer = &(ppool->pNXPBuffer[ibuf]);
+
+ LOGV("VIDEOEDITOR_BUFFER_getBuffer: idx = %d", ibuf);
+
+ return(err);
+}
+
+M4OSA_ERR VIDEOEDITOR_BUFFER_initPoolBuffers(VIDEOEDITOR_BUFFER_Pool* pool,
+ M4OSA_UInt32 lSize)
+{
+ M4OSA_ERR err = M4NO_ERROR;
+ M4OSA_UInt32 index, j;
+
+ /**
+ * Initialize all the buffers in the pool */
+ for(index = 0; index< pool->NB; index++)
+ {
+ pool->pNXPBuffer[index].pData = M4OSA_NULL;
+ pool->pNXPBuffer[index].pData = (M4OSA_Void*)M4OSA_malloc(
+ lSize, VIDEOEDITOR_BUFFER_EXTERNAL,
+ (M4OSA_Char*)("BUFFER_initPoolBuffers: Buffer data"));
+ if(M4OSA_NULL == pool->pNXPBuffer[index].pData)
+ {
+ for (j = 0; j < index; j++)
+ {
+ if(M4OSA_NULL != pool->pNXPBuffer[index].pData)
+ {
+ M4OSA_free((M4OSA_MemAddr32)pool->pNXPBuffer[index].pData);
+ pool->pNXPBuffer[index].pData = M4OSA_NULL;
+ }
+ }
+ err = M4ERR_ALLOC;
+ return err;
+ }
+ pool->pNXPBuffer[index].size = 0;
+ pool->pNXPBuffer[index].state = VIDEOEDITOR_BUFFER_kEmpty;
+ pool->pNXPBuffer[index].idx = index;
+ pool->pNXPBuffer[index].buffCTS = -1;
+ }
+ return err;
+}
+
+M4OSA_ERR VIDEOEDITOR_BUFFER_getOldestBuffer(VIDEOEDITOR_BUFFER_Pool *pool,
+ VIDEOEDITOR_BUFFER_State desiredState,
+ VIDEOEDITOR_BUFFER_Buffer** pNXPBuffer)
+{
+ M4OSA_ERR err = M4NO_ERROR;
+ M4OSA_UInt32 index, j;
+ M4_MediaTime candidateTimeStamp = (M4_MediaTime)0x7ffffff;
+ M4OSA_Bool bFound = M4OSA_FALSE;
+
+ *pNXPBuffer = M4OSA_NULL;
+ for(index = 0; index< pool->NB; index++)
+ {
+ if(pool->pNXPBuffer[index].state == desiredState)
+ {
+ if(pool->pNXPBuffer[index].buffCTS <= candidateTimeStamp)
+ {
+ bFound = M4OSA_TRUE;
+ candidateTimeStamp = pool->pNXPBuffer[index].buffCTS;
+ *pNXPBuffer = &(pool->pNXPBuffer[index]);
+ }
+ }
+ }
+ if(M4OSA_FALSE == bFound)
+ {
+ LOGV("VIDEOEDITOR_BUFFER_getOldestBuffer WARNING no buffer available");
+ err = M4ERR_NO_BUFFER_AVAILABLE;
+ }
+ return err;
+}
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorMp3Reader.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorMp3Reader.cpp
new file mode 100755
index 0000000..a07bf47
--- /dev/null
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorMp3Reader.cpp
@@ -0,0 +1,801 @@
+/*
+ * Copyright (C) 2011 NXP Software
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+*************************************************************************
+* @file VideoEditorMp3Reader.cpp
+* @brief StageFright shell MP3 Reader
+*************************************************************************
+*/
+#define LOG_NDEBUG 1
+#define LOG_TAG "VIDEOEDITOR_MP3READER"
+
+/**
+ * HEADERS
+ *
+ */
+#include "M4OSA_Debug.h"
+#include "M4SYS_AccessUnit.h"
+#include "VideoEditorMp3Reader.h"
+#include "VideoEditorUtils.h"
+
+#include "utils/Log.h"
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+/**
+ * SOURCE CLASS
+ */
+
+namespace android {
+/**
+ * ENGINE INTERFACE
+ */
+
+/**
+ **************************************************************************
+ * structure VideoEditorMp3Reader_Context
+ * @brief This structure defines the context of the SF MP3 reader shell.
+ **************************************************************************
+ */
+typedef struct {
+ sp<DataSource> mDataSource;
+ sp<MediaExtractor> mExtractor;
+ sp<MediaSource> mMediaSource;
+ M4_AudioStreamHandler* mAudioStreamHandler;
+ M4SYS_AccessUnit mAudioAu;
+ M4OSA_Time mMaxDuration;
+ M4OSA_UInt8 mStreamNumber;
+ M4OSA_Bool mSeeking;
+ M4OSA_Time mSeekTime;
+ uint32_t mExtractorFlags;
+} VideoEditorMp3Reader_Context;
+
+/**
+ ****************************************************************************
+ * @brief create an instance of the MP3 reader
+ * @note allocates the context
+ *
+ * @param pContext: (OUT) pointer on a reader context
+ *
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_ALLOC a memory allocation has failed
+ * @return M4ERR_PARAMETER at least one parameter is not valid
+ ****************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_create(M4OSA_Context *pContext) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorMp3Reader_Context *pReaderContext = M4OSA_NULL;
+
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ LOGV("VideoEditorMp3Reader_create begin");
+
+ /* Context allocation & initialization */
+ SAFE_MALLOC(pReaderContext, VideoEditorMp3Reader_Context, 1,
+ "VideoEditorMp3Reader");
+
+ pReaderContext->mAudioStreamHandler = M4OSA_NULL;
+ pReaderContext->mAudioAu.dataAddress = M4OSA_NULL;
+ M4OSA_INT64_FROM_INT32(pReaderContext->mMaxDuration, 0);
+ *pContext = pReaderContext;
+
+cleanUp:
+ if (M4NO_ERROR == err) {
+ LOGV("VideoEditorMp3Reader_create no error");
+ } else {
+ LOGV("VideoEditorMp3Reader_create ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorMp3Reader_create end");
+ return err;
+}
+
+/**
+ *******************************************************************************
+ * @brief destroy the instance of the MP3 reader
+ * @note after this call the context is invalid
+ * @param context: (IN) Context of the reader
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_PARAMETER The input parameter is not properly set
+ *******************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_destroy(M4OSA_Context pContext) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorMp3Reader_Context *pReaderContext =
+ (VideoEditorMp3Reader_Context*)pContext;
+
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pReaderContext, M4ERR_PARAMETER);
+ LOGV("VideoEditorMp3Reader_destroy begin");
+
+ SAFE_FREE(pReaderContext);
+cleanUp:
+ if (M4NO_ERROR == err) {
+ LOGV("VideoEditorMp3Reader_destroy no error");
+ } else {
+ LOGV("VideoEditorMp3Reader_destroy ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorMp3Reader_destroy end");
+ return err;
+}
+/**
+ ******************************************************************************
+ * @brief open the reader and initializes its created instance
+ * @note this function opens the MP3 file
+ * @param context: (IN) Context of the reader
+ * @param pFileDescriptor: (IN) Pointer to proprietary data identifying
+ * the media to open
+
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_PARAMETER the context is NULL
+ * @return M4ERR_BAD_CONTEXT provided context is not a valid one
+ ******************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_open(M4OSA_Context context,
+ M4OSA_Void* pFileDescriptor){
+ VideoEditorMp3Reader_Context *pReaderContext =
+ (VideoEditorMp3Reader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+
+ LOGV("VideoEditorMp3Reader_open begin");
+ /* Check function parameters*/
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pReaderContext), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_open: invalid context pointer");
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pFileDescriptor), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_open: invalid pointer pFileDescriptor");
+
+ LOGV("VideoEditorMp3Reader_open Datasource start %s",
+ (char*)pFileDescriptor);
+ pReaderContext->mDataSource = DataSource::CreateFromURI(
+ (char*)pFileDescriptor);
+ LOGV("VideoEditorMp3Reader_open Datasource end");
+
+ if (pReaderContext->mDataSource == NULL) {
+ LOGV("VideoEditorMp3Reader_open Datasource error");
+ return UNKNOWN_ERROR;
+ }
+
+ LOGV("VideoEditorMp3Reader_open extractor start");
+ pReaderContext->mExtractor = MediaExtractor::Create(
+ pReaderContext->mDataSource,MEDIA_MIMETYPE_AUDIO_MPEG);
+ LOGV("VideoEditorMp3Reader_open extractor end");
+
+ if (pReaderContext->mExtractor == NULL) {
+ LOGV("VideoEditorMp3Reader_open extractor error");
+ return UNKNOWN_ERROR;
+ }
+ pReaderContext->mStreamNumber = 0;
+
+ LOGV("VideoEditorMp3Reader_open end");
+ return err;
+}
+/**
+ **************************************************************************
+ * @brief close the reader
+ * @note this function closes the MP3 reader
+ * @param context: (IN) Context of the reader
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_PARAMETER the context is NULL
+ **************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_close(M4OSA_Context context) {
+ VideoEditorMp3Reader_Context *pReaderContext =
+ (VideoEditorMp3Reader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+
+ LOGV("VideoEditorMp3Reader_close begin");
+ /* Check function parameters */
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pReaderContext), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_close: invalid context pointer");
+
+ if (pReaderContext->mAudioStreamHandler != NULL) {
+ if (M4OSA_NULL != pReaderContext->mAudioStreamHandler->\
+ m_basicProperties.m_pDecoderSpecificInfo) {
+ M4OSA_free((M4OSA_MemAddr32)pReaderContext->mAudioStreamHandler->\
+ m_basicProperties.m_pDecoderSpecificInfo);
+ pReaderContext->mAudioStreamHandler->m_basicProperties.\
+ m_decoderSpecificInfoSize = 0;
+ pReaderContext->mAudioStreamHandler->m_basicProperties.\
+ m_pDecoderSpecificInfo = M4OSA_NULL;
+ }
+
+ /* Finally destroy the stream handler */
+ M4OSA_free((M4OSA_MemAddr32)pReaderContext->mAudioStreamHandler);
+ pReaderContext->mAudioStreamHandler = M4OSA_NULL;
+
+ if (pReaderContext->mAudioAu.dataAddress != NULL) {
+ M4OSA_free((M4OSA_MemAddr32)pReaderContext->mAudioAu.dataAddress);
+ pReaderContext->mAudioAu.dataAddress = NULL;
+ }
+ }
+
+ pReaderContext->mMediaSource->stop();
+ pReaderContext->mMediaSource.clear();
+ pReaderContext->mDataSource.clear();
+
+ LOGV("VideoEditorMp3Reader_close end ");
+ return err;
+}
+/**
+ ******************************************************************************
+ * @brief get an option value from the reader
+ * @note
+ * it allows the caller to retrieve a property value:
+ *
+ * @param context: (IN) Context of the reader
+ * @param optionId: (IN) indicates the option to get
+ * @param pValue: (OUT) pointer to structure or value (allocated
+ * by user) where option is stored
+ *
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_PARAMETER at least one parameter is not properly set
+ * @return M4ERR_BAD_OPTION_ID when the option ID is not a valid one
+ ******************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_getOption(M4OSA_Context context,
+ M4OSA_OptionID optionId, M4OSA_DataOption pValue) {
+ VideoEditorMp3Reader_Context *pReaderContext =
+ (VideoEditorMp3Reader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+
+ LOGV("VideoEditorMp3Reader_getOption begin: optionId= %d ",(int)optionId);
+
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pReaderContext), M4ERR_PARAMETER,
+ "invalid value pointer");
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pValue), M4ERR_PARAMETER,
+ "invalid value pointer");
+
+ switch(optionId) {
+ case M4READER_kOptionID_Duration:
+ {
+ LOGV("Mp3Reader duration=%ld",pReaderContext->mMaxDuration);
+ M4OSA_TIME_SET(*(M4OSA_Time*)pValue, pReaderContext->mMaxDuration);
+ }
+ break;
+
+ case M4READER_kOptionID_Bitrate:
+ {
+ M4OSA_UInt32* pBitrate = (M4OSA_UInt32*)pValue;
+ if (M4OSA_NULL != pReaderContext->mAudioStreamHandler) {
+ *pBitrate = pReaderContext->mAudioStreamHandler->\
+ m_basicProperties.m_averageBitRate;
+ } else {
+ pBitrate = 0;
+ err = M4ERR_PARAMETER;
+ }
+ }
+ break;
+
+ case M4READER_kOptionID_Mp3Id3v1Tag:
+ break;
+
+ case M4READER_kOptionID_Mp3Id3v2Tag:
+ break;
+
+ case M4READER_kOptionID_GetMetadata:
+ break;
+
+ default :
+ {
+ LOGV("VideoEditorMp3Reader_getOption: M4ERR_BAD_OPTION_ID");
+ err = M4ERR_BAD_OPTION_ID;
+ }
+ }
+ LOGV("VideoEditorMp3Reader_getOption end ");
+ return err;
+}
+/**
+ ******************************************************************************
+ * @brief set an option value of the reader
+ * @note
+ * it allows the caller to set a property value:
+ *
+ * @param context: (IN) Context of the reader
+ * @param optionId: (IN) Identifier indicating the option to set
+ * @param pValue: (IN) Pointer to structure or value (allocated
+ * by user) where option is stored
+ *
+ * @return M4NO_ERROR There is no error
+ * @return M4ERR_BAD_OPTION_ID The option ID is not a valid one
+ * @return M4ERR_STATE State automaton is not applied
+ * @return M4ERR_PARAMETER The option parameter is invalid
+ ******************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_setOption(M4OSA_Context context,
+ M4OSA_OptionID optionId, M4OSA_DataOption pValue) {
+ VideoEditorMp3Reader_Context *pReaderContext =
+ (VideoEditorMp3Reader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+
+ LOGV("VideoEditorMp3Reader_Context begin: optionId: %d Value: %d ",
+ (int)optionId,(int)pValue);
+
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pReaderContext), M4ERR_PARAMETER,
+ "invalid context pointer");
+ M4OSA_DEBUG_IF1((M4OSA_NULL == pValue), M4ERR_PARAMETER,
+ "invalid value pointer");
+
+ switch(optionId) {
+ case M4READER_kOptionID_SetOsaFileReaderFctsPtr:
+ default :
+ {
+ err = M4NO_ERROR;
+ }
+ }
+ LOGV("VideoEditorMp3Reader_Context end ");
+ return err;
+}
+/**
+ ******************************************************************************
+ * @brief jump into the stream at the specified time
+ * @note
+ * @param context: (IN) Context of the reader
+ * @param pStreamHandler(IN) stream description of the stream to make jump
+ * @param pTime (I/O)IN:the time to jump to (in ms)
+ * OUT: the time to which the stream really jumped
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_PARAMETER at least one parameter is not properly set
+ ******************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_jump(M4OSA_Context context,
+ M4_StreamHandler *pStreamHandler, M4OSA_Int32* pTime) {
+ VideoEditorMp3Reader_Context *pReaderContext =
+ (VideoEditorMp3Reader_Context*)context;
+ M4SYS_StreamID streamIdArray[2];
+ M4OSA_ERR err = M4NO_ERROR;
+ M4SYS_AccessUnit* pAu;
+ M4OSA_Time time64;
+ M4OSA_Double timeDouble;
+
+ LOGV("VideoEditorMp3Reader_jump begin");
+ M4OSA_DEBUG_IF1((pReaderContext == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_jump: invalid context");
+ M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_jump: invalid pointer to M4_StreamHandler");
+ M4OSA_DEBUG_IF1((pTime == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_jump: invalid time pointer");
+
+ M4OSA_INT64_FROM_INT32(time64, *pTime);
+
+ if(pStreamHandler == (M4_StreamHandler*)pReaderContext->\
+ mAudioStreamHandler){
+ pAu = &pReaderContext->mAudioAu;
+ } else {
+ LOGV("VideoEditorMp3Reader_jump: passed StreamHandler is not known");
+ return M4ERR_PARAMETER;
+ }
+
+ streamIdArray[0] = pStreamHandler->m_streamId;
+ streamIdArray[1] = 0;
+
+ LOGV("VideoEditorMp3Reader_jump time ms %ld ", time64);
+
+ pAu->CTS = time64;
+ pAu->DTS = time64;
+
+ time64 = time64 * 1000; /* Convert the time into micro sec */
+ LOGV("VideoEditorMp3Reader_jump time us %ld ", time64);
+
+ pReaderContext->mSeeking = M4OSA_TRUE;
+ pReaderContext->mSeekTime = time64;
+
+ time64 = time64 / 1000; /* Convert the time into milli sec */
+ M4OSA_INT64_TO_DOUBLE(timeDouble, time64);
+ *pTime = (M4OSA_Int32)timeDouble;
+ LOGV("VideoEditorMp3Reader_jump end ");
+ return err;
+}
+/**
+ *******************************************************************************
+ * @brief Get the next stream found in the media file
+ *
+ * @param context: (IN) Context of the reader
+ * @param pMediaFamily: (OUT) pointer to a user allocated
+ * M4READER_MediaFamily that will be filled with
+ * the media family of the found stream
+ * @param pStreamHandler: (OUT) pointer to a stream handler that will be
+ * allocated and filled with stream description
+ *
+ * @return M4NO_ERROR there is no error
+ * @return M4WAR_NO_MORE_STREAM no more available stream in the media
+ * @return M4ERR_PARAMETER at least one parameter is not properly set
+ *******************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_getNextStream(M4OSA_Context context,
+ M4READER_MediaFamily *pMediaFamily,
+ M4_StreamHandler **pStreamHandlerParam) {
+ VideoEditorMp3Reader_Context *pReaderContext =
+ (VideoEditorMp3Reader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+ M4SYS_StreamID streamIdArray[2];
+ M4SYS_StreamDescription streamDesc;
+ M4_AudioStreamHandler* pAudioStreamHandler;
+ M4_StreamHandler* pStreamHandler;
+ M4OSA_UInt8 type, temp;
+ M4OSA_Bool haveAudio = M4OSA_FALSE;
+ sp<MetaData> meta = NULL;
+ int64_t Duration;
+
+ LOGV("VideoEditorMp3Reader_getNextStream begin");
+ M4OSA_DEBUG_IF1((pReaderContext == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_getNextStream: invalid context");
+ M4OSA_DEBUG_IF1((pMediaFamily == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_getNextStream: invalid pointer to MediaFamily");
+ M4OSA_DEBUG_IF1((pStreamHandlerParam == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_getNextStream: invalid pointer to StreamHandler");
+
+ LOGV("VideoEditorMp3Reader_getNextStream stream number = %d",
+ pReaderContext->mStreamNumber);
+ if (pReaderContext->mStreamNumber >= 1) {
+ LOGV("VideoEditorMp3Reader_getNextStream max number of stream reached");
+ return M4WAR_NO_MORE_STREAM;
+ }
+ pReaderContext->mStreamNumber = pReaderContext->mStreamNumber + 1;
+ LOGV("VideoEditorMp3Reader_getNextStream number of Tracks%d",
+ pReaderContext->mExtractor->countTracks());
+ for (temp = 0; temp < pReaderContext->mExtractor->countTracks(); temp++) {
+ meta = pReaderContext->mExtractor->getTrackMetaData(temp);
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
+ pReaderContext->mMediaSource =
+ pReaderContext->mExtractor->getTrack(temp);
+ pReaderContext->mMediaSource->start();
+ haveAudio = true;
+ }
+
+ if (haveAudio) {
+ break;
+ }
+ }
+
+ if (!haveAudio) {
+ LOGV("VideoEditorMp3Reader_getNextStream no more stream ");
+ pReaderContext->mDataSource.clear();
+ return M4WAR_NO_MORE_STREAM;
+ }
+
+ pReaderContext->mExtractorFlags = pReaderContext->mExtractor->flags();
+ *pMediaFamily = M4READER_kMediaFamilyAudio;
+
+ streamDesc.duration = meta->findInt64(kKeyDuration, &Duration);
+ streamDesc.duration = (M4OSA_Time)Duration/1000;
+
+ meta->findInt32(kKeyBitRate, (int32_t*)&streamDesc.averageBitrate);
+ meta->findInt32(kKeySampleRate, (int32_t*)&streamDesc.timeScale);
+ LOGV("Bitrate = %d, SampleRate = %d duration = %lld",
+ streamDesc.averageBitrate,streamDesc.timeScale,Duration/1000);
+
+ streamDesc.streamType = M4SYS_kMP3;
+ streamDesc.profileLevel = 0xFF ;
+ streamDesc.streamID = pReaderContext->mStreamNumber;
+ streamDesc.decoderSpecificInfo = M4OSA_NULL;
+ streamDesc.decoderSpecificInfoSize = 0;
+ streamDesc.maxBitrate = streamDesc.averageBitrate;
+
+ /* Allocate the audio stream handler and set its parameters */
+ pAudioStreamHandler = (M4_AudioStreamHandler*)M4OSA_malloc(
+ sizeof(M4_AudioStreamHandler), M4READER_MP3,
+ (M4OSA_Char*)"M4_AudioStreamHandler");
+
+ if (pAudioStreamHandler == M4OSA_NULL) {
+ LOGV("VideoEditorMp3Reader_getNextStream malloc failed");
+ pReaderContext->mMediaSource->stop();
+ pReaderContext->mMediaSource.clear();
+ pReaderContext->mDataSource.clear();
+
+ return M4ERR_ALLOC;
+ }
+ pStreamHandler =(M4_StreamHandler*)(pAudioStreamHandler);
+ *pStreamHandlerParam = pStreamHandler;
+ pReaderContext->mAudioStreamHandler = pAudioStreamHandler;
+
+ pAudioStreamHandler->m_structSize = sizeof(M4_AudioStreamHandler);
+
+ if (meta == NULL) {
+ LOGV("VideoEditorMp3Reader_getNextStream meta is NULL");
+ }
+
+ pAudioStreamHandler->m_samplingFrequency = streamDesc.timeScale;
+ pStreamHandler->m_pDecoderSpecificInfo =
+ (M4OSA_UInt8*)(streamDesc.decoderSpecificInfo);
+ pStreamHandler->m_decoderSpecificInfoSize =
+ streamDesc.decoderSpecificInfoSize;
+
+ meta->findInt32(kKeyChannelCount,
+ (int32_t*)&pAudioStreamHandler->m_nbChannels);
+ pAudioStreamHandler->m_byteFrameLength = 1152;
+ pAudioStreamHandler->m_byteSampleSize = 2;
+
+ pStreamHandler->m_pUserData = NULL;
+ pStreamHandler->m_streamId = streamDesc.streamID;
+ pStreamHandler->m_duration = streamDesc.duration;
+ pReaderContext->mMaxDuration = streamDesc.duration;
+ pStreamHandler->m_averageBitRate = streamDesc.averageBitrate;
+
+ pStreamHandler->m_maxAUSize = 0;
+ pStreamHandler->m_streamType = M4DA_StreamTypeAudioMp3;
+
+ LOGV("VideoEditorMp3Reader_getNextStream end ");
+ return err;
+}
+
+/**
+ *******************************************************************************
+ * @brief fill the access unit structure with initialization values
+ * @param context: (IN) Context of the reader
+ * @param pStreamHandler: (IN) pointer to the stream handler to which
+ * the access unit will be associated
+ * @param pAccessUnit: (IN/OUT) pointer to the access unit (allocated by
+ * the caller) to initialize
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_PARAMETER at least one parameter is not properly set
+ *******************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_fillAuStruct(M4OSA_Context context,
+ M4_StreamHandler *pStreamHandler, M4_AccessUnit *pAccessUnit) {
+ VideoEditorMp3Reader_Context *pReaderContext =
+ (VideoEditorMp3Reader_Context*)context;
+ M4SYS_AccessUnit *pAu;
+
+ M4OSA_DEBUG_IF1((pReaderContext == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_fillAuStruct: invalid context");
+ M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_fillAuStruct invalid pointer to StreamHandler");
+ M4OSA_DEBUG_IF1((pAccessUnit == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_fillAuStruct: invalid pointer to M4_AccessUnit");
+
+ LOGV("VideoEditorMp3Reader_fillAuStruct start ");
+ if(pStreamHandler == (M4_StreamHandler*)pReaderContext->\
+ mAudioStreamHandler){
+ pAu = &pReaderContext->mAudioAu;
+ } else {
+ LOGV("VideoEditorMp3Reader_fillAuStruct StreamHandler is not known");
+ return M4ERR_PARAMETER;
+ }
+
+ /* Initialize pAu structure */
+ pAu->dataAddress = M4OSA_NULL;
+ pAu->size = 0;
+ pAu->CTS = 0;
+ pAu->DTS = 0;
+ pAu->attribute = 0;
+ pAu->nbFrag = 0;
+
+ /* Initialize pAccessUnit structure */
+ pAccessUnit->m_size = 0;
+ pAccessUnit->m_CTS = 0;
+ pAccessUnit->m_DTS = 0;
+ pAccessUnit->m_attribute = 0;
+ pAccessUnit->m_dataAddress = M4OSA_NULL;
+ pAccessUnit->m_maxsize = pStreamHandler->m_maxAUSize;
+ pAccessUnit->m_streamID = pStreamHandler->m_streamId;
+ pAccessUnit->m_structSize = sizeof(M4_AccessUnit);
+
+ LOGV("VideoEditorMp3Reader_fillAuStruct end");
+ return M4NO_ERROR;
+}
+
+/**
+ *******************************************************************************
+ * @brief reset the stream, i.e seek it to the beginning
+ * @note
+ * @param context: (IN) Context of the reader
+ * @param pStreamHandler (IN) The stream handler of the stream to reset
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_PARAMETER at least one parameter is not properly set
+ *******************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_reset(M4OSA_Context context,
+ M4_StreamHandler *pStreamHandler) {
+ VideoEditorMp3Reader_Context *pReaderContext =
+ (VideoEditorMp3Reader_Context*)context;
+
+ M4OSA_ERR err = M4NO_ERROR;
+ M4SYS_StreamID streamIdArray[2];
+ M4SYS_AccessUnit* pAu;
+ M4OSA_Time time64;
+
+ LOGV("VideoEditorMp3Reader_reset start");
+ M4OSA_DEBUG_IF1((pReaderContext == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_reset: invalid context");
+ M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_reset: invalid pointer to M4_StreamHandler");
+
+ M4OSA_INT64_FROM_INT32(time64, 0);
+
+ if (pStreamHandler == (M4_StreamHandler*)pReaderContext->\
+ mAudioStreamHandler) {
+ pAu = &pReaderContext->mAudioAu;
+ } else {
+ LOGV("VideoEditorMp3Reader_reset StreamHandler is not known");
+ return M4ERR_PARAMETER;
+ }
+ streamIdArray[0] = pStreamHandler->m_streamId;
+ streamIdArray[1] = 0;
+ pAu->CTS = time64;
+ pAu->DTS = time64;
+
+ pReaderContext->mSeeking = M4OSA_TRUE;
+ pReaderContext->mSeekTime = time64;
+
+ LOGV("VideoEditorMp3Reader_reset end");
+ return err;
+}
+/**
+ *******************************************************************************
+ * @brief Gets an access unit (AU) from the stream handler source.
+ * @note AU is the smallest possible amount of data to be decoded by decoder
+ *
+ * @param context: (IN) Context of the reader
+ * @param pStreamHandler (IN) The stream handler of the stream to make jump
+ * @param pAccessUnit (I/O)Pointer to an access unit to fill with read data
+ * @return M4NO_ERROR there is no error
+ * @return M4ERR_PARAMETER at least one parameter is not properly set
+ * @returns M4ERR_ALLOC memory allocation failed
+ * @returns M4WAR_NO_MORE_AU there are no more access unit in the stream
+ *******************************************************************************
+*/
+M4OSA_ERR VideoEditorMp3Reader_getNextAu(M4OSA_Context context,
+ M4_StreamHandler *pStreamHandler, M4_AccessUnit *pAccessUnit) {
+ VideoEditorMp3Reader_Context *pReaderContext =
+ (VideoEditorMp3Reader_Context*)context;
+ M4OSA_ERR err = M4NO_ERROR;
+ M4SYS_AccessUnit* pAu;
+ MediaBuffer *mAudioBuffer;
+ MediaSource::ReadOptions options;
+
+ LOGV("VideoEditorMp3Reader_getNextAu start");
+ M4OSA_DEBUG_IF1((pReaderContext == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_getNextAu: invalid context");
+ M4OSA_DEBUG_IF1((pStreamHandler == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_getNextAu: invalid pointer to M4_StreamHandler");
+ M4OSA_DEBUG_IF1((pAccessUnit == 0), M4ERR_PARAMETER,
+ "VideoEditorMp3Reader_getNextAu: invalid pointer to M4_AccessUnit");
+
+ if (pStreamHandler == (M4_StreamHandler*)pReaderContext->\
+ mAudioStreamHandler) {
+ pAu = &pReaderContext->mAudioAu;
+ } else {
+ LOGV("VideoEditorMp3Reader_getNextAu: StreamHandler is not known\n");
+ return M4ERR_PARAMETER;
+ }
+
+ if (pReaderContext->mSeeking) {
+ options.setSeekTo(pReaderContext->mSeekTime);
+ }
+
+ pReaderContext->mMediaSource->read(&mAudioBuffer, &options);
+
+ if (mAudioBuffer != NULL) {
+ if ((pAu->dataAddress == NULL) ||
+ (pAu->size < mAudioBuffer->range_length())) {
+ if (pAu->dataAddress != NULL) {
+ M4OSA_free((M4OSA_Int32*)pAu->dataAddress);
+ pAu->dataAddress = NULL;
+ }
+ pAu->dataAddress = (M4OSA_Int32*)M4OSA_malloc(
+ (mAudioBuffer->range_length() + 3) & ~0x3,
+ M4READER_MP3, (M4OSA_Char*)"pAccessUnit->m_dataAddress" );
+
+ if (pAu->dataAddress == NULL) {
+ LOGV("VideoEditorMp3Reader_getNextAu malloc failed");
+ pReaderContext->mMediaSource->stop();
+ pReaderContext->mMediaSource.clear();
+ pReaderContext->mDataSource.clear();
+
+ return M4ERR_ALLOC;
+ }
+ }
+ pAu->size = mAudioBuffer->range_length();
+ memcpy((M4OSA_MemAddr8)pAu->dataAddress,
+ (const char *)mAudioBuffer->data() + mAudioBuffer->range_offset(),
+ mAudioBuffer->range_length());
+
+ mAudioBuffer->meta_data()->findInt64(kKeyTime, (int64_t*)&pAu->CTS);
+
+
+ pAu->CTS = pAu->CTS / 1000; /*converting the microsec to millisec */
+ pAu->DTS = pAu->CTS;
+ pAu->attribute = M4SYS_kFragAttrOk;
+ mAudioBuffer->release();
+
+ LOGV("VideoEditorMp3Reader_getNextAu AU CTS = %ld",pAu->CTS);
+
+ pAccessUnit->m_dataAddress = (M4OSA_Int8*) pAu->dataAddress;
+ pAccessUnit->m_size = pAu->size;
+ pAccessUnit->m_CTS = pAu->CTS;
+ pAccessUnit->m_DTS = pAu->DTS;
+ pAccessUnit->m_attribute = pAu->attribute;
+ } else {
+ LOGV("VideoEditorMp3Reader_getNextAu EOS reached.");
+ pAccessUnit->m_size=0;
+ err = M4WAR_NO_MORE_AU;
+ }
+ pAu->nbFrag = 0;
+
+ options.clearSeekTo();
+ pReaderContext->mSeeking = M4OSA_FALSE;
+ mAudioBuffer = NULL;
+ LOGV("VideoEditorMp3Reader_getNextAu end");
+
+ return err;
+}
+
+extern "C" {
+
+M4OSA_ERR VideoEditorMp3Reader_getInterface(
+ M4READER_MediaType *pMediaType,
+ M4READER_GlobalInterface **pRdrGlobalInterface,
+ M4READER_DataInterface **pRdrDataInterface) {
+ M4OSA_ERR err = M4NO_ERROR;
+
+ LOGV("VideoEditorMp3Reader_getInterface: begin");
+ /* Input parameters check */
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pMediaType, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pRdrGlobalInterface, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pRdrDataInterface, M4ERR_PARAMETER);
+
+ SAFE_MALLOC(*pRdrGlobalInterface, M4READER_GlobalInterface, 1,
+ "VideoEditorMp3Reader_getInterface");
+ SAFE_MALLOC(*pRdrDataInterface, M4READER_DataInterface, 1,
+ "VideoEditorMp3Reader_getInterface");
+
+ *pMediaType = M4READER_kMediaTypeMP3;
+
+ (*pRdrGlobalInterface)->m_pFctCreate = VideoEditorMp3Reader_create;
+ (*pRdrGlobalInterface)->m_pFctDestroy = VideoEditorMp3Reader_destroy;
+ (*pRdrGlobalInterface)->m_pFctOpen = VideoEditorMp3Reader_open;
+ (*pRdrGlobalInterface)->m_pFctClose = VideoEditorMp3Reader_close;
+ (*pRdrGlobalInterface)->m_pFctGetOption = VideoEditorMp3Reader_getOption;
+ (*pRdrGlobalInterface)->m_pFctSetOption = VideoEditorMp3Reader_setOption;
+ (*pRdrGlobalInterface)->m_pFctGetNextStream =
+ VideoEditorMp3Reader_getNextStream;
+ (*pRdrGlobalInterface)->m_pFctFillAuStruct =
+ VideoEditorMp3Reader_fillAuStruct;
+ (*pRdrGlobalInterface)->m_pFctStart = M4OSA_NULL;
+ (*pRdrGlobalInterface)->m_pFctStop = M4OSA_NULL;
+ (*pRdrGlobalInterface)->m_pFctJump = VideoEditorMp3Reader_jump;
+ (*pRdrGlobalInterface)->m_pFctReset = VideoEditorMp3Reader_reset;
+ (*pRdrGlobalInterface)->m_pFctGetPrevRapTime = M4OSA_NULL;
+
+ (*pRdrDataInterface)->m_pFctGetNextAu = VideoEditorMp3Reader_getNextAu;
+ (*pRdrDataInterface)->m_readerContext = M4OSA_NULL;
+
+cleanUp:
+ if( M4NO_ERROR == err )
+ {
+ LOGV("VideoEditorMp3Reader_getInterface no error");
+ }
+ else
+ {
+ SAFE_FREE(*pRdrGlobalInterface);
+ SAFE_FREE(*pRdrDataInterface);
+
+ LOGV("VideoEditorMp3Reader_getInterface ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorMp3Reader_getInterface: end");
+ return err;
+}
+} /* extern "C" */
+} /* namespace android */
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorUtils.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorUtils.cpp
new file mode 100755
index 0000000..733c5d6
--- /dev/null
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorUtils.cpp
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2011 NXP Software
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+*************************************************************************
+* @file VideoEditorUtils.cpp
+* @brief StageFright shell Utilities
+*************************************************************************
+*/
+#define LOG_NDEBUG 0
+#define LOG_TAG "SF_utils"
+#include "utils/Log.h"
+
+#include "VideoEditorUtils.h"
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXCodec.h>
+
+/* Android includes*/
+#include <utils/Log.h>
+#include <memory.h>
+
+/*---------------------*/
+/* DEBUG LEVEL SETUP */
+/*---------------------*/
+#define LOG1 LOGE /*ERRORS Logging*/
+#define LOG2 LOGI /*WARNING Logging*/
+#define LOG3 //LOGV /*COMMENTS Logging*/
+
+namespace android {
+
+void displayMetaData(const sp<MetaData> meta) {
+
+ const char* charData;
+ int32_t int32Data;
+ int64_t int64Data;
+ uint32_t type;
+ const void* data;
+ void* ptr;
+ size_t size;
+
+ if (meta->findCString(kKeyMIMEType, &charData)) {
+ LOG1("displayMetaData kKeyMIMEType %s", charData);
+ }
+ if (meta->findInt32(kKeyWidth, &int32Data)) {
+ LOG1("displayMetaData kKeyWidth %d", int32Data);
+ }
+ if (meta->findInt32(kKeyHeight, &int32Data)) {
+ LOG1("displayMetaData kKeyHeight %d", int32Data);
+ }
+ if (meta->findInt32(kKeyIFramesInterval, &int32Data)) {
+ LOG1("displayMetaData kKeyIFramesInterval %d", int32Data);
+ }
+ if (meta->findInt32(kKeyStride, &int32Data)) {
+ LOG1("displayMetaData kKeyStride %d", int32Data);
+ }
+ if (meta->findInt32(kKeySliceHeight, &int32Data)) {
+ LOG1("displayMetaData kKeySliceHeight %d", int32Data);
+ }
+ if (meta->findInt32(kKeyChannelCount, &int32Data)) {
+ LOG1("displayMetaData kKeyChannelCount %d", int32Data);
+ }
+ if (meta->findInt32(kKeySampleRate, &int32Data)) {
+ LOG1("displayMetaData kKeySampleRate %d", int32Data);
+ }
+ if (meta->findInt32(kKeyBitRate, &int32Data)) {
+ LOG1("displayMetaData kKeyBitRate %d", int32Data);
+ }
+ if (meta->findData(kKeyESDS, &type, &data, &size)) {
+ LOG1("displayMetaData kKeyESDS type=%d size=%d", type, size);
+ }
+ if (meta->findData(kKeyAVCC, &type, &data, &size)) {
+ LOG1("displayMetaData kKeyAVCC data=0x%X type=%d size=%d",
+ *((unsigned int*)data), type, size);
+ }
+ if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
+ LOG1("displayMetaData kKeyVorbisInfo type=%d size=%d", type, size);
+ }
+ if (meta->findData(kKeyVorbisBooks, &type, &data, &size)) {
+ LOG1("displayMetaData kKeyVorbisBooks type=%d size=%d", type, size);
+ }
+ if (meta->findInt32(kKeyWantsNALFragments, &int32Data)) {
+ LOG1("displayMetaData kKeyWantsNALFragments %d", int32Data);
+ }
+ if (meta->findInt32(kKeyIsSyncFrame, &int32Data)) {
+ LOG1("displayMetaData kKeyIsSyncFrame %d", int32Data);
+ }
+ if (meta->findInt32(kKeyIsCodecConfig, &int32Data)) {
+ LOG1("displayMetaData kKeyIsCodecConfig %d", int32Data);
+ }
+ if (meta->findInt64(kKeyTime, &int64Data)) {
+ LOG1("displayMetaData kKeyTime %lld", int64Data);
+ }
+ if (meta->findInt32(kKeyDuration, &int32Data)) {
+ LOG1("displayMetaData kKeyDuration %d", int32Data);
+ }
+ if (meta->findInt32(kKeyColorFormat, &int32Data)) {
+ LOG1("displayMetaData kKeyColorFormat %d", int32Data);
+ }
+ if (meta->findPointer(kKeyPlatformPrivate, &ptr)) {
+ LOG1("displayMetaData kKeyPlatformPrivate pointer=0x%x", (int32_t) ptr);
+ }
+ if (meta->findCString(kKeyDecoderComponent, &charData)) {
+ LOG1("displayMetaData kKeyDecoderComponent %s", charData);
+ }
+ if (meta->findInt32(kKeyBufferID, &int32Data)) {
+ LOG1("displayMetaData kKeyBufferID %d", int32Data);
+ }
+ if (meta->findInt32(kKeyMaxInputSize, &int32Data)) {
+ LOG1("displayMetaData kKeyMaxInputSize %d", int32Data);
+ }
+ if (meta->findInt64(kKeyThumbnailTime, &int64Data)) {
+ LOG1("displayMetaData kKeyThumbnailTime %lld", int64Data);
+ }
+ if (meta->findCString(kKeyAlbum, &charData)) {
+ LOG1("displayMetaData kKeyAlbum %s", charData);
+ }
+ if (meta->findCString(kKeyArtist, &charData)) {
+ LOG1("displayMetaData kKeyArtist %s", charData);
+ }
+ if (meta->findCString(kKeyAlbumArtist, &charData)) {
+ LOG1("displayMetaData kKeyAlbumArtist %s", charData);
+ }
+ if (meta->findCString(kKeyComposer, &charData)) {
+ LOG1("displayMetaData kKeyComposer %s", charData);
+ }
+ if (meta->findCString(kKeyGenre, &charData)) {
+ LOG1("displayMetaData kKeyGenre %s", charData);
+ }
+ if (meta->findCString(kKeyTitle, &charData)) {
+ LOG1("displayMetaData kKeyTitle %s", charData);
+ }
+ if (meta->findCString(kKeyYear, &charData)) {
+ LOG1("displayMetaData kKeyYear %s", charData);
+ }
+ if (meta->findData(kKeyAlbumArt, &type, &data, &size)) {
+ LOG1("displayMetaData kKeyAlbumArt type=%d size=%d", type, size);
+ }
+ if (meta->findCString(kKeyAlbumArtMIME, &charData)) {
+ LOG1("displayMetaData kKeyAlbumArtMIME %s", charData);
+ }
+ if (meta->findCString(kKeyAuthor, &charData)) {
+ LOG1("displayMetaData kKeyAuthor %s", charData);
+ }
+ if (meta->findCString(kKeyCDTrackNumber, &charData)) {
+ LOG1("displayMetaData kKeyCDTrackNumber %s", charData);
+ }
+ if (meta->findCString(kKeyDiscNumber, &charData)) {
+ LOG1("displayMetaData kKeyDiscNumber %s", charData);
+ }
+ if (meta->findCString(kKeyDate, &charData)) {
+ LOG1("displayMetaData kKeyDate %s", charData);
+ }
+ if (meta->findCString(kKeyWriter, &charData)) {
+ LOG1("displayMetaData kKeyWriter %s", charData);
+ }
+ if (meta->findInt32(kKeyTimeScale, &int32Data)) {
+ LOG1("displayMetaData kKeyTimeScale %d", int32Data);
+ }
+ if (meta->findInt32(kKeyVideoProfile, &int32Data)) {
+ LOG1("displayMetaData kKeyVideoProfile %d", int32Data);
+ }
+ if (meta->findInt32(kKeyVideoLevel, &int32Data)) {
+ LOG1("displayMetaData kKeyVideoLevel %d", int32Data);
+ }
+ if (meta->findInt32(kKey64BitFileOffset, &int32Data)) {
+ LOG1("displayMetaData kKey64BitFileOffset %d", int32Data);
+ }
+ if (meta->findInt32(kKeyFileType, &int32Data)) {
+ LOG1("displayMetaData kKeyFileType %d", int32Data);
+ }
+ if (meta->findInt64(kKeyTrackTimeStatus, &int64Data)) {
+ LOG1("displayMetaData kKeyTrackTimeStatus %lld", int64Data);
+ }
+ if (meta->findInt32(kKeyNotRealTime, &int32Data)) {
+ LOG1("displayMetaData kKeyNotRealTime %d", int32Data);
+ }
+}
+
+/**
+ * This code was extracted from StageFright MPEG4 writer
+ * Is is used to parse and format the AVC codec specific info received
+ * from StageFright encoders
+ */
+static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
+static const uint8_t kNalUnitTypePicParamSet = 0x08;
+struct AVCParamSet {
+ AVCParamSet(uint16_t length, const uint8_t *data)
+ : mLength(length), mData(data) {}
+
+ uint16_t mLength;
+ const uint8_t *mData;
+};
+struct AVCCodecSpecificContext {
+ List<AVCParamSet> mSeqParamSets;
+ List<AVCParamSet> mPicParamSets;
+ uint8_t mProfileIdc;
+ uint8_t mProfileCompatible;
+ uint8_t mLevelIdc;
+};
+
+const uint8_t *parseParamSet(AVCCodecSpecificContext* pC,
+ const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
+ CHECK(type == kNalUnitTypeSeqParamSet ||
+ type == kNalUnitTypePicParamSet);
+
+ size_t bytesLeft = length;
+ while (bytesLeft > 4 &&
+ memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
+ --bytesLeft;
+ }
+ if (bytesLeft <= 4) {
+ bytesLeft = 0; // Last parameter set
+ }
+ const uint8_t *nextStartCode = &data[length - bytesLeft];
+ *paramSetLen = nextStartCode - data;
+ if (*paramSetLen == 0) {
+ LOGE("Param set is malformed, since its length is 0");
+ return NULL;
+ }
+
+ AVCParamSet paramSet(*paramSetLen, data);
+ if (type == kNalUnitTypeSeqParamSet) {
+ if (*paramSetLen < 4) {
+ LOGE("Seq parameter set malformed");
+ return NULL;
+ }
+ if (pC->mSeqParamSets.empty()) {
+ pC->mProfileIdc = data[1];
+ pC->mProfileCompatible = data[2];
+ pC->mLevelIdc = data[3];
+ } else {
+ if (pC->mProfileIdc != data[1] ||
+ pC->mProfileCompatible != data[2] ||
+ pC->mLevelIdc != data[3]) {
+ LOGV("Inconsistent profile/level found in seq parameter sets");
+ return NULL;
+ }
+ }
+ pC->mSeqParamSets.push_back(paramSet);
+ } else {
+ pC->mPicParamSets.push_back(paramSet);
+ }
+ return nextStartCode;
+}
+
+status_t buildAVCCodecSpecificData(uint8_t **pOutputData, size_t *pOutputSize,
+ const uint8_t *data, size_t size, MetaData *param)
+{
+ //LOGV("buildAVCCodecSpecificData");
+
+ if ( (pOutputData == NULL) || (pOutputSize == NULL) ) {
+ LOGE("output is invalid");
+ return ERROR_MALFORMED;
+ }
+
+ if (*pOutputData != NULL) {
+ LOGE("Already have codec specific data");
+ return ERROR_MALFORMED;
+ }
+
+ if (size < 4) {
+ LOGE("Codec specific data length too short: %d", size);
+ return ERROR_MALFORMED;
+ }
+
+ // Data is in the form of AVCCodecSpecificData
+ if (memcmp("\x00\x00\x00\x01", data, 4)) {
+ // 2 bytes for each of the parameter set length field
+ // plus the 7 bytes for the header
+ if (size < 4 + 7) {
+ LOGE("Codec specific data length too short: %d", size);
+ return ERROR_MALFORMED;
+ }
+
+ *pOutputSize = size;
+ *pOutputData = (uint8_t*)malloc(size);
+ memcpy(*pOutputData, data, size);
+ return OK;
+ }
+
+ AVCCodecSpecificContext ctx;
+ uint8_t *outputData = NULL;
+ size_t outputSize = 0;
+
+ // Check if the data is valid
+ uint8_t type = kNalUnitTypeSeqParamSet;
+ bool gotSps = false;
+ bool gotPps = false;
+ const uint8_t *tmp = data;
+ const uint8_t *nextStartCode = data;
+ size_t bytesLeft = size;
+ size_t paramSetLen = 0;
+ outputSize = 0;
+ while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
+ type = (*(tmp + 4)) & 0x1F;
+ if (type == kNalUnitTypeSeqParamSet) {
+ if (gotPps) {
+ LOGE("SPS must come before PPS");
+ return ERROR_MALFORMED;
+ }
+ if (!gotSps) {
+ gotSps = true;
+ }
+ nextStartCode = parseParamSet(&ctx, tmp + 4, bytesLeft - 4, type,
+ &paramSetLen);
+ } else if (type == kNalUnitTypePicParamSet) {
+ if (!gotSps) {
+ LOGE("SPS must come before PPS");
+ return ERROR_MALFORMED;
+ }
+ if (!gotPps) {
+ gotPps = true;
+ }
+ nextStartCode = parseParamSet(&ctx, tmp + 4, bytesLeft - 4, type,
+ &paramSetLen);
+ } else {
+ LOGE("Only SPS and PPS Nal units are expected");
+ return ERROR_MALFORMED;
+ }
+
+ if (nextStartCode == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ // Move on to find the next parameter set
+ bytesLeft -= nextStartCode - tmp;
+ tmp = nextStartCode;
+ outputSize += (2 + paramSetLen);
+ }
+
+ {
+ // Check on the number of seq parameter sets
+ size_t nSeqParamSets = ctx.mSeqParamSets.size();
+ if (nSeqParamSets == 0) {
+ LOGE("Cound not find sequence parameter set");
+ return ERROR_MALFORMED;
+ }
+
+ if (nSeqParamSets > 0x1F) {
+ LOGE("Too many seq parameter sets (%d) found", nSeqParamSets);
+ return ERROR_MALFORMED;
+ }
+ }
+
+ {
+ // Check on the number of pic parameter sets
+ size_t nPicParamSets = ctx.mPicParamSets.size();
+ if (nPicParamSets == 0) {
+ LOGE("Cound not find picture parameter set");
+ return ERROR_MALFORMED;
+ }
+ if (nPicParamSets > 0xFF) {
+ LOGE("Too many pic parameter sets (%d) found", nPicParamSets);
+ return ERROR_MALFORMED;
+ }
+ }
+
+ {
+ // Check on the profiles
+ // These profiles requires additional parameter set extensions
+ if (ctx.mProfileIdc == 100 || ctx.mProfileIdc == 110 ||
+ ctx.mProfileIdc == 122 || ctx.mProfileIdc == 144) {
+ LOGE("Sorry, no support for profile_idc: %d!", ctx.mProfileIdc);
+ return BAD_VALUE;
+ }
+ }
+
+ // ISO 14496-15: AVC file format
+ outputSize += 7; // 7 more bytes in the header
+ outputData = (uint8_t *)malloc(outputSize);
+ uint8_t *header = outputData;
+ header[0] = 1; // version
+ header[1] = ctx.mProfileIdc; // profile indication
+ header[2] = ctx.mProfileCompatible; // profile compatibility
+ header[3] = ctx.mLevelIdc;
+
+ // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
+ int32_t use2ByteNalLength = 0;
+ if (param &&
+ param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
+ use2ByteNalLength) {
+ header[4] = 0xfc | 1; // length size == 2 bytes
+ } else {
+ header[4] = 0xfc | 3; // length size == 4 bytes
+ }
+
+ // 3-bit '111' followed by 5-bit numSequenceParameterSets
+ int nSequenceParamSets = ctx.mSeqParamSets.size();
+ header[5] = 0xe0 | nSequenceParamSets;
+ header += 6;
+ for (List<AVCParamSet>::iterator it = ctx.mSeqParamSets.begin();
+ it != ctx.mSeqParamSets.end(); ++it) {
+ // 16-bit sequence parameter set length
+ uint16_t seqParamSetLength = it->mLength;
+ header[0] = seqParamSetLength >> 8;
+ header[1] = seqParamSetLength & 0xff;
+ //LOGE("### SPS %d %d %d", seqParamSetLength, header[0], header[1]);
+
+ // SPS NAL unit (sequence parameter length bytes)
+ memcpy(&header[2], it->mData, seqParamSetLength);
+ header += (2 + seqParamSetLength);
+ }
+
+ // 8-bit nPictureParameterSets
+ int nPictureParamSets = ctx.mPicParamSets.size();
+ header[0] = nPictureParamSets;
+ header += 1;
+ for (List<AVCParamSet>::iterator it = ctx.mPicParamSets.begin();
+ it != ctx.mPicParamSets.end(); ++it) {
+ // 16-bit picture parameter set length
+ uint16_t picParamSetLength = it->mLength;
+ header[0] = picParamSetLength >> 8;
+ header[1] = picParamSetLength & 0xff;
+//LOGE("### PPS %d %d %d", picParamSetLength, header[0], header[1]);
+
+ // PPS Nal unit (picture parameter set length bytes)
+ memcpy(&header[2], it->mData, picParamSetLength);
+ header += (2 + picParamSetLength);
+ }
+
+ *pOutputSize = outputSize;
+ *pOutputData = outputData;
+ return OK;
+}
+}// namespace android
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
new file mode 100755
index 0000000..b362197
--- /dev/null
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
@@ -0,0 +1,1404 @@
+/*
+ * Copyright (C) 2011 NXP Software
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+*************************************************************************
+* @file VideoEditorVideoDecoder.cpp
+* @brief StageFright shell video decoder
+*************************************************************************
+*/
+#define LOG_NDEBUG 1
+#define LOG_TAG "VIDEOEDITOR_VIDEODECODER"
+
+/*******************
+ * HEADERS *
+ *******************/
+
+#include "VideoEditorVideoDecoder_internal.h"
+#include "VideoEditorUtils.h"
+#include "M4VD_Tools.h"
+
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaDefs.h>
+
+/********************
+ * DEFINITIONS *
+ ********************/
+#define OMX_QCOM_COLOR_FormatYVU420SemiPlanar 0x7FA30C00
+#define MAX_DEC_BUFFERS 10
+
+/********************
+ * SOURCE CLASS *
+ ********************/
+using namespace android;
+
+class VideoEditorVideoDecoderSource : public MediaSource {
+ public:
+ VideoEditorVideoDecoderSource(const sp<MetaData> &format,
+ VIDEOEDITOR_CodecType codecType, void *decoderShellContext);
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+ protected :
+ virtual ~VideoEditorVideoDecoderSource();
+
+ private:
+ sp<MetaData> mFormat;
+ MediaBuffer* mBuffer;
+ MediaBufferGroup* mGroup;
+ Mutex mLock;
+ VideoEditorVideoDecoder_Context* mpDecShellContext;
+ int32_t mMaxAUSize;
+ bool mStarted;
+ VIDEOEDITOR_CodecType mCodecType;
+ VideoEditorVideoDecoderSource(const MediaSource &);
+ VideoEditorVideoDecoderSource &operator=(const MediaSource &);
+};
+
+VideoEditorVideoDecoderSource::VideoEditorVideoDecoderSource(
+ const sp<MetaData> &format, VIDEOEDITOR_CodecType codecType,
+ void *decoderShellContext) :
+ mFormat(format),
+ mBuffer(NULL),
+ mGroup(NULL),
+ mStarted(false),
+ mCodecType(codecType) {
+ mpDecShellContext = (VideoEditorVideoDecoder_Context*) decoderShellContext;
+}
+
+VideoEditorVideoDecoderSource::~VideoEditorVideoDecoderSource() {
+ if (mStarted == true) {
+ stop();
+ }
+}
+
+status_t VideoEditorVideoDecoderSource::start(
+ MetaData *params) {
+
+ LOGV("VideoEditorVideoDecoderSource::start() begin ");
+ if (!mStarted) {
+ if(mFormat->findInt32(kKeyMaxInputSize, &mMaxAUSize) == false) {
+ LOGW("FATAL: Should never happen ");
+ mMaxAUSize = 10000;
+ }
+
+ mGroup = new MediaBufferGroup;
+ if(mGroup == NULL) {
+ LOGE("FATAL: memory limitation ! ");
+ return NO_MEMORY;
+ }
+ LOGV("VideoEditorVideoDecoderSource:adding buffer to group MaxSize= %d",
+ mMaxAUSize);
+ mGroup->add_buffer(new MediaBuffer(mMaxAUSize));
+
+ mStarted = true;
+ }
+ LOGV("VideoEditorVideoDecoderSource::start() end OK");
+ return OK;
+}
+
+status_t VideoEditorVideoDecoderSource::stop() {
+ int ref_count = 0;
+ int i;
+
+ LOGV("VideoEditorVideoDecoderSource::stop() begin");
+ if (mStarted) {
+ if(mBuffer != NULL) {
+ ref_count = mBuffer->refcount();
+ LOGV("MediaBuffer refcount is %d",ref_count);
+ for (i=0; i< ref_count; i++) {
+ mBuffer->release();
+ }
+
+ mBuffer = NULL;
+ }
+ delete mGroup;
+ mGroup = NULL;
+ mStarted = false;
+ }
+ LOGV("VideoEditorVideoDecoderSource::stop() end");
+ return OK;
+}
+
+sp<MetaData> VideoEditorVideoDecoderSource::getFormat() {
+ Mutex::Autolock autolock(mLock);
+
+ return mFormat;
+}
+
+status_t VideoEditorVideoDecoderSource::read(MediaBuffer** buffer_out,
+ const ReadOptions *options) {
+
+ Mutex::Autolock autolock(mLock);
+ //We donot use read options on decoder hence dont impliment this option here
+ M4_AccessUnit* pAccessUnit = mpDecShellContext->m_pNextAccessUnitToDecode;
+ M4OSA_UInt32 lSize = 0;
+ M4OSA_ERR lerr = M4NO_ERROR;
+ int64_t frameTime;
+
+ *buffer_out = NULL;
+
+ LOGV("VideoEditorVideoDecoderSource::read begin");
+
+ if (options) {
+ int64_t time = 0;
+ ReadOptions::SeekMode mode = ReadOptions::SEEK_CLOSEST_SYNC;
+ bool hasOptions = FALSE;
+ hasOptions = options->getSeekTo(&time, &mode);
+ if (hasOptions) {
+ LOGV("VideoEditorVideoDecoderSource: Options is not NULL %lld %d",
+ time, mode);
+ } else {
+ LOGV("VideoEditorVideoDecoderSource: Options is not NULL ****");
+ }
+ }
+ lerr = mGroup->acquire_buffer(&mBuffer);
+ if (lerr != OK) {
+ return lerr;
+ }
+ LOGV("VideoEditorVideoDecoderSource: got a buffer from group");
+
+ if (mStarted) {
+ //getNext AU from reader.
+ lerr = mpDecShellContext->m_pReader->m_pFctGetNextAu(
+ mpDecShellContext->m_pReader->m_readerContext,
+ (M4_StreamHandler*)mpDecShellContext->m_pVideoStreamhandler,
+ pAccessUnit);
+ if (lerr == M4WAR_NO_DATA_YET) {
+ LOGV("VideoEditorVideoDecoderSource::read() M4WAR_NO_DATA_YET");
+ mBuffer->set_range(0, 0);
+ mBuffer->meta_data()->clear();
+
+ *buffer_out = mBuffer;
+ }
+ if (lerr == M4WAR_NO_MORE_AU) {
+ LOGV("VideoEditorVideoDecoderSource::read() returning err = "
+ "ERROR_END_OF_STREAM;");
+ *buffer_out = NULL;
+ return ERROR_END_OF_STREAM;
+ }
+ LOGV("VideoEditorVideoDecoderSource: getNextAU succesful ts = %lf",
+ pAccessUnit->m_CTS);
+
+ //copy the reader AU buffer to mBuffer
+ lSize = (pAccessUnit->m_size > (M4OSA_UInt32)mMaxAUSize)\
+ ? (M4OSA_UInt32)mMaxAUSize : pAccessUnit->m_size;
+ LOGV("VideoDecoderSource:Read() copying AU to i/p buffer of decoder,"
+ "Bufer Add = 0x%x, size = %d", mBuffer->data(), lSize);
+ M4OSA_memcpy((M4OSA_MemAddr8)mBuffer->data(),pAccessUnit->m_dataAddress,
+ lSize);
+
+ mBuffer->set_range(0, lSize);
+ mBuffer->meta_data()->clear();
+ frameTime = (int64_t)pAccessUnit->m_CTS;
+ mBuffer->meta_data()->setInt64(kKeyTime, (int64_t)frameTime*1000);
+
+ // Replace the AU start code for H264
+ if (VIDEOEDITOR_kH264VideoDec == mCodecType) {
+ uint8_t *data =(uint8_t *)mBuffer->data() + mBuffer->range_offset();
+ data[0]=0;
+ data[1]=0;
+ data[2]=0;
+ data[3]=1;
+ }
+ mBuffer->meta_data()->setInt32(kKeyIsSyncFrame,
+ (pAccessUnit->m_attribute == 0x04)? 1 : 0);
+ *buffer_out = mBuffer;
+ }
+ LOGV("VideoEditorVideoDecoderSource::read end");
+ return OK;
+}
+/********************
+ * TOOLS *
+ ********************/
+
+static M4OSA_UInt32 VideoEditorVideoDecoder_GetBitsFromMemory(
+ VIDEOEDITOR_VIDEO_Bitstream_ctxt* parsingCtxt, M4OSA_UInt32 nb_bits) {
+ return (M4VD_Tools_GetBitsFromMemory((M4VS_Bitstream_ctxt*) parsingCtxt,
+ nb_bits));
+}
+
+M4OSA_ERR VideoEditorVideoDecoder_internalParseVideoDSI(M4OSA_UInt8* pVol,
+ M4OSA_Int32 aVolSize, M4DECODER_MPEG4_DecoderConfigInfo* pDci,
+ M4DECODER_VideoSize* pVideoSize) {
+
+ VIDEOEDITOR_VIDEO_Bitstream_ctxt parsingCtxt;
+ M4OSA_UInt32 code, j;
+ M4OSA_MemAddr8 start;
+ M4OSA_UInt8 i;
+ M4OSA_UInt32 time_incr_length;
+ M4OSA_UInt8 vol_verid=0, b_hierarchy_type;
+
+ /* Parsing variables */
+ M4OSA_UInt8 video_object_layer_shape = 0;
+ M4OSA_UInt8 sprite_enable = 0;
+ M4OSA_UInt8 reduced_resolution_vop_enable = 0;
+ M4OSA_UInt8 scalability = 0;
+ M4OSA_UInt8 enhancement_type = 0;
+ M4OSA_UInt8 complexity_estimation_disable = 0;
+ M4OSA_UInt8 interlaced = 0;
+ M4OSA_UInt8 sprite_warping_points = 0;
+ M4OSA_UInt8 sprite_brightness_change = 0;
+ M4OSA_UInt8 quant_precision = 0;
+
+ /* Fill the structure with default parameters */
+ pVideoSize->m_uiWidth = 0;
+ pVideoSize->m_uiHeight = 0;
+
+ pDci->uiTimeScale = 0;
+ pDci->uiProfile = 0;
+ pDci->uiUseOfResynchMarker = 0;
+ pDci->bDataPartition = M4OSA_FALSE;
+ pDci->bUseOfRVLC = M4OSA_FALSE;
+
+ /* Reset the bitstream context */
+ parsingCtxt.stream_byte = 0;
+ parsingCtxt.stream_index = 8;
+ parsingCtxt.in = (M4OSA_MemAddr8) pVol;
+
+ start = (M4OSA_MemAddr8) pVol;
+
+ /* Start parsing */
+ while (parsingCtxt.in - start < aVolSize) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(&parsingCtxt, 8);
+ if (code == 0) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(&parsingCtxt, 8);
+ if (code == 0) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(&parsingCtxt,8);
+ if (code == 1) {
+ /* start code found */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 8);
+
+ /* ----- 0x20..0x2F : video_object_layer_start_code ----- */
+
+ if ((code > 0x1F) && (code < 0x30)) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 8);
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);
+ if (code == 1) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 4);
+ vol_verid = (M4OSA_UInt8)code;
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 3);
+ }
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 4);
+ if (code == 15) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 16);
+ }
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);
+ if (code == 1) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 3);
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);
+ if (code == 1) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 32);
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 31);
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 16);
+ }
+ }
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 2);
+ /* Need to save it for vop parsing */
+ video_object_layer_shape = (M4OSA_UInt8)code;
+
+ if (code != 0) {
+ return 0; /* only rectangular case supported */
+ }
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 16);
+ pDci->uiTimeScale = code;
+
+ /* Computes time increment length */
+ j = code - 1;
+ for (i = 0; (i < 32) && (j != 0); j >>=1) {
+ i++;
+ }
+ time_incr_length = (i == 0) ? 1 : i;
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);
+ if (code == 1) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, time_incr_length);
+ }
+
+ if(video_object_layer_shape != 1) { /* 1 = Binary */
+ if(video_object_layer_shape == 0) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* Marker bit */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 13);/* Width */
+ pVideoSize->m_uiWidth = code;
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* Marker bit */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 13);/* Height */
+ pVideoSize->m_uiHeight = code;
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* Marker bit */
+ }
+ }
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* interlaced */
+ interlaced = (M4OSA_UInt8)code;
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* OBMC disable */
+
+ if(vol_verid == 1) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* sprite enable */
+ sprite_enable = (M4OSA_UInt8)code;
+ } else {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 2);/* sprite enable */
+ sprite_enable = (M4OSA_UInt8)code;
+ }
+ if ((sprite_enable == 1) || (sprite_enable == 2)) {
+ if (sprite_enable != 2) {
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 13);/* sprite width */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* Marker bit */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 13);/* sprite height */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* Marker bit */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 13);/* sprite l coordinate */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* Marker bit */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 13);/* sprite top coordinate */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* Marker bit */
+ }
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 6);/* sprite warping points */
+ sprite_warping_points = (M4OSA_UInt8)code;
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 2);/* sprite warping accuracy */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* sprite brightness change */
+ sprite_brightness_change = (M4OSA_UInt8)code;
+ if (sprite_enable != 2) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);
+ }
+ }
+ if ((vol_verid != 1) && (video_object_layer_shape != 0)){
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* sadct disable */
+ }
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1); /* not 8 bits */
+ if (code) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 4);/* quant precision */
+ quant_precision = (M4OSA_UInt8)code;
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 4);/* bits per pixel */
+ }
+
+ /* greyscale not supported */
+ if(video_object_layer_shape == 3) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 3);
+ }
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* quant type */
+ if (code) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* load intra quant mat */
+ if (code) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 8);/* */
+ i = 1;
+ while (i < 64) {
+ code =
+ VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 8);
+ if (code == 0) {
+ break;
+ }
+ i++;
+ }
+ }
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* load non intra quant mat */
+ if (code) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 8);/* */
+ i = 1;
+ while (i < 64) {
+ code =
+ VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 8);
+ if (code == 0) {
+ break;
+ }
+ i++;
+ }
+ }
+ }
+
+ if (vol_verid != 1) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* quarter sample */
+ }
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* complexity estimation disable */
+ complexity_estimation_disable = (M4OSA_UInt8)code;
+ if (!code) {
+ //return M4ERR_NOT_IMPLEMENTED;
+ }
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* resync marker disable */
+ pDci->uiUseOfResynchMarker = (code) ? 0 : 1;
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* data partitionned */
+ pDci->bDataPartition = (code) ? M4OSA_TRUE : M4OSA_FALSE;
+ if (code) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* reversible VLC */
+ pDci->bUseOfRVLC = (code) ? M4OSA_TRUE : M4OSA_FALSE;
+ }
+
+ if (vol_verid != 1) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* newpred */
+ if (code) {
+ //return M4ERR_PARAMETER;
+ }
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);
+ reduced_resolution_vop_enable = (M4OSA_UInt8)code;
+ }
+
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* scalability */
+ scalability = (M4OSA_UInt8)code;
+ if (code) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* hierarchy type */
+ b_hierarchy_type = (M4OSA_UInt8)code;
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 4);/* ref layer id */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* ref sampling direct */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 5);/* hor sampling factor N */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 5);/* hor sampling factor M */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 5);/* vert sampling factor N */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 5);/* vert sampling factor M */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* enhancement type */
+ enhancement_type = (M4OSA_UInt8)code;
+ if ((!b_hierarchy_type) &&
+ (video_object_layer_shape == 1)) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* use ref shape */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* use ref texture */
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 5);
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 5);
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 5);
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 5);
+ }
+ }
+ break;
+ }
+
+ /* ----- 0xB0 : visual_object_sequence_start_code ----- */
+
+ else if(code == 0xB0) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 8);/* profile_and_level_indication */
+ pDci->uiProfile = (M4OSA_UInt8)code;
+ }
+
+ /* ----- 0xB5 : visual_object_start_code ----- */
+
+ else if(code == 0xB5) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 1);/* is object layer identifier */
+ if (code == 1) {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 4); /* visual object verid */
+ vol_verid = (M4OSA_UInt8)code;
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 3);
+ } else {
+ code = VideoEditorVideoDecoder_GetBitsFromMemory(
+ &parsingCtxt, 7); /* Realign on byte */
+ vol_verid = 1;
+ }
+ }
+
+ /* ----- end ----- */
+ } else {
+ if ((code >> 2) == 0x20) {
+ /* H263 ...-> wrong*/
+ break;
+ }
+ }
+ }
+ }
+ }
+ return M4NO_ERROR;
+}
+
+M4VIFI_UInt8 M4VIFI_SemiplanarYVU420toYUV420(void *user_data,
+ M4VIFI_UInt8 *inyuv, M4VIFI_ImagePlane *PlaneOut ) {
+ M4VIFI_UInt8 return_code = M4VIFI_OK;
+ M4VIFI_UInt8 *outyuv =
+ ((M4VIFI_UInt8*)&(PlaneOut[0].pac_data[PlaneOut[0].u_topleft]));
+ int32_t width = PlaneOut[0].u_width;
+ int32_t height = PlaneOut[0].u_height;
+
+ int32_t outYsize = width * height;
+ uint32_t *outy = (uint32_t *) outyuv;
+ uint16_t *outcb =
+ (uint16_t *) &(PlaneOut[1].pac_data[PlaneOut[1].u_topleft]);
+ uint16_t *outcr =
+ (uint16_t *) &(PlaneOut[2].pac_data[PlaneOut[2].u_topleft]);
+
+ /* Y copying */
+ memcpy(outy, inyuv, outYsize);
+
+ /* U & V copying */
+ uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
+ for (int32_t i = height >> 1; i > 0; --i) {
+ for (int32_t j = width >> 2; j > 0; --j) {
+ uint32_t temp = *inyuv_4++;
+ uint32_t tempU = temp & 0xFF;
+ tempU = tempU | ((temp >> 8) & 0xFF00);
+
+ uint32_t tempV = (temp >> 8) & 0xFF;
+ tempV = tempV | ((temp >> 16) & 0xFF00);
+
+ // Flip U and V
+ *outcb++ = tempV;
+ *outcr++ = tempU;
+ }
+ }
+ return return_code;
+}
+
+M4OSA_ERR VideoEditorVideoDecoder_ParseAVCDSI(M4OSA_UInt8* pDSI,
+ M4OSA_Int32 DSISize, M4DECODER_AVCProfileLevel *profile) {
+ M4OSA_ERR err = M4NO_ERROR;
+ M4OSA_Bool NALSPS_and_Profile0Found = M4OSA_FALSE;
+ M4OSA_UInt16 index;
+ M4OSA_Bool constraintSet3;
+
+ for(index = 0; index < (DSISize-1); index++) {
+ if(((pDSI[index] & 0x1f) == 0x07) && (pDSI[index+1] == 0x42)) {
+ NALSPS_and_Profile0Found = M4OSA_TRUE;
+ break;
+ }
+ }
+ if(M4OSA_FALSE == NALSPS_and_Profile0Found) {
+ LOGV("VideoEditorVideoDecoder_ParseAVCDSI: index bad = %d", index);
+ *profile = M4DECODER_AVC_kProfile_and_Level_Out_Of_Range;
+ } else {
+ LOGV("VideoEditorVideoDecoder_ParseAVCDSI: index = %d", index);
+ constraintSet3 = (pDSI[index+2] & 0x10);
+ LOGV("VideoEditorVideoDecoder_ParseAVCDSI: level = %d", pDSI[index+3]);
+ switch(pDSI[index+3]) {
+ case 10:
+ *profile = M4DECODER_AVC_kProfile_0_Level_1;
+ break;
+ case 11:
+ if(constraintSet3) {
+ *profile = M4DECODER_AVC_kProfile_0_Level_1b;
+ } else {
+ *profile = M4DECODER_AVC_kProfile_0_Level_1_1;
+ }
+ break;
+ case 12:
+ *profile = M4DECODER_AVC_kProfile_0_Level_1_2;
+ break;
+ case 13:
+ *profile = M4DECODER_AVC_kProfile_0_Level_1_3;
+ break;
+ case 20:
+ *profile = M4DECODER_AVC_kProfile_0_Level_2;
+ break;
+ case 21:
+ *profile = M4DECODER_AVC_kProfile_0_Level_2_1;
+ break;
+ case 22:
+ *profile = M4DECODER_AVC_kProfile_0_Level_2_2;
+ break;
+ case 30:
+ *profile = M4DECODER_AVC_kProfile_0_Level_3;
+ break;
+ case 31:
+ *profile = M4DECODER_AVC_kProfile_0_Level_3_1;
+ break;
+ case 32:
+ *profile = M4DECODER_AVC_kProfile_0_Level_3_2;
+ break;
+ case 40:
+ *profile = M4DECODER_AVC_kProfile_0_Level_4;
+ break;
+ case 41:
+ *profile = M4DECODER_AVC_kProfile_0_Level_4_1;
+ break;
+ case 42:
+ *profile = M4DECODER_AVC_kProfile_0_Level_4_2;
+ break;
+ case 50:
+ *profile = M4DECODER_AVC_kProfile_0_Level_5;
+ break;
+ case 51:
+ *profile = M4DECODER_AVC_kProfile_0_Level_5_1;
+ break;
+ default:
+ *profile = M4DECODER_AVC_kProfile_and_Level_Out_Of_Range;
+ }
+ }
+ return err;
+}
+/********************
+ * ENGINE INTERFACE *
+ ********************/
+M4OSA_ERR VideoEditorVideoDecoder_configureFromMetadata(M4OSA_Context pContext,
+ MetaData* meta) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoDecoder_Context* pDecShellContext = M4OSA_NULL;
+ bool success = OK;
+ int32_t width = 0;
+ int32_t height = 0;
+ int32_t frameSize = 0;
+
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != meta, M4ERR_PARAMETER);
+
+ LOGV("VideoEditorVideoDecoder_configureFromMetadata begin");
+
+ pDecShellContext = (VideoEditorVideoDecoder_Context*)pContext;
+
+ // Get the parameters
+ success = meta->findInt32(kKeyWidth, &width);
+ success &= meta->findInt32(kKeyHeight, &height);
+ VIDEOEDITOR_CHECK(TRUE == success, M4ERR_PARAMETER);
+
+ LOGV("VideoDecoder_configureFromMetadata : W=%d H=%d", width, height);
+ VIDEOEDITOR_CHECK((0 != width) && (0 != height), M4ERR_PARAMETER);
+
+ LOGV("VideoDecoder_configureFromMetadata : W=%d H=%d", width, height);
+
+ if( (M4OSA_NULL != pDecShellContext->m_pDecBufferPool) &&
+ (pDecShellContext->m_pVideoStreamhandler->m_videoWidth == \
+ (uint32_t)width) &&
+ (pDecShellContext->m_pVideoStreamhandler->m_videoHeight == \
+ (uint32_t)height) ) {
+ // No need to reconfigure
+ goto cleanUp;
+ }
+ LOGV("VideoDecoder_configureFromMetadata reset: W=%d H=%d", width, height);
+ // Update the stream handler parameters
+ pDecShellContext->m_pVideoStreamhandler->m_videoWidth = width;
+ pDecShellContext->m_pVideoStreamhandler->m_videoHeight = height;
+ frameSize = (width * height * 3) / 2;
+
+ // Configure the buffer pool
+ if( M4OSA_NULL != pDecShellContext->m_pDecBufferPool ) {
+ LOGV("VideoDecoder_configureFromMetadata : reset the buffer pool");
+ VIDEOEDITOR_BUFFER_freePool(pDecShellContext->m_pDecBufferPool);
+ pDecShellContext->m_pDecBufferPool = M4OSA_NULL;
+ }
+ err = VIDEOEDITOR_BUFFER_allocatePool(&pDecShellContext->m_pDecBufferPool,
+ MAX_DEC_BUFFERS, (M4OSA_Char*)"VIDEOEDITOR_DecodedBufferPool");
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+ err = VIDEOEDITOR_BUFFER_initPoolBuffers(pDecShellContext->m_pDecBufferPool,
+ frameSize + width * 2);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoDecoder_configureFromMetadata no error");
+ } else {
+ if( M4OSA_NULL != pDecShellContext->m_pDecBufferPool ) {
+ VIDEOEDITOR_BUFFER_freePool(pDecShellContext->m_pDecBufferPool);
+ pDecShellContext->m_pDecBufferPool = M4OSA_NULL;
+ }
+ LOGV("VideoEditorVideoDecoder_configureFromMetadata ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoDecoder_configureFromMetadata end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoDecoder_destroy(M4OSA_Context pContext) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoDecoder_Context* pDecShellContext =
+ (VideoEditorVideoDecoder_Context*)pContext;
+
+ // Input parameters check
+ LOGV("VideoEditorVideoDecoder_destroy begin");
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ // Destroy the graph
+ if( pDecShellContext->mVideoDecoder != NULL ) {
+ LOGV("### VideoEditorVideoDecoder_destroy : releasing decoder");
+ pDecShellContext->mVideoDecoder->stop();
+ pDecShellContext->mVideoDecoder.clear();
+ }
+ pDecShellContext->mClient.disconnect();
+ pDecShellContext->mReaderSource.clear();
+
+ // Release memory
+ if( pDecShellContext->m_pDecBufferPool != M4OSA_NULL ) {
+ VIDEOEDITOR_BUFFER_freePool(pDecShellContext->m_pDecBufferPool);
+ pDecShellContext->m_pDecBufferPool = M4OSA_NULL;
+ }
+ SAFE_FREE(pDecShellContext);
+ pContext = NULL;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoDecoder_destroy no error");
+ } else {
+ LOGV("VideoEditorVideoDecoder_destroy ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoDecoder_destroy end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoDecoder_create(M4OSA_Context *pContext,
+ M4_StreamHandler *pStreamHandler,
+ M4READER_DataInterface *pReaderDataInterface,
+ M4_AccessUnit *pAccessUnit, M4OSA_Void *pUserData) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoDecoder_Context* pDecShellContext = M4OSA_NULL;
+ status_t status = OK;
+ bool success = TRUE;
+ int32_t colorFormat = 0;
+ M4OSA_UInt32 size = 0;
+ sp<MetaData> decoderMetadata = NULL;
+
+ LOGV("VideoEditorVideoDecoder_create begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pStreamHandler, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pReaderDataInterface, M4ERR_PARAMETER);
+
+ // Context allocation & initialization
+ SAFE_MALLOC(pDecShellContext, VideoEditorVideoDecoder_Context, 1,
+ "VideoEditorVideoDecoder");
+ pDecShellContext->m_pVideoStreamhandler =
+ (M4_VideoStreamHandler*)pStreamHandler;
+ pDecShellContext->m_pNextAccessUnitToDecode = pAccessUnit;
+ pDecShellContext->m_pReader = pReaderDataInterface;
+ pDecShellContext->m_lastDecodedCTS = -1;
+ pDecShellContext->m_lastRenderCts = -1;
+ switch( pStreamHandler->m_streamType ) {
+ case M4DA_StreamTypeVideoH263:
+ pDecShellContext->mDecoderType = VIDEOEDITOR_kH263VideoDec;
+ break;
+ case M4DA_StreamTypeVideoMpeg4:
+ pDecShellContext->mDecoderType = VIDEOEDITOR_kMpeg4VideoDec;
+ // Parse the VOL header
+ err = VideoEditorVideoDecoder_internalParseVideoDSI(
+ (M4OSA_UInt8*)pDecShellContext->m_pVideoStreamhandler->\
+ m_basicProperties.m_pDecoderSpecificInfo,
+ pDecShellContext->m_pVideoStreamhandler->\
+ m_basicProperties.m_decoderSpecificInfoSize,
+ &pDecShellContext->m_Dci, &pDecShellContext->m_VideoSize);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+ break;
+ case M4DA_StreamTypeVideoMpeg4Avc:
+ pDecShellContext->mDecoderType = VIDEOEDITOR_kH264VideoDec;
+ break;
+ default:
+ VIDEOEDITOR_CHECK(!"VideoDecoder_create : incorrect stream type",
+ M4ERR_PARAMETER);
+ break;
+ }
+
+ pDecShellContext->mNbInputFrames = 0;
+ pDecShellContext->mFirstInputCts = -1.0;
+ pDecShellContext->mLastInputCts = -1.0;
+ pDecShellContext->mNbRenderedFrames = 0;
+ pDecShellContext->mFirstRenderedCts = -1.0;
+ pDecShellContext->mLastRenderedCts = -1.0;
+ pDecShellContext->mNbOutputFrames = 0;
+ pDecShellContext->mFirstOutputCts = -1;
+ pDecShellContext->mLastOutputCts = -1;
+
+ /**
+ * StageFright graph building
+ */
+ decoderMetadata = new MetaData;
+ switch( pDecShellContext->mDecoderType ) {
+ case VIDEOEDITOR_kH263VideoDec:
+ decoderMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+ break;
+ case VIDEOEDITOR_kMpeg4VideoDec:
+ decoderMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+ decoderMetadata->setData(kKeyESDS, kTypeESDS,
+ pStreamHandler->m_pESDSInfo,
+ pStreamHandler->m_ESDSInfoSize);
+ break;
+ case VIDEOEDITOR_kH264VideoDec:
+ decoderMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+ decoderMetadata->setData(kKeyAVCC, kTypeAVCC,
+ pStreamHandler->m_pH264DecoderSpecificInfo,
+ pStreamHandler->m_H264decoderSpecificInfoSize);
+ break;
+ default:
+ VIDEOEDITOR_CHECK(!"VideoDecoder_create : incorrect stream type",
+ M4ERR_PARAMETER);
+ break;
+ }
+
+ decoderMetadata->setInt32(kKeyMaxInputSize, pStreamHandler->m_maxAUSize);
+ decoderMetadata->setInt32(kKeyWidth,
+ pDecShellContext->m_pVideoStreamhandler->m_videoWidth);
+ decoderMetadata->setInt32(kKeyHeight,
+ pDecShellContext->m_pVideoStreamhandler->m_videoHeight);
+
+ // Create the decoder source
+ pDecShellContext->mReaderSource = new VideoEditorVideoDecoderSource(
+ decoderMetadata, pDecShellContext->mDecoderType,
+ (void *)pDecShellContext);
+ VIDEOEDITOR_CHECK(NULL != pDecShellContext->mReaderSource.get(),
+ M4ERR_SF_DECODER_RSRC_FAIL);
+
+ // Connect to the OMX client
+ status = pDecShellContext->mClient.connect();
+ VIDEOEDITOR_CHECK(OK == status, M4ERR_SF_DECODER_RSRC_FAIL);
+
+ // Create the decoder
+ pDecShellContext->mVideoDecoder = OMXCodec::Create(
+ pDecShellContext->mClient.interface(),
+ decoderMetadata, false, pDecShellContext->mReaderSource);
+ VIDEOEDITOR_CHECK(NULL != pDecShellContext->mVideoDecoder.get(),
+ M4ERR_SF_DECODER_RSRC_FAIL);
+
+
+ // Get the output color format
+ success = pDecShellContext->mVideoDecoder->getFormat()->findInt32(
+ kKeyColorFormat, &colorFormat);
+ VIDEOEDITOR_CHECK(TRUE == success, M4ERR_PARAMETER);
+ pDecShellContext->decOuputColorFormat = (OMX_COLOR_FORMATTYPE)colorFormat;
+
+ pDecShellContext->mVideoDecoder->getFormat()->setInt32(kKeyWidth,
+ pDecShellContext->m_pVideoStreamhandler->m_videoWidth);
+ pDecShellContext->mVideoDecoder->getFormat()->setInt32(kKeyHeight,
+ pDecShellContext->m_pVideoStreamhandler->m_videoHeight);
+
+ // Configure the buffer pool from the metadata
+ err = VideoEditorVideoDecoder_configureFromMetadata(pDecShellContext,
+ pDecShellContext->mVideoDecoder->getFormat().get());
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+
+ // Start the graph
+ status = pDecShellContext->mVideoDecoder->start();
+ VIDEOEDITOR_CHECK(OK == status, M4ERR_SF_DECODER_RSRC_FAIL);
+
+ *pContext = (M4OSA_Context)pDecShellContext;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoDecoder_create no error");
+ } else {
+ VideoEditorVideoDecoder_destroy(pDecShellContext);
+ *pContext = M4OSA_NULL;
+ LOGV("VideoEditorVideoDecoder_create ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoDecoder_create : DONE");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoDecoder_getOption(M4OSA_Context context,
+ M4OSA_OptionID optionId, M4OSA_DataOption pValue) {
+ M4OSA_ERR lerr = M4NO_ERROR;
+ VideoEditorVideoDecoder_Context* pDecShellContext =
+ (VideoEditorVideoDecoder_Context*) context;
+ M4_VersionInfo* pVersionInfo;
+ M4DECODER_VideoSize* pVideoSize;
+ M4OSA_UInt32* pNextFrameCts;
+ M4OSA_UInt32 *plastDecodedFrameCts;
+ M4DECODER_AVCProfileLevel* profile;
+ M4DECODER_MPEG4_DecoderConfigInfo* pDecConfInfo;
+
+ LOGV("VideoEditorVideoDecoder_getOption begin");
+
+ switch (optionId) {
+ case M4DECODER_kOptionID_AVCLastDecodedFrameCTS:
+ plastDecodedFrameCts = (M4OSA_UInt32 *) pValue;
+ *plastDecodedFrameCts = pDecShellContext->m_lastDecodedCTS;
+ break;
+
+ case M4DECODER_kOptionID_Version:
+ pVersionInfo = (M4_VersionInfo*)pValue;
+
+ pVersionInfo->m_major = VIDEOEDITOR_VIDEC_SHELL_VER_MAJOR;
+ pVersionInfo->m_minor= VIDEOEDITOR_VIDEC_SHELL_VER_MINOR;
+ pVersionInfo->m_revision = VIDEOEDITOR_VIDEC_SHELL_VER_REVISION;
+ pVersionInfo->m_structSize=sizeof(M4_VersionInfo);
+ break;
+
+ case M4DECODER_kOptionID_VideoSize:
+ /** Only VPS uses this Option ID. */
+ pVideoSize = (M4DECODER_VideoSize*)pValue;
+ pDecShellContext->mVideoDecoder->getFormat()->findInt32(kKeyWidth,
+ (int32_t*)(&pVideoSize->m_uiWidth));
+ pDecShellContext->mVideoDecoder->getFormat()->findInt32(kKeyHeight,
+ (int32_t*)(&pVideoSize->m_uiHeight));
+ LOGV("VideoEditorVideoDecoder_getOption : W=%d H=%d",
+ pVideoSize->m_uiWidth, pVideoSize->m_uiHeight);
+ break;
+
+ case M4DECODER_kOptionID_NextRenderedFrameCTS:
+ /** How to get this information. SF decoder does not provide this. *
+ ** Let us provide last decoded frame CTS as of now. *
+ ** Only VPS uses this Option ID. */
+ pNextFrameCts = (M4OSA_UInt32 *)pValue;
+ *pNextFrameCts = pDecShellContext->m_lastDecodedCTS;
+ break;
+ case M4DECODER_kOptionID_AVCProfileAndLevel:
+ profile = (M4DECODER_AVCProfileLevel *) pValue;
+ VideoEditorVideoDecoder_ParseAVCDSI (
+ pDecShellContext->m_pVideoStreamhandler->\
+ m_basicProperties.m_pDecoderSpecificInfo,
+ pDecShellContext->m_pVideoStreamhandler->\
+ m_basicProperties.m_decoderSpecificInfoSize,
+ profile);
+ break;
+ case M4DECODER_MPEG4_kOptionID_DecoderConfigInfo:
+ if(pDecShellContext->mDecoderType == VIDEOEDITOR_kMpeg4VideoDec) {
+ (*(M4DECODER_MPEG4_DecoderConfigInfo*)pValue) =
+ pDecShellContext->m_Dci;
+ }
+ break;
+ default:
+ lerr = M4ERR_BAD_OPTION_ID;
+ break;
+
+ }
+
+ LOGV("VideoEditorVideoDecoder_getOption: end with err = 0x%x", lerr);
+ return lerr;
+}
+
+M4OSA_ERR VideoEditorVideoDecoder_setOption(M4OSA_Context context,
+ M4OSA_OptionID optionId, M4OSA_DataOption pValue) {
+ M4OSA_ERR lerr = M4NO_ERROR;
+ VideoEditorVideoDecoder_Context *pDecShellContext =
+ (VideoEditorVideoDecoder_Context*) context;
+
+ LOGV("VideoEditorVideoDecoder_setOption begin");
+
+ switch (optionId) {
+ case M4DECODER_kOptionID_OutputFilter: {
+ M4DECODER_OutputFilter* pOutputFilter =
+ (M4DECODER_OutputFilter*) pValue;
+ pDecShellContext->m_pFilter =
+ (M4VIFI_PlanConverterFunctionType*)pOutputFilter->\
+ m_pFilterFunction;
+ pDecShellContext->m_pFilterUserData =
+ pOutputFilter->m_pFilterUserData;
+ }
+ break;
+ case M4DECODER_kOptionID_DeblockingFilter:
+ break;
+ default:
+ lerr = M4ERR_BAD_CONTEXT;
+ break;
+ }
+
+ LOGV("VideoEditorVideoDecoder_setOption: end with err = 0x%x", lerr);
+ return lerr;
+}
+
+M4OSA_ERR VideoEditorVideoDecoder_decode(M4OSA_Context context,
+ M4_MediaTime* pTime, M4OSA_Bool bJump) {
+ M4OSA_ERR lerr = M4NO_ERROR;
+ VideoEditorVideoDecoder_Context* pDecShellContext =
+ (VideoEditorVideoDecoder_Context*) context;
+ int64_t lFrameTime;
+ VIDEOEDITOR_BUFFER_Buffer* tmpDecBuffer;
+ MediaSource::ReadOptions decShellOptions;
+ MediaBuffer* pDecoderBuffer = NULL;
+ status_t errStatus;
+
+
+ LOGV("VideoEditorVideoDecoder_decode begin");
+
+ if( M4OSA_TRUE == pDecShellContext->mReachedEOS ) {
+ // Do not call read(), it could lead to a freeze
+ LOGV("VideoEditorVideoDecoder_decode : EOS already reached");
+ lerr = M4WAR_NO_MORE_AU;
+ goto VIDEOEDITOR_VideoDecode_cleanUP;
+ }
+ if(pDecShellContext->m_lastDecodedCTS >= *pTime) {
+ LOGV("VideoDecoder_decode: Already decoded up to this time CTS = %lf.",
+ pDecShellContext->m_lastDecodedCTS);
+ goto VIDEOEDITOR_VideoDecode_cleanUP;
+ }
+ if(M4OSA_TRUE == bJump) {
+ LOGV("VideoEditorVideoDecoder_decode: Jump called");
+ pDecShellContext->m_lastDecodedCTS = -1;
+ pDecShellContext->m_lastRenderCts = -1;
+ }
+
+ pDecShellContext->mNbInputFrames++;
+ if (0 > pDecShellContext->mFirstInputCts){
+ pDecShellContext->mFirstInputCts = *pTime;
+ }
+ pDecShellContext->mLastInputCts = *pTime;
+
+ while (pDecShellContext->m_lastDecodedCTS < *pTime) {
+ LOGV("VideoEditorVideoDecoder_decode, frameCTS = %lf, DecodeUpTo = %lf",
+ pDecShellContext->m_lastDecodedCTS, *pTime);
+ lerr = VIDEOEDITOR_BUFFER_getBuffer(pDecShellContext->m_pDecBufferPool,
+ VIDEOEDITOR_BUFFER_kEmpty, &tmpDecBuffer);
+ if (lerr == (M4OSA_UInt32)M4ERR_NO_BUFFER_AVAILABLE) {
+ lerr = VIDEOEDITOR_BUFFER_getOldestBuffer(
+ pDecShellContext->m_pDecBufferPool,
+ VIDEOEDITOR_BUFFER_kFilled, &tmpDecBuffer);
+ tmpDecBuffer->state = VIDEOEDITOR_BUFFER_kEmpty;
+ lerr = M4NO_ERROR;
+ }
+
+ if (lerr != M4NO_ERROR) {
+ goto VIDEOEDITOR_VideoDecode_cleanUP;
+ }
+
+ if (pDecoderBuffer != NULL) {
+ pDecoderBuffer->release();
+ pDecoderBuffer = NULL;
+ }
+
+ decShellOptions.reset();
+ errStatus = pDecShellContext->mVideoDecoder->read(&pDecoderBuffer,
+ &decShellOptions);
+ if (errStatus == ERROR_END_OF_STREAM) {
+ LOGV("End of stream reached, returning M4WAR_NO_MORE_AU ");
+ pDecShellContext->mReachedEOS = M4OSA_TRUE;
+ lerr = M4WAR_NO_MORE_AU;
+ goto VIDEOEDITOR_VideoDecode_cleanUP;
+ } else if ( INFO_FORMAT_CHANGED == errStatus ) {
+ LOGV("VideoDecoder_decode:source returns INFO_FORMAT_CHANGED:TODO");
+
+#if 1
+ LOGV("VideoDecoder_decode : source returns INFO_FORMAT_CHANGED");
+ lerr = VideoEditorVideoDecoder_configureFromMetadata(
+ pDecShellContext,
+ pDecShellContext->mVideoDecoder->getFormat().get());
+ if( M4NO_ERROR != lerr ) {
+ LOGV("!!! VideoEditorVideoDecoder_decode ERROR : "
+ "VideoDecoder_configureFromMetadata returns 0x%X", lerr);
+ break;
+ }
+#endif
+ continue;
+ }
+
+ if( 0 < pDecoderBuffer->range_length() ) {
+ LOGV("VIDEOEDITOR_VideoDecoder frame buffer size = %d",
+ pDecoderBuffer->range_length());
+
+ pDecoderBuffer->meta_data()->findInt64(kKeyTime, &lFrameTime);
+ pDecShellContext->m_lastDecodedCTS = (M4_MediaTime)(lFrameTime/1000);
+ LOGV("VideoEditorVideoDecoder_decode,decoded frametime = %lf,size = %d",
+ (M4_MediaTime)lFrameTime, pDecoderBuffer->size() );
+
+ switch ( pDecShellContext->decOuputColorFormat ) {
+ case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: {
+ M4VIFI_ImagePlane tmpPlane[3];
+ // Prepare the output image for conversion
+ if( pDecoderBuffer->range_length() != (
+ pDecShellContext->m_pVideoStreamhandler->m_videoWidth *
+ pDecShellContext->m_pVideoStreamhandler->m_videoHeight \
+ * 3)/2 ) {
+ LOGV("VideoEditorVideoDecoder_decod invalid frame size S=%d"
+ "W=%d H=%d", pDecoderBuffer->range_length(),
+ pDecShellContext->m_pVideoStreamhandler->m_videoWidth,
+ pDecShellContext->m_pVideoStreamhandler->m_videoHeight);
+ lerr = M4ERR_PARAMETER;
+ goto VIDEOEDITOR_VideoDecode_cleanUP;
+ }
+ tmpPlane[0].u_width =
+ pDecShellContext->m_pVideoStreamhandler->m_videoWidth;
+ tmpPlane[0].u_height =
+ pDecShellContext->m_pVideoStreamhandler->m_videoHeight;
+ tmpPlane[0].u_topleft = 0;
+ tmpPlane[0].u_stride = tmpPlane[0].u_width;
+ tmpPlane[0].pac_data = (M4VIFI_UInt8*)tmpDecBuffer->pData;
+ tmpPlane[1].u_width = tmpPlane[0].u_width/2;
+ tmpPlane[1].u_height = tmpPlane[0].u_height/2;
+ tmpPlane[1].u_topleft = 0;
+ tmpPlane[1].u_stride = tmpPlane[0].u_stride/2;
+ tmpPlane[1].pac_data = tmpPlane[0].pac_data +
+ (tmpPlane[0].u_stride * tmpPlane[0].u_height);
+ tmpPlane[2].u_width = tmpPlane[1].u_width;
+ tmpPlane[2].u_height = tmpPlane[1].u_height;
+ tmpPlane[2].u_topleft = 0;
+ tmpPlane[2].u_stride = tmpPlane[1].u_stride;
+ tmpPlane[2].pac_data = tmpPlane[1].pac_data +
+ (tmpPlane[1].u_stride * tmpPlane[1].u_height);
+ M4VIFI_SemiplanarYVU420toYUV420(M4OSA_NULL,
+ (M4VIFI_UInt8 *)pDecoderBuffer->data() + \
+ pDecoderBuffer->range_offset(), &tmpPlane[0]);
+ break;
+ }
+ case OMX_COLOR_FormatYUV420Planar:
+ M4OSA_memcpy((M4OSA_MemAddr8)tmpDecBuffer->pData,
+ (M4OSA_MemAddr8) pDecoderBuffer->data() +
+ pDecoderBuffer->range_offset(),
+ (M4OSA_UInt32)pDecoderBuffer->range_length());
+ break;
+ default:
+ LOGV("VideoDecoder_decode: unexpected color format 0x%X",
+ pDecShellContext->decOuputColorFormat);
+ return M4ERR_PARAMETER;
+ }
+
+ tmpDecBuffer->buffCTS = pDecShellContext->m_lastDecodedCTS;
+ tmpDecBuffer->state = VIDEOEDITOR_BUFFER_kFilled;
+ tmpDecBuffer->size = pDecoderBuffer->size();
+
+ } else {
+ LOGV("VideoEditorVideoDecoder_decode : empty buffer was returned");
+ }
+ }
+ pDecShellContext->mNbOutputFrames++;
+ if ( 0 > pDecShellContext->mFirstOutputCts ) {
+ pDecShellContext->mFirstOutputCts = *pTime;
+ }
+ pDecShellContext->mLastOutputCts = *pTime;
+
+VIDEOEDITOR_VideoDecode_cleanUP:
+ *pTime = pDecShellContext->m_lastDecodedCTS;
+ if (pDecoderBuffer != NULL) {
+ pDecoderBuffer->release();
+ pDecoderBuffer = NULL;
+ }
+
+ LOGV("VideoEditorVideoDecoder_decode: end with 0x%x", lerr);
+ return lerr;
+}
+
+M4OSA_ERR VideoEditorVideoDecoder_render(M4OSA_Context context,
+ M4_MediaTime* pTime, M4VIFI_ImagePlane* pOutputPlane,
+ M4OSA_Bool bForceRender) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoDecoder_Context* pDecShellContext =
+ (VideoEditorVideoDecoder_Context*) context;
+ M4OSA_UInt32 lindex, i;
+ M4OSA_UInt8* p_buf_src, *p_buf_dest;
+ M4VIFI_ImagePlane tmpPlaneIn, tmpPlaneOut;
+ VIDEOEDITOR_BUFFER_Buffer* pTmpVIDEOEDITORBuffer, *pRenderVIDEOEDITORBuffer
+ = M4OSA_NULL;
+ M4_MediaTime candidateTimeStamp = -1;
+ M4OSA_Bool bFound = M4OSA_FALSE;
+
+ LOGV("VideoEditorVideoDecoder_render begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != context, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pTime, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pOutputPlane, M4ERR_PARAMETER);
+
+ // The output buffer is already allocated, just copy the data
+ if ( (*pTime <= pDecShellContext->m_lastRenderCts) &&
+ (M4OSA_FALSE == bForceRender) ) {
+ LOGV("VIDEOEDITOR_VIDEO_render Frame in the past");
+ err = M4WAR_VIDEORENDERER_NO_NEW_FRAME;
+ goto cleanUp;
+ }
+ LOGV("VideoDecoder_render: lastRendered time = %lf,requested render time = "
+ "%lf", pDecShellContext->m_lastRenderCts, *pTime);
+
+ /**
+ * Find the buffer appropriate for rendering. */
+ for (i=0; i < pDecShellContext->m_pDecBufferPool->NB; i++) {
+ pTmpVIDEOEDITORBuffer = &pDecShellContext->m_pDecBufferPool\
+ ->pNXPBuffer[i];
+ if (pTmpVIDEOEDITORBuffer->state == VIDEOEDITOR_BUFFER_kFilled) {
+ /** Free all those buffers older than last rendered frame. */
+ if (pTmpVIDEOEDITORBuffer->buffCTS < pDecShellContext->\
+ m_lastRenderCts) {
+ pTmpVIDEOEDITORBuffer->state = VIDEOEDITOR_BUFFER_kEmpty;
+ }
+
+ /** Get the buffer with appropriate timestamp */
+ if ( (pTmpVIDEOEDITORBuffer->buffCTS >= pDecShellContext->\
+ m_lastRenderCts) &&
+ (pTmpVIDEOEDITORBuffer->buffCTS <= *pTime) &&
+ (pTmpVIDEOEDITORBuffer->buffCTS > candidateTimeStamp)) {
+ bFound = M4OSA_TRUE;
+ pRenderVIDEOEDITORBuffer = pTmpVIDEOEDITORBuffer;
+ candidateTimeStamp = pTmpVIDEOEDITORBuffer->buffCTS;
+ LOGV("VideoDecoder_render: found a buffer with timestamp = %lf",
+ candidateTimeStamp);
+ }
+ }
+ }
+ if (M4OSA_FALSE == bFound) {
+ err = M4WAR_VIDEORENDERER_NO_NEW_FRAME;
+ goto cleanUp;
+ }
+
+ LOGV("VideoEditorVideoDecoder_render 3 ouput %d %d %d %d",
+ pOutputPlane[0].u_width, pOutputPlane[0].u_height,
+ pOutputPlane[0].u_topleft, pOutputPlane[0].u_stride);
+
+ pDecShellContext->m_lastRenderCts = candidateTimeStamp;
+
+ if( M4OSA_NULL != pDecShellContext->m_pFilter ) {
+ // Filtering was requested
+ M4VIFI_ImagePlane tmpPlane[3];
+ // Prepare the output image for conversion
+ tmpPlane[0].u_width =
+ pDecShellContext->m_pVideoStreamhandler->m_videoWidth;
+ tmpPlane[0].u_height =
+ pDecShellContext->m_pVideoStreamhandler->m_videoHeight;
+ tmpPlane[0].u_topleft = 0;
+ tmpPlane[0].u_stride = tmpPlane[0].u_width;
+ tmpPlane[0].pac_data = (M4VIFI_UInt8*)pRenderVIDEOEDITORBuffer->pData;
+ tmpPlane[1].u_width = tmpPlane[0].u_width/2;
+ tmpPlane[1].u_height = tmpPlane[0].u_height/2;
+ tmpPlane[1].u_topleft = 0;
+ tmpPlane[1].u_stride = tmpPlane[0].u_stride/2;
+ tmpPlane[1].pac_data = tmpPlane[0].pac_data +
+ (tmpPlane[0].u_stride * tmpPlane[0].u_height);
+ tmpPlane[2].u_width = tmpPlane[1].u_width;
+ tmpPlane[2].u_height = tmpPlane[1].u_height;
+ tmpPlane[2].u_topleft = 0;
+ tmpPlane[2].u_stride = tmpPlane[1].u_stride;
+ tmpPlane[2].pac_data = tmpPlane[1].pac_data +
+ (tmpPlane[1].u_stride * tmpPlane[1].u_height);
+
+ LOGV("VideoEditorVideoDecoder_render w = %d H = %d",
+ tmpPlane[0].u_width,tmpPlane[0].u_height);
+ pDecShellContext->m_pFilter(M4OSA_NULL, &tmpPlane[0], pOutputPlane);
+ } else {
+ // Just copy the YUV420P buffer
+ M4OSA_MemAddr8 tempBuffPtr =
+ (M4OSA_MemAddr8)pRenderVIDEOEDITORBuffer->pData;
+ M4OSA_UInt32 tempWidth =
+ pDecShellContext->m_pVideoStreamhandler->m_videoWidth;
+ M4OSA_UInt32 tempHeight =
+ pDecShellContext->m_pVideoStreamhandler->m_videoHeight;
+
+ M4OSA_memcpy((M4OSA_MemAddr8) pOutputPlane[0].pac_data, tempBuffPtr,
+ tempWidth * tempHeight);
+ tempBuffPtr += (tempWidth * tempHeight);
+ M4OSA_memcpy((M4OSA_MemAddr8) pOutputPlane[1].pac_data, tempBuffPtr,
+ (tempWidth/2) * (tempHeight/2));
+ tempBuffPtr += ((tempWidth/2) * (tempHeight/2));
+ M4OSA_memcpy((M4OSA_MemAddr8) pOutputPlane[2].pac_data, tempBuffPtr,
+ (tempWidth/2) * (tempHeight/2));
+ }
+
+ pDecShellContext->mNbRenderedFrames++;
+ if ( 0 > pDecShellContext->mFirstRenderedCts ) {
+ pDecShellContext->mFirstRenderedCts = *pTime;
+ }
+ pDecShellContext->mLastRenderedCts = *pTime;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ *pTime = pDecShellContext->m_lastRenderCts;
+ LOGV("VideoEditorVideoDecoder_render no error");
+ } else {
+ LOGV("VideoEditorVideoDecoder_render ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoDecoder_render end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoDecoder_getInterface(M4DECODER_VideoType decoderType,
+ M4DECODER_VideoType *pDecoderType, M4OSA_Context *pDecInterface) {
+ M4DECODER_VideoInterface* pDecoderInterface = M4OSA_NULL;
+
+ pDecoderInterface = (M4DECODER_VideoInterface*)M4OSA_malloc(
+ sizeof(M4DECODER_VideoInterface), M4DECODER_EXTERNAL,
+ (M4OSA_Char*)"VideoEditorVideoDecoder_getInterface" );
+ if (M4OSA_NULL == pDecoderInterface) {
+ return M4ERR_ALLOC;
+ }
+
+ *pDecoderType = decoderType;
+
+ pDecoderInterface->m_pFctCreate = VideoEditorVideoDecoder_create;
+ pDecoderInterface->m_pFctDestroy = VideoEditorVideoDecoder_destroy;
+ pDecoderInterface->m_pFctGetOption = VideoEditorVideoDecoder_getOption;
+ pDecoderInterface->m_pFctSetOption = VideoEditorVideoDecoder_setOption;
+ pDecoderInterface->m_pFctDecode = VideoEditorVideoDecoder_decode;
+ pDecoderInterface->m_pFctRender = VideoEditorVideoDecoder_render;
+
+ *pDecInterface = (M4OSA_Context)pDecoderInterface;
+ return M4NO_ERROR;
+}
+
+extern "C" {
+
+M4OSA_ERR VideoEditorVideoDecoder_getInterface_MPEG4(
+ M4DECODER_VideoType *pDecoderType, M4OSA_Context *pDecInterface) {
+ return VideoEditorVideoDecoder_getInterface(M4DECODER_kVideoTypeMPEG4,
+ pDecoderType, pDecInterface);
+}
+
+M4OSA_ERR VideoEditorVideoDecoder_getInterface_H264(
+ M4DECODER_VideoType *pDecoderType, M4OSA_Context *pDecInterface) {
+ return VideoEditorVideoDecoder_getInterface(M4DECODER_kVideoTypeAVC,
+ pDecoderType, pDecInterface);
+
+}
+
+} // extern "C"
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoEncoder.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoEncoder.cpp
new file mode 100755
index 0000000..0813b5c
--- /dev/null
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoEncoder.cpp
@@ -0,0 +1,1288 @@
+/*
+ * Copyright (C) 2011 NXP Software
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+*************************************************************************
+* @file VideoEditorVideoEncoder.cpp
+* @brief StageFright shell video encoder
+*************************************************************************
+*/
+#define LOG_NDEBUG 1
+#define LOG_TAG "VIDEOEDITOR_VIDEOENCODER"
+
+/*******************
+ * HEADERS *
+ *******************/
+#include "M4OSA_Debug.h"
+#include "M4SYS_AccessUnit.h"
+#include "VideoEditorVideoEncoder.h"
+#include "VideoEditorUtils.h"
+
+#include "utils/Log.h"
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+#include "OMX_Video.h"
+
+/********************
+ * DEFINITIONS *
+ ********************/
+
+// Minimum number of buffer in the source in order to allow encoding
+#define VIDEOEDITOR_MIN_BUFFER_NB 15
+
+// Not enough source buffers available
+#define M4WAR_SF_LOW_BUFFER M4OSA_ERR_CREATE(M4_WAR, 0xFF, 0x00001)
+
+// Encoder color format
+#define VIDEOEDITOR_ENCODER_COLOR_FORMAT OMX_COLOR_FormatYUV420Planar
+
+// Force using hardware encoder
+#define VIDEOEDITOR_FORCECODEC kHardwareCodecsOnly
+
+// Force Encoder to produce a DSI by sending fake input frames upon creation
+#define VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION
+
+#if defined(VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION) && \
+ !defined(VIDEOEDITOR_FORCECODEC)
+ #error "Cannot force DSI retrieval if codec type is not fixed"
+#endif
+
+/********************
+ * SOURCE CLASS *
+ ********************/
+
+namespace android {
+
+struct VideoEditorVideoEncoderSource : public MediaSource {
+ public:
+ static sp<VideoEditorVideoEncoderSource> Create();
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+ virtual status_t read(MediaBuffer **buffer,
+ const ReadOptions *options = NULL);
+ virtual int32_t storeBuffer(MediaBuffer *buffer);
+
+ protected:
+ virtual ~VideoEditorVideoEncoderSource();
+
+ private:
+ struct MediaBufferChain {
+ MediaBuffer* buffer;
+ MediaBufferChain* nextLink;
+ };
+ enum State {
+ CREATED,
+ STARTED,
+ ERROR
+ };
+ VideoEditorVideoEncoderSource();
+ MediaBufferChain* mFirstBufferLink;
+ MediaBufferChain* mLastBufferLink;
+ int32_t mNbBuffer;
+ bool mIsEOS;
+ State mState;
+};
+
+sp<VideoEditorVideoEncoderSource> VideoEditorVideoEncoderSource::Create() {
+
+ sp<VideoEditorVideoEncoderSource> aSource =
+ new VideoEditorVideoEncoderSource();
+ return aSource;
+}
+
+VideoEditorVideoEncoderSource::VideoEditorVideoEncoderSource():
+ mFirstBufferLink(NULL),
+ mLastBufferLink(NULL),
+ mNbBuffer(0),
+ mIsEOS(false),
+ mState(CREATED) {
+ LOGV("VideoEditorVideoEncoderSource::VideoEditorVideoEncoderSource");
+}
+
+VideoEditorVideoEncoderSource::~VideoEditorVideoEncoderSource() {
+
+ // Safety clean up
+ if( STARTED == mState ) {
+ stop();
+ }
+}
+
+status_t VideoEditorVideoEncoderSource::start(MetaData *meta) {
+ status_t err = OK;
+
+ LOGV("VideoEditorVideoEncoderSource::start() begin");
+
+ if( CREATED != mState ) {
+ LOGV("VideoEditorVideoEncoderSource::start: invalid state %d", mState);
+ return UNKNOWN_ERROR;
+ }
+ mState = STARTED;
+
+ LOGV("VideoEditorVideoEncoderSource::start() END (0x%x)", err);
+ return err;
+}
+
+status_t VideoEditorVideoEncoderSource::stop() {
+ status_t err = OK;
+
+ LOGV("VideoEditorVideoEncoderSource::stop() begin");
+
+ if( STARTED != mState ) {
+ LOGV("VideoEditorVideoEncoderSource::stop: invalid state %d", mState);
+ return UNKNOWN_ERROR;
+ }
+
+ // Release the buffer chain
+ int32_t i = 0;
+ MediaBufferChain* tmpLink = NULL;
+ while( mFirstBufferLink ) {
+ i++;
+ tmpLink = mFirstBufferLink;
+ mFirstBufferLink = mFirstBufferLink->nextLink;
+ delete tmpLink;
+ }
+ LOGV("VideoEditorVideoEncoderSource::stop : %d buffer remained", i);
+ mFirstBufferLink = NULL;
+ mLastBufferLink = NULL;
+
+ mState = CREATED;
+
+ LOGV("VideoEditorVideoEncoderSource::stop() END (0x%x)", err);
+ return err;
+}
+
+sp<MetaData> VideoEditorVideoEncoderSource::getFormat() {
+
+ LOGW("VideoEditorVideoEncoderSource::getFormat:THIS IS NOT IMPLEMENTED");
+ return NULL;
+}
+
+status_t VideoEditorVideoEncoderSource::read(MediaBuffer **buffer,
+ const ReadOptions *options) {
+ MediaSource::ReadOptions readOptions;
+ status_t err = OK;
+ MediaBufferChain* tmpLink = NULL;
+
+ LOGV("VideoEditorVideoEncoderSource::read() begin");
+
+ if ( STARTED != mState ) {
+ LOGV("VideoEditorVideoEncoderSource::read: invalid state %d", mState);
+ return UNKNOWN_ERROR;
+ }
+
+ // Get a buffer from the chain
+ if ( NULL == mFirstBufferLink ) {
+ *buffer = NULL;
+ if( mIsEOS ) {
+ LOGV("VideoEditorVideoEncoderSource::read : EOS");
+ return ERROR_END_OF_STREAM;
+ } else {
+ LOGV("VideoEditorVideoEncoderSource::read: no buffer available");
+ return ERROR_END_OF_STREAM;
+ }
+ }
+ *buffer = mFirstBufferLink->buffer;
+ tmpLink = mFirstBufferLink;
+ mFirstBufferLink = mFirstBufferLink->nextLink;
+
+ if ( NULL == mFirstBufferLink ) {
+ mLastBufferLink = NULL;
+ }
+ delete tmpLink;
+ mNbBuffer--;
+
+ LOGV("VideoEditorVideoEncoderSource::read() END (0x%x)", err);
+ return err;
+}
+
+int32_t VideoEditorVideoEncoderSource::storeBuffer(MediaBuffer *buffer) {
+ status_t err = OK;
+
+ LOGV("VideoEditorVideoEncoderSource::storeBuffer() begin");
+
+ if( NULL == buffer ) {
+ LOGV("VideoEditorVideoEncoderSource::storeBuffer : reached EOS");
+ mIsEOS = true;
+ } else {
+ MediaBufferChain* newLink = new MediaBufferChain;
+ newLink->buffer = buffer;
+ newLink->nextLink = NULL;
+ if( NULL != mLastBufferLink ) {
+ mLastBufferLink->nextLink = newLink;
+ } else {
+ mFirstBufferLink = newLink;
+ }
+ mLastBufferLink = newLink;
+ mNbBuffer++;
+ }
+ LOGV("VideoEditorVideoEncoderSource::storeBuffer() end");
+ return mNbBuffer;
+}
+
+/**
+ ******************************************************************************
+ * structure VideoEditorVideoEncoder_Context
+ * @brief This structure defines the context of the StageFright video encoder
+ * shell
+ ******************************************************************************
+*/
+typedef enum {
+ CREATED = 0x1,
+ OPENED = 0x2,
+ STARTED = 0x4,
+ BUFFERING = 0x8,
+ READING = 0x10
+} VideoEditorVideoEncoder_State;
+
+typedef struct {
+ VideoEditorVideoEncoder_State mState;
+ M4ENCODER_Format mFormat;
+ M4WRITER_DataInterface* mWriterDataInterface;
+ M4VPP_apply_fct* mPreProcFunction;
+ M4VPP_Context mPreProcContext;
+ M4SYS_AccessUnit* mAccessUnit;
+ M4ENCODER_Params* mCodecParams;
+ M4ENCODER_Header mHeader;
+ H264MCS_ProcessEncodedNALU_fct* mH264NALUPostProcessFct;
+ M4OSA_Context mH264NALUPostProcessCtx;
+ M4OSA_UInt32 mLastCTS;
+ sp<VideoEditorVideoEncoderSource> mEncoderSource;
+ OMXClient mClient;
+ sp<MediaSource> mEncoder;
+ OMX_COLOR_FORMATTYPE mEncoderColorFormat;
+
+ uint32_t mNbInputFrames;
+ double mFirstInputCts;
+ double mLastInputCts;
+ uint32_t mNbOutputFrames;
+ int64_t mFirstOutputCts;
+ int64_t mLastOutputCts;
+
+} VideoEditorVideoEncoder_Context;
+
+/********************
+ * TOOLS *
+ ********************/
+
+M4OSA_ERR VideoEditorVideoEncoder_getDSI(M4ENCODER_Context pContext,
+ sp<MetaData> metaData) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+ status_t result = OK;
+ int32_t nbBuffer = 0;
+ int32_t stride = 0;
+ int32_t height = 0;
+ int32_t framerate = 0;
+ int32_t isCodecConfig = 0;
+ size_t size = 0;
+ uint32_t codecFlags = 0;
+ MediaBuffer* inputBuffer = NULL;
+ MediaBuffer* outputBuffer = NULL;
+ sp<VideoEditorVideoEncoderSource> encoderSource = NULL;
+ sp<MediaSource> encoder = NULL;;
+ OMXClient client;
+
+ LOGV("VideoEditorVideoEncoder_getDSI begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != metaData.get(), M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+ VIDEOEDITOR_CHECK(CREATED == pEncoderContext->mState, M4ERR_STATE);
+
+ // Create the encoder source
+ encoderSource = VideoEditorVideoEncoderSource::Create();
+ VIDEOEDITOR_CHECK(NULL != encoderSource.get(), M4ERR_STATE);
+
+ // Connect to the OMX client
+ result = client.connect();
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+
+ // Create the OMX codec
+ // VIDEOEDITOR_FORCECODEC MUST be defined here
+ codecFlags |= OMXCodec::VIDEOEDITOR_FORCECODEC;
+ encoder = OMXCodec::Create(client.interface(), metaData, true,
+ encoderSource, NULL, codecFlags);
+ VIDEOEDITOR_CHECK(NULL != encoder.get(), M4ERR_STATE);
+
+ /**
+ * Send fake frames and retrieve the DSI
+ */
+ // Send a fake frame to the source
+ metaData->findInt32(kKeyStride, &stride);
+ metaData->findInt32(kKeyHeight, &height);
+ metaData->findInt32(kKeySampleRate, &framerate);
+ size = (size_t)(stride*height*3)/2;
+ inputBuffer = new MediaBuffer(size);
+ inputBuffer->meta_data()->setInt64(kKeyTime, 0);
+ nbBuffer = encoderSource->storeBuffer(inputBuffer);
+ encoderSource->storeBuffer(NULL); // Signal EOS
+
+ // Call read once to get the DSI
+ result = encoder->start();;
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+ result = encoder->read(&outputBuffer, NULL);
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+ VIDEOEDITOR_CHECK(outputBuffer->meta_data()->findInt32(
+ kKeyIsCodecConfig, &isCodecConfig) && isCodecConfig, M4ERR_STATE);
+
+ VIDEOEDITOR_CHECK(M4OSA_NULL == pEncoderContext->mHeader.pBuf, M4ERR_STATE);
+ if ( M4ENCODER_kH264 == pEncoderContext->mFormat ) {
+ // For H264, format the DSI
+ result = buildAVCCodecSpecificData(
+ (uint8_t**)(&(pEncoderContext->mHeader.pBuf)),
+ (size_t*)(&(pEncoderContext->mHeader.Size)),
+ (const uint8_t*)outputBuffer->data() + outputBuffer->range_offset(),
+ outputBuffer->range_length(), encoder->getFormat().get());
+ outputBuffer->release();
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+ } else {
+ // For MPEG4, just copy the DSI
+ pEncoderContext->mHeader.Size =
+ (M4OSA_UInt32)outputBuffer->range_length();
+ SAFE_MALLOC(pEncoderContext->mHeader.pBuf, M4OSA_Int8,
+ pEncoderContext->mHeader.Size, "Encoder header");
+ M4OSA_memcpy(pEncoderContext->mHeader.pBuf,
+ (M4OSA_MemAddr8)(outputBuffer->data())+outputBuffer->range_offset(),
+ pEncoderContext->mHeader.Size);
+ outputBuffer->release();
+ }
+
+ result = encoder->stop();
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+
+cleanUp:
+ // Destroy the graph
+ if ( encoder != NULL ) { encoder.clear(); }
+ client.disconnect();
+ if ( encoderSource != NULL ) { encoderSource.clear(); }
+ if ( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_getDSI no error");
+ } else {
+ LOGV("VideoEditorVideoEncoder_getDSI ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_getDSI end");
+ return err;
+}
+/********************
+ * ENGINE INTERFACE *
+ ********************/
+
+M4OSA_ERR VideoEditorVideoEncoder_cleanup(M4ENCODER_Context pContext) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorVideoEncoder_cleanup begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+ VIDEOEDITOR_CHECK(CREATED == pEncoderContext->mState, M4ERR_STATE);
+
+ // Release memory
+ SAFE_FREE(pEncoderContext->mHeader.pBuf);
+ SAFE_FREE(pEncoderContext);
+ pContext = M4OSA_NULL;
+
+cleanUp:
+ if ( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_cleanup no error");
+ } else {
+ LOGV("VideoEditorVideoEncoder_cleanup ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_cleanup end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_init(M4ENCODER_Format format,
+ M4ENCODER_Context* pContext,
+ M4WRITER_DataInterface* pWriterDataInterface,
+ M4VPP_apply_fct* pVPPfct, M4VPP_Context pVPPctxt,
+ M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData) {
+
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorVideoEncoder_init begin: format %d", format);
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pWriterDataInterface, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pVPPfct, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pVPPctxt, M4ERR_PARAMETER);
+
+ // Context allocation & initialization
+ SAFE_MALLOC(pEncoderContext, VideoEditorVideoEncoder_Context, 1,
+ "VideoEditorVideoEncoder");
+ pEncoderContext->mState = CREATED;
+ pEncoderContext->mFormat = format;
+ pEncoderContext->mWriterDataInterface = pWriterDataInterface;
+ pEncoderContext->mPreProcFunction = pVPPfct;
+ pEncoderContext->mPreProcContext = pVPPctxt;
+
+ *pContext = pEncoderContext;
+
+cleanUp:
+ if ( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_init no error");
+ } else {
+ VideoEditorVideoEncoder_cleanup(pEncoderContext);
+ *pContext = M4OSA_NULL;
+ LOGV("VideoEditorVideoEncoder_init ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_init end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_init_H263(M4ENCODER_Context* pContext,
+ M4WRITER_DataInterface* pWriterDataInterface, M4VPP_apply_fct* pVPPfct,
+ M4VPP_Context pVPPctxt, M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData)
+ {
+
+ return VideoEditorVideoEncoder_init(M4ENCODER_kH263, pContext,
+ pWriterDataInterface, pVPPfct, pVPPctxt, pExternalAPI, pUserData);
+}
+
+
+M4OSA_ERR VideoEditorVideoEncoder_init_MPEG4(M4ENCODER_Context* pContext,
+ M4WRITER_DataInterface* pWriterDataInterface, M4VPP_apply_fct* pVPPfct,
+ M4VPP_Context pVPPctxt, M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData)
+ {
+
+ return VideoEditorVideoEncoder_init(M4ENCODER_kMPEG4, pContext,
+ pWriterDataInterface, pVPPfct, pVPPctxt, pExternalAPI, pUserData);
+}
+
+
+M4OSA_ERR VideoEditorVideoEncoder_init_H264(M4ENCODER_Context* pContext,
+ M4WRITER_DataInterface* pWriterDataInterface, M4VPP_apply_fct* pVPPfct,
+ M4VPP_Context pVPPctxt, M4OSA_Void* pExternalAPI, M4OSA_Void* pUserData)
+ {
+
+ return VideoEditorVideoEncoder_init(M4ENCODER_kH264, pContext,
+ pWriterDataInterface, pVPPfct, pVPPctxt, pExternalAPI, pUserData);
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_close(M4ENCODER_Context pContext) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorVideoEncoder_close begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+ VIDEOEDITOR_CHECK(OPENED == pEncoderContext->mState, M4ERR_STATE);
+
+ // Release memory
+ SAFE_FREE(pEncoderContext->mCodecParams);
+
+ // Destroy the graph
+ pEncoderContext->mEncoder.clear();
+ pEncoderContext->mClient.disconnect();
+ pEncoderContext->mEncoderSource.clear();
+
+ // Set the new state
+ pEncoderContext->mState = CREATED;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_close no error");
+ } else {
+ LOGV("VideoEditorVideoEncoder_close ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_close end");
+ return err;
+}
+
+
+M4OSA_ERR VideoEditorVideoEncoder_open(M4ENCODER_Context pContext,
+ M4SYS_AccessUnit* pAU, M4OSA_Void* pParams) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+ M4ENCODER_Params* pCodecParams = M4OSA_NULL;
+ status_t result = OK;
+ sp<MetaData> encoderMetadata = NULL;
+ const char* mime = NULL;
+ int32_t iProfile = 0;
+ int32_t iFrameRate = 0;
+ uint32_t codecFlags = 0;
+
+ LOGV(">>> VideoEditorVideoEncoder_open begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pAU, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pParams, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+ pCodecParams = (M4ENCODER_Params*)pParams;
+ VIDEOEDITOR_CHECK(CREATED == pEncoderContext->mState, M4ERR_STATE);
+
+ // Context initialization
+ pEncoderContext->mAccessUnit = pAU;
+
+ // Allocate & initialize the encoding parameters
+ SAFE_MALLOC(pEncoderContext->mCodecParams, M4ENCODER_Params, 1,
+ "VideoEditorVideoEncoder");
+
+
+ pEncoderContext->mCodecParams->InputFormat = pCodecParams->InputFormat;
+ pEncoderContext->mCodecParams->InputFrameWidth =
+ pCodecParams->InputFrameWidth;
+ pEncoderContext->mCodecParams->InputFrameHeight =
+ pCodecParams->InputFrameHeight;
+ pEncoderContext->mCodecParams->FrameWidth = pCodecParams->FrameWidth;
+ pEncoderContext->mCodecParams->FrameHeight = pCodecParams->FrameHeight;
+ pEncoderContext->mCodecParams->Bitrate = pCodecParams->Bitrate;
+ pEncoderContext->mCodecParams->FrameRate = pCodecParams->FrameRate;
+ pEncoderContext->mCodecParams->Format = pCodecParams->Format;
+
+ // Check output format consistency and resolution
+ VIDEOEDITOR_CHECK(
+ pEncoderContext->mCodecParams->Format == pEncoderContext->mFormat,
+ M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(0 == pEncoderContext->mCodecParams->FrameWidth % 16,
+ M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(0 == pEncoderContext->mCodecParams->FrameHeight % 16,
+ M4ERR_PARAMETER);
+
+ /**
+ * StageFright graph building
+ */
+
+ // Create the meta data for the encoder
+ encoderMetadata = new MetaData;
+ switch( pEncoderContext->mCodecParams->Format ) {
+ case M4ENCODER_kH263:
+ mime = MEDIA_MIMETYPE_VIDEO_H263;
+ iProfile = OMX_VIDEO_H263ProfileBaseline;
+ break;
+ case M4ENCODER_kMPEG4:
+ mime = MEDIA_MIMETYPE_VIDEO_MPEG4;
+ iProfile = OMX_VIDEO_MPEG4ProfileSimple;
+ break;
+ case M4ENCODER_kH264:
+ mime = MEDIA_MIMETYPE_VIDEO_AVC;
+ iProfile = OMX_VIDEO_AVCProfileBaseline;
+ break;
+ default:
+ VIDEOEDITOR_CHECK(!"VideoEncoder_open : incorrect input format",
+ M4ERR_PARAMETER);
+ break;
+ }
+ encoderMetadata->setCString(kKeyMIMEType, mime);
+ encoderMetadata->setInt32(kKeyVideoProfile, iProfile);
+ encoderMetadata->setInt32(kKeyWidth,
+ (int32_t)pEncoderContext->mCodecParams->FrameWidth);
+ encoderMetadata->setInt32(kKeyStride,
+ (int32_t)pEncoderContext->mCodecParams->FrameWidth);
+ encoderMetadata->setInt32(kKeyHeight,
+ (int32_t)pEncoderContext->mCodecParams->FrameHeight);
+ encoderMetadata->setInt32(kKeySliceHeight,
+ (int32_t)pEncoderContext->mCodecParams->FrameHeight);
+
+ switch( pEncoderContext->mCodecParams->FrameRate ) {
+ case M4ENCODER_k5_FPS: iFrameRate = 5; break;
+ case M4ENCODER_k7_5_FPS: iFrameRate = 8; break;
+ case M4ENCODER_k10_FPS: iFrameRate = 10; break;
+ case M4ENCODER_k12_5_FPS: iFrameRate = 13; break;
+ case M4ENCODER_k15_FPS: iFrameRate = 15; break;
+ case M4ENCODER_k20_FPS: iFrameRate = 20; break;
+ case M4ENCODER_k25_FPS: iFrameRate = 25; break;
+ case M4ENCODER_k30_FPS: iFrameRate = 30; break;
+ case M4ENCODER_kVARIABLE_FPS:
+ iFrameRate = 30;
+ LOGI("Frame rate set to M4ENCODER_kVARIABLE_FPS: set to 30");
+ break;
+ case M4ENCODER_kUSE_TIMESCALE:
+ iFrameRate = 30;
+ LOGI("Frame rate set to M4ENCODER_kUSE_TIMESCALE: set to 30");
+ break;
+
+ default:
+ VIDEOEDITOR_CHECK(!"VideoEncoder_open:incorrect framerate",
+ M4ERR_STATE);
+ break;
+ }
+ encoderMetadata->setInt32(kKeyFrameRate, iFrameRate);
+ encoderMetadata->setInt32(kKeyBitRate,
+ (int32_t)pEncoderContext->mCodecParams->Bitrate);
+ encoderMetadata->setInt32(kKeyIFramesInterval, 1);
+
+ pEncoderContext->mEncoderColorFormat = VIDEOEDITOR_ENCODER_COLOR_FORMAT;
+ encoderMetadata->setInt32(kKeyColorFormat,
+ pEncoderContext->mEncoderColorFormat);
+
+#ifdef VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION
+ // Get the encoder DSI
+ err = VideoEditorVideoEncoder_getDSI(pEncoderContext, encoderMetadata);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+#endif /* VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION */
+
+ // Create the encoder source
+ pEncoderContext->mEncoderSource = VideoEditorVideoEncoderSource::Create();
+ VIDEOEDITOR_CHECK(
+ NULL != pEncoderContext->mEncoderSource.get(), M4ERR_STATE);
+
+ // Connect to the OMX client
+ result = pEncoderContext->mClient.connect();
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+
+ // Create the OMX codec
+#ifdef VIDEOEDITOR_FORCECODEC
+ codecFlags |= OMXCodec::VIDEOEDITOR_FORCECODEC;
+#endif /* VIDEOEDITOR_FORCECODEC */
+ pEncoderContext->mEncoder = OMXCodec::Create(
+ pEncoderContext->mClient.interface(), encoderMetadata, true,
+ pEncoderContext->mEncoderSource, NULL, codecFlags);
+ VIDEOEDITOR_CHECK(NULL != pEncoderContext->mEncoder.get(), M4ERR_STATE);
+ LOGV("VideoEditorVideoEncoder_open : DONE");
+
+ // Set the new state
+ pEncoderContext->mState = OPENED;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_open no error");
+ } else {
+ VideoEditorVideoEncoder_close(pEncoderContext);
+ LOGV("VideoEditorVideoEncoder_open ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_open end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_processOutputBuffer(
+ M4ENCODER_Context pContext, MediaBuffer* buffer);
+M4OSA_ERR VideoEditorVideoEncoder_processInputBuffer(
+ M4ENCODER_Context pContext, M4OSA_Double Cts,
+ M4OSA_Bool bReachedEOS) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+ M4VIFI_ImagePlane pOutPlane[3];
+ MediaBuffer* buffer = NULL;
+ int32_t nbBuffer = 0;
+
+ LOGV("VideoEditorVideoEncoder_processInputBuffer begin: cts %f", Cts);
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+ pOutPlane[0].pac_data = M4OSA_NULL;
+ pOutPlane[1].pac_data = M4OSA_NULL;
+ pOutPlane[2].pac_data = M4OSA_NULL;
+
+ if ( M4OSA_FALSE == bReachedEOS ) {
+ M4OSA_UInt32 sizeY = pEncoderContext->mCodecParams->FrameWidth *
+ pEncoderContext->mCodecParams->FrameHeight;
+ M4OSA_UInt32 sizeU = sizeY >> 2;
+ M4OSA_UInt32 size = sizeY + 2*sizeU;
+ M4OSA_UInt8* pData = M4OSA_NULL;
+ buffer = new MediaBuffer((size_t)size);
+ pData = (M4OSA_UInt8*)buffer->data() + buffer->range_offset();
+
+ // Prepare the output image for pre-processing
+ pOutPlane[0].u_width = pEncoderContext->mCodecParams->FrameWidth;
+ pOutPlane[0].u_height = pEncoderContext->mCodecParams->FrameHeight;
+ pOutPlane[0].u_topleft = 0;
+ pOutPlane[0].u_stride = pOutPlane[0].u_width;
+ pOutPlane[1].u_width = pOutPlane[0].u_width/2;
+ pOutPlane[1].u_height = pOutPlane[0].u_height/2;
+ pOutPlane[1].u_topleft = 0;
+ pOutPlane[1].u_stride = pOutPlane[0].u_stride/2;
+ pOutPlane[2].u_width = pOutPlane[1].u_width;
+ pOutPlane[2].u_height = pOutPlane[1].u_height;
+ pOutPlane[2].u_topleft = 0;
+ pOutPlane[2].u_stride = pOutPlane[1].u_stride;
+
+ switch( pEncoderContext->mEncoderColorFormat ) {
+ case OMX_COLOR_FormatYUV420Planar:
+ pOutPlane[0].pac_data = pData;
+ pOutPlane[1].pac_data = pData + sizeY;
+ pOutPlane[2].pac_data = pData + sizeY + sizeU;
+ break;
+ case OMX_COLOR_FormatYUV420SemiPlanar:
+ pOutPlane[0].pac_data = pData;
+ SAFE_MALLOC(pOutPlane[1].pac_data, M4VIFI_UInt8,
+ pOutPlane[1].u_height*pOutPlane[1].u_stride,"OutputPlaneU");
+ SAFE_MALLOC(pOutPlane[2].pac_data, M4VIFI_UInt8,
+ pOutPlane[2].u_height*pOutPlane[2].u_stride,"OutputPlaneV");
+ break;
+ default:
+ LOGV("VideoEditorVideoEncoder_processInputBuffer : unsupported "
+ "color format 0x%X", pEncoderContext->mEncoderColorFormat);
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER);
+ break;
+ }
+
+ // Apply pre-processing
+ err = pEncoderContext->mPreProcFunction(
+ pEncoderContext->mPreProcContext, M4OSA_NULL, pOutPlane);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+
+ // Convert to MediaBuffer format if necessary
+ if( OMX_COLOR_FormatYUV420SemiPlanar == \
+ pEncoderContext->mEncoderColorFormat ) {
+ M4OSA_UInt8* pTmpData = M4OSA_NULL;
+ pTmpData = pData + sizeY;
+ // Highly unoptimized copy...
+ for( M4OSA_UInt32 i=0; i<sizeU; i++ ) {
+ *pTmpData = pOutPlane[2].pac_data[i]; pTmpData++;
+ *pTmpData = pOutPlane[1].pac_data[i]; pTmpData++;
+ }
+ }
+
+ // Set the metadata
+ buffer->meta_data()->setInt64(kKeyTime, (int64_t)(Cts*1000));
+ }
+
+ // Push the buffer to the source, a NULL buffer, notifies the source of EOS
+ nbBuffer = pEncoderContext->mEncoderSource->storeBuffer(buffer);
+ if ( VIDEOEDITOR_MIN_BUFFER_NB > nbBuffer ) {
+ LOGV("VideoEncoder_processInputBuffer not enough source buffer"
+ "%d", nbBuffer);
+ err = M4WAR_SF_LOW_BUFFER;
+ }
+
+cleanUp:
+ if ( OMX_COLOR_FormatYUV420SemiPlanar == \
+ pEncoderContext->mEncoderColorFormat ) {
+ // Y plane has not been allocated
+ if ( pOutPlane[1].pac_data ) {
+ SAFE_FREE(pOutPlane[1].pac_data);
+ }
+ if ( pOutPlane[2].pac_data ) {
+ SAFE_FREE(pOutPlane[2].pac_data);
+ }
+ }
+ if ( (M4NO_ERROR == err) || (M4WAR_SF_LOW_BUFFER == err) ) {
+ LOGV("VideoEditorVideoEncoder_processInputBuffer error 0x%X", err);
+ } else {
+ if( NULL != buffer ) {
+ buffer->release();
+ }
+ LOGV("VideoEditorVideoEncoder_processInputBuffer ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_processInputBuffer end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_processOutputBuffer(
+ M4ENCODER_Context pContext, MediaBuffer* buffer) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+ M4OSA_UInt32 Cts = 0;
+ int32_t i32Tmp = 0;
+ int64_t i64Tmp = 0;
+ status_t result = OK;
+
+ LOGV("VideoEditorVideoEncoder_processOutputBuffer begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != buffer, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+
+ // Process the returned AU
+ if ( 0 == buffer->range_length() ) {
+ // Encoder has no data yet, nothing unusual
+ LOGV("VideoEditorVideoEncoder_processOutputBuffer : buffer is empty");
+ goto cleanUp;
+ }
+ VIDEOEDITOR_CHECK(0 == ((M4OSA_UInt32)buffer->data())%4, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(buffer->meta_data().get(), M4ERR_PARAMETER);
+ if ( buffer->meta_data()->findInt32(kKeyIsCodecConfig, &i32Tmp) && i32Tmp ){
+#if 1
+ { // Display the DSI
+ LOGV("VideoEditorVideoEncoder_processOutputBuffer DSI %d",
+ buffer->range_length());
+ uint8_t* tmp = (uint8_t*)(buffer->data());
+ for( uint32_t i=0; i<buffer->range_length(); i++ ) {
+ LOGV("DSI [%d] %.2X", i, tmp[i]);
+ }
+ }
+#endif
+
+#ifndef VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION
+ VIDEOEDITOR_CHECK(M4OSA_NULL == pEncoderContext->mHeader.pBuf,
+ M4ERR_STATE);
+ if ( M4ENCODER_kH264 == pEncoderContext->mFormat ) {
+ result = buildAVCCodecSpecificData(
+ (uint8_t**)(&(pEncoderContext->mHeader.pBuf)),
+ (size_t*)(&(pEncoderContext->mHeader.Size)),
+ (const uint8_t *)buffer->data() + buffer->range_offset(),
+ buffer->range_length(),
+ pEncoderContext->mEncoder->getFormat().get());
+ } else {
+ pEncoderContext->mHeader.Size =
+ (M4OSA_UInt32)buffer->range_length();
+ SAFE_MALLOC(pEncoderContext->mHeader.pBuf, M4OSA_Int8,
+ pEncoderContext->mHeader.Size, "Encoder header");
+ M4OSA_memcpy(pEncoderContext->mHeader.pBuf,
+ (M4OSA_MemAddr8)(buffer->data())+buffer->range_offset(),
+ pEncoderContext->mHeader.Size);
+ }
+#endif /* VIDEOEDITOR_ENCODER_GET_DSI_AT_CREATION */
+ } else {
+ // Check the CTS
+ VIDEOEDITOR_CHECK(buffer->meta_data()->findInt64(kKeyTime, &i64Tmp),
+ M4ERR_STATE);
+
+ pEncoderContext->mNbOutputFrames++;
+ if ( 0 > pEncoderContext->mFirstOutputCts ) {
+ pEncoderContext->mFirstOutputCts = i64Tmp;
+ }
+ pEncoderContext->mLastOutputCts = i64Tmp;
+
+ Cts = (M4OSA_Int32)(i64Tmp/1000);
+ LOGV("[TS_CHECK] VI/ENC WRITE frame %d @ %lld -> %d (last %d)",
+ pEncoderContext->mNbOutputFrames, i64Tmp, Cts,
+ pEncoderContext->mLastCTS);
+ if ( Cts < pEncoderContext->mLastCTS ) {
+ LOGV("VideoEncoder_processOutputBuffer WARNING : Cts is going "
+ "backwards %d < %d", Cts, pEncoderContext->mLastCTS);
+ goto cleanUp;
+ }
+ LOGV("VideoEditorVideoEncoder_processOutputBuffer : %d %d",
+ Cts, pEncoderContext->mLastCTS);
+
+ // Retrieve the AU container
+ err = pEncoderContext->mWriterDataInterface->pStartAU(
+ pEncoderContext->mWriterDataInterface->pWriterContext,
+ pEncoderContext->mAccessUnit->stream->streamID,
+ pEncoderContext->mAccessUnit);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+
+ // Format the AU
+ VIDEOEDITOR_CHECK(
+ buffer->range_length() <= pEncoderContext->mAccessUnit->size,
+ M4ERR_PARAMETER);
+ // Remove H264 AU start code
+ if ( M4ENCODER_kH264 == pEncoderContext->mFormat ) {
+ if (!memcmp((const uint8_t *)buffer->data() + \
+ buffer->range_offset(), "\x00\x00\x00\x01", 4) ) {
+ buffer->set_range(buffer->range_offset() + 4,
+ buffer->range_length() - 4);
+ }
+ }
+
+ if ( (M4ENCODER_kH264 == pEncoderContext->mFormat) &&
+ (M4OSA_NULL != pEncoderContext->mH264NALUPostProcessFct) ) {
+ // H264 trimming case, NALU post processing is needed
+ M4OSA_Int32 outputSize = pEncoderContext->mAccessUnit->size;
+ err = pEncoderContext->mH264NALUPostProcessFct(
+ pEncoderContext->mH264NALUPostProcessCtx,
+ (M4OSA_UInt8*)buffer->data()+buffer->range_offset(),
+ buffer->range_length(),
+ (M4OSA_UInt8*)pEncoderContext->mAccessUnit->dataAddress,
+ &outputSize);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+ pEncoderContext->mAccessUnit->size = (M4OSA_UInt32)outputSize;
+ } else {
+ // The AU can just be copied
+ M4OSA_memcpy((M4OSA_MemAddr8)pEncoderContext->mAccessUnit->\
+ dataAddress, (M4OSA_MemAddr8)(buffer->data())+buffer->\
+ range_offset(), buffer->range_length());
+ pEncoderContext->mAccessUnit->size =
+ (M4OSA_UInt32)buffer->range_length();
+ }
+
+ if ( buffer->meta_data()->findInt32(kKeyIsSyncFrame,&i32Tmp) && i32Tmp){
+ pEncoderContext->mAccessUnit->attribute = AU_RAP;
+ } else {
+ pEncoderContext->mAccessUnit->attribute = AU_B_Frame;
+ }
+ pEncoderContext->mLastCTS = Cts;
+ pEncoderContext->mAccessUnit->CTS = Cts;
+ pEncoderContext->mAccessUnit->DTS = Cts;
+
+ LOGV("VideoEditorVideoEncoder_processOutputBuffer: AU @ 0x%X 0x%X %d %d",
+ pEncoderContext->mAccessUnit->dataAddress,
+ *pEncoderContext->mAccessUnit->dataAddress,
+ pEncoderContext->mAccessUnit->size,
+ pEncoderContext->mAccessUnit->CTS);
+
+ // Write the AU
+ err = pEncoderContext->mWriterDataInterface->pProcessAU(
+ pEncoderContext->mWriterDataInterface->pWriterContext,
+ pEncoderContext->mAccessUnit->stream->streamID,
+ pEncoderContext->mAccessUnit);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+ }
+
+cleanUp:
+ buffer->release();
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_processOutputBuffer no error");
+ } else {
+ SAFE_FREE(pEncoderContext->mHeader.pBuf);
+ pEncoderContext->mHeader.Size = 0;
+ LOGV("VideoEditorVideoEncoder_processOutputBuffer ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_processOutputBuffer end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_encode(M4ENCODER_Context pContext,
+ M4VIFI_ImagePlane* pInPlane, M4OSA_Double Cts,
+ M4ENCODER_FrameMode FrameMode) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+ status_t result = OK;
+ MediaBuffer* outputBuffer = NULL;
+
+ LOGV("VideoEditorVideoEncoder_encode 0x%X %f %d", pInPlane, Cts, FrameMode);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+ if ( STARTED == pEncoderContext->mState ) {
+ pEncoderContext->mState = BUFFERING;
+ }
+ VIDEOEDITOR_CHECK(
+ (BUFFERING | READING) & pEncoderContext->mState, M4ERR_STATE);
+
+ pEncoderContext->mNbInputFrames++;
+ if ( 0 > pEncoderContext->mFirstInputCts ) {
+ pEncoderContext->mFirstInputCts = Cts;
+ }
+ pEncoderContext->mLastInputCts = Cts;
+
+ LOGV("VideoEditorVideoEncoder_encode 0x%X %d %f (%d)", pInPlane, FrameMode,
+ Cts, pEncoderContext->mLastCTS);
+
+ // Push the input buffer to the encoder source
+ err = VideoEditorVideoEncoder_processInputBuffer(pEncoderContext, Cts,
+ M4OSA_FALSE);
+ VIDEOEDITOR_CHECK((M4NO_ERROR == err) || (M4WAR_SF_LOW_BUFFER == err), err);
+
+ // Notify the source in case of EOS
+ if ( M4ENCODER_kLastFrame == FrameMode ) {
+ err = VideoEditorVideoEncoder_processInputBuffer(
+ pEncoderContext, 0, M4OSA_TRUE);
+ VIDEOEDITOR_CHECK((M4NO_ERROR == err) || (M4WAR_SF_LOW_BUFFER == err),
+ err);
+ }
+
+ if ( BUFFERING == pEncoderContext->mState ) {
+ if ( M4WAR_SF_LOW_BUFFER == err ) {
+ // Insufficient prefetch, do not encode
+ err = M4NO_ERROR;
+ goto cleanUp;
+ } else {
+ // Prefetch is complete, start reading
+ pEncoderContext->mState = READING;
+ }
+ }
+ // Read
+ result = pEncoderContext->mEncoder->read(&outputBuffer, NULL);
+ if( OK != result ) {
+ LOGV("VideoEditorVideoEncoder_encode: encoder returns 0x%X", result);
+ }
+
+ if( ERROR_END_OF_STREAM == result ) {
+ if( outputBuffer != NULL ) {
+ LOGV("VideoEditorVideoEncoder_encode : EOS w/ buffer");
+ }
+ VIDEOEDITOR_CHECK(0 == VIDEOEDITOR_MIN_BUFFER_NB, M4ERR_STATE);
+ // No output provided here, just exit
+ goto cleanUp;
+ }
+ VIDEOEDITOR_CHECK((OK == result) || (ERROR_END_OF_STREAM == result),
+ M4ERR_STATE);
+
+ // Provide the encoded AU to the writer
+ err = VideoEditorVideoEncoder_processOutputBuffer(pEncoderContext,
+ outputBuffer);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_encode no error");
+ } else {
+ LOGV("VideoEditorVideoEncoder_encode ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_encode end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_start(M4ENCODER_Context pContext) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+ status_t result = OK;
+
+ LOGV("VideoEditorVideoEncoder_start begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+ VIDEOEDITOR_CHECK(OPENED == pEncoderContext->mState, M4ERR_STATE);
+
+ pEncoderContext->mNbInputFrames = 0;
+ pEncoderContext->mFirstInputCts = -1.0;
+ pEncoderContext->mLastInputCts = -1.0;
+ pEncoderContext->mNbOutputFrames = 0;
+ pEncoderContext->mFirstOutputCts = -1;
+ pEncoderContext->mLastOutputCts = -1;
+
+ result = pEncoderContext->mEncoder->start();
+ VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE);
+
+ // Set the new state
+ pEncoderContext->mState = STARTED;
+
+cleanUp:
+ if ( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_start no error");
+ } else {
+ LOGV("VideoEditorVideoEncoder_start ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_start end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_stop(M4ENCODER_Context pContext) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+ MediaBuffer* outputBuffer = NULL;
+ status_t result = OK;
+
+ LOGV("VideoEditorVideoEncoder_stop begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+
+ // Process the remaining buffers if necessary
+ if ( (BUFFERING | READING) & pEncoderContext->mState ) {
+ // Send EOS again just in case
+ err = VideoEditorVideoEncoder_processInputBuffer(pEncoderContext, 0,
+ M4OSA_TRUE);
+ VIDEOEDITOR_CHECK((M4NO_ERROR == err) || (M4WAR_SF_LOW_BUFFER == err),
+ err);
+ while( OK == result ) {
+ result = pEncoderContext->mEncoder->read(&outputBuffer, NULL);
+ if ( OK == result ) {
+ err = VideoEditorVideoEncoder_processOutputBuffer(
+ pEncoderContext, outputBuffer);
+ VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
+ }
+ }
+ pEncoderContext->mState = STARTED;
+ }
+
+ // Stop the graph module if necessary
+ if ( STARTED == pEncoderContext->mState ) {
+ pEncoderContext->mEncoder->stop();
+ pEncoderContext->mState = OPENED;
+ }
+
+ if ( pEncoderContext->mNbInputFrames != pEncoderContext->mNbInputFrames ) {
+ LOGV("VideoEditorVideoEncoder_stop: some frames were not encoded %d %d",
+ pEncoderContext->mNbInputFrames, pEncoderContext->mNbInputFrames);
+ }
+
+cleanUp:
+ if ( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_stop no error");
+ } else {
+ LOGV("VideoEditorVideoEncoder_stop ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_stop end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_regulBitRate(M4ENCODER_Context pContext) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorVideoEncoder_regulBitRate begin");
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+
+ LOGV("VideoEditorVideoEncoder_regulBitRate : THIS IS NOT IMPLEMENTED");
+
+cleanUp:
+ if ( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_regulBitRate no error");
+ } else {
+ LOGV("VideoEditorVideoEncoder_regulBitRate ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_regulBitRate end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_setOption(M4ENCODER_Context pContext,
+ M4OSA_UInt32 optionID, M4OSA_DataOption optionValue) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorVideoEncoder_setOption start optionID 0x%X", optionID);
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+
+ switch( optionID ) {
+ case M4ENCODER_kOptionID_SetH264ProcessNALUfctsPtr:
+ pEncoderContext->mH264NALUPostProcessFct =
+ (H264MCS_ProcessEncodedNALU_fct*)optionValue;
+ break;
+ case M4ENCODER_kOptionID_H264ProcessNALUContext:
+ pEncoderContext->mH264NALUPostProcessCtx =
+ (M4OSA_Context)optionValue;
+ break;
+ default:
+ LOGV("VideoEditorVideoEncoder_setOption: unsupported optionId 0x%X",
+ optionID);
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID);
+ break;
+ }
+
+cleanUp:
+ if ( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_setOption no error");
+ } else {
+ LOGV("VideoEditorVideoEncoder_setOption ERROR 0x%X", err);
+ }
+ LOGV("VideoEditorVideoEncoder_setOption end");
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_getOption(M4ENCODER_Context pContext,
+ M4OSA_UInt32 optionID, M4OSA_DataOption optionValue) {
+ M4OSA_ERR err = M4NO_ERROR;
+ VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+
+ LOGV("VideoEditorVideoEncoder_getOption begin optinId 0x%X", optionID);
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ pEncoderContext = (VideoEditorVideoEncoder_Context*)pContext;
+
+ switch( optionID ) {
+ case M4ENCODER_kOptionID_EncoderHeader:
+ VIDEOEDITOR_CHECK(
+ M4OSA_NULL != pEncoderContext->mHeader.pBuf, M4ERR_STATE);
+ *(M4ENCODER_Header**)optionValue = &(pEncoderContext->mHeader);
+ break;
+ default:
+ LOGV("VideoEditorVideoEncoder_getOption: unsupported optionId 0x%X",
+ optionID);
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID);
+ break;
+ }
+
+cleanUp:
+ if ( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_getOption no error");
+ } else {
+ LOGV("VideoEditorVideoEncoder_getOption ERROR 0x%X", err);
+ }
+ return err;
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_getInterface(M4ENCODER_Format format,
+ M4ENCODER_Format* pFormat,
+ M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
+ M4OSA_ERR err = M4NO_ERROR;
+
+ // Input parameters check
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pFormat, M4ERR_PARAMETER);
+ VIDEOEDITOR_CHECK(M4OSA_NULL != pEncoderInterface, M4ERR_PARAMETER);
+
+ LOGV("VideoEditorVideoEncoder_getInterface begin 0x%x 0x%x %d", pFormat,
+ pEncoderInterface, mode);
+
+ SAFE_MALLOC(*pEncoderInterface, M4ENCODER_GlobalInterface, 1,
+ "VideoEditorVideoEncoder");
+
+ *pFormat = format;
+
+ switch( format ) {
+ case M4ENCODER_kH263:
+ {
+ (*pEncoderInterface)->pFctInit =
+ VideoEditorVideoEncoder_init_H263;
+ break;
+ }
+ case M4ENCODER_kMPEG4:
+ {
+ (*pEncoderInterface)->pFctInit =
+ VideoEditorVideoEncoder_init_MPEG4;
+ break;
+ }
+ case M4ENCODER_kH264:
+ {
+ (*pEncoderInterface)->pFctInit =
+ VideoEditorVideoEncoder_init_H264;
+ break;
+ }
+ default:
+ LOGV("VideoEditorVideoEncoder_getInterface : unsupported format %d",
+ format);
+ VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER);
+ break;
+ }
+ (*pEncoderInterface)->pFctOpen = VideoEditorVideoEncoder_open;
+ (*pEncoderInterface)->pFctStart = VideoEditorVideoEncoder_start;
+ (*pEncoderInterface)->pFctStop = VideoEditorVideoEncoder_stop;
+ (*pEncoderInterface)->pFctPause = M4OSA_NULL;
+ (*pEncoderInterface)->pFctResume = M4OSA_NULL;
+ (*pEncoderInterface)->pFctClose = VideoEditorVideoEncoder_close;
+ (*pEncoderInterface)->pFctCleanup = VideoEditorVideoEncoder_cleanup;
+ (*pEncoderInterface)->pFctRegulBitRate =
+ VideoEditorVideoEncoder_regulBitRate;
+ (*pEncoderInterface)->pFctEncode = VideoEditorVideoEncoder_encode;
+ (*pEncoderInterface)->pFctSetOption = VideoEditorVideoEncoder_setOption;
+ (*pEncoderInterface)->pFctGetOption = VideoEditorVideoEncoder_getOption;
+
+cleanUp:
+ if( M4NO_ERROR == err ) {
+ LOGV("VideoEditorVideoEncoder_getInterface no error");
+ } else {
+ *pEncoderInterface = M4OSA_NULL;
+ LOGV("VideoEditorVideoEncoder_getInterface ERROR 0x%X", err);
+ }
+ return err;
+}
+
+extern "C" {
+
+M4OSA_ERR VideoEditorVideoEncoder_getInterface_H263(M4ENCODER_Format* pFormat,
+ M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
+ return VideoEditorVideoEncoder_getInterface(M4ENCODER_kH263, pFormat,
+ pEncoderInterface, mode);
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_getInterface_MPEG4(M4ENCODER_Format* pFormat,
+ M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
+ return VideoEditorVideoEncoder_getInterface(M4ENCODER_kMPEG4, pFormat,
+ pEncoderInterface, mode);
+}
+
+M4OSA_ERR VideoEditorVideoEncoder_getInterface_H264(M4ENCODER_Format* pFormat,
+ M4ENCODER_GlobalInterface** pEncoderInterface, M4ENCODER_OpenMode mode){
+ return VideoEditorVideoEncoder_getInterface(M4ENCODER_kH264, pFormat,
+ pEncoderInterface, mode);
+
+}
+
+} // extern "C"
+
+} // namespace android