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