Yuv12.h
1/* Copyright (C) 2016 Marc Boris Duerner
2
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Lesser General Public
5 License as published by the Free Software Foundation; either
6 version 2.1 of the License, or (at your option) any later version.
7
8 As a special exception, you may use this file as part of a free
9 software library without restriction. Specifically, if other files
10 instantiate templates or use macros or inline functions from this
11 file, or you compile this file and link it with other files to
12 produce an executable, this file does not by itself cause the
13 resulting executable to be covered by the GNU General Public
14 License. This exception does not however invalidate any other
15 reasons why the executable file might be covered by the GNU Library
16 General Public License.
17
18 This library is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
22
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 MA 02110-1301 USA
27*/
28
29#ifndef PT_GFX_YUV12_H
30#define PT_GFX_YUV12_H
31
32#include <Pt/Gfx/Api.h>
33#include <Pt/Gfx/ImageFormat.h>
34#include <Pt/Gfx/Color.h>
35#include <Pt/Types.h>
36
37namespace Pt {
38
39namespace Gfx {
40
43class PT_GFX_API Yuv12Pixel
44{
45 friend class Yuv12;
46 friend class Yuv12ConstPixel;
47
48 public:
49 typedef Yuv12 FormatType;
50 typedef ColorF ColorType;
51
52 protected:
53 Yuv12Pixel(Pt::uint8_t* data, const ViewBase& view,
54 Pt::ssize_t x, Pt::ssize_t y);
55
56 public:
57 template <typename T>
58 Yuv12Pixel(T& view, Pt::ssize_t xpos, Pt::ssize_t ypos);
59
60 Yuv12Pixel(const Yuv12Pixel& p)
61 : _view(p._view)
62 , _xpos(p._xpos)
63 , _ypos(p._ypos)
64 , _subStride(p._subStride)
65 , _y(p._y)
66 , _u(p._u)
67 , _v(p._v)
68 { }
69
70 Yuv12Pixel& operator=(const Yuv12Pixel&) = delete;
71
72 Yuv12Pixel& operator=(const ColorF& color);
73
74 const ViewBase& view() const
75 { return _view; }
76
77 Pt::ssize_t xpos() const
78 { return _xpos; }
79
80 Pt::ssize_t ypos() const
81 { return _ypos; }
82
83 Pt::uint8_t* ybase() const
84 { return _y; }
85
86 Pt::uint8_t* ubase() const
87 { return _u; }
88
89 Pt::uint8_t* vbase() const
90 { return _v; }
91
92 Pt::uint8_t y() const
93 { return *_y; }
94
95 void setY(Pt::uint8_t y) const
96 { *_y = y; }
97
98 Pt::uint8_t u() const
99 { return *_u; }
100
101 void setU(Pt::uint8_t u) const
102 { *_u = u; }
103
104 Pt::uint8_t v() const
105 { return *_v; }
106
107 void setV(Pt::uint8_t v) const
108 { *_v = v; }
109
110 ColorF getColor() const;
111
112 void advance();
113
114 void skipPadding();
115
116 void advance(Pt::ssize_t n);
117
118 void advanceLines(Pt::ssize_t n);
119
120 bool equals(const Yuv12Pixel& p) const;
121
122 bool equals(const Yuv12ConstPixel& p) const;
123
124 private:
125 const ViewBase& _view;
126 Pt::ssize_t _xpos;
127 Pt::ssize_t _ypos;
128 Pt::ssize_t _subStride;
129 Pt::uint8_t* _y;
130 Pt::uint8_t* _u;
131 Pt::uint8_t* _v;
132};
133
136class Yuv12ConstPixel
137{
138 friend class Yuv12;
139 friend class Yuv12Pixel;
140
141 public:
142 typedef Yuv12 FormatType;
143 typedef ColorF ColorType;
144
145 protected:
146 Yuv12ConstPixel(const Pt::uint8_t* data, const ViewBase& view,
147 Pt::ssize_t xpos, Pt::ssize_t ypos);
148
149 public:
150 template <typename T>
151 Yuv12ConstPixel(const T& view, Pt::ssize_t xpos, Pt::ssize_t ypos);
152
153 template <typename T>
154 Yuv12ConstPixel(T& view, Pt::ssize_t xpos, Pt::ssize_t ypos);
155
156 Yuv12ConstPixel(const Yuv12ConstPixel& p)
157 : _view(p._view)
158 , _xpos(p._xpos)
159 , _ypos(p._ypos)
160 , _subStride(p._subStride)
161 , _y(p._y)
162 , _u(p._u)
163 , _v(p._v)
164 { }
165
166 explicit Yuv12ConstPixel(const Yuv12Pixel& p)
167 : _view(p._view)
168 , _xpos(p._xpos)
169 , _ypos(p._ypos)
170 , _subStride(p._subStride)
171 , _y(p._y)
172 , _u(p._u)
173 , _v(p._v)
174 { }
175
176 Yuv12ConstPixel& operator=(const Yuv12ConstPixel&) = delete;
177
178 const ViewBase& view() const
179 { return _view; }
180
181 Pt::ssize_t xpos() const
182 { return _xpos; }
183
184 Pt::ssize_t ypos() const
185 { return _ypos; }
186
187 const Pt::uint8_t* ybase() const
188 { return _y; }
189
190 const Pt::uint8_t* ubase() const
191 { return _u; }
192
193 const Pt::uint8_t* vbase() const
194 { return _v; }
195
196 Pt::uint8_t y() const
197 { return *_y; }
198
199 Pt::uint8_t u() const
200 { return *_u; }
201
202 Pt::uint8_t v() const
203 { return *_v; }
204
205 ColorF getColor() const;
206
207 void advance();
208
209 void skipPadding();
210
211 void advance(Pt::ssize_t n);
212
213 void advanceLines(Pt::ssize_t n);
214
215 bool equals(const Yuv12ConstPixel& p) const
216 { return _y == p._y; }
217
218 bool equals(const Yuv12Pixel& p) const
219 { return _y == p._y; }
220
221 private:
222 const ViewBase& _view;
223 Pt::ssize_t _xpos;
224 Pt::ssize_t _ypos;
225 Pt::ssize_t _subStride;
226 const Pt::uint8_t* _y;
227 const Pt::uint8_t* _u;
228 const Pt::uint8_t* _v;
229};
230
233class PT_GFX_API Yuv12 final : public ImageFormat
234{
235 public:
236 typedef Yuv12Pixel Pixel;
237 typedef Yuv12ConstPixel ConstPixel;
238
239 public:
240 static const Yuv12& get()
241 {
242 static Yuv12 _yuv12;
243 return _yuv12;
244 }
245
246 public:
247 Yuv12();
248
249 Pt::ssize_t pixelStride() const
250 {
251 return 1;
252 }
253
254 std::size_t imageSize(std::size_t width, std::size_t height,
255 std::size_t padding) const
256 {
257 Pt::ssize_t stride = width + padding;
258 Pt::ssize_t planeSize = stride * height;
259
260 return planeSize + planeSize / 2;
261 }
262
263 protected:
264 virtual std::unique_ptr<ImageFormat> onClone() const override
265 {
266 return std::unique_ptr<ImageFormat>(new Yuv12);
267 }
268
269 virtual const std::type_info& onGetType() const override
270 {
271 return typeid(*this);
272 }
273
274 virtual std::size_t onImageSize(Pt::ssize_t width, Pt::ssize_t height,
275 std::size_t padding) const override;
276
277 virtual PixelBase* onCreatePixel(Pt::uint8_t* data, const ViewBase& view,
278 Pt::ssize_t x, Pt::ssize_t y,
279 PixelStorage& store) const override;
280
281 public:
282 template <typename T>
283 static void advance(T*& y, T*& u, T*& v,
284 Pt::ssize_t& xpos,
285 Pt::ssize_t uvstride)
286 {
287 ++y;
288 ++xpos;
289
290 if(xpos % 2 == 0)
291 {
292 ++u;
293 ++v;
294 }
295 }
296
297 template <typename T>
298 static void advanceN(T*& y, T*& u, T*& v,
299 Pt::ssize_t& xpos,
300 Pt::ssize_t n)
301 {
302 Pt::ssize_t old_u_col = xpos / 2;
303 Pt::ssize_t new_u_col = (xpos + n) / 2;
304
305 y += n;
306 xpos += n;
307
308 Pt::ssize_t uv_diff = new_u_col - old_u_col;
309 u += uv_diff;
310 v += uv_diff;
311 }
312
313 template <typename T>
314 static void skipPadding(T*& y, T*& u, T*& v,
315 Pt::ssize_t& xpos, Pt::ssize_t& ypos,
316 Pt::ssize_t padding, Pt::ssize_t uvstride)
317 {
318 ++u;
319 ++v;
320
321 if(ypos % 2 == 0)
322 {
323 u -= uvstride;
324 v -= uvstride;
325 }
326
327 xpos = 0;
328 ++ypos;
329 y += padding;
330 }
331
332 template <typename T>
333 static void advanceLines(T*& y, T*& u, T*& v,
334 Pt::ssize_t& ypos,
335 Pt::ssize_t n,
336 Pt::ssize_t ystride,
337 Pt::ssize_t uvstride)
338 {
339 Pt::ssize_t old_u_row = ypos / 2;
340 Pt::ssize_t new_u_row = (ypos + n) / 2;
341
342 y += n * ystride;
343 ypos += n;
344
345 Pt::ssize_t uv_diff = (new_u_row - old_u_row) * uvstride;
346 u += uv_diff;
347 v += uv_diff;
348 }
349
350 public:
351 static ColorF getColorF(Pt::uint8_t y, Pt::uint8_t u, Pt::uint8_t v)
352 {
353 const float ym = static_cast<float>(y) - 16.f;
354 const float um = static_cast<float>(u) - 128.f;
355 const float vm = static_cast<float>(v) - 128.f;
356 const float scale = 1.f / 65535.f;
357
358 const float r = (298.f * ym + 409.f * vm + 128.f) * scale;
359 const float g = (298.f * ym - 100.f * um - 208.f * vm + 128.f) * scale;
360 const float b = (298.f * ym + 516.f * um + 128.f) * scale;
361
362 return ColorF(r, g, b);
363 }
364
365 static void fromColor(Pt::uint8_t* y, Pt::uint8_t* u, Pt::uint8_t* v,
366 const ColorF& color)
367 {
368 const float r = color.red() * 65535.f;
369 const float g = color.green() * 65535.f;
370 const float b = color.blue() * 65535.f;
371 const float scale = 1.f / 65536.f;
372
373 const float yy = ( 66.f * r + 129.f * g + 25.f * b + 128.f) * scale + 16.f;
374 const float uu = (-38.f * r - 74.f * g + 112.f * b + 128.f) * scale + 128.f;
375 const float vv = (112.f * r - 94.f * g - 18.f * b + 128.f) * scale + 128.f;
376
377 *y = packYuv(yy);
378 *u = packYuv(uu);
379 *v = packYuv(vv);
380 }
381
382 private:
383 static Pt::uint8_t packYuv(float v)
384 {
385 if(v <= 0.f)
386 return 0;
387 if(v >= 255.f)
388 return 255;
389
390 return static_cast<Pt::uint8_t>(v + 0.5f);
391 }
392
393 public:
394 template <typename T>
395 static Pt::ssize_t init(T* data, Pt::ssize_t stride,
396 Pt::ssize_t width, Pt::ssize_t height,
397 Pt::ssize_t xpos, Pt::ssize_t ypos,
398 T*& y, T*& u, T*& v)
399 {
400 Pt::ssize_t yOffset = stride * ypos + xpos;
401 y = data + yOffset;
402
403 return initUV(data, stride, width, height, xpos, ypos, u, v);
404 }
405
406 template <typename T>
407 static Pt::ssize_t initUV(T* data, Pt::ssize_t stride,
408 Pt::ssize_t width, Pt::ssize_t height,
409 Pt::ssize_t xpos, Pt::ssize_t ypos,
410 T*& u, T*& v)
411 {
412 Pt::ssize_t planeSize = stride * height;
413
414 Pt::ssize_t uvstride = stride / 2;
415 Pt::ssize_t subPlaneSize = planeSize / 4;
416
417 Pt::ssize_t subXPos = xpos / 2;
418 Pt::ssize_t subYPos = ypos / 2;
419 Pt::ssize_t subOffset = uvstride * subYPos + subXPos;
420
421 Pt::ssize_t uOffset = planeSize + subOffset;
422 u = data + uOffset;
423
424 Pt::ssize_t vOffset = uOffset + subPlaneSize;
425 v = data + vOffset;
426
427 return uvstride;
428 }
429
430 template <typename T>
431 static void advance(T*& y, T*& u, T*& v,
432 Pt::ssize_t& xpos, Pt::ssize_t& ypos,
433 Pt::ssize_t width, Pt::ssize_t padding,
434 Pt::ssize_t uvstride)
435 {
436 ++y;
437
438 if( ++xpos >= width )
439 {
440 ++u;
441 ++v;
442
443 if(ypos % 2 == 0)
444 {
445 u -= uvstride;
446 v -= uvstride;
447 }
448
449 xpos = 0;
450 ++ypos;
451
452 y += padding;
453 }
454 else if(xpos % 2 == 0)
455 {
456 ++u;
457 ++v;
458 }
459 }
460
461 template <typename T>
462 static void advanceBy(T*& y, T*& u, T*& v, ssize_t n,
463 ssize_t& xpos, ssize_t& ypos, ssize_t width,
464 ssize_t ystride, ssize_t uvstride)
465 {
466 Pt::ssize_t new_abs_pos = (ypos * width) + xpos + n;
467 Pt::ssize_t new_ypos = new_abs_pos / width;
468 Pt::ssize_t new_xpos = new_abs_pos % width;
469
470 y += (new_ypos - ypos) * ystride + (new_xpos - xpos);
471
472 Pt::ssize_t old_u_row = ypos / 2;
473 Pt::ssize_t new_u_row = new_ypos / 2;
474
475 Pt::ssize_t old_u_col = xpos / 2;
476 Pt::ssize_t new_u_col = new_xpos / 2;
477
478 Pt::ssize_t uv_offset = (new_u_row - old_u_row) * uvstride + (new_u_col - old_u_col);
479
480 u += uv_offset;
481 v += uv_offset;
482
483 xpos = new_xpos;
484 ypos = new_ypos;
485 }
486};
487
488} // namespace
489
490} // namespace
491
492#endif
493
494#include <Pt/Gfx/Yuv12.hpp>
Floating-point RGBA color.
Definition Color.h:173
Pixel base class.
Definition PixelBase.h:52
Width, height and stride of an image or view.
Definition ViewBase.h:50
YV12 const pixel.
Definition Yuv12.h:137
YV-12 pixel.
Definition Yuv12.h:44
uint_type uint8_t
Unsigned 8-bit integer type.
Definition Api-Types.h:24
Graphics and imaging services.
Definition Api-Argb32Image.h:12
Core module.
Definition Allocator.h:33