| // 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 "base/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 { |
| MediaVpxDecoderPlugin* makeDecoderPlugin(uint64_t pluginid, |
| VpxPingInfoParser parser, |
| MediaCodecType type) { |
| return new MediaVpxDecoderGeneric(parser, type); |
| } |
| }; // namespace |
| |
| uint64_t MediaVpxDecoder::readId(void* ptr) { |
| if (nullptr == ptr) |
| return 0; |
| uint64_t key = VpxPingInfoParser::parseId(ptr); |
| return key; |
| } |
| |
| MediaVpxDecoder::~MediaVpxDecoder() {} |
| |
| MediaVpxDecoderPlugin* MediaVpxDecoder::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 MediaVpxDecoder::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 MediaVpxDecoder::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 MediaVpxDecoder::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 MediaVpxDecoder::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 MediaVpxDecoder::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; |
| } |
| |
| } // namespace emulation |
| } // namespace android |