Apollo 11.0
自动驾驶开放平台
compress_component.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2017 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
18
19#include <exception>
20
21#ifdef __aarch64__
22#include "arm_neon.h"
23#include "NvBufSurface.h"
24#else
25#include "opencv2/core/core.hpp"
26#include "opencv2/highgui/highgui.hpp"
27#include "opencv2/imgproc/imgproc.hpp"
28#endif
29
30#include <iostream>
31#include <fstream>
32
33namespace apollo {
34namespace drivers {
35namespace camera {
36
42
44 if (!GetProtoConfig(&config_)) {
45 AERROR << "Parse config file failed: " << ConfigFilePath();
46 return false;
47 }
48 AINFO << "Camera config: \n" << config_.DebugString();
49 // try {
50 // image_pool_.reset(new CCObjectPool<CompressedImage>(config_.compress_conf().image_pool_size()));
51 // image_pool_->ConstructAll();
52 // } catch (const std::bad_alloc& e) {
53 // AERROR << e.what();
54 // return false;
55 // }
56
57 width_ = config_.compress_conf().width();
58 height_ = config_.compress_conf().height();
59
60 writer_ = node_->CreateWriter<CompressedImage>(config_.compress_conf().output_channel());
61
62#ifdef __aarch64__
63 buffer_size_ = config_.compress_conf().width() * config_.compress_conf().height() * 3 / 2;
64 try {
65 nvbuffer_pool_.reset(new CCObjectPool<NvBuffer>(config_.compress_conf().image_pool_size()));
66 nvbuffer_pool_->ConstructAll(
67 V4L2_PIX_FMT_YUV420M, config_.compress_conf().width(), config_.compress_conf().height(), 0);
68 for (size_t i = 0; i < config_.compress_conf().image_pool_size(); i++) {
69 nvbuffer_pool_->GetObject()->allocateMemory();
70 }
71 } catch (const std::bad_alloc& e) {
72 AERROR << e.what();
73 return false;
74 }
75
76 try {
77 downsampled_image_pool_.reset(new CCObjectPool<std::pair<std::vector<char>, std::vector<unsigned char>>>(
78 config_.compress_conf().image_pool_size()));
79 downsampled_image_pool_->ConstructAll();
80 for (size_t i = 0; i < config_.compress_conf().image_pool_size(); i++) {
81 (downsampled_image_pool_->GetObject()->first).reserve(buffer_size_);
82 (downsampled_image_pool_->GetObject()->second).reserve(buffer_size_);
83 }
84 } catch (const std::bad_alloc& e) {
85 AERROR << e.what();
86 return false;
87 }
88
89 jpegenc_ = NvJPEGEncoder::createJPEGEncoder("jpegenc");
90 jpegenc_->setCropRect(0, 0, 0, 0);
91#endif
92
93 return true;
94}
95
96bool CompressComponent::Proc(const std::shared_ptr<Image>& image) {
97 ADEBUG << "procing compressed";
98 if (cyber_unlikely(image->height() != height_ || image->width() != width_)) {
99 AERROR << "Setting resolution is " << width_ << "x" << height_ << ", but received " << image->width() << "x"
100 << image->height();
101 return false;
102 }
103 // auto compressed_image = image_pool_->GetObject();
104 auto compressed_image = writer_->AcquireMessage();
105 compressed_image->mutable_header()->CopyFrom(image->header());
106 compressed_image->set_frame_id(image->frame_id());
107 compressed_image->set_measurement_time(image->measurement_time());
108 compressed_image->set_height(height_);
109 compressed_image->set_width(width_);
110
111#ifdef __aarch64__
112 compressed_image->set_format(image->encoding() + "; jpeg compressed");
113 auto nvbuffer = nvbuffer_pool_->GetObject();
114 auto downsampled_image = downsampled_image_pool_->GetObject();
115 if (cyber_unlikely(
116 YUV422ToYUV420(const_cast<char*>(image->data().data()), (downsampled_image->first).data()) != 0)) {
117 AERROR << "Failed to downsample image";
118 return false;
119 }
120 if (cyber_unlikely(ReadBuffer((downsampled_image->first).data(), &(*nvbuffer)) != 0)) {
121 AERROR << "Failed to convert image to nvbuffer";
122 return false;
123 }
124 auto out_buffer = (downsampled_image->second).data();
125 auto buffer_size = static_cast<uint64_t>(buffer_size_);
126
127 auto ret = jpegenc_->encodeFromBuffer(*nvbuffer, JCS_YCbCr, &out_buffer, buffer_size, 95);
128 if (cyber_unlikely(ret != 0)) {
129 AERROR << "nvjpeg failed to compress image";
130 }
131 compressed_image->set_data((downsampled_image->second).data(), buffer_size);
132#else
133 compressed_image->set_format(image->encoding() + "; jpeg compressed bgr8");
134
135 std::vector<int> params;
136 params.resize(3, 0);
137 params[0] = cv::IMWRITE_JPEG_QUALITY;
138 params[1] = 95;
139
140 try {
141 cv::Mat mat_image(
142 image->height(), image->width(), CV_8UC3, const_cast<char*>(image->data().data()), image->step());
143 cv::Mat tmp_mat;
144 cv::cvtColor(mat_image, tmp_mat, cv::COLOR_RGB2BGR);
145 std::vector<uint8_t> compress_buffer;
146 if (!cv::imencode(".jpg", tmp_mat, compress_buffer, params)) {
147 AERROR << "cv::imencode (jpeg) failed on input image";
148 return false;
149 }
150 compressed_image->set_data(compress_buffer.data(), compress_buffer.size());
151 } catch (std::exception& e) {
152 AERROR << "cv::imencode (jpeg) exception :" << e.what();
153 return false;
154 }
155#endif
156 writer_->Write(compressed_image);
157 return true;
158}
159
160#ifdef __aarch64__
161int CompressComponent::YUV422ToYUV420(char* src, char* dst) {
162 static uint line_length = width_ * 2;
163 static uint y_num = width_ * height_;
164 static uint cb_start = y_num;
165 static uint cr_start = cb_start + cb_start / 4;
166 uint i, j, k = 0;
167
168 if (cyber_unlikely(!src || !dst))
169 return -1;
170
171 // // Pick up y component
172 // for (i = 0; i < y_num; i++) {
173 // dst[i] = src[i * 2];
174 // }
175
176 // // Interlaced scanning for picking up cb component
177 // for (i = 0; i < height_; i = i + 2) {
178 // int offset = i * line_length;
179 // for (j = 1; j < line_length; j = j + 4) {
180 // dst[cb_start + k] = src[offset + j];
181 // k++;
182 // }
183 // }
184
185 // // Interlaced scanning for picking up cr component
186 // k = 0;
187 // for (i = 1; i < height_; i = i + 2) {
188 // int offset = i * line_length;
189 // for (j = 3; j < width_ * 2; j = j + 4) {
190 // dst[cr_start + k] = src[offset + j];
191 // k++;
192 // }
193 // }
194
195 auto usrc = reinterpret_cast<unsigned char*>(src);
196 auto udst = reinterpret_cast<unsigned char*>(dst);
197
198 int frameSize = width_ * height_;
199 int chromaSize = frameSize / 4;
200
201 unsigned char* yPlane = udst;
202 unsigned char* uPlane = udst + frameSize;
203 unsigned char* vPlane = uPlane + chromaSize;
204
205 int yIndex = 0;
206 int uIndex = 0;
207 int vIndex = 0;
208
209 for (int j = 0; j < height_; j += 2) {
210 for (int i = 0; i < width_; i += 16) {
211 // Load 16 YUYV pixels (32 bytes)
212 uint8x16x2_t row0 = vld2q_u8(usrc + j * width_ * 2 + i * 2);
213 uint8x16x2_t row1 = vld2q_u8(usrc + (j + 1) * width_ * 2 + i * 2);
214
215 // Extract Y components
216 uint8x16_t y0 = row0.val[0];
217 uint8x16_t y1 = row1.val[0];
218
219 // Store Y components
220 vst1q_u8(yPlane + yIndex, y0);
221 vst1q_u8(yPlane + yIndex + width_, y1);
222 yIndex += 16;
223
224 // Extract and average U and V components
225 uint8x16_t u0 = row0.val[1];
226 uint8x16_t v0 = row1.val[1];
227
228 uint16x8_t u16_low = vaddl_u8(vget_low_u8(u0), vget_low_u8(v0));
229 uint16x8_t u16_high = vaddl_u8(vget_high_u8(u0), vget_high_u8(v0));
230 uint8x8_t u8_avg_low = vshrn_n_u16(u16_low, 1);
231 uint8x8_t u8_avg_high = vshrn_n_u16(u16_high, 1);
232
233 uint16x8_t v16_low = vaddl_u8(vget_low_u8(row0.val[1]), vget_low_u8(row1.val[1]));
234 uint16x8_t v16_high = vaddl_u8(vget_high_u8(row0.val[1]), vget_high_u8(row1.val[1]));
235 uint8x8_t v8_avg_low = vshrn_n_u16(v16_low, 1);
236 uint8x8_t v8_avg_high = vshrn_n_u16(v16_high, 1);
237
238 uint8x16_t u_avg = vcombine_u8(u8_avg_low, u8_avg_high);
239 uint8x16_t v_avg = vcombine_u8(v8_avg_low, v8_avg_high);
240
241 // Store U and V components
242 vst1_u8(uPlane + uIndex, u8_avg_low);
243 vst1_u8(vPlane + vIndex, v8_avg_low);
244 uIndex += 8;
245 vIndex += 8;
246 }
247 yIndex += width_; // Skip to the next line
248 }
249
250 return 0;
251}
252
253int CompressComponent::ReadBuffer(char* file_buffer, NvBuffer* buffer) {
254 uint32_t i = 0;
255 uint32_t j = 0;
256 char* data = nullptr;
257
258 for (i = 0; i < buffer->n_planes; i++) {
259 NvBuffer::NvBufferPlane& plane = buffer->planes[i];
260 int bytes_to_read = plane.fmt.bytesperpixel * plane.fmt.width;
261
262 data = reinterpret_cast<char*>(plane.data);
263 plane.bytesused = 0;
264 for (j = 0; j < plane.fmt.height; j++) {
265 memcpy(data, file_buffer, bytes_to_read);
266 data += plane.fmt.stride;
267 file_buffer += bytes_to_read;
268 }
269 plane.bytesused = plane.fmt.stride * plane.fmt.height;
270 }
271 return 0;
272}
273#endif
274
275} // namespace camera
276} // namespace drivers
277} // namespace apollo
bool GetProtoConfig(T *config) const
const std::string & ConfigFilePath() const
std::shared_ptr< Node > node_
bool Proc(const std::shared_ptr< apollo::drivers::Image > &image) override
#define cyber_unlikely(x)
Definition macros.h:28
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
class register implement
Definition arena_queue.h:37
optional CompressConfig compress_conf
Definition config.proto:58