From 152b03e88d08dc50e3c18f9c2de1b4355397a159 Mon Sep 17 00:00:00 2001 From: Austin Yuan Date: Thu, 1 Apr 2010 14:43:58 +0800 Subject: [PATCH] Added MIO example based on vaPutSurface Signed-off-by: Austin Yuan --- va/android/android_surface_output.cpp | 1091 +++++++++++++++++++++++++++++++++ va/android/android_surface_output.h | 336 ++++++++++ 2 files changed, 1427 insertions(+) create mode 100644 va/android/android_surface_output.cpp create mode 100644 va/android/android_surface_output.h diff --git a/va/android/android_surface_output.cpp b/va/android/android_surface_output.cpp new file mode 100644 index 0000000..776d49d --- /dev/null +++ b/va/android/android_surface_output.cpp @@ -0,0 +1,1091 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2008 PacketVideo + * + * 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. + * ------------------------------------------------------------------- + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "VideoMIO" +#include +#include + +#include "android_surface_output.h" +#include + +#include "pvlogger.h" +#include "pv_mime_string_utils.h" +#include "oscl_snprintf.h" + +#include "oscl_dll.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +// Define entry point for this DLL +OSCL_DLL_ENTRY_POINT_DEFAULT() + +//The factory functions. +#include "oscl_mem.h" + +using namespace android; + +OSCL_EXPORT_REF AndroidSurfaceOutput::AndroidSurfaceOutput() : + OsclTimerObject(OsclActiveObject::EPriorityNominal, "androidsurfaceoutput") +{ + initData(); + + iColorConverter = NULL; + mInitialized = false; + mPvPlayer = NULL; + mEmulation = false; + iEosReceived = false; + mNumberOfFramesToHold = 2; +} + +status_t AndroidSurfaceOutput::set(PVPlayer* pvPlayer, const sp& surface, bool emulation) +{ + mPvPlayer = pvPlayer; + mEmulation = emulation; + setVideoSurface(surface); + return NO_ERROR; +} + +status_t AndroidSurfaceOutput::setVideoSurface(const sp& surface) +{ + LOGV("setVideoSurface(%p)", surface.get()); + // unregister buffers for the old surface + if (mSurface != NULL) { + LOGV("unregisterBuffers from old surface"); + mSurface->unregisterBuffers(); + } + mSurface = surface; + // register buffers for the new surface + if ((mSurface != NULL) && (mBufferHeap.heap != NULL)) { + LOGV("registerBuffers from old surface"); + mSurface->registerBuffers(mBufferHeap); + } + return NO_ERROR; +} + +void AndroidSurfaceOutput::initData() +{ + iVideoHeight = iVideoWidth = iVideoDisplayHeight = iVideoDisplayWidth = 0; + iVideoFormat=PVMF_MIME_FORMAT_UNKNOWN; + resetVideoParameterFlags(); + + iCommandCounter=0; + iLogger=NULL; + iCommandResponseQueue.reserve(5); + iWriteResponseQueue.reserve(5); + iObserver=NULL; + iLogger=NULL; + iPeer=NULL; + iState=STATE_IDLE; + iIsMIOConfigured = false; +} + +void AndroidSurfaceOutput::ResetData() + //reset all data from this session. +{ + Cleanup(); + + //reset all the received media parameters. + iVideoFormatString=""; + iVideoFormat=PVMF_MIME_FORMAT_UNKNOWN; + resetVideoParameterFlags(); + iIsMIOConfigured = false; +} + +void AndroidSurfaceOutput::resetVideoParameterFlags() +{ + iVideoParameterFlags = VIDEO_PARAMETERS_INVALID; +} + +bool AndroidSurfaceOutput::checkVideoParameterFlags() +{ + return (iVideoParameterFlags & VIDEO_PARAMETERS_MASK) == VIDEO_PARAMETERS_VALID; +} + +/* + * process the write response queue by sending writeComplete to the peer + * (nominally the decoder node). + * + * numFramesToHold is the number of frames to be held in the MIO. During + * playback, we hold the last frame which is used by SurfaceFlinger + * to composite the final output. + */ +void AndroidSurfaceOutput::processWriteResponseQueue(int numFramesToHold) +{ + LOGV("processWriteResponseQueue: queued = %d, numFramesToHold = %d", + iWriteResponseQueue.size(), numFramesToHold); + while (iWriteResponseQueue.size() > numFramesToHold) { + if (iPeer) { + iPeer->writeComplete(iWriteResponseQueue[0].iStatus, + iWriteResponseQueue[0].iCmdId, + (OsclAny*)iWriteResponseQueue[0].iContext); + } + iWriteResponseQueue.erase(&iWriteResponseQueue[0]); + } +} + +void AndroidSurfaceOutput::Cleanup() +//cleanup all allocated memory and release resources. +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Cleanup() In")); + while (!iCommandResponseQueue.empty()) + { + if (iObserver) + iObserver->RequestCompleted(PVMFCmdResp(iCommandResponseQueue[0].iCmdId, iCommandResponseQueue[0].iContext, iCommandResponseQueue[0].iStatus)); + iCommandResponseQueue.erase(&iCommandResponseQueue[0]); + } + + processWriteResponseQueue(0); + + // We'll close frame buf and delete here for now. + closeFrameBuf(); + + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Cleanup() Out")); + } + +OSCL_EXPORT_REF AndroidSurfaceOutput::~AndroidSurfaceOutput() +{ + Cleanup(); +} + + +PVMFStatus AndroidSurfaceOutput::connect(PvmiMIOSession& aSession, PvmiMIOObserver* aObserver) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::connect() called")); + // Each Session could have its own set of Configuration parameters + //in an array of structures and the session ID could be an index to that array. + + //currently supports only one session + if (iObserver) + return PVMFFailure; + + iObserver=aObserver; + return PVMFSuccess; +} + + +PVMFStatus AndroidSurfaceOutput::disconnect(PvmiMIOSession aSession) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::disconnect() called")); + //currently supports only one session + iObserver=NULL; + return PVMFSuccess; +} + + +PvmiMediaTransfer* AndroidSurfaceOutput::createMediaTransfer(PvmiMIOSession& aSession, + PvmiKvp* read_formats, int32 read_flags, + PvmiKvp* write_formats, int32 write_flags) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::createMediaTransfer() called")); + return (PvmiMediaTransfer*)this; +} + +void AndroidSurfaceOutput::QueueCommandResponse(CommandResponse& aResp) +{ + //queue a command response and schedule processing. + + iCommandResponseQueue.push_back(aResp); + + //cancel any timer delay so the command response will happen ASAP. + if (IsBusy()) + Cancel(); + + RunIfNotReady(); +} + +PVMFCommandId AndroidSurfaceOutput::QueryUUID(const PvmfMimeString& aMimeType, + Oscl_Vector& aUuids, + bool aExactUuidsOnly, const OsclAny* aContext) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::QueryUUID() called")); + + OSCL_UNUSED_ARG(aMimeType); + OSCL_UNUSED_ARG(aExactUuidsOnly); + + PVMFCommandId cmdid=iCommandCounter++; + + PVMFStatus status=PVMFFailure; + int32 err ; + OSCL_TRY(err, aUuids.push_back(PVMI_CAPABILITY_AND_CONFIG_PVUUID);); + if (err==OsclErrNone) + status= PVMFSuccess; + + CommandResponse resp(status,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + + +PVMFCommandId AndroidSurfaceOutput::QueryInterface(const PVUuid& aUuid, PVInterface*& aInterfacePtr, const OsclAny* aContext) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::QueryInterface() called")); + + PVMFCommandId cmdid=iCommandCounter++; + + PVMFStatus status=PVMFFailure; + if(aUuid == PVMI_CAPABILITY_AND_CONFIG_PVUUID) + { + PvmiCapabilityAndConfig* myInterface = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*,this); + aInterfacePtr = OSCL_STATIC_CAST(PVInterface*, myInterface); + status= PVMFSuccess; + } + else + { + status=PVMFFailure; + } + + CommandResponse resp(status,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + + +void AndroidSurfaceOutput::deleteMediaTransfer(PvmiMIOSession& aSession, PvmiMediaTransfer* media_transfer) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::deleteMediaTransfer() called")); + // This class is implementing the media transfer, so no cleanup is needed +} + + +PVMFCommandId AndroidSurfaceOutput:: Init(const OsclAny* aContext) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Init() called")); + + PVMFCommandId cmdid=iCommandCounter++; + + PVMFStatus status=PVMFFailure; + + switch(iState) + { + case STATE_LOGGED_ON: + status=PVMFSuccess; + iState=STATE_INITIALIZED; + break; + + default: + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Invalid State")); + status=PVMFErrInvalidState; + break; + } + + CommandResponse resp(status,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + +PVMFCommandId AndroidSurfaceOutput::Reset(const OsclAny* aContext) +{ + ResetData(); + PVMFCommandId cmdid=iCommandCounter++; + CommandResponse resp(PVMFSuccess,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + + +PVMFCommandId AndroidSurfaceOutput::Start(const OsclAny* aContext) +{ + iEosReceived = false; + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Start() called")); + + PVMFCommandId cmdid=iCommandCounter++; + + PVMFStatus status=PVMFFailure; + + switch(iState) + { + case STATE_INITIALIZED: + case STATE_PAUSED: + + iState=STATE_STARTED; + processWriteResponseQueue(0); + status=PVMFSuccess; + break; + + default: + status=PVMFErrInvalidState; + break; + } + + CommandResponse resp(status,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + +// post the last video frame to refresh screen after pause +void AndroidSurfaceOutput::postLastFrame() +{ + // ignore if no surface or heap + if ((mSurface == NULL) || (mBufferHeap.heap == NULL)) return; + mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]); +} + +PVMFCommandId AndroidSurfaceOutput::Pause(const OsclAny* aContext) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Pause() called")); + + PVMFCommandId cmdid=iCommandCounter++; + + PVMFStatus status=PVMFFailure; + + switch(iState) + { + case STATE_STARTED: + + iState=STATE_PAUSED; + status=PVMFSuccess; + + // post last buffer to prevent stale data + // if not configured, PVMFMIOConfigurationComplete is not sent + // there should not be any media data. + if(iIsMIOConfigured) { + postLastFrame(); + } + break; + + default: + status=PVMFErrInvalidState; + break; + } + + CommandResponse resp(status,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + + +PVMFCommandId AndroidSurfaceOutput::Flush(const OsclAny* aContext) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Flush() called")); + + PVMFCommandId cmdid=iCommandCounter++; + + PVMFStatus status=PVMFFailure; + + switch(iState) + { + case STATE_STARTED: + + iState=STATE_INITIALIZED; + status=PVMFSuccess; + break; + + default: + status=PVMFErrInvalidState; + break; + } + + CommandResponse resp(status,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + +PVMFCommandId AndroidSurfaceOutput::DiscardData(const OsclAny* aContext) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::DiscardData() called")); + + PVMFCommandId cmdid=iCommandCounter++; + + //this component doesn't buffer data, so there's nothing + //needed here. + + PVMFStatus status=PVMFSuccess; + processWriteResponseQueue(0); + + CommandResponse resp(status,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + +PVMFCommandId AndroidSurfaceOutput::DiscardData(PVMFTimestamp aTimestamp, const OsclAny* aContext) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::DiscardData() called")); + + PVMFCommandId cmdid=iCommandCounter++; + + aTimestamp = 0; + + //this component doesn't buffer data, so there's nothing + //needed here. + + PVMFStatus status=PVMFSuccess; + processWriteResponseQueue(0); + + CommandResponse resp(status,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + +PVMFCommandId AndroidSurfaceOutput::Stop(const OsclAny* aContext) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::Stop() called")); + + PVMFCommandId cmdid=iCommandCounter++; + + PVMFStatus status=PVMFFailure; + + switch(iState) + { + case STATE_STARTED: + case STATE_PAUSED: + +#ifdef PERFORMANCE_MEASUREMENTS_ENABLED + // FIXME: This should be moved to OMAP library + PVOmapVideoProfile.MarkEndTime(); + PVOmapVideoProfile.PrintStats(); + PVOmapVideoProfile.Reset(); +#endif + + iState=STATE_INITIALIZED; + status=PVMFSuccess; + break; + + default: + status=PVMFErrInvalidState; + break; + } + + CommandResponse resp(status,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + +PVMFCommandId AndroidSurfaceOutput::CancelAllCommands(const OsclAny* aContext) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::CancelAllCommands() called")); + + PVMFCommandId cmdid=iCommandCounter++; + + //commands are executed immediately upon being received, so + //it isn't really possible to cancel them. + + PVMFStatus status=PVMFSuccess; + + CommandResponse resp(status,cmdid,aContext); + QueueCommandResponse(resp); + return cmdid; +} + +PVMFCommandId AndroidSurfaceOutput::CancelCommand(PVMFCommandId aCmdId, const OsclAny* aContext) +{ + PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidSurfaceOutput::CancelCommand() called")); + + PVMFCommandId cmdid=iCommandCounter++; + + //commands are executed immediately upon being received, so + //it isn't really possible to cancel them. + + //see if the response is still queued. + PVMFStatus status=PVMFFailure; + for (uint32 i=0;iwriteComplete(iWriteResponseQueue[i].iStatus,iWriteResponseQueue[i].iCmdId,(OsclAny*)iWriteResponseQueue[i].iContext); + iWriteResponseQueue.erase(&iWriteResponseQueue[i]); + } +} + +void AndroidSurfaceOutput::setObserver (PvmiConfigAndCapabilityCmdObserver* aObserver) +{ + OSCL_UNUSED_ARG(aObserver); + //not needed since this component only supports synchronous capability & config + //APIs. +} + +PVMFStatus AndroidSurfaceOutput::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, + PvmiKvp*& aParameters, int& num_parameter_elements, + PvmiCapabilityContext aContext) +{ + OSCL_UNUSED_ARG(aSession); + OSCL_UNUSED_ARG(aContext); + aParameters=NULL; + + // This is a query for the list of supported formats. + if(pv_mime_strcmp(aIdentifier, INPUT_FORMATS_CAP_QUERY) == 0) + { + aParameters=(PvmiKvp*)oscl_malloc(sizeof(PvmiKvp)); + if (aParameters == NULL) return PVMFErrNoMemory; + aParameters[num_parameter_elements++].value.pChar_value=(char*) PVMF_MIME_YUV420; + + return PVMFSuccess; + } + + //unrecognized key. + return PVMFFailure; +} + +PVMFStatus AndroidSurfaceOutput::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements) +{ + //release parameters that were allocated by this component. + if (aParameters) + { + oscl_free(aParameters); + return PVMFSuccess; + } + return PVMFFailure; +} + +void AndroidSurfaceOutput ::createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext) +{ + OsclError::Leave(OsclErrNotSupported); +} + +void AndroidSurfaceOutput::setContextParameters(PvmiMIOSession aSession, PvmiCapabilityContext& aContext, + PvmiKvp* aParameters, int num_parameter_elements) +{ + OsclError::Leave(OsclErrNotSupported); +} + +void AndroidSurfaceOutput::DeleteContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext) +{ + OsclError::Leave(OsclErrNotSupported); +} + + +void AndroidSurfaceOutput::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, + int num_elements, PvmiKvp * & aRet_kvp) +{ + OSCL_UNUSED_ARG(aSession); + + aRet_kvp = NULL; + + LOGV("setParametersSync"); + for (int32 i=0;iReportInfoEvent(PVMFMIOConfigurationComplete); + } + } +} + +PVMFCommandId AndroidSurfaceOutput::setParametersAsync(PvmiMIOSession aSession, PvmiKvp* aParameters, + int num_elements, PvmiKvp*& aRet_kvp, OsclAny* context) +{ + OsclError::Leave(OsclErrNotSupported); + return -1; +} + +uint32 AndroidSurfaceOutput::getCapabilityMetric (PvmiMIOSession aSession) +{ + return 0; +} + +PVMFStatus AndroidSurfaceOutput::verifyParametersSync (PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements) +{ + OSCL_UNUSED_ARG(aSession); + + // Go through each parameter + for (int32 i=0; iRequestCompleted(PVMFCmdResp(iCommandResponseQueue[0].iCmdId, iCommandResponseQueue[0].iContext, iCommandResponseQueue[0].iStatus)); + iCommandResponseQueue.erase(&iCommandResponseQueue[0]); + } + + //send async write completion + if (iEosReceived) { + LOGV("Flushing buffers after EOS"); + processWriteResponseQueue(0); + } else { + processWriteResponseQueue(1); + } +} + +// create a frame buffer for software codecs +OSCL_EXPORT_REF bool AndroidSurfaceOutput::initCheck() +{ + + // initialize only when we have all the required parameters + if (!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; + + // 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 + sp heap = new MemoryHeapBase(frameSize * kBufferCount); + if (heap->heapID() < 0) { + LOGE("Error creating frame buffer heap"); + return false; + } + + mBufferHeap = ISurface::BufferHeap(displayWidth, displayHeight, + frameWidth, frameHeight, PIXEL_FORMAT_RGB_565, heap); + mSurface->registerBuffers(mBufferHeap); + + // 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); + + 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) +{ + // post to SurfaceFlinger + if ((mSurface != NULL) && (mBufferHeap.heap != NULL)) { + if (++mFrameBufferIndex == kBufferCount) mFrameBufferIndex = 0; +#if 0 + { + uint32 *data_pointer = reinterpret_cast(aData); + LOGE("the surfaceid is %x, location %x..\n", *data_pointer, data_pointer); + LOGE("the vadisplay is %x, location %x \n", *(data_pointer + 1), data_pointer + 1); + } + iColorConverter->Convert(aData, static_cast(mBufferHeap.heap->base()) + mFrameBuffers[mFrameBufferIndex]); + mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]); +#endif + uint32 *data_pointer = reinterpret_cast(aData); +// VASurfaceID surface_id = +// reinterpret_cast(*(data_pointer + 1)); + VASurfaceID surface_id = *(data_pointer); + VADisplay va_display = reinterpret_cast(*(data_pointer + 1)); + int data_len; + + LOGE("the surfaceid is %x\n", surface_id); + LOGE("the vadisplay is %x\n", va_display); +#if 0 + vaPutSurface(va_display, surface_id, 0, + 0, 0, iVideoWidth, iVideoHeight, + 0, 0, iVideoDisplayWidth, iVideoDisplayHeight, + NULL, 0, 0); +#else + vaPutSurfaceBuf(va_display, surface_id, 0, + static_cast(mBufferHeap.heap->base()) + mFrameBuffers[mFrameBufferIndex], + &data_len, 0, 0, iVideoWidth, iVideoHeight, + 0, 0, iVideoDisplayWidth, iVideoDisplayHeight, + NULL, 0, 0); + mSurface->postBuffer(mFrameBuffers[mFrameBufferIndex]); +#endif + } + return PVMFSuccess; +} + +OSCL_EXPORT_REF void AndroidSurfaceOutput::closeFrameBuf() +{ + LOGV("closeFrameBuf"); + if (!mInitialized) return; + + mInitialized = false; + if (mSurface.get()) { + LOGV("unregisterBuffers"); + mSurface->unregisterBuffers(); + } + + // free frame buffers + LOGV("free frame buffers"); + for (int i = 0; i < kBufferCount; i++) { + mFrameBuffers[i] = 0; + } + + // free heaps + LOGV("free frame heap"); + mBufferHeap.heap.clear(); + + // free color converter + if (iColorConverter != 0) + { + LOGV("free color converter"); + delete iColorConverter; + iColorConverter = 0; + } +} + +OSCL_EXPORT_REF bool AndroidSurfaceOutput::GetVideoSize(int *w, int *h) { + + *w = iVideoDisplayWidth; + *h = iVideoDisplayHeight; + return iVideoDisplayWidth != 0 && iVideoDisplayHeight != 0; +} diff --git a/va/android/android_surface_output.h b/va/android/android_surface_output.h new file mode 100644 index 0000000..095c61e --- /dev/null +++ b/va/android/android_surface_output.h @@ -0,0 +1,336 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2008 PacketVideo + * + * 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_H_INCLUDED +#define ANDROID_SURFACE_OUTPUT_H_INCLUDED + +#include "pvmi_mio_control.h" +#include "pvmi_media_transfer.h" +#include "oscl_scheduler_ao.h" +#include "pvmi_media_io_observer.h" +#include "oscl_file_io.h" +#include "pvmi_config_and_capability.h" +#include "oscl_string_containers.h" +#include "pvmi_media_io_clock_extension.h" + +#ifdef PERFORMANCE_MEASUREMENTS_ENABLED +#include "pvprofile.h" +#endif + +// FIXME: Move to OMAP library +// Linux and Kernel Includes for Frame Buffer +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include + +// SurfaceFlinger +#include + +// interprocess shared memory support +#include +#include + +// color converter +#include "cczoomrotation16.h" + +// define bits, mask and validity check for video parameters +#define VIDEO_PARAMETERS_INVALID 0 +#define VIDEO_SUBFORMAT_VALID (1 << 0) +#define DISPLAY_HEIGHT_VALID (1 << 1) +#define DISPLAY_WIDTH_VALID (1 << 2) +#define VIDEO_HEIGHT_VALID (1 << 3) +#define VIDEO_WIDTH_VALID (1 << 4) +#define VIDEO_PARAMETERS_MASK (VIDEO_SUBFORMAT_VALID | DISPLAY_HEIGHT_VALID | \ + DISPLAY_WIDTH_VALID | VIDEO_HEIGHT_VALID | VIDEO_WIDTH_VALID) +#define VIDEO_PARAMETERS_VALID (VIDEO_SUBFORMAT_VALID | DISPLAY_HEIGHT_VALID | \ + DISPLAY_WIDTH_VALID | VIDEO_HEIGHT_VALID | VIDEO_WIDTH_VALID) + +namespace android { + class PVPlayer; +} + +class PVLogger; +class PVMFMediaClock; +class AndroidSurfaceOutput; + +using namespace android; + +// 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 +{ +public: + AndroidSurfaceOutput(); + + // parameter initialization + virtual status_t set(android::PVPlayer* pvPlayer, const sp& surface, bool emulation); + virtual status_t setVideoSurface(const sp& surface); + + // For frame buffer + virtual bool initCheck(); + virtual PVMFStatus writeFrameBuf(uint8* aData, uint32 aDataLen, const PvmiMediaXferHeader& data_header_info); + virtual void postLastFrame(); + virtual void closeFrameBuf(); + + virtual ~AndroidSurfaceOutput(); + + bool GetVideoSize(int *w, int *h); + + // APIs from PvmiMIOControl + + PVMFStatus connect(PvmiMIOSession& aSession, PvmiMIOObserver* aObserver); + + PVMFStatus disconnect(PvmiMIOSession aSession); + + PVMFCommandId QueryUUID(const PvmfMimeString& aMimeType, Oscl_Vector& aUuids, + bool aExactUuidsOnly=false, const OsclAny* aContext=NULL); + + PVMFCommandId QueryInterface(const PVUuid& aUuid, PVInterface*& aInterfacePtr, const OsclAny* aContext=NULL); + + PvmiMediaTransfer* createMediaTransfer(PvmiMIOSession& aSession, PvmiKvp* read_formats=NULL, int32 read_flags=0, + PvmiKvp* write_formats=NULL, int32 write_flags=0); + + void deleteMediaTransfer(PvmiMIOSession& aSession, PvmiMediaTransfer* media_transfer); + + void processWriteResponseQueue(int numFramesToHold); + + PVMFCommandId Init(const OsclAny* aContext=NULL); + + PVMFCommandId Reset(const OsclAny* aContext=NULL); + + PVMFCommandId Start(const OsclAny* aContext=NULL); + + PVMFCommandId Pause(const OsclAny* aContext=NULL); + + PVMFCommandId Flush(const OsclAny* aContext=NULL); + + PVMFCommandId DiscardData(const OsclAny* aContext=NULL); + + PVMFCommandId DiscardData( PVMFTimestamp aTimestamp=0, const OsclAny* aContext=NULL); + + PVMFCommandId Stop(const OsclAny* aContext=NULL); + + PVMFCommandId CancelAllCommands(const OsclAny* aContext=NULL); + + PVMFCommandId CancelCommand(PVMFCommandId aCmdId, const OsclAny* aContext=NULL); + + void ThreadLogon(); + + void ThreadLogoff(); + + // APIs from PvmiMediaTransfer + + void setPeer(PvmiMediaTransfer* aPeer); + + 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); + + void writeComplete(PVMFStatus aStatus, + PVMFCommandId write_cmd_id, + OsclAny* aContext); + + 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); + + void statusUpdate(uint32 status_flags); + + void cancelCommand(PVMFCommandId command_id); + + void cancelAllCommands(); + + // Pure virtuals from PvmiCapabilityAndConfig + + void setObserver (PvmiConfigAndCapabilityCmdObserver* aObserver); + + PVMFStatus getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, + 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); + + void DeleteContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext); + + void setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, + int num_elements, PvmiKvp * & aRet_kvp); + + PVMFCommandId setParametersAsync(PvmiMIOSession aSession, PvmiKvp* aParameters, + int num_elements, PvmiKvp*& aRet_kvp, OsclAny* context=NULL); + + uint32 getCapabilityMetric (PvmiMIOSession aSession); + + PVMFStatus verifyParametersSync (PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements); + + +protected: + void initData(); + void resetVideoParameterFlags(); + bool checkVideoParameterFlags(); + + // From OsclTimerObject + void Run(); + + void Reschedule(); + + void Cleanup(); + void ResetData(); + + PvmiMediaTransfer* iPeer; + + // The PvmiMIOControl class observer. + PvmiMIOObserver* iObserver; + + //for generating command IDs + uint32 iCommandCounter; + + //State + enum PVRefFOState + { + STATE_IDLE, + STATE_LOGGED_ON, + STATE_INITIALIZED, + STATE_STARTED, + STATE_PAUSED + }; + PVRefFOState iState; + + //Control command handling. + class CommandResponse + { + public: + CommandResponse(PVMFStatus s,PVMFCommandId id,const OsclAny* ctx) + :iStatus(s),iCmdId(id),iContext(ctx) + {} + + PVMFStatus iStatus; + PVMFCommandId iCmdId; + const OsclAny* iContext; + }; + Oscl_Vector iCommandResponseQueue; + void QueueCommandResponse(CommandResponse&); + + //Write command handling + class WriteResponse + { + public: + WriteResponse(PVMFStatus s,PVMFCommandId id,const OsclAny* ctx,const PVMFTimestamp& ts) + :iStatus(s),iCmdId(id),iContext(ctx),iTimestamp(ts) + {} + + PVMFStatus iStatus; + PVMFCommandId iCmdId; + const OsclAny* iContext; + PVMFTimestamp iTimestamp; + }; + Oscl_Vector iWriteResponseQueue; + + // Output file parameters + OSCL_wHeapString iOutputFileName; + Oscl_FileServer iFs; + bool iFsConnected; + Oscl_File iOutputFile; + bool iFileOpened; + + bool iEosReceived; + + // Video parameters + uint32 iVideoParameterFlags; + OSCL_HeapString iVideoFormatString; + PVMFFormatType iVideoFormat; + int32 iVideoHeight; + int32 iVideoWidth; + int32 iVideoDisplayHeight; + int32 iVideoDisplayWidth; + + // hardware specific + PVMFFormatType iVideoSubFormat; + bool iVideoSubFormatValid; + + //For logging + PVLogger* iLogger; + + //For implementing the write flow control + bool CheckWriteBusy(uint32); + + unsigned long iFrameNumber; + + // software color conversion for software codecs + ColorConvertBase* iColorConverter; + + android::PVPlayer* mPvPlayer; + bool mInitialized; + bool mEmulation; + sp mSurface; + + // frame buffer support + static const int kBufferCount = 2; + int mFrameBufferIndex; + ISurface::BufferHeap mBufferHeap; + size_t mFrameBuffers[kBufferCount]; + + void convertFrame(void* src, void* dst, size_t len); + //This bool is set true when all necassary parameters have been received. + bool iIsMIOConfigured; + + /* + * The value of mNumberOfFramesToHold is hardware/platform specific. + * 1. On non-overlay based platforms, its value it set to 2 + * so as to avoid potential tearings oberved during video playback. + * 2. On overlay-based platforms, its value should be overwritten. + * We have observed video decoder starvation when a value other than 1. + * + * We set the default value to 2 in this class. Please change its value + * accordingly in the derived class. + */ + int mNumberOfFramesToHold; + +#ifdef PERFORMANCE_MEASUREMENTS_ENABLED + PVProfile PVOmapVideoProfile; +#endif + +}; + +#endif // ANDROID_SURFACE_OUTPUT_H_INCLUDED + -- 2.7.4