diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:43:59 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:43:59 -0800 |
commit | 4170b2688824896bd659e66afe41c4e65f8a9c8b (patch) | |
tree | 7190b917de3836bfb1161198e77ec01f163de686 | |
parent | 1d9c7dff7d4022e4a8f5553a2e79ce586fcb3da5 (diff) | |
download | opencore-4170b2688824896bd659e66afe41c4e65f8a9c8b.tar.gz |
auto import from //branches/cupcake/...@130745
26 files changed, 1119 insertions, 795 deletions
diff --git a/Android.mk b/Android.mk index b7ba29049..ee47dd1c3 100644 --- a/Android.mk +++ b/Android.mk @@ -1,38 +1,15 @@ ifneq ($(BUILD_WITHOUT_PV),true) -LOCAL_PATH := $(call my-dir) -PV_TOP := $(LOCAL_PATH) - -include $(CLEAR_VARS) -PV_CFLAGS := -Wno-non-virtual-dtor -DENABLE_MEMORY_PLAYBACK +LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -FORMAT := nj - -PV_COPY_HEADERS_TO := libpv - -PV_INCLUDES := \ - $(PV_TOP)/android \ - $(PV_TOP)/extern_libs_v2/khronos/openmax/include \ - $(PV_TOP)/engines/common/include \ - $(PV_TOP)/engines/player/config/linux_nj \ - $(PV_TOP)/engines/player/include \ - $(PV_TOP)/nodes/pvmediaoutputnode/include \ - $(PV_TOP)/nodes/pvdownloadmanagernode/config/opencore \ - $(PV_TOP)/pvmi/pvmf/include \ - $(PV_TOP)/fileformats/mp4/parser/config/opencore \ - $(PV_TOP)/oscl/oscl/config/linux_nj \ - $(PV_TOP)/oscl/oscl/config/shared \ - $(PV_TOP)/engines/author/include \ - $(PV_TOP)/android/drm/oma1/src \ - $(TARGET_OUT_HEADERS)/$(PV_COPY_HEADERS_TO) +# Set up the PV variables. +include $(LOCAL_PATH)/Config.mk -ALTERNATE_CONFIG := $(if $(wildcard vendor/pv/pvplayer.conf),true) -ifneq ($(ALTERNATE_CONFIG), true) +# Install the default configuration file +# if no value-add configuration is present. +ifneq ($(VALUE_ADD),1) $(call add-prebuilt-files, ETC, pvplayer.conf) -else -VALUE_ADD := 1 -PV_CFLAGS += -DPV_USE_VALUE_ADD=1 endif include $(PV_TOP)/pvcommon/Android.mk diff --git a/Config.mk b/Config.mk new file mode 100644 index 000000000..c5f74231c --- /dev/null +++ b/Config.mk @@ -0,0 +1,51 @@ +ifndef EXTERNAL_OPENCORE_CONFIG_ONCE + # This is the first attempt to include this file. + EXTERNAL_OPENCORE_CONFIG_ONCE := true + + PV_TOP := $(my-dir) + PV_CFLAGS := -Wno-non-virtual-dtor -DENABLE_SHAREDFD_PLAYBACK + FORMAT := nj + PV_COPY_HEADERS_TO := libpv + + alternate_config := $(if $(wildcard vendor/pv/pvplayer.conf),true) + ifeq ($(alternate_config), true) + VALUE_ADD := 1 + PV_CFLAGS += -DPV_USE_VALUE_ADD=1 + else + VALUE_ADD := + endif + alternate_config := + + PV_INCLUDES := \ + $(PV_TOP)/android \ + $(PV_TOP)/extern_libs_v2/khronos/openmax/include \ + $(PV_TOP)/engines/common/include \ + $(PV_TOP)/engines/player/config/linux_nj \ + $(PV_TOP)/engines/player/include \ + $(PV_TOP)/nodes/pvmediaoutputnode/include \ + $(PV_TOP)/nodes/pvdownloadmanagernode/config/opencore \ + $(PV_TOP)/pvmi/pvmf/include \ + $(PV_TOP)/fileformats/mp4/parser/config/opencore \ + $(PV_TOP)/oscl/oscl/config/linux_nj \ + $(PV_TOP)/oscl/oscl/config/shared \ + $(PV_TOP)/engines/author/include \ + $(PV_TOP)/android/drm/oma1/src \ + $(TARGET_OUT_HEADERS)/$(PV_COPY_HEADERS_TO) + + # Stash these values for the next includer of this file. + OPENCORE.PV_TOP := $(PV_TOP) + OPENCORE.PV_CFLAGS := $(PV_CFLAGS) + OPENCORE.FORMAT := $(FORMAT) + OPENCORE.PV_COPY_HEADERS_TO := $(PV_COPY_HEADERS_TO) + OPENCORE.VALUE_ADD := $(VALUE_ADD) + OPENCORE.PV_INCLUDES := $(PV_INCLUDES) +else + # This file has already been included by someone, so we can + # use the precomputed values. + PV_TOP := $(OPENCORE.PV_TOP) + PV_CFLAGS := $(OPENCORE.PV_CFLAGS) + FORMAT := $(OPENCORE.FORMAT) + PV_COPY_HEADERS_TO := $(OPENCORE.PV_COPY_HEADERS_TO) + VALUE_ADD := $(OPENCORE.VALUE_ADD) + PV_INCLUDES := $(OPENCORE.PV_INCLUDES) +endif diff --git a/android/android_surface_output.cpp b/android/android_surface_output.cpp index f42701f34..5fa87609b 100644 --- a/android/android_surface_output.cpp +++ b/android/android_surface_output.cpp @@ -19,6 +19,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "VideoMIO" #include <utils/Log.h> +#include <ui/ISurface.h> #include "android_surface_output.h" #include <media/PVPlayer.h> @@ -29,28 +30,14 @@ #include "oscl_dll.h" -#define PLATFORM_PRIVATE_PMEM 1 - // Define entry point for this DLL OSCL_DLL_ENTRY_POINT_DEFAULT() //The factory functions. #include "oscl_mem.h" -#include <cutils/properties.h> - -#if HAVE_ANDROID_OS -#include <linux/android_pmem.h> -#endif - using namespace android; -static const char* pmem_adsp = "/dev/pmem_adsp"; -static const char* pmem = "/dev/pmem"; - -// This class implements the reference media IO for file output -// This class constitutes the Media IO component - OSCL_EXPORT_REF AndroidSurfaceOutput::AndroidSurfaceOutput() : OsclTimerObject(OsclActiveObject::EPriorityNominal, "androidsurfaceoutput") { @@ -59,21 +46,15 @@ OSCL_EXPORT_REF AndroidSurfaceOutput::AndroidSurfaceOutput() : iColorConverter = NULL; mInitialized = false; mEmulation = false; - mHardwareCodec = false; mPvPlayer = NULL; - - // running in emulation? - char value[PROPERTY_VALUE_MAX]; - if (property_get("ro.kernel.qemu", value, 0)) { - LOGV("Emulation mode - using software codecs"); - mEmulation = true; - } + mEmulation = false; } -status_t AndroidSurfaceOutput::set(PVPlayer* pvPlayer, const sp<ISurface>& surface) +status_t AndroidSurfaceOutput::set(PVPlayer* pvPlayer, const sp<ISurface>& surface, bool emulation) { mPvPlayer = pvPlayer; mSurface = surface; + mEmulation = emulation; return NO_ERROR; } @@ -83,9 +64,6 @@ void AndroidSurfaceOutput::initData() iVideoFormat=PVMF_FORMAT_UNKNOWN; resetVideoParameterFlags(); - // hardware specific information - iVideoSubFormat = PVMF_FORMAT_UNKNOWN; - iCommandCounter=0; iLogger=NULL; iCommandResponseQueue.reserve(5); @@ -103,18 +81,13 @@ void AndroidSurfaceOutput::ResetData() //reset all the received media parameters. iVideoFormatString=""; - iVideoFormat=PVMF_FORMAT_UNKNOWN; + iVideoFormat = PVMF_FORMAT_UNKNOWN; resetVideoParameterFlags(); } void AndroidSurfaceOutput::resetVideoParameterFlags() { iVideoParameterFlags = VIDEO_PARAMETERS_INVALID; - - // FIXME: Hack required because subformat is not passed when - // hardware accelerator is not present. - // emulator never uses subformat - if (mEmulation) iVideoParameterFlags |= VIDEO_SUBFORMAT_VALID; } bool AndroidSurfaceOutput::checkVideoParameterFlags() @@ -139,7 +112,7 @@ void AndroidSurfaceOutput::Cleanup() } // We'll close frame buf and delete here for now. - CloseFrameBuf(); + closeFrameBuf(); } OSCL_EXPORT_REF AndroidSurfaceOutput::~AndroidSurfaceOutput() @@ -313,6 +286,11 @@ PVMFCommandId AndroidSurfaceOutput::Start(const OsclAny* aContext) return cmdid; } +// post the last video frame to refresh screen after pause +void AndroidSurfaceOutput::postLastFrame() +{ + mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]); +} PVMFCommandId AndroidSurfaceOutput::Pause(const OsclAny* aContext) { @@ -328,13 +306,7 @@ PVMFCommandId AndroidSurfaceOutput::Pause(const OsclAny* aContext) iState=STATE_PAUSED; status=PVMFSuccess; - - // post last buffer to prevent stale data - if (mHardwareCodec) { - mSurface->postBuffer(mOffset); - } else { - mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]); - } + postLastFrame(); break; default: @@ -424,9 +396,10 @@ PVMFCommandId AndroidSurfaceOutput::Stop(const OsclAny* aContext) case STATE_PAUSED: #ifdef PERFORMANCE_MEASUREMENTS_ENABLED - PVOmapVideoProfile.MarkEndTime(); - PVOmapVideoProfile.PrintStats(); - PVOmapVideoProfile.Reset(); + // FIXME: This should be moved to OMAP library + PVOmapVideoProfile.MarkEndTime(); + PVOmapVideoProfile.PrintStats(); + PVOmapVideoProfile.Reset(); #endif iState=STATE_INITIALIZED; @@ -488,7 +461,7 @@ void AndroidSurfaceOutput::ThreadLogon() { if(iState==STATE_IDLE) { - iLogger = PVLogger::GetLoggerObject("PVOmapVideo"); + iLogger = PVLogger::GetLoggerObject("VideoMIO"); PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::ThreadLogon() called")); AddToScheduler(); iState=STATE_LOGGED_ON; @@ -611,7 +584,7 @@ PVMFCommandId AndroidSurfaceOutput::writeAsync(uint8 aFormatType, int32 aFormatI //printf("V WriteAsync { seq=%d, ts=%d }\n", data_header_info.seq_num, data_header_info.timestamp); // Call playback to send data to IVA for Color Convert - status = WriteFrameBuf(aData, aDataLen, data_header_info); + status = writeFrameBuf(aData, aDataLen, data_header_info); PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, (0,"AndroidSurfaceOutput::writeAsync: Playback Progress - frame %d",iFrameNumber++)); @@ -845,6 +818,8 @@ LOGV("VIDEO SUBFORMAT SET TO %d\n",iVideoSubFormat); return; } } + + // if initialization is complete, update the app display info initCheck(); } @@ -866,57 +841,6 @@ PVMFStatus AndroidSurfaceOutput::verifyParametersSync (PvmiMIOSession aSession, } // -// For active timing support -// -OSCL_EXPORT_REF PVMFStatus AndroidSurfaceOutput_ActiveTimingSupport::SetClock(OsclClock *clockVal) -{ - iClock=clockVal; - return PVMFSuccess; -} - -OSCL_EXPORT_REF void AndroidSurfaceOutput_ActiveTimingSupport::addRef() -{ -} - -OSCL_EXPORT_REF void AndroidSurfaceOutput_ActiveTimingSupport::removeRef() -{ -} - -OSCL_EXPORT_REF bool AndroidSurfaceOutput_ActiveTimingSupport::queryInterface(const PVUuid& aUuid, PVInterface*& aInterface) -{ - aInterface=NULL; - PVUuid uuid; - queryUuid(uuid); - if (uuid==aUuid) - { - PvmiClockExtensionInterface* myInterface = OSCL_STATIC_CAST(PvmiClockExtensionInterface*,this); - aInterface = OSCL_STATIC_CAST(PVInterface*, myInterface); - return true; - } - return false; -} - -void AndroidSurfaceOutput_ActiveTimingSupport::queryUuid(PVUuid& uuid) -{ - uuid=PvmiClockExtensionInterfaceUuid; -} - -uint32 AndroidSurfaceOutput_ActiveTimingSupport::GetDelayMsec(PVMFTimestamp& aTs) -{ - if (iClock) - { - uint32 currentTime=0; - bool overflow=false; - iClock->GetCurrentTime32(currentTime, overflow, OSCLCLOCK_MSEC); - if(aTs>currentTime) - { - return aTs-currentTime; - } - } - return 0; -} - -// // Private section // @@ -949,7 +873,7 @@ OSCL_EXPORT_REF bool AndroidSurfaceOutput::initCheck() return mInitialized; // release resources if previously initialized - CloseFrameBuf(); + closeFrameBuf(); // reset flags in case display format changes in the middle of a stream resetVideoParameterFlags(); @@ -961,150 +885,60 @@ OSCL_EXPORT_REF bool AndroidSurfaceOutput::initCheck() int frameHeight = iVideoHeight; int frameSize; - // FIXME: Need to move hardware specific code to partners directory - -#if HAVE_ANDROID_OS - // Dream hardware codec uses semi-planar format - if (!mEmulation && iVideoSubFormat == PVMF_YUV420_SEMIPLANAR_YVU) { - LOGV("using hardware codec"); - mHardwareCodec = true; - } else -#endif - - // software codec - { - LOGV("using software codec"); - -#if HAVE_ANDROID_OS - // emulation - if (mEmulation) -#endif - { - // RGB-565 frames are 2 bytes/pixel - displayWidth = (displayWidth + 1) & -2; - displayHeight = (displayHeight + 1) & -2; - frameWidth = (frameWidth + 1) & -2; - frameHeight = (frameHeight + 1) & -2; - frameSize = frameWidth * frameHeight * 2; - - // create frame buffer heap and register with surfaceflinger - mFrameHeap = new MemoryHeapBase(frameSize * kBufferCount); - if (mFrameHeap->heapID() < 0) { - LOGE("Error creating frame buffer heap"); - return false; - } - mSurface->registerBuffers(displayWidth, displayHeight, frameWidth, frameHeight, PIXEL_FORMAT_RGB_565, mFrameHeap); - - // create frame buffers - for (int i = 0; i < kBufferCount; i++) { - mFrameBuffers[i] = i * frameSize; - } - - // initialize software color converter - iColorConverter = ColorConvert16::NewL(); - iColorConverter->Init(displayWidth, displayHeight, frameWidth, displayWidth, displayHeight, displayWidth, CCROTATE_NONE); - iColorConverter->SetMemHeight(frameHeight); - iColorConverter->SetMode(1); - } - -#if HAVE_ANDROID_OS - // FIXME: hardware specific - else { - // YUV420 frames are 1.5 bytes/pixel - frameSize = (frameWidth * frameHeight * 3) / 2; - - // create frame buffer heap - sp<MemoryHeapBase> master = new MemoryHeapBase(pmem_adsp, frameSize * kBufferCount); - if (master->heapID() < 0) { - LOGE("Error creating frame buffer heap"); - return false; - } - master->setDevice(pmem); - mHeapPmem = new MemoryHeapPmem(master, 0); - mHeapPmem->slap(); - master.clear(); - mSurface->registerBuffers(displayWidth, displayHeight, frameWidth, frameHeight, PIXEL_FORMAT_YCbCr_420_SP, mHeapPmem); - - // create frame buffers - for (int i = 0; i < kBufferCount; i++) { - mFrameBuffers[i] = i * frameSize; - } - } -#endif - - LOGV("video = %d x %d", displayWidth, displayHeight); - LOGV("frame = %d x %d", frameWidth, frameHeight); - LOGV("frame #bytes = %d", frameSize); + // RGB-565 frames are 2 bytes/pixel + displayWidth = (displayWidth + 1) & -2; + displayHeight = (displayHeight + 1) & -2; + frameWidth = (frameWidth + 1) & -2; + frameHeight = (frameHeight + 1) & -2; + frameSize = frameWidth * frameHeight * 2; + + // create frame buffer heap and register with surfaceflinger + mFrameHeap = new MemoryHeapBase(frameSize * kBufferCount); + if (mFrameHeap->heapID() < 0) { + LOGE("Error creating frame buffer heap"); + return false; + } + + ISurface::BufferHeap buffers(displayWidth, displayHeight, + frameWidth, frameHeight, PIXEL_FORMAT_RGB_565, mFrameHeap); + mSurface->registerBuffers(buffers); - // register frame buffers with SurfaceFlinger - mFrameBufferIndex = 0; - mInitialized = true; + // create frame buffers + for (int i = 0; i < kBufferCount; i++) { + mFrameBuffers[i] = i * frameSize; } - // update app - mPvPlayer->sendEvent(MEDIA_SET_VIDEO_SIZE, displayWidth, displayHeight); + // initialize software color converter + iColorConverter = ColorConvert16::NewL(); + iColorConverter->Init(displayWidth, displayHeight, frameWidth, displayWidth, displayHeight, displayWidth, CCROTATE_NONE); + iColorConverter->SetMemHeight(frameHeight); + iColorConverter->SetMode(1); + + LOGV("video = %d x %d", displayWidth, displayHeight); + LOGV("frame = %d x %d", frameWidth, frameHeight); + LOGV("frame #bytes = %d", frameSize); + // register frame buffers with SurfaceFlinger + mFrameBufferIndex = 0; + mInitialized = true; + mPvPlayer->sendEvent(MEDIA_SET_VIDEO_SIZE, iVideoDisplayWidth, iVideoDisplayHeight); return mInitialized; } -OSCL_EXPORT_REF PVMFStatus AndroidSurfaceOutput::WriteFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info) +OSCL_EXPORT_REF PVMFStatus AndroidSurfaceOutput::writeFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info) { - if (mSurface != 0) { - - // initalized? - if (!mInitialized) { - LOGV("initializing for hardware"); - // FIXME: Check for hardware codec - move to partners directory - if (iVideoSubFormat != PVMF_YUV420_SEMIPLANAR_YVU) return PVMFFailure; - LOGV("got expected format"); - LOGV("private data pointer is 0%p\n", data_header_info.private_data_ptr); - - uint32 fd; - if (!getPmemFd(data_header_info.private_data_ptr, &fd)) { - LOGE("Error getting pmem heap from private_data_ptr"); - return PVMFFailure; - } - sp<MemoryHeapBase> master = (MemoryHeapBase *) fd; - master->setDevice(pmem); - mHeapPmem = new MemoryHeapPmem(master, 0); - mHeapPmem->slap(); - master.clear(); - - // register frame buffers with SurfaceFlinger - mSurface->registerBuffers(iVideoDisplayWidth, iVideoDisplayHeight, iVideoWidth, iVideoHeight, PIXEL_FORMAT_YCbCr_420_SP, mHeapPmem); - - mInitialized = true; - } - - // hardware codec - if (mHardwareCodec) { - // get pmem offset - if (!getOffset(data_header_info.private_data_ptr, &mOffset)) { - LOGE("Error getting pmem offset from private_data_ptr"); - return PVMFFailure; - } - // post to SurfaceFlinger - mSurface->postBuffer(mOffset); - } + if (mSurface == 0) return PVMFFailure; - // software codec - else { - if (mEmulation) { - iColorConverter->Convert(aData, static_cast<uint8*>(mFrameHeap->base()) + mFrameBuffers[mFrameBufferIndex]); - } else { - convertFrame(aData, static_cast<uint8*>(mHeapPmem->base()) + mFrameBuffers[mFrameBufferIndex], aDataLen); - } - // post to SurfaceFlinger - if (++mFrameBufferIndex == kBufferCount) mFrameBufferIndex = 0; - mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]); - } - } + iColorConverter->Convert(aData, static_cast<uint8*>(mFrameHeap->base()) + mFrameBuffers[mFrameBufferIndex]); + // post to SurfaceFlinger + if (++mFrameBufferIndex == kBufferCount) mFrameBufferIndex = 0; + mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]); return PVMFSuccess; } -OSCL_EXPORT_REF void AndroidSurfaceOutput::CloseFrameBuf() +OSCL_EXPORT_REF void AndroidSurfaceOutput::closeFrameBuf() { - LOGV("CloseFrameBuf"); + LOGV("closeFrameBuf"); if (!mInitialized) return; mInitialized = false; @@ -1123,8 +957,6 @@ OSCL_EXPORT_REF void AndroidSurfaceOutput::CloseFrameBuf() // free heaps LOGV("free mFrameHeap"); mFrameHeap.clear(); - LOGV("free mHeapPmem"); - mHeapPmem.clear(); // free color converter if (iColorConverter != 0) @@ -1141,78 +973,3 @@ OSCL_EXPORT_REF bool AndroidSurfaceOutput::GetVideoSize(int *w, int *h) { *h = iVideoDisplayHeight; return iVideoDisplayWidth != 0 && iVideoDisplayHeight != 0; } - -bool AndroidSurfaceOutput::getPmemFd(OsclAny *private_data_ptr, uint32 *pmemFD) -{ - PLATFORM_PRIVATE_LIST *listPtr = NULL; - PLATFORM_PRIVATE_PMEM_INFO *pmemInfoPtr = NULL; - bool returnType = false; - LOGV("in getPmemfd - privatedataptr=%p\n",private_data_ptr); - listPtr = (PLATFORM_PRIVATE_LIST*) private_data_ptr; - - for (uint32 i=0;i<listPtr->nEntries;i++) - { - if(listPtr->entryList->type == PLATFORM_PRIVATE_PMEM) - { - LOGV("in getPmemfd - entry type = %d\n",listPtr->entryList->type); - pmemInfoPtr = (PLATFORM_PRIVATE_PMEM_INFO*) (listPtr->entryList->entry); - returnType = true; - if(pmemInfoPtr){ - *pmemFD = pmemInfoPtr->pmem_fd; - LOGV("in getPmemfd - pmemFD = %d\n",*pmemFD); - } - break; - } - } - return returnType; -} - -bool AndroidSurfaceOutput::getOffset(OsclAny *private_data_ptr, uint32 *offset) -{ - PLATFORM_PRIVATE_LIST *listPtr = NULL; - PLATFORM_PRIVATE_PMEM_INFO *pmemInfoPtr = NULL; - bool returnType = false; - - listPtr = (PLATFORM_PRIVATE_LIST*) private_data_ptr; - LOGV("in getOffset: listPtr = %p\n",listPtr); - for (uint32 i=0;i<listPtr->nEntries;i++) - { - if(listPtr->entryList->type == PLATFORM_PRIVATE_PMEM) - { - LOGV(" in getOffset: entrytype = %d\n",listPtr->entryList->type); - - pmemInfoPtr = (PLATFORM_PRIVATE_PMEM_INFO*) (listPtr->entryList->entry); - returnType = true; - if(pmemInfoPtr){ - *offset = pmemInfoPtr->offset; - LOGV("in getOffset: offset = %d\n",*offset); - } - break; - } - } - return returnType; -} - -static inline void* byteOffset(void* p, size_t offset) { return (void*)((uint8_t*)p + offset); } - -void AndroidSurfaceOutput::convertFrame(void* src, void* dst, size_t len) -{ - // copy the Y plane - size_t y_plane_size = iVideoWidth * iVideoHeight; - //LOGV("len=%u, y_plane_size=%u", len, y_plane_size); - memcpy(dst, src, y_plane_size + iVideoWidth); - - // re-arrange U's and V's - uint16_t* pu = (uint16_t*)byteOffset(src, y_plane_size); - uint16_t* pv = (uint16_t*)byteOffset(pu, y_plane_size / 4); - uint32_t* p = (uint32_t*)byteOffset(dst, y_plane_size); - - int count = y_plane_size / 8; - //LOGV("u = %p, v = %p, p = %p, count = %d", pu, pv, p, count); - do { - uint32_t u = *pu++; - uint32_t v = *pv++; - *p++ = ((u & 0xff) << 8) | ((u & 0xff00) << 16) | (v & 0xff) | ((v & 0xff00) << 8); - } while (--count); -} - diff --git a/android/android_surface_output.h b/android/android_surface_output.h index 2c2008b3b..74e459ee8 100644 --- a/android/android_surface_output.h +++ b/android/android_surface_output.h @@ -32,6 +32,7 @@ #include "pvprofile.h" #endif +// FIXME: Move to OMAP library // Linux and Kernel Includes for Frame Buffer #include <fcntl.h> #include <stdint.h> @@ -49,42 +50,13 @@ // SurfaceFlinger #include <ui/ISurface.h> -// pmem interprocess shared memory support +// interprocess shared memory support #include <utils/MemoryBase.h> #include <utils/MemoryHeapBase.h> -#include <utils/MemoryHeapPmem.h> // color converter #include "cczoomrotation16.h" -// FIXME: Dream specific -typedef struct PLATFORM_PRIVATE_PMEM_INFO -{ - /* pmem file descriptor */ - uint32 pmem_fd; - - uint32 offset; -} PLATFORM_PRIVATE_PMEM_INFO; - -typedef struct PLATFORM_PRIVATE_ENTRY -{ - /* Entry type */ - uint32 type; - - /* Pointer to platform specific entry */ - OsclAny* entry; -} PLATFORM_PRIVATE_ENTRY; - -typedef struct PLATFORM_PRIVATE_LIST -{ - /* Number of entries */ - uint32 nEntries; - - /* Pointer to array of platform specific entries * - * Contiguous block of PLATFORM_PRIVATE_ENTRY elements */ - PLATFORM_PRIVATE_ENTRY* entryList; -} PLATFORM_PRIVATE_LIST; - // define bits, mask and validity check for video parameters #define VIDEO_PARAMETERS_INVALID 0 #define VIDEO_SUBFORMAT_VALID (1 << 0) @@ -107,61 +79,30 @@ class AndroidSurfaceOutput; using namespace android; -// A test feature for simulating a component with active timing. -class AndroidSurfaceOutput_ActiveTimingSupport:public PvmiClockExtensionInterface -{ -public: - - AndroidSurfaceOutput_ActiveTimingSupport(uint32 limit) - :iQueueLimit(limit) - ,iClock(NULL) - {} - ~AndroidSurfaceOutput_ActiveTimingSupport() - {} - - //from PvmiClockExtensionInterface - OSCL_IMPORT_REF PVMFStatus SetClock(OsclClock *clockVal) ; - - //from PVInterface - OSCL_IMPORT_REF void addRef() ; - OSCL_IMPORT_REF void removeRef() ; - OSCL_IMPORT_REF bool queryInterface(const PVUuid& uuid, PVInterface*& iface) ; - - void queryUuid(PVUuid& uuid); - - uint32 GetDelayMsec(PVMFTimestamp&); - - uint32 iQueueLimit; - - OsclClock* iClock; -}; - - -typedef void (*frame_decoded_f)(void *cookie, int width, int height, int pitch, int format, uint8* data); +// FIXME: Not used? +// typedef void (*frame_decoded_f)(void *cookie, int width, int height, int pitch, int format, uint8* data); // This class implements the reference media IO for file output. // This class constitutes the Media IO component -class AndroidSurfaceOutput : public OsclTimerObject - ,public PvmiMIOControl - ,public PvmiMediaTransfer - ,public PvmiCapabilityAndConfig - +class AndroidSurfaceOutput : public OsclTimerObject, public PvmiMIOControl, + public PvmiMediaTransfer, public PvmiCapabilityAndConfig { public: - OSCL_IMPORT_REF AndroidSurfaceOutput(); + AndroidSurfaceOutput(); // parameter initialization - virtual status_t set(android::PVPlayer* pvPlayer, const sp<ISurface>& surface); + virtual status_t set(android::PVPlayer* pvPlayer, const sp<ISurface>& surface, bool emulation); - // For Frame Buffer - OSCL_IMPORT_REF bool initCheck(); - OSCL_IMPORT_REF PVMFStatus WriteFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info); - OSCL_IMPORT_REF void CloseFrameBuf(); + // For frame buffer + virtual bool initCheck(); + virtual PVMFStatus writeFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info); + virtual void postLastFrame(); + virtual void closeFrameBuf(); - OSCL_IMPORT_REF ~AndroidSurfaceOutput(); + virtual ~AndroidSurfaceOutput(); - OSCL_IMPORT_REF bool GetVideoSize(int *w, int *h); + bool GetVideoSize(int *w, int *h); // APIs from PvmiMIOControl @@ -210,20 +151,20 @@ public: void useMemoryAllocators(OsclMemAllocator* write_alloc=NULL); PVMFCommandId writeAsync(uint8 format_type, int32 format_index, - uint8* data, uint32 data_len, - const PvmiMediaXferHeader& data_header_info, - OsclAny* aContext=NULL); + uint8* data, uint32 data_len, + const PvmiMediaXferHeader& data_header_info, + OsclAny* aContext=NULL); void writeComplete(PVMFStatus aStatus, - PVMFCommandId write_cmd_id, - OsclAny* aContext); + PVMFCommandId write_cmd_id, + OsclAny* aContext); - PVMFCommandId readAsync(uint8* data, uint32 max_data_len, - OsclAny* aContext=NULL, - int32* formats=NULL, uint16 num_formats=0); + PVMFCommandId readAsync(uint8* data, uint32 max_data_len, + OsclAny* aContext=NULL, + int32* formats=NULL, uint16 num_formats=0); void readComplete(PVMFStatus aStatus, PVMFCommandId read_cmd_id, int32 format_index, - const PvmiMediaXferHeader& data_header_info, OsclAny* aContext); + const PvmiMediaXferHeader& data_header_info, OsclAny* aContext); void statusUpdate(uint32 status_flags); @@ -236,31 +177,31 @@ public: void setObserver (PvmiConfigAndCapabilityCmdObserver* aObserver); PVMFStatus getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, - PvmiKvp*& aParameters, int& num_parameter_elements, PvmiCapabilityContext aContext); + PvmiKvp*& aParameters, int& num_parameter_elements, PvmiCapabilityContext aContext); PVMFStatus releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements); void createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext); void setContextParameters(PvmiMIOSession aSession, PvmiCapabilityContext& aContext, - PvmiKvp* aParameters, int num_parameter_elements); + PvmiKvp* aParameters, int num_parameter_elements); void DeleteContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext); void setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, - int num_elements, PvmiKvp * & aRet_kvp); + int num_elements, PvmiKvp * & aRet_kvp); PVMFCommandId setParametersAsync(PvmiMIOSession aSession, PvmiKvp* aParameters, - int num_elements, PvmiKvp*& aRet_kvp, OsclAny* context=NULL); + int num_elements, PvmiKvp*& aRet_kvp, OsclAny* context=NULL); uint32 getCapabilityMetric (PvmiMIOSession aSession); PVMFStatus verifyParametersSync (PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements); + // FIXME: Not used? + // void SetFrameDecodedCallback(frame_decoded_f f, void *cookie); - void SetFrameDecodedCallback(frame_decoded_f f, void *cookie); - -private: +protected: void initData(); void resetVideoParameterFlags(); bool checkVideoParameterFlags(); @@ -273,9 +214,6 @@ private: void Cleanup(); void ResetData(); - bool getPmemFd(OsclAny *private_data_ptr, uint32 *pmemFD); - bool getOffset(OsclAny *private_data_ptr, uint32 *offset); - PvmiMediaTransfer* iPeer; // The PvmiMIOControl class observer. @@ -367,10 +305,6 @@ private: sp<MemoryHeapBase> mFrameHeap; size_t mFrameBuffers[kBufferCount]; - sp<MemoryHeapPmem> mHeapPmem; - bool mHardwareCodec; - uint32 mOffset; - void convertFrame(void* src, void* dst, size_t len); #ifdef PERFORMANCE_MEASUREMENTS_ENABLED diff --git a/android/author/PVMediaRecorder.cpp b/android/author/PVMediaRecorder.cpp index 1a5d8e4db..652d67f75 100644 --- a/android/author/PVMediaRecorder.cpp +++ b/android/author/PVMediaRecorder.cpp @@ -310,7 +310,22 @@ status_t PVMediaRecorder::reset() LOGE("failed to construct an author command"); return UNKNOWN_ERROR; } - return mAuthorDriverWrapper->enqueueCommand(ac, 0, 0); + status_t ret = mAuthorDriverWrapper->enqueueCommand(ac, 0, 0); + if (ret != OK) { + LOGE("failed to do reset(%d)", ret); + return UNKNOWN_ERROR; + } + ret = mAuthorDriverWrapper->enqueueCommand(new author_command(AUTHOR_REMOVE_VIDEO_SOURCE), 0, 0); + if (ret != OK) { + LOGE("failed to remove video source(%d)", ret); + return UNKNOWN_ERROR; + } + ret = mAuthorDriverWrapper->enqueueCommand(new author_command(AUTHOR_REMOVE_AUDIO_SOURCE), 0, 0); + if (ret != OK) { + LOGE("failed to remove audio source(%d)", ret); + return UNKNOWN_ERROR; + } + return ret; } status_t PVMediaRecorder::close() diff --git a/android/author/android_camera_input.cpp b/android/author/android_camera_input.cpp index d6e3bfca7..66d09f07e 100644 --- a/android/author/android_camera_input.cpp +++ b/android/author/android_camera_input.cpp @@ -55,17 +55,40 @@ AndroidCameraInput::AndroidCameraInput() mFrameRate = DEFAULT_FRAME_RATE; mCamera = NULL; mHeap = 0; + + // FIXME: + // mFrameRefCount is redundant. iSendMediaData.empty() can be used to + // determine if there are any frames pending in the encoder. mFrameRefCount = 0; mFlags = 0; iFrameQueue.reserve(5); iFrameQueueMutex.Create(); } +void AndroidCameraInput::ReleaseQueuedFrames() +{ + LOGV("ReleaseQueuedFrames"); + iFrameQueueMutex.Lock(); + while (!iFrameQueue.empty()) { + AndroidCameraInputMediaData data = iFrameQueue[0]; + iFrameQueue.erase(iFrameQueue.begin()); +#if (LOG_NDEBUG == 0) + ssize_t offset = 0; + size_t size = 0; + sp<IMemoryHeap> heap = data.iFrameBuffer->getMemory(&offset, &size); + LOGD("writeComplete: ID = %d, base = %p, offset = %p, size = %d ReleaseQueuedFrames", heap->getHeapID(), heap->base(), offset, size); +#endif + mCamera->releaseRecordingFrame(data.iFrameBuffer); + } + iFrameQueueMutex.Unlock(); +} + AndroidCameraInput::~AndroidCameraInput() { LOGV("destructor"); if (mCamera != NULL) { - mCamera->setFrameCallback(NULL, this, FRAME_CALLBACK_FLAG_NOOP); + mCamera->setRecordingCallback(NULL, this); + ReleaseQueuedFrames(); if ((mFlags & FLAGS_HOT_CAMERA) == 0) { LOGV("camera was cold when we started, stopping preview"); mCamera->stopPreview(); @@ -350,7 +373,7 @@ void AndroidCameraInput::setPeer(PvmiMediaTransfer* aPeer) if (iPeer) { LOGE("iPeer already exists"); } else { - LOGE("aPeer is a NULL pointer"); + LOGE("aPeer is a NULL pointer"); } OSCL_LEAVE(OsclErrGeneral); return; @@ -394,16 +417,23 @@ void AndroidCameraInput::writeComplete(PVMFStatus aStatus, { LOGV("writeComplete"); OSCL_UNUSED_ARG(aContext); - if (aStatus != PVMFSuccess) { - LOGE("writeAsync failed. aStatus=%d", aStatus); - return; - } + iFrameQueueMutex.Lock(); if (iSentMediaData.empty()) { LOGE("Nothing to complete"); + iFrameQueueMutex.Unlock(); return; } + AndroidCameraInputMediaData data = iSentMediaData[0]; +#if (LOG_NDEBUG == 0) + ssize_t offset = 0; + size_t size = 0; + sp<IMemoryHeap> heap = data.iFrameBuffer->getMemory(&offset, &size); + LOGD("writeComplete: ID = %d, base = %p, offset = %p, size = %d", heap->getHeapID(), heap->base(), offset, size); +#endif + mCamera->releaseRecordingFrame(data.iFrameBuffer); + if (mFrameRefCount) { --mFrameRefCount; } @@ -419,6 +449,12 @@ void AndroidCameraInput::writeComplete(PVMFStatus aStatus, } iSentMediaData.erase(iSentMediaData.begin()); + iFrameQueueMutex.Unlock(); + + // reference count is always updated, even if the write fails + if (aStatus != PVMFSuccess) { + LOGE("writeAsync failed. aStatus=%d", aStatus); + } } OSCL_EXPORT_REF @@ -713,13 +749,13 @@ void AndroidCameraInput::Run() // dequeue frame buffers and write to peer iFrameQueueMutex.Lock(); - if (!iFrameQueue.empty()) { + while (!iFrameQueue.empty()) { AndroidCameraInputMediaData data = iFrameQueue[0]; iFrameQueue.erase(iFrameQueue.begin()); uint32 writeAsyncID = 0; int32 error = 0; - OSCL_TRY(error,writeAsyncID = iPeer->writeAsync(0, 0, (uint8*)data.iFrameBuffer, + OSCL_TRY(error,writeAsyncID = iPeer->writeAsync(0, 0, (uint8*) (data.iFrameBuffer->pointer()), data.iFrameSize, data.iXferHeader);); if (!error) { @@ -839,14 +875,17 @@ void AndroidCameraInput::DoRequestCompleted(const AndroidCameraInputCmd& aCmd, P } } -static void preview_callback(const sp<IMemory>& frame, void *cookie) +static void recording_frame_callback(const sp<IMemory>& frame, void *cookie) { - LOGV("preview_callback"); + LOGV("recording_frame_callback"); AndroidCameraInput* input = (AndroidCameraInput*) cookie; - if (!input->isRecorderStarting()) { // this is not an error + + // this must not happen, and we can't release the frame if it does happen + if (!input) { + LOGE("Error - CameraInput has not been initialized"); return; } - + input->postWriteAsync(frame); } @@ -861,12 +900,22 @@ PVMFStatus AndroidCameraInput::DoInit() // create a camera if the app didn't supply one if (mCamera == 0) { mCamera = Camera::connect(); - if (mCamera != NULL && mSurface != NULL) { - mCamera->setPreviewDisplay(mSurface); + } + + // always call setPreviewDisplay() regardless whether mCamera is just created or not + // return failure if no display surface is available + if (mCamera != NULL && mSurface != NULL) { + mCamera->setPreviewDisplay(mSurface); + } else { + if (mCamera == NULL) { + LOGE("Camera is not available"); + } else if (mSurface == NULL) { + LOGE("No surface is available for display"); } + return PVMFFailure; } - LOGD("Intended mFrameWidth=%d, mFrameHe=%d ",mFrameWidth, mFrameHeight); + LOGD("Intended mFrameWidth=%d, mFrameHeight=%d ",mFrameWidth, mFrameHeight); String8 s = mCamera->getParameters(); CameraParameters p(s); p.setPreviewSize(mFrameWidth, mFrameHeight); @@ -878,8 +927,10 @@ PVMFStatus AndroidCameraInput::DoInit() // for video recording. CameraParameters newCameraParam(mCamera->getParameters()); newCameraParam.getPreviewSize(&mFrameWidth, &mFrameHeight); - LOGD("Actual mFrameWidth=%d, mFrameHe=%d ",mFrameWidth, mFrameHeight); - mCamera->startPreview(); + LOGD("Actual mFrameWidth=%d, mFrameHeight=%d ",mFrameWidth, mFrameHeight); + if (mCamera->startPreview() != NO_ERROR) { + return PVMFFailure; + } return PVMFSuccess; } @@ -887,10 +938,12 @@ PVMFStatus AndroidCameraInput::DoStart() { LOGV("DoStart"); iState = STATE_STARTED; - mCamera->setFrameCallback(preview_callback, this, FRAME_CALLBACK_FLAG_CAMCORDER); + mCamera->setRecordingCallback(recording_frame_callback, this); + if (mCamera->startRecording() != NO_ERROR) { + return PVMFFailure; + } AddDataEventToQueue(iMilliSecondsPerDataEvent); return PVMFSuccess; - } PVMFStatus AndroidCameraInput::DoPause() @@ -923,7 +976,10 @@ PVMFStatus AndroidCameraInput::DoStop(const AndroidCameraInputCmd& aCmd) { LOGV("DoStop"); iDataEventCounter = 0; - mCamera->setFrameCallback(NULL, this); + iState = STATE_STOPPING; + mCamera->setRecordingCallback(NULL, this); + mCamera->stopRecording(); + ReleaseQueuedFrames(); // if no buffers pending, complete the stop command if (mFrameRefCount == 0) { @@ -933,7 +989,6 @@ PVMFStatus AndroidCameraInput::DoStop(const AndroidCameraInputCmd& aCmd) // need to wait for buffers to come back before we stop preview iPendingCmd = aCmd; - iState = STATE_STOPPING; return PVMFPending; } @@ -1040,14 +1095,20 @@ void AndroidCameraInput::SetCamera(const sp<android::ICamera>& camera) PVMFStatus AndroidCameraInput::postWriteAsync(const sp<IMemory>& frame) { LOGV("postWriteAsync"); - if (iState != STATE_STARTED) { - LOGE("postWriteAsync call in an invalid state(%d)", iState); - return PVMFFailure; - } + if (frame == NULL) { LOGE("frame is a NULL pointer"); return PVMFFailure; } + + // release the received recording frame right way + // if recording has not been started yet or recording has already finished + if (!isRecorderStarting()) { + LOGV("Recording is not started, so recording frame is dropped"); + mCamera->releaseRecordingFrame(frame); + return PVMFSuccess; + } + if (!iPeer) { LOGW("iPeer is NULL"); return PVMFSuccess; @@ -1066,7 +1127,7 @@ PVMFStatus AndroidCameraInput::postWriteAsync(const sp<IMemory>& frame) ssize_t offset = 0; size_t size = 0; sp<IMemoryHeap> heap = frame->getMemory(&offset, &size); - //LOGV("ID = %d, base = %p, offset = %p, size = %d", heap->getHeapID(), heap->base(), offset, size); + LOGV("postWriteAsync: ID = %d, base = %p, offset = %p, size = %d", heap->getHeapID(), heap->base(), offset, size); //LOGV("@@@@@@@@@@@@@ incrementing reference count (%d) @@@@@@@@@@@@@@@", mFrameRefCount); if (mHeap == 0) { @@ -1084,7 +1145,7 @@ PVMFStatus AndroidCameraInput::postWriteAsync(const sp<IMemory>& frame) data.iXferHeader.flags = 0; data.iXferHeader.duration = 0; data.iXferHeader.stream_id = 0; - data.iFrameBuffer = frame->pointer(); + data.iFrameBuffer = frame; data.iFrameSize = size; // lock mutex and queue frame buffer diff --git a/android/author/android_camera_input.h b/android/author/android_camera_input.h index 5efb0b88d..f31ffa340 100644 --- a/android/author/android_camera_input.h +++ b/android/author/android_camera_input.h @@ -149,12 +149,15 @@ public: PVMFCommandId iId; PvmiMediaXferHeader iXferHeader; - void* iFrameBuffer; + sp<IMemory> iFrameBuffer; size_t iFrameSize; private: void Copy(const AndroidCameraInputMediaData& aData) { - memcpy(this, &aData, sizeof(AndroidCameraInputMediaData)); + iId = aData.iId; + iXferHeader = aData.iXferHeader; + iFrameBuffer = aData.iFrameBuffer; // won't mess up the reference count + iFrameSize = aData.iFrameSize; } }; @@ -288,6 +291,10 @@ public: bool isRecorderStarting() { return iState==STATE_STARTED?true:false; } private: + // release all queued recording frames that have not been + // given the chance to be sent out. + void ReleaseQueuedFrames(); + void Run(); void FrameSizeChanged(); diff --git a/android/author/authordriver.cpp b/android/author/authordriver.cpp index e4baaeebb..eed79964a 100644 --- a/android/author/authordriver.cpp +++ b/android/author/authordriver.cpp @@ -34,15 +34,20 @@ AuthorDriverWrapper::AuthorDriverWrapper() void AuthorDriverWrapper::resetAndClose() { + LOGV("resetAndClose"); mAuthorDriver->enqueueCommand(new author_command(AUTHOR_RESET), NULL, NULL); + mAuthorDriver->enqueueCommand(new author_command(AUTHOR_REMOVE_VIDEO_SOURCE), NULL, NULL); + mAuthorDriver->enqueueCommand(new author_command(AUTHOR_REMOVE_AUDIO_SOURCE), NULL, NULL); mAuthorDriver->enqueueCommand(new author_command(AUTHOR_CLOSE), NULL, NULL); } AuthorDriverWrapper::~AuthorDriverWrapper() { + LOGV("Destructor"); if (mAuthorDriver) { // set the authoring engine to the IDLE state. PVAEState state = mAuthorDriver->getAuthorEngineState(); + LOGV("state(%d)", state); switch (state) { case PVAE_STATE_IDLE: break; @@ -96,6 +101,7 @@ AuthorDriver::AuthorDriver() mVideoHeight(DEFAULT_FRAME_HEIGHT), mVideoFrameRate((int)DEFAULT_FRAME_RATE), mVideoEncoder(VIDEO_ENCODER_DEFAULT), + mOutputFormat(OUTPUT_FORMAT_DEFAULT), mAudioEncoder(AUDIO_ENCODER_DEFAULT) { mSyncSem = new OsclSemaphore(); @@ -240,6 +246,14 @@ void AuthorDriver::Run() handleSetOutputFile((set_output_file_command *)ac); return; + case AUTHOR_REMOVE_VIDEO_SOURCE: + handleRemoveVideoSource(ac); + return; + + case AUTHOR_REMOVE_AUDIO_SOURCE: + handleRemoveAudioSource(ac); + return; + case AUTHOR_PREPARE: handlePrepare(ac); break; case AUTHOR_START: handleStart(ac); break; case AUTHOR_STOP: handleStop(ac); break; @@ -357,6 +371,8 @@ void AuthorDriver::handleSetOutputFormat(set_output_format_command *ac) return; } + mOutputFormat = ac->of; + OSCL_TRY(error, mAuthor->SelectComposer(iComposerMimeType, mComposerConfig, ac)); OSCL_FIRST_CATCH_ANY(error, commandFailed(ac)); } @@ -429,10 +445,22 @@ void AuthorDriver::handleSetVideoSize(set_video_size_command *ac) if (mVideoInputMIO == NULL) return; - mVideoWidth = ac->width; - mVideoHeight = ac->height; + // FIXME: + // Platform-specific and temporal workaround to prevent video size from being set too large + if (ac->width > ANDROID_MAX_ENCODED_FRAME_WIDTH) { + LOGW("Intended width(%d) exceeds the max allowed width(%d). Max width is used instead.", ac->width, ANDROID_MAX_ENCODED_FRAME_WIDTH); + mVideoWidth = ANDROID_MAX_ENCODED_FRAME_WIDTH; + } else { + mVideoWidth = ac->width; + } + if (ac->height > ANDROID_MAX_ENCODED_FRAME_HEIGHT) { + LOGW("Intended height(%d) exceeds the max allowed height(%d). Max height is used instead.", ac->height, ANDROID_MAX_ENCODED_FRAME_HEIGHT); + mVideoHeight = ANDROID_MAX_ENCODED_FRAME_HEIGHT; + } else { + mVideoHeight = ac->height; + } - ((AndroidCameraInput *)mVideoInputMIO)->SetFrameSize(ac->width, ac->height); + ((AndroidCameraInput *)mVideoInputMIO)->SetFrameSize(mVideoWidth, mVideoHeight); FinishNonAsyncCommand(ac); } @@ -473,24 +501,49 @@ void AuthorDriver::handleSetOutputFile(set_output_file_command *ac) { PVMFStatus ret = PVMFFailure; PvmfFileOutputNodeConfigInterface *config = NULL; - OSCL_wHeapString<OsclMemAllocator> wFileName; - oscl_wchar output[512]; + FILE *ifpOutput = NULL; + int handle = -1; if (!mComposerConfig) goto exit; config = OSCL_STATIC_CAST(PvmfFileOutputNodeConfigInterface*, mComposerConfig); if (!config) goto exit; - oscl_UTF8ToUnicode(ac->path, strlen(ac->path), output, 512); - wFileName.set(output, oscl_strlen(output)); - ret = config->SetOutputFileName(wFileName); + handle = open(ac->path, O_RDWR | O_CREAT ); + if(-1 == handle) { + LOGE("Ln %d open() error %d", __LINE__, handle); + goto exit; + } + + ifpOutput = fdopen(handle, "wb"); + if(NULL == ifpOutput) { + LOGE("Ln %d fopen() error", __LINE__); + goto exit; + } + + if ( OUTPUT_FORMAT_RAW_AMR == mOutputFormat ) { + PvmfFileOutputNodeConfigInterface *config = OSCL_DYNAMIC_CAST(PvmfFileOutputNodeConfigInterface*, mComposerConfig); + if (!config) goto exit; + + ret = config->SetOutputFile(&OsclFileHandle(ifpOutput)); + } else if((OUTPUT_FORMAT_THREE_GPP == mOutputFormat) || (OUTPUT_FORMAT_MPEG_4 == mOutputFormat)) { + PVMp4FFCNClipConfigInterface *config = OSCL_DYNAMIC_CAST(PVMp4FFCNClipConfigInterface*, mComposerConfig); + if (!config) goto exit; + + config->SetPresentationTimescale(1000); + ret = config->SetOutputFile(&OsclFileHandle(ifpOutput)); + } + exit: + free(ac->path); + if (ret == PVMFSuccess) { mOutputFileName = ac->path; FinishNonAsyncCommand(ac); } else { - free(ac->path); + LOGE("Ln %d SetOutputFile() error", __LINE__); + fclose(ifpOutput); commandFailed(ac); } } @@ -511,6 +564,7 @@ void AuthorDriver::handleStart(author_command *ac) void AuthorDriver::handleStop(author_command *ac) { + LOGV("handleStop"); int error = 0; OSCL_TRY(error, mAuthor->Stop(ac)); OSCL_FIRST_CATCH_ANY(error, commandFailed(ac)); @@ -520,6 +574,7 @@ void AuthorDriver::handleStop(author_command *ac) void AuthorDriver::handleClose(author_command *ac) { + LOGV("handleClose"); int error = 0; OSCL_TRY(error, mAuthor->Close(ac)); OSCL_FIRST_CATCH_ANY(error, commandFailed(ac)); @@ -527,19 +582,45 @@ void AuthorDriver::handleClose(author_command *ac) void AuthorDriver::handleReset(author_command *ac) { + LOGV("handleReset"); int error = 0; OSCL_TRY(error, mAuthor->Reset(ac)); OSCL_FIRST_CATCH_ANY(error, commandFailed(ac)); - // remove data sources - removeDataSources(ac); + // remove references to configs + removeConfigRefs(ac); } -void AuthorDriver::removeDataSources(author_command *ac) +void AuthorDriver::handleRemoveVideoSource(author_command *ac) { + LOGV("handleRemoveVideoSource"); + if (mVideoNode) { + int error = 0; + OSCL_TRY(error, mAuthor->RemoveDataSource(*mVideoNode, ac)); + OSCL_FIRST_CATCH_ANY(error, commandFailed(ac)); + } else { + FinishNonAsyncCommand(ac); + } +} + +void AuthorDriver::handleRemoveAudioSource(author_command *ac) +{ + LOGV("handleRemoveAudioSource"); + if (mAudioNode) { + int error = 0; + OSCL_TRY(error, mAuthor->RemoveDataSource(*mAudioNode, ac)); + OSCL_FIRST_CATCH_ANY(error, commandFailed(ac)); + } else { + FinishNonAsyncCommand(ac); + } +} + +void AuthorDriver::removeConfigRefs(author_command *ac) +{ + LOGV("removeConfigRefs"); if (mOutputFileName) { if (!mKeepOutputFile) { - LOGV("remove output filei(%s)", mOutputFileName); + LOGV("remove output file(%s)", mOutputFileName); unlink(mOutputFileName); } free(mOutputFileName); @@ -558,19 +639,11 @@ void AuthorDriver::removeDataSources(author_command *ac) mAudioEncoderConfig->removeRef(); mAudioEncoderConfig = NULL; } - int error = 0; - if (mAudioNode) { - OSCL_TRY(error, mAuthor->RemoveDataSource(*mAudioNode)); - OSCL_FIRST_CATCH_ANY(error, commandFailed(ac)); - } - if (mVideoNode) { - OSCL_TRY(error, mAuthor->RemoveDataSource(*mVideoNode)); - OSCL_FIRST_CATCH_ANY(error, commandFailed(ac)); - } } void AuthorDriver::handleQuit(author_command *ac) { + LOGV("handleQuit"); OsclExecScheduler *sched = OsclExecScheduler::Current(); sched->StopScheduler(); } @@ -667,18 +740,9 @@ int AuthorDriver::authorThread() void AuthorDriver::CommandCompleted(const PVCmdResponse& aResponse) { author_command *ac = (author_command *)aResponse.GetContext(); - status_t s = 0; - - // XXX do we want to make this illegal? combo commands like - // SETUP_DEFAULT_SINKS will need some changing - if (ac == NULL) { - // NULL command may be expected from the author engine from - // time to time? - // LOGE("Unexpected NULL command"); - return; - } + status_t s = aResponse.GetCmdStatus(); + LOGV("Command (%d) completed with status(%d)", ac->which, s); - LOGV("Command (%d) completed with status(%d)", ac->which, aResponse.GetCmdStatus()); if (ac->which == AUTHOR_SET_OUTPUT_FORMAT) { mSelectedComposer = aResponse.GetResponseData(); } @@ -755,7 +819,7 @@ void AuthorDriver::CommandCompleted(const PVCmdResponse& aResponse) } // Translate the PVMF error codes into Android ones - switch(aResponse.GetCmdStatus()) { + switch(s) { case PVMFSuccess: s = android::OK; break; case PVMFPending: *(char *)0 = 0; break; /* XXX assert */ default: s = android::UNKNOWN_ERROR; diff --git a/android/author/authordriver.h b/android/author/authordriver.h index db0826ebf..9de4f432b 100644 --- a/android/author/authordriver.h +++ b/android/author/authordriver.h @@ -52,8 +52,17 @@ #include "pvmp4h263encextension.h" #include "pvmp4ffcn_clipconfig.h" #include "pvmf_fileoutput_config.h" +#ifndef PVMF_FILEOUTPUT_CONFIG_H_INCLUDED +#include "pvmf_fileoutput_config.h" +#endif #include "pvmfamrencnode_extension.h" +// FIXME: +// Platform-specic and temporal workaround to prevent video size +// from being set too large +#define ANDROID_MAX_ENCODED_FRAME_WIDTH 352 +#define ANDROID_MAX_ENCODED_FRAME_HEIGHT 288 + namespace android { template<class DestructClass> @@ -85,6 +94,8 @@ enum author_command_type { AUTHOR_STOP, AUTHOR_RESET, AUTHOR_CLOSE, + AUTHOR_REMOVE_VIDEO_SOURCE, + AUTHOR_REMOVE_AUDIO_SOURCE, AUTHOR_QUIT = 100 }; @@ -210,8 +221,12 @@ private: // the event loop will keep running. void FinishNonAsyncCommand(author_command *ec); - // remove input video and/or audio source(s) - void removeDataSources(author_command *ac); + // remove references to configurations + void removeConfigRefs(author_command *ac); + + // remove input video or audio source + void handleRemoveVideoSource(author_command *ac); + void handleRemoveAudioSource(author_command *ac); // Release resources acquired in a recording session // Can be called only in the IDLE state of the authoring engine @@ -246,6 +261,7 @@ private: int mVideoFrameRate; //int mVideoBitRate; video_encoder mVideoEncoder; + output_format mOutputFormat; //int mAudioBitRate; audio_encoder mAudioEncoder; diff --git a/android/mediascanner.cpp b/android/mediascanner.cpp index 6388c4a29..0509c8c61 100644 --- a/android/mediascanner.cpp +++ b/android/mediascanner.cpp @@ -426,7 +426,7 @@ static PVMFStatus parseMidi(const char *filename, MediaScannerClient& client) { file.fd = 0; file.offset = 0; file.length = 0; - result = EAS_OpenFile(easData, &file, &easHandle, NULL); + result = EAS_OpenFile(easData, &file, &easHandle); } if (result == EAS_SUCCESS) { result = EAS_Prepare(easData, easHandle); @@ -551,7 +551,7 @@ static bool fileMatchesExtension(const char* path, const char* extensions) { while (extensions[0]) { char* comma = strchr(extensions, ','); - int length = (comma ? comma - extensions : strlen(extensions)); + size_t length = (comma ? comma - extensions : strlen(extensions)); if (length == strlen(extension) && strncasecmp(extension, extensions, length) == 0) return true; extensions += length; if (extensions[0] == ',') ++extensions; @@ -611,7 +611,10 @@ status_t MediaScanner::doProcessDirectory(char *path, int pathRemaining, const c strcat(fileSpot, "/"); int err = doProcessDirectory(path, pathRemaining - nameLength - 1, extensions, client, exceptionCheck, exceptionEnv); - if (err) goto failure; + if (err) { + LOGE("Error processing '%s' - skipping\n", path); + continue; + } } else if (fileMatchesExtension(path, extensions)) { struct stat statbuf; stat(path, &statbuf); diff --git a/android/metadatadriver.cpp b/android/metadatadriver.cpp index e1c54fd48..6ef6b311f 100644 --- a/android/metadatadriver.cpp +++ b/android/metadatadriver.cpp @@ -183,7 +183,7 @@ bool MetadataDriver::containsSupportedKey(const OSCL_HeapString<OsclMemAllocator void MetadataDriver::trimKeys() { LOGV("trimKeys"); - dumpkeystolog(mMetadataKeyList); + //dumpkeystolog(mMetadataKeyList); mActualMetadataKeyList.clear(); uint32 n = mMetadataKeyList.size(); mActualMetadataKeyList.reserve(n); @@ -365,7 +365,7 @@ status_t MetadataDriver::setDataSource(const char* srcUrl) { LOGV("setDataSource"); // Don't let somebody trick us in to reading some random block of memory. - if (strncmp("mem://", srcUrl, 6) == 0) { + if (strncmp("sharedfd://", srcUrl, 11) == 0) { LOGE("setDataSource: Invalid url (%s).", srcUrl); return UNKNOWN_ERROR; } diff --git a/android/playerdriver.cpp b/android/playerdriver.cpp index 31f1a1e84..5a87d53ad 100644 --- a/android/playerdriver.cpp +++ b/android/playerdriver.cpp @@ -24,6 +24,7 @@ #include <media/thread_init.h> #include <utils/threads.h> #include <utils/List.h> +#include <cutils/properties.h> #include <media/MediaPlayerInterface.h> @@ -76,7 +77,7 @@ using namespace android; # endif // library and function name to retrieve device-specific MIOs -static const char* MIO_LIBRARY_NAME = "libopencorehal"; +static const char* MIO_LIBRARY_NAME = "libopencorehw.so"; static const char* VIDEO_MIO_FACTORY_NAME = "createVideoMio"; typedef AndroidSurfaceOutput* (*VideoMioFactory)(); @@ -183,6 +184,7 @@ private: bool mSeekComp; bool mSeekPending; + bool mEmulation; void* mLibHandle; }; @@ -196,7 +198,8 @@ PlayerDriver::PlayerDriver(PVPlayer* pvPlayer) : mEndOfData(false), mRecentSeek(0), mSeekComp(true), - mSeekPending(false) + mSeekPending(false), + mEmulation(false) { LOGV("constructor"); mSyncSem = new OsclSemaphore(); @@ -213,8 +216,21 @@ PlayerDriver::PlayerDriver(PVPlayer* pvPlayer) : mPlayerCapConfig = NULL; mDownloadContextData = NULL; - // attempt to open device-specific library - mLibHandle = ::dlopen(MIO_LIBRARY_NAME, RTLD_NOW); + // running in emulation? + mLibHandle = NULL; + char value[PROPERTY_VALUE_MAX]; + if (property_get("ro.kernel.qemu", value, 0)) { + mEmulation = true; + LOGV("Emulation mode - using software codecs"); + } else { + // attempt to open h/w specific library + mLibHandle = ::dlopen(MIO_LIBRARY_NAME, RTLD_NOW); + if (mLibHandle != NULL) { + LOGV("OpenCore hardware module loaded"); + } else { + LOGV("OpenCore hardware module not found"); + } + } // start player thread LOGV("start player thread"); @@ -601,7 +617,10 @@ void PlayerDriver::handleSetVideoSurface(PlayerSetVideoSurface* ec) if (mLibHandle != NULL) { VideoMioFactory f = (VideoMioFactory) ::dlsym(mLibHandle, VIDEO_MIO_FACTORY_NAME); if (f != NULL) { + LOGV("Creating hardware specific MIO"); mio = f(); + } else { + LOGV("MIO factory function not found"); } } @@ -612,7 +631,7 @@ void PlayerDriver::handleSetVideoSurface(PlayerSetVideoSurface* ec) } // initialize the MIO parameters - status_t ret = mio->set(mPvPlayer, ec->surface()); + status_t ret = mio->set(mPvPlayer, ec->surface(), mEmulation); if (ret != NO_ERROR) { LOGE("Video MIO set failed"); commandFailed(ec); @@ -1141,13 +1160,15 @@ void PlayerDriver::HandleInformationalEvent(const PVAsyncInformationalEvent& aEv } } -extern pthread_key_t osclfilenativesigbuskey; - namespace android { #undef LOG_TAG #define LOG_TAG "PVPlayer" +#ifdef MAX_OPENCORE_INSTANCES +/*static*/ volatile int32_t PVPlayer::sNumInstances = 0; +#endif + // ---------------------------------------------------------------------------- // implement the Packet Video player // ---------------------------------------------------------------------------- @@ -1155,13 +1176,23 @@ PVPlayer::PVPlayer() { LOGV("PVPlayer constructor"); mDataSourcePath = NULL; + mSharedFd = -1; + mIsDataSourceSet = false; + mDuration = -1; + mPlayerDriver = NULL; + +#ifdef MAX_OPENCORE_INSTANCES + if (android_atomic_inc(&sNumInstances) >= MAX_OPENCORE_INSTANCES) { + LOGW("Exceeds maximum number of OpenCore instances"); + mInit = -EBUSY; + return; + } +#endif + LOGV("construct PlayerDriver"); mPlayerDriver = new PlayerDriver(this); LOGV("send PLAYER_SETUP"); mInit = mPlayerDriver->enqueueCommand(new PlayerSetup(0,0)); - mMemBase = 0; - mIsDataSourceSet = false; - mDuration = -1; } status_t PVPlayer::initCheck() @@ -1172,32 +1203,31 @@ status_t PVPlayer::initCheck() PVPlayer::~PVPlayer() { LOGV("PVPlayer destructor"); - PlayerQuit quit = PlayerQuit(0,0); - mPlayerDriver->enqueueCommand(&quit); // will wait on mSyncSem, signaled by player thread + if (mPlayerDriver != NULL) { + PlayerQuit quit = PlayerQuit(0,0); + mPlayerDriver->enqueueCommand(&quit); // will wait on mSyncSem, signaled by player thread + } free(mDataSourcePath); - if (mMemBase) { - munmap(mMemBase, mMemSize); + if (mSharedFd >= 0) { + close(mSharedFd); } -} - -status_t PVPlayer::setSigBusHandlerStructTLSKey(pthread_key_t key) -{ - osclfilenativesigbuskey = key; - return OK; +#ifdef MAX_OPENCORE_INSTANCES + android_atomic_dec(&sNumInstances); +#endif } status_t PVPlayer::setDataSource(const char *url) { LOGV("setDataSource(%s)", url); - if (mMemBase) { - munmap(mMemBase, mMemSize); - mMemBase = NULL; + if (mSharedFd >= 0) { + close(mSharedFd); + mSharedFd = -1; } free(mDataSourcePath); mDataSourcePath = NULL; // Don't let somebody trick us in to reading some random block of memory - if (strncmp("mem://", url, 6) == 0) + if (strncmp("sharedfd://", url, 11) == 0) return android::UNKNOWN_ERROR; mDataSourcePath = strdup(url); return OK; @@ -1209,32 +1239,17 @@ status_t PVPlayer::setDataSource(int fd, int64_t offset, int64_t length) { // Eventually we'll fix PV to use a file descriptor directly instead // of using mmap(). LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); - if (mMemBase) { - munmap(mMemBase, mMemSize); - mMemBase = NULL; + if (mSharedFd >= 0) { + close(mSharedFd); + mSharedFd = -1; } free(mDataSourcePath); mDataSourcePath = NULL; - // round offset down to page size - long pagesize = PAGESIZE; - long mapoffset = offset & ~(pagesize - 1); - long mapoffsetdelta = offset - mapoffset; - - void * bar = mmap(0, length + mapoffsetdelta, PROT_READ, MAP_PRIVATE, fd, mapoffset); - if ((int)bar == -1) { - LOGV("error mapping file: %s\n", strerror(errno)); - return android::UNKNOWN_ERROR; - } - - mMemBase = bar; - mMemSize = length + mapoffsetdelta; char buf[80]; - sprintf(buf, "mem://%p:%lld:%lld", mMemBase, - (int64_t) mapoffsetdelta, - (int64_t) mMemSize - mapoffsetdelta); + mSharedFd = dup(fd); + sprintf(buf, "sharedfd://%d:%lld:%lld", mSharedFd, offset, length); mDataSourcePath = strdup(buf); - madvise(mMemBase, mMemSize, MADV_RANDOM); return OK; } @@ -1417,9 +1432,9 @@ status_t PVPlayer::reset() } mSurface.clear(); LOGV("unmap file"); - if (mMemBase) { - munmap(mMemBase, mMemSize); - mMemBase = NULL; + if (mSharedFd >= 0) { + close(mSharedFd); + mSharedFd = -1; } mIsDataSourceSet = false; return ret; diff --git a/android/samples/android_surface_output_fb.cpp b/android/samples/android_surface_output_fb.cpp new file mode 100644 index 000000000..f0056226c --- /dev/null +++ b/android/samples/android_surface_output_fb.cpp @@ -0,0 +1,318 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2009 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. + * ------------------------------------------------------------------- + */ + +/* + * This is a sample video sink using frame buffer push model. The + * video output is NV21 (YUV 420 semi-planar with VUVU ordering). + * This requires re-ordering the YUV 420 planar output from the + * software codec to match the hardware color converter. The + * encoder outputs its frames in NV21, so no re-order is necessary. + * + * The hardware decoder and hardware video unit share pmem buffers + * (tunneling mode). For software codecs, we allocate a pmem buffer + * and convert the decoded YUV frames while copying to them to the + * pmem frame buffers used by the hardware output. + * + * This code should be compiled into a libopencorehw.so module. + * Here is a sample makefile to build the library: + * + * LOCAL_PATH := $(call my-dir) + * include $(CLEAR_VARS) + * + * # Set up the OpenCore variables. + * include external/opencore/Config.mk + * LOCAL_C_INCLUDES := $(PV_INCLUDES) + * + * LOCAL_SRC_FILES := android_surface_output_fb.cpp + * + * LOCAL_CFLAGS := $(PV_CFLAGS) + * + * LOCAL_SHARED_LIBRARIES := \ + * libutils \ + * libcutils \ + * libui \ + * libhardware\ + * libandroid_runtime \ + * libmedia \ + * libsgl \ + * libopencorecommon \ + * libicuuc \ + * libopencoreplayer + * + * LOCAL_MODULE := libopencorehw + * + * LOCAL_LDLIBS += + * + * include $(BUILD_SHARED_LIBRARY) + * + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "VideoMioFB" +#include <utils/Log.h> + +#include "android_surface_output_fb.h" +#include <media/PVPlayer.h> + +#define PLATFORM_PRIVATE_PMEM 1 + +#if HAVE_ANDROID_OS +#include <linux/android_pmem.h> +#endif + +using namespace android; + +static const char* pmem_adsp = "/dev/pmem_adsp"; +static const char* pmem = "/dev/pmem"; + +OSCL_EXPORT_REF AndroidSurfaceOutputFB::AndroidSurfaceOutputFB() : + AndroidSurfaceOutput() +{ + mHardwareCodec = false; +} + +OSCL_EXPORT_REF AndroidSurfaceOutputFB::~AndroidSurfaceOutputFB() +{ +} + +// create a frame buffer for software codecs +OSCL_EXPORT_REF bool AndroidSurfaceOutputFB::initCheck() +{ + + // initialize only when we have all the required parameters + if (((iVideoParameterFlags & VIDEO_SUBFORMAT_VALID) == 0) || !checkVideoParameterFlags()) + return mInitialized; + + // release resources if previously initialized + closeFrameBuf(); + + // reset flags in case display format changes in the middle of a stream + resetVideoParameterFlags(); + + // copy parameters in case we need to adjust them + int displayWidth = iVideoDisplayWidth; + int displayHeight = iVideoDisplayHeight; + int frameWidth = iVideoWidth; + int frameHeight = iVideoHeight; + int frameSize; + + // MSM72xx hardware codec uses semi-planar format + if (iVideoSubFormat == PVMF_YUV420_SEMIPLANAR_YVU) { + LOGV("using hardware codec"); + mHardwareCodec = true; + } else { + LOGV("using software codec"); + + // YUV420 frames are 1.5 bytes/pixel + frameSize = (frameWidth * frameHeight * 3) / 2; + + // create frame buffer heap + sp<MemoryHeapBase> master = new MemoryHeapBase(pmem_adsp, frameSize * kBufferCount); + if (master->heapID() < 0) { + LOGE("Error creating frame buffer heap"); + return false; + } + master->setDevice(pmem); + mHeapPmem = new MemoryHeapPmem(master, 0); + mHeapPmem->slap(); + master.clear(); + ISurface::BufferHeap buffers(displayWidth, displayHeight, + frameWidth, frameHeight, PIXEL_FORMAT_YCbCr_420_SP, mHeapPmem); + mSurface->registerBuffers(buffers); + + // create frame buffers + for (int i = 0; i < kBufferCount; i++) { + mFrameBuffers[i] = i * frameSize; + } + + LOGV("video = %d x %d", displayWidth, displayHeight); + LOGV("frame = %d x %d", frameWidth, frameHeight); + LOGV("frame #bytes = %d", frameSize); + + // register frame buffers with SurfaceFlinger + mFrameBufferIndex = 0; + } + + mInitialized = true; + LOGV("sendEvent(MEDIA_SET_VIDEO_SIZE, %d, %d)", iVideoDisplayWidth, iVideoDisplayHeight); + mPvPlayer->sendEvent(MEDIA_SET_VIDEO_SIZE, iVideoDisplayWidth, iVideoDisplayHeight); + return mInitialized; +} + +PVMFStatus AndroidSurfaceOutputFB::writeFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info) +{ + if (mSurface == 0) return PVMFFailure; + + // hardware codec + if (mHardwareCodec) { + + // initialize frame buffer heap + if (mHeapPmem == 0) { + LOGV("initializing for hardware"); + LOGV("private data pointer is 0%p\n", data_header_info.private_data_ptr); + + // check for correct video format + if (iVideoSubFormat != PVMF_YUV420_SEMIPLANAR_YVU) return PVMFFailure; + + uint32 fd; + if (!getPmemFd(data_header_info.private_data_ptr, &fd)) { + LOGE("Error getting pmem heap from private_data_ptr"); + return PVMFFailure; + } + sp<MemoryHeapBase> master = (MemoryHeapBase *) fd; + master->setDevice(pmem); + mHeapPmem = new MemoryHeapPmem(master, 0); + mHeapPmem->slap(); + master.clear(); + + // register frame buffers with SurfaceFlinger + ISurface::BufferHeap buffers(iVideoDisplayWidth, iVideoDisplayHeight, + iVideoWidth, iVideoHeight, + PIXEL_FORMAT_YCbCr_420_SP, mHeapPmem); + mSurface->registerBuffers(buffers); + } + + // get pmem offset and post to SurfaceFlinger + if (!getOffset(data_header_info.private_data_ptr, &mOffset)) { + LOGE("Error getting pmem offset from private_data_ptr"); + return PVMFFailure; + } + mSurface->postBuffer(mOffset); + } else { + + // software codec + convertFrame(aData, static_cast<uint8*>(mHeapPmem->base()) + mFrameBuffers[mFrameBufferIndex], aDataLen); + // post to SurfaceFlinger + if (++mFrameBufferIndex == kBufferCount) mFrameBufferIndex = 0; + mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]); + } + + return PVMFSuccess; +} + +// post the last video frame to refresh screen after pause +void AndroidSurfaceOutputFB::postLastFrame() +{ + mSurface->postBuffer(mOffset); +} + +void AndroidSurfaceOutputFB::closeFrameBuf() +{ + LOGV("CloseFrameBuf"); + if (!mInitialized) return; + + mInitialized = false; + if (mSurface.get()) { + LOGV("unregisterBuffers"); + mSurface->unregisterBuffers(); + mSurface.clear(); + } + + // free frame buffers + LOGV("free frame buffers"); + for (int i = 0; i < kBufferCount; i++) { + mFrameBuffers[i] = 0; + } + + // free heaps + LOGV("free mFrameHeap"); + mFrameHeap.clear(); + LOGV("free mHeapPmem"); + mHeapPmem.clear(); +} + +bool AndroidSurfaceOutputFB::getPmemFd(OsclAny *private_data_ptr, uint32 *pmemFD) +{ + PLATFORM_PRIVATE_LIST *listPtr = NULL; + PLATFORM_PRIVATE_PMEM_INFO *pmemInfoPtr = NULL; + bool returnType = false; + LOGV("in getPmemfd - privatedataptr=%p\n",private_data_ptr); + listPtr = (PLATFORM_PRIVATE_LIST*) private_data_ptr; + + for (uint32 i=0;i<listPtr->nEntries;i++) + { + if(listPtr->entryList->type == PLATFORM_PRIVATE_PMEM) + { + LOGV("in getPmemfd - entry type = %d\n",listPtr->entryList->type); + pmemInfoPtr = (PLATFORM_PRIVATE_PMEM_INFO*) (listPtr->entryList->entry); + returnType = true; + if(pmemInfoPtr){ + *pmemFD = pmemInfoPtr->pmem_fd; + LOGV("in getPmemfd - pmemFD = %d\n",*pmemFD); + } + break; + } + } + return returnType; +} + +bool AndroidSurfaceOutputFB::getOffset(OsclAny *private_data_ptr, uint32 *offset) +{ + PLATFORM_PRIVATE_LIST *listPtr = NULL; + PLATFORM_PRIVATE_PMEM_INFO *pmemInfoPtr = NULL; + bool returnType = false; + + listPtr = (PLATFORM_PRIVATE_LIST*) private_data_ptr; + LOGV("in getOffset: listPtr = %p\n",listPtr); + for (uint32 i=0;i<listPtr->nEntries;i++) + { + if(listPtr->entryList->type == PLATFORM_PRIVATE_PMEM) + { + LOGV(" in getOffset: entrytype = %d\n",listPtr->entryList->type); + + pmemInfoPtr = (PLATFORM_PRIVATE_PMEM_INFO*) (listPtr->entryList->entry); + returnType = true; + if(pmemInfoPtr){ + *offset = pmemInfoPtr->offset; + LOGV("in getOffset: offset = %d\n",*offset); + } + break; + } + } + return returnType; +} + +static inline void* byteOffset(void* p, size_t offset) { return (void*)((uint8_t*)p + offset); } + +void AndroidSurfaceOutputFB::convertFrame(void* src, void* dst, size_t len) +{ + // copy the Y plane + size_t y_plane_size = iVideoWidth * iVideoHeight; + //LOGV("len=%u, y_plane_size=%u", len, y_plane_size); + memcpy(dst, src, y_plane_size + iVideoWidth); + + // re-arrange U's and V's + uint16_t* pu = (uint16_t*)byteOffset(src, y_plane_size); + uint16_t* pv = (uint16_t*)byteOffset(pu, y_plane_size / 4); + uint32_t* p = (uint32_t*)byteOffset(dst, y_plane_size); + + int count = y_plane_size / 8; + //LOGV("u = %p, v = %p, p = %p, count = %d", pu, pv, p, count); + do { + uint32_t u = *pu++; + uint32_t v = *pv++; + *p++ = ((u & 0xff) << 8) | ((u & 0xff00) << 16) | (v & 0xff) | ((v & 0xff00) << 8); + } while (--count); +} + +// factory function for playerdriver linkage +extern "C" AndroidSurfaceOutput* createVideoMio() +{ + return new AndroidSurfaceOutputFB(); +} + diff --git a/android/samples/android_surface_output_fb.h b/android/samples/android_surface_output_fb.h new file mode 100644 index 000000000..aa751be44 --- /dev/null +++ b/android/samples/android_surface_output_fb.h @@ -0,0 +1,79 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2009 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. + * ------------------------------------------------------------------- + */ + +#ifndef ANDROID_SURFACE_OUTPUT_FB_H_INCLUDED +#define ANDROID_SURFACE_OUTPUT_FB_H_INCLUDED + +#include "android_surface_output.h" + +// support for shared contiguous physical memory +#include <utils/MemoryHeapPmem.h> + +// data structures for tunneling buffers +typedef struct PLATFORM_PRIVATE_PMEM_INFO +{ + /* pmem file descriptor */ + uint32 pmem_fd; + uint32 offset; +} PLATFORM_PRIVATE_PMEM_INFO; + +typedef struct PLATFORM_PRIVATE_ENTRY +{ + /* Entry type */ + uint32 type; + + /* Pointer to platform specific entry */ + OsclAny* entry; +} PLATFORM_PRIVATE_ENTRY; + +typedef struct PLATFORM_PRIVATE_LIST +{ + /* Number of entries */ + uint32 nEntries; + + /* Pointer to array of platform specific entries * + * Contiguous block of PLATFORM_PRIVATE_ENTRY elements */ + PLATFORM_PRIVATE_ENTRY* entryList; +} PLATFORM_PRIVATE_LIST; + + +class AndroidSurfaceOutputFB : public AndroidSurfaceOutput +{ +public: + AndroidSurfaceOutputFB(); + + // frame buffer interface + virtual bool initCheck(); + virtual PVMFStatus writeFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info); + virtual void postLastFrame(); + virtual void closeFrameBuf(); + + OSCL_IMPORT_REF ~AndroidSurfaceOutputFB(); + +private: + bool getPmemFd(OsclAny *private_data_ptr, uint32 *pmemFD); + bool getOffset(OsclAny *private_data_ptr, uint32 *offset); + void convertFrame(void* src, void* dst, size_t len); + + // hardware frame buffer support + sp<MemoryHeapPmem> mHeapPmem; + bool mHardwareCodec; + uint32 mOffset; +}; + +#endif // ANDROID_SURFACE_OUTPUT_FB_H_INCLUDED diff --git a/engines/author/src/pvaenodeutility.cpp b/engines/author/src/pvaenodeutility.cpp index a6aab0d5d..16107c269 100644 --- a/engines/author/src/pvaenodeutility.cpp +++ b/engines/author/src/pvaenodeutility.cpp @@ -281,15 +281,6 @@ void PVAuthorEngineNodeUtility::NodeCommandCompleted(const PVMFCmdResp& aRespons PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVAuthorEngineNodeUtility::NodeCommandCompleted")); - if (aResponse.GetCmdStatus() != PVMFSuccess) - { - PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, - (0, "PVAuthorEngineNodeUtility::NodeCommandCompleted: Command failed - context=0x%x, status=0x%x", - aResponse.GetContext(), aResponse.GetCmdStatus())); - CompleteUtilityCmd(iCmdQueue[0], aResponse.GetCmdStatus()); - return; - } - if (iCmdQueue.empty()) { LOG_ERR((0, "PVAuthorEngineNodeUtility::NodeCommandCompleted: Error - Empty command queue")); @@ -298,8 +289,17 @@ void PVAuthorEngineNodeUtility::NodeCommandCompleted(const PVMFCmdResp& aRespons return; } - PVMFStatus status = PVMFSuccess; PVAENodeUtilCmd cmd = iCmdQueue[0]; + if (aResponse.GetCmdStatus() != PVMFSuccess) + { + PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, + (0, "PVAuthorEngineNodeUtility::NodeCommandCompleted: Command failed - context=0x%x, status=0x%x", + aResponse.GetContext(), aResponse.GetCmdStatus())); + CompleteUtilityCmd(cmd, aResponse.GetCmdStatus()); + return; + } + + PVMFStatus status = PVMFSuccess; switch (cmd.iType) { case PVAENU_CMD_CONNECT: @@ -339,7 +339,12 @@ void PVAuthorEngineNodeUtility::NodeCommandCompleted(const PVMFCmdResp& aRespons } if (status != PVMFPending) + { CompleteUtilityCmd(cmd, status); + } + else if (iCmdQueue.size() == 1) { // kick off the execution of the command + RunIfNotReady(); + } } //////////////////////////////////////////////////////////////////////////// @@ -440,27 +445,53 @@ void PVAuthorEngineNodeUtility::CompleteUtilityCmd(const PVAENodeUtilCmd& aCmd, { LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteUtilityCmd: Error - Observer not set")); OSCL_LEAVE(OsclErrGeneral); - // return; This statement was removed to avoid compiler warning for Unreachable Code + // return; This statement was removed to avoid compiler warning for Unreachable Code } - if (iCmdQueue.empty() || aCmd.iType != iCmdQueue[0].iType) + // make the error logs more specific + bool emptyCmdQueueOrMismatchedCmd = false; + if (iCmdQueue.empty()) + { + emptyCmdQueueOrMismatchedCmd = true; + LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteUtilityCmd: Error - Empty command queue")); + } + else if (aCmd.iType != iCmdQueue[0].iType) + { + emptyCmdQueueOrMismatchedCmd = true; + LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteUtilityCmd: Error - Mismatched command (%d vs %d)", aCmd.iType, iCmdQueue[0].iType)); + } + if (emptyCmdQueueOrMismatchedCmd) { - LOG_ERR((0, "PVAuthorEngineNodeUtility::CompleteUtilityCmd: Error - Empty command queue or mismatched command")); PVMFAsyncEvent event(PVMFErrorEvent, PVMFFailure, NULL, NULL); iObserver->NodeUtilErrorEvent(event); return; } - // Remove command from queue - iCmdQueue.erase(iCmdQueue.begin()); - - // Callback to engine - PVMFCmdResp resp(0, aCmd.iContext, aStatus); - iObserver->NodeUtilCommandCompleted(resp); + if (aStatus == PVMFFailure) + { + // if one cmd failed, skip the remaining commands in the queue. + // send the same error code via callbacks to author engine + // to signal the (failure) completion of these commands. + while (!iCmdQueue.empty()) + { + PVAENodeUtilCmd cmd = iCmdQueue[0]; + iCmdQueue.erase(iCmdQueue.begin()); + PVMFCmdResp resp(0, cmd.iContext, aStatus); + iObserver->NodeUtilCommandCompleted(resp); + } + } + else + { + iCmdQueue.erase(iCmdQueue.begin()); + PVMFCmdResp resp(0, aCmd.iContext, aStatus); + iObserver->NodeUtilCommandCompleted(resp); + } // Run next command when needed if (!iCmdQueue.empty()) + { RunIfNotReady(); + } } //////////////////////////////////////////////////////////////////////////// @@ -909,25 +940,28 @@ PVMFStatus PVAuthorEngineNodeUtility::DoReset(const PVAENodeUtilCmd& aCmd) PVMFStatus PVAuthorEngineNodeUtility::CompleteStateTransition(const PVAENodeUtilCmd& aCmd, TPVMFNodeInterfaceState aState) { - LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::CompleteStateTransition: aState=%d", aState)); + LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::CompleteStateTransition")); for (uint32 i = 0; i < aCmd.iNodes.size(); i++) { if (aCmd.iNodes[i]->iNode->GetState() != aState) { + LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::CompleteStateTransition: node %d (%d) does not have the same state as the node util(%d)", i, aCmd.iNodes[i]->iNode->GetState(), aState)); if ((aCmd.iType == PVAENU_CMD_RESET) && (aCmd.iNodes[i]->iNode->GetState() == EPVMFNodeIdle)) { + LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::CompleteStateTransition: RESET and EPVMFNodeIdle - do nothing")); //If the command is RESET and GetState() == EPVMFNodeIdle, be tolerant //do nothing; } else { // Some nodes have not completed this command. Continue to wait + LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::CompleteStateTransition: Continue to wait")); return PVMFPending; } } } + LOG_STACK_TRACE((0, "PVAuthorEngineNodeUtility::CompleteStateTransition: return PVMFSuccess")); return PVMFSuccess; } - diff --git a/nodes/pvfileoutputnode/include/pvmf_fileoutput_config.h b/nodes/pvfileoutputnode/include/pvmf_fileoutput_config.h index 0d0117057..aec47e304 100644 --- a/nodes/pvfileoutputnode/include/pvmf_fileoutput_config.h +++ b/nodes/pvfileoutputnode/include/pvmf_fileoutput_config.h @@ -70,6 +70,15 @@ class PvmfFileOutputNodeConfigInterface : public PVInterface virtual bool queryInterface(const PVUuid& uuid, PVInterface*& iface) = 0; /** + * This method sets the output file handle. This method must be called before + * Start() is called. + * + * @param aFileHandle Output file handle + * @return Completion status of this method. + */ + virtual PVMFStatus SetOutputFile(OsclFileHandle* aFileHandle) = 0; + + /** * This method sets the output file name. This method must be called before * the engine / node is initialized. * diff --git a/nodes/pvfileoutputnode/src/pvmf_fileoutput_node.cpp b/nodes/pvfileoutputnode/src/pvmf_fileoutput_node.cpp index c9fe3d1b2..c40e1ff01 100644 --- a/nodes/pvfileoutputnode/src/pvmf_fileoutput_node.cpp +++ b/nodes/pvfileoutputnode/src/pvmf_fileoutput_node.cpp @@ -417,6 +417,34 @@ bool PVMFFileOutputNode::queryInterface(const PVUuid& uuid, PVInterface*& iface) } //////////////////////////////////////////////////////////////////////////// +PVMFStatus PVMFFileOutputNode::SetOutputFile(OsclFileHandle* aFileHandle) +{ + if(iInterfaceState != EPVMFNodeIdle + && iInterfaceState != EPVMFNodeInitialized + && iInterfaceState != EPVMFNodeCreated + && iInterfaceState != EPVMFNodePrepared) + return false; + + iOutputFileName = _STRLIT("");//wipe out file name if file handle is in use + CloseOutputFile(); + + if(0 == iOutputFile.SetFileHandle(aFileHandle) ) + { + uint32 mode = Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY; + if(!iOutputFile.Open("", mode, iFs )) + { + iFileOpened = true; + iFirstMediaData=true; + return PVMFSuccess; + } + } + + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, + (0, "PVMFFileOutputNode::SetOutputFile() Error Ln %d", __LINE__)); + return PVMFFailure; +} + +//////////////////////////////////////////////////////////////////////////// PVMFStatus PVMFFileOutputNode::SetOutputFileName(const OSCL_wString& aFileName) { if (iInterfaceState != EPVMFNodeIdle @@ -425,6 +453,9 @@ PVMFStatus PVMFFileOutputNode::SetOutputFileName(const OSCL_wString& aFileName) && iInterfaceState != EPVMFNodePrepared) return false; + CloseOutputFile(); + iFirstMediaData = false; + iOutputFileName = aFileName; return PVMFSuccess; } diff --git a/nodes/pvfileoutputnode/src/pvmf_fileoutput_node.h b/nodes/pvfileoutputnode/src/pvmf_fileoutput_node.h index 8e8f50e58..b86f09a57 100644 --- a/nodes/pvfileoutputnode/src/pvmf_fileoutput_node.h +++ b/nodes/pvfileoutputnode/src/pvmf_fileoutput_node.h @@ -209,6 +209,7 @@ class PVMFFileOutputNode : public OsclActiveObject, public PVMFNodeInterface, void HandlePortActivity(const PVMFPortActivity& aActivity); // Pure virtual from PvmfFileOutputNodeConfigInterface + PVMFStatus SetOutputFile(OsclFileHandle* aFileHandle); PVMFStatus SetOutputFileName(const OSCL_wString& aFileName); // Pure virtual from PvmfComposerSizeAndDurationInterface diff --git a/nodes/pvmediainputnode/src/pvmf_media_input_node_outport.cpp b/nodes/pvmediainputnode/src/pvmf_media_input_node_outport.cpp index 23ce2daae..bd18c07a3 100644 --- a/nodes/pvmediainputnode/src/pvmf_media_input_node_outport.cpp +++ b/nodes/pvmediainputnode/src/pvmf_media_input_node_outport.cpp @@ -250,6 +250,7 @@ PVMFCommandId PvmfMediaInputNodeOutPort::writeAsync(uint8 format_type, int32 for iNode->ReportErrorEvent(PVMFErrPortProcessing); OsclError::Leave(OsclErrGeneral); + return -1; } diff --git a/nodes/pvmp4ffcomposernode/include/pvmp4ffcn_clipconfig.h b/nodes/pvmp4ffcomposernode/include/pvmp4ffcn_clipconfig.h index a32a3f662..ca90af77f 100644 --- a/nodes/pvmp4ffcomposernode/include/pvmp4ffcn_clipconfig.h +++ b/nodes/pvmp4ffcomposernode/include/pvmp4ffcn_clipconfig.h @@ -41,6 +41,9 @@ #ifndef PV_MP4FFCOMPOSER_CONFIG_H_INCLUDED #include "pv_mp4ffcomposer_config.h" #endif +#ifndef OSCL_FILE_HANDLE_H_INCLUDED +#include "oscl_file_handle.h" +#endif #define KPVMp4FFCNClipConfigUuid PVUuid(0x2e3b479f,0x2c46,0x465c,0xba,0x41,0xb8,0x91,0x11,0xa9,0xdf,0x3a) @@ -145,6 +148,16 @@ class PVMp4FFCNClipConfigInterface : public PVInterface virtual bool queryInterface(const PVUuid& uuid, PVInterface*& iface) = 0; /** + * This method sets the output file handle. This method must be called before + * Start() is called. + * + * @param aFileHandle Output file handle + * @return Completion status of this method. + */ + virtual PVMFStatus SetOutputFile(OsclFileHandle* aFileHandle) = 0; + + + /** * This method sets the output file name. This method must be called before * Start() is called. * diff --git a/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.cpp b/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.cpp index ccacf95e1..32d815ecd 100644 --- a/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.cpp +++ b/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.cpp @@ -106,6 +106,7 @@ PVMp4FFComposerNode::PVMp4FFComposerNode(int32 aPriority) , iNodeEndOfDataReached(false) , iformat_h264(PVMF_FORMAT_UNKNOWN) , iformat_text(PVMF_FORMAT_UNKNOWN) + , iOutputFileHandle(NULL) { iInterfaceState = EPVMFNodeCreated; iNum_PPS_Set = 0; @@ -168,6 +169,11 @@ PVMp4FFComposerNode::~PVMp4FFComposerNode() { PVA_FF_IMpeg4File::DestroyMP4FileObject(iMpeg4File); } + if(iOutputFileHandle) + { + OSCL_DELETE( iOutputFileHandle ); + iOutputFileHandle = NULL; + } if (pConfig != NULL) { @@ -439,12 +445,48 @@ OSCL_EXPORT_REF bool PVMp4FFComposerNode::queryInterface(const PVUuid& uuid, PVI //////////////////////////////////////////////////////////////////////////// // PVMp4FFCNClipConfigInterface routines //////////////////////////////////////////////////////////////////////////// +OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetOutputFile(OsclFileHandle* aFileHandle) +{ + if(iInterfaceState != EPVMFNodeIdle && iInterfaceState != EPVMFNodeInitialized) + return PVMFFailure; + + iFileName = _STRLIT("");//wipe out file name if file handle is in use + + if(iOutputFileHandle) + OSCL_DELETE( iOutputFileHandle ); + iOutputFileHandle = OSCL_NEW( Oscl_File, () ); + if( iOutputFileHandle ) + { + if(0 == iOutputFileHandle->SetFileHandle(aFileHandle) ) + { + uint32 mode = Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY; + if(!iOutputFileHandle->Open("", mode, iFs )) + return PVMFSuccess; + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, + (0, "PVMp4FFComposerNode::SetOutputFile: Open() Error Ln %d", __LINE__)); + } + OSCL_DELETE( iOutputFileHandle ); + iOutputFileHandle = NULL; + } + + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, + (0, "PVMp4FFComposerNode::SetOutputFile() Error Ln %d", __LINE__)); + return PVMFFailure; +} + + OSCL_EXPORT_REF PVMFStatus PVMp4FFComposerNode::SetOutputFileName(const OSCL_wString& aFileName) { if (iInterfaceState != EPVMFNodeIdle && iInterfaceState != EPVMFNodeInitialized) - return false; + return PVMFFailure; iFileName = aFileName; + if(iOutputFileHandle) + { + OSCL_DELETE( iOutputFileHandle ); + iOutputFileHandle = NULL; + } + return PVMFSuccess; } @@ -1096,8 +1138,21 @@ void PVMp4FFComposerNode::DoStart(PVMp4FFCNCmd& aCmd) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "PVMp4FFComposerNode::DoStart: Calling PVA_FF_IMpeg4File::createMP4File(%d,0x%x,%d)", iFileType, &iFs, iAuthoringMode)); - iMpeg4File = PVA_FF_IMpeg4File::createMP4File(iFileType, iOutputPath, iPostfix, - (void*) & iFs, iAuthoringMode, iFileName, iCacheSize); + if(iOutputFileHandle) + { + OSCL_ASSERT(NULL != iOutputFileHandle->Handle()); + + iMpeg4File = PVA_FF_IMpeg4File::createMP4File(iFileType, iAuthoringMode, iOutputFileHandle, iCacheSize); + if( iMpeg4File ) + { + iOutputFileHandle = NULL; //let ff take care of the file close and dealloc + } + } + else + { + iMpeg4File = PVA_FF_IMpeg4File::createMP4File(iFileType, iOutputPath, iPostfix, + (void*)&iFs, iAuthoringMode, iFileName, iCacheSize); + } if (!iMpeg4File) { diff --git a/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.h b/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.h index 9f15ee518..75e66d8a7 100644 --- a/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.h +++ b/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.h @@ -152,6 +152,7 @@ class PVMp4FFComposerNode : public PVMFNodeInterface, OSCL_IMPORT_REF bool queryInterface(const PVUuid& uuid, PVInterface*& iface); // Pure virtual functions from PVMp4FFCNClipConfigInterface + OSCL_IMPORT_REF PVMFStatus SetOutputFile(OsclFileHandle* aFileHandle); OSCL_IMPORT_REF PVMFStatus SetOutputFileName(const OSCL_wString& aFileName); OSCL_IMPORT_REF PVMFStatus SetAuthoringMode(PVMp4FFCN_AuthoringMode aAuthoringMode = PVMP4FFCN_3GPP_DOWNLOAD_MODE); OSCL_IMPORT_REF PVMFStatus SetPresentationTimescale(uint32 aTimescale); @@ -328,6 +329,7 @@ class PVMp4FFComposerNode : public PVMFNodeInterface, // File format PVA_FF_IMpeg4File* iMpeg4File; + Oscl_File *iOutputFileHandle; OSCL_wHeapString<OsclMemAllocator> iFileName; OSCL_wHeapString<OsclMemAllocator> iPostfix; OSCL_wHeapString<OsclMemAllocator> iOutputPath; diff --git a/nodes/pvomxvideodecnode/src/pvmf_omx_videodec_node.cpp b/nodes/pvomxvideodecnode/src/pvmf_omx_videodec_node.cpp index 362b1799e..0fb598294 100644 --- a/nodes/pvomxvideodecnode/src/pvmf_omx_videodec_node.cpp +++ b/nodes/pvomxvideodecnode/src/pvmf_omx_videodec_node.cpp @@ -6128,13 +6128,25 @@ void PVMFOMXVideoDecNode::DoCancelAllCommands(PVMFOMXVideoDecNodeCommand& aCmd) } //next cancel all queued commands + // Create a temporary queue for pending commands + // Copy the pending commands to the new queue + PVMFOMXVideoDecNodeCmdQ iTempPendingCmds; + for(int i=0; i< iInputCommands.size(); i++) { - //start at element 1 since this cancel command is element 0. - while (iInputCommands.size() > 1) - { - CommandComplete(iInputCommands, iInputCommands[1], PVMFErrCancelled); - } + PVMFOMXVideoDecNodeCommand* cmd = iInputCommands.FindById(i); + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXVideoDecNode::DoCancelAllCommands CancelAllCmd ID %d InputCmd ID %d", aCmd.iId , cmd->iId)); + if ((aCmd.iId > cmd->iId) && ((aCmd.iId - cmd->iId ) < 0x80000000)) + iTempPendingCmds.StoreL(*cmd); + } + for(int i=0; i< iTempPendingCmds.size(); i++) + { + // Get the queue from the top + PVMFOMXVideoDecNodeCommand* cmd = iTempPendingCmds.FindById(i); + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, (0, "PVMFOMXVideoDecNode::DoCancelAllCommands Cancel Cmd ID %d", cmd->iId)); + //cancel the queued command + CommandComplete(iInputCommands, *cmd, PVMFErrCancelled); } + iTempPendingCmds.clear(); if (iResetInProgress && !iResetMsgSent) { diff --git a/nodes/pvomxvideoencnode/src/pvmf_omx_videoenc_node.cpp b/nodes/pvomxvideoencnode/src/pvmf_omx_videoenc_node.cpp index e59441a1e..7d12693cc 100644 --- a/nodes/pvomxvideoencnode/src/pvmf_omx_videoenc_node.cpp +++ b/nodes/pvomxvideoencnode/src/pvmf_omx_videoenc_node.cpp @@ -2057,20 +2057,25 @@ void PVMFOMXVideoEncNode::DoStop(PVMFVideoEncNodeCommand& aCmd) //////////////////////////////////////////////////////////////////////////// void PVMFOMXVideoEncNode::DeleteVideoEncoder() { - - if (iOMXVideoEncoder != NULL) - { + LOGV("DeleteVideoEncoder"); + if (iOMXVideoEncoder != NULL) { OMX_ERRORTYPE err; - /* Free Component handle. */ - err = PV_MasterOMX_FreeHandle(iOMXVideoEncoder); - if (err != OMX_ErrorNone) - { - //Error condition report - PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, - (0, "PVMFOMXVideoEncNode::DeleteVideoEncoder(): Can't free encoder's handle!")); + OMX_STATETYPE state; + err = OMX_GetState(iOMXVideoEncoder, &state); + if (err != OMX_ErrorNone) { + LOGE("Failed to get encoder state with failure code(%d)", err); + } else if (state != OMX_StateLoaded && state != OMX_StateInvalid) { + LOGE("OMX_FreeHandle is called in a state(%d) other than OMX_StateLoaded or OMX_StateInvalid.", state); } - iOMXVideoEncoder = NULL; + // No matter what, call OMX_FreeHandle anyway + err = PV_MasterOMX_FreeHandle(iOMXVideoEncoder); + if (err != OMX_ErrorNone) { + LOGE("Failed to free encoder handle with failure code(%d)", err); + } else { + LOGI("video encoder handle has been successfully released"); + iOMXVideoEncoder = NULL; + } } } diff --git a/oscl/oscl/osclio/src/oscl_file_native.cpp b/oscl/oscl/osclio/src/oscl_file_native.cpp index 7817c0aca..6367088a1 100644 --- a/oscl/oscl/osclio/src/oscl_file_native.cpp +++ b/oscl/oscl/osclio/src/oscl_file_native.cpp @@ -24,7 +24,7 @@ #include "oscl_utf8conv.h" #include "oscl_int64_utils.h" -#ifdef ENABLE_MEMORY_PLAYBACK +#ifdef ENABLE_SHAREDFD_PLAYBACK #undef LOG_TAG #define LOG_TAG "OsclNativeFile" #include <utils/Log.h> @@ -34,97 +34,14 @@ #include "oscl_file_handle.h" -#ifdef ENABLE_MEMORY_PLAYBACK -pthread_key_t osclfilenativesigbuskey; - -/* - * Add a structure describing the desired signal handling behavior - * to the TLS. These structures form a linked list, which is needed - * because multiple files might be opened by the same thread, in - * which case we need to figure out which one was the one that - * faulted. - */ -static void addspecific(struct mediasigbushandler *newhandler) -{ - struct mediasigbushandler *existinghandler = - (struct mediasigbushandler*) pthread_getspecific(osclfilenativesigbuskey); - - if (existinghandler) -{ - // append the new handler - newhandler->next = NULL; - existinghandler->next = newhandler; - } - else - { - newhandler->next = NULL; - pthread_setspecific(osclfilenativesigbuskey, newhandler); - } -} - -/* - * Remove a previously added structure from the list. - */ -static void removespecific(struct mediasigbushandler *handler) -{ - struct mediasigbushandler *existinghandler = - (struct mediasigbushandler*) pthread_getspecific(osclfilenativesigbuskey); - - if (existinghandler == NULL || handler == NULL) -{ - LOGE("logic error"); - return; - } - - // to remove the first one, just set a new TLS entry - if (existinghandler == handler) - { - pthread_setspecific(osclfilenativesigbuskey, handler->next); - return; - } - - while (existinghandler->next) - { - if (existinghandler->next == handler) - { - existinghandler->next = existinghandler->next->next; - return; - } - existinghandler = existinghandler->next; - } -} - -/* - * Find the struct for a given fault address - */ -struct mediasigbushandler *OsclNativeFile::getspecificforfaultaddr(char *faultaddr) -{ - struct mediasigbushandler *h = - (struct mediasigbushandler*) pthread_getspecific(osclfilenativesigbuskey); - - while (h) -{ - OsclNativeFile *f = (OsclNativeFile*)h->data; - char *base = (char*) f->membase; - if (base <= faultaddr && faultaddr < base + f->memlen) - { - return h; - } - h = h->next; - } - LOGE("couldn't find handler for address %p\n", faultaddr); - return NULL; -} -#endif // ENABLE_MEMORY_PLAYBACK - OsclNativeFile::OsclNativeFile() { iOpenFileHandle = false; iMode = 0; iFile = 0; -#ifdef ENABLE_MEMORY_PLAYBACK - membase = NULL; +#ifdef ENABLE_SHAREDFD_PLAYBACK + iSharedFd = -1; #endif } @@ -226,23 +143,19 @@ int32 OsclNativeFile::Open(const oscl_wchar *filename, uint32 mode { return -1; } -#ifdef ENABLE_MEMORY_PLAYBACK - void* base; +#ifdef ENABLE_SHAREDFD_PLAYBACK + int fd; long long offset; long long len; - if (sscanf(convfilename, "mem://%p:%lld:%lld", &base, &offset, &len) == 3) + if (sscanf(convfilename, "sharedfd://%d:%lld:%lld", &fd, &offset, &len) == 3) { - membase = base; - memoffset = offset; - memlen = len; - mempos = 0; - - sigbushandler.handlesigbus = sigbushandlerfunc; - sigbushandler.sigbusvar = NULL; - sigbushandler.data = this; - addspecific(&sigbushandler); - sigbushandler.base = 0; // we do our own address matching - sigbushandler.len = 0; + iSharedFd = fd; + iSharedFilePosition = 0; + iSharedFileOffset = offset; + long long size = lseek64(iSharedFd, 0, SEEK_END); + lseek64(iSharedFd, 0, SEEK_SET); + size -= offset; + iSharedFileSize = size < len ? size : len; } else #endif @@ -312,22 +225,19 @@ int32 OsclNativeFile::Open(const char *filename, uint32 mode } openmode[index++] = '\0'; -#ifdef ENABLE_MEMORY_PLAYBACK - void* base; +#ifdef ENABLE_SHAREDFD_PLAYBACK + int fd; long long offset; long long len; - if (sscanf(filename, "mem://%p:%lld:%lld", &base, &offset, &len) == 3) + if (sscanf(filename, "sharedfd://%d:%lld:%lld", &fd, &offset, &len) == 3) { - membase = (void*)base; - memoffset = offset; - memlen = len; - mempos = 0; - sigbushandler.handlesigbus = sigbushandlerfunc; - sigbushandler.sigbusvar = NULL; - sigbushandler.data = this; - addspecific(&sigbushandler); - sigbushandler.base = 0; // we do our own address matching - sigbushandler.len = 0; + iSharedFd = fd; + iSharedFilePosition = 0; + iSharedFileOffset = offset; + long long size = lseek64(iSharedFd, 0, SEEK_END); + lseek64(iSharedFd, 0, SEEK_SET); + size -= offset; + iSharedFileSize = size < len ? size : len; } else #endif @@ -375,12 +285,13 @@ int32 OsclNativeFile::Close() closeret = fclose(iFile); iFile = NULL; } -#ifdef ENABLE_MEMORY_PLAYBACK - else if (membase != NULL) +#ifdef ENABLE_SHAREDFD_PLAYBACK + else if (iSharedFd >= 0) { - membase = NULL; - removespecific(&sigbushandler); - return 0; + // we don't need to, and in fact MUST NOT, close mSharedFd here, + // since it might still be shared by another OsclFileNative, and + // will be closed by the playerdriver when we're done with it. + closeret = 0; } #endif else @@ -392,59 +303,30 @@ int32 OsclNativeFile::Close() return closeret; } -#ifdef ENABLE_MEMORY_PLAYBACK -int OsclNativeFile::sigbushandlerfunc(siginfo_t *info, struct mediasigbushandler *data) -{ - char *faultaddr = (char*) info->si_addr; - LOGE("read fault at %p\n", faultaddr); - - struct mediasigbushandler *h = getspecificforfaultaddr(faultaddr); - if (h == NULL) - { - LOGE("No handler for fault range."); - return -1; - } - else - { - ((OsclNativeFile*)h->data)->memcpyfailed = 1; - // map in a zeroed out page so the operation can succeed - long pagesize = sysconf(_SC_PAGE_SIZE); - long pagemask = ~(pagesize - 1); - void * pageaddr = (void*)(((long)(faultaddr)) & pagemask); - - void * bar = mmap(pageaddr, pagesize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); - if (bar == MAP_FAILED) - { - LOGE("couldn't map zero page at %p: %s", pageaddr, strerror(errno)); - return -1; - } - } - return 0; -} -#endif - uint32 OsclNativeFile::Read(OsclAny *buffer, uint32 size, uint32 numelements) { -#ifdef ENABLE_MEMORY_PLAYBACK - if (membase) - { - int req = size * numelements; - if (mempos + req > memlen) - { - req = memlen - mempos; +#ifdef ENABLE_SHAREDFD_PLAYBACK + if (iSharedFd >= 0) { + // restore position, no locking is needed because all access to the + // shared filedescriptor is done by the same thread. + lseek64(iSharedFd, iSharedFilePosition + iSharedFileOffset, SEEK_SET); + uint32 count = size * numelements; + if (iSharedFilePosition + count > iSharedFileSize) { + count = iSharedFileSize - iSharedFilePosition; } - - memcpyfailed = 0; - memcpy(buffer, ((char*)membase) + memoffset + mempos, req); - if (memcpyfailed) - { - LOGE("got bus error while reading"); - return 0; + ssize_t numread = read(iSharedFd, buffer, count); + // unlock + long long curpos = lseek64(iSharedFd, 0, SEEK_CUR); + if (curpos >= 0) { + iSharedFilePosition = curpos - iSharedFileOffset; } - mempos += req; - return req / size; + if (numread < 0) { + return numread; + } + return numread / size; } #endif + if (iFile) { return fread(buffer, OSCL_STATIC_CAST(int32, size), OSCL_STATIC_CAST(int32, numelements), iFile); @@ -475,8 +357,8 @@ uint32 OsclNativeFile::GetReadAsyncNumElements() uint32 OsclNativeFile::Write(const OsclAny *buffer, uint32 size, uint32 numelements) { -#ifdef ENABLE_MEMORY_PLAYBACK - if (membase) +#ifdef ENABLE_SHAREDFD_PLAYBACK + if (iSharedFd >= 0) return 0; #endif if (iFile) @@ -490,18 +372,18 @@ int32 OsclNativeFile::Seek(int32 offset, Oscl_File::seek_type origin) { { -#ifdef ENABLE_MEMORY_PLAYBACK - if (membase) +#ifdef ENABLE_SHAREDFD_PLAYBACK + if (iSharedFd >= 0) { - int newpos = mempos; - if (origin == Oscl_File::SEEKCUR) newpos = mempos + offset; + int newpos = iSharedFilePosition; + if (origin == Oscl_File::SEEKCUR) newpos = newpos + offset; else if (origin == Oscl_File::SEEKSET) newpos = offset; - else if (origin == Oscl_File::SEEKEND) newpos = memlen + offset; + else if (origin == Oscl_File::SEEKEND) newpos = iSharedFileSize + offset; if (newpos < 0) return EINVAL; - if (newpos > memlen) // is this valid? - newpos = memlen; - mempos = newpos; + if (newpos > iSharedFileSize) // is this valid? + newpos = iSharedFileSize; + iSharedFilePosition = newpos; return 0; } #endif @@ -509,7 +391,7 @@ int32 OsclNativeFile::Seek(int32 offset, Oscl_File::seek_type origin) { int32 seekmode = SEEK_CUR; - if (origin == Oscl_File::SEEKCUR) seekmode = SEEK_CUR; + if (origin == Oscl_File::SEEKCUR) seekmode = SEEK_CUR; else if (origin == Oscl_File::SEEKSET) seekmode = SEEK_SET; else if (origin == Oscl_File::SEEKEND) seekmode = SEEK_END; @@ -528,9 +410,9 @@ int32 OsclNativeFile::SetSize(uint32 size) int32 OsclNativeFile::Tell() { -#ifdef ENABLE_MEMORY_PLAYBACK - if (membase) - return mempos; +#ifdef ENABLE_SHAREDFD_PLAYBACK + if (iSharedFd >= 0) + return iSharedFilePosition; #endif if (iFile) return ftell(iFile); @@ -541,11 +423,6 @@ int32 OsclNativeFile::Tell() int32 OsclNativeFile::Flush() { - -#ifdef ENABLE_MEMORY_PLAYBACK - if (membase) - return 0; -#endif if (iFile) return fflush(iFile); return EOF; @@ -556,9 +433,9 @@ int32 OsclNativeFile::Flush() int32 OsclNativeFile::EndOfFile() { -#ifdef ENABLE_MEMORY_PLAYBACK - if (membase) - return mempos >= memlen; +#ifdef ENABLE_SHAREDFD_PLAYBACK + if (iSharedFd >= 0) + return iSharedFilePosition >= iSharedFileSize; #endif if (iFile) return feof(iFile); @@ -568,10 +445,6 @@ int32 OsclNativeFile::EndOfFile() int32 OsclNativeFile::GetError() { -#ifdef ENABLE_MEMORY_PLAYBACK - if (membase) - return 0; -#endif if (iFile) return ferror(iFile); return 0; diff --git a/oscl/oscl/osclio/src/oscl_file_native.h b/oscl/oscl/osclio/src/oscl_file_native.h index b1ca76391..94d4a290c 100644 --- a/oscl/oscl/osclio/src/oscl_file_native.h +++ b/oscl/oscl/osclio/src/oscl_file_native.h @@ -56,10 +56,6 @@ #include "oscl_file_types.h" #endif -#ifdef ENABLE_MEMORY_PLAYBACK -#include <media/MediaPlayerInterface.h> -#endif - /** * OsclNativeFileIO defines the native file operations that must be implemented * by every Oscl platform. @@ -131,18 +127,13 @@ class OsclNativeFile : public HeapBase //native file object. FILE* iFile; -#ifdef ENABLE_MEMORY_PLAYBACK - static int sigbushandlerfunc(siginfo_t *, struct mediasigbushandler *); - // memory block - void* membase; - long long memoffset; - long long memlen; - int mempos; - struct mediasigbushandler sigbushandler; - int memcpyfailed; - static struct mediasigbushandler *getspecificforfaultaddr(char *faultaddr); -#endif +#ifdef ENABLE_SHAREDFD_PLAYBACK + int iSharedFd; + long long iSharedFileOffset; + long long iSharedFileSize; + long long iSharedFilePosition; +#endif }; #endif // OSCL_FILE_NATIVE_H_INCLUDED |