/*static*/ already_AddRefed<gfxASurface>
ShadowLayerForwarder::PlatformOpenDescriptor(OpenMode aMode,
                                             const SurfaceDescriptor& aSurface)
{
  PROFILER_LABEL("ShadowLayerForwarder", "PlatformOpenDescriptor");
  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aSurface.type()) {
    return nullptr;
  }

  sp<GraphicBuffer> buffer =
    GrallocBufferActor::GetFrom(aSurface.get_SurfaceDescriptorGralloc());
  uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN;
  if (OPEN_READ_WRITE == aMode) {
    usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
  }
  void *vaddr;
  DebugOnly<status_t> status = buffer->lock(usage, &vaddr);
  // If we fail to lock, we'll just end up aborting anyway.
  MOZ_ASSERT(status == OK);

  gfxIntSize size = aSurface.get_SurfaceDescriptorGralloc().size();
  gfxImageFormat format = ImageFormatForPixelFormat(buffer->getPixelFormat());
  long pixelStride = buffer->getStride();
  long byteStride = pixelStride * gfxASurface::BytePerPixelFromFormat(format);

  nsRefPtr<gfxASurface> surf =
    new gfxImageSurface((unsigned char*)vaddr, size, byteStride, format);
  return surf->CairoStatus() ? nullptr : surf.forget();
}
/*static*/ bool
ShadowLayerForwarder::PlatformGetDescriptorSurfaceSize(
  const SurfaceDescriptor& aDescriptor, OpenMode aMode,
  gfxIntSize* aSize,
  gfxASurface** aSurface)
{
  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aDescriptor.type()) {
    return false;
  }

  sp<GraphicBuffer> buffer =
    GrallocBufferActor::GetFrom(aDescriptor.get_SurfaceDescriptorGralloc());
  *aSize = aDescriptor.get_SurfaceDescriptorGralloc().size();
  return true;
}
void
GrallocDeprecatedTextureHostOGL::SwapTexturesImpl(const SurfaceDescriptor& aImage,
                                        nsIntRegion*)
{
  MOZ_ASSERT(aImage.type() == SurfaceDescriptor::TSurfaceDescriptorGralloc);

  if (mBuffer) {
    // only done for hacky fix in gecko 23 for bug 862324.
    RegisterDeprecatedTextureHostAtGrallocBufferActor(nullptr, *mBuffer);
  }

  const SurfaceDescriptorGralloc& desc = aImage.get_SurfaceDescriptorGralloc();
  mGraphicBuffer = GrallocBufferActor::GetFrom(desc);
  mIsRBSwapped = desc.isRBSwapped();
  mFormat = SurfaceFormatForAndroidPixelFormat(mGraphicBuffer->getPixelFormat(),
                                               mIsRBSwapped);

  mTextureTarget = TextureTargetForAndroidPixelFormat(mGraphicBuffer->getPixelFormat());

  DeleteTextures();

  // only done for hacky fix in gecko 23 for bug 862324.
  // Doing this in SetBuffer is not enough, as DeprecatedImageHostBuffered::SwapTextures can
  // change the value of *mBuffer without calling SetBuffer again.
  RegisterDeprecatedTextureHostAtGrallocBufferActor(this, aImage);
}
Example #4
0
// 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();
}
// only used for hacky fix in gecko 23 for bug 862324
static void
RegisterDeprecatedTextureHostAtGrallocBufferActor(DeprecatedTextureHost* aDeprecatedTextureHost, const SurfaceDescriptor& aSurfaceDescriptor)
{
  if (IsSurfaceDescriptorValid(aSurfaceDescriptor)) {
    GrallocBufferActor* actor = static_cast<GrallocBufferActor*>(aSurfaceDescriptor.get_SurfaceDescriptorGralloc().bufferParent());
    actor->SetDeprecatedTextureHost(aDeprecatedTextureHost);
  }
}
android::sp<android::GraphicBuffer>
GetGraphicBufferFromDesc(SurfaceDescriptor aDesc)
{
  MaybeMagicGrallocBufferHandle handle;
  if (aDesc.type() == SurfaceDescriptor::TSurfaceDescriptorGralloc) {
    handle = aDesc.get_SurfaceDescriptorGralloc().buffer();
  }
  return GetGraphicBufferFrom(handle);
}
bool
ImageBridgeChild::DeallocSurfaceDescriptorGrallocNow(const SurfaceDescriptor& aBuffer)
{
#ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
  PGrallocBufferChild* gbp =
    aBuffer.get_SurfaceDescriptorGralloc().bufferChild();
  PGrallocBufferChild::Send__delete__(gbp);

  return true;
#else
  NS_RUNTIMEABORT("Um, how did we get here?");
  return false;
#endif
}
/*static*/ bool
ShadowLayerForwarder::PlatformGetDescriptorSurfaceContentType(
  const SurfaceDescriptor& aDescriptor, OpenMode aMode,
  gfxContentType* aContent,
  gfxASurface** aSurface)
{
  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aDescriptor.type()) {
    return false;
  }

  sp<GraphicBuffer> buffer =
    GrallocBufferActor::GetFrom(aDescriptor.get_SurfaceDescriptorGralloc());
  *aContent = ContentTypeFromPixelFormat(buffer->getPixelFormat());
  return true;
}
Example #9
0
status_t GonkNativeWindow::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
        uint32_t format, uint32_t usage)
{
    if ((w && !h) || (!w && h)) {
        CNW_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
        return BAD_VALUE;
    }

    status_t returnFlags(OK);
    bool updateFormat = false;
    uint32_t generation;
    bool alloc = false;
    int buf = INVALID_BUFFER_SLOT;
    SurfaceDescriptor descOld;

    {
        Mutex::Autolock lock(mMutex);
        generation = mGeneration;

        int found = -1;
        int dequeuedCount = 0;
        int renderingCount = 0;
        bool tryAgain = true;

        CNW_LOGD("dequeueBuffer: E");
        while (tryAgain) {
            if (mAbandoned) {
                CNW_LOGE("dequeueBuffer: GonkNativeWindow has been abandoned!");
                return NO_INIT;
            }
            // look for a free buffer to give to the client
            found = INVALID_BUFFER_SLOT;
            dequeuedCount = 0;
            renderingCount = 0;
            for (int i = 0; i < mBufferCount; i++) {
                const int state = mSlots[i].mBufferState;
                if (state == BufferSlot::DEQUEUED) {
                    dequeuedCount++;
                }
                else if (state == BufferSlot::RENDERING) {
                    renderingCount++;
                }
                else if (state == BufferSlot::FREE) {
                    /* We return the oldest of the free buffers to avoid
                     * stalling the producer if possible.  This is because
                     * the consumer may still have pending reads of the
                     * buffers in flight.
                     */
                    if (found < 0 ||
                        mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
                        found = i;
                    }
                }
            }

            // See whether a buffer has been in RENDERING state since the last
            // setBufferCount so we know whether to perform the
            // MIN_UNDEQUEUED_BUFFERS check below.
            if (renderingCount > 0) {
                // make sure the client is not trying to dequeue more buffers
                // than allowed.
                const int avail = mBufferCount - (dequeuedCount + 1);
                if (avail < MIN_UNDEQUEUED_BUFFERS) {
                    CNW_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
                            "(dequeued=%d)",
                            MIN_UNDEQUEUED_BUFFERS,
                            dequeuedCount);
                    return -EBUSY;
                }
            }

            // we're in synchronous mode and didn't find a buffer, we need to
            // wait for some buffers to be consumed
            tryAgain = (found == INVALID_BUFFER_SLOT);
            if (tryAgain) {
                CNW_LOGD("dequeueBuffer: Try again");
                mDequeueCondition.wait(mMutex);
                CNW_LOGD("dequeueBuffer: Now");
            }
        }

        if (found == INVALID_BUFFER_SLOT) {
            // This should not happen.
            CNW_LOGE("dequeueBuffer: no available buffer slots");
            return -EBUSY;
        }

        buf = found;
        *outBuf = found;

        const bool useDefaultSize = !w && !h;
        if (useDefaultSize) {
            // use the default size
            w = mDefaultWidth;
            h = mDefaultHeight;
        }

        updateFormat = (format != 0);
        if (!updateFormat) {
            // keep the current (or default) format
            format = mPixelFormat;
        }

        mSlots[buf].mBufferState = BufferSlot::DEQUEUED;

        const sp<GraphicBuffer>& gbuf(mSlots[buf].mGraphicBuffer);
        alloc = (gbuf == NULL);
        if ((gbuf!=NULL) &&
           ((uint32_t(gbuf->width)  != w) ||
            (uint32_t(gbuf->height) != h) ||
            (uint32_t(gbuf->format) != format) ||
            ((uint32_t(gbuf->usage) & usage) != usage))) {
            alloc = true;
            descOld = mSlots[buf].mSurfaceDescriptor;
        }
    }
    
    // At this point, the buffer is now marked DEQUEUED, and no one else
    // should touch it, except for freeAllBuffersLocked(); we handle that
    // after trying to create the surface descriptor below.
    //
    // So we don't need mMutex locked, which would otherwise run the risk
    // of a deadlock on calling AllocSurfaceDescriptorGralloc().    

    SurfaceDescriptor desc;
    ImageBridgeChild* ibc;
    sp<GraphicBuffer> graphicBuffer;
    if (alloc) {
        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
        status_t error;
        ibc = ImageBridgeChild::GetSingleton();
        CNW_LOGD("dequeueBuffer: about to alloc surface descriptor");
        ibc->AllocSurfaceDescriptorGralloc(IntSize(w, h),
                                           format,
                                           usage,
                                           &desc);
        // We can only use a gralloc buffer here.  If we didn't get
        // one back, something went wrong.
        CNW_LOGD("dequeueBuffer: got surface descriptor");
        if (SurfaceDescriptor::TSurfaceDescriptorGralloc != desc.type()) {
            MOZ_ASSERT(SurfaceDescriptor::T__None == desc.type());
            CNW_LOGE("dequeueBuffer: failed to alloc gralloc buffer");
            return -ENOMEM;
        }
        graphicBuffer = GrallocBufferActor::GetFrom(desc.get_SurfaceDescriptorGralloc());
        error = graphicBuffer->initCheck();
        if (error != NO_ERROR) {
            CNW_LOGE("dequeueBuffer: createGraphicBuffer failed with error %d", error);
            return error;
        }
    }

    bool tooOld = false;
    {
        Mutex::Autolock lock(mMutex);
        if (generation == mGeneration) {
            if (updateFormat) {
                mPixelFormat = format;
            }
            if (alloc) {
                mSlots[buf].mGraphicBuffer = graphicBuffer;
                mSlots[buf].mSurfaceDescriptor = desc;
                mSlots[buf].mSurfaceDescriptor.get_SurfaceDescriptorGralloc().external() = true;
                mSlots[buf].mRequestBufferCalled = false;

                returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
            }
            CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
                    mSlots[buf].mGraphicBuffer->handle);
        } else {
            tooOld = true;
        }
    }

    if (alloc && IsSurfaceDescriptorValid(descOld)) {
        ibc->DeallocSurfaceDescriptorGralloc(descOld);
    }

    if (alloc && tooOld) {
        ibc->DeallocSurfaceDescriptorGralloc(desc);
    }

    CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
            mSlots[buf].mGraphicBuffer->handle );

    CNW_LOGD("dequeueBuffer: X");
    return returnFlags;
}
Example #10
0
already_AddRefed<TextureHost>
CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
                     ISurfaceAllocator* aDeallocator,
                     TextureFlags aFlags)
{
  RefPtr<TextureHost> result;
  switch (aDesc.type()) {
    case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
      result = CreateBackendIndependentTextureHost(aDesc,
                                                   aDeallocator, aFlags);
      break;
    }

#ifdef MOZ_WIDGET_ANDROID
    case SurfaceDescriptor::TSurfaceTextureDescriptor: {
      const SurfaceTextureDescriptor& desc = aDesc.get_SurfaceTextureDescriptor();
      result = new SurfaceTextureHost(aFlags,
                                      (AndroidSurfaceTexture*)desc.surfTex(),
                                      desc.size());
      break;
    }
#endif

    case SurfaceDescriptor::TEGLImageDescriptor: {
      const EGLImageDescriptor& desc = aDesc.get_EGLImageDescriptor();
      result = new EGLImageTextureHost(aFlags,
                                       (EGLImage)desc.image(),
                                       (EGLSync)desc.fence(),
                                       desc.size(),
                                       desc.hasAlpha());
      break;
    }

#ifdef XP_MACOSX
    case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
      const SurfaceDescriptorMacIOSurface& desc =
        aDesc.get_SurfaceDescriptorMacIOSurface();
      result = new MacIOSurfaceTextureHostOGL(aFlags, desc);
      break;
    }
