1 #include "yuvconvert.hpp"
7 #define UINT64_C(val) val##ULL
9 #include <libswscale/swscale.h>
19 sws_fmt
= (*reinterpret_cast<uint8_t*>(&magic
) == 2) ? PIX_FMT_GRAY16LE
: PIX_FMT_GRAY16BE
;
22 template<typename outv
, typename inv
>
23 void reduce_luma(outv
* out
, const inv
* in
, size_t width
, size_t height
)
25 if(sizeof(outv
) == sizeof(inv
)) {
26 memcpy(out
, in
, sizeof(inv
) * width
* height
);
29 for(size_t i
= 0; i
< width
* height
; i
++) {
30 if(sizeof(outv
) == 2 && sizeof(inv
) == 1)
31 out
[i
] = ((outv
)in
[i
] << 8) | in
[i
];
32 if(sizeof(outv
) == 1 && sizeof(inv
) == 2)
37 template<typename outv
, typename inv
>
38 void reduce_chroma_gauss(outv
* out
, const inv
* in
, size_t width
, size_t height
)
40 static SwsContext
* ctx
= NULL
;
41 PixelFormat infmt
= (sizeof(inv
) == 2) ? sws_fmt
: PIX_FMT_GRAY8
;
42 PixelFormat outfmt
= (sizeof(outv
) == 2) ? sws_fmt
: PIX_FMT_GRAY8
;
43 ctx
= sws_getCachedContext(ctx
, width
, height
, infmt
, width
/ 2, height
/ 2, outfmt
,
44 SWS_GAUSS
, NULL
, NULL
, NULL
);
45 const uint8_t* in_ptr
[1];
49 in_stride
[0] = sizeof(inv
) * width
;
50 out_stride
[0] = sizeof(outv
) * width
/ 2;
51 in_ptr
[0] = reinterpret_cast<const uint8_t*>(in
);
52 out_ptr
[0] = reinterpret_cast<uint8_t*>(out
);
53 sws_scale(ctx
, in_ptr
, in_stride
, 0, height
, out_ptr
, out_stride
);
56 template<typename outv
, typename inv
>
57 void reduce_chroma_bilinear(outv
* out
, const inv
* in
, size_t width
, size_t height
);
60 void reduce_chroma_bilinear(uint8_t* out
, const uint8_t* in
, size_t width
, size_t height
)
62 const uint16_t* _in
= reinterpret_cast<const uint16_t*>(in
);
63 size_t hwidth
= width
/ 2;
64 for(size_t i
= 0; i
< height
; i
+= 2) {
65 for(size_t j
= 0; j
< hwidth
; j
++) {
69 v1
= (v1
>> 8) + (v1
& 0xFF);
70 v2
= (v2
>> 8) + (v2
& 0xFF);
71 out
[j
] = (v1
+ v2
+ 2) >> 2;
79 void reduce_chroma_bilinear(uint8_t* out
, const uint16_t* in
, size_t width
, size_t height
)
81 const uint32_t* _in
= reinterpret_cast<const uint32_t*>(in
);
82 size_t hwidth
= width
/ 2;
83 for(size_t i
= 0; i
< height
; i
+= 2) {
84 for(size_t j
= 0; j
< hwidth
; j
++) {
88 v1
= (v1
>> 16) + (v1
& 0xFFFF);
89 v2
= (v2
>> 16) + (v2
& 0xFFFF);
90 out
[j
] = (v1
+ v2
+ 512) >> 10;
98 void reduce_chroma_bilinear(uint16_t* out
, const uint8_t* in
, size_t width
, size_t height
)
100 const uint16_t* _in
= reinterpret_cast<const uint16_t*>(in
);
101 size_t hwidth
= width
/ 2;
102 for(size_t i
= 0; i
< height
; i
+= 2) {
103 for(size_t j
= 0; j
< hwidth
; j
++) {
106 v2
= _in
[j
+ hwidth
];
107 v1
= (v1
>> 8) + (v1
& 0xFF);
108 v2
= (v2
>> 8) + (v2
& 0xFF);
109 out
[j
] = ((v1
+ v2
) << 6) + ((v1
+ v2
+ 2) >> 2);
117 void reduce_chroma_bilinear(uint16_t* out
, const uint16_t* in
, size_t width
, size_t height
)
119 const uint32_t* _in
= reinterpret_cast<const uint32_t*>(in
);
120 size_t hwidth
= width
/ 2;
121 for(size_t i
= 0; i
< height
; i
+= 2) {
122 for(size_t j
= 0; j
< hwidth
; j
++) {
125 v2
= _in
[j
+ hwidth
];
126 v1
= (v1
>> 16) + (v1
& 0xFFFF);
127 v2
= (v2
>> 16) + (v2
& 0xFFFF);
128 out
[j
] = (v1
+ v2
+ 2) >> 2;
135 template<long long b
, long long r
, long long c
, long long S
, long long Sc
, long long Sl
, long long Bl
,
139 const static long long y_r
= r
*Sl
;
140 const static long long y_g
= (c
-r
-b
)*Sl
;
141 const static long long y_b
= b
*Sl
;
142 const static long long y_c
= Bl
*S
*c
+S
*c
/2;
143 const static long long y_d
= S
*c
;
144 const static long long cb_r
= -r
*Sc
;
145 const static long long cb_g
= -(c
-r
-b
)*Sc
;
146 const static long long cb_b
= (c
-b
)*Sc
;
147 const static long long cb_c
= 2*S
*(c
-b
)*Bc
+S
*(c
-b
);
148 const static long long cb_d
= 2*S
*(c
-b
);
149 const static long long cr_r
= (c
-r
)*Sc
;
150 const static long long cr_g
= -(c
-r
-b
)*Sc
;
151 const static long long cr_b
= -b
*Sc
;
152 const static long long cr_c
= 2*S
*(c
-r
)*Bc
+S
*(c
-r
);
153 const static long long cr_d
= 2*S
*(c
-r
);
156 typedef _colormatrix
<114,299,1000,255,65534,65534,0,32768> pc601
;
157 typedef _colormatrix
<722,2126,10000,255,65534,65534,0,32768> pc709
;
158 typedef _colormatrix
<114,299,1000,255,56064,57344,4096,32768> rec601
;
159 typedef _colormatrix
<722,2126,10000,255,56064,57344,4096,32768> rec709
;
160 typedef _colormatrix
<114,299,1000,255,254,254,0,128> pc601_8
;
161 typedef _colormatrix
<722,2126,10000,255,254,254,0,128> pc709_8
;
162 typedef _colormatrix
<114,299,1000,255,219,224,16,128> rec601_8
;
163 typedef _colormatrix
<722,2126,10000,255,219,224,16,128> rec709_8
;
164 typedef _colormatrix
<593,2627,10000,255,65534,65534,0,32768> pc2020
;
165 typedef _colormatrix
<593,2627,10000,255,56064,57344,4096,32768> rec2020
;
166 typedef _colormatrix
<593,2627,10000,255,254,254,0,128> pc2020_8
;
167 typedef _colormatrix
<593,2627,10000,255,219,224,16,128> rec2020_8
;
169 template<class matrix
, class matrix_8
, size_t p
, size_t r
, size_t g
, size_t b
>
170 struct _converter
: public yuvc_converter
172 void Y(unsigned short* out
, const unsigned char* in
, size_t pixels
)
174 for(size_t i
= 0; i
< pixels
; i
++)
175 out
[i
] = (matrix::y_r
* in
[p
* i
+ r
] + matrix::y_g
* in
[p
* i
+ g
] +
176 matrix::y_b
* in
[p
* i
+ b
] + matrix::y_c
) / matrix::y_d
;
179 void Cb(unsigned short* out
, const unsigned char* in
, size_t pixels
)
181 for(size_t i
= 0; i
< pixels
; i
++)
182 out
[i
] = (matrix::cb_r
* in
[p
* i
+ r
] + matrix::cb_g
* in
[p
* i
+ g
] +
183 matrix::cb_b
* in
[p
* i
+ b
] + matrix::cb_c
) / matrix::cb_d
;
186 void Cr(unsigned short* out
, const unsigned char* in
, size_t pixels
)
188 for(size_t i
= 0; i
< pixels
; i
++)
189 out
[i
] = (matrix::cr_r
* in
[p
* i
+ r
] + matrix::cr_g
* in
[p
* i
+ g
] +
190 matrix::cr_b
* in
[p
* i
+ b
] + matrix::cr_c
) / matrix::cr_d
;
193 void Y(unsigned char* out
, const unsigned char* in
, size_t pixels
)
195 for(size_t i
= 0; i
< pixels
; i
++)
196 out
[i
] = (matrix_8::y_r
* in
[p
* i
+ r
] + matrix_8::y_g
* in
[p
* i
+ g
] +
197 matrix_8::y_b
* in
[p
* i
+ b
] + matrix_8::y_c
) / matrix_8::y_d
;
200 void Cb(unsigned char* out
, const unsigned char* in
, size_t pixels
)
202 for(size_t i
= 0; i
< pixels
; i
++)
203 out
[i
] = (matrix_8::cb_r
* in
[p
* i
+ r
] + matrix_8::cb_g
* in
[p
* i
+ g
] +
204 matrix_8::cb_b
* in
[p
* i
+ b
] + matrix_8::cb_c
) / matrix_8::cb_d
;
207 void Cr(unsigned char* out
, const unsigned char* in
, size_t pixels
)
209 for(size_t i
= 0; i
< pixels
; i
++)
210 out
[i
] = (matrix_8::cr_r
* in
[p
* i
+ r
] + matrix_8::cr_g
* in
[p
* i
+ g
] +
211 matrix_8::cr_b
* in
[p
* i
+ b
] + matrix_8::cr_c
) / matrix_8::cr_d
;
215 template<class matrix
, class matrix_8
> yuvc_converter
* get_converter(yuvc_rgbtype type
)
218 case RGB_RGB
: return new _converter
<matrix
, matrix_8
, 3, 0, 1, 2>;
219 case RGB_BGR
: return new _converter
<matrix
, matrix_8
, 3, 2, 1, 0>;
220 case RGB_RGBX
: return new _converter
<matrix
, matrix_8
, 4, 0, 1, 2>;
221 case RGB_BGRX
: return new _converter
<matrix
, matrix_8
, 4, 2, 1, 0>;
222 case RGB_XRGB
: return new _converter
<matrix
, matrix_8
, 4, 1, 2, 3>;
223 case RGB_XBGR
: return new _converter
<matrix
, matrix_8
, 4, 3, 2, 1>;
229 yuvc_converter
* yuvc_get_converter(yuvc_rgbtype type
, yuvc_csptype csp
)
232 case CSP_PC601
: return get_converter
<pc601
, pc601_8
>(type
);
233 case CSP_PC709
: return get_converter
<pc709
, pc709_8
>(type
);
234 case CSP_REC601
: return get_converter
<rec601
, rec601_8
>(type
);
235 case CSP_REC709
: return get_converter
<rec709
, rec709_8
>(type
);
236 case CSP_REC2020
: return get_converter
<rec2020
, rec2020_8
>(type
);
237 case CSP_PC2020
: return get_converter
<rec2020
, rec2020_8
>(type
);
242 yuvc_converter
* yuvc_get_converter(yuvc_rgbtype type
, const std::string
& csp
)
244 if(csp
== "rec601") return get_converter
<rec601
, rec601_8
>(type
);
245 if(csp
== "pc601") return get_converter
<pc601
, pc601_8
>(type
);
246 if(csp
== "rec709") return get_converter
<rec709
, rec709_8
>(type
);
247 if(csp
== "pc709") return get_converter
<pc709
, pc709_8
>(type
);
248 if(csp
== "rec2020") return get_converter
<rec2020
, rec2020_8
>(type
);
249 if(csp
== "pc2020") return get_converter
<pc2020
, pc2020_8
>(type
);
253 template<typename outv
, typename inv
>
254 void yuvc_shrink_croma(outv
* out
, const inv
* in
, size_t width
, size_t height
, bool gauss
)
256 if((width
| height
) & 1)
257 throw std::runtime_error("yuvc_shrink_croma: Width and height must be multiple of 2");
258 size_t pixels
= width
* height
;
259 size_t pixelsq
= pixels
/ 4;
261 reduce_luma(out
, in
, width
, height
);
263 reduce_chroma_gauss(out
+ pixels
, in
+ pixels
, width
, height
);
264 reduce_chroma_gauss(out
+ pixels
+ pixelsq
, in
+ 2 * pixels
, width
, height
);
266 reduce_chroma_bilinear(out
+ pixels
, in
+ pixels
, width
, height
);
267 reduce_chroma_bilinear(out
+ pixels
+ pixelsq
, in
+ 2 * pixels
, width
, height
);
271 template void yuvc_shrink_croma(uint8_t* out
, const uint8_t* in
, size_t width
, size_t height
, bool gauss
);
272 template void yuvc_shrink_croma(uint8_t* out
, const uint16_t* in
, size_t width
, size_t height
, bool gauss
);
273 template void yuvc_shrink_croma(uint16_t* out
, const uint8_t* in
, size_t width
, size_t height
, bool gauss
);
274 template void yuvc_shrink_croma(uint16_t* out
, const uint16_t* in
, size_t width
, size_t height
, bool gauss
);
276 void yuvc_magify_luma(unsigned char* out
, const unsigned char* in
, size_t width
, size_t height
)
278 size_t pixels
= width
* height
;
279 for(size_t y
= 0; y
< height
; y
++) {
280 for(size_t x
= 0; x
< width
; x
++)
281 out
[2 * x
+ 1] = out
[2 * x
] = in
[x
];
282 memcpy(out
+ 2 * width
, out
, 2 * width
);
286 memcpy(out
, in
, 2 * pixels
);