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 #include "MediaH264Decoder.h"
20 #include "goldfish_media_utils.h"
21 #include <string.h>
22 
MediaH264Decoder(RenderMode renderMode)23 MediaH264Decoder::MediaH264Decoder(RenderMode renderMode) :mRenderMode(renderMode) {
24   if (renderMode == RenderMode::RENDER_BY_HOST_GPU) {
25       mVersion = 200;
26   } else if (renderMode == RenderMode::RENDER_BY_GUEST_CPU) {
27       mVersion = 100;
28   }
29 }
30 
initH264Context(unsigned int width,unsigned int height,unsigned int outWidth,unsigned int outHeight,PixelFormat pixFmt)31 void MediaH264Decoder::initH264Context(unsigned int width,
32                                        unsigned int height,
33                                        unsigned int outWidth,
34                                        unsigned int outHeight,
35                                        PixelFormat pixFmt) {
36     auto transport = GoldfishMediaTransport::getInstance();
37     if (!mHasAddressSpaceMemory) {
38         int slot = transport->getMemorySlot();
39         if (slot < 0) {
40             ALOGE("ERROR: Failed to initH264Context: cannot get memory slot");
41             return;
42         }
43         mAddressOffSet = static_cast<unsigned int>(slot) * 8 * (1 << 20);
44         ALOGD("got memory lot %d addrr %x", slot, mAddressOffSet);
45         mHasAddressSpaceMemory = true;
46     }
47     transport->writeParam(mVersion, 0, mAddressOffSet);
48     transport->writeParam(width, 1, mAddressOffSet);
49     transport->writeParam(height, 2, mAddressOffSet);
50     transport->writeParam(outWidth, 3, mAddressOffSet);
51     transport->writeParam(outHeight, 4, mAddressOffSet);
52     transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
53     transport->sendOperation(MediaCodecType::H264Codec,
54                              MediaOperation::InitContext, mAddressOffSet);
55     auto* retptr = transport->getReturnAddr(mAddressOffSet);
56     mHostHandle = *(uint64_t*)(retptr);
57     ALOGD("initH264Context: got handle to host %lld", mHostHandle);
58 }
59 
60 
resetH264Context(unsigned int width,unsigned int height,unsigned int outWidth,unsigned int outHeight,PixelFormat pixFmt)61 void MediaH264Decoder::resetH264Context(unsigned int width,
62                                        unsigned int height,
63                                        unsigned int outWidth,
64                                        unsigned int outHeight,
65                                        PixelFormat pixFmt) {
66     auto transport = GoldfishMediaTransport::getInstance();
67     if (!mHasAddressSpaceMemory) {
68         ALOGE("%s no address space memory", __func__);
69         return;
70     }
71     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
72     transport->writeParam(width, 1, mAddressOffSet);
73     transport->writeParam(height, 2, mAddressOffSet);
74     transport->writeParam(outWidth, 3, mAddressOffSet);
75     transport->writeParam(outHeight, 4, mAddressOffSet);
76     transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
77     transport->sendOperation(MediaCodecType::H264Codec,
78                              MediaOperation::Reset, mAddressOffSet);
79     ALOGD("resetH264Context: done");
80 }
81 
82 
destroyH264Context()83 void MediaH264Decoder::destroyH264Context() {
84 
85     ALOGD("return memory lot %d addrr %x", (int)(mAddressOffSet >> 23), mAddressOffSet);
86     auto transport = GoldfishMediaTransport::getInstance();
87     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
88     transport->sendOperation(MediaCodecType::H264Codec,
89                              MediaOperation::DestroyContext, mAddressOffSet);
90     transport->returnMemorySlot(mAddressOffSet >> 23);
91     mHasAddressSpaceMemory = false;
92 }
93 
decodeFrame(uint8_t * img,size_t szBytes,uint64_t pts)94 h264_result_t MediaH264Decoder::decodeFrame(uint8_t* img, size_t szBytes, uint64_t pts) {
95     ALOGD("decode frame: use handle to host %lld", mHostHandle);
96     h264_result_t res = {0, 0};
97     if (!mHasAddressSpaceMemory) {
98         ALOGE("%s no address space memory", __func__);
99         return res;
100     }
101     auto transport = GoldfishMediaTransport::getInstance();
102     uint8_t* hostSrc = transport->getInputAddr(mAddressOffSet);
103     if (img != nullptr && szBytes > 0) {
104         memcpy(hostSrc, img, szBytes);
105     }
106     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
107     transport->writeParam(transport->offsetOf((uint64_t)(hostSrc)) - mAddressOffSet, 1, mAddressOffSet);
108     transport->writeParam((uint64_t)szBytes, 2, mAddressOffSet);
109     transport->writeParam((uint64_t)pts, 3, mAddressOffSet);
110     transport->sendOperation(MediaCodecType::H264Codec,
111                              MediaOperation::DecodeImage, mAddressOffSet);
112 
113 
114     auto* retptr = transport->getReturnAddr(mAddressOffSet);
115     res.bytesProcessed = *(uint64_t*)(retptr);
116     res.ret = *(int*)(retptr + 8);
117 
118     return res;
119 }
120 
flush()121 void MediaH264Decoder::flush() {
122     if (!mHasAddressSpaceMemory) {
123         ALOGE("%s no address space memory", __func__);
124         return;
125     }
126     ALOGD("flush: use handle to host %lld", mHostHandle);
127     auto transport = GoldfishMediaTransport::getInstance();
128     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
129     transport->sendOperation(MediaCodecType::H264Codec,
130                              MediaOperation::Flush, mAddressOffSet);
131 }
132 
getImage()133 h264_image_t MediaH264Decoder::getImage() {
134     ALOGD("getImage: use handle to host %lld", mHostHandle);
135     h264_image_t res { };
136     if (!mHasAddressSpaceMemory) {
137         ALOGE("%s no address space memory", __func__);
138         return res;
139     }
140     auto transport = GoldfishMediaTransport::getInstance();
141     uint8_t* dst = transport->getInputAddr(mAddressOffSet); // Note: reuse the same addr for input and output
142     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
143     transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet, 1, mAddressOffSet);
144     transport->writeParam(-1, 2, mAddressOffSet);
145     transport->sendOperation(MediaCodecType::H264Codec,
146                              MediaOperation::GetImage, mAddressOffSet);
147     auto* retptr = transport->getReturnAddr(mAddressOffSet);
148     res.ret = *(int*)(retptr);
149     if (res.ret >= 0) {
150         res.data = dst;
151         res.width = *(uint32_t*)(retptr + 8);
152         res.height = *(uint32_t*)(retptr + 16);
153         res.pts = *(uint32_t*)(retptr + 24);
154         res.color_primaries = *(uint32_t*)(retptr + 32);
155         res.color_range = *(uint32_t*)(retptr + 40);
156         res.color_trc = *(uint32_t*)(retptr + 48);
157         res.colorspace = *(uint32_t*)(retptr + 56);
158     } else if (res.ret == (int)(Err::DecoderRestarted)) {
159         res.width = *(uint32_t*)(retptr + 8);
160         res.height = *(uint32_t*)(retptr + 16);
161     }
162     return res;
163 }
164 
165 
renderOnHostAndReturnImageMetadata(int hostColorBufferId)166 h264_image_t MediaH264Decoder::renderOnHostAndReturnImageMetadata(int hostColorBufferId) {
167     ALOGD("%s: use handle to host %lld", __func__, mHostHandle);
168     h264_image_t res { };
169     if (hostColorBufferId < 0) {
170       ALOGE("%s negative color buffer id %d", __func__, hostColorBufferId);
171       return res;
172     }
173     ALOGD("%s send color buffer id %d", __func__, hostColorBufferId);
174     if (!mHasAddressSpaceMemory) {
175         ALOGE("%s no address space memory", __func__);
176         return res;
177     }
178     auto transport = GoldfishMediaTransport::getInstance();
179     uint8_t* dst = transport->getInputAddr(mAddressOffSet); // Note: reuse the same addr for input and output
180     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
181     transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet, 1, mAddressOffSet);
182     transport->writeParam((uint64_t)hostColorBufferId, 2, mAddressOffSet);
183     transport->sendOperation(MediaCodecType::H264Codec,
184                              MediaOperation::GetImage, mAddressOffSet);
185     auto* retptr = transport->getReturnAddr(mAddressOffSet);
186     res.ret = *(int*)(retptr);
187     if (res.ret >= 0) {
188         res.data = dst; // note: the data could be junk
189         res.width = *(uint32_t*)(retptr + 8);
190         res.height = *(uint32_t*)(retptr + 16);
191         res.pts = *(uint32_t*)(retptr + 24);
192         res.color_primaries = *(uint32_t*)(retptr + 32);
193         res.color_range = *(uint32_t*)(retptr + 40);
194         res.color_trc = *(uint32_t*)(retptr + 48);
195         res.colorspace = *(uint32_t*)(retptr + 56);
196     } else if (res.ret == (int)(Err::DecoderRestarted)) {
197         res.width = *(uint32_t*)(retptr + 8);
198         res.height = *(uint32_t*)(retptr + 16);
199     }
200     return res;
201 }
202