• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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