1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "host-common/MediaVpxDecoder.h"
16 #include "base/System.h"
17 #include "host-common/MediaVpxDecoderGeneric.h"
18 #include "host-common/VpxPingInfoParser.h"
19
20 #include <cstdint>
21 #include <string>
22 #include <vector>
23
24 #include <stdio.h>
25 #include <string.h>
26
27 #define MEDIA_VPX_DEBUG 0
28
29 #if MEDIA_VPX_DEBUG
30 #define VPX_DPRINT(fmt, ...) \
31 fprintf(stderr, "vpx-dec: %s:%d " fmt "\n", __func__, __LINE__, \
32 ##__VA_ARGS__);
33 #else
34 #define VPX_DPRINT(fmt,...)
35 #endif
36
37 namespace android {
38 namespace emulation {
39
40 namespace {
makeDecoderPlugin(uint64_t pluginid,VpxPingInfoParser parser,MediaCodecType type)41 MediaVpxDecoderPlugin* makeDecoderPlugin(uint64_t pluginid,
42 VpxPingInfoParser parser,
43 MediaCodecType type) {
44 return new MediaVpxDecoderGeneric(parser, type);
45 }
46 }; // namespace
47
readId(void * ptr)48 uint64_t MediaVpxDecoder::readId(void* ptr) {
49 if (nullptr == ptr)
50 return 0;
51 uint64_t key = VpxPingInfoParser::parseId(ptr);
52 return key;
53 }
54
~MediaVpxDecoder()55 MediaVpxDecoder::~MediaVpxDecoder() {}
56
getDecoder(uint64_t key)57 MediaVpxDecoderPlugin* MediaVpxDecoder::getDecoder(uint64_t key) {
58 {
59 std::lock_guard<std::mutex> g(mMapLock);
60 auto iter = mDecoders.find(key);
61 if (iter != mDecoders.end()) {
62 return iter->second;
63 }
64 }
65 VPX_DPRINT("Error: cannot find decoder with key %" PRIx64 "", key);
66 return nullptr;
67 }
68
addDecoder(uint64_t key,MediaVpxDecoderPlugin * val)69 void MediaVpxDecoder::addDecoder(uint64_t key, MediaVpxDecoderPlugin* val) {
70 {
71 std::lock_guard<std::mutex> g(mMapLock);
72 if (mDecoders.find(key) == mDecoders.end()) {
73 mDecoders[key] = val;
74 VPX_DPRINT("added decoder key %" PRIx64 " val: %p", key, val);
75 return;
76 }
77 }
78 VPX_DPRINT("cannot add: already exist");
79 }
80
removeDecoder(uint64_t key)81 void MediaVpxDecoder::removeDecoder(uint64_t key) {
82 {
83 std::lock_guard<std::mutex> g(mMapLock);
84 auto iter = mDecoders.find(key);
85 if (iter != mDecoders.end()) {
86 VPX_DPRINT("removed decoder key %" PRIx64 ", val: %p", key,
87 mDecoders[key]);
88 mDecoders.erase(iter);
89 return;
90 }
91 }
92 VPX_DPRINT("error: cannot remove decoder, not in map");
93 }
94
handlePing(MediaCodecType type,MediaOperation op,void * ptr)95 void MediaVpxDecoder::handlePing(MediaCodecType type,
96 MediaOperation op,
97 void* ptr) {
98 using InitContextParam = VpxPingInfoParser::InitContextParam;
99 using DecodeFrameParam = VpxPingInfoParser::DecodeFrameParam;
100 using GetImageParam = VpxPingInfoParser::GetImageParam;
101
102 switch (op) {
103 case MediaOperation::InitContext: {
104 VpxPingInfoParser parser{ptr};
105 InitContextParam param{};
106 parser.parseInitContextParams(ptr, param);
107 VPX_DPRINT(
108 "handle init decoder context request from guest version %u",
109 parser.version());
110 uint64_t myid = readId(ptr);
111 MediaVpxDecoderPlugin* mydecoder =
112 makeDecoderPlugin(myid, parser, type);
113 addDecoder(myid, mydecoder);
114 mydecoder->initVpxContext(ptr);
115 VPX_DPRINT("done handling InitContext");
116 break;
117 }
118 case MediaOperation::DestroyContext: {
119 VPX_DPRINT("handle destroy request from guest %p", ptr);
120 MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
121 if (!mydecoder)
122 return;
123
124 mydecoder->destroyVpxContext(ptr);
125 delete mydecoder;
126 removeDecoder(readId(ptr));
127 break;
128 }
129 case MediaOperation::DecodeImage: {
130 VPX_DPRINT("handle decodeimage request from guest %p", ptr);
131 MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
132 if (nullptr == mydecoder)
133 return;
134 mydecoder->decodeFrame(ptr);
135 break;
136 }
137 case MediaOperation::Flush: {
138 VPX_DPRINT("handle flush request from guest %p", ptr);
139 MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
140 if (nullptr == mydecoder)
141 return;
142 mydecoder->flush(ptr);
143 break;
144 }
145 case MediaOperation::GetImage: {
146 VPX_DPRINT("handle getimage request from guest %p", ptr);
147 MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
148 if (nullptr == mydecoder)
149 return;
150 mydecoder->getImage(ptr);
151 break;
152 }
153 case MediaOperation::Reset: {
154 VPX_DPRINT("Reset is not supported %u\n", (unsigned int)op);
155 }
156 default:
157 VPX_DPRINT("Unknown command %u\n", (unsigned int)op);
158 break;
159 }
160 }
161
save(base::Stream * stream) const162 void MediaVpxDecoder::save(base::Stream* stream) const {
163 int size = mDecoders.size();
164 stream->putBe32(size);
165 for (auto item : mDecoders) {
166 stream->putBe64(item.first);
167 stream->putBe32(item.second->type());
168 stream->putBe32(item.second->vpxtype());
169 stream->putBe32(item.second->version());
170 item.second->save(stream);
171 }
172 }
173
load(base::Stream * stream)174 bool MediaVpxDecoder::load(base::Stream* stream) {
175 VPX_DPRINT("loading ..");
176 int size = stream->getBe32();
177 for (int i = 0; i < size; ++i) {
178 // this is hacky; but we have to know the plugin type
179 uint64_t id = stream->getBe64();
180 int type = stream->getBe32();
181 MediaCodecType vpxtype = stream->getBe32() == 8
182 ? MediaCodecType::VP8Codec
183 : MediaCodecType::VP9Codec;
184 int version = stream->getBe32();
185 if (type == MediaVpxDecoderPlugin::PLUGIN_TYPE_GENERIC) { // libvpx
186 MediaVpxDecoderGeneric* decoder = new MediaVpxDecoderGeneric(
187 VpxPingInfoParser(version), vpxtype);
188 mDecoders[id] = decoder;
189 decoder->load(stream);
190 continue;
191 }
192 fprintf(stderr, "Error, un-implemented %s %d\n", __func__, __LINE__);
193 exit(1);
194 }
195
196 return true;
197 }
198
199 } // namespace emulation
200 } // namespace android
201