210 lines
8.5 KiB
C++
210 lines
8.5 KiB
C++
/*
|
|
* 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;
|
|
}
|