/* | |
* Copyright (C) 2011 NXP Software | |
* 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 1 | |
#define LOG_TAG "VideoEditorPreviewController" | |
#include "VideoEditorPreviewController.h" | |
namespace android { | |
#define PREVIEW_THREAD_STACK_SIZE (65536) | |
VideoEditorPreviewController::VideoEditorPreviewController() | |
: mCurrentPlayer(0), | |
mActivePlayerIndex(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), | |
mTarget(NULL), | |
mJniCookie(NULL), | |
mJniCallback(NULL), | |
mBackgroundAudioSetting(NULL), | |
mAudioMixPCMFileHandle(NULL), | |
mVideoStoryBoardTimeMsUptoFirstPreviewClip(0), | |
mCurrentPlayedDuration(0), | |
mCurrentClipDuration(0), | |
mOutputVideoWidth(0), | |
mOutputVideoHeight(0), | |
bStopThreadInProgress(false), | |
mOverlayState(OVERLAY_CLEAR), | |
mSemThreadWait(NULL) { | |
LOGV("VideoEditorPreviewController"); | |
mRenderingMode = M4xVSS_kBlackBorders; | |
mIsFiftiesEffectStarted = false; | |
for (int i=0; i<NBPLAYER_INSTANCES; i++) { | |
mVePlayer[i] = NULL; | |
} | |
} | |
VideoEditorPreviewController::~VideoEditorPreviewController() { | |
M4OSA_UInt32 i = 0; | |
M4OSA_ERR err = M4NO_ERROR; | |
LOGV("~VideoEditorPreviewController"); | |
// Stop the thread if its still running | |
if(mThreadContext != NULL) { | |
err = M4OSA_threadSyncStop(mThreadContext); | |
if(err != M4NO_ERROR) { | |
LOGV("~VideoEditorPreviewController: error 0x%x \ | |
in trying to stop thread", err); | |
// Continue even if error | |
} | |
err = M4OSA_threadSyncClose(mThreadContext); | |
if(err != M4NO_ERROR) { | |
LOGE("~VideoEditorPreviewController: error 0x%x \ | |
in trying to close thread", err); | |
// Continue even if error | |
} | |
mThreadContext = NULL; | |
} | |
for (int playerInst=0; playerInst<NBPLAYER_INSTANCES; | |
playerInst++) { | |
if(mVePlayer[playerInst] != NULL) { | |
LOGV("clearing mVePlayer %d", playerInst); | |
mVePlayer[playerInst].clear(); | |
} | |
} | |
if(mClipList != NULL) { | |
// Clean up | |
for(i=0;i<mNumberClipsInStoryBoard;i++) | |
{ | |
if(mClipList[i]->pFile != NULL) { | |
M4OSA_free((M4OSA_MemAddr32)mClipList[i]->pFile); | |
mClipList[i]->pFile = NULL; | |
} | |
M4OSA_free((M4OSA_MemAddr32)mClipList[i]); | |
} | |
M4OSA_free((M4OSA_MemAddr32)mClipList); | |
mClipList = NULL; | |
} | |
if(mEffectsSettings) { | |
for(i=0;i<mNumberEffects;i++) { | |
if(mEffectsSettings[i].xVSS.pFramingBuffer != NULL) { | |
M4OSA_free( | |
(M4OSA_MemAddr32)mEffectsSettings[i].xVSS.pFramingBuffer->pac_data); | |
M4OSA_free( | |
(M4OSA_MemAddr32)mEffectsSettings[i].xVSS.pFramingBuffer); | |
mEffectsSettings[i].xVSS.pFramingBuffer = NULL; | |
} | |
} | |
M4OSA_free((M4OSA_MemAddr32)mEffectsSettings); | |
mEffectsSettings = NULL; | |
} | |
if (mAudioMixPCMFileHandle) { | |
err = M4OSA_fileReadClose (mAudioMixPCMFileHandle); | |
mAudioMixPCMFileHandle = M4OSA_NULL; | |
} | |
if (mBackgroundAudioSetting != NULL) { | |
M4OSA_free((M4OSA_MemAddr32)mBackgroundAudioSetting); | |
mBackgroundAudioSetting = NULL; | |
} | |
if(mTarget != NULL) { | |
delete mTarget; | |
mTarget = NULL; | |
} | |
mOverlayState = OVERLAY_CLEAR; | |
LOGV("~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; | |
LOGV("loadEditSettings"); | |
LOGV("loadEditSettings Channels = %d, sampling Freq %d", | |
bgmSettings->uiNbChannels, bgmSettings->uiSamplingFrequency ); | |
bgmSettings->uiSamplingFrequency = 32000; | |
LOGV("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) { | |
M4OSA_free((M4OSA_MemAddr32)mBackgroundAudioSetting); | |
mBackgroundAudioSetting = NULL; | |
} | |
if(mClipList != NULL) { | |
// Clean up | |
for(i=0;i<mNumberClipsInStoryBoard;i++) | |
{ | |
if(mClipList[i]->pFile != NULL) { | |
M4OSA_free((M4OSA_MemAddr32)mClipList[i]->pFile); | |
mClipList[i]->pFile = NULL; | |
} | |
M4OSA_free((M4OSA_MemAddr32)mClipList[i]); | |
} | |
M4OSA_free((M4OSA_MemAddr32)mClipList); | |
mClipList = NULL; | |
} | |
if(mEffectsSettings) { | |
for(i=0;i<mNumberEffects;i++) { | |
if(mEffectsSettings[i].xVSS.pFramingBuffer != NULL) { | |
M4OSA_free( | |
(M4OSA_MemAddr32)mEffectsSettings[i].xVSS.pFramingBuffer->pac_data); | |
M4OSA_free( | |
(M4OSA_MemAddr32)mEffectsSettings[i].xVSS.pFramingBuffer); | |
mEffectsSettings[i].xVSS.pFramingBuffer = NULL; | |
} | |
} | |
M4OSA_free((M4OSA_MemAddr32)mEffectsSettings); | |
mEffectsSettings = NULL; | |
} | |
if(mClipList == NULL) { | |
mNumberClipsInStoryBoard = pSettings->uiClipNumber; | |
LOGV("loadEditSettings: # of Clips = %d", mNumberClipsInStoryBoard); | |
mClipList = (M4VSS3GPP_ClipSettings**)M4OSA_malloc( | |
sizeof(M4VSS3GPP_ClipSettings*)*pSettings->uiClipNumber, M4VS, | |
(M4OSA_Char*)"LvPP, copy of pClipList"); | |
if(NULL == mClipList) { | |
LOGE("loadEditSettings: Malloc error"); | |
return M4ERR_ALLOC; | |
} | |
M4OSA_memset((M4OSA_MemAddr8)mClipList, | |
sizeof(M4VSS3GPP_ClipSettings*)*pSettings->uiClipNumber, 0); | |
for(i=0;i<pSettings->uiClipNumber;i++) { | |
// Allocate current clip | |
mClipList[i] = | |
(M4VSS3GPP_ClipSettings*)M4OSA_malloc( | |
sizeof(M4VSS3GPP_ClipSettings),M4VS,(M4OSA_Char*)"clip settings"); | |
if(mClipList[i] == NULL) { | |
LOGE("loadEditSettings: Allocation error for mClipList[%d]", i); | |
return M4ERR_ALLOC; | |
} | |
// Copy plain structure | |
M4OSA_memcpy((M4OSA_MemAddr8)mClipList[i], | |
(M4OSA_MemAddr8)pSettings->pClipList[i], | |
sizeof(M4VSS3GPP_ClipSettings)); | |
if(NULL != pSettings->pClipList[i]->pFile) { | |
mClipList[i]->pFile = (M4OSA_Char*)M4OSA_malloc( | |
pSettings->pClipList[i]->filePathSize, M4VS, | |
(M4OSA_Char*)"pClipSettingsDest->pFile"); | |
if(NULL == mClipList[i]->pFile) | |
{ | |
LOGE("loadEditSettings : ERROR allocating filename"); | |
return M4ERR_ALLOC; | |
} | |
M4OSA_memcpy((M4OSA_MemAddr8)mClipList[i]->pFile, | |
(M4OSA_MemAddr8)pSettings->pClipList[i]->pFile, | |
pSettings->pClipList[i]->filePathSize); | |
} | |
else { | |
LOGE("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; | |
LOGV("loadEditSettings: mNumberEffects = %d", mNumberEffects); | |
if(mNumberEffects != 0) { | |
mEffectsSettings = (M4VSS3GPP_EffectSettings*)M4OSA_malloc( | |
mNumberEffects*sizeof(M4VSS3GPP_EffectSettings), | |
M4VS, (M4OSA_Char*)"effects settings"); | |
if(mEffectsSettings == NULL) { | |
LOGE("loadEffectsSettings: Allocation error"); | |
return M4ERR_ALLOC; | |
} | |
M4OSA_memset((M4OSA_MemAddr8)mEffectsSettings, | |
mNumberEffects*sizeof(M4VSS3GPP_EffectSettings), 0); | |
for(i=0;i<mNumberEffects;i++) { | |
mEffectsSettings[i].xVSS.pFramingFilePath = NULL; | |
mEffectsSettings[i].xVSS.pFramingBuffer = NULL; | |
mEffectsSettings[i].xVSS.pTextBuffer = NULL; | |
M4OSA_memcpy((M4OSA_MemAddr8)&(mEffectsSettings[i]), | |
(M4OSA_MemAddr8)&(pSettings->Effects[i]), | |
sizeof(M4VSS3GPP_EffectSettings)); | |
if(pSettings->Effects[i].VideoEffectType == | |
M4xVSS_kVideoEffectType_Framing) { | |
// Allocate the pFraming RGB buffer | |
mEffectsSettings[i].xVSS.pFramingBuffer = | |
(M4VIFI_ImagePlane *)M4OSA_malloc(sizeof(M4VIFI_ImagePlane), | |
M4VS, (M4OSA_Char*)"lvpp framing buffer"); | |
if(mEffectsSettings[i].xVSS.pFramingBuffer == NULL) { | |
LOGE("loadEffectsSettings:Alloc error for pFramingBuf"); | |
M4OSA_free((M4OSA_MemAddr32)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 { | |
LOGE("loadEffectsSettings: wrong RGB type"); | |
M4OSA_free((M4OSA_MemAddr32)mEffectsSettings); | |
mEffectsSettings = NULL; | |
return M4ERR_PARAMETER; | |
} | |
tmp = (M4VIFI_UInt8 *)M4OSA_malloc(rgbSize, M4VS, | |
(M4OSA_Char*)"framing buffer pac_data"); | |
if(tmp == NULL) { | |
LOGE("loadEffectsSettings:Alloc error pFramingBuf pac"); | |
M4OSA_free((M4OSA_MemAddr32)mEffectsSettings); | |
mEffectsSettings = NULL; | |
M4OSA_free( | |
(M4OSA_MemAddr32)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 | |
M4OSA_memcpy((M4OSA_MemAddr8) | |
mEffectsSettings[i].xVSS.pFramingBuffer->pac_data, | |
(M4OSA_MemAddr8)pSettings->Effects[i].xVSS.pFramingBuffer->pac_data, | |
rgbSize); | |
mEffectsSettings[i].xVSS.rgbType = | |
pSettings->Effects[i].xVSS.rgbType; | |
} | |
} | |
} | |
} | |
if (mBackgroundAudioSetting == NULL) { | |
mBackgroundAudioSetting = (M4xVSS_AudioMixingSettings*)M4OSA_malloc( | |
sizeof(M4xVSS_AudioMixingSettings), M4VS, | |
(M4OSA_Char*)"LvPP, copy of bgmSettings"); | |
if(NULL == mBackgroundAudioSetting) { | |
LOGE("loadEditSettings: mBackgroundAudioSetting Malloc failed"); | |
return M4ERR_ALLOC; | |
} | |
M4OSA_memset((M4OSA_MemAddr8)mBackgroundAudioSetting, sizeof(M4xVSS_AudioMixingSettings*), 0); | |
M4OSA_memcpy((M4OSA_MemAddr8)mBackgroundAudioSetting, (M4OSA_MemAddr8)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) { | |
LOGE("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) { | |
LOGV("setSurface"); | |
Mutex::Autolock autoLock(mLock); | |
mSurface = surface; | |
mISurface = surface->getISurface(); | |
LOGV("setSurface: mISurface = %p", mISurface.get()); | |
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; | |
LOGV("startPreview"); | |
if(fromMS > toMs) { | |
LOGE("startPreview: fromMS > toMs"); | |
return M4ERR_PARAMETER; | |
} | |
if(toMs == 0) { | |
LOGE("startPreview: toMs is 0"); | |
return M4ERR_PARAMETER; | |
} | |
// If already started, then stop preview first | |
for(int playerInst=0; playerInst<NBPLAYER_INSTANCES; playerInst++) { | |
if(mVePlayer[playerInst] != NULL) { | |
LOGV("startPreview: stopping previously started preview playback"); | |
stopPreview(); | |
break; | |
} | |
} | |
// If renderPreview was called previously, then delete Renderer object first | |
if(mTarget != NULL) { | |
LOGV("startPreview: delete previous PreviewRenderer"); | |
delete mTarget; | |
mTarget = NULL; | |
} | |
LOGV("startPreview: loop = %d", loop); | |
mPreviewLooping = loop; | |
LOGV("startPreview: callBackAfterFrameCount = %d", callBackAfterFrameCount); | |
mCallBackAfterFrameCnt = callBackAfterFrameCount; | |
for (int playerInst=0; playerInst<NBPLAYER_INSTANCES; playerInst++) { | |
mVePlayer[playerInst] = new VideoEditorPlayer(); | |
if(mVePlayer[playerInst] == NULL) { | |
LOGE("startPreview:Error creating VideoEditorPlayer %d",playerInst); | |
return M4ERR_ALLOC; | |
} | |
LOGV("startPreview: object created"); | |
mVePlayer[playerInst]->setNotifyCallback(this,(notify_callback_f)notify); | |
LOGV("startPreview: notify callback set"); | |
mVePlayer[playerInst]->loadEffectsSettings(mEffectsSettings, | |
mNumberEffects); | |
LOGV("startPreview: effects settings loaded"); | |
mVePlayer[playerInst]->loadAudioMixSettings(mBackgroundAudioSetting); | |
LOGV("startPreview: AudioMixSettings settings loaded"); | |
mVePlayer[playerInst]->setAudioMixPCMFileHandle(mAudioMixPCMFileHandle); | |
LOGV("startPreview: AudioMixPCMFileHandle set"); | |
mVePlayer[playerInst]->setProgressCallbackInterval( | |
mCallBackAfterFrameCnt); | |
LOGV("startPreview: setProgressCallBackInterval"); | |
} | |
mPlayerState = VePlayerIdle; | |
mPrepareReqest = M4OSA_FALSE; | |
if(fromMS == 0) { | |
mCurrentClipNumber = -1; | |
// Save original value | |
mFirstPreviewClipBeginTime = mClipList[0]->uiBeginCutTime; | |
mVideoStoryBoardTimeMsUptoFirstPreviewClip = 0; | |
} | |
else { | |
LOGV("startPreview: fromMS=%d", fromMS); | |
if(fromMS >= mClipTotalDuration) { | |
LOGE("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; | |
LOGV("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<NBPLAYER_INSTANCES; playerInst++) { | |
mVePlayer[playerInst]->setAudioMixStoryBoardParam(fromMS, | |
mFirstPreviewClipBeginTime, | |
mClipList[i]->ClipProperties.uiClipAudioVolumePercentage); | |
LOGV("startPreview:setAudioMixStoryBoardSkimTimeStamp set %d cuttime \ | |
%d", fromMS, mFirstPreviewClipBeginTime); | |
} | |
mStartingClipIndex = mCurrentClipNumber+1; | |
// Start playing with player instance 0 | |
mCurrentPlayer = 0; | |
mActivePlayerIndex = 0; | |
if(toMs == -1) { | |
LOGV("startPreview: Preview till end of storyboard"); | |
mNumberClipsToPreview = mNumberClipsInStoryBoard; | |
// Save original value | |
mLastPreviewClipEndTime = | |
mClipList[mNumberClipsToPreview-1]->uiEndCutTime; | |
} | |
else { | |
LOGV("startPreview: toMs=%d", toMs); | |
if(toMs > mClipTotalDuration) { | |
LOGE("startPreview: toMs > mClipTotalDuration"); | |
return M4ERR_PARAMETER; | |
} | |
iIncrementedDuration = 0; | |
for(i=0;i<mNumberClipsInStoryBoard;i++) { | |
if(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) { | |
LOGE("VideoEditorPreviewController:M4OSA_threadSyncOpen error %d", err); | |
return err; | |
} | |
// Set the stacksize | |
err = M4OSA_threadSyncSetOption(mThreadContext, M4OSA_ThreadStackSize, | |
(M4OSA_DataOption)PREVIEW_THREAD_STACK_SIZE); | |
if (M4NO_ERROR != err) { | |
LOGE("VideoEditorPreviewController: threadSyncSetOption error %d", err); | |
M4OSA_threadSyncClose(mThreadContext); | |
mThreadContext = NULL; | |
return err; | |
} | |
// Start the thread | |
err = M4OSA_threadSyncStart(mThreadContext, (M4OSA_Void*)this); | |
if (M4NO_ERROR != err) { | |
LOGE("VideoEditorPreviewController: threadSyncStart error %d", err); | |
M4OSA_threadSyncClose(mThreadContext); | |
mThreadContext = NULL; | |
return err; | |
} | |
bStopThreadInProgress = false; | |
LOGV("startPreview: process thread started"); | |
return M4NO_ERROR; | |
} | |
M4OSA_UInt32 VideoEditorPreviewController::stopPreview() { | |
M4OSA_ERR err = M4NO_ERROR; | |
uint32_t lastRenderedFrameTimeMs = 0; | |
LOGV("stopPreview"); | |
// Stop the thread | |
if(mThreadContext != NULL) { | |
bStopThreadInProgress = true; | |
err = M4OSA_semaphorePost(mSemThreadWait); | |
err = M4OSA_threadSyncStop(mThreadContext); | |
if(err != M4NO_ERROR) { | |
LOGV("stopPreview: error 0x%x in trying to stop thread", err); | |
// Continue even if error | |
} | |
err = M4OSA_threadSyncClose(mThreadContext); | |
if(err != M4NO_ERROR) { | |
LOGE("stopPreview: error 0x%x in trying to close thread", err); | |
// Continue even if error | |
} | |
mThreadContext = NULL; | |
} | |
// Close the semaphore first | |
if(mSemThreadWait != NULL) { | |
err = M4OSA_semaphoreClose(mSemThreadWait); | |
LOGV("stopPreview: close semaphore returns 0x%x", err); | |
} | |
for (int playerInst=0; playerInst<NBPLAYER_INSTANCES; playerInst++) { | |
if(mVePlayer[playerInst] != NULL) { | |
if(mVePlayer[playerInst]->isPlaying()) { | |
LOGV("stop the player first"); | |
mVePlayer[playerInst]->stop(); | |
} | |
if (playerInst == mActivePlayerIndex) { | |
// Return the last rendered frame time stamp | |
mVePlayer[mActivePlayerIndex]->getLastRenderedTimeMs(&lastRenderedFrameTimeMs); | |
} | |
LOGV("stopPreview: clearing mVePlayer"); | |
mVePlayer[playerInst].clear(); | |
mVePlayer[playerInst] = NULL; | |
} | |
} | |
// If image file playing, then free the buffer pointer | |
if(mFrameStr.pBuffer != M4OSA_NULL) { | |
M4OSA_free((M4OSA_MemAddr32)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; | |
LOGV("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]; | |
LOGV("Inside preview clear frame"); | |
Mutex::Autolock autoLock(mLock); | |
// Get the Isurface to be passed to renderer | |
mISurface = surface->getISurface(); | |
// 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( | |
OMX_COLOR_FormatYUV420Planar, surface, outputBufferWidth, outputBufferHeight, | |
outputBufferWidth, outputBufferHeight, 0); | |
if(mTarget == NULL) { | |
LOGE("renderPreviewFrame: cannot create PreviewRenderer"); | |
return M4ERR_ALLOC; | |
} | |
} | |
// Out plane | |
uint8_t* outBuffer; | |
size_t outBufferStride = 0; | |
LOGV("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 */ | |
M4OSA_memset((M4OSA_MemAddr8)planeOut[0].pac_data,planeOut[0].u_width * | |
planeOut[0].u_height * 1.5,0x00); | |
M4OSA_memset((M4OSA_MemAddr8)planeOut[1].pac_data,planeOut[1].u_width * | |
planeOut[1].u_height,128); | |
M4OSA_memset((M4OSA_MemAddr8)planeOut[2].pac_data,planeOut[2].u_width * | |
planeOut[2].u_height,128); | |
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); | |
// Get the Isurface to be passed to renderer | |
mISurface = surface->getISurface(); | |
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 = new PreviewRenderer( | |
OMX_COLOR_FormatYUV420Planar, surface, mOutputVideoWidth, mOutputVideoHeight, | |
mOutputVideoWidth, mOutputVideoHeight, 0);*/ | |
mTarget = PreviewRenderer::CreatePreviewRenderer( | |
OMX_COLOR_FormatYUV420Planar, surface, mOutputVideoWidth, mOutputVideoHeight, | |
mOutputVideoWidth, mOutputVideoHeight, 0); | |
if(mTarget == NULL) { | |
LOGE("renderPreviewFrame: cannot create PreviewRenderer"); | |
return M4ERR_ALLOC; | |
} | |
} | |
pixelArray = NULL; | |
// 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) { | |
int 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 == | |
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; | |
LOGV("Framing index = %d", index); | |
} else { | |
LOGV("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) { | |
LOGE("renderPreviewFrame: applyVideoEffect error 0x%x", err); | |
delete mTarget; | |
mTarget = NULL; | |
M4OSA_free((M4OSA_MemAddr32)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) { | |
LOGE("renderPreviewFrame:doImageRenderingMode error 0x%x", err); | |
delete mTarget; | |
mTarget = NULL; | |
M4OSA_free((M4OSA_MemAddr32)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) { | |
LOGE("renderPreviewFrame: doImageRenderingMode error 0x%x", err); | |
delete mTarget; | |
mTarget = NULL; | |
M4OSA_free((M4OSA_MemAddr32)pixelArray); | |
pixelArray = NULL; | |
return err; | |
} | |
} | |
mTarget->renderYV12(); | |
return err; | |
} | |
M4OSA_Void VideoEditorPreviewController::setJniCallback(void* cookie, | |
jni_progress_callback_fct callbackFct) { | |
//LOGV("setJniCallback"); | |
mJniCookie = cookie; | |
mJniCallback = callbackFct; | |
} | |
M4OSA_ERR VideoEditorPreviewController::preparePlayer( | |
void* param, int playerInstance, int index) { | |
M4OSA_ERR err = M4NO_ERROR; | |
VideoEditorPreviewController *pController = | |
(VideoEditorPreviewController *)param; | |
LOGV("preparePlayer: instance %d file %d", playerInstance, index); | |
pController->mVePlayer[playerInstance]->setDataSource( | |
(const char *)pController->mClipList[index]->pFile, NULL); | |
LOGV("preparePlayer: setDataSource instance %s", | |
(const char *)pController->mClipList[index]->pFile); | |
pController->mVePlayer[playerInstance]->setVideoISurface( | |
pController->mISurface); | |
LOGV("preparePlayer: setVideoISurface"); | |
pController->mVePlayer[playerInstance]->setVideoSurface( | |
pController->mSurface); | |
LOGV("preparePlayer: setVideoSurface"); | |
pController->mVePlayer[playerInstance]->setMediaRenderingMode( | |
pController->mClipList[index]->xVSS.MediaRendering, | |
pController->mOutputVideoSize); | |
LOGV("preparePlayer: setMediaRenderingMode"); | |
if(index == pController->mStartingClipIndex) { | |
pController->mVePlayer[playerInstance]->setPlaybackBeginTime( | |
pController->mFirstPreviewClipBeginTime); | |
} | |
else { | |
pController->mVePlayer[playerInstance]->setPlaybackBeginTime( | |
pController->mClipList[index]->uiBeginCutTime); | |
} | |
LOGV("preparePlayer: setPlaybackBeginTime(%d)", | |
pController->mClipList[index]->uiBeginCutTime); | |
pController->mVePlayer[playerInstance]->setPlaybackEndTime( | |
pController->mClipList[index]->uiEndCutTime); | |
LOGV("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); | |
LOGV("preparePlayer: setImageClipProperties"); | |
} | |
pController->mVePlayer[playerInstance]->prepare(); | |
LOGV("preparePlayer: prepared"); | |
if(pController->mClipList[index]->uiBeginCutTime > 0) { | |
pController->mVePlayer[playerInstance]->seekTo( | |
pController->mClipList[index]->uiBeginCutTime); | |
LOGV("preparePlayer: seekTo(%d)", | |
pController->mClipList[index]->uiBeginCutTime); | |
} | |
pController->mVePlayer[playerInstance]->readFirstVideoFrame(); | |
LOGV("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; | |
LOGV("inside threadProc"); | |
if(pController->mPlayerState == VePlayerIdle) { | |
(pController->mCurrentClipNumber)++; | |
LOGV("threadProc: playing file index %d total clips %d", | |
pController->mCurrentClipNumber, pController->mNumberClipsToPreview); | |
if(pController->mCurrentClipNumber >= | |
pController->mNumberClipsToPreview) { | |
LOGV("All clips previewed"); | |
pController->mCurrentPlayedDuration = 0; | |
pController->mCurrentClipDuration = 0; | |
pController->mCurrentPlayer = 0; | |
if(pController->mPreviewLooping == M4OSA_TRUE) { | |
pController->mCurrentClipNumber = | |
pController->mStartingClipIndex; | |
LOGV("Preview looping TRUE, restarting from clip index %d", | |
pController->mCurrentClipNumber); | |
// Reset the story board timestamp inside the player | |
for (int playerInst=0; playerInst<NBPLAYER_INSTANCES; | |
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(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); | |
LOGV("threadProc: setStoryboardStartTime"); | |
// Set the next clip duration for Audio mix here | |
if(pController->mCurrentClipNumber != pController->mStartingClipIndex) { | |
pController->mVePlayer[pController->mCurrentPlayer]->setAudioMixStoryBoardParam( | |
pController->mCurrentPlayedDuration, | |
pController->mClipList[index]->uiBeginCutTime, | |
pController->mClipList[index]->ClipProperties.uiClipAudioVolumePercentage); | |
LOGV("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(); | |
LOGV("threadProc: started"); | |
pController->mPlayerState = VePlayerBusy; | |
} else if(pController->mPlayerState == VePlayerAutoStop) { | |
LOGV("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); | |
err = M4OSA_semaphoreWait(pController->mSemThreadWait, | |
M4OSA_WAIT_FOREVER); | |
} else { | |
if (!pController->bStopThreadInProgress) { | |
LOGV("threadProc: state busy...wait for sem"); | |
err = M4OSA_semaphoreWait(pController->mSemThreadWait, | |
M4OSA_WAIT_FOREVER); | |
} | |
LOGV("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 | |
LOGV("MEDIA_NOP"); | |
break; | |
case MEDIA_PREPARED: | |
LOGV("MEDIA_PREPARED"); | |
break; | |
case MEDIA_PLAYBACK_COMPLETE: | |
{ | |
LOGV("notify:MEDIA_PLAYBACK_COMPLETE"); | |
pController->mPlayerState = VePlayerIdle; | |
//send progress callback with last frame timestamp | |
if(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) && | |
(pController->mCurrentClipNumber != | |
(pController->mNumberClipsToPreview-1))) { | |
VideoEditorCurretEditInfo *pEditInfo = | |
(VideoEditorCurretEditInfo*)M4OSA_malloc(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); | |
} | |
M4OSA_free((M4OSA_MemAddr32)pEditInfo); | |
} | |
M4OSA_semaphorePost(pController->mSemThreadWait); | |
break; | |
} | |
case MEDIA_ERROR: | |
{ | |
int err_val = ext1; | |
// Always log errors. | |
// ext1: Media framework error code. | |
// ext2: Implementation dependant error code. | |
LOGE("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. | |
//LOGW("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: | |
LOGV("MEDIA_SEEK_COMPLETE; Received seek complete"); | |
break; | |
case MEDIA_BUFFERING_UPDATE: | |
LOGV("MEDIA_BUFFERING_UPDATE; buffering %d", ext1); | |
break; | |
case MEDIA_SET_VIDEO_SIZE: | |
LOGV("MEDIA_SET_VIDEO_SIZE; New video size %d x %d", ext1, ext2); | |
break; | |
case 0xAAAAAAAA: | |
LOGV("VIDEO PLAYBACK ALMOST over, prepare next player"); | |
// Select next player and prepare it | |
// If there is a clip after this one | |
if ((pController->mCurrentClipNumber+1) < | |
pController->mNumberClipsToPreview) { | |
pController->mPrepareReqest = M4OSA_TRUE; | |
pController->mCurrentPlayer++; | |
if (pController->mCurrentPlayer >= NBPLAYER_INSTANCES) { | |
pController->mCurrentPlayer = 0; | |
} | |
// Prepare the first clip to be played | |
M4OSA_semaphorePost(pController->mSemThreadWait); | |
} | |
break; | |
case 0xBBBBBBBB: | |
{ | |
LOGV("VIDEO PLAYBACK, Update Overlay"); | |
int overlayIndex = ext2; | |
VideoEditorCurretEditInfo *pEditInfo = | |
(VideoEditorCurretEditInfo*)M4OSA_malloc(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; | |
LOGV("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); | |
} | |
} | |
M4OSA_free((M4OSA_MemAddr32)pEditInfo); | |
break; | |
} | |
default: | |
LOGV("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 M4VSS3GPP_kVideoEffectType_CurtainOpening: | |
effect = VIDEO_EFFECT_CURTAINOPEN; | |
break; | |
case M4VSS3GPP_kVideoEffectType_CurtainClosing: | |
effect = VIDEO_EFFECT_CURTAINCLOSE; | |
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; | |
} | |
M4OSA_ERR VideoEditorPreviewController::setPreviewFrameRenderingMode( | |
M4xVSS_MediaRendering mode, M4VIDEOEDITING_VideoFrameSize outputVideoSize) { | |
LOGV("setMediaRenderingMode: outputVideoSize = %d", outputVideoSize); | |
mRenderingMode = mode; | |
switch(outputVideoSize) { | |
case M4VIDEOEDITING_kSQCIF: | |
mOutputVideoWidth = 128; | |
mOutputVideoHeight = 96; | |
break; | |
case M4VIDEOEDITING_kQQVGA: | |
mOutputVideoWidth = 160; | |
mOutputVideoHeight = 120; | |
break; | |
case M4VIDEOEDITING_kQCIF: | |
mOutputVideoWidth = 176; | |
mOutputVideoHeight = 144; | |
break; | |
case M4VIDEOEDITING_kQVGA: | |
mOutputVideoWidth = 320; | |
mOutputVideoHeight = 240; | |
break; | |
case M4VIDEOEDITING_kCIF: | |
mOutputVideoWidth = 352; | |
mOutputVideoHeight = 288; | |
break; | |
case M4VIDEOEDITING_kVGA: | |
mOutputVideoWidth = 640; | |
mOutputVideoHeight = 480; | |
break; | |
case M4VIDEOEDITING_kWVGA: | |
mOutputVideoWidth = 800; | |
mOutputVideoHeight = 480; | |
break; | |
case M4VIDEOEDITING_kNTSC: | |
mOutputVideoWidth = 720; | |
mOutputVideoHeight = 480; | |
break; | |
case M4VIDEOEDITING_k640_360: | |
mOutputVideoWidth = 640; | |
mOutputVideoHeight = 360; | |
break; | |
case M4VIDEOEDITING_k854_480: | |
mOutputVideoWidth = 854; | |
mOutputVideoHeight = 480; | |
break; | |
case M4VIDEOEDITING_kHD1280: | |
mOutputVideoWidth = 1280; | |
mOutputVideoHeight = 720; | |
break; | |
case M4VIDEOEDITING_kHD1080: | |
mOutputVideoWidth = 1080; | |
mOutputVideoHeight = 720; | |
break; | |
case M4VIDEOEDITING_kHD960: | |
mOutputVideoWidth = 960; | |
mOutputVideoHeight = 720; | |
break; | |
default: | |
mOutputVideoWidth = 0; | |
mOutputVideoHeight = 0; | |
break; | |
} | |
return OK; | |
} | |
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; | |
LOGV("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) { | |
LOGE("doImageRenderingMode: applyRenderingMode returned err=0x%x", err); | |
} | |
return err; | |
} | |
} //namespace android |