Bug 767480 - Gralloc backed video buffer. r=roc

This commit is contained in:
Kan-Ru Chen (陳侃如) 2012-08-21 18:22:58 +08:00
Родитель a55761dc81
Коммит 967b36e8ae
8 изменённых файлов: 250 добавлений и 21 удалений

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

@ -63,6 +63,20 @@ ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
aPlane.mStride > 0;
}
static bool
IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane,
const VideoData::YCbCrBuffer::Plane& aCbPlane,
const VideoData::YCbCrBuffer::Plane& aCrPlane)
{
return
aYPlane.mWidth % 2 == 0 &&
aYPlane.mHeight % 2 == 0 &&
aYPlane.mWidth / 2 == aCbPlane.mWidth &&
aYPlane.mHeight / 2 == aCbPlane.mHeight &&
aCbPlane.mWidth == aCrPlane.mWidth &&
aCbPlane.mHeight == aCrPlane.mHeight;
}
bool
nsVideoInfo::ValidateVideoRegion(const nsIntSize& aFrame,
const nsIntRect& aPicture,
@ -183,22 +197,27 @@ VideoData* VideoData::Create(nsVideoInfo& aInfo,
aKeyframe,
aTimecode,
aInfo.mDisplay));
// Currently our decoder only knows how to output to PLANAR_YCBCR
// format.
ImageFormat format = PLANAR_YCBCR;
v->mImage = aContainer->CreateImage(&format, 1);
if (!v->mImage) {
return nullptr;
}
NS_ASSERTION(v->mImage->GetFormat() == PLANAR_YCBCR,
"Wrong format?");
PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
PlanarYCbCrImage::Data data;
const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
// Currently our decoder only knows how to output to PLANAR_YCBCR
// format.
ImageFormat format[2] = {PLANAR_YCBCR, GRALLOC_PLANAR_YCBCR};
if (IsYV12Format(Y, Cb, Cr)) {
v->mImage = aContainer->CreateImage(format, 2);
} else {
v->mImage = aContainer->CreateImage(format, 1);
}
if (!v->mImage) {
return nullptr;
}
NS_ASSERTION(v->mImage->GetFormat() == PLANAR_YCBCR ||
v->mImage->GetFormat() == GRALLOC_PLANAR_YCBCR,
"Wrong format?");
PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
PlanarYCbCrImage::Data data;
data.mYChannel = Y.mData;
data.mYSize = gfxIntSize(Y.mWidth, Y.mHeight);
data.mYStride = Y.mStride;

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

