blob: d46d119b7a8cabbdd0397ee43139ccad6f7794db [file] [log] [blame]
Ari Hausman-Cohen3eece6f2016-07-21 11:08:24 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
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
17#include "V4L2Gralloc.h"
18
19#include <linux/videodev2.h>
20
21#include <cstdlib>
22
23#include <hardware/camera3.h>
24#include <hardware/gralloc.h>
25#include <system/graphics.h>
26
27#include "Common.h"
28
29namespace v4l2_camera_hal {
30
31// Copy |height| lines from |src| to |dest|,
32// where |src| and |dest| may have different line lengths.
33void copyWithPadding(uint8_t* dest, const uint8_t* src, size_t dest_stride,
34 size_t src_stride, size_t height) {
35 size_t copy_stride = dest_stride;
36 if (copy_stride > src_stride) {
37 // Adding padding, not reducing. 0 out the extra memory.
38 memset(dest, 0, src_stride * height);
39 copy_stride = src_stride;
40 }
41 uint8_t* dest_line_start = dest;
42 const uint8_t* src_line_start = src;
43 for (size_t row = 0; row < height; ++row,
44 dest_line_start += dest_stride, src_line_start += src_stride) {
45 memcpy(dest_line_start, src_line_start, copy_stride);
46 }
47}
48
Ari Hausman-Cohen681eaa22016-07-21 16:28:17 -070049V4L2Gralloc* V4L2Gralloc::NewV4L2Gralloc() {
50 HAL_LOG_ENTER();
51
52 // Initialize and check the gralloc module.
53 const hw_module_t* module = nullptr;
54 int res = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
55 if (res || !module) {
56 HAL_LOGE("Couldn't get gralloc module.");
57 return nullptr;
58 }
59 const gralloc_module_t* gralloc =
60 reinterpret_cast<const gralloc_module_t*>(module);
61
62 // This class only supports Gralloc v0, not Gralloc V1.
63 if (gralloc->common.module_api_version > GRALLOC_MODULE_API_VERSION_0_3) {
64 HAL_LOGE("Invalid gralloc version %x. Only 0.3 (%x) "
65 "and below are supported by this HAL.",
66 gralloc->common.module_api_version,
67 GRALLOC_MODULE_API_VERSION_0_3);
68 return nullptr;
69 }
70
71 return new V4L2Gralloc(gralloc);
72}
73
74// Private. As checked by above factory, module will be non-null
75// and a supported version.
Ari Hausman-Cohen3eece6f2016-07-21 11:08:24 -070076V4L2Gralloc::V4L2Gralloc(const gralloc_module_t* module)
77 : mModule(module) {
78 HAL_LOG_ENTER();
79}
80
81V4L2Gralloc::~V4L2Gralloc() {
82 HAL_LOG_ENTER();
83
84 // Unlock buffers that are still locked.
85 for (auto const& entry : mBufferMap) {
86 mModule->unlock(mModule, *entry.second->camera_buffer->buffer);
87 // Clean up dynamically allocated stuff.
88 if (entry.second->transform_dest) {
89 delete [] reinterpret_cast<uint8_t*>(entry.first);
90 }
91 delete entry.second;
92 }
93}
94
Ari Hausman-Cohen3eece6f2016-07-21 11:08:24 -070095int V4L2Gralloc::lock(const camera3_stream_buffer_t* camera_buffer,
96 uint32_t bytes_per_line,
97 /*out*/ v4l2_buffer* device_buffer) {
98 HAL_LOG_ENTER();
99
100 // Lock the camera buffer (varies depending on if the buffer is YUV or not).
101 std::unique_ptr<BufferData> buffer_data(new BufferData {
102 camera_buffer, nullptr, bytes_per_line});
103 buffer_handle_t buffer = *camera_buffer->buffer;
104 void* data;
105 size_t size;
106 camera3_stream_t* stream = camera_buffer->stream;
107 switch(stream->format) {
108 // TODO(b/30119452): support more YCbCr formats.
109 case HAL_PIXEL_FORMAT_YCbCr_420_888:
110 android_ycbcr yuv_data;
111 mModule->lock_ycbcr(mModule, buffer, stream->usage, 0, 0,
112 stream->width, stream->height, &yuv_data);
113 // YUV_420_888 = 1.5 planes (1 Y plane, 1/4 Cb, 1/4 Cr).
114 size = bytes_per_line * stream->height * 3 / 2;
115
116 // Check if gralloc format matches v4l2 format
117 // (same padding, not interleaved, contiguous).
118 if (yuv_data.ystride == bytes_per_line &&
119 yuv_data.cstride == bytes_per_line / 2 &&
120 yuv_data.chroma_step == 1 &&
121 (reinterpret_cast<uint8_t*>(yuv_data.cb) ==
122 reinterpret_cast<uint8_t*>(yuv_data.y) +
123 (stream->height * yuv_data.ystride)) &&
124 (reinterpret_cast<uint8_t*>(yuv_data.cr) ==
125 reinterpret_cast<uint8_t*>(yuv_data.cb) +
126 (stream->height / 2 * yuv_data.cstride))) {
127 // If so, great, point to the beginning.
128 HAL_LOGV("V4L2 YUV matches gralloc YUV.");
129 data = yuv_data.y;
130 } else {
131 // If not, allocate a contiguous buffer of appropriate size
132 // (to be transformed back upon unlock).
133 HAL_LOGV("Need to transform V4L2 YUV to gralloc YUV.");
134 data = new uint8_t[size];
135 // Make a dynamically-allocated copy of yuv_data,
136 // since it will be needed at transform time.
137 buffer_data->transform_dest.reset(new android_ycbcr(yuv_data));
138 }
139 break;
140 case HAL_PIXEL_FORMAT_BLOB:
141 // Jpeg buffers are just contiguous blobs; always max_size * 1.
142 size = V4L2_MAX_JPEG_SIZE;
143 mModule->lock(mModule, buffer, stream->usage, 0, 0, size, 1, &data);
144 break;
145 default:
146 return -EINVAL;
147 }
148
149 // Set up the device buffer.
150 static_assert(sizeof(unsigned long) >= sizeof(void*),
151 "void* must be able to fit in the v4l2_buffer m.userptr "
152 "field (unsigned long) for this code to work");
153 device_buffer->m.userptr = reinterpret_cast<unsigned long>(data);
154 device_buffer->length = size;
155
156 // Note the mapping of data:buffer info for when unlock is called.
157 mBufferMap.emplace(data, buffer_data.release());
158
159 return 0;
160}
161
162int V4L2Gralloc::unlock(const v4l2_buffer* device_buffer) {
163 HAL_LOG_ENTER();
164
165 // TODO(b/30000211): support multi-planar data (video_capture_mplane).
166 if (device_buffer->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
167 return -EINVAL;
168 }
169
170 void* data = reinterpret_cast<void*>(device_buffer->m.userptr);
171
172 // Find and pop the matching entry in the map.
173 auto map_entry = mBufferMap.find(data);
174 if (map_entry == mBufferMap.end()) {
175 HAL_LOGE("No matching buffer for data at %p", data);
176 return -EINVAL;
177 }
178 std::unique_ptr<const BufferData> buffer_data(map_entry->second);
179 mBufferMap.erase(map_entry);
180
181 const camera3_stream_buffer_t* camera_buffer = buffer_data->camera_buffer;
182 const buffer_handle_t buffer = *camera_buffer->buffer;
183
184 // Check for transform.
185 if (buffer_data->transform_dest) {
186 HAL_LOGV("Transforming V4L2 YUV to gralloc YUV.");
187 // In this case data was allocated by this class, put it in a unique_ptr
188 // to ensure it gets cleaned up no matter which way this function exits.
189 std::unique_ptr<uint8_t[]> data_cleanup(reinterpret_cast<uint8_t*>(data));
190
191 uint32_t bytes_per_line = buffer_data->v4l2_bytes_per_line;
192 android_ycbcr* yuv_data = buffer_data->transform_dest.get();
193
194 // Should only occur in error situations.
195 if (device_buffer->bytesused == 0) {
196 return -EINVAL;
197 }
198
199 // Transform V4L2 to Gralloc, copying each plane to the correct place,
200 // adjusting padding, and interleaving if necessary.
201 uint32_t height = camera_buffer->stream->height;
202 // Y data first.
203 size_t y_len = bytes_per_line * height;
204 if (yuv_data->ystride == bytes_per_line) {
205 // Data should match exactly.
206 memcpy(yuv_data->y, data, y_len);
207 } else {
208 HAL_LOGV("Changing padding on Y plane from %u to %u.",
209 bytes_per_line, yuv_data->ystride);
210 // Wrong padding from V4L2.
211 copyWithPadding(reinterpret_cast<uint8_t*>(yuv_data->y),
212 reinterpret_cast<uint8_t*>(data),
213 yuv_data->ystride, bytes_per_line, height);
214 }
215 // C data.
216 // TODO(b/30119452): These calculations assume YCbCr_420_888.
217 size_t c_len = y_len / 4;
218 uint32_t c_bytes_per_line = bytes_per_line / 2;
219 // V4L2 is packed, meaning the data is stored as contiguous {y, cb, cr}.
220 uint8_t* cb_device = reinterpret_cast<uint8_t*>(data) + y_len;
221 uint8_t* cr_device = cb_device + c_len;
222 size_t step = yuv_data->chroma_step;
223 if (step == 1) {
224 // Still planar.
225 if (yuv_data->cstride == c_bytes_per_line) {
226 // Data should match exactly.
227 memcpy(yuv_data->cb, cb_device, c_len);
228 memcpy(yuv_data->cr, cr_device, c_len);
229 } else {
230 HAL_LOGV("Changing padding on C plane from %u to %u.",
231 c_bytes_per_line, yuv_data->cstride);
232 // Wrong padding from V4L2.
233 copyWithPadding(reinterpret_cast<uint8_t*>(yuv_data->cb),
234 cb_device, yuv_data->cstride,
235 c_bytes_per_line, height / 2);
236 copyWithPadding(reinterpret_cast<uint8_t*>(yuv_data->cr),
237 cr_device, yuv_data->cstride,
238 c_bytes_per_line, height / 2);
239 }
240 } else {
241 // Desire semiplanar (cb and cr interleaved).
242 HAL_LOGV("Interleaving cb and cr. Padding going from %u to %u.",
243 c_bytes_per_line, yuv_data->cstride);
244 uint32_t c_height = height / 2;
245 uint32_t c_width = camera_buffer->stream->width / 2;
246 // Zero out destination
247 uint8_t* cb_gralloc = reinterpret_cast<uint8_t*>(yuv_data->cb);
248 uint8_t* cr_gralloc = reinterpret_cast<uint8_t*>(yuv_data->cr);
249 memset(cb_gralloc, 0, c_width * c_height * step);
250
251 // Interleaving means we need to copy the cb and cr bytes one by one.
252 for (size_t line = 0; line < c_height; ++line,
253 cb_gralloc += yuv_data->cstride, cr_gralloc += yuv_data->cstride,
254 cb_device += c_bytes_per_line, cr_device += c_bytes_per_line) {
255 for (size_t i = 0; i < c_width; ++i) {
256 *(cb_gralloc + (i * step)) = *(cb_device + i);
257 *(cr_gralloc + (i * step)) = *(cr_device + i);
258 }
259 }
260 }
261 }
262
263 // Unlock.
264 int res = mModule->unlock(mModule, buffer);
265 if (res) {
266 HAL_LOGE("Failed to unlock buffer at %p", buffer);
267 return -ENODEV;
268 }
269
270 return 0;
271}
272
273} // namespace default_camera_hal