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