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/MediaH264DecoderDefault.h"
16 #include "aemu/base/system/System.h"
17 #include "host-common/H264PingInfoParser.h"
18 #include "host-common/MediaH264DecoderGeneric.h"
19
20 #include <cstdint>
21 #include <string>
22 #include <vector>
23
24 #include <stdio.h>
25 #include <string.h>
26
27 #define MEDIA_H264_DEBUG 0
28
29 #if MEDIA_H264_DEBUG
30 #define H264_DPRINT(fmt,...) fprintf(stderr, "h264-dec: %s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
31 #else
32 #define H264_DPRINT(fmt,...)
33 #endif
34
35 namespace android {
36 namespace emulation {
37
38 namespace {
makeDecoderPlugin(uint64_t pluginid,H264PingInfoParser parser)39 MediaH264DecoderPlugin* makeDecoderPlugin(uint64_t pluginid,
40 H264PingInfoParser parser) {
41 return new MediaH264DecoderGeneric(pluginid, parser);
42 }
43
44 }; // anon namespace
45
46
readId(void * ptr)47 uint64_t MediaH264DecoderDefault::readId(void* ptr) {
48 if (nullptr == ptr)
49 return 0;
50 uint64_t key = H264PingInfoParser::parseHostDecoderId(ptr);
51 return key;
52 }
53
getDecoder(uint64_t key)54 MediaH264DecoderPlugin* MediaH264DecoderDefault::getDecoder(uint64_t key) {
55 {
56 std::lock_guard<std::mutex> g(mMapLock);
57 auto iter = mDecoders.find(key);
58 if (iter != mDecoders.end()) {
59 return iter->second;
60 }
61 }
62 H264_DPRINT("Error: cannot find decoder with key %" PRIx64 "", key);
63 return nullptr;
64 }
65
createId()66 uint64_t MediaH264DecoderDefault::createId() {
67 std::lock_guard<std::mutex> g(mIdLock);
68 return ++mId;
69 }
70
addDecoder(uint64_t key,MediaH264DecoderPlugin * val)71 void MediaH264DecoderDefault::addDecoder(uint64_t key,
72 MediaH264DecoderPlugin* val) {
73 {
74 std::lock_guard<std::mutex> g(mMapLock);
75 if (mDecoders.find(key) == mDecoders.end()) {
76 mDecoders[key] = val;
77 H264_DPRINT("added decoder key %" PRIx64 " val: %p", key, val);
78 return;
79 }
80 }
81 H264_DPRINT("cannot add: already exist");
82 }
83
updateDecoder(uint64_t key,MediaH264DecoderPlugin * val)84 void MediaH264DecoderDefault::updateDecoder(uint64_t key,
85 MediaH264DecoderPlugin* val) {
86 std::lock_guard<std::mutex> g(mMapLock);
87 if (mDecoders.find(key) == mDecoders.end()) {
88 H264_DPRINT("error: decoder with key %" PRIx64 " does not exist", key);
89 } else {
90 mDecoders[key] = val;
91 H264_DPRINT("updated key %" PRIx64 " with new decoder %p", key, val);
92 }
93 }
94
removeDecoder(uint64_t key)95 void MediaH264DecoderDefault::removeDecoder(uint64_t key) {
96 {
97 std::lock_guard<std::mutex> g(mMapLock);
98 auto iter = mDecoders.find(key);
99 if (iter != mDecoders.end()) {
100 H264_DPRINT("removed decoder key %" PRIx64 ", val: %p", key,
101 mDecoders[key]);
102 mDecoders.erase(iter);
103 return;
104 }
105 }
106 H264_DPRINT("error: cannot remove decoder, not in map");
107 }
108
getReturnAddress(void * ptr)109 static void* getReturnAddress(void* ptr) {
110 uint8_t* xptr = (uint8_t*)ptr;
111 void* pint = (void*)(xptr + 256);
112 return pint;
113 }
114
115
handlePing(MediaCodecType type,MediaOperation op,void * ptr)116 void MediaH264DecoderDefault::handlePing(MediaCodecType type,
117 MediaOperation op,
118 void* ptr) {
119 using InitContextParam = H264PingInfoParser::InitContextParam;
120 using DecodeFrameParam = H264PingInfoParser::DecodeFrameParam;
121 using ResetParam = H264PingInfoParser::ResetParam;
122 using GetImageParam = H264PingInfoParser::GetImageParam;
123
124 switch (op) {
125 case MediaOperation::InitContext: {
126 H264PingInfoParser parser{ptr};
127 InitContextParam param{};
128 parser.parseInitContextParams(ptr, param);
129 H264_DPRINT(
130 "handle init decoder context request from guest version %u",
131 parser.version());
132 uint64_t myid = createId();
133 MediaH264DecoderPlugin* mydecoder = makeDecoderPlugin(myid, parser);
134 addDecoder(myid, mydecoder);
135 mydecoder->initH264Context(ptr);
136 *(param.pHostDecoderId) = myid;
137 H264_DPRINT("done handling InitContext");
138 break;
139 }
140 case MediaOperation::DestroyContext: {
141 H264_DPRINT("handle destroy request from guest %p", ptr);
142 MediaH264DecoderPlugin* mydecoder = getDecoder(readId(ptr));
143 if (!mydecoder)
144 return;
145
146 delete mydecoder;
147 removeDecoder(readId(ptr));
148 break;
149 }
150 case MediaOperation::DecodeImage: {
151 H264_DPRINT("handle decodeimage request from guest %p", ptr);
152 MediaH264DecoderPlugin* mydecoder = getDecoder(readId(ptr));
153 if (nullptr == mydecoder)
154 return;
155 mydecoder->decodeFrame(ptr);
156 break;
157 }
158 case MediaOperation::Flush: {
159 H264_DPRINT("handle flush request from guest %p", ptr);
160 MediaH264DecoderPlugin* mydecoder = getDecoder(readId(ptr));
161 if (nullptr == mydecoder)
162 return;
163 mydecoder->flush(ptr);
164 break;
165 }
166 case MediaOperation::GetImage: {
167 H264_DPRINT("handle getimage request from guest %p", ptr);
168 MediaH264DecoderPlugin* mydecoder = getDecoder(readId(ptr));
169 if (nullptr == mydecoder)
170 return;
171 mydecoder->getImage(ptr);
172 break;
173 }
174 case MediaOperation::Reset: {
175 H264_DPRINT("handle reset request from guest %p", ptr);
176 uint64_t oldId = readId(ptr);
177 MediaH264DecoderPlugin* olddecoder = getDecoder(oldId);
178 if (nullptr == olddecoder) {
179 H264_DPRINT("error, cannot reset on nullptr");
180 return;
181 }
182 MediaH264DecoderPlugin* mydecoder = olddecoder->clone();
183 delete olddecoder;
184 mydecoder->reset(ptr);
185 updateDecoder(oldId, mydecoder);
186 break;
187 }
188 default:
189 H264_DPRINT("Unknown command %u\n", (unsigned int)op);
190 break;
191 }
192 }
193
save(base::Stream * stream) const194 void MediaH264DecoderDefault::save(base::Stream* stream) const {
195 stream->putBe64(mId);
196 int size = mDecoders.size();
197 stream->putBe32(size);
198 for (auto item : mDecoders) {
199 stream->putBe64(item.first);
200 stream->putBe32(item.second->type());
201 item.second->save(stream);
202 }
203 }
204
load(base::Stream * stream)205 bool MediaH264DecoderDefault::load(base::Stream* stream) {
206 mId = stream->getBe64();
207 int size = stream->getBe32();
208 for (int i = 0; i < size; ++i) {
209 // this is hacky; but we have to know the plugin type
210 uint64_t id = stream->getBe64();
211 int type = stream->getBe32();
212 if (type == MediaH264DecoderPlugin::PLUGIN_TYPE_GENERIC) {
213 MediaH264DecoderGeneric* decoder =
214 new MediaH264DecoderGeneric(id, H264PingInfoParser(100));
215 decoder->load(stream);
216 mDecoders[id] = decoder;
217 continue;
218 }
219 fprintf(stderr, "Error, un-implemented %s %d\n", __func__, __LINE__);
220 exit(1);
221 }
222 return true;
223 }
224
225 } // namespace emulation
226 } // namespace android
227
228