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         mSlot = slot;
51         mAddressOffSet = static_cast<unsigned int>(mSlot) * (1 << 20);
52         DDD("got memory lot %d addrr %x", 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 %lld", mHostHandle);
66 }
67 
68 
resetH264Context(unsigned int width,unsigned int height,unsigned int outWidth,unsigned int outHeight,PixelFormat pixFmt)69 void MediaH264Decoder::resetH264Context(unsigned int width,
70                                        unsigned int height,
71                                        unsigned int outWidth,
72                                        unsigned int outHeight,
73                                        PixelFormat pixFmt) {
74     auto transport = GoldfishMediaTransport::getInstance();
75     if (!mHasAddressSpaceMemory) {
76         ALOGE("%s no address space memory", __func__);
77         return;
78     }
79     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
80     transport->writeParam(width, 1, mAddressOffSet);
81     transport->writeParam(height, 2, mAddressOffSet);
82     transport->writeParam(outWidth, 3, mAddressOffSet);
83     transport->writeParam(outHeight, 4, mAddressOffSet);
84     transport->writeParam(static_cast<uint64_t>(pixFmt), 5, mAddressOffSet);
85     transport->sendOperation(MediaCodecType::H264Codec,
86                              MediaOperation::Reset, mAddressOffSet);
87     DDD("resetH264Context: done");
88 }
89 
90 
destroyH264Context()91 void MediaH264Decoder::destroyH264Context() {
92 
93     DDD("return memory lot %d addrr %x", (int)(mAddressOffSet >> 23), mAddressOffSet);
94     auto transport = GoldfishMediaTransport::getInstance();
95     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
96     transport->sendOperation(MediaCodecType::H264Codec,
97                              MediaOperation::DestroyContext, mAddressOffSet);
98     transport->returnMemorySlot(mSlot);
99     mHasAddressSpaceMemory = false;
100 }
101 
decodeFrame(uint8_t * img,size_t szBytes,uint64_t pts)102 h264_result_t MediaH264Decoder::decodeFrame(uint8_t* img, size_t szBytes, uint64_t pts) {
103     DDD("decode frame: use handle to host %lld", mHostHandle);
104     h264_result_t res = {0, 0};
105     if (!mHasAddressSpaceMemory) {
106         ALOGE("%s no address space memory", __func__);
107         return res;
108     }
109     auto transport = GoldfishMediaTransport::getInstance();
110     uint8_t* hostSrc = transport->getInputAddr(mAddressOffSet);
111     if (img != nullptr && szBytes > 0) {
112         memcpy(hostSrc, img, szBytes);
113     }
114     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
115     transport->writeParam(transport->offsetOf((uint64_t)(hostSrc)) - mAddressOffSet, 1, mAddressOffSet);
116     transport->writeParam((uint64_t)szBytes, 2, mAddressOffSet);
117     transport->writeParam((uint64_t)pts, 3, mAddressOffSet);
118     transport->sendOperation(MediaCodecType::H264Codec,
119                              MediaOperation::DecodeImage, mAddressOffSet);
120 
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 
flush()129 void MediaH264Decoder::flush() {
130     if (!mHasAddressSpaceMemory) {
131         ALOGE("%s no address space memory", __func__);
132         return;
133     }
134     DDD("flush: use handle to host %lld", mHostHandle);
135     auto transport = GoldfishMediaTransport::getInstance();
136     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
137     transport->sendOperation(MediaCodecType::H264Codec,
138                              MediaOperation::Flush, mAddressOffSet);
139 }
140 
getImage()141 h264_image_t MediaH264Decoder::getImage() {
142     DDD("getImage: use handle to host %lld", mHostHandle);
143     h264_image_t res { };
144     if (!mHasAddressSpaceMemory) {
145         ALOGE("%s no address space memory", __func__);
146         return res;
147     }
148     auto transport = GoldfishMediaTransport::getInstance();
149     uint8_t* dst = transport->getInputAddr(mAddressOffSet); // Note: reuse the same addr for input and output
150     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
151     transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet, 1, mAddressOffSet);
152     transport->writeParam(-1, 2, mAddressOffSet);
153     transport->sendOperation(MediaCodecType::H264Codec,
154                              MediaOperation::GetImage, mAddressOffSet);
155     auto* retptr = transport->getReturnAddr(mAddressOffSet);
156     res.ret = *(int*)(retptr);
157     if (res.ret >= 0) {
158         res.data = dst;
159         res.width = *(uint32_t*)(retptr + 8);
160         res.height = *(uint32_t*)(retptr + 16);
161         res.pts = *(uint64_t*)(retptr + 24);
162         res.color_primaries = *(uint32_t*)(retptr + 32);
163         res.color_range = *(uint32_t*)(retptr + 40);
164         res.color_trc = *(uint32_t*)(retptr + 48);
165         res.colorspace = *(uint32_t*)(retptr + 56);
166     } else if (res.ret == (int)(Err::DecoderRestarted)) {
167         res.width = *(uint32_t*)(retptr + 8);
168         res.height = *(uint32_t*)(retptr + 16);
169     }
170     return res;
171 }
172 
173 
renderOnHostAndReturnImageMetadata(int hostColorBufferId)174 h264_image_t MediaH264Decoder::renderOnHostAndReturnImageMetadata(int hostColorBufferId) {
175     DDD("%s: use handle to host %lld", __func__, mHostHandle);
176     h264_image_t res { };
177     if (hostColorBufferId < 0) {
178       ALOGE("%s negative color buffer id %d", __func__, hostColorBufferId);
179       return res;
180     }
181     DDD("%s send color buffer id %d", __func__, hostColorBufferId);
182     if (!mHasAddressSpaceMemory) {
183         ALOGE("%s no address space memory", __func__);
184         return res;
185     }
186     auto transport = GoldfishMediaTransport::getInstance();
187     uint8_t* dst = transport->getInputAddr(mAddressOffSet); // Note: reuse the same addr for input and output
188     transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
189     transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet, 1, mAddressOffSet);
190     transport->writeParam((uint64_t)hostColorBufferId, 2, mAddressOffSet);
191     transport->sendOperation(MediaCodecType::H264Codec,
192                              MediaOperation::GetImage, mAddressOffSet);
193     auto* retptr = transport->getReturnAddr(mAddressOffSet);
194     res.ret = *(int*)(retptr);
195     if (res.ret >= 0) {
196         res.data = dst; // note: the data could be junk
197         res.width = *(uint32_t*)(retptr + 8);
198         res.height = *(uint32_t*)(retptr + 16);
199         res.pts = *(uint64_t*)(retptr + 24);
200         res.color_primaries = *(uint32_t*)(retptr + 32);
201         res.color_range = *(uint32_t*)(retptr + 40);
202         res.color_trc = *(uint32_t*)(retptr + 48);
203         res.colorspace = *(uint32_t*)(retptr + 56);
204     } else if (res.ret == (int)(Err::DecoderRestarted)) {
205         res.width = *(uint32_t*)(retptr + 8);
206         res.height = *(uint32_t*)(retptr + 16);
207     }
208     return res;
209 }
210