FFmpeg
yuv2rgb_altivec.c
Go to the documentation of this file.
1 /*
2  * AltiVec acceleration for colorspace conversion
3  *
4  * copyright (C) 2004 Marc Hoffman <marc.hoffman@analog.com>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /*
24  * Convert I420 YV12 to RGB in various formats,
25  * it rejects images that are not in 420 formats,
26  * it rejects images that don't have widths of multiples of 16,
27  * it rejects images that don't have heights of multiples of 2.
28  * Reject defers to C simulation code.
29  *
30  * Lots of optimizations to be done here.
31  *
32  * 1. Need to fix saturation code. I just couldn't get it to fly with packs
33  * and adds, so we currently use max/min to clip.
34  *
35  * 2. The inefficient use of chroma loading needs a bit of brushing up.
36  *
37  * 3. Analysis of pipeline stalls needs to be done. Use shark to identify
38  * pipeline stalls.
39  *
40  *
41  * MODIFIED to calculate coeffs from currently selected color space.
42  * MODIFIED core to be a macro where you specify the output format.
43  * ADDED UYVY conversion which is never called due to some thing in swscale.
44  * CORRECTED algorithm selection to be strict on input formats.
45  * ADDED runtime detection of AltiVec.
46  *
47  * ADDED altivec_yuv2packedX vertical scl + RGB converter
48  *
49  * March 27,2004
50  * PERFORMANCE ANALYSIS
51  *
52  * The C version uses 25% of the processor or ~250Mips for D1 video rawvideo
53  * used as test.
54  * The AltiVec version uses 10% of the processor or ~100Mips for D1 video
55  * same sequence.
56  *
57  * 720 * 480 * 30 ~10MPS
58  *
59  * so we have roughly 10 clocks per pixel. This is too high, something has
60  * to be wrong.
61  *
62  * OPTIMIZED clip codes to utilize vec_max and vec_packs removing the
63  * need for vec_min.
64  *
65  * OPTIMIZED DST OUTPUT cache/DMA controls. We are pretty much guaranteed to
66  * have the input video frame, it was just decompressed so it probably resides
67  * in L1 caches. However, we are creating the output video stream. This needs
68  * to use the DSTST instruction to optimize for the cache. We couple this with
69  * the fact that we are not going to be visiting the input buffer again so we
70  * mark it Least Recently Used. This shaves 25% of the processor cycles off.
71  *
72  * Now memcpy is the largest mips consumer in the system, probably due
73  * to the inefficient X11 stuff.
74  *
75  * GL libraries seem to be very slow on this machine 1.33Ghz PB running
76  * Jaguar, this is not the case for my 1Ghz PB. I thought it might be
77  * a versioning issue, however I have libGL.1.2.dylib for both
78  * machines. (We need to figure this out now.)
79  *
80  * GL2 libraries work now with patch for RGB32.
81  *
82  * NOTE: quartz vo driver ARGB32_to_RGB24 consumes 30% of the processor.
83  *
84  * Integrated luma prescaling adjustment for saturation/contrast/brightness
85  * adjustment.
86  */
87 
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <string.h>
91 #include <inttypes.h>
92 
93 #include "config.h"
94 #include "libswscale/rgb2rgb.h"
95 #include "libswscale/swscale.h"
97 #include "libavutil/attributes.h"
98 #include "libavutil/cpu.h"
99 #include "libavutil/error.h"
100 #include "libavutil/mem.h"
101 #include "libavutil/mem_internal.h"
102 #include "libavutil/pixdesc.h"
103 #include "yuv2rgb_altivec.h"
104 
105 #if HAVE_ALTIVEC
106 // util_altivec.h includes the system header altivec.h which redefines bool,
107 // making it incompatible with stdbool.h. It therefore must not be included
108 // before another one of our headers that may use bool.
110 #include <assert.h>
111 
112 typedef struct SwsInternalAltivec {
113  SwsInternal c;
114 
115  vector signed short CY;
116  vector signed short CRV;
117  vector signed short CBU;
118  vector signed short CGU;
119  vector signed short CGV;
120  vector signed short OY;
121  vector unsigned short CSHIFT;
122  vector signed short *vYCoeffsBank, *vCCoeffsBank;
123 } SwsInternalAltivec;
124 // Check that the sizes of the types match.
125 // Note that given that SwsInternal is always allocated via av_malloc,
126 // every pointer to an SwsInternal is always sufficiently aligned.
127 static_assert(sizeof(SwsInternalAltivec) <= sizeof(SwsInternal) + SWSINTERNAL_ADDITIONAL_ASM_SIZE,
128  "SWSINTERNAL_ADDITIONAL_ASM_SIZE needs to be increased");
129 
130 static inline SwsInternalAltivec *sws_internal_altivec(SwsInternal *c)
131 {
132  return (SwsInternalAltivec*)c;
133 }
134 
135 #undef PROFILE_THE_BEAST
136 #undef INC_SCALING
137 
138 typedef unsigned char ubyte;
139 typedef signed char sbyte;
140 
141 /* RGB interleaver, 16 planar pels 8-bit samples per channel in
142  * homogeneous vector registers x0,x1,x2 are interleaved with the
143  * following technique:
144  *
145  * o0 = vec_mergeh(x0, x1);
146  * o1 = vec_perm(o0, x2, perm_rgb_0);
147  * o2 = vec_perm(o0, x2, perm_rgb_1);
148  * o3 = vec_mergel(x0, x1);
149  * o4 = vec_perm(o3, o2, perm_rgb_2);
150  * o5 = vec_perm(o3, o2, perm_rgb_3);
151  *
152  * perm_rgb_0: o0(RG).h v1(B) --> o1*
153  * 0 1 2 3 4
154  * rgbr|gbrg|brgb|rgbr
155  * 0010 0100 1001 0010
156  * 0102 3145 2673 894A
157  *
158  * perm_rgb_1: o0(RG).h v1(B) --> o2
159  * 0 1 2 3 4
160  * gbrg|brgb|bbbb|bbbb
161  * 0100 1001 1111 1111
162  * B5CD 6EF7 89AB CDEF
163  *
164  * perm_rgb_2: o3(RG).l o2(rgbB.l) --> o4*
165  * 0 1 2 3 4
166  * gbrg|brgb|rgbr|gbrg
167  * 1111 1111 0010 0100
168  * 89AB CDEF 0182 3945
169  *
170  * perm_rgb_2: o3(RG).l o2(rgbB.l) ---> o5*
171  * 0 1 2 3 4
172  * brgb|rgbr|gbrg|brgb
173  * 1001 0010 0100 1001
174  * a67b 89cA BdCD eEFf
175  */
176 static const vector unsigned char
177  perm_rgb_0 = { 0x00, 0x01, 0x10, 0x02, 0x03, 0x11, 0x04, 0x05,
178  0x12, 0x06, 0x07, 0x13, 0x08, 0x09, 0x14, 0x0a },
179  perm_rgb_1 = { 0x0b, 0x15, 0x0c, 0x0d, 0x16, 0x0e, 0x0f, 0x17,
180  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
181  perm_rgb_2 = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
182  0x00, 0x01, 0x18, 0x02, 0x03, 0x19, 0x04, 0x05 },
183  perm_rgb_3 = { 0x1a, 0x06, 0x07, 0x1b, 0x08, 0x09, 0x1c, 0x0a,
184  0x0b, 0x1d, 0x0c, 0x0d, 0x1e, 0x0e, 0x0f, 0x1f };
185 
186 #define vec_merge3(x2, x1, x0, y0, y1, y2) \
187  do { \
188  __typeof__(x0) o0, o2, o3; \
189  o0 = vec_mergeh(x0, x1); \
190  y0 = vec_perm(o0, x2, perm_rgb_0); \
191  o2 = vec_perm(o0, x2, perm_rgb_1); \
192  o3 = vec_mergel(x0, x1); \
193  y1 = vec_perm(o3, o2, perm_rgb_2); \
194  y2 = vec_perm(o3, o2, perm_rgb_3); \
195  } while (0)
196 
197 #define vec_mstbgr24(x0, x1, x2, ptr) \
198  do { \
199  __typeof__(x0) _0, _1, _2; \
200  vec_merge3(x0, x1, x2, _0, _1, _2); \
201  vec_st(_0, 0, ptr++); \
202  vec_st(_1, 0, ptr++); \
203  vec_st(_2, 0, ptr++); \
204  } while (0)
205 
206 #define vec_mstrgb24(x0, x1, x2, ptr) \
207  do { \
208  __typeof__(x0) _0, _1, _2; \
209  vec_merge3(x2, x1, x0, _0, _1, _2); \
210  vec_st(_0, 0, ptr++); \
211  vec_st(_1, 0, ptr++); \
212  vec_st(_2, 0, ptr++); \
213  } while (0)
214 
215 /* pack the pixels in rgb0 format
216  * msb R
217  * lsb 0
218  */
219 #define vec_mstrgb32(T, x0, x1, x2, x3, ptr) \
220  do { \
221  T _0, _1, _2, _3; \
222  _0 = vec_mergeh(x0, x1); \
223  _1 = vec_mergeh(x2, x3); \
224  _2 = (T) vec_mergeh((vector unsigned short) _0, \
225  (vector unsigned short) _1); \
226  _3 = (T) vec_mergel((vector unsigned short) _0, \
227  (vector unsigned short) _1); \
228  vec_st(_2, 0 * 16, (T *) ptr); \
229  vec_st(_3, 1 * 16, (T *) ptr); \
230  _0 = vec_mergel(x0, x1); \
231  _1 = vec_mergel(x2, x3); \
232  _2 = (T) vec_mergeh((vector unsigned short) _0, \
233  (vector unsigned short) _1); \
234  _3 = (T) vec_mergel((vector unsigned short) _0, \
235  (vector unsigned short) _1); \
236  vec_st(_2, 2 * 16, (T *) ptr); \
237  vec_st(_3, 3 * 16, (T *) ptr); \
238  ptr += 4; \
239  } while (0)
240 
241 /*
242  * 1 0 1.4021 | | Y |
243  * 1 -0.3441 -0.7142 |x| Cb|
244  * 1 1.7718 0 | | Cr|
245  *
246  *
247  * Y: [-128 127]
248  * Cb/Cr : [-128 127]
249  *
250  * typical YUV conversion works on Y: 0-255 this version has been
251  * optimized for JPEG decoding.
252  */
253 
254 #if HAVE_BIGENDIAN
255 #define vec_unh(x) \
256  (vector signed short) \
257  vec_perm(x, (__typeof__(x)) { 0 }, \
258  ((vector unsigned char) { \
259  0x10, 0x00, 0x10, 0x01, 0x10, 0x02, 0x10, 0x03, \
260  0x10, 0x04, 0x10, 0x05, 0x10, 0x06, 0x10, 0x07 }))
261 
262 #define vec_unl(x) \
263  (vector signed short) \
264  vec_perm(x, (__typeof__(x)) { 0 }, \
265  ((vector unsigned char) { \
266  0x10, 0x08, 0x10, 0x09, 0x10, 0x0A, 0x10, 0x0B, \
267  0x10, 0x0C, 0x10, 0x0D, 0x10, 0x0E, 0x10, 0x0F }))
268 #else
269 #define vec_unh(x)(vector signed short) vec_mergeh(x,(__typeof__(x)) { 0 })
270 #define vec_unl(x)(vector signed short) vec_mergel(x,(__typeof__(x)) { 0 })
271 #endif
272 
273 #define vec_clip_s16(x) \
274  vec_max(vec_min(x, ((vector signed short) { \
275  235, 235, 235, 235, 235, 235, 235, 235 })), \
276  ((vector signed short) { 16, 16, 16, 16, 16, 16, 16, 16 }))
277 
278 #define vec_packclp(x, y) \
279  (vector unsigned char) \
280  vec_packs((vector unsigned short) \
281  vec_max(x, ((vector signed short) { 0 })), \
282  (vector unsigned short) \
283  vec_max(y, ((vector signed short) { 0 })))
284 
285 static inline void cvtyuvtoRGB(SwsInternal *c, vector signed short Y,
286  vector signed short U, vector signed short V,
287  vector signed short *R, vector signed short *G,
288  vector signed short *B)
289 {
290  SwsInternalAltivec *const a = sws_internal_altivec(c);
291  vector signed short vx, ux, uvx;
292 
293  Y = vec_mradds(Y, a->CY, a->OY);
294  U = vec_sub(U, (vector signed short)
295  vec_splat((vector signed short) { 128 }, 0));
296  V = vec_sub(V, (vector signed short)
297  vec_splat((vector signed short) { 128 }, 0));
298 
299  // ux = (CBU * (u << a->CSHIFT) + 0x4000) >> 15;
300  ux = vec_sl(U, a->CSHIFT);
301  *B = vec_mradds(ux, a->CBU, Y);
302 
303  // vx = (CRV * (v << a->CSHIFT) + 0x4000) >> 15;
304  vx = vec_sl(V, a->CSHIFT);
305  *R = vec_mradds(vx, a->CRV, Y);
306 
307  // uvx = ((CGU * u) + (CGV * v)) >> 15;
308  uvx = vec_mradds(U, a->CGU, Y);
309  *G = vec_mradds(V, a->CGV, uvx);
310 }
311 
312 /*
313  * ------------------------------------------------------------------------------
314  * CS converters
315  * ------------------------------------------------------------------------------
316  */
317 
318 #if !HAVE_VEC_XL
319 static inline vector unsigned char vec_xl(signed long long offset, const ubyte *addr)
320 {
321  const vector unsigned char *v_addr = (const vector unsigned char *) (addr + offset);
322  vector unsigned char align_perm = vec_lvsl(offset, addr);
323 
324  return (vector unsigned char) vec_perm(v_addr[0], v_addr[1], align_perm);
325 }
326 #endif /* !HAVE_VEC_XL */
327 
328 #define DEFCSP420_CVT(name, out_pixels) \
329 static int altivec_ ## name(SwsInternal *c, const unsigned char *const *in, \
330  const int *instrides, int srcSliceY, int srcSliceH, \
331  unsigned char *const *oplanes, const int *outstrides) \
332 { \
333  SwsInternalAltivec *const a = sws_internal_altivec(c); \
334  int w = c->opts.src_w; \
335  int h = srcSliceH; \
336  int i, j; \
337  int instrides_scl[3]; \
338  vector unsigned char y0, y1; \
339  \
340  vector signed char u, v; \
341  \
342  vector signed short Y0, Y1, Y2, Y3; \
343  vector signed short U, V; \
344  vector signed short vx, ux, uvx; \
345  vector signed short vx0, ux0, uvx0; \
346  vector signed short vx1, ux1, uvx1; \
347  vector signed short R0, G0, B0; \
348  vector signed short R1, G1, B1; \
349  vector unsigned char R, G, B; \
350  \
351  vector signed short lCY = a->CY; \
352  vector signed short lOY = a->OY; \
353  vector signed short lCRV = a->CRV; \
354  vector signed short lCBU = a->CBU; \
355  vector signed short lCGU = a->CGU; \
356  vector signed short lCGV = a->CGV; \
357  vector unsigned short lCSHIFT = a->CSHIFT; \
358  \
359  const ubyte *y1i = in[0]; \
360  const ubyte *y2i = in[0] + instrides[0]; \
361  const ubyte *ui = in[1]; \
362  const ubyte *vi = in[2]; \
363  \
364  vector unsigned char *oute, *outo; \
365  \
366  /* loop moves y{1, 2}i by w */ \
367  instrides_scl[0] = instrides[0] * 2 - w; \
368  /* loop moves ui by w / 2 */ \
369  instrides_scl[1] = instrides[1] - w / 2; \
370  /* loop moves vi by w / 2 */ \
371  instrides_scl[2] = instrides[2] - w / 2; \
372  \
373  for (i = 0; i < h / 2; i++) { \
374  oute = (vector unsigned char *)(oplanes[0] + outstrides[0] * \
375  (srcSliceY + i * 2)); \
376  outo = oute + (outstrides[0] >> 4); \
377  vec_dstst(outo, (0x02000002 | (((w * 3 + 32) / 32) << 16)), 0); \
378  vec_dstst(oute, (0x02000002 | (((w * 3 + 32) / 32) << 16)), 1); \
379  \
380  for (j = 0; j < w / 16; j++) { \
381  y0 = vec_xl(0, y1i); \
382  \
383  y1 = vec_xl(0, y2i); \
384  \
385  u = (vector signed char) vec_xl(0, ui); \
386  \
387  v = (vector signed char) vec_xl(0, vi); \
388  \
389  u = (vector signed char) \
390  vec_sub(u, \
391  (vector signed char) \
392  vec_splat((vector signed char) { 128 }, 0)); \
393  v = (vector signed char) \
394  vec_sub(v, \
395  (vector signed char) \
396  vec_splat((vector signed char) { 128 }, 0)); \
397  \
398  U = vec_unpackh(u); \
399  V = vec_unpackh(v); \
400  \
401  Y0 = vec_unh(y0); \
402  Y1 = vec_unl(y0); \
403  Y2 = vec_unh(y1); \
404  Y3 = vec_unl(y1); \
405  \
406  Y0 = vec_mradds(Y0, lCY, lOY); \
407  Y1 = vec_mradds(Y1, lCY, lOY); \
408  Y2 = vec_mradds(Y2, lCY, lOY); \
409  Y3 = vec_mradds(Y3, lCY, lOY); \
410  \
411  /* ux = (CBU * (u << CSHIFT) + 0x4000) >> 15 */ \
412  ux = vec_sl(U, lCSHIFT); \
413  ux = vec_mradds(ux, lCBU, (vector signed short) { 0 }); \
414  ux0 = vec_mergeh(ux, ux); \
415  ux1 = vec_mergel(ux, ux); \
416  \
417  /* vx = (CRV * (v << CSHIFT) + 0x4000) >> 15; */ \
418  vx = vec_sl(V, lCSHIFT); \
419  vx = vec_mradds(vx, lCRV, (vector signed short) { 0 }); \
420  vx0 = vec_mergeh(vx, vx); \
421  vx1 = vec_mergel(vx, vx); \
422  \
423  /* uvx = ((CGU * u) + (CGV * v)) >> 15 */ \
424  uvx = vec_mradds(U, lCGU, (vector signed short) { 0 }); \
425  uvx = vec_mradds(V, lCGV, uvx); \
426  uvx0 = vec_mergeh(uvx, uvx); \
427  uvx1 = vec_mergel(uvx, uvx); \
428  \
429  R0 = vec_add(Y0, vx0); \
430  G0 = vec_add(Y0, uvx0); \
431  B0 = vec_add(Y0, ux0); \
432  R1 = vec_add(Y1, vx1); \
433  G1 = vec_add(Y1, uvx1); \
434  B1 = vec_add(Y1, ux1); \
435  \
436  R = vec_packclp(R0, R1); \
437  G = vec_packclp(G0, G1); \
438  B = vec_packclp(B0, B1); \
439  \
440  out_pixels(R, G, B, oute); \
441  \
442  R0 = vec_add(Y2, vx0); \
443  G0 = vec_add(Y2, uvx0); \
444  B0 = vec_add(Y2, ux0); \
445  R1 = vec_add(Y3, vx1); \
446  G1 = vec_add(Y3, uvx1); \
447  B1 = vec_add(Y3, ux1); \
448  R = vec_packclp(R0, R1); \
449  G = vec_packclp(G0, G1); \
450  B = vec_packclp(B0, B1); \
451  \
452  \
453  out_pixels(R, G, B, outo); \
454  \
455  y1i += 16; \
456  y2i += 16; \
457  ui += 8; \
458  vi += 8; \
459  } \
460  \
461  ui += instrides_scl[1]; \
462  vi += instrides_scl[2]; \
463  y1i += instrides_scl[0]; \
464  y2i += instrides_scl[0]; \
465  } \
466  return srcSliceH; \
467 }
468 
469 #define out_abgr(a, b, c, ptr) \
470  vec_mstrgb32(__typeof__(a), ((__typeof__(a)) vec_splat((__typeof__(a)){ 255 }, 0)), c, b, a, ptr)
471 #define out_bgra(a, b, c, ptr) \
472  vec_mstrgb32(__typeof__(a), c, b, a, ((__typeof__(a)) vec_splat((__typeof__(a)){ 255 }, 0)), ptr)
473 #define out_rgba(a, b, c, ptr) \
474  vec_mstrgb32(__typeof__(a), a, b, c, ((__typeof__(a)) vec_splat((__typeof__(a)){ 255 }, 0)), ptr)
475 #define out_argb(a, b, c, ptr) \
476  vec_mstrgb32(__typeof__(a), ((__typeof__(a)) vec_splat((__typeof__(a)){ 255 }, 0)), a, b, c, ptr)
477 #define out_rgb24(a, b, c, ptr) vec_mstrgb24(a, b, c, ptr)
478 #define out_bgr24(a, b, c, ptr) vec_mstbgr24(a, b, c, ptr)
479 
480 DEFCSP420_CVT(yuv2_abgr, out_abgr)
481 DEFCSP420_CVT(yuv2_bgra, out_bgra)
482 DEFCSP420_CVT(yuv2_rgba, out_rgba)
483 DEFCSP420_CVT(yuv2_argb, out_argb)
484 DEFCSP420_CVT(yuv2_rgb24, out_rgb24)
485 DEFCSP420_CVT(yuv2_bgr24, out_bgr24)
486 
487 // uyvy|uyvy|uyvy|uyvy
488 // 0123 4567 89ab cdef
489 static const vector unsigned char
490  demux_u = { 0x10, 0x00, 0x10, 0x00,
491  0x10, 0x04, 0x10, 0x04,
492  0x10, 0x08, 0x10, 0x08,
493  0x10, 0x0c, 0x10, 0x0c },
494  demux_v = { 0x10, 0x02, 0x10, 0x02,
495  0x10, 0x06, 0x10, 0x06,
496  0x10, 0x0A, 0x10, 0x0A,
497  0x10, 0x0E, 0x10, 0x0E },
498  demux_y = { 0x10, 0x01, 0x10, 0x03,
499  0x10, 0x05, 0x10, 0x07,
500  0x10, 0x09, 0x10, 0x0B,
501  0x10, 0x0D, 0x10, 0x0F };
502 
503 /*
504  * this is so I can play live CCIR raw video
505  */
506 static int altivec_uyvy_rgb32(SwsInternal *c, const unsigned char *const *in,
507  const int *instrides, int srcSliceY, int srcSliceH,
508  unsigned char *const *oplanes, const int *outstrides)
509 {
510  int w = c->opts.src_w;
511  int h = srcSliceH;
512  int i, j;
513  vector unsigned char uyvy;
514  vector signed short Y, U, V;
515  vector signed short R0, G0, B0, R1, G1, B1;
516  vector unsigned char R, G, B;
517  vector unsigned char *out;
518  const ubyte *img;
519 
520  img = in[0];
521  out = (vector unsigned char *) (oplanes[0] + srcSliceY * outstrides[0]);
522 
523  for (i = 0; i < h; i++)
524  for (j = 0; j < w / 16; j++) {
525  uyvy = vec_ld(0, img);
526 
527  U = (vector signed short)
528  vec_perm(uyvy, (vector unsigned char) { 0 }, demux_u);
529  V = (vector signed short)
530  vec_perm(uyvy, (vector unsigned char) { 0 }, demux_v);
531  Y = (vector signed short)
532  vec_perm(uyvy, (vector unsigned char) { 0 }, demux_y);
533 
534  cvtyuvtoRGB(c, Y, U, V, &R0, &G0, &B0);
535 
536  uyvy = vec_ld(16, img);
537 
538  U = (vector signed short)
539  vec_perm(uyvy, (vector unsigned char) { 0 }, demux_u);
540  V = (vector signed short)
541  vec_perm(uyvy, (vector unsigned char) { 0 }, demux_v);
542  Y = (vector signed short)
543  vec_perm(uyvy, (vector unsigned char) { 0 }, demux_y);
544 
545  cvtyuvtoRGB(c, Y, U, V, &R1, &G1, &B1);
546 
547  R = vec_packclp(R0, R1);
548  G = vec_packclp(G0, G1);
549  B = vec_packclp(B0, B1);
550 
551  // vec_mstbgr24 (R,G,B, out);
552  out_rgba(R, G, B, out);
553 
554  img += 32;
555  }
556  return srcSliceH;
557 }
558 
559 #endif /* HAVE_ALTIVEC */
560 
561 /* Ok currently the acceleration routine only supports
562  * inputs of widths a multiple of 16
563  * and heights a multiple 2
564  *
565  * So we just fall back to the C codes for this.
566  */
568 {
569 #if HAVE_ALTIVEC
571  return NULL;
572 
573  /*
574  * and this seems not to matter too much I tried a bunch of
575  * videos with abnormal widths and MPlayer crashes elsewhere.
576  * mplayer -vo x11 -rawvideo on:w=350:h=240 raw-350x240.eyuv
577  * boom with X11 bad match.
578  *
579  */
580  if ((c->opts.src_w & 0xf) != 0)
581  return NULL;
582 
583  switch (c->opts.src_format) {
584  case AV_PIX_FMT_YUV410P:
585  case AV_PIX_FMT_YUV420P:
586  /*case IMGFMT_CLPL: ??? */
587  case AV_PIX_FMT_GRAY8:
588  case AV_PIX_FMT_NV12:
589  case AV_PIX_FMT_NV21:
590  if ((c->opts.src_h & 0x1) != 0)
591  return NULL;
592 
593 /*
594  * The below accelerations for YUV2RGB are known broken.
595  * See: 'fate-checkasm-sw_yuv2rgb' with --enable-altivec
596  * They are disabled for the moment, until such time as
597  * they can be repaired.
598  */
599 #if 0
600  switch (c->opts.dst_format) {
601  case AV_PIX_FMT_RGB24:
602  av_log(c, AV_LOG_WARNING, "ALTIVEC: Color Space RGB24\n");
603  return altivec_yuv2_rgb24;
604  case AV_PIX_FMT_BGR24:
605  av_log(c, AV_LOG_WARNING, "ALTIVEC: Color Space BGR24\n");
606  return altivec_yuv2_bgr24;
607  case AV_PIX_FMT_ARGB:
608  av_log(c, AV_LOG_WARNING, "ALTIVEC: Color Space ARGB\n");
609  return altivec_yuv2_argb;
610  case AV_PIX_FMT_ABGR:
611  av_log(c, AV_LOG_WARNING, "ALTIVEC: Color Space ABGR\n");
612  return altivec_yuv2_abgr;
613  case AV_PIX_FMT_RGBA:
614  av_log(c, AV_LOG_WARNING, "ALTIVEC: Color Space RGBA\n");
615  return altivec_yuv2_rgba;
616  case AV_PIX_FMT_BGRA:
617  av_log(c, AV_LOG_WARNING, "ALTIVEC: Color Space BGRA\n");
618  return altivec_yuv2_bgra;
619  default: return NULL;
620  }
621 #endif /* disabled YUV2RGB acceleration */
622  break;
623 
624  case AV_PIX_FMT_UYVY422:
625  switch (c->opts.dst_format) {
626  case AV_PIX_FMT_BGR32:
627  av_log(c, AV_LOG_WARNING, "ALTIVEC: Color Space UYVY -> RGB32\n");
628  return altivec_uyvy_rgb32;
629  default: return NULL;
630  }
631  break;
632  }
633 #endif /* HAVE_ALTIVEC */
634 
635  return NULL;
636 }
637 
639  const int inv_table[4],
640  int brightness,
641  int contrast,
642  int saturation)
643 {
644 #if HAVE_ALTIVEC
645  SwsInternalAltivec *const a = sws_internal_altivec(c);
646 
647  union {
648  DECLARE_ALIGNED(16, signed short, tmp)[8];
649  vector signed short vec;
650  } buf;
651 
653  return;
654 
655  buf.tmp[0] = ((0xffffLL) * contrast >> 8) >> 9; // cy
656  buf.tmp[1] = -256 * brightness; // oy
657  buf.tmp[2] = (inv_table[0] >> 3) * (contrast >> 16) * (saturation >> 16); // crv
658  buf.tmp[3] = (inv_table[1] >> 3) * (contrast >> 16) * (saturation >> 16); // cbu
659  buf.tmp[4] = -((inv_table[2] >> 1) * (contrast >> 16) * (saturation >> 16)); // cgu
660  buf.tmp[5] = -((inv_table[3] >> 1) * (contrast >> 16) * (saturation >> 16)); // cgv
661 
662  a->CSHIFT = (vector unsigned short) vec_splat_u16(2);
663  a->CY = vec_splat((vector signed short) buf.vec, 0);
664  a->OY = vec_splat((vector signed short) buf.vec, 1);
665  a->CRV = vec_splat((vector signed short) buf.vec, 2);
666  a->CBU = vec_splat((vector signed short) buf.vec, 3);
667  a->CGU = vec_splat((vector signed short) buf.vec, 4);
668  a->CGV = vec_splat((vector signed short) buf.vec, 5);
669  return;
670 #endif /* HAVE_ALTIVEC */
671 }
672 
673 #if HAVE_ALTIVEC
674 
675 static av_always_inline void yuv2packedX_altivec(SwsInternal *c,
676  const int16_t *lumFilter,
677  const int16_t **lumSrc,
678  int lumFilterSize,
679  const int16_t *chrFilter,
680  const int16_t **chrUSrc,
681  const int16_t **chrVSrc,
682  int chrFilterSize,
683  const int16_t **alpSrc,
684  uint8_t *dest,
685  int dstW, int dstY,
686  enum AVPixelFormat target)
687 {
688  SwsInternalAltivec *const a = sws_internal_altivec(c);
689 
690  int i, j;
691  vector signed short X, X0, X1, Y0, U0, V0, Y1, U1, V1, U, V;
692  vector signed short R0, G0, B0, R1, G1, B1;
693 
694  vector unsigned char R, G, B;
695  vector unsigned char *out, *nout;
696 
697  vector signed short RND = vec_splat_s16(1 << 3);
698  vector unsigned short SCL = vec_splat_u16(4);
699  DECLARE_ALIGNED(16, unsigned int, scratch)[16];
700 
701  vector signed short *YCoeffs, *CCoeffs;
702 
703  YCoeffs = a->vYCoeffsBank + dstY * lumFilterSize;
704  CCoeffs = a->vCCoeffsBank + dstY * chrFilterSize;
705 
706  out = (vector unsigned char *) dest;
707 
708  for (i = 0; i < dstW; i += 16) {
709  Y0 = RND;
710  Y1 = RND;
711  /* extract 16 coeffs from lumSrc */
712  for (j = 0; j < lumFilterSize; j++) {
713  X0 = vec_ld(0, &lumSrc[j][i]);
714  X1 = vec_ld(16, &lumSrc[j][i]);
715  Y0 = vec_mradds(X0, YCoeffs[j], Y0);
716  Y1 = vec_mradds(X1, YCoeffs[j], Y1);
717  }
718 
719  U = RND;
720  V = RND;
721  /* extract 8 coeffs from U,V */
722  for (j = 0; j < chrFilterSize; j++) {
723  X = vec_ld(0, &chrUSrc[j][i / 2]);
724  U = vec_mradds(X, CCoeffs[j], U);
725  X = vec_ld(0, &chrVSrc[j][i / 2]);
726  V = vec_mradds(X, CCoeffs[j], V);
727  }
728 
729  /* scale and clip signals */
730  Y0 = vec_sra(Y0, SCL);
731  Y1 = vec_sra(Y1, SCL);
732  U = vec_sra(U, SCL);
733  V = vec_sra(V, SCL);
734 
735  Y0 = vec_clip_s16(Y0);
736  Y1 = vec_clip_s16(Y1);
737  U = vec_clip_s16(U);
738  V = vec_clip_s16(V);
739 
740  /* now we have
741  * Y0 = y0 y1 y2 y3 y4 y5 y6 y7 Y1 = y8 y9 y10 y11 y12 y13 y14 y15
742  * U = u0 u1 u2 u3 u4 u5 u6 u7 V = v0 v1 v2 v3 v4 v5 v6 v7
743  *
744  * Y0 = y0 y1 y2 y3 y4 y5 y6 y7 Y1 = y8 y9 y10 y11 y12 y13 y14 y15
745  * U0 = u0 u0 u1 u1 u2 u2 u3 u3 U1 = u4 u4 u5 u5 u6 u6 u7 u7
746  * V0 = v0 v0 v1 v1 v2 v2 v3 v3 V1 = v4 v4 v5 v5 v6 v6 v7 v7
747  */
748 
749  U0 = vec_mergeh(U, U);
750  V0 = vec_mergeh(V, V);
751 
752  U1 = vec_mergel(U, U);
753  V1 = vec_mergel(V, V);
754 
755  cvtyuvtoRGB(c, Y0, U0, V0, &R0, &G0, &B0);
756  cvtyuvtoRGB(c, Y1, U1, V1, &R1, &G1, &B1);
757 
758  R = vec_packclp(R0, R1);
759  G = vec_packclp(G0, G1);
760  B = vec_packclp(B0, B1);
761 
762  switch (target) {
763  case AV_PIX_FMT_ABGR:
764  out_abgr(R, G, B, out);
765  break;
766  case AV_PIX_FMT_BGRA:
767  out_bgra(R, G, B, out);
768  break;
769  case AV_PIX_FMT_RGBA:
770  out_rgba(R, G, B, out);
771  break;
772  case AV_PIX_FMT_ARGB:
773  out_argb(R, G, B, out);
774  break;
775  case AV_PIX_FMT_RGB24:
776  out_rgb24(R, G, B, out);
777  break;
778  case AV_PIX_FMT_BGR24:
779  out_bgr24(R, G, B, out);
780  break;
781  default:
782  {
783  /* If this is reached, the caller should have called yuv2packedXinC
784  * instead. */
785  static int printed_error_message;
786  if (!printed_error_message) {
788  "altivec_yuv2packedX doesn't support %s output\n",
789  av_get_pix_fmt_name(c->opts.dst_format));
790  printed_error_message = 1;
791  }
792  return;
793  }
794  }
795  }
796 
797  if (i < dstW) {
798  i -= 16;
799 
800  Y0 = RND;
801  Y1 = RND;
802  /* extract 16 coeffs from lumSrc */
803  for (j = 0; j < lumFilterSize; j++) {
804  X0 = vec_ld(0, &lumSrc[j][i]);
805  X1 = vec_ld(16, &lumSrc[j][i]);
806  Y0 = vec_mradds(X0, YCoeffs[j], Y0);
807  Y1 = vec_mradds(X1, YCoeffs[j], Y1);
808  }
809 
810  U = RND;
811  V = RND;
812  /* extract 8 coeffs from U,V */
813  for (j = 0; j < chrFilterSize; j++) {
814  X = vec_ld(0, &chrUSrc[j][i / 2]);
815  U = vec_mradds(X, CCoeffs[j], U);
816  X = vec_ld(0, &chrVSrc[j][i / 2]);
817  V = vec_mradds(X, CCoeffs[j], V);
818  }
819 
820  /* scale and clip signals */
821  Y0 = vec_sra(Y0, SCL);
822  Y1 = vec_sra(Y1, SCL);
823  U = vec_sra(U, SCL);
824  V = vec_sra(V, SCL);
825 
826  Y0 = vec_clip_s16(Y0);
827  Y1 = vec_clip_s16(Y1);
828  U = vec_clip_s16(U);
829  V = vec_clip_s16(V);
830 
831  /* now we have
832  * Y0 = y0 y1 y2 y3 y4 y5 y6 y7 Y1 = y8 y9 y10 y11 y12 y13 y14 y15
833  * U = u0 u1 u2 u3 u4 u5 u6 u7 V = v0 v1 v2 v3 v4 v5 v6 v7
834  *
835  * Y0 = y0 y1 y2 y3 y4 y5 y6 y7 Y1 = y8 y9 y10 y11 y12 y13 y14 y15
836  * U0 = u0 u0 u1 u1 u2 u2 u3 u3 U1 = u4 u4 u5 u5 u6 u6 u7 u7
837  * V0 = v0 v0 v1 v1 v2 v2 v3 v3 V1 = v4 v4 v5 v5 v6 v6 v7 v7
838  */
839 
840  U0 = vec_mergeh(U, U);
841  V0 = vec_mergeh(V, V);
842 
843  U1 = vec_mergel(U, U);
844  V1 = vec_mergel(V, V);
845 
846  cvtyuvtoRGB(c, Y0, U0, V0, &R0, &G0, &B0);
847  cvtyuvtoRGB(c, Y1, U1, V1, &R1, &G1, &B1);
848 
849  R = vec_packclp(R0, R1);
850  G = vec_packclp(G0, G1);
851  B = vec_packclp(B0, B1);
852 
853  nout = (vector unsigned char *) scratch;
854  switch (target) {
855  case AV_PIX_FMT_ABGR:
856  out_abgr(R, G, B, nout);
857  break;
858  case AV_PIX_FMT_BGRA:
859  out_bgra(R, G, B, nout);
860  break;
861  case AV_PIX_FMT_RGBA:
862  out_rgba(R, G, B, nout);
863  break;
864  case AV_PIX_FMT_ARGB:
865  out_argb(R, G, B, nout);
866  break;
867  case AV_PIX_FMT_RGB24:
868  out_rgb24(R, G, B, nout);
869  break;
870  case AV_PIX_FMT_BGR24:
871  out_bgr24(R, G, B, nout);
872  break;
873  default:
874  /* Unreachable, I think. */
876  "altivec_yuv2packedX doesn't support %s output\n",
877  av_get_pix_fmt_name(c->opts.dst_format));
878  return;
879  }
880 
881  memcpy(&((uint32_t *) dest)[i], scratch, (dstW - i) / 4);
882  }
883 }
884 
885 #define YUV2PACKEDX_WRAPPER(suffix, pixfmt) \
886 void ff_yuv2 ## suffix ## _X_altivec(SwsInternal *c, \
887  const int16_t *lumFilter, \
888  const int16_t **lumSrc, \
889  int lumFilterSize, \
890  const int16_t *chrFilter, \
891  const int16_t **chrUSrc, \
892  const int16_t **chrVSrc, \
893  int chrFilterSize, \
894  const int16_t **alpSrc, \
895  uint8_t *dest, int dstW, int dstY) \
896 { \
897  yuv2packedX_altivec(c, lumFilter, lumSrc, lumFilterSize, \
898  chrFilter, chrUSrc, chrVSrc, \
899  chrFilterSize, alpSrc, \
900  dest, dstW, dstY, pixfmt); \
901 }
902 
903 YUV2PACKEDX_WRAPPER(abgr, AV_PIX_FMT_ABGR);
904 YUV2PACKEDX_WRAPPER(bgra, AV_PIX_FMT_BGRA);
905 YUV2PACKEDX_WRAPPER(argb, AV_PIX_FMT_ARGB);
906 YUV2PACKEDX_WRAPPER(rgba, AV_PIX_FMT_RGBA);
907 YUV2PACKEDX_WRAPPER(rgb24, AV_PIX_FMT_RGB24);
908 YUV2PACKEDX_WRAPPER(bgr24, AV_PIX_FMT_BGR24);
909 
911 {
912  const SwsContext *const sws = &c->opts;
913  SwsInternalAltivec *const a = sws_internal_altivec(c);
914 
915  a->vYCoeffsBank = av_malloc_array(sws->dst_h, c->vLumFilterSize * sizeof(*a->vYCoeffsBank));
916  a->vCCoeffsBank = av_malloc_array(c->chrDstH, c->vChrFilterSize * sizeof(*a->vCCoeffsBank));
917  if (!a->vYCoeffsBank || !a->vCCoeffsBank)
918  return AVERROR(ENOMEM);
919 
920  for (int i = 0; i < c->vLumFilterSize * sws->dst_h; ++i) {
921  short *p = (short *)&a->vYCoeffsBank[i];
922  for (int j = 0; j < 8; ++j)
923  p[j] = c->vLumFilter[i];
924  }
925 
926  for (int i = 0; i < c->vChrFilterSize * c->chrDstH; ++i) {
927  short *p = (short *)&a->vCCoeffsBank[i];
928  for (int j = 0; j < 8; ++j)
929  p[j] = c->vChrFilter[i];
930  }
931 
932  return 0;
933 }
934 
936 {
937  SwsInternalAltivec *const a = sws_internal_altivec(c);
938  av_freep(&a->vYCoeffsBank);
939  av_freep(&a->vCCoeffsBank);
940 }
941 #endif /* HAVE_ALTIVEC */
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
mem_internal.h
out
static FILE * out
Definition: movenc.c:55
AV_PIX_FMT_BGR32
#define AV_PIX_FMT_BGR32
Definition: pixfmt.h:513
R0
#define R0(v, w, x, y, z, i)
Definition: sha.c:57
saturation
static IPT saturation(const CmsCtx *ctx, IPT ipt)
Definition: cms.c:559
pixdesc.h
SWSINTERNAL_ADDITIONAL_ASM_SIZE
#define SWSINTERNAL_ADDITIONAL_ASM_SIZE
Definition: swscale_internal.h:47
R
#define R
Definition: huffyuv.h:44
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:76
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:102
R1
#define R1
Definition: simple_idct.c:166
av_get_cpu_flags
int av_get_cpu_flags(void)
Return the flags which specify extensions supported by the CPU.
Definition: cpu.c:109
B1
@ B1
Definition: mvs.c:532
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
av_cold
#define av_cold
Definition: attributes.h:111
CSHIFT
#define CSHIFT
Definition: audiogen.c:72
B
#define B
Definition: huffyuv.h:42
ff_yuv2rgb_init_tables_ppc
av_cold void ff_yuv2rgb_init_tables_ppc(SwsInternal *c, const int inv_table[4], int brightness, int contrast, int saturation)
Definition: yuv2rgb_altivec.c:638
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:73
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
ff_yuv2rgb_init_ppc
av_cold SwsFunc ff_yuv2rgb_init_ppc(SwsInternal *c)
Definition: yuv2rgb_altivec.c:567
NULL
#define NULL
Definition: coverity.c:32
V
#define V
Definition: avdct.c:32
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:81
AV_CPU_FLAG_ALTIVEC
#define AV_CPU_FLAG_ALTIVEC
standard
Definition: cpu.h:64
AV_PIX_FMT_ABGR
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:101
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
error.h
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:75
DECLARE_ALIGNED
#define DECLARE_ALIGNED(n, t, v)
Definition: mem_internal.h:104
cpu.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
for
for(k=2;k<=8;++k)
Definition: h264pred_template.c:424
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
img
#define img
Definition: vf_colormatrix.c:114
yuv2rgb_altivec.h
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
attributes.h
xf
#define xf(width, name, var, range_min, range_max, subs,...)
Definition: cbs_av1.c:622
Y
#define Y
Definition: boxblur.h:37
AV_PIX_FMT_ARGB
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:99
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
av_always_inline
#define av_always_inline
Definition: attributes.h:68
swscale_internal.h
AV_PIX_FMT_NV21
@ AV_PIX_FMT_NV21
as above, but U and V bytes are swapped
Definition: pixfmt.h:97
SwsContext::dst_h
int dst_h
Width and height of the destination frame.
Definition: swscale.h:254
ff_sws_init_altivec_bufs
int ff_sws_init_altivec_bufs(SwsInternal *c)
B0
@ B0
Definition: mvs.c:531
SwsInternal
Definition: swscale_internal.h:335
AV_PIX_FMT_NV12
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:96
AV_PIX_FMT_UYVY422
@ AV_PIX_FMT_UYVY422
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition: pixfmt.h:88
U
#define U(x)
Definition: vpx_arith.h:37
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
G
#define G
Definition: huffyuv.h:43
mem.h
w
uint8_t w
Definition: llvidencdsp.c:39
util_altivec.h
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
SwsFunc
int(* SwsFunc)(SwsInternal *c, const uint8_t *const src[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[])
Definition: swscale_internal.h:97
X
@ X
Definition: vf_addroi.c:27
ff_sws_free_altivec_bufs
void ff_sws_free_altivec_bufs(SwsInternal *c)
AV_PIX_FMT_YUV410P
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:79
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
h
h
Definition: vp9dsp_template.c:2070
SwsContext
Main external API structure.
Definition: swscale.h:206
short
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option keep it simple and lowercase description are short
Definition: writing_filters.txt:89
rgb2rgb.h
swscale.h
av_get_pix_fmt_name
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:3376