1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong DID Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "codec_jpeg_decoder.h"
16 #include <display_type.h>
17 #include <hdf_base.h>
18 #include <securec.h>
19 #include <thread>
20 #include <unistd.h>
21 #include "codec_jpeg_helper.h"
22 #include "codec_log_wrapper.h"
23 #include "codec_scope_guard.h"
24 #ifdef DUMP_FILE
25 #include <fstream>
26 #endif
27 namespace OHOS {
28 namespace VDI {
29 namespace JPEG {
CodecJpegDecoder(RKMppApi *mppApi)30 CodecJpegDecoder::CodecJpegDecoder(RKMppApi *mppApi)
31 : width_(0), height_(0), format_(MPP_FMT_YUV420SP), mppCtx_(nullptr), mpi_(nullptr), mppApi_(mppApi),
32 memGroup_(nullptr), packet_(nullptr), frame_(nullptr)
33 {}
34
~CodecJpegDecoder()35 CodecJpegDecoder::~CodecJpegDecoder()
36 {
37 CODEC_LOGI("enter");
38 width_ = 0;
39 height_ = 0;
40 Destory();
41 format_ = MPP_FMT_YUV420SP;
42 }
43
Destory()44 void CodecJpegDecoder::Destory()
45 {
46 ResetMppBuffer();
47 if (memGroup_) {
48 mppApi_->HdiMppBufferGroupPut(memGroup_);
49 memGroup_ = nullptr;
50 }
51 if (mppCtx_) {
52 mppApi_->HdiMppDestroy(mppCtx_);
53 mppCtx_ = nullptr;
54 }
55 mpi_ = nullptr;
56 mppApi_ = nullptr;
57 }
58
DeCode(BufferHandle *buffer, BufferHandle *outBuffer, const struct CodecJpegDecInfo &decInfo)59 int32_t CodecJpegDecoder::DeCode(BufferHandle *buffer, BufferHandle *outBuffer, const struct CodecJpegDecInfo &decInfo)
60 {
61 CODEC_LOGI("enter");
62
63 if (!PrePare()) {
64 CODEC_LOGE("PrePare failed");
65 return HDF_FAILURE;
66 }
67 if (!SetFormat(outBuffer->format)) {
68 CODEC_LOGE("format %{public}d set error", outBuffer->format);
69 return HDF_ERR_INVALID_PARAM;
70 }
71
72 width_ = decInfo.imageWidth;
73 height_ = decInfo.imageHeight;
74 if (SendData(decInfo, buffer, outBuffer) != MPP_OK) {
75 CODEC_LOGE("Send data error");
76 return HDF_FAILURE;
77 }
78
79 if (GetFrame() != MPP_OK) {
80 CODEC_LOGE("Recv frame error");
81 return HDF_FAILURE;
82 }
83 DumpOutFile();
84 CODEC_LOGI("jpeg decode end.");
85 return HDF_SUCCESS;
86 }
87
SendData(const struct CodecJpegDecInfo &decInfo, BufferHandle* buffer, BufferHandle *outHandle)88 MPP_RET CodecJpegDecoder::SendData(const struct CodecJpegDecInfo &decInfo, BufferHandle* buffer, BufferHandle *outHandle)
89 {
90 CODEC_LOGI("enter");
91 MppBuffer pktBuf = nullptr;
92 MppBuffer frmBuf = nullptr;
93 OHOS::CodecScopeGuard scope([&] {
94 if (pktBuf) {
95 mppApi_->HdiMppBufferPutWithCaller(pktBuf, __func__);
96 pktBuf = nullptr;
97 }
98 if (frmBuf) {
99 mppApi_->HdiMppBufferPutWithCaller(frmBuf, __func__);
100 frmBuf = nullptr;
101 }
102 });
103 ResetMppBuffer();
104 MppBufferInfo info;
105 memset(&info, 0, sizeof(MppBufferInfo));
106 info.type = MPP_BUFFER_TYPE_DRM;
107 info.fd = buffer->fd;
108 info.size = buffer->size;
109 auto ret = mppApi_->HdiMppBufferImportWithTag(nullptr, &info, &pktBuf, MODULE_TAG, __func__);
110 if (ret != MPP_OK) {
111 CODEC_LOGE("import input packet error %{public}d", ret);
112 return ret;
113 }
114 mppApi_->HdiMppPacketInitWithBuffer(&packet_, pktBuf); // input
115
116 DumpInFile(pktBuf);
117 // init frame_
118 mppApi_->HdiMppFrameInit(&frame_);
119 #ifndef USE_RGA
120 MppBufferInfo outputCommit;
121 memset_s(&outputCommit, sizeof(outputCommit), 0, sizeof(outputCommit));
122 outputCommit.type = MPP_BUFFER_TYPE_DRM;
123 outputCommit.size = outHandle->size;
124 outputCommit.fd = outHandle->fd;
125 ret = mppApi_->HdiMppBufferImportWithTag(nullptr, &outputCommit, &frmBuf, MODULE_TAG, __func__);
126 #else
127 ret = mppApi_->HdiMppBufferGetWithTag(memGroup_, &frmBuf, horStride * verStride * 2, // 2: max len = 2*width*height
128 MODULE_TAG, __func__);
129 #endif
130 if (ret != MPP_OK) {
131 CODEC_LOGE(" mpp buffer import/get error %{public}d", ret);
132 return ret;
133 }
134 mppApi_->HdiMppFrameSetBuffer(frame_, frmBuf);
135 ret = MppTaskProcess();
136 return ret;
137 }
138
MppTaskProcess()139 MPP_RET CodecJpegDecoder::MppTaskProcess()
140 {
141 MppTask task = nullptr;
142 /* start queue input task */
143 auto ret = mpi_->poll(mppCtx_, MPP_PORT_INPUT, MPP_POLL_BLOCK);
144 if (MPP_OK != ret) {
145 CODEC_LOGE("poll input error %{public}d", ret);
146 return ret;
147 }
148 /* input queue */
149 ret = mpi_->dequeue(mppCtx_, MPP_PORT_INPUT, &task);
150 if (MPP_OK != ret) {
151 CODEC_LOGE("dequeue input error %{public}d", ret);
152 return ret;
153 }
154 mppApi_->HdiMppTaskMetaSetPacket(task, KEY_INPUT_PACKET, packet_);
155 mppApi_->HdiMppTaskMetaSetFrame(task, KEY_OUTPUT_FRAME, frame_);
156 /* input queue */
157 ret = mpi_->enqueue(mppCtx_, MPP_PORT_INPUT, task);
158 if (ret != MPP_OK) {
159 CODEC_LOGE("enqueue input error %{public}d", ret);
160 }
161 return ret;
162 }
GetFrame()163 MPP_RET CodecJpegDecoder::GetFrame()
164 {
165 CODEC_LOGI("enter.");
166 MppTask task = nullptr;
167 /* poll and wait here */
168 MPP_RET ret = mpi_->poll(mppCtx_, MPP_PORT_OUTPUT, MPP_POLL_BLOCK);
169 if (ret != MPP_OK) {
170 CODEC_LOGE("poll output error %{public}d", ret);
171 return ret;
172 }
173
174 /* output queue */
175 ret = mpi_->dequeue(mppCtx_, MPP_PORT_OUTPUT, &task);
176 if (ret != MPP_OK) {
177 CODEC_LOGE("dequeue output error %{public}d", ret);
178 return ret;
179 }
180
181 MppFrame frameOut = NULL;
182 mppApi_->HdiMppTaskMetaGetFrame(task, KEY_OUTPUT_FRAME, &frameOut);
183 if (frameOut != frame_) {
184 CODEC_LOGE("frameOut is not match with frame_ %{public}d", ret);
185 mppApi_->HdiMppFrameDeinit(&frameOut);
186 return MPP_NOK;
187 }
188 auto err = mppApi_->HdiMppFrameGetErrinfo(frameOut) | mppApi_->HdiMppFrameGetDiscard(frameOut);
189 if (err) {
190 CODEC_LOGE("err = %{public}d", err);
191 return MPP_NOK;
192 }
193
194 /* output queue */
195 ret = mpi_->enqueue(mppCtx_, MPP_PORT_OUTPUT, task);
196 if (ret != MPP_OK) {
197 CODEC_LOGE("enqueue output error %{public}d", ret);
198 return ret;
199 }
200
201 return MPP_OK;
202 }
203
DumpOutFile()204 void CodecJpegDecoder::DumpOutFile()
205 {
206 #ifdef DUMP_FILE
207 MppBuffer buf = mppApi_->HdiMppFrameGetBuffer(frame_);
208 auto size = mppApi_->HdiMppBufferGetSizeWithCaller(buf, __func__);
209 auto ptr = mppApi_->HdiMppBufferGetPtrWithCaller(buf, __func__);
210 std::ofstream out("/data/out.raw", std::ios::trunc | std::ios::binary);
211 if (!out.is_open()) {
212 CODEC_LOGE("file open error");
213 return;
214 }
215 out.write(reinterpret_cast<char *>(ptr), size);
216 out.flush();
217 #endif
218 }
DumpInFile(MppBuffer pktBuf)219 void CodecJpegDecoder::DumpInFile(MppBuffer pktBuf)
220 {
221 #ifdef DUMP_FILE
222 auto size = mppApi_->HdiMppBufferGetSizeWithCaller(pktBuf, __func__);
223 auto data = mppApi_->HdiMppBufferGetPtrWithCaller(pktBuf, __func__);
224 CODEC_LOGD("size %{public}d", size);
225 if (data == nullptr || size == 0) {
226 CODEC_LOGE("have no data in pktbuf");
227 return;
228 }
229
230 std::ofstream out("/data/in.raw", std::ios::trunc | std::ios::binary);
231 if (!out.is_open()) {
232 CODEC_LOGE("file open error");
233 return;
234 }
235 out.write(reinterpret_cast<char*>(data), size);
236 out.flush();
237 #endif
238 }
SetFormat(int32_t format)239 bool CodecJpegDecoder::SetFormat(int32_t format)
240 {
241 bool ret = true;
242 switch (format) {
243 case PIXEL_FMT_YCBCR_420_SP:
244 format_ = MPP_FMT_YUV420SP;
245 break;
246 case PIXEL_FMT_YCRCB_420_SP:
247 format_ = MPP_FMT_YUV420SP_VU;
248 break;
249 case PIXEL_FMT_BGR_565:
250 format_ = MPP_FMT_BGR565;
251 break;
252 case PIXEL_FMT_RGB_888:
253 format_ = MPP_FMT_RGB888;
254 break;
255 default:
256 CODEC_LOGE("unsupport pixformat %{public}d", format);
257 ret = false;
258 break;
259 }
260 if (ret) {
261 auto err = mpi_->control(mppCtx_, MPP_DEC_SET_OUTPUT_FORMAT, &format_);
262 if (err != MPP_OK) {
263 CODEC_LOGE("set output fromat error %{public}d", err);
264 return false;
265 }
266 }
267 return ret;
268 }
ResetMppBuffer()269 void CodecJpegDecoder::ResetMppBuffer()
270 {
271 if (memGroup_) {
272 mppApi_->HdiMppBufferGroupClear(memGroup_);
273 }
274 if (packet_ != nullptr) {
275 mppApi_->HdiMppPacketDeinit(&packet_);
276 packet_ = nullptr;
277 }
278 if (frame_ != nullptr) {
279 mppApi_->HdiMppFrameDeinit(&frame_);
280 frame_ = nullptr;
281 }
282 }
283
PrePare(bool isDecoder)284 bool CodecJpegDecoder::PrePare(bool isDecoder)
285 {
286 MPP_RET ret = mppApi_->HdiMppCreate(&mppCtx_, &mpi_);
287 if (ret != MPP_OK) {
288 CODEC_LOGE("HdiMppCreate error %{public}d", ret);
289 return false;
290 }
291 ret = mppApi_->HdiMppInit(mppCtx_, isDecoder ? MPP_CTX_DEC : MPP_CTX_ENC, MPP_VIDEO_CodingMJPEG);
292 if (ret != MPP_OK) {
293 CODEC_LOGE("HdiMppInit error %{public}d", ret);
294 return false;
295 }
296 MppPollType timeout = MPP_POLL_BLOCK;
297 ret = mpi_->control(mppCtx_, MPP_SET_OUTPUT_TIMEOUT, &timeout);
298 if (ret != MPP_OK) {
299 CODEC_LOGE("set output timeout error %{public}d", ret);
300 return false;
301 }
302 ret = mpi_->control(mppCtx_, MPP_SET_INPUT_TIMEOUT, &timeout);
303 if (ret != MPP_OK) {
304 CODEC_LOGE("set input timeout error %{public}d", ret);
305 return false;
306 }
307 mppApi_->HdiMppBufferGroupGet(&memGroup_, MPP_BUFFER_TYPE_DRM, MPP_BUFFER_INTERNAL, nullptr, __func__);
308 mppApi_->HdiMppBufferGroupLimitConfig(memGroup_, 0, 24); // 24:buffer group limit
309 return true;
310 }
311 } // namespace JPEG
312 } // namespace VDI
313 } // namespace OHOS