@ -0,0 +1,108 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/layers/ImageBridgeChild.h"
#include "nsDebug.h"
#include "ImageContainer.h"
#include "GrallocImages.h"
using namespace mozilla::ipc;
using namespace android;
namespace mozilla {
namespace layers {
GrallocPlanarYCbCrImage::GrallocPlanarYCbCrImage()
: PlanarYCbCrImage(nullptr)
{
mFormat = GRALLOC_PLANAR_YCBCR;
}
GrallocPlanarYCbCrImage::~GrallocPlanarYCbCrImage()
{
ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
ibc->DeallocSurfaceDescriptorGralloc(mSurfaceDescriptor);
}
void
GrallocPlanarYCbCrImage::SetData(const Data& aData)
{
NS_PRECONDITION(aData.mYSize.width % 2 == 0, "Image should have even width");
NS_PRECONDITION(aData.mYSize.height % 2 == 0, "Image should have even height");
NS_PRECONDITION(aData.mYStride % 16 == 0, "Image should have stride of multiple of 16 pixels");
mData = aData;
mSize = aData.mPicSize;
if (mSurfaceDescriptor.type() == SurfaceDescriptor::T__None) {
ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
ibc->AllocSurfaceDescriptorGralloc(aData.mYSize,
HAL_PIXEL_FORMAT_YV12,
GraphicBuffer::USAGE_SW_READ_OFTEN |
GraphicBuffer::USAGE_SW_WRITE_OFTEN |
GraphicBuffer::USAGE_HW_TEXTURE,
&mSurfaceDescriptor);
}
sp<GraphicBuffer> graphicBuffer =
GrallocBufferActor::GetFrom(mSurfaceDescriptor.get_SurfaceDescriptorGralloc());
if (!graphicBuffer.get()) {
return;
}
if (graphicBuffer->initCheck() != NO_ERROR) {
return;
}
void* vaddr;
if (graphicBuffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
&vaddr) != OK) {
return;
}
PRUint8* yChannel = static_cast<PRUint8*>(vaddr);
gfxIntSize ySize = gfxIntSize(aData.mYSize.width,
aData.mYSize.height);
PRInt32 yStride = graphicBuffer->getStride();
PRUint8* vChannel = yChannel + (yStride * ySize.height);
gfxIntSize uvSize = gfxIntSize(ySize.width / 2,
ySize.height / 2);
// Align to 16 bytes boundary
PRInt32 uvStride = ((yStride / 2) + 15) & ~0x0F;
PRUint8* uChannel = vChannel + (uvStride * uvSize.height);
// Memory outside of the image width may not writable. If the stride
// equals to the image width then we can use only one copy.
if (yStride == mData.mYStride &&
yStride == ySize.width) {
memcpy(yChannel, mData.mYChannel, yStride * ySize.width);
} else {
for (int i = 0; i < ySize.height; i++) {
memcpy(yChannel + i * yStride,
mData.mYChannel + i * mData.mYStride,
ySize.width);
}
}
if (uvStride == mData.mCbCrStride &&
uvStride == uvSize.width) {
memcpy(uChannel, mData.mCbChannel, uvStride * uvSize.width);
memcpy(vChannel, mData.mCrChannel, uvStride * uvSize.width);
} else {
for (int i = 0; i < uvSize.height; i++) {
memcpy(uChannel + i * uvStride,
mData.mCbChannel + i * mData.mCbCrStride,
uvSize.width);
memcpy(vChannel + i * uvStride,
mData.mCrChannel + i * mData.mCbCrStride,
uvSize.width);
}
}
graphicBuffer->unlock();
}
} // namespace layers
} // namespace mozilla

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

@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/. */
#ifndef GRALLOCIMAGES_H
#define GRALLOCIMAGES_H
#ifdef MOZ_WIDGET_GONK
#include "mozilla/layers/LayersSurfaces.h"
#include "ImageLayers.h"
#include <ui/GraphicBuffer.h>
namespace mozilla {
namespace layers {
/**
* The YUV format supported by Android HAL
*
* 4:2:0 - CbCr width and height is half that of Y.
*
* This format assumes
* - an even width
* - an even height
* - a horizontal stride multiple of 16 pixels
* - a vertical stride equal to the height
*
* y_size = stride * height
* c_size = ALIGN(stride/2, 16) * height/2
* size = y_size + c_size * 2
* cr_offset = y_size
* cb_offset = y_size + c_size
*
* The Image that is rendered is the picture region defined by
* mPicX, mPicY and mPicSize. The size of the rendered image is
* mPicSize, not mYSize or mCbCrSize.
*/
class THEBES_API GrallocPlanarYCbCrImage : public PlanarYCbCrImage {
typedef PlanarYCbCrImage::Data Data;
public:
GrallocPlanarYCbCrImage();
virtual ~GrallocPlanarYCbCrImage();
/**
* This makes a copy of the data buffers, in order to support functioning
* in all different layer managers.
*/
virtual void SetData(const Data& aData);
virtual PRUint32 GetDataSize() { return 0; }
virtual bool IsValid() { return mSurfaceDescriptor.type() != SurfaceDescriptor::T__None; }
SurfaceDescriptor GetSurfaceDescriptor() {
return mSurfaceDescriptor;
}
private:
SurfaceDescriptor mSurfaceDescriptor;
};
} // namespace layers
} // namespace mozilla
#endif
#endif /* GRALLOCIMAGES_H */

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

