summaryrefslogtreecommitdiffstats
path: root/libvideoeditor
diff options
context:
space:
mode:
authorRajneesh Chowdury <rajneeshc@google.com>2011-08-30 12:59:30 -0700
committerRajneesh Chowdury <rajneeshc@google.com>2011-08-30 12:59:30 -0700
commite9eec0e0975c57c0dac91eb5b4cbb052b7dd011a (patch)
treea0149c5899128a58ddd146620f566371c365b049 /libvideoeditor
parentdac2f050b814bd72ff66b4ae58634c25fb2185ff (diff)
downloadframeworks_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-xlibvideoeditor/lvpp/VideoEditorPreviewController.cpp20
-rwxr-xr-xlibvideoeditor/lvpp/VideoEditorTools.cpp211
-rwxr-xr-xlibvideoeditor/lvpp/VideoEditorTools.h11
-rwxr-xr-xlibvideoeditor/vss/common/inc/M4DA_Types.h1
-rwxr-xr-xlibvideoeditor/vss/common/inc/M4_VideoEditingCommon.h2
-rwxr-xr-xlibvideoeditor/vss/inc/M4xVSS_Internal.h3
-rwxr-xr-xlibvideoeditor/vss/mcs/src/M4MCS_API.c2
-rwxr-xr-xlibvideoeditor/vss/src/M4VD_EXTERNAL_BitstreamParser.c6
-rwxr-xr-xlibvideoeditor/vss/src/M4VSS3GPP_EditVideo.c388
-rwxr-xr-xlibvideoeditor/vss/src/M4xVSS_API.c29
-rwxr-xr-xlibvideoeditor/vss/src/M4xVSS_internal.c14
-rwxr-xr-xlibvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp7
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);