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