| /* |
| * Copyright 2015 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 "MediaH264Decoder.h" |
| #include "goldfish_media_utils.h" |
| #include <string.h> |
| |
| MediaH264Decoder::MediaH264Decoder(RenderMode renderMode) :mRenderMode(renderMode) { |
| if (renderMode == RenderMode::RENDER_BY_HOST_GPU) { |
| mVersion = 200; |
| } else if (renderMode == RenderMode::RENDER_BY_GUEST_CPU) { |
| mVersion = 100; |
| } |
| } |
| |
| void MediaH264Decoder::initH264Context(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 initH264Context: 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::H264Codec, |
| MediaOperation::InitContext, mAddressOffSet); |
| auto* retptr = transport->getReturnAddr(mAddressOffSet); |
| mHostHandle = *(uint64_t*)(retptr); |
| DDD("initH264Context: got handle to host %lld", mHostHandle); |
| } |
| |
| |
| void MediaH264Decoder::resetH264Context(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::H264Codec, |
| MediaOperation::Reset, mAddressOffSet); |
| DDD("resetH264Context: done"); |
| } |
| |
| |
| void MediaH264Decoder::destroyH264Context() { |
| |
| 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::H264Codec, |
| MediaOperation::DestroyContext, mAddressOffSet); |
| transport->returnMemorySlot(mSlot); |
| mHasAddressSpaceMemory = false; |
| } |
| |
| h264_result_t MediaH264Decoder::decodeFrame(uint8_t* img, size_t szBytes, uint64_t pts) { |
| DDD("decode frame: use handle to host %lld", mHostHandle); |
| h264_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::H264Codec, |
| MediaOperation::DecodeImage, mAddressOffSet); |
| |
| |
| auto* retptr = transport->getReturnAddr(mAddressOffSet); |
| res.bytesProcessed = *(uint64_t*)(retptr); |
| res.ret = *(int*)(retptr + 8); |
| |
| return res; |
| } |
| |
| void MediaH264Decoder::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::H264Codec, |
| MediaOperation::Flush, mAddressOffSet); |
| } |
| |
| h264_image_t MediaH264Decoder::getImage() { |
| DDD("getImage: use handle to host %lld", mHostHandle); |
| h264_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::H264Codec, |
| 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; |
| } |
| |
| |
| h264_image_t MediaH264Decoder::renderOnHostAndReturnImageMetadata(int hostColorBufferId) { |
| DDD("%s: use handle to host %lld", __func__, mHostHandle); |
| h264_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::H264Codec, |
| 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; |
| } |