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