blob: 2cea9b9cdbaf9de0bc8a0eed75e68a1d7c95a73b [file] [log] [blame]
// Copyright (C) 2019 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 "host-common/MediaH264DecoderDefault.h"
#include "aemu/base/system/System.h"
#include "host-common/H264PingInfoParser.h"
#include "host-common/MediaH264DecoderGeneric.h"
#include <cstdint>
#include <string>
#include <vector>
#include <stdio.h>
#include <string.h>
#define MEDIA_H264_DEBUG 0
#if MEDIA_H264_DEBUG
#define H264_DPRINT(fmt,...) fprintf(stderr, "h264-dec: %s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
#else
#define H264_DPRINT(fmt,...)
#endif
namespace android {
namespace emulation {
namespace {
MediaH264DecoderPlugin* makeDecoderPlugin(uint64_t pluginid,
H264PingInfoParser parser) {
return new MediaH264DecoderGeneric(pluginid, parser);
}
}; // anon namespace
uint64_t MediaH264DecoderDefault::readId(void* ptr) {
if (nullptr == ptr)
return 0;
uint64_t key = H264PingInfoParser::parseHostDecoderId(ptr);
return key;
}
MediaH264DecoderPlugin* MediaH264DecoderDefault::getDecoder(uint64_t key) {
{
std::lock_guard<std::mutex> g(mMapLock);
auto iter = mDecoders.find(key);
if (iter != mDecoders.end()) {
return iter->second;
}
}
H264_DPRINT("Error: cannot find decoder with key %" PRIx64 "", key);
return nullptr;
}
uint64_t MediaH264DecoderDefault::createId() {
std::lock_guard<std::mutex> g(mIdLock);
return ++mId;
}
void MediaH264DecoderDefault::addDecoder(uint64_t key,
MediaH264DecoderPlugin* val) {
{
std::lock_guard<std::mutex> g(mMapLock);
if (mDecoders.find(key) == mDecoders.end()) {
mDecoders[key] = val;
H264_DPRINT("added decoder key %" PRIx64 " val: %p", key, val);
return;
}
}
H264_DPRINT("cannot add: already exist");
}
void MediaH264DecoderDefault::updateDecoder(uint64_t key,
MediaH264DecoderPlugin* val) {
std::lock_guard<std::mutex> g(mMapLock);
if (mDecoders.find(key) == mDecoders.end()) {
H264_DPRINT("error: decoder with key %" PRIx64 " does not exist", key);
} else {
mDecoders[key] = val;
H264_DPRINT("updated key %" PRIx64 " with new decoder %p", key, val);
}
}
void MediaH264DecoderDefault::removeDecoder(uint64_t key) {
{
std::lock_guard<std::mutex> g(mMapLock);
auto iter = mDecoders.find(key);
if (iter != mDecoders.end()) {
H264_DPRINT("removed decoder key %" PRIx64 ", val: %p", key,
mDecoders[key]);
mDecoders.erase(iter);
return;
}
}
H264_DPRINT("error: cannot remove decoder, not in map");
}
static void* getReturnAddress(void* ptr) {
uint8_t* xptr = (uint8_t*)ptr;
void* pint = (void*)(xptr + 256);
return pint;
}
void MediaH264DecoderDefault::handlePing(MediaCodecType type,
MediaOperation op,
void* ptr) {
using InitContextParam = H264PingInfoParser::InitContextParam;
using DecodeFrameParam = H264PingInfoParser::DecodeFrameParam;
using ResetParam = H264PingInfoParser::ResetParam;
using GetImageParam = H264PingInfoParser::GetImageParam;
switch (op) {
case MediaOperation::InitContext: {
H264PingInfoParser parser{ptr};
InitContextParam param{};
parser.parseInitContextParams(ptr, param);
H264_DPRINT(
"handle init decoder context request from guest version %u",
parser.version());
uint64_t myid = createId();
MediaH264DecoderPlugin* mydecoder = makeDecoderPlugin(myid, parser);
addDecoder(myid, mydecoder);
mydecoder->initH264Context(ptr);
*(param.pHostDecoderId) = myid;
H264_DPRINT("done handling InitContext");
break;
}
case MediaOperation::DestroyContext: {
H264_DPRINT("handle destroy request from guest %p", ptr);
MediaH264DecoderPlugin* mydecoder = getDecoder(readId(ptr));
if (!mydecoder)
return;
delete mydecoder;
removeDecoder(readId(ptr));
break;
}
case MediaOperation::DecodeImage: {
H264_DPRINT("handle decodeimage request from guest %p", ptr);
MediaH264DecoderPlugin* mydecoder = getDecoder(readId(ptr));
if (nullptr == mydecoder)
return;
mydecoder->decodeFrame(ptr);
break;
}
case MediaOperation::Flush: {
H264_DPRINT("handle flush request from guest %p", ptr);
MediaH264DecoderPlugin* mydecoder = getDecoder(readId(ptr));
if (nullptr == mydecoder)
return;
mydecoder->flush(ptr);
break;
}
case MediaOperation::GetImage: {
H264_DPRINT("handle getimage request from guest %p", ptr);
MediaH264DecoderPlugin* mydecoder = getDecoder(readId(ptr));
if (nullptr == mydecoder)
return;
mydecoder->getImage(ptr);
break;
}
case MediaOperation::Reset: {
H264_DPRINT("handle reset request from guest %p", ptr);
uint64_t oldId = readId(ptr);
MediaH264DecoderPlugin* olddecoder = getDecoder(oldId);
if (nullptr == olddecoder) {
H264_DPRINT("error, cannot reset on nullptr");
return;
}
MediaH264DecoderPlugin* mydecoder = olddecoder->clone();
delete olddecoder;
mydecoder->reset(ptr);
updateDecoder(oldId, mydecoder);
break;
}
default:
H264_DPRINT("Unknown command %u\n", (unsigned int)op);
break;
}
}
void MediaH264DecoderDefault::save(base::Stream* stream) const {
stream->putBe64(mId);
int size = mDecoders.size();
stream->putBe32(size);
for (auto item : mDecoders) {
stream->putBe64(item.first);
stream->putBe32(item.second->type());
item.second->save(stream);
}
}
bool MediaH264DecoderDefault::load(base::Stream* stream) {
mId = stream->getBe64();
int size = stream->getBe32();
for (int i = 0; i < size; ++i) {
// this is hacky; but we have to know the plugin type
uint64_t id = stream->getBe64();
int type = stream->getBe32();
if (type == MediaH264DecoderPlugin::PLUGIN_TYPE_GENERIC) {
MediaH264DecoderGeneric* decoder =
new MediaH264DecoderGeneric(id, H264PingInfoParser(100));
decoder->load(stream);
mDecoders[id] = decoder;
continue;
}
fprintf(stderr, "Error, un-implemented %s %d\n", __func__, __LINE__);
exit(1);
}
return true;
}
} // namespace emulation
} // namespace android