@ -9,6 +9,7 @@
#include "ImageContainer.h"
#include "GonkIOSurfaceImage.h"
#include "GrallocImages.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/CrossProcessMutex.h"
#include "SharedTextureImage.h"
@ -30,6 +31,7 @@
#endif
using namespace mozilla::ipc;
using namespace android;
using mozilla::gfx::DataSourceSurface;
using mozilla::gfx::SourceSurface;
@ -47,22 +49,37 @@ ImageFactory::CreateImage(const ImageFormat *aFormats,
return nullptr;
}
nsRefPtr<Image> img;
#ifdef MOZ_WIDGET_GONK
if (FormatInList(aFormats, aNumFormats, GRALLOC_PLANAR_YCBCR)) {
img = new GrallocPlanarYCbCrImage();
return img.forget();
}
#endif
if (FormatInList(aFormats, aNumFormats, PLANAR_YCBCR)) {
img = new PlanarYCbCrImage(aRecycleBin);
} else if (FormatInList(aFormats, aNumFormats, CAIRO_SURFACE)) {
return img.forget();
}
if (FormatInList(aFormats, aNumFormats, CAIRO_SURFACE)) {
img = new CairoImage();
} else if (FormatInList(aFormats, aNumFormats, SHARED_TEXTURE)) {
return img.forget();
}
if (FormatInList(aFormats, aNumFormats, SHARED_TEXTURE)) {
img = new SharedTextureImage();
return img.forget();
}
#ifdef XP_MACOSX
} else if (FormatInList(aFormats, aNumFormats, MAC_IO_SURFACE)) {
if (FormatInList(aFormats, aNumFormats, MAC_IO_SURFACE)) {
img = new MacIOSurfaceImage();
return img.forget();
}
#endif
#ifdef MOZ_WIDGET_GONK
} else if (FormatInList(aFormats, aNumFormats, GONK_IO_SURFACE)) {
if (FormatInList(aFormats, aNumFormats, GONK_IO_SURFACE)) {
img = new GonkIOSurfaceImage();
#endif
return img.forget();
}
return img.forget();
#endif
return nullptr;
}
BufferRecycleBin::BufferRecycleBin()

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

@ -644,7 +644,7 @@ public:
MAX_DIMENSION = 16384
};
~PlanarYCbCrImage();
virtual ~PlanarYCbCrImage();
/**
* This makes a copy of the data buffers, in order to support functioning

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

@ -16,6 +16,13 @@ enum ImageFormat {
*/
PLANAR_YCBCR,
/**
* The GRALLOC_PLANAR_YCBCR format creates a GrallocPlanarYCbCrImage, a
* subtype of PlanarYCbCrImage. It takes a PlanarYCbCrImage data and can be
* used as a texture by Gonk backend directly.
*/
GRALLOC_PLANAR_YCBCR,
/**
* The CAIRO_SURFACE format creates a CairoImage. All backends should
* support this format, because video rendering sometimes requires it.
@ -73,4 +80,4 @@ enum StereoMode {
} // namespace
#endif
#endif

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

@ -172,7 +172,10 @@ endif
# has full system permissions there.
ifeq ($(MOZ_WIDGET_TOOLKIT),gonk)
EXPORTS_mozilla/layers += ShadowLayerUtilsGralloc.h
CPPSRCS += ShadowLayerUtilsGralloc.cpp
CPPSRCS += \
ShadowLayerUtilsGralloc.cpp \
GrallocImages.cpp \
$(NULL)
endif
include $(topsrcdir)/config/rules.mk

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

@ -11,6 +11,7 @@
#include "mozilla/layers/SharedImageUtils.h"
#include "ImageContainer.h"
#include "GonkIOSurfaceImage.h"
#include "GrallocImages.h"
namespace mozilla {
namespace layers {
@ -206,6 +207,10 @@ SharedImage* ImageContainerChild::CreateSharedImageFromData(Image* image)
GonkIOSurfaceImage* gonkImage = static_cast<GonkIOSurfaceImage*>(image);
SharedImage* result = new SharedImage(gonkImage->GetSurfaceDescriptor());
return result;
} else if (image->GetFormat() == GRALLOC_PLANAR_YCBCR) {
GrallocPlanarYCbCrImage* GrallocImage = static_cast<GrallocPlanarYCbCrImage*>(image);
SharedImage* result = new SharedImage(GrallocImage->GetSurfaceDescriptor());
return result;
#endif
} else {
NS_RUNTIMEABORT("TODO: Only YUVImage is supported here right now.");