diff options
author | Rajneesh Chowdury <rajneeshc@google.com> | 2011-08-30 12:59:30 -0700 |
---|---|---|
committer | Rajneesh Chowdury <rajneeshc@google.com> | 2011-08-30 12:59:30 -0700 |
commit | e9eec0e0975c57c0dac91eb5b4cbb052b7dd011a (patch) | |
tree | a0149c5899128a58ddd146620f566371c365b049 /libvideoeditor | |
parent | dac2f050b814bd72ff66b4ae58634c25fb2185ff (diff) | |
download | frameworks_av-e9eec0e0975c57c0dac91eb5b4cbb052b7dd011a.zip frameworks_av-e9eec0e0975c57c0dac91eb5b4cbb052b7dd011a.tar.gz frameworks_av-e9eec0e0975c57c0dac91eb5b4cbb052b7dd011a.tar.bz2 |
Fix for 5156702 Rotate video output for thumbnails and export
This is part of a multi project submit.
This is the native engine part.
Change-Id: Icde922194a123a90544942caa12430fc3c4ef10e
Diffstat (limited to 'libvideoeditor')
-rwxr-xr-x | libvideoeditor/lvpp/VideoEditorPreviewController.cpp | 20 | ||||
-rwxr-xr-x | libvideoeditor/lvpp/VideoEditorTools.cpp | 211 | ||||
-rwxr-xr-x | libvideoeditor/lvpp/VideoEditorTools.h | 11 | ||||
-rwxr-xr-x | libvideoeditor/vss/common/inc/M4DA_Types.h | 1 | ||||
-rwxr-xr-x | libvideoeditor/vss/common/inc/M4_VideoEditingCommon.h | 2 | ||||
-rwxr-xr-x | libvideoeditor/vss/inc/M4xVSS_Internal.h | 3 | ||||
-rwxr-xr-x | libvideoeditor/vss/mcs/src/M4MCS_API.c | 2 | ||||
-rwxr-xr-x | libvideoeditor/vss/src/M4VD_EXTERNAL_BitstreamParser.c | 6 | ||||
-rwxr-xr-x | libvideoeditor/vss/src/M4VSS3GPP_EditVideo.c | 388 | ||||
-rwxr-xr-x | libvideoeditor/vss/src/M4xVSS_API.c | 29 | ||||
-rwxr-xr-x | libvideoeditor/vss/src/M4xVSS_internal.c | 14 | ||||
-rwxr-xr-x | libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp | 7 |
12 files changed, 663 insertions, 31 deletions
diff --git a/libvideoeditor/lvpp/VideoEditorPreviewController.cpp b/libvideoeditor/lvpp/VideoEditorPreviewController.cpp index 29dd150..27c0a0b 100755 --- a/libvideoeditor/lvpp/VideoEditorPreviewController.cpp +++ b/libvideoeditor/lvpp/VideoEditorPreviewController.cpp @@ -825,6 +825,26 @@ M4OSA_ERR VideoEditorPreviewController::renderPreviewFrame( 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) { + LOGE("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) { diff --git a/libvideoeditor/lvpp/VideoEditorTools.cpp b/libvideoeditor/lvpp/VideoEditorTools.cpp index c7c3650..f1a6c58 100755 --- a/libvideoeditor/lvpp/VideoEditorTools.cpp +++ b/libvideoeditor/lvpp/VideoEditorTools.cpp @@ -3672,3 +3672,214 @@ android::status_t getVideoSizeByResolution( return android::OK; } + +M4VIFI_UInt8 M4VIFI_Rotate90LeftYUV420toYUV420(void* pUserData, + M4VIFI_ImagePlane *pPlaneIn, M4VIFI_ImagePlane *pPlaneOut) { + + M4VIFI_Int32 plane_number; + M4VIFI_UInt32 i,j, u_stride; + M4VIFI_UInt8 *p_buf_src, *p_buf_dest; + + /**< Loop on Y,U and V planes */ + for (plane_number = 0; plane_number < 3; plane_number++) { + /**< Get adresses of first valid pixel in input and output buffer */ + /**< As we have a -90° rotation, first needed pixel is the upper-right one */ + p_buf_src = + &(pPlaneIn[plane_number].pac_data[pPlaneIn[plane_number].u_topleft]) + + pPlaneOut[plane_number].u_height - 1 ; + p_buf_dest = + &(pPlaneOut[plane_number].pac_data[pPlaneOut[plane_number].u_topleft]); + u_stride = pPlaneIn[plane_number].u_stride; + /**< Loop on output rows */ + for (i = 0; i < pPlaneOut[plane_number].u_height; i++) { + /**< Loop on all output pixels in a row */ + for (j = 0; j < pPlaneOut[plane_number].u_width; j++) { + *p_buf_dest++= *p_buf_src; + p_buf_src += u_stride; /**< Go to the next row */ + } + + /**< Go on next row of the output frame */ + p_buf_dest += + pPlaneOut[plane_number].u_stride - pPlaneOut[plane_number].u_width; + /**< Go to next pixel in the last row of the input frame*/ + p_buf_src -= + pPlaneIn[plane_number].u_stride * pPlaneOut[plane_number].u_width + 1 ; + } + } + + return M4VIFI_OK; +} + +M4VIFI_UInt8 M4VIFI_Rotate90RightYUV420toYUV420(void* pUserData, + M4VIFI_ImagePlane *pPlaneIn, M4VIFI_ImagePlane *pPlaneOut) { + + M4VIFI_Int32 plane_number; + M4VIFI_UInt32 i,j, u_stride; + M4VIFI_UInt8 *p_buf_src, *p_buf_dest; + + /**< Loop on Y,U and V planes */ + for (plane_number = 0; plane_number < 3; plane_number++) { + /**< Get adresses of first valid pixel in input and output buffer */ + /**< As we have a +90° rotation, first needed pixel is the left-down one */ + p_buf_src = + &(pPlaneIn[plane_number].pac_data[pPlaneIn[plane_number].u_topleft]) + + (pPlaneIn[plane_number].u_stride * (pPlaneOut[plane_number].u_width - 1)); + p_buf_dest = + &(pPlaneOut[plane_number].pac_data[pPlaneOut[plane_number].u_topleft]); + u_stride = pPlaneIn[plane_number].u_stride; + /**< Loop on output rows */ + for (i = 0; i < pPlaneOut[plane_number].u_height; i++) { + /**< Loop on all output pixels in a row */ + for (j = 0; j < pPlaneOut[plane_number].u_width; j++) { + *p_buf_dest++= *p_buf_src; + p_buf_src -= u_stride; /**< Go to the previous row */ + } + + /**< Go on next row of the output frame */ + p_buf_dest += + pPlaneOut[plane_number].u_stride - pPlaneOut[plane_number].u_width; + /**< Go to next pixel in the last row of the input frame*/ + p_buf_src += + pPlaneIn[plane_number].u_stride * pPlaneOut[plane_number].u_width +1 ; + } + } + + return M4VIFI_OK; +} + +M4VIFI_UInt8 M4VIFI_Rotate180YUV420toYUV420(void* pUserData, + M4VIFI_ImagePlane *pPlaneIn, M4VIFI_ImagePlane *pPlaneOut) { + M4VIFI_Int32 plane_number; + M4VIFI_UInt32 i,j; + M4VIFI_UInt8 *p_buf_src, *p_buf_dest, temp_pix1; + + /**< Loop on Y,U and V planes */ + for (plane_number = 0; plane_number < 3; plane_number++) { + /**< Get adresses of first valid pixel in input and output buffer */ + p_buf_src = + &(pPlaneIn[plane_number].pac_data[pPlaneIn[plane_number].u_topleft]); + p_buf_dest = + &(pPlaneOut[plane_number].pac_data[pPlaneOut[plane_number].u_topleft]); + + /**< If pPlaneIn = pPlaneOut, the algorithm will be different */ + if (p_buf_src == p_buf_dest) { + /**< Get Address of last pixel in the last row of the frame */ + p_buf_dest += + pPlaneOut[plane_number].u_stride*(pPlaneOut[plane_number].u_height-1) + + pPlaneOut[plane_number].u_width - 1; + + /**< We loop (height/2) times on the rows. + * In case u_height is odd, the row at the middle of the frame + * has to be processed as must be mirrored */ + for (i = 0; i < ((pPlaneOut[plane_number].u_height)>>1); i++) { + for (j = 0; j < pPlaneOut[plane_number].u_width; j++) { + temp_pix1= *p_buf_dest; + *p_buf_dest--= *p_buf_src; + *p_buf_src++ = temp_pix1; + } + /**< Go on next row in top of frame */ + p_buf_src += + pPlaneOut[plane_number].u_stride - pPlaneOut[plane_number].u_width; + /**< Go to the last pixel in previous row in bottom of frame*/ + p_buf_dest -= + pPlaneOut[plane_number].u_stride - pPlaneOut[plane_number].u_width; + } + + /**< Mirror middle row in case height is odd */ + if ((pPlaneOut[plane_number].u_height%2)!= 0) { + p_buf_src = + &(pPlaneOut[plane_number].pac_data[pPlaneIn[plane_number].u_topleft]); + p_buf_src += + pPlaneOut[plane_number].u_stride*(pPlaneOut[plane_number].u_height>>1); + p_buf_dest = + p_buf_src + pPlaneOut[plane_number].u_width; + + /**< We loop u_width/2 times on this row. + * In case u_width is odd, the pixel at the middle of this row + * remains unchanged */ + for (j = 0; j < (pPlaneOut[plane_number].u_width>>1); j++) { + temp_pix1= *p_buf_dest; + *p_buf_dest--= *p_buf_src; + *p_buf_src++ = temp_pix1; + } + } + } else { + /**< Get Address of last pixel in the last row of the output frame */ + p_buf_dest += + pPlaneOut[plane_number].u_stride*(pPlaneOut[plane_number].u_height-1) + + pPlaneIn[plane_number].u_width - 1; + + /**< Loop on rows */ + for (i = 0; i < pPlaneOut[plane_number].u_height; i++) { + for (j = 0; j < pPlaneOut[plane_number].u_width; j++) { + *p_buf_dest--= *p_buf_src++; + } + + /**< Go on next row in top of input frame */ + p_buf_src += + pPlaneIn[plane_number].u_stride - pPlaneOut[plane_number].u_width; + /**< Go to last pixel of previous row in bottom of input frame*/ + p_buf_dest -= + pPlaneOut[plane_number].u_stride - pPlaneOut[plane_number].u_width; + } + } + } + + return M4VIFI_OK; +} + +M4OSA_ERR applyVideoRotation(M4OSA_Void* pBuffer, M4OSA_UInt32 width, + M4OSA_UInt32 height, M4OSA_UInt32 rotation) { + + M4OSA_ERR err = M4NO_ERROR; + M4VIFI_ImagePlane planeIn[3], planeOut[3]; + + if (pBuffer == M4OSA_NULL) { + LOGE("applyVideoRotation: NULL input frame"); + return M4ERR_PARAMETER; + } + M4OSA_UInt8* outPtr = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc( + (width*height*1.5), M4VS, (M4OSA_Char*)("rotation out ptr")); + if (outPtr == M4OSA_NULL) { + return M4ERR_ALLOC; + } + + // In plane + prepareYUV420ImagePlane(planeIn, width, + height, (M4VIFI_UInt8 *)pBuffer, width, height); + + // Out plane + if (rotation != 180) { + prepareYUV420ImagePlane(planeOut, height, + width, outPtr, height, width); + } + + switch(rotation) { + case 90: + M4VIFI_Rotate90RightYUV420toYUV420(M4OSA_NULL, planeIn, planeOut); + memset(pBuffer, 0, (width*height*1.5)); + memcpy(pBuffer, (void *)outPtr, (width*height*1.5)); + break; + + case 180: + // In plane rotation, so planeOut = planeIn + M4VIFI_Rotate180YUV420toYUV420(M4OSA_NULL, planeIn, planeIn); + break; + + case 270: + M4VIFI_Rotate90LeftYUV420toYUV420(M4OSA_NULL, planeIn, planeOut); + memset(pBuffer, 0, (width*height*1.5)); + memcpy(pBuffer, (void *)outPtr, (width*height*1.5)); + break; + + default: + LOGE("invalid rotation param %d", (int)rotation); + err = M4ERR_PARAMETER; + break; + } + + free((void *)outPtr); + return err; + +} + diff --git a/libvideoeditor/lvpp/VideoEditorTools.h b/libvideoeditor/lvpp/VideoEditorTools.h index f39ed90..9b464da 100755 --- a/libvideoeditor/lvpp/VideoEditorTools.h +++ b/libvideoeditor/lvpp/VideoEditorTools.h @@ -139,4 +139,15 @@ M4OSA_ERR applyEffectsAndRenderingMode(vePostProcessParams *params, android::status_t getVideoSizeByResolution(M4VIDEOEDITING_VideoFrameSize resolution, uint32_t *pWidth, uint32_t *pHeight); +M4VIFI_UInt8 M4VIFI_Rotate90LeftYUV420toYUV420(void* pUserData, + M4VIFI_ImagePlane *pPlaneIn, M4VIFI_ImagePlane *pPlaneOut); + +M4VIFI_UInt8 M4VIFI_Rotate90RightYUV420toYUV420(void* pUserData, + M4VIFI_ImagePlane *pPlaneIn, M4VIFI_ImagePlane *pPlaneOut); + +M4VIFI_UInt8 M4VIFI_Rotate180YUV420toYUV420(void* pUserData, + M4VIFI_ImagePlane *pPlaneIn, M4VIFI_ImagePlane *pPlaneOut); + +M4OSA_ERR applyVideoRotation(M4OSA_Void* pBuffer, + M4OSA_UInt32 width, M4OSA_UInt32 height, M4OSA_UInt32 rotation); #endif // ANDROID_VE_TOOLS_H diff --git a/libvideoeditor/vss/common/inc/M4DA_Types.h b/libvideoeditor/vss/common/inc/M4DA_Types.h index 42637e1..58cab7e 100755 --- a/libvideoeditor/vss/common/inc/M4DA_Types.h +++ b/libvideoeditor/vss/common/inc/M4DA_Types.h @@ -118,6 +118,7 @@ typedef struct M4OSA_UInt32 m_videoHeight; /**< Height of the video in the stream */ M4OSA_Float m_averageFrameRate; /**< Average frame rate of the video in the stream */ + M4OSA_Int32 videoRotationDegrees; /**< Video rotation degree */ M4OSA_UInt32 m_structSize; /**< Size of the structure in bytes */ } M4_VideoStreamHandler; diff --git a/libvideoeditor/vss/common/inc/M4_VideoEditingCommon.h b/libvideoeditor/vss/common/inc/M4_VideoEditingCommon.h index 5581417..9e7d03f 100755 --- a/libvideoeditor/vss/common/inc/M4_VideoEditingCommon.h +++ b/libvideoeditor/vss/common/inc/M4_VideoEditingCommon.h @@ -323,6 +323,8 @@ typedef struct { M4OSA_UInt32 uiClipAudioVolumePercentage; M4OSA_Bool bSetImageData; + M4OSA_Int32 videoRotationDegrees; /**< Video rotation degree */ + } M4VIDEOEDITING_ClipProperties; diff --git a/libvideoeditor/vss/inc/M4xVSS_Internal.h b/libvideoeditor/vss/inc/M4xVSS_Internal.h index faf160f..5296572 100755 --- a/libvideoeditor/vss/inc/M4xVSS_Internal.h +++ b/libvideoeditor/vss/inc/M4xVSS_Internal.h @@ -485,7 +485,8 @@ typedef struct { /** * Internal function prototypes */ -M4OSA_ERR M4xVSS_internalStartTranscoding(M4OSA_Context pContext); +M4OSA_ERR M4xVSS_internalStartTranscoding(M4OSA_Context pContext, + M4OSA_UInt32 *rotationDegree); M4OSA_ERR M4xVSS_internalStopTranscoding(M4OSA_Context pContext); diff --git a/libvideoeditor/vss/mcs/src/M4MCS_API.c b/libvideoeditor/vss/mcs/src/M4MCS_API.c index baa0dd5..77990aa 100755 --- a/libvideoeditor/vss/mcs/src/M4MCS_API.c +++ b/libvideoeditor/vss/mcs/src/M4MCS_API.c @@ -9526,6 +9526,8 @@ static M4OSA_ERR M4MCS_intGetInputClipProperties( M4MCS_InternalContext *pC ) pC->pReaderVideoStream->m_averageFrameRate; pC->InputFileProperties.uiVideoMaxAuSize = pC->pReaderVideoStream->m_basicProperties.m_maxAUSize; + pC->InputFileProperties.videoRotationDegrees = + pC->pReaderVideoStream->videoRotationDegrees; } else { diff --git a/libvideoeditor/vss/src/M4VD_EXTERNAL_BitstreamParser.c b/libvideoeditor/vss/src/M4VD_EXTERNAL_BitstreamParser.c index 3026ab9..d1015d5 100755 --- a/libvideoeditor/vss/src/M4VD_EXTERNAL_BitstreamParser.c +++ b/libvideoeditor/vss/src/M4VD_EXTERNAL_BitstreamParser.c @@ -586,7 +586,7 @@ M4OSA_ERR getAVCProfileAndLevel(M4OSA_UInt8* pDSI, M4OSA_Int32 DSISize, default: *pLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL; } - LOGI("getAVCProfileAndLevel profile %ld level %ld", *pProfile, *pLevel); + LOGV("getAVCProfileAndLevel profile %ld level %ld", *pProfile, *pLevel); return M4NO_ERROR; } @@ -670,7 +670,7 @@ M4OSA_ERR getH263ProfileAndLevel(M4OSA_UInt8* pDSI, M4OSA_Int32 DSISize, default: *pProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE; } - LOGI("getH263ProfileAndLevel profile %ld level %ld", *pProfile, *pLevel); + LOGV("getH263ProfileAndLevel profile %ld level %ld", *pProfile, *pLevel); return M4NO_ERROR; } @@ -693,6 +693,6 @@ M4OSA_ERR getMPEG4ProfileAndLevel(M4OSA_UInt8 profileAndLevel, break; } } - LOGI("getMPEG4ProfileAndLevel profile %ld level %ld", *pProfile, *pLevel); + LOGV("getMPEG4ProfileAndLevel profile %ld level %ld", *pProfile, *pLevel); return M4NO_ERROR; } diff --git a/libvideoeditor/vss/src/M4VSS3GPP_EditVideo.c b/libvideoeditor/vss/src/M4VSS3GPP_EditVideo.c index 3dd837a..3aafbe6 100755 --- a/libvideoeditor/vss/src/M4VSS3GPP_EditVideo.c +++ b/libvideoeditor/vss/src/M4VSS3GPP_EditVideo.c @@ -104,6 +104,12 @@ static M4OSA_ERR M4VSS3GPP_intRenderFrameWithEffect( M4VIFI_ImagePlane *pPlaneNoResize, M4VIFI_ImagePlane *pPlaneOut); +static M4OSA_ERR M4VSS3GPP_intRotateVideo(M4VIFI_ImagePlane* pPlaneIn, + M4OSA_UInt32 rotationDegree); + +static M4OSA_ERR M4VSS3GPP_intSetYUV420Plane(M4VIFI_ImagePlane* planeIn, + M4OSA_UInt32 width, M4OSA_UInt32 height); + /** ****************************************************************************** * M4OSA_ERR M4VSS3GPP_intEditStepVideo() @@ -1055,7 +1061,7 @@ M4OSA_ERR M4VSS3GPP_intVPP( M4VPP_Context pContext, M4VIFI_ImagePlane *pPlaneIn, M4VIFI_ImagePlane *pDecoderRenderFrame = M4OSA_NULL; M4VIFI_ImagePlane pTemp1[3],pTemp2[3]; M4VIFI_ImagePlane pTempPlaneClip1[3],pTempPlaneClip2[3]; - M4OSA_UInt32 i = 0; + M4OSA_UInt32 i = 0, yuvFrameWidth = 0, yuvFrameHeight = 0; /** * VPP context is actually the VSS3GPP context */ @@ -1345,6 +1351,22 @@ M4OSA_ERR M4VSS3GPP_intVPP( M4VPP_Context pContext, M4VIFI_ImagePlane *pPlaneIn, pC->ewc.VppError = err; return M4NO_ERROR; } + if (pC->pC1->pSettings->FileType != + M4VIDEOEDITING_kFileType_ARGB8888) { + if (0 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees) { + // Save width and height of un-rotated frame + yuvFrameWidth = pC->pC1->m_pPreResizeFrame[0].u_width; + yuvFrameHeight = pC->pC1->m_pPreResizeFrame[0].u_height; + err = M4VSS3GPP_intRotateVideo(pC->pC1->m_pPreResizeFrame, + pC->pC1->pSettings->ClipProperties.videoRotationDegrees); + if (M4NO_ERROR != err) { + M4OSA_TRACE1_1("M4VSS3GPP_intVPP: \ + rotateVideo() returns error 0x%x", err); + pC->ewc.VppError = err; + return M4NO_ERROR; + } + } + } if (pC->nbActiveEffects > 0) { pC->pC1->bGetYuvDataFromDecoder = M4OSA_TRUE; @@ -1407,11 +1429,21 @@ M4OSA_ERR M4VSS3GPP_intVPP( M4VPP_Context pContext, M4VIFI_ImagePlane *pPlaneIn, } pC->pC1->bGetYuvDataFromDecoder = M4OSA_FALSE; } + + // Reset original width and height for resize frame plane + if (0 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees && + 180 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees) { + + M4VSS3GPP_intSetYUV420Plane(pC->pC1->m_pPreResizeFrame, + yuvFrameWidth, yuvFrameHeight); + } } else { M4OSA_TRACE3_0("M4VSS3GPP_intVPP: NO resize required"); - if (pC->nbActiveEffects > 0) { + if ((pC->nbActiveEffects > 0) || + ((0 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees) + && (180 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees))) { /** If we do modify the image, we need an * intermediate image plane */ if (M4OSA_NULL == pTemp1[0].pac_data) { @@ -1438,14 +1470,78 @@ M4OSA_ERR M4VSS3GPP_intVPP( M4VPP_Context pContext, M4VIFI_ImagePlane *pPlaneIn, return M4NO_ERROR; } + if (pC->pC1->pSettings->FileType != + M4VIDEOEDITING_kFileType_ARGB8888) { + if (0 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees) { + // Save width and height of un-rotated frame + yuvFrameWidth = pDecoderRenderFrame[0].u_width; + yuvFrameHeight = pDecoderRenderFrame[0].u_height; + err = M4VSS3GPP_intRotateVideo(pDecoderRenderFrame, + pC->pC1->pSettings->ClipProperties.videoRotationDegrees); + if (M4NO_ERROR != err) { + M4OSA_TRACE1_1("M4VSS3GPP_intVPP: \ + rotateVideo() returns error 0x%x", err); + pC->ewc.VppError = err; + return M4NO_ERROR; + } + + if (180 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees) { + // Apply black border on rotated frame + if (pC->nbActiveEffects > 0) { + /** we need an intermediate image plane */ + if (M4OSA_NULL == pTemp2[0].pac_data) { + err = M4VSS3GPP_intAllocateYUV420(pTemp2, + pC->ewc.uiVideoWidth, + pC->ewc.uiVideoHeight); + if (M4NO_ERROR != err) { + pC->ewc.VppError = err; + return M4NO_ERROR; + } + } + err = M4VSS3GPP_intApplyRenderingMode(pC, M4xVSS_kBlackBorders, + pDecoderRenderFrame, pTemp2); + } else { + err = M4VSS3GPP_intApplyRenderingMode(pC, M4xVSS_kBlackBorders, + pDecoderRenderFrame, pTmp); + } + if (M4NO_ERROR != err) { + M4OSA_TRACE1_1("M4VSS3GPP_intVPP: \ + M4VSS3GPP_intApplyRenderingMode) error 0x%x ", err); + pC->ewc.VppError = err; + return M4NO_ERROR; + } + } + } + } + if (pC->nbActiveEffects > 0) { - err = M4VSS3GPP_intApplyVideoEffect(pC, - pDecoderRenderFrame,pPlaneOut); + if ((0 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees) && + (180 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees)) { + err = M4VSS3GPP_intApplyVideoEffect(pC, + pTemp2,pPlaneOut); + } else { + err = M4VSS3GPP_intApplyVideoEffect(pC, + pDecoderRenderFrame,pPlaneOut); + } if (M4NO_ERROR != err) { pC->ewc.VppError = err; return M4NO_ERROR; } } + + // Reset original width and height for resize frame plane + if (0 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees && + 180 != pC->pC1->pSettings->ClipProperties.videoRotationDegrees) { + + M4VSS3GPP_intSetYUV420Plane(pDecoderRenderFrame, + yuvFrameWidth, yuvFrameHeight); + + if (pC->nbActiveEffects > 0) { + free((void *)pTemp2[0].pac_data); + free((void *)pTemp2[1].pac_data); + free((void *)pTemp2[2].pac_data); + } + } } pC->pC1->lastDecodedPlane = pTmp; pC->pC1->iVideoRenderCts = (M4OSA_Int32)ts; @@ -3297,6 +3393,9 @@ M4OSA_ERR M4VSS3GPP_intRenderFrameWithEffect(M4VSS3GPP_InternalEditContext *pC, M4OSA_ERR err = M4NO_ERROR; M4OSA_UInt8 numEffects = 0; M4VIFI_ImagePlane *pDecoderRenderFrame = M4OSA_NULL; + M4OSA_UInt32 yuvFrameWidth = 0, yuvFrameHeight = 0; + M4VIFI_ImagePlane* pTmp = M4OSA_NULL; + M4VIFI_ImagePlane pTemp[3]; /** Check if resizing is needed */ @@ -3350,6 +3449,22 @@ M4OSA_ERR M4VSS3GPP_intRenderFrameWithEffect(M4VSS3GPP_InternalEditContext *pC, return err; } + if (pClipCtxt->pSettings->FileType != + M4VIDEOEDITING_kFileType_ARGB8888) { + if (0 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees) { + // Save width and height of un-rotated frame + yuvFrameWidth = pClipCtxt->m_pPreResizeFrame[0].u_width; + yuvFrameHeight = pClipCtxt->m_pPreResizeFrame[0].u_height; + err = M4VSS3GPP_intRotateVideo(pClipCtxt->m_pPreResizeFrame, + pClipCtxt->pSettings->ClipProperties.videoRotationDegrees); + if (M4NO_ERROR != err) { + M4OSA_TRACE1_1("M4VSS3GPP_intRenderFrameWithEffect: \ + rotateVideo() returns error 0x%x", err); + return err; + } + } + } + if (bIsClip1 == M4OSA_TRUE) { numEffects = pC->nbActiveEffects; } else { @@ -3423,6 +3538,14 @@ M4OSA_ERR M4VSS3GPP_intRenderFrameWithEffect(M4VSS3GPP_InternalEditContext *pC, pClipCtxt->bGetYuvDataFromDecoder = M4OSA_FALSE; } + // Reset original width and height for resize frame plane + if (0 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees && + 180 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees) { + + M4VSS3GPP_intSetYUV420Plane(pClipCtxt->m_pPreResizeFrame, + yuvFrameWidth, yuvFrameHeight); + } + } else { if (bIsClip1 == M4OSA_TRUE) { numEffects = pC->nbActiveEffects; @@ -3439,13 +3562,64 @@ M4OSA_ERR M4VSS3GPP_intRenderFrameWithEffect(M4VSS3GPP_InternalEditContext *pC, Render returns error 0x%x", err); return err; } + + if (pClipCtxt->pSettings->FileType != + M4VIDEOEDITING_kFileType_ARGB8888) { + if (0 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees) { + // Save width and height of un-rotated frame + yuvFrameWidth = pPlaneNoResize[0].u_width; + yuvFrameHeight = pPlaneNoResize[0].u_height; + err = M4VSS3GPP_intRotateVideo(pPlaneNoResize, + pClipCtxt->pSettings->ClipProperties.videoRotationDegrees); + if (M4NO_ERROR != err) { + M4OSA_TRACE1_1("M4VSS3GPP_intRenderFrameWithEffect: \ + rotateVideo() returns error 0x%x", err); + return err; + } + } + + if (180 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees) { + // Apply Black Borders to rotated plane + /** we need an intermediate image plane */ + + err = M4VSS3GPP_intAllocateYUV420(pTemp, + pC->ewc.uiVideoWidth, + pC->ewc.uiVideoHeight); + if (M4NO_ERROR != err) { + M4OSA_TRACE1_1("M4VSS3GPP_intRenderFrameWithEffect: \ + memAlloc() returns error 0x%x", err); + return err; + } + err = M4VSS3GPP_intApplyRenderingMode(pC, M4xVSS_kBlackBorders, + pPlaneNoResize, pTemp); + if (M4NO_ERROR != err) { + M4OSA_TRACE1_1("M4VSS3GPP_intRenderFrameWithEffect: \ + M4VSS3GPP_intApplyRenderingMode() returns error 0x%x", err); + free((void *)pTemp[0].pac_data); + free((void *)pTemp[1].pac_data); + free((void *)pTemp[2].pac_data); + return err; + } + } + } + if (bIsClip1 == M4OSA_TRUE) { pC->bIssecondClip = M4OSA_FALSE; - err = M4VSS3GPP_intApplyVideoEffect(pC, pPlaneNoResize ,pC->yuv1); + if ((0 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees) && + (180 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees)) { + err = M4VSS3GPP_intApplyVideoEffect(pC, pTemp ,pC->yuv1); + } else { + err = M4VSS3GPP_intApplyVideoEffect(pC, pPlaneNoResize ,pC->yuv1); + } pClipCtxt->lastDecodedPlane = pC->yuv1; } else { pC->bIssecondClip = M4OSA_TRUE; - err = M4VSS3GPP_intApplyVideoEffect(pC, pPlaneNoResize ,pC->yuv2); + if ((0 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees) && + (180 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees)) { + err = M4VSS3GPP_intApplyVideoEffect(pC, pTemp ,pC->yuv2); + } else { + err = M4VSS3GPP_intApplyVideoEffect(pC, pPlaneNoResize ,pC->yuv2); + } pClipCtxt->lastDecodedPlane = pC->yuv2; } @@ -3455,24 +3629,212 @@ M4OSA_ERR M4VSS3GPP_intRenderFrameWithEffect(M4VSS3GPP_InternalEditContext *pC, return err; } + // Reset original width and height for resize frame plane + if (0 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees && + 180 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees) { + + M4VSS3GPP_intSetYUV420Plane(pPlaneNoResize, + yuvFrameWidth, yuvFrameHeight); + + free((void *)pTemp[0].pac_data); + free((void *)pTemp[1].pac_data); + free((void *)pTemp[2].pac_data); + } + } else { - if (bIsClip1 == M4OSA_TRUE) { - err = pClipCtxt->ShellAPI.m_pVideoDecoder->m_pFctRender( - pClipCtxt->pViDecCtxt, &ts, pC->yuv1, M4OSA_TRUE); - pClipCtxt->lastDecodedPlane = pC->yuv1; + + if ((0 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees) && + (180 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees)) { + pTmp = pPlaneNoResize; + } else if (bIsClip1 == M4OSA_TRUE) { + pTmp = pC->yuv1; } else { - err = pClipCtxt->ShellAPI.m_pVideoDecoder->m_pFctRender( - pClipCtxt->pViDecCtxt, &ts, pC->yuv2, M4OSA_TRUE); - pClipCtxt->lastDecodedPlane = pC->yuv2; + pTmp = pC->yuv2; } + err = pClipCtxt->ShellAPI.m_pVideoDecoder->m_pFctRender( + pClipCtxt->pViDecCtxt, &ts, pTmp, M4OSA_TRUE); if (M4NO_ERROR != err) { M4OSA_TRACE1_1("M4VSS3GPP_intRenderFrameWithEffect: \ Render returns error 0x%x,", err); return err; } + + if (0 == pClipCtxt->pSettings->ClipProperties.videoRotationDegrees) { + pClipCtxt->lastDecodedPlane = pTmp; + } else { + // Save width and height of un-rotated frame + yuvFrameWidth = pTmp[0].u_width; + yuvFrameHeight = pTmp[0].u_height; + err = M4VSS3GPP_intRotateVideo(pTmp, + pClipCtxt->pSettings->ClipProperties.videoRotationDegrees); + if (M4NO_ERROR != err) { + M4OSA_TRACE1_1("M4VSS3GPP_intRenderFrameWithEffect: \ + rotateVideo() returns error 0x%x", err); + return err; + } + + if (180 != pClipCtxt->pSettings->ClipProperties.videoRotationDegrees) { + + // Apply Black borders on rotated frame + if (bIsClip1) { + err = M4VSS3GPP_intApplyRenderingMode (pC, + M4xVSS_kBlackBorders, + pTmp,pC->yuv1); + } else { + err = M4VSS3GPP_intApplyRenderingMode (pC, + M4xVSS_kBlackBorders, + pTmp,pC->yuv2); + } + if (M4NO_ERROR != err) { + M4OSA_TRACE1_1("M4VSS3GPP_intRenderFrameWithEffect: \ + M4VSS3GPP_intApplyRenderingMode error 0x%x", err); + return err; + } + + // Reset original width and height for noresize frame plane + M4VSS3GPP_intSetYUV420Plane(pPlaneNoResize, + yuvFrameWidth, yuvFrameHeight); + } + + if (bIsClip1) { + pClipCtxt->lastDecodedPlane = pC->yuv1; + } else { + pClipCtxt->lastDecodedPlane = pC->yuv2; + } + } } pClipCtxt->iVideoRenderCts = (M4OSA_Int32)ts; } return err; } + +M4OSA_ERR M4VSS3GPP_intRotateVideo(M4VIFI_ImagePlane* pPlaneIn, + M4OSA_UInt32 rotationDegree) { + + M4OSA_ERR err = M4NO_ERROR; + M4VIFI_ImagePlane outPlane[3]; + + if (rotationDegree != 180) { + // Swap width and height of in plane + outPlane[0].u_width = pPlaneIn[0].u_height; + outPlane[0].u_height = pPlaneIn[0].u_width; + outPlane[0].u_stride = outPlane[0].u_width; + outPlane[0].u_topleft = 0; + outPlane[0].pac_data = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc( + (outPlane[0].u_stride*outPlane[0].u_height), M4VS, + (M4OSA_Char*)("out Y plane for rotation")); + if (outPlane[0].pac_data == M4OSA_NULL) { + return M4ERR_ALLOC; + } + + outPlane[1].u_width = pPlaneIn[0].u_height/2; + outPlane[1].u_height = pPlaneIn[0].u_width/2; + outPlane[1].u_stride = outPlane[1].u_width; + outPlane[1].u_topleft = 0; + outPlane[1].pac_data = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc( + (outPlane[1].u_stride*outPlane[1].u_height), M4VS, + (M4OSA_Char*)("out U plane for rotation")); + if (outPlane[1].pac_data == M4OSA_NULL) { + free((void *)outPlane[0].pac_data); + return M4ERR_ALLOC; + } + + outPlane[2].u_width = pPlaneIn[0].u_height/2; + outPlane[2].u_height = pPlaneIn[0].u_width/2; + outPlane[2].u_stride = outPlane[2].u_width; + outPlane[2].u_topleft = 0; + outPlane[2].pac_data = (M4OSA_UInt8 *)M4OSA_32bitAlignedMalloc( + (outPlane[2].u_stride*outPlane[2].u_height), M4VS, + (M4OSA_Char*)("out V plane for rotation")); + if (outPlane[2].pac_data == M4OSA_NULL) { + free((void *)outPlane[0].pac_data); + free((void *)outPlane[1].pac_data); + return M4ERR_ALLOC; + } + } + + switch(rotationDegree) { + case 90: + M4VIFI_Rotate90RightYUV420toYUV420(M4OSA_NULL, pPlaneIn, outPlane); + break; + + case 180: + // In plane rotation, so planeOut = planeIn + M4VIFI_Rotate180YUV420toYUV420(M4OSA_NULL, pPlaneIn, pPlaneIn); + break; + + case 270: + M4VIFI_Rotate90LeftYUV420toYUV420(M4OSA_NULL, pPlaneIn, outPlane); + break; + + default: + M4OSA_TRACE1_1("invalid rotation param %d", (int)rotationDegree); + err = M4ERR_PARAMETER; + break; + } + + if (rotationDegree != 180) { + memset((void *)pPlaneIn[0].pac_data, 0, + (pPlaneIn[0].u_width*pPlaneIn[0].u_height)); + memset((void *)pPlaneIn[1].pac_data, 0, + (pPlaneIn[1].u_width*pPlaneIn[1].u_height)); + memset((void *)pPlaneIn[2].pac_data, 0, + (pPlaneIn[2].u_width*pPlaneIn[2].u_height)); + // Copy Y, U and V planes + memcpy((void *)pPlaneIn[0].pac_data, (void *)outPlane[0].pac_data, + (pPlaneIn[0].u_width*pPlaneIn[0].u_height)); + memcpy((void *)pPlaneIn[1].pac_data, (void *)outPlane[1].pac_data, + (pPlaneIn[1].u_width*pPlaneIn[1].u_height)); + memcpy((void *)pPlaneIn[2].pac_data, (void *)outPlane[2].pac_data, + (pPlaneIn[2].u_width*pPlaneIn[2].u_height)); + + free((void *)outPlane[0].pac_data); + free((void *)outPlane[1].pac_data); + free((void *)outPlane[2].pac_data); + + // Swap the width and height of the in plane + uint32_t temp = 0; + temp = pPlaneIn[0].u_width; + pPlaneIn[0].u_width = pPlaneIn[0].u_height; + pPlaneIn[0].u_height = temp; + pPlaneIn[0].u_stride = pPlaneIn[0].u_width; + + temp = pPlaneIn[1].u_width; + pPlaneIn[1].u_width = pPlaneIn[1].u_height; + pPlaneIn[1].u_height = temp; + pPlaneIn[1].u_stride = pPlaneIn[1].u_width; + + temp = pPlaneIn[2].u_width; + pPlaneIn[2].u_width = pPlaneIn[2].u_height; + pPlaneIn[2].u_height = temp; + pPlaneIn[2].u_stride = pPlaneIn[2].u_width; + } + + return err; +} + +M4OSA_ERR M4VSS3GPP_intSetYUV420Plane(M4VIFI_ImagePlane* planeIn, + M4OSA_UInt32 width, M4OSA_UInt32 height) { + + M4OSA_ERR err = M4NO_ERROR; + + if (planeIn == M4OSA_NULL) { + M4OSA_TRACE1_0("NULL in plane, error"); + return M4ERR_PARAMETER; + } + + planeIn[0].u_width = width; + planeIn[0].u_height = height; + planeIn[0].u_stride = planeIn[0].u_width; + + planeIn[1].u_width = width/2; + planeIn[1].u_height = height/2; + planeIn[1].u_stride = planeIn[1].u_width; + + planeIn[2].u_width = width/2; + planeIn[2].u_height = height/2; + planeIn[2].u_stride = planeIn[1].u_width; + + return err; +} diff --git a/libvideoeditor/vss/src/M4xVSS_API.c b/libvideoeditor/vss/src/M4xVSS_API.c index a654f88..2ff1a88 100755 --- a/libvideoeditor/vss/src/M4xVSS_API.c +++ b/libvideoeditor/vss/src/M4xVSS_API.c @@ -5789,24 +5789,23 @@ M4OSA_ERR M4xVSS_Step( M4OSA_Context pContext, M4OSA_UInt8 *pProgress ) if( xVSS_context->pMCScurrentParams->isCreated == M4OSA_FALSE ) { /* Opening MCS */ - err = M4xVSS_internalStartTranscoding(xVSS_context); + M4OSA_UInt32 rotationDegree = 0; + err = M4xVSS_internalStartTranscoding(xVSS_context, &rotationDegree); if( err != M4NO_ERROR ) { M4OSA_TRACE1_1("M4xVSS_Step: M4xVSS_internalStartTranscoding returned\ - error: 0x%x", err) - /* TODO ? : Translate error code of MCS to an xVSS error - code ? */ - return err; + error: 0x%x", err); + return err; + } + int32_t index = xVSS_context->pMCScurrentParams->videoclipnumber; + if(xVSS_context->pSettings->pClipList[index]->bTranscodingRequired + == M4OSA_FALSE) { + /*the cuts are done in the MCS, so we need to replace + the beginCutTime and endCutTime to keep the entire video*/ + xVSS_context->pSettings->pClipList[index]->uiBeginCutTime = 0; + xVSS_context->pSettings->pClipList[index]->uiEndCutTime = 0; } - int32_t index = xVSS_context->pMCScurrentParams->videoclipnumber; - if(xVSS_context->pSettings->pClipList[index]->bTranscodingRequired - == M4OSA_FALSE) { - /*the cuts are done in the MCS, so we need to replace - the beginCutTime and endCutTime to keep the entire video*/ - xVSS_context->pSettings->pClipList[index]->uiBeginCutTime = 0; - xVSS_context->pSettings->pClipList[index]->uiEndCutTime = 0; - } M4OSA_TRACE1_1("M4xVSS_Step: \ M4xVSS_internalStartTranscoding returned \ @@ -5814,6 +5813,10 @@ M4OSA_ERR M4xVSS_Step( M4OSA_Context pContext, M4OSA_UInt8 *pProgress ) xVSS_context->pMCS_Ctxt); xVSS_context->analyseStep = M4xVSS_kMicroStateTranscodeMCS; + + // Retain rotation info of trimmed / transcoded file + xVSS_context->pSettings->pClipList[index]->\ + ClipProperties.videoRotationDegrees = rotationDegree; } } else if( xVSS_context->analyseStep diff --git a/libvideoeditor/vss/src/M4xVSS_internal.c b/libvideoeditor/vss/src/M4xVSS_internal.c index f4f4137..a322caa 100755 --- a/libvideoeditor/vss/src/M4xVSS_internal.c +++ b/libvideoeditor/vss/src/M4xVSS_internal.c @@ -76,7 +76,8 @@ extern M4OSA_ERR M4MCS_open_normalMode(M4MCS_Context pContext, M4OSA_Void* pFile * @return M4ERR_ALLOC: Memory allocation has failed ****************************************************************************** */ -M4OSA_ERR M4xVSS_internalStartTranscoding(M4OSA_Context pContext) +M4OSA_ERR M4xVSS_internalStartTranscoding(M4OSA_Context pContext, + M4OSA_UInt32 *rotationDegree) { M4xVSS_Context* xVSS_context = (M4xVSS_Context*)pContext; M4OSA_ERR err; @@ -84,6 +85,7 @@ M4OSA_ERR M4xVSS_internalStartTranscoding(M4OSA_Context pContext) M4MCS_OutputParams Params; M4MCS_EncodingParams Rates; M4OSA_UInt32 i; + M4VIDEOEDITING_ClipProperties clipProps; err = M4MCS_init(&mcs_context, xVSS_context->pFileReadPtr, xVSS_context->pFileWritePtr); if(err != M4NO_ERROR) @@ -103,6 +105,16 @@ M4OSA_ERR M4xVSS_internalStartTranscoding(M4OSA_Context pContext) return err; } + /** Get the clip properties + */ + err = M4MCS_getInputFileProperties(mcs_context, &clipProps); + if (err != M4NO_ERROR) { + M4OSA_TRACE1_1("Error in M4MCS_getInputFileProperties: 0x%x", err); + M4MCS_abort(mcs_context); + return err; + } + *rotationDegree = clipProps.videoRotationDegrees; + /** * Fill MCS parameters with the parameters contained in the current element of the MCS parameters chained list */ diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp index b91c2ee..52478ee 100755 --- a/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp +++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp @@ -1519,6 +1519,13 @@ M4OSA_ERR VideoEditor3gpReader_getNextStreamHandler(M4OSA_Context context, LOGV("<<<<<<<<<< video: Average FPS from MP4 extractor in FLOAT: %f", pVideoStreamHandler->m_averageFrameRate); + // Get the video rotation degree + int32_t rotationDegree; + if(!meta->findInt32(kKeyRotation, &rotationDegree)) { + rotationDegree = 0; + } + pVideoStreamHandler->videoRotationDegrees = rotationDegree; + pC->mVideoStreamHandler = (M4_StreamHandler*)(pVideoStreamHandler); |