gfx/layers/GrallocImages.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "GrallocImages.h"
     8 #include <stddef.h>                     // for size_t
     9 #include <stdint.h>                     // for int8_t, uint8_t, uint32_t, etc
    10 #include "nsDebug.h"                    // for NS_WARNING, NS_PRECONDITION
    11 #include "mozilla/layers/ImageBridgeChild.h"
    12 #include "mozilla/layers/GrallocTextureClient.h"
    13 #include "gfx2DGlue.h"
    14 #include "YCbCrUtils.h"                 // for YCbCr conversions
    16 #include <ColorConverter.h>
    17 #include <OMX_IVCommon.h>
    20 using namespace mozilla::ipc;
    21 using namespace android;
    23 #define ALIGN(x, align) ((x + align - 1) & ~(align - 1))
    25 namespace mozilla {
    26 namespace layers {
    28 uint32_t GrallocImage::sColorIdMap[] = {
    29     HAL_PIXEL_FORMAT_YCbCr_420_P, OMX_COLOR_FormatYUV420Planar,
    30     HAL_PIXEL_FORMAT_YCbCr_422_P, OMX_COLOR_FormatYUV422Planar,
    31     HAL_PIXEL_FORMAT_YCbCr_420_SP, OMX_COLOR_FormatYUV420SemiPlanar,
    32     HAL_PIXEL_FORMAT_YCrCb_420_SP, -1,
    33     HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO, -1,
    34     HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED, HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED,
    35     HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS, HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS,
    36     HAL_PIXEL_FORMAT_YV12, OMX_COLOR_FormatYUV420Planar,
    37     0, 0
    38 };
    40 struct GraphicBufferAutoUnlock {
    41   android::sp<GraphicBuffer> mGraphicBuffer;
    43   GraphicBufferAutoUnlock(android::sp<GraphicBuffer>& aGraphicBuffer)
    44     : mGraphicBuffer(aGraphicBuffer) { }
    46   ~GraphicBufferAutoUnlock() { mGraphicBuffer->unlock(); }
    47 };
    49 GrallocImage::GrallocImage()
    50   : PlanarYCbCrImage(nullptr)
    51 {
    52   mFormat = ImageFormat::GRALLOC_PLANAR_YCBCR;
    53 }
    55 GrallocImage::~GrallocImage()
    56 {
    57 }
    59 void
    60 GrallocImage::SetData(const Data& aData)
    61 {
    62   MOZ_ASSERT(!mTextureClient, "TextureClient is already set");
    63   NS_PRECONDITION(aData.mYSize.width % 2 == 0, "Image should have even width");
    64   NS_PRECONDITION(aData.mYSize.height % 2 == 0, "Image should have even height");
    65   NS_PRECONDITION(aData.mYStride % 16 == 0, "Image should have stride of multiple of 16 pixels");
    67   mData = aData;
    68   mSize = aData.mPicSize;
    70   if (gfxPlatform::GetPlatform()->IsInGonkEmulator()) {
    71     // Emulator does not support HAL_PIXEL_FORMAT_YV12.
    72     return;
    73   }
    75   RefPtr<GrallocTextureClientOGL> textureClient =
    76        new GrallocTextureClientOGL(ImageBridgeChild::GetSingleton(),
    77                                    gfx::SurfaceFormat::UNKNOWN,
    78                                    gfx::BackendType::NONE);
    79   bool result =
    80     textureClient->AllocateGralloc(mData.mYSize,
    81                                    HAL_PIXEL_FORMAT_YV12,
    82                                    GraphicBuffer::USAGE_SW_READ_OFTEN |
    83                                    GraphicBuffer::USAGE_SW_WRITE_OFTEN |
    84                                    GraphicBuffer::USAGE_HW_TEXTURE);
    85   sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer();
    86   if (!result || !graphicBuffer.get()) {
    87     mTextureClient = nullptr;
    88     return;
    89   }
    91   mTextureClient = textureClient;
    93   void* vaddr;
    94   if (graphicBuffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
    95                           &vaddr) != OK) {
    96     return;
    97   }
    99   uint8_t* yChannel = static_cast<uint8_t*>(vaddr);
   100   gfx::IntSize ySize = aData.mYSize;
   101   int32_t yStride = graphicBuffer->getStride();
   103   uint8_t* vChannel = yChannel + (yStride * ySize.height);
   104   gfx::IntSize uvSize = gfx::IntSize(ySize.width / 2,
   105                                  ySize.height / 2);
   106   // Align to 16 bytes boundary
   107   int32_t uvStride = ((yStride / 2) + 15) & ~0x0F;
   108   uint8_t* uChannel = vChannel + (uvStride * uvSize.height);
   110   // Memory outside of the image width may not writable. If the stride
   111   // equals to the image width then we can use only one copy.
   112   if (yStride == mData.mYStride &&
   113       yStride == ySize.width) {
   114     memcpy(yChannel, mData.mYChannel, yStride * ySize.height);
   115   } else {
   116     for (int i = 0; i < ySize.height; i++) {
   117       memcpy(yChannel + i * yStride,
   118              mData.mYChannel + i * mData.mYStride,
   119              ySize.width);
   120     }
   121   }
   122   if (uvStride == mData.mCbCrStride &&
   123       uvStride == uvSize.width) {
   124     memcpy(uChannel, mData.mCbChannel, uvStride * uvSize.height);
   125     memcpy(vChannel, mData.mCrChannel, uvStride * uvSize.height);
   126   } else {
   127     for (int i = 0; i < uvSize.height; i++) {
   128       memcpy(uChannel + i * uvStride,
   129              mData.mCbChannel + i * mData.mCbCrStride,
   130              uvSize.width);
   131       memcpy(vChannel + i * uvStride,
   132              mData.mCrChannel + i * mData.mCbCrStride,
   133              uvSize.width);
   134     }
   135   }
   136   graphicBuffer->unlock();
   137 }
   139 void GrallocImage::SetData(const GrallocData& aData)
   140 {
   141   mTextureClient = static_cast<GrallocTextureClientOGL*>(aData.mGraphicBuffer.get());
   142   mSize = aData.mPicSize;
   143 }
   145 /**
   146  * Converts YVU420 semi planar frames to RGB565, possibly taking different
   147  * stride values.
   148  * Needed because the Android ColorConverter class assumes that the Y and UV
   149  * channels have equal stride.
   150  */
   151 static void
   152 ConvertYVU420SPToRGB565(void *aYData, uint32_t aYStride,
   153                         void *aUVData, uint32_t aUVStride,
   154                         void *aOut,
   155                         uint32_t aWidth, uint32_t aHeight)
   156 {
   157   uint8_t *y = (uint8_t*)aYData;
   158   int8_t *uv = (int8_t*)aUVData;
   160   uint16_t *rgb = (uint16_t*)aOut;
   162   for (size_t i = 0; i < aHeight; i++) {
   163     for (size_t j = 0; j < aWidth; j++) {
   164       int8_t d = uv[j | 1] - 128;
   165       int8_t e = uv[j & ~1] - 128;
   167       // Constants taken from https://en.wikipedia.org/wiki/YUV
   168       int32_t r = (298 * y[j] + 409 * e + 128) >> 11;
   169       int32_t g = (298 * y[j] - 100 * d - 208 * e + 128) >> 10;
   170       int32_t b = (298 * y[j] + 516 * d + 128) >> 11;
   172       r = r > 0x1f ? 0x1f : r < 0 ? 0 : r;
   173       g = g > 0x3f ? 0x3f : g < 0 ? 0 : g;
   174       b = b > 0x1f ? 0x1f : b < 0 ? 0 : b;
   176       *rgb++ = (uint16_t)(r << 11 | g << 5 | b);
   177     }
   179     y += aYStride;
   180     if (i % 2) {
   181       uv += aUVStride;
   182     }
   183   }
   184 }
   186 TemporaryRef<gfx::SourceSurface>
   187 GrallocImage::GetAsSourceSurface()
   188 {
   189   if (!mTextureClient) {
   190     return nullptr;
   191   }
   192   android::sp<GraphicBuffer> graphicBuffer =
   193     mTextureClient->GetGraphicBuffer();
   195   void *buffer;
   196   int32_t rv =
   197     graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_OFTEN, &buffer);
   199   if (rv) {
   200     NS_WARNING("Couldn't lock graphic buffer");
   201     return nullptr;
   202   }
   204   GraphicBufferAutoUnlock unlock(graphicBuffer);
   206   uint32_t format = graphicBuffer->getPixelFormat();
   207   uint32_t omxFormat = 0;
   209   for (int i = 0; sColorIdMap[i]; i += 2) {
   210     if (sColorIdMap[i] == format) {
   211       omxFormat = sColorIdMap[i + 1];
   212       break;
   213     }
   214   }
   216   if (!omxFormat) {
   217     NS_WARNING("Unknown color format");
   218     return nullptr;
   219   }
   221   RefPtr<gfx::DataSourceSurface> surface
   222     = gfx::Factory::CreateDataSourceSurface(GetSize(), gfx::SurfaceFormat::R5G6B5);
   224   uint32_t width = GetSize().width;
   225   uint32_t height = GetSize().height;
   227   gfx::DataSourceSurface::MappedSurface mappedSurface;
   228   if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
   229     NS_WARNING("Could not map DataSourceSurface");
   230     return nullptr;
   231   }
   233   if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO) {
   234     // The Adreno hardware decoder aligns image dimensions to a multiple of 32,
   235     // so we have to account for that here
   236     uint32_t alignedWidth = ALIGN(width, 32);
   237     uint32_t alignedHeight = ALIGN(height, 32);
   238     uint32_t uvOffset = ALIGN(alignedHeight * alignedWidth, 4096);
   239     uint32_t uvStride = 2 * ALIGN(width / 2, 32);
   240     uint8_t* buffer_as_bytes = static_cast<uint8_t*>(buffer);
   241     ConvertYVU420SPToRGB565(buffer, alignedWidth,
   242                             buffer_as_bytes + uvOffset, uvStride,
   243                             mappedSurface.mData,
   244                             width, height);
   246     surface->Unmap();
   247     return surface;
   248   }
   250   if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
   251     uint32_t uvOffset = height * width;
   252     ConvertYVU420SPToRGB565(buffer, width,
   253                             buffer + uvOffset, width,
   254                             mappedSurface.mData,
   255                             width, height);
   257     surface->Unmap();
   258     return surface;
   259   }
   261   if (format == HAL_PIXEL_FORMAT_YV12) {
   262     gfx::ConvertYCbCrToRGB(mData,
   263                            surface->GetFormat(),
   264                            mSize,
   265                            surface->GetData(),
   266                            surface->Stride());
   267     surface->Unmap();
   268     return surface;
   269   }
   271   android::ColorConverter colorConverter((OMX_COLOR_FORMATTYPE)omxFormat,
   272                                          OMX_COLOR_Format16bitRGB565);
   274   if (!colorConverter.isValid()) {
   275     NS_WARNING("Invalid color conversion");
   276     surface->Unmap();
   277     return nullptr;
   278   }
   280   rv = colorConverter.convert(buffer, width, height,
   281                               0, 0, width - 1, height - 1 /* source crop */,
   282                               mappedSurface.mData, width, height,
   283                               0, 0, width - 1, height - 1 /* dest crop */);
   285   surface->Unmap();
   287   if (rv) {
   288     NS_WARNING("OMX color conversion failed");
   289     return nullptr;
   290   }
   292   return surface;
   293 }
   295 android::sp<android::GraphicBuffer>
   296 GrallocImage::GetGraphicBuffer() const
   297 {
   298   if (!mTextureClient) {
   299     return nullptr;
   300   }
   301   return mTextureClient->GetGraphicBuffer();
   302 }
   304 void*
   305 GrallocImage::GetNativeBuffer()
   306 {
   307   if (!mTextureClient) {
   308     return nullptr;
   309   }
   310   android::sp<android::GraphicBuffer> graphicBuffer =
   311     mTextureClient->GetGraphicBuffer();
   312   if (!graphicBuffer.get()) {
   313     return nullptr;
   314   }
   315   return graphicBuffer->getNativeBuffer();
   316 }
   318 TextureClient*
   319 GrallocImage::GetTextureClient(CompositableClient* aClient)
   320 {
   321   return mTextureClient;
   322 }
   324 } // namespace layers
   325 } // namespace mozilla

mercurial