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 <ashmem.h>
17 #include <display_type.h>
18 #include <hdf_base.h>
19 #include <securec.h>
20 #include <thread>
21 #include <unistd.h>
22 #include "codec_jpeg_helper.h"
23 #include "codec_log_wrapper.h"
24 #include "codec_scope_guard.h"
25 #ifdef DUMP_FILE
26 #include <fstream>
27 #endif
28 namespace OHOS {
29 namespace VDI {
30 namespace JPEG {
31 RKMppApi *CodecJpegDecoder::mppApi_ = nullptr;
CodecJpegDecoder()32 CodecJpegDecoder::CodecJpegDecoder()
33 : width_(0), height_(0), format_(MPP_FMT_YUV420SP), mppCtx_(nullptr), mpi_(nullptr), memGroup_(nullptr),
34 packet_(nullptr), frame_(nullptr), callback_(nullptr), running_(false), threadTask_(nullptr)
35 {}
36
~CodecJpegDecoder()37 CodecJpegDecoder::~CodecJpegDecoder()
38 {
39 CODEC_LOGI("enter");
40 width_ = 0;
41 height_ = 0;
42 running_.store(false);
43 // DeInit();// mpp_destroy in descontruct may crash
44 format_ = MPP_FMT_YUV420SP;
45 }
46
Init()47 int32_t CodecJpegDecoder::Init()
48 {
49 CODEC_LOGI("enter");
50
51 if (mppApi_ == nullptr && GetMppApi(&mppApi_) != HDF_SUCCESS) {
52 CODEC_LOGE("GetMppApi error");
53 return HDF_FAILURE;
54 }
55 return HDF_SUCCESS;
56 }
DeInit()57 void CodecJpegDecoder::DeInit()
58 {
59 CODEC_LOGI("enter");
60 if (threadTask_) {
61 threadTask_->join();
62 threadTask_ = nullptr;
63 }
64
65 if (mppApi_ != NULL) {
66 ResetMppBuffer();
67 if (memGroup_) {
68 mppApi_->HdiMppBufferGroupPut(memGroup_);
69 memGroup_ = nullptr;
70 }
71 if (mppCtx_) {
72 mppApi_->HdiMppDestroy(mppCtx_);
73 mppCtx_ = nullptr;
74 mpi_ = nullptr;
75 }
76 }
77 std::lock_guard<std::mutex> lk(mutex_);
78 callback_ = nullptr;
79 }
DeCode(BufferHandle * buffer,BufferHandle * outBuffer,const struct CodecJpegDecInfo & decInfo,CodecJpegCallbackHwi * callback)80 int32_t CodecJpegDecoder::DeCode(BufferHandle *buffer, BufferHandle *outBuffer, const struct CodecJpegDecInfo &decInfo,
81 CodecJpegCallbackHwi *callback)
82 {
83 CODEC_LOGI("enter");
84 if (running_.load()) {
85 CODEC_LOGE("task is running");
86 return HDF_ERR_DEVICE_BUSY;
87 }
88 if (threadTask_ != nullptr) {
89 threadTask_->join();
90 }
91
92 if (!PrePare()) {
93 CODEC_LOGE("PrePare failed");
94 return HDF_FAILURE;
95 }
96 if (!SetFormat(outBuffer->format)) {
97 CODEC_LOGE("format %{public}d set error", outBuffer->format);
98 return HDF_ERR_INVALID_PARAM;
99 }
100 callback_ = callback;
101 // thread start
102 threadTask_ = std::make_shared<std::thread>([&, buffer, outBuffer, decInfo] {
103 CODEC_LOGI("jpeg task decode run.");
104 running_.store(true);
105 width_ = decInfo.imageWidth;
106 height_ = decInfo.imageHeight;
107 if (SendData(decInfo, buffer->fd, outBuffer) != MPP_OK) {
108 CODEC_LOGE("Send data error");
109 running_.store(false);
110 OnEvent(HDF_FAILURE);
111 return;
112 }
113 if (GetFrame() != MPP_OK) {
114 CODEC_LOGE("Recv frame error");
115 running_.store(false);
116 OnEvent(HDF_FAILURE);
117 return;
118 }
119 DumpOutFile();
120 CODEC_LOGI("jpeg decode end.");
121 OnEvent(HDF_SUCCESS);
122 running_.store(false);
123 });
124 return HDF_SUCCESS;
125 }
126
SendData(const struct CodecJpegDecInfo & decInfo,int32_t fd,BufferHandle * outHandle)127 MPP_RET CodecJpegDecoder::SendData(const struct CodecJpegDecInfo &decInfo, int32_t fd, BufferHandle *outHandle)
128 {
129 CODEC_LOGI("enter");
130 MppBuffer pktBuf = nullptr;
131 MppBuffer frmBuf = nullptr;
132 OHOS::CodecScopeGuard scope([&] {
133 if (pktBuf) {
134 mppApi_->HdiMppBufferPutWithCaller(pktBuf, __func__);
135 pktBuf = nullptr;
136 }
137 if (frmBuf) {
138 mppApi_->HdiMppBufferPutWithCaller(frmBuf, __func__);
139 frmBuf = nullptr;
140 }
141 });
142 ResetMppBuffer();
143 auto ret = InitPacketBuffer(decInfo, fd, pktBuf);
144 if (ret != MPP_OK) {
145 CODEC_LOGE("InitPacketBuffer error %{public}d", ret);
146 return ret;
147 }
148 // init frame_
149 mppApi_->HdiMppFrameInit(&frame_);
150 #ifndef USE_RGA
151 MppBufferInfo inputCommit;
152 memset_s(&inputCommit, sizeof(inputCommit), 0, sizeof(inputCommit));
153 inputCommit.type = MPP_BUFFER_TYPE_DRM;
154 inputCommit.size = outHandle->size;
155 inputCommit.fd = outHandle->fd;
156 ret = mppApi_->HdiMppBufferImportWithTag(nullptr, &inputCommit, &frmBuf, MODULE_TAG, __func__);
157 #else
158 ret = mppApi_->HdiMppBufferGetWithTag(memGroup_, &frmBuf, horStride * verStride * 2, // 2: max len = 2*width*height
159 MODULE_TAG, __func__);
160 #endif
161 if (ret != MPP_OK) {
162 CODEC_LOGE(" mpp buffer import/get error %{public}d", ret);
163 return ret;
164 }
165 mppApi_->HdiMppFrameSetBuffer(frame_, frmBuf);
166 ret = MppTaskProcess();
167 return ret;
168 }
InitPacketBuffer(const struct CodecJpegDecInfo & decInfo,int32_t fd,MppBuffer & pktBuf)169 MPP_RET CodecJpegDecoder::InitPacketBuffer(const struct CodecJpegDecInfo &decInfo, int32_t fd, MppBuffer &pktBuf)
170 {
171 uint32_t horStride = AlignUp(width_, 16); // 16: width alignment
172 uint32_t verStride = AlignUp(height_, 16); // 16: height alignment
173 // get pkt
174 MPP_RET ret = mppApi_->HdiMppBufferGetWithTag(memGroup_, &pktBuf, horStride * verStride * 2, MODULE_TAG, __func__);
175 if (ret != MPP_OK) {
176 CODEC_LOGE(" mpp_buffer_get packet buffer error %{public}d", ret);
177 return ret;
178 }
179 mppApi_->HdiMppPacketInitWithBuffer(&packet_, pktBuf);
180 int8_t *bufAddr = reinterpret_cast<int8_t *>(mppApi_->HdiMppBufferGetPtrWithCaller(pktBuf, __func__));
181 if (bufAddr == nullptr) {
182 CODEC_LOGE(" mpp_buffer_get_ptr error");
183 return MPP_NOK;
184 }
185 CodecJpegHelper jpegHelper;
186 auto len = jpegHelper.JpegAssemble(decInfo, bufAddr, fd);
187 if (len < 0) {
188 CODEC_LOGE(" JpegAssemble error %{public}d", len);
189 return MPP_NOK;
190 }
191 DumpInFile(reinterpret_cast<char *>(bufAddr), len);
192 mppApi_->HdiMppPacketSetLength(packet_, len);
193 mppApi_->HdiMppPacketSetEos(packet_);
194 return MPP_OK;
195 }
196
MppTaskProcess()197 MPP_RET CodecJpegDecoder::MppTaskProcess()
198 {
199 MppTask task = nullptr;
200 /* start queue input task */
201 auto ret = mpi_->poll(mppCtx_, MPP_PORT_INPUT, MPP_POLL_BLOCK);
202 if (MPP_OK != ret) {
203 CODEC_LOGE("poll input error %{public}d", ret);
204 return ret;
205 }
206 /* input queue */
207 ret = mpi_->dequeue(mppCtx_, MPP_PORT_INPUT, &task);
208 if (MPP_OK != ret) {
209 CODEC_LOGE("dequeue input error %{public}d", ret);
210 return ret;
211 }
212 mppApi_->HdiMppTaskMetaSetPacket(task, KEY_INPUT_PACKET, packet_);
213 mppApi_->HdiMppTaskMetaSetFrame(task, KEY_OUTPUT_FRAME, frame_);
214 /* input queue */
215 ret = mpi_->enqueue(mppCtx_, MPP_PORT_INPUT, task);
216 if (ret != MPP_OK) {
217 CODEC_LOGE("enqueue input error %{public}d", ret);
218 }
219 return ret;
220 }
GetFrame()221 MPP_RET CodecJpegDecoder::GetFrame()
222 {
223 CODEC_LOGI("enter.");
224 MppTask task = nullptr;
225 /* poll and wait here */
226 MPP_RET ret = mpi_->poll(mppCtx_, MPP_PORT_OUTPUT, MPP_POLL_BLOCK);
227 if (ret != MPP_OK) {
228 CODEC_LOGE("poll output error %{public}d", ret);
229 return ret;
230 }
231
232 /* output queue */
233 ret = mpi_->dequeue(mppCtx_, MPP_PORT_OUTPUT, &task);
234 if (ret != MPP_OK) {
235 CODEC_LOGE("dequeue output error %{public}d", ret);
236 return ret;
237 }
238
239 MppFrame frameOut = NULL;
240 mppApi_->HdiMppTaskMetaGetFrame(task, KEY_OUTPUT_FRAME, &frameOut);
241 auto err = mppApi_->HdiMppFrameGetErrinfo(frameOut) | mppApi_->HdiMppFrameGetDiscard(frameOut);
242 (void)err;
243 /* output queue */
244 ret = mpi_->enqueue(mppCtx_, MPP_PORT_OUTPUT, task);
245 if (ret != MPP_OK) {
246 CODEC_LOGE("enqueue output error %{public}d", ret);
247 return ret;
248 }
249 if (frameOut != frame_) {
250 CODEC_LOGE("frameOut is not match with frame_ %{public}d", ret);
251 mppApi_->HdiMppFrameDeinit(&frameOut);
252 return MPP_NOK;
253 }
254 return MPP_OK;
255 }
256
DumpOutFile()257 void CodecJpegDecoder::DumpOutFile()
258 {
259 #ifdef DUMP_FILE
260 MppBuffer buf = mppApi_->HdiMppFrameGetBuffer(frame_);
261 auto size = mppApi_->HdiMppBufferGetSizeWithCaller(buf, __func__);
262 auto ptr = mppApi_->HdiMppBufferGetPtrWithCaller(buf, __func__);
263 std::ofstream out("/data/out.raw", std::ios::trunc | std::ios::binary);
264 if (!out.is_open()) {
265 CODEC_LOGE("file open error");
266 return;
267 }
268 out.write(reinterpret_cast<char *>(ptr), size); // 3: byte alignment, 2:byte alignment
269 out.flush();
270 #endif
271 }
DumpInFile(char * data,int32_t size)272 void CodecJpegDecoder::DumpInFile(char *data, int32_t size)
273 {
274 #ifdef DUMP_FILE
275 std::ofstream out("/data/in.raw", std::ios::trunc | std::ios::binary);
276 if (!out.is_open()) {
277 CODEC_LOGE("file open error");
278 return;
279 }
280 out.write(data, size); // 3: byte alignment, 2:byte alignment
281 out.flush();
282 #endif
283 }
SetFormat(int32_t format)284 bool CodecJpegDecoder::SetFormat(int32_t format)
285 {
286 bool ret = true;
287 switch (format) {
288 case PIXEL_FMT_YCBCR_420_SP:
289 format_ = MPP_FMT_YUV420SP;
290 break;
291 case PIXEL_FMT_YCRCB_420_SP:
292 format_ = MPP_FMT_YUV420SP_VU;
293 break;
294 case PIXEL_FMT_BGR_565:
295 format_ = MPP_FMT_BGR565;
296 break;
297 case PIXEL_FMT_RGB_888:
298 format_ = MPP_FMT_RGB888;
299 break;
300 default:
301 CODEC_LOGE("unsupport pixformat %{public}d", format);
302 ret = false;
303 break;
304 }
305 if (ret) {
306 auto err = mpi_->control(mppCtx_, MPP_DEC_SET_OUTPUT_FORMAT, &format_);
307 if (err != MPP_OK) {
308 CODEC_LOGE("set output fromat error %{public}d", err);
309 return false;
310 }
311 }
312 return ret;
313 }
ResetMppBuffer()314 void CodecJpegDecoder::ResetMppBuffer()
315 {
316 if (memGroup_) {
317 mppApi_->HdiMppBufferGroupClear(memGroup_);
318 }
319 if (packet_ != nullptr) {
320 mppApi_->HdiMppPacketDeinit(&packet_);
321 packet_ = nullptr;
322 }
323 if (frame_ != nullptr) {
324 mppApi_->HdiMppFrameDeinit(&frame_);
325 frame_ = nullptr;
326 }
327 }
328
PrePare(bool isDecoder)329 bool CodecJpegDecoder::PrePare(bool isDecoder)
330 {
331 MPP_RET ret = mppApi_->HdiMppCreate(&mppCtx_, &mpi_);
332 if (ret != MPP_OK) {
333 CODEC_LOGE("HdiMppCreate error %{public}d", ret);
334 return false;
335 }
336 ret = mppApi_->HdiMppInit(mppCtx_, isDecoder ? MPP_CTX_DEC : MPP_CTX_ENC, MPP_VIDEO_CodingMJPEG);
337 if (ret != MPP_OK) {
338 CODEC_LOGE("HdiMppInit error %{public}d", ret);
339 return false;
340 }
341 MppPollType timeout = MPP_POLL_BLOCK;
342 ret = mpi_->control(mppCtx_, MPP_SET_OUTPUT_TIMEOUT, &timeout);
343 if (ret != MPP_OK) {
344 CODEC_LOGE("set output timeout error %{public}d", ret);
345 return false;
346 }
347 ret = mpi_->control(mppCtx_, MPP_SET_INPUT_TIMEOUT, &timeout);
348 if (ret != MPP_OK) {
349 CODEC_LOGE("set input timeout error %{public}d", ret);
350 return false;
351 }
352 mppApi_->HdiMppBufferGroupGet(&memGroup_, MPP_BUFFER_TYPE_DRM, MPP_BUFFER_INTERNAL, nullptr, __func__);
353 mppApi_->HdiMppBufferGroupLimitConfig(memGroup_, 0, 24); // 24:buffer group limit
354 return true;
355 }
356 } // namespace JPEG
357 } // namespace VDI
358 } // namespace OHOS