• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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