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