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