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