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)
31     : mRenderMode(renderMode) {
32     if (renderMode == RenderMode::RENDER_BY_HOST_GPU) {
33         mVersion = 200;
34     } else if (renderMode == RenderMode::RENDER_BY_GUEST_CPU) {
35         mVersion = 100;
36     }
37 }
38 
initH264Context(unsigned int width,unsigned int height,unsigned int outWidth,unsigned int outHeight,PixelFormat pixFmt)39 void MediaH264Decoder::initH264Context(unsigned int width, 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         mSlot = slot;
51         mAddressOffSet = static_cast<unsigned int>(mSlot) * (1 << 20);
52         DDD("got memory lot %d addrr %lu", mSlot, mAddressOffSet);
53         mHasAddressSpaceMemory = true;
54     }
55     transport->writeParam(mVersion, 0, mAddressOffSet);
56     transport->writeParam(width, 1, mAddressOffSet);
57     transport->writeParam(height, 2, mAddressOffSet);
58     transport->writeParam(outWidth, 3, mAddressOffSet);
59     transport->writeParam(outHeight, 4, mAddressOffSet);
60     transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
61     transport->sendOperation(MediaCodecType::H264Codec,
62                              MediaOperation::InitContext, mAddressOffSet);
63     auto *retptr = transport->getReturnAddr(mAddressOffSet);
64     mHostHandle = *(uint64_t *)(retptr);
65     DDD("initH264Context: got handle to host %lu", mHostHandle);
66 }
67 
resetH264Context(unsigned int width,unsigned int height,unsigned int outWidth,unsigned int outHeight,PixelFormat pixFmt)68 void MediaH264Decoder::resetH264Context(unsigned int width, unsigned int height,
69                                         unsigned int outWidth,
70                                         unsigned int outHeight,
71                                         PixelFormat pixFmt) {
72     auto transport = GoldfishMediaTransport::getInstance();
73     if (!mHasAddressSpaceMemory) {
74         ALOGE("%s no address space memory", __func__);
75         return;
76     }
77     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
78     transport->writeParam(width, 1, mAddressOffSet);
79     transport->writeParam(height, 2, mAddressOffSet);
80     transport->writeParam(outWidth, 3, mAddressOffSet);
81     transport->writeParam(outHeight, 4, mAddressOffSet);
82     transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
83     transport->sendOperation(MediaCodecType::H264Codec, MediaOperation::Reset,
84                              mAddressOffSet);
85     DDD("resetH264Context: done");
86 }
87 
destroyH264Context()88 void MediaH264Decoder::destroyH264Context() {
89 
90     DDD("return memory lot %d addrr %lu", (int)(mAddressOffSet >> 23),
91         mAddressOffSet);
92     auto transport = GoldfishMediaTransport::getInstance();
93     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
94     transport->sendOperation(MediaCodecType::H264Codec,
95                              MediaOperation::DestroyContext, mAddressOffSet);
96     transport->returnMemorySlot(mSlot);
97     mHasAddressSpaceMemory = false;
98 }
99 
decodeFrame(uint8_t * img,size_t szBytes,uint64_t pts)100 h264_result_t MediaH264Decoder::decodeFrame(uint8_t *img, size_t szBytes,
101                                             uint64_t pts) {
102     DDD("decode frame: use handle to host %lu", 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)) -
115                               mAddressOffSet,
116                           1, mAddressOffSet);
117     transport->writeParam((uint64_t)szBytes, 2, mAddressOffSet);
118     transport->writeParam((uint64_t)pts, 3, mAddressOffSet);
119     transport->sendOperation(MediaCodecType::H264Codec,
120                              MediaOperation::DecodeImage, mAddressOffSet);
121 
122     auto *retptr = transport->getReturnAddr(mAddressOffSet);
123     res.bytesProcessed = *(uint64_t *)(retptr);
124     res.ret = *(int *)(retptr + 8);
125 
126     return res;
127 }
128 
sendMetadata(MetaDataColorAspects * ptr)129 void MediaH264Decoder::sendMetadata(MetaDataColorAspects *ptr) {
130     DDD("send metadata to host %p", ptr);
131     if (!mHasAddressSpaceMemory) {
132         ALOGE("%s no address space memory", __func__);
133         return;
134     }
135     MetaDataColorAspects& meta = *ptr;
136     auto transport = GoldfishMediaTransport::getInstance();
137     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
138     transport->writeParam(meta.type, 1, mAddressOffSet);
139     transport->writeParam(meta.primaries, 2, mAddressOffSet);
140     transport->writeParam(meta.range, 3, mAddressOffSet);
141     transport->writeParam(meta.transfer, 4, mAddressOffSet);
142     transport->sendOperation(MediaCodecType::H264Codec, MediaOperation::SendMetadata, mAddressOffSet);
143 }
144 
flush()145 void MediaH264Decoder::flush() {
146     if (!mHasAddressSpaceMemory) {
147         ALOGE("%s no address space memory", __func__);
148         return;
149     }
150     DDD("flush: use handle to host %lu", mHostHandle);
151     auto transport = GoldfishMediaTransport::getInstance();
152     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
153     transport->sendOperation(MediaCodecType::H264Codec, MediaOperation::Flush,
154                              mAddressOffSet);
155 }
156 
getImage()157 h264_image_t MediaH264Decoder::getImage() {
158     DDD("getImage: use handle to host %lu", mHostHandle);
159     h264_image_t res{};
160     if (!mHasAddressSpaceMemory) {
161         ALOGE("%s no address space memory", __func__);
162         return res;
163     }
164     auto transport = GoldfishMediaTransport::getInstance();
165     uint8_t *dst = transport->getInputAddr(
166         mAddressOffSet); // Note: reuse the same addr for input and output
167     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
168     transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet,
169                           1, mAddressOffSet);
170     transport->writeParam(-1, 2, mAddressOffSet);
171     transport->sendOperation(MediaCodecType::H264Codec,
172                              MediaOperation::GetImage, mAddressOffSet);
173     auto *retptr = transport->getReturnAddr(mAddressOffSet);
174     res.ret = *(int *)(retptr);
175     if (res.ret >= 0) {
176         res.data = dst;
177         res.width = *(uint32_t *)(retptr + 8);
178         res.height = *(uint32_t *)(retptr + 16);
179         res.pts = *(uint64_t *)(retptr + 24);
180         res.color_primaries = *(uint32_t *)(retptr + 32);
181         res.color_range = *(uint32_t *)(retptr + 40);
182         res.color_trc = *(uint32_t *)(retptr + 48);
183         res.colorspace = *(uint32_t *)(retptr + 56);
184     } else if (res.ret == (int)(Err::DecoderRestarted)) {
185         res.width = *(uint32_t *)(retptr + 8);
186         res.height = *(uint32_t *)(retptr + 16);
187     }
188     return res;
189 }
190 
191 h264_image_t
renderOnHostAndReturnImageMetadata(int hostColorBufferId)192 MediaH264Decoder::renderOnHostAndReturnImageMetadata(int hostColorBufferId) {
193     DDD("%s: use handle to host %lu", __func__, mHostHandle);
194     h264_image_t res{};
195     if (hostColorBufferId < 0) {
196         ALOGE("%s negative color buffer id %d", __func__, hostColorBufferId);
197         return res;
198     }
199     DDD("%s send color buffer id %d", __func__, hostColorBufferId);
200     if (!mHasAddressSpaceMemory) {
201         ALOGE("%s no address space memory", __func__);
202         return res;
203     }
204     auto transport = GoldfishMediaTransport::getInstance();
205     uint8_t *dst = transport->getInputAddr(
206         mAddressOffSet); // Note: reuse the same addr for input and output
207     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
208     transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet,
209                           1, mAddressOffSet);
210     transport->writeParam((uint64_t)hostColorBufferId, 2, mAddressOffSet);
211     transport->sendOperation(MediaCodecType::H264Codec,
212                              MediaOperation::GetImage, mAddressOffSet);
213     auto *retptr = transport->getReturnAddr(mAddressOffSet);
214     res.ret = *(int *)(retptr);
215     if (res.ret >= 0) {
216         res.data = dst; // note: the data could be junk
217         res.width = *(uint32_t *)(retptr + 8);
218         res.height = *(uint32_t *)(retptr + 16);
219         res.pts = *(uint64_t *)(retptr + 24);
220         res.color_primaries = *(uint32_t *)(retptr + 32);
221         res.color_range = *(uint32_t *)(retptr + 40);
222         res.color_trc = *(uint32_t *)(retptr + 48);
223         res.colorspace = *(uint32_t *)(retptr + 56);
224     } else if (res.ret == (int)(Err::DecoderRestarted)) {
225         res.width = *(uint32_t *)(retptr + 8);
226         res.height = *(uint32_t *)(retptr + 16);
227     }
228     return res;
229 }
230