| // 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 "base/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 |
| |