blob: fc2a9f02ebe039c46fd48f5c1659ddd2c2814110 [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/MediaVpxDecoder.h"
#include "aemu/base/system/System.h"
#include "host-common/MediaVpxDecoderGeneric.h"
#include "host-common/VpxPingInfoParser.h"
#include <cstdint>
#include <string>
#include <vector>
#include <stdio.h>
#include <string.h>
#define MEDIA_VPX_DEBUG 0
#if MEDIA_VPX_DEBUG
#define VPX_DPRINT(fmt, ...) \
fprintf(stderr, "vpx-dec: %s:%d " fmt "\n", __func__, __LINE__, \
##__VA_ARGS__);
#else
#define VPX_DPRINT(fmt,...)
#endif
namespace android {
namespace emulation {
namespace {
class MediaVpxDecoderImpl : MediaVpxDecoder {
public:
MediaVpxDecoderImpl() = default;
virtual ~MediaVpxDecoder() = default;
void handlePing(MediaCodecType type, MediaOperation op, void* ptr) override;
public:
virtual void save(base::Stream* stream) const override;
virtual bool load(base::Stream* stream) override;
private:
std::mutex mMapLock{};
uint64_t mId = 0;
std::unordered_map<uint64_t, MediaVpxDecoderPlugin*> mDecoders;
uint64_t readId(void* ptr); // read id from the address
void removeDecoder(uint64_t id);
void addDecoder(uint64_t key,
MediaVpxDecoderPlugin* val); // this just add
void updateDecoder(uint64_t key,
MediaVpxDecoderPlugin* val); // this will overwrite
MediaVpxDecoderPlugin* getDecoder(uint64_t key);
};
MediaVpxDecoderPlugin* makeDecoderPlugin(uint64_t pluginid,
VpxPingInfoParser parser,
MediaCodecType type) {
return new MediaVpxDecoderGeneric(parser, type);
}
}; // namespace
uint64_t MediaVpxDecoderImpl::readId(void* ptr) {
if (nullptr == ptr)
return 0;
uint64_t key = VpxPingInfoParser::parseId(ptr);
return key;
}
MediaVpxDecoderPlugin* MediaVpxDecoderImpl::getDecoder(uint64_t key) {
{
std::lock_guard<std::mutex> g(mMapLock);
auto iter = mDecoders.find(key);
if (iter != mDecoders.end()) {
return iter->second;
}
}
VPX_DPRINT("Error: cannot find decoder with key %" PRIx64 "", key);
return nullptr;
}
void MediaVpxDecoderImpl::addDecoder(uint64_t key, MediaVpxDecoderPlugin* val) {
{
std::lock_guard<std::mutex> g(mMapLock);
if (mDecoders.find(key) == mDecoders.end()) {
mDecoders[key] = val;
VPX_DPRINT("added decoder key %" PRIx64 " val: %p", key, val);
return;
}
}
VPX_DPRINT("cannot add: already exist");
}
void MediaVpxDecoderImpl::removeDecoder(uint64_t key) {
{
std::lock_guard<std::mutex> g(mMapLock);
auto iter = mDecoders.find(key);
if (iter != mDecoders.end()) {
VPX_DPRINT("removed decoder key %" PRIx64 ", val: %p", key,
mDecoders[key]);
mDecoders.erase(iter);
return;
}
}
VPX_DPRINT("error: cannot remove decoder, not in map");
}
void MediaVpxDecoderImpl::handlePing(MediaCodecType type,
MediaOperation op,
void* ptr) {
using InitContextParam = VpxPingInfoParser::InitContextParam;
using DecodeFrameParam = VpxPingInfoParser::DecodeFrameParam;
using GetImageParam = VpxPingInfoParser::GetImageParam;
switch (op) {
case MediaOperation::InitContext: {
VpxPingInfoParser parser{ptr};
InitContextParam param{};
parser.parseInitContextParams(ptr, param);
VPX_DPRINT(
"handle init decoder context request from guest version %u",
parser.version());
uint64_t myid = readId(ptr);
MediaVpxDecoderPlugin* mydecoder =
makeDecoderPlugin(myid, parser, type);
addDecoder(myid, mydecoder);
mydecoder->initVpxContext(ptr);
VPX_DPRINT("done handling InitContext");
break;
}
case MediaOperation::DestroyContext: {
VPX_DPRINT("handle destroy request from guest %p", ptr);
MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
if (!mydecoder)
return;
mydecoder->destroyVpxContext(ptr);
delete mydecoder;
removeDecoder(readId(ptr));
break;
}
case MediaOperation::DecodeImage: {
VPX_DPRINT("handle decodeimage request from guest %p", ptr);
MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
if (nullptr == mydecoder)
return;
mydecoder->decodeFrame(ptr);
break;
}
case MediaOperation::Flush: {
VPX_DPRINT("handle flush request from guest %p", ptr);
MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
if (nullptr == mydecoder)
return;
mydecoder->flush(ptr);
break;
}
case MediaOperation::GetImage: {
VPX_DPRINT("handle getimage request from guest %p", ptr);
MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
if (nullptr == mydecoder)
return;
mydecoder->getImage(ptr);
break;
}
case MediaOperation::Reset: {
VPX_DPRINT("Reset is not supported %u\n", (unsigned int)op);
}
default:
VPX_DPRINT("Unknown command %u\n", (unsigned int)op);
break;
}
}
void MediaVpxDecoderImpl::save(base::Stream* stream) const {
int size = mDecoders.size();
stream->putBe32(size);
for (auto item : mDecoders) {
stream->putBe64(item.first);
stream->putBe32(item.second->type());
stream->putBe32(item.second->vpxtype());
stream->putBe32(item.second->version());
item.second->save(stream);
}
}
bool MediaVpxDecoderImpl::load(base::Stream* stream) {
VPX_DPRINT("loading ..");
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();
MediaCodecType vpxtype = stream->getBe32() == 8
? MediaCodecType::VP8Codec
: MediaCodecType::VP9Codec;
int version = stream->getBe32();
if (type == MediaVpxDecoderPlugin::PLUGIN_TYPE_GENERIC) { // libvpx
MediaVpxDecoderGeneric* decoder = new MediaVpxDecoderGeneric(
VpxPingInfoParser(version), vpxtype);
mDecoders[id] = decoder;
decoder->load(stream);
continue;
}
fprintf(stderr, "Error, un-implemented %s %d\n", __func__, __LINE__);
exit(1);
}
return true;
}
// static
MediaVpxDecoder* MediaVpxDecoder::create() {
return new MediaVpxDecoderImpl();
}
} // namespace emulation
} // namespace android