• 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 
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