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 "aemu/base/system/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 {
41 class MediaVpxDecoderImpl : MediaVpxDecoder {
42 public:
43 MediaVpxDecoderImpl() = default;
44 virtual ~MediaVpxDecoder() = default;
45 void handlePing(MediaCodecType type, MediaOperation op, void* ptr) override;
46
47 public:
48 virtual void save(base::Stream* stream) const override;
49 virtual bool load(base::Stream* stream) override;
50
51 private:
52 std::mutex mMapLock{};
53 uint64_t mId = 0;
54 std::unordered_map<uint64_t, MediaVpxDecoderPlugin*> mDecoders;
55 uint64_t readId(void* ptr); // read id from the address
56 void removeDecoder(uint64_t id);
57 void addDecoder(uint64_t key,
58 MediaVpxDecoderPlugin* val); // this just add
59 void updateDecoder(uint64_t key,
60 MediaVpxDecoderPlugin* val); // this will overwrite
61 MediaVpxDecoderPlugin* getDecoder(uint64_t key);
62 };
63
makeDecoderPlugin(uint64_t pluginid,VpxPingInfoParser parser,MediaCodecType type)64 MediaVpxDecoderPlugin* makeDecoderPlugin(uint64_t pluginid,
65 VpxPingInfoParser parser,
66 MediaCodecType type) {
67 return new MediaVpxDecoderGeneric(parser, type);
68 }
69
70 }; // namespace
71
readId(void * ptr)72 uint64_t MediaVpxDecoderImpl::readId(void* ptr) {
73 if (nullptr == ptr)
74 return 0;
75 uint64_t key = VpxPingInfoParser::parseId(ptr);
76 return key;
77 }
78
getDecoder(uint64_t key)79 MediaVpxDecoderPlugin* MediaVpxDecoderImpl::getDecoder(uint64_t key) {
80 {
81 std::lock_guard<std::mutex> g(mMapLock);
82 auto iter = mDecoders.find(key);
83 if (iter != mDecoders.end()) {
84 return iter->second;
85 }
86 }
87 VPX_DPRINT("Error: cannot find decoder with key %" PRIx64 "", key);
88 return nullptr;
89 }
90
addDecoder(uint64_t key,MediaVpxDecoderPlugin * val)91 void MediaVpxDecoderImpl::addDecoder(uint64_t key, MediaVpxDecoderPlugin* val) {
92 {
93 std::lock_guard<std::mutex> g(mMapLock);
94 if (mDecoders.find(key) == mDecoders.end()) {
95 mDecoders[key] = val;
96 VPX_DPRINT("added decoder key %" PRIx64 " val: %p", key, val);
97 return;
98 }
99 }
100 VPX_DPRINT("cannot add: already exist");
101 }
102
removeDecoder(uint64_t key)103 void MediaVpxDecoderImpl::removeDecoder(uint64_t key) {
104 {
105 std::lock_guard<std::mutex> g(mMapLock);
106 auto iter = mDecoders.find(key);
107 if (iter != mDecoders.end()) {
108 VPX_DPRINT("removed decoder key %" PRIx64 ", val: %p", key,
109 mDecoders[key]);
110 mDecoders.erase(iter);
111 return;
112 }
113 }
114 VPX_DPRINT("error: cannot remove decoder, not in map");
115 }
116
handlePing(MediaCodecType type,MediaOperation op,void * ptr)117 void MediaVpxDecoderImpl::handlePing(MediaCodecType type,
118 MediaOperation op,
119 void* ptr) {
120 using InitContextParam = VpxPingInfoParser::InitContextParam;
121 using DecodeFrameParam = VpxPingInfoParser::DecodeFrameParam;
122 using GetImageParam = VpxPingInfoParser::GetImageParam;
123
124 switch (op) {
125 case MediaOperation::InitContext: {
126 VpxPingInfoParser parser{ptr};
127 InitContextParam param{};
128 parser.parseInitContextParams(ptr, param);
129 VPX_DPRINT(
130 "handle init decoder context request from guest version %u",
131 parser.version());
132 uint64_t myid = readId(ptr);
133 MediaVpxDecoderPlugin* mydecoder =
134 makeDecoderPlugin(myid, parser, type);
135 addDecoder(myid, mydecoder);
136 mydecoder->initVpxContext(ptr);
137 VPX_DPRINT("done handling InitContext");
138 break;
139 }
140 case MediaOperation::DestroyContext: {
141 VPX_DPRINT("handle destroy request from guest %p", ptr);
142 MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
143 if (!mydecoder)
144 return;
145
146 mydecoder->destroyVpxContext(ptr);
147 delete mydecoder;
148 removeDecoder(readId(ptr));
149 break;
150 }
151 case MediaOperation::DecodeImage: {
152 VPX_DPRINT("handle decodeimage request from guest %p", ptr);
153 MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
154 if (nullptr == mydecoder)
155 return;
156 mydecoder->decodeFrame(ptr);
157 break;
158 }
159 case MediaOperation::Flush: {
160 VPX_DPRINT("handle flush request from guest %p", ptr);
161 MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
162 if (nullptr == mydecoder)
163 return;
164 mydecoder->flush(ptr);
165 break;
166 }
167 case MediaOperation::GetImage: {
168 VPX_DPRINT("handle getimage request from guest %p", ptr);
169 MediaVpxDecoderPlugin* mydecoder = getDecoder(readId(ptr));
170 if (nullptr == mydecoder)
171 return;
172 mydecoder->getImage(ptr);
173 break;
174 }
175 case MediaOperation::Reset: {
176 VPX_DPRINT("Reset is not supported %u\n", (unsigned int)op);
177 }
178 default:
179 VPX_DPRINT("Unknown command %u\n", (unsigned int)op);
180 break;
181 }
182 }
183
save(base::Stream * stream) const184 void MediaVpxDecoderImpl::save(base::Stream* stream) const {
185 int size = mDecoders.size();
186 stream->putBe32(size);
187 for (auto item : mDecoders) {
188 stream->putBe64(item.first);
189 stream->putBe32(item.second->type());
190 stream->putBe32(item.second->vpxtype());
191 stream->putBe32(item.second->version());
192 item.second->save(stream);
193 }
194 }
195
load(base::Stream * stream)196 bool MediaVpxDecoderImpl::load(base::Stream* stream) {
197 VPX_DPRINT("loading ..");
198 int size = stream->getBe32();
199 for (int i = 0; i < size; ++i) {
200 // this is hacky; but we have to know the plugin type
201 uint64_t id = stream->getBe64();
202 int type = stream->getBe32();
203 MediaCodecType vpxtype = stream->getBe32() == 8
204 ? MediaCodecType::VP8Codec
205 : MediaCodecType::VP9Codec;
206 int version = stream->getBe32();
207 if (type == MediaVpxDecoderPlugin::PLUGIN_TYPE_GENERIC) { // libvpx
208 MediaVpxDecoderGeneric* decoder = new MediaVpxDecoderGeneric(
209 VpxPingInfoParser(version), vpxtype);
210 mDecoders[id] = decoder;
211 decoder->load(stream);
212 continue;
213 }
214 fprintf(stderr, "Error, un-implemented %s %d\n", __func__, __LINE__);
215 exit(1);
216 }
217
218 return true;
219 }
220
221 // static
create()222 MediaVpxDecoder* MediaVpxDecoder::create() {
223 return new MediaVpxDecoderImpl();
224 }
225
226 } // namespace emulation
227 } // namespace android
228