1 /*
2  * Copyright 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <utils/Log.h>
18 
19 #define DEBUG  0
20 #if DEBUG
21 #  define  DDD(...)    ALOGD(__VA_ARGS__)
22 #else
23 #  define  DDD(...)    ((void)0)
24 #endif
25 
26 #include "MediaH264Decoder.h"
27 #include "goldfish_media_utils.h"
28 #include <string.h>
29 
MediaH264Decoder(RenderMode renderMode)30 MediaH264Decoder::MediaH264Decoder(RenderMode renderMode) :mRenderMode(renderMode) {
31   if (renderMode == RenderMode::RENDER_BY_HOST_GPU) {
32       mVersion = 200;
33   } else if (renderMode == RenderMode::RENDER_BY_GUEST_CPU) {
34       mVersion = 100;
35   }
36 }
37 
initH264Context(unsigned int width,unsigned int height,unsigned int outWidth,unsigned int outHeight,PixelFormat pixFmt)38 void MediaH264Decoder::initH264Context(unsigned int width,
39                                        unsigned int height,
40                                        unsigned int outWidth,
41                                        unsigned int outHeight,
42                                        PixelFormat pixFmt) {
43     auto transport = GoldfishMediaTransport::getInstance();
44     if (!mHasAddressSpaceMemory) {
45         int slot = transport->getMemorySlot();
46         if (slot < 0) {
47             ALOGE("ERROR: Failed to initH264Context: cannot get memory slot");
48             return;
49         }
50         mAddressOffSet = static_cast<unsigned int>(slot) * 8 * (1 << 20);
51         DDD("got memory lot %d addrr %x", slot, mAddressOffSet);
52         mHasAddressSpaceMemory = true;
53     }
54     transport->writeParam(mVersion, 0, mAddressOffSet);
55     transport->writeParam(width, 1, mAddressOffSet);
56     transport->writeParam(height, 2, mAddressOffSet);
57     transport->writeParam(outWidth, 3, mAddressOffSet);
58     transport->writeParam(outHeight, 4, mAddressOffSet);
59     transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
60     transport->sendOperation(MediaCodecType::H264Codec,
61                              MediaOperation::InitContext, mAddressOffSet);
62     auto* retptr = transport->getReturnAddr(mAddressOffSet);
63     mHostHandle = *(uint64_t*)(retptr);
64     DDD("initH264Context: got handle to host %lld", mHostHandle);
65 }
66 
67 
resetH264Context(unsigned int width,unsigned int height,unsigned int outWidth,unsigned int outHeight,PixelFormat pixFmt)68 void MediaH264Decoder::resetH264Context(unsigned int width,
69                                        unsigned int height,
70                                        unsigned int outWidth,
71                                        unsigned int outHeight,
72                                        PixelFormat pixFmt) {
73     auto transport = GoldfishMediaTransport::getInstance();
74     if (!mHasAddressSpaceMemory) {
75         ALOGE("%s no address space memory", __func__);
76         return;
77     }
78     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
79     transport->writeParam(width, 1, mAddressOffSet);
80     transport->writeParam(height, 2, mAddressOffSet);
81     transport->writeParam(outWidth, 3, mAddressOffSet);
82     transport->writeParam(outHeight, 4, mAddressOffSet);
83     transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
84     transport->sendOperation(MediaCodecType::H264Codec,
85                              MediaOperation::Reset, mAddressOffSet);
86     DDD("resetH264Context: done");
87 }
88 
89 
destroyH264Context()90 void MediaH264Decoder::destroyH264Context() {
91 
92     DDD("return memory lot %d addrr %x", (int)(mAddressOffSet >> 23), mAddressOffSet);
93     auto transport = GoldfishMediaTransport::getInstance();
94     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
95     transport->sendOperation(MediaCodecType::H264Codec,
96                              MediaOperation::DestroyContext, mAddressOffSet);
97     transport->returnMemorySlot(mAddressOffSet >> 23);
98     mHasAddressSpaceMemory = false;
99 }
100 
decodeFrame(uint8_t * img,size_t szBytes,uint64_t pts)101 h264_result_t MediaH264Decoder::decodeFrame(uint8_t* img, size_t szBytes, uint64_t pts) {
102     DDD("decode frame: use handle to host %lld", mHostHandle);
103     h264_result_t res = {0, 0};
104     if (!mHasAddressSpaceMemory) {
105         ALOGE("%s no address space memory", __func__);
106         return res;
107     }
108     auto transport = GoldfishMediaTransport::getInstance();
109     uint8_t* hostSrc = transport->getInputAddr(mAddressOffSet);
110     if (img != nullptr && szBytes > 0) {
111         memcpy(hostSrc, img, szBytes);
112     }
113     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
114     transport->writeParam(transport->offsetOf((uint64_t)(hostSrc)) - mAddressOffSet, 1, mAddressOffSet);
115     transport->writeParam((uint64_t)szBytes, 2, mAddressOffSet);
116     transport->writeParam((uint64_t)pts, 3, mAddressOffSet);
117     transport->sendOperation(MediaCodecType::H264Codec,
118                              MediaOperation::DecodeImage, mAddressOffSet);
119 
120 
121     auto* retptr = transport->getReturnAddr(mAddressOffSet);
122     res.bytesProcessed = *(uint64_t*)(retptr);
123     res.ret = *(int*)(retptr + 8);
124 
125     return res;
126 }
127 
flush()128 void MediaH264Decoder::flush() {
129     if (!mHasAddressSpaceMemory) {
130         ALOGE("%s no address space memory", __func__);
131         return;
132     }
133     DDD("flush: use handle to host %lld", mHostHandle);
134     auto transport = GoldfishMediaTransport::getInstance();
135     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
136     transport->sendOperation(MediaCodecType::H264Codec,
137                              MediaOperation::Flush, mAddressOffSet);
138 }
139 
getImage()140 h264_image_t MediaH264Decoder::getImage() {
141     DDD("getImage: use handle to host %lld", mHostHandle);
142     h264_image_t res { };
143     if (!mHasAddressSpaceMemory) {
144         ALOGE("%s no address space memory", __func__);
145         return res;
146     }
147     auto transport = GoldfishMediaTransport::getInstance();
148     uint8_t* dst = transport->getInputAddr(mAddressOffSet); // Note: reuse the same addr for input and output
149     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
150     transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet, 1, mAddressOffSet);
151     transport->writeParam(-1, 2, mAddressOffSet);
152     transport->sendOperation(MediaCodecType::H264Codec,
153                              MediaOperation::GetImage, mAddressOffSet);
154     auto* retptr = transport->getReturnAddr(mAddressOffSet);
155     res.ret = *(int*)(retptr);
156     if (res.ret >= 0) {
157         res.data = dst;
158         res.width = *(uint32_t*)(retptr + 8);
159         res.height = *(uint32_t*)(retptr + 16);
160         res.pts = *(uint32_t*)(retptr + 24);
161         res.color_primaries = *(uint32_t*)(retptr + 32);
162         res.color_range = *(uint32_t*)(retptr + 40);
163         res.color_trc = *(uint32_t*)(retptr + 48);
164         res.colorspace = *(uint32_t*)(retptr + 56);
165     } else if (res.ret == (int)(Err::DecoderRestarted)) {
166         res.width = *(uint32_t*)(retptr + 8);
167         res.height = *(uint32_t*)(retptr + 16);
168     }
169     return res;
170 }
171 
172 
renderOnHostAndReturnImageMetadata(int hostColorBufferId)173 h264_image_t MediaH264Decoder::renderOnHostAndReturnImageMetadata(int hostColorBufferId) {
174     DDD("%s: use handle to host %lld", __func__, mHostHandle);
175     h264_image_t res { };
176     if (hostColorBufferId < 0) {
177       ALOGE("%s negative color buffer id %d", __func__, hostColorBufferId);
178       return res;
179     }
180     DDD("%s send color buffer id %d", __func__, hostColorBufferId);
181     if (!mHasAddressSpaceMemory) {
182         ALOGE("%s no address space memory", __func__);
183         return res;
184     }
185     auto transport = GoldfishMediaTransport::getInstance();
186     uint8_t* dst = transport->getInputAddr(mAddressOffSet); // Note: reuse the same addr for input and output
187     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
188     transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet, 1, mAddressOffSet);
189     transport->writeParam((uint64_t)hostColorBufferId, 2, mAddressOffSet);
190     transport->sendOperation(MediaCodecType::H264Codec,
191                              MediaOperation::GetImage, mAddressOffSet);
192     auto* retptr = transport->getReturnAddr(mAddressOffSet);
193     res.ret = *(int*)(retptr);
194     if (res.ret >= 0) {
195         res.data = dst; // note: the data could be junk
196         res.width = *(uint32_t*)(retptr + 8);
197         res.height = *(uint32_t*)(retptr + 16);
198         res.pts = *(uint32_t*)(retptr + 24);
199         res.color_primaries = *(uint32_t*)(retptr + 32);
200         res.color_range = *(uint32_t*)(retptr + 40);
201         res.color_trc = *(uint32_t*)(retptr + 48);
202         res.colorspace = *(uint32_t*)(retptr + 56);
203     } else if (res.ret == (int)(Err::DecoderRestarted)) {
204         res.width = *(uint32_t*)(retptr + 8);
205         res.height = *(uint32_t*)(retptr + 16);
206     }
207     return res;
208 }
209