diff -r f9bb0fca356a -r 0fd27995241b javauis/mmapi_qt/baseline/src.nga/cmmavideoplayer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/mmapi_qt/baseline/src.nga/cmmavideoplayer.cpp Tue May 11 16:07:20 2010 +0300 @@ -0,0 +1,525 @@ +/* +* Copyright (c) 2002-2007 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: This class is used for playing video. +* +*/ + +// INCLUDE FILES +#include +#include + +#include "cmmavideoplayer.h" +#include "mmmadisplay.h" +#include "mmafunctionserver.h" +#include "cmmasurfacewindow.h" + +// CONSTANTS +_LIT(KVideoControlName, "VideoControl"); + +CMMAVideoPlayer* CMMAVideoPlayer::NewLC( + CMMAMMFResolver* aResolver) +{ + CMMAVideoPlayer* self = + new(ELeave) CMMAVideoPlayer(aResolver); + CleanupStack::PushL(self); + self->ConstructL(); + return self; +} + +CMMAVideoPlayer::~CMMAVideoPlayer() + { + LOG(EJavaMMAPI,EInfo, "MMA::CMMAVideoPlayer::~CMMAVideoPlayer" ); + + // Window is not able to send any + // callback requests to UI from now. + if (iSurfaceWindow) + { + iSurfaceWindow->SetDisplay(NULL); + } + + if ( iDisplay && iDisplay->HasContainer() ) + { + // Window will delete itself + // after all pending events are processed + // (lazy delete) +// iDisplay->UIGetCallback( + // *iSurfaceWindow, CMMASurfaceWindow::EDestroyWindow ); + iDisplay->GetCallbackInUiThread((TInt)CMMASurfaceWindow::EDestroyWindow ); + } + else + { + delete iSurfaceWindow; + } + + if (iDisplay) + { + TRAPD(err, iDisplay->SetWindowL(NULL)); + if (err != KErrNone) + { + __ASSERT_DEBUG(EFalse, User::Invariant()); + } + } + + delete iEmptySnapshotImage; + delete iActiveSchedulerWait; +} + +CMMAVideoPlayer::CMMAVideoPlayer( + CMMAMMFResolver* aResolver): + CMMAAudioPlayer(aResolver), + iVideoControllerCustomCommands(iController), + iVideoPlayControllerCustomCommands(iController), + iVideoPlaySurfaceSupportCustomCommands(iController) +{ + iMMASurface.iPrevSurfaceAvailable = EFalse; +} + +void CMMAVideoPlayer::ConstructL() +{ + CMMAAudioPlayer::ConstructL(); + iActiveSchedulerWait = new(ELeave)CActiveSchedulerWait; +} + +EXPORT_C void CMMAVideoPlayer::SetPlayerListenerObjectL(jobject aListenerObject, + JNIEnv* aJni, + MMMAEventPoster* aEventPoster) +{ + CMMAPlayer::SetPlayerListenerObjectL(aListenerObject, + aJni, + aEventPoster); + + // this method must be called only ones + __ASSERT_DEBUG(!iSurfaceWindow, User::Invariant()); + + // create window for videoplayer + // event poster is always MMAFunctionServer type. + + iSurfaceWindow = CMMASurfaceWindow::NewL( + static_cast< MMAFunctionServer* >(iEventPoster), + this); +} + +EXPORT_C void CMMAVideoPlayer::SetDisplayL(MMMADisplay* aDisplay) +{ + // now it is ready to draw + iDisplay = aDisplay; + iDisplay->SetWindowL( iSurfaceWindow ); + iSurfaceWindow->SetDisplay( aDisplay ); + iDisplay->SetUIPlayer(this); + + +/* + // if state < prefeteched then we dont know actual source size yet + // and it will be set after prefetch + if ( iState >= EPrefetched ) + { + SourceSizeChanged(); + } + */ + } +void CMMAVideoPlayer::RealizeL() +{ + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::RealizeL" ); + // DataSource must have at least 1 stream or + // we must have file to play + if ((iSourceStreams.Count() == 0) && !iFileName) + { + User::Leave(KErrNotEnoughStreams); + } + + // If file locator is used, then file is prefetched + // in realized state so that FramePositioningControl + // can acquire frame count in REALIZED state + if (iFileName) + { + PrefetchFileL(); + if (!iActiveSchedulerWait->IsStarted()) + { + iActiveSchedulerWait->Start(); + } + // If the player has not changed state during wait, + // Then there is an error condition. + if (iState != ERealized) + { + User::Leave(KErrNotSupported); + } + } + else + { + CMMAPlayer::RealizeL(); + } +} + +void CMMAVideoPlayer::PrefetchL() +{ + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::PrefetchL" ); + if (iFileName) + { + // File has already been prefetched when realizing + + // If initDisplayMode was called before prefetch, + // then the display must notified about source size. + if (iDisplay) + { + SourceSizeChanged(); + } + + PostActionCompletedFile(); + ChangeState( EPrefetched ); + } + else + { + // Using TDes -- load the whole video + iSourceStreams[ 0 ]->ReadAllL(); + } + // CMMASourceStream will notify with ReadCompleted +} + +EXPORT_C void CMMAVideoPlayer::ReadCompletedL(TInt aStatus, const TDesC8& aData) +{ + LOG1( EJavaMMAPI, EInfo, "CMMAVideoPlayer::ReadCompletedL: status = %d", aStatus ); + if (aStatus < KErrNone) + { + PostActionCompleted(aStatus); + } + else + { + TRAPD(err, PrefetchDataL(aData)); + if (err != KErrNone) + { + PostActionCompleted(err); + } + // action completed event will be delivered from handleEvent + } +} + +void CMMAVideoPlayer::HandleEvent(const TMMFEvent& aEvent) +{ + LOG1( EJavaMMAPI, EInfo, "MMA:CMMAVideoPlayer::HandleEvent %d", aEvent.iEventType.iUid ); + + // event KMMFEventCategoryPlaybackComplete is handled by both Video + // and Audio players. first it should be handled by Video player + if (aEvent.iEventType == KMMFEventCategoryPlaybackComplete) + { + iSurfaceWindow->RemoveSurface(); + } + + // KNotCompleteVideoError can be notified when video is not complete + // ( missing sound ) but still can be played. Because + // CMMAAudioPlayer::HandleEvent fails with all negative error codes, + // do not call it with KNotCompleteVideoError error when preparing. + if ((aEvent.iErrorCode != KNotCompleteVideoError) || + (aEvent.iEventType != KMMFEventCategoryVideoPrepareComplete)) + { + CMMAAudioPlayer::HandleEvent(aEvent); + } + + if (aEvent.iEventType == KMMFEventCategoryVideoSurfaceCreated) + { + if (aEvent.iErrorCode == KErrNone) + { + TSurfaceId surfaceId; + TRect cropRect; + TVideoAspectRatio pixelAspectRatio; + + iVideoPlaySurfaceSupportCustomCommands.GetSurfaceParameters(surfaceId, + cropRect, + pixelAspectRatio); + + if (iMMASurface.iPrevSurfaceAvailable) + { + // free Surface + TInt error = iVideoPlaySurfaceSupportCustomCommands.SurfaceRemoved(iMMASurface.iPrevSurfaceId); + if (KErrNone != error) + { + ELOG1( EJavaMMAPI, "CMMAVideoPlayer::HandleEvent:SurfaceRemoved error, %d", aEvent.iErrorCode); + } + } + iMMASurface.iPrevSurfaceId = surfaceId; + iMMASurface.iPrevSurfaceAvailable = ETrue; + + iSurfaceWindow->SetSurfaceParameters(surfaceId, + cropRect, + pixelAspectRatio); + + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::HandleEvent: KMMFEventCategoryVideoSurfaceCreated, surface parameters set" ); + } + else + { + ELOG1( EJavaMMAPI, "CMMAVideoPlayer::HandleEvent: error getting surface parameters, %d", aEvent.iErrorCode ); + } + } + else if (aEvent.iEventType == KMMFEventCategoryVideoSurfaceParametersChanged) + { + if (aEvent.iErrorCode == KErrNone) + { + TSurfaceId surfaceId; + TRect cropRect; + TVideoAspectRatio pixelAspectRatio; + + iVideoPlaySurfaceSupportCustomCommands.GetSurfaceParameters(surfaceId, + cropRect, + pixelAspectRatio); + + if (iMMASurface.iPrevSurfaceAvailable) + { + // free Surface + TInt error = iVideoPlaySurfaceSupportCustomCommands.SurfaceRemoved(iMMASurface.iPrevSurfaceId); + if (KErrNone != error) + { + LOG1( EJavaMMAPI, EInfo, "CMMAVideoPlayer::HandleEvent:SurfaceRemoved error, %d", aEvent.iErrorCode); + } + } + iMMASurface.iPrevSurfaceAvailable = ETrue; + iMMASurface.iPrevSurfaceId = surfaceId; + + iSurfaceWindow->SetChangedSurfaceParameters(surfaceId, + cropRect, + pixelAspectRatio); + + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::HandleEvent: KMMFEventCategoryVideoSurfaceParametersChanged" ); + } + else + { + ELOG1( EJavaMMAPI, "CMMAVideoPlayer::HandleEvent: surface parameters changed error, %d", aEvent.iErrorCode ); + } + } + else if (aEvent.iEventType == KMMFEventCategoryVideoRemoveSurface) + { + if (aEvent.iErrorCode == KErrNone) + { + if (iMMASurface.iPrevSurfaceAvailable) + { + // free Surface + TInt error = iVideoPlaySurfaceSupportCustomCommands.SurfaceRemoved(iMMASurface.iPrevSurfaceId); + if (KErrNone != error) + { + ELOG1( EJavaMMAPI, "CMMAVideoPlayer::HandleEvent:SurfaceRemoved error, %d", aEvent.iErrorCode); + } + iMMASurface.iPrevSurfaceAvailable = EFalse; + } + } + else + { + ELOG1( EJavaMMAPI, "CMMAVideoPlayer::HandleEvent:KMMFEventCategoryVideoRemoveSurface error, %d", aEvent.iErrorCode); + } + } + // video opened, preparing + else if (aEvent.iEventType == KMMFEventCategoryVideoOpenComplete) + { + if (aEvent.iErrorCode == KErrNone) + { + TInt error = iVideoPlaySurfaceSupportCustomCommands.UseSurfaces(); + ELOG1( EJavaMMAPI, "MMA::CMMAVideoPlayer::HandleEvent::After UseSurfaces(), error = %d", error ); + TInt prepareError(iVideoPlayControllerCustomCommands.Prepare()); + if (prepareError != KErrNone) + { + // opening failed, notifying java + PostActionCompleted(prepareError); + } + } + else + { + // opening failed, notifying java + PostActionCompleted(aEvent.iErrorCode); + } + } + // final state of prefetch ( prepare completed ) + else if (aEvent.iEventType == KMMFEventCategoryVideoPrepareComplete) + { + // This callback must be handled differently depending on whether + // player is created for a file locator or for a stream. When file + // locator is used, this callback is made in realized state. For + // stream it is made in prefetched state. + PrepareDisplay(); + if (iFileName) + { + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::HandleEvent: Using filename, change state to REALIZED" ); + + // If there is an error condition, then the player state is not + // changed, which indicates the error condition to StartL when + // the ActiveSchedulerWait returns. KNotCompleteVideoError is not + // considered as an error condition, instead it indicates that some + // elements of the media cannot be played (e.g. video OR audio) + if (aEvent.iErrorCode == KErrNone || + aEvent.iErrorCode == KNotCompleteVideoError) + { + ChangeState(ERealized); + } + __ASSERT_DEBUG(iActiveSchedulerWait->IsStarted(), User::Invariant()); + iActiveSchedulerWait->AsyncStop(); + } + else + { + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::HandleEvent: Not using filename, change state to PREFETCHED" ); + CompletePrefetch(aEvent.iErrorCode); + } + } + else // in case of any other event + { + if (aEvent.iErrorCode != KErrNone) + { + PostActionCompleted(aEvent.iErrorCode); //some other error + } + } +} + +void CMMAVideoPlayer::CompletePrefetch(TInt aError) +{ + ELOG1( EJavaMMAPI, "CMMAVideoPlayer::CompletePrefetch + error = %d",aError); + // Post KNotCompleteVideoError as KErrNone to the Java side, because + // video can be played. + if (aError == KNotCompleteVideoError) + { + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::CompletePrefetch KNotCompleteVideoError "); + // release java + PostActionCompleted(KErrNone); + } + else + { + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::CompletePrefetch CompleteVideoError "); + // release java + PostActionCompleted(aError); + } + + if (aError == KErrNone || aError == KNotCompleteVideoError) + { + ChangeState(EPrefetched); + } + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::CompletePrefetch - "); +} + +void CMMAVideoPlayer::PrepareDisplay() +{ + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::PrepareDisplay +" ); + // construction should have leaved if iSurfaceWindow does not exist + __ASSERT_DEBUG(iSurfaceWindow, + User::Panic(_L("CMMVideoPlayer::iSurfaceWindow is null"), + KErrArgument)); + + //First place where we are certain that source size can be fetched + TSize sourceSize; + + TInt err = iVideoControllerCustomCommands.GetVideoFrameSize(sourceSize); + + ELOG1( EJavaMMAPI, "MID::CMMAVideoPlayer::PrepareDisplay: GetVideoFrameSize err = %d", err ); + + // Still we did not get the size of video + if ((err != KErrNone) || + (sourceSize.iWidth <= 0) || + (sourceSize.iHeight <= 0)) + { + LOG( EJavaMMAPI, EInfo, "MID::CMMAVideoPlayer::PrepareDisplay: No sourcesize found, using SurfaceWindow size" ); + // setting size to window size (client rect) + sourceSize = iSurfaceWindow->WindowSize(); + } + + // If 1x1 was got (the default size of form), it must be replaced + // with a valid size as controller will not accept 1x1. + if ((sourceSize.iWidth < KMMAVideoMinDimension) || + (sourceSize.iHeight < KMMAVideoMinDimension)) + { + LOG( EJavaMMAPI, EInfo, "MID::CMMAVideoPlayer::PrepareDisplay: Unacceptable source size, using failsafe" ); + // This is a special case and ought to be used only in + // the rare case that real size is not got from stream. + sourceSize = TSize(KMMAVideoMinDimension, KMMAVideoMinDimension); + } + + iSourceSize = sourceSize; + + // If init has been already done + if (iDisplay) + { + LOG( EJavaMMAPI, EInfo, "MID::CMMAVideoPlayer::PrepareDisplay: display exists, changing source size" ); + SourceSizeChanged(); + } + + // Setting (in)visible if something has changed the DSA state + // (e.g. prepare). If initDisplayMode is not called, this will always + // set visibility to false. + iSurfaceWindow->SetVisible(iSurfaceWindow->IsVisible(), EFalse); + LOG( EJavaMMAPI, EInfo, "CMMAVideoPlayer::PrepareDisplay -" ); +} + +EXPORT_C const TDesC& CMMAVideoPlayer::Type() +{ + return KMMAVideoPlayer; +} + +EXPORT_C TSize CMMAVideoPlayer::SourceSize() +{ + return iSourceSize; +} + +EXPORT_C MMMASnapshot::TEncoding CMMAVideoPlayer::TakeSnapshotL(TRequestStatus* aStatus, + const TSize& /*aSize*/, + const CMMAImageSettings& /*aSettings*/) +{ + if (iEmptySnapshotImage) + { + // Ealier snapshot was not got with SnapshotBitmap method. + User::Leave(KErrInUse); + } + // frame can't be got from video player, but TCK requires that it should + // be available. So returning empty image + iEmptySnapshotImage = new(ELeave) CFbsBitmap(); + User::LeaveIfError(iEmptySnapshotImage->Create(TSize(1, 1), + EColor4K)); + + + User::RequestComplete(aStatus, KErrNone); + + // Return raw bitmap encoding and thus SnapshotEncoded() should not + // get called later on. + return EBitmap; +} + +EXPORT_C CFbsBitmap* CMMAVideoPlayer::SnapshotBitmap() +{ + // snapshot is not supported, returning empty image + CFbsBitmap* image = iEmptySnapshotImage; + + // ownership is transferred to caller + iEmptySnapshotImage = NULL; + return image; +} + +EXPORT_C HBufC8* CMMAVideoPlayer::SnapshotEncoded() +{ + // This method should never be called. + // Asserted in debug build to be sure. + __ASSERT_DEBUG(EFalse, User::Invariant()); + + return NULL; +} + +EXPORT_C void CMMAVideoPlayer::NotifyWithStringEvent( + CMMAPlayerEvent::TEventType aEventType, + const TDesC& aStringEventData) +{ + PostStringEvent(aEventType, aStringEventData); +} + +EXPORT_C MMMASnapshot* CMMAVideoPlayer::SnapshoterL() +{ + return this; +} + +void CMMAVideoPlayer::SourceSizeChanged() +{ + iDisplay->SourceSizeChanged(iSourceSize); + NotifyWithStringEvent(CMMAPlayerEvent::ESizeChanged, KVideoControlName); +} + +// END OF FILE