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 #include <gst/base/base.h>
38
39 #include "video-orc.h"
40
41 /**
42 * SECTION:videoconverter
43 * @title: GstVideoConverter
44 * @short_description: Generic video conversion
45 *
46 * This object is used to convert video frames from one format to another.
47 * The object can perform conversion of:
48 *
49 * * video format
50 * * video colorspace
51 * * chroma-siting
52 * * video size
53 *
54 */
55
56 /*
57 * (a) unpack
58 * (b) chroma upsample
59 * (c) (convert Y'CbCr to R'G'B')
60 * (d) gamma decode
61 * (e) downscale
62 * (f) colorspace convert through XYZ
63 * (g) upscale
64 * (h) gamma encode
65 * (i) (convert R'G'B' to Y'CbCr)
66 * (j) chroma downsample
67 * (k) pack
68 *
69 * quality options
70 *
71 * (a) range truncate, range expand
72 * (b) full upsample, 1-1 non-cosited upsample, no upsample
73 * (c) 8 bits, 16 bits
74 * (d)
75 * (e) 8 bits, 16 bits
76 * (f) 8 bits, 16 bits
77 * (g) 8 bits, 16 bits
78 * (h)
79 * (i) 8 bits, 16 bits
80 * (j) 1-1 cosited downsample, no downsample
81 * (k)
82 *
83 *
84 * 1 : a -> -> -> -> e -> f -> g -> -> -> -> k
85 * 2 : a -> -> -> -> e -> f* -> g -> -> -> -> k
86 * 3 : a -> -> -> -> e* -> f* -> g* -> -> -> -> k
87 * 4 : a -> b -> -> -> e -> f -> g -> -> -> j -> k
88 * 5 : a -> b -> -> -> e* -> f* -> g* -> -> -> j -> k
89 * 6 : a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k
90 * 7 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
91 *
92 * 8 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
93 * 9 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
94 * 10 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
95 */
96
97 #ifndef GST_DISABLE_GST_DEBUG
98 #define GST_CAT_DEFAULT ensure_debug_category()
99 static GstDebugCategory *
ensure_debug_category(void)100 ensure_debug_category (void)
101 {
102 static gsize cat_gonce = 0;
103
104 if (g_once_init_enter (&cat_gonce)) {
105 gsize cat_done;
106
107 cat_done = (gsize) _gst_debug_category_new ("video-converter", 0,
108 "video-converter object");
109
110 g_once_init_leave (&cat_gonce, cat_done);
111 }
112
113 return (GstDebugCategory *) cat_gonce;
114 }
115 #else
116 #define ensure_debug_category() /* NOOP */
117 #endif /* GST_DISABLE_GST_DEBUG */
118
119 typedef void (*GstParallelizedTaskFunc) (gpointer user_data);
120
121 typedef struct _GstParallelizedTaskRunner GstParallelizedTaskRunner;
122 typedef struct _GstParallelizedWorkItem GstParallelizedWorkItem;
123
124 struct _GstParallelizedWorkItem
125 {
126 GstParallelizedTaskRunner *self;
127 GstParallelizedTaskFunc func;
128 gpointer user_data;
129 };
130
131 struct _GstParallelizedTaskRunner
132 {
133 GstTaskPool *pool;
134 gboolean own_pool;
135 guint n_threads;
136
137 GstQueueArray *tasks;
138 GstQueueArray *work_items;
139
140 GMutex lock;
141
142 gboolean async_tasks;
143 };
144
145 static void
gst_parallelized_task_thread_func(gpointer data)146 gst_parallelized_task_thread_func (gpointer data)
147 {
148 GstParallelizedTaskRunner *runner = data;
149 GstParallelizedWorkItem *work_item;
150
151 g_mutex_lock (&runner->lock);
152 work_item = gst_queue_array_pop_head (runner->work_items);
153 g_mutex_unlock (&runner->lock);
154
155 g_assert (work_item != NULL);
156 g_assert (work_item->func != NULL);
157
158
159 work_item->func (work_item->user_data);
160 if (runner->async_tasks)
161 g_free (work_item);
162 }
163
164 static void
gst_parallelized_task_runner_join(GstParallelizedTaskRunner * self)165 gst_parallelized_task_runner_join (GstParallelizedTaskRunner * self)
166 {
167 gboolean joined = FALSE;
168
169 while (!joined) {
170 g_mutex_lock (&self->lock);
171 if (!(joined = gst_queue_array_is_empty (self->tasks))) {
172 gpointer task = gst_queue_array_pop_head (self->tasks);
173 g_mutex_unlock (&self->lock);
174 gst_task_pool_join (self->pool, task);
175 } else {
176 g_mutex_unlock (&self->lock);
177 }
178 }
179 }
180
181 static void
gst_parallelized_task_runner_free(GstParallelizedTaskRunner * self)182 gst_parallelized_task_runner_free (GstParallelizedTaskRunner * self)
183 {
184 gst_parallelized_task_runner_join (self);
185
186 gst_queue_array_free (self->work_items);
187 gst_queue_array_free (self->tasks);
188 if (self->own_pool)
189 gst_task_pool_cleanup (self->pool);
190 gst_object_unref (self->pool);
191 g_mutex_clear (&self->lock);
192 g_free (self);
193 }
194
195 static GstParallelizedTaskRunner *
gst_parallelized_task_runner_new(guint n_threads,GstTaskPool * pool,gboolean async_tasks)196 gst_parallelized_task_runner_new (guint n_threads, GstTaskPool * pool,
197 gboolean async_tasks)
198 {
199 GstParallelizedTaskRunner *self;
200
201 if (n_threads == 0)
202 n_threads = g_get_num_processors ();
203
204 self = g_new0 (GstParallelizedTaskRunner, 1);
205
206 if (pool) {
207 self->pool = g_object_ref (pool);
208 self->own_pool = FALSE;
209
210 /* No reason to split up the work between more threads than the
211 * pool can spawn */
212 if (GST_IS_SHARED_TASK_POOL (pool))
213 n_threads =
214 MIN (n_threads,
215 gst_shared_task_pool_get_max_threads (GST_SHARED_TASK_POOL (pool)));
216 } else {
217 self->pool = gst_shared_task_pool_new ();
218 self->own_pool = TRUE;
219 gst_shared_task_pool_set_max_threads (GST_SHARED_TASK_POOL (self->pool),
220 n_threads);
221 gst_task_pool_prepare (self->pool, NULL);
222 }
223
224 self->tasks = gst_queue_array_new (n_threads);
225 self->work_items = gst_queue_array_new (n_threads);
226
227 self->n_threads = n_threads;
228
229 g_mutex_init (&self->lock);
230
231 /* Set when scheduling a job */
232 self->async_tasks = async_tasks;
233
234 return self;
235 }
236
237 static void
gst_parallelized_task_runner_finish(GstParallelizedTaskRunner * self)238 gst_parallelized_task_runner_finish (GstParallelizedTaskRunner * self)
239 {
240 gst_parallelized_task_runner_join (self);
241 }
242
243 static void
gst_parallelized_task_runner_run(GstParallelizedTaskRunner * self,GstParallelizedTaskFunc func,gpointer * task_data)244 gst_parallelized_task_runner_run (GstParallelizedTaskRunner * self,
245 GstParallelizedTaskFunc func, gpointer * task_data)
246 {
247 guint n_threads = self->n_threads;
248
249 if (n_threads > 1 || self->async_tasks) {
250 guint i = 0;
251 g_mutex_lock (&self->lock);
252 if (!self->async_tasks) {
253 /* if not async, perform one of the functions in the current thread */
254 i = 1;
255 }
256 for (; i < n_threads; i++) {
257 gpointer task;
258 GstParallelizedWorkItem *work_item;
259
260 if (!self->async_tasks)
261 work_item = g_newa (GstParallelizedWorkItem, 1);
262 else
263 work_item = g_new0 (GstParallelizedWorkItem, 1);
264
265 work_item->self = self;
266 work_item->func = func;
267 work_item->user_data = task_data[i];
268 gst_queue_array_push_tail (self->work_items, work_item);
269
270 task =
271 gst_task_pool_push (self->pool, gst_parallelized_task_thread_func,
272 self, NULL);
273
274 /* The return value of push() is unfortunately nullable, and we can't deal with that */
275 g_assert (task != NULL);
276 gst_queue_array_push_tail (self->tasks, task);
277 }
278 g_mutex_unlock (&self->lock);
279 }
280
281 if (!self->async_tasks) {
282 func (task_data[0]);
283
284 gst_parallelized_task_runner_finish (self);
285 }
286 }
287
288 typedef struct _GstLineCache GstLineCache;
289
290 #define SCALE (8)
291 #define SCALE_F ((float) (1 << SCALE))
292
293 typedef struct _MatrixData MatrixData;
294
295 struct _MatrixData
296 {
297 gdouble dm[4][4];
298 gint im[4][4];
299 gint width;
300 guint64 orc_p1;
301 guint64 orc_p2;
302 guint64 orc_p3;
303 guint64 orc_p4;
304 gint64 *t_r;
305 gint64 *t_g;
306 gint64 *t_b;
307 gint64 t_c;
308 void (*matrix_func) (MatrixData * data, gpointer pixels);
309 };
310
311 typedef struct _GammaData GammaData;
312
313 struct _GammaData
314 {
315 gpointer gamma_table;
316 gint width;
317 void (*gamma_func) (GammaData * data, gpointer dest, gpointer src);
318 };
319
320 typedef enum
321 {
322 ALPHA_MODE_NONE = 0,
323 ALPHA_MODE_COPY = (1 << 0),
324 ALPHA_MODE_SET = (1 << 1),
325 ALPHA_MODE_MULT = (1 << 2)
326 } AlphaMode;
327
328 typedef struct
329 {
330 guint8 *data;
331 guint stride;
332 guint n_lines;
333 guint idx;
334 gpointer user_data;
335 GDestroyNotify notify;
336 } ConverterAlloc;
337
338 typedef void (*FastConvertFunc) (GstVideoConverter * convert,
339 const GstVideoFrame * src, GstVideoFrame * dest, gint plane);
340
341 struct _GstVideoConverter
342 {
343 gint flags;
344
345 GstVideoInfo in_info;
346 GstVideoInfo out_info;
347
348 gint in_x;
349 gint in_y;
350 gint in_width;
351 gint in_height;
352 gint in_maxwidth;
353 gint in_maxheight;
354 gint out_x;
355 gint out_y;
356 gint out_width;
357 gint out_height;
358 gint out_maxwidth;
359 gint out_maxheight;
360
361 gint current_pstride;
362 gint current_width;
363 gint current_height;
364 GstVideoFormat current_format;
365 gint current_bits;
366
367 GstStructure *config;
368
369 GstParallelizedTaskRunner *conversion_runner;
370
371 guint16 **tmpline;
372
373 gboolean fill_border;
374 gpointer borderline;
375 guint64 borders[4];
376 guint32 border_argb;
377 guint32 alpha_value;
378 AlphaMode alpha_mode;
379
380 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
381 GstVideoFrame * dest);
382
383 /* data for unpack */
384 GstLineCache **unpack_lines;
385 GstVideoFormat unpack_format;
386 guint unpack_bits;
387 gboolean unpack_rgb;
388 gboolean identity_unpack;
389 gint unpack_pstride;
390
391 /* chroma upsample */
392 GstLineCache **upsample_lines;
393 GstVideoChromaResample **upsample;
394 GstVideoChromaResample **upsample_p;
395 GstVideoChromaResample **upsample_i;
396 guint up_n_lines;
397 gint up_offset;
398
399 /* to R'G'B */
400 GstLineCache **to_RGB_lines;
401 MatrixData to_RGB_matrix;
402 /* gamma decode */
403 GammaData gamma_dec;
404
405 /* scaling */
406 GstLineCache **hscale_lines;
407 GstVideoScaler **h_scaler;
408 gint h_scale_format;
409 GstLineCache **vscale_lines;
410 GstVideoScaler **v_scaler;
411 GstVideoScaler **v_scaler_p;
412 GstVideoScaler **v_scaler_i;
413 gint v_scale_width;
414 gint v_scale_format;
415
416 /* color space conversion */
417 GstLineCache **convert_lines;
418 MatrixData convert_matrix;
419 gint in_bits;
420 gint out_bits;
421
422 /* alpha correction */
423 GstLineCache **alpha_lines;
424 void (*alpha_func) (GstVideoConverter * convert, gpointer pixels, gint width);
425
426 /* gamma encode */
427 GammaData gamma_enc;
428 /* to Y'CbCr */
429 GstLineCache **to_YUV_lines;
430 MatrixData to_YUV_matrix;
431
432 /* chroma downsample */
433 GstLineCache **downsample_lines;
434 GstVideoChromaResample **downsample;
435 GstVideoChromaResample **downsample_p;
436 GstVideoChromaResample **downsample_i;
437 guint down_n_lines;
438 gint down_offset;
439
440 /* dither */
441 GstLineCache **dither_lines;
442 GstVideoDither **dither;
443
444 /* pack */
445 GstLineCache **pack_lines;
446 guint pack_nlines;
447 GstVideoFormat pack_format;
448 guint pack_bits;
449 gboolean pack_rgb;
450 gboolean identity_pack;
451 gint pack_pstride;
452 gconstpointer pack_pal;
453 gsize pack_palsize;
454
455 const GstVideoFrame *src;
456 GstVideoFrame *dest;
457
458 /* fastpath */
459 GstVideoFormat fformat[4];
460 gint fin_x[4];
461 gint fin_y[4];
462 gint fout_x[4];
463 gint fout_y[4];
464 gint fout_width[4];
465 gint fout_height[4];
466 gint fsplane[4];
467 gint ffill[4];
468
469 struct
470 {
471 GstVideoScaler **scaler;
472 } fh_scaler[4];
473 struct
474 {
475 GstVideoScaler **scaler;
476 } fv_scaler[4];
477 FastConvertFunc fconvert[4];
478
479 /* for parallel async running */
480 gpointer tasks[4];
481 gpointer tasks_p[4];
482 };
483
484 typedef gpointer (*GstLineCacheAllocLineFunc) (GstLineCache * cache, gint idx,
485 gpointer user_data);
486 typedef gboolean (*GstLineCacheNeedLineFunc) (GstLineCache * cache, gint idx,
487 gint out_line, gint in_line, gpointer user_data);
488
489 struct _GstLineCache
490 {
491 gint first;
492 gint backlog;
493 GPtrArray *lines;
494
495 GstLineCache *prev;
496 gboolean write_input;
497 gboolean pass_alloc;
498 gboolean alloc_writable;
499
500 GstLineCacheNeedLineFunc need_line;
501 gint need_line_idx;
502 gpointer need_line_data;
503 GDestroyNotify need_line_notify;
504
505 guint n_lines;
506 guint stride;
507 GstLineCacheAllocLineFunc alloc_line;
508 gpointer alloc_line_data;
509 GDestroyNotify alloc_line_notify;
510 };
511
512 static GstLineCache *
gst_line_cache_new(GstLineCache * prev)513 gst_line_cache_new (GstLineCache * prev)
514 {
515 GstLineCache *result;
516
517 result = g_slice_new0 (GstLineCache);
518 result->lines = g_ptr_array_new ();
519 result->prev = prev;
520
521 return result;
522 }
523
524 static void
gst_line_cache_clear(GstLineCache * cache)525 gst_line_cache_clear (GstLineCache * cache)
526 {
527 g_return_if_fail (cache != NULL);
528
529 g_ptr_array_set_size (cache->lines, 0);
530 cache->first = 0;
531 }
532
533 static void
gst_line_cache_free(GstLineCache * cache)534 gst_line_cache_free (GstLineCache * cache)
535 {
536 if (cache->need_line_notify)
537 cache->need_line_notify (cache->need_line_data);
538 if (cache->alloc_line_notify)
539 cache->alloc_line_notify (cache->alloc_line_data);
540 gst_line_cache_clear (cache);
541 g_ptr_array_unref (cache->lines);
542 g_slice_free (GstLineCache, cache);
543 }
544
545 static void
gst_line_cache_set_need_line_func(GstLineCache * cache,GstLineCacheNeedLineFunc need_line,gint idx,gpointer user_data,GDestroyNotify notify)546 gst_line_cache_set_need_line_func (GstLineCache * cache,
547 GstLineCacheNeedLineFunc need_line, gint idx, gpointer user_data,
548 GDestroyNotify notify)
549 {
550 cache->need_line = need_line;
551 cache->need_line_idx = idx;
552 cache->need_line_data = user_data;
553 cache->need_line_notify = notify;
554 }
555
556 static void
gst_line_cache_set_alloc_line_func(GstLineCache * cache,GstLineCacheAllocLineFunc alloc_line,gpointer user_data,GDestroyNotify notify)557 gst_line_cache_set_alloc_line_func (GstLineCache * cache,
558 GstLineCacheAllocLineFunc alloc_line, gpointer user_data,
559 GDestroyNotify notify)
560 {
561 cache->alloc_line = alloc_line;
562 cache->alloc_line_data = user_data;
563 cache->alloc_line_notify = notify;
564 }
565
566 /* keep this much backlog for interlaced video */
567 #define BACKLOG 2
568
569 static gpointer *
gst_line_cache_get_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gint n_lines)570 gst_line_cache_get_lines (GstLineCache * cache, gint idx, gint out_line,
571 gint in_line, gint n_lines)
572 {
573 if (cache->first + cache->backlog < in_line) {
574 gint to_remove =
575 MIN (in_line - (cache->first + cache->backlog), cache->lines->len);
576 if (to_remove > 0) {
577 g_ptr_array_remove_range (cache->lines, 0, to_remove);
578 }
579 cache->first += to_remove;
580 } else if (in_line < cache->first) {
581 gst_line_cache_clear (cache);
582 cache->first = in_line;
583 }
584
585 while (TRUE) {
586 gint oline;
587
588 if (cache->first <= in_line
589 && in_line + n_lines <= cache->first + (gint) cache->lines->len) {
590 return cache->lines->pdata + (in_line - cache->first);
591 }
592
593 if (cache->need_line == NULL)
594 break;
595
596 /* We may be able to skip ahead to the earliest line needed */
597 if (cache->lines->len == 0 && cache->first + cache->backlog < in_line)
598 cache->first = in_line - cache->backlog;
599
600 oline = out_line + cache->first + cache->lines->len - in_line;
601
602 if (!cache->need_line (cache, idx, oline, cache->first + cache->lines->len,
603 cache->need_line_data))
604 break;
605 }
606 GST_DEBUG ("no lines");
607 return NULL;
608 }
609
610 static void
gst_line_cache_add_line(GstLineCache * cache,gint idx,gpointer line)611 gst_line_cache_add_line (GstLineCache * cache, gint idx, gpointer line)
612 {
613 if (cache->first + cache->lines->len != idx) {
614 gst_line_cache_clear (cache);
615 cache->first = idx;
616 }
617 g_ptr_array_add (cache->lines, line);
618 }
619
620 static gpointer
gst_line_cache_alloc_line(GstLineCache * cache,gint idx)621 gst_line_cache_alloc_line (GstLineCache * cache, gint idx)
622 {
623 gpointer res;
624
625 if (cache->alloc_line)
626 res = cache->alloc_line (cache, idx, cache->alloc_line_data);
627 else
628 res = NULL;
629
630 return res;
631 }
632
633 static void video_converter_generic (GstVideoConverter * convert,
634 const GstVideoFrame * src, GstVideoFrame * dest);
635 static gboolean video_converter_lookup_fastpath (GstVideoConverter * convert);
636 static void video_converter_compute_matrix (GstVideoConverter * convert);
637 static void video_converter_compute_resample (GstVideoConverter * convert,
638 gint idx);
639
640 static gpointer get_dest_line (GstLineCache * cache, gint idx,
641 gpointer user_data);
642
643 static gboolean do_unpack_lines (GstLineCache * cache, gint idx, gint out_line,
644 gint in_line, gpointer user_data);
645 static gboolean do_downsample_lines (GstLineCache * cache, gint idx,
646 gint out_line, gint in_line, gpointer user_data);
647 static gboolean do_convert_to_RGB_lines (GstLineCache * cache, gint idx,
648 gint out_line, gint in_line, gpointer user_data);
649 static gboolean do_convert_lines (GstLineCache * cache, gint idx, gint out_line,
650 gint in_line, gpointer user_data);
651 static gboolean do_alpha_lines (GstLineCache * cache, gint idx, gint out_line,
652 gint in_line, gpointer user_data);
653 static gboolean do_convert_to_YUV_lines (GstLineCache * cache, gint idx,
654 gint out_line, gint in_line, gpointer user_data);
655 static gboolean do_upsample_lines (GstLineCache * cache, gint idx,
656 gint out_line, gint in_line, gpointer user_data);
657 static gboolean do_vscale_lines (GstLineCache * cache, gint idx, gint out_line,
658 gint in_line, gpointer user_data);
659 static gboolean do_hscale_lines (GstLineCache * cache, gint idx, gint out_line,
660 gint in_line, gpointer user_data);
661 static gboolean do_dither_lines (GstLineCache * cache, gint idx, gint out_line,
662 gint in_line, gpointer user_data);
663
664 static ConverterAlloc *
converter_alloc_new(guint stride,guint n_lines,gpointer user_data,GDestroyNotify notify)665 converter_alloc_new (guint stride, guint n_lines, gpointer user_data,
666 GDestroyNotify notify)
667 {
668 ConverterAlloc *alloc;
669
670 GST_DEBUG ("stride %d, n_lines %d", stride, n_lines);
671 alloc = g_slice_new0 (ConverterAlloc);
672 alloc->data = g_malloc (stride * n_lines);
673 alloc->stride = stride;
674 alloc->n_lines = n_lines;
675 alloc->idx = 0;
676 alloc->user_data = user_data;
677 alloc->notify = notify;
678
679 return alloc;
680 }
681
682 static void
converter_alloc_free(ConverterAlloc * alloc)683 converter_alloc_free (ConverterAlloc * alloc)
684 {
685 if (alloc->notify)
686 alloc->notify (alloc->user_data);
687 g_free (alloc->data);
688 g_slice_free (ConverterAlloc, alloc);
689 }
690
691 static void
setup_border_alloc(GstVideoConverter * convert,ConverterAlloc * alloc)692 setup_border_alloc (GstVideoConverter * convert, ConverterAlloc * alloc)
693 {
694 gint i;
695
696 if (convert->borderline) {
697 for (i = 0; i < alloc->n_lines; i++)
698 memcpy (&alloc->data[i * alloc->stride], convert->borderline,
699 alloc->stride);
700 }
701 }
702
703 static gpointer
get_temp_line(GstLineCache * cache,gint idx,gpointer user_data)704 get_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
705 {
706 ConverterAlloc *alloc = user_data;
707 gpointer tmpline;
708
709 GST_DEBUG ("get temp line %d (%p %d)", idx, alloc, alloc->idx);
710 tmpline = &alloc->data[alloc->stride * alloc->idx];
711 alloc->idx = (alloc->idx + 1) % alloc->n_lines;
712
713 return tmpline;
714 }
715
716 static gpointer
get_border_temp_line(GstLineCache * cache,gint idx,gpointer user_data)717 get_border_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
718 {
719 ConverterAlloc *alloc = user_data;
720 GstVideoConverter *convert = alloc->user_data;
721 gpointer tmpline;
722
723 GST_DEBUG ("get temp line %d (%p %d)", idx, alloc, alloc->idx);
724 tmpline = &alloc->data[alloc->stride * alloc->idx] +
725 (convert->out_x * convert->pack_pstride);
726 alloc->idx = (alloc->idx + 1) % alloc->n_lines;
727
728 return tmpline;
729 }
730
731 static gint
get_opt_int(GstVideoConverter * convert,const gchar * opt,gint def)732 get_opt_int (GstVideoConverter * convert, const gchar * opt, gint def)
733 {
734 gint res;
735 if (!gst_structure_get_int (convert->config, opt, &res))
736 res = def;
737 return res;
738 }
739
740 static guint
get_opt_uint(GstVideoConverter * convert,const gchar * opt,guint def)741 get_opt_uint (GstVideoConverter * convert, const gchar * opt, guint def)
742 {
743 guint res;
744 if (!gst_structure_get_uint (convert->config, opt, &res))
745 res = def;
746 return res;
747 }
748
749 static gdouble
get_opt_double(GstVideoConverter * convert,const gchar * opt,gdouble def)750 get_opt_double (GstVideoConverter * convert, const gchar * opt, gdouble def)
751 {
752 gdouble res;
753 if (!gst_structure_get_double (convert->config, opt, &res))
754 res = def;
755 return res;
756 }
757
758 static gboolean
get_opt_bool(GstVideoConverter * convert,const gchar * opt,gboolean def)759 get_opt_bool (GstVideoConverter * convert, const gchar * opt, gboolean def)
760 {
761 gboolean res;
762 if (!gst_structure_get_boolean (convert->config, opt, &res))
763 res = def;
764 return res;
765 }
766
767 static gint
get_opt_enum(GstVideoConverter * convert,const gchar * opt,GType type,gint def)768 get_opt_enum (GstVideoConverter * convert, const gchar * opt, GType type,
769 gint def)
770 {
771 gint res;
772 if (!gst_structure_get_enum (convert->config, opt, type, &res))
773 res = def;
774 return res;
775 }
776
777 #define DEFAULT_OPT_FILL_BORDER TRUE
778 #define DEFAULT_OPT_ALPHA_VALUE 1.0
779 /* options copy, set, mult */
780 #define DEFAULT_OPT_ALPHA_MODE GST_VIDEO_ALPHA_MODE_COPY
781 #define DEFAULT_OPT_BORDER_ARGB 0xff000000
782 /* options full, input-only, output-only, none */
783 #define DEFAULT_OPT_MATRIX_MODE GST_VIDEO_MATRIX_MODE_FULL
784 /* none, remap */
785 #define DEFAULT_OPT_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
786 /* none, merge-only, fast */
787 #define DEFAULT_OPT_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
788 /* options full, upsample-only, downsample-only, none */
789 #define DEFAULT_OPT_CHROMA_MODE GST_VIDEO_CHROMA_MODE_FULL
790 #define DEFAULT_OPT_RESAMPLER_METHOD GST_VIDEO_RESAMPLER_METHOD_CUBIC
791 #define DEFAULT_OPT_CHROMA_RESAMPLER_METHOD GST_VIDEO_RESAMPLER_METHOD_LINEAR
792 #define DEFAULT_OPT_RESAMPLER_TAPS 0
793 #define DEFAULT_OPT_DITHER_METHOD GST_VIDEO_DITHER_BAYER
794 #define DEFAULT_OPT_DITHER_QUANTIZATION 1
795 #define DEFAULT_OPT_ASYNC_TASKS FALSE
796
797 #define GET_OPT_FILL_BORDER(c) get_opt_bool(c, \
798 GST_VIDEO_CONVERTER_OPT_FILL_BORDER, DEFAULT_OPT_FILL_BORDER)
799 #define GET_OPT_ALPHA_VALUE(c) get_opt_double(c, \
800 GST_VIDEO_CONVERTER_OPT_ALPHA_VALUE, DEFAULT_OPT_ALPHA_VALUE)
801 #define GET_OPT_ALPHA_MODE(c) get_opt_enum(c, \
802 GST_VIDEO_CONVERTER_OPT_ALPHA_MODE, GST_TYPE_VIDEO_ALPHA_MODE, DEFAULT_OPT_ALPHA_MODE)
803 #define GET_OPT_BORDER_ARGB(c) get_opt_uint(c, \
804 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB)
805 #define GET_OPT_MATRIX_MODE(c) get_opt_enum(c, \
806 GST_VIDEO_CONVERTER_OPT_MATRIX_MODE, GST_TYPE_VIDEO_MATRIX_MODE, DEFAULT_OPT_MATRIX_MODE)
807 #define GET_OPT_GAMMA_MODE(c) get_opt_enum(c, \
808 GST_VIDEO_CONVERTER_OPT_GAMMA_MODE, GST_TYPE_VIDEO_GAMMA_MODE, DEFAULT_OPT_GAMMA_MODE)
809 #define GET_OPT_PRIMARIES_MODE(c) get_opt_enum(c, \
810 GST_VIDEO_CONVERTER_OPT_PRIMARIES_MODE, GST_TYPE_VIDEO_PRIMARIES_MODE, DEFAULT_OPT_PRIMARIES_MODE)
811 #define GET_OPT_CHROMA_MODE(c) get_opt_enum(c, \
812 GST_VIDEO_CONVERTER_OPT_CHROMA_MODE, GST_TYPE_VIDEO_CHROMA_MODE, DEFAULT_OPT_CHROMA_MODE)
813 #define GET_OPT_RESAMPLER_METHOD(c) get_opt_enum(c, \
814 GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD, GST_TYPE_VIDEO_RESAMPLER_METHOD, \
815 DEFAULT_OPT_RESAMPLER_METHOD)
816 #define GET_OPT_CHROMA_RESAMPLER_METHOD(c) get_opt_enum(c, \
817 GST_VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD, GST_TYPE_VIDEO_RESAMPLER_METHOD, \
818 DEFAULT_OPT_CHROMA_RESAMPLER_METHOD)
819 #define GET_OPT_RESAMPLER_TAPS(c) get_opt_uint(c, \
820 GST_VIDEO_CONVERTER_OPT_RESAMPLER_TAPS, DEFAULT_OPT_RESAMPLER_TAPS)
821 #define GET_OPT_DITHER_METHOD(c) get_opt_enum(c, \
822 GST_VIDEO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_VIDEO_DITHER_METHOD, \
823 DEFAULT_OPT_DITHER_METHOD)
824 #define GET_OPT_DITHER_QUANTIZATION(c) get_opt_uint(c, \
825 GST_VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, DEFAULT_OPT_DITHER_QUANTIZATION)
826 #define GET_OPT_ASYNC_TASKS(c) get_opt_bool(c, \
827 GST_VIDEO_CONVERTER_OPT_ASYNC_TASKS, DEFAULT_OPT_ASYNC_TASKS)
828
829 #define CHECK_ALPHA_COPY(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_COPY)
830 #define CHECK_ALPHA_SET(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_SET)
831 #define CHECK_ALPHA_MULT(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_MULT)
832
833 #define CHECK_MATRIX_FULL(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_FULL)
834 #define CHECK_MATRIX_INPUT(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_INPUT_ONLY)
835 #define CHECK_MATRIX_OUTPUT(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_OUTPUT_ONLY)
836 #define CHECK_MATRIX_NONE(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_NONE)
837
838 #define CHECK_GAMMA_NONE(c) (GET_OPT_GAMMA_MODE(c) == GST_VIDEO_GAMMA_MODE_NONE)
839 #define CHECK_GAMMA_REMAP(c) (GET_OPT_GAMMA_MODE(c) == GST_VIDEO_GAMMA_MODE_REMAP)
840
841 #define CHECK_PRIMARIES_NONE(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_NONE)
842 #define CHECK_PRIMARIES_MERGE(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_MERGE_ONLY)
843 #define CHECK_PRIMARIES_FAST(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_FAST)
844
845 #define CHECK_CHROMA_FULL(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_FULL)
846 #define CHECK_CHROMA_UPSAMPLE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_UPSAMPLE_ONLY)
847 #define CHECK_CHROMA_DOWNSAMPLE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_DOWNSAMPLE_ONLY)
848 #define CHECK_CHROMA_NONE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_NONE)
849
850 static GstLineCache *
chain_unpack_line(GstVideoConverter * convert,gint idx)851 chain_unpack_line (GstVideoConverter * convert, gint idx)
852 {
853 GstLineCache *prev;
854 GstVideoInfo *info;
855
856 info = &convert->in_info;
857
858 convert->current_format = convert->unpack_format;
859 convert->current_bits = convert->unpack_bits;
860 convert->current_pstride = convert->current_bits >> 1;
861
862 convert->unpack_pstride = convert->current_pstride;
863 convert->identity_unpack = (convert->current_format == info->finfo->format);
864
865 GST_DEBUG ("chain unpack line format %s, pstride %d, identity_unpack %d",
866 gst_video_format_to_string (convert->current_format),
867 convert->current_pstride, convert->identity_unpack);
868
869 prev = convert->unpack_lines[idx] = gst_line_cache_new (NULL);
870 prev->write_input = FALSE;
871 prev->pass_alloc = FALSE;
872 prev->n_lines = 1;
873 prev->stride = convert->current_pstride * convert->current_width;
874 gst_line_cache_set_need_line_func (prev, do_unpack_lines, idx, convert, NULL);
875
876 return prev;
877 }
878
879 static GstLineCache *
chain_upsample(GstVideoConverter * convert,GstLineCache * prev,gint idx)880 chain_upsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
881 {
882 video_converter_compute_resample (convert, idx);
883
884 if (convert->upsample_p[idx] || convert->upsample_i[idx]) {
885 GST_DEBUG ("chain upsample");
886 prev = convert->upsample_lines[idx] = gst_line_cache_new (prev);
887 prev->write_input = TRUE;
888 prev->pass_alloc = TRUE;
889 /* XXX: why this hardcoded value? */
890 prev->n_lines = 5;
891 prev->stride = convert->current_pstride * convert->current_width;
892 gst_line_cache_set_need_line_func (prev,
893 do_upsample_lines, idx, convert, NULL);
894 }
895 return prev;
896 }
897
898 static void
color_matrix_set_identity(MatrixData * m)899 color_matrix_set_identity (MatrixData * m)
900 {
901 int i, j;
902
903 for (i = 0; i < 4; i++) {
904 for (j = 0; j < 4; j++) {
905 m->dm[i][j] = (i == j);
906 }
907 }
908 }
909
910 static void
color_matrix_copy(MatrixData * d,const MatrixData * s)911 color_matrix_copy (MatrixData * d, const MatrixData * s)
912 {
913 gint i, j;
914
915 for (i = 0; i < 4; i++)
916 for (j = 0; j < 4; j++)
917 d->dm[i][j] = s->dm[i][j];
918 }
919
920 /* Perform 4x4 matrix multiplication:
921 * - @dst@ = @a@ * @b@
922 * - @dst@ may be a pointer to @a@ andor @b@
923 */
924 static void
color_matrix_multiply(MatrixData * dst,MatrixData * a,MatrixData * b)925 color_matrix_multiply (MatrixData * dst, MatrixData * a, MatrixData * b)
926 {
927 MatrixData tmp;
928 int i, j, k;
929
930 for (i = 0; i < 4; i++) {
931 for (j = 0; j < 4; j++) {
932 double x = 0;
933 for (k = 0; k < 4; k++) {
934 x += a->dm[i][k] * b->dm[k][j];
935 }
936 tmp.dm[i][j] = x;
937 }
938 }
939 color_matrix_copy (dst, &tmp);
940 }
941
942 static void
color_matrix_invert(MatrixData * d,MatrixData * s)943 color_matrix_invert (MatrixData * d, MatrixData * s)
944 {
945 MatrixData tmp;
946 int i, j;
947 double det;
948
949 color_matrix_set_identity (&tmp);
950 for (j = 0; j < 3; j++) {
951 for (i = 0; i < 3; i++) {
952 tmp.dm[j][i] =
953 s->dm[(i + 1) % 3][(j + 1) % 3] * s->dm[(i + 2) % 3][(j + 2) % 3] -
954 s->dm[(i + 1) % 3][(j + 2) % 3] * s->dm[(i + 2) % 3][(j + 1) % 3];
955 }
956 }
957 det =
958 tmp.dm[0][0] * s->dm[0][0] + tmp.dm[0][1] * s->dm[1][0] +
959 tmp.dm[0][2] * s->dm[2][0];
960 for (j = 0; j < 3; j++) {
961 for (i = 0; i < 3; i++) {
962 tmp.dm[i][j] /= det;
963 }
964 }
965 color_matrix_copy (d, &tmp);
966 }
967
968 static void
color_matrix_offset_components(MatrixData * m,double a1,double a2,double a3)969 color_matrix_offset_components (MatrixData * m, double a1, double a2, double a3)
970 {
971 MatrixData a;
972
973 color_matrix_set_identity (&a);
974 a.dm[0][3] = a1;
975 a.dm[1][3] = a2;
976 a.dm[2][3] = a3;
977 color_matrix_multiply (m, &a, m);
978 }
979
980 static void
color_matrix_scale_components(MatrixData * m,double a1,double a2,double a3)981 color_matrix_scale_components (MatrixData * m, double a1, double a2, double a3)
982 {
983 MatrixData a;
984
985 color_matrix_set_identity (&a);
986 a.dm[0][0] = a1;
987 a.dm[1][1] = a2;
988 a.dm[2][2] = a3;
989 color_matrix_multiply (m, &a, m);
990 }
991
992 static void
color_matrix_debug(const MatrixData * s)993 color_matrix_debug (const MatrixData * s)
994 {
995 GST_DEBUG ("[%f %f %f %f]", s->dm[0][0], s->dm[0][1], s->dm[0][2],
996 s->dm[0][3]);
997 GST_DEBUG ("[%f %f %f %f]", s->dm[1][0], s->dm[1][1], s->dm[1][2],
998 s->dm[1][3]);
999 GST_DEBUG ("[%f %f %f %f]", s->dm[2][0], s->dm[2][1], s->dm[2][2],
1000 s->dm[2][3]);
1001 GST_DEBUG ("[%f %f %f %f]", s->dm[3][0], s->dm[3][1], s->dm[3][2],
1002 s->dm[3][3]);
1003 }
1004
1005 static void
color_matrix_convert(MatrixData * s)1006 color_matrix_convert (MatrixData * s)
1007 {
1008 gint i, j;
1009
1010 for (i = 0; i < 4; i++)
1011 for (j = 0; j < 4; j++)
1012 s->im[i][j] = rint (s->dm[i][j]);
1013
1014 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[0][0], s->im[0][1], s->im[0][2],
1015 s->im[0][3]);
1016 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[1][0], s->im[1][1], s->im[1][2],
1017 s->im[1][3]);
1018 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[2][0], s->im[2][1], s->im[2][2],
1019 s->im[2][3]);
1020 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[3][0], s->im[3][1], s->im[3][2],
1021 s->im[3][3]);
1022 }
1023
1024 static void
color_matrix_YCbCr_to_RGB(MatrixData * m,double Kr,double Kb)1025 color_matrix_YCbCr_to_RGB (MatrixData * m, double Kr, double Kb)
1026 {
1027 double Kg = 1.0 - Kr - Kb;
1028 MatrixData k = {
1029 {
1030 {1., 0., 2 * (1 - Kr), 0.},
1031 {1., -2 * Kb * (1 - Kb) / Kg, -2 * Kr * (1 - Kr) / Kg, 0.},
1032 {1., 2 * (1 - Kb), 0., 0.},
1033 {0., 0., 0., 1.},
1034 }
1035 };
1036
1037 color_matrix_multiply (m, &k, m);
1038 }
1039
1040 static void
color_matrix_RGB_to_YCbCr(MatrixData * m,double Kr,double Kb)1041 color_matrix_RGB_to_YCbCr (MatrixData * m, double Kr, double Kb)
1042 {
1043 double Kg = 1.0 - Kr - Kb;
1044 MatrixData k;
1045 double x;
1046
1047 k.dm[0][0] = Kr;
1048 k.dm[0][1] = Kg;
1049 k.dm[0][2] = Kb;
1050 k.dm[0][3] = 0;
1051
1052 x = 1 / (2 * (1 - Kb));
1053 k.dm[1][0] = -x * Kr;
1054 k.dm[1][1] = -x * Kg;
1055 k.dm[1][2] = x * (1 - Kb);
1056 k.dm[1][3] = 0;
1057
1058 x = 1 / (2 * (1 - Kr));
1059 k.dm[2][0] = x * (1 - Kr);
1060 k.dm[2][1] = -x * Kg;
1061 k.dm[2][2] = -x * Kb;
1062 k.dm[2][3] = 0;
1063
1064 k.dm[3][0] = 0;
1065 k.dm[3][1] = 0;
1066 k.dm[3][2] = 0;
1067 k.dm[3][3] = 1;
1068
1069 color_matrix_multiply (m, &k, m);
1070 }
1071
1072 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)1073 color_matrix_RGB_to_XYZ (MatrixData * dst, double Rx, double Ry, double Gx,
1074 double Gy, double Bx, double By, double Wx, double Wy)
1075 {
1076 MatrixData m, im;
1077 double sx, sy, sz;
1078 double wx, wy, wz;
1079
1080 color_matrix_set_identity (&m);
1081
1082 m.dm[0][0] = Rx;
1083 m.dm[1][0] = Ry;
1084 m.dm[2][0] = (1.0 - Rx - Ry);
1085 m.dm[0][1] = Gx;
1086 m.dm[1][1] = Gy;
1087 m.dm[2][1] = (1.0 - Gx - Gy);
1088 m.dm[0][2] = Bx;
1089 m.dm[1][2] = By;
1090 m.dm[2][2] = (1.0 - Bx - By);
1091
1092 color_matrix_invert (&im, &m);
1093
1094 wx = Wx / Wy;
1095 wy = 1.0;
1096 wz = (1.0 - Wx - Wy) / Wy;
1097
1098 sx = im.dm[0][0] * wx + im.dm[0][1] * wy + im.dm[0][2] * wz;
1099 sy = im.dm[1][0] * wx + im.dm[1][1] * wy + im.dm[1][2] * wz;
1100 sz = im.dm[2][0] * wx + im.dm[2][1] * wy + im.dm[2][2] * wz;
1101
1102 m.dm[0][0] *= sx;
1103 m.dm[1][0] *= sx;
1104 m.dm[2][0] *= sx;
1105 m.dm[0][1] *= sy;
1106 m.dm[1][1] *= sy;
1107 m.dm[2][1] *= sy;
1108 m.dm[0][2] *= sz;
1109 m.dm[1][2] *= sz;
1110 m.dm[2][2] *= sz;
1111
1112 color_matrix_copy (dst, &m);
1113 }
1114
1115 static void
videoconvert_convert_init_tables(MatrixData * data)1116 videoconvert_convert_init_tables (MatrixData * data)
1117 {
1118 gint i, j;
1119
1120 data->t_r = g_new (gint64, 256);
1121 data->t_g = g_new (gint64, 256);
1122 data->t_b = g_new (gint64, 256);
1123
1124 for (i = 0; i < 256; i++) {
1125 gint64 r = 0, g = 0, b = 0;
1126
1127 for (j = 0; j < 3; j++) {
1128 r = (r << 16) + data->im[j][0] * i;
1129 g = (g << 16) + data->im[j][1] * i;
1130 b = (b << 16) + data->im[j][2] * i;
1131 }
1132 data->t_r[i] = r;
1133 data->t_g[i] = g;
1134 data->t_b[i] = b;
1135 }
1136 data->t_c = ((gint64) data->im[0][3] << 32)
1137 + ((gint64) data->im[1][3] << 16)
1138 + ((gint64) data->im[2][3] << 0);
1139 }
1140
1141 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)1142 _custom_video_orc_matrix8 (guint8 * ORC_RESTRICT d1,
1143 const guint8 * ORC_RESTRICT s1, orc_int64 p1, orc_int64 p2, orc_int64 p3,
1144 orc_int64 p4, int n)
1145 {
1146 gint i;
1147 gint r, g, b;
1148 gint y, u, v;
1149 gint a00, a01, a02, a03;
1150 gint a10, a11, a12, a13;
1151 gint a20, a21, a22, a23;
1152
1153 a00 = (gint16) (p1 >> 16);
1154 a01 = (gint16) (p2 >> 16);
1155 a02 = (gint16) (p3 >> 16);
1156 a03 = (gint16) (p4 >> 16);
1157 a10 = (gint16) (p1 >> 32);
1158 a11 = (gint16) (p2 >> 32);
1159 a12 = (gint16) (p3 >> 32);
1160 a13 = (gint16) (p4 >> 32);
1161 a20 = (gint16) (p1 >> 48);
1162 a21 = (gint16) (p2 >> 48);
1163 a22 = (gint16) (p3 >> 48);
1164 a23 = (gint16) (p4 >> 48);
1165
1166 for (i = 0; i < n; i++) {
1167 r = s1[i * 4 + 1];
1168 g = s1[i * 4 + 2];
1169 b = s1[i * 4 + 3];
1170
1171 y = ((a00 * r + a01 * g + a02 * b) >> SCALE) + a03;
1172 u = ((a10 * r + a11 * g + a12 * b) >> SCALE) + a13;
1173 v = ((a20 * r + a21 * g + a22 * b) >> SCALE) + a23;
1174
1175 d1[i * 4 + 1] = CLAMP (y, 0, 255);
1176 d1[i * 4 + 2] = CLAMP (u, 0, 255);
1177 d1[i * 4 + 3] = CLAMP (v, 0, 255);
1178 }
1179 }
1180
1181 static void
video_converter_matrix8(MatrixData * data,gpointer pixels)1182 video_converter_matrix8 (MatrixData * data, gpointer pixels)
1183 {
1184 gpointer d = pixels;
1185 video_orc_matrix8 (d, pixels, data->orc_p1, data->orc_p2,
1186 data->orc_p3, data->orc_p4, data->width);
1187 }
1188
1189 static void
video_converter_matrix8_table(MatrixData * data,gpointer pixels)1190 video_converter_matrix8_table (MatrixData * data, gpointer pixels)
1191 {
1192 gint i, width = data->width * 4;
1193 guint8 r, g, b;
1194 gint64 c = data->t_c;
1195 guint8 *p = pixels;
1196 gint64 x;
1197
1198 for (i = 0; i < width; i += 4) {
1199 r = p[i + 1];
1200 g = p[i + 2];
1201 b = p[i + 3];
1202
1203 x = data->t_r[r] + data->t_g[g] + data->t_b[b] + c;
1204
1205 p[i + 1] = x >> (32 + SCALE);
1206 p[i + 2] = x >> (16 + SCALE);
1207 p[i + 3] = x >> (0 + SCALE);
1208 }
1209 }
1210
1211 static void
video_converter_matrix8_AYUV_ARGB(MatrixData * data,gpointer pixels)1212 video_converter_matrix8_AYUV_ARGB (MatrixData * data, gpointer pixels)
1213 {
1214 gpointer d = pixels;
1215
1216 video_orc_convert_AYUV_ARGB (d, 0, pixels, 0,
1217 data->im[0][0], data->im[0][2],
1218 data->im[2][1], data->im[1][1], data->im[1][2], data->width, 1);
1219 }
1220
1221 static gboolean
is_ayuv_to_rgb_matrix(MatrixData * data)1222 is_ayuv_to_rgb_matrix (MatrixData * data)
1223 {
1224 if (data->im[0][0] != data->im[1][0] || data->im[1][0] != data->im[2][0])
1225 return FALSE;
1226
1227 if (data->im[0][1] != 0 || data->im[2][2] != 0)
1228 return FALSE;
1229
1230 return TRUE;
1231 }
1232
1233 static gboolean
is_identity_matrix(MatrixData * data)1234 is_identity_matrix (MatrixData * data)
1235 {
1236 gint i, j;
1237 gint c = data->im[0][0];
1238
1239 /* not really checking identity because of rounding errors but given
1240 * the conversions we do we just check for anything that looks like:
1241 *
1242 * c 0 0 0
1243 * 0 c 0 0
1244 * 0 0 c 0
1245 * 0 0 0 1
1246 */
1247 for (i = 0; i < 4; i++) {
1248 for (j = 0; j < 4; j++) {
1249 if (i == j) {
1250 if (i == 3 && data->im[i][j] != 1)
1251 return FALSE;
1252 else if (data->im[i][j] != c)
1253 return FALSE;
1254 } else if (data->im[i][j] != 0)
1255 return FALSE;
1256 }
1257 }
1258 return TRUE;
1259 }
1260
1261 static gboolean
is_no_clip_matrix(MatrixData * data)1262 is_no_clip_matrix (MatrixData * data)
1263 {
1264 gint i;
1265 static const guint8 test[8][3] = {
1266 {0, 0, 0},
1267 {0, 0, 255},
1268 {0, 255, 0},
1269 {0, 255, 255},
1270 {255, 0, 0},
1271 {255, 0, 255},
1272 {255, 255, 0},
1273 {255, 255, 255}
1274 };
1275
1276 for (i = 0; i < 8; i++) {
1277 gint r, g, b;
1278 gint y, u, v;
1279
1280 r = test[i][0];
1281 g = test[i][1];
1282 b = test[i][2];
1283
1284 y = (data->im[0][0] * r + data->im[0][1] * g +
1285 data->im[0][2] * b + data->im[0][3]) >> SCALE;
1286 u = (data->im[1][0] * r + data->im[1][1] * g +
1287 data->im[1][2] * b + data->im[1][3]) >> SCALE;
1288 v = (data->im[2][0] * r + data->im[2][1] * g +
1289 data->im[2][2] * b + data->im[2][3]) >> SCALE;
1290
1291 if (y != CLAMP (y, 0, 255) || u != CLAMP (u, 0, 255)
1292 || v != CLAMP (v, 0, 255))
1293 return FALSE;
1294 }
1295 return TRUE;
1296 }
1297
1298 static void
video_converter_matrix16(MatrixData * data,gpointer pixels)1299 video_converter_matrix16 (MatrixData * data, gpointer pixels)
1300 {
1301 int i;
1302 int r, g, b;
1303 int y, u, v;
1304 guint16 *p = pixels;
1305 gint width = data->width;
1306
1307 for (i = 0; i < width; i++) {
1308 r = p[i * 4 + 1];
1309 g = p[i * 4 + 2];
1310 b = p[i * 4 + 3];
1311
1312 y = (data->im[0][0] * r + data->im[0][1] * g +
1313 data->im[0][2] * b + data->im[0][3]) >> SCALE;
1314 u = (data->im[1][0] * r + data->im[1][1] * g +
1315 data->im[1][2] * b + data->im[1][3]) >> SCALE;
1316 v = (data->im[2][0] * r + data->im[2][1] * g +
1317 data->im[2][2] * b + data->im[2][3]) >> SCALE;
1318
1319 p[i * 4 + 1] = CLAMP (y, 0, 65535);
1320 p[i * 4 + 2] = CLAMP (u, 0, 65535);
1321 p[i * 4 + 3] = CLAMP (v, 0, 65535);
1322 }
1323 }
1324
1325
1326 static void
prepare_matrix(GstVideoConverter * convert,MatrixData * data)1327 prepare_matrix (GstVideoConverter * convert, MatrixData * data)
1328 {
1329 if (is_identity_matrix (data))
1330 return;
1331
1332 color_matrix_scale_components (data, SCALE_F, SCALE_F, SCALE_F);
1333 color_matrix_convert (data);
1334
1335 data->width = convert->current_width;
1336
1337 if (convert->current_bits == 8) {
1338 if (!convert->unpack_rgb && convert->pack_rgb
1339 && is_ayuv_to_rgb_matrix (data)) {
1340 GST_DEBUG ("use fast AYUV -> RGB matrix");
1341 data->matrix_func = video_converter_matrix8_AYUV_ARGB;
1342 } else if (is_no_clip_matrix (data)) {
1343 GST_DEBUG ("use 8bit table");
1344 data->matrix_func = video_converter_matrix8_table;
1345 videoconvert_convert_init_tables (data);
1346 } else {
1347 gint a03, a13, a23;
1348
1349 GST_DEBUG ("use 8bit matrix");
1350 data->matrix_func = video_converter_matrix8;
1351
1352 data->orc_p1 = (((guint64) (guint16) data->im[2][0]) << 48) |
1353 (((guint64) (guint16) data->im[1][0]) << 32) |
1354 (((guint64) (guint16) data->im[0][0]) << 16);
1355 data->orc_p2 = (((guint64) (guint16) data->im[2][1]) << 48) |
1356 (((guint64) (guint16) data->im[1][1]) << 32) |
1357 (((guint64) (guint16) data->im[0][1]) << 16);
1358 data->orc_p3 = (((guint64) (guint16) data->im[2][2]) << 48) |
1359 (((guint64) (guint16) data->im[1][2]) << 32) |
1360 (((guint64) (guint16) data->im[0][2]) << 16);
1361
1362 a03 = data->im[0][3] >> SCALE;
1363 a13 = data->im[1][3] >> SCALE;
1364 a23 = data->im[2][3] >> SCALE;
1365
1366 data->orc_p4 = (((guint64) (guint16) a23) << 48) |
1367 (((guint64) (guint16) a13) << 32) | (((guint64) (guint16) a03) << 16);
1368 }
1369 } else {
1370 GST_DEBUG ("use 16bit matrix");
1371 data->matrix_func = video_converter_matrix16;
1372 }
1373 }
1374
1375 static void
compute_matrix_to_RGB(GstVideoConverter * convert,MatrixData * data)1376 compute_matrix_to_RGB (GstVideoConverter * convert, MatrixData * data)
1377 {
1378 GstVideoInfo *info;
1379 gdouble Kr = 0, Kb = 0;
1380
1381 info = &convert->in_info;
1382
1383 {
1384 const GstVideoFormatInfo *uinfo;
1385 gint offset[4], scale[4];
1386
1387 uinfo = gst_video_format_get_info (convert->unpack_format);
1388
1389 /* bring color components to [0..1.0] range */
1390 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1391 scale);
1392
1393 color_matrix_offset_components (data, -offset[0], -offset[1], -offset[2]);
1394 color_matrix_scale_components (data, 1 / ((float) scale[0]),
1395 1 / ((float) scale[1]), 1 / ((float) scale[2]));
1396 }
1397
1398 if (!convert->unpack_rgb && !CHECK_MATRIX_NONE (convert)) {
1399 if (CHECK_MATRIX_OUTPUT (convert))
1400 info = &convert->out_info;
1401
1402 /* bring components to R'G'B' space */
1403 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
1404 color_matrix_YCbCr_to_RGB (data, Kr, Kb);
1405 }
1406 color_matrix_debug (data);
1407 }
1408
1409 static void
compute_matrix_to_YUV(GstVideoConverter * convert,MatrixData * data,gboolean force)1410 compute_matrix_to_YUV (GstVideoConverter * convert, MatrixData * data,
1411 gboolean force)
1412 {
1413 GstVideoInfo *info;
1414 gdouble Kr = 0, Kb = 0;
1415
1416 if (force || (!convert->pack_rgb && !CHECK_MATRIX_NONE (convert))) {
1417 if (CHECK_MATRIX_INPUT (convert))
1418 info = &convert->in_info;
1419 else
1420 info = &convert->out_info;
1421
1422 /* bring components to YCbCr space */
1423 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
1424 color_matrix_RGB_to_YCbCr (data, Kr, Kb);
1425 }
1426
1427 info = &convert->out_info;
1428
1429 {
1430 const GstVideoFormatInfo *uinfo;
1431 gint offset[4], scale[4];
1432
1433 uinfo = gst_video_format_get_info (convert->pack_format);
1434
1435 /* bring color components to nominal range */
1436 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1437 scale);
1438
1439 color_matrix_scale_components (data, (float) scale[0], (float) scale[1],
1440 (float) scale[2]);
1441 color_matrix_offset_components (data, offset[0], offset[1], offset[2]);
1442 }
1443
1444 color_matrix_debug (data);
1445 }
1446
1447
1448 static void
gamma_convert_u8_u16(GammaData * data,gpointer dest,gpointer src)1449 gamma_convert_u8_u16 (GammaData * data, gpointer dest, gpointer src)
1450 {
1451 gint i;
1452 guint8 *s = src;
1453 guint16 *d = dest;
1454 guint16 *table = data->gamma_table;
1455 gint width = data->width * 4;
1456
1457 for (i = 0; i < width; i += 4) {
1458 d[i + 0] = (s[i] << 8) | s[i];
1459 d[i + 1] = table[s[i + 1]];
1460 d[i + 2] = table[s[i + 2]];
1461 d[i + 3] = table[s[i + 3]];
1462 }
1463 }
1464
1465 static void
gamma_convert_u16_u8(GammaData * data,gpointer dest,gpointer src)1466 gamma_convert_u16_u8 (GammaData * data, gpointer dest, gpointer src)
1467 {
1468 gint i;
1469 guint16 *s = src;
1470 guint8 *d = dest;
1471 guint8 *table = data->gamma_table;
1472 gint width = data->width * 4;
1473
1474 for (i = 0; i < width; i += 4) {
1475 d[i + 0] = s[i] >> 8;
1476 d[i + 1] = table[s[i + 1]];
1477 d[i + 2] = table[s[i + 2]];
1478 d[i + 3] = table[s[i + 3]];
1479 }
1480 }
1481
1482 static void
gamma_convert_u16_u16(GammaData * data,gpointer dest,gpointer src)1483 gamma_convert_u16_u16 (GammaData * data, gpointer dest, gpointer src)
1484 {
1485 gint i;
1486 guint16 *s = src;
1487 guint16 *d = dest;
1488 guint16 *table = data->gamma_table;
1489 gint width = data->width * 4;
1490
1491 for (i = 0; i < width; i += 4) {
1492 d[i + 0] = s[i];
1493 d[i + 1] = table[s[i + 1]];
1494 d[i + 2] = table[s[i + 2]];
1495 d[i + 3] = table[s[i + 3]];
1496 }
1497 }
1498
1499 static void
setup_gamma_decode(GstVideoConverter * convert)1500 setup_gamma_decode (GstVideoConverter * convert)
1501 {
1502 GstVideoTransferFunction func;
1503 guint16 *t;
1504 gint i;
1505
1506 func = convert->in_info.colorimetry.transfer;
1507
1508 convert->gamma_dec.width = convert->current_width;
1509 if (convert->gamma_dec.gamma_table) {
1510 GST_DEBUG ("gamma decode already set up");
1511 } else if (convert->current_bits == 8) {
1512 GST_DEBUG ("gamma decode 8->16: %d", func);
1513 convert->gamma_dec.gamma_func = gamma_convert_u8_u16;
1514 t = convert->gamma_dec.gamma_table = g_malloc (sizeof (guint16) * 256);
1515
1516 for (i = 0; i < 256; i++)
1517 t[i] =
1518 rint (gst_video_transfer_function_decode (func, i / 255.0) * 65535.0);
1519 } else {
1520 GST_DEBUG ("gamma decode 16->16: %d", func);
1521 convert->gamma_dec.gamma_func = gamma_convert_u16_u16;
1522 t = convert->gamma_dec.gamma_table = g_malloc (sizeof (guint16) * 65536);
1523
1524 for (i = 0; i < 65536; i++)
1525 t[i] =
1526 rint (gst_video_transfer_function_decode (func,
1527 i / 65535.0) * 65535.0);
1528 }
1529 convert->current_bits = 16;
1530 convert->current_pstride = 8;
1531 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1532 }
1533
1534 static void
setup_gamma_encode(GstVideoConverter * convert,gint target_bits)1535 setup_gamma_encode (GstVideoConverter * convert, gint target_bits)
1536 {
1537 GstVideoTransferFunction func;
1538 gint i;
1539
1540 func = convert->out_info.colorimetry.transfer;
1541
1542 convert->gamma_enc.width = convert->current_width;
1543 if (convert->gamma_enc.gamma_table) {
1544 GST_DEBUG ("gamma encode already set up");
1545 } else if (target_bits == 8) {
1546 guint8 *t;
1547
1548 GST_DEBUG ("gamma encode 16->8: %d", func);
1549 convert->gamma_enc.gamma_func = gamma_convert_u16_u8;
1550 t = convert->gamma_enc.gamma_table = g_malloc (sizeof (guint8) * 65536);
1551
1552 for (i = 0; i < 65536; i++)
1553 t[i] =
1554 rint (gst_video_transfer_function_encode (func, i / 65535.0) * 255.0);
1555 } else {
1556 guint16 *t;
1557
1558 GST_DEBUG ("gamma encode 16->16: %d", func);
1559 convert->gamma_enc.gamma_func = gamma_convert_u16_u16;
1560 t = convert->gamma_enc.gamma_table = g_malloc (sizeof (guint16) * 65536);
1561
1562 for (i = 0; i < 65536; i++)
1563 t[i] =
1564 rint (gst_video_transfer_function_encode (func,
1565 i / 65535.0) * 65535.0);
1566 }
1567 }
1568
1569 static GstLineCache *
chain_convert_to_RGB(GstVideoConverter * convert,GstLineCache * prev,gint idx)1570 chain_convert_to_RGB (GstVideoConverter * convert, GstLineCache * prev,
1571 gint idx)
1572 {
1573 gboolean do_gamma;
1574
1575 do_gamma = CHECK_GAMMA_REMAP (convert);
1576
1577 if (do_gamma) {
1578 gint scale;
1579
1580 /* Set up conversion matrices if needed, but only for the first thread */
1581 if (idx == 0 && !convert->unpack_rgb) {
1582 color_matrix_set_identity (&convert->to_RGB_matrix);
1583 compute_matrix_to_RGB (convert, &convert->to_RGB_matrix);
1584
1585 /* matrix is in 0..1 range, scale to current bits */
1586 GST_DEBUG ("chain RGB convert");
1587 scale = 1 << convert->current_bits;
1588 color_matrix_scale_components (&convert->to_RGB_matrix,
1589 (float) scale, (float) scale, (float) scale);
1590
1591 prepare_matrix (convert, &convert->to_RGB_matrix);
1592
1593 if (convert->current_bits == 8)
1594 convert->current_format = GST_VIDEO_FORMAT_ARGB;
1595 else
1596 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1597 }
1598
1599 prev = convert->to_RGB_lines[idx] = gst_line_cache_new (prev);
1600 prev->write_input = TRUE;
1601 prev->pass_alloc = FALSE;
1602 prev->n_lines = 1;
1603 prev->stride = convert->current_pstride * convert->current_width;
1604 gst_line_cache_set_need_line_func (prev,
1605 do_convert_to_RGB_lines, idx, convert, NULL);
1606
1607 GST_DEBUG ("chain gamma decode");
1608 setup_gamma_decode (convert);
1609 }
1610 return prev;
1611 }
1612
1613 static GstLineCache *
chain_hscale(GstVideoConverter * convert,GstLineCache * prev,gint idx)1614 chain_hscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1615 {
1616 gint method;
1617 guint taps;
1618
1619 method = GET_OPT_RESAMPLER_METHOD (convert);
1620 taps = GET_OPT_RESAMPLER_TAPS (convert);
1621
1622 convert->h_scaler[idx] =
1623 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
1624 convert->in_width, convert->out_width, convert->config);
1625
1626 gst_video_scaler_get_coeff (convert->h_scaler[idx], 0, NULL, &taps);
1627
1628 GST_DEBUG ("chain hscale %d->%d, taps %d, method %d",
1629 convert->in_width, convert->out_width, taps, method);
1630
1631 convert->current_width = convert->out_width;
1632 convert->h_scale_format = convert->current_format;
1633
1634 prev = convert->hscale_lines[idx] = gst_line_cache_new (prev);
1635 prev->write_input = FALSE;
1636 prev->pass_alloc = FALSE;
1637 prev->n_lines = 1;
1638 prev->stride = convert->current_pstride * convert->current_width;
1639 gst_line_cache_set_need_line_func (prev, do_hscale_lines, idx, convert, NULL);
1640
1641 return prev;
1642 }
1643
1644 static GstLineCache *
chain_vscale(GstVideoConverter * convert,GstLineCache * prev,gint idx)1645 chain_vscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1646 {
1647 gint method;
1648 guint taps, taps_i = 0;
1649 gint backlog = 0;
1650
1651 method = GET_OPT_RESAMPLER_METHOD (convert);
1652 taps = GET_OPT_RESAMPLER_TAPS (convert);
1653
1654 if (GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)
1655 && (GST_VIDEO_INFO_INTERLACE_MODE (&convert->in_info) !=
1656 GST_VIDEO_INTERLACE_MODE_ALTERNATE)) {
1657 convert->v_scaler_i[idx] =
1658 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_INTERLACED, taps,
1659 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 if (idx == 0)
1837 prepare_matrix (convert, &convert->convert_matrix);
1838 }
1839 if (convert->in_bits == convert->out_bits)
1840 pass_alloc = TRUE;
1841 } else
1842 do_conversion = FALSE;
1843
1844 convert->current_bits = convert->pack_bits;
1845 convert->current_format = convert->pack_format;
1846 convert->current_pstride = convert->current_bits >> 1;
1847 } else {
1848 /* we did gamma, just do colorspace conversion if needed */
1849 if (same_primaries) {
1850 do_conversion = FALSE;
1851 } else {
1852 if (idx == 0)
1853 prepare_matrix (convert, &convert->convert_matrix);
1854 convert->in_bits = convert->out_bits = 16;
1855 pass_alloc = TRUE;
1856 do_conversion = TRUE;
1857 }
1858 }
1859
1860 if (do_conversion) {
1861 GST_DEBUG ("chain conversion");
1862 prev = convert->convert_lines[idx] = gst_line_cache_new (prev);
1863 prev->write_input = TRUE;
1864 prev->pass_alloc = pass_alloc;
1865 prev->n_lines = 1;
1866 prev->stride = convert->current_pstride * convert->current_width;
1867 gst_line_cache_set_need_line_func (prev,
1868 do_convert_lines, idx, convert, NULL);
1869 }
1870 return prev;
1871 }
1872
1873 static void
convert_set_alpha_u8(GstVideoConverter * convert,gpointer pixels,gint width)1874 convert_set_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1875 {
1876 guint8 *p = pixels;
1877 guint8 alpha = MIN (convert->alpha_value, 255);
1878 int i;
1879
1880 for (i = 0; i < width; i++)
1881 p[i * 4] = alpha;
1882 }
1883
1884 static void
convert_set_alpha_u16(GstVideoConverter * convert,gpointer pixels,gint width)1885 convert_set_alpha_u16 (GstVideoConverter * convert, gpointer pixels, gint width)
1886 {
1887 guint16 *p = pixels;
1888 guint16 alpha;
1889 int i;
1890
1891 alpha = MIN (convert->alpha_value, 255);
1892 alpha |= alpha << 8;
1893
1894 for (i = 0; i < width; i++)
1895 p[i * 4] = alpha;
1896 }
1897
1898 static void
convert_mult_alpha_u8(GstVideoConverter * convert,gpointer pixels,gint width)1899 convert_mult_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1900 {
1901 guint8 *p = pixels;
1902 guint alpha = convert->alpha_value;
1903 int i;
1904
1905 for (i = 0; i < width; i++) {
1906 gint a = (p[i * 4] * alpha) / 255;
1907 p[i * 4] = CLAMP (a, 0, 255);
1908 }
1909 }
1910
1911 static void
convert_mult_alpha_u16(GstVideoConverter * convert,gpointer pixels,gint width)1912 convert_mult_alpha_u16 (GstVideoConverter * convert, gpointer pixels,
1913 gint width)
1914 {
1915 guint16 *p = pixels;
1916 guint alpha = convert->alpha_value;
1917 int i;
1918
1919 for (i = 0; i < width; i++) {
1920 gint a = (p[i * 4] * alpha) / 255;
1921 p[i * 4] = CLAMP (a, 0, 65535);
1922 }
1923 }
1924
1925 static GstLineCache *
chain_alpha(GstVideoConverter * convert,GstLineCache * prev,gint idx)1926 chain_alpha (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1927 {
1928 switch (convert->alpha_mode) {
1929 case ALPHA_MODE_NONE:
1930 case ALPHA_MODE_COPY:
1931 return prev;
1932
1933 case ALPHA_MODE_SET:
1934 if (convert->current_bits == 8)
1935 convert->alpha_func = convert_set_alpha_u8;
1936 else
1937 convert->alpha_func = convert_set_alpha_u16;
1938 break;
1939 case ALPHA_MODE_MULT:
1940 if (convert->current_bits == 8)
1941 convert->alpha_func = convert_mult_alpha_u8;
1942 else
1943 convert->alpha_func = convert_mult_alpha_u16;
1944 break;
1945 }
1946
1947 GST_DEBUG ("chain alpha mode %d", convert->alpha_mode);
1948 prev = convert->alpha_lines[idx] = gst_line_cache_new (prev);
1949 prev->write_input = TRUE;
1950 prev->pass_alloc = TRUE;
1951 prev->n_lines = 1;
1952 prev->stride = convert->current_pstride * convert->current_width;
1953 gst_line_cache_set_need_line_func (prev, do_alpha_lines, idx, convert, NULL);
1954
1955 return prev;
1956 }
1957
1958 static GstLineCache *
chain_convert_to_YUV(GstVideoConverter * convert,GstLineCache * prev,gint idx)1959 chain_convert_to_YUV (GstVideoConverter * convert, GstLineCache * prev,
1960 gint idx)
1961 {
1962 gboolean do_gamma;
1963
1964 do_gamma = CHECK_GAMMA_REMAP (convert);
1965
1966 if (do_gamma) {
1967 gint scale;
1968
1969 GST_DEBUG ("chain gamma encode");
1970 setup_gamma_encode (convert, convert->pack_bits);
1971
1972 convert->current_bits = convert->pack_bits;
1973 convert->current_pstride = convert->current_bits >> 1;
1974
1975 if (idx == 0 && !convert->pack_rgb) {
1976 color_matrix_set_identity (&convert->to_YUV_matrix);
1977
1978 /* When gamma remap is enabled, we do
1979 * 1) converts to ARGB64 linear RGB
1980 * - if input is 8bits, convert to ARGB and scaled to 16bits with gamma
1981 * decoding at once
1982 * - otherwise converted ARGB64 and gamma decoded
1983 * 2) scale/convert etc,
1984 * 3) and gamma encode
1985 *
1986 * So source data to the do_convert_to_YUV_lines() method is always
1987 * ARGB64
1988 *
1989 * Then, if output unpack format is 8bits, setup_gamma_encode() will scale
1990 * ARGB64 down to ARGB as a part of gamma encoding, otherwise it's still
1991 * ARGB64
1992 *
1993 * Finally this to_YUV_matrix is applied. Since compute_matrix_to_YUV()
1994 * expects [0, 1.0] range RGB as an input, scale down identity matrix
1995 * to expected scale here, otherwise offset of the matrix would be
1996 * very wrong
1997 */
1998 GST_DEBUG ("chain YUV convert");
1999 scale = 1 << convert->pack_bits;
2000 color_matrix_scale_components (&convert->to_YUV_matrix,
2001 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
2002
2003 compute_matrix_to_YUV (convert, &convert->to_YUV_matrix, FALSE);
2004 prepare_matrix (convert, &convert->to_YUV_matrix);
2005 }
2006 convert->current_format = convert->pack_format;
2007
2008 prev = convert->to_YUV_lines[idx] = gst_line_cache_new (prev);
2009 prev->write_input = FALSE;
2010 prev->pass_alloc = FALSE;
2011 prev->n_lines = 1;
2012 prev->stride = convert->current_pstride * convert->current_width;
2013 gst_line_cache_set_need_line_func (prev,
2014 do_convert_to_YUV_lines, idx, convert, NULL);
2015 }
2016
2017 return prev;
2018 }
2019
2020 static GstLineCache *
chain_downsample(GstVideoConverter * convert,GstLineCache * prev,gint idx)2021 chain_downsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2022 {
2023 if (convert->downsample_p[idx] || convert->downsample_i[idx]) {
2024 GST_DEBUG ("chain downsample");
2025 prev = convert->downsample_lines[idx] = gst_line_cache_new (prev);
2026 prev->write_input = TRUE;
2027 prev->pass_alloc = TRUE;
2028 /* XXX: why this hardcoded value? */
2029 prev->n_lines = 5;
2030 prev->stride = convert->current_pstride * convert->current_width;
2031 gst_line_cache_set_need_line_func (prev,
2032 do_downsample_lines, idx, convert, NULL);
2033 }
2034 return prev;
2035 }
2036
2037 static GstLineCache *
chain_dither(GstVideoConverter * convert,GstLineCache * prev,gint idx)2038 chain_dither (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2039 {
2040 gint i;
2041 gboolean do_dither = FALSE;
2042 GstVideoDitherFlags flags = 0;
2043 GstVideoDitherMethod method;
2044 guint quant[4], target_quant;
2045
2046 method = GET_OPT_DITHER_METHOD (convert);
2047 if (method == GST_VIDEO_DITHER_NONE)
2048 return prev;
2049
2050 target_quant = GET_OPT_DITHER_QUANTIZATION (convert);
2051 GST_DEBUG ("method %d, target-quantization %d", method, target_quant);
2052
2053 if (convert->pack_pal) {
2054 quant[0] = 47;
2055 quant[1] = 47;
2056 quant[2] = 47;
2057 quant[3] = 1;
2058 do_dither = TRUE;
2059 } else {
2060 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++) {
2061 gint depth;
2062
2063 depth = convert->out_info.finfo->depth[i];
2064
2065 if (depth == 0) {
2066 quant[i] = 0;
2067 continue;
2068 }
2069
2070 if (convert->current_bits >= depth) {
2071 quant[i] = 1 << (convert->current_bits - depth);
2072 if (target_quant > quant[i]) {
2073 flags |= GST_VIDEO_DITHER_FLAG_QUANTIZE;
2074 quant[i] = target_quant;
2075 }
2076 } else {
2077 quant[i] = 0;
2078 }
2079 if (quant[i] > 1)
2080 do_dither = TRUE;
2081 }
2082 }
2083
2084 if (do_dither) {
2085 GST_DEBUG ("chain dither");
2086
2087 convert->dither[idx] = gst_video_dither_new (method,
2088 flags, convert->pack_format, quant, convert->current_width);
2089
2090 prev = convert->dither_lines[idx] = gst_line_cache_new (prev);
2091 prev->write_input = TRUE;
2092 prev->pass_alloc = TRUE;
2093 prev->n_lines = 1;
2094 prev->stride = convert->current_pstride * convert->current_width;
2095 gst_line_cache_set_need_line_func (prev, do_dither_lines, idx, convert,
2096 NULL);
2097 }
2098 return prev;
2099 }
2100
2101 static GstLineCache *
chain_pack(GstVideoConverter * convert,GstLineCache * prev,gint idx)2102 chain_pack (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2103 {
2104 convert->pack_nlines = convert->out_info.finfo->pack_lines;
2105 convert->pack_pstride = convert->current_pstride;
2106 convert->identity_pack =
2107 (convert->out_info.finfo->format ==
2108 convert->out_info.finfo->unpack_format);
2109 GST_DEBUG ("chain pack line format %s, pstride %d, identity_pack %d (%d %d)",
2110 gst_video_format_to_string (convert->current_format),
2111 convert->current_pstride, convert->identity_pack,
2112 convert->out_info.finfo->format, convert->out_info.finfo->unpack_format);
2113
2114 return prev;
2115 }
2116
2117 static void
setup_allocators(GstVideoConverter * convert)2118 setup_allocators (GstVideoConverter * convert)
2119 {
2120 GstLineCache *cache, *prev;
2121 GstLineCacheAllocLineFunc alloc_line;
2122 gboolean alloc_writable;
2123 gpointer user_data;
2124 GDestroyNotify notify;
2125 gint width;
2126 gint i;
2127
2128 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2129 width += convert->out_x;
2130
2131 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2132 /* start with using dest lines if we can directly write into it */
2133 if (convert->identity_pack) {
2134 alloc_line = get_dest_line;
2135 alloc_writable = TRUE;
2136 user_data = convert;
2137 notify = NULL;
2138 } else {
2139 user_data =
2140 converter_alloc_new (sizeof (guint16) * width * 4, 4 + BACKLOG,
2141 convert, NULL);
2142 setup_border_alloc (convert, user_data);
2143 notify = (GDestroyNotify) converter_alloc_free;
2144 alloc_line = get_border_temp_line;
2145 /* when we add a border, we need to write */
2146 alloc_writable = convert->borderline != NULL;
2147 }
2148
2149 /* First step, try to calculate how many temp lines we need. Go backwards,
2150 * keep track of the maximum number of lines we need for each intermediate
2151 * step. */
2152 for (prev = cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2153 GST_DEBUG ("looking at cache %p, %d lines, %d backlog", cache,
2154 cache->n_lines, cache->backlog);
2155 prev->n_lines = MAX (prev->n_lines, cache->n_lines);
2156 if (!cache->pass_alloc) {
2157 GST_DEBUG ("cache %p, needs %d lines", prev, prev->n_lines);
2158 prev = cache;
2159 }
2160 }
2161
2162 /* now walk backwards, we try to write into the dest lines directly
2163 * and keep track if the source needs to be writable */
2164 for (cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2165 gst_line_cache_set_alloc_line_func (cache, alloc_line, user_data, notify);
2166 cache->alloc_writable = alloc_writable;
2167
2168 /* make sure only one cache frees the allocator */
2169 notify = NULL;
2170
2171 if (!cache->pass_alloc) {
2172 /* can't pass allocator, make new temp line allocator */
2173 user_data =
2174 converter_alloc_new (sizeof (guint16) * width * 4,
2175 cache->n_lines + cache->backlog, convert, NULL);
2176 notify = (GDestroyNotify) converter_alloc_free;
2177 alloc_line = get_temp_line;
2178 alloc_writable = FALSE;
2179 }
2180 /* if someone writes to the input, we need a writable line from the
2181 * previous cache */
2182 if (cache->write_input)
2183 alloc_writable = TRUE;
2184 }
2185 /* free leftover allocator */
2186 if (notify)
2187 notify (user_data);
2188 }
2189 }
2190
2191 static void
setup_borderline(GstVideoConverter * convert)2192 setup_borderline (GstVideoConverter * convert)
2193 {
2194 gint width;
2195
2196 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2197 width += convert->out_x;
2198
2199 if (convert->fill_border && (convert->out_height < convert->out_maxheight ||
2200 convert->out_width < convert->out_maxwidth)) {
2201 guint32 border_val;
2202 gint i, w_sub;
2203 const GstVideoFormatInfo *out_finfo;
2204 gpointer planes[GST_VIDEO_MAX_PLANES];
2205 gint strides[GST_VIDEO_MAX_PLANES];
2206
2207 convert->borderline = g_malloc0 (sizeof (guint16) * width * 4);
2208
2209 out_finfo = convert->out_info.finfo;
2210
2211 if (GST_VIDEO_INFO_IS_YUV (&convert->out_info)) {
2212 MatrixData cm;
2213 gint a, r, g, b;
2214 gint y, u, v;
2215
2216 /* Get Color matrix. */
2217 color_matrix_set_identity (&cm);
2218 compute_matrix_to_YUV (convert, &cm, TRUE);
2219 color_matrix_convert (&cm);
2220
2221 border_val = GINT32_FROM_BE (convert->border_argb);
2222
2223 b = (0xFF000000 & border_val) >> 24;
2224 g = (0x00FF0000 & border_val) >> 16;
2225 r = (0x0000FF00 & border_val) >> 8;
2226 a = (0x000000FF & border_val);
2227
2228 y = 16 + ((r * cm.im[0][0] + g * cm.im[0][1] + b * cm.im[0][2]) >> 8);
2229 u = 128 + ((r * cm.im[1][0] + g * cm.im[1][1] + b * cm.im[1][2]) >> 8);
2230 v = 128 + ((r * cm.im[2][0] + g * cm.im[2][1] + b * cm.im[2][2]) >> 8);
2231
2232 a = CLAMP (a, 0, 255);
2233 y = CLAMP (y, 0, 255);
2234 u = CLAMP (u, 0, 255);
2235 v = CLAMP (v, 0, 255);
2236
2237 border_val = a | (y << 8) | (u << 16) | ((guint32) v << 24);
2238 } else {
2239 border_val = GINT32_FROM_BE (convert->border_argb);
2240 }
2241 if (convert->pack_bits == 8)
2242 video_orc_splat_u32 (convert->borderline, border_val, width);
2243 else
2244 video_orc_splat2_u64 (convert->borderline, border_val, width);
2245
2246 /* convert pixels */
2247 for (i = 0; i < out_finfo->n_planes; i++) {
2248 planes[i] = &convert->borders[i];
2249 strides[i] = sizeof (guint64);
2250 }
2251 w_sub = 0;
2252 if (out_finfo->n_planes == 1) {
2253 /* for packed formats, convert based on subsampling so that we
2254 * get a complete group of pixels */
2255 for (i = 0; i < out_finfo->n_components; i++) {
2256 w_sub = MAX (w_sub, out_finfo->w_sub[i]);
2257 }
2258 }
2259 out_finfo->pack_func (out_finfo, GST_VIDEO_PACK_FLAG_NONE,
2260 convert->borderline, 0, planes, strides,
2261 GST_VIDEO_CHROMA_SITE_UNKNOWN, 0, 1 << w_sub);
2262 } else {
2263 convert->borderline = NULL;
2264 }
2265 }
2266
2267 static AlphaMode
convert_get_alpha_mode(GstVideoConverter * convert)2268 convert_get_alpha_mode (GstVideoConverter * convert)
2269 {
2270 gboolean in_alpha, out_alpha;
2271
2272 in_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->in_info);
2273 out_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->out_info);
2274
2275 /* no output alpha, do nothing */
2276 if (!out_alpha)
2277 return ALPHA_MODE_NONE;
2278
2279 if (in_alpha) {
2280 /* in and out */
2281 if (CHECK_ALPHA_COPY (convert))
2282 return ALPHA_MODE_COPY;
2283
2284 if (CHECK_ALPHA_MULT (convert)) {
2285 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2286 return ALPHA_MODE_COPY;
2287 else
2288 return ALPHA_MODE_MULT;
2289 }
2290 }
2291 /* nothing special, this is what unpack etc does automatically */
2292 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2293 return ALPHA_MODE_NONE;
2294
2295 /* everything else becomes SET */
2296 return ALPHA_MODE_SET;
2297 }
2298
2299 /**
2300 * gst_video_converter_new_with_pool: (skip)
2301 * @in_info: a #GstVideoInfo
2302 * @out_info: a #GstVideoInfo
2303 * @config: (transfer full): a #GstStructure with configuration options
2304 * @pool: (nullable): a #GstTaskPool to spawn threads from
2305 *
2306 * Create a new converter object to convert between @in_info and @out_info
2307 * with @config.
2308 *
2309 * The optional @pool can be used to spawn threads, this is useful when
2310 * creating new converters rapidly, for example when updating cropping.
2311 *
2312 * Returns: a #GstVideoConverter or %NULL if conversion is not possible.
2313 *
2314 * Since: 1.20
2315 */
2316 GstVideoConverter *
gst_video_converter_new_with_pool(const GstVideoInfo * in_info,const GstVideoInfo * out_info,GstStructure * config,GstTaskPool * pool)2317 gst_video_converter_new_with_pool (const GstVideoInfo * in_info,
2318 const GstVideoInfo * out_info, GstStructure * config, GstTaskPool * pool)
2319 {
2320 GstVideoConverter *convert;
2321 GstLineCache *prev;
2322 const GstVideoFormatInfo *fin, *fout, *finfo;
2323 gdouble alpha_value;
2324 gint n_threads, i;
2325 gboolean async_tasks;
2326
2327 g_return_val_if_fail (in_info != NULL, NULL);
2328 g_return_val_if_fail (out_info != NULL, NULL);
2329 /* we won't ever do framerate conversion */
2330 g_return_val_if_fail (in_info->fps_n == out_info->fps_n, NULL);
2331 g_return_val_if_fail (in_info->fps_d == out_info->fps_d, NULL);
2332 /* we won't ever do deinterlace */
2333 g_return_val_if_fail (in_info->interlace_mode == out_info->interlace_mode,
2334 NULL);
2335
2336 convert = g_slice_new0 (GstVideoConverter);
2337
2338 fin = in_info->finfo;
2339 fout = out_info->finfo;
2340
2341 convert->in_info = *in_info;
2342 convert->out_info = *out_info;
2343
2344 /* default config */
2345 convert->config = gst_structure_new_empty ("GstVideoConverter");
2346 if (config)
2347 gst_video_converter_set_config (convert, config);
2348
2349 convert->in_maxwidth = GST_VIDEO_INFO_WIDTH (in_info);
2350 convert->in_maxheight = GST_VIDEO_INFO_FIELD_HEIGHT (in_info);
2351 convert->out_maxwidth = GST_VIDEO_INFO_WIDTH (out_info);
2352 convert->out_maxheight = GST_VIDEO_INFO_FIELD_HEIGHT (out_info);
2353
2354 convert->in_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_X, 0);
2355 convert->in_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_Y, 0);
2356 convert->in_x &= ~((1 << fin->w_sub[1]) - 1);
2357 convert->in_y &= ~((1 << fin->h_sub[1]) - 1);
2358
2359 convert->in_width = get_opt_int (convert,
2360 GST_VIDEO_CONVERTER_OPT_SRC_WIDTH, convert->in_maxwidth - convert->in_x);
2361 convert->in_height = get_opt_int (convert,
2362 GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT,
2363 convert->in_maxheight - convert->in_y);
2364
2365 convert->in_width =
2366 MIN (convert->in_width, convert->in_maxwidth - convert->in_x);
2367 if (convert->in_width + convert->in_x < 0 ||
2368 convert->in_width + convert->in_x > convert->in_maxwidth) {
2369 convert->in_width = 0;
2370 }
2371
2372 convert->in_height =
2373 MIN (convert->in_height, convert->in_maxheight - convert->in_y);
2374 if (convert->in_height + convert->in_y < 0 ||
2375 convert->in_height + convert->in_y > convert->in_maxheight) {
2376 convert->in_height = 0;
2377 }
2378
2379 convert->out_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_X, 0);
2380 convert->out_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_Y, 0);
2381 convert->out_x &= ~((1 << fout->w_sub[1]) - 1);
2382 convert->out_y &= ~((1 << fout->h_sub[1]) - 1);
2383
2384 convert->out_width = get_opt_int (convert,
2385 GST_VIDEO_CONVERTER_OPT_DEST_WIDTH,
2386 convert->out_maxwidth - convert->out_x);
2387 convert->out_height =
2388 get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT,
2389 convert->out_maxheight - convert->out_y);
2390
2391 if (convert->out_width > convert->out_maxwidth - convert->out_x)
2392 convert->out_width = convert->out_maxwidth - convert->out_x;
2393 convert->out_width = CLAMP (convert->out_width, 0, convert->out_maxwidth);
2394
2395 /* Check if completely outside the framebuffer */
2396 if (convert->out_width + convert->out_x < 0 ||
2397 convert->out_width + convert->out_x > convert->out_maxwidth) {
2398 convert->out_width = 0;
2399 }
2400
2401 /* Same for height */
2402 if (convert->out_height > convert->out_maxheight - convert->out_y)
2403 convert->out_height = convert->out_maxheight - convert->out_y;
2404 convert->out_height = CLAMP (convert->out_height, 0, convert->out_maxheight);
2405
2406 if (convert->out_height + convert->out_y < 0 ||
2407 convert->out_height + convert->out_y > convert->out_maxheight) {
2408 convert->out_height = 0;
2409 }
2410
2411 convert->fill_border = GET_OPT_FILL_BORDER (convert);
2412 convert->border_argb = get_opt_uint (convert,
2413 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB);
2414
2415 alpha_value = GET_OPT_ALPHA_VALUE (convert);
2416 convert->alpha_value = 255 * alpha_value;
2417 convert->alpha_mode = convert_get_alpha_mode (convert);
2418
2419 convert->unpack_format = in_info->finfo->unpack_format;
2420 finfo = gst_video_format_get_info (convert->unpack_format);
2421 convert->unpack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2422 convert->unpack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2423 if (convert->unpack_rgb
2424 && in_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2425 /* force identity matrix for RGB input */
2426 GST_WARNING ("invalid matrix %d for input RGB format, using RGB",
2427 in_info->colorimetry.matrix);
2428 convert->in_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2429 }
2430
2431 convert->pack_format = out_info->finfo->unpack_format;
2432 finfo = gst_video_format_get_info (convert->pack_format);
2433 convert->pack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2434 convert->pack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2435 convert->pack_pal =
2436 gst_video_format_get_palette (GST_VIDEO_INFO_FORMAT (out_info),
2437 &convert->pack_palsize);
2438 if (convert->pack_rgb
2439 && out_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2440 /* force identity matrix for RGB output */
2441 GST_WARNING ("invalid matrix %d for output RGB format, using RGB",
2442 out_info->colorimetry.matrix);
2443 convert->out_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2444 }
2445
2446 n_threads = get_opt_uint (convert, GST_VIDEO_CONVERTER_OPT_THREADS, 1);
2447 if (n_threads == 0 || n_threads > g_get_num_processors ())
2448 n_threads = g_get_num_processors ();
2449 /* Magic number of 200 lines */
2450 if (MAX (convert->out_height, convert->in_height) / n_threads < 200)
2451 n_threads = (MAX (convert->out_height, convert->in_height) + 199) / 200;
2452 if (n_threads < 1)
2453 n_threads = 1;
2454
2455 async_tasks = GET_OPT_ASYNC_TASKS (convert);
2456 convert->conversion_runner =
2457 gst_parallelized_task_runner_new (n_threads, pool, async_tasks);
2458
2459 if (video_converter_lookup_fastpath (convert))
2460 goto done;
2461
2462 if (in_info->finfo->unpack_func == NULL)
2463 goto no_unpack_func;
2464
2465 if (out_info->finfo->pack_func == NULL)
2466 goto no_pack_func;
2467
2468 convert->convert = video_converter_generic;
2469
2470 convert->upsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2471 convert->upsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2472 convert->downsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2473 convert->downsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2474 convert->v_scaler_p = g_new0 (GstVideoScaler *, n_threads);
2475 convert->v_scaler_i = g_new0 (GstVideoScaler *, n_threads);
2476 convert->h_scaler = g_new0 (GstVideoScaler *, n_threads);
2477 convert->unpack_lines = g_new0 (GstLineCache *, n_threads);
2478 convert->pack_lines = g_new0 (GstLineCache *, n_threads);
2479 convert->upsample_lines = g_new0 (GstLineCache *, n_threads);
2480 convert->to_RGB_lines = g_new0 (GstLineCache *, n_threads);
2481 convert->hscale_lines = g_new0 (GstLineCache *, n_threads);
2482 convert->vscale_lines = g_new0 (GstLineCache *, n_threads);
2483 convert->convert_lines = g_new0 (GstLineCache *, n_threads);
2484 convert->alpha_lines = g_new0 (GstLineCache *, n_threads);
2485 convert->to_YUV_lines = g_new0 (GstLineCache *, n_threads);
2486 convert->downsample_lines = g_new0 (GstLineCache *, n_threads);
2487 convert->dither_lines = g_new0 (GstLineCache *, n_threads);
2488 convert->dither = g_new0 (GstVideoDither *, n_threads);
2489
2490 if (convert->in_width > 0 && convert->out_width > 0 && convert->in_height > 0
2491 && convert->out_height > 0) {
2492 for (i = 0; i < n_threads; i++) {
2493 convert->current_format = GST_VIDEO_INFO_FORMAT (in_info);
2494 convert->current_width = convert->in_width;
2495 convert->current_height = convert->in_height;
2496
2497 /* unpack */
2498 prev = chain_unpack_line (convert, i);
2499 /* upsample chroma */
2500 prev = chain_upsample (convert, prev, i);
2501 /* convert to gamma decoded RGB */
2502 prev = chain_convert_to_RGB (convert, prev, i);
2503 /* do all downscaling */
2504 prev = chain_scale (convert, prev, FALSE, i);
2505 /* do conversion between color spaces */
2506 prev = chain_convert (convert, prev, i);
2507 /* do alpha channels */
2508 prev = chain_alpha (convert, prev, i);
2509 /* do all remaining (up)scaling */
2510 prev = chain_scale (convert, prev, TRUE, i);
2511 /* convert to gamma encoded Y'Cb'Cr' */
2512 prev = chain_convert_to_YUV (convert, prev, i);
2513 /* downsample chroma */
2514 prev = chain_downsample (convert, prev, i);
2515 /* dither */
2516 prev = chain_dither (convert, prev, i);
2517 /* pack into final format */
2518 convert->pack_lines[i] = chain_pack (convert, prev, i);
2519 }
2520 }
2521
2522 setup_borderline (convert);
2523 /* now figure out allocators */
2524 setup_allocators (convert);
2525
2526 done:
2527 return convert;
2528
2529 /* ERRORS */
2530 no_unpack_func:
2531 {
2532 GST_ERROR ("no unpack_func for format %s",
2533 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
2534 gst_video_converter_free (convert);
2535 return NULL;
2536 }
2537 no_pack_func:
2538 {
2539 GST_ERROR ("no pack_func for format %s",
2540 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
2541 gst_video_converter_free (convert);
2542 return NULL;
2543 }
2544 }
2545
2546 /**
2547 * gst_video_converter_new: (skip)
2548 * @in_info: a #GstVideoInfo
2549 * @out_info: a #GstVideoInfo
2550 * @config: (transfer full): a #GstStructure with configuration options
2551 *
2552 * Create a new converter object to convert between @in_info and @out_info
2553 * with @config.
2554 *
2555 * Returns: a #GstVideoConverter or %NULL if conversion is not possible.
2556 *
2557 * Since: 1.6
2558 */
2559 GstVideoConverter *
gst_video_converter_new(const GstVideoInfo * in_info,const GstVideoInfo * out_info,GstStructure * config)2560 gst_video_converter_new (const GstVideoInfo * in_info,
2561 const GstVideoInfo * out_info, GstStructure * config)
2562 {
2563 return gst_video_converter_new_with_pool (in_info, out_info, config, NULL);
2564 }
2565
2566 static void
clear_matrix_data(MatrixData * data)2567 clear_matrix_data (MatrixData * data)
2568 {
2569 g_free (data->t_r);
2570 g_free (data->t_g);
2571 g_free (data->t_b);
2572 }
2573
2574 /**
2575 * gst_video_converter_free:
2576 * @convert: a #GstVideoConverter
2577 *
2578 * Free @convert
2579 *
2580 * Since: 1.6
2581 */
2582 void
gst_video_converter_free(GstVideoConverter * convert)2583 gst_video_converter_free (GstVideoConverter * convert)
2584 {
2585 guint i, j;
2586
2587 g_return_if_fail (convert != NULL);
2588
2589 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2590 if (convert->upsample_p && convert->upsample_p[i])
2591 gst_video_chroma_resample_free (convert->upsample_p[i]);
2592 if (convert->upsample_i && convert->upsample_i[i])
2593 gst_video_chroma_resample_free (convert->upsample_i[i]);
2594 if (convert->downsample_p && convert->downsample_p[i])
2595 gst_video_chroma_resample_free (convert->downsample_p[i]);
2596 if (convert->downsample_i && convert->downsample_i[i])
2597 gst_video_chroma_resample_free (convert->downsample_i[i]);
2598 if (convert->v_scaler_p && convert->v_scaler_p[i])
2599 gst_video_scaler_free (convert->v_scaler_p[i]);
2600 if (convert->v_scaler_i && convert->v_scaler_i[i])
2601 gst_video_scaler_free (convert->v_scaler_i[i]);
2602 if (convert->h_scaler && convert->h_scaler[i])
2603 gst_video_scaler_free (convert->h_scaler[i]);
2604 if (convert->unpack_lines && convert->unpack_lines[i])
2605 gst_line_cache_free (convert->unpack_lines[i]);
2606 if (convert->upsample_lines && convert->upsample_lines[i])
2607 gst_line_cache_free (convert->upsample_lines[i]);
2608 if (convert->to_RGB_lines && convert->to_RGB_lines[i])
2609 gst_line_cache_free (convert->to_RGB_lines[i]);
2610 if (convert->hscale_lines && convert->hscale_lines[i])
2611 gst_line_cache_free (convert->hscale_lines[i]);
2612 if (convert->vscale_lines && convert->vscale_lines[i])
2613 gst_line_cache_free (convert->vscale_lines[i]);
2614 if (convert->convert_lines && convert->convert_lines[i])
2615 gst_line_cache_free (convert->convert_lines[i]);
2616 if (convert->alpha_lines && convert->alpha_lines[i])
2617 gst_line_cache_free (convert->alpha_lines[i]);
2618 if (convert->to_YUV_lines && convert->to_YUV_lines[i])
2619 gst_line_cache_free (convert->to_YUV_lines[i]);
2620 if (convert->downsample_lines && convert->downsample_lines[i])
2621 gst_line_cache_free (convert->downsample_lines[i]);
2622 if (convert->dither_lines && convert->dither_lines[i])
2623 gst_line_cache_free (convert->dither_lines[i]);
2624 if (convert->dither && convert->dither[i])
2625 gst_video_dither_free (convert->dither[i]);
2626 }
2627 g_free (convert->upsample_p);
2628 g_free (convert->upsample_i);
2629 g_free (convert->downsample_p);
2630 g_free (convert->downsample_i);
2631 g_free (convert->v_scaler_p);
2632 g_free (convert->v_scaler_i);
2633 g_free (convert->h_scaler);
2634 g_free (convert->unpack_lines);
2635 g_free (convert->pack_lines);
2636 g_free (convert->upsample_lines);
2637 g_free (convert->to_RGB_lines);
2638 g_free (convert->hscale_lines);
2639 g_free (convert->vscale_lines);
2640 g_free (convert->convert_lines);
2641 g_free (convert->alpha_lines);
2642 g_free (convert->to_YUV_lines);
2643 g_free (convert->downsample_lines);
2644 g_free (convert->dither_lines);
2645 g_free (convert->dither);
2646
2647 g_free (convert->gamma_dec.gamma_table);
2648 g_free (convert->gamma_enc.gamma_table);
2649
2650 if (convert->tmpline) {
2651 for (i = 0; i < convert->conversion_runner->n_threads; i++)
2652 g_free (convert->tmpline[i]);
2653 g_free (convert->tmpline);
2654 }
2655
2656 g_free (convert->borderline);
2657
2658 if (convert->config)
2659 gst_structure_free (convert->config);
2660
2661 for (i = 0; i < 4; i++) {
2662 for (j = 0; j < convert->conversion_runner->n_threads; j++) {
2663 if (convert->fv_scaler[i].scaler)
2664 gst_video_scaler_free (convert->fv_scaler[i].scaler[j]);
2665 if (convert->fh_scaler[i].scaler)
2666 gst_video_scaler_free (convert->fh_scaler[i].scaler[j]);
2667 }
2668 g_free (convert->fv_scaler[i].scaler);
2669 g_free (convert->fh_scaler[i].scaler);
2670 }
2671
2672 if (convert->conversion_runner)
2673 gst_parallelized_task_runner_free (convert->conversion_runner);
2674
2675 clear_matrix_data (&convert->to_RGB_matrix);
2676 clear_matrix_data (&convert->convert_matrix);
2677 clear_matrix_data (&convert->to_YUV_matrix);
2678
2679 for (i = 0; i < 4; i++) {
2680 g_free (convert->tasks[i]);
2681 g_free (convert->tasks_p[i]);
2682 }
2683
2684 g_slice_free (GstVideoConverter, convert);
2685 }
2686
2687 static gboolean
copy_config(GQuark field_id,const GValue * value,gpointer user_data)2688 copy_config (GQuark field_id, const GValue * value, gpointer user_data)
2689 {
2690 GstVideoConverter *convert = user_data;
2691
2692 gst_structure_id_set_value (convert->config, field_id, value);
2693
2694 return TRUE;
2695 }
2696
2697 /**
2698 * gst_video_converter_set_config:
2699 * @convert: a #GstVideoConverter
2700 * @config: (transfer full): a #GstStructure
2701 *
2702 * Set @config as extra configuration for @convert.
2703 *
2704 * If the parameters in @config can not be set exactly, this function returns
2705 * %FALSE and will try to update as much state as possible. The new state can
2706 * then be retrieved and refined with gst_video_converter_get_config().
2707 *
2708 * Look at the `GST_VIDEO_CONVERTER_OPT_*` fields to check valid configuration
2709 * option and values.
2710 *
2711 * Returns: %TRUE when @config could be set.
2712 *
2713 * Since: 1.6
2714 */
2715 gboolean
gst_video_converter_set_config(GstVideoConverter * convert,GstStructure * config)2716 gst_video_converter_set_config (GstVideoConverter * convert,
2717 GstStructure * config)
2718 {
2719 g_return_val_if_fail (convert != NULL, FALSE);
2720 g_return_val_if_fail (config != NULL, FALSE);
2721
2722 gst_structure_foreach (config, copy_config, convert);
2723 gst_structure_free (config);
2724
2725 return TRUE;
2726 }
2727
2728 /**
2729 * gst_video_converter_get_config:
2730 * @convert: a #GstVideoConverter
2731 *
2732 * Get the current configuration of @convert.
2733 *
2734 * Returns: a #GstStructure that remains valid for as long as @convert is valid
2735 * or until gst_video_converter_set_config() is called.
2736 */
2737 const GstStructure *
gst_video_converter_get_config(GstVideoConverter * convert)2738 gst_video_converter_get_config (GstVideoConverter * convert)
2739 {
2740 g_return_val_if_fail (convert != NULL, NULL);
2741
2742 return convert->config;
2743 }
2744
2745 /**
2746 * gst_video_converter_frame:
2747 * @convert: a #GstVideoConverter
2748 * @dest: a #GstVideoFrame
2749 * @src: a #GstVideoFrame
2750 *
2751 * Convert the pixels of @src into @dest using @convert.
2752 *
2753 * If #GST_VIDEO_CONVERTER_OPT_ASYNC_TASKS is %TRUE then this function will
2754 * return immediately and needs to be followed by a call to
2755 * gst_video_converter_frame_finish().
2756 *
2757 * Since: 1.6
2758 */
2759 void
gst_video_converter_frame(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)2760 gst_video_converter_frame (GstVideoConverter * convert,
2761 const GstVideoFrame * src, GstVideoFrame * dest)
2762 {
2763 g_return_if_fail (convert != NULL);
2764 g_return_if_fail (src != NULL);
2765 g_return_if_fail (dest != NULL);
2766
2767 /* Check the frames we've been passed match the layout
2768 * we were configured for or we might go out of bounds */
2769 if (G_UNLIKELY (GST_VIDEO_INFO_FORMAT (&convert->in_info) !=
2770 GST_VIDEO_FRAME_FORMAT (src)
2771 || GST_VIDEO_INFO_WIDTH (&convert->in_info) >
2772 GST_VIDEO_FRAME_WIDTH (src)
2773 || GST_VIDEO_INFO_FIELD_HEIGHT (&convert->in_info) >
2774 GST_VIDEO_FRAME_HEIGHT (src))) {
2775 g_critical ("Input video frame does not match configuration");
2776 return;
2777 }
2778 if (G_UNLIKELY (GST_VIDEO_INFO_FORMAT (&convert->out_info) !=
2779 GST_VIDEO_FRAME_FORMAT (dest)
2780 || GST_VIDEO_INFO_WIDTH (&convert->out_info) >
2781 GST_VIDEO_FRAME_WIDTH (dest)
2782 || GST_VIDEO_INFO_FIELD_HEIGHT (&convert->out_info) >
2783 GST_VIDEO_FRAME_HEIGHT (dest))) {
2784 g_critical ("Output video frame does not match configuration");
2785 return;
2786 }
2787
2788 if (G_UNLIKELY (convert->in_width == 0 || convert->in_height == 0 ||
2789 convert->out_width == 0 || convert->out_height == 0))
2790 return;
2791
2792 convert->convert (convert, src, dest);
2793 }
2794
2795 /**
2796 * gst_video_converter_frame_finish:
2797 * @convert: a #GstVideoConverter
2798 *
2799 * Wait for a previous async conversion performed using
2800 * gst_video_converter_frame() to complete.
2801 *
2802 * Since: 1.20
2803 */
2804 void
gst_video_converter_frame_finish(GstVideoConverter * convert)2805 gst_video_converter_frame_finish (GstVideoConverter * convert)
2806 {
2807 g_return_if_fail (convert);
2808 g_return_if_fail (convert->conversion_runner);
2809 g_return_if_fail (convert->conversion_runner->async_tasks);
2810
2811 gst_parallelized_task_runner_finish (convert->conversion_runner);
2812 }
2813
2814 static void
video_converter_compute_matrix(GstVideoConverter * convert)2815 video_converter_compute_matrix (GstVideoConverter * convert)
2816 {
2817 MatrixData *dst = &convert->convert_matrix;
2818
2819 color_matrix_set_identity (dst);
2820 compute_matrix_to_RGB (convert, dst);
2821 compute_matrix_to_YUV (convert, dst, FALSE);
2822
2823 convert->current_bits = 8;
2824 prepare_matrix (convert, dst);
2825 }
2826
2827 static void
video_converter_compute_resample(GstVideoConverter * convert,gint idx)2828 video_converter_compute_resample (GstVideoConverter * convert, gint idx)
2829 {
2830 GstVideoInfo *in_info, *out_info;
2831 const GstVideoFormatInfo *sfinfo, *dfinfo;
2832
2833 if (CHECK_CHROMA_NONE (convert))
2834 return;
2835
2836 in_info = &convert->in_info;
2837 out_info = &convert->out_info;
2838
2839 sfinfo = in_info->finfo;
2840 dfinfo = out_info->finfo;
2841
2842 GST_DEBUG ("site: %d->%d, w_sub: %d->%d, h_sub: %d->%d", in_info->chroma_site,
2843 out_info->chroma_site, sfinfo->w_sub[2], dfinfo->w_sub[2],
2844 sfinfo->h_sub[2], dfinfo->h_sub[2]);
2845
2846 if (sfinfo->w_sub[2] != dfinfo->w_sub[2] ||
2847 sfinfo->h_sub[2] != dfinfo->h_sub[2] ||
2848 in_info->chroma_site != out_info->chroma_site ||
2849 in_info->width != out_info->width ||
2850 in_info->height != out_info->height) {
2851 if (GST_VIDEO_INFO_IS_INTERLACED (in_info)
2852 && GST_VIDEO_INFO_INTERLACE_MODE (in_info) !=
2853 GST_VIDEO_INTERLACE_MODE_ALTERNATE) {
2854 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2855 convert->upsample_i[idx] = gst_video_chroma_resample_new (0,
2856 in_info->chroma_site, GST_VIDEO_CHROMA_FLAG_INTERLACED,
2857 sfinfo->unpack_format, sfinfo->w_sub[2], sfinfo->h_sub[2]);
2858 if (!CHECK_CHROMA_UPSAMPLE (convert))
2859 convert->downsample_i[idx] =
2860 gst_video_chroma_resample_new (0, out_info->chroma_site,
2861 GST_VIDEO_CHROMA_FLAG_INTERLACED, dfinfo->unpack_format,
2862 -dfinfo->w_sub[2], -dfinfo->h_sub[2]);
2863 }
2864 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2865 convert->upsample_p[idx] = gst_video_chroma_resample_new (0,
2866 in_info->chroma_site, 0, sfinfo->unpack_format, sfinfo->w_sub[2],
2867 sfinfo->h_sub[2]);
2868 if (!CHECK_CHROMA_UPSAMPLE (convert))
2869 convert->downsample_p[idx] = gst_video_chroma_resample_new (0,
2870 out_info->chroma_site, 0, dfinfo->unpack_format, -dfinfo->w_sub[2],
2871 -dfinfo->h_sub[2]);
2872 }
2873 }
2874
2875 #define FRAME_GET_PLANE_STRIDE(frame, plane) \
2876 GST_VIDEO_FRAME_PLANE_STRIDE (frame, plane)
2877 #define FRAME_GET_PLANE_LINE(frame, plane, line) \
2878 (gpointer)(((guint8*)(GST_VIDEO_FRAME_PLANE_DATA (frame, plane))) + \
2879 FRAME_GET_PLANE_STRIDE (frame, plane) * (line))
2880
2881 #define FRAME_GET_COMP_STRIDE(frame, comp) \
2882 GST_VIDEO_FRAME_COMP_STRIDE (frame, comp)
2883 #define FRAME_GET_COMP_LINE(frame, comp, line) \
2884 (gpointer)(((guint8*)(GST_VIDEO_FRAME_COMP_DATA (frame, comp))) + \
2885 FRAME_GET_COMP_STRIDE (frame, comp) * (line))
2886
2887 #define FRAME_GET_STRIDE(frame) FRAME_GET_PLANE_STRIDE (frame, 0)
2888 #define FRAME_GET_LINE(frame,line) FRAME_GET_PLANE_LINE (frame, 0, line)
2889
2890 #define FRAME_GET_Y_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_Y, line)
2891 #define FRAME_GET_U_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_U, line)
2892 #define FRAME_GET_V_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_V, line)
2893 #define FRAME_GET_A_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_A, line)
2894
2895 #define FRAME_GET_Y_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_Y)
2896 #define FRAME_GET_U_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_U)
2897 #define FRAME_GET_V_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_V)
2898 #define FRAME_GET_A_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_A)
2899
2900
2901 #define UNPACK_FRAME(frame,dest,line,x,width) \
2902 frame->info.finfo->unpack_func (frame->info.finfo, \
2903 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2904 GST_VIDEO_PACK_FLAG_INTERLACED : \
2905 GST_VIDEO_PACK_FLAG_NONE), \
2906 dest, frame->data, frame->info.stride, x, \
2907 line, width)
2908 #define PACK_FRAME(frame,src,line,width) \
2909 frame->info.finfo->pack_func (frame->info.finfo, \
2910 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2911 GST_VIDEO_PACK_FLAG_INTERLACED : \
2912 GST_VIDEO_PACK_FLAG_NONE), \
2913 src, 0, frame->data, frame->info.stride, \
2914 frame->info.chroma_site, line, width);
2915
2916 static gpointer
get_dest_line(GstLineCache * cache,gint idx,gpointer user_data)2917 get_dest_line (GstLineCache * cache, gint idx, gpointer user_data)
2918 {
2919 GstVideoConverter *convert = user_data;
2920 guint8 *line;
2921 gint pstride = convert->pack_pstride;
2922 gint out_x = convert->out_x;
2923 guint cline;
2924
2925 cline = CLAMP (idx, 0, convert->out_maxheight - 1);
2926
2927 line = FRAME_GET_LINE (convert->dest, cline);
2928 GST_DEBUG ("get dest line %d %p", cline, line);
2929
2930 if (convert->borderline) {
2931 gint r_border = (out_x + convert->out_width) * pstride;
2932 gint rb_width = convert->out_maxwidth * pstride - r_border;
2933 gint lb_width = out_x * pstride;
2934
2935 memcpy (line, convert->borderline, lb_width);
2936 memcpy (line + r_border, convert->borderline, rb_width);
2937 }
2938 line += out_x * pstride;
2939
2940 return line;
2941 }
2942
2943 static gboolean
do_unpack_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)2944 do_unpack_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2945 gpointer user_data)
2946 {
2947 GstVideoConverter *convert = user_data;
2948 gpointer tmpline;
2949 guint cline;
2950
2951 cline = CLAMP (in_line + convert->in_y, 0, convert->in_maxheight - 1);
2952
2953 if (cache->alloc_writable || !convert->identity_unpack) {
2954 tmpline = gst_line_cache_alloc_line (cache, out_line);
2955 GST_DEBUG ("unpack line %d (%u) %p", in_line, cline, tmpline);
2956 UNPACK_FRAME (convert->src, tmpline, cline, convert->in_x,
2957 convert->in_width);
2958 } else {
2959 tmpline = ((guint8 *) FRAME_GET_LINE (convert->src, cline)) +
2960 convert->in_x * convert->unpack_pstride;
2961 GST_DEBUG ("get src line %d (%u) %p", in_line, cline, tmpline);
2962 }
2963 gst_line_cache_add_line (cache, in_line, tmpline);
2964
2965 return TRUE;
2966 }
2967
2968 static gboolean
do_upsample_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)2969 do_upsample_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2970 gpointer user_data)
2971 {
2972 GstVideoConverter *convert = user_data;
2973 gpointer *lines;
2974 gint i, start_line, n_lines;
2975
2976 n_lines = convert->up_n_lines;
2977 start_line = in_line;
2978 if (start_line < n_lines + convert->up_offset) {
2979 start_line += convert->up_offset;
2980 out_line += convert->up_offset;
2981 }
2982
2983 /* get the lines needed for chroma upsample */
2984 lines =
2985 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
2986 n_lines);
2987
2988 if (convert->upsample[idx]) {
2989 GST_DEBUG ("doing upsample %d-%d %p", start_line, start_line + n_lines - 1,
2990 lines[0]);
2991 gst_video_chroma_resample (convert->upsample[idx], lines,
2992 convert->in_width);
2993 }
2994
2995 for (i = 0; i < n_lines; i++)
2996 gst_line_cache_add_line (cache, start_line + i, lines[i]);
2997
2998 return TRUE;
2999 }
3000
3001 static gboolean
do_convert_to_RGB_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3002 do_convert_to_RGB_lines (GstLineCache * cache, gint idx, gint out_line,
3003 gint in_line, gpointer user_data)
3004 {
3005 GstVideoConverter *convert = user_data;
3006 MatrixData *data = &convert->to_RGB_matrix;
3007 gpointer *lines, destline;
3008
3009 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3010 destline = lines[0];
3011
3012 if (data->matrix_func) {
3013 GST_DEBUG ("to RGB line %d %p", in_line, destline);
3014 data->matrix_func (data, destline);
3015 }
3016 if (convert->gamma_dec.gamma_func) {
3017 destline = gst_line_cache_alloc_line (cache, out_line);
3018
3019 GST_DEBUG ("gamma decode line %d %p->%p", in_line, lines[0], destline);
3020 convert->gamma_dec.gamma_func (&convert->gamma_dec, destline, lines[0]);
3021 }
3022 gst_line_cache_add_line (cache, in_line, destline);
3023
3024 return TRUE;
3025 }
3026
3027 static gboolean
do_hscale_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3028 do_hscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3029 gpointer user_data)
3030 {
3031 GstVideoConverter *convert = user_data;
3032 gpointer *lines, destline;
3033
3034 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3035
3036 destline = gst_line_cache_alloc_line (cache, out_line);
3037
3038 GST_DEBUG ("hresample line %d %p->%p", in_line, lines[0], destline);
3039 gst_video_scaler_horizontal (convert->h_scaler[idx], convert->h_scale_format,
3040 lines[0], destline, 0, convert->out_width);
3041
3042 gst_line_cache_add_line (cache, in_line, destline);
3043
3044 return TRUE;
3045 }
3046
3047 static gboolean
do_vscale_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3048 do_vscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3049 gpointer user_data)
3050 {
3051 GstVideoConverter *convert = user_data;
3052 gpointer *lines, destline;
3053 guint sline, n_lines;
3054 guint cline;
3055
3056 cline = CLAMP (in_line, 0, convert->out_height - 1);
3057
3058 gst_video_scaler_get_coeff (convert->v_scaler[idx], cline, &sline, &n_lines);
3059 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, sline, n_lines);
3060
3061 destline = gst_line_cache_alloc_line (cache, out_line);
3062
3063 GST_DEBUG ("vresample line %d %d-%d %p->%p", in_line, sline,
3064 sline + n_lines - 1, lines[0], destline);
3065 gst_video_scaler_vertical (convert->v_scaler[idx], convert->v_scale_format,
3066 lines, destline, cline, convert->v_scale_width);
3067
3068 gst_line_cache_add_line (cache, in_line, destline);
3069
3070 return TRUE;
3071 }
3072
3073 static gboolean
do_convert_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3074 do_convert_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3075 gpointer user_data)
3076 {
3077 GstVideoConverter *convert = user_data;
3078 MatrixData *data = &convert->convert_matrix;
3079 gpointer *lines, destline;
3080 guint in_bits, out_bits;
3081 gint width;
3082
3083 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3084
3085 destline = lines[0];
3086
3087 in_bits = convert->in_bits;
3088 out_bits = convert->out_bits;
3089
3090 width = MIN (convert->in_width, convert->out_width);
3091
3092 if (out_bits == 16 || in_bits == 16) {
3093 gpointer srcline = lines[0];
3094
3095 if (out_bits != in_bits)
3096 destline = gst_line_cache_alloc_line (cache, out_line);
3097
3098 /* FIXME, we can scale in the conversion matrix */
3099 if (in_bits == 8) {
3100 GST_DEBUG ("8->16 line %d %p->%p", in_line, srcline, destline);
3101 video_orc_convert_u8_to_u16 (destline, srcline, width * 4);
3102 srcline = destline;
3103 }
3104
3105 if (data->matrix_func) {
3106 GST_DEBUG ("matrix line %d %p", in_line, srcline);
3107 data->matrix_func (data, srcline);
3108 }
3109
3110 /* FIXME, dither here */
3111 if (out_bits == 8) {
3112 GST_DEBUG ("16->8 line %d %p->%p", in_line, srcline, destline);
3113 video_orc_convert_u16_to_u8 (destline, srcline, width * 4);
3114 }
3115 } else {
3116 if (data->matrix_func) {
3117 GST_DEBUG ("matrix line %d %p", in_line, destline);
3118 data->matrix_func (data, destline);
3119 }
3120 }
3121 gst_line_cache_add_line (cache, in_line, destline);
3122
3123 return TRUE;
3124 }
3125
3126 static gboolean
do_alpha_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3127 do_alpha_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3128 gpointer user_data)
3129 {
3130 gpointer *lines, destline;
3131 GstVideoConverter *convert = user_data;
3132 gint width = MIN (convert->in_width, convert->out_width);
3133
3134 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3135 destline = lines[0];
3136
3137 GST_DEBUG ("alpha line %d %p", in_line, destline);
3138 convert->alpha_func (convert, destline, width);
3139
3140 gst_line_cache_add_line (cache, in_line, destline);
3141
3142 return TRUE;
3143 }
3144
3145 static gboolean
do_convert_to_YUV_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3146 do_convert_to_YUV_lines (GstLineCache * cache, gint idx, gint out_line,
3147 gint in_line, gpointer user_data)
3148 {
3149 GstVideoConverter *convert = user_data;
3150 MatrixData *data = &convert->to_YUV_matrix;
3151 gpointer *lines, destline;
3152
3153 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3154 destline = lines[0];
3155
3156 if (convert->gamma_enc.gamma_func) {
3157 destline = gst_line_cache_alloc_line (cache, out_line);
3158
3159 GST_DEBUG ("gamma encode line %d %p->%p", in_line, lines[0], destline);
3160 convert->gamma_enc.gamma_func (&convert->gamma_enc, destline, lines[0]);
3161 }
3162 if (data->matrix_func) {
3163 GST_DEBUG ("to YUV line %d %p", in_line, destline);
3164 data->matrix_func (data, destline);
3165 }
3166 gst_line_cache_add_line (cache, in_line, destline);
3167
3168 return TRUE;
3169 }
3170
3171 static gboolean
do_downsample_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3172 do_downsample_lines (GstLineCache * cache, gint idx, gint out_line,
3173 gint in_line, gpointer user_data)
3174 {
3175 GstVideoConverter *convert = user_data;
3176 gpointer *lines;
3177 gint i, start_line, n_lines;
3178
3179 n_lines = convert->down_n_lines;
3180 start_line = in_line;
3181 if (start_line < n_lines + convert->down_offset)
3182 start_line += convert->down_offset;
3183
3184 /* get the lines needed for chroma downsample */
3185 lines =
3186 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
3187 n_lines);
3188
3189 if (convert->downsample[idx]) {
3190 GST_DEBUG ("downsample line %d %d-%d %p", in_line, start_line,
3191 start_line + n_lines - 1, lines[0]);
3192 gst_video_chroma_resample (convert->downsample[idx], lines,
3193 convert->out_width);
3194 }
3195
3196 for (i = 0; i < n_lines; i++)
3197 gst_line_cache_add_line (cache, start_line + i, lines[i]);
3198
3199 return TRUE;
3200 }
3201
3202 static gboolean
do_dither_lines(GstLineCache * cache,gint idx,gint out_line,gint in_line,gpointer user_data)3203 do_dither_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3204 gpointer user_data)
3205 {
3206 GstVideoConverter *convert = user_data;
3207 gpointer *lines, destline;
3208
3209 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3210 destline = lines[0];
3211
3212 if (convert->dither[idx]) {
3213 GST_DEBUG ("Dither line %d %p", in_line, destline);
3214 gst_video_dither_line (convert->dither[idx], destline, 0, out_line,
3215 convert->out_width);
3216 }
3217 gst_line_cache_add_line (cache, in_line, destline);
3218
3219 return TRUE;
3220 }
3221
3222 typedef struct
3223 {
3224 GstLineCache *pack_lines;
3225 gint idx;
3226 gint h_0, h_1;
3227 gint pack_lines_count;
3228 gint out_y;
3229 gboolean identity_pack;
3230 gint lb_width, out_maxwidth;
3231 GstVideoFrame *dest;
3232 } ConvertTask;
3233
3234 static void
convert_generic_task(ConvertTask * task)3235 convert_generic_task (ConvertTask * task)
3236 {
3237 gint i;
3238
3239 for (i = task->h_0; i < task->h_1; i += task->pack_lines_count) {
3240 gpointer *lines;
3241
3242 /* load the lines needed to pack */
3243 lines =
3244 gst_line_cache_get_lines (task->pack_lines, task->idx, i + task->out_y,
3245 i, task->pack_lines_count);
3246
3247 if (!task->identity_pack) {
3248 /* take away the border */
3249 guint8 *l = ((guint8 *) lines[0]) - task->lb_width;
3250 /* and pack into destination */
3251 GST_DEBUG ("pack line %d %p (%p)", i + task->out_y, lines[0], l);
3252 PACK_FRAME (task->dest, l, i + task->out_y, task->out_maxwidth);
3253 }
3254 }
3255 }
3256
3257 static void
video_converter_generic(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3258 video_converter_generic (GstVideoConverter * convert, const GstVideoFrame * src,
3259 GstVideoFrame * dest)
3260 {
3261 gint i;
3262 gint out_maxwidth, out_maxheight;
3263 gint out_x, out_y, out_height;
3264 gint pack_lines, pstride;
3265 gint lb_width;
3266 ConvertTask *tasks;
3267 ConvertTask **tasks_p;
3268 gint n_threads;
3269 gint lines_per_thread;
3270
3271 out_height = convert->out_height;
3272 out_maxwidth = convert->out_maxwidth;
3273 out_maxheight = convert->out_maxheight;
3274
3275 out_x = convert->out_x;
3276 out_y = convert->out_y;
3277
3278 convert->src = src;
3279 convert->dest = dest;
3280
3281 if (GST_VIDEO_FRAME_IS_INTERLACED (src)) {
3282 GST_DEBUG ("setup interlaced frame");
3283 convert->upsample = convert->upsample_i;
3284 convert->downsample = convert->downsample_i;
3285 convert->v_scaler = convert->v_scaler_i;
3286 } else {
3287 GST_DEBUG ("setup progressive frame");
3288 convert->upsample = convert->upsample_p;
3289 convert->downsample = convert->downsample_p;
3290 convert->v_scaler = convert->v_scaler_p;
3291 }
3292 if (convert->upsample[0]) {
3293 gst_video_chroma_resample_get_info (convert->upsample[0],
3294 &convert->up_n_lines, &convert->up_offset);
3295 } else {
3296 convert->up_n_lines = 1;
3297 convert->up_offset = 0;
3298 }
3299 if (convert->downsample[0]) {
3300 gst_video_chroma_resample_get_info (convert->downsample[0],
3301 &convert->down_n_lines, &convert->down_offset);
3302 } else {
3303 convert->down_n_lines = 1;
3304 convert->down_offset = 0;
3305 }
3306
3307 pack_lines = convert->pack_nlines; /* only 1 for now */
3308 pstride = convert->pack_pstride;
3309
3310 lb_width = out_x * pstride;
3311
3312 if (convert->borderline) {
3313 /* FIXME we should try to avoid PACK_FRAME */
3314 for (i = 0; i < out_y; i++)
3315 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3316 }
3317
3318 n_threads = convert->conversion_runner->n_threads;
3319 tasks = convert->tasks[0] =
3320 g_renew (ConvertTask, convert->tasks[0], n_threads);
3321 tasks_p = convert->tasks_p[0] =
3322 g_renew (ConvertTask *, convert->tasks_p[0], n_threads);
3323
3324 lines_per_thread =
3325 GST_ROUND_UP_N ((out_height + n_threads - 1) / n_threads, pack_lines);
3326
3327 for (i = 0; i < n_threads; i++) {
3328 tasks[i].dest = dest;
3329 tasks[i].pack_lines = convert->pack_lines[i];
3330 tasks[i].idx = i;
3331 tasks[i].pack_lines_count = pack_lines;
3332 tasks[i].out_y = out_y;
3333 tasks[i].identity_pack = convert->identity_pack;
3334 tasks[i].lb_width = lb_width;
3335 tasks[i].out_maxwidth = out_maxwidth;
3336
3337 tasks[i].h_0 = i * lines_per_thread;
3338 tasks[i].h_1 = MIN ((i + 1) * lines_per_thread, out_height);
3339
3340 tasks_p[i] = &tasks[i];
3341 }
3342
3343 gst_parallelized_task_runner_run (convert->conversion_runner,
3344 (GstParallelizedTaskFunc) convert_generic_task, (gpointer) tasks_p);
3345
3346 if (convert->borderline) {
3347 for (i = out_y + out_height; i < out_maxheight; i++)
3348 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3349 }
3350 if (convert->pack_pal) {
3351 memcpy (GST_VIDEO_FRAME_PLANE_DATA (dest, 1), convert->pack_pal,
3352 convert->pack_palsize);
3353 }
3354 }
3355
3356 static void convert_fill_border (GstVideoConverter * convert,
3357 GstVideoFrame * dest);
3358
3359 /* Fast paths */
3360
3361 #define GET_LINE_OFFSETS(interlaced,line,l1,l2) \
3362 if (interlaced) { \
3363 l1 = (line & 2 ? line - 1 : line); \
3364 l2 = l1 + 2; \
3365 } else { \
3366 l1 = line; \
3367 l2 = l1 + 1; \
3368 }
3369
3370 typedef struct
3371 {
3372 const GstVideoFrame *src;
3373 GstVideoFrame *dest;
3374 gint height_0, height_1;
3375
3376 /* parameters */
3377 gboolean interlaced;
3378 gint width;
3379 gint alpha;
3380 MatrixData *data;
3381 gint in_x, in_y;
3382 gint out_x, out_y;
3383 gpointer tmpline;
3384 } FConvertTask;
3385
3386 static void
convert_I420_YUY2_task(FConvertTask * task)3387 convert_I420_YUY2_task (FConvertTask * task)
3388 {
3389 gint i;
3390 gint l1, l2;
3391
3392 for (i = task->height_0; i < task->height_1; i += 2) {
3393 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3394
3395 video_orc_convert_I420_YUY2 (FRAME_GET_LINE (task->dest, l1),
3396 FRAME_GET_LINE (task->dest, l2),
3397 FRAME_GET_Y_LINE (task->src, l1),
3398 FRAME_GET_Y_LINE (task->src, l2),
3399 FRAME_GET_U_LINE (task->src, i >> 1),
3400 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3401 }
3402 }
3403
3404 static void
convert_I420_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3405 convert_I420_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
3406 GstVideoFrame * dest)
3407 {
3408 int i;
3409 gint width = convert->in_width;
3410 gint height = convert->in_height;
3411 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3412 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3413 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3414 gint h2;
3415 FConvertTask *tasks;
3416 FConvertTask **tasks_p;
3417 gint n_threads;
3418 gint lines_per_thread;
3419
3420 /* I420 has half as many chroma lines, as such we have to
3421 * always merge two into one. For non-interlaced these are
3422 * the two next to each other, for interlaced one is skipped
3423 * in between. */
3424 if (interlaced)
3425 h2 = GST_ROUND_DOWN_4 (height);
3426 else
3427 h2 = GST_ROUND_DOWN_2 (height);
3428
3429 n_threads = convert->conversion_runner->n_threads;
3430 tasks = convert->tasks[0] =
3431 g_renew (FConvertTask, convert->tasks[0], n_threads);
3432 tasks_p = convert->tasks_p[0] =
3433 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3434
3435 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3436
3437 for (i = 0; i < n_threads; i++) {
3438 tasks[i].src = src;
3439 tasks[i].dest = dest;
3440
3441 tasks[i].interlaced = interlaced;
3442 tasks[i].width = width;
3443
3444 tasks[i].height_0 = i * lines_per_thread;
3445 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3446 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3447
3448 tasks_p[i] = &tasks[i];
3449 }
3450
3451 gst_parallelized_task_runner_run (convert->conversion_runner,
3452 (GstParallelizedTaskFunc) convert_I420_YUY2_task, (gpointer) tasks_p);
3453
3454 /* now handle last lines. For interlaced these are up to 3 */
3455 if (h2 != height) {
3456 for (i = h2; i < height; i++) {
3457 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3458 PACK_FRAME (dest, convert->tmpline[0], i, width);
3459 }
3460 }
3461 }
3462
3463 static void
convert_I420_UYVY_task(FConvertTask * task)3464 convert_I420_UYVY_task (FConvertTask * task)
3465 {
3466 gint i;
3467 gint l1, l2;
3468
3469 for (i = task->height_0; i < task->height_1; i += 2) {
3470 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3471
3472 video_orc_convert_I420_UYVY (FRAME_GET_LINE (task->dest, l1),
3473 FRAME_GET_LINE (task->dest, l2),
3474 FRAME_GET_Y_LINE (task->src, l1),
3475 FRAME_GET_Y_LINE (task->src, l2),
3476 FRAME_GET_U_LINE (task->src, i >> 1),
3477 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3478 }
3479 }
3480
3481 static void
convert_I420_UYVY(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3482 convert_I420_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
3483 GstVideoFrame * dest)
3484 {
3485 int i;
3486 gint width = convert->in_width;
3487 gint height = convert->in_height;
3488 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3489 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3490 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3491 gint h2;
3492 FConvertTask *tasks;
3493 FConvertTask **tasks_p;
3494 gint n_threads;
3495 gint lines_per_thread;
3496
3497 /* I420 has half as many chroma lines, as such we have to
3498 * always merge two into one. For non-interlaced these are
3499 * the two next to each other, for interlaced one is skipped
3500 * in between. */
3501 if (interlaced)
3502 h2 = GST_ROUND_DOWN_4 (height);
3503 else
3504 h2 = GST_ROUND_DOWN_2 (height);
3505
3506 n_threads = convert->conversion_runner->n_threads;
3507 tasks = convert->tasks[0] =
3508 g_renew (FConvertTask, convert->tasks[0], n_threads);
3509 tasks_p = convert->tasks_p[0] =
3510 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3511
3512 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3513
3514 for (i = 0; i < n_threads; i++) {
3515 tasks[i].src = src;
3516 tasks[i].dest = dest;
3517
3518 tasks[i].interlaced = interlaced;
3519 tasks[i].width = width;
3520
3521 tasks[i].height_0 = i * lines_per_thread;
3522 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3523 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3524
3525 tasks_p[i] = &tasks[i];
3526 }
3527
3528 gst_parallelized_task_runner_run (convert->conversion_runner,
3529 (GstParallelizedTaskFunc) convert_I420_UYVY_task, (gpointer) tasks_p);
3530
3531 /* now handle last lines. For interlaced these are up to 3 */
3532 if (h2 != height) {
3533 for (i = h2; i < height; i++) {
3534 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3535 PACK_FRAME (dest, convert->tmpline[0], i, width);
3536 }
3537 }
3538 }
3539
3540 static void
convert_I420_AYUV_task(FConvertTask * task)3541 convert_I420_AYUV_task (FConvertTask * task)
3542 {
3543 gint i;
3544 gint l1, l2;
3545
3546 for (i = task->height_0; i < task->height_1; i += 2) {
3547 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3548
3549 video_orc_convert_I420_AYUV (FRAME_GET_LINE (task->dest, l1),
3550 FRAME_GET_LINE (task->dest, l2),
3551 FRAME_GET_Y_LINE (task->src, l1),
3552 FRAME_GET_Y_LINE (task->src, l2),
3553 FRAME_GET_U_LINE (task->src, i >> 1), FRAME_GET_V_LINE (task->src,
3554 i >> 1), task->alpha, task->width);
3555 }
3556 }
3557
3558 static void
convert_I420_AYUV(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3559 convert_I420_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3560 GstVideoFrame * dest)
3561 {
3562 int i;
3563 gint width = convert->in_width;
3564 gint height = convert->in_height;
3565 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3566 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3567 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3568 guint8 alpha = MIN (convert->alpha_value, 255);
3569 gint h2;
3570 FConvertTask *tasks;
3571 FConvertTask **tasks_p;
3572 gint n_threads;
3573 gint lines_per_thread;
3574
3575 /* I420 has half as many chroma lines, as such we have to
3576 * always merge two into one. For non-interlaced these are
3577 * the two next to each other, for interlaced one is skipped
3578 * in between. */
3579 if (interlaced)
3580 h2 = GST_ROUND_DOWN_4 (height);
3581 else
3582 h2 = GST_ROUND_DOWN_2 (height);
3583
3584
3585 n_threads = convert->conversion_runner->n_threads;
3586 tasks = convert->tasks[0] =
3587 g_renew (FConvertTask, convert->tasks[0], n_threads);
3588 tasks_p = convert->tasks_p[0] =
3589 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3590
3591 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3592
3593 for (i = 0; i < n_threads; i++) {
3594 tasks[i].src = src;
3595 tasks[i].dest = dest;
3596
3597 tasks[i].interlaced = interlaced;
3598 tasks[i].width = width;
3599 tasks[i].alpha = alpha;
3600
3601 tasks[i].height_0 = i * lines_per_thread;
3602 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3603 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3604
3605 tasks_p[i] = &tasks[i];
3606 }
3607
3608 gst_parallelized_task_runner_run (convert->conversion_runner,
3609 (GstParallelizedTaskFunc) convert_I420_AYUV_task, (gpointer) tasks_p);
3610
3611 /* now handle last lines. For interlaced these are up to 3 */
3612 if (h2 != height) {
3613 for (i = h2; i < height; i++) {
3614 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3615 if (alpha != 0xff)
3616 convert_set_alpha_u8 (convert, convert->tmpline[0], width);
3617 PACK_FRAME (dest, convert->tmpline[0], i, width);
3618 }
3619 }
3620 }
3621
3622 static void
convert_I420_v210_task(FConvertTask * task)3623 convert_I420_v210_task (FConvertTask * task)
3624 {
3625 gint i, j;
3626 gint l1, l2;
3627 const guint8 *s_y1, *s_y2, *s_u, *s_v;
3628 guint8 *d1, *d2;
3629 guint32 a0, a1, a2, a3;
3630 guint8 y0_1, y1_1, y2_1, y3_1, y4_1, y5_1;
3631 guint8 u0_1, u2_1, u4_1;
3632 guint8 v0_1, v2_1, v4_1;
3633 guint8 y0_2, y1_2, y2_2, y3_2, y4_2, y5_2;
3634 guint8 u0_2, u2_2, u4_2;
3635 guint8 v0_2, v2_2, v4_2;
3636
3637 for (i = task->height_0; i < task->height_1; i += 2) {
3638 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3639
3640 s_y1 = FRAME_GET_Y_LINE (task->src, l1);
3641 s_y2 = FRAME_GET_Y_LINE (task->src, l2);
3642 s_u = FRAME_GET_U_LINE (task->src, i >> 1);
3643 s_v = FRAME_GET_V_LINE (task->src, i >> 1);
3644
3645 d1 = FRAME_GET_LINE (task->dest, l1);
3646 d2 = FRAME_GET_LINE (task->dest, l2);
3647
3648 for (j = 0; j < task->width; j += 6) {
3649 y1_1 = y2_1 = y3_1 = y4_1 = y5_1 = 0;
3650 u2_1 = u4_1 = v2_1 = v4_1 = 0;
3651 y1_2 = y2_2 = y3_2 = y4_2 = y5_2 = 0;
3652 u2_2 = u4_2 = v2_2 = v4_2 = 0;
3653
3654 y0_1 = s_y1[j];
3655 y0_2 = s_y2[j];
3656
3657 u0_1 = u0_2 = s_u[j / 2];
3658 v0_1 = v0_2 = s_v[j / 2];
3659
3660 if (j < task->width - 1) {
3661 y1_1 = s_y1[j + 1];
3662 y1_2 = s_y2[j + 1];
3663 }
3664
3665 if (j < task->width - 2) {
3666 y2_1 = s_y1[j + 2];
3667 y2_2 = s_y2[j + 2];
3668
3669 u2_1 = u2_2 = s_u[j / 2 + 1];
3670 v2_1 = v2_2 = s_v[j / 2 + 1];
3671 }
3672
3673 if (j < task->width - 3) {
3674 y3_1 = s_y1[j + 3];
3675 y3_2 = s_y2[j + 3];
3676 }
3677
3678 if (j < task->width - 4) {
3679 y4_1 = s_y1[j + 4];
3680 y4_2 = s_y2[j + 4];
3681
3682 u4_1 = u4_2 = s_u[j / 2 + 2];
3683 v4_1 = v4_2 = s_v[j / 2 + 2];
3684 }
3685
3686 if (j < task->width - 5) {
3687 y5_1 = s_y1[j + 5];
3688 y5_2 = s_y2[j + 5];
3689 }
3690
3691 a0 = u0_1 << 2 | (y0_1 << 12) | (v0_1 << 22);
3692 a1 = y1_1 << 2 | (u2_1 << 12) | (y2_1 << 22);
3693 a2 = v2_1 << 2 | (y3_1 << 12) | (u4_1 << 22);
3694 a3 = y4_1 << 2 | (v4_1 << 12) | (y5_1 << 22);
3695
3696 GST_WRITE_UINT32_LE (d1 + (j / 6) * 16 + 0, a0);
3697 GST_WRITE_UINT32_LE (d1 + (j / 6) * 16 + 4, a1);
3698 GST_WRITE_UINT32_LE (d1 + (j / 6) * 16 + 8, a2);
3699 GST_WRITE_UINT32_LE (d1 + (j / 6) * 16 + 12, a3);
3700
3701 a0 = u0_2 << 2 | (y0_2 << 12) | (v0_2 << 22);
3702 a1 = y1_2 << 2 | (u2_2 << 12) | (y2_2 << 22);
3703 a2 = v2_2 << 2 | (y3_2 << 12) | (u4_2 << 22);
3704 a3 = y4_2 << 2 | (v4_2 << 12) | (y5_2 << 22);
3705
3706 GST_WRITE_UINT32_LE (d2 + (j / 6) * 16 + 0, a0);
3707 GST_WRITE_UINT32_LE (d2 + (j / 6) * 16 + 4, a1);
3708 GST_WRITE_UINT32_LE (d2 + (j / 6) * 16 + 8, a2);
3709 GST_WRITE_UINT32_LE (d2 + (j / 6) * 16 + 12, a3);
3710 }
3711 }
3712 }
3713
3714 static void
convert_I420_v210(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3715 convert_I420_v210 (GstVideoConverter * convert, const GstVideoFrame * src,
3716 GstVideoFrame * dest)
3717 {
3718 int i;
3719 gint width = convert->in_width;
3720 gint height = convert->in_height;
3721 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3722 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3723 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3724 gint h2;
3725 FConvertTask *tasks;
3726 FConvertTask **tasks_p;
3727 gint n_threads;
3728 gint lines_per_thread;
3729 guint8 *tmpline_8;
3730
3731 /* I420 has half as many chroma lines, as such we have to
3732 * always merge two into one. For non-interlaced these are
3733 * the two next to each other, for interlaced one is skipped
3734 * in between. */
3735 if (interlaced)
3736 h2 = GST_ROUND_DOWN_4 (height);
3737 else
3738 h2 = GST_ROUND_DOWN_2 (height);
3739
3740 n_threads = convert->conversion_runner->n_threads;
3741 tasks = convert->tasks[0] =
3742 g_renew (FConvertTask, convert->tasks[0], n_threads);
3743 tasks_p = convert->tasks_p[0] =
3744 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3745
3746 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3747
3748 for (i = 0; i < n_threads; i++) {
3749 tasks[i].src = src;
3750 tasks[i].dest = dest;
3751
3752 tasks[i].interlaced = interlaced;
3753 tasks[i].width = width;
3754
3755 tasks[i].height_0 = i * lines_per_thread;
3756 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3757 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3758
3759 tasks_p[i] = &tasks[i];
3760 }
3761
3762 gst_parallelized_task_runner_run (convert->conversion_runner,
3763 (GstParallelizedTaskFunc) convert_I420_v210_task, (gpointer) tasks_p);
3764
3765 /* now handle last lines. For interlaced these are up to 3 */
3766 if (h2 != height) {
3767 for (i = h2; i < height; i++) {
3768 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3769
3770 tmpline_8 = (guint8 *) convert->tmpline[0];
3771 for (int j = width * 4 - 1; j >= 0; j--) {
3772 convert->tmpline[0][j] = tmpline_8[j] << 8;
3773 }
3774
3775 PACK_FRAME (dest, convert->tmpline[0], i, width);
3776 }
3777 }
3778 }
3779
3780 static void
convert_YUY2_I420_task(FConvertTask * task)3781 convert_YUY2_I420_task (FConvertTask * task)
3782 {
3783 gint i;
3784 gint l1, l2;
3785
3786 for (i = task->height_0; i < task->height_1; i += 2) {
3787 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3788
3789 video_orc_convert_YUY2_I420 (FRAME_GET_Y_LINE (task->dest, l1),
3790 FRAME_GET_Y_LINE (task->dest, l2),
3791 FRAME_GET_U_LINE (task->dest, i >> 1),
3792 FRAME_GET_V_LINE (task->dest, i >> 1),
3793 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
3794 (task->width + 1) / 2);
3795 }
3796 }
3797
3798 static void
convert_YUY2_I420(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3799 convert_YUY2_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3800 GstVideoFrame * dest)
3801 {
3802 int i;
3803 gint width = convert->in_width;
3804 gint height = convert->in_height;
3805 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3806 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3807 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3808 gint h2;
3809 FConvertTask *tasks;
3810 FConvertTask **tasks_p;
3811 gint n_threads;
3812 gint lines_per_thread;
3813
3814 /* I420 has half as many chroma lines, as such we have to
3815 * always merge two into one. For non-interlaced these are
3816 * the two next to each other, for interlaced one is skipped
3817 * in between. */
3818 if (interlaced)
3819 h2 = GST_ROUND_DOWN_4 (height);
3820 else
3821 h2 = GST_ROUND_DOWN_2 (height);
3822
3823 n_threads = convert->conversion_runner->n_threads;
3824 tasks = convert->tasks[0] =
3825 g_renew (FConvertTask, convert->tasks[0], n_threads);
3826 tasks_p = convert->tasks_p[0] =
3827 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3828
3829 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3830
3831 for (i = 0; i < n_threads; i++) {
3832 tasks[i].src = src;
3833 tasks[i].dest = dest;
3834
3835 tasks[i].interlaced = interlaced;
3836 tasks[i].width = width;
3837
3838 tasks[i].height_0 = i * lines_per_thread;
3839 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3840 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3841
3842 tasks_p[i] = &tasks[i];
3843 }
3844
3845 gst_parallelized_task_runner_run (convert->conversion_runner,
3846 (GstParallelizedTaskFunc) convert_YUY2_I420_task, (gpointer) tasks_p);
3847
3848 /* now handle last lines. For interlaced these are up to 3 */
3849 if (h2 != height) {
3850 for (i = h2; i < height; i++) {
3851 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3852 PACK_FRAME (dest, convert->tmpline[0], i, width);
3853 }
3854 }
3855 }
3856
3857 static void
convert_v210_I420_task(FConvertTask * task)3858 convert_v210_I420_task (FConvertTask * task)
3859 {
3860 gint i, j;
3861 gint l1, l2;
3862 guint8 *d_y1, *d_y2, *d_u, *d_v;
3863 const guint8 *s1, *s2;
3864 guint32 a0, a1, a2, a3;
3865 guint16 y0_1, y1_1, y2_1, y3_1, y4_1, y5_1;
3866 guint16 u0_1, u2_1, u4_1;
3867 guint16 v0_1, v2_1, v4_1;
3868 guint16 y0_2, y1_2, y2_2, y3_2, y4_2, y5_2;
3869 guint16 u0_2, u2_2, u4_2;
3870 guint16 v0_2, v2_2, v4_2;
3871
3872 for (i = task->height_0; i < task->height_1; i += 2) {
3873 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3874
3875 d_y1 = FRAME_GET_Y_LINE (task->dest, l1);
3876 d_y2 = FRAME_GET_Y_LINE (task->dest, l2);
3877 d_u = FRAME_GET_U_LINE (task->dest, i >> 1);
3878 d_v = FRAME_GET_V_LINE (task->dest, i >> 1);
3879
3880 s1 = FRAME_GET_LINE (task->src, l1);
3881 s2 = FRAME_GET_LINE (task->src, l2);
3882
3883 for (j = 0; j < task->width; j += 6) {
3884 a0 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 0);
3885 a1 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 4);
3886 a2 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 8);
3887 a3 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 12);
3888
3889 u0_1 = ((a0 >> 0) & 0x3ff) >> 2;
3890 y0_1 = ((a0 >> 10) & 0x3ff) >> 2;
3891 v0_1 = ((a0 >> 20) & 0x3ff) >> 2;
3892 y1_1 = ((a1 >> 0) & 0x3ff) >> 2;
3893
3894 u2_1 = ((a1 >> 10) & 0x3ff) >> 2;
3895 y2_1 = ((a1 >> 20) & 0x3ff) >> 2;
3896 v2_1 = ((a2 >> 0) & 0x3ff) >> 2;
3897 y3_1 = ((a2 >> 10) & 0x3ff) >> 2;
3898
3899 u4_1 = ((a2 >> 20) & 0x3ff) >> 2;
3900 y4_1 = ((a3 >> 0) & 0x3ff) >> 2;
3901 v4_1 = ((a3 >> 10) & 0x3ff) >> 2;
3902 y5_1 = ((a3 >> 20) & 0x3ff) >> 2;
3903
3904 a0 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 0);
3905 a1 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 4);
3906 a2 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 8);
3907 a3 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 12);
3908
3909 u0_2 = ((a0 >> 0) & 0x3ff) >> 2;
3910 y0_2 = ((a0 >> 10) & 0x3ff) >> 2;
3911 v0_2 = ((a0 >> 20) & 0x3ff) >> 2;
3912 y1_2 = ((a1 >> 0) & 0x3ff) >> 2;
3913
3914 u2_2 = ((a1 >> 10) & 0x3ff) >> 2;
3915 y2_2 = ((a1 >> 20) & 0x3ff) >> 2;
3916 v2_2 = ((a2 >> 0) & 0x3ff) >> 2;
3917 y3_2 = ((a2 >> 10) & 0x3ff) >> 2;
3918
3919 u4_2 = ((a2 >> 20) & 0x3ff) >> 2;
3920 y4_2 = ((a3 >> 0) & 0x3ff) >> 2;
3921 v4_2 = ((a3 >> 10) & 0x3ff) >> 2;
3922 y5_2 = ((a3 >> 20) & 0x3ff) >> 2;
3923
3924 d_y1[j] = y0_1;
3925 d_y2[j] = y0_2;
3926 d_u[j / 2] = (u0_1 + u0_2) / 2;
3927 d_v[j / 2] = (v0_1 + v0_2) / 2;
3928
3929 if (j < task->width - 1) {
3930 d_y1[j + 1] = y1_1;
3931 d_y2[j + 1] = y1_2;
3932 }
3933
3934 if (j < task->width - 2) {
3935 d_y1[j + 2] = y2_1;
3936 d_y2[j + 2] = y2_2;
3937 d_u[j / 2 + 1] = (u2_1 + u2_2) / 2;
3938 d_v[j / 2 + 1] = (v2_1 + v2_2) / 2;
3939 }
3940
3941 if (j < task->width - 3) {
3942 d_y1[j + 3] = y3_1;
3943 d_y2[j + 3] = y3_2;
3944 }
3945
3946 if (j < task->width - 4) {
3947 d_y1[j + 4] = y4_1;
3948 d_y2[j + 4] = y4_2;
3949 d_u[j / 2 + 2] = (u4_1 + u4_2) / 2;
3950 d_v[j / 2 + 2] = (v4_1 + v4_2) / 2;
3951 }
3952
3953 if (j < task->width - 5) {
3954 d_y1[j + 5] = y5_1;
3955 d_y2[j + 5] = y5_2;
3956 }
3957 }
3958 }
3959 }
3960
3961 static void
convert_v210_I420(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)3962 convert_v210_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3963 GstVideoFrame * dest)
3964 {
3965 int i;
3966 gint width = convert->in_width;
3967 gint height = convert->in_height;
3968 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3969 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3970 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3971 gint h2;
3972 FConvertTask *tasks;
3973 FConvertTask **tasks_p;
3974 gint n_threads;
3975 gint lines_per_thread;
3976 guint8 *tmpline_8;
3977
3978 /* I420 has half as many chroma lines, as such we have to
3979 * always merge two into one. For non-interlaced these are
3980 * the two next to each other, for interlaced one is skipped
3981 * in between. */
3982 if (interlaced)
3983 h2 = GST_ROUND_DOWN_4 (height);
3984 else
3985 h2 = GST_ROUND_DOWN_2 (height);
3986
3987 n_threads = convert->conversion_runner->n_threads;
3988 tasks = convert->tasks[0] =
3989 g_renew (FConvertTask, convert->tasks[0], n_threads);
3990 tasks_p = convert->tasks_p[0] =
3991 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3992
3993 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3994
3995 for (i = 0; i < n_threads; i++) {
3996 tasks[i].src = src;
3997 tasks[i].dest = dest;
3998
3999 tasks[i].interlaced = interlaced;
4000 tasks[i].width = width;
4001
4002 tasks[i].height_0 = i * lines_per_thread;
4003 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
4004 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
4005
4006 tasks_p[i] = &tasks[i];
4007 }
4008
4009 gst_parallelized_task_runner_run (convert->conversion_runner,
4010 (GstParallelizedTaskFunc) convert_v210_I420_task, (gpointer) tasks_p);
4011
4012 /* now handle last lines. For interlaced these are up to 3 */
4013 if (h2 != height) {
4014 for (i = h2; i < height; i++) {
4015 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
4016
4017 tmpline_8 = (guint8 *) convert->tmpline[0];
4018 for (int j = 0; j < width * 4; j++) {
4019 tmpline_8[j] = convert->tmpline[0][j] >> 8;
4020 }
4021
4022 PACK_FRAME (dest, convert->tmpline[0], i, width);
4023 }
4024 }
4025 }
4026
4027 typedef struct
4028 {
4029 const guint8 *s, *s2, *su, *sv;
4030 guint8 *d, *d2, *du, *dv;
4031 gint sstride, sustride, svstride;
4032 gint dstride, dustride, dvstride;
4033 gint width, height;
4034 gint alpha;
4035 MatrixData *data;
4036 } FConvertPlaneTask;
4037
4038 static void
convert_YUY2_AYUV_task(FConvertPlaneTask * task)4039 convert_YUY2_AYUV_task (FConvertPlaneTask * task)
4040 {
4041 video_orc_convert_YUY2_AYUV (task->d, task->dstride, task->s,
4042 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
4043 }
4044
4045 static void
convert_YUY2_AYUV(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4046 convert_YUY2_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
4047 GstVideoFrame * dest)
4048 {
4049 gint width = convert->in_width;
4050 gint height = convert->in_height;
4051 guint8 *s, *d;
4052 guint8 alpha = MIN (convert->alpha_value, 255);
4053 FConvertPlaneTask *tasks;
4054 FConvertPlaneTask **tasks_p;
4055 gint n_threads;
4056 gint lines_per_thread;
4057 gint i;
4058
4059 s = FRAME_GET_LINE (src, convert->in_y);
4060 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4061 d = FRAME_GET_LINE (dest, convert->out_y);
4062 d += (convert->out_x * 4);
4063
4064 n_threads = convert->conversion_runner->n_threads;
4065 tasks = convert->tasks[0] =
4066 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4067 tasks_p = convert->tasks_p[0] =
4068 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4069
4070 lines_per_thread = (height + n_threads - 1) / n_threads;
4071
4072 for (i = 0; i < n_threads; i++) {
4073 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4074 tasks[i].sstride = FRAME_GET_STRIDE (src);
4075 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4076 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4077
4078 tasks[i].width = width;
4079 tasks[i].height = (i + 1) * lines_per_thread;
4080 tasks[i].height = MIN (tasks[i].height, height);
4081 tasks[i].height -= i * lines_per_thread;
4082 tasks[i].alpha = alpha;
4083
4084 tasks_p[i] = &tasks[i];
4085 }
4086
4087 gst_parallelized_task_runner_run (convert->conversion_runner,
4088 (GstParallelizedTaskFunc) convert_YUY2_AYUV_task, (gpointer) tasks_p);
4089
4090 convert_fill_border (convert, dest);
4091 }
4092
4093 static void
convert_YUY2_v210_task(FConvertPlaneTask * task)4094 convert_YUY2_v210_task (FConvertPlaneTask * task)
4095 {
4096 gint i, j;
4097 guint8 *d;
4098 const guint8 *s;
4099 guint32 a0, a1, a2, a3;
4100 guint8 y0, y1, y2, y3, y4, y5;
4101 guint8 u0, u2, u4;
4102 guint8 v0, v2, v4;
4103
4104 for (i = 0; i < task->height; i++) {
4105 d = task->d + i * task->dstride;
4106 s = task->s + i * task->sstride;
4107
4108 for (j = 0; j < task->width; j += 6) {
4109 y1 = y2 = y3 = y4 = y5 = 0;
4110 u2 = u4 = v2 = v4 = 0;
4111
4112 y0 = s[2 * j];
4113 u0 = s[2 * j + 1];
4114 v0 = s[2 * j + 3];
4115
4116 if (j < task->width - 1) {
4117 y1 = s[2 * j + 2];
4118 }
4119
4120 if (j < task->width - 2) {
4121 y2 = s[2 * j + 4];
4122 u2 = s[2 * j + 5];
4123 v2 = s[2 * j + 7];
4124 }
4125
4126 if (j < task->width - 3) {
4127 y3 = s[2 * j + 6];
4128 }
4129
4130 if (j < task->width - 4) {
4131 y4 = s[2 * j + 8];
4132 u4 = s[2 * j + 9];
4133 v4 = s[2 * j + 11];
4134 }
4135
4136 if (j < task->width - 5) {
4137 y5 = s[2 * j + 10];
4138 }
4139
4140 a0 = u0 << 2 | (y0 << 12) | (v0 << 22);
4141 a1 = y1 << 2 | (u2 << 12) | (y2 << 22);
4142 a2 = v2 << 2 | (y3 << 12) | (u4 << 22);
4143 a3 = y4 << 2 | (v4 << 12) | (y5 << 22);
4144
4145 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 0, a0);
4146 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 4, a1);
4147 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 8, a2);
4148 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 12, a3);
4149 }
4150 }
4151 }
4152
4153 static void
convert_YUY2_v210(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4154 convert_YUY2_v210 (GstVideoConverter * convert, const GstVideoFrame * src,
4155 GstVideoFrame * dest)
4156 {
4157 gint width = convert->in_width;
4158 gint height = convert->in_height;
4159 guint8 *s, *d;
4160 FConvertPlaneTask *tasks;
4161 FConvertPlaneTask **tasks_p;
4162 gint n_threads;
4163 gint lines_per_thread;
4164 gint i;
4165
4166 s = FRAME_GET_LINE (src, convert->in_y);
4167 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4168 d = FRAME_GET_LINE (dest, convert->out_y);
4169 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4170
4171 n_threads = convert->conversion_runner->n_threads;
4172 tasks = convert->tasks[0] =
4173 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4174 tasks_p = convert->tasks_p[0] =
4175 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4176
4177 lines_per_thread = (height + n_threads - 1) / n_threads;
4178
4179 for (i = 0; i < n_threads; i++) {
4180 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4181 tasks[i].sstride = FRAME_GET_STRIDE (src);
4182 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4183 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4184
4185 tasks[i].width = width;
4186 tasks[i].height = (i + 1) * lines_per_thread;
4187 tasks[i].height = MIN (tasks[i].height, height);
4188 tasks[i].height -= i * lines_per_thread;
4189
4190 tasks_p[i] = &tasks[i];
4191 }
4192
4193 gst_parallelized_task_runner_run (convert->conversion_runner,
4194 (GstParallelizedTaskFunc) convert_YUY2_v210_task, (gpointer) tasks_p);
4195
4196 convert_fill_border (convert, dest);
4197 }
4198
4199 static void
convert_YUY2_Y42B_task(FConvertPlaneTask * task)4200 convert_YUY2_Y42B_task (FConvertPlaneTask * task)
4201 {
4202 video_orc_convert_YUY2_Y42B (task->d, task->dstride, task->du,
4203 task->dustride, task->dv, task->dvstride,
4204 task->s, task->sstride, (task->width + 1) / 2, task->height);
4205 }
4206
4207 static void
convert_YUY2_Y42B(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4208 convert_YUY2_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4209 GstVideoFrame * dest)
4210 {
4211 gint width = convert->in_width;
4212 gint height = convert->in_height;
4213 guint8 *s, *dy, *du, *dv;
4214 FConvertPlaneTask *tasks;
4215 FConvertPlaneTask **tasks_p;
4216 gint n_threads;
4217 gint lines_per_thread;
4218 gint i;
4219
4220 s = FRAME_GET_LINE (src, convert->in_y);
4221 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4222
4223 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4224 dy += convert->out_x;
4225 du = FRAME_GET_U_LINE (dest, convert->out_y);
4226 du += convert->out_x >> 1;
4227 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4228 dv += convert->out_x >> 1;
4229
4230 n_threads = convert->conversion_runner->n_threads;
4231 tasks = convert->tasks[0] =
4232 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4233 tasks_p = convert->tasks_p[0] =
4234 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4235
4236 lines_per_thread = (height + n_threads - 1) / n_threads;
4237
4238 for (i = 0; i < n_threads; i++) {
4239 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4240 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4241 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4242 tasks[i].sstride = FRAME_GET_STRIDE (src);
4243 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4244 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4245 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4246 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4247
4248 tasks[i].width = width;
4249 tasks[i].height = (i + 1) * lines_per_thread;
4250 tasks[i].height = MIN (tasks[i].height, height);
4251 tasks[i].height -= i * lines_per_thread;
4252
4253 tasks_p[i] = &tasks[i];
4254 }
4255
4256 gst_parallelized_task_runner_run (convert->conversion_runner,
4257 (GstParallelizedTaskFunc) convert_YUY2_Y42B_task, (gpointer) tasks_p);
4258
4259 convert_fill_border (convert, dest);
4260 }
4261
4262 static void
convert_YUY2_Y444_task(FConvertPlaneTask * task)4263 convert_YUY2_Y444_task (FConvertPlaneTask * task)
4264 {
4265 video_orc_convert_YUY2_Y444 (task->d,
4266 task->dstride, task->du,
4267 task->dustride, task->dv,
4268 task->dvstride, task->s,
4269 task->sstride, (task->width + 1) / 2, task->height);
4270 }
4271
4272 static void
convert_YUY2_Y444(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4273 convert_YUY2_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
4274 GstVideoFrame * dest)
4275 {
4276 gint width = convert->in_width;
4277 gint height = convert->in_height;
4278 guint8 *s, *dy, *du, *dv;
4279 FConvertPlaneTask *tasks;
4280 FConvertPlaneTask **tasks_p;
4281 gint n_threads;
4282 gint lines_per_thread;
4283 gint i;
4284
4285 s = FRAME_GET_LINE (src, convert->in_y);
4286 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4287
4288 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4289 dy += convert->out_x;
4290 du = FRAME_GET_U_LINE (dest, convert->out_y);
4291 du += convert->out_x;
4292 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4293 dv += convert->out_x;
4294
4295 n_threads = convert->conversion_runner->n_threads;
4296 tasks = convert->tasks[0] =
4297 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4298 tasks_p = convert->tasks_p[0] =
4299 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4300
4301 lines_per_thread = (height + n_threads - 1) / n_threads;
4302
4303 for (i = 0; i < n_threads; i++) {
4304 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4305 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4306 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4307 tasks[i].sstride = FRAME_GET_STRIDE (src);
4308 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4309 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4310 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4311 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4312
4313 tasks[i].width = width;
4314 tasks[i].height = (i + 1) * lines_per_thread;
4315 tasks[i].height = MIN (tasks[i].height, height);
4316 tasks[i].height -= i * lines_per_thread;
4317
4318 tasks_p[i] = &tasks[i];
4319 }
4320
4321 gst_parallelized_task_runner_run (convert->conversion_runner,
4322 (GstParallelizedTaskFunc) convert_YUY2_Y444_task, (gpointer) tasks_p);
4323
4324 convert_fill_border (convert, dest);
4325 }
4326
4327 static void
convert_v210_Y42B_task(FConvertPlaneTask * task)4328 convert_v210_Y42B_task (FConvertPlaneTask * task)
4329 {
4330 gint i, j;
4331 guint8 *d_y, *d_u, *d_v;
4332 const guint8 *s;
4333 guint32 a0, a1, a2, a3;
4334 guint16 y0, y1, y2, y3, y4, y5;
4335 guint16 u0, u2, u4;
4336 guint16 v0, v2, v4;
4337
4338 for (i = 0; i < task->height; i++) {
4339 d_y = task->d + i * task->dstride;
4340 d_u = task->du + i * task->dustride;
4341 d_v = task->dv + i * task->dvstride;
4342 s = task->s + i * task->sstride;
4343
4344 for (j = 0; j < task->width; j += 6) {
4345 a0 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 0);
4346 a1 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 4);
4347 a2 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 8);
4348 a3 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 12);
4349
4350 u0 = ((a0 >> 0) & 0x3ff) >> 2;
4351 y0 = ((a0 >> 10) & 0x3ff) >> 2;
4352 v0 = ((a0 >> 20) & 0x3ff) >> 2;
4353 y1 = ((a1 >> 0) & 0x3ff) >> 2;
4354
4355 u2 = ((a1 >> 10) & 0x3ff) >> 2;
4356 y2 = ((a1 >> 20) & 0x3ff) >> 2;
4357 v2 = ((a2 >> 0) & 0x3ff) >> 2;
4358 y3 = ((a2 >> 10) & 0x3ff) >> 2;
4359
4360 u4 = ((a2 >> 20) & 0x3ff) >> 2;
4361 y4 = ((a3 >> 0) & 0x3ff) >> 2;
4362 v4 = ((a3 >> 10) & 0x3ff) >> 2;
4363 y5 = ((a3 >> 20) & 0x3ff) >> 2;
4364
4365 d_y[j] = y0;
4366 d_u[j / 2] = u0;
4367 d_v[j / 2] = v0;
4368
4369 if (j < task->width - 1) {
4370 d_y[j + 1] = y1;
4371 }
4372
4373 if (j < task->width - 2) {
4374 d_y[j + 2] = y2;
4375 d_u[j / 2 + 1] = u2;
4376 d_v[j / 2 + 1] = v2;
4377 }
4378
4379 if (j < task->width - 3) {
4380 d_y[j + 3] = y3;
4381 }
4382
4383 if (j < task->width - 4) {
4384 d_y[j + 4] = y4;
4385 d_u[j / 2 + 2] = u4;
4386 d_v[j / 2 + 2] = v4;
4387 }
4388
4389 if (j < task->width - 5) {
4390 d_y[j + 5] = y5;
4391 }
4392 }
4393 }
4394 }
4395
4396 static void
convert_v210_Y42B(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4397 convert_v210_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4398 GstVideoFrame * dest)
4399 {
4400 gint width = convert->in_width;
4401 gint height = convert->in_height;
4402 guint8 *s, *dy, *du, *dv;
4403 FConvertPlaneTask *tasks;
4404 FConvertPlaneTask **tasks_p;
4405 gint n_threads;
4406 gint lines_per_thread;
4407 gint i;
4408
4409 s = FRAME_GET_LINE (src, convert->in_y);
4410 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4411
4412 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4413 dy += convert->out_x;
4414 du = FRAME_GET_U_LINE (dest, convert->out_y);
4415 du += convert->out_x >> 1;
4416 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4417 dv += convert->out_x >> 1;
4418
4419 n_threads = convert->conversion_runner->n_threads;
4420 tasks = convert->tasks[0] =
4421 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4422 tasks_p = convert->tasks_p[0] =
4423 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4424
4425 lines_per_thread = (height + n_threads - 1) / n_threads;
4426
4427 for (i = 0; i < n_threads; i++) {
4428 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4429 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4430 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4431 tasks[i].sstride = FRAME_GET_STRIDE (src);
4432 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4433 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4434 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4435 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4436
4437 tasks[i].width = width;
4438 tasks[i].height = (i + 1) * lines_per_thread;
4439 tasks[i].height = MIN (tasks[i].height, height);
4440 tasks[i].height -= i * lines_per_thread;
4441
4442 tasks_p[i] = &tasks[i];
4443 }
4444
4445 gst_parallelized_task_runner_run (convert->conversion_runner,
4446 (GstParallelizedTaskFunc) convert_v210_Y42B_task, (gpointer) tasks_p);
4447
4448 convert_fill_border (convert, dest);
4449 }
4450
4451 static void
convert_UYVY_I420_task(FConvertTask * task)4452 convert_UYVY_I420_task (FConvertTask * task)
4453 {
4454 gint i;
4455 gint l1, l2;
4456
4457 for (i = task->height_0; i < task->height_1; i += 2) {
4458 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
4459
4460 video_orc_convert_UYVY_I420 (FRAME_GET_COMP_LINE (task->dest, 0, l1),
4461 FRAME_GET_COMP_LINE (task->dest, 0, l2),
4462 FRAME_GET_COMP_LINE (task->dest, 1, i >> 1),
4463 FRAME_GET_COMP_LINE (task->dest, 2, i >> 1),
4464 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
4465 (task->width + 1) / 2);
4466 }
4467 }
4468
4469 static void
convert_UYVY_I420(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4470 convert_UYVY_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
4471 GstVideoFrame * dest)
4472 {
4473 int i;
4474 gint width = convert->in_width;
4475 gint height = convert->in_height;
4476 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
4477 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
4478 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
4479 gint h2;
4480 FConvertTask *tasks;
4481 FConvertTask **tasks_p;
4482 gint n_threads;
4483 gint lines_per_thread;
4484
4485 /* I420 has half as many chroma lines, as such we have to
4486 * always merge two into one. For non-interlaced these are
4487 * the two next to each other, for interlaced one is skipped
4488 * in between. */
4489 if (interlaced)
4490 h2 = GST_ROUND_DOWN_4 (height);
4491 else
4492 h2 = GST_ROUND_DOWN_2 (height);
4493
4494 n_threads = convert->conversion_runner->n_threads;
4495 tasks = convert->tasks[0] =
4496 g_renew (FConvertTask, convert->tasks[0], n_threads);
4497 tasks_p = convert->tasks_p[0] =
4498 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
4499
4500 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
4501
4502 for (i = 0; i < n_threads; i++) {
4503 tasks[i].src = src;
4504 tasks[i].dest = dest;
4505
4506 tasks[i].interlaced = interlaced;
4507 tasks[i].width = width;
4508
4509 tasks[i].height_0 = i * lines_per_thread;
4510 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
4511 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
4512
4513 tasks_p[i] = &tasks[i];
4514 }
4515
4516 gst_parallelized_task_runner_run (convert->conversion_runner,
4517 (GstParallelizedTaskFunc) convert_UYVY_I420_task, (gpointer) tasks_p);
4518
4519 /* now handle last lines. For interlaced these are up to 3 */
4520 if (h2 != height) {
4521 for (i = h2; i < height; i++) {
4522 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
4523 PACK_FRAME (dest, convert->tmpline[0], i, width);
4524 }
4525 }
4526 }
4527
4528 static void
convert_UYVY_AYUV_task(FConvertPlaneTask * task)4529 convert_UYVY_AYUV_task (FConvertPlaneTask * task)
4530 {
4531 video_orc_convert_UYVY_AYUV (task->d, task->dstride, task->s,
4532 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
4533 }
4534
4535 static void
convert_UYVY_AYUV(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4536 convert_UYVY_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
4537 GstVideoFrame * dest)
4538 {
4539 gint width = convert->in_width;
4540 gint height = convert->in_height;
4541 guint8 *s, *d;
4542 guint8 alpha = MIN (convert->alpha_value, 255);
4543 FConvertPlaneTask *tasks;
4544 FConvertPlaneTask **tasks_p;
4545 gint n_threads;
4546 gint lines_per_thread;
4547 gint i;
4548
4549 s = FRAME_GET_LINE (src, convert->in_y);
4550 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4551 d = FRAME_GET_LINE (dest, convert->out_y);
4552 d += (convert->out_x * 4);
4553
4554 n_threads = convert->conversion_runner->n_threads;
4555 tasks = convert->tasks[0] =
4556 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4557 tasks_p = convert->tasks_p[0] =
4558 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4559
4560 lines_per_thread = (height + n_threads - 1) / n_threads;
4561
4562 for (i = 0; i < n_threads; i++) {
4563 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4564 tasks[i].sstride = FRAME_GET_STRIDE (src);
4565 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4566 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4567
4568 tasks[i].width = width;
4569 tasks[i].height = (i + 1) * lines_per_thread;
4570 tasks[i].height = MIN (tasks[i].height, height);
4571 tasks[i].height -= i * lines_per_thread;
4572 tasks[i].alpha = alpha;
4573
4574 tasks_p[i] = &tasks[i];
4575 }
4576
4577 gst_parallelized_task_runner_run (convert->conversion_runner,
4578 (GstParallelizedTaskFunc) convert_UYVY_AYUV_task, (gpointer) tasks_p);
4579
4580 convert_fill_border (convert, dest);
4581 }
4582
4583 static void
convert_UYVY_v210_task(FConvertPlaneTask * task)4584 convert_UYVY_v210_task (FConvertPlaneTask * task)
4585 {
4586 gint i, j;
4587 guint8 *d;
4588 const guint8 *s;
4589 guint32 a0, a1, a2, a3;
4590 guint8 y0, y1, y2, y3, y4, y5;
4591 guint8 u0, u2, u4;
4592 guint8 v0, v2, v4;
4593
4594 for (i = 0; i < task->height; i++) {
4595 d = task->d + i * task->dstride;
4596 s = task->s + i * task->sstride;
4597
4598 for (j = 0; j < task->width; j += 6) {
4599 y1 = y2 = y3 = y4 = y5 = 0;
4600 u2 = u4 = v2 = v4 = 0;
4601
4602 y0 = s[2 * j + 1];
4603 u0 = s[2 * j];
4604 v0 = s[2 * j + 2];
4605
4606 if (j < task->width - 1) {
4607 y1 = s[2 * j + 3];
4608 }
4609
4610 if (j < task->width - 2) {
4611 y2 = s[2 * j + 5];
4612 u2 = s[2 * j + 4];
4613 v2 = s[2 * j + 6];
4614 }
4615
4616 if (j < task->width - 3) {
4617 y3 = s[2 * j + 7];
4618 }
4619
4620 if (j < task->width - 4) {
4621 y4 = s[2 * j + 9];
4622 u4 = s[2 * j + 8];
4623 v4 = s[2 * j + 10];
4624 }
4625
4626 if (j < task->width - 5) {
4627 y5 = s[2 * j + 11];
4628 }
4629
4630 a0 = u0 << 2 | (y0 << 12) | (v0 << 22);
4631 a1 = y1 << 2 | (u2 << 12) | (y2 << 22);
4632 a2 = v2 << 2 | (y3 << 12) | (u4 << 22);
4633 a3 = y4 << 2 | (v4 << 12) | (y5 << 22);
4634
4635 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 0, a0);
4636 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 4, a1);
4637 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 8, a2);
4638 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 12, a3);
4639 }
4640 }
4641 }
4642
4643 static void
convert_UYVY_v210(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4644 convert_UYVY_v210 (GstVideoConverter * convert, const GstVideoFrame * src,
4645 GstVideoFrame * dest)
4646 {
4647 gint width = convert->in_width;
4648 gint height = convert->in_height;
4649 guint8 *s, *d;
4650 FConvertPlaneTask *tasks;
4651 FConvertPlaneTask **tasks_p;
4652 gint n_threads;
4653 gint lines_per_thread;
4654 gint i;
4655
4656 s = FRAME_GET_LINE (src, convert->in_y);
4657 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4658 d = FRAME_GET_LINE (dest, convert->out_y);
4659 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4660
4661 n_threads = convert->conversion_runner->n_threads;
4662 tasks = convert->tasks[0] =
4663 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4664 tasks_p = convert->tasks_p[0] =
4665 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4666
4667 lines_per_thread = (height + n_threads - 1) / n_threads;
4668
4669 for (i = 0; i < n_threads; i++) {
4670 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4671 tasks[i].sstride = FRAME_GET_STRIDE (src);
4672 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4673 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4674
4675 tasks[i].width = width;
4676 tasks[i].height = (i + 1) * lines_per_thread;
4677 tasks[i].height = MIN (tasks[i].height, height);
4678 tasks[i].height -= i * lines_per_thread;
4679
4680 tasks_p[i] = &tasks[i];
4681 }
4682
4683 gst_parallelized_task_runner_run (convert->conversion_runner,
4684 (GstParallelizedTaskFunc) convert_UYVY_v210_task, (gpointer) tasks_p);
4685
4686 convert_fill_border (convert, dest);
4687 }
4688
4689 static void
convert_UYVY_YUY2_task(FConvertPlaneTask * task)4690 convert_UYVY_YUY2_task (FConvertPlaneTask * task)
4691 {
4692 video_orc_convert_UYVY_YUY2 (task->d, task->dstride, task->s,
4693 task->sstride, (task->width + 1) / 2, task->height);
4694 }
4695
4696 static void
convert_UYVY_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4697 convert_UYVY_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4698 GstVideoFrame * dest)
4699 {
4700 gint width = convert->in_width;
4701 gint height = convert->in_height;
4702 guint8 *s, *d;
4703 FConvertPlaneTask *tasks;
4704 FConvertPlaneTask **tasks_p;
4705 gint n_threads;
4706 gint lines_per_thread;
4707 gint i;
4708
4709 s = FRAME_GET_LINE (src, convert->in_y);
4710 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4711 d = FRAME_GET_LINE (dest, convert->out_y);
4712 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4713
4714 n_threads = convert->conversion_runner->n_threads;
4715 tasks = convert->tasks[0] =
4716 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4717 tasks_p = convert->tasks_p[0] =
4718 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4719
4720 lines_per_thread = (height + n_threads - 1) / n_threads;
4721
4722 for (i = 0; i < n_threads; i++) {
4723 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4724 tasks[i].sstride = FRAME_GET_STRIDE (src);
4725 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4726 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4727
4728 tasks[i].width = width;
4729 tasks[i].height = (i + 1) * lines_per_thread;
4730 tasks[i].height = MIN (tasks[i].height, height);
4731 tasks[i].height -= i * lines_per_thread;
4732
4733 tasks_p[i] = &tasks[i];
4734 }
4735
4736 gst_parallelized_task_runner_run (convert->conversion_runner,
4737 (GstParallelizedTaskFunc) convert_UYVY_YUY2_task, (gpointer) tasks_p);
4738
4739 convert_fill_border (convert, dest);
4740 }
4741
4742 static void
convert_v210_UYVY_task(FConvertPlaneTask * task)4743 convert_v210_UYVY_task (FConvertPlaneTask * task)
4744 {
4745 gint i, j;
4746 guint8 *d;
4747 const guint8 *s;
4748 guint32 a0, a1, a2, a3;
4749 guint16 y0, y1, y2, y3, y4, y5;
4750 guint16 u0, u2, u4;
4751 guint16 v0, v2, v4;
4752
4753 for (i = 0; i < task->height; i++) {
4754 d = task->d + i * task->dstride;
4755 s = task->s + i * task->sstride;
4756
4757 for (j = 0; j < task->width; j += 6) {
4758 a0 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 0);
4759 a1 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 4);
4760 a2 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 8);
4761 a3 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 12);
4762
4763 u0 = ((a0 >> 0) & 0x3ff) >> 2;
4764 y0 = ((a0 >> 10) & 0x3ff) >> 2;
4765 v0 = ((a0 >> 20) & 0x3ff) >> 2;
4766 y1 = ((a1 >> 0) & 0x3ff) >> 2;
4767
4768 u2 = ((a1 >> 10) & 0x3ff) >> 2;
4769 y2 = ((a1 >> 20) & 0x3ff) >> 2;
4770 v2 = ((a2 >> 0) & 0x3ff) >> 2;
4771 y3 = ((a2 >> 10) & 0x3ff) >> 2;
4772
4773 u4 = ((a2 >> 20) & 0x3ff) >> 2;
4774 y4 = ((a3 >> 0) & 0x3ff) >> 2;
4775 v4 = ((a3 >> 10) & 0x3ff) >> 2;
4776 y5 = ((a3 >> 20) & 0x3ff) >> 2;
4777
4778 d[2 * j + 1] = y0;
4779 d[2 * j] = u0;
4780 d[2 * j + 2] = v0;
4781
4782 if (j < task->width - 1) {
4783 d[2 * j + 3] = y1;
4784 }
4785
4786 if (j < task->width - 2) {
4787 d[2 * j + 5] = y2;
4788 d[2 * j + 4] = u2;
4789 d[2 * j + 6] = v2;
4790 }
4791
4792 if (j < task->width - 3) {
4793 d[2 * j + 7] = y3;
4794 }
4795
4796 if (j < task->width - 4) {
4797 d[2 * j + 9] = y4;
4798 d[2 * j + 8] = u4;
4799 d[2 * j + 10] = v4;
4800 }
4801
4802 if (j < task->width - 5) {
4803 d[2 * j + 11] = y5;
4804 }
4805 }
4806 }
4807 }
4808
4809 static void
convert_v210_UYVY(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4810 convert_v210_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4811 GstVideoFrame * dest)
4812 {
4813 gint width = convert->in_width;
4814 gint height = convert->in_height;
4815 guint8 *s, *d;
4816 FConvertPlaneTask *tasks;
4817 FConvertPlaneTask **tasks_p;
4818 gint n_threads;
4819 gint lines_per_thread;
4820 gint i;
4821
4822 s = FRAME_GET_LINE (src, convert->in_y);
4823 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4824 d = FRAME_GET_LINE (dest, convert->out_y);
4825 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4826
4827 n_threads = convert->conversion_runner->n_threads;
4828 tasks = convert->tasks[0] =
4829 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4830 tasks_p = convert->tasks_p[0] =
4831 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4832
4833 lines_per_thread = (height + n_threads - 1) / n_threads;
4834
4835 for (i = 0; i < n_threads; i++) {
4836 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4837 tasks[i].sstride = FRAME_GET_STRIDE (src);
4838 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4839 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4840
4841 tasks[i].width = width;
4842 tasks[i].height = (i + 1) * lines_per_thread;
4843 tasks[i].height = MIN (tasks[i].height, height);
4844 tasks[i].height -= i * lines_per_thread;
4845
4846 tasks_p[i] = &tasks[i];
4847 }
4848
4849 gst_parallelized_task_runner_run (convert->conversion_runner,
4850 (GstParallelizedTaskFunc) convert_v210_UYVY_task, (gpointer) tasks_p);
4851
4852 convert_fill_border (convert, dest);
4853 }
4854
4855 static void
convert_v210_YUY2_task(FConvertPlaneTask * task)4856 convert_v210_YUY2_task (FConvertPlaneTask * task)
4857 {
4858 gint i, j;
4859 guint8 *d;
4860 const guint8 *s;
4861 guint32 a0, a1, a2, a3;
4862 guint16 y0, y1, y2, y3, y4, y5;
4863 guint16 u0, u2, u4;
4864 guint16 v0, v2, v4;
4865
4866 for (i = 0; i < task->height; i++) {
4867 d = task->d + i * task->dstride;
4868 s = task->s + i * task->sstride;
4869
4870 for (j = 0; j < task->width; j += 6) {
4871 a0 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 0);
4872 a1 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 4);
4873 a2 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 8);
4874 a3 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 12);
4875
4876 u0 = ((a0 >> 0) & 0x3ff) >> 2;
4877 y0 = ((a0 >> 10) & 0x3ff) >> 2;
4878 v0 = ((a0 >> 20) & 0x3ff) >> 2;
4879 y1 = ((a1 >> 0) & 0x3ff) >> 2;
4880
4881 u2 = ((a1 >> 10) & 0x3ff) >> 2;
4882 y2 = ((a1 >> 20) & 0x3ff) >> 2;
4883 v2 = ((a2 >> 0) & 0x3ff) >> 2;
4884 y3 = ((a2 >> 10) & 0x3ff) >> 2;
4885
4886 u4 = ((a2 >> 20) & 0x3ff) >> 2;
4887 y4 = ((a3 >> 0) & 0x3ff) >> 2;
4888 v4 = ((a3 >> 10) & 0x3ff) >> 2;
4889 y5 = ((a3 >> 20) & 0x3ff) >> 2;
4890
4891 d[2 * j] = y0;
4892 d[2 * j + 1] = u0;
4893 d[2 * j + 3] = v0;
4894
4895 if (j < task->width - 1) {
4896 d[2 * j + 2] = y1;
4897 }
4898
4899 if (j < task->width - 2) {
4900 d[2 * j + 4] = y2;
4901 d[2 * j + 5] = u2;
4902 d[2 * j + 7] = v2;
4903 }
4904
4905 if (j < task->width - 3) {
4906 d[2 * j + 6] = y3;
4907 }
4908
4909 if (j < task->width - 4) {
4910 d[2 * j + 8] = y4;
4911 d[2 * j + 9] = u4;
4912 d[2 * j + 11] = v4;
4913 }
4914
4915 if (j < task->width - 5) {
4916 d[2 * j + 10] = y5;
4917 }
4918 }
4919 }
4920 }
4921
4922 static void
convert_v210_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4923 convert_v210_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4924 GstVideoFrame * dest)
4925 {
4926 gint width = convert->in_width;
4927 gint height = convert->in_height;
4928 guint8 *s, *d;
4929 FConvertPlaneTask *tasks;
4930 FConvertPlaneTask **tasks_p;
4931 gint n_threads;
4932 gint lines_per_thread;
4933 gint i;
4934
4935 s = FRAME_GET_LINE (src, convert->in_y);
4936 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4937 d = FRAME_GET_LINE (dest, convert->out_y);
4938 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4939
4940 n_threads = convert->conversion_runner->n_threads;
4941 tasks = convert->tasks[0] =
4942 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4943 tasks_p = convert->tasks_p[0] =
4944 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4945
4946 lines_per_thread = (height + n_threads - 1) / n_threads;
4947
4948 for (i = 0; i < n_threads; i++) {
4949 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4950 tasks[i].sstride = FRAME_GET_STRIDE (src);
4951 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4952 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4953
4954 tasks[i].width = width;
4955 tasks[i].height = (i + 1) * lines_per_thread;
4956 tasks[i].height = MIN (tasks[i].height, height);
4957 tasks[i].height -= i * lines_per_thread;
4958
4959 tasks_p[i] = &tasks[i];
4960 }
4961
4962 gst_parallelized_task_runner_run (convert->conversion_runner,
4963 (GstParallelizedTaskFunc) convert_v210_YUY2_task, (gpointer) tasks_p);
4964
4965 convert_fill_border (convert, dest);
4966 }
4967
4968 static void
convert_UYVY_Y42B_task(FConvertPlaneTask * task)4969 convert_UYVY_Y42B_task (FConvertPlaneTask * task)
4970 {
4971 video_orc_convert_UYVY_Y42B (task->d, task->dstride, task->du,
4972 task->dustride, task->dv, task->dvstride,
4973 task->s, task->sstride, (task->width + 1) / 2, task->height);
4974 }
4975
4976 static void
convert_UYVY_Y42B(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)4977 convert_UYVY_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4978 GstVideoFrame * dest)
4979 {
4980 gint width = convert->in_width;
4981 gint height = convert->in_height;
4982 guint8 *s, *dy, *du, *dv;
4983 FConvertPlaneTask *tasks;
4984 FConvertPlaneTask **tasks_p;
4985 gint n_threads;
4986 gint lines_per_thread;
4987 gint i;
4988
4989 s = FRAME_GET_LINE (src, convert->in_y);
4990 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4991
4992 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4993 dy += convert->out_x;
4994 du = FRAME_GET_U_LINE (dest, convert->out_y);
4995 du += convert->out_x >> 1;
4996 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4997 dv += convert->out_x >> 1;
4998
4999 n_threads = convert->conversion_runner->n_threads;
5000 tasks = convert->tasks[0] =
5001 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5002 tasks_p = convert->tasks_p[0] =
5003 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5004
5005 lines_per_thread = (height + n_threads - 1) / n_threads;
5006
5007 for (i = 0; i < n_threads; i++) {
5008 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
5009 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
5010 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
5011 tasks[i].sstride = FRAME_GET_STRIDE (src);
5012 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
5013 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
5014 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
5015 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5016
5017 tasks[i].width = width;
5018 tasks[i].height = (i + 1) * lines_per_thread;
5019 tasks[i].height = MIN (tasks[i].height, height);
5020 tasks[i].height -= i * lines_per_thread;
5021
5022 tasks_p[i] = &tasks[i];
5023 }
5024
5025 gst_parallelized_task_runner_run (convert->conversion_runner,
5026 (GstParallelizedTaskFunc) convert_UYVY_Y42B_task, (gpointer) tasks_p);
5027
5028 convert_fill_border (convert, dest);
5029 }
5030
5031 static void
convert_UYVY_Y444_task(FConvertPlaneTask * task)5032 convert_UYVY_Y444_task (FConvertPlaneTask * task)
5033 {
5034 video_orc_convert_UYVY_Y444 (task->d,
5035 task->dstride, task->du,
5036 task->dustride, task->dv,
5037 task->dvstride, task->s,
5038 task->sstride, (task->width + 1) / 2, task->height);
5039 }
5040
5041 static void
convert_UYVY_Y444(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5042 convert_UYVY_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
5043 GstVideoFrame * dest)
5044 {
5045 gint width = convert->in_width;
5046 gint height = convert->in_height;
5047 guint8 *s, *dy, *du, *dv;
5048 FConvertPlaneTask *tasks;
5049 FConvertPlaneTask **tasks_p;
5050 gint n_threads;
5051 gint lines_per_thread;
5052 gint i;
5053
5054 s = FRAME_GET_LINE (src, convert->in_y);
5055 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
5056
5057 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
5058 dy += convert->out_x;
5059 du = FRAME_GET_U_LINE (dest, convert->out_y);
5060 du += convert->out_x;
5061 dv = FRAME_GET_V_LINE (dest, convert->out_y);
5062 dv += convert->out_x;
5063
5064 n_threads = convert->conversion_runner->n_threads;
5065 tasks = convert->tasks[0] =
5066 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5067 tasks_p = convert->tasks_p[0] =
5068 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5069
5070 lines_per_thread = (height + n_threads - 1) / n_threads;
5071
5072 for (i = 0; i < n_threads; i++) {
5073 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
5074 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
5075 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
5076 tasks[i].sstride = FRAME_GET_STRIDE (src);
5077 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
5078 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
5079 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
5080 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5081
5082 tasks[i].width = width;
5083 tasks[i].height = (i + 1) * lines_per_thread;
5084 tasks[i].height = MIN (tasks[i].height, height);
5085 tasks[i].height -= i * lines_per_thread;
5086
5087 tasks_p[i] = &tasks[i];
5088 }
5089
5090 gst_parallelized_task_runner_run (convert->conversion_runner,
5091 (GstParallelizedTaskFunc) convert_UYVY_Y444_task, (gpointer) tasks_p);
5092
5093 convert_fill_border (convert, dest);
5094 }
5095
5096 static void
convert_UYVY_GRAY8_task(FConvertPlaneTask * task)5097 convert_UYVY_GRAY8_task (FConvertPlaneTask * task)
5098 {
5099 video_orc_convert_UYVY_GRAY8 (task->d, task->dstride, (guint16 *) task->s,
5100 task->sstride, task->width, task->height);
5101 }
5102
5103 static void
convert_UYVY_GRAY8(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5104 convert_UYVY_GRAY8 (GstVideoConverter * convert, const GstVideoFrame * src,
5105 GstVideoFrame * dest)
5106 {
5107 gint width = convert->in_width;
5108 gint height = convert->in_height;
5109 guint8 *s;
5110 guint8 *d;
5111 FConvertPlaneTask *tasks;
5112 FConvertPlaneTask **tasks_p;
5113 gint n_threads;
5114 gint lines_per_thread;
5115 gint i;
5116
5117 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
5118 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
5119
5120 n_threads = convert->conversion_runner->n_threads;
5121 tasks = convert->tasks[0] =
5122 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5123 tasks_p = convert->tasks_p[0] =
5124 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5125
5126 lines_per_thread = (height + n_threads - 1) / n_threads;
5127
5128 for (i = 0; i < n_threads; i++) {
5129 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5130 tasks[i].sstride = FRAME_GET_STRIDE (src);
5131 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5132 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5133
5134 tasks[i].width = width;
5135 tasks[i].height = (i + 1) * lines_per_thread;
5136 tasks[i].height = MIN (tasks[i].height, height);
5137 tasks[i].height -= i * lines_per_thread;
5138
5139 tasks_p[i] = &tasks[i];
5140 }
5141
5142 gst_parallelized_task_runner_run (convert->conversion_runner,
5143 (GstParallelizedTaskFunc) convert_UYVY_GRAY8_task, (gpointer) tasks_p);
5144
5145 convert_fill_border (convert, dest);
5146 }
5147
5148 static void
convert_AYUV_I420_task(FConvertPlaneTask * task)5149 convert_AYUV_I420_task (FConvertPlaneTask * task)
5150 {
5151 video_orc_convert_AYUV_I420 (task->d,
5152 2 * task->dstride, task->d2,
5153 2 * task->dstride, task->du,
5154 task->dustride, task->dv,
5155 task->dvstride, task->s,
5156 2 * task->sstride, task->s2,
5157 2 * task->sstride, task->width / 2, task->height / 2);
5158 }
5159
5160 static void
convert_AYUV_I420(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5161 convert_AYUV_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
5162 GstVideoFrame * dest)
5163 {
5164 gint width = convert->in_width;
5165 gint height = convert->in_height;
5166 guint8 *s1, *s2, *dy1, *dy2, *du, *dv;
5167 FConvertPlaneTask *tasks;
5168 FConvertPlaneTask **tasks_p;
5169 gint n_threads;
5170 gint lines_per_thread;
5171 gint i;
5172
5173 s1 = FRAME_GET_LINE (src, convert->in_y + 0);
5174 s1 += convert->in_x * 4;
5175 s2 = FRAME_GET_LINE (src, convert->in_y + 1);
5176 s2 += convert->in_x * 4;
5177
5178 dy1 = FRAME_GET_Y_LINE (dest, convert->out_y + 0);
5179 dy1 += convert->out_x;
5180 dy2 = FRAME_GET_Y_LINE (dest, convert->out_y + 1);
5181 dy2 += convert->out_x;
5182 du = FRAME_GET_U_LINE (dest, convert->out_y >> 1);
5183 du += convert->out_x >> 1;
5184 dv = FRAME_GET_V_LINE (dest, convert->out_y >> 1);
5185 dv += convert->out_x >> 1;
5186
5187 /* only for even width/height */
5188
5189 n_threads = convert->conversion_runner->n_threads;
5190 tasks = convert->tasks[0] =
5191 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5192 tasks_p = convert->tasks_p[0] =
5193 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5194
5195 lines_per_thread = GST_ROUND_UP_2 ((height + n_threads - 1) / n_threads);
5196
5197 for (i = 0; i < n_threads; i++) {
5198 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
5199 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
5200 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
5201 tasks[i].sstride = FRAME_GET_STRIDE (src);
5202 tasks[i].d = dy1 + i * lines_per_thread * tasks[i].dstride;
5203 tasks[i].d2 = dy2 + i * lines_per_thread * tasks[i].dstride;
5204 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride / 2;
5205 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride / 2;
5206 tasks[i].s = s1 + i * lines_per_thread * tasks[i].sstride;
5207 tasks[i].s2 = s2 + i * lines_per_thread * tasks[i].sstride;
5208
5209 tasks[i].width = width;
5210 tasks[i].height = (i + 1) * lines_per_thread;
5211 tasks[i].height = MIN (tasks[i].height, height);
5212 tasks[i].height -= i * lines_per_thread;
5213
5214 tasks_p[i] = &tasks[i];
5215 }
5216
5217 gst_parallelized_task_runner_run (convert->conversion_runner,
5218 (GstParallelizedTaskFunc) convert_AYUV_I420_task, (gpointer) tasks_p);
5219
5220 convert_fill_border (convert, dest);
5221 }
5222
5223 static void
convert_AYUV_YUY2_task(FConvertPlaneTask * task)5224 convert_AYUV_YUY2_task (FConvertPlaneTask * task)
5225 {
5226 video_orc_convert_AYUV_YUY2 (task->d, task->dstride, task->s,
5227 task->sstride, task->width / 2, task->height);
5228 }
5229
5230 static void
convert_AYUV_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5231 convert_AYUV_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
5232 GstVideoFrame * dest)
5233 {
5234 gint width = convert->in_width;
5235 gint height = convert->in_height;
5236 guint8 *s, *d;
5237 FConvertPlaneTask *tasks;
5238 FConvertPlaneTask **tasks_p;
5239 gint n_threads;
5240 gint lines_per_thread;
5241 gint i;
5242
5243 s = FRAME_GET_LINE (src, convert->in_y);
5244 s += convert->in_x * 4;
5245 d = FRAME_GET_LINE (dest, convert->out_y);
5246 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5247
5248 /* only for even width */
5249 n_threads = convert->conversion_runner->n_threads;
5250 tasks = convert->tasks[0] =
5251 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5252 tasks_p = convert->tasks_p[0] =
5253 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5254
5255 lines_per_thread = (height + n_threads - 1) / n_threads;
5256
5257 for (i = 0; i < n_threads; i++) {
5258 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5259 tasks[i].sstride = FRAME_GET_STRIDE (src);
5260 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5261 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5262
5263 tasks[i].width = width;
5264 tasks[i].height = (i + 1) * lines_per_thread;
5265 tasks[i].height = MIN (tasks[i].height, height);
5266 tasks[i].height -= i * lines_per_thread;
5267
5268 tasks_p[i] = &tasks[i];
5269 }
5270
5271 gst_parallelized_task_runner_run (convert->conversion_runner,
5272 (GstParallelizedTaskFunc) convert_AYUV_YUY2_task, (gpointer) tasks_p);
5273
5274 convert_fill_border (convert, dest);
5275 }
5276
5277 static void
convert_AYUV_UYVY_task(FConvertPlaneTask * task)5278 convert_AYUV_UYVY_task (FConvertPlaneTask * task)
5279 {
5280 video_orc_convert_AYUV_UYVY (task->d, task->dstride, task->s,
5281 task->sstride, task->width / 2, task->height);
5282 }
5283
5284 static void
convert_AYUV_UYVY(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5285 convert_AYUV_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
5286 GstVideoFrame * dest)
5287 {
5288 gint width = convert->in_width;
5289 gint height = convert->in_height;
5290 guint8 *s, *d;
5291 FConvertPlaneTask *tasks;
5292 FConvertPlaneTask **tasks_p;
5293 gint n_threads;
5294 gint lines_per_thread;
5295 gint i;
5296
5297 s = FRAME_GET_LINE (src, convert->in_y);
5298 s += convert->in_x * 4;
5299 d = FRAME_GET_LINE (dest, convert->out_y);
5300 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5301
5302 /* only for even width */
5303 n_threads = convert->conversion_runner->n_threads;
5304 tasks = convert->tasks[0] =
5305 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5306 tasks_p = convert->tasks_p[0] =
5307 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5308
5309 lines_per_thread = (height + n_threads - 1) / n_threads;
5310
5311 for (i = 0; i < n_threads; i++) {
5312 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5313 tasks[i].sstride = FRAME_GET_STRIDE (src);
5314 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5315 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5316
5317 tasks[i].width = width;
5318 tasks[i].height = (i + 1) * lines_per_thread;
5319 tasks[i].height = MIN (tasks[i].height, height);
5320 tasks[i].height -= i * lines_per_thread;
5321
5322 tasks_p[i] = &tasks[i];
5323 }
5324
5325 gst_parallelized_task_runner_run (convert->conversion_runner,
5326 (GstParallelizedTaskFunc) convert_AYUV_UYVY_task, (gpointer) tasks_p);
5327
5328 convert_fill_border (convert, dest);
5329 }
5330
5331 static void
convert_AYUV_Y42B_task(FConvertPlaneTask * task)5332 convert_AYUV_Y42B_task (FConvertPlaneTask * task)
5333 {
5334 video_orc_convert_AYUV_Y42B (task->d, task->dstride, task->du,
5335 task->dustride, task->dv, task->dvstride,
5336 task->s, task->sstride, task->width / 2, task->height);
5337 }
5338
5339 static void
convert_AYUV_Y42B(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5340 convert_AYUV_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
5341 GstVideoFrame * dest)
5342 {
5343 gint width = convert->in_width;
5344 gint height = convert->in_height;
5345 guint8 *s, *dy, *du, *dv;
5346 FConvertPlaneTask *tasks;
5347 FConvertPlaneTask **tasks_p;
5348 gint n_threads;
5349 gint lines_per_thread;
5350 gint i;
5351
5352 s = FRAME_GET_LINE (src, convert->in_y);
5353 s += convert->in_x * 4;
5354
5355 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
5356 dy += convert->out_x;
5357 du = FRAME_GET_U_LINE (dest, convert->out_y);
5358 du += convert->out_x >> 1;
5359 dv = FRAME_GET_V_LINE (dest, convert->out_y);
5360 dv += convert->out_x >> 1;
5361
5362 /* only works for even width */
5363 n_threads = convert->conversion_runner->n_threads;
5364 tasks = convert->tasks[0] =
5365 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5366 tasks_p = convert->tasks_p[0] =
5367 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5368
5369 lines_per_thread = (height + n_threads - 1) / n_threads;
5370
5371 for (i = 0; i < n_threads; i++) {
5372 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
5373 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
5374 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
5375 tasks[i].sstride = FRAME_GET_STRIDE (src);
5376 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
5377 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
5378 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
5379 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5380
5381 tasks[i].width = width;
5382 tasks[i].height = (i + 1) * lines_per_thread;
5383 tasks[i].height = MIN (tasks[i].height, height);
5384 tasks[i].height -= i * lines_per_thread;
5385
5386 tasks_p[i] = &tasks[i];
5387 }
5388
5389 gst_parallelized_task_runner_run (convert->conversion_runner,
5390 (GstParallelizedTaskFunc) convert_AYUV_Y42B_task, (gpointer) tasks_p);
5391
5392 convert_fill_border (convert, dest);
5393 }
5394
5395 static void
convert_AYUV_Y444_task(FConvertPlaneTask * task)5396 convert_AYUV_Y444_task (FConvertPlaneTask * task)
5397 {
5398 video_orc_convert_AYUV_Y444 (task->d, task->dstride, task->du,
5399 task->dustride, task->dv, task->dvstride,
5400 task->s, task->sstride, task->width, task->height);
5401 }
5402
5403 static void
convert_AYUV_Y444(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5404 convert_AYUV_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
5405 GstVideoFrame * dest)
5406 {
5407 gint width = convert->in_width;
5408 gint height = convert->in_height;
5409 guint8 *s, *dy, *du, *dv;
5410 FConvertPlaneTask *tasks;
5411 FConvertPlaneTask **tasks_p;
5412 gint n_threads;
5413 gint lines_per_thread;
5414 gint i;
5415
5416 s = FRAME_GET_LINE (src, convert->in_y);
5417 s += convert->in_x * 4;
5418
5419 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
5420 dy += convert->out_x;
5421 du = FRAME_GET_U_LINE (dest, convert->out_y);
5422 du += convert->out_x;
5423 dv = FRAME_GET_V_LINE (dest, convert->out_y);
5424 dv += convert->out_x;
5425
5426 n_threads = convert->conversion_runner->n_threads;
5427 tasks = convert->tasks[0] =
5428 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5429 tasks_p = convert->tasks_p[0] =
5430 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5431
5432 lines_per_thread = (height + n_threads - 1) / n_threads;
5433
5434 for (i = 0; i < n_threads; i++) {
5435 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
5436 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
5437 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
5438 tasks[i].sstride = FRAME_GET_STRIDE (src);
5439 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
5440 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
5441 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
5442 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5443
5444 tasks[i].width = width;
5445 tasks[i].height = (i + 1) * lines_per_thread;
5446 tasks[i].height = MIN (tasks[i].height, height);
5447 tasks[i].height -= i * lines_per_thread;
5448
5449 tasks_p[i] = &tasks[i];
5450 }
5451
5452 gst_parallelized_task_runner_run (convert->conversion_runner,
5453 (GstParallelizedTaskFunc) convert_AYUV_Y444_task, (gpointer) tasks_p);
5454 convert_fill_border (convert, dest);
5455 }
5456
5457 static void
convert_Y42B_YUY2_task(FConvertPlaneTask * task)5458 convert_Y42B_YUY2_task (FConvertPlaneTask * task)
5459 {
5460 video_orc_convert_Y42B_YUY2 (task->d, task->dstride,
5461 task->s, task->sstride,
5462 task->su, task->sustride,
5463 task->sv, task->svstride, (task->width + 1) / 2, task->height);
5464 }
5465
5466 static void
convert_Y42B_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5467 convert_Y42B_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
5468 GstVideoFrame * dest)
5469 {
5470 gint width = convert->in_width;
5471 gint height = convert->in_height;
5472 guint8 *sy, *su, *sv, *d;
5473 FConvertPlaneTask *tasks;
5474 FConvertPlaneTask **tasks_p;
5475 gint n_threads;
5476 gint lines_per_thread;
5477 gint i;
5478
5479 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5480 sy += convert->in_x;
5481 su = FRAME_GET_U_LINE (src, convert->in_y);
5482 su += convert->in_x >> 1;
5483 sv = FRAME_GET_V_LINE (src, convert->in_y);
5484 sv += convert->in_x >> 1;
5485
5486 d = FRAME_GET_LINE (dest, convert->out_y);
5487 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5488
5489 n_threads = convert->conversion_runner->n_threads;
5490 tasks = convert->tasks[0] =
5491 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5492 tasks_p = convert->tasks_p[0] =
5493 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5494
5495 lines_per_thread = (height + n_threads - 1) / n_threads;
5496
5497 for (i = 0; i < n_threads; i++) {
5498 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5499 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5500 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5501 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5502 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5503 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5504 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5505 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5506
5507 tasks[i].width = width;
5508 tasks[i].height = (i + 1) * lines_per_thread;
5509 tasks[i].height = MIN (tasks[i].height, height);
5510 tasks[i].height -= i * lines_per_thread;
5511
5512 tasks_p[i] = &tasks[i];
5513 }
5514
5515 gst_parallelized_task_runner_run (convert->conversion_runner,
5516 (GstParallelizedTaskFunc) convert_Y42B_YUY2_task, (gpointer) tasks_p);
5517
5518 convert_fill_border (convert, dest);
5519 }
5520
5521 static void
convert_Y42B_UYVY_task(FConvertPlaneTask * task)5522 convert_Y42B_UYVY_task (FConvertPlaneTask * task)
5523 {
5524 video_orc_convert_Y42B_UYVY (task->d, task->dstride,
5525 task->s, task->sstride,
5526 task->su, task->sustride,
5527 task->sv, task->svstride, (task->width + 1) / 2, task->height);
5528 }
5529
5530 static void
convert_Y42B_UYVY(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5531 convert_Y42B_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
5532 GstVideoFrame * dest)
5533 {
5534 gint width = convert->in_width;
5535 gint height = convert->in_height;
5536 guint8 *sy, *su, *sv, *d;
5537 FConvertPlaneTask *tasks;
5538 FConvertPlaneTask **tasks_p;
5539 gint n_threads;
5540 gint lines_per_thread;
5541 gint i;
5542
5543 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5544 sy += convert->in_x;
5545 su = FRAME_GET_U_LINE (src, convert->in_y);
5546 su += convert->in_x >> 1;
5547 sv = FRAME_GET_V_LINE (src, convert->in_y);
5548 sv += convert->in_x >> 1;
5549
5550 d = FRAME_GET_LINE (dest, convert->out_y);
5551 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5552
5553 n_threads = convert->conversion_runner->n_threads;
5554 tasks = convert->tasks[0] =
5555 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5556 tasks_p = convert->tasks_p[0] =
5557 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5558
5559 lines_per_thread = (height + n_threads - 1) / n_threads;
5560
5561 for (i = 0; i < n_threads; i++) {
5562 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5563 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5564 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5565 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5566 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5567 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5568 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5569 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5570
5571 tasks[i].width = width;
5572 tasks[i].height = (i + 1) * lines_per_thread;
5573 tasks[i].height = MIN (tasks[i].height, height);
5574 tasks[i].height -= i * lines_per_thread;
5575
5576 tasks_p[i] = &tasks[i];
5577 }
5578
5579 gst_parallelized_task_runner_run (convert->conversion_runner,
5580 (GstParallelizedTaskFunc) convert_Y42B_UYVY_task, (gpointer) tasks_p);
5581
5582 convert_fill_border (convert, dest);
5583 }
5584
5585 static void
convert_Y42B_AYUV_task(FConvertPlaneTask * task)5586 convert_Y42B_AYUV_task (FConvertPlaneTask * task)
5587 {
5588 video_orc_convert_Y42B_AYUV (task->d, task->dstride, task->s,
5589 task->sstride,
5590 task->su,
5591 task->sustride,
5592 task->sv, task->svstride, task->alpha, task->width / 2, task->height);
5593 }
5594
5595 static void
convert_Y42B_AYUV(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5596 convert_Y42B_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
5597 GstVideoFrame * dest)
5598 {
5599 gint width = convert->in_width;
5600 gint height = convert->in_height;
5601 guint8 *sy, *su, *sv, *d;
5602 guint8 alpha = MIN (convert->alpha_value, 255);
5603 FConvertPlaneTask *tasks;
5604 FConvertPlaneTask **tasks_p;
5605 gint n_threads;
5606 gint lines_per_thread;
5607 gint i;
5608
5609 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5610 sy += convert->in_x;
5611 su = FRAME_GET_U_LINE (src, convert->in_y);
5612 su += convert->in_x >> 1;
5613 sv = FRAME_GET_V_LINE (src, convert->in_y);
5614 sv += convert->in_x >> 1;
5615
5616 d = FRAME_GET_LINE (dest, convert->out_y);
5617 d += convert->out_x * 4;
5618
5619 /* only for even width */
5620 n_threads = convert->conversion_runner->n_threads;
5621 tasks = convert->tasks[0] =
5622 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5623 tasks_p = convert->tasks_p[0] =
5624 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5625
5626 lines_per_thread = (height + n_threads - 1) / n_threads;
5627
5628 for (i = 0; i < n_threads; i++) {
5629 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5630 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5631 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5632 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5633 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5634 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5635 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5636 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5637
5638 tasks[i].width = width;
5639 tasks[i].height = (i + 1) * lines_per_thread;
5640 tasks[i].height = MIN (tasks[i].height, height);
5641 tasks[i].height -= i * lines_per_thread;
5642 tasks[i].alpha = alpha;
5643
5644 tasks_p[i] = &tasks[i];
5645 }
5646
5647 gst_parallelized_task_runner_run (convert->conversion_runner,
5648 (GstParallelizedTaskFunc) convert_Y42B_AYUV_task, (gpointer) tasks_p);
5649
5650 convert_fill_border (convert, dest);
5651 }
5652
5653 static void
convert_Y42B_v210_task(FConvertPlaneTask * task)5654 convert_Y42B_v210_task (FConvertPlaneTask * task)
5655 {
5656 gint i, j;
5657 guint8 *d;
5658 const guint8 *s_y, *s_u, *s_v;
5659 guint32 a0, a1, a2, a3;
5660 guint8 y0, y1, y2, y3, y4, y5;
5661 guint8 u0, u2, u4;
5662 guint8 v0, v2, v4;
5663
5664 for (i = 0; i < task->height; i++) {
5665 d = task->d + i * task->dstride;
5666 s_y = task->s + i * task->sstride;
5667 s_u = task->su + i * task->sustride;
5668 s_v = task->sv + i * task->svstride;
5669
5670 for (j = 0; j < task->width; j += 6) {
5671 y1 = y2 = y3 = y4 = y5 = 0;
5672 u2 = u4 = v2 = v4 = 0;
5673
5674 y0 = s_y[j];
5675 u0 = s_u[j / 2];
5676 v0 = s_v[j / 2];
5677
5678 if (j < task->width - 1) {
5679 y1 = s_y[j + 1];
5680 }
5681
5682 if (j < task->width - 2) {
5683 y2 = s_y[j + 2];
5684 u2 = s_u[j / 2 + 1];
5685 v2 = s_v[j / 2 + 1];
5686 }
5687
5688 if (j < task->width - 3) {
5689 y3 = s_y[j + 3];
5690 }
5691
5692 if (j < task->width - 4) {
5693 y4 = s_y[j + 4];
5694 u4 = s_u[j / 2 + 2];
5695 v4 = s_v[j / 2 + 2];
5696 }
5697
5698 if (j < task->width - 5) {
5699 y5 = s_y[j + 5];
5700 }
5701
5702 a0 = u0 << 2 | (y0 << 12) | (v0 << 22);
5703 a1 = y1 << 2 | (u2 << 12) | (y2 << 22);
5704 a2 = v2 << 2 | (y3 << 12) | (u4 << 22);
5705 a3 = y4 << 2 | (v4 << 12) | (y5 << 22);
5706
5707 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 0, a0);
5708 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 4, a1);
5709 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 8, a2);
5710 GST_WRITE_UINT32_LE (d + (j / 6) * 16 + 12, a3);
5711 }
5712 }
5713 }
5714
5715 static void
convert_Y42B_v210(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5716 convert_Y42B_v210 (GstVideoConverter * convert, const GstVideoFrame * src,
5717 GstVideoFrame * dest)
5718 {
5719 gint width = convert->in_width;
5720 gint height = convert->in_height;
5721 guint8 *d, *sy, *su, *sv;
5722 FConvertPlaneTask *tasks;
5723 FConvertPlaneTask **tasks_p;
5724 gint n_threads;
5725 gint lines_per_thread;
5726 gint i;
5727
5728 d = FRAME_GET_LINE (dest, convert->out_y);
5729 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5730
5731 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5732 sy += convert->in_x;
5733 su = FRAME_GET_U_LINE (src, convert->in_y);
5734 su += convert->in_x >> 1;
5735 sv = FRAME_GET_V_LINE (src, convert->in_y);
5736 sv += convert->in_x >> 1;
5737
5738 n_threads = convert->conversion_runner->n_threads;
5739 tasks = convert->tasks[0] =
5740 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5741 tasks_p = convert->tasks_p[0] =
5742 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5743
5744 lines_per_thread = (height + n_threads - 1) / n_threads;
5745
5746 for (i = 0; i < n_threads; i++) {
5747 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5748 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5749 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5750 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5751 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5752 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5753 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5754 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5755
5756 tasks[i].width = width;
5757 tasks[i].height = (i + 1) * lines_per_thread;
5758 tasks[i].height = MIN (tasks[i].height, height);
5759 tasks[i].height -= i * lines_per_thread;
5760
5761 tasks_p[i] = &tasks[i];
5762 }
5763
5764 gst_parallelized_task_runner_run (convert->conversion_runner,
5765 (GstParallelizedTaskFunc) convert_Y42B_v210_task, (gpointer) tasks_p);
5766
5767 convert_fill_border (convert, dest);
5768 }
5769
5770 static void
convert_Y444_YUY2_task(FConvertPlaneTask * task)5771 convert_Y444_YUY2_task (FConvertPlaneTask * task)
5772 {
5773 video_orc_convert_Y444_YUY2 (task->d, task->dstride, task->s,
5774 task->sstride,
5775 task->su,
5776 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
5777 }
5778
5779 static void
convert_Y444_YUY2(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5780 convert_Y444_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
5781 GstVideoFrame * dest)
5782 {
5783 gint width = convert->in_width;
5784 gint height = convert->in_height;
5785 guint8 *sy, *su, *sv, *d;
5786 FConvertPlaneTask *tasks;
5787 FConvertPlaneTask **tasks_p;
5788 gint n_threads;
5789 gint lines_per_thread;
5790 gint i;
5791
5792 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5793 sy += convert->in_x;
5794 su = FRAME_GET_U_LINE (src, convert->in_y);
5795 su += convert->in_x;
5796 sv = FRAME_GET_V_LINE (src, convert->in_y);
5797 sv += convert->in_x;
5798
5799 d = FRAME_GET_LINE (dest, convert->out_y);
5800 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5801
5802 n_threads = convert->conversion_runner->n_threads;
5803 tasks = convert->tasks[0] =
5804 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5805 tasks_p = convert->tasks_p[0] =
5806 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5807
5808 lines_per_thread = (height + n_threads - 1) / n_threads;
5809
5810 for (i = 0; i < n_threads; i++) {
5811 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5812 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5813 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5814 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5815 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5816 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5817 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5818 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5819
5820 tasks[i].width = width;
5821 tasks[i].height = (i + 1) * lines_per_thread;
5822 tasks[i].height = MIN (tasks[i].height, height);
5823 tasks[i].height -= i * lines_per_thread;
5824
5825 tasks_p[i] = &tasks[i];
5826 }
5827
5828 gst_parallelized_task_runner_run (convert->conversion_runner,
5829 (GstParallelizedTaskFunc) convert_Y444_YUY2_task, (gpointer) tasks_p);
5830
5831 convert_fill_border (convert, dest);
5832 }
5833
5834 static void
convert_Y444_UYVY_task(FConvertPlaneTask * task)5835 convert_Y444_UYVY_task (FConvertPlaneTask * task)
5836 {
5837 video_orc_convert_Y444_UYVY (task->d, task->dstride, task->s,
5838 task->sstride,
5839 task->su,
5840 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
5841 }
5842
5843 static void
convert_Y444_UYVY(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5844 convert_Y444_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
5845 GstVideoFrame * dest)
5846 {
5847 gint width = convert->in_width;
5848 gint height = convert->in_height;
5849 guint8 *sy, *su, *sv, *d;
5850 FConvertPlaneTask *tasks;
5851 FConvertPlaneTask **tasks_p;
5852 gint n_threads;
5853 gint lines_per_thread;
5854 gint i;
5855
5856 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5857 sy += convert->in_x;
5858 su = FRAME_GET_U_LINE (src, convert->in_y);
5859 su += convert->in_x;
5860 sv = FRAME_GET_V_LINE (src, convert->in_y);
5861 sv += convert->in_x;
5862
5863 d = FRAME_GET_LINE (dest, convert->out_y);
5864 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5865
5866 n_threads = convert->conversion_runner->n_threads;
5867 tasks = convert->tasks[0] =
5868 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5869 tasks_p = convert->tasks_p[0] =
5870 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5871
5872 lines_per_thread = (height + n_threads - 1) / n_threads;
5873
5874 for (i = 0; i < n_threads; i++) {
5875 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5876 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5877 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5878 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5879 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5880 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5881 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5882 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5883
5884 tasks[i].width = width;
5885 tasks[i].height = (i + 1) * lines_per_thread;
5886 tasks[i].height = MIN (tasks[i].height, height);
5887 tasks[i].height -= i * lines_per_thread;
5888
5889 tasks_p[i] = &tasks[i];
5890 }
5891
5892 gst_parallelized_task_runner_run (convert->conversion_runner,
5893 (GstParallelizedTaskFunc) convert_Y444_UYVY_task, (gpointer) tasks_p);
5894
5895 convert_fill_border (convert, dest);
5896 }
5897
5898 static void
convert_Y444_AYUV_task(FConvertPlaneTask * task)5899 convert_Y444_AYUV_task (FConvertPlaneTask * task)
5900 {
5901 video_orc_convert_Y444_AYUV (task->d, task->dstride, task->s,
5902 task->sstride,
5903 task->su,
5904 task->sustride,
5905 task->sv, task->svstride, task->alpha, task->width, task->height);
5906 }
5907
5908 static void
convert_Y444_AYUV(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5909 convert_Y444_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
5910 GstVideoFrame * dest)
5911 {
5912 gint width = convert->in_width;
5913 gint height = convert->in_height;
5914 guint8 *sy, *su, *sv, *d;
5915 guint8 alpha = MIN (convert->alpha_value, 255);
5916 FConvertPlaneTask *tasks;
5917 FConvertPlaneTask **tasks_p;
5918 gint n_threads;
5919 gint lines_per_thread;
5920 gint i;
5921
5922 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5923 sy += convert->in_x;
5924 su = FRAME_GET_U_LINE (src, convert->in_y);
5925 su += convert->in_x;
5926 sv = FRAME_GET_V_LINE (src, convert->in_y);
5927 sv += convert->in_x;
5928
5929 d = FRAME_GET_LINE (dest, convert->out_y);
5930 d += convert->out_x * 4;
5931
5932 n_threads = convert->conversion_runner->n_threads;
5933 tasks = convert->tasks[0] =
5934 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5935 tasks_p = convert->tasks_p[0] =
5936 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5937
5938 lines_per_thread = (height + n_threads - 1) / n_threads;
5939
5940 for (i = 0; i < n_threads; i++) {
5941 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5942 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5943 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5944 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5945 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5946 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5947 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5948 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5949
5950 tasks[i].width = width;
5951 tasks[i].height = (i + 1) * lines_per_thread;
5952 tasks[i].height = MIN (tasks[i].height, height);
5953 tasks[i].height -= i * lines_per_thread;
5954 tasks[i].alpha = alpha;
5955
5956 tasks_p[i] = &tasks[i];
5957 }
5958
5959 gst_parallelized_task_runner_run (convert->conversion_runner,
5960 (GstParallelizedTaskFunc) convert_Y444_AYUV_task, (gpointer) tasks_p);
5961
5962 convert_fill_border (convert, dest);
5963 }
5964
5965 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5966 static void
convert_AYUV_ARGB_task(FConvertPlaneTask * task)5967 convert_AYUV_ARGB_task (FConvertPlaneTask * task)
5968 {
5969 video_orc_convert_AYUV_ARGB (task->d, task->dstride, task->s,
5970 task->sstride, task->data->im[0][0], task->data->im[0][2],
5971 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5972 task->width, task->height);
5973 }
5974
5975 static void
convert_AYUV_ARGB(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)5976 convert_AYUV_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5977 GstVideoFrame * dest)
5978 {
5979 gint width = convert->in_width;
5980 gint height = convert->in_height;
5981 MatrixData *data = &convert->convert_matrix;
5982 guint8 *s, *d;
5983 FConvertPlaneTask *tasks;
5984 FConvertPlaneTask **tasks_p;
5985 gint n_threads;
5986 gint lines_per_thread;
5987 gint i;
5988
5989 s = FRAME_GET_LINE (src, convert->in_y);
5990 s += (convert->in_x * 4);
5991 d = FRAME_GET_LINE (dest, convert->out_y);
5992 d += (convert->out_x * 4);
5993
5994 n_threads = convert->conversion_runner->n_threads;
5995 tasks = convert->tasks[0] =
5996 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5997 tasks_p = convert->tasks_p[0] =
5998 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5999
6000 lines_per_thread = (height + n_threads - 1) / n_threads;
6001
6002 for (i = 0; i < n_threads; i++) {
6003 tasks[i].dstride = FRAME_GET_STRIDE (dest);
6004 tasks[i].sstride = FRAME_GET_STRIDE (src);
6005 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
6006 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
6007
6008 tasks[i].width = width;
6009 tasks[i].height = (i + 1) * lines_per_thread;
6010 tasks[i].height = MIN (tasks[i].height, height);
6011 tasks[i].height -= i * lines_per_thread;
6012 tasks[i].data = data;
6013
6014 tasks_p[i] = &tasks[i];
6015 }
6016
6017 gst_parallelized_task_runner_run (convert->conversion_runner,
6018 (GstParallelizedTaskFunc) convert_AYUV_ARGB_task, (gpointer) tasks_p);
6019
6020 convert_fill_border (convert, dest);
6021 }
6022
6023 static void
convert_AYUV_BGRA_task(FConvertPlaneTask * task)6024 convert_AYUV_BGRA_task (FConvertPlaneTask * task)
6025 {
6026 video_orc_convert_AYUV_BGRA (task->d, task->dstride, task->s,
6027 task->sstride, task->data->im[0][0], task->data->im[0][2],
6028 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6029 task->width, task->height);
6030 }
6031
6032 static void
convert_AYUV_BGRA(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)6033 convert_AYUV_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
6034 GstVideoFrame * dest)
6035 {
6036 gint width = convert->in_width;
6037 gint height = convert->in_height;
6038 MatrixData *data = &convert->convert_matrix;
6039 guint8 *s, *d;
6040 FConvertPlaneTask *tasks;
6041 FConvertPlaneTask **tasks_p;
6042 gint n_threads;
6043 gint lines_per_thread;
6044 gint i;
6045
6046 s = FRAME_GET_LINE (src, convert->in_y);
6047 s += (convert->in_x * 4);
6048 d = FRAME_GET_LINE (dest, convert->out_y);
6049 d += (convert->out_x * 4);
6050
6051 n_threads = convert->conversion_runner->n_threads;
6052 tasks = convert->tasks[0] =
6053 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
6054 tasks_p = convert->tasks_p[0] =
6055 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
6056
6057 lines_per_thread = (height + n_threads - 1) / n_threads;
6058
6059 for (i = 0; i < n_threads; i++) {
6060 tasks[i].dstride = FRAME_GET_STRIDE (dest);
6061 tasks[i].sstride = FRAME_GET_STRIDE (src);
6062 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
6063 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
6064
6065 tasks[i].width = width;
6066 tasks[i].height = (i + 1) * lines_per_thread;
6067 tasks[i].height = MIN (tasks[i].height, height);
6068 tasks[i].height -= i * lines_per_thread;
6069 tasks[i].data = data;
6070
6071 tasks_p[i] = &tasks[i];
6072 }
6073
6074 gst_parallelized_task_runner_run (convert->conversion_runner,
6075 (GstParallelizedTaskFunc) convert_AYUV_BGRA_task, (gpointer) tasks_p);
6076
6077 convert_fill_border (convert, dest);
6078 }
6079
6080 static void
convert_AYUV_ABGR_task(FConvertPlaneTask * task)6081 convert_AYUV_ABGR_task (FConvertPlaneTask * task)
6082 {
6083 video_orc_convert_AYUV_ABGR (task->d, task->dstride, task->s,
6084 task->sstride, task->data->im[0][0], task->data->im[0][2],
6085 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6086 task->width, task->height);
6087 }
6088
6089 static void
convert_AYUV_ABGR(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)6090 convert_AYUV_ABGR (GstVideoConverter * convert, const GstVideoFrame * src,
6091 GstVideoFrame * dest)
6092 {
6093 gint width = convert->in_width;
6094 gint height = convert->in_height;
6095 MatrixData *data = &convert->convert_matrix;
6096 guint8 *s, *d;
6097 FConvertPlaneTask *tasks;
6098 FConvertPlaneTask **tasks_p;
6099 gint n_threads;
6100 gint lines_per_thread;
6101 gint i;
6102
6103 s = FRAME_GET_LINE (src, convert->in_y);
6104 s += (convert->in_x * 4);
6105 d = FRAME_GET_LINE (dest, convert->out_y);
6106 d += (convert->out_x * 4);
6107
6108 n_threads = convert->conversion_runner->n_threads;
6109 tasks = convert->tasks[0] =
6110 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
6111 tasks_p = convert->tasks_p[0] =
6112 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
6113
6114 lines_per_thread = (height + n_threads - 1) / n_threads;
6115
6116 for (i = 0; i < n_threads; i++) {
6117 tasks[i].dstride = FRAME_GET_STRIDE (dest);
6118 tasks[i].sstride = FRAME_GET_STRIDE (src);
6119 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
6120 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
6121
6122 tasks[i].width = width;
6123 tasks[i].height = (i + 1) * lines_per_thread;
6124 tasks[i].height = MIN (tasks[i].height, height);
6125 tasks[i].height -= i * lines_per_thread;
6126 tasks[i].data = data;
6127
6128 tasks_p[i] = &tasks[i];
6129 }
6130
6131 gst_parallelized_task_runner_run (convert->conversion_runner,
6132 (GstParallelizedTaskFunc) convert_AYUV_ABGR_task, (gpointer) tasks_p);
6133
6134 convert_fill_border (convert, dest);
6135 }
6136
6137 static void
convert_AYUV_RGBA_task(FConvertPlaneTask * task)6138 convert_AYUV_RGBA_task (FConvertPlaneTask * task)
6139 {
6140 video_orc_convert_AYUV_RGBA (task->d, task->dstride, task->s,
6141 task->sstride, task->data->im[0][0], task->data->im[0][2],
6142 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6143 task->width, task->height);
6144 }
6145
6146 static void
convert_AYUV_RGBA(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)6147 convert_AYUV_RGBA (GstVideoConverter * convert, const GstVideoFrame * src,
6148 GstVideoFrame * dest)
6149 {
6150 gint width = convert->in_width;
6151 gint height = convert->in_height;
6152 MatrixData *data = &convert->convert_matrix;
6153 guint8 *s, *d;
6154 FConvertPlaneTask *tasks;
6155 FConvertPlaneTask **tasks_p;
6156 gint n_threads;
6157 gint lines_per_thread;
6158 gint i;
6159
6160 s = FRAME_GET_LINE (src, convert->in_y);
6161 s += (convert->in_x * 4);
6162 d = FRAME_GET_LINE (dest, convert->out_y);
6163 d += (convert->out_x * 4);
6164
6165 n_threads = convert->conversion_runner->n_threads;
6166 tasks = convert->tasks[0] =
6167 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
6168 tasks_p = convert->tasks_p[0] =
6169 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
6170
6171 lines_per_thread = (height + n_threads - 1) / n_threads;
6172
6173 for (i = 0; i < n_threads; i++) {
6174 tasks[i].dstride = FRAME_GET_STRIDE (dest);
6175 tasks[i].sstride = FRAME_GET_STRIDE (src);
6176 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
6177 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
6178
6179 tasks[i].width = width;
6180 tasks[i].height = (i + 1) * lines_per_thread;
6181 tasks[i].height = MIN (tasks[i].height, height);
6182 tasks[i].height -= i * lines_per_thread;
6183 tasks[i].data = data;
6184
6185 tasks_p[i] = &tasks[i];
6186 }
6187
6188 gst_parallelized_task_runner_run (convert->conversion_runner,
6189 (GstParallelizedTaskFunc) convert_AYUV_RGBA_task, (gpointer) tasks_p);
6190
6191 convert_fill_border (convert, dest);
6192 }
6193 #endif
6194
6195 static void
convert_I420_BGRA_task(FConvertTask * task)6196 convert_I420_BGRA_task (FConvertTask * task)
6197 {
6198 gint i;
6199
6200 for (i = task->height_0; i < task->height_1; i++) {
6201 guint8 *sy, *su, *sv, *d;
6202
6203 d = FRAME_GET_LINE (task->dest, i + task->out_y);
6204 d += (task->out_x * 4);
6205 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
6206 sy += task->in_x;
6207 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
6208 su += (task->in_x >> 1);
6209 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
6210 sv += (task->in_x >> 1);
6211
6212 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
6213 video_orc_convert_I420_BGRA (d, sy, su, sv,
6214 task->data->im[0][0], task->data->im[0][2],
6215 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6216 task->width);
6217 #else
6218 video_orc_convert_I420_ARGB (d, sy, su, sv,
6219 task->data->im[0][0], task->data->im[0][2],
6220 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6221 task->width);
6222 #endif
6223 }
6224 }
6225
6226 static void
convert_I420_BGRA(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)6227 convert_I420_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
6228 GstVideoFrame * dest)
6229 {
6230 int i;
6231 gint width = convert->in_width;
6232 gint height = convert->in_height;
6233 MatrixData *data = &convert->convert_matrix;
6234 FConvertTask *tasks;
6235 FConvertTask **tasks_p;
6236 gint n_threads;
6237 gint lines_per_thread;
6238
6239 n_threads = convert->conversion_runner->n_threads;
6240 tasks = convert->tasks[0] =
6241 g_renew (FConvertTask, convert->tasks[0], n_threads);
6242 tasks_p = convert->tasks_p[0] =
6243 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
6244
6245 lines_per_thread = (height + n_threads - 1) / n_threads;
6246
6247 for (i = 0; i < n_threads; i++) {
6248 tasks[i].src = src;
6249 tasks[i].dest = dest;
6250
6251 tasks[i].width = width;
6252 tasks[i].data = data;
6253 tasks[i].in_x = convert->in_x;
6254 tasks[i].in_y = convert->in_y;
6255 tasks[i].out_x = convert->out_x;
6256 tasks[i].out_y = convert->out_y;
6257
6258 tasks[i].height_0 = i * lines_per_thread;
6259 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
6260 tasks[i].height_1 = MIN (height, tasks[i].height_1);
6261
6262 tasks_p[i] = &tasks[i];
6263 }
6264
6265 gst_parallelized_task_runner_run (convert->conversion_runner,
6266 (GstParallelizedTaskFunc) convert_I420_BGRA_task, (gpointer) tasks_p);
6267
6268 convert_fill_border (convert, dest);
6269 }
6270
6271 static void
convert_I420_ARGB_task(FConvertTask * task)6272 convert_I420_ARGB_task (FConvertTask * task)
6273 {
6274 gint i;
6275
6276 for (i = task->height_0; i < task->height_1; i++) {
6277 guint8 *sy, *su, *sv, *d;
6278
6279 d = FRAME_GET_LINE (task->dest, i + task->out_y);
6280 d += (task->out_x * 4);
6281 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
6282 sy += task->in_x;
6283 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
6284 su += (task->in_x >> 1);
6285 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
6286 sv += (task->in_x >> 1);
6287
6288 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
6289 video_orc_convert_I420_ARGB (d, sy, su, sv,
6290 task->data->im[0][0], task->data->im[0][2],
6291 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6292 task->width);
6293 #else
6294 video_orc_convert_I420_BGRA (d, sy, su, sv,
6295 task->data->im[0][0], task->data->im[0][2],
6296 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6297 task->width);
6298 #endif
6299 }
6300 }
6301
6302 static void
convert_I420_ARGB(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)6303 convert_I420_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
6304 GstVideoFrame * dest)
6305 {
6306 int i;
6307 gint width = convert->in_width;
6308 gint height = convert->in_height;
6309 MatrixData *data = &convert->convert_matrix;
6310 FConvertTask *tasks;
6311 FConvertTask **tasks_p;
6312 gint n_threads;
6313 gint lines_per_thread;
6314
6315 n_threads = convert->conversion_runner->n_threads;
6316 tasks = convert->tasks[0] =
6317 g_renew (FConvertTask, convert->tasks[0], n_threads);
6318 tasks_p = convert->tasks_p[0] =
6319 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
6320
6321 lines_per_thread = (height + n_threads - 1) / n_threads;
6322
6323 for (i = 0; i < n_threads; i++) {
6324 tasks[i].src = src;
6325 tasks[i].dest = dest;
6326
6327 tasks[i].width = width;
6328 tasks[i].data = data;
6329 tasks[i].in_x = convert->in_x;
6330 tasks[i].in_y = convert->in_y;
6331 tasks[i].out_x = convert->out_x;
6332 tasks[i].out_y = convert->out_y;
6333
6334 tasks[i].height_0 = i * lines_per_thread;
6335 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
6336 tasks[i].height_1 = MIN (height, tasks[i].height_1);
6337
6338 tasks_p[i] = &tasks[i];
6339 }
6340
6341 gst_parallelized_task_runner_run (convert->conversion_runner,
6342 (GstParallelizedTaskFunc) convert_I420_ARGB_task, (gpointer) tasks_p);
6343
6344 convert_fill_border (convert, dest);
6345 }
6346
6347 static void
convert_I420_pack_ARGB_task(FConvertTask * task)6348 convert_I420_pack_ARGB_task (FConvertTask * task)
6349 {
6350 gint i;
6351 gpointer d[GST_VIDEO_MAX_PLANES];
6352
6353 d[0] = FRAME_GET_LINE (task->dest, 0);
6354 d[0] =
6355 (guint8 *) d[0] +
6356 task->out_x * GST_VIDEO_FORMAT_INFO_PSTRIDE (task->dest->info.finfo, 0);
6357
6358 for (i = task->height_0; i < task->height_1; i++) {
6359 guint8 *sy, *su, *sv;
6360
6361 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
6362 sy += task->in_x;
6363 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
6364 su += (task->in_x >> 1);
6365 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
6366 sv += (task->in_x >> 1);
6367
6368 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
6369 video_orc_convert_I420_ARGB (task->tmpline, sy, su, sv,
6370 task->data->im[0][0], task->data->im[0][2],
6371 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6372 task->width);
6373 #else
6374 video_orc_convert_I420_BGRA (task->tmpline, sy, su, sv,
6375 task->data->im[0][0], task->data->im[0][2],
6376 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6377 task->width);
6378 #endif
6379 task->dest->info.finfo->pack_func (task->dest->info.finfo,
6380 (GST_VIDEO_FRAME_IS_INTERLACED (task->dest) ?
6381 GST_VIDEO_PACK_FLAG_INTERLACED :
6382 GST_VIDEO_PACK_FLAG_NONE),
6383 task->tmpline, 0, d, task->dest->info.stride,
6384 task->dest->info.chroma_site, i + task->out_y, task->width);
6385 }
6386 }
6387
6388 static void
convert_I420_pack_ARGB(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)6389 convert_I420_pack_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
6390 GstVideoFrame * dest)
6391 {
6392 int i;
6393 gint width = convert->in_width;
6394 gint height = convert->in_height;
6395 MatrixData *data = &convert->convert_matrix;
6396 FConvertTask *tasks;
6397 FConvertTask **tasks_p;
6398 gint n_threads;
6399 gint lines_per_thread;
6400
6401 n_threads = convert->conversion_runner->n_threads;
6402 tasks = convert->tasks[0] =
6403 g_renew (FConvertTask, convert->tasks[0], n_threads);
6404 tasks_p = convert->tasks_p[0] =
6405 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
6406
6407 lines_per_thread = (height + n_threads - 1) / n_threads;
6408
6409 for (i = 0; i < n_threads; i++) {
6410 tasks[i].src = src;
6411 tasks[i].dest = dest;
6412
6413 tasks[i].width = width;
6414 tasks[i].data = data;
6415 tasks[i].in_x = convert->in_x;
6416 tasks[i].in_y = convert->in_y;
6417 tasks[i].out_x = convert->out_x;
6418 tasks[i].out_y = convert->out_y;
6419 tasks[i].tmpline = convert->tmpline[i];
6420
6421 tasks[i].height_0 = i * lines_per_thread;
6422 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
6423 tasks[i].height_1 = MIN (height, tasks[i].height_1);
6424
6425 tasks_p[i] = &tasks[i];
6426 }
6427
6428 gst_parallelized_task_runner_run (convert->conversion_runner,
6429 (GstParallelizedTaskFunc) convert_I420_pack_ARGB_task,
6430 (gpointer) tasks_p);
6431
6432 convert_fill_border (convert, dest);
6433 }
6434
6435 static void
convert_A420_pack_ARGB_task(FConvertTask * task)6436 convert_A420_pack_ARGB_task (FConvertTask * task)
6437 {
6438 gint i;
6439 gpointer d[GST_VIDEO_MAX_PLANES];
6440
6441 d[0] = FRAME_GET_LINE (task->dest, 0);
6442 d[0] =
6443 (guint8 *) d[0] +
6444 task->out_x * GST_VIDEO_FORMAT_INFO_PSTRIDE (task->dest->info.finfo, 0);
6445
6446 for (i = task->height_0; i < task->height_1; i++) {
6447 guint8 *sy, *su, *sv, *sa;
6448
6449 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
6450 sy += task->in_x;
6451 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
6452 su += (task->in_x >> 1);
6453 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
6454 sv += (task->in_x >> 1);
6455 sa = FRAME_GET_A_LINE (task->src, i + task->in_y);
6456 sa += task->in_x;
6457
6458 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
6459 video_orc_convert_A420_ARGB (task->tmpline, sy, su, sv, sa,
6460 task->data->im[0][0], task->data->im[0][2],
6461 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6462 task->width);
6463 #else
6464 video_orc_convert_A420_BGRA (task->tmpline, sy, su, sv, sa,
6465 task->data->im[0][0], task->data->im[0][2],
6466 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6467 task->width);
6468 #endif
6469
6470 task->dest->info.finfo->pack_func (task->dest->info.finfo,
6471 (GST_VIDEO_FRAME_IS_INTERLACED (task->dest) ?
6472 GST_VIDEO_PACK_FLAG_INTERLACED :
6473 GST_VIDEO_PACK_FLAG_NONE),
6474 task->tmpline, 0, d, task->dest->info.stride,
6475 task->dest->info.chroma_site, i + task->out_y, task->width);
6476 }
6477 }
6478
6479 static void
convert_A420_pack_ARGB(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)6480 convert_A420_pack_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
6481 GstVideoFrame * dest)
6482 {
6483 int i;
6484 gint width = convert->in_width;
6485 gint height = convert->in_height;
6486 MatrixData *data = &convert->convert_matrix;
6487 FConvertTask *tasks;
6488 FConvertTask **tasks_p;
6489 gint n_threads;
6490 gint lines_per_thread;
6491
6492 n_threads = convert->conversion_runner->n_threads;
6493 tasks = convert->tasks[0] =
6494 g_renew (FConvertTask, convert->tasks[0], n_threads);
6495 tasks_p = convert->tasks_p[0] =
6496 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
6497
6498 lines_per_thread = (height + n_threads - 1) / n_threads;
6499
6500 for (i = 0; i < n_threads; i++) {
6501 tasks[i].src = src;
6502 tasks[i].dest = dest;
6503
6504 tasks[i].width = width;
6505 tasks[i].data = data;
6506 tasks[i].in_x = convert->in_x;
6507 tasks[i].in_y = convert->in_y;
6508 tasks[i].out_x = convert->out_x;
6509 tasks[i].out_y = convert->out_y;
6510 tasks[i].tmpline = convert->tmpline[i];
6511
6512 tasks[i].height_0 = i * lines_per_thread;
6513 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
6514 tasks[i].height_1 = MIN (height, tasks[i].height_1);
6515
6516 tasks_p[i] = &tasks[i];
6517 }
6518
6519 gst_parallelized_task_runner_run (convert->conversion_runner,
6520 (GstParallelizedTaskFunc) convert_A420_pack_ARGB_task,
6521 (gpointer) tasks_p);
6522
6523 convert_fill_border (convert, dest);
6524 }
6525
6526 static void
convert_A420_BGRA_task(FConvertTask * task)6527 convert_A420_BGRA_task (FConvertTask * task)
6528 {
6529 gint i;
6530
6531 for (i = task->height_0; i < task->height_1; i++) {
6532 guint8 *sy, *su, *sv, *sa, *d;
6533
6534 d = FRAME_GET_LINE (task->dest, i + task->out_y);
6535 d += (task->out_x * 4);
6536 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
6537 sy += task->in_x;
6538 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
6539 su += (task->in_x >> 1);
6540 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
6541 sv += (task->in_x >> 1);
6542 sa = FRAME_GET_A_LINE (task->src, i + task->in_y);
6543 sa += task->in_x;
6544
6545 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
6546 video_orc_convert_A420_BGRA (d, sy, su, sv, sa,
6547 task->data->im[0][0], task->data->im[0][2],
6548 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6549 task->width);
6550 #else
6551 video_orc_convert_A420_ARGB (d, sy, su, sv, sa,
6552 task->data->im[0][0], task->data->im[0][2],
6553 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
6554 task->width);
6555 #endif
6556 }
6557 }
6558
6559 static void
convert_A420_BGRA(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)6560 convert_A420_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
6561 GstVideoFrame * dest)
6562 {
6563 int i;
6564 gint width = convert->in_width;
6565 gint height = convert->in_height;
6566 MatrixData *data = &convert->convert_matrix;
6567 FConvertTask *tasks;
6568 FConvertTask **tasks_p;
6569 gint n_threads;
6570 gint lines_per_thread;
6571
6572 n_threads = convert->conversion_runner->n_threads;
6573 tasks = convert->tasks[0] =
6574 g_renew (FConvertTask, convert->tasks[0], n_threads);
6575 tasks_p = convert->tasks_p[0] =
6576 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
6577
6578 lines_per_thread = (height + n_threads - 1) / n_threads;
6579
6580 for (i = 0; i < n_threads; i++) {
6581 tasks[i].src = src;
6582 tasks[i].dest = dest;
6583
6584 tasks[i].width = width;
6585 tasks[i].data = data;
6586 tasks[i].in_x = convert->in_x;
6587 tasks[i].in_y = convert->in_y;
6588 tasks[i].out_x = convert->out_x;
6589 tasks[i].out_y = convert->out_y;
6590
6591 tasks[i].height_0 = i * lines_per_thread;
6592 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
6593 tasks[i].height_1 = MIN (height, tasks[i].height_1);
6594
6595 tasks_p[i] = &tasks[i];
6596 }
6597
6598 gst_parallelized_task_runner_run (convert->conversion_runner,
6599 (GstParallelizedTaskFunc) convert_A420_BGRA_task, (gpointer) tasks_p);
6600
6601 convert_fill_border (convert, dest);
6602 }
6603
6604 static void
memset_u24(guint8 * data,guint8 col[3],unsigned int n)6605 memset_u24 (guint8 * data, guint8 col[3], unsigned int n)
6606 {
6607 unsigned int i;
6608
6609 for (i = 0; i < n; i++) {
6610 data[0] = col[0];
6611 data[1] = col[1];
6612 data[2] = col[2];
6613 data += 3;
6614 }
6615 }
6616
6617 static void
memset_u32_16(guint8 * data,guint8 col[4],unsigned int n)6618 memset_u32_16 (guint8 * data, guint8 col[4], unsigned int n)
6619 {
6620 unsigned int i;
6621
6622 for (i = 0; i < n; i += 2) {
6623 data[0] = col[0];
6624 data[1] = col[1];
6625 if (i + 1 < n) {
6626 data[2] = col[2];
6627 data[3] = col[3];
6628 }
6629 data += 4;
6630 }
6631 }
6632
6633 #define MAKE_BORDER_FUNC(func) \
6634 for (i = 0; i < out_y; i++) \
6635 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
6636 if (rb_width || lb_width) { \
6637 for (i = 0; i < out_height; i++) { \
6638 guint8 *d = FRAME_GET_PLANE_LINE (dest, k, i + out_y); \
6639 if (lb_width) \
6640 func (d, col, lb_width); \
6641 if (rb_width) \
6642 func (d + (pstride * r_border), col, rb_width); \
6643 } \
6644 } \
6645 for (i = out_y + out_height; i < out_maxheight; i++) \
6646 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
6647
6648 static void
convert_fill_border(GstVideoConverter * convert,GstVideoFrame * dest)6649 convert_fill_border (GstVideoConverter * convert, GstVideoFrame * dest)
6650 {
6651 int k, n_planes;
6652 const GstVideoFormatInfo *out_finfo;
6653
6654 if (!convert->fill_border || !convert->borderline)
6655 return;
6656
6657 out_finfo = convert->out_info.finfo;
6658
6659 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
6660
6661 for (k = 0; k < n_planes; k++) {
6662 gint comp[GST_VIDEO_MAX_COMPONENTS];
6663 gint i, out_x, out_y, out_width, out_height, pstride, pgroup;
6664 gint r_border, lb_width, rb_width;
6665 gint out_maxwidth, out_maxheight;
6666 gpointer borders;
6667
6668 gst_video_format_info_component (out_finfo, k, comp);
6669 out_x = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, comp[0],
6670 convert->out_x);
6671 out_y = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, comp[0],
6672 convert->out_y);
6673 out_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, comp[0],
6674 convert->out_width);
6675 out_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, comp[0],
6676 convert->out_height);
6677 out_maxwidth = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, comp[0],
6678 convert->out_maxwidth);
6679 out_maxheight = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, comp[0],
6680 convert->out_maxheight);
6681
6682 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, comp[0]);
6683
6684 switch (GST_VIDEO_FORMAT_INFO_FORMAT (out_finfo)) {
6685 case GST_VIDEO_FORMAT_YUY2:
6686 case GST_VIDEO_FORMAT_YVYU:
6687 case GST_VIDEO_FORMAT_UYVY:
6688 pgroup = 42;
6689 out_maxwidth = GST_ROUND_UP_2 (out_maxwidth);
6690 break;
6691 default:
6692 pgroup = pstride;
6693 break;
6694 }
6695
6696 r_border = out_x + out_width;
6697 rb_width = out_maxwidth - r_border;
6698 lb_width = out_x;
6699
6700 borders = &convert->borders[k];
6701
6702 switch (pgroup) {
6703 case 1:
6704 {
6705 guint8 col = ((guint8 *) borders)[0];
6706 MAKE_BORDER_FUNC (memset);
6707 break;
6708 }
6709 case 2:
6710 {
6711 guint16 col = ((guint16 *) borders)[0];
6712 MAKE_BORDER_FUNC (video_orc_splat_u16);
6713 break;
6714 }
6715 case 3:
6716 {
6717 guint8 col[3];
6718 col[0] = ((guint8 *) borders)[0];
6719 col[1] = ((guint8 *) borders)[1];
6720 col[2] = ((guint8 *) borders)[2];
6721 MAKE_BORDER_FUNC (memset_u24);
6722 break;
6723 }
6724 case 4:
6725 {
6726 guint32 col = ((guint32 *) borders)[0];
6727 MAKE_BORDER_FUNC (video_orc_splat_u32);
6728 break;
6729 }
6730 case 8:
6731 {
6732 guint64 col = ((guint64 *) borders)[0];
6733 MAKE_BORDER_FUNC (video_orc_splat_u64);
6734 break;
6735 }
6736 case 42:
6737 {
6738 guint8 col[4];
6739 col[0] = ((guint8 *) borders)[0];
6740 col[2] = ((guint8 *) borders)[2];
6741 col[1] = ((guint8 *) borders)[r_border & 1 ? 3 : 1];
6742 col[3] = ((guint8 *) borders)[r_border & 1 ? 1 : 3];
6743 MAKE_BORDER_FUNC (memset_u32_16);
6744 break;
6745 }
6746 default:
6747 break;
6748 }
6749 }
6750 }
6751
6752 typedef struct
6753 {
6754 const guint8 *s, *s2;
6755 guint8 *d, *d2;
6756 gint sstride, dstride;
6757 gint width, height;
6758 gint fill;
6759 } FSimpleScaleTask;
6760
6761 static void
convert_plane_fill_task(FSimpleScaleTask * task)6762 convert_plane_fill_task (FSimpleScaleTask * task)
6763 {
6764 video_orc_memset_2d (task->d, task->dstride,
6765 task->fill, task->width, task->height);
6766 }
6767
6768 static void
convert_plane_fill(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)6769 convert_plane_fill (GstVideoConverter * convert,
6770 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6771 {
6772 guint8 *d;
6773 FSimpleScaleTask *tasks;
6774 FSimpleScaleTask **tasks_p;
6775 gint n_threads;
6776 gint lines_per_thread;
6777 gint i;
6778
6779 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6780 d += convert->fout_x[plane];
6781
6782 n_threads = convert->conversion_runner->n_threads;
6783 tasks = convert->tasks[plane] =
6784 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6785 tasks_p = convert->tasks_p[plane] =
6786 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6787 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6788
6789 for (i = 0; i < n_threads; i++) {
6790 tasks[i].d = d + i * lines_per_thread * convert->fout_width[plane];
6791
6792 tasks[i].fill = convert->ffill[plane];
6793 tasks[i].width = convert->fout_width[plane];
6794 tasks[i].height = (i + 1) * lines_per_thread;
6795 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6796 tasks[i].height -= i * lines_per_thread;
6797 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
6798
6799 tasks_p[i] = &tasks[i];
6800 }
6801
6802 gst_parallelized_task_runner_run (convert->conversion_runner,
6803 (GstParallelizedTaskFunc) convert_plane_fill_task, (gpointer) tasks_p);
6804 }
6805
6806 static void
convert_plane_h_double_task(FSimpleScaleTask * task)6807 convert_plane_h_double_task (FSimpleScaleTask * task)
6808 {
6809 video_orc_planar_chroma_422_444 (task->d,
6810 task->dstride, task->s, task->sstride, task->width / 2, task->height);
6811 }
6812
6813 static void
convert_plane_h_double(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)6814 convert_plane_h_double (GstVideoConverter * convert,
6815 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6816 {
6817 guint8 *s, *d;
6818 gint splane = convert->fsplane[plane];
6819 FSimpleScaleTask *tasks;
6820 FSimpleScaleTask **tasks_p;
6821 gint n_threads;
6822 gint lines_per_thread;
6823 gint i;
6824
6825 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6826 s += convert->fin_x[splane];
6827 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6828 d += convert->fout_x[plane];
6829
6830 n_threads = convert->conversion_runner->n_threads;
6831 tasks = convert->tasks[plane] =
6832 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6833 tasks_p = convert->tasks_p[plane] =
6834 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6835 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6836
6837 for (i = 0; i < n_threads; i++) {
6838 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
6839 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6840
6841 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
6842 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
6843
6844 tasks[i].width = convert->fout_width[plane];
6845 tasks[i].height = (i + 1) * lines_per_thread;
6846 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6847 tasks[i].height -= i * lines_per_thread;
6848
6849 tasks_p[i] = &tasks[i];
6850 }
6851
6852 gst_parallelized_task_runner_run (convert->conversion_runner,
6853 (GstParallelizedTaskFunc) convert_plane_h_double_task,
6854 (gpointer) tasks_p);
6855 }
6856
6857 static void
convert_plane_h_halve_task(FSimpleScaleTask * task)6858 convert_plane_h_halve_task (FSimpleScaleTask * task)
6859 {
6860 video_orc_planar_chroma_444_422 (task->d,
6861 task->dstride, task->s, task->sstride, task->width, task->height);
6862 }
6863
6864 static void
convert_plane_h_halve(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)6865 convert_plane_h_halve (GstVideoConverter * convert,
6866 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6867 {
6868 guint8 *s, *d;
6869 gint splane = convert->fsplane[plane];
6870 FSimpleScaleTask *tasks;
6871 FSimpleScaleTask **tasks_p;
6872 gint n_threads;
6873 gint lines_per_thread;
6874 gint i;
6875
6876 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6877 s += convert->fin_x[splane];
6878 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6879 d += convert->fout_x[plane];
6880
6881 n_threads = convert->conversion_runner->n_threads;
6882 tasks = convert->tasks[plane] =
6883 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6884 tasks_p = convert->tasks_p[plane] =
6885 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6886 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6887
6888 for (i = 0; i < n_threads; i++) {
6889 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
6890 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6891
6892 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
6893 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
6894
6895 tasks[i].width = convert->fout_width[plane];
6896 tasks[i].height = (i + 1) * lines_per_thread;
6897 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6898 tasks[i].height -= i * lines_per_thread;
6899
6900 tasks_p[i] = &tasks[i];
6901 }
6902
6903 gst_parallelized_task_runner_run (convert->conversion_runner,
6904 (GstParallelizedTaskFunc) convert_plane_h_halve_task, (gpointer) tasks_p);
6905 }
6906
6907 static void
convert_plane_v_double_task(FSimpleScaleTask * task)6908 convert_plane_v_double_task (FSimpleScaleTask * task)
6909 {
6910 video_orc_planar_chroma_420_422 (task->d, 2 * task->dstride, task->d2,
6911 2 * task->dstride, task->s, task->sstride, task->width, task->height / 2);
6912 }
6913
6914 static void
convert_plane_v_double(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)6915 convert_plane_v_double (GstVideoConverter * convert,
6916 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6917 {
6918 guint8 *s, *d1, *d2;
6919 gint ds, splane = convert->fsplane[plane];
6920 FSimpleScaleTask *tasks;
6921 FSimpleScaleTask **tasks_p;
6922 gint n_threads;
6923 gint lines_per_thread;
6924 gint i;
6925
6926 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6927 s += convert->fin_x[splane];
6928 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6929 d1 += convert->fout_x[plane];
6930 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
6931 d2 += convert->fout_x[plane];
6932 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
6933
6934 n_threads = convert->conversion_runner->n_threads;
6935 tasks = convert->tasks[plane] =
6936 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6937 tasks_p = convert->tasks_p[plane] =
6938 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6939 lines_per_thread =
6940 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
6941 1) / n_threads);
6942
6943 for (i = 0; i < n_threads; i++) {
6944 tasks[i].d = d1 + i * lines_per_thread * ds;
6945 tasks[i].d2 = d2 + i * lines_per_thread * ds;
6946 tasks[i].dstride = ds;
6947 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6948 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride / 2;
6949
6950 tasks[i].width = convert->fout_width[plane];
6951 tasks[i].height = (i + 1) * lines_per_thread;
6952 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6953 tasks[i].height -= i * lines_per_thread;
6954
6955 tasks_p[i] = &tasks[i];
6956 }
6957
6958 gst_parallelized_task_runner_run (convert->conversion_runner,
6959 (GstParallelizedTaskFunc) convert_plane_v_double_task,
6960 (gpointer) tasks_p);
6961 }
6962
6963 static void
convert_plane_v_halve_task(FSimpleScaleTask * task)6964 convert_plane_v_halve_task (FSimpleScaleTask * task)
6965 {
6966 video_orc_planar_chroma_422_420 (task->d, task->dstride, task->s,
6967 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
6968 task->height);
6969 }
6970
6971 static void
convert_plane_v_halve(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)6972 convert_plane_v_halve (GstVideoConverter * convert,
6973 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6974 {
6975 guint8 *s1, *s2, *d;
6976 gint ss, ds, splane = convert->fsplane[plane];
6977 FSimpleScaleTask *tasks;
6978 FSimpleScaleTask **tasks_p;
6979 gint n_threads;
6980 gint lines_per_thread;
6981 gint i;
6982
6983 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6984 s1 += convert->fin_x[splane];
6985 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
6986 s2 += convert->fin_x[splane];
6987 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6988 d += convert->fout_x[plane];
6989
6990 ss = FRAME_GET_PLANE_STRIDE (src, splane);
6991 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
6992
6993 n_threads = convert->conversion_runner->n_threads;
6994 tasks = convert->tasks[plane] =
6995 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6996 tasks_p = convert->tasks_p[plane] =
6997 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6998 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6999
7000 for (i = 0; i < n_threads; i++) {
7001 tasks[i].d = d + i * lines_per_thread * ds;
7002 tasks[i].dstride = ds;
7003 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
7004 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
7005 tasks[i].sstride = ss;
7006
7007 tasks[i].width = convert->fout_width[plane];
7008 tasks[i].height = (i + 1) * lines_per_thread;
7009 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
7010 tasks[i].height -= i * lines_per_thread;
7011
7012 tasks_p[i] = &tasks[i];
7013 }
7014
7015 gst_parallelized_task_runner_run (convert->conversion_runner,
7016 (GstParallelizedTaskFunc) convert_plane_v_halve_task, (gpointer) tasks_p);
7017 }
7018
7019 static void
convert_plane_hv_double_task(FSimpleScaleTask * task)7020 convert_plane_hv_double_task (FSimpleScaleTask * task)
7021 {
7022 video_orc_planar_chroma_420_444 (task->d, 2 * task->dstride, task->d2,
7023 2 * task->dstride, task->s, task->sstride, (task->width + 1) / 2,
7024 task->height / 2);
7025 }
7026
7027 static void
convert_plane_hv_double(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)7028 convert_plane_hv_double (GstVideoConverter * convert,
7029 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
7030 {
7031 guint8 *s, *d1, *d2;
7032 gint ss, ds, splane = convert->fsplane[plane];
7033 FSimpleScaleTask *tasks;
7034 FSimpleScaleTask **tasks_p;
7035 gint n_threads;
7036 gint lines_per_thread;
7037 gint i;
7038
7039 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
7040 s += convert->fin_x[splane];
7041 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
7042 d1 += convert->fout_x[plane];
7043 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
7044 d2 += convert->fout_x[plane];
7045 ss = FRAME_GET_PLANE_STRIDE (src, splane);
7046 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
7047
7048 n_threads = convert->conversion_runner->n_threads;
7049 tasks = convert->tasks[plane] =
7050 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
7051 tasks_p = convert->tasks_p[plane] =
7052 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
7053 lines_per_thread =
7054 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
7055 1) / n_threads);
7056
7057 for (i = 0; i < n_threads; i++) {
7058 tasks[i].d = d1 + i * lines_per_thread * ds;
7059 tasks[i].d2 = d2 + i * lines_per_thread * ds;
7060 tasks[i].dstride = ds;
7061 tasks[i].sstride = ss;
7062 tasks[i].s = s + i * lines_per_thread * ss / 2;
7063
7064 tasks[i].width = convert->fout_width[plane];
7065 tasks[i].height = (i + 1) * lines_per_thread;
7066 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
7067 tasks[i].height -= i * lines_per_thread;
7068
7069 tasks_p[i] = &tasks[i];
7070 }
7071
7072 gst_parallelized_task_runner_run (convert->conversion_runner,
7073 (GstParallelizedTaskFunc) convert_plane_hv_double_task,
7074 (gpointer) tasks_p);
7075 }
7076
7077 static void
convert_plane_hv_halve_task(FSimpleScaleTask * task)7078 convert_plane_hv_halve_task (FSimpleScaleTask * task)
7079 {
7080 video_orc_planar_chroma_444_420 (task->d, task->dstride, task->s,
7081 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
7082 task->height);
7083 }
7084
7085 static void
convert_plane_hv_halve(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)7086 convert_plane_hv_halve (GstVideoConverter * convert,
7087 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
7088 {
7089 guint8 *s1, *s2, *d;
7090 gint ss, ds, splane = convert->fsplane[plane];
7091 FSimpleScaleTask *tasks;
7092 FSimpleScaleTask **tasks_p;
7093 gint n_threads;
7094 gint lines_per_thread;
7095 gint i;
7096
7097 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
7098 s1 += convert->fin_x[splane];
7099 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
7100 s2 += convert->fin_x[splane];
7101 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
7102 d += convert->fout_x[plane];
7103 ss = FRAME_GET_PLANE_STRIDE (src, splane);
7104 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
7105
7106 n_threads = convert->conversion_runner->n_threads;
7107 tasks = convert->tasks[plane] =
7108 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
7109 tasks_p = convert->tasks_p[plane] =
7110 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
7111 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
7112
7113 for (i = 0; i < n_threads; i++) {
7114 tasks[i].d = d + i * lines_per_thread * ds;
7115 tasks[i].dstride = ds;
7116 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
7117 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
7118 tasks[i].sstride = ss;
7119
7120 tasks[i].width = convert->fout_width[plane];
7121 tasks[i].height = (i + 1) * lines_per_thread;
7122 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
7123 tasks[i].height -= i * lines_per_thread;
7124
7125 tasks_p[i] = &tasks[i];
7126 }
7127
7128 gst_parallelized_task_runner_run (convert->conversion_runner,
7129 (GstParallelizedTaskFunc) convert_plane_hv_halve_task,
7130 (gpointer) tasks_p);
7131 }
7132
7133 typedef struct
7134 {
7135 GstVideoScaler *h_scaler, *v_scaler;
7136 GstVideoFormat format;
7137 const guint8 *s;
7138 guint8 *d;
7139 gint sstride, dstride;
7140 guint x, y, w, h;
7141 } FScaleTask;
7142
7143 static void
convert_plane_hv_task(FScaleTask * task)7144 convert_plane_hv_task (FScaleTask * task)
7145 {
7146 gst_video_scaler_2d (task->h_scaler, task->v_scaler, task->format,
7147 (guint8 *) task->s, task->sstride,
7148 task->d, task->dstride, task->x, task->y, task->w, task->h);
7149 }
7150
7151 static void
convert_plane_hv(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest,gint plane)7152 convert_plane_hv (GstVideoConverter * convert,
7153 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
7154 {
7155 gint in_x, in_y, out_x, out_y, out_width, out_height;
7156 GstVideoFormat format;
7157 gint splane = convert->fsplane[plane];
7158 guint8 *s, *d;
7159 gint sstride, dstride;
7160 FScaleTask *tasks;
7161 FScaleTask **tasks_p;
7162 gint i, n_threads, lines_per_thread;
7163
7164 in_x = convert->fin_x[splane];
7165 in_y = convert->fin_y[splane];
7166 out_x = convert->fout_x[plane];
7167 out_y = convert->fout_y[plane];
7168 out_width = convert->fout_width[plane];
7169 out_height = convert->fout_height[plane];
7170 format = convert->fformat[plane];
7171
7172 s = FRAME_GET_PLANE_LINE (src, splane, in_y);
7173 s += in_x;
7174 d = FRAME_GET_PLANE_LINE (dest, plane, out_y);
7175 d += out_x;
7176
7177 sstride = FRAME_GET_PLANE_STRIDE (src, splane);
7178 dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
7179
7180 n_threads = convert->conversion_runner->n_threads;
7181 tasks = convert->tasks[plane] =
7182 g_renew (FScaleTask, convert->tasks[plane], n_threads);
7183 tasks_p = convert->tasks_p[plane] =
7184 g_renew (FScaleTask *, convert->tasks_p[plane], n_threads);
7185
7186 lines_per_thread = (out_height + n_threads - 1) / n_threads;
7187
7188 for (i = 0; i < n_threads; i++) {
7189 tasks[i].h_scaler =
7190 convert->fh_scaler[plane].scaler ? convert->
7191 fh_scaler[plane].scaler[i] : NULL;
7192 tasks[i].v_scaler =
7193 convert->fv_scaler[plane].scaler ? convert->
7194 fv_scaler[plane].scaler[i] : NULL;
7195 tasks[i].format = format;
7196 tasks[i].s = s;
7197 tasks[i].d = d;
7198 tasks[i].sstride = sstride;
7199 tasks[i].dstride = dstride;
7200
7201 tasks[i].x = 0;
7202 tasks[i].w = out_width;
7203
7204 tasks[i].y = i * lines_per_thread;
7205 tasks[i].h = tasks[i].y + lines_per_thread;
7206 tasks[i].h = MIN (out_height, tasks[i].h);
7207
7208 tasks_p[i] = &tasks[i];
7209 }
7210
7211 gst_parallelized_task_runner_run (convert->conversion_runner,
7212 (GstParallelizedTaskFunc) convert_plane_hv_task, (gpointer) tasks_p);
7213 }
7214
7215 static void
convert_scale_planes(GstVideoConverter * convert,const GstVideoFrame * src,GstVideoFrame * dest)7216 convert_scale_planes (GstVideoConverter * convert,
7217 const GstVideoFrame * src, GstVideoFrame * dest)
7218 {
7219 int i, n_planes;
7220
7221 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
7222 for (i = 0; i < n_planes; i++) {
7223 if (convert->fconvert[i])
7224 convert->fconvert[i] (convert, src, dest, i);
7225 }
7226 convert_fill_border (convert, dest);
7227 }
7228
7229 static GstVideoFormat
get_scale_format(GstVideoFormat format,gint plane)7230 get_scale_format (GstVideoFormat format, gint plane)
7231 {
7232 GstVideoFormat res = GST_VIDEO_FORMAT_UNKNOWN;
7233
7234 switch (format) {
7235 case GST_VIDEO_FORMAT_I420:
7236 case GST_VIDEO_FORMAT_YV12:
7237 case GST_VIDEO_FORMAT_Y41B:
7238 case GST_VIDEO_FORMAT_Y42B:
7239 case GST_VIDEO_FORMAT_Y444:
7240 case GST_VIDEO_FORMAT_GRAY8:
7241 case GST_VIDEO_FORMAT_A420:
7242 case GST_VIDEO_FORMAT_YUV9:
7243 case GST_VIDEO_FORMAT_YVU9:
7244 case GST_VIDEO_FORMAT_GBR:
7245 case GST_VIDEO_FORMAT_GBRA:
7246 case GST_VIDEO_FORMAT_RGBP:
7247 case GST_VIDEO_FORMAT_BGRP:
7248 res = GST_VIDEO_FORMAT_GRAY8;
7249 break;
7250 case GST_VIDEO_FORMAT_GRAY16_BE:
7251 case GST_VIDEO_FORMAT_GRAY16_LE:
7252 res = GST_VIDEO_FORMAT_GRAY16_BE;
7253 break;
7254 case GST_VIDEO_FORMAT_YUY2:
7255 case GST_VIDEO_FORMAT_UYVY:
7256 case GST_VIDEO_FORMAT_VYUY:
7257 case GST_VIDEO_FORMAT_YVYU:
7258 case GST_VIDEO_FORMAT_AYUV:
7259 case GST_VIDEO_FORMAT_VUYA:
7260 case GST_VIDEO_FORMAT_RGBx:
7261 case GST_VIDEO_FORMAT_BGRx:
7262 case GST_VIDEO_FORMAT_xRGB:
7263 case GST_VIDEO_FORMAT_xBGR:
7264 case GST_VIDEO_FORMAT_RGBA:
7265 case GST_VIDEO_FORMAT_BGRA:
7266 case GST_VIDEO_FORMAT_ARGB:
7267 case GST_VIDEO_FORMAT_ABGR:
7268 case GST_VIDEO_FORMAT_RGB:
7269 case GST_VIDEO_FORMAT_BGR:
7270 case GST_VIDEO_FORMAT_v308:
7271 case GST_VIDEO_FORMAT_IYU2:
7272 case GST_VIDEO_FORMAT_ARGB64:
7273 case GST_VIDEO_FORMAT_ARGB64_LE:
7274 case GST_VIDEO_FORMAT_ARGB64_BE:
7275 case GST_VIDEO_FORMAT_RGBA64_BE:
7276 case GST_VIDEO_FORMAT_RGBA64_LE:
7277 case GST_VIDEO_FORMAT_BGRA64_BE:
7278 case GST_VIDEO_FORMAT_BGRA64_LE:
7279 case GST_VIDEO_FORMAT_ABGR64_BE:
7280 case GST_VIDEO_FORMAT_ABGR64_LE:
7281 case GST_VIDEO_FORMAT_AYUV64:
7282 res = format;
7283 break;
7284 case GST_VIDEO_FORMAT_RGB15:
7285 case GST_VIDEO_FORMAT_BGR15:
7286 case GST_VIDEO_FORMAT_RGB16:
7287 case GST_VIDEO_FORMAT_BGR16:
7288 res = GST_VIDEO_FORMAT_NV12;
7289 break;
7290 case GST_VIDEO_FORMAT_NV12:
7291 case GST_VIDEO_FORMAT_NV21:
7292 case GST_VIDEO_FORMAT_NV16:
7293 case GST_VIDEO_FORMAT_NV61:
7294 case GST_VIDEO_FORMAT_NV24:
7295 res = plane == 0 ? GST_VIDEO_FORMAT_GRAY8 : GST_VIDEO_FORMAT_NV12;
7296 break;
7297 case GST_VIDEO_FORMAT_AV12:
7298 res = (plane == 0
7299 || plane == 2) ? GST_VIDEO_FORMAT_GRAY8 : GST_VIDEO_FORMAT_NV12;
7300 break;
7301 case GST_VIDEO_FORMAT_UNKNOWN:
7302 case GST_VIDEO_FORMAT_ENCODED:
7303 case GST_VIDEO_FORMAT_v210:
7304 case GST_VIDEO_FORMAT_v216:
7305 case GST_VIDEO_FORMAT_Y210:
7306 case GST_VIDEO_FORMAT_Y410:
7307 case GST_VIDEO_FORMAT_UYVP:
7308 case GST_VIDEO_FORMAT_RGB8P:
7309 case GST_VIDEO_FORMAT_IYU1:
7310 case GST_VIDEO_FORMAT_r210:
7311 case GST_VIDEO_FORMAT_I420_10BE:
7312 case GST_VIDEO_FORMAT_I420_10LE:
7313 case GST_VIDEO_FORMAT_I422_10BE:
7314 case GST_VIDEO_FORMAT_I422_10LE:
7315 case GST_VIDEO_FORMAT_Y444_10BE:
7316 case GST_VIDEO_FORMAT_Y444_10LE:
7317 case GST_VIDEO_FORMAT_I420_12BE:
7318 case GST_VIDEO_FORMAT_I420_12LE:
7319 case GST_VIDEO_FORMAT_I422_12BE:
7320 case GST_VIDEO_FORMAT_I422_12LE:
7321 case GST_VIDEO_FORMAT_Y444_12BE:
7322 case GST_VIDEO_FORMAT_Y444_12LE:
7323 case GST_VIDEO_FORMAT_GBR_10BE:
7324 case GST_VIDEO_FORMAT_GBR_10LE:
7325 case GST_VIDEO_FORMAT_GBRA_10BE:
7326 case GST_VIDEO_FORMAT_GBRA_10LE:
7327 case GST_VIDEO_FORMAT_GBR_12BE:
7328 case GST_VIDEO_FORMAT_GBR_12LE:
7329 case GST_VIDEO_FORMAT_GBRA_12BE:
7330 case GST_VIDEO_FORMAT_GBRA_12LE:
7331 case GST_VIDEO_FORMAT_NV12_64Z32:
7332 case GST_VIDEO_FORMAT_NV12_4L4:
7333 case GST_VIDEO_FORMAT_NV12_32L32:
7334 case GST_VIDEO_FORMAT_A420_10BE:
7335 case GST_VIDEO_FORMAT_A420_10LE:
7336 case GST_VIDEO_FORMAT_A422_10BE:
7337 case GST_VIDEO_FORMAT_A422_10LE:
7338 case GST_VIDEO_FORMAT_A444_10BE:
7339 case GST_VIDEO_FORMAT_A444_10LE:
7340 case GST_VIDEO_FORMAT_P010_10BE:
7341 case GST_VIDEO_FORMAT_P010_10LE:
7342 case GST_VIDEO_FORMAT_GRAY10_LE32:
7343 case GST_VIDEO_FORMAT_NV12_10LE32:
7344 case GST_VIDEO_FORMAT_NV16_10LE32:
7345 case GST_VIDEO_FORMAT_NV12_10LE40:
7346 case GST_VIDEO_FORMAT_BGR10A2_LE:
7347 case GST_VIDEO_FORMAT_RGB10A2_LE:
7348 case GST_VIDEO_FORMAT_Y444_16BE:
7349 case GST_VIDEO_FORMAT_Y444_16LE:
7350 case GST_VIDEO_FORMAT_P016_BE:
7351 case GST_VIDEO_FORMAT_P016_LE:
7352 case GST_VIDEO_FORMAT_P012_BE:
7353 case GST_VIDEO_FORMAT_P012_LE:
7354 case GST_VIDEO_FORMAT_Y212_BE:
7355 case GST_VIDEO_FORMAT_Y212_LE:
7356 case GST_VIDEO_FORMAT_Y412_BE:
7357 case GST_VIDEO_FORMAT_Y412_LE:
7358 res = format;
7359 g_assert_not_reached ();
7360 break;
7361 }
7362 return res;
7363 }
7364
7365 static gboolean
is_merge_yuv(GstVideoInfo * info)7366 is_merge_yuv (GstVideoInfo * info)
7367 {
7368 switch (GST_VIDEO_INFO_FORMAT (info)) {
7369 case GST_VIDEO_FORMAT_YUY2:
7370 case GST_VIDEO_FORMAT_YVYU:
7371 case GST_VIDEO_FORMAT_UYVY:
7372 case GST_VIDEO_FORMAT_VYUY:
7373 return TRUE;
7374 default:
7375 return FALSE;
7376 }
7377 }
7378
7379 static gboolean
setup_scale(GstVideoConverter * convert)7380 setup_scale (GstVideoConverter * convert)
7381 {
7382 int i, n_planes;
7383 gint method, cr_method, in_width, in_height, out_width, out_height;
7384 guint taps;
7385 GstVideoInfo *in_info, *out_info;
7386 const GstVideoFormatInfo *in_finfo, *out_finfo;
7387 GstVideoFormat in_format, out_format;
7388 gboolean interlaced;
7389 guint n_threads = convert->conversion_runner->n_threads;
7390
7391 in_info = &convert->in_info;
7392 out_info = &convert->out_info;
7393
7394 in_finfo = in_info->finfo;
7395 out_finfo = out_info->finfo;
7396
7397 n_planes = GST_VIDEO_INFO_N_PLANES (out_info);
7398
7399 interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)
7400 && GST_VIDEO_INFO_INTERLACE_MODE (&convert->in_info) !=
7401 GST_VIDEO_INTERLACE_MODE_ALTERNATE;
7402
7403 method = GET_OPT_RESAMPLER_METHOD (convert);
7404 if (method == GST_VIDEO_RESAMPLER_METHOD_NEAREST)
7405 cr_method = method;
7406 else
7407 cr_method = GET_OPT_CHROMA_RESAMPLER_METHOD (convert);
7408 taps = GET_OPT_RESAMPLER_TAPS (convert);
7409
7410 in_format = GST_VIDEO_INFO_FORMAT (in_info);
7411 out_format = GST_VIDEO_INFO_FORMAT (out_info);
7412
7413 switch (in_format) {
7414 case GST_VIDEO_FORMAT_RGB15:
7415 case GST_VIDEO_FORMAT_RGB16:
7416 case GST_VIDEO_FORMAT_BGR15:
7417 case GST_VIDEO_FORMAT_BGR16:
7418 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
7419 case GST_VIDEO_FORMAT_GRAY16_BE:
7420 #else
7421 case GST_VIDEO_FORMAT_GRAY16_LE:
7422 #endif
7423 if (method != GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
7424 GST_DEBUG ("%s only with nearest resampling",
7425 gst_video_format_to_string (in_format));
7426 return FALSE;
7427 }
7428 break;
7429 default:
7430 break;
7431 }
7432
7433 in_width = convert->in_width;
7434 in_height = convert->in_height;
7435 out_width = convert->out_width;
7436 out_height = convert->out_height;
7437
7438 if (n_planes == 1 && !GST_VIDEO_FORMAT_INFO_IS_GRAY (out_finfo)) {
7439 gint pstride;
7440 guint j;
7441
7442 if (is_merge_yuv (in_info)) {
7443 GstVideoScaler *y_scaler, *uv_scaler;
7444
7445 if (in_width != out_width) {
7446 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
7447 for (j = 0; j < n_threads; j++) {
7448 y_scaler =
7449 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
7450 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_Y,
7451 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
7452 GST_VIDEO_COMP_Y, out_width), convert->config);
7453 uv_scaler =
7454 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE,
7455 gst_video_scaler_get_max_taps (y_scaler),
7456 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_U,
7457 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
7458 GST_VIDEO_COMP_U, out_width), convert->config);
7459
7460 convert->fh_scaler[0].scaler[j] =
7461 gst_video_scaler_combine_packed_YUV (y_scaler, uv_scaler,
7462 in_format, out_format);
7463
7464 gst_video_scaler_free (y_scaler);
7465 gst_video_scaler_free (uv_scaler);
7466 }
7467 } else {
7468 convert->fh_scaler[0].scaler = NULL;
7469 }
7470
7471 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_Y);
7472 convert->fin_x[0] = GST_ROUND_UP_2 (convert->in_x) * pstride;
7473 convert->fout_x[0] = GST_ROUND_UP_2 (convert->out_x) * pstride;
7474
7475 } else {
7476 if (in_width != out_width && in_width != 0 && out_width != 0) {
7477 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
7478 for (j = 0; j < n_threads; j++) {
7479 convert->fh_scaler[0].scaler[j] =
7480 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
7481 in_width, out_width, convert->config);
7482 }
7483 } else {
7484 convert->fh_scaler[0].scaler = NULL;
7485 }
7486
7487 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_R);
7488 convert->fin_x[0] = convert->in_x * pstride;
7489 convert->fout_x[0] = convert->out_x * pstride;
7490 }
7491
7492 if (in_height != out_height && in_height != 0 && out_height != 0) {
7493 convert->fv_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
7494
7495 for (j = 0; j < n_threads; j++) {
7496 convert->fv_scaler[0].scaler[j] =
7497 gst_video_scaler_new (method,
7498 interlaced ?
7499 GST_VIDEO_SCALER_FLAG_INTERLACED : GST_VIDEO_SCALER_FLAG_NONE, taps,
7500 in_height, out_height, convert->config);
7501 }
7502 } else {
7503 convert->fv_scaler[0].scaler = NULL;
7504 }
7505
7506 convert->fin_y[0] = convert->in_y;
7507 convert->fout_y[0] = convert->out_y;
7508 convert->fout_width[0] = out_width;
7509 convert->fout_height[0] = out_height;
7510 convert->fconvert[0] = convert_plane_hv;
7511 convert->fformat[0] = get_scale_format (in_format, 0);
7512 convert->fsplane[0] = 0;
7513 } else {
7514 for (i = 0; i < n_planes; i++) {
7515 gint out_comp[GST_VIDEO_MAX_COMPONENTS];
7516 gint comp, j, iw, ih, ow, oh, pstride;
7517 gboolean need_v_scaler, need_h_scaler;
7518 GstStructure *config;
7519 gint resample_method;
7520
7521 gst_video_format_info_component (out_finfo, i, out_comp);
7522 ow = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, out_comp[0],
7523 out_width);
7524 oh = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, out_comp[0],
7525 out_height);
7526 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, out_comp[0]);
7527
7528 /* find the component in this plane and map it to the plane of
7529 * the source */
7530 if (out_comp[0] < GST_VIDEO_FORMAT_INFO_N_COMPONENTS (in_finfo)) {
7531 comp = out_comp[0];
7532 iw = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, comp, in_width);
7533 ih = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, comp, in_height);
7534 convert->fin_x[i] = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, comp,
7535 convert->in_x);
7536 convert->fin_x[i] *= pstride;
7537 convert->fin_y[i] = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, comp,
7538 convert->in_y);
7539 } else {
7540 /* we will use a fill instead, setting the parameters to an invalid
7541 * size to reduce confusion */
7542 comp = -1;
7543 iw = ih = -1;
7544 convert->fin_x[i] = -1;
7545 convert->fin_y[i] = -1;
7546 }
7547
7548 convert->fout_width[i] = ow;
7549 convert->fout_height[i] = oh;
7550
7551 convert->fout_x[i] = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
7552 out_comp[0], convert->out_x);
7553 convert->fout_x[i] *= pstride;
7554 convert->fout_y[i] = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo,
7555 out_comp[0], convert->out_y);
7556
7557 GST_DEBUG ("plane %d: %dx%d -> %dx%d", i, iw, ih, ow, oh);
7558 GST_DEBUG ("plane %d: pstride %d", i, pstride);
7559 GST_DEBUG ("plane %d: in_x %d, in_y %d", i, convert->fin_x[i],
7560 convert->fin_y[i]);
7561 GST_DEBUG ("plane %d: out_x %d, out_y %d", i, convert->fout_x[i],
7562 convert->fout_y[i]);
7563
7564 if (comp == -1) {
7565 convert->fconvert[i] = convert_plane_fill;
7566 if (GST_VIDEO_INFO_IS_YUV (out_info)) {
7567 if (i == 3)
7568 convert->ffill[i] = convert->alpha_value;
7569 if (i == 0)
7570 convert->ffill[i] = 0x00;
7571 else
7572 convert->ffill[i] = 0x80;
7573 } else {
7574 if (i == 3)
7575 convert->ffill[i] = convert->alpha_value;
7576 else
7577 convert->ffill[i] = 0x00;
7578 }
7579 GST_DEBUG ("plane %d fill %02x", i, convert->ffill[i]);
7580 continue;
7581 } else {
7582 convert->fsplane[i] = GST_VIDEO_FORMAT_INFO_PLANE (in_finfo, comp);
7583 GST_DEBUG ("plane %d -> %d (comp %d)", i, convert->fsplane[i], comp);
7584 }
7585
7586 config = gst_structure_copy (convert->config);
7587
7588 resample_method = (i == 0 ? method : cr_method);
7589
7590 need_v_scaler = FALSE;
7591 need_h_scaler = FALSE;
7592 if (iw == ow) {
7593 if (!interlaced && ih == oh) {
7594 convert->fconvert[i] = convert_plane_hv;
7595 GST_DEBUG ("plane %d: copy", i);
7596 } else if (!interlaced && ih == 2 * oh && pstride == 1
7597 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
7598 convert->fconvert[i] = convert_plane_v_halve;
7599 GST_DEBUG ("plane %d: vertical halve", i);
7600 } else if (!interlaced && 2 * ih == oh && pstride == 1
7601 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
7602 convert->fconvert[i] = convert_plane_v_double;
7603 GST_DEBUG ("plane %d: vertical double", i);
7604 } else {
7605 convert->fconvert[i] = convert_plane_hv;
7606 GST_DEBUG ("plane %d: vertical scale", i);
7607 need_v_scaler = TRUE;
7608 }
7609 } else if (ih == oh) {
7610 if (!interlaced && iw == 2 * ow && pstride == 1
7611 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
7612 convert->fconvert[i] = convert_plane_h_halve;
7613 GST_DEBUG ("plane %d: horizontal halve", i);
7614 } else if (!interlaced && 2 * iw == ow && pstride == 1
7615 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
7616 convert->fconvert[i] = convert_plane_h_double;
7617 GST_DEBUG ("plane %d: horizontal double", i);
7618 } else {
7619 convert->fconvert[i] = convert_plane_hv;
7620 GST_DEBUG ("plane %d: horizontal scale", i);
7621 need_h_scaler = TRUE;
7622 }
7623 } else {
7624 if (!interlaced && iw == 2 * ow && ih == 2 * oh && pstride == 1
7625 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
7626 convert->fconvert[i] = convert_plane_hv_halve;
7627 GST_DEBUG ("plane %d: horizontal/vertical halve", i);
7628 } else if (!interlaced && 2 * iw == ow && 2 * ih == oh && pstride == 1
7629 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
7630 convert->fconvert[i] = convert_plane_hv_double;
7631 GST_DEBUG ("plane %d: horizontal/vertical double", i);
7632 } else {
7633 convert->fconvert[i] = convert_plane_hv;
7634 GST_DEBUG ("plane %d: horizontal/vertical scale", i);
7635 need_v_scaler = TRUE;
7636 need_h_scaler = TRUE;
7637 }
7638 }
7639
7640 if (need_h_scaler && iw != 0 && ow != 0) {
7641 convert->fh_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
7642
7643 for (j = 0; j < n_threads; j++) {
7644 convert->fh_scaler[i].scaler[j] =
7645 gst_video_scaler_new (resample_method, GST_VIDEO_SCALER_FLAG_NONE,
7646 taps, iw, ow, config);
7647 }
7648 } else {
7649 convert->fh_scaler[i].scaler = NULL;
7650 }
7651
7652 if (need_v_scaler && ih != 0 && oh != 0) {
7653 convert->fv_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
7654
7655 for (j = 0; j < n_threads; j++) {
7656 convert->fv_scaler[i].scaler[j] =
7657 gst_video_scaler_new (resample_method,
7658 interlaced ?
7659 GST_VIDEO_SCALER_FLAG_INTERLACED : GST_VIDEO_SCALER_FLAG_NONE,
7660 taps, ih, oh, config);
7661 }
7662 } else {
7663 convert->fv_scaler[i].scaler = NULL;
7664 }
7665
7666 gst_structure_free (config);
7667 convert->fformat[i] = get_scale_format (in_format, i);
7668 }
7669 }
7670
7671 return TRUE;
7672 }
7673
7674 /* Fast paths */
7675
7676 typedef struct
7677 {
7678 GstVideoFormat in_format;
7679 GstVideoFormat out_format;
7680 gboolean keeps_interlaced;
7681 gboolean needs_color_matrix;
7682 gboolean keeps_size;
7683 gboolean do_crop;
7684 gboolean do_border;
7685 gboolean alpha_copy;
7686 gboolean alpha_set;
7687 gboolean alpha_mult;
7688 gint width_align, height_align;
7689 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
7690 GstVideoFrame * dest);
7691 } VideoTransform;
7692
7693 static const VideoTransform transforms[] = {
7694 /* planar -> packed */
7695 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
7696 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
7697 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
7698 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
7699 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
7700 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
7701 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_v210, TRUE, FALSE, TRUE, FALSE,
7702 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_v210},
7703
7704 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
7705 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
7706 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
7707 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
7708 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
7709 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
7710 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_v210, TRUE, FALSE, TRUE, FALSE,
7711 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_v210},
7712
7713 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
7714 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_YUY2},
7715 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
7716 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_UYVY},
7717 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
7718 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_Y42B_AYUV},
7719 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_v210, TRUE, FALSE, TRUE, TRUE,
7720 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_v210},
7721
7722 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
7723 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_YUY2},
7724 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
7725 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_UYVY},
7726 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
7727 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_Y444_AYUV},
7728
7729 /* packed -> packed */
7730 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, FALSE, TRUE,
7731 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7732 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
7733 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2}, /* alias */
7734 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
7735 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_YUY2_AYUV},
7736 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_v210, TRUE, FALSE, TRUE, FALSE,
7737 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_v210},
7738
7739 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, FALSE, TRUE,
7740 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7741 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
7742 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2},
7743 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
7744 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_UYVY_AYUV},
7745 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_v210, TRUE, FALSE, TRUE, FALSE,
7746 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_v210},
7747
7748 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, FALSE, TRUE, TRUE,
7749 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7750 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
7751 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_YUY2},
7752 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
7753 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_UYVY},
7754
7755 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
7756 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_v210_UYVY},
7757 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
7758 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_v210_YUY2},
7759
7760 /* packed -> planar */
7761 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
7762 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
7763 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
7764 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
7765 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
7766 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y42B},
7767 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
7768 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y444},
7769 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_GRAY8, TRUE, TRUE, TRUE, TRUE,
7770 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_GRAY8},
7771
7772 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
7773 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
7774 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
7775 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
7776 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
7777 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y42B},
7778 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
7779 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y444},
7780
7781 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_I420, FALSE, FALSE, TRUE, TRUE,
7782 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
7783 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, TRUE, TRUE,
7784 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
7785 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
7786 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_Y42B},
7787 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
7788 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_AYUV_Y444},
7789
7790 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
7791 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_v210_I420},
7792 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
7793 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_v210_I420},
7794 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, FALSE,
7795 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_v210_Y42B},
7796
7797 /* planar -> planar */
7798 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_I420, TRUE, FALSE, FALSE, TRUE,
7799 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7800 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, FALSE, TRUE,
7801 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7802 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7803 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7804 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7805 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7806 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7807 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7808 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7809 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7810 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7811 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7812 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7813 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7814 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7815 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7816
7817 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_I420, TRUE, FALSE, FALSE, TRUE,
7818 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7819 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, FALSE, TRUE,
7820 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7821 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7822 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7823 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7824 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7825 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7826 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7827 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7828 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7829 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7830 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7831 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7832 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7833 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7834 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7835
7836 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7837 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7838 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7839 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7840 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y41B, TRUE, FALSE, FALSE, TRUE,
7841 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7842 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7843 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7844 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7845 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7846 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7847 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7848 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7849 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7850 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7851 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7852 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7853 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7854
7855 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7856 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7857 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7858 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7859 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7860 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7861 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, FALSE, TRUE,
7862 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7863 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7864 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7865 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7866 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7867 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7868 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7869 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7870 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7871 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7872 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7873
7874 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7875 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7876 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7877 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7878 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7879 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7880 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7881 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7882 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, FALSE, TRUE,
7883 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7884 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7885 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7886 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7887 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7888 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7889 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7890 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7891 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7892
7893 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7894 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7895 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7896 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7897 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7898 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7899 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7900 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7901 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7902 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7903 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_GRAY8, TRUE, FALSE, FALSE, TRUE,
7904 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7905 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7906 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7907 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7908 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7909 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7910 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7911
7912 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7913 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7914 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7915 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7916 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7917 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7918 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7919 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7920 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7921 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7922 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7923 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7924 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_A420, TRUE, FALSE, FALSE, TRUE,
7925 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7926 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7927 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7928 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7929 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7930
7931 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7932 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7933 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7934 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7935 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7936 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7937 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7938 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7939 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7940 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7941 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7942 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7943 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7944 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7945 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YUV9, TRUE, FALSE, FALSE, TRUE,
7946 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7947 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YVU9, TRUE, FALSE, FALSE, TRUE,
7948 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7949
7950 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7951 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7952 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7953 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7954 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7955 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7956 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7957 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7958 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7959 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7960 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7961 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7962 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7963 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7964 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YUV9, TRUE, FALSE, FALSE, TRUE,
7965 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7966 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YVU9, TRUE, FALSE, FALSE, TRUE,
7967 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7968
7969 /* sempiplanar -> semiplanar */
7970 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
7971 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7972 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
7973 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7974 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
7975 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7976
7977 {GST_VIDEO_FORMAT_NV21, GST_VIDEO_FORMAT_NV21, TRUE, FALSE, FALSE, TRUE,
7978 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7979
7980 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
7981 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7982 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
7983 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7984 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
7985 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7986
7987 {GST_VIDEO_FORMAT_NV61, GST_VIDEO_FORMAT_NV61, TRUE, FALSE, FALSE, TRUE,
7988 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7989
7990 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
7991 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7992 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
7993 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7994 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
7995 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7996
7997 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
7998 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ARGB, TRUE, TRUE, TRUE, TRUE, TRUE,
7999 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB},
8000 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRA, TRUE, TRUE, TRUE, TRUE, TRUE,
8001 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA},
8002 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xRGB, TRUE, TRUE, TRUE, TRUE, TRUE,
8003 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB}, /* alias */
8004 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRx, TRUE, TRUE, TRUE, TRUE, TRUE,
8005 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA}, /* alias */
8006 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ABGR, TRUE, TRUE, TRUE, TRUE, TRUE,
8007 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR},
8008 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBA, TRUE, TRUE, TRUE, TRUE, TRUE,
8009 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA},
8010 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xBGR, TRUE, TRUE, TRUE, TRUE, TRUE,
8011 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR}, /* alias */
8012 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBx, TRUE, TRUE, TRUE, TRUE, TRUE,
8013 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA}, /* alias */
8014 #endif
8015
8016 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
8017 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
8018 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
8019 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
8020 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
8021 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
8022 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
8023 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
8024
8025 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
8026 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
8027 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
8028 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
8029 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
8030 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
8031 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
8032 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
8033
8034 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
8035 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8036 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
8037 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8038 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
8039 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8040 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
8041 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8042 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
8043 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8044 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
8045 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8046 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
8047 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8048 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
8049 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8050 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
8051 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8052 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
8053 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8054
8055 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
8056 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8057 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
8058 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8059 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
8060 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8061 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
8062 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8063 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
8064 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8065 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
8066 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8067 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
8068 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8069 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
8070 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8071 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
8072 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8073 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
8074 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8075
8076 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
8077 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_A420_pack_ARGB},
8078 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
8079 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_A420_pack_ARGB},
8080 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
8081 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_A420_BGRA},
8082 /* A420 to non-alpha RGB formats, reuse I420_* method */
8083 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
8084 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
8085 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
8086 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8087 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
8088 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8089 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
8090 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8091 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
8092 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8093 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
8094 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8095 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
8096 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
8097
8098 /* scalers */
8099 {GST_VIDEO_FORMAT_GBR, GST_VIDEO_FORMAT_GBR, TRUE, FALSE, FALSE, TRUE,
8100 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8101 {GST_VIDEO_FORMAT_GBRA, GST_VIDEO_FORMAT_GBRA, TRUE, FALSE, FALSE, TRUE,
8102 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
8103 {GST_VIDEO_FORMAT_RGBP, GST_VIDEO_FORMAT_RGBP, TRUE, FALSE, FALSE, TRUE,
8104 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8105 {GST_VIDEO_FORMAT_BGRP, GST_VIDEO_FORMAT_BGRP, TRUE, FALSE, FALSE, TRUE,
8106 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8107
8108 {GST_VIDEO_FORMAT_YVYU, GST_VIDEO_FORMAT_YVYU, TRUE, FALSE, FALSE, TRUE,
8109 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8110
8111 {GST_VIDEO_FORMAT_RGB15, GST_VIDEO_FORMAT_RGB15, TRUE, FALSE, FALSE, TRUE,
8112 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8113 {GST_VIDEO_FORMAT_RGB16, GST_VIDEO_FORMAT_RGB16, TRUE, FALSE, FALSE, TRUE,
8114 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8115 {GST_VIDEO_FORMAT_BGR15, GST_VIDEO_FORMAT_BGR15, TRUE, FALSE, FALSE, TRUE,
8116 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8117 {GST_VIDEO_FORMAT_BGR16, GST_VIDEO_FORMAT_BGR16, TRUE, FALSE, FALSE, TRUE,
8118 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8119
8120 {GST_VIDEO_FORMAT_RGB, GST_VIDEO_FORMAT_RGB, TRUE, FALSE, FALSE, TRUE, TRUE,
8121 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8122 {GST_VIDEO_FORMAT_BGR, GST_VIDEO_FORMAT_BGR, TRUE, FALSE, FALSE, TRUE, TRUE,
8123 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8124 {GST_VIDEO_FORMAT_v308, GST_VIDEO_FORMAT_v308, TRUE, FALSE, FALSE, TRUE, TRUE,
8125 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8126 {GST_VIDEO_FORMAT_IYU2, GST_VIDEO_FORMAT_IYU2, TRUE, FALSE, FALSE, TRUE, TRUE,
8127 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8128
8129 {GST_VIDEO_FORMAT_ARGB, GST_VIDEO_FORMAT_ARGB, TRUE, FALSE, FALSE, TRUE, TRUE,
8130 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
8131 {GST_VIDEO_FORMAT_xRGB, GST_VIDEO_FORMAT_xRGB, TRUE, FALSE, FALSE, TRUE, TRUE,
8132 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8133 {GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_ABGR, TRUE, FALSE, FALSE, TRUE, TRUE,
8134 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
8135 {GST_VIDEO_FORMAT_xBGR, GST_VIDEO_FORMAT_xBGR, TRUE, FALSE, FALSE, TRUE, TRUE,
8136 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8137 {GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_RGBA, TRUE, FALSE, FALSE, TRUE, TRUE,
8138 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
8139 {GST_VIDEO_FORMAT_RGBx, GST_VIDEO_FORMAT_RGBx, TRUE, FALSE, FALSE, TRUE, TRUE,
8140 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8141 {GST_VIDEO_FORMAT_BGRA, GST_VIDEO_FORMAT_BGRA, TRUE, FALSE, FALSE, TRUE, TRUE,
8142 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
8143 {GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_BGRx, TRUE, FALSE, FALSE, TRUE, TRUE,
8144 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8145
8146 {GST_VIDEO_FORMAT_ARGB64, GST_VIDEO_FORMAT_ARGB64, TRUE, FALSE, FALSE, TRUE,
8147 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
8148 {GST_VIDEO_FORMAT_AYUV64, GST_VIDEO_FORMAT_AYUV64, TRUE, FALSE, FALSE, TRUE,
8149 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
8150
8151 {GST_VIDEO_FORMAT_GRAY16_LE, GST_VIDEO_FORMAT_GRAY16_LE, TRUE, FALSE, FALSE,
8152 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8153 {GST_VIDEO_FORMAT_GRAY16_BE, GST_VIDEO_FORMAT_GRAY16_BE, TRUE, FALSE, FALSE,
8154 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
8155 };
8156
8157 static gboolean
video_converter_lookup_fastpath(GstVideoConverter * convert)8158 video_converter_lookup_fastpath (GstVideoConverter * convert)
8159 {
8160 int i;
8161 GstVideoFormat in_format, out_format;
8162 GstVideoTransferFunction in_transf, out_transf;
8163 gboolean interlaced, same_matrix, same_primaries, same_size, crop, border;
8164 gboolean need_copy, need_set, need_mult;
8165 gint width, height;
8166 guint in_bpp, out_bpp;
8167
8168 width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
8169 height = GST_VIDEO_INFO_FIELD_HEIGHT (&convert->in_info);
8170
8171 if (GET_OPT_DITHER_QUANTIZATION (convert) != 1)
8172 return FALSE;
8173
8174 in_bpp = convert->in_info.finfo->bits;
8175 out_bpp = convert->out_info.finfo->bits;
8176
8177 /* we don't do gamma conversion in fastpath */
8178 in_transf = convert->in_info.colorimetry.transfer;
8179 out_transf = convert->out_info.colorimetry.transfer;
8180
8181 same_size = (width == convert->out_width && height == convert->out_height);
8182
8183 /* fastpaths don't do gamma */
8184 if (CHECK_GAMMA_REMAP (convert) && (!same_size
8185 || !gst_video_transfer_function_is_equivalent (in_transf, in_bpp,
8186 out_transf, out_bpp)))
8187 return FALSE;
8188
8189 need_copy = (convert->alpha_mode & ALPHA_MODE_COPY) == ALPHA_MODE_COPY;
8190 need_set = (convert->alpha_mode & ALPHA_MODE_SET) == ALPHA_MODE_SET;
8191 need_mult = (convert->alpha_mode & ALPHA_MODE_MULT) == ALPHA_MODE_MULT;
8192 GST_DEBUG ("alpha copy %d, set %d, mult %d", need_copy, need_set, need_mult);
8193
8194 in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
8195 out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
8196
8197 if (CHECK_MATRIX_NONE (convert)) {
8198 same_matrix = TRUE;
8199 } else {
8200 GstVideoColorMatrix in_matrix, out_matrix;
8201
8202 in_matrix = convert->in_info.colorimetry.matrix;
8203 out_matrix = convert->out_info.colorimetry.matrix;
8204 same_matrix = in_matrix == out_matrix;
8205 }
8206
8207 if (CHECK_PRIMARIES_NONE (convert)) {
8208 same_primaries = TRUE;
8209 } else {
8210 GstVideoColorPrimaries in_primaries, out_primaries;
8211
8212 in_primaries = convert->in_info.colorimetry.primaries;
8213 out_primaries = convert->out_info.colorimetry.primaries;
8214 same_primaries = in_primaries == out_primaries;
8215 }
8216
8217 interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info);
8218 interlaced |= GST_VIDEO_INFO_IS_INTERLACED (&convert->out_info);
8219
8220 crop = convert->in_x || convert->in_y
8221 || convert->in_width < convert->in_maxwidth
8222 || convert->in_height < convert->in_maxheight;
8223 border = convert->out_x || convert->out_y
8224 || convert->out_width < convert->out_maxwidth
8225 || convert->out_height < convert->out_maxheight;
8226
8227 for (i = 0; i < G_N_ELEMENTS (transforms); i++) {
8228 if (transforms[i].in_format == in_format &&
8229 transforms[i].out_format == out_format &&
8230 (transforms[i].keeps_interlaced || !interlaced) &&
8231 (transforms[i].needs_color_matrix || (same_matrix && same_primaries))
8232 && (!transforms[i].keeps_size || same_size)
8233 && (transforms[i].width_align & width) == 0
8234 && (transforms[i].height_align & height) == 0
8235 && (transforms[i].do_crop || !crop)
8236 && (transforms[i].do_border || !border)
8237 && (transforms[i].alpha_copy || !need_copy)
8238 && (transforms[i].alpha_set || !need_set)
8239 && (transforms[i].alpha_mult || !need_mult)) {
8240 guint j;
8241
8242 GST_DEBUG ("using fastpath");
8243 if (transforms[i].needs_color_matrix)
8244 video_converter_compute_matrix (convert);
8245 convert->convert = transforms[i].convert;
8246
8247 convert->tmpline =
8248 g_new (guint16 *, convert->conversion_runner->n_threads);
8249 for (j = 0; j < convert->conversion_runner->n_threads; j++)
8250 convert->tmpline[j] = g_malloc0 (sizeof (guint16) * (width + 8) * 4);
8251
8252 if (!transforms[i].keeps_size)
8253 if (!setup_scale (convert))
8254 return FALSE;
8255 if (border)
8256 setup_borderline (convert);
8257 return TRUE;
8258 }
8259 }
8260 GST_DEBUG ("no fastpath found");
8261 return FALSE;
8262 }
8263