1 /* GStreamer
2 * Copyright (C) 2010 David Schleef <ds@schleef.org>
3 * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #if 0
26 #ifdef HAVE_PTHREAD
27 #define _GNU_SOURCE
28 #include <pthread.h>
29 #endif
30 #endif
31
32 #include "video-converter.h"
33
34 #include <glib.h>
35 #include <string.h>
36 #include <math.h>
37
38 #include "video-orc.h"
39
40 /**
41 * SECTION:videoconverter
42 * @title: GstVideoConverter
43 * @short_description: Generic video conversion
44 *
45 * This object is used to convert video frames from one format to another.
46 * The object can perform conversion of:
47 *
48 * * video format
49 * * video colorspace
50 * * chroma-siting
51 * * video size
52 *
53 */
54
55 /*
56 * (a) unpack
57 * (b) chroma upsample
58 * (c) (convert Y'CbCr to R'G'B')
59 * (d) gamma decode
60 * (e) downscale
61 * (f) colorspace convert through XYZ
62 * (g) upscale
63 * (h) gamma encode
64 * (i) (convert R'G'B' to Y'CbCr)
65 * (j) chroma downsample
66 * (k) pack
67 *
68 * quality options
69 *
70 * (a) range truncate, range expand
71 * (b) full upsample, 1-1 non-cosited upsample, no upsample
72 * (c) 8 bits, 16 bits
73 * (d)
74 * (e) 8 bits, 16 bits
75 * (f) 8 bits, 16 bits
76 * (g) 8 bits, 16 bits
77 * (h)
78 * (i) 8 bits, 16 bits
79 * (j) 1-1 cosited downsample, no downsample
80 * (k)
81 *
82 *
83 * 1 : a -> -> -> -> e -> f -> g -> -> -> -> k
84 * 2 : a -> -> -> -> e -> f* -> g -> -> -> -> k
85 * 3 : a -> -> -> -> e* -> f* -> g* -> -> -> -> k
86 * 4 : a -> b -> -> -> e -> f -> g -> -> -> j -> k
87 * 5 : a -> b -> -> -> e* -> f* -> g* -> -> -> j -> k
88 * 6 : a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k
89 * 7 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
90 *
91 * 8 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
92 * 9 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
93 * 10 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
94 */
95
96 #ifndef GST_DISABLE_GST_DEBUG
97 #define GST_CAT_DEFAULT ensure_debug_category()
98 static GstDebugCategory *
ensure_debug_category(void)99 ensure_debug_category (void)
100 {
101 static gsize cat_gonce = 0;
102
103 if (g_once_init_enter (&cat_gonce)) {
104 gsize cat_done;
105
106 cat_done = (gsize) _gst_debug_category_new ("video-converter", 0,
107 "video-converter object");
108
109 g_once_init_leave (&cat_gonce, cat_done);
110 }
111
112 return (GstDebugCategory *) cat_gonce;
113 }
114 #else
115 #define ensure_debug_category() /* NOOP */
116 #endif /* GST_DISABLE_GST_DEBUG */
117
118 typedef void (*GstParallelizedTaskFunc) (gpointer user_data);
119
120 typedef struct _GstParallelizedTaskRunner GstParallelizedTaskRunner;
121 typedef struct _GstParallelizedTaskThread GstParallelizedTaskThread;
122
123 struct _GstParallelizedTaskThread
124 {
125 GstParallelizedTaskRunner *runner;
126 guint idx;
127 GThread *thread;
128 };
129
130 struct _GstParallelizedTaskRunner
131 {
132 guint n_threads;
133
134 GstParallelizedTaskThread *threads;
135
136 GstParallelizedTaskFunc func;
137 gpointer *task_data;
138
139 GMutex lock;
140 GCond cond_todo, cond_done;
141 gint n_todo, n_done;
142 gboolean quit;
143 };
144
145 static gpointer
gst_parallelized_task_thread_func(gpointer data)146 gst_parallelized_task_thread_func (gpointer data)
147 {
148 GstParallelizedTaskThread *self = data;
149
150 #if 0
151 #ifdef HAVE_PTHREAD
152 {
153 pthread_t thread = pthread_self ();
154 cpu_set_t cpuset;
155 int r;
156
157 CPU_ZERO (&cpuset);
158 CPU_SET (self->idx, &cpuset);
159 if ((r = pthread_setaffinity_np (thread, sizeof (cpuset), &cpuset)) != 0)
160 GST_ERROR ("Failed to set thread affinity for thread %d: %s", self->idx,
161 g_strerror (r));
162 }
163 #endif
164 #endif
165
166 g_mutex_lock (&self->runner->lock);
167 self->runner->n_done++;
168 if (self->runner->n_done == self->runner->n_threads - 1)
169 g_cond_signal (&self->runner->cond_done);
170
171 do {
172 gint idx;
173
174 while (self->runner->n_todo == -1 && !self->runner->quit)
175 g_cond_wait (&self->runner->cond_todo, &self->runner->lock);
176
177 if (self->runner->quit)
178 break;
179
180 idx = self->runner->n_todo--;
181 g_assert (self->runner->n_todo >= -1);
182 g_mutex_unlock (&self->runner->lock);
183
184 g_assert (self->runner->func != NULL);
185
186 self->runner->func (self->runner->task_data[idx]);
187
188 g_mutex_lock (&self->runner->lock);
189 self->runner->n_done++;
190 if (self->runner->n_done == self->runner->n_threads - 1)
191 g_cond_signal (&self->runner->cond_done);
192 } while (TRUE);
193
194 g_mutex_unlock (&self->runner->lock);
195
196 return NULL;
197 }
198
199 static void
gst_parallelized_task_runner_free(GstParallelizedTaskRunner * self)200 gst_parallelized_task_runner_free (GstParallelizedTaskRunner * self)
201 {
202 guint i;
203
204 g_mutex_lock (&self->lock);
205 self->quit = TRUE;
206 g_cond_broadcast (&self->cond_todo);
207 g_mutex_unlock (&self->lock);
208
209 for (i = 1; i < self->n_threads; i++) {
210 if (!self->threads[i].thread)
211 continue;
212
213 g_thread_join (self->threads[i].thread);
214 }
215
216 g_mutex_clear (&self->lock);
217 g_cond_clear (&self->cond_todo);
218 g_cond_clear (&self->cond_done);
219 g_free (self->threads);
220 g_free (self);
221 }
222
223 static GstParallelizedTaskRunner *
gst_parallelized_task_runner_new(guint n_threads)224 gst_parallelized_task_runner_new (guint n_threads)
225 {
226 GstParallelizedTaskRunner *self;
227 guint i;
228 GError *err = NULL;
229
230 if (n_threads == 0)
231 n_threads = g_get_num_processors ();
232
233 self = g_new0 (GstParallelizedTaskRunner, 1);
234 self->n_threads = n_threads;
235 self->threads = g_new0 (GstParallelizedTaskThread, n_threads);
236
237 self->quit = FALSE;
238 self->n_todo = -1;
239 self->n_done = 0;
240 g_mutex_init (&self->lock);
241 g_cond_init (&self->cond_todo);
242 g_cond_init (&self->cond_done);
243
244 /* Set when scheduling a job */
245 self->func = NULL;
246 self->task_data = NULL;
247
248 for (i = 0; i < n_threads; i++) {
249 self->threads[i].runner = self;
250 self->threads[i].idx = i;
251
252 /* First thread is the one calling run() */
253 if (i > 0) {
254 self->threads[i].thread =
255 g_thread_try_new ("videoconvert", gst_parallelized_task_thread_func,
256 &self->threads[i], &err);
257 if (!self->threads[i].thread)
258 goto error;
259 }
260 }
261
262 g_mutex_lock (&self->lock);
263 while (self->n_done < self->n_threads - 1)
264 g_cond_wait (&self->cond_done, &self->lock);
265 self->n_done = 0;
266 g_mutex_unlock (&self->lock);
267
268 return self;
269
270 error:
271 {
272 GST_ERROR ("Failed to start thread %u: %s", i, err->message);
273 g_clear_error (&err);
274
275 gst_parallelized_task_runner_free (self);
276 return NULL;
277 }
278 }
279
280 static void
gst_parallelized_task_runner_run(GstParallelizedTaskRunner * self,GstParallelizedTaskFunc func,gpointer * task_data)281 gst_parallelized_task_runner_run (GstParallelizedTaskRunner * self,
282 GstParallelizedTaskFunc func, gpointer * task_data)
283 {
284 guint n_threads = self->n_threads;
285
286 self->func = func;
287 self->task_data = task_data;
288
289 if (n_threads > 1) {
290 g_mutex_lock (&self->lock);
291 self->n_todo = self->n_threads - 2;
292 self->n_done = 0;
293 g_cond_broadcast (&self->cond_todo);
294 g_mutex_unlock (&self->lock);
295 }
296
297 self->func (self->task_data[self->n_threads - 1]);
298
299 if (n_threads > 1) {
300 g_mutex_lock (&self->lock);
301 while (self->n_done < self->n_threads - 1)
302 g_cond_wait (&self->cond_done, &self->lock);
303 self->n_done = 0;
304 g_mutex_unlock (&self->lock);
305 }
306
307 self->func = NULL;
308 self->task_data = NULL;
309 }
310
311 typedef struct _GstLineCache GstLineCache;
312
313 #define SCALE (8)
314 #define SCALE_F ((float) (1 << SCALE))
315
316 typedef struct _MatrixData MatrixData;
317
318 struct _MatrixData
319 {
320 gdouble dm[4][4];
321 gint im[4][4];
322 gint width;
323 guint64 orc_p1;
324 guint64 orc_p2;
325 guint64 orc_p3;
326 guint64 orc_p4;
327 gint64 *t_r;
328 gint64 *t_g;
329 gint64 *t_b;
330 gint64 t_c;
331 void (*matrix_func) (MatrixData * data, gpointer pixels);
332 };
333
334 typedef struct _GammaData GammaData;
335
336 struct _GammaData
337 {
338 gpointer gamma_table;
339 gint width;
340 void (*gamma_func) (GammaData * data, gpointer dest, gpointer src);
341 };
342
343 typedef enum
344 {
345 ALPHA_MODE_NONE = 0,
346 ALPHA_MODE_COPY = (1 << 0),
347 ALPHA_MODE_SET = (1 << 1),
348 ALPHA_MODE_MULT = (1 << 2)
349 } AlphaMode;
350
351 typedef struct
352 {
353 guint8 *data;
354 guint stride;
355 guint n_lines;
356 guint idx;
357 gpointer user_data;
358 GDestroyNotify notify;
359 } ConverterAlloc;
360
361 typedef void (*FastConvertFunc) (GstVideoConverter * convert,
362 const GstVideoFrame * src, GstVideoFrame * dest, gint plane);
363
364 struct _GstVideoConverter
365 {
366 gint flags;
367
368 GstVideoInfo in_info;
369 GstVideoInfo out_info;
370
371 gint in_x;
372 gint in_y;
373 gint in_width;
374 gint in_height;
375 gint in_maxwidth;
376 gint in_maxheight;
377 gint out_x;
378 gint out_y;
379 gint out_width;
380 gint out_height;
381 gint out_maxwidth;
382 gint out_maxheight;
383
384 gint current_pstride;
385 gint current_width;
386 gint current_height;
387 GstVideoFormat current_format;
388 gint current_bits;
389
390 GstStructure *config;
391
392 GstParallelizedTaskRunner *conversion_runner;
393
394 guint16 **tmpline;
395
396 gboolean fill_border;
397 gpointer borderline;
398 guint64 borders[4];
399 guint32 border_argb;
400 guint32 alpha_value;
401 AlphaMode alpha_mode;
402
403 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
404 GstVideoFrame * dest);
405
406 /* data for unpack */
407 GstLineCache **unpack_lines;
408 GstVideoFormat unpack_format;
409 guint unpack_bits;
410 gboolean unpack_rgb;
411 gboolean identity_unpack;
412 gint unpack_pstride;
413
414 /* chroma upsample */
415 GstLineCache **upsample_lines;
416 GstVideoChromaResample **upsample;
417 GstVideoChromaResample **upsample_p;
418 GstVideoChromaResample **upsample_i;
419 guint up_n_lines;
420 gint up_offset;
421
422 /* to R'G'B */
423 GstLineCache **to_RGB_lines;
424 MatrixData to_RGB_matrix;
425 /* gamma decode */
426 GammaData gamma_dec;
427
428 /* scaling */
429 GstLineCache **hscale_lines;
430 GstVideoScaler **h_scaler;
431 gint h_scale_format;
432 GstLineCache **vscale_lines;
433 GstVideoScaler **v_scaler;
434 GstVideoScaler **v_scaler_p;
435 GstVideoScaler **v_scaler_i;
436 gint v_scale_width;
437 gint v_scale_format;
438
439 /* color space conversion */
440 GstLineCache **convert_lines;
441 MatrixData convert_matrix;
442 gint in_bits;
443 gint out_bits;
444
445 /* alpha correction */
446 GstLineCache **alpha_lines;
447 void (*alpha_func) (GstVideoConverter * convert, gpointer pixels, gint width);
448
449 /* gamma encode */
450 GammaData gamma_enc;
451 /* to Y'CbCr */
452 GstLineCache **to_YUV_lines;
453 MatrixData to_YUV_matrix;
454
455 /* chroma downsample */
456 GstLineCache **downsample_lines;
457 GstVideoChromaResample **downsample;
458 GstVideoChromaResample **downsample_p;
459 GstVideoChromaResample **downsample_i;
460 guint down_n_lines;
461 gint down_offset;
462
463 /* dither */
464 GstLineCache **dither_lines;
465 GstVideoDither **dither;
466
467 /* pack */
468 GstLineCache **pack_lines;
469 guint pack_nlines;
470 GstVideoFormat pack_format;
471 guint pack_bits;
472 gboolean pack_rgb;
473 gboolean identity_pack;
474 gint pack_pstride;
475 gconstpointer pack_pal;
476 gsize pack_palsize;
477
478 const GstVideoFrame *src;
479 GstVideoFrame *dest;
480
481 /* fastpath */
482 GstVideoFormat fformat[4];
483 gint fin_x[4];
484 gint fin_y[4];
485 gint fout_x[4];
486 gint fout_y[4];
487 gint fout_width[4];
488 gint fout_height[4];
489 gint fsplane[4];
490 gint ffill[4];
491
492 struct
493 {
494 GstVideoScaler **scaler;
495 } fh_scaler[4];
496 struct
497 {
498 GstVideoScaler **scaler;
499 } fv_scaler[4];
500 FastConvertFunc fconvert[4];
501 };
502
503 typedef gpointer (*GstLineCacheAllocLineFunc) (GstLineCache * cache, gint idx,
504 gpointer user_data);
505 typedef gboolean (*GstLineCacheNeedLineFunc) (GstLineCache * cache, gint idx,
506 gint out_line, gint in_line, gpointer user_data);
507
508 struct _GstLineCache
509 {
510 gint first;
511 gint backlog;
512 GPtrArray *lines;
513
514 GstLineCache *prev;
515 gboolean write_input;
516 gboolean pass_alloc;
517 gboolean alloc_writable;
518
519 GstLineCacheNeedLineFunc need_line;
520 gint need_line_idx;
521 gpointer need_line_data;
522 GDestroyNotify need_line_notify;
523
524 guint n_lines;
525 guint stride;
526 GstLineCacheAllocLineFunc alloc_line;
527 gpointer alloc_line_data;
528 GDestroyNotify alloc_line_notify;
529 };
530
531 static GstLineCache *
gst_line_cache_new(GstLineCache * prev)532 gst_line_cache_new (GstLineCache * prev)
533 {
534 GstLineCache *result;
535
536 result = g_slice_new0 (GstLineCache);
537 result->lines = g_ptr_array_new ();
538 result->prev = prev;
539
540 return result;
541 }
542
543 static void
gst_line_cache_clear(GstLineCache * cache)544 gst_line_cache_clear (GstLineCache * cache)
545 {
546 g_return_if_fail (cache != NULL);
547
548 g_ptr_array_set_size (cache->lines, 0);
549 cache->first = 0;
550 }
551
552 static void
gst_line_cache_free(GstLineCache * cache)553 gst_line_cache_free (GstLineCache * cache)
554 {
555 if (cache->need_line_notify)
556 cache->need_line_notify (cache->need_line_data);
557 if (cache->alloc_line_notify)
558 cache->alloc_line_notify (cache->alloc_line_data);
559 gst_line_cache_clear (cache);
560 g_ptr_array_unref (cache->lines);
561 g_slice_free (GstLineCache, cache);
562 }
563
564 static void
gst_line_cache_set_need_line_func(GstLineCache * cache,GstLineCacheNeedLineFunc need_line,gint idx,gpointer user_data,GDestroyNotify notify)565 gst_line_cache_set_need_line_func (GstLineCache * cache,
566 GstLineCacheNeedLineFunc need_line, gint idx, gpointer user_data,
567 GDestroyNotify notify)
568 {
569 cache->need_line = need_line;
570 cache->need_line_idx = idx;
571 cache->need_line_data = user_data;
572 cache->need_line_notify = notify;
573 }
574
575 static void
gst_line_cache_set_alloc_line_func(GstLineCache * cache,GstLineCacheAllocLineFunc alloc_line,gpointer user_data,GDestroyNotify notify)576 gst_line_cache_set_alloc_line_func (GstLineCache * cache,
577 GstLineCacheAllocLineFunc alloc_line, gpointer user_data,
578 GDestroyNotify notify)
579 {
580 cache->alloc_line = alloc_line;
581 cache->alloc_line_data = user_data;
582 cache->alloc_line_notify = notify;
583 }
584
585 /* keep this much backlog for interlaced video */
586 #define BACKLOG 2
587
588 static gpointer *
gst_line_cache_get_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gint n_lines)589 gst_line_cache_get_lines (GstLineCache * cache, gint idx, gint out_line,
590 gint in_line, gint n_lines)
591 {
592 if (cache->first + cache->backlog < in_line) {
593 gint to_remove =
594 MIN (in_line - (cache->first + cache->backlog), cache->lines->len);
595 if (to_remove > 0) {
596 g_ptr_array_remove_range (cache->lines, 0, to_remove);
597 }
598 cache->first += to_remove;
599 } else if (in_line < cache->first) {
600 gst_line_cache_clear (cache);
601 cache->first = in_line;
602 }
603
604 while (TRUE) {
605 gint oline;
606
607 if (cache->first <= in_line
608 && in_line + n_lines <= cache->first + (gint) cache->lines->len) {
609 return cache->lines->pdata + (in_line - cache->first);
610 }
611
612 if (cache->need_line == NULL)
613 break;
614
615 oline = out_line + cache->first + cache->lines->len - in_line;
616
617 if (!cache->need_line (cache, idx, oline, cache->first + cache->lines->len,
618 cache->need_line_data))
619 break;
620 }
621 GST_DEBUG ("no lines");
622 return NULL;
623 }
624
625 static void
gst_line_cache_add_line(GstLineCache * cache,gint idx,gpointer line)626 gst_line_cache_add_line (GstLineCache * cache, gint idx, gpointer line)
627 {
628 if (cache->first + cache->lines->len != idx) {
629 gst_line_cache_clear (cache);
630 cache->first = idx;
631 }
632 g_ptr_array_add (cache->lines, line);
633 }
634
635 static gpointer
gst_line_cache_alloc_line(GstLineCache * cache,gint idx)636 gst_line_cache_alloc_line (GstLineCache * cache, gint idx)
637 {
638 gpointer res;
639
640 if (cache->alloc_line)
641 res = cache->alloc_line (cache, idx, cache->alloc_line_data);
642 else
643 res = NULL;
644
645 return res;
646 }
647
648 static void video_converter_generic (GstVideoConverter * convert,
649 const GstVideoFrame * src, GstVideoFrame * dest);
650 static gboolean video_converter_lookup_fastpath (GstVideoConverter * convert);
651 static void video_converter_compute_matrix (GstVideoConverter * convert);
652 static void video_converter_compute_resample (GstVideoConverter * convert,
653 gint idx);
654
655 static gpointer get_dest_line (GstLineCache * cache, gint idx,
656 gpointer user_data);
657
658 static gboolean do_unpack_lines (GstLineCache * cache, gint idx, gint out_line,
659 gint in_line, gpointer user_data);
660 static gboolean do_downsample_lines (GstLineCache * cache, gint idx,
661 gint out_line, gint in_line, gpointer user_data);
662 static gboolean do_convert_to_RGB_lines (GstLineCache * cache, gint idx,
663 gint out_line, gint in_line, gpointer user_data);
664 static gboolean do_convert_lines (GstLineCache * cache, gint idx, gint out_line,
665 gint in_line, gpointer user_data);
666 static gboolean do_alpha_lines (GstLineCache * cache, gint idx, gint out_line,
667 gint in_line, gpointer user_data);
668 static gboolean do_convert_to_YUV_lines (GstLineCache * cache, gint idx,
669 gint out_line, gint in_line, gpointer user_data);
670 static gboolean do_upsample_lines (GstLineCache * cache, gint idx,
671 gint out_line, gint in_line, gpointer user_data);
672 static gboolean do_vscale_lines (GstLineCache * cache, gint idx, gint out_line,
673 gint in_line, gpointer user_data);
674 static gboolean do_hscale_lines (GstLineCache * cache, gint idx, gint out_line,
675 gint in_line, gpointer user_data);
676 static gboolean do_dither_lines (GstLineCache * cache, gint idx, gint out_line,
677 gint in_line, gpointer user_data);
678
679 static ConverterAlloc *
converter_alloc_new(guint stride,guint n_lines,gpointer user_data,GDestroyNotify notify)680 converter_alloc_new (guint stride, guint n_lines, gpointer user_data,
681 GDestroyNotify notify)
682 {
683 ConverterAlloc *alloc;
684
685 GST_DEBUG ("stride %d, n_lines %d", stride, n_lines);
686 alloc = g_slice_new0 (ConverterAlloc);
687 alloc->data = g_malloc (stride * n_lines);
688 alloc->stride = stride;
689 alloc->n_lines = n_lines;
690 alloc->idx = 0;
691 alloc->user_data = user_data;
692 alloc->notify = notify;
693
694 return alloc;
695 }
696
697 static void
converter_alloc_free(ConverterAlloc * alloc)698 converter_alloc_free (ConverterAlloc * alloc)
699 {
700 if (alloc->notify)
701 alloc->notify (alloc->user_data);
702 g_free (alloc->data);
703 g_slice_free (ConverterAlloc, alloc);
704 }
705
706 static void
setup_border_alloc(GstVideoConverter * convert,ConverterAlloc * alloc)707 setup_border_alloc (GstVideoConverter * convert, ConverterAlloc * alloc)
708 {
709 gint i;
710
711 if (convert->borderline) {
712 for (i = 0; i < alloc->n_lines; i++)
713 memcpy (&alloc->data[i * alloc->stride], convert->borderline,
714 alloc->stride);
715 }
716 }
717
718 static gpointer
get_temp_line(GstLineCache * cache,gint idx,gpointer user_data)719 get_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
720 {
721 ConverterAlloc *alloc = user_data;
722 gpointer tmpline;
723
724 GST_DEBUG ("get temp line %d (%p %d)", idx, alloc, alloc->idx);
725 tmpline = &alloc->data[alloc->stride * alloc->idx];
726 alloc->idx = (alloc->idx + 1) % alloc->n_lines;
727
728 return tmpline;
729 }
730
731 static gpointer
get_border_temp_line(GstLineCache * cache,gint idx,gpointer user_data)732 get_border_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
733 {
734 ConverterAlloc *alloc = user_data;
735 GstVideoConverter *convert = alloc->user_data;
736 gpointer tmpline;
737
738 GST_DEBUG ("get temp line %d (%p %d)", idx, alloc, alloc->idx);
739 tmpline = &alloc->data[alloc->stride * alloc->idx] +
740 (convert->out_x * convert->pack_pstride);
741 alloc->idx = (alloc->idx + 1) % alloc->n_lines;
742
743 return tmpline;
744 }
745
746 static gint
get_opt_int(GstVideoConverter * convert,const gchar * opt,gint def)747 get_opt_int (GstVideoConverter * convert, const gchar * opt, gint def)
748 {
749 gint res;
750 if (!gst_structure_get_int (convert->config, opt, &res))
751 res = def;
752 return res;
753 }
754
755 static guint
get_opt_uint(GstVideoConverter * convert,const gchar * opt,guint def)756 get_opt_uint (GstVideoConverter * convert, const gchar * opt, guint def)
757 {
758 guint res;
759 if (!gst_structure_get_uint (convert->config, opt, &res))
760 res = def;
761 return res;
762 }
763
764 static gdouble
get_opt_double(GstVideoConverter * convert,const gchar * opt,gdouble def)765 get_opt_double (GstVideoConverter * convert, const gchar * opt, gdouble def)
766 {
767 gdouble res;
768 if (!gst_structure_get_double (convert->config, opt, &res))
769 res = def;
770 return res;
771 }
772
773 static gboolean
get_opt_bool(GstVideoConverter * convert,const gchar * opt,gboolean def)774 get_opt_bool (GstVideoConverter * convert, const gchar * opt, gboolean def)
775 {
776 gboolean res;
777 if (!gst_structure_get_boolean (convert->config, opt, &res))
778 res = def;
779 return res;
780 }
781
782 static gint
get_opt_enum(GstVideoConverter * convert,const gchar * opt,GType type,gint def)783 get_opt_enum (GstVideoConverter * convert, const gchar * opt, GType type,
784 gint def)
785 {
786 gint res;
787 if (!gst_structure_get_enum (convert->config, opt, type, &res))
788 res = def;
789 return res;
790 }
791
792 #define DEFAULT_OPT_FILL_BORDER TRUE
793 #define DEFAULT_OPT_ALPHA_VALUE 1.0
794 /* options copy, set, mult */
795 #define DEFAULT_OPT_ALPHA_MODE GST_VIDEO_ALPHA_MODE_COPY
796 #define DEFAULT_OPT_BORDER_ARGB 0xff000000
797 /* options full, input-only, output-only, none */
798 #define DEFAULT_OPT_MATRIX_MODE GST_VIDEO_MATRIX_MODE_FULL
799 /* none, remap */
800 #define DEFAULT_OPT_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
801 /* none, merge-only, fast */
802 #define DEFAULT_OPT_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
803 /* options full, upsample-only, downsample-only, none */
804 #define DEFAULT_OPT_CHROMA_MODE GST_VIDEO_CHROMA_MODE_FULL
805 #define DEFAULT_OPT_RESAMPLER_METHOD GST_VIDEO_RESAMPLER_METHOD_CUBIC
806 #define DEFAULT_OPT_CHROMA_RESAMPLER_METHOD GST_VIDEO_RESAMPLER_METHOD_LINEAR
807 #define DEFAULT_OPT_RESAMPLER_TAPS 0
808 #define DEFAULT_OPT_DITHER_METHOD GST_VIDEO_DITHER_BAYER
809 #define DEFAULT_OPT_DITHER_QUANTIZATION 1
810
811 #define GET_OPT_FILL_BORDER(c) get_opt_bool(c, \
812 GST_VIDEO_CONVERTER_OPT_FILL_BORDER, DEFAULT_OPT_FILL_BORDER)
813 #define GET_OPT_ALPHA_VALUE(c) get_opt_double(c, \
814 GST_VIDEO_CONVERTER_OPT_ALPHA_VALUE, DEFAULT_OPT_ALPHA_VALUE)
815 #define GET_OPT_ALPHA_MODE(c) get_opt_enum(c, \
816 GST_VIDEO_CONVERTER_OPT_ALPHA_MODE, GST_TYPE_VIDEO_ALPHA_MODE, DEFAULT_OPT_ALPHA_MODE)
817 #define GET_OPT_BORDER_ARGB(c) get_opt_uint(c, \
818 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB)
819 #define GET_OPT_MATRIX_MODE(c) get_opt_enum(c, \
820 GST_VIDEO_CONVERTER_OPT_MATRIX_MODE, GST_TYPE_VIDEO_MATRIX_MODE, DEFAULT_OPT_MATRIX_MODE)
821 #define GET_OPT_GAMMA_MODE(c) get_opt_enum(c, \
822 GST_VIDEO_CONVERTER_OPT_GAMMA_MODE, GST_TYPE_VIDEO_GAMMA_MODE, DEFAULT_OPT_GAMMA_MODE)
823 #define GET_OPT_PRIMARIES_MODE(c) get_opt_enum(c, \
824 GST_VIDEO_CONVERTER_OPT_PRIMARIES_MODE, GST_TYPE_VIDEO_PRIMARIES_MODE, DEFAULT_OPT_PRIMARIES_MODE)
825 #define GET_OPT_CHROMA_MODE(c) get_opt_enum(c, \
826 GST_VIDEO_CONVERTER_OPT_CHROMA_MODE, GST_TYPE_VIDEO_CHROMA_MODE, DEFAULT_OPT_CHROMA_MODE)
827 #define GET_OPT_RESAMPLER_METHOD(c) get_opt_enum(c, \
828 GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD, GST_TYPE_VIDEO_RESAMPLER_METHOD, \
829 DEFAULT_OPT_RESAMPLER_METHOD)
830 #define GET_OPT_CHROMA_RESAMPLER_METHOD(c) get_opt_enum(c, \
831 GST_VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD, GST_TYPE_VIDEO_RESAMPLER_METHOD, \
832 DEFAULT_OPT_CHROMA_RESAMPLER_METHOD)
833 #define GET_OPT_RESAMPLER_TAPS(c) get_opt_uint(c, \
834 GST_VIDEO_CONVERTER_OPT_RESAMPLER_TAPS, DEFAULT_OPT_RESAMPLER_TAPS)
835 #define GET_OPT_DITHER_METHOD(c) get_opt_enum(c, \
836 GST_VIDEO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_VIDEO_DITHER_METHOD, \
837 DEFAULT_OPT_DITHER_METHOD)
838 #define GET_OPT_DITHER_QUANTIZATION(c) get_opt_uint(c, \
839 GST_VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, DEFAULT_OPT_DITHER_QUANTIZATION)
840
841 #define CHECK_ALPHA_COPY(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_COPY)
842 #define CHECK_ALPHA_SET(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_SET)
843 #define CHECK_ALPHA_MULT(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_MULT)
844
845 #define CHECK_MATRIX_FULL(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_FULL)
846 #define CHECK_MATRIX_INPUT(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_INPUT_ONLY)
847 #define CHECK_MATRIX_OUTPUT(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_OUTPUT_ONLY)
848 #define CHECK_MATRIX_NONE(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_NONE)
849
850 #define CHECK_GAMMA_NONE(c) (GET_OPT_GAMMA_MODE(c) == GST_VIDEO_GAMMA_MODE_NONE)
851 #define CHECK_GAMMA_REMAP(c) (GET_OPT_GAMMA_MODE(c) == GST_VIDEO_GAMMA_MODE_REMAP)
852
853 #define CHECK_PRIMARIES_NONE(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_NONE)
854 #define CHECK_PRIMARIES_MERGE(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_MERGE_ONLY)
855 #define CHECK_PRIMARIES_FAST(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_FAST)
856
857 #define CHECK_CHROMA_FULL(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_FULL)
858 #define CHECK_CHROMA_UPSAMPLE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_UPSAMPLE_ONLY)
859 #define CHECK_CHROMA_DOWNSAMPLE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_DOWNSAMPLE_ONLY)
860 #define CHECK_CHROMA_NONE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_NONE)
861
862 static GstLineCache *
chain_unpack_line(GstVideoConverter * convert,gint idx)863 chain_unpack_line (GstVideoConverter * convert, gint idx)
864 {
865 GstLineCache *prev;
866 GstVideoInfo *info;
867
868 info = &convert->in_info;
869
870 convert->current_format = convert->unpack_format;
871 convert->current_bits = convert->unpack_bits;
872 convert->current_pstride = convert->current_bits >> 1;
873
874 convert->unpack_pstride = convert->current_pstride;
875 convert->identity_unpack = (convert->current_format == info->finfo->format);
876
877 GST_DEBUG ("chain unpack line format %s, pstride %d, identity_unpack %d",
878 gst_video_format_to_string (convert->current_format),
879 convert->current_pstride, convert->identity_unpack);
880
881 prev = convert->unpack_lines[idx] = gst_line_cache_new (NULL);
882 prev->write_input = FALSE;
883 prev->pass_alloc = FALSE;
884 prev->n_lines = 1;
885 prev->stride = convert->current_pstride * convert->current_width;
886 gst_line_cache_set_need_line_func (prev, do_unpack_lines, idx, convert, NULL);
887
888 return prev;
889 }
890
891 static GstLineCache *
chain_upsample(GstVideoConverter * convert,GstLineCache * prev,gint idx)892 chain_upsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
893 {
894 video_converter_compute_resample (convert, idx);
895
896 if (convert->upsample_p[idx] || convert->upsample_i[idx]) {
897 GST_DEBUG ("chain upsample");
898 prev = convert->upsample_lines[idx] = gst_line_cache_new (prev);
899 prev->write_input = TRUE;
900 prev->pass_alloc = TRUE;
901 prev->n_lines = 4;
902 prev->stride = convert->current_pstride * convert->current_width;
903 gst_line_cache_set_need_line_func (prev,
904 do_upsample_lines, idx, convert, NULL);
905 }
906 return prev;
907 }
908
909 static void
color_matrix_set_identity(MatrixData * m)910 color_matrix_set_identity (MatrixData * m)
911 {
912 int i, j;
913
914 for (i = 0; i < 4; i++) {
915 for (j = 0; j < 4; j++) {
916 m->dm[i][j] = (i == j);
917 }
918 }
919 }
920
921 static void
color_matrix_copy(MatrixData * d,const MatrixData * s)922 color_matrix_copy (MatrixData * d, const MatrixData * s)
923 {
924 gint i, j;
925
926 for (i = 0; i < 4; i++)
927 for (j = 0; j < 4; j++)
928 d->dm[i][j] = s->dm[i][j];
929 }
930
931 /* Perform 4x4 matrix multiplication:
932 * - @dst@ = @a@ * @b@
933 * - @dst@ may be a pointer to @a@ andor @b@
934 */
935 static void
color_matrix_multiply(MatrixData * dst,MatrixData * a,MatrixData * b)936 color_matrix_multiply (MatrixData * dst, MatrixData * a, MatrixData * b)
937 {
938 MatrixData tmp;
939 int i, j, k;
940
941 for (i = 0; i < 4; i++) {
942 for (j = 0; j < 4; j++) {
943 double x = 0;
944 for (k = 0; k < 4; k++) {
945 x += a->dm[i][k] * b->dm[k][j];
946 }
947 tmp.dm[i][j] = x;
948 }
949 }
950 color_matrix_copy (dst, &tmp);
951 }
952
953 static void
color_matrix_invert(MatrixData * d,MatrixData * s)954 color_matrix_invert (MatrixData * d, MatrixData * s)
955 {
956 MatrixData tmp;
957 int i, j;
958 double det;
959
960 color_matrix_set_identity (&tmp);
961 for (j = 0; j < 3; j++) {
962 for (i = 0; i < 3; i++) {
963 tmp.dm[j][i] =
964 s->dm[(i + 1) % 3][(j + 1) % 3] * s->dm[(i + 2) % 3][(j + 2) % 3] -
965 s->dm[(i + 1) % 3][(j + 2) % 3] * s->dm[(i + 2) % 3][(j + 1) % 3];
966 }
967 }
968 det =
969 tmp.dm[0][0] * s->dm[0][0] + tmp.dm[0][1] * s->dm[1][0] +
970 tmp.dm[0][2] * s->dm[2][0];
971 for (j = 0; j < 3; j++) {
972 for (i = 0; i < 3; i++) {
973 tmp.dm[i][j] /= det;
974 }
975 }
976 color_matrix_copy (d, &tmp);
977 }
978
979 static void
color_matrix_offset_components(MatrixData * m,double a1,double a2,double a3)980 color_matrix_offset_components (MatrixData * m, double a1, double a2, double a3)
981 {
982 MatrixData a;
983
984 color_matrix_set_identity (&a);
985 a.dm[0][3] = a1;
986 a.dm[1][3] = a2;
987 a.dm[2][3] = a3;
988 color_matrix_multiply (m, &a, m);
989 }
990
991 static void
color_matrix_scale_components(MatrixData * m,double a1,double a2,double a3)992 color_matrix_scale_components (MatrixData * m, double a1, double a2, double a3)
993 {
994 MatrixData a;
995
996 color_matrix_set_identity (&a);
997 a.dm[0][0] = a1;
998 a.dm[1][1] = a2;
999 a.dm[2][2] = a3;
1000 color_matrix_multiply (m, &a, m);
1001 }
1002
1003 static void
color_matrix_debug(const MatrixData * s)1004 color_matrix_debug (const MatrixData * s)
1005 {
1006 GST_DEBUG ("[%f %f %f %f]", s->dm[0][0], s->dm[0][1], s->dm[0][2],
1007 s->dm[0][3]);
1008 GST_DEBUG ("[%f %f %f %f]", s->dm[1][0], s->dm[1][1], s->dm[1][2],
1009 s->dm[1][3]);
1010 GST_DEBUG ("[%f %f %f %f]", s->dm[2][0], s->dm[2][1], s->dm[2][2],
1011 s->dm[2][3]);
1012 GST_DEBUG ("[%f %f %f %f]", s->dm[3][0], s->dm[3][1], s->dm[3][2],
1013 s->dm[3][3]);
1014 }
1015
1016 static void
color_matrix_convert(MatrixData * s)1017 color_matrix_convert (MatrixData * s)
1018 {
1019 gint i, j;
1020
1021 for (i = 0; i < 4; i++)
1022 for (j = 0; j < 4; j++)
1023 s->im[i][j] = rint (s->dm[i][j]);
1024
1025 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[0][0], s->im[0][1], s->im[0][2],
1026 s->im[0][3]);
1027 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[1][0], s->im[1][1], s->im[1][2],
1028 s->im[1][3]);
1029 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[2][0], s->im[2][1], s->im[2][2],
1030 s->im[2][3]);
1031 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[3][0], s->im[3][1], s->im[3][2],
1032 s->im[3][3]);
1033 }
1034
1035 static void
color_matrix_YCbCr_to_RGB(MatrixData * m,double Kr,double Kb)1036 color_matrix_YCbCr_to_RGB (MatrixData * m, double Kr, double Kb)
1037 {
1038 double Kg = 1.0 - Kr - Kb;
1039 MatrixData k = {
1040 {
1041 {1., 0., 2 * (1 - Kr), 0.},
1042 {1., -2 * Kb * (1 - Kb) / Kg, -2 * Kr * (1 - Kr) / Kg, 0.},
1043 {1., 2 * (1 - Kb), 0., 0.},
1044 {0., 0., 0., 1.},
1045 }
1046 };
1047
1048 color_matrix_multiply (m, &k, m);
1049 }
1050
1051 static void
color_matrix_RGB_to_YCbCr(MatrixData * m,double Kr,double Kb)1052 color_matrix_RGB_to_YCbCr (MatrixData * m, double Kr, double Kb)
1053 {
1054 double Kg = 1.0 - Kr - Kb;
1055 MatrixData k;
1056 double x;
1057
1058 k.dm[0][0] = Kr;
1059 k.dm[0][1] = Kg;
1060 k.dm[0][2] = Kb;
1061 k.dm[0][3] = 0;
1062
1063 x = 1 / (2 * (1 - Kb));
1064 k.dm[1][0] = -x * Kr;
1065 k.dm[1][1] = -x * Kg;
1066 k.dm[1][2] = x * (1 - Kb);
1067 k.dm[1][3] = 0;
1068
1069 x = 1 / (2 * (1 - Kr));
1070 k.dm[2][0] = x * (1 - Kr);
1071 k.dm[2][1] = -x * Kg;
1072 k.dm[2][2] = -x * Kb;
1073 k.dm[2][3] = 0;
1074
1075 k.dm[3][0] = 0;
1076 k.dm[3][1] = 0;
1077 k.dm[3][2] = 0;
1078 k.dm[3][3] = 1;
1079
1080 color_matrix_multiply (m, &k, m);
1081 }
1082
1083 static void
color_matrix_RGB_to_XYZ(MatrixData * dst,double Rx,double Ry,double Gx,double Gy,double Bx,double By,double Wx,double Wy)1084 color_matrix_RGB_to_XYZ (MatrixData * dst, double Rx, double Ry, double Gx,
1085 double Gy, double Bx, double By, double Wx, double Wy)
1086 {
1087 MatrixData m, im;
1088 double sx, sy, sz;
1089 double wx, wy, wz;
1090
1091 color_matrix_set_identity (&m);
1092
1093 m.dm[0][0] = Rx;
1094 m.dm[1][0] = Ry;
1095 m.dm[2][0] = (1.0 - Rx - Ry);
1096 m.dm[0][1] = Gx;
1097 m.dm[1][1] = Gy;
1098 m.dm[2][1] = (1.0 - Gx - Gy);
1099 m.dm[0][2] = Bx;
1100 m.dm[1][2] = By;
1101 m.dm[2][2] = (1.0 - Bx - By);
1102
1103 color_matrix_invert (&im, &m);
1104
1105 wx = Wx / Wy;
1106 wy = 1.0;
1107 wz = (1.0 - Wx - Wy) / Wy;
1108
1109 sx = im.dm[0][0] * wx + im.dm[0][1] * wy + im.dm[0][2] * wz;
1110 sy = im.dm[1][0] * wx + im.dm[1][1] * wy + im.dm[1][2] * wz;
1111 sz = im.dm[2][0] * wx + im.dm[2][1] * wy + im.dm[2][2] * wz;
1112
1113 m.dm[0][0] *= sx;
1114 m.dm[1][0] *= sx;
1115 m.dm[2][0] *= sx;
1116 m.dm[0][1] *= sy;
1117 m.dm[1][1] *= sy;
1118 m.dm[2][1] *= sy;
1119 m.dm[0][2] *= sz;
1120 m.dm[1][2] *= sz;
1121 m.dm[2][2] *= sz;
1122
1123 color_matrix_copy (dst, &m);
1124 }
1125
1126 static void
videoconvert_convert_init_tables(MatrixData * data)1127 videoconvert_convert_init_tables (MatrixData * data)
1128 {
1129 gint i, j;
1130
1131 data->t_r = g_new (gint64, 256);
1132 data->t_g = g_new (gint64, 256);
1133 data->t_b = g_new (gint64, 256);
1134
1135 for (i = 0; i < 256; i++) {
1136 gint64 r = 0, g = 0, b = 0;
1137
1138 for (j = 0; j < 3; j++) {
1139 r = (r << 16) + data->im[j][0] * i;
1140 g = (g << 16) + data->im[j][1] * i;
1141 b = (b << 16) + data->im[j][2] * i;
1142 }
1143 data->t_r[i] = r;
1144 data->t_g[i] = g;
1145 data->t_b[i] = b;
1146 }
1147 data->t_c = ((gint64) data->im[0][3] << 32)
1148 + ((gint64) data->im[1][3] << 16)
1149 + ((gint64) data->im[2][3] << 0);
1150 }
1151
1152 void
_custom_video_orc_matrix8(guint8 * ORC_RESTRICT d1,const guint8 * ORC_RESTRICT s1,orc_int64 p1,orc_int64 p2,orc_int64 p3,orc_int64 p4,int n)1153 _custom_video_orc_matrix8 (guint8 * ORC_RESTRICT d1,
1154 const guint8 * ORC_RESTRICT s1, orc_int64 p1, orc_int64 p2, orc_int64 p3,
1155 orc_int64 p4, int n)
1156 {
1157 gint i;
1158 gint r, g, b;
1159 gint y, u, v;
1160 gint a00, a01, a02, a03;
1161 gint a10, a11, a12, a13;
1162 gint a20, a21, a22, a23;
1163
1164 a00 = (gint16) (p1 >> 16);
1165 a01 = (gint16) (p2 >> 16);
1166 a02 = (gint16) (p3 >> 16);
1167 a03 = (gint16) (p4 >> 16);
1168 a10 = (gint16) (p1 >> 32);
1169 a11 = (gint16) (p2 >> 32);
1170 a12 = (gint16) (p3 >> 32);
1171 a13 = (gint16) (p4 >> 32);
1172 a20 = (gint16) (p1 >> 48);
1173 a21 = (gint16) (p2 >> 48);
1174 a22 = (gint16) (p3 >> 48);
1175 a23 = (gint16) (p4 >> 48);
1176
1177 for (i = 0; i < n; i++) {
1178 r = s1[i * 4 + 1];
1179 g = s1[i * 4 + 2];
1180 b = s1[i * 4 + 3];
1181
1182 y = ((a00 * r + a01 * g + a02 * b) >> SCALE) + a03;
1183 u = ((a10 * r + a11 * g + a12 * b) >> SCALE) + a13;
1184 v = ((a20 * r + a21 * g + a22 * b) >> SCALE) + a23;
1185
1186 d1[i * 4 + 1] = CLAMP (y, 0, 255);
1187 d1[i * 4 + 2] = CLAMP (u, 0, 255);
1188 d1[i * 4 + 3] = CLAMP (v, 0, 255);
1189 }
1190 }
1191
1192 static void
video_converter_matrix8(MatrixData * data,gpointer pixels)1193 video_converter_matrix8 (MatrixData * data, gpointer pixels)
1194 {
1195 gpointer d = pixels;
1196 video_orc_matrix8 (d, pixels, data->orc_p1, data->orc_p2,
1197 data->orc_p3, data->orc_p4, data->width);
1198 }
1199
1200 static void
video_converter_matrix8_table(MatrixData * data,gpointer pixels)1201 video_converter_matrix8_table (MatrixData * data, gpointer pixels)
1202 {
1203 gint i, width = data->width * 4;
1204 guint8 r, g, b;
1205 gint64 c = data->t_c;
1206 guint8 *p = pixels;
1207 gint64 x;
1208
1209 for (i = 0; i < width; i += 4) {
1210 r = p[i + 1];
1211 g = p[i + 2];
1212 b = p[i + 3];
1213
1214 x = data->t_r[r] + data->t_g[g] + data->t_b[b] + c;
1215
1216 p[i + 1] = x >> (32 + SCALE);
1217 p[i + 2] = x >> (16 + SCALE);
1218 p[i + 3] = x >> (0 + SCALE);
1219 }
1220 }
1221
1222 static void
video_converter_matrix8_AYUV_ARGB(MatrixData * data,gpointer pixels)1223 video_converter_matrix8_AYUV_ARGB (MatrixData * data, gpointer pixels)
1224 {
1225 gpointer d = pixels;
1226
1227 video_orc_convert_AYUV_ARGB (d, 0, pixels, 0,
1228 data->im[0][0], data->im[0][2],
1229 data->im[2][1], data->im[1][1], data->im[1][2], data->width, 1);
1230 }
1231
1232 static gboolean
is_ayuv_to_rgb_matrix(MatrixData * data)1233 is_ayuv_to_rgb_matrix (MatrixData * data)
1234 {
1235 if (data->im[0][0] != data->im[1][0] || data->im[1][0] != data->im[2][0])
1236 return FALSE;
1237
1238 if (data->im[0][1] != 0 || data->im[2][2] != 0)
1239 return FALSE;
1240
1241 return TRUE;
1242 }
1243
1244 static gboolean
is_identity_matrix(MatrixData * data)1245 is_identity_matrix (MatrixData * data)
1246 {
1247 gint i, j;
1248 gint c = data->im[0][0];
1249
1250 /* not really checking identity because of rounding errors but given
1251 * the conversions we do we just check for anything that looks like:
1252 *
1253 * c 0 0 0
1254 * 0 c 0 0
1255 * 0 0 c 0
1256 * 0 0 0 1
1257 */
1258 for (i = 0; i < 4; i++) {
1259 for (j = 0; j < 4; j++) {
1260 if (i == j) {
1261 if (i == 3 && data->im[i][j] != 1)
1262 return FALSE;
1263 else if (data->im[i][j] != c)
1264 return FALSE;
1265 } else if (data->im[i][j] != 0)
1266 return FALSE;
1267 }
1268 }
1269 return TRUE;
1270 }
1271
1272 static gboolean
is_no_clip_matrix(MatrixData * data)1273 is_no_clip_matrix (MatrixData * data)
1274 {
1275 gint i;
1276 static const guint8 test[8][3] = {
1277 {0, 0, 0},
1278 {0, 0, 255},
1279 {0, 255, 0},
1280 {0, 255, 255},
1281 {255, 0, 0},
1282 {255, 0, 255},
1283 {255, 255, 0},
1284 {255, 255, 255}
1285 };
1286
1287 for (i = 0; i < 8; i++) {
1288 gint r, g, b;
1289 gint y, u, v;
1290
1291 r = test[i][0];
1292 g = test[i][1];
1293 b = test[i][2];
1294
1295 y = (data->im[0][0] * r + data->im[0][1] * g +
1296 data->im[0][2] * b + data->im[0][3]) >> SCALE;
1297 u = (data->im[1][0] * r + data->im[1][1] * g +
1298 data->im[1][2] * b + data->im[1][3]) >> SCALE;
1299 v = (data->im[2][0] * r + data->im[2][1] * g +
1300 data->im[2][2] * b + data->im[2][3]) >> SCALE;
1301
1302 if (y != CLAMP (y, 0, 255) || u != CLAMP (u, 0, 255)
1303 || v != CLAMP (v, 0, 255))
1304 return FALSE;
1305 }
1306 return TRUE;
1307 }
1308
1309 static void
video_converter_matrix16(MatrixData * data,gpointer pixels)1310 video_converter_matrix16 (MatrixData * data, gpointer pixels)
1311 {
1312 int i;
1313 int r, g, b;
1314 int y, u, v;
1315 guint16 *p = pixels;
1316 gint width = data->width;
1317
1318 for (i = 0; i < width; i++) {
1319 r = p[i * 4 + 1];
1320 g = p[i * 4 + 2];
1321 b = p[i * 4 + 3];
1322
1323 y = (data->im[0][0] * r + data->im[0][1] * g +
1324 data->im[0][2] * b + data->im[0][3]) >> SCALE;
1325 u = (data->im[1][0] * r + data->im[1][1] * g +
1326 data->im[1][2] * b + data->im[1][3]) >> SCALE;
1327 v = (data->im[2][0] * r + data->im[2][1] * g +
1328 data->im[2][2] * b + data->im[2][3]) >> SCALE;
1329
1330 p[i * 4 + 1] = CLAMP (y, 0, 65535);
1331 p[i * 4 + 2] = CLAMP (u, 0, 65535);
1332 p[i * 4 + 3] = CLAMP (v, 0, 65535);
1333 }
1334 }
1335
1336
1337 static void
prepare_matrix(GstVideoConverter * convert,MatrixData * data)1338 prepare_matrix (GstVideoConverter * convert, MatrixData * data)
1339 {
1340 if (is_identity_matrix (data))
1341 return;
1342
1343 color_matrix_scale_components (data, SCALE_F, SCALE_F, SCALE_F);
1344 color_matrix_convert (data);
1345
1346 data->width = convert->current_width;
1347
1348 if (convert->current_bits == 8) {
1349 if (!convert->unpack_rgb && convert->pack_rgb
1350 && is_ayuv_to_rgb_matrix (data)) {
1351 GST_DEBUG ("use fast AYUV -> RGB matrix");
1352 data->matrix_func = video_converter_matrix8_AYUV_ARGB;
1353 } else if (is_no_clip_matrix (data)) {
1354 GST_DEBUG ("use 8bit table");
1355 data->matrix_func = video_converter_matrix8_table;
1356 videoconvert_convert_init_tables (data);
1357 } else {
1358 gint a03, a13, a23;
1359
1360 GST_DEBUG ("use 8bit matrix");
1361 data->matrix_func = video_converter_matrix8;
1362
1363 data->orc_p1 = (((guint64) (guint16) data->im[2][0]) << 48) |
1364 (((guint64) (guint16) data->im[1][0]) << 32) |
1365 (((guint64) (guint16) data->im[0][0]) << 16);
1366 data->orc_p2 = (((guint64) (guint16) data->im[2][1]) << 48) |
1367 (((guint64) (guint16) data->im[1][1]) << 32) |
1368 (((guint64) (guint16) data->im[0][1]) << 16);
1369 data->orc_p3 = (((guint64) (guint16) data->im[2][2]) << 48) |
1370 (((guint64) (guint16) data->im[1][2]) << 32) |
1371 (((guint64) (guint16) data->im[0][2]) << 16);
1372
1373 a03 = data->im[0][3] >> SCALE;
1374 a13 = data->im[1][3] >> SCALE;
1375 a23 = data->im[2][3] >> SCALE;
1376
1377 data->orc_p4 = (((guint64) (guint16) a23) << 48) |
1378 (((guint64) (guint16) a13) << 32) | (((guint64) (guint16) a03) << 16);
1379 }
1380 } else {
1381 GST_DEBUG ("use 16bit matrix");
1382 data->matrix_func = video_converter_matrix16;
1383 }
1384 }
1385
1386 static void
compute_matrix_to_RGB(GstVideoConverter * convert,MatrixData * data)1387 compute_matrix_to_RGB (GstVideoConverter * convert, MatrixData * data)
1388 {
1389 GstVideoInfo *info;
1390 gdouble Kr = 0, Kb = 0;
1391
1392 info = &convert->in_info;
1393
1394 {
1395 const GstVideoFormatInfo *uinfo;
1396 gint offset[4], scale[4];
1397
1398 uinfo = gst_video_format_get_info (convert->unpack_format);
1399
1400 /* bring color components to [0..1.0] range */
1401 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1402 scale);
1403
1404 color_matrix_offset_components (data, -offset[0], -offset[1], -offset[2]);
1405 color_matrix_scale_components (data, 1 / ((float) scale[0]),
1406 1 / ((float) scale[1]), 1 / ((float) scale[2]));
1407 }
1408
1409 if (!convert->unpack_rgb && !CHECK_MATRIX_NONE (convert)) {
1410 if (CHECK_MATRIX_OUTPUT (convert))
1411 info = &convert->out_info;
1412
1413 /* bring components to R'G'B' space */
1414 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
1415 color_matrix_YCbCr_to_RGB (data, Kr, Kb);
1416 }
1417 color_matrix_debug (data);
1418 }
1419
1420 static void
compute_matrix_to_YUV(GstVideoConverter * convert,MatrixData * data,gboolean force)1421 compute_matrix_to_YUV (GstVideoConverter * convert, MatrixData * data,
1422 gboolean force)
1423 {
1424 GstVideoInfo *info;
1425 gdouble Kr = 0, Kb = 0;
1426
1427 if (force || (!convert->pack_rgb && !CHECK_MATRIX_NONE (convert))) {
1428 if (CHECK_MATRIX_INPUT (convert))
1429 info = &convert->in_info;
1430 else
1431 info = &convert->out_info;
1432
1433 /* bring components to YCbCr space */
1434 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
1435 color_matrix_RGB_to_YCbCr (data, Kr, Kb);
1436 }
1437
1438 info = &convert->out_info;
1439
1440 {
1441 const GstVideoFormatInfo *uinfo;
1442 gint offset[4], scale[4];
1443
1444 uinfo = gst_video_format_get_info (convert->pack_format);
1445
1446 /* bring color components to nominal range */
1447 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1448 scale);
1449
1450 color_matrix_scale_components (data, (float) scale[0], (float) scale[1],
1451 (float) scale[2]);
1452 color_matrix_offset_components (data, offset[0], offset[1], offset[2]);
1453 }
1454
1455 color_matrix_debug (data);
1456 }
1457
1458
1459 static void
gamma_convert_u8_u16(GammaData * data,gpointer dest,gpointer src)1460 gamma_convert_u8_u16 (GammaData * data, gpointer dest, gpointer src)
1461 {
1462 gint i;
1463 guint8 *s = src;
1464 guint16 *d = dest;
1465 guint16 *table = data->gamma_table;
1466 gint width = data->width * 4;
1467
1468 for (i = 0; i < width; i += 4) {
1469 d[i + 0] = (s[i] << 8) | s[i];
1470 d[i + 1] = table[s[i + 1]];
1471 d[i + 2] = table[s[i + 2]];
1472 d[i + 3] = table[s[i + 3]];
1473 }
1474 }
1475
1476 static void
gamma_convert_u16_u8(GammaData * data,gpointer dest,gpointer src)1477 gamma_convert_u16_u8 (GammaData * data, gpointer dest, gpointer src)
1478 {
1479 gint i;
1480 guint16 *s = src;
1481 guint8 *d = dest;
1482 guint8 *table = data->gamma_table;
1483 gint width = data->width * 4;
1484
1485 for (i = 0; i < width; i += 4) {
1486 d[i + 0] = s[i] >> 8;
1487 d[i + 1] = table[s[i + 1]];
1488 d[i + 2] = table[s[i + 2]];
1489 d[i + 3] = table[s[i + 3]];
1490 }
1491 }
1492
1493 static void
gamma_convert_u16_u16(GammaData * data,gpointer dest,gpointer src)1494 gamma_convert_u16_u16 (GammaData * data, gpointer dest, gpointer src)
1495 {
1496 gint i;
1497 guint16 *s = src;
1498 guint16 *d = dest;
1499 guint16 *table = data->gamma_table;
1500 gint width = data->width * 4;
1501
1502 for (i = 0; i < width; i += 4) {
1503 d[i + 0] = s[i];
1504 d[i + 1] = table[s[i + 1]];
1505 d[i + 2] = table[s[i + 2]];
1506 d[i + 3] = table[s[i + 3]];
1507 }
1508 }
1509
1510 static void
setup_gamma_decode(GstVideoConverter * convert)1511 setup_gamma_decode (GstVideoConverter * convert)
1512 {
1513 GstVideoTransferFunction func;
1514 guint16 *t;
1515 gint i;
1516
1517 func = convert->in_info.colorimetry.transfer;
1518
1519 convert->gamma_dec.width = convert->current_width;
1520 if (convert->current_bits == 8) {
1521 GST_DEBUG ("gamma decode 8->16: %d", func);
1522 convert->gamma_dec.gamma_func = gamma_convert_u8_u16;
1523 t = convert->gamma_dec.gamma_table = g_malloc (sizeof (guint16) * 256);
1524
1525 for (i = 0; i < 256; i++)
1526 t[i] = rint (gst_video_color_transfer_decode (func, i / 255.0) * 65535.0);
1527 } else {
1528 GST_DEBUG ("gamma decode 16->16: %d", func);
1529 convert->gamma_dec.gamma_func = gamma_convert_u16_u16;
1530 t = convert->gamma_dec.gamma_table = g_malloc (sizeof (guint16) * 65536);
1531
1532 for (i = 0; i < 65536; i++)
1533 t[i] =
1534 rint (gst_video_color_transfer_decode (func, i / 65535.0) * 65535.0);
1535 }
1536 convert->current_bits = 16;
1537 convert->current_pstride = 8;
1538 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1539 }
1540
1541 static void
setup_gamma_encode(GstVideoConverter * convert,gint target_bits)1542 setup_gamma_encode (GstVideoConverter * convert, gint target_bits)
1543 {
1544 GstVideoTransferFunction func;
1545 gint i;
1546
1547 func = convert->out_info.colorimetry.transfer;
1548
1549 convert->gamma_enc.width = convert->current_width;
1550 if (target_bits == 8) {
1551 guint8 *t;
1552
1553 GST_DEBUG ("gamma encode 16->8: %d", func);
1554 convert->gamma_enc.gamma_func = gamma_convert_u16_u8;
1555 t = convert->gamma_enc.gamma_table = g_malloc (sizeof (guint8) * 65536);
1556
1557 for (i = 0; i < 65536; i++)
1558 t[i] = rint (gst_video_color_transfer_encode (func, i / 65535.0) * 255.0);
1559 } else {
1560 guint16 *t;
1561
1562 GST_DEBUG ("gamma encode 16->16: %d", func);
1563 convert->gamma_enc.gamma_func = gamma_convert_u16_u16;
1564 t = convert->gamma_enc.gamma_table = g_malloc (sizeof (guint16) * 65536);
1565
1566 for (i = 0; i < 65536; i++)
1567 t[i] =
1568 rint (gst_video_color_transfer_encode (func, i / 65535.0) * 65535.0);
1569 }
1570 }
1571
1572 static GstLineCache *
chain_convert_to_RGB(GstVideoConverter * convert,GstLineCache * prev,gint idx)1573 chain_convert_to_RGB (GstVideoConverter * convert, GstLineCache * prev,
1574 gint idx)
1575 {
1576 gboolean do_gamma;
1577
1578 do_gamma = CHECK_GAMMA_REMAP (convert);
1579
1580 if (do_gamma) {
1581 gint scale;
1582
1583 if (!convert->unpack_rgb) {
1584 color_matrix_set_identity (&convert->to_RGB_matrix);
1585 compute_matrix_to_RGB (convert, &convert->to_RGB_matrix);
1586
1587 /* matrix is in 0..1 range, scale to current bits */
1588 GST_DEBUG ("chain RGB convert");
1589 scale = 1 << convert->current_bits;
1590 color_matrix_scale_components (&convert->to_RGB_matrix,
1591 (float) scale, (float) scale, (float) scale);
1592
1593 prepare_matrix (convert, &convert->to_RGB_matrix);
1594
1595 if (convert->current_bits == 8)
1596 convert->current_format = GST_VIDEO_FORMAT_ARGB;
1597 else
1598 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1599 }
1600
1601 prev = convert->to_RGB_lines[idx] = gst_line_cache_new (prev);
1602 prev->write_input = TRUE;
1603 prev->pass_alloc = FALSE;
1604 prev->n_lines = 1;
1605 prev->stride = convert->current_pstride * convert->current_width;
1606 gst_line_cache_set_need_line_func (prev,
1607 do_convert_to_RGB_lines, idx, convert, NULL);
1608
1609 GST_DEBUG ("chain gamma decode");
1610 setup_gamma_decode (convert);
1611 }
1612 return prev;
1613 }
1614
1615 static GstLineCache *
chain_hscale(GstVideoConverter * convert,GstLineCache * prev,gint idx)1616 chain_hscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1617 {
1618 gint method;
1619 guint taps;
1620
1621 method = GET_OPT_RESAMPLER_METHOD (convert);
1622 taps = GET_OPT_RESAMPLER_TAPS (convert);
1623
1624 convert->h_scaler[idx] =
1625 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
1626 convert->in_width, convert->out_width, convert->config);
1627
1628 gst_video_scaler_get_coeff (convert->h_scaler[idx], 0, NULL, &taps);
1629
1630 GST_DEBUG ("chain hscale %d->%d, taps %d, method %d",
1631 convert->in_width, convert->out_width, taps, method);
1632
1633 convert->current_width = convert->out_width;
1634 convert->h_scale_format = convert->current_format;
1635
1636 prev = convert->hscale_lines[idx] = gst_line_cache_new (prev);
1637 prev->write_input = FALSE;
1638 prev->pass_alloc = FALSE;
1639 prev->n_lines = 1;
1640 prev->stride = convert->current_pstride * convert->current_width;
1641 gst_line_cache_set_need_line_func (prev, do_hscale_lines, idx, convert, NULL);
1642
1643 return prev;
1644 }
1645
1646 static GstLineCache *
chain_vscale(GstVideoConverter * convert,GstLineCache * prev,gint idx)1647 chain_vscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1648 {
1649 gint method;
1650 guint taps, taps_i = 0;
1651 gint backlog = 0;
1652
1653 method = GET_OPT_RESAMPLER_METHOD (convert);
1654 taps = GET_OPT_RESAMPLER_TAPS (convert);
1655
1656 if (GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)) {
1657 convert->v_scaler_i[idx] =
1658 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_INTERLACED,
1659 taps, convert->in_height, convert->out_height, convert->config);
1660
1661 gst_video_scaler_get_coeff (convert->v_scaler_i[idx], 0, NULL, &taps_i);
1662 backlog = taps_i;
1663 }
1664 convert->v_scaler_p[idx] =
1665 gst_video_scaler_new (method, 0, taps, convert->in_height,
1666 convert->out_height, convert->config);
1667 convert->v_scale_width = convert->current_width;
1668 convert->v_scale_format = convert->current_format;
1669 convert->current_height = convert->out_height;
1670
1671 gst_video_scaler_get_coeff (convert->v_scaler_p[idx], 0, NULL, &taps);
1672
1673 GST_DEBUG ("chain vscale %d->%d, taps %d, method %d, backlog %d",
1674 convert->in_height, convert->out_height, taps, method, backlog);
1675
1676 prev->backlog = backlog;
1677 prev = convert->vscale_lines[idx] = gst_line_cache_new (prev);
1678 prev->pass_alloc = (taps == 1);
1679 prev->write_input = FALSE;
1680 prev->n_lines = MAX (taps_i, taps);
1681 prev->stride = convert->current_pstride * convert->current_width;
1682 gst_line_cache_set_need_line_func (prev, do_vscale_lines, idx, convert, NULL);
1683
1684 return prev;
1685 }
1686
1687 static GstLineCache *
chain_scale(GstVideoConverter * convert,GstLineCache * prev,gboolean force,gint idx)1688 chain_scale (GstVideoConverter * convert, GstLineCache * prev, gboolean force,
1689 gint idx)
1690 {
1691 gint s0, s1, s2, s3;
1692
1693 s0 = convert->current_width * convert->current_height;
1694 s3 = convert->out_width * convert->out_height;
1695
1696 GST_DEBUG ("in pixels %d <> out pixels %d", s0, s3);
1697
1698 if (s3 <= s0 || force) {
1699 /* we are making the image smaller or are forced to resample */
1700 s1 = convert->out_width * convert->current_height;
1701 s2 = convert->current_width * convert->out_height;
1702
1703 GST_DEBUG ("%d <> %d", s1, s2);
1704
1705 if (s1 <= s2) {
1706 /* h scaling first produces less pixels */
1707 if (convert->current_width != convert->out_width)
1708 prev = chain_hscale (convert, prev, idx);
1709 if (convert->current_height != convert->out_height)
1710 prev = chain_vscale (convert, prev, idx);
1711 } else {
1712 /* v scaling first produces less pixels */
1713 if (convert->current_height != convert->out_height)
1714 prev = chain_vscale (convert, prev, idx);
1715 if (convert->current_width != convert->out_width)
1716 prev = chain_hscale (convert, prev, idx);
1717 }
1718 }
1719 return prev;
1720 }
1721
1722 static GstLineCache *
chain_convert(GstVideoConverter * convert,GstLineCache * prev,gint idx)1723 chain_convert (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1724 {
1725 gboolean do_gamma, do_conversion, pass_alloc = FALSE;
1726 gboolean same_matrix, same_primaries, same_bits;
1727 MatrixData p1, p2;
1728
1729 same_bits = convert->unpack_bits == convert->pack_bits;
1730 if (CHECK_MATRIX_NONE (convert)) {
1731 same_matrix = TRUE;
1732 } else {
1733 same_matrix =
1734 convert->in_info.colorimetry.matrix ==
1735 convert->out_info.colorimetry.matrix;
1736 }
1737
1738 if (CHECK_PRIMARIES_NONE (convert)) {
1739 same_primaries = TRUE;
1740 } else {
1741 same_primaries =
1742 convert->in_info.colorimetry.primaries ==
1743 convert->out_info.colorimetry.primaries;
1744 }
1745
1746 GST_DEBUG ("matrix %d -> %d (%d)", convert->in_info.colorimetry.matrix,
1747 convert->out_info.colorimetry.matrix, same_matrix);
1748 GST_DEBUG ("bits %d -> %d (%d)", convert->unpack_bits, convert->pack_bits,
1749 same_bits);
1750 GST_DEBUG ("primaries %d -> %d (%d)", convert->in_info.colorimetry.primaries,
1751 convert->out_info.colorimetry.primaries, same_primaries);
1752
1753 color_matrix_set_identity (&convert->convert_matrix);
1754
1755 if (!same_primaries) {
1756 const GstVideoColorPrimariesInfo *pi;
1757
1758 /* Convert from RGB_input to RGB_output via XYZ
1759 * res = XYZ_to_RGB_output ( RGB_to_XYZ_input ( input ) )
1760 * or in matricial form:
1761 * RGB_output = XYZ_to_RGB_output_matrix * RGB_TO_XYZ_input_matrix * RGB_input
1762 *
1763 * The RGB_input is the pre-existing convert_matrix
1764 * The convert_matrix will become the RGB_output
1765 */
1766
1767 /* Convert input RGB to XYZ */
1768 pi = gst_video_color_primaries_get_info (convert->in_info.colorimetry.
1769 primaries);
1770 /* Get the RGB_TO_XYZ_input_matrix */
1771 color_matrix_RGB_to_XYZ (&p1, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx,
1772 pi->By, pi->Wx, pi->Wy);
1773 GST_DEBUG ("to XYZ matrix");
1774 color_matrix_debug (&p1);
1775 GST_DEBUG ("current matrix");
1776 /* convert_matrix = RGB_TO_XYZ_input_matrix * input_RGB */
1777 color_matrix_multiply (&convert->convert_matrix, &convert->convert_matrix,
1778 &p1);
1779 color_matrix_debug (&convert->convert_matrix);
1780
1781 /* Convert XYZ to output RGB */
1782 pi = gst_video_color_primaries_get_info (convert->out_info.colorimetry.
1783 primaries);
1784 /* Calculate the XYZ_to_RGB_output_matrix
1785 * * Get the RGB_TO_XYZ_output_matrix
1786 * * invert it
1787 * * store in p2
1788 */
1789 color_matrix_RGB_to_XYZ (&p2, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx,
1790 pi->By, pi->Wx, pi->Wy);
1791 color_matrix_invert (&p2, &p2);
1792 GST_DEBUG ("to RGB matrix");
1793 color_matrix_debug (&p2);
1794 /* Finally:
1795 * convert_matrix = XYZ_to_RGB_output_matrix * RGB_TO_XYZ_input_matrix * RGB_input
1796 * = XYZ_to_RGB_output_matrix * convert_matrix
1797 * = p2 * convert_matrix
1798 */
1799 color_matrix_multiply (&convert->convert_matrix, &p2,
1800 &convert->convert_matrix);
1801 GST_DEBUG ("current matrix");
1802 color_matrix_debug (&convert->convert_matrix);
1803 }
1804
1805 do_gamma = CHECK_GAMMA_REMAP (convert);
1806 if (!do_gamma) {
1807
1808 convert->in_bits = convert->unpack_bits;
1809 convert->out_bits = convert->pack_bits;
1810
1811 if (!same_bits || !same_matrix || !same_primaries) {
1812 /* no gamma, combine all conversions into 1 */
1813 if (convert->in_bits < convert->out_bits) {
1814 gint scale = 1 << (convert->out_bits - convert->in_bits);
1815 color_matrix_scale_components (&convert->convert_matrix,
1816 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
1817 }
1818 GST_DEBUG ("to RGB matrix");
1819 compute_matrix_to_RGB (convert, &convert->convert_matrix);
1820 GST_DEBUG ("current matrix");
1821 color_matrix_debug (&convert->convert_matrix);
1822
1823 GST_DEBUG ("to YUV matrix");
1824 compute_matrix_to_YUV (convert, &convert->convert_matrix, FALSE);
1825 GST_DEBUG ("current matrix");
1826 color_matrix_debug (&convert->convert_matrix);
1827 if (convert->in_bits > convert->out_bits) {
1828 gint scale = 1 << (convert->in_bits - convert->out_bits);
1829 color_matrix_scale_components (&convert->convert_matrix,
1830 (float) scale, (float) scale, (float) scale);
1831 }
1832 convert->current_bits = MAX (convert->in_bits, convert->out_bits);
1833
1834 do_conversion = TRUE;
1835 if (!same_matrix || !same_primaries)
1836 prepare_matrix (convert, &convert->convert_matrix);
1837 if (convert->in_bits == convert->out_bits)
1838 pass_alloc = TRUE;
1839 } else
1840 do_conversion = FALSE;
1841
1842 convert->current_bits = convert->pack_bits;
1843 convert->current_format = convert->pack_format;
1844 convert->current_pstride = convert->current_bits >> 1;
1845 } else {
1846 /* we did gamma, just do colorspace conversion if needed */
1847 if (same_primaries) {
1848 do_conversion = FALSE;
1849 } else {
1850 prepare_matrix (convert, &convert->convert_matrix);
1851 convert->in_bits = convert->out_bits = 16;
1852 pass_alloc = TRUE;
1853 do_conversion = TRUE;
1854 }
1855 }
1856
1857 if (do_conversion) {
1858 GST_DEBUG ("chain conversion");
1859 prev = convert->convert_lines[idx] = gst_line_cache_new (prev);
1860 prev->write_input = TRUE;
1861 prev->pass_alloc = pass_alloc;
1862 prev->n_lines = 1;
1863 prev->stride = convert->current_pstride * convert->current_width;
1864 gst_line_cache_set_need_line_func (prev,
1865 do_convert_lines, idx, convert, NULL);
1866 }
1867 return prev;
1868 }
1869
1870 static void
convert_set_alpha_u8(GstVideoConverter * convert,gpointer pixels,gint width)1871 convert_set_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1872 {
1873 guint8 *p = pixels;
1874 guint8 alpha = MIN (convert->alpha_value, 255);
1875 int i;
1876
1877 for (i = 0; i < width; i++)
1878 p[i * 4] = alpha;
1879 }
1880
1881 static void
convert_set_alpha_u16(GstVideoConverter * convert,gpointer pixels,gint width)1882 convert_set_alpha_u16 (GstVideoConverter * convert, gpointer pixels, gint width)
1883 {
1884 guint16 *p = pixels;
1885 guint16 alpha;
1886 int i;
1887
1888 alpha = MIN (convert->alpha_value, 255);
1889 alpha |= alpha << 8;
1890
1891 for (i = 0; i < width; i++)
1892 p[i * 4] = alpha;
1893 }
1894
1895 static void
convert_mult_alpha_u8(GstVideoConverter * convert,gpointer pixels,gint width)1896 convert_mult_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1897 {
1898 guint8 *p = pixels;
1899 guint alpha = convert->alpha_value;
1900 int i;
1901
1902 for (i = 0; i < width; i++) {
1903 gint a = (p[i * 4] * alpha) / 255;
1904 p[i * 4] = CLAMP (a, 0, 255);
1905 }
1906 }
1907
1908 static void
convert_mult_alpha_u16(GstVideoConverter * convert,gpointer pixels,gint width)1909 convert_mult_alpha_u16 (GstVideoConverter * convert, gpointer pixels,
1910 gint width)
1911 {
1912 guint16 *p = pixels;
1913 guint alpha = convert->alpha_value;
1914 int i;
1915
1916 for (i = 0; i < width; i++) {
1917 gint a = (p[i * 4] * alpha) / 255;
1918 p[i * 4] = CLAMP (a, 0, 65535);
1919 }
1920 }
1921
1922 static GstLineCache *
chain_alpha(GstVideoConverter * convert,GstLineCache * prev,gint idx)1923 chain_alpha (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1924 {
1925 switch (convert->alpha_mode) {
1926 case ALPHA_MODE_NONE:
1927 case ALPHA_MODE_COPY:
1928 return prev;
1929
1930 case ALPHA_MODE_SET:
1931 if (convert->current_bits == 8)
1932 convert->alpha_func = convert_set_alpha_u8;
1933 else
1934 convert->alpha_func = convert_set_alpha_u16;
1935 break;
1936 case ALPHA_MODE_MULT:
1937 if (convert->current_bits == 8)
1938 convert->alpha_func = convert_mult_alpha_u8;
1939 else
1940 convert->alpha_func = convert_mult_alpha_u16;
1941 break;
1942 }
1943
1944 GST_DEBUG ("chain alpha mode %d", convert->alpha_mode);
1945 prev = convert->alpha_lines[idx] = gst_line_cache_new (prev);
1946 prev->write_input = TRUE;
1947 prev->pass_alloc = TRUE;
1948 prev->n_lines = 1;
1949 prev->stride = convert->current_pstride * convert->current_width;
1950 gst_line_cache_set_need_line_func (prev, do_alpha_lines, idx, convert, NULL);
1951
1952 return prev;
1953 }
1954
1955 static GstLineCache *
chain_convert_to_YUV(GstVideoConverter * convert,GstLineCache * prev,gint idx)1956 chain_convert_to_YUV (GstVideoConverter * convert, GstLineCache * prev,
1957 gint idx)
1958 {
1959 gboolean do_gamma;
1960
1961 do_gamma = CHECK_GAMMA_REMAP (convert);
1962
1963 if (do_gamma) {
1964 gint scale;
1965
1966 GST_DEBUG ("chain gamma encode");
1967 setup_gamma_encode (convert, convert->pack_bits);
1968
1969 convert->current_bits = convert->pack_bits;
1970 convert->current_pstride = convert->current_bits >> 1;
1971
1972 if (!convert->pack_rgb) {
1973 color_matrix_set_identity (&convert->to_YUV_matrix);
1974 compute_matrix_to_YUV (convert, &convert->to_YUV_matrix, FALSE);
1975
1976 /* matrix is in 0..255 range, scale to pack bits */
1977 GST_DEBUG ("chain YUV convert");
1978 scale = 1 << convert->pack_bits;
1979 color_matrix_scale_components (&convert->to_YUV_matrix,
1980 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
1981 prepare_matrix (convert, &convert->to_YUV_matrix);
1982 }
1983 convert->current_format = convert->pack_format;
1984
1985 prev = convert->to_YUV_lines[idx] = gst_line_cache_new (prev);
1986 prev->write_input = FALSE;
1987 prev->pass_alloc = FALSE;
1988 prev->n_lines = 1;
1989 prev->stride = convert->current_pstride * convert->current_width;
1990 gst_line_cache_set_need_line_func (prev,
1991 do_convert_to_YUV_lines, idx, convert, NULL);
1992 }
1993
1994 return prev;
1995 }
1996
1997 static GstLineCache *
chain_downsample(GstVideoConverter * convert,GstLineCache * prev,gint idx)1998 chain_downsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1999 {
2000 if (convert->downsample_p[idx] || convert->downsample_i[idx]) {
2001 GST_DEBUG ("chain downsample");
2002 prev = convert->downsample_lines[idx] = gst_line_cache_new (prev);
2003 prev->write_input = TRUE;
2004 prev->pass_alloc = TRUE;
2005 prev->n_lines = 4;
2006 prev->stride = convert->current_pstride * convert->current_width;
2007 gst_line_cache_set_need_line_func (prev,
2008 do_downsample_lines, idx, convert, NULL);
2009 }
2010 return prev;
2011 }
2012
2013 static GstLineCache *
chain_dither(GstVideoConverter * convert,GstLineCache * prev,gint idx)2014 chain_dither (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2015 {
2016 gint i;
2017 gboolean do_dither = FALSE;
2018 GstVideoDitherFlags flags = 0;
2019 GstVideoDitherMethod method;
2020 guint quant[4], target_quant;
2021
2022 method = GET_OPT_DITHER_METHOD (convert);
2023 if (method == GST_VIDEO_DITHER_NONE)
2024 return prev;
2025
2026 target_quant = GET_OPT_DITHER_QUANTIZATION (convert);
2027 GST_DEBUG ("method %d, target-quantization %d", method, target_quant);
2028
2029 if (convert->pack_pal) {
2030 quant[0] = 47;
2031 quant[1] = 47;
2032 quant[2] = 47;
2033 quant[3] = 1;
2034 do_dither = TRUE;
2035 } else {
2036 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++) {
2037 gint depth;
2038
2039 depth = convert->out_info.finfo->depth[i];
2040
2041 if (depth == 0) {
2042 quant[i] = 0;
2043 continue;
2044 }
2045
2046 if (convert->current_bits >= depth) {
2047 quant[i] = 1 << (convert->current_bits - depth);
2048 if (target_quant > quant[i]) {
2049 flags |= GST_VIDEO_DITHER_FLAG_QUANTIZE;
2050 quant[i] = target_quant;
2051 }
2052 } else {
2053 quant[i] = 0;
2054 }
2055 if (quant[i] > 1)
2056 do_dither = TRUE;
2057 }
2058 }
2059
2060 if (do_dither) {
2061 GST_DEBUG ("chain dither");
2062
2063 convert->dither[idx] = gst_video_dither_new (method,
2064 flags, convert->pack_format, quant, convert->current_width);
2065
2066 prev = convert->dither_lines[idx] = gst_line_cache_new (prev);
2067 prev->write_input = TRUE;
2068 prev->pass_alloc = TRUE;
2069 prev->n_lines = 1;
2070 prev->stride = convert->current_pstride * convert->current_width;
2071 gst_line_cache_set_need_line_func (prev, do_dither_lines, idx, convert,
2072 NULL);
2073 }
2074 return prev;
2075 }
2076
2077 static GstLineCache *
chain_pack(GstVideoConverter * convert,GstLineCache * prev,gint idx)2078 chain_pack (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2079 {
2080 convert->pack_nlines = convert->out_info.finfo->pack_lines;
2081 convert->pack_pstride = convert->current_pstride;
2082 convert->identity_pack =
2083 (convert->out_info.finfo->format ==
2084 convert->out_info.finfo->unpack_format);
2085 GST_DEBUG ("chain pack line format %s, pstride %d, identity_pack %d (%d %d)",
2086 gst_video_format_to_string (convert->current_format),
2087 convert->current_pstride, convert->identity_pack,
2088 convert->out_info.finfo->format, convert->out_info.finfo->unpack_format);
2089
2090 return prev;
2091 }
2092
2093 static void
setup_allocators(GstVideoConverter * convert)2094 setup_allocators (GstVideoConverter * convert)
2095 {
2096 GstLineCache *cache, *prev;
2097 GstLineCacheAllocLineFunc alloc_line;
2098 gboolean alloc_writable;
2099 gpointer user_data;
2100 GDestroyNotify notify;
2101 gint width;
2102 gint i;
2103
2104 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2105 width += convert->out_x;
2106
2107 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2108 /* start with using dest lines if we can directly write into it */
2109 if (convert->identity_pack) {
2110 alloc_line = get_dest_line;
2111 alloc_writable = TRUE;
2112 user_data = convert;
2113 notify = NULL;
2114 } else {
2115 user_data =
2116 converter_alloc_new (sizeof (guint16) * width * 4, 4 + BACKLOG,
2117 convert, NULL);
2118 setup_border_alloc (convert, user_data);
2119 notify = (GDestroyNotify) converter_alloc_free;
2120 alloc_line = get_border_temp_line;
2121 /* when we add a border, we need to write */
2122 alloc_writable = convert->borderline != NULL;
2123 }
2124
2125 /* First step, try to calculate how many temp lines we need. Go backwards,
2126 * keep track of the maximum number of lines we need for each intermediate
2127 * step. */
2128 for (prev = cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2129 GST_DEBUG ("looking at cache %p, %d lines, %d backlog", cache,
2130 cache->n_lines, cache->backlog);
2131 prev->n_lines = MAX (prev->n_lines, cache->n_lines);
2132 if (!cache->pass_alloc) {
2133 GST_DEBUG ("cache %p, needs %d lines", prev, prev->n_lines);
2134 prev = cache;
2135 }
2136 }
2137
2138 /* now walk backwards, we try to write into the dest lines directly
2139 * and keep track if the source needs to be writable */
2140 for (cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2141 gst_line_cache_set_alloc_line_func (cache, alloc_line, user_data, notify);
2142 cache->alloc_writable = alloc_writable;
2143
2144 /* make sure only one cache frees the allocator */
2145 notify = NULL;
2146
2147 if (!cache->pass_alloc) {
2148 /* can't pass allocator, make new temp line allocator */
2149 user_data =
2150 converter_alloc_new (sizeof (guint16) * width * 4,
2151 cache->n_lines + cache->backlog, convert, NULL);
2152 notify = (GDestroyNotify) converter_alloc_free;
2153 alloc_line = get_temp_line;
2154 alloc_writable = FALSE;
2155 }
2156 /* if someone writes to the input, we need a writable line from the
2157 * previous cache */
2158 if (cache->write_input)
2159 alloc_writable = TRUE;
2160 }
2161 /* free leftover allocator */
2162 if (notify)
2163 notify (user_data);
2164 }
2165 }
2166
2167 static void
setup_borderline(GstVideoConverter * convert)2168 setup_borderline (GstVideoConverter * convert)
2169 {
2170 gint width;
2171
2172 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2173 width += convert->out_x;
2174
2175 if (convert->fill_border && (convert->out_height < convert->out_maxheight ||
2176 convert->out_width < convert->out_maxwidth)) {
2177 guint32 border_val;
2178 gint i, w_sub;
2179 const GstVideoFormatInfo *out_finfo;
2180 gpointer planes[GST_VIDEO_MAX_PLANES];
2181 gint strides[GST_VIDEO_MAX_PLANES];
2182
2183 convert->borderline = g_malloc0 (sizeof (guint16) * width * 4);
2184
2185 out_finfo = convert->out_info.finfo;
2186
2187 if (GST_VIDEO_INFO_IS_YUV (&convert->out_info)) {
2188 MatrixData cm;
2189 gint a, r, g, b;
2190 gint y, u, v;
2191
2192 /* Get Color matrix. */
2193 color_matrix_set_identity (&cm);
2194 compute_matrix_to_YUV (convert, &cm, TRUE);
2195 color_matrix_convert (&cm);
2196
2197 border_val = GINT32_FROM_BE (convert->border_argb);
2198
2199 b = (0xFF000000 & border_val) >> 24;
2200 g = (0x00FF0000 & border_val) >> 16;
2201 r = (0x0000FF00 & border_val) >> 8;
2202 a = (0x000000FF & border_val);
2203
2204 y = 16 + ((r * cm.im[0][0] + g * cm.im[0][1] + b * cm.im[0][2]) >> 8);
2205 u = 128 + ((r * cm.im[1][0] + g * cm.im[1][1] + b * cm.im[1][2]) >> 8);
2206 v = 128 + ((r * cm.im[2][0] + g * cm.im[2][1] + b * cm.im[2][2]) >> 8);
2207
2208 a = CLAMP (a, 0, 255);
2209 y = CLAMP (y, 0, 255);
2210 u = CLAMP (u, 0, 255);
2211 v = CLAMP (v, 0, 255);
2212
2213 border_val = a | (y << 8) | (u << 16) | ((guint32) v << 24);
2214 } else {
2215 border_val = GINT32_FROM_BE (convert->border_argb);
2216 }
2217 if (convert->pack_bits == 8)
2218 video_orc_splat_u32 (convert->borderline, border_val, width);
2219 else
2220 video_orc_splat2_u64 (convert->borderline, border_val, width);
2221
2222 /* convert pixels */
2223 for (i = 0; i < out_finfo->n_planes; i++) {
2224 planes[i] = &convert->borders[i];
2225 strides[i] = sizeof (guint64);
2226 }
2227 w_sub = 0;
2228 if (out_finfo->n_planes == 1) {
2229 /* for packed formats, convert based on subsampling so that we
2230 * get a complete group of pixels */
2231 for (i = 0; i < out_finfo->n_components; i++) {
2232 w_sub = MAX (w_sub, out_finfo->w_sub[i]);
2233 }
2234 }
2235 out_finfo->pack_func (out_finfo, GST_VIDEO_PACK_FLAG_NONE,
2236 convert->borderline, 0, planes, strides,
2237 GST_VIDEO_CHROMA_SITE_UNKNOWN, 0, 1 << w_sub);
2238 } else {
2239 convert->borderline = NULL;
2240 }
2241 }
2242
2243 static AlphaMode
convert_get_alpha_mode(GstVideoConverter * convert)2244 convert_get_alpha_mode (GstVideoConverter * convert)
2245 {
2246 gboolean in_alpha, out_alpha;
2247
2248 in_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->in_info);
2249 out_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->out_info);
2250
2251 /* no output alpha, do nothing */
2252 if (!out_alpha)
2253 return ALPHA_MODE_NONE;
2254
2255 if (in_alpha) {
2256 /* in and out */
2257 if (CHECK_ALPHA_COPY (convert))
2258 return ALPHA_MODE_COPY;
2259
2260 if (CHECK_ALPHA_MULT (convert)) {
2261 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2262 return ALPHA_MODE_COPY;
2263 else
2264 return ALPHA_MODE_MULT;
2265 }
2266 }
2267 /* nothing special, this is what unpack etc does automatically */
2268 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2269 return ALPHA_MODE_NONE;
2270
2271 /* everything else becomes SET */
2272 return ALPHA_MODE_SET;
2273 }
2274
2275 /**
2276 * gst_video_converter_new: (skip)
2277 * @in_info: a #GstVideoInfo
2278 * @out_info: a #GstVideoInfo
2279 * @config: (transfer full): a #GstStructure with configuration options
2280 *
2281 * Create a new converter object to convert between @in_info and @out_info
2282 * with @config.
2283 *
2284 * Returns: a #GstVideoConverter or %NULL if conversion is not possible.
2285 *
2286 * Since: 1.6
2287 */
2288 GstVideoConverter *
gst_video_converter_new(GstVideoInfo * in_info,GstVideoInfo * out_info,GstStructure * config)2289 gst_video_converter_new (GstVideoInfo * in_info, GstVideoInfo * out_info,
2290 GstStructure * config)
2291 {
2292 GstVideoConverter *convert;
2293 GstLineCache *prev;
2294 const GstVideoFormatInfo *fin, *fout, *finfo;
2295 gdouble alpha_value;
2296 gint n_threads, i;
2297
2298 g_return_val_if_fail (in_info != NULL, NULL);
2299 g_return_val_if_fail (out_info != NULL, NULL);
2300 /* we won't ever do framerate conversion */
2301 g_return_val_if_fail (in_info->fps_n == out_info->fps_n, NULL);
2302 g_return_val_if_fail (in_info->fps_d == out_info->fps_d, NULL);
2303 /* we won't ever do deinterlace */
2304 g_return_val_if_fail (in_info->interlace_mode == out_info->interlace_mode,
2305 NULL);
2306
2307 convert = g_slice_new0 (GstVideoConverter);
2308
2309 fin = in_info->finfo;
2310 fout = out_info->finfo;
2311
2312 convert->in_info = *in_info;
2313 convert->out_info = *out_info;
2314
2315 /* default config */
2316 convert->config = gst_structure_new_empty ("GstVideoConverter");
2317 if (config)
2318 gst_video_converter_set_config (convert, config);
2319
2320 convert->in_maxwidth = GST_VIDEO_INFO_WIDTH (in_info);
2321 convert->in_maxheight = GST_VIDEO_INFO_HEIGHT (in_info);
2322 convert->out_maxwidth = GST_VIDEO_INFO_WIDTH (out_info);
2323 convert->out_maxheight = GST_VIDEO_INFO_HEIGHT (out_info);
2324
2325 convert->in_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_X, 0);
2326 convert->in_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_Y, 0);
2327 convert->in_x &= ~((1 << fin->w_sub[1]) - 1);
2328 convert->in_y &= ~((1 << fin->h_sub[1]) - 1);
2329
2330 convert->in_width = get_opt_int (convert,
2331 GST_VIDEO_CONVERTER_OPT_SRC_WIDTH, convert->in_maxwidth - convert->in_x);
2332 convert->in_height = get_opt_int (convert,
2333 GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT,
2334 convert->in_maxheight - convert->in_y);
2335
2336 convert->in_width =
2337 MIN (convert->in_width, convert->in_maxwidth - convert->in_x);
2338 convert->in_height =
2339 MIN (convert->in_height, convert->in_maxheight - convert->in_y);
2340
2341 convert->out_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_X, 0);
2342 convert->out_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_Y, 0);
2343 convert->out_x &= ~((1 << fout->w_sub[1]) - 1);
2344 convert->out_y &= ~((1 << fout->h_sub[1]) - 1);
2345
2346 convert->out_width = get_opt_int (convert,
2347 GST_VIDEO_CONVERTER_OPT_DEST_WIDTH,
2348 convert->out_maxwidth - convert->out_x);
2349 convert->out_height =
2350 get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT,
2351 convert->out_maxheight - convert->out_y);
2352
2353 convert->out_width =
2354 MIN (convert->out_width, convert->out_maxwidth - convert->out_x);
2355 convert->out_height =
2356 MIN (convert->out_height, convert->out_maxheight - convert->out_y);
2357
2358 convert->fill_border = GET_OPT_FILL_BORDER (convert);
2359 convert->border_argb = get_opt_uint (convert,
2360 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB);
2361
2362 alpha_value = GET_OPT_ALPHA_VALUE (convert);
2363 convert->alpha_value = 255 * alpha_value;
2364 convert->alpha_mode = convert_get_alpha_mode (convert);
2365
2366 convert->unpack_format = in_info->finfo->unpack_format;
2367 finfo = gst_video_format_get_info (convert->unpack_format);
2368 convert->unpack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2369 convert->unpack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2370 if (convert->unpack_rgb
2371 && in_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2372 /* force identity matrix for RGB input */
2373 GST_WARNING ("invalid matrix %d for input RGB format, using RGB",
2374 in_info->colorimetry.matrix);
2375 convert->in_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2376 }
2377
2378 convert->pack_format = out_info->finfo->unpack_format;
2379 finfo = gst_video_format_get_info (convert->pack_format);
2380 convert->pack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2381 convert->pack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2382 convert->pack_pal =
2383 gst_video_format_get_palette (GST_VIDEO_INFO_FORMAT (out_info),
2384 &convert->pack_palsize);
2385 if (convert->pack_rgb
2386 && out_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2387 /* force identity matrix for RGB output */
2388 GST_WARNING ("invalid matrix %d for output RGB format, using RGB",
2389 out_info->colorimetry.matrix);
2390 convert->out_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2391 }
2392
2393 n_threads = get_opt_uint (convert, GST_VIDEO_CONVERTER_OPT_THREADS, 1);
2394 if (n_threads == 0 || n_threads > g_get_num_processors ())
2395 n_threads = g_get_num_processors ();
2396 /* Magic number of 200 lines */
2397 if (MAX (convert->out_height, convert->in_height) / n_threads < 200)
2398 n_threads = (MAX (convert->out_height, convert->in_height) + 199) / 200;
2399 convert->conversion_runner = gst_parallelized_task_runner_new (n_threads);
2400
2401 if (video_converter_lookup_fastpath (convert))
2402 goto done;
2403
2404 if (in_info->finfo->unpack_func == NULL)
2405 goto no_unpack_func;
2406
2407 if (out_info->finfo->pack_func == NULL)
2408 goto no_pack_func;
2409
2410 convert->convert = video_converter_generic;
2411
2412 convert->upsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2413 convert->upsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2414 convert->downsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2415 convert->downsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2416 convert->v_scaler_p = g_new0 (GstVideoScaler *, n_threads);
2417 convert->v_scaler_i = g_new0 (GstVideoScaler *, n_threads);
2418 convert->h_scaler = g_new0 (GstVideoScaler *, n_threads);
2419 convert->unpack_lines = g_new0 (GstLineCache *, n_threads);
2420 convert->pack_lines = g_new0 (GstLineCache *, n_threads);
2421 convert->upsample_lines = g_new0 (GstLineCache *, n_threads);
2422 convert->to_RGB_lines = g_new0 (GstLineCache *, n_threads);
2423 convert->hscale_lines = g_new0 (GstLineCache *, n_threads);
2424 convert->vscale_lines = g_new0 (GstLineCache *, n_threads);
2425 convert->convert_lines = g_new0 (GstLineCache *, n_threads);
2426 convert->alpha_lines = g_new0 (GstLineCache *, n_threads);
2427 convert->to_YUV_lines = g_new0 (GstLineCache *, n_threads);
2428 convert->downsample_lines = g_new0 (GstLineCache *, n_threads);
2429 convert->dither_lines = g_new0 (GstLineCache *, n_threads);
2430 convert->dither = g_new0 (GstVideoDither *, n_threads);
2431
2432 for (i = 0; i < n_threads; i++) {
2433 convert->current_format = GST_VIDEO_INFO_FORMAT (in_info);
2434 convert->current_width = convert->in_width;
2435 convert->current_height = convert->in_height;
2436
2437 /* unpack */
2438 prev = chain_unpack_line (convert, i);
2439 /* upsample chroma */
2440 prev = chain_upsample (convert, prev, i);
2441 /* convert to gamma decoded RGB */
2442 prev = chain_convert_to_RGB (convert, prev, i);
2443 /* do all downscaling */
2444 prev = chain_scale (convert, prev, FALSE, i);
2445 /* do conversion between color spaces */
2446 prev = chain_convert (convert, prev, i);
2447 /* do alpha channels */
2448 prev = chain_alpha (convert, prev, i);
2449 /* do all remaining (up)scaling */
2450 prev = chain_scale (convert, prev, TRUE, i);
2451 /* convert to gamma encoded Y'Cb'Cr' */
2452 prev = chain_convert_to_YUV (convert, prev, i);
2453 /* downsample chroma */
2454 prev = chain_downsample (convert, prev, i);
2455 /* dither */
2456 prev = chain_dither (convert, prev, i);
2457 /* pack into final format */
2458 convert->pack_lines[i] = chain_pack (convert, prev, i);
2459 }
2460
2461 setup_borderline (convert);
2462 /* now figure out allocators */
2463 setup_allocators (convert);
2464
2465 done:
2466 return convert;
2467
2468 /* ERRORS */
2469 no_unpack_func:
2470 {
2471 GST_ERROR ("no unpack_func for format %s",
2472 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
2473 gst_video_converter_free (convert);
2474 return NULL;
2475 }
2476 no_pack_func:
2477 {
2478 GST_ERROR ("no pack_func for format %s",
2479 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
2480 gst_video_converter_free (convert);
2481 return NULL;
2482 }
2483 }
2484
2485 static void
clear_matrix_data(MatrixData * data)2486 clear_matrix_data (MatrixData * data)
2487 {
2488 g_free (data->t_r);
2489 g_free (data->t_g);
2490 g_free (data->t_b);
2491 }
2492
2493 /**
2494 * gst_video_converter_free:
2495 * @convert: a #GstVideoConverter
2496 *
2497 * Free @convert
2498 *
2499 * Since: 1.6
2500 */
2501 void
gst_video_converter_free(GstVideoConverter * convert)2502 gst_video_converter_free (GstVideoConverter * convert)
2503 {
2504 guint i, j;
2505
2506 g_return_if_fail (convert != NULL);
2507
2508 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2509 if (convert->upsample_p && convert->upsample_p[i])
2510 gst_video_chroma_resample_free (convert->upsample_p[i]);
2511 if (convert->upsample_i && convert->upsample_i[i])
2512 gst_video_chroma_resample_free (convert->upsample_i[i]);
2513 if (convert->downsample_p && convert->downsample_p[i])
2514 gst_video_chroma_resample_free (convert->downsample_p[i]);
2515 if (convert->downsample_i && convert->downsample_i[i])
2516 gst_video_chroma_resample_free (convert->downsample_i[i]);
2517 if (convert->v_scaler_p && convert->v_scaler_p[i])
2518 gst_video_scaler_free (convert->v_scaler_p[i]);
2519 if (convert->v_scaler_i && convert->v_scaler_i[i])
2520 gst_video_scaler_free (convert->v_scaler_i[i]);
2521 if (convert->h_scaler && convert->h_scaler[i])
2522 gst_video_scaler_free (convert->h_scaler[i]);
2523 if (convert->unpack_lines && convert->unpack_lines[i])
2524 gst_line_cache_free (convert->unpack_lines[i]);
2525 if (convert->upsample_lines && convert->upsample_lines[i])
2526 gst_line_cache_free (convert->upsample_lines[i]);
2527 if (convert->to_RGB_lines && convert->to_RGB_lines[i])
2528 gst_line_cache_free (convert->to_RGB_lines[i]);
2529 if (convert->hscale_lines && convert->hscale_lines[i])
2530 gst_line_cache_free (convert->hscale_lines[i]);
2531 if (convert->vscale_lines && convert->vscale_lines[i])
2532 gst_line_cache_free (convert->vscale_lines[i]);
2533 if (convert->convert_lines && convert->convert_lines[i])
2534 gst_line_cache_free (convert->convert_lines[i]);
2535 if (convert->alpha_lines && convert->alpha_lines[i])
2536 gst_line_cache_free (convert->alpha_lines[i]);
2537 if (convert->to_YUV_lines && convert->to_YUV_lines[i])
2538 gst_line_cache_free (convert->to_YUV_lines[i]);
2539 if (convert->downsample_lines && convert->downsample_lines[i])
2540 gst_line_cache_free (convert->downsample_lines[i]);
2541 if (convert->dither_lines && convert->dither_lines[i])
2542 gst_line_cache_free (convert->dither_lines[i]);
2543 if (convert->dither && convert->dither[i])
2544 gst_video_dither_free (convert->dither[i]);
2545 }
2546 g_free (convert->upsample_p);
2547 g_free (convert->upsample_i);
2548 g_free (convert->downsample_p);
2549 g_free (convert->downsample_i);
2550 g_free (convert->v_scaler_p);
2551 g_free (convert->v_scaler_i);
2552 g_free (convert->h_scaler);
2553 g_free (convert->unpack_lines);
2554 g_free (convert->pack_lines);
2555 g_free (convert->upsample_lines);
2556 g_free (convert->to_RGB_lines);
2557 g_free (convert->hscale_lines);
2558 g_free (convert->vscale_lines);
2559 g_free (convert->convert_lines);
2560 g_free (convert->alpha_lines);
2561 g_free (convert->to_YUV_lines);
2562 g_free (convert->downsample_lines);
2563 g_free (convert->dither_lines);
2564 g_free (convert->dither);
2565
2566 g_free (convert->gamma_dec.gamma_table);
2567 g_free (convert->gamma_enc.gamma_table);
2568
2569 if (convert->tmpline) {
2570 for (i = 0; i < convert->conversion_runner->n_threads; i++)
2571 g_free (convert->tmpline[i]);
2572 g_free (convert->tmpline);
2573 }
2574
2575 g_free (convert->borderline);
2576
2577 if (convert->config)
2578 gst_structure_free (convert->config);
2579
2580 for (i = 0; i < 4; i++) {
2581 for (j = 0; j < convert->conversion_runner->n_threads; j++) {
2582 if (convert->fv_scaler[i].scaler)
2583 gst_video_scaler_free (convert->fv_scaler[i].scaler[j]);
2584 if (convert->fh_scaler[i].scaler)
2585 gst_video_scaler_free (convert->fh_scaler[i].scaler[j]);
2586 }
2587 g_free (convert->fv_scaler[i].scaler);
2588 g_free (convert->fh_scaler[i].scaler);
2589 }
2590
2591 if (convert->conversion_runner)
2592 gst_parallelized_task_runner_free (convert->conversion_runner);
2593
2594 clear_matrix_data (&convert->to_RGB_matrix);
2595 clear_matrix_data (&convert->convert_matrix);
2596 clear_matrix_data (&convert->to_YUV_matrix);
2597
2598 g_slice_free (GstVideoConverter, convert);
2599 }
2600
2601 static gboolean
copy_config(GQuark field_id,const GValue * value,gpointer user_data)2602 copy_config (GQuark field_id, const GValue * value, gpointer user_data)
2603 {
2604 GstVideoConverter *convert = user_data;
2605
2606 gst_structure_id_set_value (convert->config, field_id, value);
2607
2608 return TRUE;
2609 }
2610
2611 /**
2612 * gst_video_converter_set_config:
2613 * @convert: a #GstVideoConverter
2614 * @config: (transfer full): a #GstStructure
2615 *
2616 * Set @config as extra configuraion for @convert.
2617 *
2618 * If the parameters in @config can not be set exactly, this function returns
2619 * %FALSE and will try to update as much state as possible. The new state can
2620 * then be retrieved and refined with gst_video_converter_get_config().
2621 *
2622 * Look at the #GST_VIDEO_CONVERTER_OPT_* fields to check valid configuration
2623 * option and values.
2624 *
2625 * Returns: %TRUE when @config could be set.
2626 *
2627 * Since: 1.6
2628 */
2629 gboolean
gst_video_converter_set_config(GstVideoConverter * convert,GstStructure * config)2630 gst_video_converter_set_config (GstVideoConverter * convert,
2631 GstStructure * config)
2632 {
2633 g_return_val_if_fail (convert != NULL, FALSE);
2634 g_return_val_if_fail (config != NULL, FALSE);
2635
2636 gst_structure_foreach (config, copy_config, convert);
2637 gst_structure_free (config);
2638
2639 return TRUE;
2640 }
2641
2642 /**
2643 * gst_video_converter_get_config:
2644 * @convert: a #GstVideoConverter
2645 *
2646 * Get the current configuration of @convert.
2647 *
2648 * Returns: a #GstStructure that remains valid for as long as @convert is valid
2649 * or until gst_video_converter_set_config() is called.
2650 */
2651 const GstStructure *
gst_video_converter_get_config(GstVideoConverter * convert)2652 gst_video_converter_get_config (GstVideoConverter * convert)
2653 {
2654 g_return_val_if_fail (convert != NULL, NULL);
2655
2656 return convert->config;
2657 }
2658
2659 /**
2660 * gst_video_converter_frame:
2661 * @convert: a #GstVideoConverter
2662 * @dest: a #GstVideoFrame
2663 * @src: a #GstVideoFrame
2664 *
2665 * Convert the pixels of @src into @dest using @convert.
2666 *
2667 * Since: 1.6
2668 */
2669 void
gst_video_converter_frame(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)2670 gst_video_converter_frame (GstVideoConverter * convert,
2671 const GstVideoFrame * src, GstVideoFrame * dest)
2672 {
2673 g_return_if_fail (convert != NULL);
2674 g_return_if_fail (src != NULL);
2675 g_return_if_fail (dest != NULL);
2676
2677 convert->convert (convert, src, dest);
2678 }
2679
2680 static void
video_converter_compute_matrix(GstVideoConverter * convert)2681 video_converter_compute_matrix (GstVideoConverter * convert)
2682 {
2683 MatrixData *dst = &convert->convert_matrix;
2684
2685 color_matrix_set_identity (dst);
2686 compute_matrix_to_RGB (convert, dst);
2687 compute_matrix_to_YUV (convert, dst, FALSE);
2688
2689 convert->current_bits = 8;
2690 prepare_matrix (convert, dst);
2691 }
2692
2693 static void
video_converter_compute_resample(GstVideoConverter * convert,gint idx)2694 video_converter_compute_resample (GstVideoConverter * convert, gint idx)
2695 {
2696 GstVideoInfo *in_info, *out_info;
2697 const GstVideoFormatInfo *sfinfo, *dfinfo;
2698
2699 if (CHECK_CHROMA_NONE (convert))
2700 return;
2701
2702 in_info = &convert->in_info;
2703 out_info = &convert->out_info;
2704
2705 sfinfo = in_info->finfo;
2706 dfinfo = out_info->finfo;
2707
2708 GST_DEBUG ("site: %d->%d, w_sub: %d->%d, h_sub: %d->%d", in_info->chroma_site,
2709 out_info->chroma_site, sfinfo->w_sub[2], dfinfo->w_sub[2],
2710 sfinfo->h_sub[2], dfinfo->h_sub[2]);
2711
2712 if (sfinfo->w_sub[2] != dfinfo->w_sub[2] ||
2713 sfinfo->h_sub[2] != dfinfo->h_sub[2] ||
2714 in_info->chroma_site != out_info->chroma_site ||
2715 in_info->width != out_info->width ||
2716 in_info->height != out_info->height) {
2717 if (GST_VIDEO_INFO_IS_INTERLACED (in_info)) {
2718 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2719 convert->upsample_i[idx] = gst_video_chroma_resample_new (0,
2720 in_info->chroma_site, GST_VIDEO_CHROMA_FLAG_INTERLACED,
2721 sfinfo->unpack_format, sfinfo->w_sub[2], sfinfo->h_sub[2]);
2722 if (!CHECK_CHROMA_UPSAMPLE (convert))
2723 convert->downsample_i[idx] =
2724 gst_video_chroma_resample_new (0, out_info->chroma_site,
2725 GST_VIDEO_CHROMA_FLAG_INTERLACED, dfinfo->unpack_format,
2726 -dfinfo->w_sub[2], -dfinfo->h_sub[2]);
2727 }
2728 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2729 convert->upsample_p[idx] = gst_video_chroma_resample_new (0,
2730 in_info->chroma_site, 0, sfinfo->unpack_format, sfinfo->w_sub[2],
2731 sfinfo->h_sub[2]);
2732 if (!CHECK_CHROMA_UPSAMPLE (convert))
2733 convert->downsample_p[idx] = gst_video_chroma_resample_new (0,
2734 out_info->chroma_site, 0, dfinfo->unpack_format, -dfinfo->w_sub[2],
2735 -dfinfo->h_sub[2]);
2736 }
2737 }
2738
2739 #define FRAME_GET_PLANE_STRIDE(frame, plane) \
2740 GST_VIDEO_FRAME_PLANE_STRIDE (frame, plane)
2741 #define FRAME_GET_PLANE_LINE(frame, plane, line) \
2742 (gpointer)(((guint8*)(GST_VIDEO_FRAME_PLANE_DATA (frame, plane))) + \
2743 FRAME_GET_PLANE_STRIDE (frame, plane) * (line))
2744
2745 #define FRAME_GET_COMP_STRIDE(frame, comp) \
2746 GST_VIDEO_FRAME_COMP_STRIDE (frame, comp)
2747 #define FRAME_GET_COMP_LINE(frame, comp, line) \
2748 (gpointer)(((guint8*)(GST_VIDEO_FRAME_COMP_DATA (frame, comp))) + \
2749 FRAME_GET_COMP_STRIDE (frame, comp) * (line))
2750
2751 #define FRAME_GET_STRIDE(frame) FRAME_GET_PLANE_STRIDE (frame, 0)
2752 #define FRAME_GET_LINE(frame,line) FRAME_GET_PLANE_LINE (frame, 0, line)
2753
2754 #define FRAME_GET_Y_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_Y, line)
2755 #define FRAME_GET_U_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_U, line)
2756 #define FRAME_GET_V_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_V, line)
2757 #define FRAME_GET_A_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_A, line)
2758
2759 #define FRAME_GET_Y_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_Y)
2760 #define FRAME_GET_U_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_U)
2761 #define FRAME_GET_V_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_V)
2762 #define FRAME_GET_A_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_A)
2763
2764
2765 #define UNPACK_FRAME(frame,dest,line,x,width) \
2766 frame->info.finfo->unpack_func (frame->info.finfo, \
2767 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2768 GST_VIDEO_PACK_FLAG_INTERLACED : \
2769 GST_VIDEO_PACK_FLAG_NONE), \
2770 dest, frame->data, frame->info.stride, x, \
2771 line, width)
2772 #define PACK_FRAME(frame,src,line,width) \
2773 frame->info.finfo->pack_func (frame->info.finfo, \
2774 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2775 GST_VIDEO_PACK_FLAG_INTERLACED : \
2776 GST_VIDEO_PACK_FLAG_NONE), \
2777 src, 0, frame->data, frame->info.stride, \
2778 frame->info.chroma_site, line, width);
2779
2780 static gpointer
get_dest_line(GstLineCache * cache,gint idx,gpointer user_data)2781 get_dest_line (GstLineCache * cache, gint idx, gpointer user_data)
2782 {
2783 GstVideoConverter *convert = user_data;
2784 guint8 *line;
2785 gint pstride = convert->pack_pstride;
2786 gint out_x = convert->out_x;
2787 guint cline;
2788
2789 cline = CLAMP (idx, 0, convert->out_maxheight - 1);
2790
2791 line = FRAME_GET_LINE (convert->dest, cline);
2792 GST_DEBUG ("get dest line %d %p", cline, line);
2793
2794 if (convert->borderline) {
2795 gint r_border = (out_x + convert->out_width) * pstride;
2796 gint rb_width = convert->out_maxwidth * pstride - r_border;
2797 gint lb_width = out_x * pstride;
2798
2799 memcpy (line, convert->borderline, lb_width);
2800 memcpy (line + r_border, convert->borderline, rb_width);
2801 }
2802 line += out_x * pstride;
2803
2804 return line;
2805 }
2806
2807 static gboolean
do_unpack_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)2808 do_unpack_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2809 gpointer user_data)
2810 {
2811 GstVideoConverter *convert = user_data;
2812 gpointer tmpline;
2813 guint cline;
2814
2815 cline = CLAMP (in_line + convert->in_y, 0, convert->in_maxheight - 1);
2816
2817 if (cache->alloc_writable || !convert->identity_unpack) {
2818 tmpline = gst_line_cache_alloc_line (cache, out_line);
2819 GST_DEBUG ("unpack line %d (%u) %p", in_line, cline, tmpline);
2820 UNPACK_FRAME (convert->src, tmpline, cline, convert->in_x,
2821 convert->in_width);
2822 } else {
2823 tmpline = ((guint8 *) FRAME_GET_LINE (convert->src, cline)) +
2824 convert->in_x * convert->unpack_pstride;
2825 GST_DEBUG ("get src line %d (%u) %p", in_line, cline, tmpline);
2826 }
2827 gst_line_cache_add_line (cache, in_line, tmpline);
2828
2829 return TRUE;
2830 }
2831
2832 static gboolean
do_upsample_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)2833 do_upsample_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2834 gpointer user_data)
2835 {
2836 GstVideoConverter *convert = user_data;
2837 gpointer *lines;
2838 gint i, start_line, n_lines;
2839
2840 n_lines = convert->up_n_lines;
2841 start_line = in_line;
2842 if (start_line < n_lines + convert->up_offset) {
2843 start_line += convert->up_offset;
2844 out_line += convert->up_offset;
2845 }
2846
2847 /* get the lines needed for chroma upsample */
2848 lines =
2849 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
2850 n_lines);
2851
2852 if (convert->upsample) {
2853 GST_DEBUG ("doing upsample %d-%d %p", start_line, start_line + n_lines - 1,
2854 lines[0]);
2855 gst_video_chroma_resample (convert->upsample[idx], lines,
2856 convert->in_width);
2857 }
2858
2859 for (i = 0; i < n_lines; i++)
2860 gst_line_cache_add_line (cache, start_line + i, lines[i]);
2861
2862 return TRUE;
2863 }
2864
2865 static gboolean
do_convert_to_RGB_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)2866 do_convert_to_RGB_lines (GstLineCache * cache, gint idx, gint out_line,
2867 gint in_line, gpointer user_data)
2868 {
2869 GstVideoConverter *convert = user_data;
2870 MatrixData *data = &convert->to_RGB_matrix;
2871 gpointer *lines, destline;
2872
2873 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2874 destline = lines[0];
2875
2876 if (data->matrix_func) {
2877 GST_DEBUG ("to RGB line %d %p", in_line, destline);
2878 data->matrix_func (data, destline);
2879 }
2880 if (convert->gamma_dec.gamma_func) {
2881 destline = gst_line_cache_alloc_line (cache, out_line);
2882
2883 GST_DEBUG ("gamma decode line %d %p->%p", in_line, lines[0], destline);
2884 convert->gamma_dec.gamma_func (&convert->gamma_dec, destline, lines[0]);
2885 }
2886 gst_line_cache_add_line (cache, in_line, destline);
2887
2888 return TRUE;
2889 }
2890
2891 static gboolean
do_hscale_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)2892 do_hscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2893 gpointer user_data)
2894 {
2895 GstVideoConverter *convert = user_data;
2896 gpointer *lines, destline;
2897
2898 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2899
2900 destline = gst_line_cache_alloc_line (cache, out_line);
2901
2902 GST_DEBUG ("hresample line %d %p->%p", in_line, lines[0], destline);
2903 gst_video_scaler_horizontal (convert->h_scaler[idx], convert->h_scale_format,
2904 lines[0], destline, 0, convert->out_width);
2905
2906 gst_line_cache_add_line (cache, in_line, destline);
2907
2908 return TRUE;
2909 }
2910
2911 static gboolean
do_vscale_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)2912 do_vscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2913 gpointer user_data)
2914 {
2915 GstVideoConverter *convert = user_data;
2916 gpointer *lines, destline;
2917 guint sline, n_lines;
2918 guint cline;
2919
2920 cline = CLAMP (in_line, 0, convert->out_height - 1);
2921
2922 gst_video_scaler_get_coeff (convert->v_scaler[idx], cline, &sline, &n_lines);
2923 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, sline, n_lines);
2924
2925 destline = gst_line_cache_alloc_line (cache, out_line);
2926
2927 GST_DEBUG ("vresample line %d %d-%d %p->%p", in_line, sline,
2928 sline + n_lines - 1, lines[0], destline);
2929 gst_video_scaler_vertical (convert->v_scaler[idx], convert->v_scale_format,
2930 lines, destline, cline, convert->v_scale_width);
2931
2932 gst_line_cache_add_line (cache, in_line, destline);
2933
2934 return TRUE;
2935 }
2936
2937 static gboolean
do_convert_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)2938 do_convert_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2939 gpointer user_data)
2940 {
2941 GstVideoConverter *convert = user_data;
2942 MatrixData *data = &convert->convert_matrix;
2943 gpointer *lines, destline;
2944 guint in_bits, out_bits;
2945 gint width;
2946
2947 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2948
2949 destline = lines[0];
2950
2951 in_bits = convert->in_bits;
2952 out_bits = convert->out_bits;
2953
2954 width = MIN (convert->in_width, convert->out_width);
2955
2956 if (out_bits == 16 || in_bits == 16) {
2957 gpointer srcline = lines[0];
2958
2959 if (out_bits != in_bits)
2960 destline = gst_line_cache_alloc_line (cache, out_line);
2961
2962 /* FIXME, we can scale in the conversion matrix */
2963 if (in_bits == 8) {
2964 GST_DEBUG ("8->16 line %d %p->%p", in_line, srcline, destline);
2965 video_orc_convert_u8_to_u16 (destline, srcline, width * 4);
2966 srcline = destline;
2967 }
2968
2969 if (data->matrix_func) {
2970 GST_DEBUG ("matrix line %d %p", in_line, srcline);
2971 data->matrix_func (data, srcline);
2972 }
2973
2974 /* FIXME, dither here */
2975 if (out_bits == 8) {
2976 GST_DEBUG ("16->8 line %d %p->%p", in_line, srcline, destline);
2977 video_orc_convert_u16_to_u8 (destline, srcline, width * 4);
2978 }
2979 } else {
2980 if (data->matrix_func) {
2981 GST_DEBUG ("matrix line %d %p", in_line, destline);
2982 data->matrix_func (data, destline);
2983 }
2984 }
2985 gst_line_cache_add_line (cache, in_line, destline);
2986
2987 return TRUE;
2988 }
2989
2990 static gboolean
do_alpha_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)2991 do_alpha_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2992 gpointer user_data)
2993 {
2994 gpointer *lines, destline;
2995 GstVideoConverter *convert = user_data;
2996 gint width = MIN (convert->in_width, convert->out_width);
2997
2998 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2999 destline = lines[0];
3000
3001 GST_DEBUG ("alpha line %d %p", in_line, destline);
3002 convert->alpha_func (convert, destline, width);
3003
3004 gst_line_cache_add_line (cache, in_line, destline);
3005
3006 return TRUE;
3007 }
3008
3009 static gboolean
do_convert_to_YUV_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3010 do_convert_to_YUV_lines (GstLineCache * cache, gint idx, gint out_line,
3011 gint in_line, gpointer user_data)
3012 {
3013 GstVideoConverter *convert = user_data;
3014 MatrixData *data = &convert->to_YUV_matrix;
3015 gpointer *lines, destline;
3016
3017 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3018 destline = lines[0];
3019
3020 if (convert->gamma_enc.gamma_func) {
3021 destline = gst_line_cache_alloc_line (cache, out_line);
3022
3023 GST_DEBUG ("gamma encode line %d %p->%p", in_line, lines[0], destline);
3024 convert->gamma_enc.gamma_func (&convert->gamma_enc, destline, lines[0]);
3025 }
3026 if (data->matrix_func) {
3027 GST_DEBUG ("to YUV line %d %p", in_line, destline);
3028 data->matrix_func (data, destline);
3029 }
3030 gst_line_cache_add_line (cache, in_line, destline);
3031
3032 return TRUE;
3033 }
3034
3035 static gboolean
do_downsample_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3036 do_downsample_lines (GstLineCache * cache, gint idx, gint out_line,
3037 gint in_line, gpointer user_data)
3038 {
3039 GstVideoConverter *convert = user_data;
3040 gpointer *lines;
3041 gint i, start_line, n_lines;
3042
3043 n_lines = convert->down_n_lines;
3044 start_line = in_line;
3045 if (start_line < n_lines + convert->down_offset)
3046 start_line += convert->down_offset;
3047
3048 /* get the lines needed for chroma downsample */
3049 lines =
3050 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
3051 n_lines);
3052
3053 if (convert->downsample) {
3054 GST_DEBUG ("downsample line %d %d-%d %p", in_line, start_line,
3055 start_line + n_lines - 1, lines[0]);
3056 gst_video_chroma_resample (convert->downsample[idx], lines,
3057 convert->out_width);
3058 }
3059
3060 for (i = 0; i < n_lines; i++)
3061 gst_line_cache_add_line (cache, start_line + i, lines[i]);
3062
3063 return TRUE;
3064 }
3065
3066 static gboolean
do_dither_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3067 do_dither_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3068 gpointer user_data)
3069 {
3070 GstVideoConverter *convert = user_data;
3071 gpointer *lines, destline;
3072
3073 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3074 destline = lines[0];
3075
3076 if (convert->dither) {
3077 GST_DEBUG ("Dither line %d %p", in_line, destline);
3078 gst_video_dither_line (convert->dither[idx], destline, 0, out_line,
3079 convert->out_width);
3080 }
3081 gst_line_cache_add_line (cache, in_line, destline);
3082
3083 return TRUE;
3084 }
3085
3086 typedef struct
3087 {
3088 GstLineCache *pack_lines;
3089 gint idx;
3090 gint h_0, h_1;
3091 gint pack_lines_count;
3092 gint out_y;
3093 gboolean identity_pack;
3094 gint lb_width, out_maxwidth;
3095 GstVideoFrame *dest;
3096 } ConvertTask;
3097
3098 static void
convert_generic_task(ConvertTask * task)3099 convert_generic_task (ConvertTask * task)
3100 {
3101 gint i;
3102
3103 for (i = task->h_0; i < task->h_1; i += task->pack_lines_count) {
3104 gpointer *lines;
3105
3106 /* load the lines needed to pack */
3107 lines =
3108 gst_line_cache_get_lines (task->pack_lines, task->idx, i + task->out_y,
3109 i, task->pack_lines_count);
3110
3111 if (!task->identity_pack) {
3112 /* take away the border */
3113 guint8 *l = ((guint8 *) lines[0]) - task->lb_width;
3114 /* and pack into destination */
3115 GST_DEBUG ("pack line %d %p (%p)", i + task->out_y, lines[0], l);
3116 PACK_FRAME (task->dest, l, i + task->out_y, task->out_maxwidth);
3117 }
3118 }
3119 }
3120
3121 static void
video_converter_generic(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3122 video_converter_generic (GstVideoConverter * convert, const GstVideoFrame * src,
3123 GstVideoFrame * dest)
3124 {
3125 gint i;
3126 gint out_maxwidth, out_maxheight;
3127 gint out_x, out_y, out_height;
3128 gint pack_lines, pstride;
3129 gint lb_width;
3130 ConvertTask *tasks;
3131 ConvertTask **tasks_p;
3132 gint n_threads;
3133 gint lines_per_thread;
3134
3135 out_height = convert->out_height;
3136 out_maxwidth = convert->out_maxwidth;
3137 out_maxheight = convert->out_maxheight;
3138
3139 out_x = convert->out_x;
3140 out_y = convert->out_y;
3141
3142 convert->src = src;
3143 convert->dest = dest;
3144
3145 if (GST_VIDEO_FRAME_IS_INTERLACED (src)) {
3146 GST_DEBUG ("setup interlaced frame");
3147 convert->upsample = convert->upsample_i;
3148 convert->downsample = convert->downsample_i;
3149 convert->v_scaler = convert->v_scaler_i;
3150 } else {
3151 GST_DEBUG ("setup progressive frame");
3152 convert->upsample = convert->upsample_p;
3153 convert->downsample = convert->downsample_p;
3154 convert->v_scaler = convert->v_scaler_p;
3155 }
3156 if (convert->upsample[0]) {
3157 gst_video_chroma_resample_get_info (convert->upsample[0],
3158 &convert->up_n_lines, &convert->up_offset);
3159 } else {
3160 convert->up_n_lines = 1;
3161 convert->up_offset = 0;
3162 }
3163 if (convert->downsample[0]) {
3164 gst_video_chroma_resample_get_info (convert->downsample[0],
3165 &convert->down_n_lines, &convert->down_offset);
3166 } else {
3167 convert->down_n_lines = 1;
3168 convert->down_offset = 0;
3169 }
3170
3171 pack_lines = convert->pack_nlines; /* only 1 for now */
3172 pstride = convert->pack_pstride;
3173
3174 lb_width = out_x * pstride;
3175
3176 if (convert->borderline) {
3177 /* FIXME we should try to avoid PACK_FRAME */
3178 for (i = 0; i < out_y; i++)
3179 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3180 }
3181
3182 n_threads = convert->conversion_runner->n_threads;
3183 tasks = g_newa (ConvertTask, n_threads);
3184 tasks_p = g_newa (ConvertTask *, n_threads);
3185
3186 lines_per_thread =
3187 GST_ROUND_UP_N ((out_height + n_threads - 1) / n_threads, pack_lines);
3188
3189 for (i = 0; i < n_threads; i++) {
3190 tasks[i].dest = dest;
3191 tasks[i].pack_lines = convert->pack_lines[i];
3192 tasks[i].idx = i;
3193 tasks[i].pack_lines_count = pack_lines;
3194 tasks[i].out_y = out_y;
3195 tasks[i].identity_pack = convert->identity_pack;
3196 tasks[i].lb_width = lb_width;
3197 tasks[i].out_maxwidth = out_maxwidth;
3198
3199 tasks[i].h_0 = i * lines_per_thread;
3200 tasks[i].h_1 = MIN ((i + 1) * lines_per_thread, out_height);
3201
3202 tasks_p[i] = &tasks[i];
3203 }
3204
3205 gst_parallelized_task_runner_run (convert->conversion_runner,
3206 (GstParallelizedTaskFunc) convert_generic_task, (gpointer) tasks_p);
3207
3208 if (convert->borderline) {
3209 for (i = out_y + out_height; i < out_maxheight; i++)
3210 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3211 }
3212 if (convert->pack_pal) {
3213 memcpy (GST_VIDEO_FRAME_PLANE_DATA (dest, 1), convert->pack_pal,
3214 convert->pack_palsize);
3215 }
3216 }
3217
3218 static void convert_fill_border (GstVideoConverter * convert,
3219 GstVideoFrame * dest);
3220
3221 /* Fast paths */
3222
3223 #define GET_LINE_OFFSETS(interlaced,line,l1,l2) \
3224 if (interlaced) { \
3225 l1 = (line & 2 ? line - 1 : line); \
3226 l2 = l1 + 2; \
3227 } else { \
3228 l1 = line; \
3229 l2 = l1 + 1; \
3230 }
3231
3232 typedef struct
3233 {
3234 const GstVideoFrame *src;
3235 GstVideoFrame *dest;
3236 gint height_0, height_1;
3237
3238 /* parameters */
3239 gboolean interlaced;
3240 gint width;
3241 gint alpha;
3242 MatrixData *data;
3243 gint in_x, in_y;
3244 gint out_x, out_y;
3245 gpointer tmpline;
3246 } FConvertTask;
3247
3248 static void
convert_I420_YUY2_task(FConvertTask * task)3249 convert_I420_YUY2_task (FConvertTask * task)
3250 {
3251 gint i;
3252 gint l1, l2;
3253
3254 for (i = task->height_0; i < task->height_1; i += 2) {
3255 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3256
3257 video_orc_convert_I420_YUY2 (FRAME_GET_LINE (task->dest, l1),
3258 FRAME_GET_LINE (task->dest, l2),
3259 FRAME_GET_Y_LINE (task->src, l1),
3260 FRAME_GET_Y_LINE (task->src, l2),
3261 FRAME_GET_U_LINE (task->src, i >> 1),
3262 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3263 }
3264 }
3265
3266 static void
convert_I420_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3267 convert_I420_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
3268 GstVideoFrame * dest)
3269 {
3270 int i;
3271 gint width = convert->in_width;
3272 gint height = convert->in_height;
3273 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3274 gint h2;
3275 FConvertTask *tasks;
3276 FConvertTask **tasks_p;
3277 gint n_threads;
3278 gint lines_per_thread;
3279
3280 /* I420 has half as many chroma lines, as such we have to
3281 * always merge two into one. For non-interlaced these are
3282 * the two next to each other, for interlaced one is skipped
3283 * in between. */
3284 if (interlaced)
3285 h2 = GST_ROUND_DOWN_4 (height);
3286 else
3287 h2 = GST_ROUND_DOWN_2 (height);
3288
3289 n_threads = convert->conversion_runner->n_threads;
3290 tasks = g_newa (FConvertTask, n_threads);
3291 tasks_p = g_newa (FConvertTask *, n_threads);
3292
3293 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3294
3295 for (i = 0; i < n_threads; i++) {
3296 tasks[i].src = src;
3297 tasks[i].dest = dest;
3298
3299 tasks[i].interlaced = interlaced;
3300 tasks[i].width = width;
3301
3302 tasks[i].height_0 = i * lines_per_thread;
3303 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3304 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3305
3306 tasks_p[i] = &tasks[i];
3307 }
3308
3309 gst_parallelized_task_runner_run (convert->conversion_runner,
3310 (GstParallelizedTaskFunc) convert_I420_YUY2_task, (gpointer) tasks_p);
3311
3312 /* now handle last lines. For interlaced these are up to 3 */
3313 if (h2 != height) {
3314 for (i = h2; i < height; i++) {
3315 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3316 PACK_FRAME (dest, convert->tmpline[0], i, width);
3317 }
3318 }
3319 }
3320
3321 static void
convert_I420_UYVY_task(FConvertTask * task)3322 convert_I420_UYVY_task (FConvertTask * task)
3323 {
3324 gint i;
3325 gint l1, l2;
3326
3327 for (i = task->height_0; i < task->height_1; i += 2) {
3328 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3329
3330 video_orc_convert_I420_UYVY (FRAME_GET_LINE (task->dest, l1),
3331 FRAME_GET_LINE (task->dest, l2),
3332 FRAME_GET_Y_LINE (task->src, l1),
3333 FRAME_GET_Y_LINE (task->src, l2),
3334 FRAME_GET_U_LINE (task->src, i >> 1),
3335 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3336 }
3337 }
3338
3339 static void
convert_I420_UYVY(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3340 convert_I420_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
3341 GstVideoFrame * dest)
3342 {
3343 int i;
3344 gint width = convert->in_width;
3345 gint height = convert->in_height;
3346 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3347 gint h2;
3348 FConvertTask *tasks;
3349 FConvertTask **tasks_p;
3350 gint n_threads;
3351 gint lines_per_thread;
3352
3353 /* I420 has half as many chroma lines, as such we have to
3354 * always merge two into one. For non-interlaced these are
3355 * the two next to each other, for interlaced one is skipped
3356 * in between. */
3357 if (interlaced)
3358 h2 = GST_ROUND_DOWN_4 (height);
3359 else
3360 h2 = GST_ROUND_DOWN_2 (height);
3361
3362 n_threads = convert->conversion_runner->n_threads;
3363 tasks = g_newa (FConvertTask, n_threads);
3364 tasks_p = g_newa (FConvertTask *, n_threads);
3365
3366 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3367
3368 for (i = 0; i < n_threads; i++) {
3369 tasks[i].src = src;
3370 tasks[i].dest = dest;
3371
3372 tasks[i].interlaced = interlaced;
3373 tasks[i].width = width;
3374
3375 tasks[i].height_0 = i * lines_per_thread;
3376 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3377 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3378
3379 tasks_p[i] = &tasks[i];
3380 }
3381
3382 gst_parallelized_task_runner_run (convert->conversion_runner,
3383 (GstParallelizedTaskFunc) convert_I420_UYVY_task, (gpointer) tasks_p);
3384
3385 /* now handle last lines. For interlaced these are up to 3 */
3386 if (h2 != height) {
3387 for (i = h2; i < height; i++) {
3388 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3389 PACK_FRAME (dest, convert->tmpline[0], i, width);
3390 }
3391 }
3392 }
3393
3394 static void
convert_I420_AYUV_task(FConvertTask * task)3395 convert_I420_AYUV_task (FConvertTask * task)
3396 {
3397 gint i;
3398 gint l1, l2;
3399
3400 for (i = task->height_0; i < task->height_1; i += 2) {
3401 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3402
3403 video_orc_convert_I420_AYUV (FRAME_GET_LINE (task->dest, l1),
3404 FRAME_GET_LINE (task->dest, l2),
3405 FRAME_GET_Y_LINE (task->src, l1),
3406 FRAME_GET_Y_LINE (task->src, l2),
3407 FRAME_GET_U_LINE (task->src, i >> 1), FRAME_GET_V_LINE (task->src,
3408 i >> 1), task->alpha, task->width);
3409 }
3410 }
3411
3412 static void
convert_I420_AYUV(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3413 convert_I420_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3414 GstVideoFrame * dest)
3415 {
3416 int i;
3417 gint width = convert->in_width;
3418 gint height = convert->in_height;
3419 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3420 guint8 alpha = MIN (convert->alpha_value, 255);
3421 gint h2;
3422 FConvertTask *tasks;
3423 FConvertTask **tasks_p;
3424 gint n_threads;
3425 gint lines_per_thread;
3426
3427 /* I420 has half as many chroma lines, as such we have to
3428 * always merge two into one. For non-interlaced these are
3429 * the two next to each other, for interlaced one is skipped
3430 * in between. */
3431 if (interlaced)
3432 h2 = GST_ROUND_DOWN_4 (height);
3433 else
3434 h2 = GST_ROUND_DOWN_2 (height);
3435
3436
3437 n_threads = convert->conversion_runner->n_threads;
3438 tasks = g_newa (FConvertTask, n_threads);
3439 tasks_p = g_newa (FConvertTask *, n_threads);
3440
3441 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3442
3443 for (i = 0; i < n_threads; i++) {
3444 tasks[i].src = src;
3445 tasks[i].dest = dest;
3446
3447 tasks[i].interlaced = interlaced;
3448 tasks[i].width = width;
3449 tasks[i].alpha = alpha;
3450
3451 tasks[i].height_0 = i * lines_per_thread;
3452 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3453 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3454
3455 tasks_p[i] = &tasks[i];
3456 }
3457
3458 gst_parallelized_task_runner_run (convert->conversion_runner,
3459 (GstParallelizedTaskFunc) convert_I420_AYUV_task, (gpointer) tasks_p);
3460
3461 /* now handle last lines. For interlaced these are up to 3 */
3462 if (h2 != height) {
3463 for (i = h2; i < height; i++) {
3464 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3465 if (alpha != 0xff)
3466 convert_set_alpha_u8 (convert, convert->tmpline[0], width);
3467 PACK_FRAME (dest, convert->tmpline[0], i, width);
3468 }
3469 }
3470 }
3471
3472 static void
convert_YUY2_I420_task(FConvertTask * task)3473 convert_YUY2_I420_task (FConvertTask * task)
3474 {
3475 gint i;
3476 gint l1, l2;
3477
3478 for (i = task->height_0; i < task->height_1; i += 2) {
3479 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3480
3481 video_orc_convert_YUY2_I420 (FRAME_GET_Y_LINE (task->dest, l1),
3482 FRAME_GET_Y_LINE (task->dest, l2),
3483 FRAME_GET_U_LINE (task->dest, i >> 1),
3484 FRAME_GET_V_LINE (task->dest, i >> 1),
3485 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
3486 (task->width + 1) / 2);
3487 }
3488 }
3489
3490 static void
convert_YUY2_I420(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3491 convert_YUY2_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3492 GstVideoFrame * dest)
3493 {
3494 int i;
3495 gint width = convert->in_width;
3496 gint height = convert->in_height;
3497 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3498 gint h2;
3499 FConvertTask *tasks;
3500 FConvertTask **tasks_p;
3501 gint n_threads;
3502 gint lines_per_thread;
3503
3504 /* I420 has half as many chroma lines, as such we have to
3505 * always merge two into one. For non-interlaced these are
3506 * the two next to each other, for interlaced one is skipped
3507 * in between. */
3508 if (interlaced)
3509 h2 = GST_ROUND_DOWN_4 (height);
3510 else
3511 h2 = GST_ROUND_DOWN_2 (height);
3512
3513 n_threads = convert->conversion_runner->n_threads;
3514 tasks = g_newa (FConvertTask, n_threads);
3515 tasks_p = g_newa (FConvertTask *, n_threads);
3516
3517 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3518
3519 for (i = 0; i < n_threads; i++) {
3520 tasks[i].src = src;
3521 tasks[i].dest = dest;
3522
3523 tasks[i].interlaced = interlaced;
3524 tasks[i].width = width;
3525
3526 tasks[i].height_0 = i * lines_per_thread;
3527 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3528 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3529
3530 tasks_p[i] = &tasks[i];
3531 }
3532
3533 gst_parallelized_task_runner_run (convert->conversion_runner,
3534 (GstParallelizedTaskFunc) convert_YUY2_I420_task, (gpointer) tasks_p);
3535
3536 /* now handle last lines. For interlaced these are up to 3 */
3537 if (h2 != height) {
3538 for (i = h2; i < height; i++) {
3539 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3540 PACK_FRAME (dest, convert->tmpline[0], i, width);
3541 }
3542 }
3543 }
3544
3545 typedef struct
3546 {
3547 const guint8 *s, *s2, *su, *sv;
3548 guint8 *d, *d2, *du, *dv;
3549 gint sstride, sustride, svstride;
3550 gint dstride, dustride, dvstride;
3551 gint width, height;
3552 gint alpha;
3553 MatrixData *data;
3554 } FConvertPlaneTask;
3555
3556 static void
convert_YUY2_AYUV_task(FConvertPlaneTask * task)3557 convert_YUY2_AYUV_task (FConvertPlaneTask * task)
3558 {
3559 video_orc_convert_YUY2_AYUV (task->d, task->dstride, task->s,
3560 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
3561 }
3562
3563 static void
convert_YUY2_AYUV(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3564 convert_YUY2_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3565 GstVideoFrame * dest)
3566 {
3567 gint width = convert->in_width;
3568 gint height = convert->in_height;
3569 guint8 *s, *d;
3570 guint8 alpha = MIN (convert->alpha_value, 255);
3571 FConvertPlaneTask *tasks;
3572 FConvertPlaneTask **tasks_p;
3573 gint n_threads;
3574 gint lines_per_thread;
3575 gint i;
3576
3577 s = FRAME_GET_LINE (src, convert->in_y);
3578 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3579 d = FRAME_GET_LINE (dest, convert->out_y);
3580 d += (convert->out_x * 4);
3581
3582 n_threads = convert->conversion_runner->n_threads;
3583 tasks = g_newa (FConvertPlaneTask, n_threads);
3584 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3585
3586 lines_per_thread = (height + n_threads - 1) / n_threads;
3587
3588 for (i = 0; i < n_threads; i++) {
3589 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3590 tasks[i].sstride = FRAME_GET_STRIDE (src);
3591 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3592 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3593
3594 tasks[i].width = width;
3595 tasks[i].height = (i + 1) * lines_per_thread;
3596 tasks[i].height = MIN (tasks[i].height, height);
3597 tasks[i].height -= i * lines_per_thread;
3598 tasks[i].alpha = alpha;
3599
3600 tasks_p[i] = &tasks[i];
3601 }
3602
3603 gst_parallelized_task_runner_run (convert->conversion_runner,
3604 (GstParallelizedTaskFunc) convert_YUY2_AYUV_task, (gpointer) tasks_p);
3605
3606 convert_fill_border (convert, dest);
3607 }
3608
3609 static void
convert_YUY2_Y42B_task(FConvertPlaneTask * task)3610 convert_YUY2_Y42B_task (FConvertPlaneTask * task)
3611 {
3612 video_orc_convert_YUY2_Y42B (task->d, task->dstride, task->du,
3613 task->dustride, task->dv, task->dvstride,
3614 task->s, task->sstride, (task->width + 1) / 2, task->height);
3615 }
3616
3617 static void
convert_YUY2_Y42B(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3618 convert_YUY2_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
3619 GstVideoFrame * dest)
3620 {
3621 gint width = convert->in_width;
3622 gint height = convert->in_height;
3623 guint8 *s, *dy, *du, *dv;
3624 FConvertPlaneTask *tasks;
3625 FConvertPlaneTask **tasks_p;
3626 gint n_threads;
3627 gint lines_per_thread;
3628 gint i;
3629
3630 s = FRAME_GET_LINE (src, convert->in_y);
3631 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3632
3633 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3634 dy += convert->out_x;
3635 du = FRAME_GET_U_LINE (dest, convert->out_y);
3636 du += convert->out_x >> 1;
3637 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3638 dv += convert->out_x >> 1;
3639
3640 n_threads = convert->conversion_runner->n_threads;
3641 tasks = g_newa (FConvertPlaneTask, n_threads);
3642 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3643
3644 lines_per_thread = (height + n_threads - 1) / n_threads;
3645
3646 for (i = 0; i < n_threads; i++) {
3647 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3648 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3649 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3650 tasks[i].sstride = FRAME_GET_STRIDE (src);
3651 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3652 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3653 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3654 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3655
3656 tasks[i].width = width;
3657 tasks[i].height = (i + 1) * lines_per_thread;
3658 tasks[i].height = MIN (tasks[i].height, height);
3659 tasks[i].height -= i * lines_per_thread;
3660
3661 tasks_p[i] = &tasks[i];
3662 }
3663
3664 gst_parallelized_task_runner_run (convert->conversion_runner,
3665 (GstParallelizedTaskFunc) convert_YUY2_Y42B_task, (gpointer) tasks_p);
3666
3667 convert_fill_border (convert, dest);
3668 }
3669
3670 static void
convert_YUY2_Y444_task(FConvertPlaneTask * task)3671 convert_YUY2_Y444_task (FConvertPlaneTask * task)
3672 {
3673 video_orc_convert_YUY2_Y444 (task->d,
3674 task->dstride, task->du,
3675 task->dustride, task->dv,
3676 task->dvstride, task->s,
3677 task->sstride, (task->width + 1) / 2, task->height);
3678 }
3679
3680 static void
convert_YUY2_Y444(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3681 convert_YUY2_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
3682 GstVideoFrame * dest)
3683 {
3684 gint width = convert->in_width;
3685 gint height = convert->in_height;
3686 guint8 *s, *dy, *du, *dv;
3687 FConvertPlaneTask *tasks;
3688 FConvertPlaneTask **tasks_p;
3689 gint n_threads;
3690 gint lines_per_thread;
3691 gint i;
3692
3693 s = FRAME_GET_LINE (src, convert->in_y);
3694 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3695
3696 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3697 dy += convert->out_x;
3698 du = FRAME_GET_U_LINE (dest, convert->out_y);
3699 du += convert->out_x;
3700 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3701 dv += convert->out_x;
3702
3703 n_threads = convert->conversion_runner->n_threads;
3704 tasks = g_newa (FConvertPlaneTask, n_threads);
3705 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3706
3707 lines_per_thread = (height + n_threads - 1) / n_threads;
3708
3709 for (i = 0; i < n_threads; i++) {
3710 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3711 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3712 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3713 tasks[i].sstride = FRAME_GET_STRIDE (src);
3714 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3715 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3716 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3717 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3718
3719 tasks[i].width = width;
3720 tasks[i].height = (i + 1) * lines_per_thread;
3721 tasks[i].height = MIN (tasks[i].height, height);
3722 tasks[i].height -= i * lines_per_thread;
3723
3724 tasks_p[i] = &tasks[i];
3725 }
3726
3727 gst_parallelized_task_runner_run (convert->conversion_runner,
3728 (GstParallelizedTaskFunc) convert_YUY2_Y444_task, (gpointer) tasks_p);
3729
3730 convert_fill_border (convert, dest);
3731 }
3732
3733 static void
convert_UYVY_I420_task(FConvertTask * task)3734 convert_UYVY_I420_task (FConvertTask * task)
3735 {
3736 gint i;
3737 gint l1, l2;
3738
3739 for (i = task->height_0; i < task->height_1; i += 2) {
3740 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3741
3742 video_orc_convert_UYVY_I420 (FRAME_GET_COMP_LINE (task->dest, 0, l1),
3743 FRAME_GET_COMP_LINE (task->dest, 0, l2),
3744 FRAME_GET_COMP_LINE (task->dest, 1, i >> 1),
3745 FRAME_GET_COMP_LINE (task->dest, 2, i >> 1),
3746 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
3747 (task->width + 1) / 2);
3748 }
3749 }
3750
3751 static void
convert_UYVY_I420(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3752 convert_UYVY_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3753 GstVideoFrame * dest)
3754 {
3755 int i;
3756 gint width = convert->in_width;
3757 gint height = convert->in_height;
3758 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3759 gint h2;
3760 FConvertTask *tasks;
3761 FConvertTask **tasks_p;
3762 gint n_threads;
3763 gint lines_per_thread;
3764
3765 /* I420 has half as many chroma lines, as such we have to
3766 * always merge two into one. For non-interlaced these are
3767 * the two next to each other, for interlaced one is skipped
3768 * in between. */
3769 if (interlaced)
3770 h2 = GST_ROUND_DOWN_4 (height);
3771 else
3772 h2 = GST_ROUND_DOWN_2 (height);
3773
3774 n_threads = convert->conversion_runner->n_threads;
3775 tasks = g_newa (FConvertTask, n_threads);
3776 tasks_p = g_newa (FConvertTask *, n_threads);
3777
3778 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3779
3780 for (i = 0; i < n_threads; i++) {
3781 tasks[i].src = src;
3782 tasks[i].dest = dest;
3783
3784 tasks[i].interlaced = interlaced;
3785 tasks[i].width = width;
3786
3787 tasks[i].height_0 = i * lines_per_thread;
3788 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3789 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3790
3791 tasks_p[i] = &tasks[i];
3792 }
3793
3794 gst_parallelized_task_runner_run (convert->conversion_runner,
3795 (GstParallelizedTaskFunc) convert_UYVY_I420_task, (gpointer) tasks_p);
3796
3797 /* now handle last lines. For interlaced these are up to 3 */
3798 if (h2 != height) {
3799 for (i = h2; i < height; i++) {
3800 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3801 PACK_FRAME (dest, convert->tmpline[0], i, width);
3802 }
3803 }
3804 }
3805
3806 static void
convert_UYVY_AYUV_task(FConvertPlaneTask * task)3807 convert_UYVY_AYUV_task (FConvertPlaneTask * task)
3808 {
3809 video_orc_convert_UYVY_AYUV (task->d, task->dstride, task->s,
3810 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
3811 }
3812
3813 static void
convert_UYVY_AYUV(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3814 convert_UYVY_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3815 GstVideoFrame * dest)
3816 {
3817 gint width = convert->in_width;
3818 gint height = convert->in_height;
3819 guint8 *s, *d;
3820 guint8 alpha = MIN (convert->alpha_value, 255);
3821 FConvertPlaneTask *tasks;
3822 FConvertPlaneTask **tasks_p;
3823 gint n_threads;
3824 gint lines_per_thread;
3825 gint i;
3826
3827 s = FRAME_GET_LINE (src, convert->in_y);
3828 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3829 d = FRAME_GET_LINE (dest, convert->out_y);
3830 d += (convert->out_x * 4);
3831
3832 n_threads = convert->conversion_runner->n_threads;
3833 tasks = g_newa (FConvertPlaneTask, n_threads);
3834 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3835
3836 lines_per_thread = (height + n_threads - 1) / n_threads;
3837
3838 for (i = 0; i < n_threads; i++) {
3839 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3840 tasks[i].sstride = FRAME_GET_STRIDE (src);
3841 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3842 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3843
3844 tasks[i].width = width;
3845 tasks[i].height = (i + 1) * lines_per_thread;
3846 tasks[i].height = MIN (tasks[i].height, height);
3847 tasks[i].height -= i * lines_per_thread;
3848 tasks[i].alpha = alpha;
3849
3850 tasks_p[i] = &tasks[i];
3851 }
3852
3853 gst_parallelized_task_runner_run (convert->conversion_runner,
3854 (GstParallelizedTaskFunc) convert_UYVY_AYUV_task, (gpointer) tasks_p);
3855
3856 convert_fill_border (convert, dest);
3857 }
3858
3859 static void
convert_UYVY_YUY2_task(FConvertPlaneTask * task)3860 convert_UYVY_YUY2_task (FConvertPlaneTask * task)
3861 {
3862 video_orc_convert_UYVY_YUY2 (task->d, task->dstride, task->s,
3863 task->sstride, (task->width + 1) / 2, task->height);
3864 }
3865
3866 static void
convert_UYVY_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3867 convert_UYVY_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
3868 GstVideoFrame * dest)
3869 {
3870 gint width = convert->in_width;
3871 gint height = convert->in_height;
3872 guint8 *s, *d;
3873 FConvertPlaneTask *tasks;
3874 FConvertPlaneTask **tasks_p;
3875 gint n_threads;
3876 gint lines_per_thread;
3877 gint i;
3878
3879 s = FRAME_GET_LINE (src, convert->in_y);
3880 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3881 d = FRAME_GET_LINE (dest, convert->out_y);
3882 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
3883
3884 n_threads = convert->conversion_runner->n_threads;
3885 tasks = g_newa (FConvertPlaneTask, n_threads);
3886 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3887
3888 lines_per_thread = (height + n_threads - 1) / n_threads;
3889
3890 for (i = 0; i < n_threads; i++) {
3891 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3892 tasks[i].sstride = FRAME_GET_STRIDE (src);
3893 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3894 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3895
3896 tasks[i].width = width;
3897 tasks[i].height = (i + 1) * lines_per_thread;
3898 tasks[i].height = MIN (tasks[i].height, height);
3899 tasks[i].height -= i * lines_per_thread;
3900
3901 tasks_p[i] = &tasks[i];
3902 }
3903
3904 gst_parallelized_task_runner_run (convert->conversion_runner,
3905 (GstParallelizedTaskFunc) convert_UYVY_YUY2_task, (gpointer) tasks_p);
3906
3907 convert_fill_border (convert, dest);
3908 }
3909
3910 static void
convert_UYVY_Y42B_task(FConvertPlaneTask * task)3911 convert_UYVY_Y42B_task (FConvertPlaneTask * task)
3912 {
3913 video_orc_convert_UYVY_Y42B (task->d, task->dstride, task->du,
3914 task->dustride, task->dv, task->dvstride,
3915 task->s, task->sstride, (task->width + 1) / 2, task->height);
3916 }
3917
3918 static void
convert_UYVY_Y42B(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3919 convert_UYVY_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
3920 GstVideoFrame * dest)
3921 {
3922 gint width = convert->in_width;
3923 gint height = convert->in_height;
3924 guint8 *s, *dy, *du, *dv;
3925 FConvertPlaneTask *tasks;
3926 FConvertPlaneTask **tasks_p;
3927 gint n_threads;
3928 gint lines_per_thread;
3929 gint i;
3930
3931 s = FRAME_GET_LINE (src, convert->in_y);
3932 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3933
3934 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3935 dy += convert->out_x;
3936 du = FRAME_GET_U_LINE (dest, convert->out_y);
3937 du += convert->out_x >> 1;
3938 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3939 dv += convert->out_x >> 1;
3940
3941 n_threads = convert->conversion_runner->n_threads;
3942 tasks = g_newa (FConvertPlaneTask, n_threads);
3943 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3944
3945 lines_per_thread = (height + n_threads - 1) / n_threads;
3946
3947 for (i = 0; i < n_threads; i++) {
3948 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3949 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3950 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3951 tasks[i].sstride = FRAME_GET_STRIDE (src);
3952 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3953 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3954 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3955 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3956
3957 tasks[i].width = width;
3958 tasks[i].height = (i + 1) * lines_per_thread;
3959 tasks[i].height = MIN (tasks[i].height, height);
3960 tasks[i].height -= i * lines_per_thread;
3961
3962 tasks_p[i] = &tasks[i];
3963 }
3964
3965 gst_parallelized_task_runner_run (convert->conversion_runner,
3966 (GstParallelizedTaskFunc) convert_UYVY_Y42B_task, (gpointer) tasks_p);
3967
3968 convert_fill_border (convert, dest);
3969 }
3970
3971 static void
convert_UYVY_Y444_task(FConvertPlaneTask * task)3972 convert_UYVY_Y444_task (FConvertPlaneTask * task)
3973 {
3974 video_orc_convert_UYVY_Y444 (task->d,
3975 task->dstride, task->du,
3976 task->dustride, task->dv,
3977 task->dvstride, task->s,
3978 task->sstride, (task->width + 1) / 2, task->height);
3979 }
3980
3981 static void
convert_UYVY_Y444(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3982 convert_UYVY_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
3983 GstVideoFrame * dest)
3984 {
3985 gint width = convert->in_width;
3986 gint height = convert->in_height;
3987 guint8 *s, *dy, *du, *dv;
3988 FConvertPlaneTask *tasks;
3989 FConvertPlaneTask **tasks_p;
3990 gint n_threads;
3991 gint lines_per_thread;
3992 gint i;
3993
3994 s = FRAME_GET_LINE (src, convert->in_y);
3995 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3996
3997 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3998 dy += convert->out_x;
3999 du = FRAME_GET_U_LINE (dest, convert->out_y);
4000 du += convert->out_x;
4001 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4002 dv += convert->out_x;
4003
4004 n_threads = convert->conversion_runner->n_threads;
4005 tasks = g_newa (FConvertPlaneTask, n_threads);
4006 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4007
4008 lines_per_thread = (height + n_threads - 1) / n_threads;
4009
4010 for (i = 0; i < n_threads; i++) {
4011 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4012 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4013 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4014 tasks[i].sstride = FRAME_GET_STRIDE (src);
4015 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4016 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4017 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4018 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4019
4020 tasks[i].width = width;
4021 tasks[i].height = (i + 1) * lines_per_thread;
4022 tasks[i].height = MIN (tasks[i].height, height);
4023 tasks[i].height -= i * lines_per_thread;
4024
4025 tasks_p[i] = &tasks[i];
4026 }
4027
4028 gst_parallelized_task_runner_run (convert->conversion_runner,
4029 (GstParallelizedTaskFunc) convert_UYVY_Y444_task, (gpointer) tasks_p);
4030
4031 convert_fill_border (convert, dest);
4032 }
4033
4034 static void
convert_UYVY_GRAY8_task(FConvertPlaneTask * task)4035 convert_UYVY_GRAY8_task (FConvertPlaneTask * task)
4036 {
4037 video_orc_convert_UYVY_GRAY8 (task->d, task->dstride, (guint16 *) task->s,
4038 task->sstride, task->width, task->height);
4039 }
4040
4041 static void
convert_UYVY_GRAY8(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4042 convert_UYVY_GRAY8 (GstVideoConverter * convert, const GstVideoFrame * src,
4043 GstVideoFrame * dest)
4044 {
4045 gint width = convert->in_width;
4046 gint height = convert->in_height;
4047 guint8 *s;
4048 guint8 *d;
4049 FConvertPlaneTask *tasks;
4050 FConvertPlaneTask **tasks_p;
4051 gint n_threads;
4052 gint lines_per_thread;
4053 gint i;
4054
4055 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
4056 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
4057
4058 n_threads = convert->conversion_runner->n_threads;
4059 tasks = g_newa (FConvertPlaneTask, n_threads);
4060 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4061
4062 lines_per_thread = (height + n_threads - 1) / n_threads;
4063
4064 for (i = 0; i < n_threads; i++) {
4065 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4066 tasks[i].sstride = FRAME_GET_STRIDE (src);
4067 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4068 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4069
4070 tasks[i].width = width;
4071 tasks[i].height = (i + 1) * lines_per_thread;
4072 tasks[i].height = MIN (tasks[i].height, height);
4073 tasks[i].height -= i * lines_per_thread;
4074
4075 tasks_p[i] = &tasks[i];
4076 }
4077
4078 gst_parallelized_task_runner_run (convert->conversion_runner,
4079 (GstParallelizedTaskFunc) convert_UYVY_GRAY8_task, (gpointer) tasks_p);
4080
4081 convert_fill_border (convert, dest);
4082 }
4083
4084 static void
convert_AYUV_I420_task(FConvertPlaneTask * task)4085 convert_AYUV_I420_task (FConvertPlaneTask * task)
4086 {
4087 video_orc_convert_AYUV_I420 (task->d,
4088 2 * task->dstride, task->d2,
4089 2 * task->dstride, task->du,
4090 task->dustride, task->dv,
4091 task->dvstride, task->s,
4092 2 * task->sstride, task->s2,
4093 2 * task->sstride, task->width / 2, task->height / 2);
4094 }
4095
4096 static void
convert_AYUV_I420(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4097 convert_AYUV_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
4098 GstVideoFrame * dest)
4099 {
4100 gint width = convert->in_width;
4101 gint height = convert->in_height;
4102 guint8 *s1, *s2, *dy1, *dy2, *du, *dv;
4103 FConvertPlaneTask *tasks;
4104 FConvertPlaneTask **tasks_p;
4105 gint n_threads;
4106 gint lines_per_thread;
4107 gint i;
4108
4109 s1 = FRAME_GET_LINE (src, convert->in_y + 0);
4110 s1 += convert->in_x * 4;
4111 s2 = FRAME_GET_LINE (src, convert->in_y + 1);
4112 s2 += convert->in_x * 4;
4113
4114 dy1 = FRAME_GET_Y_LINE (dest, convert->out_y + 0);
4115 dy1 += convert->out_x;
4116 dy2 = FRAME_GET_Y_LINE (dest, convert->out_y + 1);
4117 dy2 += convert->out_x;
4118 du = FRAME_GET_U_LINE (dest, convert->out_y >> 1);
4119 du += convert->out_x >> 1;
4120 dv = FRAME_GET_V_LINE (dest, convert->out_y >> 1);
4121 dv += convert->out_x >> 1;
4122
4123 /* only for even width/height */
4124
4125 n_threads = convert->conversion_runner->n_threads;
4126 tasks = g_newa (FConvertPlaneTask, n_threads);
4127 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4128
4129 lines_per_thread = GST_ROUND_UP_2 ((height + n_threads - 1) / n_threads);
4130
4131 for (i = 0; i < n_threads; i++) {
4132 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4133 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4134 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4135 tasks[i].sstride = FRAME_GET_STRIDE (src);
4136 tasks[i].d = dy1 + i * lines_per_thread * tasks[i].dstride;
4137 tasks[i].d2 = dy2 + i * lines_per_thread * tasks[i].dstride;
4138 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride / 2;
4139 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride / 2;
4140 tasks[i].s = s1 + i * lines_per_thread * tasks[i].sstride;
4141 tasks[i].s2 = s2 + i * lines_per_thread * tasks[i].sstride;
4142
4143 tasks[i].width = width;
4144 tasks[i].height = (i + 1) * lines_per_thread;
4145 tasks[i].height = MIN (tasks[i].height, height);
4146 tasks[i].height -= i * lines_per_thread;
4147
4148 tasks_p[i] = &tasks[i];
4149 }
4150
4151 gst_parallelized_task_runner_run (convert->conversion_runner,
4152 (GstParallelizedTaskFunc) convert_AYUV_I420_task, (gpointer) tasks_p);
4153
4154 convert_fill_border (convert, dest);
4155 }
4156
4157 static void
convert_AYUV_YUY2_task(FConvertPlaneTask * task)4158 convert_AYUV_YUY2_task (FConvertPlaneTask * task)
4159 {
4160 video_orc_convert_AYUV_YUY2 (task->d, task->dstride, task->s,
4161 task->sstride, task->width / 2, task->height);
4162 }
4163
4164 static void
convert_AYUV_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4165 convert_AYUV_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4166 GstVideoFrame * dest)
4167 {
4168 gint width = convert->in_width;
4169 gint height = convert->in_height;
4170 guint8 *s, *d;
4171 FConvertPlaneTask *tasks;
4172 FConvertPlaneTask **tasks_p;
4173 gint n_threads;
4174 gint lines_per_thread;
4175 gint i;
4176
4177 s = FRAME_GET_LINE (src, convert->in_y);
4178 s += convert->in_x * 4;
4179 d = FRAME_GET_LINE (dest, convert->out_y);
4180 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4181
4182 /* only for even width */
4183 n_threads = convert->conversion_runner->n_threads;
4184 tasks = g_newa (FConvertPlaneTask, n_threads);
4185 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4186
4187 lines_per_thread = (height + n_threads - 1) / n_threads;
4188
4189 for (i = 0; i < n_threads; i++) {
4190 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4191 tasks[i].sstride = FRAME_GET_STRIDE (src);
4192 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4193 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4194
4195 tasks[i].width = width;
4196 tasks[i].height = (i + 1) * lines_per_thread;
4197 tasks[i].height = MIN (tasks[i].height, height);
4198 tasks[i].height -= i * lines_per_thread;
4199
4200 tasks_p[i] = &tasks[i];
4201 }
4202
4203 gst_parallelized_task_runner_run (convert->conversion_runner,
4204 (GstParallelizedTaskFunc) convert_AYUV_YUY2_task, (gpointer) tasks_p);
4205
4206 convert_fill_border (convert, dest);
4207 }
4208
4209 static void
convert_AYUV_UYVY_task(FConvertPlaneTask * task)4210 convert_AYUV_UYVY_task (FConvertPlaneTask * task)
4211 {
4212 video_orc_convert_AYUV_UYVY (task->d, task->dstride, task->s,
4213 task->sstride, task->width / 2, task->height);
4214 }
4215
4216 static void
convert_AYUV_UYVY(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4217 convert_AYUV_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4218 GstVideoFrame * dest)
4219 {
4220 gint width = convert->in_width;
4221 gint height = convert->in_height;
4222 guint8 *s, *d;
4223 FConvertPlaneTask *tasks;
4224 FConvertPlaneTask **tasks_p;
4225 gint n_threads;
4226 gint lines_per_thread;
4227 gint i;
4228
4229 s = FRAME_GET_LINE (src, convert->in_y);
4230 s += convert->in_x * 4;
4231 d = FRAME_GET_LINE (dest, convert->out_y);
4232 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4233
4234 /* only for even width */
4235 n_threads = convert->conversion_runner->n_threads;
4236 tasks = g_newa (FConvertPlaneTask, n_threads);
4237 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4238
4239 lines_per_thread = (height + n_threads - 1) / n_threads;
4240
4241 for (i = 0; i < n_threads; i++) {
4242 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4243 tasks[i].sstride = FRAME_GET_STRIDE (src);
4244 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4245 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4246
4247 tasks[i].width = width;
4248 tasks[i].height = (i + 1) * lines_per_thread;
4249 tasks[i].height = MIN (tasks[i].height, height);
4250 tasks[i].height -= i * lines_per_thread;
4251
4252 tasks_p[i] = &tasks[i];
4253 }
4254
4255 gst_parallelized_task_runner_run (convert->conversion_runner,
4256 (GstParallelizedTaskFunc) convert_AYUV_UYVY_task, (gpointer) tasks_p);
4257
4258 convert_fill_border (convert, dest);
4259 }
4260
4261 static void
convert_AYUV_Y42B_task(FConvertPlaneTask * task)4262 convert_AYUV_Y42B_task (FConvertPlaneTask * task)
4263 {
4264 video_orc_convert_AYUV_Y42B (task->d, task->dstride, task->du,
4265 task->dustride, task->dv, task->dvstride,
4266 task->s, task->sstride, task->width / 2, task->height);
4267 }
4268
4269 static void
convert_AYUV_Y42B(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4270 convert_AYUV_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4271 GstVideoFrame * dest)
4272 {
4273 gint width = convert->in_width;
4274 gint height = convert->in_height;
4275 guint8 *s, *dy, *du, *dv;
4276 FConvertPlaneTask *tasks;
4277 FConvertPlaneTask **tasks_p;
4278 gint n_threads;
4279 gint lines_per_thread;
4280 gint i;
4281
4282 s = FRAME_GET_LINE (src, convert->in_y);
4283 s += convert->in_x * 4;
4284
4285 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4286 dy += convert->out_x;
4287 du = FRAME_GET_U_LINE (dest, convert->out_y);
4288 du += convert->out_x >> 1;
4289 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4290 dv += convert->out_x >> 1;
4291
4292 /* only works for even width */
4293 n_threads = convert->conversion_runner->n_threads;
4294 tasks = g_newa (FConvertPlaneTask, n_threads);
4295 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4296
4297 lines_per_thread = (height + n_threads - 1) / n_threads;
4298
4299 for (i = 0; i < n_threads; i++) {
4300 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4301 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4302 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4303 tasks[i].sstride = FRAME_GET_STRIDE (src);
4304 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4305 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4306 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4307 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4308
4309 tasks[i].width = width;
4310 tasks[i].height = (i + 1) * lines_per_thread;
4311 tasks[i].height = MIN (tasks[i].height, height);
4312 tasks[i].height -= i * lines_per_thread;
4313
4314 tasks_p[i] = &tasks[i];
4315 }
4316
4317 gst_parallelized_task_runner_run (convert->conversion_runner,
4318 (GstParallelizedTaskFunc) convert_AYUV_Y42B_task, (gpointer) tasks_p);
4319
4320 convert_fill_border (convert, dest);
4321 }
4322
4323 static void
convert_AYUV_Y444_task(FConvertPlaneTask * task)4324 convert_AYUV_Y444_task (FConvertPlaneTask * task)
4325 {
4326 video_orc_convert_AYUV_Y444 (task->d, task->dstride, task->du,
4327 task->dustride, task->dv, task->dvstride,
4328 task->s, task->sstride, task->width, task->height);
4329 }
4330
4331 static void
convert_AYUV_Y444(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4332 convert_AYUV_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
4333 GstVideoFrame * dest)
4334 {
4335 gint width = convert->in_width;
4336 gint height = convert->in_height;
4337 guint8 *s, *dy, *du, *dv;
4338 FConvertPlaneTask *tasks;
4339 FConvertPlaneTask **tasks_p;
4340 gint n_threads;
4341 gint lines_per_thread;
4342 gint i;
4343
4344 s = FRAME_GET_LINE (src, convert->in_y);
4345 s += convert->in_x * 4;
4346
4347 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4348 dy += convert->out_x;
4349 du = FRAME_GET_U_LINE (dest, convert->out_y);
4350 du += convert->out_x;
4351 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4352 dv += convert->out_x;
4353
4354 n_threads = convert->conversion_runner->n_threads;
4355 tasks = g_newa (FConvertPlaneTask, n_threads);
4356 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4357
4358 lines_per_thread = (height + n_threads - 1) / n_threads;
4359
4360 for (i = 0; i < n_threads; i++) {
4361 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4362 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4363 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4364 tasks[i].sstride = FRAME_GET_STRIDE (src);
4365 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4366 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4367 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4368 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4369
4370 tasks[i].width = width;
4371 tasks[i].height = (i + 1) * lines_per_thread;
4372 tasks[i].height = MIN (tasks[i].height, height);
4373 tasks[i].height -= i * lines_per_thread;
4374
4375 tasks_p[i] = &tasks[i];
4376 }
4377
4378 gst_parallelized_task_runner_run (convert->conversion_runner,
4379 (GstParallelizedTaskFunc) convert_AYUV_Y444_task, (gpointer) tasks_p);
4380 convert_fill_border (convert, dest);
4381 }
4382
4383 static void
convert_Y42B_YUY2_task(FConvertPlaneTask * task)4384 convert_Y42B_YUY2_task (FConvertPlaneTask * task)
4385 {
4386 video_orc_convert_Y42B_YUY2 (task->d, task->dstride,
4387 task->s, task->sstride,
4388 task->su, task->sustride,
4389 task->sv, task->svstride, (task->width + 1) / 2, task->height);
4390 }
4391
4392 static void
convert_Y42B_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4393 convert_Y42B_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4394 GstVideoFrame * dest)
4395 {
4396 gint width = convert->in_width;
4397 gint height = convert->in_height;
4398 guint8 *sy, *su, *sv, *d;
4399 FConvertPlaneTask *tasks;
4400 FConvertPlaneTask **tasks_p;
4401 gint n_threads;
4402 gint lines_per_thread;
4403 gint i;
4404
4405 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4406 sy += convert->in_x;
4407 su = FRAME_GET_U_LINE (src, convert->in_y);
4408 su += convert->in_x >> 1;
4409 sv = FRAME_GET_V_LINE (src, convert->in_y);
4410 sv += convert->in_x >> 1;
4411
4412 d = FRAME_GET_LINE (dest, convert->out_y);
4413 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4414
4415 n_threads = convert->conversion_runner->n_threads;
4416 tasks = g_newa (FConvertPlaneTask, n_threads);
4417 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4418
4419 lines_per_thread = (height + n_threads - 1) / n_threads;
4420
4421 for (i = 0; i < n_threads; i++) {
4422 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4423 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4424 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4425 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4426 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4427 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4428 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4429 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4430
4431 tasks[i].width = width;
4432 tasks[i].height = (i + 1) * lines_per_thread;
4433 tasks[i].height = MIN (tasks[i].height, height);
4434 tasks[i].height -= i * lines_per_thread;
4435
4436 tasks_p[i] = &tasks[i];
4437 }
4438
4439 gst_parallelized_task_runner_run (convert->conversion_runner,
4440 (GstParallelizedTaskFunc) convert_Y42B_YUY2_task, (gpointer) tasks_p);
4441
4442 convert_fill_border (convert, dest);
4443 }
4444
4445 static void
convert_Y42B_UYVY_task(FConvertPlaneTask * task)4446 convert_Y42B_UYVY_task (FConvertPlaneTask * task)
4447 {
4448 video_orc_convert_Y42B_UYVY (task->d, task->dstride,
4449 task->s, task->sstride,
4450 task->su, task->sustride,
4451 task->sv, task->svstride, (task->width + 1) / 2, task->height);
4452 }
4453
4454 static void
convert_Y42B_UYVY(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4455 convert_Y42B_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4456 GstVideoFrame * dest)
4457 {
4458 gint width = convert->in_width;
4459 gint height = convert->in_height;
4460 guint8 *sy, *su, *sv, *d;
4461 FConvertPlaneTask *tasks;
4462 FConvertPlaneTask **tasks_p;
4463 gint n_threads;
4464 gint lines_per_thread;
4465 gint i;
4466
4467 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4468 sy += convert->in_x;
4469 su = FRAME_GET_U_LINE (src, convert->in_y);
4470 su += convert->in_x >> 1;
4471 sv = FRAME_GET_V_LINE (src, convert->in_y);
4472 sv += convert->in_x >> 1;
4473
4474 d = FRAME_GET_LINE (dest, convert->out_y);
4475 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4476
4477 n_threads = convert->conversion_runner->n_threads;
4478 tasks = g_newa (FConvertPlaneTask, n_threads);
4479 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4480
4481 lines_per_thread = (height + n_threads - 1) / n_threads;
4482
4483 for (i = 0; i < n_threads; i++) {
4484 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4485 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4486 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4487 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4488 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4489 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4490 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4491 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4492
4493 tasks[i].width = width;
4494 tasks[i].height = (i + 1) * lines_per_thread;
4495 tasks[i].height = MIN (tasks[i].height, height);
4496 tasks[i].height -= i * lines_per_thread;
4497
4498 tasks_p[i] = &tasks[i];
4499 }
4500
4501 gst_parallelized_task_runner_run (convert->conversion_runner,
4502 (GstParallelizedTaskFunc) convert_Y42B_UYVY_task, (gpointer) tasks_p);
4503
4504 convert_fill_border (convert, dest);
4505 }
4506
4507 static void
convert_Y42B_AYUV_task(FConvertPlaneTask * task)4508 convert_Y42B_AYUV_task (FConvertPlaneTask * task)
4509 {
4510 video_orc_convert_Y42B_AYUV (task->d, task->dstride, task->s,
4511 task->sstride,
4512 task->su,
4513 task->sustride,
4514 task->sv, task->svstride, task->alpha, task->width / 2, task->height);
4515 }
4516
4517 static void
convert_Y42B_AYUV(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4518 convert_Y42B_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
4519 GstVideoFrame * dest)
4520 {
4521 gint width = convert->in_width;
4522 gint height = convert->in_height;
4523 guint8 *sy, *su, *sv, *d;
4524 guint8 alpha = MIN (convert->alpha_value, 255);
4525 FConvertPlaneTask *tasks;
4526 FConvertPlaneTask **tasks_p;
4527 gint n_threads;
4528 gint lines_per_thread;
4529 gint i;
4530
4531 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4532 sy += convert->in_x;
4533 su = FRAME_GET_U_LINE (src, convert->in_y);
4534 su += convert->in_x >> 1;
4535 sv = FRAME_GET_V_LINE (src, convert->in_y);
4536 sv += convert->in_x >> 1;
4537
4538 d = FRAME_GET_LINE (dest, convert->out_y);
4539 d += convert->out_x * 4;
4540
4541 /* only for even width */
4542 n_threads = convert->conversion_runner->n_threads;
4543 tasks = g_newa (FConvertPlaneTask, n_threads);
4544 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4545
4546 lines_per_thread = (height + n_threads - 1) / n_threads;
4547
4548 for (i = 0; i < n_threads; i++) {
4549 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4550 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4551 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4552 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4553 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4554 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4555 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4556 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4557
4558 tasks[i].width = width;
4559 tasks[i].height = (i + 1) * lines_per_thread;
4560 tasks[i].height = MIN (tasks[i].height, height);
4561 tasks[i].height -= i * lines_per_thread;
4562 tasks[i].alpha = alpha;
4563
4564 tasks_p[i] = &tasks[i];
4565 }
4566
4567 gst_parallelized_task_runner_run (convert->conversion_runner,
4568 (GstParallelizedTaskFunc) convert_Y42B_AYUV_task, (gpointer) tasks_p);
4569
4570 convert_fill_border (convert, dest);
4571 }
4572
4573 static void
convert_Y444_YUY2_task(FConvertPlaneTask * task)4574 convert_Y444_YUY2_task (FConvertPlaneTask * task)
4575 {
4576 video_orc_convert_Y444_YUY2 (task->d, task->dstride, task->s,
4577 task->sstride,
4578 task->su,
4579 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
4580 }
4581
4582 static void
convert_Y444_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4583 convert_Y444_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4584 GstVideoFrame * dest)
4585 {
4586 gint width = convert->in_width;
4587 gint height = convert->in_height;
4588 guint8 *sy, *su, *sv, *d;
4589 FConvertPlaneTask *tasks;
4590 FConvertPlaneTask **tasks_p;
4591 gint n_threads;
4592 gint lines_per_thread;
4593 gint i;
4594
4595 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4596 sy += convert->in_x;
4597 su = FRAME_GET_U_LINE (src, convert->in_y);
4598 su += convert->in_x;
4599 sv = FRAME_GET_V_LINE (src, convert->in_y);
4600 sv += convert->in_x;
4601
4602 d = FRAME_GET_LINE (dest, convert->out_y);
4603 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4604
4605 n_threads = convert->conversion_runner->n_threads;
4606 tasks = g_newa (FConvertPlaneTask, n_threads);
4607 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4608
4609 lines_per_thread = (height + n_threads - 1) / n_threads;
4610
4611 for (i = 0; i < n_threads; i++) {
4612 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4613 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4614 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4615 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4616 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4617 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4618 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4619 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4620
4621 tasks[i].width = width;
4622 tasks[i].height = (i + 1) * lines_per_thread;
4623 tasks[i].height = MIN (tasks[i].height, height);
4624 tasks[i].height -= i * lines_per_thread;
4625
4626 tasks_p[i] = &tasks[i];
4627 }
4628
4629 gst_parallelized_task_runner_run (convert->conversion_runner,
4630 (GstParallelizedTaskFunc) convert_Y444_YUY2_task, (gpointer) tasks_p);
4631
4632 convert_fill_border (convert, dest);
4633 }
4634
4635 static void
convert_Y444_UYVY_task(FConvertPlaneTask * task)4636 convert_Y444_UYVY_task (FConvertPlaneTask * task)
4637 {
4638 video_orc_convert_Y444_UYVY (task->d, task->dstride, task->s,
4639 task->sstride,
4640 task->su,
4641 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
4642 }
4643
4644 static void
convert_Y444_UYVY(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4645 convert_Y444_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4646 GstVideoFrame * dest)
4647 {
4648 gint width = convert->in_width;
4649 gint height = convert->in_height;
4650 guint8 *sy, *su, *sv, *d;
4651 FConvertPlaneTask *tasks;
4652 FConvertPlaneTask **tasks_p;
4653 gint n_threads;
4654 gint lines_per_thread;
4655 gint i;
4656
4657 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4658 sy += convert->in_x;
4659 su = FRAME_GET_U_LINE (src, convert->in_y);
4660 su += convert->in_x;
4661 sv = FRAME_GET_V_LINE (src, convert->in_y);
4662 sv += convert->in_x;
4663
4664 d = FRAME_GET_LINE (dest, convert->out_y);
4665 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4666
4667 n_threads = convert->conversion_runner->n_threads;
4668 tasks = g_newa (FConvertPlaneTask, n_threads);
4669 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4670
4671 lines_per_thread = (height + n_threads - 1) / n_threads;
4672
4673 for (i = 0; i < n_threads; i++) {
4674 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4675 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4676 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4677 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4678 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4679 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4680 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4681 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4682
4683 tasks[i].width = width;
4684 tasks[i].height = (i + 1) * lines_per_thread;
4685 tasks[i].height = MIN (tasks[i].height, height);
4686 tasks[i].height -= i * lines_per_thread;
4687
4688 tasks_p[i] = &tasks[i];
4689 }
4690
4691 gst_parallelized_task_runner_run (convert->conversion_runner,
4692 (GstParallelizedTaskFunc) convert_Y444_UYVY_task, (gpointer) tasks_p);
4693
4694 convert_fill_border (convert, dest);
4695 }
4696
4697 static void
convert_Y444_AYUV_task(FConvertPlaneTask * task)4698 convert_Y444_AYUV_task (FConvertPlaneTask * task)
4699 {
4700 video_orc_convert_Y444_AYUV (task->d, task->dstride, task->s,
4701 task->sstride,
4702 task->su,
4703 task->sustride,
4704 task->sv, task->svstride, task->alpha, task->width, task->height);
4705 }
4706
4707 static void
convert_Y444_AYUV(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4708 convert_Y444_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
4709 GstVideoFrame * dest)
4710 {
4711 gint width = convert->in_width;
4712 gint height = convert->in_height;
4713 guint8 *sy, *su, *sv, *d;
4714 guint8 alpha = MIN (convert->alpha_value, 255);
4715 FConvertPlaneTask *tasks;
4716 FConvertPlaneTask **tasks_p;
4717 gint n_threads;
4718 gint lines_per_thread;
4719 gint i;
4720
4721 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4722 sy += convert->in_x;
4723 su = FRAME_GET_U_LINE (src, convert->in_y);
4724 su += convert->in_x;
4725 sv = FRAME_GET_V_LINE (src, convert->in_y);
4726 sv += convert->in_x;
4727
4728 d = FRAME_GET_LINE (dest, convert->out_y);
4729 d += convert->out_x * 4;
4730
4731 n_threads = convert->conversion_runner->n_threads;
4732 tasks = g_newa (FConvertPlaneTask, n_threads);
4733 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4734
4735 lines_per_thread = (height + n_threads - 1) / n_threads;
4736
4737 for (i = 0; i < n_threads; i++) {
4738 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4739 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4740 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4741 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4742 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4743 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4744 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4745 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4746
4747 tasks[i].width = width;
4748 tasks[i].height = (i + 1) * lines_per_thread;
4749 tasks[i].height = MIN (tasks[i].height, height);
4750 tasks[i].height -= i * lines_per_thread;
4751 tasks[i].alpha = alpha;
4752
4753 tasks_p[i] = &tasks[i];
4754 }
4755
4756 gst_parallelized_task_runner_run (convert->conversion_runner,
4757 (GstParallelizedTaskFunc) convert_Y444_AYUV_task, (gpointer) tasks_p);
4758
4759 convert_fill_border (convert, dest);
4760 }
4761
4762 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4763 static void
convert_AYUV_ARGB_task(FConvertPlaneTask * task)4764 convert_AYUV_ARGB_task (FConvertPlaneTask * task)
4765 {
4766 video_orc_convert_AYUV_ARGB (task->d, task->dstride, task->s,
4767 task->sstride, task->data->im[0][0], task->data->im[0][2],
4768 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4769 task->width, task->height);
4770 }
4771
4772 static void
convert_AYUV_ARGB(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4773 convert_AYUV_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
4774 GstVideoFrame * dest)
4775 {
4776 gint width = convert->in_width;
4777 gint height = convert->in_height;
4778 MatrixData *data = &convert->convert_matrix;
4779 guint8 *s, *d;
4780 FConvertPlaneTask *tasks;
4781 FConvertPlaneTask **tasks_p;
4782 gint n_threads;
4783 gint lines_per_thread;
4784 gint i;
4785
4786 s = FRAME_GET_LINE (src, convert->in_y);
4787 s += (convert->in_x * 4);
4788 d = FRAME_GET_LINE (dest, convert->out_y);
4789 d += (convert->out_x * 4);
4790
4791 n_threads = convert->conversion_runner->n_threads;
4792 tasks = g_newa (FConvertPlaneTask, n_threads);
4793 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4794
4795 lines_per_thread = (height + n_threads - 1) / n_threads;
4796
4797 for (i = 0; i < n_threads; i++) {
4798 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4799 tasks[i].sstride = FRAME_GET_STRIDE (src);
4800 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4801 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4802
4803 tasks[i].width = width;
4804 tasks[i].height = (i + 1) * lines_per_thread;
4805 tasks[i].height = MIN (tasks[i].height, height);
4806 tasks[i].height -= i * lines_per_thread;
4807 tasks[i].data = data;
4808
4809 tasks_p[i] = &tasks[i];
4810 }
4811
4812 gst_parallelized_task_runner_run (convert->conversion_runner,
4813 (GstParallelizedTaskFunc) convert_AYUV_ARGB_task, (gpointer) tasks_p);
4814
4815 convert_fill_border (convert, dest);
4816 }
4817
4818 static void
convert_AYUV_BGRA_task(FConvertPlaneTask * task)4819 convert_AYUV_BGRA_task (FConvertPlaneTask * task)
4820 {
4821 video_orc_convert_AYUV_BGRA (task->d, task->dstride, task->s,
4822 task->sstride, task->data->im[0][0], task->data->im[0][2],
4823 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4824 task->width, task->height);
4825 }
4826
4827 static void
convert_AYUV_BGRA(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4828 convert_AYUV_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
4829 GstVideoFrame * dest)
4830 {
4831 gint width = convert->in_width;
4832 gint height = convert->in_height;
4833 MatrixData *data = &convert->convert_matrix;
4834 guint8 *s, *d;
4835 FConvertPlaneTask *tasks;
4836 FConvertPlaneTask **tasks_p;
4837 gint n_threads;
4838 gint lines_per_thread;
4839 gint i;
4840
4841 s = FRAME_GET_LINE (src, convert->in_y);
4842 s += (convert->in_x * 4);
4843 d = FRAME_GET_LINE (dest, convert->out_y);
4844 d += (convert->out_x * 4);
4845
4846 n_threads = convert->conversion_runner->n_threads;
4847 tasks = g_newa (FConvertPlaneTask, n_threads);
4848 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4849
4850 lines_per_thread = (height + n_threads - 1) / n_threads;
4851
4852 for (i = 0; i < n_threads; i++) {
4853 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4854 tasks[i].sstride = FRAME_GET_STRIDE (src);
4855 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4856 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4857
4858 tasks[i].width = width;
4859 tasks[i].height = (i + 1) * lines_per_thread;
4860 tasks[i].height = MIN (tasks[i].height, height);
4861 tasks[i].height -= i * lines_per_thread;
4862 tasks[i].data = data;
4863
4864 tasks_p[i] = &tasks[i];
4865 }
4866
4867 gst_parallelized_task_runner_run (convert->conversion_runner,
4868 (GstParallelizedTaskFunc) convert_AYUV_BGRA_task, (gpointer) tasks_p);
4869
4870 convert_fill_border (convert, dest);
4871 }
4872
4873 static void
convert_AYUV_ABGR_task(FConvertPlaneTask * task)4874 convert_AYUV_ABGR_task (FConvertPlaneTask * task)
4875 {
4876 video_orc_convert_AYUV_ABGR (task->d, task->dstride, task->s,
4877 task->sstride, task->data->im[0][0], task->data->im[0][2],
4878 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4879 task->width, task->height);
4880 }
4881
4882 static void
convert_AYUV_ABGR(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4883 convert_AYUV_ABGR (GstVideoConverter * convert, const GstVideoFrame * src,
4884 GstVideoFrame * dest)
4885 {
4886 gint width = convert->in_width;
4887 gint height = convert->in_height;
4888 MatrixData *data = &convert->convert_matrix;
4889 guint8 *s, *d;
4890 FConvertPlaneTask *tasks;
4891 FConvertPlaneTask **tasks_p;
4892 gint n_threads;
4893 gint lines_per_thread;
4894 gint i;
4895
4896 s = FRAME_GET_LINE (src, convert->in_y);
4897 s += (convert->in_x * 4);
4898 d = FRAME_GET_LINE (dest, convert->out_y);
4899 d += (convert->out_x * 4);
4900
4901 n_threads = convert->conversion_runner->n_threads;
4902 tasks = g_newa (FConvertPlaneTask, n_threads);
4903 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4904
4905 lines_per_thread = (height + n_threads - 1) / n_threads;
4906
4907 for (i = 0; i < n_threads; i++) {
4908 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4909 tasks[i].sstride = FRAME_GET_STRIDE (src);
4910 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4911 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4912
4913 tasks[i].width = width;
4914 tasks[i].height = (i + 1) * lines_per_thread;
4915 tasks[i].height = MIN (tasks[i].height, height);
4916 tasks[i].height -= i * lines_per_thread;
4917 tasks[i].data = data;
4918
4919 tasks_p[i] = &tasks[i];
4920 }
4921
4922 gst_parallelized_task_runner_run (convert->conversion_runner,
4923 (GstParallelizedTaskFunc) convert_AYUV_ABGR_task, (gpointer) tasks_p);
4924
4925 convert_fill_border (convert, dest);
4926 }
4927
4928 static void
convert_AYUV_RGBA_task(FConvertPlaneTask * task)4929 convert_AYUV_RGBA_task (FConvertPlaneTask * task)
4930 {
4931 video_orc_convert_AYUV_RGBA (task->d, task->dstride, task->s,
4932 task->sstride, task->data->im[0][0], task->data->im[0][2],
4933 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4934 task->width, task->height);
4935 }
4936
4937 static void
convert_AYUV_RGBA(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4938 convert_AYUV_RGBA (GstVideoConverter * convert, const GstVideoFrame * src,
4939 GstVideoFrame * dest)
4940 {
4941 gint width = convert->in_width;
4942 gint height = convert->in_height;
4943 MatrixData *data = &convert->convert_matrix;
4944 guint8 *s, *d;
4945 FConvertPlaneTask *tasks;
4946 FConvertPlaneTask **tasks_p;
4947 gint n_threads;
4948 gint lines_per_thread;
4949 gint i;
4950
4951 s = FRAME_GET_LINE (src, convert->in_y);
4952 s += (convert->in_x * 4);
4953 d = FRAME_GET_LINE (dest, convert->out_y);
4954 d += (convert->out_x * 4);
4955
4956 n_threads = convert->conversion_runner->n_threads;
4957 tasks = g_newa (FConvertPlaneTask, n_threads);
4958 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4959
4960 lines_per_thread = (height + n_threads - 1) / n_threads;
4961
4962 for (i = 0; i < n_threads; i++) {
4963 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4964 tasks[i].sstride = FRAME_GET_STRIDE (src);
4965 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4966 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4967
4968 tasks[i].width = width;
4969 tasks[i].height = (i + 1) * lines_per_thread;
4970 tasks[i].height = MIN (tasks[i].height, height);
4971 tasks[i].height -= i * lines_per_thread;
4972 tasks[i].data = data;
4973
4974 tasks_p[i] = &tasks[i];
4975 }
4976
4977 gst_parallelized_task_runner_run (convert->conversion_runner,
4978 (GstParallelizedTaskFunc) convert_AYUV_RGBA_task, (gpointer) tasks_p);
4979
4980 convert_fill_border (convert, dest);
4981 }
4982 #endif
4983
4984 static void
convert_I420_BGRA_task(FConvertTask * task)4985 convert_I420_BGRA_task (FConvertTask * task)
4986 {
4987 gint i;
4988
4989 for (i = task->height_0; i < task->height_1; i++) {
4990 guint8 *sy, *su, *sv, *d;
4991
4992 d = FRAME_GET_LINE (task->dest, i + task->out_y);
4993 d += (task->out_x * 4);
4994 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
4995 sy += task->in_x;
4996 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
4997 su += (task->in_x >> 1);
4998 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
4999 sv += (task->in_x >> 1);
5000
5001 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5002 video_orc_convert_I420_BGRA (d, sy, su, sv,
5003 task->data->im[0][0], task->data->im[0][2],
5004 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5005 task->width);
5006 #else
5007 video_orc_convert_I420_ARGB (d, sy, su, sv,
5008 task->data->im[0][0], task->data->im[0][2],
5009 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5010 task->width);
5011 #endif
5012 }
5013 }
5014
5015 static void
convert_I420_BGRA(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5016 convert_I420_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
5017 GstVideoFrame * dest)
5018 {
5019 int i;
5020 gint width = convert->in_width;
5021 gint height = convert->in_height;
5022 MatrixData *data = &convert->convert_matrix;
5023 FConvertTask *tasks;
5024 FConvertTask **tasks_p;
5025 gint n_threads;
5026 gint lines_per_thread;
5027
5028 n_threads = convert->conversion_runner->n_threads;
5029 tasks = g_newa (FConvertTask, n_threads);
5030 tasks_p = g_newa (FConvertTask *, n_threads);
5031
5032 lines_per_thread = (height + n_threads - 1) / n_threads;
5033
5034 for (i = 0; i < n_threads; i++) {
5035 tasks[i].src = src;
5036 tasks[i].dest = dest;
5037
5038 tasks[i].width = width;
5039 tasks[i].data = data;
5040 tasks[i].in_x = convert->in_x;
5041 tasks[i].in_y = convert->in_y;
5042 tasks[i].out_x = convert->out_x;
5043 tasks[i].out_y = convert->out_y;
5044
5045 tasks[i].height_0 = i * lines_per_thread;
5046 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5047 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5048
5049 tasks_p[i] = &tasks[i];
5050 }
5051
5052 gst_parallelized_task_runner_run (convert->conversion_runner,
5053 (GstParallelizedTaskFunc) convert_I420_BGRA_task, (gpointer) tasks_p);
5054
5055 convert_fill_border (convert, dest);
5056 }
5057
5058 static void
convert_I420_ARGB_task(FConvertTask * task)5059 convert_I420_ARGB_task (FConvertTask * task)
5060 {
5061 gint i;
5062
5063 for (i = task->height_0; i < task->height_1; i++) {
5064 guint8 *sy, *su, *sv, *d;
5065
5066 d = FRAME_GET_LINE (task->dest, i + task->out_y);
5067 d += (task->out_x * 4);
5068 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5069 sy += task->in_x;
5070 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5071 su += (task->in_x >> 1);
5072 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5073 sv += (task->in_x >> 1);
5074
5075 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5076 video_orc_convert_I420_ARGB (d, sy, su, sv,
5077 task->data->im[0][0], task->data->im[0][2],
5078 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5079 task->width);
5080 #else
5081 video_orc_convert_I420_BGRA (d, sy, su, sv,
5082 task->data->im[0][0], task->data->im[0][2],
5083 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5084 task->width);
5085 #endif
5086 }
5087 }
5088
5089 static void
convert_I420_ARGB(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5090 convert_I420_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5091 GstVideoFrame * dest)
5092 {
5093 int i;
5094 gint width = convert->in_width;
5095 gint height = convert->in_height;
5096 MatrixData *data = &convert->convert_matrix;
5097 FConvertTask *tasks;
5098 FConvertTask **tasks_p;
5099 gint n_threads;
5100 gint lines_per_thread;
5101
5102 n_threads = convert->conversion_runner->n_threads;
5103 tasks = g_newa (FConvertTask, n_threads);
5104 tasks_p = g_newa (FConvertTask *, n_threads);
5105
5106 lines_per_thread = (height + n_threads - 1) / n_threads;
5107
5108 for (i = 0; i < n_threads; i++) {
5109 tasks[i].src = src;
5110 tasks[i].dest = dest;
5111
5112 tasks[i].width = width;
5113 tasks[i].data = data;
5114 tasks[i].in_x = convert->in_x;
5115 tasks[i].in_y = convert->in_y;
5116 tasks[i].out_x = convert->out_x;
5117 tasks[i].out_y = convert->out_y;
5118
5119 tasks[i].height_0 = i * lines_per_thread;
5120 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5121 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5122
5123 tasks_p[i] = &tasks[i];
5124 }
5125
5126 gst_parallelized_task_runner_run (convert->conversion_runner,
5127 (GstParallelizedTaskFunc) convert_I420_ARGB_task, (gpointer) tasks_p);
5128
5129 convert_fill_border (convert, dest);
5130 }
5131
5132 static void
convert_I420_pack_ARGB_task(FConvertTask * task)5133 convert_I420_pack_ARGB_task (FConvertTask * task)
5134 {
5135 gint i;
5136 gpointer d[GST_VIDEO_MAX_PLANES];
5137
5138 d[0] = FRAME_GET_LINE (task->dest, 0);
5139 d[0] =
5140 (guint8 *) d[0] +
5141 task->out_x * GST_VIDEO_FORMAT_INFO_PSTRIDE (task->dest->info.finfo, 0);
5142
5143 for (i = task->height_0; i < task->height_1; i++) {
5144 guint8 *sy, *su, *sv;
5145
5146 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5147 sy += task->in_x;
5148 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5149 su += (task->in_x >> 1);
5150 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5151 sv += (task->in_x >> 1);
5152
5153 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5154 video_orc_convert_I420_ARGB (task->tmpline, sy, su, sv,
5155 task->data->im[0][0], task->data->im[0][2],
5156 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5157 task->width);
5158 #else
5159 video_orc_convert_I420_BGRA (task->tmpline, sy, su, sv,
5160 task->data->im[0][0], task->data->im[0][2],
5161 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5162 task->width);
5163 #endif
5164 task->dest->info.finfo->pack_func (task->dest->info.finfo,
5165 (GST_VIDEO_FRAME_IS_INTERLACED (task->dest) ?
5166 GST_VIDEO_PACK_FLAG_INTERLACED :
5167 GST_VIDEO_PACK_FLAG_NONE),
5168 task->tmpline, 0, d, task->dest->info.stride,
5169 task->dest->info.chroma_site, i + task->out_y, task->width);
5170 }
5171 }
5172
5173 static void
convert_I420_pack_ARGB(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5174 convert_I420_pack_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5175 GstVideoFrame * dest)
5176 {
5177 int i;
5178 gint width = convert->in_width;
5179 gint height = convert->in_height;
5180 MatrixData *data = &convert->convert_matrix;
5181 FConvertTask *tasks;
5182 FConvertTask **tasks_p;
5183 gint n_threads;
5184 gint lines_per_thread;
5185
5186 n_threads = convert->conversion_runner->n_threads;
5187 tasks = g_newa (FConvertTask, n_threads);
5188 tasks_p = g_newa (FConvertTask *, n_threads);
5189
5190 lines_per_thread = (height + n_threads - 1) / n_threads;
5191
5192 for (i = 0; i < n_threads; i++) {
5193 tasks[i].src = src;
5194 tasks[i].dest = dest;
5195
5196 tasks[i].width = width;
5197 tasks[i].data = data;
5198 tasks[i].in_x = convert->in_x;
5199 tasks[i].in_y = convert->in_y;
5200 tasks[i].out_x = convert->out_x;
5201 tasks[i].out_y = convert->out_y;
5202 tasks[i].tmpline = convert->tmpline[i];
5203
5204 tasks[i].height_0 = i * lines_per_thread;
5205 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5206 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5207
5208 tasks_p[i] = &tasks[i];
5209 }
5210
5211 gst_parallelized_task_runner_run (convert->conversion_runner,
5212 (GstParallelizedTaskFunc) convert_I420_pack_ARGB_task,
5213 (gpointer) tasks_p);
5214
5215 convert_fill_border (convert, dest);
5216 }
5217
5218 static void
memset_u24(guint8 * data,guint8 col[3],unsigned int n)5219 memset_u24 (guint8 * data, guint8 col[3], unsigned int n)
5220 {
5221 unsigned int i;
5222
5223 for (i = 0; i < n; i++) {
5224 data[0] = col[0];
5225 data[1] = col[1];
5226 data[2] = col[2];
5227 data += 3;
5228 }
5229 }
5230
5231 static void
memset_u32_16(guint8 * data,guint8 col[4],unsigned int n)5232 memset_u32_16 (guint8 * data, guint8 col[4], unsigned int n)
5233 {
5234 unsigned int i;
5235
5236 for (i = 0; i < n; i += 2) {
5237 data[0] = col[0];
5238 data[1] = col[1];
5239 if (i + 1 < n) {
5240 data[2] = col[2];
5241 data[3] = col[3];
5242 }
5243 data += 4;
5244 }
5245 }
5246
5247 #define MAKE_BORDER_FUNC(func) \
5248 for (i = 0; i < out_y; i++) \
5249 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
5250 if (rb_width || lb_width) { \
5251 for (i = 0; i < out_height; i++) { \
5252 guint8 *d = FRAME_GET_PLANE_LINE (dest, k, i + out_y); \
5253 if (lb_width) \
5254 func (d, col, lb_width); \
5255 if (rb_width) \
5256 func (d + (pstride * r_border), col, rb_width); \
5257 } \
5258 } \
5259 for (i = out_y + out_height; i < out_maxheight; i++) \
5260 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
5261
5262 static void
convert_fill_border(GstVideoConverter * convert,GstVideoFrame * dest)5263 convert_fill_border (GstVideoConverter * convert, GstVideoFrame * dest)
5264 {
5265 int k, n_planes;
5266 const GstVideoFormatInfo *out_finfo;
5267
5268 if (!convert->fill_border || !convert->borderline)
5269 return;
5270
5271 out_finfo = convert->out_info.finfo;
5272
5273 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
5274
5275 for (k = 0; k < n_planes; k++) {
5276 gint i, out_x, out_y, out_width, out_height, pstride, pgroup;
5277 gint r_border, lb_width, rb_width;
5278 gint out_maxwidth, out_maxheight;
5279 gpointer borders;
5280
5281 out_x = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_x);
5282 out_y = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k, convert->out_y);
5283 out_width =
5284 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_width);
5285 out_height =
5286 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k, convert->out_height);
5287 out_maxwidth =
5288 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_maxwidth);
5289 out_maxheight =
5290 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k,
5291 convert->out_maxheight);
5292
5293 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, k);
5294
5295 switch (GST_VIDEO_FORMAT_INFO_FORMAT (out_finfo)) {
5296 case GST_VIDEO_FORMAT_YUY2:
5297 case GST_VIDEO_FORMAT_YVYU:
5298 case GST_VIDEO_FORMAT_UYVY:
5299 pgroup = 42;
5300 out_maxwidth = GST_ROUND_UP_2 (out_maxwidth);
5301 break;
5302 default:
5303 pgroup = pstride;
5304 break;
5305 }
5306
5307 r_border = out_x + out_width;
5308 rb_width = out_maxwidth - r_border;
5309 lb_width = out_x;
5310
5311 borders = &convert->borders[k];
5312
5313 switch (pgroup) {
5314 case 1:
5315 {
5316 guint8 col = ((guint8 *) borders)[0];
5317 MAKE_BORDER_FUNC (memset);
5318 break;
5319 }
5320 case 2:
5321 {
5322 guint16 col = ((guint16 *) borders)[0];
5323 MAKE_BORDER_FUNC (video_orc_splat_u16);
5324 break;
5325 }
5326 case 3:
5327 {
5328 guint8 col[3];
5329 col[0] = ((guint8 *) borders)[0];
5330 col[1] = ((guint8 *) borders)[1];
5331 col[2] = ((guint8 *) borders)[2];
5332 MAKE_BORDER_FUNC (memset_u24);
5333 break;
5334 }
5335 case 4:
5336 {
5337 guint32 col = ((guint32 *) borders)[0];
5338 MAKE_BORDER_FUNC (video_orc_splat_u32);
5339 break;
5340 }
5341 case 8:
5342 {
5343 guint64 col = ((guint64 *) borders)[0];
5344 MAKE_BORDER_FUNC (video_orc_splat_u64);
5345 break;
5346 }
5347 case 42:
5348 {
5349 guint8 col[4];
5350 col[0] = ((guint8 *) borders)[0];
5351 col[2] = ((guint8 *) borders)[2];
5352 col[1] = ((guint8 *) borders)[r_border & 1 ? 3 : 1];
5353 col[3] = ((guint8 *) borders)[r_border & 1 ? 1 : 3];
5354 MAKE_BORDER_FUNC (memset_u32_16);
5355 break;
5356 }
5357 default:
5358 break;
5359 }
5360 }
5361 }
5362
5363 typedef struct
5364 {
5365 const guint8 *s, *s2;
5366 guint8 *d, *d2;
5367 gint sstride, dstride;
5368 gint width, height;
5369 gint fill;
5370 } FSimpleScaleTask;
5371
5372 static void
convert_plane_fill_task(FSimpleScaleTask * task)5373 convert_plane_fill_task (FSimpleScaleTask * task)
5374 {
5375 video_orc_memset_2d (task->d, task->dstride,
5376 task->fill, task->width, task->height);
5377 }
5378
5379 static void
convert_plane_fill(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)5380 convert_plane_fill (GstVideoConverter * convert,
5381 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5382 {
5383 guint8 *d;
5384 FSimpleScaleTask *tasks;
5385 FSimpleScaleTask **tasks_p;
5386 gint n_threads;
5387 gint lines_per_thread;
5388 gint i;
5389
5390 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5391 d += convert->fout_x[plane];
5392
5393 n_threads = convert->conversion_runner->n_threads;
5394 tasks = g_newa (FSimpleScaleTask, n_threads);
5395 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5396 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5397
5398 for (i = 0; i < n_threads; i++) {
5399 tasks[i].d = d + i * lines_per_thread * convert->fout_width[plane];
5400
5401 tasks[i].fill = convert->ffill[plane];
5402 tasks[i].width = convert->fout_width[plane];
5403 tasks[i].height = (i + 1) * lines_per_thread;
5404 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5405 tasks[i].height -= i * lines_per_thread;
5406 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5407
5408 tasks_p[i] = &tasks[i];
5409 }
5410
5411 gst_parallelized_task_runner_run (convert->conversion_runner,
5412 (GstParallelizedTaskFunc) convert_plane_fill_task, (gpointer) tasks_p);
5413 }
5414
5415 static void
convert_plane_h_double_task(FSimpleScaleTask * task)5416 convert_plane_h_double_task (FSimpleScaleTask * task)
5417 {
5418 video_orc_planar_chroma_422_444 (task->d,
5419 task->dstride, task->s, task->sstride, task->width / 2, task->height);
5420 }
5421
5422 static void
convert_plane_h_double(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)5423 convert_plane_h_double (GstVideoConverter * convert,
5424 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5425 {
5426 guint8 *s, *d;
5427 gint splane = convert->fsplane[plane];
5428 FSimpleScaleTask *tasks;
5429 FSimpleScaleTask **tasks_p;
5430 gint n_threads;
5431 gint lines_per_thread;
5432 gint i;
5433
5434 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5435 s += convert->fin_x[splane];
5436 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5437 d += convert->fout_x[plane];
5438
5439 n_threads = convert->conversion_runner->n_threads;
5440 tasks = g_newa (FSimpleScaleTask, n_threads);
5441 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5442 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5443
5444 for (i = 0; i < n_threads; i++) {
5445 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5446 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5447
5448 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5449 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5450
5451 tasks[i].width = convert->fout_width[plane];
5452 tasks[i].height = (i + 1) * lines_per_thread;
5453 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5454 tasks[i].height -= i * lines_per_thread;
5455
5456 tasks_p[i] = &tasks[i];
5457 }
5458
5459 gst_parallelized_task_runner_run (convert->conversion_runner,
5460 (GstParallelizedTaskFunc) convert_plane_h_double_task,
5461 (gpointer) tasks_p);
5462 }
5463
5464 static void
convert_plane_h_halve_task(FSimpleScaleTask * task)5465 convert_plane_h_halve_task (FSimpleScaleTask * task)
5466 {
5467 video_orc_planar_chroma_444_422 (task->d,
5468 task->dstride, task->s, task->sstride, task->width, task->height);
5469 }
5470
5471 static void
convert_plane_h_halve(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)5472 convert_plane_h_halve (GstVideoConverter * convert,
5473 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5474 {
5475 guint8 *s, *d;
5476 gint splane = convert->fsplane[plane];
5477 FSimpleScaleTask *tasks;
5478 FSimpleScaleTask **tasks_p;
5479 gint n_threads;
5480 gint lines_per_thread;
5481 gint i;
5482
5483 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5484 s += convert->fin_x[splane];
5485 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5486 d += convert->fout_x[plane];
5487
5488 n_threads = convert->conversion_runner->n_threads;
5489 tasks = g_newa (FSimpleScaleTask, n_threads);
5490 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5491 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5492
5493 for (i = 0; i < n_threads; i++) {
5494 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5495 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5496
5497 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5498 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5499
5500 tasks[i].width = convert->fout_width[plane];
5501 tasks[i].height = (i + 1) * lines_per_thread;
5502 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5503 tasks[i].height -= i * lines_per_thread;
5504
5505 tasks_p[i] = &tasks[i];
5506 }
5507
5508 gst_parallelized_task_runner_run (convert->conversion_runner,
5509 (GstParallelizedTaskFunc) convert_plane_h_halve_task, (gpointer) tasks_p);
5510 }
5511
5512 static void
convert_plane_v_double_task(FSimpleScaleTask * task)5513 convert_plane_v_double_task (FSimpleScaleTask * task)
5514 {
5515 video_orc_planar_chroma_420_422 (task->d, 2 * task->dstride, task->d2,
5516 2 * task->dstride, task->s, task->sstride, task->width, task->height / 2);
5517 }
5518
5519 static void
convert_plane_v_double(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)5520 convert_plane_v_double (GstVideoConverter * convert,
5521 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5522 {
5523 guint8 *s, *d1, *d2;
5524 gint ds, splane = convert->fsplane[plane];
5525 FSimpleScaleTask *tasks;
5526 FSimpleScaleTask **tasks_p;
5527 gint n_threads;
5528 gint lines_per_thread;
5529 gint i;
5530
5531 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5532 s += convert->fin_x[splane];
5533 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5534 d1 += convert->fout_x[plane];
5535 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
5536 d2 += convert->fout_x[plane];
5537 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5538
5539 n_threads = convert->conversion_runner->n_threads;
5540 tasks = g_newa (FSimpleScaleTask, n_threads);
5541 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5542 lines_per_thread =
5543 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
5544 1) / n_threads);
5545
5546 for (i = 0; i < n_threads; i++) {
5547 tasks[i].d = d1 + i * lines_per_thread * ds;
5548 tasks[i].d2 = d2 + i * lines_per_thread * ds;
5549 tasks[i].dstride = ds;
5550 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5551 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride / 2;
5552
5553 tasks[i].width = convert->fout_width[plane];
5554 tasks[i].height = (i + 1) * lines_per_thread;
5555 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5556 tasks[i].height -= i * lines_per_thread;
5557
5558 tasks_p[i] = &tasks[i];
5559 }
5560
5561 gst_parallelized_task_runner_run (convert->conversion_runner,
5562 (GstParallelizedTaskFunc) convert_plane_v_double_task,
5563 (gpointer) tasks_p);
5564 }
5565
5566 static void
convert_plane_v_halve_task(FSimpleScaleTask * task)5567 convert_plane_v_halve_task (FSimpleScaleTask * task)
5568 {
5569 video_orc_planar_chroma_422_420 (task->d, task->dstride, task->s,
5570 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
5571 task->height);
5572 }
5573
5574 static void
convert_plane_v_halve(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)5575 convert_plane_v_halve (GstVideoConverter * convert,
5576 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5577 {
5578 guint8 *s1, *s2, *d;
5579 gint ss, ds, splane = convert->fsplane[plane];
5580 FSimpleScaleTask *tasks;
5581 FSimpleScaleTask **tasks_p;
5582 gint n_threads;
5583 gint lines_per_thread;
5584 gint i;
5585
5586 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5587 s1 += convert->fin_x[splane];
5588 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
5589 s2 += convert->fin_x[splane];
5590 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5591 d += convert->fout_x[plane];
5592
5593 ss = FRAME_GET_PLANE_STRIDE (src, splane);
5594 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5595
5596 n_threads = convert->conversion_runner->n_threads;
5597 tasks = g_newa (FSimpleScaleTask, n_threads);
5598 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5599 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5600
5601 for (i = 0; i < n_threads; i++) {
5602 tasks[i].d = d + i * lines_per_thread * ds;
5603 tasks[i].dstride = ds;
5604 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
5605 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
5606 tasks[i].sstride = ss;
5607
5608 tasks[i].width = convert->fout_width[plane];
5609 tasks[i].height = (i + 1) * lines_per_thread;
5610 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5611 tasks[i].height -= i * lines_per_thread;
5612
5613 tasks_p[i] = &tasks[i];
5614 }
5615
5616 gst_parallelized_task_runner_run (convert->conversion_runner,
5617 (GstParallelizedTaskFunc) convert_plane_v_halve_task, (gpointer) tasks_p);
5618 }
5619
5620 static void
convert_plane_hv_double_task(FSimpleScaleTask * task)5621 convert_plane_hv_double_task (FSimpleScaleTask * task)
5622 {
5623 video_orc_planar_chroma_420_444 (task->d, 2 * task->dstride, task->d2,
5624 2 * task->dstride, task->s, task->sstride, (task->width + 1) / 2,
5625 task->height / 2);
5626 }
5627
5628 static void
convert_plane_hv_double(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)5629 convert_plane_hv_double (GstVideoConverter * convert,
5630 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5631 {
5632 guint8 *s, *d1, *d2;
5633 gint ss, ds, splane = convert->fsplane[plane];
5634 FSimpleScaleTask *tasks;
5635 FSimpleScaleTask **tasks_p;
5636 gint n_threads;
5637 gint lines_per_thread;
5638 gint i;
5639
5640 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5641 s += convert->fin_x[splane];
5642 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5643 d1 += convert->fout_x[plane];
5644 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
5645 d2 += convert->fout_x[plane];
5646 ss = FRAME_GET_PLANE_STRIDE (src, splane);
5647 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5648
5649 n_threads = convert->conversion_runner->n_threads;
5650 tasks = g_newa (FSimpleScaleTask, n_threads);
5651 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5652 lines_per_thread =
5653 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
5654 1) / n_threads);
5655
5656 for (i = 0; i < n_threads; i++) {
5657 tasks[i].d = d1 + i * lines_per_thread * ds;
5658 tasks[i].d2 = d2 + i * lines_per_thread * ds;
5659 tasks[i].dstride = ds;
5660 tasks[i].sstride = ss;
5661 tasks[i].s = s + i * lines_per_thread * ss / 2;
5662
5663 tasks[i].width = convert->fout_width[plane];
5664 tasks[i].height = (i + 1) * lines_per_thread;
5665 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5666 tasks[i].height -= i * lines_per_thread;
5667
5668 tasks_p[i] = &tasks[i];
5669 }
5670
5671 gst_parallelized_task_runner_run (convert->conversion_runner,
5672 (GstParallelizedTaskFunc) convert_plane_hv_double_task,
5673 (gpointer) tasks_p);
5674 }
5675
5676 static void
convert_plane_hv_halve_task(FSimpleScaleTask * task)5677 convert_plane_hv_halve_task (FSimpleScaleTask * task)
5678 {
5679 video_orc_planar_chroma_444_420 (task->d, task->dstride, task->s,
5680 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
5681 task->height);
5682 }
5683
5684 static void
convert_plane_hv_halve(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)5685 convert_plane_hv_halve (GstVideoConverter * convert,
5686 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5687 {
5688 guint8 *s1, *s2, *d;
5689 gint ss, ds, splane = convert->fsplane[plane];
5690 FSimpleScaleTask *tasks;
5691 FSimpleScaleTask **tasks_p;
5692 gint n_threads;
5693 gint lines_per_thread;
5694 gint i;
5695
5696 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5697 s1 += convert->fin_x[splane];
5698 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
5699 s2 += convert->fin_x[splane];
5700 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5701 d += convert->fout_x[plane];
5702 ss = FRAME_GET_PLANE_STRIDE (src, splane);
5703 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5704
5705 n_threads = convert->conversion_runner->n_threads;
5706 tasks = g_newa (FSimpleScaleTask, n_threads);
5707 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5708 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5709
5710 for (i = 0; i < n_threads; i++) {
5711 tasks[i].d = d + i * lines_per_thread * ds;
5712 tasks[i].dstride = ds;
5713 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
5714 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
5715 tasks[i].sstride = ss;
5716
5717 tasks[i].width = convert->fout_width[plane];
5718 tasks[i].height = (i + 1) * lines_per_thread;
5719 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5720 tasks[i].height -= i * lines_per_thread;
5721
5722 tasks_p[i] = &tasks[i];
5723 }
5724
5725 gst_parallelized_task_runner_run (convert->conversion_runner,
5726 (GstParallelizedTaskFunc) convert_plane_hv_halve_task,
5727 (gpointer) tasks_p);
5728 }
5729
5730 typedef struct
5731 {
5732 GstVideoScaler *h_scaler, *v_scaler;
5733 GstVideoFormat format;
5734 const guint8 *s;
5735 guint8 *d;
5736 gint sstride, dstride;
5737 guint x, y, w, h;
5738 } FScaleTask;
5739
5740 static void
convert_plane_hv_task(FScaleTask * task)5741 convert_plane_hv_task (FScaleTask * task)
5742 {
5743 gst_video_scaler_2d (task->h_scaler, task->v_scaler, task->format,
5744 (guint8 *) task->s, task->sstride,
5745 task->d, task->dstride, task->x, task->y, task->w, task->h);
5746 }
5747
5748 static void
convert_plane_hv(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)5749 convert_plane_hv (GstVideoConverter * convert,
5750 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5751 {
5752 gint in_x, in_y, out_x, out_y, out_width, out_height;
5753 GstVideoFormat format;
5754 gint splane = convert->fsplane[plane];
5755 guint8 *s, *d;
5756 gint sstride, dstride;
5757 FScaleTask *tasks;
5758 FScaleTask **tasks_p;
5759 gint i, n_threads, lines_per_thread;
5760
5761 in_x = convert->fin_x[splane];
5762 in_y = convert->fin_y[splane];
5763 out_x = convert->fout_x[plane];
5764 out_y = convert->fout_y[plane];
5765 out_width = convert->fout_width[plane];
5766 out_height = convert->fout_height[plane];
5767 format = convert->fformat[plane];
5768
5769 s = FRAME_GET_PLANE_LINE (src, splane, in_y);
5770 s += in_x;
5771 d = FRAME_GET_PLANE_LINE (dest, plane, out_y);
5772 d += out_x;
5773
5774 sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5775 dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5776
5777 n_threads = convert->conversion_runner->n_threads;
5778 tasks = g_newa (FScaleTask, n_threads);
5779 tasks_p = g_newa (FScaleTask *, n_threads);
5780
5781 lines_per_thread = (out_height + n_threads - 1) / n_threads;
5782
5783 for (i = 0; i < n_threads; i++) {
5784 tasks[i].h_scaler =
5785 convert->fh_scaler[plane].scaler ? convert->
5786 fh_scaler[plane].scaler[i] : NULL;
5787 tasks[i].v_scaler =
5788 convert->fv_scaler[plane].scaler ? convert->
5789 fv_scaler[plane].scaler[i] : NULL;
5790 tasks[i].format = format;
5791 tasks[i].s = s;
5792 tasks[i].d = d;
5793 tasks[i].sstride = sstride;
5794 tasks[i].dstride = dstride;
5795
5796 tasks[i].x = 0;
5797 tasks[i].w = out_width;
5798
5799 tasks[i].y = i * lines_per_thread;
5800 tasks[i].h = tasks[i].y + lines_per_thread;
5801 tasks[i].h = MIN (out_height, tasks[i].h);
5802
5803 tasks_p[i] = &tasks[i];
5804 }
5805
5806 gst_parallelized_task_runner_run (convert->conversion_runner,
5807 (GstParallelizedTaskFunc) convert_plane_hv_task, (gpointer) tasks_p);
5808 }
5809
5810 static void
convert_scale_planes(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5811 convert_scale_planes (GstVideoConverter * convert,
5812 const GstVideoFrame * src, GstVideoFrame * dest)
5813 {
5814 int i, n_planes;
5815
5816 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
5817 for (i = 0; i < n_planes; i++) {
5818 if (convert->fconvert[i])
5819 convert->fconvert[i] (convert, src, dest, i);
5820 }
5821 convert_fill_border (convert, dest);
5822 }
5823
5824 static GstVideoFormat
get_scale_format(GstVideoFormat format,gint plane)5825 get_scale_format (GstVideoFormat format, gint plane)
5826 {
5827 GstVideoFormat res = GST_VIDEO_FORMAT_UNKNOWN;
5828
5829 switch (format) {
5830 case GST_VIDEO_FORMAT_I420:
5831 case GST_VIDEO_FORMAT_YV12:
5832 case GST_VIDEO_FORMAT_Y41B:
5833 case GST_VIDEO_FORMAT_Y42B:
5834 case GST_VIDEO_FORMAT_Y444:
5835 case GST_VIDEO_FORMAT_GRAY8:
5836 case GST_VIDEO_FORMAT_A420:
5837 case GST_VIDEO_FORMAT_YUV9:
5838 case GST_VIDEO_FORMAT_YVU9:
5839 case GST_VIDEO_FORMAT_GBR:
5840 case GST_VIDEO_FORMAT_GBRA:
5841 res = GST_VIDEO_FORMAT_GRAY8;
5842 break;
5843 case GST_VIDEO_FORMAT_GRAY16_BE:
5844 case GST_VIDEO_FORMAT_GRAY16_LE:
5845 res = GST_VIDEO_FORMAT_GRAY16_BE;
5846 break;
5847 case GST_VIDEO_FORMAT_YUY2:
5848 case GST_VIDEO_FORMAT_UYVY:
5849 case GST_VIDEO_FORMAT_VYUY:
5850 case GST_VIDEO_FORMAT_YVYU:
5851 case GST_VIDEO_FORMAT_AYUV:
5852 case GST_VIDEO_FORMAT_VUYA:
5853 case GST_VIDEO_FORMAT_RGBx:
5854 case GST_VIDEO_FORMAT_BGRx:
5855 case GST_VIDEO_FORMAT_xRGB:
5856 case GST_VIDEO_FORMAT_xBGR:
5857 case GST_VIDEO_FORMAT_RGBA:
5858 case GST_VIDEO_FORMAT_BGRA:
5859 case GST_VIDEO_FORMAT_ARGB:
5860 case GST_VIDEO_FORMAT_ABGR:
5861 case GST_VIDEO_FORMAT_RGB:
5862 case GST_VIDEO_FORMAT_BGR:
5863 case GST_VIDEO_FORMAT_v308:
5864 case GST_VIDEO_FORMAT_IYU2:
5865 case GST_VIDEO_FORMAT_ARGB64:
5866 case GST_VIDEO_FORMAT_AYUV64:
5867 res = format;
5868 break;
5869 case GST_VIDEO_FORMAT_RGB15:
5870 case GST_VIDEO_FORMAT_BGR15:
5871 case GST_VIDEO_FORMAT_RGB16:
5872 case GST_VIDEO_FORMAT_BGR16:
5873 res = GST_VIDEO_FORMAT_NV12;
5874 break;
5875 case GST_VIDEO_FORMAT_NV12:
5876 case GST_VIDEO_FORMAT_NV21:
5877 case GST_VIDEO_FORMAT_NV16:
5878 case GST_VIDEO_FORMAT_NV61:
5879 case GST_VIDEO_FORMAT_NV24:
5880 res = plane == 0 ? GST_VIDEO_FORMAT_GRAY8 : GST_VIDEO_FORMAT_NV12;
5881 break;
5882 case GST_VIDEO_FORMAT_UNKNOWN:
5883 case GST_VIDEO_FORMAT_ENCODED:
5884 case GST_VIDEO_FORMAT_v210:
5885 case GST_VIDEO_FORMAT_v216:
5886 case GST_VIDEO_FORMAT_Y210:
5887 case GST_VIDEO_FORMAT_Y410:
5888 case GST_VIDEO_FORMAT_UYVP:
5889 case GST_VIDEO_FORMAT_RGB8P:
5890 case GST_VIDEO_FORMAT_IYU1:
5891 case GST_VIDEO_FORMAT_r210:
5892 case GST_VIDEO_FORMAT_I420_10BE:
5893 case GST_VIDEO_FORMAT_I420_10LE:
5894 case GST_VIDEO_FORMAT_I422_10BE:
5895 case GST_VIDEO_FORMAT_I422_10LE:
5896 case GST_VIDEO_FORMAT_Y444_10BE:
5897 case GST_VIDEO_FORMAT_Y444_10LE:
5898 case GST_VIDEO_FORMAT_I420_12BE:
5899 case GST_VIDEO_FORMAT_I420_12LE:
5900 case GST_VIDEO_FORMAT_I422_12BE:
5901 case GST_VIDEO_FORMAT_I422_12LE:
5902 case GST_VIDEO_FORMAT_Y444_12BE:
5903 case GST_VIDEO_FORMAT_Y444_12LE:
5904 case GST_VIDEO_FORMAT_GBR_10BE:
5905 case GST_VIDEO_FORMAT_GBR_10LE:
5906 case GST_VIDEO_FORMAT_GBRA_10BE:
5907 case GST_VIDEO_FORMAT_GBRA_10LE:
5908 case GST_VIDEO_FORMAT_GBR_12BE:
5909 case GST_VIDEO_FORMAT_GBR_12LE:
5910 case GST_VIDEO_FORMAT_GBRA_12BE:
5911 case GST_VIDEO_FORMAT_GBRA_12LE:
5912 case GST_VIDEO_FORMAT_NV12_64Z32:
5913 case GST_VIDEO_FORMAT_A420_10BE:
5914 case GST_VIDEO_FORMAT_A420_10LE:
5915 case GST_VIDEO_FORMAT_A422_10BE:
5916 case GST_VIDEO_FORMAT_A422_10LE:
5917 case GST_VIDEO_FORMAT_A444_10BE:
5918 case GST_VIDEO_FORMAT_A444_10LE:
5919 case GST_VIDEO_FORMAT_P010_10BE:
5920 case GST_VIDEO_FORMAT_P010_10LE:
5921 case GST_VIDEO_FORMAT_GRAY10_LE32:
5922 case GST_VIDEO_FORMAT_NV12_10LE32:
5923 case GST_VIDEO_FORMAT_NV16_10LE32:
5924 case GST_VIDEO_FORMAT_NV12_10LE40:
5925 case GST_VIDEO_FORMAT_BGR10A2_LE:
5926 res = format;
5927 g_assert_not_reached ();
5928 break;
5929 }
5930 return res;
5931 }
5932
5933 static gboolean
is_merge_yuv(GstVideoInfo * info)5934 is_merge_yuv (GstVideoInfo * info)
5935 {
5936 switch (GST_VIDEO_INFO_FORMAT (info)) {
5937 case GST_VIDEO_FORMAT_YUY2:
5938 case GST_VIDEO_FORMAT_YVYU:
5939 case GST_VIDEO_FORMAT_UYVY:
5940 case GST_VIDEO_FORMAT_VYUY:
5941 return TRUE;
5942 default:
5943 return FALSE;
5944 }
5945 }
5946
5947 static gboolean
setup_scale(GstVideoConverter * convert)5948 setup_scale (GstVideoConverter * convert)
5949 {
5950 int i, n_planes;
5951 gint method, cr_method, in_width, in_height, out_width, out_height;
5952 guint taps;
5953 GstVideoInfo *in_info, *out_info;
5954 const GstVideoFormatInfo *in_finfo, *out_finfo;
5955 GstVideoFormat in_format, out_format;
5956 gboolean interlaced;
5957 guint n_threads = convert->conversion_runner->n_threads;
5958
5959 in_info = &convert->in_info;
5960 out_info = &convert->out_info;
5961
5962 in_finfo = in_info->finfo;
5963 out_finfo = out_info->finfo;
5964
5965 n_planes = GST_VIDEO_INFO_N_PLANES (out_info);
5966
5967 interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info);
5968
5969 method = GET_OPT_RESAMPLER_METHOD (convert);
5970 if (method == GST_VIDEO_RESAMPLER_METHOD_NEAREST)
5971 cr_method = method;
5972 else
5973 cr_method = GET_OPT_CHROMA_RESAMPLER_METHOD (convert);
5974 taps = GET_OPT_RESAMPLER_TAPS (convert);
5975
5976 in_format = GST_VIDEO_INFO_FORMAT (in_info);
5977 out_format = GST_VIDEO_INFO_FORMAT (out_info);
5978
5979 switch (in_format) {
5980 case GST_VIDEO_FORMAT_RGB15:
5981 case GST_VIDEO_FORMAT_RGB16:
5982 case GST_VIDEO_FORMAT_BGR15:
5983 case GST_VIDEO_FORMAT_BGR16:
5984 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5985 case GST_VIDEO_FORMAT_GRAY16_BE:
5986 #else
5987 case GST_VIDEO_FORMAT_GRAY16_LE:
5988 #endif
5989 if (method != GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
5990 GST_DEBUG ("%s only with nearest resampling",
5991 gst_video_format_to_string (in_format));
5992 return FALSE;
5993 }
5994 break;
5995 default:
5996 break;
5997 }
5998
5999 in_width = convert->in_width;
6000 in_height = convert->in_height;
6001 out_width = convert->out_width;
6002 out_height = convert->out_height;
6003
6004 if (n_planes == 1 && !GST_VIDEO_FORMAT_INFO_IS_GRAY (out_finfo)) {
6005 gint pstride;
6006 guint j;
6007
6008 if (is_merge_yuv (in_info)) {
6009 GstVideoScaler *y_scaler, *uv_scaler;
6010
6011 if (in_width != out_width) {
6012 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6013 for (j = 0; j < n_threads; j++) {
6014 y_scaler =
6015 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6016 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_Y,
6017 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
6018 GST_VIDEO_COMP_Y, out_width), convert->config);
6019 uv_scaler =
6020 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE,
6021 gst_video_scaler_get_max_taps (y_scaler),
6022 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_U,
6023 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
6024 GST_VIDEO_COMP_U, out_width), convert->config);
6025
6026 convert->fh_scaler[0].scaler[j] =
6027 gst_video_scaler_combine_packed_YUV (y_scaler, uv_scaler,
6028 in_format, out_format);
6029
6030 gst_video_scaler_free (y_scaler);
6031 gst_video_scaler_free (uv_scaler);
6032 }
6033 } else {
6034 convert->fh_scaler[0].scaler = NULL;
6035 }
6036
6037 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_Y);
6038 convert->fin_x[0] = GST_ROUND_UP_2 (convert->in_x) * pstride;
6039 convert->fout_x[0] = GST_ROUND_UP_2 (convert->out_x) * pstride;
6040
6041 } else {
6042 if (in_width != out_width && in_width != 0 && out_width != 0) {
6043 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6044 for (j = 0; j < n_threads; j++) {
6045 convert->fh_scaler[0].scaler[j] =
6046 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6047 in_width, out_width, convert->config);
6048 }
6049 } else {
6050 convert->fh_scaler[0].scaler = NULL;
6051 }
6052
6053 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_R);
6054 convert->fin_x[0] = convert->in_x * pstride;
6055 convert->fout_x[0] = convert->out_x * pstride;
6056 }
6057
6058 if (in_height != out_height && in_height != 0 && out_height != 0) {
6059 convert->fv_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6060
6061 for (j = 0; j < n_threads; j++) {
6062 convert->fv_scaler[0].scaler[j] =
6063 gst_video_scaler_new (method,
6064 interlaced ?
6065 GST_VIDEO_SCALER_FLAG_INTERLACED : GST_VIDEO_SCALER_FLAG_NONE, taps,
6066 in_height, out_height, convert->config);
6067 }
6068 } else {
6069 convert->fv_scaler[0].scaler = NULL;
6070 }
6071
6072 convert->fin_y[0] = convert->in_y;
6073 convert->fout_y[0] = convert->out_y;
6074 convert->fout_width[0] = out_width;
6075 convert->fout_height[0] = out_height;
6076 convert->fconvert[0] = convert_plane_hv;
6077 convert->fformat[0] = get_scale_format (in_format, 0);
6078 convert->fsplane[0] = 0;
6079 } else {
6080 for (i = 0; i < n_planes; i++) {
6081 gint comp, n_comp, j, iw, ih, ow, oh, pstride;
6082 gboolean need_v_scaler, need_h_scaler;
6083 GstStructure *config;
6084 gint resample_method;
6085
6086 n_comp = GST_VIDEO_FORMAT_INFO_N_COMPONENTS (in_finfo);
6087
6088 /* find the component in this plane and map it to the plane of
6089 * the source */
6090 comp = -1;
6091 for (j = 0; j < n_comp; j++) {
6092 if (GST_VIDEO_FORMAT_INFO_PLANE (out_finfo, j) == i) {
6093 comp = j;
6094 break;
6095 }
6096 }
6097
6098 iw = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, i, in_width);
6099 ih = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, i, in_height);
6100 ow = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, i, out_width);
6101 oh = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, i, out_height);
6102
6103 GST_DEBUG ("plane %d: %dx%d -> %dx%d", i, iw, ih, ow, oh);
6104
6105 convert->fout_width[i] = ow;
6106 convert->fout_height[i] = oh;
6107
6108 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, i);
6109 convert->fin_x[i] =
6110 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, i, convert->in_x);
6111 convert->fin_x[i] *= pstride;
6112 convert->fin_y[i] =
6113 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, i, convert->in_y);
6114 convert->fout_x[i] =
6115 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, i, convert->out_x);
6116 convert->fout_x[i] *= pstride;
6117 convert->fout_y[i] =
6118 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, i, convert->out_y);
6119
6120 GST_DEBUG ("plane %d: pstride %d", i, pstride);
6121 GST_DEBUG ("plane %d: in_x %d, in_y %d", i, convert->fin_x[i],
6122 convert->fin_y[i]);
6123 GST_DEBUG ("plane %d: out_x %d, out_y %d", i, convert->fout_x[i],
6124 convert->fout_y[i]);
6125
6126 if (comp == -1) {
6127 convert->fconvert[i] = convert_plane_fill;
6128 if (GST_VIDEO_INFO_IS_YUV (out_info)) {
6129 if (i == 3)
6130 convert->ffill[i] = convert->alpha_value;
6131 if (i == 0)
6132 convert->ffill[i] = 0x00;
6133 else
6134 convert->ffill[i] = 0x80;
6135 } else {
6136 if (i == 3)
6137 convert->ffill[i] = convert->alpha_value;
6138 else
6139 convert->ffill[i] = 0x00;
6140 }
6141 GST_DEBUG ("plane %d fill %02x", i, convert->ffill[i]);
6142 continue;
6143 } else {
6144 convert->fsplane[i] = GST_VIDEO_FORMAT_INFO_PLANE (in_finfo, comp);
6145 GST_DEBUG ("plane %d -> %d (comp %d)", i, convert->fsplane[i], comp);
6146 }
6147
6148 config = gst_structure_copy (convert->config);
6149
6150 resample_method = (i == 0 ? method : cr_method);
6151
6152 need_v_scaler = FALSE;
6153 need_h_scaler = FALSE;
6154 if (iw == ow) {
6155 if (!interlaced && ih == oh) {
6156 convert->fconvert[i] = convert_plane_hv;
6157 GST_DEBUG ("plane %d: copy", i);
6158 } else if (!interlaced && ih == 2 * oh && pstride == 1
6159 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6160 convert->fconvert[i] = convert_plane_v_halve;
6161 GST_DEBUG ("plane %d: vertical halve", i);
6162 } else if (!interlaced && 2 * ih == oh && pstride == 1
6163 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6164 convert->fconvert[i] = convert_plane_v_double;
6165 GST_DEBUG ("plane %d: vertical double", i);
6166 } else {
6167 convert->fconvert[i] = convert_plane_hv;
6168 GST_DEBUG ("plane %d: vertical scale", i);
6169 need_v_scaler = TRUE;
6170 }
6171 } else if (ih == oh) {
6172 if (!interlaced && iw == 2 * ow && pstride == 1
6173 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6174 convert->fconvert[i] = convert_plane_h_halve;
6175 GST_DEBUG ("plane %d: horizontal halve", i);
6176 } else if (!interlaced && 2 * iw == ow && pstride == 1
6177 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6178 convert->fconvert[i] = convert_plane_h_double;
6179 GST_DEBUG ("plane %d: horizontal double", i);
6180 } else {
6181 convert->fconvert[i] = convert_plane_hv;
6182 GST_DEBUG ("plane %d: horizontal scale", i);
6183 need_h_scaler = TRUE;
6184 }
6185 } else {
6186 if (!interlaced && iw == 2 * ow && ih == 2 * oh && pstride == 1
6187 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6188 convert->fconvert[i] = convert_plane_hv_halve;
6189 GST_DEBUG ("plane %d: horizontal/vertical halve", i);
6190 } else if (!interlaced && 2 * iw == ow && 2 * ih == oh && pstride == 1
6191 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6192 convert->fconvert[i] = convert_plane_hv_double;
6193 GST_DEBUG ("plane %d: horizontal/vertical double", i);
6194 } else {
6195 convert->fconvert[i] = convert_plane_hv;
6196 GST_DEBUG ("plane %d: horizontal/vertical scale", i);
6197 need_v_scaler = TRUE;
6198 need_h_scaler = TRUE;
6199 }
6200 }
6201
6202 if (need_h_scaler && iw != 0 && ow != 0) {
6203 convert->fh_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
6204
6205 for (j = 0; j < n_threads; j++) {
6206 convert->fh_scaler[i].scaler[j] =
6207 gst_video_scaler_new (resample_method, GST_VIDEO_SCALER_FLAG_NONE,
6208 taps, iw, ow, config);
6209 }
6210 } else {
6211 convert->fh_scaler[i].scaler = NULL;
6212 }
6213
6214 if (need_v_scaler && ih != 0 && oh != 0) {
6215 convert->fv_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
6216
6217 for (j = 0; j < n_threads; j++) {
6218 convert->fv_scaler[i].scaler[j] =
6219 gst_video_scaler_new (resample_method,
6220 interlaced ?
6221 GST_VIDEO_SCALER_FLAG_INTERLACED : GST_VIDEO_SCALER_FLAG_NONE,
6222 taps, ih, oh, config);
6223 }
6224 } else {
6225 convert->fv_scaler[i].scaler = NULL;
6226 }
6227
6228 gst_structure_free (config);
6229 convert->fformat[i] = get_scale_format (in_format, i);
6230 }
6231 }
6232
6233 return TRUE;
6234 }
6235
6236 /* Fast paths */
6237
6238 typedef struct
6239 {
6240 GstVideoFormat in_format;
6241 GstVideoFormat out_format;
6242 gboolean keeps_interlaced;
6243 gboolean needs_color_matrix;
6244 gboolean keeps_size;
6245 gboolean do_crop;
6246 gboolean do_border;
6247 gboolean alpha_copy;
6248 gboolean alpha_set;
6249 gboolean alpha_mult;
6250 gint width_align, height_align;
6251 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
6252 GstVideoFrame * dest);
6253 } VideoTransform;
6254
6255 static const VideoTransform transforms[] = {
6256 /* planar -> packed */
6257 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
6258 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
6259 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
6260 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
6261 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
6262 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
6263
6264 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
6265 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
6266 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
6267 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
6268 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
6269 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
6270
6271 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6272 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_YUY2},
6273 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6274 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_UYVY},
6275 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6276 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_Y42B_AYUV},
6277
6278 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6279 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_YUY2},
6280 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6281 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_UYVY},
6282 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6283 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_Y444_AYUV},
6284
6285 /* packed -> packed */
6286 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, FALSE, TRUE,
6287 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6288 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6289 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2}, /* alias */
6290 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6291 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_YUY2_AYUV},
6292
6293 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, FALSE, TRUE,
6294 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6295 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6296 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2},
6297 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6298 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_UYVY_AYUV},
6299
6300 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, FALSE, TRUE, TRUE,
6301 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6302 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6303 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_YUY2},
6304 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6305 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_UYVY},
6306
6307 /* packed -> planar */
6308 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
6309 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
6310 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
6311 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
6312 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6313 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y42B},
6314 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6315 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y444},
6316 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_GRAY8, TRUE, TRUE, TRUE, TRUE,
6317 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_GRAY8},
6318
6319 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
6320 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
6321 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
6322 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
6323 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6324 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y42B},
6325 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6326 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y444},
6327
6328 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_I420, FALSE, FALSE, TRUE, TRUE,
6329 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
6330 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, TRUE, TRUE,
6331 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
6332 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6333 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_Y42B},
6334 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6335 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_AYUV_Y444},
6336
6337 /* planar -> planar */
6338 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_I420, TRUE, FALSE, FALSE, TRUE,
6339 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6340 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, FALSE, TRUE,
6341 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6342 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6343 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6344 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6345 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6346 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6347 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6348 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6349 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6350 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6351 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6352 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6353 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6354 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6355 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6356
6357 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_I420, TRUE, FALSE, FALSE, TRUE,
6358 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6359 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, FALSE, TRUE,
6360 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6361 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6362 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6363 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6364 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6365 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6366 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6367 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6368 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6369 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6370 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6371 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6372 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6373 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6374 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6375
6376 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6377 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6378 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6379 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6380 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y41B, TRUE, FALSE, FALSE, TRUE,
6381 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6382 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6383 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6384 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6385 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6386 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6387 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6388 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6389 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6390 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6391 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6392 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6393 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6394
6395 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6396 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6397 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6398 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6399 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6400 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6401 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, FALSE, TRUE,
6402 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6403 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6404 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6405 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6406 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6407 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6408 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6409 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6410 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6411 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6412 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6413
6414 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6415 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6416 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6417 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6418 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6419 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6420 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6421 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6422 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, FALSE, TRUE,
6423 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6424 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6425 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6426 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6427 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6428 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6429 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6430 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6431 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6432
6433 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6434 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6435 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6436 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6437 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6438 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6439 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6440 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6441 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6442 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6443 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_GRAY8, TRUE, FALSE, FALSE, TRUE,
6444 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6445 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6446 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6447 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6448 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6449 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6450 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6451
6452 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6453 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6454 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6455 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6456 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6457 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6458 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6459 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6460 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6461 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6462 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6463 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6464 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_A420, TRUE, FALSE, FALSE, TRUE,
6465 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6466 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6467 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6468 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6469 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6470
6471 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6472 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6473 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6474 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6475 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6476 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6477 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6478 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6479 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6480 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6481 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6482 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6483 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6484 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6485 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YUV9, TRUE, FALSE, FALSE, TRUE,
6486 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6487 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YVU9, TRUE, FALSE, FALSE, TRUE,
6488 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6489
6490 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6491 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6492 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6493 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6494 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6495 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6496 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6497 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6498 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6499 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6500 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6501 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6502 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6503 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6504 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YUV9, TRUE, FALSE, FALSE, TRUE,
6505 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6506 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YVU9, TRUE, FALSE, FALSE, TRUE,
6507 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6508
6509 /* sempiplanar -> semiplanar */
6510 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
6511 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6512 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
6513 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6514 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
6515 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6516
6517 {GST_VIDEO_FORMAT_NV21, GST_VIDEO_FORMAT_NV21, TRUE, FALSE, FALSE, TRUE,
6518 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6519
6520 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
6521 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6522 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
6523 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6524 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
6525 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6526
6527 {GST_VIDEO_FORMAT_NV61, GST_VIDEO_FORMAT_NV61, TRUE, FALSE, FALSE, TRUE,
6528 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6529
6530 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
6531 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6532 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
6533 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6534 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
6535 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6536
6537 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
6538 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ARGB, TRUE, TRUE, TRUE, TRUE, TRUE,
6539 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB},
6540 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRA, TRUE, TRUE, TRUE, TRUE, TRUE,
6541 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA},
6542 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xRGB, TRUE, TRUE, TRUE, TRUE, TRUE,
6543 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB}, /* alias */
6544 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRx, TRUE, TRUE, TRUE, TRUE, TRUE,
6545 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA}, /* alias */
6546 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ABGR, TRUE, TRUE, TRUE, TRUE, TRUE,
6547 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR},
6548 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBA, TRUE, TRUE, TRUE, TRUE, TRUE,
6549 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA},
6550 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xBGR, TRUE, TRUE, TRUE, TRUE, TRUE,
6551 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR}, /* alias */
6552 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBx, TRUE, TRUE, TRUE, TRUE, TRUE,
6553 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA}, /* alias */
6554 #endif
6555
6556 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
6557 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6558 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
6559 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6560 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
6561 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6562 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
6563 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6564
6565 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
6566 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6567 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
6568 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6569 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
6570 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6571 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
6572 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6573
6574 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
6575 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6576 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
6577 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6578 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
6579 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6580 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
6581 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6582 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
6583 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6584 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
6585 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6586 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
6587 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6588 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
6589 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6590 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
6591 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6592 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
6593 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6594
6595 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
6596 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6597 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
6598 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6599 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
6600 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6601 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
6602 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6603 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
6604 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6605 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
6606 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6607 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
6608 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6609 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
6610 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6611 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
6612 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6613 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
6614 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6615
6616 /* scalers */
6617 {GST_VIDEO_FORMAT_GBR, GST_VIDEO_FORMAT_GBR, TRUE, FALSE, FALSE, TRUE,
6618 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6619
6620 {GST_VIDEO_FORMAT_YVYU, GST_VIDEO_FORMAT_YVYU, TRUE, FALSE, FALSE, TRUE,
6621 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6622
6623 {GST_VIDEO_FORMAT_RGB15, GST_VIDEO_FORMAT_RGB15, TRUE, FALSE, FALSE, TRUE,
6624 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6625 {GST_VIDEO_FORMAT_RGB16, GST_VIDEO_FORMAT_RGB16, TRUE, FALSE, FALSE, TRUE,
6626 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6627 {GST_VIDEO_FORMAT_BGR15, GST_VIDEO_FORMAT_BGR15, TRUE, FALSE, FALSE, TRUE,
6628 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6629 {GST_VIDEO_FORMAT_BGR16, GST_VIDEO_FORMAT_BGR16, TRUE, FALSE, FALSE, TRUE,
6630 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6631
6632 {GST_VIDEO_FORMAT_RGB, GST_VIDEO_FORMAT_RGB, TRUE, FALSE, FALSE, TRUE, TRUE,
6633 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6634 {GST_VIDEO_FORMAT_BGR, GST_VIDEO_FORMAT_BGR, TRUE, FALSE, FALSE, TRUE, TRUE,
6635 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6636 {GST_VIDEO_FORMAT_v308, GST_VIDEO_FORMAT_v308, TRUE, FALSE, FALSE, TRUE, TRUE,
6637 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6638 {GST_VIDEO_FORMAT_IYU2, GST_VIDEO_FORMAT_IYU2, TRUE, FALSE, FALSE, TRUE, TRUE,
6639 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6640
6641 {GST_VIDEO_FORMAT_ARGB, GST_VIDEO_FORMAT_ARGB, TRUE, FALSE, FALSE, TRUE, TRUE,
6642 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6643 {GST_VIDEO_FORMAT_xRGB, GST_VIDEO_FORMAT_xRGB, TRUE, FALSE, FALSE, TRUE, TRUE,
6644 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6645 {GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_ABGR, TRUE, FALSE, FALSE, TRUE, TRUE,
6646 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6647 {GST_VIDEO_FORMAT_xBGR, GST_VIDEO_FORMAT_xBGR, TRUE, FALSE, FALSE, TRUE, TRUE,
6648 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6649 {GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_RGBA, TRUE, FALSE, FALSE, TRUE, TRUE,
6650 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6651 {GST_VIDEO_FORMAT_RGBx, GST_VIDEO_FORMAT_RGBx, TRUE, FALSE, FALSE, TRUE, TRUE,
6652 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6653 {GST_VIDEO_FORMAT_BGRA, GST_VIDEO_FORMAT_BGRA, TRUE, FALSE, FALSE, TRUE, TRUE,
6654 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6655 {GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_BGRx, TRUE, FALSE, FALSE, TRUE, TRUE,
6656 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6657
6658 {GST_VIDEO_FORMAT_ARGB64, GST_VIDEO_FORMAT_ARGB64, TRUE, FALSE, FALSE, TRUE,
6659 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6660 {GST_VIDEO_FORMAT_AYUV64, GST_VIDEO_FORMAT_AYUV64, TRUE, FALSE, FALSE, TRUE,
6661 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6662
6663 {GST_VIDEO_FORMAT_GRAY16_LE, GST_VIDEO_FORMAT_GRAY16_LE, TRUE, FALSE, FALSE,
6664 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6665 {GST_VIDEO_FORMAT_GRAY16_BE, GST_VIDEO_FORMAT_GRAY16_BE, TRUE, FALSE, FALSE,
6666 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6667 };
6668
6669 static gboolean
video_converter_lookup_fastpath(GstVideoConverter * convert)6670 video_converter_lookup_fastpath (GstVideoConverter * convert)
6671 {
6672 int i;
6673 GstVideoFormat in_format, out_format;
6674 GstVideoTransferFunction in_transf, out_transf;
6675 gboolean interlaced, same_matrix, same_primaries, same_size, crop, border;
6676 gboolean need_copy, need_set, need_mult;
6677 gint width, height;
6678
6679 width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
6680 height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);
6681
6682 if (GET_OPT_DITHER_QUANTIZATION (convert) != 1)
6683 return FALSE;
6684
6685 /* we don't do gamma conversion in fastpath */
6686 in_transf = convert->in_info.colorimetry.transfer;
6687 out_transf = convert->out_info.colorimetry.transfer;
6688
6689 same_size = (width == convert->out_width && height == convert->out_height);
6690
6691 /* fastpaths don't do gamma */
6692 if (CHECK_GAMMA_REMAP (convert) && (!same_size || in_transf != out_transf))
6693 return FALSE;
6694
6695 need_copy = (convert->alpha_mode & ALPHA_MODE_COPY) == ALPHA_MODE_COPY;
6696 need_set = (convert->alpha_mode & ALPHA_MODE_SET) == ALPHA_MODE_SET;
6697 need_mult = (convert->alpha_mode & ALPHA_MODE_MULT) == ALPHA_MODE_MULT;
6698 GST_DEBUG ("alpha copy %d, set %d, mult %d", need_copy, need_set, need_mult);
6699
6700 in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
6701 out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
6702
6703 if (CHECK_MATRIX_NONE (convert)) {
6704 same_matrix = TRUE;
6705 } else {
6706 GstVideoColorMatrix in_matrix, out_matrix;
6707
6708 in_matrix = convert->in_info.colorimetry.matrix;
6709 out_matrix = convert->out_info.colorimetry.matrix;
6710 same_matrix = in_matrix == out_matrix;
6711 }
6712
6713 if (CHECK_PRIMARIES_NONE (convert)) {
6714 same_primaries = TRUE;
6715 } else {
6716 GstVideoColorPrimaries in_primaries, out_primaries;
6717
6718 in_primaries = convert->in_info.colorimetry.primaries;
6719 out_primaries = convert->out_info.colorimetry.primaries;
6720 same_primaries = in_primaries == out_primaries;
6721 }
6722
6723 interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info);
6724 interlaced |= GST_VIDEO_INFO_IS_INTERLACED (&convert->out_info);
6725
6726 crop = convert->in_x || convert->in_y
6727 || convert->in_width < convert->in_maxwidth
6728 || convert->in_height < convert->in_maxheight;
6729 border = convert->out_x || convert->out_y
6730 || convert->out_width < convert->out_maxwidth
6731 || convert->out_height < convert->out_maxheight;
6732
6733 for (i = 0; i < G_N_ELEMENTS (transforms); i++) {
6734 if (transforms[i].in_format == in_format &&
6735 transforms[i].out_format == out_format &&
6736 (transforms[i].keeps_interlaced || !interlaced) &&
6737 (transforms[i].needs_color_matrix || (same_matrix && same_primaries))
6738 && (!transforms[i].keeps_size || same_size)
6739 && (transforms[i].width_align & width) == 0
6740 && (transforms[i].height_align & height) == 0
6741 && (transforms[i].do_crop || !crop)
6742 && (transforms[i].do_border || !border)
6743 && (transforms[i].alpha_copy || !need_copy)
6744 && (transforms[i].alpha_set || !need_set)
6745 && (transforms[i].alpha_mult || !need_mult)) {
6746 guint j;
6747
6748 GST_DEBUG ("using fastpath");
6749 if (transforms[i].needs_color_matrix)
6750 video_converter_compute_matrix (convert);
6751 convert->convert = transforms[i].convert;
6752
6753 convert->tmpline =
6754 g_new (guint16 *, convert->conversion_runner->n_threads);
6755 for (j = 0; j < convert->conversion_runner->n_threads; j++)
6756 convert->tmpline[j] = g_malloc0 (sizeof (guint16) * (width + 8) * 4);
6757
6758 if (!transforms[i].keeps_size)
6759 if (!setup_scale (convert))
6760 return FALSE;
6761 if (border)
6762 setup_borderline (convert);
6763 return TRUE;
6764 }
6765 }
6766 GST_DEBUG ("no fastpath found");
6767 return FALSE;
6768 }
6769