• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device 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  *     http://www.apache.org/licenses/LICENSE-2.0
7  * Unless required by applicable law or agreed to in writing, software
8  * distributed under the License is distributed on an "AS IS" BASIS,
9  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10  * See the License for the specific language governing permissions and
11  * limitations under the License.
12  */
13 
14 #include "rk_codec_node.h"
15 #include <securec.h>
16 
17 extern "C" {
18 #include <jpeglib.h>
19 #include <transupp.h>
20 }
21 
22 namespace OHOS::Camera {
23 uint32_t RKCodecNode::previewWidth_ = 0;
24 uint32_t RKCodecNode::previewHeight_ = 0;
25 const unsigned long long TIME_CONVERSION_NS_S = 1000000000ULL; /* ns to s */
26 
RKCodecNode(const std::string & name,const std::string & type)27 RKCodecNode::RKCodecNode(const std::string& name, const std::string& type) : NodeBase(name, type)
28 {
29     CAMERA_LOGV("%{public}s enter, type(%{public}s)\n", name_.c_str(), type_.c_str());
30     jpegRotation_ = static_cast<uint32_t>(JXFORM_ROT_270);
31 }
32 
~RKCodecNode()33 RKCodecNode::~RKCodecNode()
34 {
35     CAMERA_LOGI("~RKCodecNode Node exit.");
36 }
37 
Start(const int32_t streamId)38 RetCode RKCodecNode::Start(const int32_t streamId)
39 {
40     CAMERA_LOGI("RKCodecNode::Start streamId = %{public}d\n", streamId);
41     return RC_OK;
42 }
43 
Stop(const int32_t streamId)44 RetCode RKCodecNode::Stop(const int32_t streamId)
45 {
46     CAMERA_LOGI("RKCodecNode::Stop streamId = %{public}d\n", streamId);
47 
48     if (halCtx_ != nullptr) {
49         CAMERA_LOGI("RKCodecNode::Stop hal_mpp_ctx_delete\n");
50         hal_mpp_ctx_delete(halCtx_);
51         halCtx_ = nullptr;
52         mppStatus_ = 0;
53     }
54 
55     return RC_OK;
56 }
57 
Flush(const int32_t streamId)58 RetCode RKCodecNode::Flush(const int32_t streamId)
59 {
60     CAMERA_LOGI("RKCodecNode::Flush streamId = %{public}d\n", streamId);
61     return RC_OK;
62 }
63 
RotJpegImg(const unsigned char * inputImg,size_t inputSize,unsigned char ** outImg,size_t * outSize,JXFORM_CODE rotDegrees)64 static void RotJpegImg(
65     const unsigned char *inputImg, size_t inputSize, unsigned char **outImg, size_t *outSize, JXFORM_CODE rotDegrees)
66 {
67     struct jpeg_decompress_struct inputInfo;
68     struct jpeg_error_mgr jerrIn;
69     struct jpeg_compress_struct outInfo;
70     struct jpeg_error_mgr jerrOut;
71     jvirt_barray_ptr *src_coef_arrays;
72     jvirt_barray_ptr *dst_coef_arrays;
73 
74     inputInfo.err = jpeg_std_error(&jerrIn);
75     jpeg_create_decompress(&inputInfo);
76     outInfo.err = jpeg_std_error(&jerrOut);
77     jpeg_create_compress(&outInfo);
78     jpeg_mem_src(&inputInfo, inputImg, inputSize);
79     jpeg_mem_dest(&outInfo, outImg, (unsigned long *)outSize);
80 
81     JCOPY_OPTION copyoption;
82     jpeg_transform_info transformoption;
83     transformoption.transform = rotDegrees;
84     transformoption.perfect = TRUE;
85     transformoption.trim = FALSE;
86     transformoption.force_grayscale = FALSE;
87     transformoption.crop = FALSE;
88 
89     jcopy_markers_setup(&inputInfo, copyoption);
90     (void)jpeg_read_header(&inputInfo, TRUE);
91 
92     if (!jtransform_request_workspace(&inputInfo, &transformoption)) {
93         CAMERA_LOGE("%s: transformation is not perfect", __func__);
94         return;
95     }
96 
97     src_coef_arrays = jpeg_read_coefficients(&inputInfo);
98     jpeg_copy_critical_parameters(&inputInfo, &outInfo);
99     dst_coef_arrays = jtransform_adjust_parameters(&inputInfo, &outInfo, src_coef_arrays, &transformoption);
100     jpeg_write_coefficients(&outInfo, dst_coef_arrays);
101     jcopy_markers_execute(&inputInfo, &outInfo, copyoption);
102     jtransform_execute_transformation(&inputInfo, &outInfo, src_coef_arrays, &transformoption);
103 
104     jpeg_finish_compress(&outInfo);
105     jpeg_destroy_compress(&outInfo);
106     (void)jpeg_finish_decompress(&inputInfo);
107     jpeg_destroy_decompress(&inputInfo);
108 }
109 
Config(const int32_t streamId,const CaptureMeta & meta)110 RetCode RKCodecNode::Config(const int32_t streamId, const CaptureMeta& meta)
111 {
112     if (meta == nullptr) {
113         CAMERA_LOGE("meta is nullptr");
114         return RC_ERROR;
115     }
116 
117     common_metadata_header_t* data = meta->get();
118     if (data == nullptr) {
119         CAMERA_LOGE("data is nullptr");
120         return RC_ERROR;
121     }
122 
123     camera_metadata_item_t entry;
124     int ret = FindCameraMetadataItem(data, OHOS_JPEG_ORIENTATION, &entry);
125     if (ret != 0 || entry.data.i32 == nullptr) {
126         CAMERA_LOGI("tag not found");
127         return RC_ERROR;
128     }
129 
130     JXFORM_CODE jxRotation = JXFORM_ROT_270;
131     int32_t ohosRotation = *entry.data.i32;
132     if (ohosRotation == OHOS_CAMERA_JPEG_ROTATION_0) {
133         jxRotation = JXFORM_NONE;
134     } else if (ohosRotation == OHOS_CAMERA_JPEG_ROTATION_90) {
135         jxRotation = JXFORM_ROT_90;
136     } else if (ohosRotation == OHOS_CAMERA_JPEG_ROTATION_180) {
137         jxRotation = JXFORM_ROT_180;
138     } else {
139         jxRotation = JXFORM_ROT_270;
140     }
141     jpegRotation_ = static_cast<uint32_t>(jxRotation);
142     return RC_OK;
143 }
144 
encodeJpegToMemory(unsigned char * image,int width,int height,const char * comment,unsigned long * jpegSize,unsigned char ** jpegBuf)145 void RKCodecNode::encodeJpegToMemory(unsigned char* image, int width, int height,
146     const char* comment, unsigned long* jpegSize, unsigned char** jpegBuf)
147 {
148     struct jpeg_compress_struct cInfo;
149     struct jpeg_error_mgr jErr;
150     JSAMPROW row_pointer[1];
151     int row_stride = 0;
152     constexpr uint32_t colorMap = 3;
153     constexpr uint32_t compressionRatio = 100;
154     constexpr uint32_t pixelsThick = 3;
155 
156     cInfo.err = jpeg_std_error(&jErr);
157 
158     jpeg_create_compress(&cInfo);
159     cInfo.image_width = width;
160     cInfo.image_height = height;
161     cInfo.input_components = colorMap;
162     cInfo.in_color_space = JCS_RGB;
163 
164     jpeg_set_defaults(&cInfo);
165     jpeg_set_quality(&cInfo, compressionRatio, TRUE);
166     jpeg_mem_dest(&cInfo, jpegBuf, jpegSize);
167     jpeg_start_compress(&cInfo, TRUE);
168 
169     if (comment) {
170         jpeg_write_marker(&cInfo, JPEG_COM, (const JOCTET*)comment, strlen(comment));
171     }
172 
173     row_stride = width;
174     while (cInfo.next_scanline < cInfo.image_height) {
175         row_pointer[0] = &image[cInfo.next_scanline * row_stride * pixelsThick];
176         jpeg_write_scanlines(&cInfo, row_pointer, 1);
177     }
178 
179     jpeg_finish_compress(&cInfo);
180     jpeg_destroy_compress(&cInfo);
181 
182     size_t rotJpgSize = 0;
183     unsigned char* rotJpgBuf = nullptr;
184     /* rotate image */
185     RotJpegImg(*jpegBuf, *jpegSize, &rotJpgBuf, &rotJpgSize, static_cast<JXFORM_CODE>(jpegRotation_));
186     if (rotJpgBuf != nullptr && rotJpgSize != 0) {
187         free(*jpegBuf);
188         *jpegBuf = rotJpgBuf;
189         *jpegSize = rotJpgSize;
190     }
191 }
192 
findStartCode(unsigned char * data,size_t dataSz)193 int RKCodecNode::findStartCode(unsigned char *data, size_t dataSz)
194 {
195     constexpr uint32_t dataSize = 4;
196     constexpr uint32_t dataBit2 = 2;
197     constexpr uint32_t dataBit3 = 3;
198 
199     if (data == nullptr) {
200         CAMERA_LOGI("RKCodecNode::findStartCode paramater == nullptr");
201         return -1;
202     }
203 
204     if ((dataSz > dataSize) && (data[0] == 0) && (data[1] == 0) && \
205         (data[dataBit2] == 0) && (data[dataBit3] == 1)) {
206         return 4; // 4:start node
207     }
208 
209     return -1;
210 }
211 
212 static constexpr uint32_t nalBit = 0x1F;
213 
SerchIFps(unsigned char * buf,size_t bufSize,std::shared_ptr<IBuffer> & buffer)214 void RKCodecNode::SerchIFps(unsigned char* buf, size_t bufSize, std::shared_ptr<IBuffer>& buffer)
215 {
216     size_t nalType = 0;
217     size_t idx = 0;
218     size_t size = bufSize;
219     constexpr uint32_t nalTypeValue = 0x05;
220 
221     if (buffer == nullptr || buf == nullptr) {
222         CAMERA_LOGI("RKCodecNode::SerchIFps paramater == nullptr");
223         return;
224     }
225 
226     for (int i = 0; i < bufSize; i++) {
227         int ret = findStartCode(buf + idx, size);
228         if (ret == -1) {
229             idx += 1;
230             size -= 1;
231         } else {
232             nalType = ((buf[idx + ret]) & nalBit);
233             CAMERA_LOGI("ForkNode::ForkBuffers nalu == 0x%{public}x buf == 0x%{public}x \n", nalType, buf[idx + ret]);
234             if (nalType == nalTypeValue) {
235                 buffer->SetEsKeyFrame(1);
236                 CAMERA_LOGI("ForkNode::ForkBuffers SetEsKeyFrame == 1 nalu == 0x%{public}x\n", nalType);
237                 break;
238             } else {
239                 idx += ret;
240                 size -= ret;
241             }
242         }
243 
244         if (idx >= bufSize) {
245             break;
246         }
247     }
248 
249     if (idx >= bufSize) {
250         buffer->SetEsKeyFrame(0);
251         CAMERA_LOGI("ForkNode::ForkBuffers SetEsKeyFrame == 0 nalu == 0x%{public}x idx = %{public}d\n",
252             nalType, idx);
253     }
254 }
255 
Yuv420ToRGBA8888(std::shared_ptr<IBuffer> & buffer)256 void RKCodecNode::Yuv420ToRGBA8888(std::shared_ptr<IBuffer>& buffer)
257 {
258     if (buffer == nullptr) {
259         CAMERA_LOGI("RKCodecNode::Yuv420ToRGBA8888 buffer == nullptr");
260         return;
261     }
262 
263     int dma_fd = buffer->GetFileDescriptor();
264     void* temp = malloc(buffer->GetSize());
265     if (temp == nullptr) {
266         CAMERA_LOGI("RKCodecNode::Yuv420ToRGBA8888 malloc buffer == nullptr");
267         return;
268     }
269 
270     previewWidth_ = buffer->GetWidth();
271     previewHeight_ = buffer->GetHeight();
272     int ret = memcpy_s(temp, buffer->GetSize(), (const void *)buffer->GetVirAddress(), buffer->GetSize());
273     if (ret == 0) {
274         buffer->SetEsFrameSize(buffer->GetSize());
275     } else {
276         printf("memcpy_s failed!\n");
277         buffer->SetEsFrameSize(0);
278     }
279     RockchipRga rkRga;
280 
281     rga_info_t src = {};
282     rga_info_t dst = {};
283 
284     src.fd = -1;
285     src.mmuFlag = 1;
286     src.rotation = 0;
287     src.virAddr = (void *)temp;
288 
289     dst.fd = dma_fd;
290     dst.mmuFlag = 1;
291     dst.virAddr = 0;
292 
293     rga_set_rect(&src.rect, 0, 0, buffer->GetWidth(), buffer->GetHeight(),
294         buffer->GetWidth(), buffer->GetHeight(), RK_FORMAT_YCbCr_420_P);
295     rga_set_rect(&dst.rect, 0, 0, buffer->GetWidth(), buffer->GetHeight(),
296         buffer->GetWidth(), buffer->GetHeight(), RK_FORMAT_RGBA_8888);
297 
298     rkRga.RkRgaBlit(&src, &dst, NULL);
299     rkRga.RkRgaFlush();
300     free(temp);
301 }
302 
Yuv420ToJpeg(std::shared_ptr<IBuffer> & buffer)303 void RKCodecNode::Yuv420ToJpeg(std::shared_ptr<IBuffer>& buffer)
304 {
305     constexpr uint32_t RGB24Width = 3;
306 
307     if (buffer == nullptr) {
308         CAMERA_LOGI("RKCodecNode::Yuv420ToJpeg buffer == nullptr");
309         return;
310     }
311 
312     int dma_fd = buffer->GetFileDescriptor();
313     unsigned char* jBuf = nullptr;
314     unsigned long jpegSize = 0;
315     uint32_t tempSize = (previewWidth_ * previewHeight_ * RGB24Width);
316 
317     void* temp = malloc(tempSize);
318     if (temp == nullptr) {
319         CAMERA_LOGI("RKCodecNode::Yuv420ToJpeg malloc buffer == nullptr");
320         return;
321     }
322 
323     RockchipRga rkRga;
324     rga_info_t src = {};
325     rga_info_t dst = {};
326 
327     src.mmuFlag = 1;
328     src.rotation = 0;
329     src.virAddr = 0;
330     src.fd = dma_fd;
331 
332     dst.fd = -1;
333     dst.mmuFlag = 1;
334     dst.virAddr = temp;
335 
336     rga_set_rect(&src.rect, 0, 0, previewWidth_, previewHeight_,
337         previewWidth_, previewHeight_, RK_FORMAT_YCbCr_420_P);
338     rga_set_rect(&dst.rect, 0, 0, previewWidth_, previewHeight_,
339         previewWidth_, previewHeight_, RK_FORMAT_RGB_888);
340 
341     rkRga.RkRgaBlit(&src, &dst, NULL);
342     rkRga.RkRgaFlush();
343     encodeJpegToMemory((unsigned char *)temp, previewWidth_, previewHeight_, nullptr, &jpegSize, &jBuf);
344 
345     int ret = memcpy_s((unsigned char*)buffer->GetVirAddress(), buffer->GetSize(), jBuf, jpegSize);
346     if (ret == 0) {
347         buffer->SetEsFrameSize(jpegSize);
348     } else {
349         CAMERA_LOGI("memcpy_s failed, ret = %{public}d\n", ret);
350         buffer->SetEsFrameSize(0);
351     }
352 
353     free(jBuf);
354     free(temp);
355 
356     CAMERA_LOGE("RKCodecNode::Yuv420ToJpeg jpegSize = %{public}d\n", jpegSize);
357 }
358 
Yuv420ToH264(std::shared_ptr<IBuffer> & buffer)359 void RKCodecNode::Yuv420ToH264(std::shared_ptr<IBuffer>& buffer)
360 {
361     if (buffer == nullptr) {
362         CAMERA_LOGI("RKCodecNode::Yuv420ToH264 buffer == nullptr");
363         return;
364     }
365 
366     int ret = 0;
367     size_t buf_size = 0;
368     struct timespec ts = {};
369     int64_t timestamp = 0;
370     int dma_fd = buffer->GetFileDescriptor();
371 
372     if (mppStatus_ == 0) {
373         MpiEncTestArgs args = {};
374         args.width       = previewWidth_;
375         args.height      = previewHeight_;
376         args.format      = MPP_FMT_YUV420P;
377         args.type        = MPP_VIDEO_CodingAVC;
378         halCtx_ = hal_mpp_ctx_create(&args);
379         if (halCtx_ == nullptr) {
380             CAMERA_LOGI("RKCodecNode::Yuv420ToH264 halCtx_ = %{public}p\n", halCtx_);
381             return;
382         }
383         mppStatus_ = 1;
384         buf_size = ((MpiEncTestData *)halCtx_)->frame_size;
385 
386         ret = hal_mpp_encode(halCtx_, dma_fd, (unsigned char *)buffer->GetVirAddress(), &buf_size);
387         SerchIFps((unsigned char *)buffer->GetVirAddress(), buf_size, buffer);
388 
389         buffer->SetEsFrameSize(buf_size);
390         clock_gettime(CLOCK_MONOTONIC, &ts);
391         timestamp = ts.tv_nsec + ts.tv_sec * TIME_CONVERSION_NS_S;
392         buffer->SetEsTimestamp(timestamp);
393         CAMERA_LOGI("RKCodecNode::Yuv420ToH264 video capture on\n");
394     } else {
395         if (halCtx_ == nullptr) {
396             CAMERA_LOGI("RKCodecNode::Yuv420ToH264 halCtx_ = %{public}p\n", halCtx_);
397             return;
398         }
399         buf_size = ((MpiEncTestData *)halCtx_)->frame_size;
400         ret = hal_mpp_encode(halCtx_, dma_fd, (unsigned char *)buffer->GetVirAddress(), &buf_size);
401         SerchIFps((unsigned char *)buffer->GetVirAddress(), buf_size, buffer);
402         buffer->SetEsFrameSize(buf_size);
403         clock_gettime(CLOCK_MONOTONIC, &ts);
404         timestamp = ts.tv_nsec + ts.tv_sec * TIME_CONVERSION_NS_S;
405         buffer->SetEsTimestamp(timestamp);
406     }
407 
408     CAMERA_LOGI("ForkNode::ForkBuffers H264 size = %{public}d ret = %{public}d timestamp = %{public}lld\n",
409         buf_size, ret, timestamp);
410 }
411 
DeliverBuffer(std::shared_ptr<IBuffer> & buffer)412 void RKCodecNode::DeliverBuffer(std::shared_ptr<IBuffer>& buffer)
413 {
414     if (buffer == nullptr) {
415         CAMERA_LOGE("RKCodecNode::DeliverBuffer frameSpec is null");
416         return;
417     }
418 
419     int32_t id = buffer->GetStreamId();
420     CAMERA_LOGE("RKCodecNode::DeliverBuffer StreamId %{public}d", id);
421     if (buffer->GetEncodeType() == ENCODE_TYPE_JPEG) {
422         Yuv420ToJpeg(buffer);
423     } else if (buffer->GetEncodeType() == ENCODE_TYPE_H264) {
424         Yuv420ToH264(buffer);
425     } else {
426         Yuv420ToRGBA8888(buffer);
427     }
428 
429     outPutPorts_ = GetOutPorts();
430     for (auto& it : outPutPorts_) {
431         if (it->format_.streamId_ == id) {
432             it->DeliverBuffer(buffer);
433             CAMERA_LOGI("RKCodecNode deliver buffer streamid = %{public}d", it->format_.streamId_);
434             return;
435         }
436     }
437 }
438 
Capture(const int32_t streamId,const int32_t captureId)439 RetCode RKCodecNode::Capture(const int32_t streamId, const int32_t captureId)
440 {
441     CAMERA_LOGV("RKCodecNode::Capture");
442     return RC_OK;
443 }
444 
CancelCapture(const int32_t streamId)445 RetCode RKCodecNode::CancelCapture(const int32_t streamId)
446 {
447     CAMERA_LOGI("RKCodecNode::CancelCapture streamid = %{public}d", streamId);
448 
449     return RC_OK;
450 }
451 
452 REGISTERNODE(RKCodecNode, {"RKCodec"})
453 } // namespace OHOS::Camera
454