Bug 866080 - Use Android I420ColorConverter in OMX plugin r=sotaro,doublec

This commit is contained in:
Edwin Flores 2013-12-17 11:58:16 +13:00
Родитель b038c71e60
Коммит 8d1888e84a
11 изменённых файлов: 393 добавлений и 44 удалений

Просмотреть файл

@ -11,7 +11,7 @@
namespace MPAPI {
enum ColorFormat {
YCbCr,
I420,
RGB565
};

Просмотреть файл

@ -18,6 +18,7 @@
namespace mozilla {
typedef mozilla::layers::Image Image;
typedef mozilla::layers::PlanarYCbCrImage PlanarYCbCrImage;
MediaPluginReader::MediaPluginReader(AbstractMediaDecoder *aDecoder,
const nsACString& aContentType) :
@ -170,7 +171,7 @@ bool MediaPluginReader::DecodeVideoFrame(bool &aKeyframeSkip,
currentImage = bufferCallback.GetImage();
int64_t pos = mDecoder->GetResource()->Tell();
nsIntRect picture = mPicture;
nsAutoPtr<VideoData> v;
if (currentImage) {
gfx::IntSize frameSize = currentImage->GetSize();
@ -338,33 +339,79 @@ MediaPluginReader::ImageBufferCallback::ImageBufferCallback(mozilla::layers::Ima
void *
MediaPluginReader::ImageBufferCallback::operator()(size_t aWidth, size_t aHeight,
MPAPI::ColorFormat aColorFormat)
MPAPI::ColorFormat aColorFormat)
{
if (!mImageContainer) {
NS_WARNING("No image container to construct an image");
return nullptr;
}
nsRefPtr<Image> rgbImage;
nsRefPtr<Image> image;
switch(aColorFormat) {
case MPAPI::RGB565:
rgbImage = mozilla::layers::CreateSharedRGBImage(mImageContainer,
nsIntSize(aWidth, aHeight),
gfxImageFormatRGB16_565);
if (!rgbImage) {
image = mozilla::layers::CreateSharedRGBImage(mImageContainer,
nsIntSize(aWidth, aHeight),
gfxImageFormatRGB16_565);
if (!image) {
NS_WARNING("Could not create rgb image");
return nullptr;
}
mImage = rgbImage;
return rgbImage->AsSharedImage()->GetBuffer();
case MPAPI::YCbCr:
mImage = image;
return image->AsSharedImage()->GetBuffer();
case MPAPI::I420:
return CreateI420Image(aWidth, aHeight);
default:
NS_NOTREACHED("Color format not supported");
return nullptr;
}
}
uint8_t *
MediaPluginReader::ImageBufferCallback::CreateI420Image(size_t aWidth,
size_t aHeight)
{
ImageFormat format = PLANAR_YCBCR;
mImage = mImageContainer->CreateImage(&format, 1 /* numFormats */);
PlanarYCbCrImage *yuvImage = static_cast<PlanarYCbCrImage *>(mImage.get());
if (!yuvImage) {
NS_WARNING("Could not create I420 image");
return nullptr;
}
size_t frameSize = aWidth * aHeight;
// Allocate enough for one full resolution Y plane
// and two quarter resolution Cb/Cr planes.
uint8_t *buffer = yuvImage->AllocateAndGetNewBuffer(frameSize * 3 / 2);
mozilla::layers::PlanarYCbCrData frameDesc;
frameDesc.mYChannel = buffer;
frameDesc.mCbChannel = buffer + frameSize;
frameDesc.mCrChannel = buffer + frameSize * 5 / 4;
frameDesc.mYSize = gfxIntSize(aWidth, aHeight);
frameDesc.mCbCrSize = gfxIntSize(aWidth / 2, aHeight / 2);
frameDesc.mYStride = aWidth;
frameDesc.mCbCrStride = aWidth / 2;
frameDesc.mYSkip = 0;
frameDesc.mCbSkip = 0;
frameDesc.mCrSkip = 0;
frameDesc.mPicX = 0;
frameDesc.mPicY = 0;
frameDesc.mPicSize = gfxIntSize(aWidth, aHeight);
yuvImage->SetDataNoCopy(frameDesc);
return buffer;
}
already_AddRefed<Image>
MediaPluginReader::ImageBufferCallback::GetImage()
{

Просмотреть файл

@ -65,17 +65,23 @@ public:
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags);
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
class ImageBufferCallback : public MPAPI::BufferCallback {
typedef mozilla::layers::Image Image;
public:
ImageBufferCallback(mozilla::layers::ImageContainer *aImageContainer);
void *operator()(size_t aWidth, size_t aHeight,
MPAPI::ColorFormat aColorFormat) MOZ_OVERRIDE;
already_AddRefed<Image> GetImage();
private:
uint8_t *CreateI420Image(size_t aWidth, size_t aHeight);
mozilla::layers::ImageContainer *mImageContainer;
nsRefPtr<Image> mImage;
};
};
} // namespace mozilla

Просмотреть файл

@ -53,6 +53,8 @@ EXTRA_DSO_LDOPTS += \
-lutils \
-L$(DEPTH)/media/omx-plugin/lib/ics/libstagefright \
-lstagefright \
-L$(DEPTH)/media/omx-plugin/lib/ics/libvideoeditorplayer \
-lvideoeditorplayer \
$(NULL)
INCLUDES += \

Просмотреть файл

@ -37,6 +37,14 @@
#define MOZ_ANDROID_V2_X_X
#endif
#if !defined(MOZ_ANDROID_V2_X_X) && !defined(MOZ_ANDROID_HC)
#define MOZ_ANDROID_V4_OR_ABOVE
#endif
#if defined(MOZ_ANDROID_V4_OR_ABOVE)
#include <I420ColorConverter.h>
#endif
using namespace MPAPI;
#if !defined(MOZ_STAGEFRIGHT_OFF_T)
@ -68,6 +76,8 @@ class OmxDecoder {
int32_t mVideoSliceHeight;
int32_t mVideoCropLeft;
int32_t mVideoCropTop;
int32_t mVideoCropRight;
int32_t mVideoCropBottom;
int32_t mVideoRotation;
int32_t mAudioChannels;
int32_t mAudioSampleRate;
@ -92,6 +102,7 @@ class OmxDecoder {
void ToVideoFrame_YVU420PackedSemiPlanar32m4ka(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame);
bool ToVideoFrame_RGB565(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback);
bool ToVideoFrame_ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback);
bool ToVideoFrame_I420ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback);
bool ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback);
bool ToAudioFrame(AudioFrame *aFrame, int64_t aTimeUs, void *aData, size_t aDataOffset, size_t aSize,
int32_t aAudioChannels, int32_t aAudioSampleRate);
@ -139,6 +150,8 @@ OmxDecoder::OmxDecoder(PluginHost *aPluginHost, Decoder *aDecoder) :
mVideoSliceHeight(0),
mVideoCropLeft(0),
mVideoCropTop(0),
mVideoCropRight(0),
mVideoCropBottom(0),
mVideoRotation(0),
mAudioChannels(-1),
mAudioSampleRate(-1),
@ -226,11 +239,48 @@ static uint32_t GetVideoCreationFlags(PluginHost* aPluginHost)
#endif
}
static bool
IsColorFormatSupported(OMX_COLOR_FORMATTYPE aColorFormat)
{
switch (aColorFormat) {
case OMX_COLOR_FormatCbYCrY:
case OMX_COLOR_FormatYUV420Planar:
case OMX_COLOR_FormatYUV420SemiPlanar:
case OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka:
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
LOG("Colour format %#x supported natively.", aColorFormat);
return true;
default:
break;
}
#if !defined(MOZ_ANDROID_HC)
if (ColorConverter(aColorFormat, OMX_COLOR_Format16bitRGB565).isValid()) {
LOG("Colour format %#x supported by Android ColorConverter.", aColorFormat);
return true;
}
#endif
#if defined(MOZ_ANDROID_V4_OR_ABOVE)
I420ColorConverter yuvConverter;
if (yuvConverter.isLoaded() &&
yuvConverter.getDecoderOutputFormat() == aColorFormat) {
LOG("Colour format %#x supported by Android I420ColorConverter.", aColorFormat);
return true;
}
#endif
return false;
}
static sp<MediaSource> CreateVideoSource(PluginHost* aPluginHost,
const sp<IOMX>& aOmx,
const sp<MediaSource>& aVideoTrack)
{
uint32_t flags = GetVideoCreationFlags(aPluginHost);
if (flags == DEFAULT_STAGEFRIGHT_FLAGS) {
// Let Stagefright choose hardware or software decoder.
sp<MediaSource> videoSource = OMXCodec::Create(aOmx, aVideoTrack->getFormat(),
@ -242,30 +292,14 @@ static sp<MediaSource> CreateVideoSource(PluginHost* aPluginHost,
// check whether we know how to decode this video.
int32_t videoColorFormat;
if (videoSource->getFormat()->findInt32(kKeyColorFormat, &videoColorFormat)) {
switch (videoColorFormat) {
// We know how to convert these color formats.
case OMX_COLOR_FormatCbYCrY:
case OMX_COLOR_FormatYUV420Planar:
case OMX_COLOR_FormatYUV420SemiPlanar:
case OMX_QCOM_COLOR_FormatYVU420PackedSemiPlanar32m4ka:
case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
// Use the decoder Stagefright chose for us!
return videoSource;
// Use software decoder for color formats we don't know how to convert.
default:
#ifndef MOZ_ANDROID_HC
if (ColorConverter((OMX_COLOR_FORMATTYPE)videoColorFormat,
OMX_COLOR_Format16bitRGB565).isValid()) {
return videoSource;
}
#endif
// We need to implement a ToVideoFrame_*() color conversion
// function for this video color format.
LOG("Unknown video color format: %#x", videoColorFormat);
break;
if (IsColorFormatSupported((OMX_COLOR_FORMATTYPE)videoColorFormat)) {
return videoSource;
}
// We need to implement a ToVideoFrame_*() color conversion
// function for this video color format.
LOG("Unknown video color format: %#x", videoColorFormat);
} else {
LOG("Video color format not found");
}
@ -472,29 +506,28 @@ bool OmxDecoder::SetVideoFormat() {
return false;
}
int32_t cropRight, cropBottom;
// Gingerbread does not support the kKeyCropRect key
#if !defined(MOZ_ANDROID_V2_X_X)
if (!format->findRect(kKeyCropRect, &mVideoCropLeft, &mVideoCropTop,
&cropRight, &cropBottom)) {
&mVideoCropRight, &mVideoCropBottom)) {
#endif
mVideoCropLeft = 0;
mVideoCropTop = 0;
cropRight = mVideoStride - 1;
cropBottom = mVideoSliceHeight - 1;
mVideoCropRight = mVideoStride - 1;
mVideoCropBottom = mVideoSliceHeight - 1;
LOG("crop rect not available, assuming no cropping");
#if !defined(MOZ_ANDROID_V2_X_X)
}
#endif
if (mVideoCropLeft < 0 || mVideoCropLeft >= cropRight || cropRight >= mVideoStride ||
mVideoCropTop < 0 || mVideoCropTop >= cropBottom || cropBottom >= mVideoSliceHeight) {
LOG("invalid crop rect %d,%d-%d,%d", mVideoCropLeft, mVideoCropTop, cropRight, cropBottom);
if (mVideoCropLeft < 0 || mVideoCropLeft >= mVideoCropRight || mVideoCropRight >= mVideoStride ||
mVideoCropTop < 0 || mVideoCropTop >= mVideoCropBottom || mVideoCropBottom >= mVideoSliceHeight) {
LOG("invalid crop rect %d,%d-%d,%d", mVideoCropLeft, mVideoCropTop, mVideoCropRight, mVideoCropBottom);
return false;
}
mVideoWidth = cropRight - mVideoCropLeft + 1;
mVideoHeight = cropBottom - mVideoCropTop + 1;
mVideoWidth = mVideoCropRight - mVideoCropLeft + 1;
mVideoHeight = mVideoCropBottom - mVideoCropTop + 1;
MOZ_ASSERT(mVideoWidth > 0 && mVideoWidth <= mVideoStride);
MOZ_ASSERT(mVideoHeight > 0 && mVideoHeight <= mVideoSliceHeight);
@ -515,7 +548,7 @@ bool OmxDecoder::SetVideoFormat() {
LOG("width: %d height: %d component: %s format: %#x stride: %d sliceHeight: %d rotation: %d crop: %d,%d-%d,%d",
mVideoWidth, mVideoHeight, componentName, mVideoColorFormat,
mVideoStride, mVideoSliceHeight, mVideoRotation,
mVideoCropLeft, mVideoCropTop, cropRight, cropBottom);
mVideoCropLeft, mVideoCropTop, mVideoCropRight, mVideoCropBottom);
return true;
}
@ -682,6 +715,40 @@ bool OmxDecoder::ToVideoFrame_ColorConverter(VideoFrame *aFrame, int64_t aTimeUs
#endif
}
bool OmxDecoder::ToVideoFrame_I420ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback)
{
#if defined(MOZ_ANDROID_V4_OR_ABOVE)
I420ColorConverter yuvConverter;
if (!yuvConverter.isLoaded()) {
return false;
}
if (yuvConverter.getDecoderOutputFormat() != mVideoColorFormat) {
return false;
}
void *buffer = (*aBufferCallback)(mVideoWidth, mVideoHeight, MPAPI::I420);
ARect crop = { mVideoCropLeft, mVideoCropTop, mVideoCropRight, mVideoCropBottom };
int result = yuvConverter.convertDecoderOutputToI420(aData,
mVideoWidth,
mVideoHeight,
crop,
buffer);
// result is 0 on success, -1 otherwise.
if (result == OK) {
aFrame->mTimeUs = aTimeUs;
aFrame->mSize = mVideoWidth * mVideoHeight * 3 / 2;
}
return result == OK;
#else
return false;
#endif
}
bool OmxDecoder::ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback) {
switch (mVideoColorFormat) {
// Froyo support is best handled with the android color conversion code. I
@ -710,7 +777,8 @@ bool OmxDecoder::ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData,
break;
#endif
default:
if (!ToVideoFrame_ColorConverter(aFrame, aTimeUs, aData, aSize, aKeyFrame, aBufferCallback)) {
if (!ToVideoFrame_ColorConverter(aFrame, aTimeUs, aData, aSize, aKeyFrame, aBufferCallback) &&
!ToVideoFrame_I420ColorConverter(aFrame, aTimeUs, aData, aSize, aKeyFrame, aBufferCallback)) {
LOG("Unknown video color format: %#x", mVideoColorFormat);
return false;
}

Просмотреть файл

@ -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 I420_COLOR_CONVERTER_H
#define I420_COLOR_CONVERTER_H
#include <II420ColorConverter.h>
// This is a wrapper around the I420 color converter functions in
// II420ColorConverter, which is loaded from a shared library.
class I420ColorConverter: public II420ColorConverter {
public:
I420ColorConverter();
~I420ColorConverter();
// Returns true if the converter functions are successfully loaded.
bool isLoaded();
private:
void* mHandle;
};
#endif /* I420_COLOR_CONVERTER_H */

Просмотреть файл

@ -0,0 +1,127 @@
/*
* 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 II420_COLOR_CONVERTER_H
#define II420_COLOR_CONVERTER_H
#include <stdint.h>
#include <android/rect.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct II420ColorConverter {
/*
* getDecoderOutputFormat
* Returns the color format (OMX_COLOR_FORMATTYPE) of the decoder output.
* If it is I420 (OMX_COLOR_FormatYUV420Planar), no conversion is needed,
* and convertDecoderOutputToI420() can be a no-op.
*/
int (*getDecoderOutputFormat)();
/*
* convertDecoderOutputToI420
* @Desc Converts from the decoder output format to I420 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 I420 buffer
* @return -1 Any error
* @return 0 No Error
*/
int (*convertDecoderOutputToI420)(
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 I420 (OMX_COLOR_FormatYUV420Planar), no conversion is needed,
* and convertI420ToEncoderInput() and getEncoderInputBufferInfo() can
* be no-ops.
*/
int (*getEncoderInputFormat)();
/* convertI420ToEncoderInput
* @Desc This function converts from I420 to the encoder input format
* @note Caller (e.g. VideoEditor) owns the buffers
* @param srcBits (IN) Pointer to the input I420 buffer
* @param srcWidth (IN) Width of the I420 frame
* @param srcHeight (IN) Height of the I420 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 (*convertI420ToEncoderInput)(
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 I420 frame width and height.
* @note This API should be be used to obtain the necessary information
* before calling convertI420ToEncoderInput().
* VideoEditor knows only the width and height of the I420 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 I420 frame
* @param srcHeight (IN) Height of the I420 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
* convertI420ToEncoderInput().
* @return -1 Any error
* @return 0 No Error
*/
int (*getEncoderInputBufferInfo)(
int srcWidth, int srcHeight,
int* encoderWidth, int* encoderHeight,
ARect* encoderRect, int* encoderBufferSize);
} II420ColorConverter;
/* The only function that the shared library needs to expose: It fills the
function pointers in II420ColorConverter */
void getI420ColorConverter(II420ColorConverter *converter);
#if defined(__cplusplus)
}
#endif
#endif // II420_COLOR_CONVERTER_H

Просмотреть файл

@ -0,0 +1,25 @@
# Copyright 2012 Mozilla Foundation and Mozilla contributors
#
# 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.
# Don't use STL wrappers; this isn't Gecko code
STL_FLAGS =
# must link statically with the CRT; this isn't Gecko code
USE_STATIC_LIBS = 1
include $(topsrcdir)/config/rules.mk
INCLUDES += \
-I$(topsrcdir)/media/omx-plugin/include/ics \
$(NULL)

Просмотреть файл

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Types.h"
#include "I420ColorConverter.h"
MOZ_EXPORT
I420ColorConverter::I420ColorConverter()
{
}
MOZ_EXPORT
I420ColorConverter::~I420ColorConverter()
{
}
MOZ_EXPORT bool
I420ColorConverter::isLoaded()
{
return false;
}

Просмотреть файл

@ -0,0 +1,15 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
NO_DIST_INSTALL = True
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
SOURCES += [
'libvideoeditorplayer.cpp',
]
LIBRARY_NAME = 'videoeditorplayer'
FORCE_SHARED_LIB = True

Просмотреть файл

@ -75,6 +75,7 @@ if CONFIG['MOZ_OMX_PLUGIN']:
add_tier_dir('platform', [
'media/omx-plugin/lib/ics/libutils',
'media/omx-plugin/lib/ics/libstagefright',
'media/omx-plugin/lib/ics/libvideoeditorplayer',
'media/omx-plugin/lib/gb/libutils',
'media/omx-plugin/lib/gb/libstagefright',
'media/omx-plugin/lib/gb/libstagefright_color_conversion',