| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // #define LOG_NDEBUG 0 |
| #define LOG_TAG "PreviewController" |
| #include <utils/Log.h> |
| |
| #include <gui/Surface.h> |
| |
| #include "VideoEditorAudioPlayer.h" |
| #include "PreviewRenderer.h" |
| #include "M4OSA_Semaphore.h" |
| #include "M4OSA_Thread.h" |
| #include "VideoEditorPreviewController.h" |
| |
| namespace android { |
| |
| |
| VideoEditorPreviewController::VideoEditorPreviewController() |
| : mCurrentPlayer(0), |
| mThreadContext(NULL), |
| mPlayerState(VePlayerIdle), |
| mPrepareReqest(M4OSA_FALSE), |
| mClipList(NULL), |
| mNumberClipsInStoryBoard(0), |
| mNumberClipsToPreview(0), |
| mStartingClipIndex(0), |
| mPreviewLooping(M4OSA_FALSE), |
| mCallBackAfterFrameCnt(0), |
| mEffectsSettings(NULL), |
| mNumberEffects(0), |
| mCurrentClipNumber(-1), |
| mClipTotalDuration(0), |
| mCurrentVideoEffect(VIDEO_EFFECT_NONE), |
| mBackgroundAudioSetting(NULL), |
| mAudioMixPCMFileHandle(NULL), |
| mTarget(NULL), |
| mJniCookie(NULL), |
| mJniCallback(NULL), |
| mCurrentPlayedDuration(0), |
| mCurrentClipDuration(0), |
| mVideoStoryBoardTimeMsUptoFirstPreviewClip(0), |
| mOverlayState(OVERLAY_CLEAR), |
| mActivePlayerIndex(0), |
| mOutputVideoWidth(0), |
| mOutputVideoHeight(0), |
| bStopThreadInProgress(false), |
| mSemThreadWait(NULL) { |
| ALOGV("VideoEditorPreviewController"); |
| mRenderingMode = M4xVSS_kBlackBorders; |
| mIsFiftiesEffectStarted = false; |
| |
| for (int i = 0; i < kTotalNumPlayerInstances; ++i) { |
| mVePlayer[i] = NULL; |
| } |
| } |
| |
| VideoEditorPreviewController::~VideoEditorPreviewController() { |
| ALOGV("~VideoEditorPreviewController"); |
| M4OSA_UInt32 i = 0; |
| M4OSA_ERR err = M4NO_ERROR; |
| |
| // Stop the thread if its still running |
| if(mThreadContext != NULL) { |
| err = M4OSA_threadSyncStop(mThreadContext); |
| if(err != M4NO_ERROR) { |
| ALOGV("~VideoEditorPreviewController: error 0x%x \ |
| in trying to stop thread", err); |
| // Continue even if error |
| } |
| |
| err = M4OSA_threadSyncClose(mThreadContext); |
| if(err != M4NO_ERROR) { |
| ALOGE("~VideoEditorPreviewController: error 0x%x \ |
| in trying to close thread", (unsigned int) err); |
| // Continue even if error |
| } |
| |
| mThreadContext = NULL; |
| } |
| |
| for (int playerInst=0; playerInst<kTotalNumPlayerInstances; |
| playerInst++) { |
| if(mVePlayer[playerInst] != NULL) { |
| ALOGV("clearing mVePlayer %d", playerInst); |
| mVePlayer[playerInst].clear(); |
| } |
| } |
| |
| if(mClipList != NULL) { |
| // Clean up |
| for(i=0;i<mNumberClipsInStoryBoard;i++) |
| { |
| if(mClipList[i]->pFile != NULL) { |
| free(mClipList[i]->pFile); |
| mClipList[i]->pFile = NULL; |
| } |
| |
| free(mClipList[i]); |
| } |
| free(mClipList); |
| mClipList = NULL; |
| } |
| |
| if(mEffectsSettings) { |
| for(i=0;i<mNumberEffects;i++) { |
| if(mEffectsSettings[i].xVSS.pFramingBuffer != NULL) { |
| free(mEffectsSettings[i].xVSS.pFramingBuffer->pac_data); |
| |
| free(mEffectsSettings[i].xVSS.pFramingBuffer); |
| |
| mEffectsSettings[i].xVSS.pFramingBuffer = NULL; |
| } |
| } |
| free(mEffectsSettings); |
| mEffectsSettings = NULL; |
| } |
| |
| if (mAudioMixPCMFileHandle) { |
| err = M4OSA_fileReadClose (mAudioMixPCMFileHandle); |
| mAudioMixPCMFileHandle = M4OSA_NULL; |
| } |
| |
| if (mBackgroundAudioSetting != NULL) { |
| free(mBackgroundAudioSetting); |
| mBackgroundAudioSetting = NULL; |
| } |
| |
| if(mTarget != NULL) { |
| delete mTarget; |
| mTarget = NULL; |
| } |
| |
| mOverlayState = OVERLAY_CLEAR; |
| |
| ALOGV("~VideoEditorPreviewController returns"); |
| } |
| |
| M4OSA_ERR VideoEditorPreviewController::loadEditSettings( |
| M4VSS3GPP_EditSettings* pSettings,M4xVSS_AudioMixingSettings* bgmSettings) { |
| |
| M4OSA_UInt32 i = 0, iClipDuration = 0, rgbSize = 0; |
| M4VIFI_UInt8 *tmp = NULL; |
| M4OSA_ERR err = M4NO_ERROR; |
| |
| ALOGV("loadEditSettings"); |
| ALOGV("loadEditSettings Channels = %d, sampling Freq %d", |
| bgmSettings->uiNbChannels, bgmSettings->uiSamplingFrequency ); |
| bgmSettings->uiSamplingFrequency = 32000; |
| |
| ALOGV("loadEditSettings Channels = %d, sampling Freq %d", |
| bgmSettings->uiNbChannels, bgmSettings->uiSamplingFrequency ); |
| Mutex::Autolock autoLock(mLock); |
| |
| // Clean up any previous Edit settings before loading new ones |
| mCurrentVideoEffect = VIDEO_EFFECT_NONE; |
| |
| if(mAudioMixPCMFileHandle) { |
| err = M4OSA_fileReadClose (mAudioMixPCMFileHandle); |
| mAudioMixPCMFileHandle = M4OSA_NULL; |
| } |
| |
| if(mBackgroundAudioSetting != NULL) { |
| free(mBackgroundAudioSetting); |
| mBackgroundAudioSetting = NULL; |
| } |
| |
| if(mClipList != NULL) { |
| // Clean up |
| for(i=0;i<mNumberClipsInStoryBoard;i++) |
| { |
| if(mClipList[i]->pFile != NULL) { |
| free(mClipList[i]->pFile); |
| mClipList[i]->pFile = NULL; |
| } |
| |
| free(mClipList[i]); |
| } |
| free(mClipList); |
| mClipList = NULL; |
| } |
| |
| if(mEffectsSettings) { |
| for(i=0;i<mNumberEffects;i++) { |
| if(mEffectsSettings[i].xVSS.pFramingBuffer != NULL) { |
| free(mEffectsSettings[i].xVSS.pFramingBuffer->pac_data); |
| |
| free(mEffectsSettings[i].xVSS.pFramingBuffer); |
| |
| mEffectsSettings[i].xVSS.pFramingBuffer = NULL; |
| } |
| } |
| free(mEffectsSettings); |
| mEffectsSettings = NULL; |
| } |
| |
| if(mClipList == NULL) { |
| mNumberClipsInStoryBoard = pSettings->uiClipNumber; |
| ALOGV("loadEditSettings: # of Clips = %d", mNumberClipsInStoryBoard); |
| |
| mClipList = (M4VSS3GPP_ClipSettings**)M4OSA_32bitAlignedMalloc( |
| sizeof(M4VSS3GPP_ClipSettings*)*pSettings->uiClipNumber, M4VS, |
| (M4OSA_Char*)"LvPP, copy of pClipList"); |
| |
| if(NULL == mClipList) { |
| ALOGE("loadEditSettings: Malloc error"); |
| return M4ERR_ALLOC; |
| } |
| memset((void *)mClipList,0, |
| sizeof(M4VSS3GPP_ClipSettings*)*pSettings->uiClipNumber); |
| |
| for(i=0;i<pSettings->uiClipNumber;i++) { |
| |
| // Allocate current clip |
| mClipList[i] = |
| (M4VSS3GPP_ClipSettings*)M4OSA_32bitAlignedMalloc( |
| sizeof(M4VSS3GPP_ClipSettings),M4VS,(M4OSA_Char*)"clip settings"); |
| |
| if(mClipList[i] == NULL) { |
| |
| ALOGE("loadEditSettings: Allocation error for mClipList[%d]", (int)i); |
| return M4ERR_ALLOC; |
| } |
| // Copy plain structure |
| memcpy((void *)mClipList[i], |
| (void *)pSettings->pClipList[i], |
| sizeof(M4VSS3GPP_ClipSettings)); |
| |
| if(NULL != pSettings->pClipList[i]->pFile) { |
| mClipList[i]->pFile = (M4OSA_Char*)M4OSA_32bitAlignedMalloc( |
| pSettings->pClipList[i]->filePathSize, M4VS, |
| (M4OSA_Char*)"pClipSettingsDest->pFile"); |
| |
| if(NULL == mClipList[i]->pFile) |
| { |
| ALOGE("loadEditSettings : ERROR allocating filename"); |
| return M4ERR_ALLOC; |
| } |
| |
| memcpy((void *)mClipList[i]->pFile, |
| (void *)pSettings->pClipList[i]->pFile, |
| pSettings->pClipList[i]->filePathSize); |
| } |
| else { |
| ALOGE("NULL file path"); |
| return M4ERR_PARAMETER; |
| } |
| |
| // Calculate total duration of all clips |
| iClipDuration = pSettings->pClipList[i]->uiEndCutTime - |
| pSettings->pClipList[i]->uiBeginCutTime; |
| |
| mClipTotalDuration = mClipTotalDuration+iClipDuration; |
| } |
| } |
| |
| if(mEffectsSettings == NULL) { |
| mNumberEffects = pSettings->nbEffects; |
| ALOGV("loadEditSettings: mNumberEffects = %d", mNumberEffects); |
| |
| if(mNumberEffects != 0) { |
| mEffectsSettings = (M4VSS3GPP_EffectSettings*)M4OSA_32bitAlignedMalloc( |
| mNumberEffects*sizeof(M4VSS3GPP_EffectSettings), |
| M4VS, (M4OSA_Char*)"effects settings"); |
| |
| if(mEffectsSettings == NULL) { |
| ALOGE("loadEffectsSettings: Allocation error"); |
| return M4ERR_ALLOC; |
| } |
| |
| memset((void *)mEffectsSettings,0, |
| mNumberEffects*sizeof(M4VSS3GPP_EffectSettings)); |
| |
| for(i=0;i<mNumberEffects;i++) { |
| |
| mEffectsSettings[i].xVSS.pFramingFilePath = NULL; |
| mEffectsSettings[i].xVSS.pFramingBuffer = NULL; |
| mEffectsSettings[i].xVSS.pTextBuffer = NULL; |
| |
| memcpy((void *)&(mEffectsSettings[i]), |
| (void *)&(pSettings->Effects[i]), |
| sizeof(M4VSS3GPP_EffectSettings)); |
| |
| if(pSettings->Effects[i].VideoEffectType == |
| (M4VSS3GPP_VideoEffectType)M4xVSS_kVideoEffectType_Framing) { |
| // Allocate the pFraming RGB buffer |
| mEffectsSettings[i].xVSS.pFramingBuffer = |
| (M4VIFI_ImagePlane *)M4OSA_32bitAlignedMalloc(sizeof(M4VIFI_ImagePlane), |
| M4VS, (M4OSA_Char*)"lvpp framing buffer"); |
| |
| if(mEffectsSettings[i].xVSS.pFramingBuffer == NULL) { |
| ALOGE("loadEffectsSettings:Alloc error for pFramingBuf"); |
| free(mEffectsSettings); |
| mEffectsSettings = NULL; |
| return M4ERR_ALLOC; |
| } |
| |
| // Allocate the pac_data (RGB) |
| if(pSettings->Effects[i].xVSS.rgbType == M4VSS3GPP_kRGB565){ |
| rgbSize = |
| pSettings->Effects[i].xVSS.pFramingBuffer->u_width * |
| pSettings->Effects[i].xVSS.pFramingBuffer->u_height*2; |
| } |
| else if( |
| pSettings->Effects[i].xVSS.rgbType == M4VSS3GPP_kRGB888) { |
| rgbSize = |
| pSettings->Effects[i].xVSS.pFramingBuffer->u_width * |
| pSettings->Effects[i].xVSS.pFramingBuffer->u_height*3; |
| } |
| else { |
| ALOGE("loadEffectsSettings: wrong RGB type"); |
| free(mEffectsSettings); |
| mEffectsSettings = NULL; |
| return M4ERR_PARAMETER; |
| } |
| |
| tmp = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(rgbSize, M4VS, |
| (M4OSA_Char*)"framing buffer pac_data"); |
| |
| if(tmp == NULL) { |
| ALOGE("loadEffectsSettings:Alloc error pFramingBuf pac"); |
| free(mEffectsSettings); |
| mEffectsSettings = NULL; |
| free(mEffectsSettings[i].xVSS.pFramingBuffer); |
| |
| mEffectsSettings[i].xVSS.pFramingBuffer = NULL; |
| return M4ERR_ALLOC; |
| } |
| /* Initialize the pFramingBuffer*/ |
| mEffectsSettings[i].xVSS.pFramingBuffer->pac_data = tmp; |
| mEffectsSettings[i].xVSS.pFramingBuffer->u_height = |
| pSettings->Effects[i].xVSS.pFramingBuffer->u_height; |
| |
| mEffectsSettings[i].xVSS.pFramingBuffer->u_width = |
| pSettings->Effects[i].xVSS.pFramingBuffer->u_width; |
| |
| mEffectsSettings[i].xVSS.pFramingBuffer->u_stride = |
| pSettings->Effects[i].xVSS.pFramingBuffer->u_stride; |
| |
| mEffectsSettings[i].xVSS.pFramingBuffer->u_topleft = |
| pSettings->Effects[i].xVSS.pFramingBuffer->u_topleft; |
| |
| mEffectsSettings[i].xVSS.uialphaBlendingStart = |
| pSettings->Effects[i].xVSS.uialphaBlendingStart; |
| |
| mEffectsSettings[i].xVSS.uialphaBlendingMiddle = |
| pSettings->Effects[i].xVSS.uialphaBlendingMiddle; |
| |
| mEffectsSettings[i].xVSS.uialphaBlendingEnd = |
| pSettings->Effects[i].xVSS.uialphaBlendingEnd; |
| |
| mEffectsSettings[i].xVSS.uialphaBlendingFadeInTime = |
| pSettings->Effects[i].xVSS.uialphaBlendingFadeInTime; |
| mEffectsSettings[i].xVSS.uialphaBlendingFadeOutTime = |
| pSettings->Effects[i].xVSS.uialphaBlendingFadeOutTime; |
| |
| // Copy the pFraming data |
| memcpy((void *) |
| mEffectsSettings[i].xVSS.pFramingBuffer->pac_data, |
| (void *)pSettings->Effects[i].xVSS.pFramingBuffer->pac_data, |
| rgbSize); |
| |
| mEffectsSettings[i].xVSS.rgbType = |
| pSettings->Effects[i].xVSS.rgbType; |
| } |
| } |
| } |
| } |
| |
| if (mBackgroundAudioSetting == NULL) { |
| |
| mBackgroundAudioSetting = (M4xVSS_AudioMixingSettings*)M4OSA_32bitAlignedMalloc( |
| sizeof(M4xVSS_AudioMixingSettings), M4VS, |
| (M4OSA_Char*)"LvPP, copy of bgmSettings"); |
| |
| if(NULL == mBackgroundAudioSetting) { |
| ALOGE("loadEditSettings: mBackgroundAudioSetting Malloc failed"); |
| return M4ERR_ALLOC; |
| } |
| |
| memset((void *)mBackgroundAudioSetting, 0,sizeof(M4xVSS_AudioMixingSettings*)); |
| memcpy((void *)mBackgroundAudioSetting, (void *)bgmSettings, sizeof(M4xVSS_AudioMixingSettings)); |
| |
| if ( mBackgroundAudioSetting->pFile != M4OSA_NULL ) { |
| |
| mBackgroundAudioSetting->pFile = (M4OSA_Void*) bgmSettings->pPCMFilePath; |
| mBackgroundAudioSetting->uiNbChannels = 2; |
| mBackgroundAudioSetting->uiSamplingFrequency = 32000; |
| } |
| |
| // Open the BG file |
| if ( mBackgroundAudioSetting->pFile != M4OSA_NULL ) { |
| err = M4OSA_fileReadOpen(&mAudioMixPCMFileHandle, |
| mBackgroundAudioSetting->pFile, M4OSA_kFileRead); |
| |
| if (err != M4NO_ERROR) { |
| ALOGE("loadEditSettings: mBackgroundAudio PCM File open failed"); |
| return M4ERR_PARAMETER; |
| } |
| } |
| } |
| |
| mOutputVideoSize = pSettings->xVSS.outputVideoSize; |
| mFrameStr.pBuffer = M4OSA_NULL; |
| return M4NO_ERROR; |
| } |
| |
| M4OSA_ERR VideoEditorPreviewController::setSurface(const sp<Surface> &surface) { |
| ALOGV("setSurface"); |
| Mutex::Autolock autoLock(mLock); |
| |
| mSurface = surface; |
| return M4NO_ERROR; |
| } |
| |
| M4OSA_ERR VideoEditorPreviewController::startPreview( |
| M4OSA_UInt32 fromMS, M4OSA_Int32 toMs, M4OSA_UInt16 callBackAfterFrameCount, |
| M4OSA_Bool loop) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| M4OSA_UInt32 i = 0, iIncrementedDuration = 0; |
| ALOGV("startPreview"); |
| |
| if(fromMS > (M4OSA_UInt32)toMs) { |
| ALOGE("startPreview: fromMS > toMs"); |
| return M4ERR_PARAMETER; |
| } |
| |
| if(toMs == 0) { |
| ALOGE("startPreview: toMs is 0"); |
| return M4ERR_PARAMETER; |
| } |
| |
| // If already started, then stop preview first |
| for(int playerInst=0; playerInst<kTotalNumPlayerInstances; playerInst++) { |
| if(mVePlayer[playerInst] != NULL) { |
| ALOGV("startPreview: stopping previously started preview playback"); |
| stopPreview(); |
| break; |
| } |
| } |
| |
| // If renderPreview was called previously, then delete Renderer object first |
| if(mTarget != NULL) { |
| ALOGV("startPreview: delete previous PreviewRenderer"); |
| delete mTarget; |
| mTarget = NULL; |
| } |
| |
| // Create Audio player to be used for entire |
| // storyboard duration |
| mVEAudioSink = new VideoEditorPlayer::VeAudioOutput(); |
| mVEAudioPlayer = new VideoEditorAudioPlayer(mVEAudioSink); |
| mVEAudioPlayer->setAudioMixSettings(mBackgroundAudioSetting); |
| mVEAudioPlayer->setAudioMixPCMFileHandle(mAudioMixPCMFileHandle); |
| |
| // Create Video Renderer to be used for the entire storyboard duration. |
| uint32_t width, height; |
| getVideoSizeByResolution(mOutputVideoSize, &width, &height); |
| mNativeWindowRenderer = new NativeWindowRenderer(mSurface, width, height); |
| |
| ALOGV("startPreview: loop = %d", loop); |
| mPreviewLooping = loop; |
| |
| ALOGV("startPreview: callBackAfterFrameCount = %d", callBackAfterFrameCount); |
| mCallBackAfterFrameCnt = callBackAfterFrameCount; |
| |
| for (int playerInst=0; playerInst<kTotalNumPlayerInstances; playerInst++) { |
| mVePlayer[playerInst] = new VideoEditorPlayer(mNativeWindowRenderer); |
| if(mVePlayer[playerInst] == NULL) { |
| ALOGE("startPreview:Error creating VideoEditorPlayer %d",playerInst); |
| return M4ERR_ALLOC; |
| } |
| ALOGV("startPreview: object created"); |
| |
| mVePlayer[playerInst]->setNotifyCallback(this,(notify_callback_f)notify); |
| ALOGV("startPreview: notify callback set"); |
| |
| mVePlayer[playerInst]->loadEffectsSettings(mEffectsSettings, |
| mNumberEffects); |
| ALOGV("startPreview: effects settings loaded"); |
| |
| mVePlayer[playerInst]->loadAudioMixSettings(mBackgroundAudioSetting); |
| ALOGV("startPreview: AudioMixSettings settings loaded"); |
| |
| mVePlayer[playerInst]->setAudioMixPCMFileHandle(mAudioMixPCMFileHandle); |
| ALOGV("startPreview: AudioMixPCMFileHandle set"); |
| |
| mVePlayer[playerInst]->setProgressCallbackInterval( |
| mCallBackAfterFrameCnt); |
| ALOGV("startPreview: setProgressCallBackInterval"); |
| } |
| |
| mPlayerState = VePlayerIdle; |
| mPrepareReqest = M4OSA_FALSE; |
| |
| if(fromMS == 0) { |
| mCurrentClipNumber = -1; |
| // Save original value |
| mFirstPreviewClipBeginTime = mClipList[0]->uiBeginCutTime; |
| mVideoStoryBoardTimeMsUptoFirstPreviewClip = 0; |
| } |
| else { |
| ALOGV("startPreview: fromMS=%d", fromMS); |
| if(fromMS >= mClipTotalDuration) { |
| ALOGE("startPreview: fromMS >= mClipTotalDuration"); |
| return M4ERR_PARAMETER; |
| } |
| for(i=0;i<mNumberClipsInStoryBoard;i++) { |
| if(fromMS < (iIncrementedDuration + (mClipList[i]->uiEndCutTime - |
| mClipList[i]->uiBeginCutTime))) { |
| // Set to 1 index below, |
| // as threadProcess first increments the clip index |
| // and then processes clip in thread loop |
| mCurrentClipNumber = i-1; |
| ALOGD("startPreview:mCurrentClipNumber = %d fromMS=%d",i,fromMS); |
| |
| // Save original value |
| mFirstPreviewClipBeginTime = mClipList[i]->uiBeginCutTime; |
| |
| // Set correct begin time to start playback |
| if((fromMS+mClipList[i]->uiBeginCutTime) > |
| (iIncrementedDuration+mClipList[i]->uiBeginCutTime)) { |
| |
| mClipList[i]->uiBeginCutTime = |
| mClipList[i]->uiBeginCutTime + |
| (fromMS - iIncrementedDuration); |
| } |
| break; |
| } |
| else { |
| iIncrementedDuration = iIncrementedDuration + |
| (mClipList[i]->uiEndCutTime - mClipList[i]->uiBeginCutTime); |
| } |
| } |
| mVideoStoryBoardTimeMsUptoFirstPreviewClip = iIncrementedDuration; |
| } |
| |
| for (int playerInst=0; playerInst<kTotalNumPlayerInstances; playerInst++) { |
| mVePlayer[playerInst]->setAudioMixStoryBoardParam(fromMS, |
| mFirstPreviewClipBeginTime, |
| mClipList[i]->ClipProperties.uiClipAudioVolumePercentage); |
| |
| ALOGV("startPreview:setAudioMixStoryBoardSkimTimeStamp set %d cuttime \ |
| %d", fromMS, mFirstPreviewClipBeginTime); |
| } |
| |
| mStartingClipIndex = mCurrentClipNumber+1; |
| |
| // Start playing with player instance 0 |
| mCurrentPlayer = 0; |
| mActivePlayerIndex = 0; |
| |
| if(toMs == -1) { |
| ALOGV("startPreview: Preview till end of storyboard"); |
| mNumberClipsToPreview = mNumberClipsInStoryBoard; |
| // Save original value |
| mLastPreviewClipEndTime = |
| mClipList[mNumberClipsToPreview-1]->uiEndCutTime; |
| } |
| else { |
| ALOGV("startPreview: toMs=%d", toMs); |
| if((M4OSA_UInt32)toMs > mClipTotalDuration) { |
| ALOGE("startPreview: toMs > mClipTotalDuration"); |
| return M4ERR_PARAMETER; |
| } |
| |
| iIncrementedDuration = 0; |
| |
| for(i=0;i<mNumberClipsInStoryBoard;i++) { |
| if((M4OSA_UInt32)toMs <= (iIncrementedDuration + |
| (mClipList[i]->uiEndCutTime - mClipList[i]->uiBeginCutTime))) { |
| // Save original value |
| mLastPreviewClipEndTime = mClipList[i]->uiEndCutTime; |
| // Set the end cut time of clip index i to toMs |
| mClipList[i]->uiEndCutTime = toMs; |
| |
| // Number of clips to be previewed is from index 0 to i |
| // increment by 1 as i starts from 0 |
| mNumberClipsToPreview = i+1; |
| break; |
| } |
| else { |
| iIncrementedDuration = iIncrementedDuration + |
| (mClipList[i]->uiEndCutTime - mClipList[i]->uiBeginCutTime); |
| } |
| } |
| } |
| |
| // Open the thread semaphore |
| M4OSA_semaphoreOpen(&mSemThreadWait, 1); |
| |
| // Open the preview process thread |
| err = M4OSA_threadSyncOpen(&mThreadContext, (M4OSA_ThreadDoIt)threadProc); |
| if (M4NO_ERROR != err) { |
| ALOGE("VideoEditorPreviewController:M4OSA_threadSyncOpen error %d", (int) err); |
| return err; |
| } |
| |
| // Set the stacksize |
| err = M4OSA_threadSyncSetOption(mThreadContext, M4OSA_ThreadStackSize, |
| (M4OSA_DataOption) kPreviewThreadStackSize); |
| |
| if (M4NO_ERROR != err) { |
| ALOGE("VideoEditorPreviewController: threadSyncSetOption error %d", (int) err); |
| M4OSA_threadSyncClose(mThreadContext); |
| mThreadContext = NULL; |
| return err; |
| } |
| |
| // Start the thread |
| err = M4OSA_threadSyncStart(mThreadContext, (M4OSA_Void*)this); |
| if (M4NO_ERROR != err) { |
| ALOGE("VideoEditorPreviewController: threadSyncStart error %d", (int) err); |
| M4OSA_threadSyncClose(mThreadContext); |
| mThreadContext = NULL; |
| return err; |
| } |
| bStopThreadInProgress = false; |
| |
| ALOGV("startPreview: process thread started"); |
| return M4NO_ERROR; |
| } |
| |
| M4OSA_UInt32 VideoEditorPreviewController::stopPreview() { |
| M4OSA_ERR err = M4NO_ERROR; |
| uint32_t lastRenderedFrameTimeMs = 0; |
| ALOGV("stopPreview"); |
| |
| // Stop the thread |
| if(mThreadContext != NULL) { |
| bStopThreadInProgress = true; |
| { |
| Mutex::Autolock autoLock(mLockSem); |
| if (mSemThreadWait != NULL) { |
| err = M4OSA_semaphorePost(mSemThreadWait); |
| } |
| } |
| |
| err = M4OSA_threadSyncStop(mThreadContext); |
| if(err != M4NO_ERROR) { |
| ALOGV("stopPreview: error 0x%x in trying to stop thread", err); |
| // Continue even if error |
| } |
| |
| err = M4OSA_threadSyncClose(mThreadContext); |
| if(err != M4NO_ERROR) { |
| ALOGE("stopPreview: error 0x%x in trying to close thread", (unsigned int)err); |
| // Continue even if error |
| } |
| |
| mThreadContext = NULL; |
| } |
| |
| // Close the semaphore first |
| { |
| Mutex::Autolock autoLock(mLockSem); |
| if(mSemThreadWait != NULL) { |
| err = M4OSA_semaphoreClose(mSemThreadWait); |
| ALOGV("stopPreview: close semaphore returns 0x%x", err); |
| mSemThreadWait = NULL; |
| } |
| } |
| |
| for (int playerInst=0; playerInst<kTotalNumPlayerInstances; playerInst++) { |
| if(mVePlayer[playerInst] != NULL) { |
| if(mVePlayer[playerInst]->isPlaying()) { |
| ALOGV("stop the player first"); |
| mVePlayer[playerInst]->stop(); |
| } |
| if (playerInst == mActivePlayerIndex) { |
| // Return the last rendered frame time stamp |
| mVePlayer[mActivePlayerIndex]->getLastRenderedTimeMs(&lastRenderedFrameTimeMs); |
| } |
| |
| //This is used to syncronize onStreamDone() in PreviewPlayer and |
| //stopPreview() in PreviewController |
| sp<VideoEditorPlayer> temp = mVePlayer[playerInst]; |
| temp->acquireLock(); |
| ALOGV("stopPreview: clearing mVePlayer"); |
| mVePlayer[playerInst].clear(); |
| mVePlayer[playerInst] = NULL; |
| temp->releaseLock(); |
| } |
| } |
| ALOGV("stopPreview: clear audioSink and audioPlayer"); |
| mVEAudioSink.clear(); |
| if (mVEAudioPlayer) { |
| delete mVEAudioPlayer; |
| mVEAudioPlayer = NULL; |
| } |
| |
| delete mNativeWindowRenderer; |
| mNativeWindowRenderer = NULL; |
| |
| // If image file playing, then free the buffer pointer |
| if(mFrameStr.pBuffer != M4OSA_NULL) { |
| free(mFrameStr.pBuffer); |
| mFrameStr.pBuffer = M4OSA_NULL; |
| } |
| |
| // Reset original begin cuttime of first previewed clip*/ |
| mClipList[mStartingClipIndex]->uiBeginCutTime = mFirstPreviewClipBeginTime; |
| // Reset original end cuttime of last previewed clip*/ |
| mClipList[mNumberClipsToPreview-1]->uiEndCutTime = mLastPreviewClipEndTime; |
| |
| mPlayerState = VePlayerIdle; |
| mPrepareReqest = M4OSA_FALSE; |
| |
| mCurrentPlayedDuration = 0; |
| mCurrentClipDuration = 0; |
| mRenderingMode = M4xVSS_kBlackBorders; |
| mOutputVideoWidth = 0; |
| mOutputVideoHeight = 0; |
| |
| ALOGV("stopPreview() lastRenderedFrameTimeMs %ld", lastRenderedFrameTimeMs); |
| return lastRenderedFrameTimeMs; |
| } |
| |
| M4OSA_ERR VideoEditorPreviewController::clearSurface( |
| const sp<Surface> &surface, VideoEditor_renderPreviewFrameStr* pFrameInfo) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| VideoEditor_renderPreviewFrameStr* pFrameStr = pFrameInfo; |
| M4OSA_UInt32 outputBufferWidth =0, outputBufferHeight=0; |
| M4VIFI_ImagePlane planeOut[3]; |
| ALOGV("Inside preview clear frame"); |
| |
| Mutex::Autolock autoLock(mLock); |
| |
| // Delete previous renderer instance |
| if(mTarget != NULL) { |
| delete mTarget; |
| mTarget = NULL; |
| } |
| |
| outputBufferWidth = pFrameStr->uiFrameWidth; |
| outputBufferHeight = pFrameStr->uiFrameHeight; |
| |
| // Initialize the renderer |
| if(mTarget == NULL) { |
| |
| mTarget = PreviewRenderer::CreatePreviewRenderer( |
| surface, |
| outputBufferWidth, outputBufferHeight); |
| |
| if(mTarget == NULL) { |
| ALOGE("renderPreviewFrame: cannot create PreviewRenderer"); |
| return M4ERR_ALLOC; |
| } |
| } |
| |
| // Out plane |
| uint8_t* outBuffer; |
| size_t outBufferStride = 0; |
| |
| ALOGV("doMediaRendering CALL getBuffer()"); |
| mTarget->getBufferYV12(&outBuffer, &outBufferStride); |
| |
| // Set the output YUV420 plane to be compatible with YV12 format |
| //In YV12 format, sizes must be even |
| M4OSA_UInt32 yv12PlaneWidth = ((outputBufferWidth +1)>>1)<<1; |
| M4OSA_UInt32 yv12PlaneHeight = ((outputBufferHeight+1)>>1)<<1; |
| |
| prepareYV12ImagePlane(planeOut, yv12PlaneWidth, yv12PlaneHeight, |
| (M4OSA_UInt32)outBufferStride, (M4VIFI_UInt8 *)outBuffer); |
| |
| /* Fill the surface with black frame */ |
| memset((void *)planeOut[0].pac_data,0x00,planeOut[0].u_width * |
| planeOut[0].u_height * 1.5); |
| memset((void *)planeOut[1].pac_data,128,planeOut[1].u_width * |
| planeOut[1].u_height); |
| memset((void *)planeOut[2].pac_data,128,planeOut[2].u_width * |
| planeOut[2].u_height); |
| |
| mTarget->renderYV12(); |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorPreviewController::renderPreviewFrame( |
| const sp<Surface> &surface, |
| VideoEditor_renderPreviewFrameStr* pFrameInfo, |
| VideoEditorCurretEditInfo *pCurrEditInfo) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| M4OSA_UInt32 i = 0, iIncrementedDuration = 0, tnTimeMs=0, framesize =0; |
| VideoEditor_renderPreviewFrameStr* pFrameStr = pFrameInfo; |
| M4VIFI_UInt8 *pixelArray = NULL; |
| Mutex::Autolock autoLock(mLock); |
| |
| if (pCurrEditInfo != NULL) { |
| pCurrEditInfo->overlaySettingsIndex = -1; |
| } |
| // Delete previous renderer instance |
| if(mTarget != NULL) { |
| delete mTarget; |
| mTarget = NULL; |
| } |
| |
| if(mOutputVideoWidth == 0) { |
| mOutputVideoWidth = pFrameStr->uiFrameWidth; |
| } |
| |
| if(mOutputVideoHeight == 0) { |
| mOutputVideoHeight = pFrameStr->uiFrameHeight; |
| } |
| |
| // Initialize the renderer |
| if(mTarget == NULL) { |
| mTarget = PreviewRenderer::CreatePreviewRenderer( |
| surface, |
| mOutputVideoWidth, mOutputVideoHeight); |
| |
| if(mTarget == NULL) { |
| ALOGE("renderPreviewFrame: cannot create PreviewRenderer"); |
| return M4ERR_ALLOC; |
| } |
| } |
| |
| pixelArray = NULL; |
| |
| // Apply rotation if required |
| if (pFrameStr->videoRotationDegree != 0) { |
| err = applyVideoRotation((M4OSA_Void *)pFrameStr->pBuffer, |
| pFrameStr->uiFrameWidth, pFrameStr->uiFrameHeight, |
| pFrameStr->videoRotationDegree); |
| if (M4NO_ERROR != err) { |
| ALOGE("renderPreviewFrame: cannot rotate video, err 0x%x", (unsigned int)err); |
| delete mTarget; |
| mTarget = NULL; |
| return err; |
| } else { |
| // Video rotation done. |
| // Swap width and height if 90 or 270 degrees |
| if (pFrameStr->videoRotationDegree != 180) { |
| int32_t temp = pFrameStr->uiFrameWidth; |
| pFrameStr->uiFrameWidth = pFrameStr->uiFrameHeight; |
| pFrameStr->uiFrameHeight = temp; |
| } |
| } |
| } |
| // Postprocessing (apply video effect) |
| if(pFrameStr->bApplyEffect == M4OSA_TRUE) { |
| |
| for(i=0;i<mNumberEffects;i++) { |
| // First check if effect starttime matches the clip being previewed |
| if((mEffectsSettings[i].uiStartTime < pFrameStr->clipBeginCutTime) |
| ||(mEffectsSettings[i].uiStartTime >= pFrameStr->clipEndCutTime)) { |
| // This effect doesn't belong to this clip, check next one |
| continue; |
| } |
| if((mEffectsSettings[i].uiStartTime <= pFrameStr->timeMs) && |
| ((mEffectsSettings[i].uiStartTime+mEffectsSettings[i].uiDuration) >= |
| pFrameStr->timeMs) && (mEffectsSettings[i].uiDuration != 0)) { |
| setVideoEffectType(mEffectsSettings[i].VideoEffectType, TRUE); |
| } |
| else { |
| setVideoEffectType(mEffectsSettings[i].VideoEffectType, FALSE); |
| } |
| } |
| |
| //Provide the overlay Update indication when there is an overlay effect |
| if (mCurrentVideoEffect & VIDEO_EFFECT_FRAMING) { |
| M4OSA_UInt32 index; |
| mCurrentVideoEffect &= ~VIDEO_EFFECT_FRAMING; //never apply framing here. |
| |
| // Find the effect in effectSettings array |
| for (index = 0; index < mNumberEffects; index++) { |
| if(mEffectsSettings[index].VideoEffectType == |
| (M4VSS3GPP_VideoEffectType)M4xVSS_kVideoEffectType_Framing) { |
| |
| if((mEffectsSettings[index].uiStartTime <= pFrameInfo->timeMs) && |
| ((mEffectsSettings[index].uiStartTime+ |
| mEffectsSettings[index].uiDuration) >= pFrameInfo->timeMs)) |
| { |
| break; |
| } |
| } |
| } |
| if ((index < mNumberEffects) && (pCurrEditInfo != NULL)) { |
| pCurrEditInfo->overlaySettingsIndex = index; |
| ALOGV("Framing index = %d", index); |
| } else { |
| ALOGV("No framing effects found"); |
| } |
| } |
| |
| if(mCurrentVideoEffect != VIDEO_EFFECT_NONE) { |
| err = applyVideoEffect((M4OSA_Void *)pFrameStr->pBuffer, |
| OMX_COLOR_FormatYUV420Planar, pFrameStr->uiFrameWidth, |
| pFrameStr->uiFrameHeight, pFrameStr->timeMs, |
| (M4OSA_Void *)pixelArray); |
| |
| if(err != M4NO_ERROR) { |
| ALOGE("renderPreviewFrame: applyVideoEffect error 0x%x", (unsigned int)err); |
| delete mTarget; |
| mTarget = NULL; |
| free(pixelArray); |
| pixelArray = NULL; |
| return err; |
| } |
| mCurrentVideoEffect = VIDEO_EFFECT_NONE; |
| } |
| else { |
| // Apply the rendering mode |
| err = doImageRenderingMode((M4OSA_Void *)pFrameStr->pBuffer, |
| OMX_COLOR_FormatYUV420Planar, pFrameStr->uiFrameWidth, |
| pFrameStr->uiFrameHeight, (M4OSA_Void *)pixelArray); |
| |
| if(err != M4NO_ERROR) { |
| ALOGE("renderPreviewFrame:doImageRenderingMode error 0x%x", (unsigned int)err); |
| delete mTarget; |
| mTarget = NULL; |
| free(pixelArray); |
| pixelArray = NULL; |
| return err; |
| } |
| } |
| } |
| else { |
| // Apply the rendering mode |
| err = doImageRenderingMode((M4OSA_Void *)pFrameStr->pBuffer, |
| OMX_COLOR_FormatYUV420Planar, pFrameStr->uiFrameWidth, |
| pFrameStr->uiFrameHeight, (M4OSA_Void *)pixelArray); |
| |
| if(err != M4NO_ERROR) { |
| ALOGE("renderPreviewFrame: doImageRenderingMode error 0x%x", (unsigned int)err); |
| delete mTarget; |
| mTarget = NULL; |
| free(pixelArray); |
| pixelArray = NULL; |
| return err; |
| } |
| } |
| |
| mTarget->renderYV12(); |
| return err; |
| } |
| |
| M4OSA_Void VideoEditorPreviewController::setJniCallback(void* cookie, |
| jni_progress_callback_fct callbackFct) { |
| //ALOGV("setJniCallback"); |
| mJniCookie = cookie; |
| mJniCallback = callbackFct; |
| } |
| |
| M4OSA_ERR VideoEditorPreviewController::preparePlayer( |
| void* param, int playerInstance, int index) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| VideoEditorPreviewController *pController = |
| (VideoEditorPreviewController *)param; |
| |
| ALOGV("preparePlayer: instance %d file %d", playerInstance, index); |
| |
| const char* fileName = (const char*) pController->mClipList[index]->pFile; |
| pController->mVePlayer[playerInstance]->setDataSource(fileName, NULL); |
| |
| ALOGV("preparePlayer: setDataSource instance %s", |
| (const char *)pController->mClipList[index]->pFile); |
| |
| pController->mVePlayer[playerInstance]->setVideoSurface( |
| pController->mSurface); |
| ALOGV("preparePlayer: setVideoSurface"); |
| |
| pController->mVePlayer[playerInstance]->setMediaRenderingMode( |
| pController->mClipList[index]->xVSS.MediaRendering, |
| pController->mOutputVideoSize); |
| ALOGV("preparePlayer: setMediaRenderingMode"); |
| |
| if((M4OSA_UInt32)index == pController->mStartingClipIndex) { |
| pController->mVePlayer[playerInstance]->setPlaybackBeginTime( |
| pController->mFirstPreviewClipBeginTime); |
| } |
| else { |
| pController->mVePlayer[playerInstance]->setPlaybackBeginTime( |
| pController->mClipList[index]->uiBeginCutTime); |
| } |
| ALOGV("preparePlayer: setPlaybackBeginTime(%d)", |
| pController->mClipList[index]->uiBeginCutTime); |
| |
| pController->mVePlayer[playerInstance]->setPlaybackEndTime( |
| pController->mClipList[index]->uiEndCutTime); |
| ALOGV("preparePlayer: setPlaybackEndTime(%d)", |
| pController->mClipList[index]->uiEndCutTime); |
| |
| if(pController->mClipList[index]->FileType == M4VIDEOEDITING_kFileType_ARGB8888) { |
| pController->mVePlayer[playerInstance]->setImageClipProperties( |
| pController->mClipList[index]->ClipProperties.uiVideoWidth, |
| pController->mClipList[index]->ClipProperties.uiVideoHeight); |
| ALOGV("preparePlayer: setImageClipProperties"); |
| } |
| |
| pController->mVePlayer[playerInstance]->prepare(); |
| ALOGV("preparePlayer: prepared"); |
| |
| if(pController->mClipList[index]->uiBeginCutTime > 0) { |
| pController->mVePlayer[playerInstance]->seekTo( |
| pController->mClipList[index]->uiBeginCutTime); |
| |
| ALOGV("preparePlayer: seekTo(%d)", |
| pController->mClipList[index]->uiBeginCutTime); |
| } |
| pController->mVePlayer[pController->mCurrentPlayer]->setAudioPlayer(pController->mVEAudioPlayer); |
| |
| pController->mVePlayer[playerInstance]->readFirstVideoFrame(); |
| ALOGV("preparePlayer: readFirstVideoFrame of clip"); |
| |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorPreviewController::threadProc(M4OSA_Void* param) { |
| M4OSA_ERR err = M4NO_ERROR; |
| M4OSA_Int32 index = 0; |
| VideoEditorPreviewController *pController = |
| (VideoEditorPreviewController *)param; |
| |
| ALOGV("inside threadProc"); |
| if(pController->mPlayerState == VePlayerIdle) { |
| (pController->mCurrentClipNumber)++; |
| |
| ALOGD("threadProc: playing file index %d total clips %d", |
| pController->mCurrentClipNumber, pController->mNumberClipsToPreview); |
| |
| if((M4OSA_UInt32)pController->mCurrentClipNumber >= |
| pController->mNumberClipsToPreview) { |
| |
| ALOGD("All clips previewed"); |
| |
| pController->mCurrentPlayedDuration = 0; |
| pController->mCurrentClipDuration = 0; |
| pController->mCurrentPlayer = 0; |
| |
| if(pController->mPreviewLooping == M4OSA_TRUE) { |
| pController->mCurrentClipNumber = |
| pController->mStartingClipIndex; |
| |
| ALOGD("Preview looping TRUE, restarting from clip index %d", |
| pController->mCurrentClipNumber); |
| |
| // Reset the story board timestamp inside the player |
| for (int playerInst=0; playerInst<kTotalNumPlayerInstances; |
| playerInst++) { |
| pController->mVePlayer[playerInst]->resetJniCallbackTimeStamp(); |
| } |
| } |
| else { |
| M4OSA_UInt32 endArgs = 0; |
| if(pController->mJniCallback != NULL) { |
| pController->mJniCallback( |
| pController->mJniCookie, MSG_TYPE_PREVIEW_END, &endArgs); |
| } |
| pController->mPlayerState = VePlayerAutoStop; |
| |
| // Reset original begin cuttime of first previewed clip |
| pController->mClipList[pController->mStartingClipIndex]->uiBeginCutTime = |
| pController->mFirstPreviewClipBeginTime; |
| // Reset original end cuttime of last previewed clip |
| pController->mClipList[pController->mNumberClipsToPreview-1]->uiEndCutTime = |
| pController->mLastPreviewClipEndTime; |
| |
| // Return a warning to M4OSA thread handler |
| // so that thread is moved from executing state to open state |
| return M4WAR_NO_MORE_STREAM; |
| } |
| } |
| |
| index=pController->mCurrentClipNumber; |
| if((M4OSA_UInt32)pController->mCurrentClipNumber == pController->mStartingClipIndex) { |
| pController->mCurrentPlayedDuration += |
| pController->mVideoStoryBoardTimeMsUptoFirstPreviewClip; |
| |
| pController->mCurrentClipDuration = |
| pController->mClipList[pController->mCurrentClipNumber]->uiEndCutTime |
| - pController->mFirstPreviewClipBeginTime; |
| |
| preparePlayer((void*)pController, pController->mCurrentPlayer, index); |
| } |
| else { |
| pController->mCurrentPlayedDuration += |
| pController->mCurrentClipDuration; |
| |
| pController->mCurrentClipDuration = |
| pController->mClipList[pController->mCurrentClipNumber]->uiEndCutTime - |
| pController->mClipList[pController->mCurrentClipNumber]->uiBeginCutTime; |
| } |
| |
| pController->mVePlayer[pController->mCurrentPlayer]->setStoryboardStartTime( |
| pController->mCurrentPlayedDuration); |
| ALOGV("threadProc: setStoryboardStartTime"); |
| |
| // Set the next clip duration for Audio mix here |
| if((M4OSA_UInt32)pController->mCurrentClipNumber != pController->mStartingClipIndex) { |
| |
| pController->mVePlayer[pController->mCurrentPlayer]->setAudioMixStoryBoardParam( |
| pController->mCurrentPlayedDuration, |
| pController->mClipList[index]->uiBeginCutTime, |
| pController->mClipList[index]->ClipProperties.uiClipAudioVolumePercentage); |
| |
| ALOGV("threadProc: setAudioMixStoryBoardParam fromMS %d \ |
| ClipBeginTime %d", pController->mCurrentPlayedDuration + |
| pController->mClipList[index]->uiBeginCutTime, |
| pController->mClipList[index]->uiBeginCutTime, |
| pController->mClipList[index]->ClipProperties.uiClipAudioVolumePercentage); |
| } |
| // Capture the active player being used |
| pController->mActivePlayerIndex = pController->mCurrentPlayer; |
| |
| pController->mVePlayer[pController->mCurrentPlayer]->start(); |
| ALOGV("threadProc: started"); |
| |
| pController->mPlayerState = VePlayerBusy; |
| |
| } else if(pController->mPlayerState == VePlayerAutoStop) { |
| ALOGV("Preview completed..auto stop the player"); |
| } else if ((pController->mPlayerState == VePlayerBusy) && (pController->mPrepareReqest)) { |
| // Prepare the player here |
| pController->mPrepareReqest = M4OSA_FALSE; |
| preparePlayer((void*)pController, pController->mCurrentPlayer, |
| pController->mCurrentClipNumber+1); |
| if (pController->mSemThreadWait != NULL) { |
| err = M4OSA_semaphoreWait(pController->mSemThreadWait, |
| M4OSA_WAIT_FOREVER); |
| } |
| } else { |
| if (!pController->bStopThreadInProgress) { |
| ALOGV("threadProc: state busy...wait for sem"); |
| if (pController->mSemThreadWait != NULL) { |
| err = M4OSA_semaphoreWait(pController->mSemThreadWait, |
| M4OSA_WAIT_FOREVER); |
| } |
| } |
| ALOGV("threadProc: sem wait returned err = 0x%x", err); |
| } |
| |
| //Always return M4NO_ERROR to ensure the thread keeps running |
| return M4NO_ERROR; |
| } |
| |
| void VideoEditorPreviewController::notify( |
| void* cookie, int msg, int ext1, int ext2) |
| { |
| VideoEditorPreviewController *pController = |
| (VideoEditorPreviewController *)cookie; |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| uint32_t clipDuration = 0; |
| switch (msg) { |
| case MEDIA_NOP: // interface test message |
| ALOGV("MEDIA_NOP"); |
| break; |
| case MEDIA_PREPARED: |
| ALOGV("MEDIA_PREPARED"); |
| break; |
| case MEDIA_PLAYBACK_COMPLETE: |
| { |
| ALOGD("notify:MEDIA_PLAYBACK_COMPLETE, mCurrentClipNumber = %d", |
| pController->mCurrentClipNumber); |
| pController->mPlayerState = VePlayerIdle; |
| |
| //send progress callback with last frame timestamp |
| if((M4OSA_UInt32)pController->mCurrentClipNumber == |
| pController->mStartingClipIndex) { |
| clipDuration = |
| pController->mClipList[pController->mCurrentClipNumber]->uiEndCutTime |
| - pController->mFirstPreviewClipBeginTime; |
| } |
| else { |
| clipDuration = |
| pController->mClipList[pController->mCurrentClipNumber]->uiEndCutTime |
| - pController->mClipList[pController->mCurrentClipNumber]->uiBeginCutTime; |
| } |
| |
| M4OSA_UInt32 playedDuration = clipDuration+pController->mCurrentPlayedDuration; |
| pController->mJniCallback( |
| pController->mJniCookie, MSG_TYPE_PROGRESS_INDICATION, |
| &playedDuration); |
| |
| if ((pController->mOverlayState == OVERLAY_UPDATE) && |
| ((M4OSA_UInt32)pController->mCurrentClipNumber != |
| (pController->mNumberClipsToPreview-1))) { |
| VideoEditorCurretEditInfo *pEditInfo = |
| (VideoEditorCurretEditInfo*)M4OSA_32bitAlignedMalloc(sizeof(VideoEditorCurretEditInfo), |
| M4VS, (M4OSA_Char*)"Current Edit info"); |
| pEditInfo->overlaySettingsIndex = ext2; |
| pEditInfo->clipIndex = pController->mCurrentClipNumber; |
| pController->mOverlayState == OVERLAY_CLEAR; |
| if (pController->mJniCallback != NULL) { |
| pController->mJniCallback(pController->mJniCookie, |
| MSG_TYPE_OVERLAY_CLEAR, pEditInfo); |
| } |
| free(pEditInfo); |
| } |
| { |
| Mutex::Autolock autoLock(pController->mLockSem); |
| if (pController->mSemThreadWait != NULL) { |
| M4OSA_semaphorePost(pController->mSemThreadWait); |
| return; |
| } |
| } |
| |
| break; |
| } |
| case MEDIA_ERROR: |
| { |
| int err_val = ext1; |
| // Always log errors. |
| // ext1: Media framework error code. |
| // ext2: Implementation dependant error code. |
| ALOGE("MEDIA_ERROR; error (%d, %d)", ext1, ext2); |
| if(pController->mJniCallback != NULL) { |
| pController->mJniCallback(pController->mJniCookie, |
| MSG_TYPE_PLAYER_ERROR, &err_val); |
| } |
| break; |
| } |
| case MEDIA_INFO: |
| { |
| int info_val = ext2; |
| // ext1: Media framework error code. |
| // ext2: Implementation dependant error code. |
| //ALOGW("MEDIA_INFO; info/warning (%d, %d)", ext1, ext2); |
| if(pController->mJniCallback != NULL) { |
| pController->mJniCallback(pController->mJniCookie, |
| MSG_TYPE_PROGRESS_INDICATION, &info_val); |
| } |
| break; |
| } |
| case MEDIA_SEEK_COMPLETE: |
| ALOGV("MEDIA_SEEK_COMPLETE; Received seek complete"); |
| break; |
| case MEDIA_BUFFERING_UPDATE: |
| ALOGV("MEDIA_BUFFERING_UPDATE; buffering %d", ext1); |
| break; |
| case MEDIA_SET_VIDEO_SIZE: |
| ALOGV("MEDIA_SET_VIDEO_SIZE; New video size %d x %d", ext1, ext2); |
| break; |
| case 0xAAAAAAAA: |
| ALOGV("VIDEO PLAYBACK ALMOST over, prepare next player"); |
| // Select next player and prepare it |
| // If there is a clip after this one |
| if ((M4OSA_UInt32)(pController->mCurrentClipNumber+1) < |
| pController->mNumberClipsToPreview) { |
| pController->mPrepareReqest = M4OSA_TRUE; |
| pController->mCurrentPlayer++; |
| if (pController->mCurrentPlayer >= kTotalNumPlayerInstances) { |
| pController->mCurrentPlayer = 0; |
| } |
| // Prepare the first clip to be played |
| { |
| Mutex::Autolock autoLock(pController->mLockSem); |
| if (pController->mSemThreadWait != NULL) { |
| M4OSA_semaphorePost(pController->mSemThreadWait); |
| } |
| } |
| } |
| break; |
| case 0xBBBBBBBB: |
| { |
| ALOGV("VIDEO PLAYBACK, Update Overlay"); |
| int overlayIndex = ext2; |
| VideoEditorCurretEditInfo *pEditInfo = |
| (VideoEditorCurretEditInfo*)M4OSA_32bitAlignedMalloc(sizeof(VideoEditorCurretEditInfo), |
| M4VS, (M4OSA_Char*)"Current Edit info"); |
| //ext1 = 1; start the overlay display |
| // = 2; Clear the overlay. |
| pEditInfo->overlaySettingsIndex = ext2; |
| pEditInfo->clipIndex = pController->mCurrentClipNumber; |
| ALOGV("pController->mCurrentClipNumber = %d",pController->mCurrentClipNumber); |
| if (pController->mJniCallback != NULL) { |
| if (ext1 == 1) { |
| pController->mOverlayState = OVERLAY_UPDATE; |
| pController->mJniCallback(pController->mJniCookie, |
| MSG_TYPE_OVERLAY_UPDATE, pEditInfo); |
| } else { |
| pController->mOverlayState = OVERLAY_CLEAR; |
| pController->mJniCallback(pController->mJniCookie, |
| MSG_TYPE_OVERLAY_CLEAR, pEditInfo); |
| } |
| } |
| free(pEditInfo); |
| break; |
| } |
| default: |
| ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2); |
| break; |
| } |
| } |
| |
| void VideoEditorPreviewController::setVideoEffectType( |
| M4VSS3GPP_VideoEffectType type, M4OSA_Bool enable) { |
| |
| M4OSA_UInt32 effect = VIDEO_EFFECT_NONE; |
| |
| // map M4VSS3GPP_VideoEffectType to local enum |
| switch(type) { |
| case M4VSS3GPP_kVideoEffectType_FadeFromBlack: |
| effect = VIDEO_EFFECT_FADEFROMBLACK; |
| break; |
| |
| case M4VSS3GPP_kVideoEffectType_FadeToBlack: |
| effect = VIDEO_EFFECT_FADETOBLACK; |
| break; |
| |
| case M4xVSS_kVideoEffectType_BlackAndWhite: |
| effect = VIDEO_EFFECT_BLACKANDWHITE; |
| break; |
| |
| case M4xVSS_kVideoEffectType_Pink: |
| effect = VIDEO_EFFECT_PINK; |
| break; |
| |
| case M4xVSS_kVideoEffectType_Green: |
| effect = VIDEO_EFFECT_GREEN; |
| break; |
| |
| case M4xVSS_kVideoEffectType_Sepia: |
| effect = VIDEO_EFFECT_SEPIA; |
| break; |
| |
| case M4xVSS_kVideoEffectType_Negative: |
| effect = VIDEO_EFFECT_NEGATIVE; |
| break; |
| |
| case M4xVSS_kVideoEffectType_Framing: |
| effect = VIDEO_EFFECT_FRAMING; |
| break; |
| |
| case M4xVSS_kVideoEffectType_Fifties: |
| effect = VIDEO_EFFECT_FIFTIES; |
| break; |
| |
| case M4xVSS_kVideoEffectType_ColorRGB16: |
| effect = VIDEO_EFFECT_COLOR_RGB16; |
| break; |
| |
| case M4xVSS_kVideoEffectType_Gradient: |
| effect = VIDEO_EFFECT_GRADIENT; |
| break; |
| |
| default: |
| effect = VIDEO_EFFECT_NONE; |
| break; |
| } |
| |
| if(enable == M4OSA_TRUE) { |
| // If already set, then no need to set again |
| if(!(mCurrentVideoEffect & effect)) |
| mCurrentVideoEffect |= effect; |
| if(effect == VIDEO_EFFECT_FIFTIES) { |
| mIsFiftiesEffectStarted = true; |
| } |
| } |
| else { |
| // Reset only if already set |
| if(mCurrentVideoEffect & effect) |
| mCurrentVideoEffect &= ~effect; |
| } |
| |
| return; |
| } |
| |
| |
| M4OSA_ERR VideoEditorPreviewController::applyVideoEffect( |
| M4OSA_Void * dataPtr, M4OSA_UInt32 colorFormat, M4OSA_UInt32 videoWidth, |
| M4OSA_UInt32 videoHeight, M4OSA_UInt32 timeMs, M4OSA_Void* outPtr) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| vePostProcessParams postProcessParams; |
| |
| postProcessParams.vidBuffer = (M4VIFI_UInt8*)dataPtr; |
| postProcessParams.videoWidth = videoWidth; |
| postProcessParams.videoHeight = videoHeight; |
| postProcessParams.timeMs = timeMs; |
| postProcessParams.timeOffset = 0; //Since timeMS already takes care of offset in this case |
| postProcessParams.effectsSettings = mEffectsSettings; |
| postProcessParams.numberEffects = mNumberEffects; |
| postProcessParams.outVideoWidth = mOutputVideoWidth; |
| postProcessParams.outVideoHeight = mOutputVideoHeight; |
| postProcessParams.currentVideoEffect = mCurrentVideoEffect; |
| postProcessParams.renderingMode = mRenderingMode; |
| if(mIsFiftiesEffectStarted == M4OSA_TRUE) { |
| postProcessParams.isFiftiesEffectStarted = M4OSA_TRUE; |
| mIsFiftiesEffectStarted = M4OSA_FALSE; |
| } |
| else { |
| postProcessParams.isFiftiesEffectStarted = M4OSA_FALSE; |
| } |
| //postProcessParams.renderer = mTarget; |
| postProcessParams.overlayFrameRGBBuffer = NULL; |
| postProcessParams.overlayFrameYUVBuffer = NULL; |
| |
| mTarget->getBufferYV12(&(postProcessParams.pOutBuffer), &(postProcessParams.outBufferStride)); |
| |
| err = applyEffectsAndRenderingMode(&postProcessParams, videoWidth, videoHeight); |
| return err; |
| } |
| |
| status_t VideoEditorPreviewController::setPreviewFrameRenderingMode( |
| M4xVSS_MediaRendering mode, M4VIDEOEDITING_VideoFrameSize outputVideoSize) { |
| |
| ALOGV("setMediaRenderingMode: outputVideoSize = %d", outputVideoSize); |
| mRenderingMode = mode; |
| |
| status_t err = OK; |
| /* get the video width and height by resolution */ |
| err = getVideoSizeByResolution(outputVideoSize, |
| &mOutputVideoWidth, &mOutputVideoHeight); |
| |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorPreviewController::doImageRenderingMode( |
| M4OSA_Void * dataPtr, M4OSA_UInt32 colorFormat, M4OSA_UInt32 videoWidth, |
| M4OSA_UInt32 videoHeight, M4OSA_Void* outPtr) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| M4VIFI_ImagePlane planeIn[3], planeOut[3]; |
| M4VIFI_UInt8 *inBuffer = M4OSA_NULL; |
| M4OSA_UInt32 outputBufferWidth =0, outputBufferHeight=0; |
| |
| //frameSize = (videoWidth*videoHeight*3) >> 1; |
| inBuffer = (M4OSA_UInt8 *)dataPtr; |
| |
| // In plane |
| prepareYUV420ImagePlane(planeIn, videoWidth, |
| videoHeight, (M4VIFI_UInt8 *)inBuffer, videoWidth, videoHeight); |
| |
| outputBufferWidth = mOutputVideoWidth; |
| outputBufferHeight = mOutputVideoHeight; |
| |
| // Out plane |
| uint8_t* outBuffer; |
| size_t outBufferStride = 0; |
| |
| ALOGV("doMediaRendering CALL getBuffer()"); |
| mTarget->getBufferYV12(&outBuffer, &outBufferStride); |
| |
| // Set the output YUV420 plane to be compatible with YV12 format |
| //In YV12 format, sizes must be even |
| M4OSA_UInt32 yv12PlaneWidth = ((mOutputVideoWidth +1)>>1)<<1; |
| M4OSA_UInt32 yv12PlaneHeight = ((mOutputVideoHeight+1)>>1)<<1; |
| |
| prepareYV12ImagePlane(planeOut, yv12PlaneWidth, yv12PlaneHeight, |
| (M4OSA_UInt32)outBufferStride, (M4VIFI_UInt8 *)outBuffer); |
| |
| err = applyRenderingMode(planeIn, planeOut, mRenderingMode); |
| if(err != M4NO_ERROR) { |
| ALOGE("doImageRenderingMode: applyRenderingMode returned err=0x%x", (unsigned int)err); |
| } |
| return err; |
| } |
| |
| } //namespace android |