| /* ------------------------------------------------------------------ |
| * 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_mio_avi_wavfile.cpp |
| * @brief PV Media IO interface implementation using file input |
| */ |
| |
| #ifndef PVMI_MIO_AVIFILE_H_INCLUDED |
| #include "pvmi_mio_avi_wav_file.h" |
| #endif |
| #ifndef OSCL_MIME_STRING_UTILS_H |
| #include "pv_mime_string_utils.h" |
| #endif |
| #ifndef OSCL_DLL_H_INCLUDED |
| #include "oscl_dll.h" |
| #endif |
| |
| // Define entry point for this DLL |
| OSCL_DLL_ENTRY_POINT_DEFAULT() |
| |
| #define PVMIOFILEIN_MEDIADATA_POOLNUM 8 |
| |
| // Logging macros |
| #define LOG_STACK_TRACE(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, m) |
| #define LOG_DEBUG(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, m) |
| #define LOG_ERR(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_ERR,m) |
| #define LOGDATATRAFFIC(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iDataPathLogger,PVLOGMSG_INFO,m); |
| #define LOGDIAGNOSTICS_AVI_FF(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iDiagnosticsLoggerAVIFF,PVLOGMSG_INFO,m); |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PvmiMIOControl* PvmiMIOAviWavFileFactory::Create(uint32 aNumLoops, bool aRecordingMode, uint32 aStreamNo, OsclAny* aFileParser, FileFormatType aFileType, int32& arError) |
| { |
| PvmiMIOControl *mioFilein = (PvmiMIOControl*) OSCL_NEW(PvmiMIOAviWavFile, (aNumLoops, aRecordingMode, aStreamNo, aFileParser, aFileType, arError)); |
| |
| return mioFilein; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF bool PvmiMIOAviWavFileFactory::Delete(PvmiMIOControl* aMio) |
| { |
| PvmiMIOAviWavFile* mioFilein = (PvmiMIOAviWavFile*)aMio; |
| if (!mioFilein) |
| { |
| return false; |
| } |
| OSCL_DELETE(mioFilein); |
| |
| mioFilein = NULL; |
| return true; |
| |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PvmiMIOAviWavFile::~PvmiMIOAviWavFile() |
| { |
| #if PROFILING_ON |
| if (!oDiagnosticsLogged) |
| LogDiagnostics(); |
| #endif |
| |
| if (iMediaBufferMemPool) |
| { |
| if (iSentMediaData.size() > 0) |
| { |
| for (int ii = iSentMediaData.size() - 1; ii >= 0; ii--) |
| { |
| iMediaBufferMemPool->deallocate(iSentMediaData[ii].iData); |
| } |
| } |
| if (iData) |
| { |
| iMediaBufferMemPool->deallocate(iData); |
| iData = NULL; |
| iDataSize = 0; |
| } |
| OSCL_DELETE(iMediaBufferMemPool); |
| iMediaBufferMemPool = NULL; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFStatus PvmiMIOAviWavFile::connect(PvmiMIOSession& aSession, PvmiMIOObserver* aObserver) |
| { |
| if (!aObserver) |
| { |
| return PVMFFailure; |
| } |
| |
| int32 err = 0; |
| OSCL_TRY(err, iObservers.push_back(aObserver)); |
| OSCL_FIRST_CATCH_ANY(err, return PVMFErrNoMemory); |
| aSession = (PvmiMIOSession)(iObservers.size() - 1); // Session ID is the index of observer in the vector |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFStatus PvmiMIOAviWavFile::disconnect(PvmiMIOSession aSession) |
| { |
| uint32 index = (uint32)aSession; |
| if (index >= iObservers.size()) |
| { |
| // Invalid session ID |
| return PVMFFailure; |
| } |
| |
| iObservers.erase(iObservers.begin() + index); |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PvmiMediaTransfer* PvmiMIOAviWavFile::createMediaTransfer(PvmiMIOSession& aSession, |
| PvmiKvp* aRead_formats, |
| int32 aRead_flags, |
| PvmiKvp* aWrite_formats, |
| int32 aWrite_flags) |
| { |
| OSCL_UNUSED_ARG(aRead_formats); |
| OSCL_UNUSED_ARG(aRead_flags); |
| OSCL_UNUSED_ARG(aWrite_formats); |
| OSCL_UNUSED_ARG(aWrite_flags); |
| |
| uint32 index = (uint32)aSession; |
| if (index >= iObservers.size()) |
| { |
| // Invalid session ID |
| OSCL_LEAVE(OsclErrArgument); |
| return NULL; |
| } |
| |
| return (PvmiMediaTransfer*)this; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::deleteMediaTransfer(PvmiMIOSession& aSession, |
| PvmiMediaTransfer* aMediaTransfer) |
| { |
| uint32 index = (uint32)aSession; |
| if (!aMediaTransfer || index >= iObservers.size()) |
| { |
| // Invalid session ID |
| OSCL_LEAVE(OsclErrArgument); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::QueryUUID(const PvmfMimeString& aMimeType, |
| Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids, |
| bool aExactUuidsOnly, |
| const OsclAny* aContext) |
| { |
| OSCL_UNUSED_ARG(aMimeType); |
| OSCL_UNUSED_ARG(aExactUuidsOnly); |
| |
| int32 err = 0; |
| OSCL_TRY(err, aUuids.push_back(PVMI_CAPABILITY_AND_CONFIG_PVUUID);); |
| OSCL_FIRST_CATCH_ANY(err, OSCL_LEAVE(OsclErrNoMemory);); |
| |
| return AddCmdToQueue(CMD_QUERY_UUID, aContext); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::QueryInterface(const PVUuid& aUuid, |
| PVInterface*& aInterfacePtr, |
| const OsclAny* aContext) |
| { |
| if (PVMI_CAPABILITY_AND_CONFIG_PVUUID == aUuid) |
| { |
| PvmiCapabilityAndConfig* myInterface = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*, this); |
| aInterfacePtr = OSCL_STATIC_CAST(PVInterface*, myInterface); |
| } |
| else |
| { |
| aInterfacePtr = NULL; |
| } |
| |
| return AddCmdToQueue(CMD_QUERY_INTERFACE, aContext, (OsclAny*)&aInterfacePtr); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::Init(const OsclAny* aContext) |
| { |
| if (iState != STATE_IDLE && iState != STATE_INITIALIZED) |
| { |
| OSCL_LEAVE(OsclErrInvalidState); |
| return -1; |
| } |
| |
| return AddCmdToQueue(CMD_INIT, aContext); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::Start(const OsclAny* aContext) |
| { |
| if (iState != STATE_INITIALIZED |
| && iState != STATE_PAUSED |
| && iState != STATE_STARTED) |
| { |
| OSCL_LEAVE(OsclErrInvalidState); |
| return -1; |
| } |
| |
| return AddCmdToQueue(CMD_START, aContext); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::Pause(const OsclAny* aContext) |
| { |
| if (iState != STATE_STARTED && iState != STATE_PAUSED) |
| { |
| OSCL_LEAVE(OsclErrInvalidState); |
| return -1; |
| } |
| |
| return AddCmdToQueue(CMD_PAUSE, aContext); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::Flush(const OsclAny* aContext) |
| { |
| if (iState != STATE_STARTED || iState != STATE_PAUSED) |
| { |
| OSCL_LEAVE(OsclErrInvalidState); |
| return -1; |
| } |
| |
| return AddCmdToQueue(CMD_FLUSH, aContext); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::Reset(const OsclAny* aContext) |
| { |
| if (iState != STATE_STARTED || iState != STATE_PAUSED) |
| { |
| OSCL_LEAVE(OsclErrInvalidState); |
| return -1; |
| } |
| |
| return AddCmdToQueue(CMD_RESET, aContext); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::DiscardData(PVMFTimestamp aTimestamp, const OsclAny* aContext) |
| { |
| OSCL_UNUSED_ARG(aContext); |
| OSCL_UNUSED_ARG(aTimestamp); |
| OSCL_LEAVE(OsclErrNotSupported); |
| return -1; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::DiscardData(const OsclAny* aContext) |
| { |
| OSCL_UNUSED_ARG(aContext); |
| OSCL_LEAVE(OsclErrNotSupported); |
| return -1; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::Stop(const OsclAny* aContext) |
| { |
| if (iState != STATE_STARTED |
| && iState != STATE_PAUSED |
| && iState != STATE_STOPPED) |
| { |
| OSCL_LEAVE(OsclErrInvalidState); |
| return -1; |
| } |
| |
| return AddCmdToQueue(CMD_STOP, aContext); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::ThreadLogon() |
| { |
| |
| if (!iThreadLoggedOn) |
| { |
| if (iSettings.iRecModeSyncWithClock) |
| { |
| iMioClock = OSCL_NEW(PVMFMediaClock, ()); |
| iMioClock->SetClockTimebase(iClockTimeBase); |
| uint32 start = 0; |
| bool overflowFlag = false; |
| iMioClock->SetStartTime32(start, PVMF_MEDIA_CLOCK_MSEC, overflowFlag); |
| } |
| AddToScheduler(); |
| iThreadLoggedOn = true; |
| |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::ThreadLogoff() |
| { |
| if (iThreadLoggedOn) |
| { |
| if (iSettings.iRecModeSyncWithClock && iMioClock != NULL) |
| { |
| OSCL_DELETE(iMioClock); |
| } |
| RemoveFromScheduler(); |
| iLogger = NULL; |
| iDataPathLogger = NULL; |
| iThreadLoggedOn = false; |
| } |
| |
| } |
| |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::CancelAllCommands(const OsclAny* aContext) |
| { |
| OSCL_UNUSED_ARG(aContext); |
| OSCL_LEAVE(OsclErrNotSupported); |
| return -1; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::CancelCommand(PVMFCommandId aCmdId, const OsclAny* aContext) |
| { |
| OSCL_UNUSED_ARG(aCmdId); |
| OSCL_UNUSED_ARG(aContext); |
| OSCL_LEAVE(OsclErrNotSupported); |
| return -1; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::setPeer(PvmiMediaTransfer* aPeer) |
| { |
| iPeer = aPeer; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::useMemoryAllocators(OsclMemAllocator* aWrite_alloc) |
| { |
| OSCL_UNUSED_ARG(aWrite_alloc); |
| OSCL_LEAVE(OsclErrNotSupported); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::writeAsync(uint8 aFormatType, int32 aFormatIndex, |
| uint8* aData, uint32 aDataLen, |
| const PvmiMediaXferHeader& aData_header_info, |
| OsclAny* aContext) |
| { |
| OSCL_UNUSED_ARG(aFormatType); |
| OSCL_UNUSED_ARG(aFormatIndex); |
| OSCL_UNUSED_ARG(aData); |
| OSCL_UNUSED_ARG(aDataLen); |
| OSCL_UNUSED_ARG(aData_header_info); |
| OSCL_UNUSED_ARG(aContext); |
| // This is an active data source. writeAsync is not supported. |
| OSCL_LEAVE(OsclErrNotSupported); |
| return -1; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::writeComplete(PVMFStatus aStatus, PVMFCommandId aWrite_cmd_id, |
| OsclAny* aContext) |
| { |
| OSCL_UNUSED_ARG(aContext); |
| if ((aStatus != PVMFSuccess) && (aStatus != PVMFErrCancelled)) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PvmiMIOAviWavFile::writeComplete: Error - writeAsync failed. aStatus=%d", aStatus)); |
| OSCL_LEAVE(OsclErrGeneral); |
| } |
| |
| for (int ii = iSentMediaData.size() - 1; ii >= 0; ii--) |
| { |
| if (iSentMediaData[ii].iId == aWrite_cmd_id) |
| { |
| iMediaBufferMemPool->deallocate(iSentMediaData[ii].iData); |
| iSentMediaData.erase(&iSentMediaData[ii]); |
| return; |
| } |
| } |
| |
| // Error: unmatching ID. |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PvmiMIOAviWavFile::writeComplete: Error - unmatched cmdId %d failed. QSize %d", aWrite_cmd_id, iSentMediaData.size())); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::readAsync(uint8* aData, uint32 aMax_data_len, |
| OsclAny* aContext, int32* aFormats, uint16 aNum_formats) |
| { |
| OSCL_UNUSED_ARG(aData); |
| OSCL_UNUSED_ARG(aMax_data_len); |
| OSCL_UNUSED_ARG(aContext); |
| OSCL_UNUSED_ARG(aFormats); |
| OSCL_UNUSED_ARG(aNum_formats); |
| // This is an active data source. readAsync is not supported. |
| OSCL_LEAVE(OsclErrNotSupported); |
| return -1; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::readComplete(PVMFStatus aStatus, PVMFCommandId aRead_cmd_id, |
| int32 aFormat_index, const PvmiMediaXferHeader& aData_header_info, |
| OsclAny* aContext) |
| { |
| OSCL_UNUSED_ARG(aStatus); |
| OSCL_UNUSED_ARG(aRead_cmd_id); |
| OSCL_UNUSED_ARG(aFormat_index); |
| OSCL_UNUSED_ARG(aData_header_info); |
| OSCL_UNUSED_ARG(aContext); |
| // This is an active data source. readComplete is not supported. |
| OSCL_LEAVE(OsclErrNotSupported); |
| return; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::statusUpdate(uint32 aStatus_flags) |
| { |
| if (aStatus_flags == PVMI_MEDIAXFER_STATUS_WRITE) |
| { |
| iWriteState = EWriteOK; |
| iMicroSecondsPerDataEvent = 0; |
| AddDataEventToQueue(iMicroSecondsPerDataEvent); |
| } |
| else |
| { |
| // Ideally this routine should update the status of media input component. |
| // It should check then for the status. If media input buffer is consumed, |
| // media input object should be resheduled. |
| // Since the Media avifile component is designed with single buffer, two |
| // asynchronous reads are not possible. So this function will not be required |
| // and hence not been implemented. |
| OSCL_LEAVE(OsclErrNotSupported); |
| } |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::cancelCommand(PVMFCommandId aCmdId) |
| { |
| OSCL_UNUSED_ARG(aCmdId); |
| // This cancel command ( with a small "c" in cancel ) is for the media transfer interface. |
| // implementation is similar to the cancel command of the media I/O interface. |
| OSCL_LEAVE(OsclErrNotSupported); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::cancelAllCommands() |
| { |
| OSCL_LEAVE(OsclErrNotSupported); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::setObserver(PvmiConfigAndCapabilityCmdObserver* aObserver) |
| { |
| OSCL_UNUSED_ARG(aObserver); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFStatus PvmiMIOAviWavFile::getParametersSync(PvmiMIOSession aSession, |
| PvmiKeyType aIdentifier, |
| PvmiKvp*& aParameters, |
| int& aNum_parameter_elements, |
| PvmiCapabilityContext aContext) |
| { |
| LOG_STACK_TRACE((0, "PvmiMIOAviWavFile::getParametersSync")); |
| OSCL_UNUSED_ARG(aSession); |
| OSCL_UNUSED_ARG(aContext); |
| |
| aParameters = NULL; |
| aNum_parameter_elements = 0; |
| PVMFStatus status = PVMFFailure; |
| |
| if (pv_mime_strcmp(aIdentifier, OUTPUT_FORMATS_CAP_QUERY) == 0 || |
| pv_mime_strcmp(aIdentifier, OUTPUT_FORMATS_CUR_QUERY) == 0) |
| { |
| aNum_parameter_elements = 1; |
| status = AllocateKvp(aParameters, (PvmiKeyType)OUTPUT_FORMATS_VALTYPE, aNum_parameter_elements); |
| if (status != PVMFSuccess) |
| { |
| LOG_ERR((0, "PvmiMIOAviWavFile::GetOutputParametersSync: Error - AllocateKvp failed. status=%d", status)); |
| } |
| else |
| { |
| aParameters[0].value.pChar_value = (char*)iSettings.iMediaFormat.getMIMEStrPtr(); |
| |
| } |
| } |
| else if (pv_mime_strcmp(aIdentifier, VIDEO_OUTPUT_WIDTH_CUR_QUERY) == 0) |
| { |
| aNum_parameter_elements = 1; |
| status = AllocateKvp(aParameters, (PvmiKeyType)VIDEO_OUTPUT_WIDTH_CUR_VALUE, aNum_parameter_elements); |
| if (status != PVMFSuccess) |
| { |
| LOG_ERR((0, "PvmiMIOAviWavFile::GetOutputParametersSync: Error - AllocateKvp failed. status=%d", status)); |
| return status; |
| } |
| |
| aParameters[0].value.uint32_value = iSettings.iFrameWidth; |
| } |
| else if (pv_mime_strcmp(aIdentifier, VIDEO_FRAME_ORIENTATION_CUR_QUERY) == 0) |
| { |
| aNum_parameter_elements = 1; |
| status = AllocateKvp(aParameters, (PvmiKeyType)VIDEO_FRAME_ORIENTATION_CUR_VALUE, aNum_parameter_elements); |
| if (status != PVMFSuccess) |
| { |
| LOG_ERR((0, "PvmiMIOAviWavFile::GetOutputParametersSync: Error - AllocateKvp failed. status=%d", status)); |
| return status; |
| } |
| |
| aParameters[0].value.uint8_value = iSettings.iPicBottomUp; |
| |
| } |
| else if (pv_mime_strcmp(aIdentifier, VIDEO_OUTPUT_HEIGHT_CUR_QUERY) == 0) |
| { |
| aNum_parameter_elements = 1; |
| status = AllocateKvp(aParameters, (PvmiKeyType)VIDEO_OUTPUT_HEIGHT_CUR_VALUE, aNum_parameter_elements); |
| if (status != PVMFSuccess) |
| { |
| LOG_ERR((0, "PvmiMIOAviWavFile::GetOutputParametersSync: Error - AllocateKvp failed. status=%d", status)); |
| return status; |
| } |
| |
| aParameters[0].value.uint32_value = iSettings.iFrameHeight; |
| } |
| else if (pv_mime_strcmp(aIdentifier, VIDEO_OUTPUT_FRAME_RATE_CUR_QUERY) == 0) |
| { |
| aNum_parameter_elements = 1; |
| status = AllocateKvp(aParameters, (PvmiKeyType)VIDEO_OUTPUT_FRAME_RATE_CUR_VALUE, aNum_parameter_elements); |
| if (status != PVMFSuccess) |
| { |
| LOG_ERR((0, "PvmiMIOAviWavFile::GetOutputParametersSync: Error - AllocateKvp failed. status=%d", status)); |
| return status; |
| } |
| |
| aParameters[0].value.float_value = iSettings.iFrameRate; |
| } |
| else if (pv_mime_strcmp(aIdentifier, OUTPUT_TIMESCALE_CUR_QUERY) == 0) |
| { |
| aNum_parameter_elements = 1; |
| status = AllocateKvp(aParameters, (PvmiKeyType)OUTPUT_TIMESCALE_CUR_VALUE, aNum_parameter_elements); |
| if (status != PVMFSuccess) |
| { |
| LOG_ERR((0, "PVMFVideoEncPort::GetOutputParametersSync: Error - AllocateKvp failed. status=%d", status)); |
| return status; |
| } |
| else |
| { |
| if (iSettings.iMediaFormat.isAudio()) |
| { |
| aParameters[0].value.uint32_value = (uint32)iSettings.iSamplingFrequency; |
| } |
| else |
| { |
| aParameters[0].value.uint32_value = iSettings.iTimescale; |
| } |
| } |
| } |
| |
| return status; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFStatus PvmiMIOAviWavFile::releaseParameters(PvmiMIOSession aSession, |
| PvmiKvp* aParameters, |
| int aNum_elements) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| OSCL_UNUSED_ARG(aNum_elements); |
| |
| if (aParameters) |
| { |
| iAlloc.deallocate((OsclAny*)aParameters); |
| return PVMFSuccess; |
| } |
| else |
| { |
| return PVMFFailure; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| OSCL_UNUSED_ARG(aContext); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::setContextParameters(PvmiMIOSession aSession, |
| PvmiCapabilityContext& aContext, |
| PvmiKvp* aParameters, int aNum_parameter_elements) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| OSCL_UNUSED_ARG(aContext); |
| OSCL_UNUSED_ARG(aParameters); |
| OSCL_UNUSED_ARG(aNum_parameter_elements); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::DeleteContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| OSCL_UNUSED_ARG(aContext); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF void PvmiMIOAviWavFile::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, |
| int aNum_elements, PvmiKvp*& aRet_kvp) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| PVMFStatus status = PVMFSuccess; |
| aRet_kvp = NULL; |
| |
| for (int32 ii = 0; ii < aNum_elements; ii++) |
| { |
| status = VerifyAndSetParameter(&(aParameters[ii]), true); |
| if (status != PVMFSuccess) |
| { |
| LOG_ERR((0, "PvmiMIOAviWavFile::setParametersSync: Error - VerifiyAndSetParameter failed on parameter #%d", ii)); |
| aRet_kvp = &(aParameters[ii]); |
| OSCL_LEAVE(OsclErrArgument); |
| } |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFCommandId PvmiMIOAviWavFile::setParametersAsync(PvmiMIOSession aSession, |
| PvmiKvp* aParameters, |
| int aNum_elements, |
| PvmiKvp*& aRet_kvp, |
| OsclAny* aContext) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| OSCL_UNUSED_ARG(aParameters); |
| OSCL_UNUSED_ARG(aNum_elements); |
| OSCL_UNUSED_ARG(aRet_kvp); |
| OSCL_UNUSED_ARG(aContext); |
| OSCL_LEAVE(OsclErrNotSupported); |
| return -1; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF uint32 PvmiMIOAviWavFile::getCapabilityMetric(PvmiMIOSession aSession) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| return 0; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| OSCL_EXPORT_REF PVMFStatus PvmiMIOAviWavFile::verifyParametersSync(PvmiMIOSession aSession, |
| PvmiKvp* aParameters, int aNum_elements) |
| { |
| OSCL_UNUSED_ARG(aSession); |
| OSCL_UNUSED_ARG(aParameters); |
| OSCL_UNUSED_ARG(aNum_elements); |
| return PVMFErrNotSupported; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| // Private methods |
| //////////////////////////////////////////////////////////////////////////// |
| PvmiMIOAviWavFile::PvmiMIOAviWavFile(uint32 aNumLoops, bool aRecordingMode, uint32 aStreamNo, OsclAny* aFileParser, |
| FileFormatType aFileType, int32& arError) |
| : OsclTimerObject(OsclActiveObject::EPriorityNominal, "PvmiMIOAviWavFile"), |
| iCmdIdCounter(0), |
| iPeer(NULL), |
| iThreadLoggedOn(false), |
| iDataEventCounter(0), |
| iTotalNumFrames(0), |
| iFileHeaderSize(0), |
| iMilliSecondsPerDataEvent(0), |
| iMicroSecondsPerDataEvent(0), |
| iMediaBufferMemPool(NULL), |
| iLogger(NULL), |
| iDataPathLogger(NULL), |
| iState(STATE_IDLE), |
| iWaitingOnClock(false), |
| iTimeStamp(0), |
| iStreamDuration(0), |
| iCurrentTimeStamp(0), |
| iWriteState(EWriteOK), |
| iData(NULL), |
| iNoMemBufferData(false) |
| { |
| #if PROFILING_ON |
| iNumEarlyFrames = 0; |
| iNumLateFrames = 0; |
| iTotalFrames = 0; |
| iPercFramesDropped = 0; |
| iMaxDataSize = 0; |
| iMinDataSize = 0; |
| iMaxFileReadTime = 0; |
| iMinFileReadTime = 0; |
| oDiagnosticsLogged = false; |
| #endif |
| iSettings.iNumLoops = aNumLoops; |
| iSettings.iStreamNumber = aStreamNo; |
| iSettings.iRecModeSyncWithClock = aRecordingMode; |
| arError = InitComp(aFileParser, aFileType); |
| |
| iLogger = PVLogger::GetLoggerObject("PvmiMIOAviWavFile"); |
| iDiagnosticsLogger = PVLogger::GetLoggerObject("pvauthordiagnostics.mio.aviwav"); |
| iDiagnosticsLoggerAVIFF = PVLogger::GetLoggerObject("pvauthordiagnostics.mio.aviwav.ff"); |
| iDataPathLogger = PVLogger::GetLoggerObject("datapath.mio.aviwav"); |
| } |
| |
| bool PvmiMIOAviWavFile::IsYUVFormat_Supported(uint32 aFcc) |
| { |
| uint32 ii; |
| bool pattern_found = false; |
| |
| for (ii = 0 ; ii < NUM_YUV_FMT; ii++) |
| { |
| if (YUV_FMT[ii] == aFcc) |
| { |
| pattern_found = true; |
| break; |
| } |
| } |
| |
| return pattern_found; |
| } |
| //////////////////////////////////////////////////////////////////////////// |
| int32 PvmiMIOAviWavFile::InitComp(OsclAny* aFileParser, FileFormatType aFileType) |
| { |
| |
| switch (aFileType) |
| { |
| case FILE_FORMAT_AVI: |
| { |
| iPVAviFile = OSCL_STATIC_CAST(PVAviFile*, aFileParser); |
| iPVWavFile = NULL; |
| iSettings.iFrameDuration = iPVAviFile->GetFrameDuration(); |
| uint32 ii = iSettings.iStreamNumber; |
| iStreamDuration = iPVAviFile->GetStreamDuration(ii); |
| iPVAviFile->GetFormatSpecificInfo(ii, iFormatSpecificDataFrag); |
| |
| if (oscl_strstr((iPVAviFile->GetStreamMimeType(ii)).get_cstr(), "video")) |
| { |
| iSettings.iFrameHeight = iPVAviFile->GetHeight(iSettings.iPicBottomUp, ii); |
| iSettings.iFrameWidth = iPVAviFile->GetWidth(ii); |
| iSettings.iFrameRate = iPVAviFile->GetFrameRate(ii); |
| iSettings.iTimescale = iPVAviFile->GetScale(ii); |
| uint8 fmtType[4] = {0}; |
| uint32 size = 4; |
| |
| iPVAviFile->GetVideoFormatType((uint8*)fmtType, size, ii); |
| |
| uint32 temp = MAKE_FOURCC(fmtType[0], fmtType[1], fmtType[2], fmtType[3]); |
| |
| BitmapInfoHhr* videoHdr = OSCL_STATIC_CAST(BitmapInfoHhr*, iFormatSpecificDataFrag.getMemFragPtr()); |
| |
| if (!oscl_strncmp((char*)fmtType, "DIB ", size)) |
| { |
| |
| if (BITS_PER_SAMPLE12 == videoHdr->BiBitCount) |
| { |
| iSettings.iMediaFormat = PVMF_MIME_RGB12; |
| iSettings.iMimeType = PVMF_MIME_RGB12; |
| iSettings.iSampleSize = videoHdr->BiBitCount; |
| } |
| else if (BITS_PER_SAMPLE24 == videoHdr->BiBitCount) |
| { |
| iSettings.iMediaFormat = PVMF_MIME_RGB24; |
| iSettings.iMimeType = PVMF_MIME_RGB24; |
| |
| iSettings.iSampleSize = videoHdr->BiBitCount; |
| } |
| else |
| { |
| return PVMFErrNotSupported; |
| } |
| } |
| else if (IsYUVFormat_Supported(temp)) |
| { |
| iSettings.iMediaFormat = PVMF_MIME_YUV420; |
| iSettings.iMimeType = PVMF_MIME_YUV420; |
| |
| } |
| else |
| { |
| return PVMFErrNotSupported; |
| } |
| } |
| |
| if (oscl_strstr((iPVAviFile->GetStreamMimeType(ii)).get_cstr(), "audio")) |
| { |
| iSettings.iNumChannels = iPVAviFile->GetNumAudioChannels(ii); |
| iSettings.iSamplingFrequency = iPVAviFile->GetFrameRate(ii); |
| |
| WaveFormatExStruct* audioHdr = OSCL_STATIC_CAST(WaveFormatExStruct*, |
| iFormatSpecificDataFrag.getMemFragPtr()); |
| |
| iSettings.iSampleSize = audioHdr->BitsPerSample; |
| iSettings.iByteRate = audioHdr->AvgBytesPerSec; |
| |
| if (WAVE_FORMAT_PCM == audioHdr->FormatTag) |
| { |
| if (BITS_PER_SAMPLE8 == audioHdr->BitsPerSample) |
| { |
| iSettings.iMediaFormat = PVMF_MIME_PCM8; |
| iSettings.iMimeType = PVMF_MIME_PCM8; |
| } |
| else if (BITS_PER_SAMPLE16 == audioHdr->BitsPerSample) |
| { |
| iSettings.iMediaFormat = PVMF_MIME_PCM16; |
| iSettings.iMimeType = PVMF_MIME_PCM16; |
| } |
| else |
| { |
| return PVMFErrNotSupported; |
| } |
| } |
| else |
| { |
| return PVMFErrNotSupported; |
| } |
| } |
| } |
| break; |
| |
| case FILE_FORMAT_WAV: |
| { |
| iPVAviFile = NULL; |
| iPVWavFile = OSCL_STATIC_CAST(PV_Wav_Parser*, aFileParser); |
| PVWAVFileInfo wavFileInfo; |
| iPVWavFile->RetrieveFileInfo(wavFileInfo); |
| |
| if ((PVWAV_ITU_G711_ALAW == wavFileInfo.AudioFormat) |
| || (PVWAV_ITU_G711_ULAW == wavFileInfo.AudioFormat)) |
| { |
| if (iPVWavFile->SetOutputToUncompressedPCM()) |
| { |
| wavFileInfo.AudioFormat = PVWAV_PCM_AUDIO_FORMAT; |
| wavFileInfo.BitsPerSample = BITS_PER_SAMPLE16; |
| wavFileInfo.BytesPerSample = BITS_PER_SAMPLE16 / BYTE_COUNT; |
| } |
| } |
| |
| iSettings.iNumChannels = wavFileInfo.NumChannels; |
| iSettings.iSamplingFrequency = (OsclFloat)wavFileInfo.SampleRate; |
| iSettings.iSampleSize = wavFileInfo.BitsPerSample; |
| iSettings.iByteRate = wavFileInfo.ByteRate; |
| iStreamDuration = (1000000 / wavFileInfo.SampleRate) * wavFileInfo.NumSamples; |
| |
| if (BITS_PER_SAMPLE16 == wavFileInfo.BitsPerSample) |
| { |
| iSettings.iMediaFormat = PVMF_MIME_PCM16; |
| iSettings.iMimeType = PVMF_MIME_PCM16; |
| } |
| else if (BITS_PER_SAMPLE8 == wavFileInfo.BitsPerSample) |
| { |
| iSettings.iMediaFormat = PVMF_MIME_PCM8; |
| iSettings.iMimeType = PVMF_MIME_PCM8; |
| } |
| else |
| { |
| return PVMFErrNotSupported; |
| } |
| |
| } |
| break; |
| |
| default: |
| return PVMFErrNotSupported; |
| |
| } // end switch |
| |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PvmiMIOAviWavFile::Run() |
| { |
| if (!iCmdQueue.empty()) |
| { |
| PvmiMIOAviWavFileCmd cmd = iCmdQueue[0]; |
| iCmdQueue.erase(iCmdQueue.begin()); |
| |
| switch (cmd.iType) |
| { |
| |
| case CMD_INIT: |
| DoRequestCompleted(cmd, DoInit()); |
| break; |
| |
| case CMD_START: |
| DoRequestCompleted(cmd, DoStart()); |
| break; |
| |
| case CMD_PAUSE: |
| DoRequestCompleted(cmd, DoPause()); |
| break; |
| |
| case CMD_FLUSH: |
| DoRequestCompleted(cmd, DoFlush()); |
| break; |
| |
| case CMD_RESET: |
| DoRequestCompleted(cmd, DoReset()); |
| break; |
| |
| case CMD_STOP: |
| DoRequestCompleted(cmd, DoStop()); |
| break; |
| |
| case DATA_EVENT: |
| DoRead(); |
| break; |
| |
| case CMD_QUERY_UUID: |
| case CMD_QUERY_INTERFACE: |
| DoRequestCompleted(cmd, PVMFSuccess); |
| break; |
| |
| case CMD_CANCEL_ALL_COMMANDS: |
| case CMD_CANCEL_COMMAND: |
| DoRequestCompleted(cmd, PVMFFailure); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| if (!iCmdQueue.empty()) |
| { |
| // Run again if there are more things to process |
| RunIfNotReady(); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFCommandId PvmiMIOAviWavFile::AddCmdToQueue(PvmiMIOAviWavFileCmdType aType, |
| const OsclAny* aContext, OsclAny* aData1) |
| { |
| if (DATA_EVENT == aType) |
| { |
| OSCL_LEAVE(OsclErrArgument); |
| } |
| |
| PvmiMIOAviWavFileCmd cmd; |
| cmd.iType = aType; |
| cmd.iContext = OSCL_STATIC_CAST(OsclAny*, aContext); |
| cmd.iData1 = aData1; |
| cmd.iId = iCmdIdCounter; |
| ++iCmdIdCounter; |
| iCmdQueue.push_back(cmd); |
| RunIfNotReady(); |
| return cmd.iId; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PvmiMIOAviWavFile::AddDataEventToQueue(uint32 aMicroSecondsToEvent) |
| { |
| PvmiMIOAviWavFileCmd cmd; |
| cmd.iType = DATA_EVENT; |
| iCmdQueue.push_back(cmd); |
| RunIfNotReady(aMicroSecondsToEvent); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| void PvmiMIOAviWavFile::DoRequestCompleted(const PvmiMIOAviWavFileCmd& aCmd, PVMFStatus aStatus, OsclAny* aEventData) |
| { |
| PVMFCmdResp response(aCmd.iId, aCmd.iContext, aStatus, aEventData); |
| |
| for (uint32 ii = 0; ii < iObservers.size(); ii++) |
| { |
| iObservers[ii]->RequestCompleted(response); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PvmiMIOAviWavFile::DoInit() |
| { |
| if (STATE_INITIALIZED == iState) |
| { |
| return PVMFSuccess; |
| } |
| iDataEventCounter = 0; |
| // Create memory pool for the media data, using the maximum frame size found earlier |
| int32 err = 0; |
| OSCL_TRY(err, |
| if (iMediaBufferMemPool) |
| { |
| OSCL_DELETE(iMediaBufferMemPool); |
| iMediaBufferMemPool = NULL; |
| } |
| iMediaBufferMemPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, |
| (PVMIOFILEIN_MEDIADATA_POOLNUM)); |
| |
| if (!iMediaBufferMemPool) |
| { |
| OSCL_LEAVE(OsclErrNoMemory); |
| } |
| |
| ); |
| |
| OSCL_FIRST_CATCH_ANY(err, return PVMFErrNoMemory); |
| |
| //set chunk size |
| uint32 dataSize = GetDataSize(); |
| //add bytes in 1 msec |
| dataSize += (uint32)(iSettings.iSampleSize / BYTE_COUNT * iSettings.iSamplingFrequency / 1000); |
| iSettings.iDataBufferSize = dataSize; |
| |
| uint8* data = (uint8*)iMediaBufferMemPool->allocate(dataSize); |
| iMediaBufferMemPool->deallocate(data); |
| iState = STATE_INITIALIZED; |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PvmiMIOAviWavFile::DoStart() |
| { |
| iState = STATE_STARTED; |
| AddDataEventToQueue(0); |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PvmiMIOAviWavFile::DoPause() |
| { |
| iState = STATE_PAUSED; |
| if ((iMioClock) && (iSettings.iRecModeSyncWithClock)) |
| { |
| iMioClock->Pause(); |
| } |
| return PVMFSuccess; |
| } |
| |
| PVMFStatus PvmiMIOAviWavFile::DoReset() |
| { |
| iWriteState = EWriteOK; |
| #if PROFILING_ON |
| if (!oDiagnosticsLogged) |
| LogDiagnostics(); |
| #endif |
| |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PvmiMIOAviWavFile::DoFlush() |
| { |
| // This method should stop capturing media data but continue to send captured |
| // media data that is already in buffer and then go to stopped state. |
| // However, in this case of file input we do not have such a buffer for |
| // captured data, so this behaves the same way as stop. |
| return DoStop(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PvmiMIOAviWavFile::DoStop() |
| { |
| iWriteState = EWriteOK; |
| iDataEventCounter = 0; |
| iState = STATE_STOPPED; |
| if ((iMioClock != NULL) && (iSettings.iRecModeSyncWithClock)) |
| { |
| iMioClock->Stop(); |
| } |
| #if PROFILING_ON |
| if (!oDiagnosticsLogged) |
| LogDiagnostics(); |
| #endif |
| |
| iState = STATE_STOPPED; |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| uint32 PvmiMIOAviWavFile::GetDataSize() |
| { |
| uint32 size = 0; |
| if (iPVAviFile != NULL) |
| { |
| size = iPVAviFile->GetStreamSuggestedBufferSize(iSettings.iStreamNumber); |
| } |
| else if (iPVWavFile != NULL) |
| { |
| //number of samples in data buffer |
| uint32 numSamples = (uint32)(iSettings.iSamplingFrequency * PVWAV_MSEC_PER_BUFFER) / 1000; |
| size = numSamples * iSettings.iNumChannels * (iSettings.iSampleSize / BYTE_COUNT); // in bytes |
| } |
| else |
| { |
| return 0; |
| } |
| |
| return size; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PvmiMIOAviWavFile::GetMediaData(uint8* aData, uint32& aDataSize, uint32& aTimeStamp) |
| { |
| aTimeStamp = iCurrentTimeStamp; |
| uint32 iNptTS = 0; |
| // Read data from file |
| if (iPVAviFile != NULL) |
| { |
| PV_AVI_FILE_PARSER_ERROR_TYPE error = PV_AVI_FILE_PARSER_SUCCESS; |
| |
| uint32 currticks = 0; |
| currticks = OsclTickCount::TickCount(); |
| uint32 starttime = 0; |
| starttime = OsclTickCount::TicksToMsec(currticks); |
| |
| error = iPVAviFile->GetNextStreamMediaSample(iSettings.iStreamNumber, aData, aDataSize, iNptTS); |
| |
| currticks = OsclTickCount::TickCount(); |
| uint32 endtime = 0; |
| endtime = OsclTickCount::TicksToMsec(currticks); |
| |
| LOGDIAGNOSTICS_AVI_FF((0, "PvmiMIOAviWavFile::GetMediaData:" |
| "StreamNum=%d, NptTS=%d, Size=%d, TimeToRead=%d, MimeType=%s", |
| iSettings.iStreamNumber, iNptTS, aDataSize, (endtime - starttime), |
| iSettings.iMimeType.get_cstr())); |
| |
| if (error != PV_AVI_FILE_PARSER_SUCCESS) |
| { |
| if (PV_AVI_FILE_PARSER_EOS_REACHED == error) |
| { |
| // Loop or report end of data now... |
| if (iSettings.iNumLoops) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PvmiMIOAviWavFile::LoopInputFile")); |
| |
| iPVAviFile->Reset(iSettings.iStreamNumber); |
| iSettings.iNumLoops--; |
| //retrieve sample again |
| PV_AVI_FILE_PARSER_ERROR_TYPE error = PV_AVI_FILE_PARSER_SUCCESS; |
| |
| uint32 currticks = 0; |
| currticks = OsclTickCount::TickCount(); |
| uint32 starttime = 0; |
| starttime = OsclTickCount::TicksToMsec(currticks); |
| |
| error = iPVAviFile->GetNextStreamMediaSample(iSettings.iStreamNumber, aData, aDataSize, iNptTS); |
| |
| currticks = OsclTickCount::TickCount(); |
| uint32 endtime = 0; |
| endtime = OsclTickCount::TicksToMsec(currticks); |
| |
| LOGDIAGNOSTICS_AVI_FF((0, "PvmiMIOAviWavFile::GetMediaData:" |
| "StreamNum=%d, NptTS=%d, Size=%d, TimeToRead=%d, MimeType=%s", |
| iSettings.iStreamNumber, iNptTS, aDataSize, (endtime - starttime), |
| iSettings.iMimeType.get_cstr())); |
| |
| if (error != PV_AVI_FILE_PARSER_SUCCESS) |
| { |
| return PVMFFailure; |
| } |
| else |
| { |
| UpdateCurrentTimeStamp(aDataSize); |
| return PVMFSuccess; |
| } |
| } |
| else |
| { |
| UpdateCurrentTimeStamp(aDataSize); |
| return PVMFInfoEndOfData; |
| } |
| } |
| else |
| { |
| return PVMFFailure; |
| } |
| } |
| } |
| else //WAV file |
| { |
| uint32 samplesRead = 0; |
| uint32 numSamples = (uint32)(iSettings.iSamplingFrequency * PVWAV_MSEC_PER_BUFFER) / 1000; |
| PVWavParserReturnCode retcode = iPVWavFile->GetPCMData(aData, aDataSize, numSamples, samplesRead); |
| if (PVWAVPARSER_OK == retcode) |
| { |
| if (samplesRead > 0) |
| { |
| aDataSize = samplesRead * iSettings.iNumChannels * (iSettings.iSampleSize / BYTE_COUNT); |
| } |
| } |
| else if (PVWAVPARSER_END_OF_FILE == retcode) |
| { |
| if (iSettings.iNumLoops) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PvmiMIOAviWavFile::LoopInputFile Not Supported")); |
| |
| iPVWavFile->SeekPCMSample(0); |
| iSettings.iNumLoops--; |
| PVWavParserReturnCode retcode = iPVWavFile->GetPCMData(aData, aDataSize, numSamples, samplesRead); |
| if (PVWAVPARSER_OK == retcode) |
| { |
| if (samplesRead > 0) |
| { |
| aDataSize = samplesRead * iSettings.iNumChannels * (iSettings.iSampleSize / BYTE_COUNT); |
| } |
| UpdateCurrentTimeStamp(aDataSize); |
| return PVMFSuccess; |
| } |
| else |
| { |
| return PVMFFailure; |
| } |
| } |
| else |
| { |
| UpdateCurrentTimeStamp(aDataSize); |
| return PVMFInfoEndOfData; |
| } |
| } |
| else |
| { |
| return PVMFFailure; |
| } |
| } |
| UpdateCurrentTimeStamp(aDataSize); |
| return PVMFSuccess; |
| } |
| //////////////////////////////////////////////////////////////////////////// |
| void PvmiMIOAviWavFile::UpdateCurrentTimeStamp(uint32 aDataSize) |
| { |
| if (iPVAviFile != NULL) |
| { |
| if (oscl_strstr((iPVAviFile->GetStreamMimeType(iSettings.iStreamNumber)).get_cstr(), "video")) |
| { |
| iCurrentTimeStamp += (iPVAviFile->GetFrameDuration() / 1000); //in msec |
| } |
| else if (oscl_strstr((iPVAviFile->GetStreamMimeType(iSettings.iStreamNumber)).get_cstr(), "audio")) |
| { |
| uint32 numSamples = aDataSize * BYTE_COUNT / iSettings.iSampleSize; |
| iCurrentTimeStamp = (uint32)((OsclFloat)iCurrentTimeStamp + (OsclFloat)(numSamples * 1000) / iSettings.iSamplingFrequency); |
| } |
| } |
| else //WAV File |
| { |
| iCurrentTimeStamp += PVWAV_MSEC_PER_BUFFER; |
| } |
| |
| |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PvmiMIOAviWavFile::DoRead() |
| { |
| // Just copy from PVMFAviFileNode::HandleEventPortActivity. The only difference |
| // is that data buffer is allocated by calling iMediaBufferMemPool->allocate(bytesToRead) |
| // and there's no need to wrap it in a PVMFSharedMediaDataPtr. Also, you'll need to |
| // keep track of the data pointer and the write command id received from peer->writeAsync |
| // and put it in the iSentMediaData queue |
| |
| if (iState != STATE_STARTED) |
| { |
| return PVMFSuccess; |
| } |
| |
| uint32 dataSize = 0; |
| uint32 timeStamp = 0; |
| uint8* data = NULL; |
| uint32 writeAsyncID = 0; |
| |
| PVMFStatus error = PVMFSuccess; |
| |
| dataSize = iSettings.iDataBufferSize; |
| |
| if (dataSize <= 0) |
| { |
| return PVMFErrArgument; |
| } |
| |
| // for realtime recording, read new media data only if not iWaitingOnClock. |
| // otherwise process previously read data |
| int32 err = 0; |
| |
| //process new data only if previous data has been send to MIO node. |
| if ((!iWaitingOnClock) && (iWriteState == EWriteOK)) |
| { |
| // Create new media data buffer |
| data = AllocateMemPool(iMediaBufferMemPool, dataSize, err); |
| |
| if (err) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, |
| (0, "PvmiMIOAviWavFile::No buffer available, wait till next data event")); |
| |
| if (iSettings.iRecModeSyncWithClock) |
| CalcMicroSecPerDataEvent(dataSize); |
| else |
| iMicroSecondsPerDataEvent = 0; |
| |
| AddDataEventToQueue(iMicroSecondsPerDataEvent); |
| return PVMFSuccess; |
| } |
| |
| if (iNoMemBufferData)//check added for ErrorHandling test case for no memory buffer |
| { |
| iMediaBufferMemPool->deallocate(iData); |
| iData = NULL; |
| iDataSize = 0; |
| iNoMemBufferData = false; |
| } |
| else |
| { |
| iData = NULL; |
| iDataSize = 0; |
| iTimeStamp = 0; |
| } |
| |
| bool senddata = false; |
| |
| |
| while (!senddata) |
| { |
| |
| #if PROFILING_ON |
| uint32 start = OsclTickCount::TickCount(); |
| #endif |
| //read media data |
| error = GetMediaData(data, dataSize, timeStamp); |
| |
| #if PROFILING_ON |
| uint32 stop = OsclTickCount::TickCount(); |
| uint32 freadTime = OsclTickCount::TicksToMsec(stop - start); |
| |
| if (error == PVMFSuccess) |
| { |
| if (iMaxDataSize < dataSize) |
| { |
| iMaxDataSize = dataSize; |
| } |
| if ((iMinDataSize > dataSize) || (0 == iMinDataSize)) |
| { |
| iMinDataSize = dataSize; |
| } |
| if (iMaxFileReadTime < freadTime) |
| { |
| iMaxFileReadTime = freadTime; |
| } |
| if ((iMinFileReadTime > freadTime) || (0 == iMinFileReadTime)) |
| { |
| iMinFileReadTime = freadTime; |
| } |
| } |
| #endif |
| if (error != PVMFSuccess) |
| { |
| if (PVMFInfoEndOfData == error) //EOS Reached |
| { |
| //free the allocated data buffer |
| iMediaBufferMemPool->deallocate(data); |
| data = NULL; |
| |
| PvmiMediaXferHeader data_hdr; |
| data_hdr.seq_num = iDataEventCounter - 1; |
| data_hdr.timestamp = timeStamp; |
| data_hdr.flags = 0; |
| data_hdr.duration = 0; |
| data_hdr.stream_id = iSettings.iStreamNumber; |
| dataSize = 0; |
| //send EOS information to MIO Node |
| error = WriteAsyncDataHdr(writeAsyncID, iPeer, dataSize, data_hdr, NULL, PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION, PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM); |
| |
| if (error) |
| { |
| if (iSettings.iRecModeSyncWithClock) |
| CalcMicroSecPerDataEvent(dataSize); |
| else |
| iMicroSecondsPerDataEvent = 0; |
| |
| //some error occured, retry sending EOS next time. |
| AddDataEventToQueue(iMicroSecondsPerDataEvent); |
| return PVMFSuccess; |
| } |
| iWriteState = EWriteOK; |
| |
| LOGDATATRAFFIC((0, "PvmiMIOAviWavFile::DoRead - EOS Sent:" |
| "StreamID=%d, TS=%d, SN=%d, MimeType=%s", |
| data_hdr.stream_id, data_hdr.timestamp, |
| data_hdr.seq_num, iSettings.iMimeType.get_cstr())); |
| //EOS message was sent so PAUSE MIO Component. |
| AddCmdToQueue(CMD_PAUSE, NULL); |
| |
| return PVMFSuccess; |
| } |
| else |
| { |
| //free the allocated data buffer |
| iMediaBufferMemPool->deallocate(data); |
| data = NULL; |
| AddCmdToQueue(CMD_STOP, NULL); |
| return error; |
| } |
| } |
| |
| #if PROFILING_ON |
| iTotalFrames++; |
| #endif |
| if (iSettings.iRecModeSyncWithClock) |
| { |
| |
| uint32 clockTime32 = 0; |
| uint32 clockTimeBase32 = 0; |
| bool overflowFlag = false; |
| |
| if (iMioClock->GetState() != PVMFMediaClock::RUNNING) |
| { |
| iMioClock->SetStartTime32(timeStamp, PVMF_MEDIA_CLOCK_MSEC, overflowFlag); |
| iMioClock->Start(); |
| } |
| |
| |
| //Compare with Clock time to pass data forward. |
| iMioClock->GetCurrentTime32(clockTime32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, clockTimeBase32); |
| |
| if (timeStamp > clockTime32) |
| { |
| uint32 delta = timeStamp - clockTime32; |
| //store data info to be send forward in next callback. |
| iData = data; |
| iDataSize = dataSize; |
| iTimeStamp = timeStamp; |
| AddDataEventToQueue(delta * 1000); //delta in microseconds. |
| iWaitingOnClock = true; |
| #if PROFILING_ON |
| iNumEarlyFrames++; |
| #endif |
| return PVMFSuccess; |
| } |
| |
| if (timeStamp < clockTime32) |
| { |
| #if PROFILING_ON |
| iNumLateFrames++; |
| #endif |
| dataSize = iSettings.iDataBufferSize; |
| |
| if (dataSize <= 0) |
| { |
| return PVMFErrArgument; |
| } |
| } |
| |
| if (timeStamp == clockTime32) |
| { |
| senddata = true; |
| } |
| |
| } // if (iSettings.iRecModeSyncWithClock) |
| else |
| { |
| senddata = true; |
| } |
| } // while (!senddata) |
| } // if (!iWaitingOnClock) |
| |
| iWaitingOnClock = false; |
| |
| if (iData != NULL) |
| { |
| data = iData; |
| dataSize = iDataSize; |
| timeStamp = iTimeStamp; |
| iData = NULL; |
| } |
| |
| // send data to Peer & store the id |
| PvmiMediaXferHeader data_hdr; |
| data_hdr.seq_num = iDataEventCounter - 1; |
| data_hdr.timestamp = timeStamp; |
| data_hdr.flags = 0; |
| data_hdr.duration = 0; |
| data_hdr.stream_id = iSettings.iStreamNumber; |
| |
| if (!iPeer) |
| { |
| return PVMFSuccess; |
| } |
| err = WriteAsyncDataHdr(writeAsyncID, iPeer, dataSize, data_hdr, data, PVMI_MEDIAXFER_FMT_TYPE_DATA, 0); |
| if (!err) |
| { |
| LOGDATATRAFFIC((0, "PvmiMIOAviWavFile::DoRead:" |
| "StreamID=%d, TS=%d, Size=%d, SN=%d, MimeType=%s", |
| data_hdr.stream_id, data_hdr.timestamp, dataSize, |
| data_hdr.seq_num, iSettings.iMimeType.get_cstr())); |
| |
| // Save the id and data pointer on iSentMediaData queue for writeComplete call |
| PvmiMIOAviWavFileMediaData sentData; |
| sentData.iId = writeAsyncID; |
| sentData.iData = data; |
| iSentMediaData.push_back(sentData); |
| iMicroSecondsPerDataEvent = 0; |
| // Queue the next data event |
| AddDataEventToQueue(iMicroSecondsPerDataEvent); |
| } |
| else if (err == OsclErrBusy) |
| { |
| iData = data; |
| iDataSize = dataSize; |
| iTimeStamp = timeStamp; |
| iWriteState = EWriteBusy; |
| iNoMemBufferData = true; |
| } |
| else |
| { |
| iMediaBufferMemPool->deallocate(data); |
| } |
| |
| return PVMFSuccess; |
| } |
| |
| PVMFStatus PvmiMIOAviWavFile::CalcMicroSecPerDataEvent(uint32 aDataSize) |
| { |
| //calculate time for a buffer to fill |
| if (iSettings.iMediaFormat == PVMF_MIME_YUV420) |
| { |
| //calculate time for a buffer to fill |
| iMilliSecondsPerDataEvent = (int32)(1000 / iSettings.iFrameRate); |
| |
| iMicroSecondsPerDataEvent = (int32)(1000000 / iSettings.iFrameRate); |
| } |
| else if (iSettings.iMediaFormat == PVMF_MIME_RGB16 || |
| iSettings.iMediaFormat == PVMF_MIME_RGB24) |
| { |
| //calculate time for a buffer to fill |
| iMilliSecondsPerDataEvent = (int32)(1000 / iSettings.iFrameRate); |
| iMicroSecondsPerDataEvent = (int32)(1000000 / iSettings.iFrameRate); |
| } |
| else if (iSettings.iMediaFormat == PVMF_MIME_PCM16 || |
| iSettings.iMediaFormat == PVMF_MIME_PCM8) |
| { |
| OsclFloat chunkrate = (OsclFloat)((OsclFloat)iSettings.iByteRate / (OsclFloat)aDataSize); |
| iMilliSecondsPerDataEvent = (uint32)(1000 / chunkrate); |
| iMicroSecondsPerDataEvent = iMilliSecondsPerDataEvent * 1000; |
| } |
| else |
| { |
| return PVMFErrArgument; |
| } |
| |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PvmiMIOAviWavFile::AllocateKvp(PvmiKvp*& aKvp, PvmiKeyType aKey, int32 aNumParams) |
| { |
| LOG_STACK_TRACE((0, "PvmiMIOAviWavFile::AllocateKvp")); |
| uint8* buf = NULL; |
| uint32 keyLen = oscl_strlen(aKey) + 1; |
| int32 err = 0; |
| |
| OSCL_TRY(err, |
| buf = (uint8*)iAlloc.allocate(aNumParams * (sizeof(PvmiKvp) + keyLen)); |
| if (!buf) |
| { |
| OSCL_LEAVE(OsclErrNoMemory); |
| } |
| ); |
| |
| OSCL_FIRST_CATCH_ANY(err, |
| LOG_ERR((0, "PvmiMIOAviWavFile::AllocateKvp: Error - kvp allocation failed")); |
| return PVMFErrNoMemory; |
| ); |
| |
| int32 ii = 0; |
| PvmiKvp* curKvp = aKvp = OSCL_PLACEMENT_NEW(buf, PvmiKvp); |
| buf += sizeof(PvmiKvp); |
| for (ii = 1; ii < aNumParams; ii++) |
| { |
| curKvp += ii; |
| curKvp = OSCL_PLACEMENT_NEW(buf, PvmiKvp); |
| buf += sizeof(PvmiKvp); |
| } |
| |
| for (ii = 0; ii < aNumParams; ii++) |
| { |
| aKvp[ii].key = (char*)buf; |
| oscl_strncpy(aKvp[ii].key, aKey, keyLen); |
| buf += keyLen; |
| } |
| |
| return PVMFSuccess; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////// |
| PVMFStatus PvmiMIOAviWavFile::VerifyAndSetParameter(PvmiKvp* aKvp, bool aSetParam) |
| { |
| OSCL_UNUSED_ARG(aSetParam); |
| LOG_STACK_TRACE((0, "PvmiMIOAviWavFile::VerifyAndSetParameter: aKvp=0x%x, aSetParam=%d", aKvp, aSetParam)); |
| |
| if (!aKvp) |
| { |
| LOG_ERR((0, "PvmiMIOAviWavFile::VerifyAndSetParameter: Error - Invalid key-value pair")); |
| return PVMFFailure; |
| } |
| |
| if (pv_mime_strcmp(aKvp->key, OUTPUT_FORMATS_VALTYPE) == 0) |
| { |
| if (aKvp->value.pChar_value == (char*)iSettings.iMediaFormat.getMIMEStrPtr()) |
| { |
| return PVMFSuccess; |
| } |
| else |
| { |
| LOG_ERR((0, "PvmiMIOAviWavFile::VerifyAndSetParameter: Error - Unsupported format %d", |
| aKvp->value.uint32_value)); |
| return PVMFFailure; |
| } |
| } |
| |
| LOG_ERR((0, "PvmiMIOAviWavFile::VerifyAndSetParameter: Error - Unsupported parameter")); |
| return PVMFFailure; |
| } |
| |
| void PvmiMIOAviWavFile::LogDiagnostics() |
| { |
| #if PROFILING_ON |
| oDiagnosticsLogged = true; |
| if (iPVAviFile) |
| { |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iDiagnosticsLogger, PVLOGMSG_DEBUG, |
| (0, "PvmiMIOAviWavFile Stats: Stream :%s\n", |
| (iPVAviFile->GetStreamMimeType(iSettings.iStreamNumber)).get_cstr())); |
| } |
| uint32 framerate = 0; |
| |
| if (iCurrentTimeStamp > 0) |
| { |
| framerate = (iTotalFrames * 1000) / iCurrentTimeStamp; |
| } |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iDiagnosticsLogger, PVLOGMSG_DEBUG, |
| (0, "PvmiMIOAviWavFile Stats: File read duration(Max:%d, Min:%d), Data Size read(Max:%d, Min:%d), Total frames send: %d, Frame Rate: %d\n", iMaxFileReadTime, iMinFileReadTime, iMaxDataSize, iMinDataSize, iTotalFrames, framerate)); |
| |
| //Log status of early and late frames for real time authoring |
| if (iSettings.iRecModeSyncWithClock) |
| { |
| |
| if (iTotalFrames > 0) |
| { |
| iPercFramesDropped = (iNumLateFrames * 100) / iTotalFrames; |
| } |
| |
| PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iDiagnosticsLogger, PVLOGMSG_DEBUG, |
| (0, "PvmiMIOAviWavFile Stats: Num Early frames:%d, Num late frames:%d, Total Frames:%d, percent Late frames:%d\n", iNumEarlyFrames, iNumLateFrames, iTotalFrames, iPercFramesDropped)); |
| } |
| #endif |
| } |
| |
| uint8* PvmiMIOAviWavFile::AllocateMemPool(OsclMemPoolFixedChunkAllocator*& aMediaBufferMemPool, uint32 aDataSize, int32 &aErr) |
| { |
| uint8* data = NULL;; |
| OSCL_TRY(aErr, data = (uint8*)aMediaBufferMemPool->allocate(aDataSize);); |
| return data; |
| } |
| |
| int32 PvmiMIOAviWavFile::WriteAsyncDataHdr(uint32& aWriteAsyncID, PvmiMediaTransfer*& aPeer, uint32& aBytesToRead, PvmiMediaXferHeader& aData_hdr, uint8* aData, uint32 aFormatType, uint32 aFormatIndex) |
| { |
| int err = 0; |
| OSCL_TRY(err, aWriteAsyncID = aPeer->writeAsync(aFormatType, aFormatIndex, aData, aBytesToRead, aData_hdr);); |
| return err; |
| } |