1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 // Note: ported from Chromium commit head: 3b7ce92816e2
5 // Note: only necessary functions are ported from video_types.cc
6
7 #include <v4l2_codec2/common/VideoPixelFormat.h>
8
9 #include <base/bits.h>
10 #include <utils/Log.h>
11
12 namespace android {
13
14 namespace {
15
16 enum {
17 kMaxPlanes = 4,
18 kYPlane = 0,
19 kARGBPlane = kYPlane,
20 kUPlane = 1,
21 kUVPlane = kUPlane,
22 kVPlane = 2,
23 kAPlane = 3,
24 };
25 }
26
videoPixelFormatToString(VideoPixelFormat format)27 std::string videoPixelFormatToString(VideoPixelFormat format) {
28 switch (format) {
29 case VideoPixelFormat::I420:
30 return "I420";
31 case VideoPixelFormat::YV12:
32 return "YV12";
33 case VideoPixelFormat::I422:
34 return "I422";
35 case VideoPixelFormat::I420A:
36 return "I420A";
37 case VideoPixelFormat::I444:
38 return "I444";
39 case VideoPixelFormat::NV12:
40 return "NV12";
41 case VideoPixelFormat::NV21:
42 return "NV21";
43 case VideoPixelFormat::YUY2:
44 return "YUY2";
45 case VideoPixelFormat::ARGB:
46 return "ARGB";
47 case VideoPixelFormat::XRGB:
48 return "XRGB";
49 case VideoPixelFormat::RGB24:
50 return "RGB24";
51 case VideoPixelFormat::MJPEG:
52 return "MJPEG";
53 case VideoPixelFormat::YUV420P9:
54 return "YUV420P9";
55 case VideoPixelFormat::YUV420P10:
56 return "YUV420P10";
57 case VideoPixelFormat::YUV422P9:
58 return "YUV422P9";
59 case VideoPixelFormat::YUV422P10:
60 return "YUV422P10";
61 case VideoPixelFormat::YUV444P9:
62 return "YUV444P9";
63 case VideoPixelFormat::YUV444P10:
64 return "YUV444P10";
65 case VideoPixelFormat::YUV420P12:
66 return "YUV420P12";
67 case VideoPixelFormat::YUV422P12:
68 return "YUV422P12";
69 case VideoPixelFormat::YUV444P12:
70 return "YUV444P12";
71 case VideoPixelFormat::Y16:
72 return "Y16";
73 case VideoPixelFormat::ABGR:
74 return "ABGR";
75 case VideoPixelFormat::XBGR:
76 return "XBGR";
77 case VideoPixelFormat::P016LE:
78 return "P016LE";
79 case VideoPixelFormat::XR30:
80 return "XR30";
81 case VideoPixelFormat::XB30:
82 return "XB30";
83 case VideoPixelFormat::BGRA:
84 return "BGRA";
85 case VideoPixelFormat::RGBA:
86 return "BGRA";
87 case VideoPixelFormat::UNKNOWN:
88 return "UNKNOWN";
89 }
90 }
91
fourccToString(uint32_t fourcc)92 std::string fourccToString(uint32_t fourcc) {
93 std::string result = "0000";
94 for (size_t i = 0; i < 4; ++i, fourcc >>= 8) {
95 const char c = static_cast<char>(fourcc & 0xFF);
96 if (c <= 0x1f || c >= 0x7f) {
97 return (std::stringstream("0x") << std::hex << fourcc).str();
98 }
99 result[i] = c;
100 }
101 return result;
102 }
103
bitDepth(VideoPixelFormat format)104 size_t bitDepth(VideoPixelFormat format) {
105 switch (format) {
106 case VideoPixelFormat::I420:
107 case VideoPixelFormat::YV12:
108 case VideoPixelFormat::I422:
109 case VideoPixelFormat::I420A:
110 case VideoPixelFormat::I444:
111 case VideoPixelFormat::NV12:
112 case VideoPixelFormat::NV21:
113 case VideoPixelFormat::YUY2:
114 case VideoPixelFormat::ARGB:
115 case VideoPixelFormat::XRGB:
116 case VideoPixelFormat::RGB24:
117 case VideoPixelFormat::MJPEG:
118 case VideoPixelFormat::ABGR:
119 case VideoPixelFormat::XBGR:
120 case VideoPixelFormat::BGRA:
121 case VideoPixelFormat::RGBA:
122 return 8;
123 case VideoPixelFormat::YUV420P9:
124 case VideoPixelFormat::YUV422P9:
125 case VideoPixelFormat::YUV444P9:
126 return 9;
127 case VideoPixelFormat::YUV420P10:
128 case VideoPixelFormat::YUV422P10:
129 case VideoPixelFormat::YUV444P10:
130 case VideoPixelFormat::XR30:
131 case VideoPixelFormat::XB30:
132 return 10;
133 case VideoPixelFormat::YUV420P12:
134 case VideoPixelFormat::YUV422P12:
135 case VideoPixelFormat::YUV444P12:
136 return 12;
137 case VideoPixelFormat::Y16:
138 case VideoPixelFormat::P016LE:
139 return 16;
140 case VideoPixelFormat::UNKNOWN:
141 ALOGE("Invalid pixel format");
142 return 0;
143 }
144 }
145
146 // If it is required to allocate aligned to multiple-of-two size overall for the
147 // frame of pixel |format|.
RequiresEvenSizeAllocation(VideoPixelFormat format)148 static bool RequiresEvenSizeAllocation(VideoPixelFormat format) {
149 switch (format) {
150 case VideoPixelFormat::ARGB:
151 case VideoPixelFormat::XRGB:
152 case VideoPixelFormat::RGB24:
153 case VideoPixelFormat::Y16:
154 case VideoPixelFormat::ABGR:
155 case VideoPixelFormat::XBGR:
156 case VideoPixelFormat::XR30:
157 case VideoPixelFormat::XB30:
158 case VideoPixelFormat::BGRA:
159 case VideoPixelFormat::RGBA:
160 return false;
161 case VideoPixelFormat::NV12:
162 case VideoPixelFormat::NV21:
163 case VideoPixelFormat::I420:
164 case VideoPixelFormat::MJPEG:
165 case VideoPixelFormat::YUY2:
166 case VideoPixelFormat::YV12:
167 case VideoPixelFormat::I422:
168 case VideoPixelFormat::I444:
169 case VideoPixelFormat::YUV420P9:
170 case VideoPixelFormat::YUV422P9:
171 case VideoPixelFormat::YUV444P9:
172 case VideoPixelFormat::YUV420P10:
173 case VideoPixelFormat::YUV422P10:
174 case VideoPixelFormat::YUV444P10:
175 case VideoPixelFormat::YUV420P12:
176 case VideoPixelFormat::YUV422P12:
177 case VideoPixelFormat::YUV444P12:
178 case VideoPixelFormat::I420A:
179 case VideoPixelFormat::P016LE:
180 return true;
181 case VideoPixelFormat::UNKNOWN:
182 ALOGE("Invalid pixel format");
183 return false;
184 }
185 }
186
numPlanes(VideoPixelFormat format)187 size_t numPlanes(VideoPixelFormat format) {
188 switch (format) {
189 case VideoPixelFormat::YUY2:
190 case VideoPixelFormat::ARGB:
191 case VideoPixelFormat::BGRA:
192 case VideoPixelFormat::RGBA:
193 case VideoPixelFormat::XRGB:
194 case VideoPixelFormat::RGB24:
195 case VideoPixelFormat::MJPEG:
196 case VideoPixelFormat::Y16:
197 case VideoPixelFormat::ABGR:
198 case VideoPixelFormat::XBGR:
199 case VideoPixelFormat::XR30:
200 case VideoPixelFormat::XB30:
201 return 1;
202 case VideoPixelFormat::NV12:
203 case VideoPixelFormat::NV21:
204 case VideoPixelFormat::P016LE:
205 return 2;
206 case VideoPixelFormat::I420:
207 case VideoPixelFormat::YV12:
208 case VideoPixelFormat::I422:
209 case VideoPixelFormat::I444:
210 case VideoPixelFormat::YUV420P9:
211 case VideoPixelFormat::YUV422P9:
212 case VideoPixelFormat::YUV444P9:
213 case VideoPixelFormat::YUV420P10:
214 case VideoPixelFormat::YUV422P10:
215 case VideoPixelFormat::YUV444P10:
216 case VideoPixelFormat::YUV420P12:
217 case VideoPixelFormat::YUV422P12:
218 case VideoPixelFormat::YUV444P12:
219 return 3;
220 case VideoPixelFormat::I420A:
221 return 4;
222 case VideoPixelFormat::UNKNOWN:
223 // Note: VideoPixelFormat::UNKNOWN is used for end-of-stream frame.
224 return 0;
225 }
226 }
227
allocationSize(VideoPixelFormat format,const android::ui::Size & coded_size)228 size_t allocationSize(VideoPixelFormat format, const android::ui::Size& coded_size) {
229 size_t total = 0;
230 for (size_t i = 0; i < numPlanes(format); ++i) {
231 android::ui::Size plane_size = planeSize(format, i, coded_size);
232 total += (plane_size.width * plane_size.height);
233 }
234
235 return total;
236 }
237
planeSize(VideoPixelFormat format,size_t plane,const android::ui::Size & coded_size)238 android::ui::Size planeSize(VideoPixelFormat format, size_t plane,
239 const android::ui::Size& coded_size) {
240 ALOG_ASSERT(isValidPlane(plane, format));
241
242 int width = coded_size.width;
243 int height = coded_size.height;
244 if (RequiresEvenSizeAllocation(format)) {
245 // Align to multiple-of-two size overall. This ensures that non-subsampled
246 // planes can be addressed by pixel with the same scaling as the subsampled
247 // planes.
248 width = base::bits::Align(width, 2);
249 height = base::bits::Align(height, 2);
250 }
251
252 const android::ui::Size subsample = SampleSize(format, plane);
253 ALOG_ASSERT(width % subsample.width == 0);
254 ALOG_ASSERT(height % subsample.height == 0);
255 return android::ui::Size(bytesPerElement(format, plane) * width / subsample.width,
256 height / subsample.height);
257 }
258
planeHorizontalBitsPerPixel(VideoPixelFormat format,size_t plane)259 int planeHorizontalBitsPerPixel(VideoPixelFormat format, size_t plane) {
260 ALOG_ASSERT(isValidPlane(plane, format));
261 const int bitsPerElement = 8 * bytesPerElement(format, plane);
262 const int horizPixelsPerElement = SampleSize(format, plane).width;
263 ALOG_ASSERT(bitsPerElement % horizPixelsPerElement == 0);
264 return bitsPerElement / horizPixelsPerElement;
265 }
266
planeBitsPerPixel(VideoPixelFormat format,size_t plane)267 int planeBitsPerPixel(VideoPixelFormat format, size_t plane) {
268 ALOG_ASSERT(isValidPlane(plane, format));
269 return planeHorizontalBitsPerPixel(format, plane) / SampleSize(format, plane).height;
270 }
271
bytesPerElement(VideoPixelFormat format,size_t plane)272 int bytesPerElement(VideoPixelFormat format, size_t plane) {
273 ALOG_ASSERT(isValidPlane(format, plane));
274 switch (format) {
275 case VideoPixelFormat::ARGB:
276 case VideoPixelFormat::BGRA:
277 case VideoPixelFormat::RGBA:
278 case VideoPixelFormat::XRGB:
279 case VideoPixelFormat::ABGR:
280 case VideoPixelFormat::XBGR:
281 case VideoPixelFormat::XR30:
282 case VideoPixelFormat::XB30:
283 return 4;
284 case VideoPixelFormat::RGB24:
285 return 3;
286 case VideoPixelFormat::Y16:
287 case VideoPixelFormat::YUY2:
288 case VideoPixelFormat::YUV420P9:
289 case VideoPixelFormat::YUV422P9:
290 case VideoPixelFormat::YUV444P9:
291 case VideoPixelFormat::YUV420P10:
292 case VideoPixelFormat::YUV422P10:
293 case VideoPixelFormat::YUV444P10:
294 case VideoPixelFormat::YUV420P12:
295 case VideoPixelFormat::YUV422P12:
296 case VideoPixelFormat::YUV444P12:
297 case VideoPixelFormat::P016LE:
298 return 2;
299 case VideoPixelFormat::NV12:
300 case VideoPixelFormat::NV21: {
301 static const int bytes_per_element[] = {1, 2};
302 ALOG_ASSERT(plane < base::size(bytes_per_element));
303 return bytes_per_element[plane];
304 }
305 case VideoPixelFormat::YV12:
306 case VideoPixelFormat::I420:
307 case VideoPixelFormat::I422:
308 case VideoPixelFormat::I420A:
309 case VideoPixelFormat::I444:
310 return 1;
311 case VideoPixelFormat::MJPEG:
312 return 0;
313 case VideoPixelFormat::UNKNOWN:
314 ALOGE("Invalid pixel format");
315 return 0;
316 }
317 }
318
isValidPlane(VideoPixelFormat format,size_t plane)319 bool isValidPlane(VideoPixelFormat format, size_t plane) {
320 ALOG_ASSERT(numPlanes(format) <= static_cast<size_t>(kMaxPlanes));
321 return plane < numPlanes(format);
322 }
323
SampleSize(VideoPixelFormat format,size_t plane)324 android::ui::Size SampleSize(VideoPixelFormat format, size_t plane) {
325 ALOG_ASSERT(isValidPlane(format, plane));
326
327 switch (plane) {
328 case kYPlane: // and kARGBPlane:
329 case kAPlane:
330 return android::ui::Size(1, 1);
331
332 case kUPlane: // and kUVPlane:
333 case kVPlane:
334 switch (format) {
335 case VideoPixelFormat::I444:
336 case VideoPixelFormat::YUV444P9:
337 case VideoPixelFormat::YUV444P10:
338 case VideoPixelFormat::YUV444P12:
339 case VideoPixelFormat::Y16:
340 return android::ui::Size(1, 1);
341
342 case VideoPixelFormat::I422:
343 case VideoPixelFormat::YUV422P9:
344 case VideoPixelFormat::YUV422P10:
345 case VideoPixelFormat::YUV422P12:
346 return android::ui::Size(2, 1);
347
348 case VideoPixelFormat::YV12:
349 case VideoPixelFormat::I420:
350 case VideoPixelFormat::I420A:
351 case VideoPixelFormat::NV12:
352 case VideoPixelFormat::NV21:
353 case VideoPixelFormat::YUV420P9:
354 case VideoPixelFormat::YUV420P10:
355 case VideoPixelFormat::YUV420P12:
356 case VideoPixelFormat::P016LE:
357 return android::ui::Size(2, 2);
358
359 case VideoPixelFormat::UNKNOWN:
360 case VideoPixelFormat::YUY2:
361 case VideoPixelFormat::ARGB:
362 case VideoPixelFormat::XRGB:
363 case VideoPixelFormat::RGB24:
364 case VideoPixelFormat::MJPEG:
365 case VideoPixelFormat::ABGR:
366 case VideoPixelFormat::XBGR:
367 case VideoPixelFormat::XR30:
368 case VideoPixelFormat::XB30:
369 case VideoPixelFormat::BGRA:
370 case VideoPixelFormat::RGBA:
371 ALOGE("Invalid pixel format");
372 }
373 }
374
375 return android::ui::Size();
376 }
377
378 } // namespace android
379