• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2013 Wim Taymans <wim.taymans@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23 
24 #include <string.h>
25 #include <stdio.h>
26 
27 #include "video-orc.h"
28 #include "video-format.h"
29 
30 
31 /**
32  * SECTION:gstvideochroma
33  * @title: GstVideoChromaResample
34  * @short_description: Functions and utility object for operating on chroma video planes
35  *
36  * The functions gst_video_chroma_from_string() and gst_video_chroma_to_string() convert
37  * between #GstVideoChromaSite and string descriptions.
38  *
39  * #GstVideoChromaResample is a utility object for resampling chroma planes
40  * and converting between different chroma sampling sitings.
41  *
42  */
43 
44 #ifndef GST_DISABLE_GST_DEBUG
45 #define GST_CAT_DEFAULT ensure_debug_category()
46 static GstDebugCategory *
ensure_debug_category(void)47 ensure_debug_category (void)
48 {
49   static gsize cat_gonce = 0;
50 
51   if (g_once_init_enter (&cat_gonce)) {
52     gsize cat_done;
53 
54     cat_done = (gsize) _gst_debug_category_new ("video-chroma", 0,
55         "video-chroma object");
56 
57     g_once_init_leave (&cat_gonce, cat_done);
58   }
59 
60   return (GstDebugCategory *) cat_gonce;
61 }
62 #else
63 #define ensure_debug_category() /* NOOP */
64 #endif /* GST_DISABLE_GST_DEBUG */
65 
66 typedef struct
67 {
68   const gchar *name;
69   GstVideoChromaSite site;
70 } ChromaSiteInfo;
71 
72 static const ChromaSiteInfo chromasite[] = {
73   {"jpeg", GST_VIDEO_CHROMA_SITE_JPEG},
74   {"mpeg2", GST_VIDEO_CHROMA_SITE_MPEG2},
75   {"dv", GST_VIDEO_CHROMA_SITE_DV}
76 };
77 
78 /**
79  * gst_video_chroma_from_string:
80  * @s: a chromasite string
81  *
82  * Convert @s to a #GstVideoChromaSite
83  *
84  * Returns: a #GstVideoChromaSite or %GST_VIDEO_CHROMA_SITE_UNKNOWN when @s does
85  * not contain a valid chroma description.
86  */
87 GstVideoChromaSite
gst_video_chroma_from_string(const gchar * s)88 gst_video_chroma_from_string (const gchar * s)
89 {
90   gint i;
91   for (i = 0; i < G_N_ELEMENTS (chromasite); i++) {
92     if (g_str_equal (chromasite[i].name, s))
93       return chromasite[i].site;
94   }
95   return GST_VIDEO_CHROMA_SITE_UNKNOWN;
96 }
97 
98 /**
99  * gst_video_chroma_to_string:
100  * @site: a #GstVideoChromaSite
101  *
102  * Converts @site to its string representation.
103  *
104  * Returns: a string describing @site.
105  */
106 const gchar *
gst_video_chroma_to_string(GstVideoChromaSite site)107 gst_video_chroma_to_string (GstVideoChromaSite site)
108 {
109   gint i;
110   for (i = 0; i < G_N_ELEMENTS (chromasite); i++) {
111     if (chromasite[i].site == site)
112       return chromasite[i].name;
113   }
114   return NULL;
115 }
116 
117 struct _GstVideoChromaResample
118 {
119   GstVideoChromaMethod method;
120   GstVideoChromaSite site;
121   GstVideoChromaFlags flags;
122   GstVideoFormat format;
123   gint h_factor, v_factor;
124   guint n_lines;
125   gint offset;
126   void (*h_resample) (GstVideoChromaResample * resample, gpointer pixels,
127       gint width);
128   void (*v_resample) (GstVideoChromaResample * resample, gpointer lines[],
129       gint width);
130 };
131 
132 #define PR(i)          (p[2 + 4 * (i)])
133 #define PB(i)          (p[3 + 4 * (i)])
134 
135 #define PR0(i)         (l0[2 + 4 * (i)])
136 #define PR1(i)         (l1[2 + 4 * (i)])
137 #define PR2(i)         (l2[2 + 4 * (i)])
138 #define PR3(i)         (l3[2 + 4 * (i)])
139 #define PB0(i)         (l0[3 + 4 * (i)])
140 #define PB1(i)         (l1[3 + 4 * (i)])
141 #define PB2(i)         (l2[3 + 4 * (i)])
142 #define PB3(i)         (l3[3 + 4 * (i)])
143 
144 #define FILT_1_1(a,b)          ((a) + (b) + 1) >> 1
145 #define FILT_1_3_3_1(a,b,c,d)  ((a) + 3*((b)+(c)) + (d) + 4) >> 3
146 
147 #define FILT_3_1(a,b)          (3*(a) + (b) + 2) >> 2
148 #define FILT_1_3(a,b)          ((a) + 3*(b) + 2) >> 2
149 #define FILT_1_2_1(a,b,c)      ((a) + 2*(b) + (c) + 2) >> 2
150 
151 #define FILT_7_1(a,b)          (7*(a) + 1*(b) + 4) >> 3
152 #define FILT_1_7(a,b)          (1*(a) + 7*(b) + 4) >> 3
153 
154 #define FILT_5_3(a,b)          (5*(a) + 3*(b) + 4) >> 3
155 #define FILT_3_5(a,b)          (3*(a) + 5*(b) + 4) >> 3
156 
157 #define FILT_10_3_2_1(a,b,c,d)      (10*(a) + 3*(b) + 2*(c) + (d) + 8) >> 16
158 #define FILT_1_2_3_10(a,b,c,d)      ((a) + 2*(b) + 3*(c) + 10*(d) + 8) >> 16
159 #define FILT_1_2_3_4_3_2_1(a,b,c,d,e,f,g) ((a) + 2*((b)+(f)) + 3*((c)+(e)) + 4*(d) + (g) + 8) >> 16
160 
161 /* 2x horizontal upsampling without cositing
162  *
163  * +----------    a
164  * | +------ (3*a +   b + 2) >> 2
165  * | | +---- (  a + 3*b + 2) >> 2
166  * v v v
167  * O-O-O-O-
168  *  x   x
169  *  a   b
170  */
171 #define MAKE_UPSAMPLE_H2(name,type)                                     \
172 static void                                                             \
173 video_chroma_up_h2_##name (GstVideoChromaResample *resample,            \
174     gpointer pixels, gint width)                                        \
175 {                                                                       \
176   type *p = pixels;                                                     \
177   gint i;                                                               \
178   type tr0, tr1;                                                        \
179   type tb0, tb1;                                                        \
180                                                                         \
181   tr1 = PR(0);                                                          \
182   tb1 = PB(0);                                                          \
183   for (i = 1; i < width - 1; i += 2) {                                  \
184     tr0 = tr1, tr1 = PR(i+1);                                           \
185     tb0 = tb1, tb1 = PB(i+1);                                           \
186                                                                         \
187     PR(i) = FILT_3_1 (tr0, tr1);                                        \
188     PB(i) = FILT_3_1 (tb0, tb1);                                        \
189     PR(i+1) = FILT_1_3 (tr0, tr1);                                      \
190     PB(i+1) = FILT_1_3 (tb0, tb1);                                      \
191   }                                                                     \
192 }
193 
194 /* 2x vertical upsampling without cositing
195  *
196  *   O--O--O-  <---- a
197  * a x  x  x
198  *   O--O--O-  <---- (3*a +   b + 2) >> 2
199  *   O--O--O-  <-----(  a + 3*b + 2) >> 2
200  * b x  x  x
201  *   O--O--O-  <---- b
202  */
203 #define MAKE_UPSAMPLE_V2(name,type)                                     \
204 static void                                                             \
205 video_chroma_up_v2_##name (GstVideoChromaResample *resample,            \
206     gpointer lines[], gint width)                                       \
207 {                                                                       \
208   type *l0 = lines[0];                                                  \
209   type *l1 = lines[1];                                                  \
210                                                                         \
211   if (resample->h_resample) {                                           \
212     resample->h_resample (resample, l0, width);                         \
213     if (l0 != l1)                                                       \
214       resample->h_resample (resample, l1, width);                       \
215   }                                                                     \
216   if (l0 != l1) {                                                       \
217     type *d0 = l0;							\
218     type *d1 = l1;							\
219     video_orc_chroma_up_v2_##name (d0, d1, l0, l1, width);              \
220   }                                                                     \
221 }
222 /* 2x vertical upsampling interlaced without cositing
223  *
224  *   even           odd
225  *
226  *   O--O--O--------------- <---  a
227  * a x  x  x
228  *   --------------O--O--O- <---  c
229  *   O--O--O--------------- <--- (5*a + 3*b + 4) >> 3
230  * c               x  x  x
231  *   --------------O--O--O- <--- (7*c +   d + 4) >> 3
232  *   O--O--O--------------- <--- (  a + 7*b + 4) >> 3
233  * b x  x  x
234  *   --------------O--O--O- <--- (3*c + 5*d + 4) >> 3
235  *   O--O--O---------------
236  * d               x  x  x
237  *   --------------O--O--O-
238  */
239 #define MAKE_UPSAMPLE_VI2(name,type)                                    \
240 static void                                                             \
241 video_chroma_up_vi2_##name (GstVideoChromaResample *resample,           \
242     gpointer lines[], gint width)                                       \
243 {                                                                       \
244   gint i;                                                               \
245   type *l0 = lines[0];                                                  \
246   type *l1 = lines[1];                                                  \
247   type *l2 = lines[2];                                                  \
248   type *l3 = lines[3];                                                  \
249   type tr0, tr1, tr2, tr3;                                              \
250   type tb0, tb1, tb2, tb3;                                              \
251                                                                         \
252   if (resample->h_resample) {                                           \
253     if (l0 != l1) {                                                     \
254       resample->h_resample (resample, l0, width);                       \
255       resample->h_resample (resample, l1, width);                       \
256     }                                                                   \
257     if (l2 != l3) {                                                     \
258       resample->h_resample (resample, l2, width);                       \
259       resample->h_resample (resample, l3, width);                       \
260     }                                                                   \
261   }                                                                     \
262   if (l0 != l1 && l2 != l3) {                                           \
263     for (i = 0; i < width; i++) {                                       \
264       tr0 = PR0(i), tr2 = PR2(i);                                       \
265       tb0 = PB0(i), tb2 = PB2(i);                                       \
266       tr1 = PR1(i), tr3 = PR3(i);                                       \
267       tb1 = PB1(i), tb3 = PB3(i);                                       \
268                                                                         \
269       PR0(i) = FILT_5_3 (tr0, tr2);                                     \
270       PB0(i) = FILT_5_3 (tb0, tb2);                                     \
271       PR1(i) = FILT_7_1 (tr1, tr3);                                     \
272       PB1(i) = FILT_7_1 (tb1, tb3);                                     \
273       PR2(i) = FILT_1_7 (tr0, tr2);                                     \
274       PB2(i) = FILT_1_7 (tb0, tb2);                                     \
275       PR3(i) = FILT_3_5 (tr1, tr3);                                     \
276       PB3(i) = FILT_3_5 (tb1, tb3);                                     \
277     }                                                                   \
278   }                                                                     \
279 }
280 
281 /* 2x horizontal downsampling without cositing
282  *
283  *  +------ (a + b+ 1) >> 1
284  *  |
285  *  v
286  * -O---O--
287  * x x x x
288  * a b c d
289  */
290 #define MAKE_DOWNSAMPLE_H2_ORC(name,type)                               \
291 static void                                                             \
292 video_chroma_down_h2_##name (GstVideoChromaResample *resample,          \
293     gpointer pixels, gint width)                                        \
294 {                                                                       \
295   type *p = pixels;                                                     \
296   type *d = p;								\
297                                                                         \
298   video_orc_chroma_down_h2_##name (d, p, width / 2);                    \
299 }
300 
301 #define MAKE_DOWNSAMPLE_H2(name,type)                                   \
302 static void                                                             \
303 video_chroma_down_h2_##name (GstVideoChromaResample *resample,          \
304     gpointer pixels, gint width)                                        \
305 {                                                                       \
306   type *p = pixels;                                                     \
307   gint i;                                                               \
308                                                                         \
309   for (i = 0; i < width - 1; i += 2) {                                  \
310     type tr0 = PR(i), tr1 = PR(i+1);                                    \
311     type tb0 = PB(i), tb1 = PB(i+1);                                    \
312                                                                         \
313     PR(i) = FILT_1_1 (tr0, tr1);                                        \
314     PB(i) = FILT_1_1 (tb0, tb1);                                        \
315   }                                                                     \
316 }
317 /* 2x vertical downsampling without cositing
318  *
319  * a x--x--x-
320  *   O  O  O <---- (a + b + 1) >> 1
321  * b x--x--x-
322  * c x--x--x-
323  *   O  O  O
324  * d x--x--x-
325  */
326 #define MAKE_DOWNSAMPLE_V2(name,type)                                   \
327 static void                                                             \
328 video_chroma_down_v2_##name (GstVideoChromaResample *resample,          \
329     gpointer lines[], gint width)                                       \
330 {                                                                       \
331   type *l0 = lines[0];                                                  \
332   type *l1 = lines[1];                                                  \
333                                                                         \
334   if (l0 != l1) {							\
335     type *d0 = l0;							\
336     video_orc_chroma_down_v2_##name (d0, l0, l1, width);                \
337   }									\
338                                                                         \
339   if (resample->h_resample)                                             \
340     resample->h_resample (resample, l0, width);                         \
341 }
342 /* 2x vertical downsampling interlaced without cositing
343  *
344  *   even           odd
345  *
346  * a x--x--x---------------
347  *   O  O  O                <---
348  * b --------------x--x--x-
349  * c x--x--x---------------
350  *                 O  O  O  <---
351  * d --------------x--x--x-
352  */
353 #define MAKE_DOWNSAMPLE_VI2(name,type)                                  \
354 static void                                                             \
355 video_chroma_down_vi2_##name (GstVideoChromaResample *resample,         \
356     gpointer lines[], gint width)                                       \
357 {                                                                       \
358   /* FIXME */                                                           \
359   if (resample->h_resample)                                             \
360     resample->h_resample (resample, lines[0], width);                   \
361 }
362 
363 MAKE_UPSAMPLE_H2 (u16, guint16);
364 MAKE_UPSAMPLE_H2 (u8, guint8);
365 MAKE_UPSAMPLE_V2 (u16, guint16);
366 MAKE_UPSAMPLE_V2 (u8, guint8);
367 MAKE_UPSAMPLE_VI2 (u16, guint16);
368 MAKE_UPSAMPLE_VI2 (u8, guint8);
369 MAKE_DOWNSAMPLE_H2 (u16, guint16);
370 MAKE_DOWNSAMPLE_H2_ORC (u8, guint8);
371 MAKE_DOWNSAMPLE_V2 (u16, guint16);
372 MAKE_DOWNSAMPLE_V2 (u8, guint8);
373 MAKE_DOWNSAMPLE_VI2 (u16, guint16);
374 MAKE_DOWNSAMPLE_VI2 (u8, guint8);
375 
376 /* 4x horizontal upsampling without cositing
377  *
378  *     +---------- (7*a +   b + 4) >> 3
379  *     | +-------- (5*a + 3*b + 4) >> 3
380  * a a | | +------ (3*a + 5*b + 4) >> 3
381  * | | | | | +---- (  a + 7*b + 4) >> 3
382  * v v v v v v
383  * O-O-O-O-O-O-O-O-
384  *    x       x
385  *    a       b
386  */
387 #define MAKE_UPSAMPLE_H4(name,type)                                          \
388 static void                                                             \
389 video_chroma_up_h4_##name (GstVideoChromaResample *resample,           \
390     gpointer pixels, gint width)                        \
391 {                                                                       \
392   type *p = pixels;                                                     \
393   gint i;                                                               \
394   type tr0, tr1;                                                        \
395   type tb0, tb1;                                                        \
396                                                                         \
397   tr1 = PR(0);                                                          \
398   tb1 = PB(0);                                                          \
399   for (i = 2; i < width - 3; i += 4) {                                  \
400     tr0 = tr1, tr1 = PR(i+2);                                           \
401     tb0 = tb1, tb1 = PB(i+2);                                           \
402                                                                         \
403     PR(i) = FILT_7_1 (tr0, tr1);                                        \
404     PB(i) = FILT_7_1 (tb0, tb1);                                        \
405     PR(i+1) = FILT_5_3 (tr0, tr1);                                      \
406     PB(i+1) = FILT_5_3 (tb0, tb1);                                      \
407     PR(i+2) = FILT_3_5 (tr0, tr1);                                      \
408     PB(i+2) = FILT_3_5 (tb0, tb1);                                      \
409     PR(i+3) = FILT_1_7 (tr0, tr1);                                      \
410     PB(i+3) = FILT_1_7 (tb0, tb1);                                      \
411   }                                                                     \
412 }
413 
414 /* 4x vertical upsampling without cositing
415  *
416  *   O--O--O-  <---- a
417  *   O--O--O-  <---- a
418  * a x  x  x
419  *   O--O--O-  <---- (7*a +   b + 4) >> 3
420  *   O--O--O-  <---- (5*a + 3*b + 4) >> 3
421  *   O--O--O-  <---- (3*a + 5*b + 4) >> 3
422  *   O--O--O-  <-----(  a + 7*b + 4) >> 3
423  * b x  x  x
424  *   O--O--O-
425  *   O--O--O-
426  */
427 #define MAKE_UPSAMPLE_V4(name,type)                                          \
428 static void                                                             \
429 video_chroma_up_v4_##name (GstVideoChromaResample *resample,            \
430     gpointer lines[], gint width)                                       \
431 {                                                                       \
432   gint i;                                                               \
433   type *l0 = lines[0];                                                  \
434   type *l1 = lines[1];                                                  \
435   type *l2 = lines[2];                                                  \
436   type *l3 = lines[3];                                                  \
437   type tr0, tr1;                                                        \
438   type tb0, tb1;                                                        \
439                                                                         \
440   if (resample->h_resample) {                                           \
441     if (l0 != l1) {                                                     \
442       resample->h_resample (resample, l0, width);                       \
443       resample->h_resample (resample, l1, width);                       \
444     }                                                                   \
445     if (l2 != l3) {                                                     \
446       resample->h_resample (resample, l2, width);                       \
447       resample->h_resample (resample, l3, width);                       \
448     }                                                                   \
449   }                                                                     \
450   if (l0 != l1 && l2 != l3) {                                           \
451     for (i = 0; i < width; i++) {                                       \
452       tr0 = PR0(i), tr1 = PR2(i);                                       \
453       tb0 = PB0(i), tb1 = PB2(i);                                       \
454                                                                         \
455       PR0(i) = FILT_7_1 (tr0, tr1);                                     \
456       PB0(i) = FILT_7_1 (tb0, tb1);                                     \
457       PR1(i) = FILT_5_3 (tr0, tr1);                                     \
458       PB1(i) = FILT_5_3 (tb0, tb1);                                     \
459       PR2(i) = FILT_3_5 (tr0, tr1);                                     \
460       PB2(i) = FILT_3_5 (tb0, tb1);                                     \
461       PR3(i) = FILT_1_7 (tr0, tr1);                                     \
462       PB3(i) = FILT_1_7 (tb0, tb1);                                     \
463     }                                                                   \
464   }                                                                     \
465 }
466 /* 4x vertical upsampling interlaced without cositing
467  *
468  */
469 #define MAKE_UPSAMPLE_VI4(name,type)                                         \
470 static void                                                             \
471 video_chroma_up_vi4_##name (GstVideoChromaResample *resample,           \
472     gpointer lines[], gint width)                                       \
473 {                                                                       \
474   /* FIXME */                                                           \
475   if (resample->h_resample) {                                           \
476     resample->h_resample (resample, lines[0], width);                   \
477   }                                                                     \
478 }
479 
480 /* 4x horizontal downsampling without cositing
481  *
482  *    +------ (a + 3*b + 3*c + d + 4) >> 3
483  *    |
484  *    v
485  * ---O-------O---
486  * x x x x x x x x
487  * a b c d e f g h
488  */
489 #define MAKE_DOWNSAMPLE_H4(name,type)                                        \
490 static void                                                             \
491 video_chroma_down_h4_##name (GstVideoChromaResample *resample,         \
492     gpointer pixels, gint width)                        \
493 {                                                                       \
494   type *p = pixels;                                                     \
495   gint i;                                                               \
496                                                                         \
497   for (i = 0; i < width - 4; i += 4) {                                  \
498     type tr0 = PR(i), tr1 = PR(i+1), tr2 = PR(i+2), tr3 = PR(i+3);      \
499     type tb0 = PB(i), tb1 = PB(i+1), tb2 = PB(i+2), tb3 = PB(i+3);      \
500                                                                         \
501     PR(i) = FILT_1_3_3_1 (tr0, tr1, tr2, tr3);                          \
502     PB(i) = FILT_1_3_3_1 (tb0, tb1, tb2, tb3);                          \
503   }                                                                     \
504 }
505 
506 /* 4x vertical downsampling without cositing
507  *
508  * a x--x--x-
509  * b x--x--x-
510  *   O  O  O   <---- (a + 3*b + 3*c + d + 4) >> 4
511  * c x--x--x-
512  * d x--x--x-
513  * e x--x--x-
514  * f x--x--x-
515  *   O  O  O
516  * g x--x--x-
517  * h x--x--x-
518  */
519 #define MAKE_DOWNSAMPLE_V4(name,type)                               \
520 static void                                                             \
521 video_chroma_down_v4_##name (GstVideoChromaResample *resample,          \
522     gpointer lines[], gint width)                                       \
523 {                                                                       \
524   type *l0 = lines[0];                                                  \
525   type *l1 = lines[1];                                                  \
526   type *l2 = lines[2];                                                  \
527   type *l3 = lines[3];                                                  \
528   type *d = l0;								\
529 									\
530   video_orc_chroma_down_v4_##name(d, l0, l1, l2, l3, width);		\
531                                                                         \
532   if (resample->h_resample)                                             \
533     resample->h_resample (resample, l0, width);                         \
534 }
535 /* 4x vertical downsampling interlaced without cositing
536  *
537  */
538 #define MAKE_DOWNSAMPLE_VI4(name,type)                                       \
539 static void                                                             \
540 video_chroma_down_vi4_##name (GstVideoChromaResample *resample,         \
541     gpointer lines[], gint width)                                       \
542 {                                                                       \
543   /* FIXME */                                                           \
544   if (resample->h_resample) {                                           \
545     resample->h_resample (resample, lines[0], width);                   \
546   }                                                                     \
547 }
548 
549 MAKE_UPSAMPLE_H4 (u16, guint16);
550 MAKE_UPSAMPLE_H4 (u8, guint8);
551 MAKE_UPSAMPLE_V4 (u16, guint16);
552 MAKE_UPSAMPLE_V4 (u8, guint8);
553 MAKE_UPSAMPLE_VI4 (u16, guint16);
554 MAKE_UPSAMPLE_VI4 (u8, guint8);
555 MAKE_DOWNSAMPLE_H4 (u16, guint16);
556 MAKE_DOWNSAMPLE_H4 (u8, guint8);
557 MAKE_DOWNSAMPLE_V4 (u16, guint16);
558 MAKE_DOWNSAMPLE_V4 (u8, guint8);
559 MAKE_DOWNSAMPLE_VI4 (u16, guint16);
560 MAKE_DOWNSAMPLE_VI4 (u8, guint8);
561 
562 /* 2x horizontal upsampling with cositing
563  *
564  * a +------ (a + b + 1) >> 1
565  * | |
566  * v v
567  * O-O-O-O
568  * x   x
569  * a   b
570  */
571 #define MAKE_UPSAMPLE_H2_CS_ORC(name,type)                              \
572 static void                                                             \
573 video_chroma_up_h2_cs_##name (GstVideoChromaResample *resample,         \
574     gpointer pixels, gint width)                                        \
575 {                                                                       \
576   type *p = pixels;                                                     \
577   /* ORC version is slower */                                           \
578   video_orc_chroma_up_h2_cs_##name (p, p, p, width-1);                  \
579 }
580 
581 #define MAKE_UPSAMPLE_H2_CS(name,type)                                  \
582 static void                                                             \
583 video_chroma_up_h2_cs_##name (GstVideoChromaResample *resample,         \
584     gpointer pixels, gint width)                                        \
585 {                                                                       \
586   type *p = pixels;                                                     \
587   gint i;                                                               \
588                                                                         \
589   for (i = 1; i < width - 1; i += 2) {                                  \
590     PR(i) = FILT_1_1 (PR(i-1), PR(i+1));                                \
591     PB(i) = FILT_1_1 (PB(i-1), PB(i+1));                                \
592   }                                                                     \
593 }
594 /* 2x vertical upsampling with cositing
595  *
596  * a x O--O--O-  <---- a
597  *     O--O--O-  <---- (a +  b + 1) >> 1
598  * b x O--O--O-
599  *     O--O--O-
600  */
601 #define MAKE_UPSAMPLE_V2_CS(name,type)                                       \
602 static void                                                             \
603 video_chroma_up_v2_cs_##name (GstVideoChromaResample *resample,         \
604     gpointer lines[], gint width)                                       \
605 {                                                                       \
606   /* FIXME */                                                           \
607   if (resample->h_resample) {                                           \
608     resample->h_resample (resample, lines[0], width);                   \
609   }                                                                     \
610 }
611 /* 2x vertical upsampling interlaced with cositing
612  *
613  */
614 #define MAKE_UPSAMPLE_VI2_CS(name,type)                                      \
615 static void                                                             \
616 video_chroma_up_vi2_cs_##name (GstVideoChromaResample *resample,        \
617     gpointer lines[], gint width)                                       \
618 {                                                                       \
619   /* FIXME */                                                           \
620   if (resample->h_resample) {                                           \
621     resample->h_resample (resample, lines[0], width);                   \
622   }                                                                     \
623 }
624 
625 /* 2x horizontal downsampling with cositing
626  *
627  * a
628  * |   +------ (b + 2*c + d + 2) >> 2
629  * v   v
630  * O---O---O---
631  * x x x x x x
632  * a b c d e f
633  */
634 #define MAKE_DOWNSAMPLE_H2_CS(name,type)                                     \
635 static void                                                             \
636 video_chroma_down_h2_cs_##name (GstVideoChromaResample *resample,       \
637     gpointer pixels, gint width)                                        \
638 {                                                                       \
639   type *p = pixels;                                                     \
640   gint i;                                                               \
641                                                                         \
642   if (width < 2)                                                        \
643     return;                                                             \
644                                                                         \
645   PR(0) = FILT_3_1 (PR(0), PR(1));                                      \
646   PB(0) = FILT_3_1 (PB(0), PB(1));                                      \
647                                                                         \
648   for (i = 2; i < width - 2; i += 2) {                                  \
649     PR(i) = FILT_1_2_1 (PR(i-1), PR(i), PR(i+1));                       \
650     PB(i) = FILT_1_2_1 (PB(i-1), PB(i), PB(i+1));                       \
651   }                                                                     \
652   if (i < width) {                                                      \
653     PR(i) = FILT_1_3 (PR(i-1), PR(i));                                  \
654     PB(i) = FILT_1_3 (PB(i-1), PB(i));                                  \
655   }                                                                     \
656 }
657 /* 2x vertical downsampling with cositing
658  *
659  * a x O--O--O-  <---- a
660  * b x --------
661  * c x O--O--O-  <---- (b + 2*c + d + 2) >> 2
662  * d x --------
663  * e x O--O--O-
664  * f x --------
665  */
666 #define MAKE_DOWNSAMPLE_V2_CS(name,type)                                     \
667 static void                                                             \
668 video_chroma_down_v2_cs_##name (GstVideoChromaResample *resample,       \
669     gpointer lines[], gint width)                                       \
670 {                                                                       \
671   /* FIXME */                                                           \
672   if (resample->h_resample) {                                           \
673     resample->h_resample (resample, lines[0], width);                   \
674   }                                                                     \
675 }
676 /* 2x vertical downsampling interlaced with cositing
677  *
678  */
679 #define MAKE_DOWNSAMPLE_VI2_CS(name,type)                                    \
680 static void                                                             \
681 video_chroma_down_vi2_cs_##name (GstVideoChromaResample *resample,      \
682     gpointer lines[], gint width)                                       \
683 {                                                                       \
684   /* FIXME */                                                           \
685   if (resample->h_resample) {                                           \
686     resample->h_resample (resample, lines[0], width);                   \
687   }                                                                     \
688 }
689 
690 MAKE_UPSAMPLE_H2_CS (u16, guint16);
691 MAKE_UPSAMPLE_H2_CS (u8, guint8);
692 MAKE_UPSAMPLE_V2_CS (u16, guint16);
693 MAKE_UPSAMPLE_V2_CS (u8, guint8);
694 MAKE_UPSAMPLE_VI2_CS (u16, guint16);
695 MAKE_UPSAMPLE_VI2_CS (u8, guint8);
696 MAKE_DOWNSAMPLE_H2_CS (u16, guint16);
697 MAKE_DOWNSAMPLE_H2_CS (u8, guint8);
698 MAKE_DOWNSAMPLE_V2_CS (u16, guint16);
699 MAKE_DOWNSAMPLE_V2_CS (u8, guint8);
700 MAKE_DOWNSAMPLE_VI2_CS (u16, guint16);
701 MAKE_DOWNSAMPLE_VI2_CS (u8, guint8);
702 
703 /* 4x horizontal upsampling with cositing
704  *
705  *   +---------- (3*a +   b + 2) >> 2
706  * a | +-------- (  a +   b + 1) >> 1
707  * | | | +------ (  a + 3*b + 2) >> 2
708  * v v v v
709  * O-O-O-O-O-O-O-O
710  * x       x
711  * a       b
712  */
713 #define MAKE_UPSAMPLE_H4_CS(name,type)                                       \
714 static void                                                             \
715 video_chroma_up_h4_cs_##name (GstVideoChromaResample *resample,        \
716     gpointer pixels, gint width)                        \
717 {                                                                       \
718   type *p = pixels;                                                        \
719   gint i;                                                               \
720                                                                         \
721   for (i = 0; i < width - 4; i += 4) {                                  \
722     type tr0 = PR(i), tr1 = PR(i+4);                                    \
723     type tb0 = PB(i), tb1 = PB(i+4);                                    \
724                                                                         \
725     PR(i+1) = FILT_3_1 (tr0, tr1);                                      \
726     PB(i+1) = FILT_3_1 (tb0, tb1);                                      \
727     PR(i+2) = FILT_1_1 (tr0, tr1);                                      \
728     PB(i+2) = FILT_1_1 (tb0, tb1);                                      \
729     PR(i+3) = FILT_1_3 (tr0, tr1);                                      \
730     PB(i+3) = FILT_1_3 (tb0, tb1);                                      \
731   }                                                                     \
732 }
733 /* 4x vertical upsampling with cositing
734  *
735  * a x O--O--O-  <---- a
736  *     O--O--O-  <---- (3*a +   b + 2) >> 2
737  *     O--O--O-  <---- (  a +   b + 1) >> 1
738  *     O--O--O-  <---- (  a + 3*b + 2) >> 2
739  * b x O--O--O-
740  *     O--O--O-
741  */
742 #define MAKE_UPSAMPLE_V4_CS(name,type)                                       \
743 static void                                                             \
744 video_chroma_up_v4_cs_##name (GstVideoChromaResample *resample,         \
745     gpointer lines[], gint width)                                       \
746 {                                                                       \
747   /* FIXME */                                                           \
748   if (resample->h_resample) {                                           \
749     resample->h_resample (resample, lines[0], width);                   \
750   }                                                                     \
751 }
752 /* 4x vertical upsampling interlaced with cositing
753  *
754  */
755 #define MAKE_UPSAMPLE_VI4_CS(name,type)                                      \
756 static void                                                             \
757 video_chroma_up_vi4_cs_##name (GstVideoChromaResample *resample,        \
758     gpointer lines[], gint width)                                       \
759 {                                                                       \
760   /* FIXME */                                                           \
761   if (resample->h_resample) {                                           \
762     resample->h_resample (resample, lines[0], width);                   \
763   }                                                                     \
764 }
765 /* 4x horizontal downsampling with cositing
766  *
767  * a
768  * |       +------ (b + 2*c + 3*d + 4*e + 3*f + 2*g + h + 8) >> 16
769  * v       v
770  * O-------O-------
771  * x x x x x x x x
772  * a b c d e f g h
773  */
774 #define MAKE_DOWNSAMPLE_H4_CS(name,type)                                     \
775 static void                                                             \
776 video_chroma_down_h4_cs_##name (GstVideoChromaResample *resample,      \
777     gpointer pixels, gint width)                        \
778 {                                                                       \
779   type *p = pixels;                                                     \
780   gint i;                                                               \
781                                                                         \
782   if (width < 4)                                                        \
783     return;                                                             \
784                                                                         \
785   PR(0) = FILT_10_3_2_1 (PR(0), PR(1), PR(2), PR(3));                   \
786   PB(0) = FILT_10_3_2_1 (PB(0), PB(1), PB(2), PB(3));                   \
787                                                                         \
788   for (i = 4; i < width - 4; i += 4) {                                  \
789     PR(i) = FILT_1_2_3_4_3_2_1 (PR(i-3), PR(i-2), PR(i-1), PR(i), PR(i+1), PR(i+2), PR(i+3));   \
790     PB(i) = FILT_1_2_3_4_3_2_1 (PB(i-3), PB(i-2), PB(i-1), PB(i), PB(i+1), PB(i+2), PB(i+3));   \
791   }                                                                     \
792   if (i < width) {                                                      \
793     PR(i) = FILT_1_2_3_10 (PR(i-3), PR(i-2), PR(i-1), PR(i));           \
794     PB(i) = FILT_1_2_3_10 (PB(i-3), PB(i-2), PB(i-1), PB(i));           \
795   }                                                                     \
796 }
797 /* 4x vertical downsampling with cositing
798  *
799  * a x O--O--O-  <---- a
800  * b x --------
801  * c x --------
802  * d x --------
803  * e x O--O--O-  <---- (b + 2*c + 3*d + 4*e + 3*f + 2*g + h + 8) >> 16
804  * f x --------
805  * g x --------
806  * h x --------
807  * i x O--O--O-
808  * j x --------
809  */
810 #define MAKE_DOWNSAMPLE_V4_CS(name,type)                                     \
811 static void                                                             \
812 video_chroma_down_v4_cs_##name (GstVideoChromaResample *resample,       \
813     gpointer lines[], gint width)                                       \
814 {                                                                       \
815   /* FIXME */                                                           \
816   if (resample->h_resample) {                                           \
817     resample->h_resample (resample, lines[0], width);                   \
818   }                                                                     \
819 }
820 /* 4x vertical downsampling interlaced with cositing
821  *
822  */
823 #define MAKE_DOWNSAMPLE_VI4_CS(name,type)                                    \
824 static void                                                             \
825 video_chroma_down_vi4_cs_##name (GstVideoChromaResample *resample,      \
826     gpointer lines[], gint width)                                       \
827 {                                                                       \
828   /* FIXME */                                                           \
829   if (resample->h_resample) {                                           \
830     resample->h_resample (resample, lines[0], width);                   \
831   }                                                                     \
832 }
833 
834 MAKE_UPSAMPLE_H4_CS (u16, guint16);
835 MAKE_UPSAMPLE_H4_CS (u8, guint8);
836 MAKE_UPSAMPLE_V4_CS (u16, guint16);
837 MAKE_UPSAMPLE_V4_CS (u8, guint8);
838 MAKE_UPSAMPLE_VI4_CS (u16, guint16);
839 MAKE_UPSAMPLE_VI4_CS (u8, guint8);
840 MAKE_DOWNSAMPLE_H4_CS (u16, guint16);
841 MAKE_DOWNSAMPLE_H4_CS (u8, guint8);
842 MAKE_DOWNSAMPLE_V4_CS (u16, guint16);
843 MAKE_DOWNSAMPLE_V4_CS (u8, guint8);
844 MAKE_DOWNSAMPLE_VI4_CS (u16, guint16);
845 MAKE_DOWNSAMPLE_VI4_CS (u8, guint8);
846 
847 typedef struct
848 {
849   void (*resample) (GstVideoChromaResample * resample, gpointer pixels,
850       gint width);
851 } HorizResampler;
852 
853 static const HorizResampler h_resamplers[] = {
854   {NULL},
855   {video_chroma_up_h2_u8},
856   {video_chroma_down_h2_u8},
857   {video_chroma_up_h2_u16},
858   {video_chroma_down_h2_u16},
859   {video_chroma_up_h2_cs_u8},
860   {video_chroma_down_h2_cs_u8},
861   {video_chroma_up_h2_cs_u16},
862   {video_chroma_down_h2_cs_u16},
863   {video_chroma_up_h4_u8},
864   {video_chroma_down_h4_u8},
865   {video_chroma_up_h4_u16},
866   {video_chroma_down_h4_u16},
867   {video_chroma_up_h4_cs_u8},
868   {video_chroma_down_h4_cs_u8},
869   {video_chroma_up_h4_cs_u16},
870   {video_chroma_down_h4_cs_u16}
871 };
872 
873 typedef struct
874 {
875   void (*resample) (GstVideoChromaResample * resample, gpointer lines[],
876       gint width);
877   guint n_lines;
878   gint offset;
879 } VertResampler;
880 
881 static void
video_chroma_none(GstVideoChromaResample * resample,gpointer lines[],gint width)882 video_chroma_none (GstVideoChromaResample * resample,
883     gpointer lines[], gint width)
884 {
885   if (resample->h_resample)
886     resample->h_resample (resample, lines[0], width);
887 }
888 
889 static const VertResampler v_resamplers[] = {
890   {video_chroma_none, 1, 0},
891   {video_chroma_up_v2_u8, 2, -1},
892   {video_chroma_down_v2_u8, 2, 0},
893   /* 16 bits */
894   {video_chroma_up_v2_u16, 2, -1},
895   {video_chroma_down_v2_u16, 2, 0},
896   /* cosited */
897   {video_chroma_up_v2_cs_u8, 1, 0},     /* IMPLEMENT ME */
898   {video_chroma_down_v2_cs_u8, 1, 0},   /* IMPLEMENT ME */
899   {video_chroma_up_v2_cs_u16, 1, 0},    /* IMPLEMENT ME */
900   {video_chroma_down_v2_cs_u16, 1, 0},  /* IMPLEMENT ME */
901   /* 4x */
902   {video_chroma_up_v4_u8, 4, -2},
903   {video_chroma_down_v4_u8, 4, 0},
904   {video_chroma_up_v4_u16, 4, -2},
905   {video_chroma_down_v4_u16, 4, 0},
906   {video_chroma_up_v4_cs_u8, 1, 0},     /* IMPLEMENT ME */
907   {video_chroma_down_v4_cs_u8, 1, 0},   /* IMPLEMENT ME */
908   {video_chroma_up_v4_cs_u16, 1, 0},    /* IMPLEMENT ME */
909   {video_chroma_down_v4_cs_u16, 1, 0},  /* IMPLEMENT ME */
910   /* interlaced */
911   {video_chroma_up_vi2_u8, 4, -2},
912   {video_chroma_down_vi2_u8, 1, 0},     /* IMPLEMENT ME */
913   {video_chroma_up_vi2_u16, 4, -2},
914   {video_chroma_down_vi2_u16, 1, 0},    /* IMPLEMENT ME */
915   {video_chroma_up_vi2_cs_u8, 1, 0},    /* IMPLEMENT ME */
916   {video_chroma_down_vi2_cs_u8, 1, 0},  /* IMPLEMENT ME */
917   {video_chroma_up_vi2_cs_u16, 1, 0},   /* IMPLEMENT ME */
918   {video_chroma_down_vi2_cs_u16, 1, 0}, /* IMPLEMENT ME */
919   {video_chroma_up_vi4_u8, 1, 0},       /* IMPLEMENT ME */
920   {video_chroma_down_vi4_u8, 1, 0},     /* IMPLEMENT ME */
921   {video_chroma_up_vi4_u16, 1, 0},      /* IMPLEMENT ME */
922   {video_chroma_down_vi4_u16, 1, 0},    /* IMPLEMENT ME */
923   {video_chroma_up_vi4_cs_u8, 1, 0},    /* IMPLEMENT ME */
924   {video_chroma_down_vi4_cs_u8, 1, 0},  /* IMPLEMENT ME */
925   {video_chroma_up_vi4_cs_u16, 1, 0},   /* IMPLEMENT ME */
926   {video_chroma_down_vi4_cs_u16, 1, 0}, /* IMPLEMENT ME */
927 };
928 
929 /**
930  * gst_video_chroma_resample_new: (skip)
931  * @method: a #GstVideoChromaMethod
932  * @site: a #GstVideoChromaSite
933  * @flags: #GstVideoChromaFlags
934  * @format: the #GstVideoFormat
935  * @h_factor: horizontal resampling factor
936  * @v_factor: vertical resampling factor
937  *
938  * Create a new resampler object for the given parameters. When @h_factor or
939  * @v_factor is > 0, upsampling will be used, otherwise subsampling is
940  * performed.
941  *
942  * Returns: a new #GstVideoChromaResample that should be freed with
943  *     gst_video_chroma_resample_free() after usage.
944  */
945 GstVideoChromaResample *
gst_video_chroma_resample_new(GstVideoChromaMethod method,GstVideoChromaSite site,GstVideoChromaFlags flags,GstVideoFormat format,gint h_factor,gint v_factor)946 gst_video_chroma_resample_new (GstVideoChromaMethod method,
947     GstVideoChromaSite site, GstVideoChromaFlags flags,
948     GstVideoFormat format, gint h_factor, gint v_factor)
949 {
950   GstVideoChromaResample *result;
951   guint cosite, h_index, v_index, bits;
952 
953   /* no resampling */
954   if (h_factor == 0 && v_factor == 0)
955     return NULL;
956 
957   if (format == GST_VIDEO_FORMAT_AYUV)
958     bits = 8;
959   else if (format == GST_VIDEO_FORMAT_AYUV64)
960     bits = 16;
961   else
962     return NULL;
963 
964   cosite = (site & GST_VIDEO_CHROMA_SITE_H_COSITED ? 1 : 0);
965   if (h_factor == 0)
966     h_index = 0;
967   else
968     h_index =
969         ((ABS (h_factor) - 1) * 8) + (cosite ? 4 : 0) + (bits ==
970         16 ? 2 : 0) + (h_factor < 0 ? 1 : 0) + 1;
971 
972   GST_DEBUG ("h_resample %d, factor %d, cosite %d", h_index, h_factor, cosite);
973 
974   cosite = (site & GST_VIDEO_CHROMA_SITE_V_COSITED ? 1 : 0);
975   if (v_factor == 0)
976     v_index = 0;
977   else
978     v_index =
979         ((ABS (v_factor) - 1) * 8) + (cosite ? 4 : 0) + (bits ==
980         16 ? 2 : 0) + (v_factor < 0 ? 1 : 0) + 1;
981 
982   if (flags & GST_VIDEO_CHROMA_FLAG_INTERLACED)
983     v_index += 16;
984 
985   GST_DEBUG ("v_resample %d, factor %d, cosite %d", v_index, v_factor, cosite);
986 
987   result = g_slice_new (GstVideoChromaResample);
988   result->method = method;
989   result->site = site;
990   result->flags = flags;
991   result->format = format;
992   result->h_factor = h_factor;
993   result->v_factor = v_factor;
994   result->h_resample = h_resamplers[h_index].resample;
995   result->v_resample = v_resamplers[v_index].resample;
996   result->n_lines = v_resamplers[v_index].n_lines;
997   result->offset = v_resamplers[v_index].offset;
998 
999   GST_DEBUG ("resample %p, bits %d, n_lines %u, offset %d", result, bits,
1000       result->n_lines, result->offset);
1001 
1002   return result;
1003 }
1004 
1005 /**
1006  * gst_video_chroma_resample_get_info:
1007  * @resample: a #GstVideoChromaResample
1008  * @n_lines: the number of input lines
1009  * @offset: the first line
1010  *
1011  * The resampler must be fed @n_lines at a time. The first line should be
1012  * at @offset.
1013  */
1014 void
gst_video_chroma_resample_get_info(GstVideoChromaResample * resample,guint * n_lines,gint * offset)1015 gst_video_chroma_resample_get_info (GstVideoChromaResample * resample,
1016     guint * n_lines, gint * offset)
1017 {
1018   g_return_if_fail (resample != NULL);
1019 
1020   if (n_lines)
1021     *n_lines = resample->n_lines;
1022   if (offset)
1023     *offset = resample->offset;
1024 }
1025 
1026 /**
1027  * gst_video_chroma_resample_free:
1028  * @resample: a #GstVideoChromaResample
1029  *
1030  * Free @resample
1031  */
1032 void
gst_video_chroma_resample_free(GstVideoChromaResample * resample)1033 gst_video_chroma_resample_free (GstVideoChromaResample * resample)
1034 {
1035   g_return_if_fail (resample != NULL);
1036 
1037   g_slice_free (GstVideoChromaResample, resample);
1038 }
1039 
1040 /**
1041  * gst_video_chroma_resample:
1042  * @resample: a #GstVideoChromaResample
1043  * @lines: pixel lines
1044  * @width: the number of pixels on one line
1045  *
1046  * Perform resampling of @width chroma pixels in @lines.
1047  */
1048 void
gst_video_chroma_resample(GstVideoChromaResample * resample,gpointer lines[],gint width)1049 gst_video_chroma_resample (GstVideoChromaResample * resample,
1050     gpointer lines[], gint width)
1051 {
1052   g_return_if_fail (resample != NULL);
1053 
1054   resample->v_resample (resample, lines, width);
1055 }
1056