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 namespace OHOS::Camera {
18 uint32_t RKCodecNode::previewWidth_ = 0;
19 uint32_t RKCodecNode::previewHeight_ = 0;
20 const unsigned long long TIME_CONVERSION_NS_S = 1000000000ULL; /* ns to s */
21
RKCodecNode(const std::string & name,const std::string & type)22 RKCodecNode::RKCodecNode(const std::string& name, const std::string& type) : NodeBase(name, type)
23 {
24 CAMERA_LOGV("%{public}s enter, type(%{public}s)\n", name_.c_str(), type_.c_str());
25 }
26
~RKCodecNode()27 RKCodecNode::~RKCodecNode()
28 {
29 CAMERA_LOGI("~RKCodecNode Node exit.");
30 }
31
Start(const int32_t streamId)32 RetCode RKCodecNode::Start(const int32_t streamId)
33 {
34 CAMERA_LOGI("RKCodecNode::Start streamId = %{public}d\n", streamId);
35 return RC_OK;
36 }
37
Stop(const int32_t streamId)38 RetCode RKCodecNode::Stop(const int32_t streamId)
39 {
40 CAMERA_LOGI("RKCodecNode::Stop streamId = %{public}d\n", streamId);
41
42 if (halCtx_ != nullptr) {
43 CAMERA_LOGI("RKCodecNode::Stop hal_mpp_ctx_delete\n");
44 hal_mpp_ctx_delete(halCtx_);
45 halCtx_ = nullptr;
46 mppStatus_ = 0;
47 }
48
49 return RC_OK;
50 }
51
Flush(const int32_t streamId)52 RetCode RKCodecNode::Flush(const int32_t streamId)
53 {
54 CAMERA_LOGI("RKCodecNode::Flush streamId = %{public}d\n", streamId);
55 return RC_OK;
56 }
57
encodeJpegToMemory(unsigned char * image,int width,int height,const char * comment,size_t * jpegSize,unsigned char ** jpegBuf)58 void RKCodecNode::encodeJpegToMemory(unsigned char* image, int width, int height,
59 const char* comment, size_t* jpegSize, unsigned char** jpegBuf)
60 {
61 struct jpeg_compress_struct cInfo;
62 struct jpeg_error_mgr jErr;
63 JSAMPROW row_pointer[1];
64 int row_stride = 0;
65 constexpr uint32_t colorMap = 3;
66 constexpr uint32_t compressionRatio = 100;
67 constexpr uint32_t pixelsThick = 3;
68
69 cInfo.err = jpeg_std_error(&jErr);
70
71 jpeg_create_compress(&cInfo);
72 cInfo.image_width = width;
73 cInfo.image_height = height;
74 cInfo.input_components = colorMap;
75 cInfo.in_color_space = JCS_RGB;
76
77 jpeg_set_defaults(&cInfo);
78 jpeg_set_quality(&cInfo, compressionRatio, TRUE);
79 jpeg_mem_dest(&cInfo, jpegBuf, jpegSize);
80 jpeg_start_compress(&cInfo, TRUE);
81
82 if (comment) {
83 jpeg_write_marker(&cInfo, JPEG_COM, (const JOCTET*)comment, strlen(comment));
84 }
85
86 row_stride = width;
87 while (cInfo.next_scanline < cInfo.image_height) {
88 row_pointer[0] = &image[cInfo.next_scanline * row_stride * pixelsThick];
89 jpeg_write_scanlines(&cInfo, row_pointer, 1);
90 }
91
92 jpeg_finish_compress(&cInfo);
93 jpeg_destroy_compress(&cInfo);
94 }
95
findStartCode(unsigned char * data,size_t dataSz)96 int RKCodecNode::findStartCode(unsigned char *data, size_t dataSz)
97 {
98 constexpr uint32_t dataSize = 4;
99 constexpr uint32_t dataBit2 = 2;
100 constexpr uint32_t dataBit3 = 3;
101
102 if (data == nullptr) {
103 CAMERA_LOGI("RKCodecNode::findStartCode paramater == nullptr");
104 return -1;
105 }
106
107 if ((dataSz > dataSize) && (data[0] == 0) && (data[1] == 0) && \
108 (data[dataBit2] == 0) && (data[dataBit3] == 1)) {
109 return 4; // 4:start node
110 }
111
112 return -1;
113 }
114
115 static constexpr uint32_t nalBit = 0x1F;
116 #define NAL_TYPE(value) ((value) & nalBit)
SerchIFps(unsigned char * buf,size_t bufSize,std::shared_ptr<IBuffer> & buffer)117 void RKCodecNode::SerchIFps(unsigned char* buf, size_t bufSize, std::shared_ptr<IBuffer>& buffer)
118 {
119 size_t nalType = 0;
120 size_t idx = 0;
121 size_t size = bufSize;
122 constexpr uint32_t nalTypeValue = 0x05;
123
124 if (buffer == nullptr || buf == nullptr) {
125 CAMERA_LOGI("RKCodecNode::SerchIFps paramater == nullptr");
126 return;
127 }
128
129 for (int i = 0; i < bufSize; i++) {
130 int ret = findStartCode(buf + idx, size);
131 if (ret == -1) {
132 idx += 1;
133 size -= 1;
134 } else {
135 nalType = NAL_TYPE(buf[idx + ret]);
136 CAMERA_LOGI("ForkNode::ForkBuffers nalu == 0x%{public}x buf == 0x%{public}x \n", nalType, buf[idx + ret]);
137 if (nalType == nalTypeValue) {
138 buffer->SetEsKeyFrame(1);
139 CAMERA_LOGI("ForkNode::ForkBuffers SetEsKeyFrame == 1 nalu == 0x%{public}x\n", nalType);
140 break;
141 } else {
142 idx += ret;
143 size -= ret;
144 }
145 }
146
147 if (idx >= bufSize) {
148 break;
149 }
150 }
151
152 if (idx >= bufSize) {
153 buffer->SetEsKeyFrame(0);
154 CAMERA_LOGI("ForkNode::ForkBuffers SetEsKeyFrame == 0 nalu == 0x%{public}x idx = %{public}d\n",
155 nalType, idx);
156 }
157 }
158
Yuv420ToRGBA8888(std::shared_ptr<IBuffer> & buffer)159 void RKCodecNode::Yuv420ToRGBA8888(std::shared_ptr<IBuffer>& buffer)
160 {
161 if (buffer == nullptr) {
162 CAMERA_LOGI("RKCodecNode::Yuv420ToRGBA8888 buffer == nullptr");
163 return;
164 }
165
166 int dma_fd = buffer->GetFileDescriptor();
167 void* temp = malloc(buffer->GetSize());
168 if (temp == nullptr) {
169 CAMERA_LOGI("RKCodecNode::Yuv420ToRGBA8888 malloc buffer == nullptr");
170 return;
171 }
172
173 previewWidth_ = buffer->GetWidth();
174 previewHeight_ = buffer->GetHeight();
175 int ret = memcpy_s(temp, buffer->GetSize(), (const void *)buffer->GetVirAddress(), buffer->GetSize());
176 if (ret != 0) {
177 printf("memcpy_s failed!\n");
178 }
179 RockchipRga rkRga;
180
181 rga_info_t src = {};
182 rga_info_t dst = {};
183
184 src.fd = -1;
185 src.mmuFlag = 1;
186 src.rotation = 0;
187 src.virAddr = (void *)temp;
188
189 dst.fd = dma_fd;
190 dst.mmuFlag = 1;
191 dst.virAddr = 0;
192
193 rga_set_rect(&src.rect, 0, 0, buffer->GetWidth(), buffer->GetHeight(),
194 buffer->GetWidth(), buffer->GetHeight(), RK_FORMAT_YCbCr_420_P);
195 rga_set_rect(&dst.rect, 0, 0, buffer->GetWidth(), buffer->GetHeight(),
196 buffer->GetWidth(), buffer->GetHeight(), RK_FORMAT_RGBA_8888);
197
198 rkRga.RkRgaBlit(&src, &dst, NULL);
199 rkRga.RkRgaFlush();
200 free(temp);
201 }
202
Yuv420ToJpeg(std::shared_ptr<IBuffer> & buffer)203 void RKCodecNode::Yuv420ToJpeg(std::shared_ptr<IBuffer>& buffer)
204 {
205 constexpr uint32_t RGB24Width = 3;
206
207 if (buffer == nullptr) {
208 CAMERA_LOGI("RKCodecNode::Yuv420ToJpeg buffer == nullptr");
209 return;
210 }
211
212 int dma_fd = buffer->GetFileDescriptor();
213 unsigned char* jBuf = nullptr;
214 size_t jpegSize = 0;
215 uint32_t tempSize = (previewWidth_ * previewHeight_ * RGB24Width);
216
217 void* temp = malloc(tempSize);
218 if (temp == nullptr) {
219 CAMERA_LOGI("RKCodecNode::Yuv420ToJpeg malloc buffer == nullptr");
220 return;
221 }
222
223 RockchipRga rkRga;
224 rga_info_t src = {};
225 rga_info_t dst = {};
226
227 src.mmuFlag = 1;
228 src.rotation = 0;
229 src.virAddr = 0;
230 src.fd = dma_fd;
231
232 dst.fd = -1;
233 dst.mmuFlag = 1;
234 dst.virAddr = temp;
235
236 rga_set_rect(&src.rect, 0, 0, previewWidth_, previewHeight_,
237 previewWidth_, previewHeight_, RK_FORMAT_YCbCr_420_P);
238 rga_set_rect(&dst.rect, 0, 0, previewWidth_, previewHeight_,
239 previewWidth_, previewHeight_, RK_FORMAT_RGB_888);
240
241 rkRga.RkRgaBlit(&src, &dst, NULL);
242 rkRga.RkRgaFlush();
243 encodeJpegToMemory((unsigned char *)temp, previewWidth_, previewHeight_, nullptr, &jpegSize, &jBuf);
244
245 int ret = memcpy_s((unsigned char*)buffer->GetVirAddress(), buffer->GetSize(), jBuf, jpegSize);
246 if (ret == 0) {
247 buffer->SetEsFrameSize(jpegSize);
248 } else {
249 CAMERA_LOGI("memcpy_s failed, ret = %{public}d\n", ret);
250 buffer->SetEsFrameSize(0);
251 }
252
253 free(jBuf);
254 free(temp);
255
256 CAMERA_LOGE("RKCodecNode::Yuv420ToJpeg jpegSize = %{public}d\n", jpegSize);
257 }
258
Yuv420ToH264(std::shared_ptr<IBuffer> & buffer)259 void RKCodecNode::Yuv420ToH264(std::shared_ptr<IBuffer>& buffer)
260 {
261 if (buffer == nullptr) {
262 CAMERA_LOGI("RKCodecNode::Yuv420ToH264 buffer == nullptr");
263 return;
264 }
265
266 int ret = 0;
267 size_t buf_size = 0;
268 struct timespec ts = {};
269 int64_t timestamp = 0;
270 int dma_fd = buffer->GetFileDescriptor();
271
272 if (mppStatus_ == 0) {
273 MpiEncTestArgs args = {};
274 args.width = previewWidth_;
275 args.height = previewHeight_;
276 args.format = MPP_FMT_YUV420P;
277 args.type = MPP_VIDEO_CodingAVC;
278 halCtx_ = hal_mpp_ctx_create(&args);
279 if (halCtx_ == nullptr) {
280 CAMERA_LOGI("RKCodecNode::Yuv420ToH264 halCtx_ = %{public}p\n", halCtx_);
281 return;
282 }
283 mppStatus_ = 1;
284 buf_size = ((MpiEncTestData *)halCtx_)->frame_size;
285
286 ret = hal_mpp_encode(halCtx_, dma_fd, (unsigned char *)buffer->GetVirAddress(), &buf_size);
287 SerchIFps((unsigned char *)buffer->GetVirAddress(), buf_size, buffer);
288
289 buffer->SetEsFrameSize(buf_size);
290 clock_gettime(CLOCK_MONOTONIC, &ts);
291 timestamp = ts.tv_nsec + ts.tv_sec * TIME_CONVERSION_NS_S;
292 buffer->SetEsTimestamp(timestamp);
293 CAMERA_LOGI("RKCodecNode::Yuv420ToH264 video capture on\n");
294 } else {
295 if (halCtx_ == nullptr) {
296 CAMERA_LOGI("RKCodecNode::Yuv420ToH264 halCtx_ = %{public}p\n", halCtx_);
297 return;
298 }
299 buf_size = ((MpiEncTestData *)halCtx_)->frame_size;
300 ret = hal_mpp_encode(halCtx_, dma_fd, (unsigned char *)buffer->GetVirAddress(), &buf_size);
301 SerchIFps((unsigned char *)buffer->GetVirAddress(), buf_size, buffer);
302 buffer->SetEsFrameSize(buf_size);
303 clock_gettime(CLOCK_MONOTONIC, &ts);
304 timestamp = ts.tv_nsec + ts.tv_sec * TIME_CONVERSION_NS_S;
305 buffer->SetEsTimestamp(timestamp);
306 }
307
308 CAMERA_LOGI("ForkNode::ForkBuffers H264 size = %{public}d ret = %{public}d timestamp = %{public}lld\n",
309 buf_size, ret, timestamp);
310 }
311
DeliverBuffer(std::shared_ptr<IBuffer> & buffer)312 void RKCodecNode::DeliverBuffer(std::shared_ptr<IBuffer>& buffer)
313 {
314 if (buffer == nullptr) {
315 CAMERA_LOGE("RKCodecNode::DeliverBuffer frameSpec is null");
316 return;
317 }
318
319 int32_t id = buffer->GetStreamId();
320 CAMERA_LOGE("RKCodecNode::DeliverBuffer StreamId %{public}d", id);
321 if (buffer->GetEncodeType() == ENCODE_TYPE_JPEG) {
322 Yuv420ToJpeg(buffer);
323 } else if (buffer->GetEncodeType() == ENCODE_TYPE_H264) {
324 Yuv420ToH264(buffer);
325 } else {
326 Yuv420ToRGBA8888(buffer);
327 }
328
329 outPutPorts_ = GetOutPorts();
330 for (auto& it : outPutPorts_) {
331 if (it->format_.streamId_ == id) {
332 it->DeliverBuffer(buffer);
333 CAMERA_LOGI("RKCodecNode deliver buffer streamid = %{public}d", it->format_.streamId_);
334 return;
335 }
336 }
337 }
338
Capture(const int32_t streamId,const int32_t captureId)339 RetCode RKCodecNode::Capture(const int32_t streamId, const int32_t captureId)
340 {
341 CAMERA_LOGV("RKCodecNode::Capture");
342 return RC_OK;
343 }
344
CancelCapture(const int32_t streamId)345 RetCode RKCodecNode::CancelCapture(const int32_t streamId)
346 {
347 CAMERA_LOGI("RKCodecNode::CancelCapture streamid = %{public}d", streamId);
348
349 return RC_OK;
350 }
351
352 REGISTERNODE(RKCodecNode, {"RKCodec"})
353 } // namespace OHOS::Camera
354