Bug 983039 - [Media encoder] Support YV12 GrallocImage in OMXVideoEncoder on B2G. r=roc

This commit is contained in:
John Lin 2014-03-14 09:43:13 -04:00
parent 7fa7c646c0
commit 10519ff8ea

View File

@ -230,6 +230,72 @@ ConvertPlanarYCbCrToNV12(const PlanarYCbCrData* aSource, uint8_t* aDestination)
}
}
// Convert pixels in graphic buffer to NV12 format. aSource is the layer image
// containing source graphic buffer, and aDestination is the destination of
// conversion. Currently only 2 source format are supported:
// - NV21/HAL_PIXEL_FORMAT_YCrCb_420_SP (from camera preview window).
// - YV12/HAL_PIXEL_FORMAT_YV12 (from video decoder).
static
void
ConvertGrallocImageToNV12(GrallocImage* aSource, uint8_t* aDestination)
{
// Get graphic buffer.
SurfaceDescriptor handle = aSource->GetSurfaceDescriptor();
SurfaceDescriptorGralloc gralloc = handle.get_SurfaceDescriptorGralloc();
sp<GraphicBuffer> graphicBuffer = GrallocBufferActor::GetFrom(gralloc);
int pixelFormat = graphicBuffer->getPixelFormat();
// Only support NV21 (from camera) or YV12 (from HW decoder output) for now.
NS_ENSURE_TRUE_VOID(pixelFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP ||
pixelFormat == HAL_PIXEL_FORMAT_YV12);
void* imgPtr = nullptr;
graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &imgPtr);
// Build PlanarYCbCrData for NV21 or YV12 buffer.
PlanarYCbCrData yuv;
switch (pixelFormat) {
case HAL_PIXEL_FORMAT_YCrCb_420_SP: // From camera.
yuv.mYChannel = static_cast<uint8_t*>(imgPtr);
yuv.mYSkip = 0;
yuv.mYSize.width = graphicBuffer->getWidth();
yuv.mYSize.height = graphicBuffer->getHeight();
yuv.mYStride = graphicBuffer->getStride();
// 4:2:0.
yuv.mCbCrSize.width = yuv.mYSize.width / 2;
yuv.mCbCrSize.height = yuv.mYSize.height / 2;
// Interleaved VU plane.
yuv.mCrChannel = yuv.mYChannel + (yuv.mYStride * yuv.mYSize.height);
yuv.mCrSkip = 1;
yuv.mCbChannel = yuv.mCrChannel + 1;
yuv.mCbSkip = 1;
yuv.mCbCrStride = yuv.mYStride;
ConvertPlanarYCbCrToNV12(&yuv, aDestination);
break;
case HAL_PIXEL_FORMAT_YV12: // From video decoder.
// Android YV12 format is defined in system/core/include/system/graphics.h
yuv.mYChannel = static_cast<uint8_t*>(imgPtr);
yuv.mYSkip = 0;
yuv.mYSize.width = graphicBuffer->getWidth();
yuv.mYSize.height = graphicBuffer->getHeight();
yuv.mYStride = graphicBuffer->getStride();
// 4:2:0.
yuv.mCbCrSize.width = yuv.mYSize.width / 2;
yuv.mCbCrSize.height = yuv.mYSize.height / 2;
yuv.mCrChannel = yuv.mYChannel + (yuv.mYStride * yuv.mYSize.height);
// Aligned to 16 bytes boundary.
yuv.mCbCrStride = (yuv.mYStride / 2 + 15) & ~0x0F;
yuv.mCrSkip = 0;
yuv.mCbChannel = yuv.mCrChannel + (yuv.mCbCrStride * yuv.mCbCrSize.height);
yuv.mCbSkip = 0;
ConvertPlanarYCbCrToNV12(&yuv, aDestination);
break;
default:
NS_ERROR("Unsupported input gralloc image type. Should never be here.");
}
graphicBuffer->unlock();
}
nsresult
OMXVideoEncoder::Encode(const Image* aImage, int aWidth, int aHeight,
int64_t aTimestamp, int aInputFlags)
@ -252,7 +318,6 @@ OMXVideoEncoder::Encode(const Image* aImage, int aWidth, int aHeight,
size_t yLen = aWidth * aHeight;
size_t uvLen = yLen / 2;
// Buffer should be large enough to hold input image data.
MOZ_ASSERT(dstSize >= yLen + uvLen);
@ -273,40 +338,7 @@ OMXVideoEncoder::Encode(const Image* aImage, int aWidth, int aHeight,
aHeight == img->GetSize().height);
if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) {
// Get graphic buffer pointer.
void* imgPtr = nullptr;
GrallocImage* nativeImage = static_cast<GrallocImage*>(img);
SurfaceDescriptor handle = nativeImage->GetSurfaceDescriptor();
SurfaceDescriptorGralloc gralloc = handle.get_SurfaceDescriptorGralloc();
sp<GraphicBuffer> graphicBuffer = GrallocBufferActor::GetFrom(gralloc);
graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &imgPtr);
uint8_t* src = static_cast<uint8_t*>(imgPtr);
// Only support NV21 for now.
MOZ_ASSERT(graphicBuffer->getPixelFormat() ==
HAL_PIXEL_FORMAT_YCrCb_420_SP);
// Build PlanarYCbCrData for NV21 buffer.
PlanarYCbCrData nv21;
// Y plane.
nv21.mYChannel = src;
nv21.mYSize.width = aWidth;
nv21.mYSize.height = aHeight;
nv21.mYStride = aWidth;
nv21.mYSkip = 0;
// Interleaved VU plane.
nv21.mCrChannel = src + yLen;
nv21.mCrSkip = 1;
nv21.mCbChannel = nv21.mCrChannel + 1;
nv21.mCbSkip = 1;
nv21.mCbCrStride = aWidth;
// 4:2:0.
nv21.mCbCrSize.width = aWidth / 2;
nv21.mCbCrSize.height = aHeight / 2;
ConvertPlanarYCbCrToNV12(&nv21, dst);
graphicBuffer->unlock();
ConvertGrallocImageToNV12(static_cast<GrallocImage*>(img), dst);
} else if (format == ImageFormat::PLANAR_YCBCR) {
ConvertPlanarYCbCrToNV12(static_cast<PlanarYCbCrImage*>(img)->GetData(),
dst);