Loading media/libstagefright/codecs/on2/enc/Android.mk +5 −0 Original line number Diff line number Diff line Loading @@ -12,11 +12,16 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libstagefright/include \ frameworks/native/include/media/openmax \ ifeq ($(TARGET_DEVICE), manta) LOCAL_CFLAGS += -DSURFACE_IS_BGR32 endif LOCAL_STATIC_LIBRARIES := \ libvpx LOCAL_SHARED_LIBRARIES := \ libstagefright libstagefright_omx libstagefright_foundation libutils liblog \ libhardware \ LOCAL_MODULE := libstagefright_soft_vpxenc LOCAL_MODULE_TAGS := optional Loading media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp +142 −17 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include <utils/Log.h> #include <media/hardware/HardwareAPI.h> #include <media/hardware/MetadataBufferType.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/MediaDefs.h> Loading Loading @@ -81,6 +83,52 @@ inline static void ConvertSemiPlanarToPlanar(uint8_t *inyuv, } } static void ConvertRGB32ToPlanar( const uint8_t *src, uint8_t *dstY, int32_t width, int32_t height) { CHECK((width & 1) == 0); CHECK((height & 1) == 0); uint8_t *dstU = dstY + width * height; uint8_t *dstV = dstU + (width / 2) * (height / 2); for (int32_t y = 0; y < height; ++y) { for (int32_t x = 0; x < width; ++x) { #ifdef SURFACE_IS_BGR32 unsigned blue = src[4 * x]; unsigned green = src[4 * x + 1]; unsigned red= src[4 * x + 2]; #else unsigned red= src[4 * x]; unsigned green = src[4 * x + 1]; unsigned blue = src[4 * x + 2]; #endif unsigned luma = ((red * 66 + green * 129 + blue * 25) >> 8) + 16; dstY[x] = luma; if ((x & 1) == 0 && (y & 1) == 0) { unsigned U = ((-red * 38 - green * 74 + blue * 112) >> 8) + 128; unsigned V = ((red * 112 - green * 94 - blue * 18) >> 8) + 128; dstU[x / 2] = U; dstV[x / 2] = V; } } if ((y & 1) == 0) { dstU += width / 2; dstV += width / 2; } src += 4 * width; dstY += width; } } SoftVPXEncoder::SoftVPXEncoder(const char *name, const OMX_CALLBACKTYPE *callbacks, Loading @@ -99,8 +147,9 @@ SoftVPXEncoder::SoftVPXEncoder(const char *name, mErrorResilience(OMX_FALSE), mColorFormat(OMX_COLOR_FormatYUV420Planar), mLevel(OMX_VIDEO_VP8Level_Version0), mConversionBuffer(NULL) { mConversionBuffer(NULL), mInputDataIsMeta(false), mGrallocModule(NULL) { initPorts(); } Loading Loading @@ -247,7 +296,7 @@ status_t SoftVPXEncoder::initEncoder() { return UNKNOWN_ERROR; } if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) { if (mConversionBuffer == NULL) { mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2); if (mConversionBuffer == NULL) { Loading Loading @@ -427,9 +476,17 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index, (const OMX_VIDEO_PARAM_BITRATETYPE *)param); case OMX_IndexParamPortDefinition: return internalSetPortParams( { OMX_ERRORTYPE err = internalSetPortParams( (const OMX_PARAM_PORTDEFINITIONTYPE *)param); if (err != OMX_ErrorNone) { return err; } return SimpleSoftOMXComponent::internalSetParameter(index, param); } case OMX_IndexParamVideoPortFormat: return internalSetFormatParams( (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param); Loading @@ -442,6 +499,21 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index, return internalSetProfileLevel( (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param); case OMX_IndexVendorStartUnused: { // storeMetaDataInBuffers const StoreMetaDataInBuffersParams *storeParam = (const StoreMetaDataInBuffersParams *)param; if (storeParam->nPortIndex != kInputPortIndex) { return OMX_ErrorBadPortIndex; } mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE); return OMX_ErrorNone; } default: return SimpleSoftOMXComponent::internalSetParameter(index, param); } Loading Loading @@ -507,6 +579,10 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams( format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) { mColorFormat = format->eColorFormat; OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; def->format.video.eColorFormat = mColorFormat; return OMX_ErrorNone; } else { ALOGE("Unsupported color format %i", format->eColorFormat); Loading Loading @@ -557,6 +633,12 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams( return OMX_ErrorUnsupportedSetting; } OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; def->format.video.nFrameWidth = mWidth; def->format.video.nFrameHeight = mHeight; def->format.video.xFramerate = port->format.video.xFramerate; def->format.video.eColorFormat = mColorFormat; return OMX_ErrorNone; } else if (port->nPortIndex == kOutputPortIndex) { mBitrate = port->format.video.nBitrate; Loading Loading @@ -625,19 +707,51 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { return; } uint8_t* source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset; uint8_t *source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset; if (mInputDataIsMeta) { CHECK_GE(inputBufferHeader->nFilledLen, 4 + sizeof(buffer_handle_t)); uint32_t bufferType = *(uint32_t *)source; CHECK_EQ(bufferType, kMetadataBufferTypeGrallocSource); if (mGrallocModule == NULL) { CHECK_EQ(0, hw_get_module( GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule)); } const gralloc_module_t *grmodule = (const gralloc_module_t *)mGrallocModule; buffer_handle_t handle = *(buffer_handle_t *)(source + 4); void *bits; CHECK_EQ(0, grmodule->lock( grmodule, handle, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, 0, 0, mWidth, mHeight, &bits)); ConvertRGB32ToPlanar( (const uint8_t *)bits, mConversionBuffer, mWidth, mHeight); source = mConversionBuffer; CHECK_EQ(0, grmodule->unlock(grmodule, handle)); } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { ConvertSemiPlanarToPlanar( source, mConversionBuffer, mWidth, mHeight); // NOTE: As much as nothing is known about color format // when it is denoted as AndroidOpaque, it is at least // assumed to be planar. if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { ConvertSemiPlanarToPlanar(source, mConversionBuffer, mWidth, mHeight); source = mConversionBuffer; } vpx_image_t raw_frame; vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight, kInputBufferAlignment, source); codec_return = vpx_codec_encode(mCodecContext, codec_return = vpx_codec_encode( mCodecContext, &raw_frame, inputBufferHeader->nTimeStamp, // in timebase units mFrameDurationUs, // frame duration in timebase units Loading Loading @@ -676,6 +790,17 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { notifyEmptyBufferDone(inputBufferHeader); } } OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex( const char *name, OMX_INDEXTYPE *index) { if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) { *index = OMX_IndexVendorStartUnused; return OMX_ErrorNone; } return SimpleSoftOMXComponent::getExtensionIndex(name, index); } } // namespace android Loading media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h +11 −4 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <OMX_VideoExt.h> #include <OMX_IndexExt.h> #include <hardware/gralloc.h> #include "vpx/vpx_encoder.h" #include "vpx/vpx_codec.h" #include "vpx/vp8cx.h" Loading Loading @@ -57,8 +59,7 @@ namespace android { // - OMX timestamps are in microseconds, therefore // encoder timebase is fixed to 1/1000000 class SoftVPXEncoder : public SimpleSoftOMXComponent { public: struct SoftVPXEncoder : public SimpleSoftOMXComponent { SoftVPXEncoder(const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, Loading @@ -83,6 +84,9 @@ class SoftVPXEncoder : public SimpleSoftOMXComponent { // encoding of the frame virtual void onQueueFilled(OMX_U32 portIndex); virtual OMX_ERRORTYPE getExtensionIndex( const char *name, OMX_INDEXTYPE *index); private: // number of buffers allocated per port static const uint32_t kNumBuffers = 4; Loading Loading @@ -156,6 +160,9 @@ class SoftVPXEncoder : public SimpleSoftOMXComponent { // indeed YUV420SemiPlanar. uint8_t* mConversionBuffer; bool mInputDataIsMeta; const hw_module_t *mGrallocModule; // Initializes input and output OMX ports with sensible // default values. void initPorts(); Loading Loading
media/libstagefright/codecs/on2/enc/Android.mk +5 −0 Original line number Diff line number Diff line Loading @@ -12,11 +12,16 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libstagefright/include \ frameworks/native/include/media/openmax \ ifeq ($(TARGET_DEVICE), manta) LOCAL_CFLAGS += -DSURFACE_IS_BGR32 endif LOCAL_STATIC_LIBRARIES := \ libvpx LOCAL_SHARED_LIBRARIES := \ libstagefright libstagefright_omx libstagefright_foundation libutils liblog \ libhardware \ LOCAL_MODULE := libstagefright_soft_vpxenc LOCAL_MODULE_TAGS := optional Loading
media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp +142 −17 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include <utils/Log.h> #include <media/hardware/HardwareAPI.h> #include <media/hardware/MetadataBufferType.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/MediaDefs.h> Loading Loading @@ -81,6 +83,52 @@ inline static void ConvertSemiPlanarToPlanar(uint8_t *inyuv, } } static void ConvertRGB32ToPlanar( const uint8_t *src, uint8_t *dstY, int32_t width, int32_t height) { CHECK((width & 1) == 0); CHECK((height & 1) == 0); uint8_t *dstU = dstY + width * height; uint8_t *dstV = dstU + (width / 2) * (height / 2); for (int32_t y = 0; y < height; ++y) { for (int32_t x = 0; x < width; ++x) { #ifdef SURFACE_IS_BGR32 unsigned blue = src[4 * x]; unsigned green = src[4 * x + 1]; unsigned red= src[4 * x + 2]; #else unsigned red= src[4 * x]; unsigned green = src[4 * x + 1]; unsigned blue = src[4 * x + 2]; #endif unsigned luma = ((red * 66 + green * 129 + blue * 25) >> 8) + 16; dstY[x] = luma; if ((x & 1) == 0 && (y & 1) == 0) { unsigned U = ((-red * 38 - green * 74 + blue * 112) >> 8) + 128; unsigned V = ((red * 112 - green * 94 - blue * 18) >> 8) + 128; dstU[x / 2] = U; dstV[x / 2] = V; } } if ((y & 1) == 0) { dstU += width / 2; dstV += width / 2; } src += 4 * width; dstY += width; } } SoftVPXEncoder::SoftVPXEncoder(const char *name, const OMX_CALLBACKTYPE *callbacks, Loading @@ -99,8 +147,9 @@ SoftVPXEncoder::SoftVPXEncoder(const char *name, mErrorResilience(OMX_FALSE), mColorFormat(OMX_COLOR_FormatYUV420Planar), mLevel(OMX_VIDEO_VP8Level_Version0), mConversionBuffer(NULL) { mConversionBuffer(NULL), mInputDataIsMeta(false), mGrallocModule(NULL) { initPorts(); } Loading Loading @@ -247,7 +296,7 @@ status_t SoftVPXEncoder::initEncoder() { return UNKNOWN_ERROR; } if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) { if (mConversionBuffer == NULL) { mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2); if (mConversionBuffer == NULL) { Loading Loading @@ -427,9 +476,17 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index, (const OMX_VIDEO_PARAM_BITRATETYPE *)param); case OMX_IndexParamPortDefinition: return internalSetPortParams( { OMX_ERRORTYPE err = internalSetPortParams( (const OMX_PARAM_PORTDEFINITIONTYPE *)param); if (err != OMX_ErrorNone) { return err; } return SimpleSoftOMXComponent::internalSetParameter(index, param); } case OMX_IndexParamVideoPortFormat: return internalSetFormatParams( (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param); Loading @@ -442,6 +499,21 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index, return internalSetProfileLevel( (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param); case OMX_IndexVendorStartUnused: { // storeMetaDataInBuffers const StoreMetaDataInBuffersParams *storeParam = (const StoreMetaDataInBuffersParams *)param; if (storeParam->nPortIndex != kInputPortIndex) { return OMX_ErrorBadPortIndex; } mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE); return OMX_ErrorNone; } default: return SimpleSoftOMXComponent::internalSetParameter(index, param); } Loading Loading @@ -507,6 +579,10 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams( format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) { mColorFormat = format->eColorFormat; OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; def->format.video.eColorFormat = mColorFormat; return OMX_ErrorNone; } else { ALOGE("Unsupported color format %i", format->eColorFormat); Loading Loading @@ -557,6 +633,12 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams( return OMX_ErrorUnsupportedSetting; } OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; def->format.video.nFrameWidth = mWidth; def->format.video.nFrameHeight = mHeight; def->format.video.xFramerate = port->format.video.xFramerate; def->format.video.eColorFormat = mColorFormat; return OMX_ErrorNone; } else if (port->nPortIndex == kOutputPortIndex) { mBitrate = port->format.video.nBitrate; Loading Loading @@ -625,19 +707,51 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { return; } uint8_t* source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset; uint8_t *source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset; if (mInputDataIsMeta) { CHECK_GE(inputBufferHeader->nFilledLen, 4 + sizeof(buffer_handle_t)); uint32_t bufferType = *(uint32_t *)source; CHECK_EQ(bufferType, kMetadataBufferTypeGrallocSource); if (mGrallocModule == NULL) { CHECK_EQ(0, hw_get_module( GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule)); } const gralloc_module_t *grmodule = (const gralloc_module_t *)mGrallocModule; buffer_handle_t handle = *(buffer_handle_t *)(source + 4); void *bits; CHECK_EQ(0, grmodule->lock( grmodule, handle, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, 0, 0, mWidth, mHeight, &bits)); ConvertRGB32ToPlanar( (const uint8_t *)bits, mConversionBuffer, mWidth, mHeight); source = mConversionBuffer; CHECK_EQ(0, grmodule->unlock(grmodule, handle)); } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { ConvertSemiPlanarToPlanar( source, mConversionBuffer, mWidth, mHeight); // NOTE: As much as nothing is known about color format // when it is denoted as AndroidOpaque, it is at least // assumed to be planar. if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { ConvertSemiPlanarToPlanar(source, mConversionBuffer, mWidth, mHeight); source = mConversionBuffer; } vpx_image_t raw_frame; vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight, kInputBufferAlignment, source); codec_return = vpx_codec_encode(mCodecContext, codec_return = vpx_codec_encode( mCodecContext, &raw_frame, inputBufferHeader->nTimeStamp, // in timebase units mFrameDurationUs, // frame duration in timebase units Loading Loading @@ -676,6 +790,17 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { notifyEmptyBufferDone(inputBufferHeader); } } OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex( const char *name, OMX_INDEXTYPE *index) { if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) { *index = OMX_IndexVendorStartUnused; return OMX_ErrorNone; } return SimpleSoftOMXComponent::getExtensionIndex(name, index); } } // namespace android Loading
media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h +11 −4 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <OMX_VideoExt.h> #include <OMX_IndexExt.h> #include <hardware/gralloc.h> #include "vpx/vpx_encoder.h" #include "vpx/vpx_codec.h" #include "vpx/vp8cx.h" Loading Loading @@ -57,8 +59,7 @@ namespace android { // - OMX timestamps are in microseconds, therefore // encoder timebase is fixed to 1/1000000 class SoftVPXEncoder : public SimpleSoftOMXComponent { public: struct SoftVPXEncoder : public SimpleSoftOMXComponent { SoftVPXEncoder(const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, Loading @@ -83,6 +84,9 @@ class SoftVPXEncoder : public SimpleSoftOMXComponent { // encoding of the frame virtual void onQueueFilled(OMX_U32 portIndex); virtual OMX_ERRORTYPE getExtensionIndex( const char *name, OMX_INDEXTYPE *index); private: // number of buffers allocated per port static const uint32_t kNumBuffers = 4; Loading Loading @@ -156,6 +160,9 @@ class SoftVPXEncoder : public SimpleSoftOMXComponent { // indeed YUV420SemiPlanar. uint8_t* mConversionBuffer; bool mInputDataIsMeta; const hw_module_t *mGrallocModule; // Initializes input and output OMX ports with sensible // default values. void initPorts(); Loading