#endif

#ifdef MOZ_WIDGET_GONK
    case SurfaceDescriptor::TSurfaceDescriptorGralloc: {
      const SurfaceDescriptorGralloc& desc =
        aDesc.get_SurfaceDescriptorGralloc();
      result = new GrallocTextureHostOGL(aFlags, desc);
      break;
    }
#endif

#ifdef GL_PROVIDER_GLX
    case SurfaceDescriptor::TSurfaceDescriptorX11: {
      const auto& desc = aDesc.get_SurfaceDescriptorX11();
      result = new X11TextureHost(aFlags, desc);
      break;
    }
#endif

    case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture: {
      const auto& desc = aDesc.get_SurfaceDescriptorSharedGLTexture();
      result = new GLTextureHost(aFlags, desc.texture(),
                                 desc.target(),
                                 (GLsync)desc.fence(),
                                 desc.size(),
                                 desc.hasAlpha());
      break;
    }
    default: return nullptr;
  }
  return result.forget();
}
SharedSurface_Gralloc*
SharedSurface_Gralloc::Create(GLContext* prodGL,
                              const GLFormats& formats,
                              const gfxIntSize& size,
                              bool hasAlpha,
                              ISurfaceAllocator* allocator)
{
    static bool runOnce = true;
    if (runOnce) {
        sForceReadPixelsToFence = false;
        mozilla::Preferences::AddBoolVarCache(&sForceReadPixelsToFence,
                                              "gfx.gralloc.fence-with-readpixels");
        runOnce = false;
    }

    GLLibraryEGL* egl = prodGL->GetLibraryEGL();
    MOZ_ASSERT(egl);

    DEBUG_PRINT("SharedSurface_Gralloc::Create -------\n");

    if (!HasExtensions(egl, prodGL))
        return nullptr;

    SurfaceDescriptor baseDesc;
    SurfaceDescriptorGralloc desc;

    gfxContentType type = hasAlpha ? GFX_CONTENT_COLOR_ALPHA
                                                : GFX_CONTENT_COLOR;
    if (!allocator->AllocSurfaceDescriptorWithCaps(size, type, USING_GL_RENDERING_ONLY, &baseDesc))
        return false;

    if (baseDesc.type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) {
        allocator->DestroySharedSurface(&baseDesc);
        return false;
    }

    desc = baseDesc.get_SurfaceDescriptorGralloc();

    sp<GraphicBuffer> buffer = GrallocBufferActor::GetFrom(desc);

    EGLDisplay display = egl->Display();
    EGLClientBuffer clientBuffer = buffer->getNativeBuffer();
    EGLint attrs[] = {
        LOCAL_EGL_NONE, LOCAL_EGL_NONE
    };
    EGLImage image = egl->fCreateImage(display,
                                       EGL_NO_CONTEXT,
                                       LOCAL_EGL_NATIVE_BUFFER_ANDROID,
                                       clientBuffer, attrs);
    if (!image) {
        allocator->DestroySharedSurface(&baseDesc);
        return nullptr;
    }

    prodGL->MakeCurrent();
    GLuint prodTex = 0;
    prodGL->fGenTextures(1, &prodTex);
    ScopedBindTexture autoTex(prodGL, prodTex);

    prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
    prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
    prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
    prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);

    prodGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, image);

    egl->fDestroyImage(display, image);

    SharedSurface_Gralloc *surf = new SharedSurface_Gralloc(prodGL, size, hasAlpha, egl, allocator, desc, prodTex);

    DEBUG_PRINT("SharedSurface_Gralloc::Create: success -- surface %p, GraphicBuffer %p.\n", surf, buffer.get());

    return surf;
}
int GonkNativeWindow::dequeueBuffer(android_native_buffer_t** buffer)
{
    Mutex::Autolock lock(mMutex);

    int found = -1;
    int dequeuedCount = 0;
    bool tryAgain = true;

    CNW_LOGD("dequeueBuffer: E");
    while (tryAgain) {
        // look for a free buffer to give to the client
        found = INVALID_BUFFER_SLOT;
        dequeuedCount = 0;
        for (int i = 0; i < mBufferCount; i++) {
            const int state = mSlots[i].mBufferState;
            if (state == BufferSlot::DEQUEUED) {
                dequeuedCount++;
            }
            else if (state == BufferSlot::FREE) {
                /* We return the oldest of the free buffers to avoid
                 * stalling the producer if possible.  This is because
                 * the consumer may still have pending reads of the
                 * buffers in flight.
                 */
                bool isOlder = mSlots[i].mFrameNumber < mSlots[found].mFrameNumber;
                if (found < 0 || isOlder) {
                    found = i;
                }
            }
        }

        // we're in synchronous mode and didn't find a buffer, we need to
        // wait for some buffers to be consumed
        tryAgain = (found == INVALID_BUFFER_SLOT);
        if (tryAgain) {
            CNW_LOGD("dequeueBuffer: Try again");
            mDequeueCondition.wait(mMutex);
            CNW_LOGD("dequeueBuffer: Now");
        }
    }

    if (found == INVALID_BUFFER_SLOT) {
        // This should not happen.
        CNW_LOGE("dequeueBuffer: no available buffer slots");
        return -EBUSY;
    }

    const int buf = found;

    // buffer is now in DEQUEUED
    mSlots[buf].mBufferState = BufferSlot::DEQUEUED;

    const sp<GraphicBuffer>& gbuf(mSlots[buf].mGraphicBuffer);

    if (gbuf == NULL) {
        status_t error;
        SurfaceDescriptor buffer;
        ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
        ibc->AllocSurfaceDescriptorGralloc(gfxIntSize(mDefaultWidth, mDefaultHeight),
                                           mPixelFormat,
                                           mUsage,
                                           &buffer);
        sp<GraphicBuffer> graphicBuffer =
          GrallocBufferActor::GetFrom(buffer.get_SurfaceDescriptorGralloc());
        if (!graphicBuffer.get()) {
            return -ENOMEM;
        }
        error = graphicBuffer->initCheck();
        if (error != NO_ERROR) {
            CNW_LOGE("dequeueBuffer: createGraphicBuffer failed with error %d",error);
            return error;
        }
        mSlots[buf].mGraphicBuffer = graphicBuffer;
        mSlots[buf].mSurfaceDescriptor = buffer;
        mSlots[buf].mSurfaceDescriptor.get_SurfaceDescriptorGralloc().external() = true;
    }
    *buffer = mSlots[buf].mGraphicBuffer.get();

    CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
            mSlots[buf].mGraphicBuffer->handle );

    CNW_LOGD("dequeueBuffer: X");
    return NO_ERROR;
}
Example #13
0
nsresult
OMXVideoEncoder::Encode(const Image* aImage, int aWidth, int aHeight,
                        int64_t aTimestamp, int aInputFlags)
{
  MOZ_ASSERT(mStarted, "Configure() should be called before Encode().");

  NS_ENSURE_TRUE(aWidth == mWidth && aHeight == mHeight && aTimestamp >= 0,
                 NS_ERROR_INVALID_ARG);

  status_t result;

  // Dequeue an input buffer.
  uint32_t index;
  result = mCodec->dequeueInputBuffer(&index, INPUT_BUFFER_TIMEOUT_US);
  NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);

  const sp<ABuffer>& inBuf = mInputBufs.itemAt(index);
  uint8_t* dst = inBuf->data();
  size_t dstSize = inBuf->capacity();

  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);

  inBuf->setRange(0, yLen + uvLen);

  if (!aImage) {
    // Generate muted/black image directly in buffer.
    dstSize = yLen + uvLen;
    // Fill Y plane.
    memset(dst, 0x10, yLen);
    // Fill UV plane.
    memset(dst + yLen, 0x80, uvLen);
  } else {
    Image* img = const_cast<Image*>(aImage);
    ImageFormat format = img->GetFormat();

    MOZ_ASSERT(aWidth == img->GetSize().width &&
               aHeight == img->GetSize().height);

    if (format == 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();
    } else if (format == PLANAR_YCBCR) {
      ConvertPlanarYCbCrToNV12(static_cast<PlanarYCbCrImage*>(img)->GetData(),
                             dst);
    } else {
      // TODO: support RGB to YUV color conversion.
      NS_ERROR("Unsupported input image type.");
    }
  }

  // Queue this input buffer.
  result = mCodec->queueInputBuffer(index, 0, dstSize, aTimestamp, aInputFlags);

  return result == OK ? NS_OK : NS_ERROR_FAILURE;
}