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::UNKNOWN:
86         return "UNKNOWN";
87     }
88 }
89 
fourccToString(uint32_t fourcc)90 std::string fourccToString(uint32_t fourcc) {
91     std::string result = "0000";
92     for (size_t i = 0; i < 4; ++i, fourcc >>= 8) {
93         const char c = static_cast<char>(fourcc & 0xFF);
94         if (c <= 0x1f || c >= 0x7f) {
95             return (std::stringstream("0x") << std::hex << fourcc).str();
96         }
97         result[i] = c;
98     }
99     return result;
100 }
101 
bitDepth(VideoPixelFormat format)102 size_t bitDepth(VideoPixelFormat format) {
103     switch (format) {
104     case VideoPixelFormat::I420:
105     case VideoPixelFormat::YV12:
106     case VideoPixelFormat::I422:
107     case VideoPixelFormat::I420A:
108     case VideoPixelFormat::I444:
109     case VideoPixelFormat::NV12:
110     case VideoPixelFormat::NV21:
111     case VideoPixelFormat::YUY2:
112     case VideoPixelFormat::ARGB:
113     case VideoPixelFormat::XRGB:
114     case VideoPixelFormat::RGB24:
115     case VideoPixelFormat::MJPEG:
116     case VideoPixelFormat::ABGR:
117     case VideoPixelFormat::XBGR:
118     case VideoPixelFormat::BGRA:
119         return 8;
120     case VideoPixelFormat::YUV420P9:
121     case VideoPixelFormat::YUV422P9:
122     case VideoPixelFormat::YUV444P9:
123         return 9;
124     case VideoPixelFormat::YUV420P10:
125     case VideoPixelFormat::YUV422P10:
126     case VideoPixelFormat::YUV444P10:
127     case VideoPixelFormat::XR30:
128     case VideoPixelFormat::XB30:
129         return 10;
130     case VideoPixelFormat::YUV420P12:
131     case VideoPixelFormat::YUV422P12:
132     case VideoPixelFormat::YUV444P12:
133         return 12;
134     case VideoPixelFormat::Y16:
135     case VideoPixelFormat::P016LE:
136         return 16;
137     case VideoPixelFormat::UNKNOWN:
138         ALOGE("Invalid pixel format");
139         return 0;
140     }
141 }
142 
143 // If it is required to allocate aligned to multiple-of-two size overall for the
144 // frame of pixel |format|.
RequiresEvenSizeAllocation(VideoPixelFormat format)145 static bool RequiresEvenSizeAllocation(VideoPixelFormat format) {
146     switch (format) {
147     case VideoPixelFormat::ARGB:
148     case VideoPixelFormat::XRGB:
149     case VideoPixelFormat::RGB24:
150     case VideoPixelFormat::Y16:
151     case VideoPixelFormat::ABGR:
152     case VideoPixelFormat::XBGR:
153     case VideoPixelFormat::XR30:
154     case VideoPixelFormat::XB30:
155     case VideoPixelFormat::BGRA:
156         return false;
157     case VideoPixelFormat::NV12:
158     case VideoPixelFormat::NV21:
159     case VideoPixelFormat::I420:
160     case VideoPixelFormat::MJPEG:
161     case VideoPixelFormat::YUY2:
162     case VideoPixelFormat::YV12:
163     case VideoPixelFormat::I422:
164     case VideoPixelFormat::I444:
165     case VideoPixelFormat::YUV420P9:
166     case VideoPixelFormat::YUV422P9:
167     case VideoPixelFormat::YUV444P9:
168     case VideoPixelFormat::YUV420P10:
169     case VideoPixelFormat::YUV422P10:
170     case VideoPixelFormat::YUV444P10:
171     case VideoPixelFormat::YUV420P12:
172     case VideoPixelFormat::YUV422P12:
173     case VideoPixelFormat::YUV444P12:
174     case VideoPixelFormat::I420A:
175     case VideoPixelFormat::P016LE:
176         return true;
177     case VideoPixelFormat::UNKNOWN:
178         ALOGE("Invalid pixel format");
179         return false;
180     }
181 }
182 
numPlanes(VideoPixelFormat format)183 size_t numPlanes(VideoPixelFormat format) {
184     switch (format) {
185     case VideoPixelFormat::YUY2:
186     case VideoPixelFormat::ARGB:
187     case VideoPixelFormat::BGRA:
188     case VideoPixelFormat::XRGB:
189     case VideoPixelFormat::RGB24:
190     case VideoPixelFormat::MJPEG:
191     case VideoPixelFormat::Y16:
192     case VideoPixelFormat::ABGR:
193     case VideoPixelFormat::XBGR:
194     case VideoPixelFormat::XR30:
195     case VideoPixelFormat::XB30:
196         return 1;
197     case VideoPixelFormat::NV12:
198     case VideoPixelFormat::NV21:
199     case VideoPixelFormat::P016LE:
200         return 2;
201     case VideoPixelFormat::I420:
202     case VideoPixelFormat::YV12:
203     case VideoPixelFormat::I422:
204     case VideoPixelFormat::I444:
205     case VideoPixelFormat::YUV420P9:
206     case VideoPixelFormat::YUV422P9:
207     case VideoPixelFormat::YUV444P9:
208     case VideoPixelFormat::YUV420P10:
209     case VideoPixelFormat::YUV422P10:
210     case VideoPixelFormat::YUV444P10:
211     case VideoPixelFormat::YUV420P12:
212     case VideoPixelFormat::YUV422P12:
213     case VideoPixelFormat::YUV444P12:
214         return 3;
215     case VideoPixelFormat::I420A:
216         return 4;
217     case VideoPixelFormat::UNKNOWN:
218         // Note: VideoPixelFormat::UNKNOWN is used for end-of-stream frame.
219         return 0;
220     }
221 }
222 
allocationSize(VideoPixelFormat format,const android::ui::Size & coded_size)223 size_t allocationSize(VideoPixelFormat format, const android::ui::Size& coded_size) {
224     size_t total = 0;
225     for (size_t i = 0; i < numPlanes(format); ++i) {
226         android::ui::Size plane_size = planeSize(format, i, coded_size);
227         total += (plane_size.width * plane_size.height);
228     }
229 
230     return total;
231 }
232 
planeSize(VideoPixelFormat format,size_t plane,const android::ui::Size & coded_size)233 android::ui::Size planeSize(VideoPixelFormat format, size_t plane,
234                             const android::ui::Size& coded_size) {
235     ALOG_ASSERT(isValidPlane(plane, format));
236 
237     int width = coded_size.width;
238     int height = coded_size.height;
239     if (RequiresEvenSizeAllocation(format)) {
240         // Align to multiple-of-two size overall. This ensures that non-subsampled
241         // planes can be addressed by pixel with the same scaling as the subsampled
242         // planes.
243         width = base::bits::Align(width, 2);
244         height = base::bits::Align(height, 2);
245     }
246 
247     const android::ui::Size subsample = SampleSize(format, plane);
248     ALOG_ASSERT(width % subsample.width == 0);
249     ALOG_ASSERT(height % subsample.height == 0);
250     return android::ui::Size(bytesPerElement(format, plane) * width / subsample.width,
251                              height / subsample.height);
252 }
253 
planeHorizontalBitsPerPixel(VideoPixelFormat format,size_t plane)254 int planeHorizontalBitsPerPixel(VideoPixelFormat format, size_t plane) {
255     ALOG_ASSERT(isValidPlane(plane, format));
256     const int bitsPerElement = 8 * bytesPerElement(format, plane);
257     const int horizPixelsPerElement = SampleSize(format, plane).width;
258     ALOG_ASSERT(bitsPerElement % horizPixelsPerElement == 0);
259     return bitsPerElement / horizPixelsPerElement;
260 }
261 
planeBitsPerPixel(VideoPixelFormat format,size_t plane)262 int planeBitsPerPixel(VideoPixelFormat format, size_t plane) {
263     ALOG_ASSERT(isValidPlane(plane, format));
264     return planeHorizontalBitsPerPixel(format, plane) / SampleSize(format, plane).height;
265 }
266 
bytesPerElement(VideoPixelFormat format,size_t plane)267 int bytesPerElement(VideoPixelFormat format, size_t plane) {
268     ALOG_ASSERT(isValidPlane(format, plane));
269     switch (format) {
270     case VideoPixelFormat::ARGB:
271     case VideoPixelFormat::BGRA:
272     case VideoPixelFormat::XRGB:
273     case VideoPixelFormat::ABGR:
274     case VideoPixelFormat::XBGR:
275     case VideoPixelFormat::XR30:
276     case VideoPixelFormat::XB30:
277         return 4;
278     case VideoPixelFormat::RGB24:
279         return 3;
280     case VideoPixelFormat::Y16:
281     case VideoPixelFormat::YUY2:
282     case VideoPixelFormat::YUV420P9:
283     case VideoPixelFormat::YUV422P9:
284     case VideoPixelFormat::YUV444P9:
285     case VideoPixelFormat::YUV420P10:
286     case VideoPixelFormat::YUV422P10:
287     case VideoPixelFormat::YUV444P10:
288     case VideoPixelFormat::YUV420P12:
289     case VideoPixelFormat::YUV422P12:
290     case VideoPixelFormat::YUV444P12:
291     case VideoPixelFormat::P016LE:
292         return 2;
293     case VideoPixelFormat::NV12:
294     case VideoPixelFormat::NV21: {
295         static const int bytes_per_element[] = {1, 2};
296         ALOG_ASSERT(plane < base::size(bytes_per_element));
297         return bytes_per_element[plane];
298     }
299     case VideoPixelFormat::YV12:
300     case VideoPixelFormat::I420:
301     case VideoPixelFormat::I422:
302     case VideoPixelFormat::I420A:
303     case VideoPixelFormat::I444:
304         return 1;
305     case VideoPixelFormat::MJPEG:
306         return 0;
307     case VideoPixelFormat::UNKNOWN:
308         ALOGE("Invalid pixel format");
309         return 0;
310     }
311 }
312 
isValidPlane(VideoPixelFormat format,size_t plane)313 bool isValidPlane(VideoPixelFormat format, size_t plane) {
314     ALOG_ASSERT(numPlanes(format) <= static_cast<size_t>(kMaxPlanes));
315     return plane < numPlanes(format);
316 }
317 
SampleSize(VideoPixelFormat format,size_t plane)318 android::ui::Size SampleSize(VideoPixelFormat format, size_t plane) {
319     ALOG_ASSERT(isValidPlane(format, plane));
320 
321     switch (plane) {
322     case kYPlane:  // and kARGBPlane:
323     case kAPlane:
324         return android::ui::Size(1, 1);
325 
326     case kUPlane:  // and kUVPlane:
327     case kVPlane:
328         switch (format) {
329         case VideoPixelFormat::I444:
330         case VideoPixelFormat::YUV444P9:
331         case VideoPixelFormat::YUV444P10:
332         case VideoPixelFormat::YUV444P12:
333         case VideoPixelFormat::Y16:
334             return android::ui::Size(1, 1);
335 
336         case VideoPixelFormat::I422:
337         case VideoPixelFormat::YUV422P9:
338         case VideoPixelFormat::YUV422P10:
339         case VideoPixelFormat::YUV422P12:
340             return android::ui::Size(2, 1);
341 
342         case VideoPixelFormat::YV12:
343         case VideoPixelFormat::I420:
344         case VideoPixelFormat::I420A:
345         case VideoPixelFormat::NV12:
346         case VideoPixelFormat::NV21:
347         case VideoPixelFormat::YUV420P9:
348         case VideoPixelFormat::YUV420P10:
349         case VideoPixelFormat::YUV420P12:
350         case VideoPixelFormat::P016LE:
351             return android::ui::Size(2, 2);
352 
353         case VideoPixelFormat::UNKNOWN:
354         case VideoPixelFormat::YUY2:
355         case VideoPixelFormat::ARGB:
356         case VideoPixelFormat::XRGB:
357         case VideoPixelFormat::RGB24:
358         case VideoPixelFormat::MJPEG:
359         case VideoPixelFormat::ABGR:
360         case VideoPixelFormat::XBGR:
361         case VideoPixelFormat::XR30:
362         case VideoPixelFormat::XB30:
363         case VideoPixelFormat::BGRA:
364             ALOGE("Invalid pixel format");
365         }
366     }
367 
368     return android::ui::Size();
369 }
370 
371 }  // namespace android
372