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