Add YV12 color converter interface for VideoEditor.
The original assumption in VideoEditor is that the decoder output
and encoder input are in YV12 format. However on different
hardware platform the actual formats may be different. So now we
load a platform-specific YV12 color conversion module which
knows the actual format and can convert to/from YV12, which is
the format used in VideoEditor internally for processing.
Bug: 5061733
Change-Id: I852f85efd30c05cf6c42810059ee4d2ef37ee3da
diff --git a/libvideoeditor/include/IYV12ColorConverter.h b/libvideoeditor/include/IYV12ColorConverter.h
new file mode 100644
index 0000000..e8f497a
--- /dev/null
+++ b/libvideoeditor/include/IYV12ColorConverter.h
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#ifndef IYV12_COLOR_CONVERTER_H
+
+#define IYV12_COLOR_CONVERTER_H
+
+#include <stdint.h>
+#include <android/rect.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct IYV12ColorConverter {
+
+ /*
+ * getDecoderOutputFormat
+ * Returns the color format (OMX_COLOR_FORMATTYPE) of the decoder output.
+ * If it is YV12 (OMX_COLOR_FormatYUV420Planar), no conversion is needed,
+ * and convertDecoderOutputToYV12() can be a no-op.
+ */
+ int (*getDecoderOutputFormat)();
+
+ /*
+ * convertDecoderOutputToYV12
+ * @Desc Converts from the decoder output format to YV12 format.
+ * @note Caller (e.g. VideoEditor) owns the buffers
+ * @param decoderBits (IN) Pointer to the buffer contains decoder output
+ * @param decoderWidth (IN) Buffer width, as reported by the decoder
+ * metadata (kKeyWidth)
+ * @param decoderHeight (IN) Buffer height, as reported by the decoder
+ * metadata (kKeyHeight)
+ * @param decoderRect (IN) The rectangle of the actual frame, as
+ * reported by decoder metadata (kKeyCropRect)
+ * @param dstBits (OUT) Pointer to the output YV12 buffer
+ * @return -1 Any error
+ * @return 0 No Error
+ */
+ int (*convertDecoderOutputToYV12)(
+ void* decoderBits, int decoderWidth, int decoderHeight,
+ ARect decoderRect, void* dstBits);
+
+ /*
+ * getEncoderIntputFormat
+ * Returns the color format (OMX_COLOR_FORMATTYPE) of the encoder input.
+ * If it is YV12 (OMX_COLOR_FormatYUV420Planar), no conversion is needed,
+ * and convertYV12ToEncoderInput() and getEncoderInputBufferInfo() can
+ * be no-ops.
+ */
+ int (*getEncoderInputFormat)();
+
+ /* convertYV12ToEncoderInput
+ * @Desc This function converts from YV12 to the encoder input format
+ * @note Caller (e.g. VideoEditor) owns the buffers
+ * @param srcBits (IN) Pointer to the input YV12 buffer
+ * @param srcWidth (IN) Width of the YV12 frame
+ * @param srcHeight (IN) Height of the YV12 frame
+ * @param encoderWidth (IN) Encoder buffer width, as calculated by
+ * getEncoderBufferInfo()
+ * @param encoderHeight (IN) Encoder buffer height, as calculated by
+ * getEncoderBufferInfo()
+ * @param encoderRect (IN) Rect coordinates of the actual frame inside
+ * the encoder buffer, as calculated by
+ * getEncoderBufferInfo().
+ * @param encoderBits (OUT) Pointer to the output buffer. The size of
+ * this buffer is calculated by
+ * getEncoderBufferInfo()
+ * @return -1 Any error
+ * @return 0 No Error
+ */
+ int (*convertYV12ToEncoderInput)(
+ void* srcBits, int srcWidth, int srcHeight,
+ int encoderWidth, int encoderHeight, ARect encoderRect,
+ void* encoderBits);
+
+ /* getEncoderInputBufferInfo
+ * @Desc This function returns metadata for the encoder input buffer
+ * based on the actual YV12 frame width and height.
+ * @note This API should be be used to obtain the necessary information
+ * before calling convertYV12ToEncoderInput().
+ * VideoEditor knows only the width and height of the YV12 buffer,
+ * but it also needs know the width, height, and size of the
+ * encoder input buffer. The encoder input buffer width and height
+ * are used to set the metadata for the encoder.
+ * @param srcWidth (IN) Width of the YV12 frame
+ * @param srcHeight (IN) Height of the YV12 frame
+ * @param encoderWidth (OUT) Encoder buffer width needed
+ * @param encoderHeight (OUT) Encoder buffer height needed
+ * @param encoderRect (OUT) Rect coordinates of the actual frame inside
+ * the encoder buffer
+ * @param encoderBufferSize (OUT) The size of the buffer that need to be
+ * allocated by the caller before invoking
+ * convertYV12ToEncoderInput().
+ * @return -1 Any error
+ * @return 0 No Error
+ */
+ int (*getEncoderInputBufferInfo)(
+ int srcWidth, int srcHeight,
+ int* encoderWidth, int* encoderHeight,
+ ARect* encoderRect, int* encoderBufferSize);
+
+} IYV12ColorConverter;
+
+/* The only function that the shared library needs to expose: It fills the
+ function pointers in IYV12ColorConverter */
+void getYV12ColorConverter(IYV12ColorConverter *converter);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // IYV12_COLOR_CONVERTER_H
diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk
index be17b83..64e7c73 100755
--- a/libvideoeditor/lvpp/Android.mk
+++ b/libvideoeditor/lvpp/Android.mk
@@ -36,7 +36,8 @@
VideoEditorBGAudioProcessing.cpp \
AudioPlayerBase.cpp \
PreviewPlayerBase.cpp \
- PreviewRenderer.cpp
+ PreviewRenderer.cpp \
+ YV12ColorConverter.cpp
LOCAL_MODULE_TAGS := optional
@@ -77,6 +78,7 @@
$(TOP)/frameworks/media/libvideoeditor/vss/inc \
$(TOP)/frameworks/media/libvideoeditor/vss/stagefrightshells/inc \
$(TOP)/frameworks/media/libvideoeditor/lvpp \
+ $(TOP)/frameworks/media/libvideoeditor/include \
$(TOP)/frameworks/base/media/jni/mediaeditor \
$(TOP)/frameworks/base/services/audioflinger
diff --git a/libvideoeditor/lvpp/PreviewPlayer.cpp b/libvideoeditor/lvpp/PreviewPlayer.cpp
index b70ff4a..f2b82d9 100755
--- a/libvideoeditor/lvpp/PreviewPlayer.cpp
+++ b/libvideoeditor/lvpp/PreviewPlayer.cpp
@@ -178,7 +178,6 @@
mVideoRenderer = NULL;
mLastVideoBuffer = NULL;
- mSuspensionState = NULL;
mEffectsSettings = NULL;
mVeAudioPlayer = NULL;
mAudioMixStoryBoardTS = 0;
@@ -442,9 +441,6 @@
mFileSource.clear();
- delete mSuspensionState;
- mSuspensionState = NULL;
-
mCurrentVideoEffect = VIDEO_EFFECT_NONE;
mIsVideoSourceJpg = false;
mFrameRGBBuffer = NULL;
@@ -759,13 +755,8 @@
if (mSurface != NULL) {
sp<MetaData> meta = mVideoSource->getFormat();
- int32_t format;
const char *component;
- int32_t decodedWidth, decodedHeight;
- CHECK(meta->findInt32(kKeyColorFormat, &format));
CHECK(meta->findCString(kKeyDecoderComponent, &component));
- CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
- CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
// Must ensure that mVideoRenderer's destructor is actually executed
// before creating a new one.
@@ -779,7 +770,7 @@
mVideoRenderer = PreviewLocalRenderer:: initPreviewLocalRenderer (
false, // previewOnly
- (OMX_COLOR_FORMATTYPE)format,
+ OMX_COLOR_FormatYUV420Planar,
mSurface,
mOutputVideoWidth, mOutputVideoHeight,
mOutputVideoWidth, mOutputVideoHeight);
@@ -883,9 +874,7 @@
}
}
- CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
- CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
-
+ getVideoBufferSize(mVideoTrack->getFormat(), &mVideoWidth, &mVideoHeight);
mReportedWidth = mVideoWidth;
mReportedHeight = mVideoHeight;
@@ -958,7 +947,7 @@
mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST);
}
for (;;) {
- status_t err = mVideoSource->read(&mVideoBuffer, &options);
+ status_t err = readYV12Buffer(mVideoSource, &mVideoBuffer, &options);
options.clearSeekTo();
if (err != OK) {
@@ -968,9 +957,8 @@
LOGV("LV PLAYER VideoSource signalled format change");
notifyVideoSize_l();
sp<MetaData> meta = mVideoSource->getFormat();
+ getVideoBufferSize(meta, &mReportedWidth, &mReportedHeight);
- CHECK(meta->findInt32(kKeyWidth, &mReportedWidth));
- CHECK(meta->findInt32(kKeyHeight, &mReportedHeight));
if (mVideoRenderer != NULL) {
mVideoRendererIsPreview = false;
err = initRenderer_l();
@@ -1418,77 +1406,6 @@
mPreparedCondition.broadcast();
}
-status_t PreviewPlayer::suspend() {
- LOGV("suspend");
- Mutex::Autolock autoLock(mLock);
-
- if (mSuspensionState != NULL) {
- if (mLastVideoBuffer == NULL) {
- //go into here if video is suspended again
- //after resuming without being played between
- //them
- SuspensionState *state = mSuspensionState;
- mSuspensionState = NULL;
- reset_l();
- mSuspensionState = state;
- return OK;
- }
-
- delete mSuspensionState;
- mSuspensionState = NULL;
- }
-
- if (mFlags & PREPARING) {
- mFlags |= PREPARE_CANCELLED;
- }
-
- while (mFlags & PREPARING) {
- mPreparedCondition.wait(mLock);
- }
-
- SuspensionState *state = new SuspensionState;
- state->mUri = mUri;
- state->mUriHeaders = mUriHeaders;
- state->mFileSource = mFileSource;
-
- state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
- getPosition(&state->mPositionUs);
-
- if (mLastVideoBuffer) {
- size_t size = mLastVideoBuffer->range_length();
- if (size) {
- int32_t unreadable;
- if (!mLastVideoBuffer->meta_data()->findInt32(
- kKeyIsUnreadable, &unreadable)
- || unreadable == 0) {
- state->mLastVideoFrameSize = size;
- state->mLastVideoFrame = malloc(size);
- memcpy(state->mLastVideoFrame,
- (const uint8_t *)mLastVideoBuffer->data()
- + mLastVideoBuffer->range_offset(),
- size);
-
- state->mVideoWidth = mVideoWidth;
- state->mVideoHeight = mVideoHeight;
-
- sp<MetaData> meta = mVideoSource->getFormat();
- CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat));
- CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth));
- CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight));
- } else {
- LOGV("Unable to save last video frame, we have no access to "
- "the decoded video data.");
- }
- }
- }
-
- reset_l();
-
- mSuspensionState = state;
-
- return OK;
-}
-
void PreviewPlayer::acquireLock() {
LOGV("acquireLock");
mLockControl.lock();
@@ -1499,67 +1416,6 @@
mLockControl.unlock();
}
-status_t PreviewPlayer::resume() {
- LOGV("resume");
- Mutex::Autolock autoLock(mLock);
-
- if (mSuspensionState == NULL) {
- return INVALID_OPERATION;
- }
-
- SuspensionState *state = mSuspensionState;
- mSuspensionState = NULL;
-
- status_t err;
- if (state->mFileSource != NULL) {
- err = PreviewPlayerBase::setDataSource_l(state->mFileSource);
-
- if (err == OK) {
- mFileSource = state->mFileSource;
- }
- } else {
- err = PreviewPlayerBase::setDataSource_l(state->mUri, &state->mUriHeaders);
- }
-
- if (err != OK) {
- delete state;
- state = NULL;
-
- return err;
- }
-
- seekTo_l(state->mPositionUs);
-
- mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
-
- if (state->mLastVideoFrame && (mSurface != NULL)) {
- mVideoRenderer =
- PreviewLocalRenderer::initPreviewLocalRenderer(
- true, // previewOnly
- (OMX_COLOR_FORMATTYPE)state->mColorFormat,
- mSurface,
- state->mVideoWidth,
- state->mVideoHeight,
- state->mDecodedWidth,
- state->mDecodedHeight);
-
- mVideoRendererIsPreview = true;
-
- ((PreviewLocalRenderer *)mVideoRenderer.get())->render(
- state->mLastVideoFrame, state->mLastVideoFrameSize);
- }
-
- if (state->mFlags & PLAYING) {
- play_l();
- }
-
- mSuspensionState = state;
- state = NULL;
-
- return OK;
-}
-
-
status_t PreviewPlayer::loadEffectsSettings(
M4VSS3GPP_EffectSettings* pEffectSettings, int nEffects) {
M4OSA_UInt32 i = 0, rgbSize = 0;
@@ -1647,15 +1503,6 @@
M4VIFI_UInt8 *tempOutputBuffer= M4OSA_NULL;
size_t videoBufferSize = 0;
M4OSA_UInt32 frameSize = 0, i=0, index =0, nFrameCount =0, bufferOffset =0;
- int32_t colorFormat = 0;
-
- if(!mIsVideoSourceJpg) {
- sp<MetaData> meta = mVideoSource->getFormat();
- CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
- }
- else {
- colorFormat = OMX_COLOR_FormatYUV420Planar;
- }
videoBufferSize = mVideoBuffer->size();
frameSize = (mVideoWidth*mVideoHeight*3) >> 1;
@@ -1841,22 +1688,6 @@
M4OSA_ERR PreviewPlayer::doVideoPostProcessing() {
M4OSA_ERR err = M4NO_ERROR;
vePostProcessParams postProcessParams;
- int32_t colorFormat = 0;
-
-
- if(!mIsVideoSourceJpg) {
- sp<MetaData> meta = mVideoSource->getFormat();
- CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
- }
- else {
- colorFormat = OMX_COLOR_FormatYUV420Planar;
- }
-
- if((colorFormat == OMX_COLOR_FormatYUV420SemiPlanar) ||
- (colorFormat == 0x7FA30C00)) {
- LOGE("doVideoPostProcessing: colorFormat YUV420Sp not supported");
- return M4ERR_UNSUPPORTED_MEDIA_TYPE;
- }
postProcessParams.vidBuffer = (M4VIFI_UInt8*)mVideoBuffer->data()
+ mVideoBuffer->range_offset();
@@ -1900,7 +1731,7 @@
mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST);
}
for (;;) {
- status_t err = mVideoSource->read(&mVideoBuffer, &options);
+ status_t err = readYV12Buffer(mVideoSource, &mVideoBuffer, &options);
options.clearSeekTo();
if (err != OK) {
@@ -1910,9 +1741,7 @@
LOGV("LV PLAYER VideoSource signalled format change");
notifyVideoSize_l();
sp<MetaData> meta = mVideoSource->getFormat();
-
- CHECK(meta->findInt32(kKeyWidth, &mReportedWidth));
- CHECK(meta->findInt32(kKeyHeight, &mReportedHeight));
+ getVideoBufferSize(meta, &mReportedWidth, &mReportedHeight);
if (mVideoRenderer != NULL) {
mVideoRendererIsPreview = false;
diff --git a/libvideoeditor/lvpp/PreviewPlayer.h b/libvideoeditor/lvpp/PreviewPlayer.h
index 74a09eb..ccd88a7 100755
--- a/libvideoeditor/lvpp/PreviewPlayer.h
+++ b/libvideoeditor/lvpp/PreviewPlayer.h
@@ -62,8 +62,6 @@
status_t getVideoDimensions(int32_t *width, int32_t *height) const;
- status_t suspend();
- status_t resume();
void acquireLock();
void releaseLock();
@@ -134,32 +132,6 @@
MediaBuffer *mLastVideoBuffer;
- struct SuspensionState {
- String8 mUri;
- KeyedVector<String8, String8> mUriHeaders;
- sp<DataSource> mFileSource;
-
- uint32_t mFlags;
- int64_t mPositionUs;
-
- void *mLastVideoFrame;
- size_t mLastVideoFrameSize;
- int32_t mColorFormat;
- int32_t mVideoWidth, mVideoHeight;
- int32_t mDecodedWidth, mDecodedHeight;
-
- SuspensionState()
- : mLastVideoFrame(NULL) {
- }
-
- ~SuspensionState() {
- if (mLastVideoFrame) {
- free(mLastVideoFrame);
- mLastVideoFrame = NULL;
- }
- }
- } *mSuspensionState;
-
//Data structures used for audio and video effects
M4VSS3GPP_EffectSettings* mEffectsSettings;
M4xVSS_AudioMixingSettings* mPreviewPlayerAudioMixSettings;
diff --git a/libvideoeditor/lvpp/PreviewPlayerBase.cpp b/libvideoeditor/lvpp/PreviewPlayerBase.cpp
index 62b8a72..8e27a27 100644
--- a/libvideoeditor/lvpp/PreviewPlayerBase.cpp
+++ b/libvideoeditor/lvpp/PreviewPlayerBase.cpp
@@ -204,6 +204,13 @@
mAudioStatusEventPending = false;
+ mYV12ColorConverter = new YV12ColorConverter();
+ if (!mYV12ColorConverter->isLoaded() ||
+ mYV12ColorConverter->getDecoderOutputFormat() == OMX_COLOR_FormatYUV420Planar) {
+ delete mYV12ColorConverter;
+ mYV12ColorConverter = NULL;
+ }
+
reset();
}
@@ -212,6 +219,8 @@
mQueue.stop();
}
+ delete mYV12ColorConverter;
+
reset();
mClient.disconnect();
@@ -849,23 +858,33 @@
void PreviewPlayerBase::notifyVideoSize_l() {
sp<MetaData> meta = mVideoSource->getFormat();
+ int32_t vWidth, vHeight;
int32_t cropLeft, cropTop, cropRight, cropBottom;
+
+ CHECK(meta->findInt32(kKeyWidth, &vWidth));
+ CHECK(meta->findInt32(kKeyHeight, &vHeight));
+
+ mGivenWidth = vWidth;
+ mGivenHeight = vHeight;
+
if (!meta->findRect(
kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
- int32_t width, height;
- CHECK(meta->findInt32(kKeyWidth, &width));
- CHECK(meta->findInt32(kKeyHeight, &height));
cropLeft = cropTop = 0;
- cropRight = width - 1;
- cropBottom = height - 1;
+ cropRight = vWidth - 1;
+ cropBottom = vHeight - 1;
- LOGV("got dimensions only %d x %d", width, height);
+ LOGD("got dimensions only %d x %d", vWidth, vHeight);
} else {
- LOGV("got crop rect %d, %d, %d, %d",
+ LOGD("got crop rect %d, %d, %d, %d",
cropLeft, cropTop, cropRight, cropBottom);
}
+ mCropRect.left = cropLeft;
+ mCropRect.right = cropRight;
+ mCropRect.top = cropTop;
+ mCropRect.bottom = cropBottom;
+
int32_t displayWidth;
if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
LOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth);
@@ -910,11 +929,8 @@
int32_t format;
const char *component;
- int32_t decodedWidth, decodedHeight;
CHECK(meta->findInt32(kKeyColorFormat, &format));
CHECK(meta->findCString(kKeyDecoderComponent, &component));
- CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
- CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
int32_t rotationDegrees;
if (!mVideoTrack->getFormat()->findInt32(
@@ -1395,7 +1411,7 @@
: MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
}
for (;;) {
- status_t err = mVideoSource->read(&mVideoBuffer, &options);
+ status_t err = readYV12Buffer(mVideoSource, &mVideoBuffer, &options);
options.clearSeekTo();
if (err != OK) {
@@ -1912,4 +1928,59 @@
status_t PreviewPlayerBase::getParameter(int key, Parcel *reply) {
return OK;
}
+
+status_t PreviewPlayerBase::readYV12Buffer(sp<MediaSource> source, MediaBuffer **buffer,
+ const MediaSource::ReadOptions *options) {
+ status_t result = source->read(buffer, options);
+ if (mYV12ColorConverter == NULL || *buffer == NULL) {
+ return result;
+ }
+
+ int width = mCropRect.right - mCropRect.left + 1;
+ int height = mCropRect.bottom - mCropRect.top + 1;
+
+ MediaBuffer *origBuffer = *buffer;
+ MediaBuffer *newBuffer = new MediaBuffer(width * height * 3 / 2);
+
+ LOGD("convertDecoderOutputToYV12: mGivenWidth = %d, mGivenHeight = %d",
+ mGivenWidth, mGivenHeight);
+ LOGD("width = %d, height = %d", width, height);
+
+ if (mYV12ColorConverter->convertDecoderOutputToYV12(
+ (uint8_t *)origBuffer->data(), // ?? + origBuffer->range_offset(), // decoderBits
+ mGivenWidth, // decoderWidth
+ mGivenHeight, // decoderHeight
+ mCropRect, // decoderRect
+ (uint8_t *)newBuffer->data() + newBuffer->range_offset() /* dstBits */) < 0) {
+ LOGE("convertDecoderOutputToYV12 failed");
+ }
+
+ // Copy the timestamp
+ int64_t timeUs;
+ CHECK(origBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
+ newBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+
+ origBuffer->release();
+ *buffer = newBuffer;
+
+ return result;
+}
+
+void PreviewPlayerBase::getVideoBufferSize(sp<MetaData> meta, int* width, int* height) {
+ if (mYV12ColorConverter) {
+ int32_t cropLeft, cropTop, cropRight, cropBottom;
+ if (meta->findRect(
+ kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) {
+ *width = cropRight - cropLeft + 1;
+ *height = cropBottom - cropTop + 1;
+ } else {
+ CHECK(meta->findInt32(kKeyWidth, width));
+ CHECK(meta->findInt32(kKeyHeight, height));
+ }
+ } else {
+ CHECK(meta->findInt32(kKeyWidth, width));
+ CHECK(meta->findInt32(kKeyHeight, height));
+ }
+}
+
} // namespace android
diff --git a/libvideoeditor/lvpp/PreviewPlayerBase.h b/libvideoeditor/lvpp/PreviewPlayerBase.h
index a68d53c..c094e25 100644
--- a/libvideoeditor/lvpp/PreviewPlayerBase.h
+++ b/libvideoeditor/lvpp/PreviewPlayerBase.h
@@ -23,10 +23,12 @@
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaSource.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/TimeSource.h>
#include <utils/threads.h>
#include <drm/DrmManagerClient.h>
+#include <YV12ColorConverter.h>
namespace android {
@@ -99,6 +101,11 @@
void postAudioEOS(int64_t delayUs = 0ll);
void postAudioSeekComplete();
+protected:
+ status_t readYV12Buffer(sp<MediaSource> source, MediaBuffer **buffer,
+ const MediaSource::ReadOptions *options);
+ void getVideoBufferSize(sp<MetaData> meta, int* width, int* height);
+
private:
friend struct AwesomeEvent;
friend struct PreviewPlayer;
@@ -223,6 +230,10 @@
int64_t mLastVideoTimeUs;
+ ARect mCropRect;
+ int32_t mGivenWidth, mGivenHeight;
+ YV12ColorConverter *mYV12ColorConverter;
+
status_t setDataSource_l(
const char *uri,
const KeyedVector<String8, String8> *headers = NULL);
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.cpp b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
index 2af0e8c..1a298c6 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.cpp
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
@@ -173,16 +173,6 @@
return STAGEFRIGHT_PLAYER;
}
-status_t VideoEditorPlayer::suspend() {
- LOGV("suspend");
- return mPlayer->suspend();
-}
-
-status_t VideoEditorPlayer::resume() {
- LOGV("resume");
- return mPlayer->resume();
-}
-
void VideoEditorPlayer::acquireLock() {
LOGV("acquireLock");
mPlayer->acquireLock();
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.h b/libvideoeditor/lvpp/VideoEditorPlayer.h
index 1afdd88..d1df0e0 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.h
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.h
@@ -112,8 +112,6 @@
virtual player_type playerType();
virtual status_t invoke(const Parcel &request, Parcel *reply);
virtual void setAudioSink(const sp<AudioSink> &audioSink);
- virtual status_t suspend();
- virtual status_t resume();
virtual void acquireLock();
virtual void releaseLock();
virtual status_t setParameter(int key, const Parcel &request);
diff --git a/libvideoeditor/lvpp/YV12ColorConverter.cpp b/libvideoeditor/lvpp/YV12ColorConverter.cpp
new file mode 100755
index 0000000..07fa063
--- /dev/null
+++ b/libvideoeditor/lvpp/YV12ColorConverter.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include <YV12ColorConverter.h>
+#include <cutils/log.h>
+#include <dlfcn.h>
+
+YV12ColorConverter::YV12ColorConverter() {
+ // Open the shared library
+ mHandle = dlopen("libyv12colorconvert.so", RTLD_NOW);
+
+ if (mHandle == NULL) {
+ LOGW("YV12ColorConverter: cannot load libyv12colorconvert.so");
+ return;
+ }
+
+ // Find the entry point
+ void (*getYV12ColorConverter)(YV12ColorConverter *converter) =
+ (void (*)(YV12ColorConverter*)) dlsym(mHandle, "getYV12ColorConverter");
+
+ if (getYV12ColorConverter == NULL) {
+ LOGW("YV12ColorConverter: cannot load getYV12ColorConverter");
+ dlclose(mHandle);
+ mHandle = NULL;
+ return;
+ }
+
+ // Fill the function pointers.
+ getYV12ColorConverter(this);
+
+ LOGI("YV12ColorConverter: libyv12colorconvert.so loaded");
+}
+
+bool YV12ColorConverter::isLoaded() {
+ return mHandle != NULL;
+}
+
+YV12ColorConverter::~YV12ColorConverter() {
+ if (mHandle) {
+ dlclose(mHandle);
+ }
+}
diff --git a/libvideoeditor/lvpp/YV12ColorConverter.h b/libvideoeditor/lvpp/YV12ColorConverter.h
new file mode 100755
index 0000000..32b52f7
--- /dev/null
+++ b/libvideoeditor/lvpp/YV12ColorConverter.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#ifndef YV12_COLOR_CONVERTER_H
+#define YV12_COLOR_CONVERTER_H
+
+#include <IYV12ColorConverter.h>
+
+// This is a wrapper around the YV12 color converter functions in
+// IYV12ColorConverter, which is loaded from a shared library.
+class YV12ColorConverter: public IYV12ColorConverter {
+public:
+ YV12ColorConverter();
+ ~YV12ColorConverter();
+
+ // Returns true if the converter functions are successfully loaded.
+ bool isLoaded();
+private:
+ void* mHandle;
+};
+
+#endif /* YV12_COLOR_CONVERTER_H */
diff --git a/libvideoeditor/vss/stagefrightshells/inc/VideoEditorVideoDecoder_internal.h b/libvideoeditor/vss/stagefrightshells/inc/VideoEditorVideoDecoder_internal.h
index 7d9281b..55d536d 100755
--- a/libvideoeditor/vss/stagefrightshells/inc/VideoEditorVideoDecoder_internal.h
+++ b/libvideoeditor/vss/stagefrightshells/inc/VideoEditorVideoDecoder_internal.h
@@ -35,8 +35,10 @@
#include "M4OSA_Semaphore.h"
#include "VideoEditorBuffer.h"
#include "M4VD_Tools.h"
+#include "YV12ColorConverter.h"
#include <utils/RefBase.h>
+#include <android/rect.h>
#include <OMX_Video.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/OMXCodec.h>
@@ -109,6 +111,8 @@
M4OSA_Double mLastOutputCts;
M4OSA_Int32 mGivenWidth, mGivenHeight; //Used in case of
//INFO_FORMAT_CHANGED
+ ARect mCropRect; // These are obtained from kKeyCropRect.
+ YV12ColorConverter* mYV12ColorConverter;
} VideoEditorVideoDecoder_Context;
diff --git a/libvideoeditor/vss/stagefrightshells/src/Android.mk b/libvideoeditor/vss/stagefrightshells/src/Android.mk
index 2418c89..398750e 100755
--- a/libvideoeditor/vss/stagefrightshells/src/Android.mk
+++ b/libvideoeditor/vss/stagefrightshells/src/Android.mk
@@ -44,6 +44,7 @@
$(TOP)/frameworks/media/libvideoeditor/vss/mcs/inc \
$(TOP)/frameworks/media/libvideoeditor/lvpp \
$(TOP)/frameworks/media/libvideoeditor/osal/inc \
+ $(TOP)/frameworks/media/libvideoeditor/include \
$(TOP)/frameworks/media/libvideoeditor/vss/stagefrightshells/inc
LOCAL_SHARED_LIBRARIES := \
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
index 74508cb..42cfa65 100755
--- a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
@@ -704,6 +704,8 @@
success = meta->findInt32(kKeyHeight, &vHeight);
VIDEOEDITOR_CHECK(TRUE == success, M4ERR_PARAMETER);
+ LOGD("vWidth = %d, vHeight = %d", vWidth, vHeight);
+
pDecShellContext->mGivenWidth = vWidth;
pDecShellContext->mGivenHeight = vHeight;
@@ -715,19 +717,25 @@
cropBottom = vHeight - 1;
LOGV("got dimensions only %d x %d", width, height);
+ LOGD("got dimensions only %d x %d", width, height);
} else {
LOGV("got crop rect %d, %d, %d, %d",
cropLeft, cropTop, cropRight, cropBottom);
+ LOGD("got crop rect %d, %d, %d, %d",
+ cropLeft, cropTop, cropRight, cropBottom);
}
+ pDecShellContext->mCropRect.left = cropLeft;
+ pDecShellContext->mCropRect.right = cropRight;
+ pDecShellContext->mCropRect.top = cropTop;
+ pDecShellContext->mCropRect.bottom = cropBottom;
+
width = cropRight - cropLeft + 1;
height = cropBottom - cropTop + 1;
LOGV("VideoDecoder_configureFromMetadata : W=%d H=%d", width, height);
VIDEOEDITOR_CHECK((0 != width) && (0 != height), M4ERR_PARAMETER);
- LOGV("VideoDecoder_configureFromMetadata : W=%d H=%d", width, height);
-
if( (M4OSA_NULL != pDecShellContext->m_pDecBufferPool) &&
(pDecShellContext->m_pVideoStreamhandler->m_videoWidth == \
(uint32_t)width) &&
@@ -779,6 +787,9 @@
LOGV("VideoEditorVideoDecoder_destroy begin");
VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER);
+ // Release the color converter
+ delete pDecShellContext->mYV12ColorConverter;
+
// Destroy the graph
if( pDecShellContext->mVideoDecoder != NULL ) {
LOGV("### VideoEditorVideoDecoder_destroy : releasing decoder");
@@ -817,6 +828,7 @@
int32_t colorFormat = 0;
M4OSA_UInt32 size = 0;
sp<MetaData> decoderMetadata = NULL;
+ int decoderOutput = OMX_COLOR_FormatYUV420Planar;
LOGV("VideoEditorVideoDecoder_create begin");
// Input parameters check
@@ -930,6 +942,19 @@
pDecShellContext->mVideoDecoder->getFormat()->setInt32(kKeyHeight,
pDecShellContext->m_pVideoStreamhandler->m_videoHeight);
+ // Get the color converter
+ pDecShellContext->mYV12ColorConverter = new YV12ColorConverter;
+ if (pDecShellContext->mYV12ColorConverter->isLoaded()) {
+ decoderOutput = pDecShellContext->mYV12ColorConverter->getDecoderOutputFormat();
+ }
+
+ if (decoderOutput == OMX_COLOR_FormatYUV420Planar) {
+ delete pDecShellContext->mYV12ColorConverter;
+ pDecShellContext->mYV12ColorConverter = NULL;
+ }
+
+ LOGI("decoder output format = 0x%X\n", decoderOutput);
+
// Configure the buffer pool from the metadata
err = VideoEditorVideoDecoder_configureFromMetadata(pDecShellContext,
pDecShellContext->mVideoDecoder->getFormat().get());
@@ -1283,7 +1308,8 @@
}
if( 0 < pDecoderBuffer->range_length() ) {
- LOGV("VIDEOEDITOR_VideoDecoder frame buffer size = %d",
+ LOGV("VIDEOEDITOR_VideoDecoder frame buffer offset = %d, size = %d",
+ pDecoderBuffer->range_offset(),
pDecoderBuffer->range_length());
pDecoderBuffer->meta_data()->findInt64(kKeyTime, &lFrameTime);
@@ -1386,9 +1412,21 @@
break;
}
default:
- LOGV("VideoDecoder_decode: unexpected color format 0x%X",
- pDecShellContext->decOuputColorFormat);
- return M4ERR_PARAMETER;
+ if (pDecShellContext->mYV12ColorConverter) {
+ if (pDecShellContext->mYV12ColorConverter->convertDecoderOutputToYV12(
+ (uint8_t *)pDecoderBuffer->data(),// ?? + pDecoderBuffer->range_offset(), // decoderBits
+ pDecShellContext->mGivenWidth, // decoderWidth
+ pDecShellContext->mGivenHeight, // decoderHeight
+ pDecShellContext->mCropRect, // decoderRect
+ tmpDecBuffer->pData /* dstBits */) < 0) {
+ LOGE("convertDecoderOutputToYV12 failed");
+ }
+ } else {
+ LOGW("VideoDecoder_decode: unexpected color format 0x%X",
+ pDecShellContext->decOuputColorFormat);
+ lerr = M4ERR_PARAMETER;
+ goto VIDEOEDITOR_VideoDecode_cleanUP;
+ }
}
tmpDecBuffer->buffCTS = pDecShellContext->m_lastDecodedCTS;
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoEncoder.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoEncoder.cpp
index 7152ccd..41c757c 100755
--- a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoEncoder.cpp
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoEncoder.cpp
@@ -29,6 +29,7 @@
#include "M4SYS_AccessUnit.h"
#include "VideoEditorVideoEncoder.h"
#include "VideoEditorUtils.h"
+#include <YV12ColorConverter.h>
#include "utils/Log.h"
#include "utils/Vector.h"
@@ -44,9 +45,6 @@
* DEFINITIONS *
********************/
-// Encoder color format
-#define VIDEOEDITOR_ENCODER_COLOR_FORMAT OMX_COLOR_FormatYUV420Planar
-
// Force using hardware encoder
#define VIDEOEDITOR_FORCECODEC kHardwareCodecsOnly
@@ -457,6 +455,7 @@
sp<MediaSource> mEncoder;
OMX_COLOR_FORMATTYPE mEncoderColorFormat;
VideoEditorVideoEncoderPuller* mPuller;
+ YV12ColorConverter* mYV12ColorConverter;
uint32_t mNbInputFrames;
double mFirstInputCts;
@@ -609,6 +608,7 @@
M4OSA_ERR err = M4NO_ERROR;
VideoEditorVideoEncoder_Context* pEncoderContext = M4OSA_NULL;
+ int encoderInput = OMX_COLOR_FormatYUV420Planar;
LOGV("VideoEditorVideoEncoder_init begin: format %d", format);
// Input parameters check
@@ -627,6 +627,18 @@
pEncoderContext->mPreProcContext = pVPPctxt;
pEncoderContext->mPuller = NULL;
+ // Get color converter and determine encoder input format
+ pEncoderContext->mYV12ColorConverter = new YV12ColorConverter;
+ if (pEncoderContext->mYV12ColorConverter->isLoaded()) {
+ encoderInput = pEncoderContext->mYV12ColorConverter->getEncoderInputFormat();
+ }
+ if (encoderInput == OMX_COLOR_FormatYUV420Planar) {
+ delete pEncoderContext->mYV12ColorConverter;
+ pEncoderContext->mYV12ColorConverter = NULL;
+ }
+ pEncoderContext->mEncoderColorFormat = (OMX_COLOR_FORMATTYPE)encoderInput;
+ LOGI("encoder input format = 0x%X\n", encoderInput);
+
*pContext = pEncoderContext;
cleanUp:
@@ -692,6 +704,9 @@
delete pEncoderContext->mPuller;
pEncoderContext->mPuller = NULL;
+ delete pEncoderContext->mYV12ColorConverter;
+ pEncoderContext->mYV12ColorConverter = NULL;
+
// Set the new state
pEncoderContext->mState = CREATED;
@@ -819,7 +834,6 @@
(int32_t)pEncoderContext->mCodecParams->Bitrate);
encoderMetadata->setInt32(kKeyIFramesInterval, 1);
- pEncoderContext->mEncoderColorFormat = VIDEOEDITOR_ENCODER_COLOR_FORMAT;
encoderMetadata->setInt32(kKeyColorFormat,
pEncoderContext->mEncoderColorFormat);
@@ -929,15 +943,35 @@
pEncoderContext->mPreProcContext, M4OSA_NULL, pOutPlane);
VIDEOEDITOR_CHECK(M4NO_ERROR == err, err);
- // Convert to MediaBuffer format if necessary
- if( OMX_COLOR_FormatYUV420SemiPlanar == \
- pEncoderContext->mEncoderColorFormat ) {
- M4OSA_UInt8* pTmpData = M4OSA_NULL;
- pTmpData = pData + sizeY;
- // Highly unoptimized copy...
- for( M4OSA_UInt32 i=0; i<sizeU; i++ ) {
- *pTmpData = pOutPlane[2].pac_data[i]; pTmpData++;
- *pTmpData = pOutPlane[1].pac_data[i]; pTmpData++;
+ // Convert MediaBuffer to the encoder input format if necessary
+ if (pEncoderContext->mYV12ColorConverter) {
+ YV12ColorConverter* converter = pEncoderContext->mYV12ColorConverter;
+ int actualWidth = pEncoderContext->mCodecParams->FrameWidth;
+ int actualHeight = pEncoderContext->mCodecParams->FrameHeight;
+
+ int encoderWidth, encoderHeight;
+ ARect encoderRect;
+ int encoderBufferSize;
+
+ if (converter->getEncoderInputBufferInfo(
+ actualWidth, actualHeight,
+ &encoderWidth, &encoderHeight,
+ &encoderRect, &encoderBufferSize) == 0) {
+
+ MediaBuffer* newBuffer = new MediaBuffer(encoderBufferSize);
+
+ if (converter->convertYV12ToEncoderInput(
+ pData, // srcBits
+ actualWidth, actualHeight,
+ encoderWidth, encoderHeight,
+ encoderRect,
+ (uint8_t*)newBuffer->data() + newBuffer->range_offset()) < 0) {
+ LOGE("convertYV12ToEncoderInput failed");
+ }
+
+ // switch to new buffer
+ buffer->release();
+ buffer = newBuffer;
}
}