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 %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
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 %x", (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 %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)) -
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
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, MediaOperation::Flush,
138 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(
150 mAddressOffSet); // Note: reuse the same addr for input and output
151 transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
152 transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet,
153 1, mAddressOffSet);
154 transport->writeParam(-1, 2, mAddressOffSet);
155 transport->sendOperation(MediaCodecType::H264Codec,
156 MediaOperation::GetImage, mAddressOffSet);
157 auto *retptr = transport->getReturnAddr(mAddressOffSet);
158 res.ret = *(int *)(retptr);
159 if (res.ret >= 0) {
160 res.data = dst;
161 res.width = *(uint32_t *)(retptr + 8);
162 res.height = *(uint32_t *)(retptr + 16);
163 res.pts = *(uint64_t *)(retptr + 24);
164 res.color_primaries = *(uint32_t *)(retptr + 32);
165 res.color_range = *(uint32_t *)(retptr + 40);
166 res.color_trc = *(uint32_t *)(retptr + 48);
167 res.colorspace = *(uint32_t *)(retptr + 56);
168 } else if (res.ret == (int)(Err::DecoderRestarted)) {
169 res.width = *(uint32_t *)(retptr + 8);
170 res.height = *(uint32_t *)(retptr + 16);
171 }
172 return res;
173 }
174
175 h264_image_t
renderOnHostAndReturnImageMetadata(int hostColorBufferId)176 MediaH264Decoder::renderOnHostAndReturnImageMetadata(int hostColorBufferId) {
177 DDD("%s: use handle to host %lld", __func__, mHostHandle);
178 h264_image_t res{};
179 if (hostColorBufferId < 0) {
180 ALOGE("%s negative color buffer id %d", __func__, hostColorBufferId);
181 return res;
182 }
183 DDD("%s send color buffer id %d", __func__, hostColorBufferId);
184 if (!mHasAddressSpaceMemory) {
185 ALOGE("%s no address space memory", __func__);
186 return res;
187 }
188 auto transport = GoldfishMediaTransport::getInstance();
189 uint8_t *dst = transport->getInputAddr(
190 mAddressOffSet); // Note: reuse the same addr for input and output
191 transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
192 transport->writeParam(transport->offsetOf((uint64_t)(dst)) - mAddressOffSet,
193 1, mAddressOffSet);
194 transport->writeParam((uint64_t)hostColorBufferId, 2, mAddressOffSet);
195 transport->sendOperation(MediaCodecType::H264Codec,
196 MediaOperation::GetImage, mAddressOffSet);
197 auto *retptr = transport->getReturnAddr(mAddressOffSet);
198 res.ret = *(int *)(retptr);
199 if (res.ret >= 0) {
200 res.data = dst; // note: the data could be junk
201 res.width = *(uint32_t *)(retptr + 8);
202 res.height = *(uint32_t *)(retptr + 16);
203 res.pts = *(uint64_t *)(retptr + 24);
204 res.color_primaries = *(uint32_t *)(retptr + 32);
205 res.color_range = *(uint32_t *)(retptr + 40);
206 res.color_trc = *(uint32_t *)(retptr + 48);
207 res.colorspace = *(uint32_t *)(retptr + 56);
208 } else if (res.ret == (int)(Err::DecoderRestarted)) {
209 res.width = *(uint32_t *)(retptr + 8);
210 res.height = *(uint32_t *)(retptr + 16);
211 }
212 return res;
213 }
214