| /* ------------------------------------------------------------------ |
| * Copyright (C) 1998-2009 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. |
| * ------------------------------------------------------------------- |
| */ |
| /** |
| * |
| * @file pvmi_io_interface_node_inport.cpp |
| * @brief Input port for media io interface wrapper node |
| * |
| */ |
| |
| #include "pv_media_output_node_inport.h" |
| #include "pv_media_output_node.h" |
| #include "pvmf_common_audio_decnode.h" |
| #include "pvmf_video.h" |
| #include "pv_mime_string_utils.h" |
| #include "pvmf_media_cmd.h" |
| #include "pvmf_media_msg_format_ids.h" |
| #include "latmpayloadparser.h" |
| #include "media_clock_converter.h" |
| #include "time_comparison_utils.h" |
| |
| #define LOGDATAPATH(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLogger, PVLOGMSG_INFO, x); |
| |
| #define PVMF_MOPORT_LOGDATAPATH(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLogger, PVLOGMSG_INFO, x); |
| #define PVMF_MOPORT_LOGDATAPATH_IN(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLoggerIn, PVLOGMSG_INFO, x); |
| #define PVMF_MOPORT_LOGDATAPATH_OUT(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLoggerOut, PVLOGMSG_INFO, x); |
| #define PVMF_MOPORT_LOGREPOS(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iReposLogger, PVLOGMSG_INFO, x); |
| #define PVMF_MOPORT_LOGDEBUG(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, x); |
| #define PVMF_MOPORT_LOGERROR(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, x); |
| |
| |
| //for logging media data info |
| void PVMediaOutputNodePort::LogMediaDataInfo(const char* msg, PVMFSharedMediaDataPtr mediaData) |
| { |
| if (!mediaData.GetRep()) |
| { |
| OSCL_UNUSED_ARG(msg); |
| return; |
| } |
| LOGDATAPATH( |
| (0, "MOUT %s %s MediaData SeqNum %d, SId %d, TS %d" |
| , PortName() |
| , msg |
| , mediaData->getSeqNum() |
| , mediaData->getStreamID() |
| , mediaData->getTimestamp() |
| )); |
| } |
| |
| |
| //for logging media data info plus write ID and cleanup q depth |
| void PVMediaOutputNodePort::LogMediaDataInfo(const char* msg, PVMFSharedMediaDataPtr mediaData, int32 cmdid, int32 qdepth) |
| { |
| if (!mediaData.GetRep()) |
| { |
| OSCL_UNUSED_ARG(msg); |
| OSCL_UNUSED_ARG(cmdid); |
| OSCL_UNUSED_ARG(qdepth); |
| return; |
| } |
| LOGDATAPATH( |
| (0, "MOUT %s %s, Write Id %d, MediaData SeqNum %d, SId %d, TS %d, Cleanup Q-depth %d" |
| , PortName() |
| , msg |
| , cmdid |
| , mediaData->getSeqNum() |
| , mediaData->getStreamID() |
| , mediaData->getTimestamp() |
| , qdepth |
| )); |
| } |
| |
| |
| //for logging media xfer info |
| void PVMediaOutputNodePort::LogDatapath(const char*msg) |
| { |
| |
| if (!iDatapathLogger) |
| { |
| OSCL_UNUSED_ARG(msg); |
| return; //unexpected call. |
| } |
| LOGDATAPATH( |
| (0, "MOUT %s %s" |
| , PortName() |
| , msg |
| )); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMediaOutputNodePort::PVMediaOutputNodePort(PVMediaOutputNode* aNode) |
| : OsclTimerObject(OsclActiveObject::EPriorityNominal, "PVMediaOutputNodePort") |
| , PvmfPortBaseImpl(PVMF_MEDIAIO_NODE_INPUT_PORT_TAG |
| //this port handles its own port activity |
| , this |
| , 10, 10, 70 |
| //output queue isn't needed. |
| , 0, 0, 0, "MediaOut") |
| , iNode(aNode) |
| { |
| AddToScheduler(); |
| isUnCompressedMIO = false; |
| |
| iExtensionRefCount = 0; |
| iPortFormat = PVMF_MIME_FORMAT_UNKNOWN; |
| |
| iMediaTransfer = NULL; |
| iMioInfoErrorCmdId = 0; |
| iMediaType = PVMF_MEDIA_UNKNOWN; |
| iWriteState = EWriteOK; |
| iCleanupQueue.reserve(1); |
| iWriteAsyncContext = 0; |
| iWriteAsyncEOSContext = 0; |
| iWriteAsyncReConfigContext = 0; |
| iClock = NULL; |
| iClockNotificationsInf = NULL; |
| oClockCallBackPending = false; |
| iDelayEarlyFrameCallBkId = 0; |
| iClockRate = 1; |
| iEarlyMargin = 0; |
| iLateMargin = 0; |
| oActiveMediaOutputComp = true; // By default we treat the MIO's to be active. |
| |
| // MIO node waits for MIO component configuration to complete before sending data. Once configuration is |
| // complete, MIO node waits for clock to start if mio component is passive. For active MIO's, it does not |
| // wait for clock to start before sending data. It sends data as soon as MIO component configuration is |
| // complete. |
| |
| oProcessIncomingMessage = false; |
| |
| |
| oMIOComponentConfigured = false; |
| |
| iConsecutiveFramesDropped = 0; |
| iLateFrameEventSent = false; |
| |
| iFragIndex = 0; |
| |
| iSkipTimestamp = 0; |
| iRecentStreamID = 0; |
| iSendStartOfDataEvent = false; |
| |
| iFrameStepMode = false; |
| iClockFrameCount = 0; |
| iSyncFrameCount = 0; |
| iFramesDropped = 0; |
| iTotalFrames = 0; |
| |
| iEosStreamIDVec.reserve(2); |
| |
| iOsclErrorTrapImp = OsclErrorTrap::GetErrorTrapImp(); |
| iLogger = PVLogger::GetLoggerObject("PVMediaOutputNodePort"); |
| iDatapathLogger = PVLogger::GetLoggerObject("datapath.sinknode"); |
| iDatapathLoggerIn = PVLogger::GetLoggerObject("datapath.sinknode.in"); |
| iDatapathLoggerOut = PVLogger::GetLoggerObject("datapath.sinknode.out"); |
| iReposLogger = PVLogger::GetLoggerObject("pvplayerrepos.mionode"); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::ClearCleanupQueue() |
| //clear the media transfer cleanup queue and log all messages. |
| { |
| while (!iCleanupQueue.empty()) |
| { |
| PVMFSharedMediaDataPtr mediaData = iCleanupQueue.begin()->iData; |
| PVMFCommandId cmdId = iCleanupQueue.begin()->iCmdId; |
| iCleanupQueue.erase(iCleanupQueue.begin()); |
| LogMediaDataInfo("Cleared" |
| , mediaData |
| , cmdId |
| , iCleanupQueue.size() |
| ); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMediaOutputNodePort::~PVMediaOutputNodePort() |
| { |
| Disconnect(); |
| PvmfPortBaseImpl::ClearMsgQueues(); |
| //cancel any pending write operations |
| if (!iCleanupQueue.empty()) |
| { |
| int32 err; |
| OSCL_TRY(err, iMediaTransfer->cancelAllCommands();); |
| ClearCleanupQueue(); |
| } |
| if (iClock != NULL) |
| { |
| if (iClockNotificationsInf != NULL) |
| { |
| iClockNotificationsInf->RemoveClockObserver(*this); |
| iClockNotificationsInf->RemoveClockStateObserver(*this); |
| iClock->DestroyMediaClockNotificationsInterface(iClockNotificationsInf); |
| iClockNotificationsInf = NULL; |
| } |
| } |
| // we need to clear the activity handler, since otherwise the PvmfPortBaseImpl destructor |
| // ends up calling back onto our HandlePortActivity method, which no longer exists because |
| // this objects's destructor has already been called. |
| SetActivityHandler(NULL); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMediaOutputNodePort::Configure(OSCL_String& fmtstr) |
| { |
| //This is called when the format is being set. |
| if (iConnectedPort) |
| { |
| // Must disconnect before changing port properties, so return error |
| return PVMFFailure; |
| } |
| PVMFFormatType fmt = fmtstr.get_cstr(); |
| |
| if (IsFormatSupported(fmt)) |
| { |
| iPortFormat = fmt; |
| iSinkFormat = fmt; |
| iSinkFormatString = fmtstr; |
| FormatUpdated(); |
| return PVMFSuccess; |
| } |
| else |
| { |
| iPortFormat = PVMF_MIME_FORMAT_UNKNOWN; |
| iSinkFormat = PVMF_MIME_FORMAT_UNKNOWN; |
| iSinkFormatString = fmtstr; |
| return PVMFFailure; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // override the PvmfPortBaseImpl routine |
| OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::Connect(PVMFPortInterface* aPort) |
| { |
| PVMFStatus status = PvmfPortBaseImpl::Connect(aPort); |
| if (status != PVMFSuccess) |
| { |
| return status; |
| } |
| |
| if (iMediaTransfer == NULL) |
| { |
| iMediaTransfer = iNode->iMIOControl->createMediaTransfer(iNode->iMIOSession); |
| if (iMediaTransfer) |
| { |
| iMediaTransfer->setPeer(this); |
| } |
| else |
| { |
| return PVMFFailure; |
| } |
| } |
| |
| iSkipTimestamp = 0; |
| |
| OsclAny* temp = NULL; |
| aPort->QueryInterface(PVMI_CAPABILITY_AND_CONFIG_PVUUID, temp); |
| PvmiCapabilityAndConfig *config = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*, temp); |
| |
| if (config != NULL) |
| { |
| PvmiKvp* configKvp = NULL; |
| PvmiKvp* aRet_kvp = NULL; |
| int num_elements = 0; |
| PVMFStatus status = config->getParametersSync(NULL, NULL, configKvp, num_elements, NULL); |
| |
| if (status == PVMFSuccess) |
| { |
| iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, |
| configKvp, |
| num_elements, |
| aRet_kvp); |
| config->releaseParameters(NULL, configKvp, num_elements); |
| } |
| } |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // override the PvmfPortBaseImpl routine |
| OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::PeerConnect(PVMFPortInterface* aPort) |
| { |
| PVMFStatus status = PvmfPortBaseImpl::PeerConnect(aPort); |
| if (status != PVMFSuccess) |
| { |
| return status; |
| } |
| |
| if (iMediaTransfer == NULL) |
| { |
| iMediaTransfer = iNode->iMIOControl->createMediaTransfer(iNode->iMIOSession); |
| if (iMediaTransfer) |
| { |
| iMediaTransfer->setPeer(this); |
| } |
| else |
| { |
| return PVMFFailure; |
| } |
| } |
| return PVMFSuccess; |
| } |
| |
| void PVMediaOutputNodePort::CleanupMediaTransfer() |
| { |
| int32 err; |
| //Just in case the media transfer did not report all the async write |
| //completes, cancel any pending write operations and clear up the cleanup queue |
| if (!iCleanupQueue.empty()) |
| { |
| err = 0; |
| OSCL_TRY(err, iMediaTransfer->cancelAllCommands();); |
| ClearCleanupQueue(); |
| } |
| if (iNode && iNode->iMIOControl && iMediaTransfer) |
| { |
| iMediaTransfer->setPeer(NULL); |
| err = 0; |
| OSCL_TRY(err, iNode->iMIOControl->deleteMediaTransfer(iNode->iMIOSession, iMediaTransfer)); |
| OSCL_FIRST_CATCH_ANY(err, |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMediaOutputNodePort::CleanupMediaTransfer Caught a leave when calling deleteMediaTransfer!")); |
| ); |
| iMediaTransfer = NULL; |
| } |
| if (iClock != NULL) |
| { |
| if (iClockNotificationsInf != NULL) |
| { |
| iClockNotificationsInf->RemoveClockObserver(*this); |
| iClockNotificationsInf->RemoveClockStateObserver(*this); |
| iClock->DestroyMediaClockNotificationsInterface(iClockNotificationsInf); |
| } |
| iClockNotificationsInf = NULL; |
| iClock = NULL; |
| } |
| if (iCurrentMediaMsg.GetRep() != NULL) |
| { |
| iCurrentMediaMsg.Unbind(); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // override the PvmfPortBaseImpl routine |
| OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::Disconnect() |
| { |
| CleanupMediaTransfer(); |
| return PvmfPortBaseImpl::Disconnect(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // override the PvmfPortBaseImpl routine |
| OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::PeerDisconnect() |
| { |
| PVMFStatus status = PvmfPortBaseImpl::PeerDisconnect(); |
| if (status != PVMFSuccess) |
| { |
| return status; |
| } |
| CleanupMediaTransfer(); |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // override the PvmfPortBaseImpl routine |
| OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::ClearMsgQueues() |
| { |
| if (iCurrentMediaMsg.GetRep() != NULL) |
| { |
| iCurrentMediaMsg.Unbind(); |
| } |
| |
| PvmfPortBaseImpl::ClearMsgQueues(); |
| //cancel any pending write operations |
| if (!iCleanupQueue.empty()) |
| { |
| int32 err; |
| OSCL_TRY(err, iMediaTransfer->cancelAllCommands();); |
| ClearCleanupQueue(); |
| } |
| |
| //may need to generate port flow control now |
| PvmfPortBaseImpl::EvaluateIncomingBusy(); |
| |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::addRef() |
| // for PVInterface |
| { |
| ++iExtensionRefCount; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::removeRef() |
| // for PVInterface |
| { |
| if (iExtensionRefCount > 0) |
| { |
| --iExtensionRefCount; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| bool PVMediaOutputNodePort::queryInterface(const PVUuid& uuid, PVInterface*& iface) |
| // for PVInterface |
| { |
| if (uuid == PvmfNodesSyncControlUuid) |
| { |
| PvmfNodesSyncControlInterface* myInterface = OSCL_STATIC_CAST(PvmfNodesSyncControlInterface*, this); |
| iface = OSCL_STATIC_CAST(PVInterface*, myInterface); |
| addRef(); |
| } |
| else |
| { |
| iface = NULL; |
| return false; |
| } |
| return true; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::NodeStarted() |
| { |
| //it is possible that we attempted to call writeasync |
| //before media output comp start (can happen for active components) |
| //in those cases the comp can either accept or reject data |
| //if it rejected it by doing a leave, attempt to send data again |
| //now that we are done with start. Do not do the same for passive |
| //comps since this method is called during a pause-resume, and we |
| //do not want to attempt sending media data to passive comps till |
| //clock has been started |
| if ((iWriteState == EWriteWait) && |
| (true == oActiveMediaOutputComp)) |
| { |
| iWriteState = EWriteOK; |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::NodeStarted - WriteAsync Enabled - Fmt=%s, iWriteState=%d", |
| iSinkFormatString.get_str(), |
| iWriteState)); |
| oProcessIncomingMessage = true; |
| |
| if (iCurrentMediaMsg.GetRep() != NULL) |
| { |
| //attempt to send data current media msg if any |
| SendData(); |
| } |
| } |
| |
| RunIfNotReady(); |
| } |
| |
| // Attempt to process incoming message only after the mio component is fully configured |
| // and the clock is set by the node. |
| void PVMediaOutputNodePort::ProcessIncomingMessageIfPossible() |
| { |
| if (oMIOComponentConfigured && iClock) |
| { |
| PVMF_MOPORT_LOGDATAPATH( |
| (0, "PVMediaOutputNodePort::ProcessIncomingMessageIfPossible: Fmt - Fmt=%s, MIOCompConfigured=%d, ActiveMIO=%d, ClockState=%d", |
| iSinkFormatString.get_str(), oMIOComponentConfigured, oActiveMediaOutputComp, iClock->GetState())); |
| |
| PVMF_MOPORT_LOGDEBUG( |
| (0, "PVMediaOutputNodePort::ProcessIncomingMessageIfPossible: Fmt - Fmt=%s, MIOCompConfigured=%d, ActiveMIO=%d, ClockState=%d", |
| iSinkFormatString.get_str(), oMIOComponentConfigured, oActiveMediaOutputComp, iClock->GetState())); |
| |
| if (true == oActiveMediaOutputComp) |
| { |
| oProcessIncomingMessage = true; |
| } |
| else |
| { |
| if (iClock->GetState() == PVMFMediaClock::RUNNING) |
| { |
| oProcessIncomingMessage = true; |
| } |
| } |
| RunIfNotReady(); |
| } |
| else |
| { |
| PVMF_MOPORT_LOGDEBUG( |
| (0, "PVMediaOutputNodePort::ProcessIncomingMessageIfPossible: Fmt - Fmt=%s, MIOCompConfigured=%d, iClock=0x%x", |
| iSinkFormatString.get_str(), oMIOComponentConfigured, iClock)); |
| } |
| } |
| |
| void PVMediaOutputNodePort::SetMIOComponentConfigStatus(bool aStatus) |
| { |
| oMIOComponentConfigured = aStatus; |
| |
| ProcessIncomingMessageIfPossible(); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| //for sync control interface |
| PVMFStatus PVMediaOutputNodePort::SetClock(PVMFMediaClock* aClock) |
| { |
| if (NULL == aClock) |
| { |
| return PVMFErrArgument; |
| } |
| iClock = aClock; |
| |
| ProcessIncomingMessageIfPossible(); |
| |
| iClock->ConstructMediaClockNotificationsInterface(iClockNotificationsInf, *this); |
| |
| if (NULL == iClockNotificationsInf) |
| { |
| return PVMFErrNoMemory; |
| } |
| |
| iClockNotificationsInf->SetClockObserver(*this); |
| iClockNotificationsInf->SetClockStateObserver(*this); |
| |
| return PVMFSuccess; |
| } |
| |
| void PVMediaOutputNodePort::EnableMediaSync() |
| { |
| //wait on play clock |
| oProcessIncomingMessage = false; |
| oActiveMediaOutputComp = false; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| //for sync control interface |
| PVMFStatus PVMediaOutputNodePort::ChangeClockRate(int32 aRate) |
| { |
| if (0 == aRate) |
| { |
| // A 0 value of clockrate is not handled |
| return PVMFFailure; |
| } |
| iClockRate = aRate; |
| |
| PVMFStatus status; |
| status = SetMIOParameterInt32((char*)MOUT_MEDIAXFER_OUTPUT_RATE, aRate); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, |
| "PVMediaOutputNodePort::ChangeClockRate rate %d", |
| aRate)); |
| |
| return status; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMediaOutputNodePort::SetMargins(int32 aEarlyMargin, int32 aLateMargin) |
| //for sync control interface |
| { |
| iEarlyMargin = aEarlyMargin; |
| iLateMargin = aLateMargin; |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::ClockStarted() |
| //for sync control interface |
| { |
| if (IsBusy()) |
| { |
| // Cancel any long waits due to data synchronization done |
| // before clock was set and started |
| Cancel(); |
| } |
| RunIfNotReady(); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::ClockStopped() |
| //for sync control interface |
| { |
| ;//ignore |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::setPeer(PvmiMediaTransfer *aPeer) |
| //for PvmiMediaTransfer |
| { |
| OSCL_UNUSED_ARG(aPeer); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::useMemoryAllocators(OsclMemAllocator* write_alloc) |
| //for PvmiMediaTransfer |
| { |
| OSCL_UNUSED_ARG(write_alloc); |
| OSCL_LEAVE(OsclErrNotSupported); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMediaOutputNodePort::writeAsync(uint8 format_type, int32 format_index, |
| uint8* data, uint32 data_len, |
| const PvmiMediaXferHeader& data_header_info, |
| OsclAny* context) |
| //for PvmiMediaTransfer |
| { |
| OSCL_UNUSED_ARG(data_header_info); |
| OSCL_UNUSED_ARG(context); |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, |
| (0, "PVMediaOutputNodePort::writeAsync: format_type=%d, format_index=%d, data=0x%x, data_len=%d", |
| format_type, format_index, data, data_len)); |
| |
| PVMFAsyncEvent* event = NULL; |
| switch (format_type) |
| { |
| case PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION: |
| switch (format_index) |
| { |
| case PVMI_MEDIAXFER_FMT_INDEX_INFO_EVENT: |
| OSCL_ASSERT(iNode); |
| OSCL_ASSERT(iMediaTransfer); |
| |
| if (!data) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMediaOutputNodePort::writeAsync: Error - data is NULL")); |
| OSCL_LEAVE(OsclErrArgument); |
| return -1; |
| } |
| |
| if (data_len != sizeof(PVMFAsyncEvent)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMediaOutputNodePort::writeAsync: Error - data length is not size of PVMFAsyncEvent")); |
| OSCL_LEAVE(OsclErrArgument); |
| return -1; |
| } |
| |
| event = OSCL_STATIC_CAST(PVMFAsyncEvent*, data); |
| iNode->ReportInfoEvent((*event)); |
| |
| // Not really processing this asynchronously. Just call writeComplete |
| // synchronously |
| iMediaTransfer->writeComplete(PVMFSuccess, iMioInfoErrorCmdId, context); |
| return iMioInfoErrorCmdId++; |
| |
| case PVMI_MEDIAXFER_FMT_INDEX_ERROR_EVENT: |
| OSCL_ASSERT(iNode); |
| OSCL_ASSERT(iMediaTransfer); |
| |
| if (!data) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMediaOutputNodePort::writeAsync: Error - data is NULL")); |
| OSCL_LEAVE(OsclErrArgument); |
| return -1; |
| } |
| |
| if (data_len != sizeof(PVMFAsyncEvent)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMediaOutputNodePort::writeAsync: Error - data length is not size of PVMFAsyncEvent")); |
| OSCL_LEAVE(OsclErrArgument); |
| return -1; |
| } |
| |
| event = OSCL_STATIC_CAST(PVMFAsyncEvent*, data); |
| iNode->ReportErrorEvent((*event)); |
| |
| // Not really processing this asynchronously. Just call writeComplete |
| // synchronously |
| iMediaTransfer->writeComplete(PVMFSuccess, iMioInfoErrorCmdId, context); |
| return iMioInfoErrorCmdId++; |
| |
| default: |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMediaOutputNodePort::writeAsync: Error - Unsupported format_index")); |
| OSCL_LEAVE(OsclErrNotSupported); |
| break; |
| } |
| |
| default: |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PVMediaOutputNodePort::writeAsync: Error - Unsupported format_type")); |
| OSCL_LEAVE(OsclErrNotSupported); |
| break; |
| } |
| |
| return -1; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::writeComplete(PVMFStatus status, PVMFCommandId aCmdId, OsclAny* aContext) |
| //for PvmiMediaTransfer |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, |
| (0, "PVMediaOutputNodePort::writeComplete status %d cmdId %d context 0x%x", status, aCmdId, aContext)); |
| |
| // Check if the writeComplete is in response to EOS message |
| if (&iWriteAsyncEOSContext == (uint32*)aContext) |
| { |
| if (iWriteState == EWriteBusy) |
| { |
| // Synchronous completion |
| // Let EndOfData info event be sent out in EndOfData() function |
| iWriteState = EWriteOK; |
| } |
| else |
| { |
| // Report End of Data to the user of media output node |
| // only if the EOS media transfer completes successfully and |
| // there is no pending MIO control request |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete For EOS - Fmt=%s", |
| iSinkFormatString.get_str())); |
| if (iEosStreamIDVec.size() != 0) |
| { |
| //iEosStreamIDVec is used as a FIFO to store the steamids of eos sent to mio comp. |
| //streamid is pushed in at front when call writeasync(eos) to mio comp. |
| //streamid is poped out from end when mio comp. calls writecomplete(eos), |
| //we report PVMFInfoEndOfData with the poped streamid. |
| //This logic depends on Mio comp. process data(at least eos msg) in a sequencial style. |
| uint32 EosStreamID = iEosStreamIDVec.back(); |
| |
| // Asynchronous completion |
| if (status == PVMFSuccess) |
| { |
| // Report EndofData to engine only if MIO comp sends success for End Of Stream. |
| // FOr other return codes just pop out the EOS from the vector. |
| iNode->ReportInfoEvent(PVMFInfoEndOfData, (OsclAny*)&EosStreamID); |
| } |
| else |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete EOS media transfer completed but PVMFInfoEndOfData not sent")); |
| } |
| |
| iEosStreamIDVec.pop_back(); |
| } |
| else |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::writeComplete - Invalid iEosStreamIDVec size=0")); |
| OSCL_ASSERT(false); |
| } |
| |
| } |
| } |
| // Check if the writeComplete is in response to Reconfig message |
| else if (&iWriteAsyncReConfigContext == (uint32*)aContext) |
| { |
| if (iWriteState == EWriteBusy) |
| { |
| // Synchronous completion |
| iWriteState = EWriteOK; |
| } |
| else |
| { |
| // Asynchronous completion |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete For RECONFIG - Fmt=%s", |
| iSinkFormatString.get_str())); |
| } |
| } |
| //detect cases where the current SendData call is completing synchronously. |
| else if (iWriteState == EWriteBusy) |
| { |
| //synchronous completion |
| iWriteState = EWriteOK; |
| } |
| else |
| { |
| //asynchronous completion. |
| //do any memory cleanup |
| bool oCmdIdFound = false; |
| uint32 i; |
| for (i = 0; i < iCleanupQueue.size(); i++) |
| { |
| if (iCleanupQueue[i].iCmdId == aCmdId) |
| { |
| PVMFSharedMediaDataPtr mediaData = iCleanupQueue[i].iData; |
| iCleanupQueue.erase(&iCleanupQueue[i]); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete - Fmt=%s, Seq=%d, TS=%d, FIdx=%d, ClnUpQSize=%d", |
| iSinkFormatString.get_str(), |
| mediaData->getSeqNum(), |
| mediaData->getTimestamp(), |
| iFragIndex, |
| iCleanupQueue.size())); |
| oCmdIdFound = true; |
| break; |
| } |
| } |
| if (oCmdIdFound == false) |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::writeComplete - CmdId Not Found - Fmt=%s, FIdx=%d, ClnUpQSize=%d", |
| iSinkFormatString.get_str(), |
| iFragIndex, |
| iCleanupQueue.size())); |
| } |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PVMediaOutputNodePort::readAsync(uint8* data, uint32 max_data_len, OsclAny* context, |
| int32* formats, uint16 num_formats) |
| //for PvmiMediaTransfer |
| { |
| OSCL_UNUSED_ARG(data); |
| OSCL_UNUSED_ARG(max_data_len); |
| OSCL_UNUSED_ARG(context); |
| OSCL_UNUSED_ARG(formats); |
| OSCL_UNUSED_ARG(num_formats); |
| OSCL_LEAVE(OsclErrNotSupported); |
| return -1; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::readComplete(PVMFStatus status, PVMFCommandId read_cmd_id, |
| int32 format_index, const PvmiMediaXferHeader& data_header_info, |
| OsclAny* context) |
| //for PvmiMediaTransfer |
| { |
| OSCL_UNUSED_ARG(status); |
| OSCL_UNUSED_ARG(read_cmd_id); |
| OSCL_UNUSED_ARG(format_index); |
| OSCL_UNUSED_ARG(data_header_info); |
| OSCL_UNUSED_ARG(context); |
| OSCL_LEAVE(OsclErrNotSupported); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::statusUpdate(uint32 status_flags) |
| //for PvmiMediaTransfer |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO, |
| (0, "PVMediaOutputNodePort::statusUpdate flags %d", status_flags)); |
| |
| if (status_flags & PVMI_MEDIAXFER_STATUS_WRITE) |
| { |
| //recover from a previous async write error. |
| if (iWriteState == EWriteWait) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::statusUpdate - WriteAsync Enabled - Fmt=%s, iWriteState=%d", |
| iSinkFormatString.get_str(), |
| iWriteState)); |
| iWriteState = EWriteOK; |
| |
| // Allow data to be processed if possible |
| ProcessIncomingMessageIfPossible(); |
| |
| if (oProcessIncomingMessage == true) |
| { |
| if (iCurrentMediaMsg.GetRep() != NULL) |
| { |
| //attempt to send data current media msg if any |
| SendData(); |
| } |
| //reschedule if there is more stuff waiting and |
| //if we can process more data |
| if (IncomingMsgQueueSize() > 0) |
| { |
| RunIfNotReady(); |
| } |
| } |
| } |
| } |
| else |
| { |
| //disable write |
| iWriteState = EWriteWait; |
| oProcessIncomingMessage = false; |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::statusUpdate - WriteAsync Disabled - Fmt=%s, iWriteState=%d", |
| iSinkFormatString.get_str(), |
| iWriteState)); |
| } |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::cancelCommand(PVMFCommandId command_id) |
| //for PvmiMediaTransfer |
| { |
| OSCL_UNUSED_ARG(command_id); |
| OSCL_LEAVE(OsclErrNotSupported); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::cancelAllCommands() |
| //for PvmiMediaTransfer |
| { |
| OSCL_LEAVE(OsclErrNotSupported); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| bool PVMediaOutputNodePort::IsFormatSupported(PVMFFormatType aFmt) |
| // for PvmiCapabilityAndConfigPortFormatImpl interface |
| { |
| //Verify if the format is supported by the media I/O component. |
| PvmiKvp kvpFormatType; |
| |
| OSCL_StackString<64> iKVPFormatType = _STRLIT_CHAR(PVMF_FORMAT_TYPE_VALUE_KEY); |
| |
| kvpFormatType.key = NULL; |
| kvpFormatType.key = iKVPFormatType.get_str(); |
| kvpFormatType.value.pChar_value = (char*)aFmt.getMIMEStrPtr(); |
| |
| PVMFStatus status = iNode->iMIOConfig->verifyParametersSync(NULL, &kvpFormatType, 1); |
| if (status != PVMFSuccess) |
| { |
| return false; |
| } |
| return true; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::FormatUpdated() |
| // for PvmiCapabilityAndConfigPortFormatImpl interface |
| { |
| //called when format was just set, either through capability and config, |
| //for by node during port request. |
| if (iSinkFormat.isAudio()) |
| { |
| //set port name for datapath logging. |
| SetName("MediaOutIn(Audio)"); |
| |
| //pass the selected format to the MIO component. |
| //ignore any failure since not all MIO may support the feature. |
| SetMIOParameterPchar((char*)MOUT_AUDIO_FORMAT_KEY, iSinkFormatString.get_str()); |
| |
| //save the media type. |
| if (iSinkFormat.isCompressed()) |
| { |
| iMediaType = PVMF_MEDIA_COMPRESSED_AUDIO; |
| } |
| else |
| { |
| iMediaType = PVMF_MEDIA_UNCOMPRESSED_AUDIO; |
| isUnCompressedMIO = true; |
| } |
| } |
| else if (iSinkFormat.isVideo()) |
| { |
| //set port name for datapath logging. |
| SetName("MediaOutIn(Video)"); |
| |
| //pass the selected format to the MIO component. |
| //ignore any failure since not all MIO may support the feature. |
| SetMIOParameterPchar((char*)MOUT_VIDEO_FORMAT_KEY, iSinkFormatString.get_str()); |
| |
| //save the media type. |
| if (iSinkFormat.isCompressed()) |
| { |
| iMediaType = PVMF_MEDIA_COMPRESSED_VIDEO; |
| } |
| else |
| { |
| iMediaType = PVMF_MEDIA_UNCOMPRESSED_VIDEO; |
| isUnCompressedMIO = true; |
| } |
| } |
| else if (iSinkFormat.isText()) |
| { |
| //set port name for datapath logging. |
| SetName("MediaOutIn"); |
| |
| //pass the selected format to the MIO component. |
| //ignore any failure since not all MIO may support the feature. |
| SetMIOParameterPchar((char*)MOUT_TEXT_FORMAT_KEY, iSinkFormatString.get_str()); |
| |
| //save the media type. |
| iMediaType = PVMF_MEDIA_TEXT; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::SendData() |
| //send data to the MIO componenent. |
| { |
| const int32 toleranceWndForCallback = 0; |
| if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID) |
| { |
| if (oActiveMediaOutputComp) |
| { |
| SendEndOfData(); |
| } |
| else if (iFrameStepMode == false) |
| { |
| uint32 delta = 0; |
| PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaTimeStamp(delta); |
| if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME || status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE) |
| { |
| SendEndOfData(); |
| } |
| else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY) |
| { |
| |
| OSCL_ASSERT(false == oClockCallBackPending); |
| //stop processing input, since we are not done with the current media msg |
| oProcessIncomingMessage = false; |
| oClockCallBackPending = false; |
| |
| if (NULL != iClockNotificationsInf) |
| { |
| PVMFStatus status = |
| iClockNotificationsInf->SetCallbackDeltaTime(delta, //delta time in clock when callBack should be called |
| toleranceWndForCallback, |
| this, //observer object to be called on timeout |
| false, //no threadLock |
| NULL, //no context |
| iDelayEarlyFrameCallBkId); //ID used to identify the timer for cancellation |
| if (PVMFSuccess != status) |
| { |
| //If delta specified for the callback is too large, then callback to the Mediaclock notification interface does not succeed |
| //Possible reasons for huge difference between the playback clock and the timestamp could be |
| //Sample is intended to be played after a very long time from now (as indicated by the data source(streaming server/file)). |
| //Timestamp is corrupted in the source node. |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Could not set callback notification for send data %d delta %u", status, delta)); |
| iNode->ReportErrorEvent(PVMFErrCorrupt, NULL, PVMFMoutNodeErr_Unexpected); |
| return; |
| } |
| else |
| { |
| oClockCallBackPending = true; |
| } |
| } |
| else |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Fmt=%s, No callback notification Intf ", |
| iSinkFormatString.get_str())); |
| OSCL_ASSERT(false); |
| } |
| } |
| } |
| else if (iFrameStepMode == true) |
| { |
| PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaFrameStep(); |
| if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME || status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE) |
| { |
| SendEndOfData(); |
| } |
| else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY) |
| { |
| //stop processing input, since we are not done with the current media msg |
| oProcessIncomingMessage = false; |
| //wait on ClockCountUpdated call back from oscl clock |
| } |
| } |
| } |
| else if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_RE_CONFIG_FORMAT_ID) |
| { |
| SendReConfigNotification(); |
| } |
| else if (iCurrentMediaMsg->getFormatID() < PVMF_MEDIA_CMD_FORMAT_IDS_START) |
| { |
| if (oActiveMediaOutputComp) |
| { |
| SendMediaData(); |
| } |
| else if (iFrameStepMode == false) |
| { |
| uint32 delta = 0; |
| PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaTimeStamp(delta); |
| if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME) |
| { |
| SendMediaData(); |
| } |
| else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE) |
| { |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY) |
| { |
| |
| OSCL_ASSERT(false == oClockCallBackPending); |
| //stop processing input, since we are not done with the current media msg |
| oProcessIncomingMessage = false; |
| oClockCallBackPending = false; |
| |
| if (NULL != iClockNotificationsInf) |
| { |
| PVMFStatus status = |
| iClockNotificationsInf->SetCallbackDeltaTime(delta, //delta time in clock when callBack should be called |
| toleranceWndForCallback, |
| this, //observer object to be called on timeout |
| false, //no threadLock |
| NULL, //no context |
| iDelayEarlyFrameCallBkId); //ID used to identify the timer for cancellation |
| if (PVMFSuccess != status) |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Could not set callback notification for early frame %d delta %u", status, delta)); |
| iNode->ReportErrorEvent(PVMFErrCorrupt, NULL, PVMFMoutNodeErr_Unexpected); |
| return; |
| } |
| else |
| { |
| oClockCallBackPending = true; |
| } |
| } |
| else |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Fmt=%s, No callback notification Intf ", |
| iSinkFormatString.get_str())); |
| OSCL_ASSERT(false); |
| } |
| } |
| } |
| else if (iFrameStepMode == true) |
| { |
| PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaFrameStep(); |
| if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME) |
| { |
| SendMediaData(); |
| } |
| else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE) |
| { |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY) |
| { |
| //stop processing input, since we are not done with the current media msg |
| oProcessIncomingMessage = false; |
| //wait on ClockCountUpdated call back from oscl clock |
| } |
| } |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::SendMediaData() |
| //send media data to the MIO componenent. |
| { |
| if (iWriteState != EWriteOK) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - Fmt=%s - Invalid WriteAsync State - State=%d", |
| iSinkFormatString.get_str(), |
| iWriteState)); |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendMediaData - Fmt=%s - Invalid WriteAsync State - State=%d", |
| iSinkFormatString.get_str(), |
| iWriteState)); |
| OSCL_ASSERT(false); |
| } |
| |
| PVMFSharedMediaDataPtr mediaData; |
| convertToPVMFMediaData(mediaData, iCurrentMediaMsg); |
| |
| uint32 duration = 0; |
| if (mediaData->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_DURATION_AVAILABLE_BIT) |
| { |
| duration = mediaData->getDuration(); |
| } |
| |
| // extract private data (if it is in fsi) |
| OsclAny *privatedataptr = NULL; |
| uint32 privatedatalength = 0; |
| |
| OsclRefCounterMemFrag fsifrag; |
| mediaData->getFormatSpecificInfo(fsifrag); |
| |
| uint32 *data = (uint32 *)fsifrag.getMemFragPtr(); |
| uint32 data_len = fsifrag.getMemFragSize(); |
| if (data && data_len > 0) |
| { |
| //data to extract |
| privatedataptr = (OsclAny*)(*data); |
| privatedatalength = data_len; |
| } |
| |
| |
| for (uint32 fragindex = iFragIndex; fragindex < mediaData->getNumFragments();) |
| { |
| OsclRefCounterMemFrag frag; |
| mediaData->getMediaFragment(fragindex, frag); |
| |
| iWriteState = EWriteBusy; |
| int32 err = OsclErrNone; |
| int32 cmdId = 0; |
| |
| uint32 flags = PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NONE; |
| |
| // The marker bit should only be set for the final frag to allow MIO to reassemble data properly |
| if ((mediaData->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT) && |
| (fragindex == (mediaData->getNumFragments() - 1))) |
| { |
| flags |= PVMI_MEDIAXFER_MEDIA_DATA_FLAG_MARKER_BIT; |
| } |
| if (mediaData->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_NO_RENDER_BIT) |
| { |
| flags |= PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NO_RENDER_BIT; |
| } |
| PvmiMediaXferHeader mediaxferhdr; |
| mediaxferhdr.seq_num = mediaData->getSeqNum(); |
| mediaxferhdr.timestamp = mediaData->getTimestamp(); |
| mediaxferhdr.duration = duration; |
| mediaxferhdr.flags = flags; |
| mediaxferhdr.stream_id = mediaData->getStreamID(); |
| mediaxferhdr.private_data_length = privatedatalength; |
| mediaxferhdr.private_data_ptr = privatedataptr; |
| err = WriteDataToMIO(cmdId, mediaxferhdr, frag); |
| |
| if (err != OsclErrNone) |
| { |
| // A Busy or an InvalidState leave can occur in a writeAsync call. If a leave occurs in writeasync call, |
| // suspend data transfer. |
| // A Busy leave is not an error and is a normal flow control mechanism. |
| // Some MIO components can do a InvalidState leave if writeasyncs are called before calling Start on MIOs. |
| // Data transfer to MIOs will resume when |
| // 1) In case of Busy Leave: A statusUpdate call from the MIO component tells us to resume. |
| // 2) In case of InvalidState Leave: A statusUpdate call from the MIO component tells us to resume. OR |
| // MIO sends the command complete for Start. |
| iWriteState = EWriteWait; |
| |
| //stop processing input, since we are not done with the current media msg |
| oProcessIncomingMessage = false; |
| |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - WriteAsyncLeave - Fmt=%s, LeaveCode=%d", |
| iSinkFormatString.get_str(), |
| err)); |
| |
| return ;//wait on statusUpdate call or start complete from the MIO component. |
| } |
| else |
| { |
| fragindex++; |
| iFragIndex++; |
| if (fragindex == mediaData->getNumFragments()) |
| { |
| //all fragments have been sent. see whether completion |
| //is synchronous or asynchronous. |
| if (iWriteState == EWriteBusy) |
| { |
| //asynchronous completion. |
| //push the data onto the cleanup stack so it won't get cleaned |
| //up until the component consumes it. |
| iCleanupQueue.push_back(CleanupQueueElement(mediaData, cmdId)); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - AsyncWrite - Fmt=%s, Seq=%d, TS=%d, Dur=%d, FIdx=%d, ClnUpQSize=%d", |
| iSinkFormatString.get_str(), |
| mediaData->getSeqNum(), |
| mediaData->getTimestamp(), |
| duration, |
| iFragIndex, |
| iCleanupQueue.size())); |
| } |
| //else the write already completed synchronously. |
| else |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - SyncWrite - Fmt=%s, Seq=%d, TS=%d, Dur=%d, FIdx=%d, ClnUpQSize=%d", |
| iSinkFormatString.get_str(), |
| mediaData->getSeqNum(), |
| mediaData->getTimestamp(), |
| duration, |
| iFragIndex, |
| iCleanupQueue.size())); |
| } |
| //we are done with current media msg - either we are truly done (sync write complete) or we are |
| //waiting on async write complete in which case media msg has been pushed into the cleanup queue |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| iWriteState = EWriteOK; |
| } |
| } |
| return; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::SendEndOfData() |
| //send end of data notice to the MIO componenent. |
| { |
| if (iWriteState != EWriteOK) |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendEndOfData - Invalid WriteAsync State - State=%d", iWriteState)); |
| OSCL_ASSERT(false); |
| } |
| |
| uint32 eosseqnum = iCurrentMediaMsg->getSeqNum(); |
| uint32 eostimestamp = iCurrentMediaMsg->getTimestamp(); |
| |
| iWriteState = EWriteBusy; |
| |
| int32 err; |
| int32 cmdId = 0; |
| |
| PvmiMediaXferHeader mediaxferhdr; |
| mediaxferhdr.seq_num = eosseqnum; |
| mediaxferhdr.timestamp = eostimestamp; |
| mediaxferhdr.duration = 0; |
| mediaxferhdr.flags = PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NONE; |
| mediaxferhdr.stream_id = iCurrentMediaMsg->getStreamID(); |
| uint32 EosStreamId = mediaxferhdr.stream_id; |
| |
| //iEosStreamIDVec is used as a FIFO to store the steamids of eos sent to mio comp. |
| //streamid is pushed in at front when call writeasync(eos) to mio comp. |
| //streamid is poped out from end when mio comp. calls writecomplete(eos), |
| //we report PVMFInfoEndOfData with the poped streamid. |
| //This logic depends on Mio comp. process data(at least eos msg) in a sequencial style. |
| iEosStreamIDVec.push_front(EosStreamId); |
| OSCL_TRY(err, |
| cmdId = iMediaTransfer->writeAsync(PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION, /*format_type*/ |
| PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM, /*format_index*/ |
| NULL, |
| 0, |
| mediaxferhdr, |
| (OsclAny*) & iWriteAsyncEOSContext); |
| ); |
| |
| if (err != OsclErrNone) |
| { |
| // A Busy or an InvalidState leave can occur in a writeAsync call. If a leave occurs in writeasync call, |
| // suspend data transfer. |
| // A Busy leave is not an error and is a normal flow control mechanism. |
| // Some MIO components can do a InvalidState leave if writeasyncs are called before calling Start on MIOs. |
| // Data transfer to MIOs will resume when |
| // 1) In case of Busy Leave: A statusUpdate call from the MIO component tells us to resume. |
| // 2) In case of InvalidState Leave: A statusUpdate call from the MIO component tells us to resume. OR |
| // MIO sends the command complete for Start. |
| iWriteState = EWriteWait; |
| |
| //stop processing input, since we are not done with the current media msg |
| oProcessIncomingMessage = false; |
| |
| // StreamID popped from vector when leave occurs in the writeAsync call |
| if (iEosStreamIDVec.size() != 0) |
| { |
| iEosStreamIDVec.erase(iEosStreamIDVec.begin()); |
| } |
| else |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendEndOfData - Invalid iEosStreamIDVec size=0")); |
| OSCL_ASSERT(false); |
| } |
| |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - WriteAsyncLeave - Fmt=%s, LeaveCode=%d", |
| iSinkFormatString.get_str(), |
| err)); |
| |
| return ;//wait on statusUpdate call or start complete from the MIO component. |
| } |
| else |
| { |
| if (iWriteState == EWriteBusy) |
| { |
| //asynchronous completion. |
| //wait for writeComplete to be called for this request |
| //log media data info. |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - AsyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iCleanupQueue.size())); |
| |
| iWriteState = EWriteOK; |
| |
| } |
| //else the write already completed synchronously. |
| else |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - SyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iCleanupQueue.size())); |
| |
| // Report End of Data to the user of media output node |
| if (iEosStreamIDVec.size() != 0) |
| { |
| //iEosStreamIDVec is used as a FIFO to store the steamids of eos sent to mio comp. |
| //streamid is pushed in at front when call writeasync(eos) to mio comp. |
| //streamid is poped out from end when mio comp. calls writecomplete(eos), |
| //we report PVMFInfoEndOfData with the poped streamid. |
| //This logic depends on Mio comp. process data(at least eos msg) in a sequencial style. |
| uint32 EosStreamID = iEosStreamIDVec.back(); |
| iNode->ReportInfoEvent(PVMFInfoEndOfData, (OsclAny*)&EosStreamID); |
| iEosStreamIDVec.pop_back(); |
| } |
| else |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendEndOfData - Invalid iEosStreamIDVec size=0")); |
| OSCL_ASSERT(false); |
| } |
| } |
| //we are done with current media msg - either we are truly done (sync write complete) or we are |
| //waiting on async write complete. there is no need to push this msg into cleanup queue since it |
| //is a notification as opossed to media data |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::SendReConfigNotification() |
| //send reconfig notice to the MIO componenent. |
| { |
| if (iWriteState != EWriteOK) |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendReConfigNotification - Invalid WriteAsync State - State=%d", iWriteState)); |
| OSCL_ASSERT(false); |
| } |
| |
| iWriteState = EWriteBusy; |
| int32 err; |
| int32 cmdId = 0; |
| PvmiMediaXferHeader mediaxferhdr; |
| mediaxferhdr.seq_num = iCurrentMediaMsg->getSeqNum(); |
| mediaxferhdr.timestamp = 0; |
| mediaxferhdr.duration = 0; |
| mediaxferhdr.flags = PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NONE; |
| mediaxferhdr.stream_id = iCurrentMediaMsg->getStreamID(); |
| OSCL_TRY(err, |
| cmdId = iMediaTransfer->writeAsync(PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION, /*format_type*/ |
| PVMI_MEDIAXFER_FMT_INDEX_RE_CONFIG_NOTIFICATION, /*format_index*/ |
| NULL, 0, |
| mediaxferhdr, |
| (OsclAny*) & iWriteAsyncReConfigContext); |
| ); |
| |
| if (err != OsclErrNone) |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendReConfigNotification SendReConfigNotification leave code %d", err)); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendReConfigNotification SendReConfigNotification leave code %d", err)); |
| //we don't handle a leave here-- it's an error |
| //media output comps should be open to recving reconfig anytime |
| //they are free to process it at a later point in time and they may |
| //choose to accept the reconfig and reject it. but there should never |
| //be a case where cannot even queue the reconfig request |
| iNode->ReportErrorEvent(PVMFErrResource, NULL, PVMFMoutNodeErr_WriteAsync); |
| } |
| else |
| { |
| if (iWriteState == EWriteBusy) |
| { |
| //asynchronous completion. |
| //wait for writeComplete to be called for this request |
| //log media data info. |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendReConfigNotification - AsyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iCleanupQueue.size())); |
| |
| iWriteState = EWriteOK; |
| |
| } |
| //else the write already completed synchronously. |
| else |
| { |
| //log media data info. |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - SyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iCleanupQueue.size())); |
| } |
| //we are done with current media msg - either we are truly done (sync write complete) or we are |
| //waiting on async write complete. there is no need to push this msg into cleanup queue since it |
| //is a notification as opossed to media data |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFMediaOutputNodePortMediaTimeStatus |
| PVMediaOutputNodePort::CheckMediaTimeStamp(uint32& aDelta) |
| { |
| PVMFTimestamp aTimeStamp = iCurrentMediaMsg->getTimestamp(); |
| aDelta = 0; |
| //aTimeStamp is assumed to be in milliseconds |
| if (iClock != NULL) |
| { |
| uint32 clock_msec32; |
| bool overflowFlag = false; |
| |
| iClock->GetCurrentTime32(clock_msec32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC); |
| |
| |
| uint32 clock_adjforearlymargin = clock_msec32 + iEarlyMargin; |
| uint32 ts_adjforlatemargin = aTimeStamp + iLateMargin; |
| |
| if ((clock_adjforearlymargin - aTimeStamp) > WRAP_THRESHOLD) |
| { |
| // This condition indicates that the timestamp is ahead of the adjusted playback clock |
| // Note that since the computation is based on 32-bit values, it has a limitation that |
| // it will not work for durations exceeding 2^32 milliseconds = 49+ days which is an acceptable |
| // limit for this application. |
| // Say clock is 1000ms, early margin is 200ms, then any timestamp later than 1200ms should be |
| // held back. If ts is greater than 1200ms, then (1200 - ts) will be larger than wrap threshold |
| uint32 deltaInMS = (aTimeStamp - clock_msec32); |
| deltaInMS -= iEarlyMargin; |
| if (iClockRate > 1) |
| { |
| //In case of rate change, calculate delta to acct |
| //for clock rate |
| MediaClockConverter mcc; |
| mcc.set_timescale(iClockRate); |
| //delta is in milliseconds |
| mcc.set_clock_other_timescale(deltaInMS, 1000); |
| //get the value in milliseconds |
| aDelta = mcc.get_converted_ts(1000); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Early - Fmt=%s, Seq=%d, Ts=%d, Clock=%d, DeltaInMS=%d, ClkRate=%d, DeltaInClkUnits=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| aTimeStamp, |
| clock_msec32, |
| deltaInMS, |
| iClockRate, |
| aDelta)); |
| } |
| else |
| { |
| aDelta = deltaInMS; |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Early - Fmt=%s, Seq=%d, Ts=%d, Clock=%d, Delta=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| aTimeStamp, |
| clock_msec32, |
| aDelta)); |
| } |
| iConsecutiveFramesDropped = 0; |
| return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY; |
| } |
| else if ((ts_adjforlatemargin - clock_msec32) > WRAP_THRESHOLD) |
| { |
| // This condition indicates that the clock is ahead of the adjusted timestamp |
| // Note that since the computation is based on 32-bit values, it has a limitation that |
| // it will not work for durations exceeding 2^32 milliseconds = 49+ days which is an acceptable |
| // limit for this application. |
| // Say clock is 1000ms, late margin is 200ms, then any timestamp earlier than 800ms should be |
| // dropped, as late. If ts is less than 800ms, then (ts + 200 - 1000) will be larger than wrap threshold |
| aDelta = (clock_msec32 - aTimeStamp); |
| iFramesDropped++; |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Late - Fmt=%s, Seq=%d, Ts=%d, Clock=%d, Delta=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| aTimeStamp, |
| clock_msec32, |
| aDelta)); |
| iConsecutiveFramesDropped++; |
| if (iMediaType == PVMF_MEDIA_UNCOMPRESSED_VIDEO) |
| { |
| if ((iConsecutiveFramesDropped >= THRESHOLD_FOR_DROPPED_VIDEO_FRAMES) && (iLateFrameEventSent == false)) |
| { |
| iLateFrameEventSent = true; |
| iNode->ReportInfoEvent(PVMFInfoVideoTrackFallingBehind, (OsclAny*)NULL); |
| } |
| } |
| return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE; |
| } |
| else |
| { |
| //ts falls in the interval (clock-latermargin, clock+earlymargin) |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - OnTime - Fmt=%s, Seq=%d, Ts=%d, Clock=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| aTimeStamp, |
| clock_msec32)); |
| iConsecutiveFramesDropped = 0; |
| return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME; |
| } |
| } |
| else |
| { |
| |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Fmt=%s, No PlayBack Clock!!!", |
| iSinkFormatString.get_str())); |
| OSCL_ASSERT(false); |
| return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ERROR; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFMediaOutputNodePortMediaTimeStatus |
| PVMediaOutputNodePort::CheckMediaFrameStep() |
| { |
| if (iClock != NULL) |
| { |
| if (iClockFrameCount > iSyncFrameCount) |
| { |
| //this condition implies that clock count has |
| //gone past the sync frame count, late frame, drop it |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaFrameStep - Late - Fmt=%s, Seq=%d, Ts=%d, iClockFrameCount=%d, iSyncFrameCount=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iClockFrameCount, |
| iSyncFrameCount)); |
| iSyncFrameCount++; |
| return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE; |
| } |
| else if (iClockFrameCount < iSyncFrameCount) |
| { |
| //this condition implies that clock count is less than |
| //the sync frame count, early frame, hold it |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaFrameStep - Early - Fmt=%s, Seq=%d, Ts=%d, iClockFrameCount=%d, iSyncFrameCount=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iClockFrameCount, |
| iSyncFrameCount)); |
| return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY; |
| } |
| else |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaFrameStep - OnTime - Fmt=%s, Seq=%d, Ts=%d, iClockFrameCount=%d, iSyncFrameCount=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iClockFrameCount, |
| iSyncFrameCount)); |
| iSyncFrameCount++; |
| return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME; |
| } |
| } |
| else |
| { |
| |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Fmt=%s, No PlayBack Clock!!!", |
| iSinkFormatString.get_str())); |
| OSCL_ASSERT(false); |
| return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ERROR; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::Run() |
| { |
| /* |
| * Media Output node inport does not process any more incoming messages |
| * under following circumstances: |
| * 1) Playback clock is NOT in RUNNING state |
| * 2) Media output comp is in a STARTED state |
| * 3) When waiting on media output comp to go ready from a busy state |
| * Boolean "oProcessIncomingMessage" will be false if any of the above |
| * conditions is true. |
| * This while loop is intentional. This port doesnt do much in terms of |
| * data processing. So we attempt to send as much data as we can in a |
| * single Run call. Since we could process multiple media msgs per Run |
| * we need to account for BOS and Skip as well. |
| */ |
| while ((IncomingMsgQueueSize() > 0) || (iCurrentMediaMsg.GetRep() != NULL)) |
| { |
| bool oMsgDqd = false; |
| if (iCurrentMediaMsg.GetRep() == NULL) |
| { |
| //we are starting to process a new media msg |
| iFragIndex = 0; |
| if (DequeueIncomingMsg(iCurrentMediaMsg) != PVMFSuccess) |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::Run: DequeueIncomingMsg Failed - Fmt=%s", |
| iSinkFormatString.get_str())); |
| OSCL_ASSERT(0); |
| } |
| else |
| { |
| //this boolean avoids duplicate logs in case we are skipping data |
| oMsgDqd = true; |
| } |
| } |
| if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_BOS_FORMAT_ID) |
| { |
| uint32 msgStreamId = iCurrentMediaMsg->getStreamID(); |
| iBOSStreamIDVec.push_back(msgStreamId); |
| |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getTimestamp(), |
| msgStreamId, |
| IncomingMsgQueueSize())); |
| |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d", |
| iSinkFormatString.get_str(), |
| iCurrentMediaMsg->getTimestamp(), |
| msgStreamId, |
| IncomingMsgQueueSize())); |
| |
| iNode->ReportBOS(); |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| else if (DataToSkip(iCurrentMediaMsg) == true) |
| { |
| //this condition implies that a skip timestamp has been set |
| //and we are looking for a mediamsg whole timestamp is equal or greater than |
| //iSkipTimestamp. All media msgs whose timestamps are less than iSkipTimestamp |
| //will be dropped. There is no need for any additional checks. Just dequeue and toss |
| if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID) |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str())); |
| |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str())); |
| } |
| else |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str())); |
| |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str())); |
| } |
| |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| else |
| { |
| //implies that this message needs to be consumed |
| if (oMsgDqd == true) |
| { |
| //logging |
| if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run - EOS Recvd - StreamID=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str(), |
| IncomingMsgQueueSize())); |
| } |
| else if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_RE_CONFIG_FORMAT_ID) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run - RECONFIG Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d", |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str(), |
| IncomingMsgQueueSize())); |
| } |
| else if (iCurrentMediaMsg->getFormatID() < PVMF_MEDIA_CMD_FORMAT_IDS_START) |
| { |
| iTotalFrames++; |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run - MediaMsg Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d", |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str(), |
| IncomingMsgQueueSize())); |
| } |
| } |
| |
| if ((iSendStartOfDataEvent == true) && oMIOComponentConfigured) |
| { |
| //implies that we are attempting to process the first media msg during |
| //after skip, a mediamsg whose timestamp is equal to or greater than |
| //iSkipTimestamp |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: PVMFInfoStartOfData - Fmt=%s", |
| iSinkFormatString.get_str())); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: PVMFInfoStartOfData - Fmt=%s", |
| iSinkFormatString.get_str())); |
| uint32 iStreamID = iRecentStreamID; |
| iNode->ReportInfoEvent(PVMFInfoStartOfData, (OsclAny*)&iStreamID); |
| iSendStartOfDataEvent = false; |
| } |
| |
| // We need to check for valid CurrentMediaMsg because it is possible that SendData has been |
| // called from ClockStateUpdated when all tracks report InfoStartofData and Engine starts the clock |
| // If dequeued data has already been sent, we cant send that data again, it will crash |
| // so just return and AO will be scheduled again for next data. |
| if ((oProcessIncomingMessage == true) && (iCurrentMediaMsg.GetRep() != NULL)) |
| { |
| SendData(); |
| } |
| else |
| { |
| //implies that we cannot send out any more data |
| //no point continuing, just return |
| //Do not reschedule here. We need to wait for |
| //oProcessIncomingMessage to be true again |
| return; |
| } |
| } |
| } |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PVMediaOutputNodePort::HandlePortActivity(const PVMFPortActivity& aActivity) |
| //from PVMFPortActivityHandler. this port handles its own activity. |
| { |
| switch (aActivity.iType) |
| { |
| case PVMF_PORT_ACTIVITY_CREATED: |
| iNode->ReportInfoEvent(PVMFInfoPortCreated, (OsclAny*)aActivity.iPort); |
| break; |
| |
| case PVMF_PORT_ACTIVITY_DELETED: |
| iNode->ReportInfoEvent(PVMFInfoPortDeleted, (OsclAny*)aActivity.iPort); |
| break; |
| |
| case PVMF_PORT_ACTIVITY_CONNECT: |
| iNode->ReportInfoEvent(PVMFInfoPortConnected, (OsclAny*)aActivity.iPort); |
| break; |
| |
| case PVMF_PORT_ACTIVITY_DISCONNECT: |
| iNode->ReportInfoEvent(PVMFInfoPortDisconnected, (OsclAny*)aActivity.iPort); |
| break; |
| |
| case PVMF_PORT_ACTIVITY_INCOMING_MSG: |
| if (IncomingMsgQueueSize() > 0) |
| { |
| PVMFSharedMediaMsgPtr peekMsgPtr; |
| bool oBos = false; |
| bool oMIOAlreadyConfigured = false; |
| oMIOAlreadyConfigured = oMIOComponentConfigured; |
| if (peekHead(peekMsgPtr, oBos)) |
| { |
| /* |
| * Media Output node inport does not process any more incoming messages |
| * under following circumstances: |
| * 1) Playback clock is NOT in RUNNING state |
| * 2) Media output comp is in a STARTED state |
| * 3) When waiting on media output comp to go ready from a busy state |
| * Boolean "oProcessIncomingMessage" will be false if any of the above |
| * conditions is true. |
| * However BOS is an exception to all of these. BOS is not sent to media output comp, |
| * nor should we worry about playback clock state or media output comp state while |
| * processing BOS. When we get BOS we always send a notification to mediaoutput node |
| * via the BOSObserver with BOS stream-id. |
| */ |
| if (oBos) |
| { |
| if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess) |
| { |
| uint32 msgStreamId = peekMsgPtr->getStreamID(); |
| iBOSStreamIDVec.push_back(msgStreamId); |
| |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d", |
| iSinkFormatString.get_str(), |
| peekMsgPtr->getTimestamp(), |
| msgStreamId, |
| IncomingMsgQueueSize())); |
| |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d", |
| iSinkFormatString.get_str(), |
| peekMsgPtr->getTimestamp(), |
| msgStreamId, |
| IncomingMsgQueueSize())); |
| |
| iNode->ReportBOS(); |
| |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| else |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s", |
| iSinkFormatString.get_str())); |
| OSCL_ASSERT(false); |
| } |
| } |
| else if (DataToSkip(peekMsgPtr) == true) |
| { |
| //this condition implies that a skip timestamp has been set |
| //and we are looking for a mediamsg whole timestamp is equal or greater than |
| //iSkipTimestamp. All media msgs whose timestamps are less than iSkipTimestamp |
| //will be dropped. There is no need for any additional checks. Just dequeue and toss |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess) |
| { |
| if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID) |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str())); |
| |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str())); |
| } |
| else |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str(), |
| IncomingMsgQueueSize())); |
| |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str(), |
| IncomingMsgQueueSize())); |
| } |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| else |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s", |
| iSinkFormatString.get_str())); |
| OSCL_ASSERT(false); |
| } |
| } |
| else |
| { |
| if ((iSendStartOfDataEvent == true) && oMIOComponentConfigured) |
| { |
| //implies that we are attempting to process the first media msg during |
| //after skip, a mediamsg whose timestamp is equal to or greater than |
| //iSkipTimestamp |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: PVMFInfoStartOfData - Fmt=%s", |
| iSinkFormatString.get_str())); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: PVMFInfoStartOfData - Fmt=%s", |
| iSinkFormatString.get_str())); |
| uint32 iStreamID = iRecentStreamID; |
| iNode->ReportInfoEvent(PVMFInfoStartOfData, (OsclAny*)&iStreamID); |
| iSendStartOfDataEvent = false; |
| // Now check if the media msg is EOS notification OR media data. |
| // If EOS then need to do writeComplete for EOS without sending it downstream |
| // This will happen in cases where the media output node is waiting on configuration, |
| // but for some reason the upstream node does not have a config to send. |
| // (Think of cases where we have empty tracks in a presentation OR reposition to EndofClip just after Prepare). |
| // In such cases, if we get EOS we want to notify the Engine with InfoEndofData for the track |
| // so that Engine does not wait for EndOfData from the track and be in a hang state. |
| if (peekMsgPtr->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID) |
| { |
| // There could be cases where MIO was already configured and then a reposition to End cmd |
| // was given to Engine. In this case again EOS will be the first msg after skip but in this |
| // case we want to send EOS downstream rather than sending InfoEndofData from here. |
| if (!oMIOAlreadyConfigured) |
| { |
| // EOS is the first media msg received after Skip |
| if (iCurrentMediaMsg.GetRep() != NULL) |
| { |
| // This should never happen. We cannot have a media msg being processed in this condition. |
| // Just assert and return |
| OSCL_ASSERT(false); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: Processing previous msg iCurrentMediaMsg: 0x%x - Fmt=%s \ |
| when 1st media msg after skip is EOS, wrong, asserting", |
| iCurrentMediaMsg.GetRep(), iSinkFormatString.get_str())); |
| return; |
| } |
| // Dequeue the Incoming msg and send EndofData |
| if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - EOS Recvd - StreamID=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str(), |
| IncomingMsgQueueSize())); |
| |
| uint32 eosStreamId = iCurrentMediaMsg->getStreamID(); |
| |
| iNode->ReportInfoEvent(PVMFInfoEndOfData, (OsclAny*)&eosStreamId); |
| |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| else |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s", |
| iSinkFormatString.get_str())); |
| OSCL_ASSERT(false); |
| } |
| return; |
| } |
| } |
| } |
| if (oProcessIncomingMessage) |
| { |
| //we are starting to process a new media msg |
| if ((iCurrentMediaMsg.GetRep() != NULL) || |
| (iFragIndex != 0)) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg ignoring msg. Still processing previous msg iCurrentMediaMsg: 0x%x iFragIndex: %d- Fmt=%s", |
| iCurrentMediaMsg.GetRep(), iFragIndex, iSinkFormatString.get_str())); |
| return; |
| } |
| if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess) |
| { |
| if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - EOS Recvd - StreamID=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str(), |
| IncomingMsgQueueSize())); |
| } |
| else if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_RE_CONFIG_FORMAT_ID) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - RECONFIG Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d", |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str(), |
| IncomingMsgQueueSize())); |
| } |
| else if (iCurrentMediaMsg->getFormatID() < PVMF_MEDIA_CMD_FORMAT_IDS_START) |
| { |
| iTotalFrames++; |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - MediaMsg Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d", |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str(), |
| IncomingMsgQueueSize())); |
| } |
| |
| SendData(); |
| |
| |
| |
| if ((oProcessIncomingMessage == true) && |
| (IncomingMsgQueueSize() > 0)) |
| { |
| //implies that we can process more data, so reschedule |
| //we could process all the messages in the incoming msg q |
| //in a while loop here, but that might not be advisable |
| //since this call is sort of an observer callback and |
| //it might not be good idea to process more than one msg |
| RunIfNotReady(); |
| } |
| } |
| else |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s", |
| iSinkFormatString.get_str())); |
| OSCL_ASSERT(false); |
| } |
| } |
| } |
| } |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMediaOutputNodePort::ConfigMIO(PvmiKvp* aParameters, PvmiKvp* &aRetParameters) |
| //send config info to media I/O component. |
| { |
| |
| if (iMediaTransfer == NULL) |
| { |
| iMediaTransfer = iNode->iMIOControl->createMediaTransfer(iNode->iMIOSession); |
| if (iMediaTransfer) |
| { |
| iMediaTransfer->setPeer(this); |
| } |
| else |
| { |
| return PVMFFailure; |
| } |
| } |
| |
| if (0 == aParameters) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO: No format-specific info for this track.")); |
| return PVMFSuccess;//no format-specific info, so nothing needed. |
| } |
| uint8* data = (uint8*)aParameters->value.key_specific_value; |
| PVMFStatus status = PVMFFailure; |
| |
| //formatted data gets sent to the MIO on first arrival |
| switch (iMediaType) |
| { |
| case PVMF_MEDIA_UNCOMPRESSED_AUDIO: |
| { |
| //Send pcm16 info. |
| |
| if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY) == 0) |
| { |
| //ignore any failures since not all MIO may suppport the parameters. |
| //Note: send the parameters individually since some MIO may not know |
| //how to process arrays. |
| channelSampleInfo* pcm16Info = (channelSampleInfo*)data; |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO - SamplingRate=%d, NumChannels=%d", |
| pcm16Info->samplingRate, pcm16Info->desiredChannels)); |
| |
| status = SetMIOParameterUint32((char*)MOUT_AUDIO_SAMPLING_RATE_KEY, |
| pcm16Info->samplingRate); |
| if (status == PVMFSuccess) |
| { |
| SetMIOParameterUint32((char*)MOUT_AUDIO_NUM_CHANNELS_KEY, |
| pcm16Info->desiredChannels); |
| } |
| } |
| else if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY_PCM) == 0) |
| { |
| // this is |
| //Do not send individual parameters to MIO component, send them all at once |
| |
| int32 err; |
| OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters);); |
| |
| if (err != OsclErrNone || aRetParameters) |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_AUDIO failed ")); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_AUDIO failed ")); |
| |
| iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync); |
| return PVMFFailure; |
| } |
| |
| status = PVMFSuccess; |
| } |
| } |
| break; |
| |
| case PVMF_MEDIA_UNCOMPRESSED_VIDEO: |
| { |
| //Send yuv info. |
| if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY) == 0) |
| { |
| PVMFYuvFormatSpecificInfo0* yuvInfo = (PVMFYuvFormatSpecificInfo0*)data; |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO - Width=%d, Height=%d, DispWidth=%d, DispHeight=%d", |
| yuvInfo->width, yuvInfo->height, yuvInfo->display_width, yuvInfo->display_height)); |
| //Send yuv info. |
| //ignore any failures since not all MIO may suppport the parameters. |
| //Note: send the parameters individually since some MIO may not know |
| //how to process arrays. |
| status = SetMIOParameterUint32((char*)MOUT_VIDEO_WIDTH_KEY, |
| yuvInfo->width); |
| if (status == PVMFSuccess) |
| { |
| status = SetMIOParameterUint32((char*)MOUT_VIDEO_HEIGHT_KEY, |
| yuvInfo->height); |
| } |
| if (status == PVMFSuccess) |
| { |
| status = SetMIOParameterUint32((char*)MOUT_VIDEO_DISPLAY_WIDTH_KEY, |
| yuvInfo->display_width); |
| } |
| if (status == PVMFSuccess) |
| { |
| status = SetMIOParameterUint32((char*)MOUT_VIDEO_DISPLAY_HEIGHT_KEY, |
| yuvInfo->display_height); |
| } |
| if (status == PVMFSuccess) |
| { |
| // ignore status here |
| SetMIOParameterFormat((char*)MOUT_VIDEO_SUBFORMAT_KEY, |
| yuvInfo->video_format); |
| } |
| |
| |
| } |
| else if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY_YUV) == 0) |
| { |
| |
| //Do not send individual parameters to MIO component, send them all at once |
| |
| int32 err; |
| OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters);); |
| |
| if (err != OsclErrNone || aRetParameters) |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_VIDEO failed ")); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_VIDEO failed ")); |
| |
| iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync); |
| return PVMFFailure; |
| } |
| |
| status = PVMFSuccess; |
| } |
| } |
| break; |
| case PVMF_MEDIA_COMPRESSED_AUDIO: |
| case PVMF_MEDIA_COMPRESSED_VIDEO: |
| //for compressed formats, the format-specific info is sent as kvp |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO Setting Codec Header - Len=%d, Fmt=%s", |
| aParameters->capacity, iSinkFormatString.get_str())); |
| |
| // We will enable the following line after source node fix KVP issue |
| //oscl_assert(aParameters->length == aParameters->capacity) |
| |
| // We will remove the following line after source node fix KVP issue |
| aParameters->length = aParameters->capacity; |
| |
| int32 err; |
| OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters);); |
| |
| if (err != OsclErrNone || aRetParameters) |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed ")); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed ")); |
| //this is the first call, we don't handle a leave here-- it's an error |
| iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync); |
| return PVMFFailure; |
| } |
| status = PVMFSuccess; |
| |
| } |
| break; |
| |
| case PVMF_MEDIA_TEXT: |
| //for text formats, the format-specific info is sent as kvp |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO Setting Codec Header - Len=%d, Fmt=%s", |
| aParameters->capacity, iSinkFormatString.get_str())); |
| |
| // We will enable the following line after source node fix KVP issue |
| //oscl_assert(aParameters->length == aParameters->capacity) |
| |
| // We will remove the following line after source node fix KVP issue |
| aParameters->length = aParameters->capacity; |
| |
| int32 err; |
| OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters);); |
| |
| if (err != OsclErrNone || aRetParameters) |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed ")); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed ")); |
| //this is the first call, we don't handle a leave here-- it's an error |
| iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync); |
| return PVMFFailure; |
| } |
| status = PVMFSuccess; |
| } |
| break; |
| |
| default: |
| status = PVMFErrNotSupported; |
| OSCL_ASSERT(false); |
| break; |
| } |
| if (status != PVMFSuccess) |
| { |
| iNode->ReportErrorEvent(PVMFErrResource, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync); |
| } |
| |
| return status; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMediaOutputNodePort::SetMIOParameterInt32(PvmiKeyType aKey, int32 aValue) |
| //to set parameters to the MIO component through its config interface. |
| { |
| OsclMemAllocator alloc; |
| PvmiKvp kvp; |
| PvmiKvp* retKvp = NULL; // for return value |
| |
| kvp.key = NULL; |
| kvp.length = oscl_strlen(aKey) + 1; // +1 for \0 |
| kvp.capacity = kvp.length; |
| |
| kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length); |
| if (!kvp.key) |
| return PVMFErrNoMemory; |
| |
| oscl_strncpy(kvp.key, aKey, kvp.length); |
| kvp.value.int32_value = aValue; |
| |
| int32 err; |
| OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp);); |
| alloc.deallocate(kvp.key); |
| |
| if (err != OsclErrNone || retKvp) |
| return PVMFFailure; |
| |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMediaOutputNodePort::SetMIOParameterUint32(PvmiKeyType aKey, uint32 aValue) |
| //to set parameters to the MIO component through its config interface. |
| { |
| OsclMemAllocator alloc; |
| PvmiKvp kvp; |
| PvmiKvp* retKvp = NULL; // for return value |
| |
| kvp.key = NULL; |
| kvp.length = oscl_strlen(aKey) + 1; // +1 for \0 |
| kvp.capacity = kvp.length; |
| |
| kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length); |
| if (!kvp.key) |
| return PVMFErrNoMemory; |
| |
| oscl_strncpy(kvp.key, aKey, kvp.length); |
| kvp.value.uint32_value = aValue; |
| |
| int32 err; |
| OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp);); |
| alloc.deallocate(kvp.key); |
| |
| if (err != OsclErrNone || retKvp) |
| return PVMFFailure; |
| |
| return PVMFSuccess; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMediaOutputNodePort::SetMIOParameterPchar(PvmiKeyType aKey, char* aValue) |
| //to set parameters to the MIO component through its config interface. |
| { |
| OsclMemAllocator alloc; |
| PvmiKvp kvp; |
| PvmiKvp* retKvp = NULL; // for return value |
| |
| kvp.key = NULL; |
| kvp.length = oscl_strlen(aKey) + 1; // +1 for \0 |
| kvp.capacity = kvp.length; |
| |
| kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length); |
| if (!kvp.key) |
| return PVMFErrNoMemory; |
| |
| oscl_strncpy(kvp.key, aKey, kvp.length); |
| kvp.value.pChar_value = aValue; |
| |
| int32 err; |
| OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp);); |
| alloc.deallocate(kvp.key); |
| |
| if (err != OsclErrNone || retKvp) |
| return PVMFFailure; |
| |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PVMediaOutputNodePort::SetMIOParameterFormat(PvmiKeyType aKey, PVMFFormatType aFormatType) |
| //to set parameters to the MIO component through its config interface. |
| { |
| OsclMemAllocator alloc; |
| PvmiKvp kvp; |
| PvmiKvp* retKvp = NULL; // for return value |
| |
| kvp.key = NULL; |
| kvp.length = oscl_strlen(aKey) + 1; // +1 for \0 |
| kvp.capacity = kvp.length; |
| |
| kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length); |
| if (!kvp.key) |
| return PVMFErrNoMemory; |
| |
| oscl_strncpy(kvp.key, aKey, kvp.length); |
| kvp.value.pChar_value = (char*)aFormatType.getMIMEStrPtr(); |
| |
| int32 err; |
| OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp);); |
| alloc.deallocate(kvp.key); |
| |
| if (err != OsclErrNone || retKvp) |
| return PVMFFailure; |
| |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, |
| PvmiKvp*& aParameters, int& num_parameter_elements, |
| PvmiCapabilityContext aContext) |
| { |
| PVMFStatus status = iNode->iMIOConfig->getParametersSync(aSession, aIdentifier, aParameters, num_parameter_elements, |
| aContext); |
| return status; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| |
| if (aParameters && iNode) |
| { |
| return iNode->iMIOConfig->releaseParameters(aSession, aParameters, num_elements); |
| } |
| return PVMFFailure; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PVMediaOutputNodePort::setParametersSync(PvmiMIOSession aSession, |
| PvmiKvp* aParameters, |
| int num_elements, |
| PvmiKvp * &aRet_kvp) |
| { |
| PVMFStatus status = PVMFSuccess; |
| OSCL_UNUSED_ARG(aSession); |
| for (int32 i = 0; i < num_elements; i++) |
| { |
| if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY) == 0) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s", |
| iSinkFormatString.get_str())); |
| ConfigMIO(&aParameters[i], aRet_kvp); |
| } |
| else if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY_YUV) == 0) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s", |
| iSinkFormatString.get_str())); |
| status = ConfigMIO(&aParameters[i], aRet_kvp); |
| if (status != PVMFSuccess) |
| OSCL_LEAVE(PVMFFailure); |
| } |
| else if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY_PCM) == 0) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s", |
| iSinkFormatString.get_str())); |
| status = ConfigMIO(&aParameters[i], aRet_kvp); |
| if (status != PVMFSuccess) |
| OSCL_LEAVE(PVMFFailure); |
| } |
| else if ((pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_SAMPLING_RATE_KEY) == 0) || |
| (pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_NUM_CHANNELS_KEY) == 0) || |
| (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_WIDTH_KEY) == 0) || |
| (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_HEIGHT_KEY) == 0) || |
| (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_DISPLAY_WIDTH_KEY) == 0) || |
| (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_DISPLAY_HEIGHT_KEY) == 0)) |
| { |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s", |
| iSinkFormatString.get_str())); |
| //Null parameters, because we just notify that MIO has been configured. |
| ConfigMIO(0, aRet_kvp); |
| iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &aParameters[i], 1, aRet_kvp); |
| } |
| else |
| iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &aParameters[i], 1, aRet_kvp); |
| } |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::verifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| return (iNode->iMIOConfig->verifyParametersSync(iNode->iMIOSession, aParameters, num_elements)); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| bool PVMediaOutputNodePort::peekHead(PVMFSharedMediaMsgPtr& aMsgPtr, |
| bool& bBos) |
| { |
| if (iIncomingQueue.iQ.empty()) |
| { |
| return false; |
| } |
| // get a pointer to the queue head |
| aMsgPtr = iIncomingQueue.iQ.front(); |
| // check the format id first - treat BOS special |
| if (aMsgPtr->getFormatID() == PVMF_MEDIA_CMD_BOS_FORMAT_ID) |
| { |
| bBos = true; |
| } |
| else |
| { |
| bBos = false; |
| } |
| |
| // This check is needed to handle cases where the media output node is waiting on configuration, |
| // but for some reason the upstream node does not have a config to send. |
| // (Think of cases where we have empty tracks in a presentation). In such cases, if we get EOS we want |
| // to notify the media output node that configuration is complete, so that media output node can complete its pending start |
| if (aMsgPtr->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID) |
| { |
| if (false == oMIOComponentConfigured) |
| { |
| OSCL_ASSERT(oProcessIncomingMessage != true); |
| oMIOComponentConfigured = true; |
| oProcessIncomingMessage = true; |
| } |
| } |
| return true; |
| } |
| |
| void PVMediaOutputNodePort::ProcessCallBack(uint32 callBackID, |
| PVTimeComparisonUtils::MediaTimeStatus aTimerAccuracy, |
| uint32 aDelta, |
| const OsclAny* aContextData, |
| PVMFStatus aStatus) |
| { |
| OSCL_UNUSED_ARG(aTimerAccuracy); |
| OSCL_UNUSED_ARG(aDelta); |
| OSCL_UNUSED_ARG(aContextData); |
| PVMF_MOPORT_LOGDEBUG((0, "PVMediaOutputNodePort::ProcessCallBack In Callback id [%d] CallbackStatus [%d]", callBackID, aStatus)); |
| if (PVMFSuccess == aStatus) |
| { |
| if (iDelayEarlyFrameCallBkId == callBackID) |
| { |
| oClockCallBackPending = false; |
| //timer expires, reset the boolean so that we can start processing more data if need be |
| oProcessIncomingMessage = true; |
| if (iCurrentMediaMsg.GetRep() != NULL) |
| { |
| //attempt to send data current media msg if any |
| SendData(); |
| } |
| //reschedule if there is more stuff waiting and |
| //if we can process more data |
| if ((oProcessIncomingMessage == true) && |
| (IncomingMsgQueueSize() > 0)) |
| { |
| RunIfNotReady(); |
| } |
| } |
| else |
| { |
| PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ProcessCallBack- Error stray callback from iClockNotificationsInf callBackID[%d]", callBackID)); |
| OSCL_ASSERT(false); |
| } |
| |
| } |
| } |
| |
| void PVMediaOutputNodePort::SetSkipTimeStamp(uint32 aSkipTS, |
| uint32 aStreamID) |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::SetSkipTimeStamp: TS=%d, Fmt=%s", |
| aSkipTS, |
| iSinkFormatString.get_str())); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SetSkipTimeStamp: TS=%d, Fmt=%s", |
| aSkipTS, |
| iSinkFormatString.get_str())); |
| iSkipTimestamp = aSkipTS; |
| iRecentStreamID = aStreamID; |
| iSendStartOfDataEvent = true; |
| if (oClockCallBackPending) |
| { |
| iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false); |
| } |
| oClockCallBackPending = false; |
| iDelayEarlyFrameCallBkId = 0; |
| |
| //release the current media msg right here instead of |
| //waiting on a reschedule. this is to avoid deadlocks |
| //in case the upstream node is just operating with a |
| //single media msg |
| if (iCurrentMediaMsg.GetRep() != NULL) |
| { |
| if (DataToSkip(iCurrentMediaMsg) == true) |
| { |
| if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID) |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::SetSkipTimeStamp: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str())); |
| |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SetSkipTimeStamp: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str())); |
| } |
| else |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::SetSkipTimeStamp: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str())); |
| |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SetSkipTimeStamp: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s", |
| iCurrentMediaMsg->getStreamID(), |
| iCurrentMediaMsg->getSeqNum(), |
| iCurrentMediaMsg->getTimestamp(), |
| iSinkFormatString.get_str())); |
| } |
| iCurrentMediaMsg.Unbind(); |
| iFragIndex = 0; |
| } |
| } |
| //wake up the AO to start processing messages |
| RunIfNotReady(); |
| } |
| |
| void PVMediaOutputNodePort::CancelSkip() |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::CancelSkip: Fmt=%s", |
| iSinkFormatString.get_str())); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CancelSkip: Fmt=%s", |
| iSinkFormatString.get_str())); |
| iSkipTimestamp = 0; |
| iRecentStreamID = 0; |
| iSendStartOfDataEvent = false; |
| } |
| |
| bool PVMediaOutputNodePort::DataToSkip(PVMFSharedMediaMsgPtr& aMsg) |
| { |
| //iRecentStreamID reflects the latest stream |
| //that is being played. Msg with a streamid less than |
| //iRecentStreamID belongs to an older stream and should |
| //be skipped. Do not skip Msg that belong to the current |
| //stream or a future stream (future being the case where |
| //msg arrives before a skip request. Pls note that we |
| //assume that the stream ids are a montonically increasing |
| //sequence |
| uint32 delta = 0; |
| bool oOldStream = PVTimeComparisonUtils::IsEarlier(aMsg->getStreamID(), iRecentStreamID, delta); |
| if (oOldStream && delta > 0) |
| { |
| //a zero delta could mean the stream ids are equal |
| return true; |
| } |
| //we typically do not do timestamp checks on EOS. |
| //old EOSes that needed to be discarded during a repositioning |
| //would not pass the stream id check above. If we get this far |
| //it means that the EOS belong to the current stream id and its |
| //timestamp does not really matter. |
| if (aMsg->getFormatID() != PVMF_MEDIA_CMD_EOS_FORMAT_ID) |
| { |
| //if we get here it means that the msg belong to current or a |
| //future media stream. check against skip timestamp if we are |
| //required to send PVMFInfoStartOfData. If we are not reqd to |
| //send the event, we intentionally by pass any timestamp checks |
| if (iSendStartOfDataEvent == true) |
| { |
| delta = 0; |
| bool tsEarly = PVTimeComparisonUtils::IsEarlier(aMsg->getTimestamp(), iSkipTimestamp, delta); |
| if (tsEarly && delta > 0) |
| { |
| //a zero delta could mean the timestamps are equal |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| void PVMediaOutputNodePort::ClockTimebaseUpdated() |
| { |
| if (iClock == NULL) |
| return; |
| |
| if (iClock->GetCountTimebase()) |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Added - Fmt=%s", |
| iSinkFormatString.get_str())); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Added - Fmt=%s", |
| iSinkFormatString.get_str())); |
| //Reset the frame step delta to zero. |
| iFrameStepMode = true; |
| iClock->GetCountTimebase()->GetCount(iClockFrameCount); |
| iSyncFrameCount = iClockFrameCount; |
| } |
| else |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Removed - Fmt=%s", |
| iSinkFormatString.get_str())); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Removed - Fmt=%s", |
| iSinkFormatString.get_str())); |
| //reset frame step variables. |
| iFrameStepMode = false; |
| iSyncFrameCount = 0; |
| iClockFrameCount = 0; |
| } |
| if (oClockCallBackPending) |
| { |
| iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false); |
| } |
| oClockCallBackPending = false; |
| iDelayEarlyFrameCallBkId = 0; |
| |
| //reschedule if there is more stuff waiting and |
| //if we can process more data |
| if ((oProcessIncomingMessage == true) && |
| (IncomingMsgQueueSize() > 0)) |
| { |
| RunIfNotReady(); |
| } |
| } |
| |
| void PVMediaOutputNodePort::ClockCountUpdated() |
| { |
| if (iClock && iClock->GetCountTimebase()) |
| { |
| //read the new framecount |
| iClock->GetCountTimebase()->GetCount(iClockFrameCount); |
| //wake up the AO to process data |
| oProcessIncomingMessage = true; |
| |
| if (iCurrentMediaMsg.GetRep() != NULL) |
| { |
| //attempt to send data current media msg if any |
| SendData(); |
| } |
| //reschedule if there is more stuff waiting and |
| //if we can process more data |
| if ((oProcessIncomingMessage == true) && |
| (IncomingMsgQueueSize() > 0)) |
| { |
| RunIfNotReady(); |
| } |
| } |
| } |
| |
| void PVMediaOutputNodePort::ClockAdjusted() |
| { |
| } |
| |
| void PVMediaOutputNodePort::NotificationsInterfaceDestroyed() |
| { |
| iClockNotificationsInf = NULL; |
| } |
| |
| void PVMediaOutputNodePort::ClockStateUpdated() |
| { |
| if (iClock == NULL) |
| return; |
| |
| if (iClock->GetState() == PVMFMediaClock::PAUSED) |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Paused - Fmt=%s", |
| iSinkFormatString.get_str())); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Paused - Fmt=%s", |
| iSinkFormatString.get_str())); |
| //stop processing input msgs only for passive mediaoutput comps |
| //for active ones continue to send, since the mediaoutput comp |
| //is responsible for pacing of the data |
| if (oActiveMediaOutputComp == false) |
| { |
| oProcessIncomingMessage = false; |
| if (oClockCallBackPending) |
| { |
| iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false); |
| } |
| oClockCallBackPending = false; |
| iDelayEarlyFrameCallBkId = 0; |
| } |
| } |
| else if (iClock->GetState() == PVMFMediaClock::RUNNING) |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Running - Fmt=%s", |
| iSinkFormatString.get_str())); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Running - Fmt=%s", |
| iSinkFormatString.get_str())); |
| |
| //If MIO component is configured, messages can be processed now. |
| if (oMIOComponentConfigured) |
| { |
| oProcessIncomingMessage = true; |
| } |
| |
| if (oClockCallBackPending) |
| { |
| iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false); |
| } |
| oClockCallBackPending = false; |
| iDelayEarlyFrameCallBkId = 0; |
| |
| |
| //reset write state as well, in case mo comp is still busy |
| //it will leave again, so that state will get reset |
| iWriteState = EWriteOK; |
| |
| if (iCurrentMediaMsg.GetRep() != NULL) |
| { |
| //attempt to send data current media msg if any |
| SendData(); |
| } |
| |
| //reschedule if there is more stuff waiting and |
| //if we can process more data |
| if ((oProcessIncomingMessage == true) && |
| (IncomingMsgQueueSize() > 0)) |
| { |
| RunIfNotReady(); |
| } |
| } |
| else if (iClock->GetState() == PVMFMediaClock::STOPPED) |
| { |
| PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Stopped - Fmt=%s", |
| iSinkFormatString.get_str())); |
| PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Stopped - Fmt=%s", |
| iSinkFormatString.get_str())); |
| //stop processing input msgs only for passive mediaoutput comps |
| //for active ones continue to send, since the mediaoutput comp |
| //is responsible for pacing of the data, this is to account for a case when clock is stopped |
| //after repositioning. |
| if (oActiveMediaOutputComp == false) |
| { |
| oProcessIncomingMessage = false; |
| if (oClockCallBackPending) |
| { |
| iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false); |
| } |
| oClockCallBackPending = false; |
| iDelayEarlyFrameCallBkId = 0; |
| } |
| } |
| RunIfNotReady(); |
| } |
| |
| void PVMediaOutputNodePort::ClearPreviousBOSStreamIDs(uint32 aID) |
| { |
| //Pls note that we |
| //assume that the stream ids are a montonically increasing |
| //sequence |
| Oscl_Vector<uint32, OsclMemAllocator>::iterator it; |
| it = iBOSStreamIDVec.begin(); |
| while (it != iBOSStreamIDVec.end()) |
| { |
| // iBOSStreamIDVec will contain the stream ID of the current stream being Played. On each skip call |
| // all the previous streamid's will be removed from the vector leaving the current stream id. The |
| // current stream id will be erased in the next skip media data call. |
| if (*it < aID) |
| { |
| it = iBOSStreamIDVec.erase(it); |
| } |
| else |
| { |
| it++; |
| } |
| } |
| } |
| |
| int32 PVMediaOutputNodePort::WriteDataToMIO(int32 &aCmdId, PvmiMediaXferHeader &aMediaxferhdr, OsclRefCounterMemFrag &aFrag) |
| { |
| int32 leavecode = OsclErrNone; |
| OSCL_TRY_NO_TLS(iOsclErrorTrapImp, leavecode, |
| aCmdId = iMediaTransfer->writeAsync(PVMI_MEDIAXFER_FMT_TYPE_DATA, /*format_type*/ |
| PVMI_MEDIAXFER_FMT_INDEX_DATA, /*format_index*/ |
| (uint8*)aFrag.getMemFragPtr(), |
| aFrag.getMemFragSize(), |
| aMediaxferhdr, |
| (OsclAny*) & iWriteAsyncContext);); |
| return leavecode; |
| } |