Bug 1141979 - part4 - Add NVImage; r=jrmuizel

MozReview-Commit-ID: 9kacGnqHVRH

--HG--
extra : transplant_source : %D2%95%C2%5E%F40%0D%86.%CD%F7%236%E8%D3%D8%7Frv%99
This commit is contained in:
Kaku Kuo 2016-03-10 10:35:27 +08:00
Родитель 089b22220f
Коммит 802fc0f1d8
4 изменённых файлов: 210 добавлений и 0 удалений

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

@ -10,6 +10,7 @@
#include "gfx2DGlue.h"
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxUtils.h" // for gfxUtils
#include "libyuv.h"
#include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/ipc/CrossProcessMutex.h" // for CrossProcessMutex, etc
#include "mozilla/layers/CompositorTypes.h"
@ -598,6 +599,163 @@ PlanarYCbCrImage::GetAsSourceSurface()
return surface.forget();
}
NVImage::NVImage()
: Image(nullptr, ImageFormat::NV_IMAGE)
, mBufferSize(0)
{
}
NVImage::~NVImage()
{
}
IntSize
NVImage::GetSize()
{
return mSize;
}
IntRect
NVImage::GetPictureRect()
{
return mData.GetPictureRect();
}
already_AddRefed<SourceSurface>
NVImage::GetAsSourceSurface()
{
if (mSourceSurface) {
RefPtr<gfx::SourceSurface> surface(mSourceSurface);
return surface.forget();
}
// Convert the current NV12 or NV21 data to YUV420P so that we can follow the
// logics in PlanarYCbCrImage::GetAsSourceSurface().
const int bufferLength = mData.mYSize.height * mData.mYStride +
mData.mCbCrSize.height * mData.mCbCrSize.width * 2;
uint8_t* buffer = new uint8_t[bufferLength];
Data aData = mData;
aData.mCbCrStride = aData.mCbCrSize.width;
aData.mCbSkip = 0;
aData.mCrSkip = 0;
aData.mYChannel = buffer;
aData.mCbChannel = aData.mYChannel + aData.mYSize.height * aData.mYStride;
aData.mCrChannel = aData.mCbChannel + aData.mCbCrSize.height * aData.mCbCrStride;
if (mData.mCbChannel < mData.mCrChannel) { // NV12
libyuv::NV12ToI420(mData.mYChannel, mData.mYStride,
mData.mCbChannel, mData.mCbCrStride,
aData.mYChannel, aData.mYStride,
aData.mCbChannel, aData.mCbCrStride,
aData.mCrChannel, aData.mCbCrStride,
aData.mYSize.width, aData.mYSize.height);
} else { // NV21
libyuv::NV21ToI420(mData.mYChannel, mData.mYStride,
mData.mCrChannel, mData.mCbCrStride,
aData.mYChannel, aData.mYStride,
aData.mCbChannel, aData.mCbCrStride,
aData.mCrChannel, aData.mCbCrStride,
aData.mYSize.width, aData.mYSize.height);
}
// The logics in PlanarYCbCrImage::GetAsSourceSurface().
gfx::IntSize size(mSize);
gfx::SurfaceFormat format =
gfx::ImageFormatToSurfaceFormat(gfxPlatform::GetPlatform()->GetOffscreenFormat());
gfx::GetYCbCrToRGBDestFormatAndSize(aData, format, size);
if (mSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
mSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
NS_ERROR("Illegal image dest width or height");
return nullptr;
}
RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(size, format);
if (NS_WARN_IF(!surface)) {
return nullptr;
}
DataSourceSurface::ScopedMap mapping(surface, DataSourceSurface::WRITE);
if (NS_WARN_IF(!mapping.IsMapped())) {
return nullptr;
}
gfx::ConvertYCbCrToRGB(aData, format, size, mapping.GetData(), mapping.GetStride());
mSourceSurface = surface;
// Release the temporary buffer.
delete[] buffer;
return surface.forget();
}
bool
NVImage::IsValid()
{
return !!mBufferSize;
}
uint32_t
NVImage::GetBufferSize() const
{
return mBufferSize;
}
NVImage*
NVImage::AsNVImage()
{
return this;
};
bool
NVImage::SetData(const Data& aData)
{
MOZ_ASSERT(aData.mCbSkip == 1 && aData.mCrSkip == 1);
MOZ_ASSERT((int)std::abs(aData.mCbChannel - aData.mCrChannel) == 1);
// Calculate buffer size
const uint32_t size = aData.mYSize.height * aData.mYStride +
aData.mCbCrSize.height * aData.mCbCrStride;
// Allocate a new buffer.
mBuffer = AllocateBuffer(size);
if (!mBuffer) {
return false;
}
// Update mBufferSize.
mBufferSize = size;
// Update mData.
mData = aData;
mData.mYChannel = mBuffer.get();
mData.mCbChannel = mData.mYChannel + (aData.mCbChannel - aData.mYChannel);
mData.mCrChannel = mData.mYChannel + (aData.mCrChannel - aData.mYChannel);
// Update mSize.
mSize = aData.mPicSize;
// Copy the input data into mBuffer.
// This copies the y-channel and the interleaving CbCr-channel.
memcpy(mData.mYChannel, aData.mYChannel, mBufferSize);
return true;
}
const NVImage::Data*
NVImage::GetData() const
{
return &mData;
}
UniquePtr<uint8_t>
NVImage::AllocateBuffer(uint32_t aSize)
{
UniquePtr<uint8_t> buffer(new uint8_t[aSize]);
return buffer;
}
SourceSurfaceImage::SourceSurfaceImage(const gfx::IntSize& aSize, gfx::SourceSurface* aSourceSurface)
: Image(nullptr, ImageFormat::CAIRO_SURFACE),
mSize(aSize),

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

