summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/platforms/gonk/GonkVideoDecoderManager.cpp')
-rw-r--r--dom/media/platforms/gonk/GonkVideoDecoderManager.cpp772
1 files changed, 0 insertions, 772 deletions
diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
deleted file mode 100644
index 0c7b3b6af..000000000
--- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
+++ /dev/null
@@ -1,772 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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 "MediaCodecProxy.h"
-#include <OMX_IVCommon.h>
-#include <gui/Surface.h>
-#include <ICrypto.h>
-#include "GonkVideoDecoderManager.h"
-#include "GrallocImages.h"
-#include "MediaDecoderReader.h"
-#include "ImageContainer.h"
-#include "VideoUtils.h"
-#include "nsThreadUtils.h"
-#include "Layers.h"
-#include "mozilla/Logging.h"
-#include <stagefright/MediaBuffer.h>
-#include <stagefright/MetaData.h>
-#include <stagefright/MediaErrors.h>
-#include <stagefright/foundation/AString.h>
-#include "GonkNativeWindow.h"
-#include "mozilla/layers/GrallocTextureClient.h"
-#include "mozilla/layers/ImageBridgeChild.h"
-#include "mozilla/layers/TextureClient.h"
-#include "mozilla/layers/TextureClientRecycleAllocator.h"
-#include <cutils/properties.h>
-
-#define CODECCONFIG_TIMEOUT_US 10000LL
-#define READ_OUTPUT_BUFFER_TIMEOUT_US 0LL
-
-#include <android/log.h>
-#define GVDM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkVideoDecoderManager", __VA_ARGS__)
-
-#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-using namespace mozilla::layers;
-using namespace android;
-typedef android::MediaCodecProxy MediaCodecProxy;
-
-namespace mozilla {
-
-class GonkTextureClientAllocationHelper : public layers::ITextureClientAllocationHelper
-{
-public:
- GonkTextureClientAllocationHelper(uint32_t aGrallocFormat,
- gfx::IntSize aSize)
- : ITextureClientAllocationHelper(gfx::SurfaceFormat::UNKNOWN,
- aSize,
- BackendSelector::Content,
- TextureFlags::DEALLOCATE_CLIENT,
- ALLOC_DISALLOW_BUFFERTEXTURECLIENT)
- , mGrallocFormat(aGrallocFormat)
- {}
-
- already_AddRefed<TextureClient> Allocate(KnowsCompositor* aAllocator) override
- {
- uint32_t usage = android::GraphicBuffer::USAGE_SW_READ_OFTEN |
- android::GraphicBuffer::USAGE_SW_WRITE_OFTEN |
- android::GraphicBuffer::USAGE_HW_TEXTURE;
-
- GrallocTextureData* texData = GrallocTextureData::Create(mSize, mGrallocFormat,
- gfx::BackendType::NONE,
- usage, aAllocator->GetTextureForwarder());
- if (!texData) {
- return nullptr;
- }
- sp<GraphicBuffer> graphicBuffer = texData->GetGraphicBuffer();
- if (!graphicBuffer.get()) {
- return nullptr;
- }
- RefPtr<TextureClient> textureClient =
- TextureClient::CreateWithData(texData, TextureFlags::DEALLOCATE_CLIENT, aAllocator->GetTextureForwarder());
- return textureClient.forget();
- }
-
- bool IsCompatible(TextureClient* aTextureClient) override
- {
- if (!aTextureClient) {
- return false;
- }
- sp<GraphicBuffer> graphicBuffer =
- static_cast<GrallocTextureData*>(aTextureClient->GetInternalData())->GetGraphicBuffer();
- if (!graphicBuffer.get() ||
- static_cast<uint32_t>(graphicBuffer->getPixelFormat()) != mGrallocFormat ||
- aTextureClient->GetSize() != mSize) {
- return false;
- }
- return true;
- }
-
-private:
- uint32_t mGrallocFormat;
-};
-
-GonkVideoDecoderManager::GonkVideoDecoderManager(
- mozilla::layers::ImageContainer* aImageContainer,
- const VideoInfo& aConfig)
- : mConfig(aConfig)
- , mImageContainer(aImageContainer)
- , mColorConverterBufferSize(0)
- , mPendingReleaseItemsLock("GonkVideoDecoderManager::mPendingReleaseItemsLock")
- , mNeedsCopyBuffer(false)
-{
- MOZ_COUNT_CTOR(GonkVideoDecoderManager);
-}
-
-GonkVideoDecoderManager::~GonkVideoDecoderManager()
-{
- MOZ_COUNT_DTOR(GonkVideoDecoderManager);
-}
-
-nsresult
-GonkVideoDecoderManager::Shutdown()
-{
- mVideoCodecRequest.DisconnectIfExists();
- return GonkDecoderManager::Shutdown();
-}
-
-RefPtr<MediaDataDecoder::InitPromise>
-GonkVideoDecoderManager::Init()
-{
- mNeedsCopyBuffer = false;
-
- uint32_t maxWidth, maxHeight;
- char propValue[PROPERTY_VALUE_MAX];
- property_get("ro.moz.omx.hw.max_width", propValue, "-1");
- maxWidth = -1 == atoi(propValue) ? MAX_VIDEO_WIDTH : atoi(propValue);
- property_get("ro.moz.omx.hw.max_height", propValue, "-1");
- maxHeight = -1 == atoi(propValue) ? MAX_VIDEO_HEIGHT : atoi(propValue) ;
-
- if (uint32_t(mConfig.mImage.width * mConfig.mImage.height) > maxWidth * maxHeight) {
- GVDM_LOG("Video resolution exceeds hw codec capability");
- return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
- }
-
- // Validate the container-reported frame and pictureRect sizes. This ensures
- // that our video frame creation code doesn't overflow.
- if (!IsValidVideoRegion(mConfig.mImage, mConfig.ImageRect(), mConfig.mDisplay)) {
- GVDM_LOG("It is not a valid region");
- return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
- }
-
- mReaderTaskQueue = AbstractThread::GetCurrent()->AsTaskQueue();
- MOZ_ASSERT(mReaderTaskQueue);
-
- if (mDecodeLooper.get() != nullptr) {
- return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
- }
-
- if (!InitLoopers(MediaData::VIDEO_DATA)) {
- return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
- }
-
- RefPtr<InitPromise> p = mInitPromise.Ensure(__func__);
- android::sp<GonkVideoDecoderManager> self = this;
- mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper,
- mConfig.mMimeType.get(),
- false);
-
- uint32_t capability = MediaCodecProxy::kEmptyCapability;
- if (mDecoder->getCapability(&capability) == OK && (capability &
- MediaCodecProxy::kCanExposeGraphicBuffer)) {
-#if ANDROID_VERSION >= 21
- sp<IGonkGraphicBufferConsumer> consumer;
- GonkBufferQueue::createBufferQueue(&mGraphicBufferProducer, &consumer);
- mNativeWindow = new GonkNativeWindow(consumer);
-#else
- mNativeWindow = new GonkNativeWindow();
-#endif
- }
-
- mVideoCodecRequest.Begin(mDecoder->AsyncAllocateVideoMediaCodec()
- ->Then(mReaderTaskQueue, __func__,
- [self] (bool) -> void {
- self->mVideoCodecRequest.Complete();
- self->codecReserved();
- }, [self] (bool) -> void {
- self->mVideoCodecRequest.Complete();
- self->codecCanceled();
- }));
-
- return p;
-}
-
-nsresult
-GonkVideoDecoderManager::CreateVideoData(MediaBuffer* aBuffer,
- int64_t aStreamOffset,
- VideoData **v)
-{
- *v = nullptr;
- RefPtr<VideoData> data;
- int64_t timeUs;
- int32_t keyFrame;
-
- if (aBuffer == nullptr) {
- GVDM_LOG("Video Buffer is not valid!");
- return NS_ERROR_UNEXPECTED;
- }
-
- AutoReleaseMediaBuffer autoRelease(aBuffer, mDecoder.get());
-
- if (!aBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- GVDM_LOG("Decoder did not return frame time");
- return NS_ERROR_UNEXPECTED;
- }
-
- if (mLastTime > timeUs) {
- GVDM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
- return NS_ERROR_NOT_AVAILABLE;
- }
- mLastTime = timeUs;
-
- if (aBuffer->range_length() == 0) {
- // Some decoders may return spurious empty buffers that we just want to ignore
- // quoted from Android's AwesomePlayer.cpp
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- if (!aBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &keyFrame)) {
- keyFrame = 0;
- }
-
- gfx::IntRect picture =
- mConfig.ScaledImageRect(mFrameInfo.mWidth, mFrameInfo.mHeight);
- if (aBuffer->graphicBuffer().get()) {
- data = CreateVideoDataFromGraphicBuffer(aBuffer, picture);
- if (data && !mNeedsCopyBuffer) {
- // RecycleCallback() will be responsible for release the buffer.
- autoRelease.forget();
- }
- mNeedsCopyBuffer = false;
- } else {
- data = CreateVideoDataFromDataBuffer(aBuffer, picture);
- }
-
- if (!data) {
- return NS_ERROR_UNEXPECTED;
- }
- // Fill necessary info.
- data->mOffset = aStreamOffset;
- data->mTime = timeUs;
- data->mKeyframe = keyFrame;
-
- data.forget(v);
- return NS_OK;
-}
-
-// Copy pixels from one planar YUV to another.
-static void
-CopyYUV(PlanarYCbCrData& aSource, PlanarYCbCrData& aDestination)
-{
- // Fill Y plane.
- uint8_t* srcY = aSource.mYChannel;
- gfx::IntSize ySize = aSource.mYSize;
- uint8_t* destY = aDestination.mYChannel;
- // Y plane.
- for (int i = 0; i < ySize.height; i++) {
- memcpy(destY, srcY, ySize.width);
- srcY += aSource.mYStride;
- destY += aDestination.mYStride;
- }
-
- // Fill UV plane.
- // Line start
- uint8_t* srcU = aSource.mCbChannel;
- uint8_t* srcV = aSource.mCrChannel;
- uint8_t* destU = aDestination.mCbChannel;
- uint8_t* destV = aDestination.mCrChannel;
-
- gfx::IntSize uvSize = aSource.mCbCrSize;
- for (int i = 0; i < uvSize.height; i++) {
- uint8_t* su = srcU;
- uint8_t* sv = srcV;
- uint8_t* du = destU;
- uint8_t* dv =destV;
- for (int j = 0; j < uvSize.width; j++) {
- *du++ = *su++;
- *dv++ = *sv++;
- // Move to next pixel.
- su += aSource.mCbSkip;
- sv += aSource.mCrSkip;
- du += aDestination.mCbSkip;
- dv += aDestination.mCrSkip;
- }
- // Move to next line.
- srcU += aSource.mCbCrStride;
- srcV += aSource.mCbCrStride;
- destU += aDestination.mCbCrStride;
- destV += aDestination.mCbCrStride;
- }
-}
-
-inline static int
-Align(int aX, int aAlign)
-{
- return (aX + aAlign - 1) & ~(aAlign - 1);
-}
-
-// Venus formats are doucmented in kernel/include/media/msm_media_info.h:
-// * Y_Stride : Width aligned to 128
-// * UV_Stride : Width aligned to 128
-// * Y_Scanlines: Height aligned to 32
-// * UV_Scanlines: Height/2 aligned to 16
-// * Total size = align((Y_Stride * Y_Scanlines
-// * + UV_Stride * UV_Scanlines + 4096), 4096)
-static void
-CopyVenus(uint8_t* aSrc, uint8_t* aDest, uint32_t aWidth, uint32_t aHeight)
-{
- size_t yStride = Align(aWidth, 128);
- uint8_t* s = aSrc;
- uint8_t* d = aDest;
- for (size_t i = 0; i < aHeight; i++) {
- memcpy(d, s, aWidth);
- s += yStride;
- d += yStride;
- }
- size_t uvStride = yStride;
- size_t uvLines = (aHeight + 1) / 2;
- size_t ySize = yStride * Align(aHeight, 32);
- s = aSrc + ySize;
- d = aDest + ySize;
- for (size_t i = 0; i < uvLines; i++) {
- memcpy(d, s, aWidth);
- s += uvStride;
- d += uvStride;
- }
-}
-
-static void
-CopyGraphicBuffer(sp<GraphicBuffer>& aSource, sp<GraphicBuffer>& aDestination)
-{
- void* srcPtr = nullptr;
- aSource->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &srcPtr);
- void* destPtr = nullptr;
- aDestination->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &destPtr);
- MOZ_ASSERT(srcPtr && destPtr);
-
- // Build PlanarYCbCrData for source buffer.
- PlanarYCbCrData srcData;
- switch (aSource->getPixelFormat()) {
- case HAL_PIXEL_FORMAT_YV12: {
- // Android YV12 format is defined in system/core/include/system/graphics.h
- srcData.mYChannel = static_cast<uint8_t*>(srcPtr);
- srcData.mYSkip = 0;
- srcData.mYSize.width = aSource->getWidth();
- srcData.mYSize.height = aSource->getHeight();
- srcData.mYStride = aSource->getStride();
- // 4:2:0.
- srcData.mCbCrSize.width = srcData.mYSize.width / 2;
- srcData.mCbCrSize.height = srcData.mYSize.height / 2;
- srcData.mCrChannel = srcData.mYChannel + (srcData.mYStride * srcData.mYSize.height);
- // Aligned to 16 bytes boundary.
- srcData.mCbCrStride = Align(srcData.mYStride / 2, 16);
- srcData.mCrSkip = 0;
- srcData.mCbChannel = srcData.mCrChannel + (srcData.mCbCrStride * srcData.mCbCrSize.height);
- srcData.mCbSkip = 0;
-
- // Build PlanarYCbCrData for destination buffer.
- PlanarYCbCrData destData;
- destData.mYChannel = static_cast<uint8_t*>(destPtr);
- destData.mYSkip = 0;
- destData.mYSize.width = aDestination->getWidth();
- destData.mYSize.height = aDestination->getHeight();
- destData.mYStride = aDestination->getStride();
- // 4:2:0.
- destData.mCbCrSize.width = destData.mYSize.width / 2;
- destData.mCbCrSize.height = destData.mYSize.height / 2;
- destData.mCrChannel = destData.mYChannel + (destData.mYStride * destData.mYSize.height);
- // Aligned to 16 bytes boundary.
- destData.mCbCrStride = Align(destData.mYStride / 2, 16);
- destData.mCrSkip = 0;
- destData.mCbChannel = destData.mCrChannel + (destData.mCbCrStride * destData.mCbCrSize.height);
- destData.mCbSkip = 0;
-
- CopyYUV(srcData, destData);
- break;
- }
- case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
- CopyVenus(static_cast<uint8_t*>(srcPtr),
- static_cast<uint8_t*>(destPtr),
- aSource->getWidth(),
- aSource->getHeight());
- break;
- default:
- NS_ERROR("Unsupported input gralloc image type. Should never be here.");
- }
-
-
- aSource->unlock();
- aDestination->unlock();
-}
-
-already_AddRefed<VideoData>
-GonkVideoDecoderManager::CreateVideoDataFromGraphicBuffer(MediaBuffer* aSource,
- gfx::IntRect& aPicture)
-{
- sp<GraphicBuffer> srcBuffer(aSource->graphicBuffer());
- RefPtr<TextureClient> textureClient;
-
- if (mNeedsCopyBuffer) {
- // Copy buffer contents for bug 1199809.
- if (!mCopyAllocator) {
- RefPtr<layers::ImageBridgeChild> bridge = layers::ImageBridgeChild::GetSingleton();
- mCopyAllocator = new TextureClientRecycleAllocator(bridge);
- }
- if (!mCopyAllocator) {
- GVDM_LOG("Create buffer allocator failed!");
- return nullptr;
- }
-
- gfx::IntSize size(srcBuffer->getWidth(), srcBuffer->getHeight());
- GonkTextureClientAllocationHelper helper(srcBuffer->getPixelFormat(), size);
- textureClient = mCopyAllocator->CreateOrRecycle(helper);
- if (!textureClient) {
- GVDM_LOG("Copy buffer allocation failed!");
- return nullptr;
- }
-
- sp<GraphicBuffer> destBuffer =
- static_cast<GrallocTextureData*>(textureClient->GetInternalData())->GetGraphicBuffer();
-
- CopyGraphicBuffer(srcBuffer, destBuffer);
- } else {
- textureClient = mNativeWindow->getTextureClientFromBuffer(srcBuffer.get());
- textureClient->SetRecycleCallback(GonkVideoDecoderManager::RecycleCallback, this);
- static_cast<GrallocTextureData*>(textureClient->GetInternalData())->SetMediaBuffer(aSource);
- }
-
- RefPtr<VideoData> data =
- VideoData::CreateAndCopyIntoTextureClient(mConfig,
- 0, // Filled later by caller.
- 0, // Filled later by caller.
- 1, // No way to pass sample duration from muxer to
- // OMX codec, so we hardcode the duration here.
- textureClient,
- false, // Filled later by caller.
- -1,
- aPicture);
- return data.forget();
-}
-
-already_AddRefed<VideoData>
-GonkVideoDecoderManager::CreateVideoDataFromDataBuffer(MediaBuffer* aSource, gfx::IntRect& aPicture)
-{
- if (!aSource->data()) {
- GVDM_LOG("No data in Video Buffer!");
- return nullptr;
- }
- uint8_t *yuv420p_buffer = (uint8_t *)aSource->data();
- int32_t stride = mFrameInfo.mStride;
- int32_t slice_height = mFrameInfo.mSliceHeight;
-
- // Converts to OMX_COLOR_FormatYUV420Planar
- if (mFrameInfo.mColorFormat != OMX_COLOR_FormatYUV420Planar) {
- ARect crop;
- crop.top = 0;
- crop.bottom = mFrameInfo.mHeight;
- crop.left = 0;
- crop.right = mFrameInfo.mWidth;
- yuv420p_buffer = GetColorConverterBuffer(mFrameInfo.mWidth, mFrameInfo.mHeight);
- if (mColorConverter.convertDecoderOutputToI420(aSource->data(),
- mFrameInfo.mWidth, mFrameInfo.mHeight, crop, yuv420p_buffer) != OK) {
- GVDM_LOG("Color conversion failed!");
- return nullptr;
- }
- stride = mFrameInfo.mWidth;
- slice_height = mFrameInfo.mHeight;
- }
-
- size_t yuv420p_y_size = stride * slice_height;
- size_t yuv420p_u_size = ((stride + 1) / 2) * ((slice_height + 1) / 2);
- uint8_t *yuv420p_y = yuv420p_buffer;
- uint8_t *yuv420p_u = yuv420p_y + yuv420p_y_size;
- uint8_t *yuv420p_v = yuv420p_u + yuv420p_u_size;
-
- VideoData::YCbCrBuffer b;
- b.mPlanes[0].mData = yuv420p_y;
- b.mPlanes[0].mWidth = mFrameInfo.mWidth;
- b.mPlanes[0].mHeight = mFrameInfo.mHeight;
- b.mPlanes[0].mStride = stride;
- b.mPlanes[0].mOffset = 0;
- b.mPlanes[0].mSkip = 0;
-
- b.mPlanes[1].mData = yuv420p_u;
- b.mPlanes[1].mWidth = (mFrameInfo.mWidth + 1) / 2;
- b.mPlanes[1].mHeight = (mFrameInfo.mHeight + 1) / 2;
- b.mPlanes[1].mStride = (stride + 1) / 2;
- b.mPlanes[1].mOffset = 0;
- b.mPlanes[1].mSkip = 0;
-
- b.mPlanes[2].mData = yuv420p_v;
- b.mPlanes[2].mWidth =(mFrameInfo.mWidth + 1) / 2;
- b.mPlanes[2].mHeight = (mFrameInfo.mHeight + 1) / 2;
- b.mPlanes[2].mStride = (stride + 1) / 2;
- b.mPlanes[2].mOffset = 0;
- b.mPlanes[2].mSkip = 0;
-
- RefPtr<VideoData> data =
- VideoData::CreateAndCopyData(mConfig,
- mImageContainer,
- 0, // Filled later by caller.
- 0, // Filled later by caller.
- 1, // We don't know the duration.
- b,
- 0, // Filled later by caller.
- -1,
- aPicture);
-
- return data.forget();
-}
-
-bool
-GonkVideoDecoderManager::SetVideoFormat()
-{
- // read video metadata from MediaCodec
- sp<AMessage> codecFormat;
- if (mDecoder->getOutputFormat(&codecFormat) == OK) {
- AString mime;
- int32_t width = 0;
- int32_t height = 0;
- int32_t stride = 0;
- int32_t slice_height = 0;
- int32_t color_format = 0;
- int32_t crop_left = 0;
- int32_t crop_top = 0;
- int32_t crop_right = 0;
- int32_t crop_bottom = 0;
- if (!codecFormat->findString("mime", &mime) ||
- !codecFormat->findInt32("width", &width) ||
- !codecFormat->findInt32("height", &height) ||
- !codecFormat->findInt32("stride", &stride) ||
- !codecFormat->findInt32("slice-height", &slice_height) ||
- !codecFormat->findInt32("color-format", &color_format) ||
- !codecFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
- GVDM_LOG("Failed to find values");
- return false;
- }
- mFrameInfo.mWidth = width;
- mFrameInfo.mHeight = height;
- mFrameInfo.mStride = stride;
- mFrameInfo.mSliceHeight = slice_height;
- mFrameInfo.mColorFormat = color_format;
-
- nsIntSize displaySize(width, height);
- if (!IsValidVideoRegion(mConfig.mDisplay,
- mConfig.ScaledImageRect(width, height),
- displaySize)) {
- GVDM_LOG("It is not a valid region");
- return false;
- }
- return true;
- }
- GVDM_LOG("Fail to get output format");
- return false;
-}
-
-// Blocks until decoded sample is produced by the deoder.
-nsresult
-GonkVideoDecoderManager::Output(int64_t aStreamOffset,
- RefPtr<MediaData>& aOutData)
-{
- aOutData = nullptr;
- status_t err;
- if (mDecoder == nullptr) {
- GVDM_LOG("Decoder is not inited");
- return NS_ERROR_UNEXPECTED;
- }
- MediaBuffer* outputBuffer = nullptr;
- err = mDecoder->Output(&outputBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US);
-
- switch (err) {
- case OK:
- {
- RefPtr<VideoData> data;
- nsresult rv = CreateVideoData(outputBuffer, aStreamOffset, getter_AddRefs(data));
- if (rv == NS_ERROR_NOT_AVAILABLE) {
- // Decoder outputs a empty video buffer, try again
- return NS_ERROR_NOT_AVAILABLE;
- } else if (rv != NS_OK || data == nullptr) {
- GVDM_LOG("Failed to create VideoData");
- return NS_ERROR_UNEXPECTED;
- }
- aOutData = data;
- return NS_OK;
- }
- case android::INFO_FORMAT_CHANGED:
- {
- // If the format changed, update our cached info.
- GVDM_LOG("Decoder format changed");
- if (!SetVideoFormat()) {
- return NS_ERROR_UNEXPECTED;
- }
- return Output(aStreamOffset, aOutData);
- }
- case android::INFO_OUTPUT_BUFFERS_CHANGED:
- {
- if (mDecoder->UpdateOutputBuffers()) {
- return Output(aStreamOffset, aOutData);
- }
- GVDM_LOG("Fails to update output buffers!");
- return NS_ERROR_FAILURE;
- }
- case -EAGAIN:
- {
-// GVDM_LOG("Need to try again!");
- return NS_ERROR_NOT_AVAILABLE;
- }
- case android::ERROR_END_OF_STREAM:
- {
- GVDM_LOG("Got the EOS frame!");
- RefPtr<VideoData> data;
- nsresult rv = CreateVideoData(outputBuffer, aStreamOffset, getter_AddRefs(data));
- if (rv == NS_ERROR_NOT_AVAILABLE) {
- // For EOS, no need to do any thing.
- return NS_ERROR_ABORT;
- }
- if (rv != NS_OK || data == nullptr) {
- GVDM_LOG("Failed to create video data");
- return NS_ERROR_UNEXPECTED;
- }
- aOutData = data;
- return NS_ERROR_ABORT;
- }
- case -ETIMEDOUT:
- {
- GVDM_LOG("Timeout. can try again next time");
- return NS_ERROR_UNEXPECTED;
- }
- default:
- {
- GVDM_LOG("Decoder failed, err=%d", err);
- return NS_ERROR_UNEXPECTED;
- }
- }
-
- return NS_OK;
-}
-
-void
-GonkVideoDecoderManager::codecReserved()
-{
- if (mInitPromise.IsEmpty()) {
- return;
- }
- GVDM_LOG("codecReserved");
- sp<AMessage> format = new AMessage;
- sp<Surface> surface;
- status_t rv = OK;
- // Fixed values
- GVDM_LOG("Configure video mime type: %s, width:%d, height:%d", mConfig.mMimeType.get(), mConfig.mImage.width, mConfig.mImage.height);
- format->setString("mime", mConfig.mMimeType.get());
- format->setInt32("width", mConfig.mImage.width);
- format->setInt32("height", mConfig.mImage.height);
- // Set the "moz-use-undequeued-bufs" to use the undeque buffers to accelerate
- // the video decoding.
- format->setInt32("moz-use-undequeued-bufs", 1);
- if (mNativeWindow != nullptr) {
-#if ANDROID_VERSION >= 21
- surface = new Surface(mGraphicBufferProducer);
-#else
- surface = new Surface(mNativeWindow->getBufferQueue());
-#endif
- }
- mDecoder->configure(format, surface, nullptr, 0);
- mDecoder->Prepare();
-
- if (mConfig.mMimeType.EqualsLiteral("video/mp4v-es")) {
- rv = mDecoder->Input(mConfig.mCodecSpecificConfig->Elements(),
- mConfig.mCodecSpecificConfig->Length(), 0,
- android::MediaCodec::BUFFER_FLAG_CODECCONFIG,
- CODECCONFIG_TIMEOUT_US);
- }
-
- if (rv != OK) {
- GVDM_LOG("Failed to configure codec!!!!");
- mInitPromise.Reject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
- return;
- }
-
- mInitPromise.Resolve(TrackType::kVideoTrack, __func__);
-}
-
-void
-GonkVideoDecoderManager::codecCanceled()
-{
- GVDM_LOG("codecCanceled");
- mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
-}
-
-// Called on GonkDecoderManager::mTaskLooper thread.
-void
-GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
-{
- switch (aMessage->what()) {
- case kNotifyPostReleaseBuffer:
- {
- ReleaseAllPendingVideoBuffers();
- break;
- }
-
- default:
- {
- GonkDecoderManager::onMessageReceived(aMessage);
- break;
- }
- }
-}
-
-uint8_t *
-GonkVideoDecoderManager::GetColorConverterBuffer(int32_t aWidth, int32_t aHeight)
-{
- // Allocate a temporary YUV420Planer buffer.
- size_t yuv420p_y_size = aWidth * aHeight;
- size_t yuv420p_u_size = ((aWidth + 1) / 2) * ((aHeight + 1) / 2);
- size_t yuv420p_v_size = yuv420p_u_size;
- size_t yuv420p_size = yuv420p_y_size + yuv420p_u_size + yuv420p_v_size;
- if (mColorConverterBufferSize != yuv420p_size) {
- mColorConverterBuffer = MakeUnique<uint8_t[]>(yuv420p_size);
- mColorConverterBufferSize = yuv420p_size;
- }
- return mColorConverterBuffer.get();
-}
-
-/* static */
-void
-GonkVideoDecoderManager::RecycleCallback(TextureClient* aClient, void* aClosure)
-{
- MOZ_ASSERT(aClient && !aClient->IsDead());
- GonkVideoDecoderManager* videoManager = static_cast<GonkVideoDecoderManager*>(aClosure);
- GrallocTextureData* client = static_cast<GrallocTextureData*>(aClient->GetInternalData());
- aClient->ClearRecycleCallback();
- FenceHandle handle = aClient->GetAndResetReleaseFenceHandle();
- videoManager->PostReleaseVideoBuffer(client->GetMediaBuffer(), handle);
-}
-
-void GonkVideoDecoderManager::PostReleaseVideoBuffer(
- android::MediaBuffer *aBuffer,
- FenceHandle aReleaseFence)
-{
- {
- MutexAutoLock autoLock(mPendingReleaseItemsLock);
- if (aBuffer) {
- mPendingReleaseItems.AppendElement(ReleaseItem(aBuffer, aReleaseFence));
- }
- }
- sp<AMessage> notify =
- new AMessage(kNotifyPostReleaseBuffer, id());
- notify->post();
-
-}
-
-void GonkVideoDecoderManager::ReleaseAllPendingVideoBuffers()
-{
- nsTArray<ReleaseItem> releasingItems;
- {
- MutexAutoLock autoLock(mPendingReleaseItemsLock);
- releasingItems.AppendElements(mPendingReleaseItems);
- mPendingReleaseItems.Clear();
- }
-
- // Free all pending video buffers without holding mPendingReleaseItemsLock.
- size_t size = releasingItems.Length();
- for (size_t i = 0; i < size; i++) {
- RefPtr<FenceHandle::FdObj> fdObj = releasingItems[i].mReleaseFence.GetAndResetFdObj();
- sp<Fence> fence = new Fence(fdObj->GetAndResetFd());
- fence->waitForever("GonkVideoDecoderManager");
- mDecoder->ReleaseMediaBuffer(releasingItems[i].mBuffer);
- }
- releasingItems.Clear();
-}
-
-} // namespace mozilla