/* * 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 #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 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(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(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(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; }