@ -152,6 +152,7 @@ class PlanarYCbCrImage;
class TextureClient;
class CompositableClient;
class GrallocImage;
class NVImage;
struct ImageBackendData
{
@ -237,6 +238,8 @@ public:
#endif
virtual PlanarYCbCrImage* AsPlanarYCbCrImage() { return nullptr; }
virtual NVImage* AsNVImage() { return nullptr; }
protected:
Image(void* aImplData, ImageFormat aFormat) :
mImplData(aImplData),
@ -814,6 +817,48 @@ protected:
mozilla::UniquePtr<uint8_t[]> mBuffer;
};
/**
* NVImage is used to store YUV420SP_NV12 and YUV420SP_NV21 data natively, which
* are not supported by PlanarYCbCrImage. (PlanarYCbCrImage only stores YUV444P,
* YUV422P and YUV420P, it converts YUV420SP_NV12 and YUV420SP_NV21 data into
* YUV420P in its PlanarYCbCrImage::SetData() method.)
*
* PlanarYCbCrData is able to express all the YUV family and so we keep use it
* in NVImage.
*/
class NVImage: public Image {
typedef PlanarYCbCrData Data;
public:
explicit NVImage();
virtual ~NVImage() override;
// Methods inherited from layers::Image.
virtual gfx::IntSize GetSize() override;
virtual gfx::IntRect GetPictureRect() override;
virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
virtual bool IsValid() override;
virtual NVImage* AsNVImage() override;
// Methods mimic layers::PlanarYCbCrImage.
virtual bool SetData(const Data& aData);
virtual const Data* GetData() const;
virtual uint32_t GetBufferSize() const;
protected:
/**
* Return a buffer to store image data in.
*/
mozilla::UniquePtr<uint8_t> AllocateBuffer(uint32_t aSize);
mozilla::UniquePtr<uint8_t> mBuffer;
uint32_t mBufferSize;
gfx::IntSize mSize;
Data mData;
nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
};
/**
* Currently, the data in a SourceSurfaceImage surface is treated as being in the
* device output color space. This class is very simple as all backends

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

@ -16,6 +16,12 @@ enum class ImageFormat {
*/
PLANAR_YCBCR,
/**
* The NV_IMAGE format creates a NVImage. The PLANAR_YCBCR together with this
* complete the YUV format family.
*/
NV_IMAGE,
/**
* The GRALLOC_PLANAR_YCBCR format creates a GrallocImage, a subtype of
* PlanarYCbCrImage. It takes a PlanarYCbCrImage data or the raw gralloc

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

@ -428,6 +428,7 @@ LOCAL_INCLUDES += [
'/docshell/base', # for nsDocShell.h
'/layout/base', # for TouchManager.h
'/layout/generic', # for nsTextFrame.h
'/media/libyuv/include', # for libyuv.h
]
FINAL_LIBRARY = 'xul'