blob: f1bc356f4a333ec71467bd2780508eb871957cb2 [file] [log] [blame]
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <utils/Log.h>
#define DEBUG 0
#if DEBUG
#define DDD(...) ALOGD(__VA_ARGS__)
#else
#define DDD(...) ((void)0)
#endif
#include "MediaHevcDecoder.h"
#include "goldfish_media_utils.h"
#include <string.h>
MediaHevcDecoder::MediaHevcDecoder(RenderMode renderMode)
: mRenderMode(renderMode) {
if (renderMode == RenderMode::RENDER_BY_HOST_GPU) {
mVersion = 200;
} else if (renderMode == RenderMode::RENDER_BY_GUEST_CPU) {
mVersion = 100;
}
}
void MediaHevcDecoder::initHevcContext(unsigned int width, unsigned int height,
unsigned int outWidth,
unsigned int outHeight,
PixelFormat pixFmt) {
auto transport = GoldfishMediaTransport::getInstance();
if (!mHasAddressSpaceMemory) {
int slot = transport->getMemorySlot();
if (slot < 0) {
ALOGE("ERROR: Failed to initHevcContext: cannot get memory slot");
return;
}
mSlot = slot;
mAddressOffSet = static_cast<unsigned int>(mSlot) * (1 << 20);
DDD("got memory lot %d addrr %x", mSlot, mAddressOffSet);
mHasAddressSpaceMemory = true;
}
transport->writeParam(mVersion, 0, mAddressOffSet);
transport->writeParam(width, 1, mAddressOffSet);
transport->writeParam(height, 2, mAddressOffSet);
transport->writeParam(outWidth, 3, mAddressOffSet);
transport->writeParam(outHeight, 4, mAddressOffSet);
transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
transport->sendOperation(MediaCodecType::HevcCodec,
MediaOperation::InitContext, mAddressOffSet);
auto *retptr = transport->getReturnAddr(mAddressOffSet);
mHostHandle = *(uint64_t *)(retptr);
DDD("initHevcContext: got handle to host %lld", mHostHandle);
}
void MediaHevcDecoder::resetHevcContext(unsigned int width, unsigned int height,
unsigned int outWidth,
unsigned int outHeight,
PixelFormat pixFmt) {
auto transport = GoldfishMediaTransport::getInstance();
if (!mHasAddressSpaceMemory) {
ALOGE("%s no address space memory", __func__);
return;
}
transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
transport->writeParam(width, 1, mAddressOffSet);
transport->writeParam(height, 2, mAddressOffSet);
transport->writeParam(outWidth, 3, mAddressOffSet);
transport->writeParam(outHeight, 4, mAddressOffSet);
transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
transport->sendOperation(MediaCodecType::HevcCodec, MediaOperation::Reset,
mAddressOffSet);
DDD("resetHevcContext: done");
}
void MediaHevcDecoder::destroyHevcContext() {
DDD("return memory lot %d addrr %x", (int)(mAddressOffSet >> 23),
mAddressOffSet);
auto transport = GoldfishMediaTransport::getInstance();
transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
transport->sendOperation(MediaCodecType::HevcCodec,
MediaOperation::DestroyContext, mAddressOffSet);
transport->returnMemorySlot(mSlot);
mHasAddressSpaceMemory = false;
}
hevc_result_t MediaHevcDecoder::decodeFrame(uint8_t *img, size_t szBytes,
uint64_t pts) {
DDD("decode frame: use handle to host %lld", mHostHandle);
hevc_result_t res = {0, 0};
if (!mHasAddressSpaceMemory) {
ALOGE("%s no address space memory", __func__);
return res;
}
auto transport = GoldfishMediaTransport::getInstance();
uint8_t *hostSrc = transport->getInputAddr(mAddressOffSet);
if (img != nullptr && szBytes > 0) {
memcpy(hostSrc, img, szBytes);
}
transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
transport->writeParam(transport->offsetOf((uint64_t)(hostSrc)) -
mAddressOffSet,
1, mAddressOffSet);
transport->writeParam((uint64_t)szBytes, 2, mAddressOffSet);
transport->writeParam((uint64_t)pts, 3, mAddressOffSet);
transport->sendOperation(MediaCodecType::HevcCodec,
MediaOperation::DecodeImage, mAddressOffSet);
auto *retptr = transport->getReturnAddr(mAddressOffSet);
res.bytesProcessed = *(uint64_t *)(retptr);
res.ret = *(int *)(retptr + 8);
return res;
}
void MediaHevcDecoder::sendMetadata(MetaDataColorAspects *ptr) {
DDD("send metadata to host %p", ptr);
if (!mHasAddressSpaceMemory) {
ALOGE("%s no address space memory", __func__);
return;
}
MetaDataColorAspects& meta = *ptr;
auto transport = GoldfishMediaTransport::getInstance();
transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
transport->writeParam(meta.type, 1, mAddressOffSet);
transport->writeParam(meta.primaries, 2, mAddressOffSet);
transport->writeParam(meta.range, 3, mAddressOffSet);
transport->writeParam(meta.transfer, 4, mAddressOffSet);
transport->sendOperation(MediaCodecType::HevcCodec, MediaOperation::SendMetadata, mAddressOffSet);
}
void MediaHevcDecoder::flush() {
if (!mHasAddressSpaceMemory) {
ALOGE("%s no address space memory", __func__);
return;
}
DDD("flush: use handle to host %lld", mHostHandle);
auto transport = GoldfishMediaTransport::getInstance();
transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
transport->sendOperation(MediaCodecType::HevcCodec, MediaOperation::Flush,
mAddressOffSet);
}
hevc_image_t MediaHevcDecoder::getImage() {
DDD("getImage: use handle to host %lld", mHostHandle);
hevc_image_t res{};
if (!mHasAddressSpaceMemory) {
ALOGE("%s no address space memory", __func__);
return res;
}
auto transport = GoldfishMediaTransport::getInstance();
uint8_t *dst = transport->getInputAddr(
mAddressOffSet); // Note: reuse the same addr for input and output
transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet,
1, mAddressOffSet);
transport->writeParam(-1, 2, mAddressOffSet);
transport->sendOperation(MediaCodecType::HevcCodec,
MediaOperation::GetImage, mAddressOffSet);
auto *retptr = transport->getReturnAddr(mAddressOffSet);
res.ret = *(int *)(retptr);
if (res.ret >= 0) {
res.data = dst;
res.width = *(uint32_t *)(retptr + 8);
res.height = *(uint32_t *)(retptr + 16);
res.pts = *(uint64_t *)(retptr + 24);
res.color_primaries = *(uint32_t *)(retptr + 32);
res.color_range = *(uint32_t *)(retptr + 40);
res.color_trc = *(uint32_t *)(retptr + 48);
res.colorspace = *(uint32_t *)(retptr + 56);
} else if (res.ret == (int)(Err::DecoderRestarted)) {
res.width = *(uint32_t *)(retptr + 8);
res.height = *(uint32_t *)(retptr + 16);
}
return res;
}
hevc_image_t
MediaHevcDecoder::renderOnHostAndReturnImageMetadata(int hostColorBufferId) {
DDD("%s: use handle to host %lld", __func__, mHostHandle);
hevc_image_t res{};
if (hostColorBufferId < 0) {
ALOGE("%s negative color buffer id %d", __func__, hostColorBufferId);
return res;
}
DDD("%s send color buffer id %d", __func__, hostColorBufferId);
if (!mHasAddressSpaceMemory) {
ALOGE("%s no address space memory", __func__);
return res;
}
auto transport = GoldfishMediaTransport::getInstance();
uint8_t *dst = transport->getInputAddr(
mAddressOffSet); // Note: reuse the same addr for input and output
transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet,
1, mAddressOffSet);
transport->writeParam((uint64_t)hostColorBufferId, 2, mAddressOffSet);
transport->sendOperation(MediaCodecType::HevcCodec,
MediaOperation::GetImage, mAddressOffSet);
auto *retptr = transport->getReturnAddr(mAddressOffSet);
res.ret = *(int *)(retptr);
if (res.ret >= 0) {
res.data = dst; // note: the data could be junk
res.width = *(uint32_t *)(retptr + 8);
res.height = *(uint32_t *)(retptr + 16);
res.pts = *(uint64_t *)(retptr + 24);
res.color_primaries = *(uint32_t *)(retptr + 32);
res.color_range = *(uint32_t *)(retptr + 40);
res.color_trc = *(uint32_t *)(retptr + 48);
res.colorspace = *(uint32_t *)(retptr + 56);
} else if (res.ret == (int)(Err::DecoderRestarted)) {
res.width = *(uint32_t *)(retptr + 8);
res.height = *(uint32_t *)(retptr + 16);
}
return res;
}