diff -r 000000000000 -r 40261b775718 mmdevicefw/mdf/src/video/decoderadapter/mdfvideodecodehwdeviceadapter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmdevicefw/mdf/src/video/decoderadapter/mdfvideodecodehwdeviceadapter.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,1402 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include "mdfvideodecodehwdeviceadapter.h" +#include "displaymodeutils.h" + +#if defined (SYMBIAN_MDFVIDEODECODERHWDEVICE_DEBUG) +#define DEBUG_PRINT RDebug::Print +#else +#define DEBUG_PRINT +#endif // defined (SYMBIAN_MDFVIDEODECODERHWDEVICE_DEBUG) + +const TInt KOutputFormatsArraySize = 3; +const TInt KTenFPS = 10; +const TInt KOneSecond = 1000000; +const TInt KInputBufferSize = 8192; + +_LIT(KDevVideoHwDeviceDecoderPanicCategory, "DevVideoHwDeviceDecoder"); +void DevVideoHwDeviceDecoderPanic(TInt aReason) + { + User::Panic(KDevVideoHwDeviceDecoderPanicCategory, aReason); + } + +/* + Constructs a new instance of CMdfVideoDecodeHwDeviceAdapter. + @return "CMdfVideoDecodeHwDeviceAdapter*" + A pointer to the newly constructed HwDevice + */ +CMdfVideoDecodeHwDeviceAdapter* CMdfVideoDecodeHwDeviceAdapter::NewL() + { + CMdfVideoDecodeHwDeviceAdapter* self = new (ELeave) CMdfVideoDecodeHwDeviceAdapter; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/* + Default constructor +*/ +CMdfVideoDecodeHwDeviceAdapter::CMdfVideoDecodeHwDeviceAdapter() + { + } + +void CMdfVideoDecodeHwDeviceAdapter::ConstructL() + { + // system clock without HAL + TInt64 tt64; + TTime ttime; + ttime.HomeTime(); + tt64 = ttime.Int64(); + iSystemClock = tt64; + + // reset picture format + iFormat.iDataFormat = (TImageDataFormat)0; + + // Load the PU Loader plugin + iPuLoader = static_cast + (REComSession::CreateImplementationL(TUid::Uid(KUidPuLoaderImplementation), iPuLoaderDtorKey)); + iState = EProcessingUnitLoaderLoaded; + } + +/* + Default destructor +*/ +CMdfVideoDecodeHwDeviceAdapter::~CMdfVideoDecodeHwDeviceAdapter() + { + DEBUG_PRINT(_L("HwDevice: Destroying")); + // stop playing if necessary + Stop(); + + delete iPlayerEngine; + delete iScreenDeviceGc; + + // destroy the buffer manager + delete iBufferManager; + // destroy the picture header + delete iPictureHeader; + + // Unload the DecoderPU + if (iDecoderPU) + { + iPuLoader->UnloadProcessingUnit(iDecoderPU); + } + + delete iPuLoader; + delete iPuData; + delete iManufacturer; + REComSession::DestroyedImplementation(iPuLoaderDtorKey); + + iInputVidFormats.ResetAndDestroy(); // will destroy contents as well + iOutputVidFormats.Close(); + iPictureRates.Close(); + + DEBUG_PRINT(_L("HwDevice: Destroyed")); + } + +/* + @see CMMFVideoHwDevice::CustomInterface() + */ +TAny* CMdfVideoDecodeHwDeviceAdapter::CustomInterface(TUid aInterface) + { + if (aInterface.iUid == KUidDevVideoHwDeviceAdapterSetup) + { + return static_cast(this); + } + return NULL; + } + +/* + @see CMMFVideoPlayHwDevice::PostProcessorInfoLC() + */ +CPostProcessorInfo* CMdfVideoDecodeHwDeviceAdapter::PostProcessorInfoLC() + { + // post processor info will be obtained from the post processor plugin, if any + return NULL; + } + +/* + @see CMMFVideoPlayHwDevice::GetOutputFormatListL() + */ +void CMdfVideoDecodeHwDeviceAdapter::GetOutputFormatListL(RArray& aFormats) + { + // TUncompressedVideoFormats is a union - therefore using hard initialisation + iOutputVidFormats.Reset(); + TUncompressedVideoFormat outputFormats[KOutputFormatsArraySize]; + + outputFormats[0].iDataFormat = ERgbRawData; + outputFormats[0].iRgbFormat = ERgb16bit565; + iOutputVidFormats.AppendL(outputFormats[0]); + aFormats.AppendL(outputFormats[0]); + + outputFormats[1].iDataFormat = ERgbFbsBitmap; + outputFormats[1].iRgbFormat = EFbsBitmapColor16M; + iOutputVidFormats.AppendL(outputFormats[1]); + aFormats.AppendL(outputFormats[1]); + + outputFormats[2].iDataFormat = EYuvRawData; + iOutputVidFormats.AppendL(outputFormats[2]); + aFormats.AppendL(outputFormats[2]); + } + +/* + @see CMMFVideoPlayHwDevice::SetOutputFormatL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetOutputFormatL(const TUncompressedVideoFormat& aFormat) + { + // check size and format are supported + if(iOutputVidFormats.Count() == 0) + { + User::Leave(KErrNotReady); + } + if(!iOutputVidFormats.Find(aFormat)) + { + User::Leave(KErrNotSupported); + } + + iFormat = aFormat; + TDevVideoPlayPuConfig decodeConfig; + decodeConfig.iImageFormat = iFormat; + decodeConfig.iInputBufferSize = KInputBufferSize; + TPuConfigVideoPlayback puConfig(decodeConfig); + + User::LeaveIfError(iDecoderPU->Configure(puConfig)); + } + +/* + @see CMMFVideoPlayHwDevice::SetClockSource() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetClockSource(MMMFClockSource* aClock) + { + iClockSource = aClock; + } + +/* + @see CMMFVideoPlayHwDevice::SetVideoDestScreenL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetVideoDestScreenL(TBool aScreen) + { + if(aScreen) + { + // NB we expect the output format to have been set before this is called + if(!iFormat.iDataFormat) + { + User::Leave(KErrNotReady); + } + + // we support only bitmaps for DSA, not raw data + if(iFormat.iDataFormat != ERgbFbsBitmap) + { + User::Leave(KErrNotSupported); + } + } + + // ETrue = use DSA + iDSAEnabled = aScreen; + } + +/* + @see CMMFVideoPlayHwDevice::SetPostProcessTypesL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetPostProcessTypesL(TUint32 /* aPostProcCombination */) + { + // the decoder is not configurable + User::Leave(KErrNotSupported); + } + +/* + @see CMMFVideoPlayHwDevice::SetInputCropOptionsL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetInputCropOptionsL(const TRect& /* aRect */) + { + // the decoder is not configurable + User::Leave(KErrNotSupported); + } + +/* + @see CMMFVideoPlayHwDevice::SetYuvToRgbOptionsL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetYuvToRgbOptionsL(const TYuvToRgbOptions& /* aOptions */, const TYuvFormat& /* aYuvFormat */, TRgbFormat /* aRgbFormat */) + { + // the decoder is not configurable + User::Leave(KErrNotSupported); + } + +/* + @see CMMFVideoPlayHwDevice::SetYuvToRgbOptionsL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetYuvToRgbOptionsL(const TYuvToRgbOptions& /* aOptions */) + { + // the decoder is not configurable + User::Leave(KErrNotSupported); + } + +/* + @see CMMFVideoPlayHwDevice::SetRotateOptionsL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetRotateOptionsL(TRotationType /* aRotationType */) + { + // the decoder is not configurable + User::Leave(KErrNotSupported); + } + +/* + @see CMMFVideoPlayHwDevice::SetScaleOptionsL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetScaleOptionsL(const TSize& /* aTargetSize */, TBool /* aAntiAliasFiltering */) + { + // the decoder is not configurable + User::Leave(KErrNotSupported); + } + +/* + @see CMMFVideoPlayHwDevice::SetOutputCropOptionsL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetOutputCropOptionsL(const TRect& /* aRect */) + { + // the decoder is not configurable + User::Leave(KErrNotSupported); + } + +/* + @see CMMFVideoPlayHwDevice::SetPostProcSpecificOptionsL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetPostProcSpecificOptionsL(const TDesC8& /* aOptions */) + { + // the decoder is not configurable + User::Leave(KErrNotSupported); + } + +/* + @see CMMFVideoPlayHwDevice::Initialize() + */ +void CMdfVideoDecodeHwDeviceAdapter::Initialize() + { + __ASSERT_ALWAYS(iProxy, DevVideoHwDeviceDecoderPanic(0)); + + TRAPD(err, InitializeL()); + if(err == KErrNone && !iPUInitialized) + { + err = KErrNotSupported; + } + iProxy->MdvppInitializeComplete(this, err); + } + +// private method : body of Initialize() +void CMdfVideoDecodeHwDeviceAdapter::InitializeL() + { + // pre-check format + switch(iFormat.iDataFormat) + { + case 0: + User::Leave(KErrNotReady); + break; + case ERgbRawData: + case ERgbFbsBitmap: + case EYuvRawData: + break; + default: + User::Leave(KErrNotSupported); + break; + } + + // create and initialise the buffer manager + iBufferManager = CMdfVideoDecoderBufferManager::NewL(); + + iBufferManager->Init(iFormat); + iBufferManager->SetFrameSize(iFrameSize); + + DEBUG_PRINT(_L("HwDevice: Buffer Manager initialized")); + + // The actual frame rate will come from the VOL headers. + iFrameRate = KTenFPS; + + // reset the player flags + iPrimed = EFalse; + iInputBufferWaiting = EFalse; + iInputEnd = EFalse; + + // create the player engine + iPlayerEngine = CMdfVideoPlayerEngine::NewL(*this); + + RPointerArray inputPorts; + // Get ports and set observers + User::LeaveIfError(iDecoderPU->GetInputPorts(inputPorts)); + if (inputPorts.Count()==0) + { + inputPorts.Close(); + User::Leave(KErrNotFound); + } + iDecoderPUInputPort = inputPorts[0]; + iDecoderPUInputPort->MipSetObserver(*this); + inputPorts.Close(); + + RPointerArray outputPorts; + User::LeaveIfError(iDecoderPU->GetOutputPorts(outputPorts)); + if (outputPorts.Count()==0) + { + outputPorts.Close(); + User::Leave(KErrNotFound); + } + iDecoderPUOutputPort = outputPorts[0]; + iDecoderPUOutputPort->MopSetObserver(*this); + outputPorts.Close(); + + iState = EProcessingUnitLoaded; + + DEBUG_PRINT(_L("HwDevice: Decoder Processing Unit Loaded")); + + // Create the buffers that are associated with the input and output ports + iInputBuffer = &iBufferManager->CreateDataBufferL(iDecoderPUInputPort->MipBufferSize()); + iPUInputBuffer = *iInputBuffer; + User::LeaveIfError(iDecoderPUInputPort->MipUseBuffer(*iPUInputBuffer)); + + CVideoFrameBuffer& frameBuffer = iBufferManager->CreateFrameBufferL(TMMFDisplayModeUtils::DisplayMode(iFormat.iRgbFormat)); + User::LeaveIfError(iDecoderPUOutputPort->MopUseBuffer(frameBuffer)); + + // VD: should not move the set up of the state after sending the Initialize() calls??? + iState = EProcessingUnitInitializing; + + // async call, that calls back to InitializeComplete() + iDecoderPU->Initialize(); + + DEBUG_PRINT(_L("HwDevice: Initialized OK")); + } + +/* + @see CMMFVideoPlayHwDevice::StartDirectScreenAccessL() + */ +void CMdfVideoDecodeHwDeviceAdapter::StartDirectScreenAccessL(const TRect& aVideoRect, CFbsScreenDevice& aScreenDevice, const TRegion& aClipRegion) + { + // ensure SetVideoDestScreenL() has been called + if(!iDSAEnabled) + { + User::Leave(KErrNotReady); + } + + DEBUG_PRINT(_L("HwDevice: Starting DSA")); + + iDSAStarted = ETrue; + + // the CDirectScreenAccess must be created by the client app. + // the CFbsScreenDevice (only) is passed across... + // we need to blit the bitmap into it, i.e. we need to create our own GC + if(!iScreenDevice) + { + User::LeaveIfError(aScreenDevice.CreateContext(iScreenDeviceGc)); + iScreenDevice = &aScreenDevice; + iScreenDeviceRect = aVideoRect; + iScreenDeviceGc->SetClippingRegion(aClipRegion); + } + } + +/* + @see CMMFVideoPlayHwDevice::SetScreenClipRegion() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetScreenClipRegion(const TRegion& aRegion) + { + __ASSERT_ALWAYS(iScreenDeviceGc, DevVideoHwDeviceDecoderPanic(0)); + + iScreenDeviceGc->SetClippingRegion(aRegion); + } + +/* + @see CMMFVideoPlayHwDevice::SetPauseOnClipFail() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetPauseOnClipFail(TBool /* aPause */) + { + // not implemented - will pause by default + } + +/* + @see CMMFVideoPlayHwDevice::AbortDirectScreenAccess() + */ +void CMdfVideoDecodeHwDeviceAdapter::AbortDirectScreenAccess() + { + DEBUG_PRINT(_L("HwDevice: Stopping DSA")); + iDSAStarted = EFalse; + } + +/* + @see CMMFVideoPlayHwDevice::IsPlaying() + */ +TBool CMdfVideoDecodeHwDeviceAdapter::IsPlaying() + { + return (iState == EProcessingUnitExecuting ? ETrue : EFalse); + } + +/* + @see CMMFVideoPlayHwDevice::Redraw() + */ +void CMdfVideoDecodeHwDeviceAdapter::Redraw() + { + if(iDSAStarted) + { + DisplayLastFrameDirect(); + } + } + +/* + @see CMMFVideoPlayHwDevice::Start() + */ +void CMdfVideoDecodeHwDeviceAdapter::Start() + { + __ASSERT_ALWAYS(iPlayerEngine, DevVideoHwDeviceDecoderPanic(0)); + __ASSERT_ALWAYS(iDecoderPU, DevVideoHwDeviceDecoderPanic(0)); + + if(iState != EProcessingUnitExecuting) + { + CVideoFrameBuffer* frameBuffer = NULL; + TRAPD(err, frameBuffer = &iBufferManager->GetEmptyFrameBufferL(ETrue)); + if (err != KErrNone) + { + iProxy->MdvppFatalError(this, err); + return; + } + + iDecoderPUOutputPort->MopReadData(*frameBuffer); + + iDecoderPU->Execute(); + TProcessingUnitState puState = iDecoderPU->State(); + if(puState == EProcessingUnitInvalid) + { + return; + } + iState = EProcessingUnitExecuting; + + // if we are using raw decoding, then play as fast as we can, + // otherwise use the actual frame rate + TInt playerFrameRate; + if(iSynchronize) + { + playerFrameRate = TInt(iFrameRate); + } + else + { + playerFrameRate = CMdfVideoPlayerEngine::KUnsynchronized; + } + TRAP(err, iPlayerEngine->StartL(playerFrameRate)); + if(err != KErrNone) + { + // the player failed to start. this is a fatal error + iProxy->MdvppFatalError(this, err); + } + else + { + iProxy->MdvppNewBuffers(); + } + } + } + +/* + @see CMMFVideoPlayHwDevice::Stop() + */ +void CMdfVideoDecodeHwDeviceAdapter::Stop() + { + if(iState == EProcessingUnitExecuting) + { + iPlayerEngine->Stop(); + iDecoderPU->Stop(); + iState = EProcessingUnitIdle; + } + } + +/* + @see CMMFVideoPlayHwDevice::Pause() + */ +void CMdfVideoDecodeHwDeviceAdapter::Pause() + { + Stop(); + } + +/* + @see CMMFVideoPlayHwDevice::Resume() + */ +void CMdfVideoDecodeHwDeviceAdapter::Resume() + { + Start(); + } + +/* + @see CMMFVideoPlayHwDevice::SetPosition() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetPosition(const TTimeIntervalMicroSeconds& aPlaybackPosition) + { + TPuConfigTimestamp timeStamp(aPlaybackPosition); + // we have no way report a failure here, and it is not a fatal error so any error is ignored + iDecoderPU->Configure(timeStamp); + } +/* + @see CMMFVideoPlayHwDevice::FreezePicture() + */ +void CMdfVideoDecodeHwDeviceAdapter::FreezePicture(const TTimeIntervalMicroSeconds& /* aTimestamp */) + { + // not supported; we have no presentation timestamps + // however should not cause a fatal error + } + +/* + @see CMMFVideoPlayHwDevice::ReleaseFreeze() + */ +void CMdfVideoDecodeHwDeviceAdapter::ReleaseFreeze(const TTimeIntervalMicroSeconds& /* aTimestamp */) + { + // not supported; we have no presentation timestamps + // however should not cause a fatal error + } + +/* + @see CMMFVideoPlayHwDevice::PlaybackPosition() + */ +TTimeIntervalMicroSeconds CMdfVideoDecodeHwDeviceAdapter::PlaybackPosition() + { + if(iFrameRate == 0.0) + { + return 0; + } + // this is the total number of pictures displayed or discarded + // NB it is NOT equivalent to the number of pictures decoded, as the + // player may be running a few frames behind the decoder + return ((iPictureCounters.iPicturesDisplayed + iPictureCounters.iPicturesSkipped) * (KOneSecond / (TInt)iFrameRate)); + } + +/* + @see CMMFVideoPlayHwDevice::PictureBufferBytes() + */ +TUint CMdfVideoDecodeHwDeviceAdapter::PictureBufferBytes() + { + __ASSERT_ALWAYS(iBufferManager, DevVideoHwDeviceDecoderPanic(0)); + + return (iBufferManager->FrameBufferSize() * iBufferManager->MaxFrameBuffers()); + } + +/* + @see CMMFVideoPlayHwDevice::GetPictureCounters() + */ +void CMdfVideoDecodeHwDeviceAdapter::GetPictureCounters(CMMFDevVideoPlay::TPictureCounters& aCounters) + { + aCounters = iPictureCounters; + } + +/* + @see CMMFVideoPlayHwDevice::SetComplexityLevel() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetComplexityLevel(TUint /* aLevel */) + { + // separate complexity levels are not available; ignored + } + +/* + @see CMMFVideoPlayHwDevice::NumComplexityLevels() + */ +TUint CMdfVideoDecodeHwDeviceAdapter::NumComplexityLevels() + { + // separate complexity levels are not available; return 1 + return 1; + } + +/* + @see CMMFVideoPlayHwDevice::GetComplexityLevelInfo() + */ +void CMdfVideoDecodeHwDeviceAdapter::GetComplexityLevelInfo(TUint aLevel, CMMFDevVideoPlay::TComplexityLevelInfo& aInfo) + { + // ignore call if aLevel is not 0 + if(aLevel == 0) + { + aInfo = iComplexityLevelInfo; + } + } + +/* + @see CMMFVideoPlayHwDevice::ReturnPicture() + */ +void CMdfVideoDecodeHwDeviceAdapter::ReturnPicture(TVideoPicture* aPicture) + { + __ASSERT_ALWAYS(iBufferManager, DevVideoHwDeviceDecoderPanic(0)); + + // return the frame buffer that has been emptied + TRAPD(err, iBufferManager->ReturnFrameBufferL(*aPicture, CVideoFrameBuffer::EEmptied)); + if (err == KErrNone) + { + if (!iLastFrameBufferReceived) + { + + // request the next empty frame buffer + CVideoFrameBuffer* frameBuffer = NULL; + TRAP(err, frameBuffer = &iBufferManager->GetEmptyFrameBufferL(ETrue)); + if (err == KErrNone) + { + CMMFBuffer* buffer = *frameBuffer; + iDecoderPUOutputPort->MopReadData(*buffer); + } + } + // DoPostPictureNotify() will handle MdvppStreamEnd() + } + else + { + iProxy->MdvppFatalError(this, err); + } + ASSERT(err == KErrNone); + DoPostPictureNotify(); + } + +/* + @see CMMFVideoPlayHwDevice::GetSnapshotL() + */ +TBool CMdfVideoDecodeHwDeviceAdapter::GetSnapshotL(TPictureData& /*aPictureData*/, const TUncompressedVideoFormat& /*aFormat*/) + { + // not supported - no presentation timestamps + User::Leave(KErrNotSupported); + return EFalse; + } + +/* + @see CMMFVideoPlayHwDevice::GetTimedSnapshotL() + */ +void CMdfVideoDecodeHwDeviceAdapter::GetTimedSnapshotL(TPictureData* /*aPictureData*/, const TUncompressedVideoFormat& /*aFormat*/, const TTimeIntervalMicroSeconds& /*aPresentationTimestamp*/) + { + // this method should be called on the post processor not on the decoder + // ending up here is a programming error and hence a PANIC condition + DevVideoHwDeviceDecoderPanic(0); + } + +/* + @see CMMFVideoPlayHwDevice::GetTimedSnapshotL() + */ +void CMdfVideoDecodeHwDeviceAdapter::GetTimedSnapshotL(TPictureData* /*aPictureData*/, const TUncompressedVideoFormat& /*aFormat*/, const TPictureId& /*aPictureId*/) + { + // this method should be called on the post processor not on the decoder + // ending up here is a programming error and hence a PANIC condition + DevVideoHwDeviceDecoderPanic(0); + } + +/* + @see CMMFVideoPlayHwDevice::CancelTimedSnapshot() + */ +void CMdfVideoDecodeHwDeviceAdapter::CancelTimedSnapshot() + { + // this method should be called on the post processor not on the decoder + // ending up here is a programming error and hence a PANIC condition + DevVideoHwDeviceDecoderPanic(0); + } + +/* + @see CMMFVideoPlayHwDevice::GetSupportedSnapshotFormatsL() + */ +void CMdfVideoDecodeHwDeviceAdapter::GetSupportedSnapshotFormatsL(RArray& /*aFormats*/) + { + // this method should be called on the post processor not on the decoder + // ending up here is a programming error and hence a PANIC condition + DevVideoHwDeviceDecoderPanic(0); + } + +/* + @see CMMFVideoPlayHwDevice::InputEnd() + */ +void CMdfVideoDecodeHwDeviceAdapter::InputEnd() + { + __ASSERT_ALWAYS(iBufferManager, DevVideoHwDeviceDecoderPanic(0)); + + DEBUG_PRINT(_L("HwDevice: Input end")); + + iInputEnd = ETrue; + + // if there isn't an outstanding write to the PU, write + // an empty buffer + if(!iWriteRequestOutstanding) + { + SendLastBuffer(); + } + } + +/* + @see CMMFVideoDecodeHwDevice::VideoDecoderInfoLC() + */ +CVideoDecoderInfo* CMdfVideoDecodeHwDeviceAdapter::VideoDecoderInfoLC() + { + // this is a complicated structure, ensure all fields are + // filled with some valid value + + //if PU is not loaded panic + if(iPuData == NULL) + { + DevVideoHwDeviceDecoderPanic(KErrNotReady); + } + // supported formats array + iInputVidFormats.Reset(); + CCompressedVideoFormat* vidCV = NULL; + vidCV = CCompressedVideoFormat::NewL(iPuData->InputDataType() , KNullDesC8); + CleanupStack::PushL(vidCV); + iInputVidFormats.AppendL(vidCV); + CleanupStack::Pop(vidCV); // CCompressedVideo object is destroyed in destructor + + + // construct the video decoder info object + CVideoDecoderInfo* vInfo = CVideoDecoderInfo::NewL( + iPuUid, + *iManufacturer, + KNullDesC, + TVersion(KVideoDecoderInfoVersionMaj, KVideoDecoderInfoVersionMin, KVideoDecoderInfoVersionBuild), + iInputVidFormats.Array(), + EFalse, // not accelerated + ETrue, // supports direct screen access + iMaxPictureSize, + KMaxTUint32, // max bitrate supported + iPuData->MaxPictureRates().Array(), + EFalse, // picture loss not supported, + EFalse, // slice loss not supported, + KVideoDecoderInfoCSInfo, + KVideoDecoderInfoISInfo ); + + CleanupStack::PushL(vInfo); + return vInfo; + } + + +/* + @see CMMFVideoDecodeHwDevice::GetHeaderInformationL() + */ + +TVideoPictureHeader* CMdfVideoDecodeHwDeviceAdapter::GetHeaderInformationL(TVideoDataUnitType aDataUnitType, TVideoDataUnitEncapsulation aEncapsulation, TVideoInputBuffer* aDataUnit) + { + // NB this may be called EITHER before OR after the decoder is initialized. + // ensure at least that SetOutputFormatL() has been called before this, + // as the decoder requires it to be able to initialize. + + __ASSERT_ALWAYS(iFormat.iDataFormat, DevVideoHwDeviceDecoderPanic(0)); + + TDevVideoHeaderPuConfig header; + header.iDataUnitType = aDataUnitType; + header.iDataUnitEncapsulation = aEncapsulation; + header.iHeaderData.Set(aDataUnit->iData.Ptr(),aDataUnit->iData.Size()); + + TPuConfigVideoHeader headerConfig(header); + + // Configure the decoder with the Header Information + User::LeaveIfError(iDecoderPU->Configure(headerConfig)); + + // retrieve the picture information from the config structure + + TPuConfigVideoPictureHeader pict; + User::LeaveIfError(iDecoderPU->GetConfig(pict)); + + delete iPictureHeader; + iPictureHeader = NULL; + // Create a new header from the returned data + iPictureHeader = new (ELeave)TVideoPictureHeader( + *TPuConfigVideoPictureHeader::GetStructure(pict)); + iFrameSize = iPictureHeader->iSizeInMemory; + return iPictureHeader; + + } + +/* + @see CMMFVideoDecodeHwDevice::ConfigureDecoderL() + */ +void CMdfVideoDecodeHwDeviceAdapter::ConfigureDecoderL(const TVideoPictureHeader& /* aVideoPictureHeader */) + { + // there is nothing configurable + User::Leave(KErrNotSupported); + } + +/* + @see CMMFVideoDecodeHwDevice::ReturnHeader() + */ +void CMdfVideoDecodeHwDeviceAdapter::ReturnHeader(TVideoPictureHeader* aHeader) + { + if(aHeader == iPictureHeader) // only free our created header + { + delete iPictureHeader; + iPictureHeader = NULL; + } + } + +/* + @see CMMFVideoDecodeHwDevice::SetInputFormatL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetInputFormatL(const CCompressedVideoFormat& aFormat, TVideoDataUnitType aDataUnitType, TVideoDataUnitEncapsulation aEncapsulation, TBool aDataInOrder) + { + // EDuCodedPicture, EDuElementaryStream, aDataInOrder == ETrue + if(aFormat.MimeType() != iPuData->InputDataType()) + { + User::Leave(KErrNotSupported); + } + if(aDataUnitType != EDuCodedPicture) + { + User::Leave(KErrNotSupported); + } + if(aEncapsulation != EDuElementaryStream) + { + User::Leave(KErrNotSupported); + } + if(!aDataInOrder) + { + User::Leave(KErrNotSupported); + } + } + +/* + @see CMMFVideoDecodeHwDevice::SynchronizeDecoding() + */ +void CMdfVideoDecodeHwDeviceAdapter::SynchronizeDecoding(TBool aSynchronize) + { + iSynchronize = aSynchronize; + } + +/* + @see CMMFVideoDecodeHwDevice::SetBufferOptionsL() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetBufferOptionsL(const CMMFDevVideoPlay::TBufferOptions& aOptions) + { + // check values are within the constraints of this device + if(aOptions.iPreDecoderBufferPeriod != 0) + { + User::Leave(KErrNotSupported); + } + if(aOptions.iMaxPostDecodeBufferSize != 0) + { + User::Leave(KErrNotSupported); + } + if(aOptions.iPreDecoderBufferPeriod != 0) + { + User::Leave(KErrNotSupported); + } + if(aOptions.iPostDecoderBufferPeriod != 0) + { + User::Leave(KErrNotSupported); + } + if(aOptions.iMaxInputBufferSize > KVideoDecoderMaxDataBufferSize) + { + User::Leave(KErrNotSupported); + } + if(aOptions.iMinNumInputBuffers > 1) + { + User::Leave(KErrNotSupported); + } + // input is OK; write it + iBufferOptions = aOptions; + } + +/* + @see CMMFVideoDecodeHwDevice::GetBufferOptions() + */ +void CMdfVideoDecodeHwDeviceAdapter::GetBufferOptions(CMMFDevVideoPlay::TBufferOptions& aOptions) + { + aOptions = iBufferOptions; + } + +/* + @see CMMFVideoDecodeHwDevice::SetHrdVbvSpec() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetHrdVbvSpec(THrdVbvSpecification /* aHrdVbvSpec */, const TDesC8& /* aHrdVbvParams */) + { + // the decoder is not configurable + // however this should not cause a fatal error + } + +/* + @see CMMFVideoDecodeHwDevice::SetOutputDevice() + */ +void CMdfVideoDecodeHwDeviceAdapter::SetOutputDevice(CMMFVideoPostProcHwDevice* aDevice) + { + // we allow output to be sent to a post-processor, + // even though this plugin doesn not itself provide one + iPostProcOutputDevice = aDevice; + } + +/* + @see CMMFVideoDecodeHwDevice::DecodingPosition() + */ +TTimeIntervalMicroSeconds CMdfVideoDecodeHwDeviceAdapter::DecodingPosition() + { + if(iFrameRate == 0.0) + { + return 0; + } + // this is the total number of pictures decoded + return (iPictureCounters.iPicturesDecoded * (KOneSecond / (TInt)iFrameRate)); + } + +/* + @see CMMFVideoDecodeHwDevice::PreDecoderBufferBytes() + */ +TUint CMdfVideoDecodeHwDeviceAdapter::PreDecoderBufferBytes() + { + return 0; + } + +/* + @see CMMFVideoDecodeHwDevice::GetBitstreamCounters() + */ +void CMdfVideoDecodeHwDeviceAdapter::GetBitstreamCounters(CMMFDevVideoPlay::TBitstreamCounters& aCounters) + { + aCounters = iBitstreamCounters; + } + +/* + @see CMMFVideoDecodeHwDevice::NumFreeBuffers() + */ +TUint CMdfVideoDecodeHwDeviceAdapter::NumFreeBuffers() + { + __ASSERT_ALWAYS(iBufferManager, DevVideoHwDeviceDecoderPanic(0)); + + if(!FrameBufferAvailable()) + { + // if there are too many output buffers waiting, we refuse an input buffer + // until some output buffers have been processed. + return 0; + } + else + { + return (iBufferManager->DataBuffersAvailable()); + } + } + +/* + @see CMMFVideoDecodeHwDevice::GetBufferL() + + This will return a buffer of the requested size, within min/max constraints + */ +TVideoInputBuffer* CMdfVideoDecodeHwDeviceAdapter::GetBufferL(TUint /* aBufferSize */) + { + __ASSERT_ALWAYS(iBufferManager, DevVideoHwDeviceDecoderPanic(0)); + + TVideoInputBuffer& buf = iBufferManager->GetDataBufferL(); + return &buf; + } + +/* + @see CMMFVideoDecodeHwDevice::WriteCodedDataL() + */ +void CMdfVideoDecodeHwDeviceAdapter::WriteCodedDataL(TVideoInputBuffer* aInputBuffer) + { + // Leave on null input buffer + if(!aInputBuffer) + { + User::Leave(KErrArgument); + } + + // increment received buffer count + iBitstreamCounters.iTotalPackets++; + + CMMFDataBuffer* dataBuffer = static_cast(iPUInputBuffer); + dataBuffer->Data().SetLength(aInputBuffer->iData.Length()); + dataBuffer->SetPosition(0); + iDecoderPUInputPort->MipWriteData(*iPUInputBuffer); + iWriteRequestOutstanding = ETrue; + } + +/* + @see CMMFVideoPlayHwDevice::CommitL() + */ +void CMdfVideoDecodeHwDeviceAdapter::CommitL() + { + // the decoder is not configurable + User::Leave(KErrNotSupported); + } + +/* + @see CMMFVideoPlayHwDevice::Revert() + */ +void CMdfVideoDecodeHwDeviceAdapter::Revert() + { + // the decoder is not configurable + // however this should not cause a fatal error + } + +void CMdfVideoDecodeHwDeviceAdapter::SetProxy(MMMFDevVideoPlayProxy& aProxy) + { + ASSERT(!iProxy); + iProxy = &aProxy; + } + + +/* + @see MMdfDecoderHwDeviceObserver::FrameBufferAvailable() + */ +TBool CMdfVideoDecodeHwDeviceAdapter::FrameBufferAvailable() const + { + __ASSERT_ALWAYS(iBufferManager, DevVideoHwDeviceDecoderPanic(0)); + + return (iBufferManager->EmptyFrameBuffersAvailable() > 0); + } + +/* + @see MMdfVideoPlayerHwDeviceObserver::Time() + */ +TUint CMdfVideoDecodeHwDeviceAdapter::Time() const + { + + if(iClockSource) + { + return iClockSource->Time().Int64(); + } + else + { + // system clock without HAL + TInt64 tt64; + TTime ttime; + ttime.HomeTime(); + tt64 = ttime.Int64(); + return (tt64 - iSystemClock); + } + } + +/* + @see MMdfVideoPlayerHwDeviceObserver::DisplayFrame() + */ +void CMdfVideoDecodeHwDeviceAdapter::DisplayFrame() + { + __ASSERT_ALWAYS(iBufferManager, DevVideoHwDeviceDecoderPanic(0)); + + CVideoFrameBuffer* frameBuffer = NULL; + TRAPD(err, frameBuffer = &iBufferManager->GetFilledFrameBufferL(EFalse)); + if(err != KErrNone) + { + // the buffer manager has failed + DEBUG_PRINT(_L("HwDevice: Buffer Manager failed")); + iProxy->MdvppFatalError(this, err); + } + else + { + // is this the last buffer? + iLastFrameBufferReceived = frameBuffer->LastBuffer(); + + TVideoPicture& thePicture = *frameBuffer; + + // increment picture counter + CMMFBuffer& theBuffer = *frameBuffer; + if(theBuffer.BufferSize()) + { + iPictureCounters.iPicturesDisplayed++; + } + + iDisplayPictureAvailable = EFalse; + + // send it to post-processor output, DSA, or the client + if(iPostProcOutputDevice) + { + TRAP(err, iPostProcOutputDevice->WritePictureL(&thePicture)); + } + else if(iDSAStarted) + { + DisplayFrameDirect(&thePicture); + TRAP(err, iBufferManager->ReturnFrameBufferL(thePicture, CVideoFrameBuffer::EEmptied)); + + if (!iLastFrameBufferReceived) + { + CVideoFrameBuffer* frameBuffer = NULL; + TRAP(err, frameBuffer = &iBufferManager->GetEmptyFrameBufferL(ETrue)); + if (err == KErrNone) + { + iDecoderPUOutputPort->MopReadData(*frameBuffer); + } + else + { + iProxy->MdvppFatalError(this, err); + return; + } + } + // DoPostPictureNotify() will handle MdvppStreamEnd() + // NB we need to notify the client here as there will be no callback + DoPostPictureNotify(); + } + else + { + iProxy->MdvppNewPicture(&thePicture); + } + } + } + +/* + @see MMdfVideoPlayerHwDeviceObserver::DiscardFrame() + */ +void CMdfVideoDecodeHwDeviceAdapter::DiscardFrame() + { + __ASSERT_ALWAYS(iBufferManager, DevVideoHwDeviceDecoderPanic(0)); + + CVideoFrameBuffer* frameBuffer = NULL; + TVideoPicture* thePicture = NULL; + TRAPD(err, frameBuffer = &iBufferManager->GetFilledFrameBufferL(EFalse)); + if(err != KErrNone) + { + // the buffer manager has failed + DEBUG_PRINT(_L("HwDevice: Buffer Manager failed")); + iProxy->MdvppFatalError(this, err); + } + else + { + thePicture = *frameBuffer; + + // increment picture counter + CMMFBuffer& theBuffer = *frameBuffer; + if(theBuffer.BufferSize()) + { + iPictureCounters.iPicturesSkipped++; + } + + iDisplayPictureAvailable = EFalse; + + // this should never leave, as thePicture has been given to us by + // iBufferManager to start with. + TRAP(err, iBufferManager->ReturnFrameBufferL(*thePicture, CVideoFrameBuffer::EEmptied)); + if (err != KErrNone) + { + DEBUG_PRINT(_L("HwDevice: ReturnFrameBufferL failed")); + iProxy->MdvppFatalError(this, err); + } + + TRAP(err, frameBuffer = &iBufferManager->GetEmptyFrameBufferL(ETrue)); + if (err == KErrNone) + { + iDecoderPUOutputPort->MopReadData(*frameBuffer); + } + + // NB we need to notify the client here as there will be no callback + DoPostPictureNotify(); + } + } + +/* + @see MMdfVideoPlayerHwDeviceObserver::FrameAvailable() + */ +TBool CMdfVideoDecodeHwDeviceAdapter::FrameAvailable() const + { + return iDisplayPictureAvailable; + } + +/* + @see MMdfInputPortObserver::MipoWriteDataComplete() + */ +void CMdfVideoDecodeHwDeviceAdapter::MipoWriteDataComplete(const MMdfInputPort* aInputPort, + CMMFBuffer* /* aBuffer */, TInt aErrorCode) + { + iWriteRequestOutstanding = EFalse; + __ASSERT_ALWAYS(aInputPort == iDecoderPUInputPort, DevVideoHwDeviceDecoderPanic(0)); + if (aErrorCode != KErrNone) + { + iProxy->MdvppFatalError(this, aErrorCode); + return; + } + // Return the data buffer, the position tells us how much data + // was used + if (!iInputEnd) + { + TRAPD(err, iBufferManager->ReturnDataBufferL(*iInputBuffer)); + if(err == KErrNone) + { + iProxy->MdvppNewBuffers(); + } + else + { + iProxy->MdvppFatalError(this, err); + } + } + else + { + // Send an empty buffer to the decoder to signal the + // end of the stream + SendLastBuffer(); + } + } + +/* + @see MMdfInputPortObserver::MipoStopComplete() + */ +void CMdfVideoDecodeHwDeviceAdapter::MipoDisconnectTunnelComplete(const MMdfInputPort* /* aInputPort */, + TInt /* aErrorCode */) + { + } + +/* + @see MMdfInputPortObserver::MipoRestartComplete() + */ +void CMdfVideoDecodeHwDeviceAdapter::MipoRestartTunnelComplete(const MMdfInputPort* /* aInputPort */, + TInt /* aErrorCode */) + { + } + +/* + @see MMdfOutputPortObserver::MopoReadDataComplete() + */ +void CMdfVideoDecodeHwDeviceAdapter::MopoReadDataComplete(const MMdfOutputPort* aOutputPort, + CMMFBuffer* aBuffer, TInt aErrorCode) + { + if(aErrorCode != KErrNone) + { + iProxy->MdvppFatalError(this, aErrorCode); + return; + } + + if(aOutputPort != iDecoderPUOutputPort) + { + iProxy->MdvppFatalError(this, KErrArgument); + return; + } + + // increment iPicturesDecoded + if(aBuffer->BufferSize()) + { + iPictureCounters.iPicturesDecoded++; + } + + iDisplayPictureAvailable = ETrue; + + TRAPD(err, iBufferManager->ReturnFrameBufferL(aBuffer, CVideoFrameBuffer::EFilled, aBuffer->LastBuffer())); + if(err != KErrNone) + { + iProxy->MdvppFatalError(this, err); + } + } + +/* + @see MMdfOutputPortObserver::MopoStopComplete() + */ +void CMdfVideoDecodeHwDeviceAdapter::MopoDisconnectTunnelComplete(const MMdfOutputPort* /* aOutputPort */, + TInt /* aErrorCode */) + { + } + +/* + @see MMdfOutputPortObserver::MopoRestartComplete() + */ +void CMdfVideoDecodeHwDeviceAdapter::MopoRestartTunnelComplete(const MMdfOutputPort* /* aOutputPort */, + TInt /* aErrorCode */) + { + } + +/* + @see MMdfProcessingUnitObserver::InitializeComplete() + */ +void CMdfVideoDecodeHwDeviceAdapter::InitializeComplete(const CMdfProcessingUnit* aPu, TInt aErrorCode) + { + __ASSERT_ALWAYS(aPu == iDecoderPU, DevVideoHwDeviceDecoderPanic(0)); + + if(aErrorCode != KErrNone) + { + iProxy->MdvppFatalError(this, aErrorCode); + return; + } + + iPUInitialized = ETrue; + } + +/* + @see MMdfProcessingUnitObserver::ExecuteComplete() + */ +void CMdfVideoDecodeHwDeviceAdapter::ExecuteComplete(const CMdfProcessingUnit* aPu, TInt aErrorCode) + { + __ASSERT_ALWAYS(aPu == iDecoderPU, DevVideoHwDeviceDecoderPanic(0)); + + if(aErrorCode != KErrNone) + { + iProxy->MdvppFatalError(this, aErrorCode); + return; + } + + if (iState == EProcessingUnitExecuting) + { + DEBUG_PRINT(_L("HwDevice: 3() - Stream end")); + iProxy->MdvppStreamEnd(); + iState = EProcessingUnitIdle; + } + } + +// private method - DoPostPictureNotify +void CMdfVideoDecodeHwDeviceAdapter::DoPostPictureNotify() + { + __ASSERT_ALWAYS(iBufferManager, DevVideoHwDeviceDecoderPanic(0)); + + DEBUG_PRINT(_L("HwDevice: PostPictureNotify")); + // notify the client that an input buffer is available if we weren't able to + // do it before + if(iInputBufferWaiting && iBufferManager->DataBuffersAvailable()) + { + iInputBufferWaiting = EFalse; + iProxy->MdvppNewBuffers(); + } + + // at this point, if there are no frames left, the input buffer is free + // and InputEnd() has been called, then we have finished. + if(iInputEnd && !iBufferManager->FilledFrameBuffersAvailable() && iBufferManager->DataBuffersAvailable()) + { + iLastFrameBufferReceived = ETrue; + } + + // NB iLastFrameBufferReceived may have been set beforehand + if(iLastFrameBufferReceived) + { + DEBUG_PRINT(_L("HwDevice: Stream end")); + iProxy->MdvppStreamEnd(); + } + } + +// private method - display the frame using direct screen access +void CMdfVideoDecodeHwDeviceAdapter::DisplayFrameDirect(TVideoPicture* aPicture) + { + __ASSERT_ALWAYS(iScreenDevice, DevVideoHwDeviceDecoderPanic(0)); + + DEBUG_PRINT(_L("HwDevice: Displaying frame using DSA")); + // draw into our GC + // NB this will only work if the picture is a CFbsBitmap + CFbsBitmap* theBitmap = aPicture->iData.iRgbBitmap; + iScreenDeviceGc->DrawBitmap(iScreenDeviceRect, theBitmap); + iScreenDevice->Update(); + } + +// private method - display the last frame using direct screen access +void CMdfVideoDecodeHwDeviceAdapter::DisplayLastFrameDirect() + { + __ASSERT_ALWAYS(iScreenDevice, DevVideoHwDeviceDecoderPanic(0)); + + DEBUG_PRINT(_L("HwDevice: Redrawing last frame using DSA")); + // redraw + // NB this will only work if the picture is a CFbsBitmap + const TPictureData* lastFrame = NULL; + TRAPD(err, lastFrame = &iBufferManager->LastPictureL()); + if(!err) + { + CFbsBitmap* theBitmap = lastFrame->iRgbBitmap; + iScreenDeviceGc->DrawBitmap(iScreenDeviceRect, theBitmap); + iScreenDevice->Update(); + } + } + +void CMdfVideoDecodeHwDeviceAdapter::LoadProcessingUnitL(const CImplementationInformation& aImplInfo) + { + __ASSERT_ALWAYS(iPuLoader, DevVideoHwDeviceDecoderPanic(0)); + iPuUid = aImplInfo.ImplementationUid(); + iDecoderPU = iPuLoader->LoadProcessingUnitL(*this, iPuUid); + // store the opaque data associated with this PU so we can extract information about + // the PU later + iPuData = CCodecApiVideoOpaqueData::NewL(aImplInfo.OpaqueData()); + iManufacturer = HBufC::NewL(iPuData->Manufacturer().Length()); + iManufacturer->Des().Copy(iPuData->Manufacturer()); + iMaxPictureSize = iPuData->MaxPictureSize(); + } + +void CMdfVideoDecodeHwDeviceAdapter::SendLastBuffer() + { + __ASSERT_ALWAYS(iPUInputBuffer, DevVideoHwDeviceDecoderPanic(0)); + __ASSERT_ALWAYS(iDecoderPUInputPort, DevVideoHwDeviceDecoderPanic(0)); + // Send an empty buffer to the decoder to signal the + // end of the stream + iPUInputBuffer->SetLastBuffer(ETrue); + CMMFDataBuffer* dataBuffer = static_cast(iPUInputBuffer); + dataBuffer->Data().SetLength(0); + dataBuffer->SetPosition(0); + iDecoderPUInputPort->MipWriteData(*iPUInputBuffer); + }