• 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 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