2 * Copyright (C) 2010 David Schleef <ds@schleef.org>
3 * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
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.
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.
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.
32 #include "video-converter.h"
37 #include <gst/base/base.h>
39 #include "video-orc.h"
42 * SECTION:videoconverter
43 * @title: GstVideoConverter
44 * @short_description: Generic video conversion
46 * This object is used to convert video frames from one format to another.
47 * The object can perform conversion of:
59 * (c) (convert Y'CbCr to R'G'B')
62 * (f) colorspace convert through XYZ
65 * (i) (convert R'G'B' to Y'CbCr)
66 * (j) chroma downsample
71 * (a) range truncate, range expand
72 * (b) full upsample, 1-1 non-cosited upsample, no upsample
80 * (j) 1-1 cosited downsample, no downsample
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
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
97 #ifndef GST_DISABLE_GST_DEBUG
98 #define GST_CAT_DEFAULT ensure_debug_category()
99 static GstDebugCategory *
100 ensure_debug_category (void)
102 static gsize cat_gonce = 0;
104 if (g_once_init_enter (&cat_gonce)) {
107 cat_done = (gsize) _gst_debug_category_new ("video-converter", 0,
108 "video-converter object");
110 g_once_init_leave (&cat_gonce, cat_done);
113 return (GstDebugCategory *) cat_gonce;
116 #define ensure_debug_category() /* NOOP */
117 #endif /* GST_DISABLE_GST_DEBUG */
119 typedef void (*GstParallelizedTaskFunc) (gpointer user_data);
121 typedef struct _GstParallelizedTaskRunner GstParallelizedTaskRunner;
122 typedef struct _GstParallelizedWorkItem GstParallelizedWorkItem;
124 struct _GstParallelizedWorkItem
126 GstParallelizedTaskRunner *self;
127 GstParallelizedTaskFunc func;
131 struct _GstParallelizedTaskRunner
137 GstQueueArray *tasks;
138 GstQueueArray *work_items;
142 gboolean async_tasks;
146 gst_parallelized_task_thread_func (gpointer data)
148 GstParallelizedTaskRunner *runner = data;
149 GstParallelizedWorkItem *work_item;
151 g_mutex_lock (&runner->lock);
152 work_item = gst_queue_array_pop_head (runner->work_items);
153 g_mutex_unlock (&runner->lock);
155 g_assert (work_item != NULL);
156 g_assert (work_item->func != NULL);
159 work_item->func (work_item->user_data);
160 if (runner->async_tasks)
165 gst_parallelized_task_runner_join (GstParallelizedTaskRunner * self)
167 gboolean joined = FALSE;
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);
176 g_mutex_unlock (&self->lock);
182 gst_parallelized_task_runner_free (GstParallelizedTaskRunner * self)
184 gst_parallelized_task_runner_join (self);
186 gst_queue_array_free (self->work_items);
187 gst_queue_array_free (self->tasks);
189 gst_task_pool_cleanup (self->pool);
190 gst_object_unref (self->pool);
191 g_mutex_clear (&self->lock);
195 static GstParallelizedTaskRunner *
196 gst_parallelized_task_runner_new (guint n_threads, GstTaskPool * pool,
197 gboolean async_tasks)
199 GstParallelizedTaskRunner *self;
202 n_threads = g_get_num_processors ();
204 self = g_new0 (GstParallelizedTaskRunner, 1);
207 self->pool = g_object_ref (pool);
208 self->own_pool = FALSE;
210 /* No reason to split up the work between more threads than the
212 if (GST_IS_SHARED_TASK_POOL (pool))
215 gst_shared_task_pool_get_max_threads (GST_SHARED_TASK_POOL (pool)));
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),
221 gst_task_pool_prepare (self->pool, NULL);
224 self->tasks = gst_queue_array_new (n_threads);
225 self->work_items = gst_queue_array_new (n_threads);
227 self->n_threads = n_threads;
229 g_mutex_init (&self->lock);
231 /* Set when scheduling a job */
232 self->async_tasks = async_tasks;
238 gst_parallelized_task_runner_finish (GstParallelizedTaskRunner * self)
240 gst_parallelized_task_runner_join (self);
244 gst_parallelized_task_runner_run (GstParallelizedTaskRunner * self,
245 GstParallelizedTaskFunc func, gpointer * task_data)
247 guint n_threads = self->n_threads;
249 if (n_threads > 1 || self->async_tasks) {
251 g_mutex_lock (&self->lock);
252 if (!self->async_tasks) {
253 /* if not async, perform one of the functions in the current thread */
256 for (; i < n_threads; i++) {
258 GstParallelizedWorkItem *work_item;
260 if (!self->async_tasks)
261 work_item = g_newa (GstParallelizedWorkItem, 1);
263 work_item = g_new0 (GstParallelizedWorkItem, 1);
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);
271 gst_task_pool_push (self->pool, gst_parallelized_task_thread_func,
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);
278 g_mutex_unlock (&self->lock);
281 if (!self->async_tasks) {
284 gst_parallelized_task_runner_finish (self);
288 typedef struct _GstLineCache GstLineCache;
291 #define SCALE_F ((float) (1 << SCALE))
293 typedef struct _MatrixData MatrixData;
308 void (*matrix_func) (MatrixData * data, gpointer pixels);
311 typedef struct _GammaData GammaData;
315 gpointer gamma_table;
317 void (*gamma_func) (GammaData * data, gpointer dest, gpointer src);
323 ALPHA_MODE_COPY = (1 << 0),
324 ALPHA_MODE_SET = (1 << 1),
325 ALPHA_MODE_MULT = (1 << 2)
335 GDestroyNotify notify;
338 typedef void (*FastConvertFunc) (GstVideoConverter * convert,
339 const GstVideoFrame * src, GstVideoFrame * dest, gint plane);
341 struct _GstVideoConverter
345 GstVideoInfo in_info;
346 GstVideoInfo out_info;
361 gint current_pstride;
364 GstVideoFormat current_format;
367 GstStructure *config;
369 GstParallelizedTaskRunner *conversion_runner;
373 gboolean fill_border;
378 AlphaMode alpha_mode;
380 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
381 GstVideoFrame * dest);
383 /* data for unpack */
384 GstLineCache **unpack_lines;
385 GstVideoFormat unpack_format;
388 gboolean identity_unpack;
391 /* chroma upsample */
392 GstLineCache **upsample_lines;
393 GstVideoChromaResample **upsample;
394 GstVideoChromaResample **upsample_p;
395 GstVideoChromaResample **upsample_i;
400 GstLineCache **to_RGB_lines;
401 MatrixData to_RGB_matrix;
406 GstLineCache **hscale_lines;
407 GstVideoScaler **h_scaler;
409 GstLineCache **vscale_lines;
410 GstVideoScaler **v_scaler;
411 GstVideoScaler **v_scaler_p;
412 GstVideoScaler **v_scaler_i;
416 /* color space conversion */
417 GstLineCache **convert_lines;
418 MatrixData convert_matrix;
422 /* alpha correction */
423 GstLineCache **alpha_lines;
424 void (*alpha_func) (GstVideoConverter * convert, gpointer pixels, gint width);
429 GstLineCache **to_YUV_lines;
430 MatrixData to_YUV_matrix;
432 /* chroma downsample */
433 GstLineCache **downsample_lines;
434 GstVideoChromaResample **downsample;
435 GstVideoChromaResample **downsample_p;
436 GstVideoChromaResample **downsample_i;
441 GstLineCache **dither_lines;
442 GstVideoDither **dither;
445 GstLineCache **pack_lines;
447 GstVideoFormat pack_format;
450 gboolean identity_pack;
452 gconstpointer pack_pal;
455 const GstVideoFrame *src;
459 GstVideoFormat fformat[4];
471 GstVideoScaler **scaler;
475 GstVideoScaler **scaler;
477 FastConvertFunc fconvert[4];
479 /* for parallel async running */
484 typedef gpointer (*GstLineCacheAllocLineFunc) (GstLineCache * cache, gint idx,
486 typedef gboolean (*GstLineCacheNeedLineFunc) (GstLineCache * cache, gint idx,
487 gint out_line, gint in_line, gpointer user_data);
496 gboolean write_input;
498 gboolean alloc_writable;
500 GstLineCacheNeedLineFunc need_line;
502 gpointer need_line_data;
503 GDestroyNotify need_line_notify;
507 GstLineCacheAllocLineFunc alloc_line;
508 gpointer alloc_line_data;
509 GDestroyNotify alloc_line_notify;
512 static GstLineCache *
513 gst_line_cache_new (GstLineCache * prev)
515 GstLineCache *result;
517 result = g_slice_new0 (GstLineCache);
518 result->lines = g_ptr_array_new ();
525 gst_line_cache_clear (GstLineCache * cache)
527 g_return_if_fail (cache != NULL);
529 g_ptr_array_set_size (cache->lines, 0);
534 gst_line_cache_free (GstLineCache * cache)
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);
546 gst_line_cache_set_need_line_func (GstLineCache * cache,
547 GstLineCacheNeedLineFunc need_line, gint idx, gpointer user_data,
548 GDestroyNotify notify)
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;
557 gst_line_cache_set_alloc_line_func (GstLineCache * cache,
558 GstLineCacheAllocLineFunc alloc_line, gpointer user_data,
559 GDestroyNotify notify)
561 cache->alloc_line = alloc_line;
562 cache->alloc_line_data = user_data;
563 cache->alloc_line_notify = notify;
566 /* keep this much backlog for interlaced video */
570 gst_line_cache_get_lines (GstLineCache * cache, gint idx, gint out_line,
571 gint in_line, gint n_lines)
573 if (cache->first + cache->backlog < in_line) {
575 MIN (in_line - (cache->first + cache->backlog), cache->lines->len);
577 g_ptr_array_remove_range (cache->lines, 0, to_remove);
579 cache->first += to_remove;
580 } else if (in_line < cache->first) {
581 gst_line_cache_clear (cache);
582 cache->first = in_line;
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);
593 if (cache->need_line == NULL)
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;
600 oline = out_line + cache->first + cache->lines->len - in_line;
602 if (!cache->need_line (cache, idx, oline, cache->first + cache->lines->len,
603 cache->need_line_data))
606 GST_DEBUG ("no lines");
611 gst_line_cache_add_line (GstLineCache * cache, gint idx, gpointer line)
613 if (cache->first + cache->lines->len != idx) {
614 gst_line_cache_clear (cache);
617 g_ptr_array_add (cache->lines, line);
621 gst_line_cache_alloc_line (GstLineCache * cache, gint idx)
625 if (cache->alloc_line)
626 res = cache->alloc_line (cache, idx, cache->alloc_line_data);
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,
640 static gpointer get_dest_line (GstLineCache * cache, gint idx,
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);
664 static ConverterAlloc *
665 converter_alloc_new (guint stride, guint n_lines, gpointer user_data,
666 GDestroyNotify notify)
668 ConverterAlloc *alloc;
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;
676 alloc->user_data = user_data;
677 alloc->notify = notify;
683 converter_alloc_free (ConverterAlloc * alloc)
686 alloc->notify (alloc->user_data);
687 g_free (alloc->data);
688 g_slice_free (ConverterAlloc, alloc);
692 setup_border_alloc (GstVideoConverter * convert, ConverterAlloc * alloc)
696 if (convert->borderline) {
697 for (i = 0; i < alloc->n_lines; i++)
698 memcpy (&alloc->data[i * alloc->stride], convert->borderline,
704 get_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
706 ConverterAlloc *alloc = user_data;
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;
717 get_border_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
719 ConverterAlloc *alloc = user_data;
720 GstVideoConverter *convert = alloc->user_data;
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;
732 get_opt_int (GstVideoConverter * convert, const gchar * opt, gint def)
735 if (!gst_structure_get_int (convert->config, opt, &res))
741 get_opt_uint (GstVideoConverter * convert, const gchar * opt, guint def)
744 if (!gst_structure_get_uint (convert->config, opt, &res))
750 get_opt_double (GstVideoConverter * convert, const gchar * opt, gdouble def)
753 if (!gst_structure_get_double (convert->config, opt, &res))
759 get_opt_bool (GstVideoConverter * convert, const gchar * opt, gboolean def)
762 if (!gst_structure_get_boolean (convert->config, opt, &res))
768 get_opt_enum (GstVideoConverter * convert, const gchar * opt, GType type,
772 if (!gst_structure_get_enum (convert->config, opt, type, &res))
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
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
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)
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)
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)
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)
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)
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)
850 static GstLineCache *
851 chain_unpack_line (GstVideoConverter * convert, gint idx)
856 info = &convert->in_info;
858 convert->current_format = convert->unpack_format;
859 convert->current_bits = convert->unpack_bits;
860 convert->current_pstride = convert->current_bits >> 1;
862 convert->unpack_pstride = convert->current_pstride;
863 convert->identity_unpack = (convert->current_format == info->finfo->format);
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);
869 prev = convert->unpack_lines[idx] = gst_line_cache_new (NULL);
870 prev->write_input = FALSE;
871 prev->pass_alloc = FALSE;
873 prev->stride = convert->current_pstride * convert->current_width;
874 gst_line_cache_set_need_line_func (prev, do_unpack_lines, idx, convert, NULL);
879 static GstLineCache *
880 chain_upsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
882 video_converter_compute_resample (convert, idx);
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? */
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);
899 color_matrix_set_identity (MatrixData * m)
903 for (i = 0; i < 4; i++) {
904 for (j = 0; j < 4; j++) {
905 m->dm[i][j] = (i == j);
911 color_matrix_copy (MatrixData * d, const MatrixData * s)
915 for (i = 0; i < 4; i++)
916 for (j = 0; j < 4; j++)
917 d->dm[i][j] = s->dm[i][j];
920 /* Perform 4x4 matrix multiplication:
921 * - @dst@ = @a@ * @b@
922 * - @dst@ may be a pointer to @a@ andor @b@
925 color_matrix_multiply (MatrixData * dst, MatrixData * a, MatrixData * b)
930 for (i = 0; i < 4; i++) {
931 for (j = 0; j < 4; j++) {
933 for (k = 0; k < 4; k++) {
934 x += a->dm[i][k] * b->dm[k][j];
939 color_matrix_copy (dst, &tmp);
943 color_matrix_invert (MatrixData * d, MatrixData * s)
949 color_matrix_set_identity (&tmp);
950 for (j = 0; j < 3; j++) {
951 for (i = 0; i < 3; 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];
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++) {
965 color_matrix_copy (d, &tmp);
969 color_matrix_offset_components (MatrixData * m, double a1, double a2, double a3)
973 color_matrix_set_identity (&a);
977 color_matrix_multiply (m, &a, m);
981 color_matrix_scale_components (MatrixData * m, double a1, double a2, double a3)
985 color_matrix_set_identity (&a);
989 color_matrix_multiply (m, &a, m);
993 color_matrix_debug (const MatrixData * s)
995 GST_DEBUG ("[%f %f %f %f]", s->dm[0][0], s->dm[0][1], s->dm[0][2],
997 GST_DEBUG ("[%f %f %f %f]", s->dm[1][0], s->dm[1][1], s->dm[1][2],
999 GST_DEBUG ("[%f %f %f %f]", s->dm[2][0], s->dm[2][1], s->dm[2][2],
1001 GST_DEBUG ("[%f %f %f %f]", s->dm[3][0], s->dm[3][1], s->dm[3][2],
1006 color_matrix_convert (MatrixData * s)
1010 for (i = 0; i < 4; i++)
1011 for (j = 0; j < 4; j++)
1012 s->im[i][j] = rint (s->dm[i][j]);
1014 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[0][0], s->im[0][1], s->im[0][2],
1016 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[1][0], s->im[1][1], s->im[1][2],
1018 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[2][0], s->im[2][1], s->im[2][2],
1020 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[3][0], s->im[3][1], s->im[3][2],
1025 color_matrix_YCbCr_to_RGB (MatrixData * m, double Kr, double Kb)
1027 double Kg = 1.0 - Kr - Kb;
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.},
1037 color_matrix_multiply (m, &k, m);
1041 color_matrix_RGB_to_YCbCr (MatrixData * m, double Kr, double Kb)
1043 double Kg = 1.0 - Kr - Kb;
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);
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;
1069 color_matrix_multiply (m, &k, m);
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)
1080 color_matrix_set_identity (&m);
1084 m.dm[2][0] = (1.0 - Rx - Ry);
1087 m.dm[2][1] = (1.0 - Gx - Gy);
1090 m.dm[2][2] = (1.0 - Bx - By);
1092 color_matrix_invert (&im, &m);
1096 wz = (1.0 - Wx - Wy) / Wy;
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;
1112 color_matrix_copy (dst, &m);
1116 videoconvert_convert_init_tables (MatrixData * data)
1120 data->t_r = g_new (gint64, 256);
1121 data->t_g = g_new (gint64, 256);
1122 data->t_b = g_new (gint64, 256);
1124 for (i = 0; i < 256; i++) {
1125 gint64 r = 0, g = 0, b = 0;
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;
1136 data->t_c = ((gint64) data->im[0][3] << 32)
1137 + ((gint64) data->im[1][3] << 16)
1138 + ((gint64) data->im[2][3] << 0);
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)
1149 gint a00, a01, a02, a03;
1150 gint a10, a11, a12, a13;
1151 gint a20, a21, a22, a23;
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);
1166 for (i = 0; i < n; i++) {
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;
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);
1182 video_converter_matrix8 (MatrixData * data, gpointer pixels)
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);
1190 video_converter_matrix8_table (MatrixData * data, gpointer pixels)
1192 gint i, width = data->width * 4;
1194 gint64 c = data->t_c;
1198 for (i = 0; i < width; i += 4) {
1203 x = data->t_r[r] + data->t_g[g] + data->t_b[b] + c;
1205 p[i + 1] = x >> (32 + SCALE);
1206 p[i + 2] = x >> (16 + SCALE);
1207 p[i + 3] = x >> (0 + SCALE);
1212 video_converter_matrix8_AYUV_ARGB (MatrixData * data, gpointer pixels)
1214 gpointer d = pixels;
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);
1222 is_ayuv_to_rgb_matrix (MatrixData * data)
1224 if (data->im[0][0] != data->im[1][0] || data->im[1][0] != data->im[2][0])
1227 if (data->im[0][1] != 0 || data->im[2][2] != 0)
1234 is_identity_matrix (MatrixData * data)
1237 gint c = data->im[0][0];
1239 /* not really checking identity because of rounding errors but given
1240 * the conversions we do we just check for anything that looks like:
1247 for (i = 0; i < 4; i++) {
1248 for (j = 0; j < 4; j++) {
1250 if (i == 3 && data->im[i][j] != 1)
1252 else if (data->im[i][j] != c)
1254 } else if (data->im[i][j] != 0)
1262 is_no_clip_matrix (MatrixData * data)
1265 static const guint8 test[8][3] = {
1276 for (i = 0; i < 8; i++) {
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;
1291 if (y != CLAMP (y, 0, 255) || u != CLAMP (u, 0, 255)
1292 || v != CLAMP (v, 0, 255))
1299 video_converter_matrix16 (MatrixData * data, gpointer pixels)
1304 guint16 *p = pixels;
1305 gint width = data->width;
1307 for (i = 0; i < width; i++) {
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;
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);
1327 prepare_matrix (GstVideoConverter * convert, MatrixData * data)
1329 if (is_identity_matrix (data))
1332 color_matrix_scale_components (data, SCALE_F, SCALE_F, SCALE_F);
1333 color_matrix_convert (data);
1335 data->width = convert->current_width;
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);
1349 GST_DEBUG ("use 8bit matrix");
1350 data->matrix_func = video_converter_matrix8;
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);
1362 a03 = data->im[0][3] >> SCALE;
1363 a13 = data->im[1][3] >> SCALE;
1364 a23 = data->im[2][3] >> SCALE;
1366 data->orc_p4 = (((guint64) (guint16) a23) << 48) |
1367 (((guint64) (guint16) a13) << 32) | (((guint64) (guint16) a03) << 16);
1370 GST_DEBUG ("use 16bit matrix");
1371 data->matrix_func = video_converter_matrix16;
1376 compute_matrix_to_RGB (GstVideoConverter * convert, MatrixData * data)
1379 gdouble Kr = 0, Kb = 0;
1381 info = &convert->in_info;
1384 const GstVideoFormatInfo *uinfo;
1385 gint offset[4], scale[4];
1387 uinfo = gst_video_format_get_info (convert->unpack_format);
1389 /* bring color components to [0..1.0] range */
1390 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
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]));
1398 if (!convert->unpack_rgb && !CHECK_MATRIX_NONE (convert)) {
1399 if (CHECK_MATRIX_OUTPUT (convert))
1400 info = &convert->out_info;
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);
1406 color_matrix_debug (data);
1410 compute_matrix_to_YUV (GstVideoConverter * convert, MatrixData * data,
1414 gdouble Kr = 0, Kb = 0;
1416 if (force || (!convert->pack_rgb && !CHECK_MATRIX_NONE (convert))) {
1417 if (CHECK_MATRIX_INPUT (convert))
1418 info = &convert->in_info;
1420 info = &convert->out_info;
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);
1427 info = &convert->out_info;
1430 const GstVideoFormatInfo *uinfo;
1431 gint offset[4], scale[4];
1433 uinfo = gst_video_format_get_info (convert->pack_format);
1435 /* bring color components to nominal range */
1436 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1439 color_matrix_scale_components (data, (float) scale[0], (float) scale[1],
1441 color_matrix_offset_components (data, offset[0], offset[1], offset[2]);
1444 color_matrix_debug (data);
1449 gamma_convert_u8_u16 (GammaData * data, gpointer dest, gpointer src)
1454 guint16 *table = data->gamma_table;
1455 gint width = data->width * 4;
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]];
1466 gamma_convert_u16_u8 (GammaData * data, gpointer dest, gpointer src)
1471 guint8 *table = data->gamma_table;
1472 gint width = data->width * 4;
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]];
1483 gamma_convert_u16_u16 (GammaData * data, gpointer dest, gpointer src)
1488 guint16 *table = data->gamma_table;
1489 gint width = data->width * 4;
1491 for (i = 0; i < width; i += 4) {
1493 d[i + 1] = table[s[i + 1]];
1494 d[i + 2] = table[s[i + 2]];
1495 d[i + 3] = table[s[i + 3]];
1500 setup_gamma_decode (GstVideoConverter * convert)
1502 GstVideoTransferFunction func;
1506 func = convert->in_info.colorimetry.transfer;
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);
1516 for (i = 0; i < 256; i++)
1518 rint (gst_video_transfer_function_decode (func, i / 255.0) * 65535.0);
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);
1524 for (i = 0; i < 65536; i++)
1526 rint (gst_video_transfer_function_decode (func,
1527 i / 65535.0) * 65535.0);
1529 convert->current_bits = 16;
1530 convert->current_pstride = 8;
1531 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1535 setup_gamma_encode (GstVideoConverter * convert, gint target_bits)
1537 GstVideoTransferFunction func;
1540 func = convert->out_info.colorimetry.transfer;
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) {
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);
1552 for (i = 0; i < 65536; i++)
1554 rint (gst_video_transfer_function_encode (func, i / 65535.0) * 255.0);
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);
1562 for (i = 0; i < 65536; i++)
1564 rint (gst_video_transfer_function_encode (func,
1565 i / 65535.0) * 65535.0);
1569 static GstLineCache *
1570 chain_convert_to_RGB (GstVideoConverter * convert, GstLineCache * prev,
1575 do_gamma = CHECK_GAMMA_REMAP (convert);
1580 if (!convert->unpack_rgb) {
1581 color_matrix_set_identity (&convert->to_RGB_matrix);
1582 compute_matrix_to_RGB (convert, &convert->to_RGB_matrix);
1584 /* matrix is in 0..1 range, scale to current bits */
1585 GST_DEBUG ("chain RGB convert");
1586 scale = 1 << convert->current_bits;
1587 color_matrix_scale_components (&convert->to_RGB_matrix,
1588 (float) scale, (float) scale, (float) scale);
1590 prepare_matrix (convert, &convert->to_RGB_matrix);
1592 if (convert->current_bits == 8)
1593 convert->current_format = GST_VIDEO_FORMAT_ARGB;
1595 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1598 prev = convert->to_RGB_lines[idx] = gst_line_cache_new (prev);
1599 prev->write_input = TRUE;
1600 prev->pass_alloc = FALSE;
1602 prev->stride = convert->current_pstride * convert->current_width;
1603 gst_line_cache_set_need_line_func (prev,
1604 do_convert_to_RGB_lines, idx, convert, NULL);
1606 GST_DEBUG ("chain gamma decode");
1607 setup_gamma_decode (convert);
1612 static GstLineCache *
1613 chain_hscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1618 method = GET_OPT_RESAMPLER_METHOD (convert);
1619 taps = GET_OPT_RESAMPLER_TAPS (convert);
1621 convert->h_scaler[idx] =
1622 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
1623 convert->in_width, convert->out_width, convert->config);
1625 gst_video_scaler_get_coeff (convert->h_scaler[idx], 0, NULL, &taps);
1627 GST_DEBUG ("chain hscale %d->%d, taps %d, method %d",
1628 convert->in_width, convert->out_width, taps, method);
1630 convert->current_width = convert->out_width;
1631 convert->h_scale_format = convert->current_format;
1633 prev = convert->hscale_lines[idx] = gst_line_cache_new (prev);
1634 prev->write_input = FALSE;
1635 prev->pass_alloc = FALSE;
1637 prev->stride = convert->current_pstride * convert->current_width;
1638 gst_line_cache_set_need_line_func (prev, do_hscale_lines, idx, convert, NULL);
1643 static GstLineCache *
1644 chain_vscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1647 guint taps, taps_i = 0;
1650 method = GET_OPT_RESAMPLER_METHOD (convert);
1651 taps = GET_OPT_RESAMPLER_TAPS (convert);
1653 if (GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)
1654 && (GST_VIDEO_INFO_INTERLACE_MODE (&convert->in_info) !=
1655 GST_VIDEO_INTERLACE_MODE_ALTERNATE)) {
1656 convert->v_scaler_i[idx] =
1657 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_INTERLACED, taps,
1658 convert->in_height, convert->out_height, convert->config);
1660 gst_video_scaler_get_coeff (convert->v_scaler_i[idx], 0, NULL, &taps_i);
1663 convert->v_scaler_p[idx] =
1664 gst_video_scaler_new (method, 0, taps, convert->in_height,
1665 convert->out_height, convert->config);
1666 convert->v_scale_width = convert->current_width;
1667 convert->v_scale_format = convert->current_format;
1668 convert->current_height = convert->out_height;
1670 gst_video_scaler_get_coeff (convert->v_scaler_p[idx], 0, NULL, &taps);
1672 GST_DEBUG ("chain vscale %d->%d, taps %d, method %d, backlog %d",
1673 convert->in_height, convert->out_height, taps, method, backlog);
1675 prev->backlog = backlog;
1676 prev = convert->vscale_lines[idx] = gst_line_cache_new (prev);
1677 prev->pass_alloc = (taps == 1);
1678 prev->write_input = FALSE;
1679 prev->n_lines = MAX (taps_i, taps);
1680 prev->stride = convert->current_pstride * convert->current_width;
1681 gst_line_cache_set_need_line_func (prev, do_vscale_lines, idx, convert, NULL);
1686 static GstLineCache *
1687 chain_scale (GstVideoConverter * convert, GstLineCache * prev, gboolean force,
1690 gint s0, s1, s2, s3;
1692 s0 = convert->current_width * convert->current_height;
1693 s3 = convert->out_width * convert->out_height;
1695 GST_DEBUG ("in pixels %d <> out pixels %d", s0, s3);
1697 if (s3 <= s0 || force) {
1698 /* we are making the image smaller or are forced to resample */
1699 s1 = convert->out_width * convert->current_height;
1700 s2 = convert->current_width * convert->out_height;
1702 GST_DEBUG ("%d <> %d", s1, s2);
1705 /* h scaling first produces less pixels */
1706 if (convert->current_width != convert->out_width)
1707 prev = chain_hscale (convert, prev, idx);
1708 if (convert->current_height != convert->out_height)
1709 prev = chain_vscale (convert, prev, idx);
1711 /* v scaling first produces less pixels */
1712 if (convert->current_height != convert->out_height)
1713 prev = chain_vscale (convert, prev, idx);
1714 if (convert->current_width != convert->out_width)
1715 prev = chain_hscale (convert, prev, idx);
1721 static GstLineCache *
1722 chain_convert (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1724 gboolean do_gamma, do_conversion, pass_alloc = FALSE;
1725 gboolean same_matrix, same_primaries, same_bits;
1728 same_bits = convert->unpack_bits == convert->pack_bits;
1729 if (CHECK_MATRIX_NONE (convert)) {
1733 convert->in_info.colorimetry.matrix ==
1734 convert->out_info.colorimetry.matrix;
1737 if (CHECK_PRIMARIES_NONE (convert)) {
1738 same_primaries = TRUE;
1741 convert->in_info.colorimetry.primaries ==
1742 convert->out_info.colorimetry.primaries;
1745 GST_DEBUG ("matrix %d -> %d (%d)", convert->in_info.colorimetry.matrix,
1746 convert->out_info.colorimetry.matrix, same_matrix);
1747 GST_DEBUG ("bits %d -> %d (%d)", convert->unpack_bits, convert->pack_bits,
1749 GST_DEBUG ("primaries %d -> %d (%d)", convert->in_info.colorimetry.primaries,
1750 convert->out_info.colorimetry.primaries, same_primaries);
1752 color_matrix_set_identity (&convert->convert_matrix);
1754 if (!same_primaries) {
1755 const GstVideoColorPrimariesInfo *pi;
1757 /* Convert from RGB_input to RGB_output via XYZ
1758 * res = XYZ_to_RGB_output ( RGB_to_XYZ_input ( input ) )
1759 * or in matricial form:
1760 * RGB_output = XYZ_to_RGB_output_matrix * RGB_TO_XYZ_input_matrix * RGB_input
1762 * The RGB_input is the pre-existing convert_matrix
1763 * The convert_matrix will become the RGB_output
1766 /* Convert input RGB to XYZ */
1767 pi = gst_video_color_primaries_get_info (convert->in_info.colorimetry.
1769 /* Get the RGB_TO_XYZ_input_matrix */
1770 color_matrix_RGB_to_XYZ (&p1, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx,
1771 pi->By, pi->Wx, pi->Wy);
1772 GST_DEBUG ("to XYZ matrix");
1773 color_matrix_debug (&p1);
1774 GST_DEBUG ("current matrix");
1775 /* convert_matrix = RGB_TO_XYZ_input_matrix * input_RGB */
1776 color_matrix_multiply (&convert->convert_matrix, &convert->convert_matrix,
1778 color_matrix_debug (&convert->convert_matrix);
1780 /* Convert XYZ to output RGB */
1781 pi = gst_video_color_primaries_get_info (convert->out_info.colorimetry.
1783 /* Calculate the XYZ_to_RGB_output_matrix
1784 * * Get the RGB_TO_XYZ_output_matrix
1788 color_matrix_RGB_to_XYZ (&p2, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx,
1789 pi->By, pi->Wx, pi->Wy);
1790 color_matrix_invert (&p2, &p2);
1791 GST_DEBUG ("to RGB matrix");
1792 color_matrix_debug (&p2);
1794 * convert_matrix = XYZ_to_RGB_output_matrix * RGB_TO_XYZ_input_matrix * RGB_input
1795 * = XYZ_to_RGB_output_matrix * convert_matrix
1796 * = p2 * convert_matrix
1798 color_matrix_multiply (&convert->convert_matrix, &p2,
1799 &convert->convert_matrix);
1800 GST_DEBUG ("current matrix");
1801 color_matrix_debug (&convert->convert_matrix);
1804 do_gamma = CHECK_GAMMA_REMAP (convert);
1807 convert->in_bits = convert->unpack_bits;
1808 convert->out_bits = convert->pack_bits;
1810 if (!same_bits || !same_matrix || !same_primaries) {
1811 /* no gamma, combine all conversions into 1 */
1812 if (convert->in_bits < convert->out_bits) {
1813 gint scale = 1 << (convert->out_bits - convert->in_bits);
1814 color_matrix_scale_components (&convert->convert_matrix,
1815 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
1817 GST_DEBUG ("to RGB matrix");
1818 compute_matrix_to_RGB (convert, &convert->convert_matrix);
1819 GST_DEBUG ("current matrix");
1820 color_matrix_debug (&convert->convert_matrix);
1822 GST_DEBUG ("to YUV matrix");
1823 compute_matrix_to_YUV (convert, &convert->convert_matrix, FALSE);
1824 GST_DEBUG ("current matrix");
1825 color_matrix_debug (&convert->convert_matrix);
1826 if (convert->in_bits > convert->out_bits) {
1827 gint scale = 1 << (convert->in_bits - convert->out_bits);
1828 color_matrix_scale_components (&convert->convert_matrix,
1829 (float) scale, (float) scale, (float) scale);
1831 convert->current_bits = MAX (convert->in_bits, convert->out_bits);
1833 do_conversion = TRUE;
1834 if (!same_matrix || !same_primaries)
1835 prepare_matrix (convert, &convert->convert_matrix);
1836 if (convert->in_bits == convert->out_bits)
1839 do_conversion = FALSE;
1841 convert->current_bits = convert->pack_bits;
1842 convert->current_format = convert->pack_format;
1843 convert->current_pstride = convert->current_bits >> 1;
1845 /* we did gamma, just do colorspace conversion if needed */
1846 if (same_primaries) {
1847 do_conversion = FALSE;
1849 prepare_matrix (convert, &convert->convert_matrix);
1850 convert->in_bits = convert->out_bits = 16;
1852 do_conversion = TRUE;
1856 if (do_conversion) {
1857 GST_DEBUG ("chain conversion");
1858 prev = convert->convert_lines[idx] = gst_line_cache_new (prev);
1859 prev->write_input = TRUE;
1860 prev->pass_alloc = pass_alloc;
1862 prev->stride = convert->current_pstride * convert->current_width;
1863 gst_line_cache_set_need_line_func (prev,
1864 do_convert_lines, idx, convert, NULL);
1870 convert_set_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1873 guint8 alpha = MIN (convert->alpha_value, 255);
1876 for (i = 0; i < width; i++)
1881 convert_set_alpha_u16 (GstVideoConverter * convert, gpointer pixels, gint width)
1883 guint16 *p = pixels;
1887 alpha = MIN (convert->alpha_value, 255);
1888 alpha |= alpha << 8;
1890 for (i = 0; i < width; i++)
1895 convert_mult_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1898 guint alpha = convert->alpha_value;
1901 for (i = 0; i < width; i++) {
1902 gint a = (p[i * 4] * alpha) / 255;
1903 p[i * 4] = CLAMP (a, 0, 255);
1908 convert_mult_alpha_u16 (GstVideoConverter * convert, gpointer pixels,
1911 guint16 *p = pixels;
1912 guint alpha = convert->alpha_value;
1915 for (i = 0; i < width; i++) {
1916 gint a = (p[i * 4] * alpha) / 255;
1917 p[i * 4] = CLAMP (a, 0, 65535);
1921 static GstLineCache *
1922 chain_alpha (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1924 switch (convert->alpha_mode) {
1925 case ALPHA_MODE_NONE:
1926 case ALPHA_MODE_COPY:
1929 case ALPHA_MODE_SET:
1930 if (convert->current_bits == 8)
1931 convert->alpha_func = convert_set_alpha_u8;
1933 convert->alpha_func = convert_set_alpha_u16;
1935 case ALPHA_MODE_MULT:
1936 if (convert->current_bits == 8)
1937 convert->alpha_func = convert_mult_alpha_u8;
1939 convert->alpha_func = convert_mult_alpha_u16;
1943 GST_DEBUG ("chain alpha mode %d", convert->alpha_mode);
1944 prev = convert->alpha_lines[idx] = gst_line_cache_new (prev);
1945 prev->write_input = TRUE;
1946 prev->pass_alloc = TRUE;
1948 prev->stride = convert->current_pstride * convert->current_width;
1949 gst_line_cache_set_need_line_func (prev, do_alpha_lines, idx, convert, NULL);
1954 static GstLineCache *
1955 chain_convert_to_YUV (GstVideoConverter * convert, GstLineCache * prev,
1960 do_gamma = CHECK_GAMMA_REMAP (convert);
1965 GST_DEBUG ("chain gamma encode");
1966 setup_gamma_encode (convert, convert->pack_bits);
1968 convert->current_bits = convert->pack_bits;
1969 convert->current_pstride = convert->current_bits >> 1;
1971 if (!convert->pack_rgb) {
1972 color_matrix_set_identity (&convert->to_YUV_matrix);
1973 compute_matrix_to_YUV (convert, &convert->to_YUV_matrix, FALSE);
1975 /* matrix is in 0..255 range, scale to pack bits */
1976 GST_DEBUG ("chain YUV convert");
1977 scale = 1 << convert->pack_bits;
1978 color_matrix_scale_components (&convert->to_YUV_matrix,
1979 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
1980 prepare_matrix (convert, &convert->to_YUV_matrix);
1982 convert->current_format = convert->pack_format;
1984 prev = convert->to_YUV_lines[idx] = gst_line_cache_new (prev);
1985 prev->write_input = FALSE;
1986 prev->pass_alloc = FALSE;
1988 prev->stride = convert->current_pstride * convert->current_width;
1989 gst_line_cache_set_need_line_func (prev,
1990 do_convert_to_YUV_lines, idx, convert, NULL);
1996 static GstLineCache *
1997 chain_downsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1999 if (convert->downsample_p[idx] || convert->downsample_i[idx]) {
2000 GST_DEBUG ("chain downsample");
2001 prev = convert->downsample_lines[idx] = gst_line_cache_new (prev);
2002 prev->write_input = TRUE;
2003 prev->pass_alloc = TRUE;
2004 /* XXX: why this hardcoded value? */
2006 prev->stride = convert->current_pstride * convert->current_width;
2007 gst_line_cache_set_need_line_func (prev,
2008 do_downsample_lines, idx, convert, NULL);
2013 static GstLineCache *
2014 chain_dither (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2017 gboolean do_dither = FALSE;
2018 GstVideoDitherFlags flags = 0;
2019 GstVideoDitherMethod method;
2020 guint quant[4], target_quant;
2022 method = GET_OPT_DITHER_METHOD (convert);
2023 if (method == GST_VIDEO_DITHER_NONE)
2026 target_quant = GET_OPT_DITHER_QUANTIZATION (convert);
2027 GST_DEBUG ("method %d, target-quantization %d", method, target_quant);
2029 if (convert->pack_pal) {
2036 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++) {
2039 depth = convert->out_info.finfo->depth[i];
2046 if (convert->current_bits >= depth) {
2047 quant[i] = 1 << (convert->current_bits - depth);
2048 if (target_quant > quant[i]) {
2049 flags |= GST_VIDEO_DITHER_FLAG_QUANTIZE;
2050 quant[i] = target_quant;
2061 GST_DEBUG ("chain dither");
2063 convert->dither[idx] = gst_video_dither_new (method,
2064 flags, convert->pack_format, quant, convert->current_width);
2066 prev = convert->dither_lines[idx] = gst_line_cache_new (prev);
2067 prev->write_input = TRUE;
2068 prev->pass_alloc = TRUE;
2070 prev->stride = convert->current_pstride * convert->current_width;
2071 gst_line_cache_set_need_line_func (prev, do_dither_lines, idx, convert,
2077 static GstLineCache *
2078 chain_pack (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2080 convert->pack_nlines = convert->out_info.finfo->pack_lines;
2081 convert->pack_pstride = convert->current_pstride;
2082 convert->identity_pack =
2083 (convert->out_info.finfo->format ==
2084 convert->out_info.finfo->unpack_format);
2085 GST_DEBUG ("chain pack line format %s, pstride %d, identity_pack %d (%d %d)",
2086 gst_video_format_to_string (convert->current_format),
2087 convert->current_pstride, convert->identity_pack,
2088 convert->out_info.finfo->format, convert->out_info.finfo->unpack_format);
2094 setup_allocators (GstVideoConverter * convert)
2096 GstLineCache *cache, *prev;
2097 GstLineCacheAllocLineFunc alloc_line;
2098 gboolean alloc_writable;
2100 GDestroyNotify notify;
2104 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2105 width += convert->out_x;
2107 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2108 /* start with using dest lines if we can directly write into it */
2109 if (convert->identity_pack) {
2110 alloc_line = get_dest_line;
2111 alloc_writable = TRUE;
2112 user_data = convert;
2116 converter_alloc_new (sizeof (guint16) * width * 4, 4 + BACKLOG,
2118 setup_border_alloc (convert, user_data);
2119 notify = (GDestroyNotify) converter_alloc_free;
2120 alloc_line = get_border_temp_line;
2121 /* when we add a border, we need to write */
2122 alloc_writable = convert->borderline != NULL;
2125 /* First step, try to calculate how many temp lines we need. Go backwards,
2126 * keep track of the maximum number of lines we need for each intermediate
2128 for (prev = cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2129 GST_DEBUG ("looking at cache %p, %d lines, %d backlog", cache,
2130 cache->n_lines, cache->backlog);
2131 prev->n_lines = MAX (prev->n_lines, cache->n_lines);
2132 if (!cache->pass_alloc) {
2133 GST_DEBUG ("cache %p, needs %d lines", prev, prev->n_lines);
2138 /* now walk backwards, we try to write into the dest lines directly
2139 * and keep track if the source needs to be writable */
2140 for (cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2141 gst_line_cache_set_alloc_line_func (cache, alloc_line, user_data, notify);
2142 cache->alloc_writable = alloc_writable;
2144 /* make sure only one cache frees the allocator */
2147 if (!cache->pass_alloc) {
2148 /* can't pass allocator, make new temp line allocator */
2150 converter_alloc_new (sizeof (guint16) * width * 4,
2151 cache->n_lines + cache->backlog, convert, NULL);
2152 notify = (GDestroyNotify) converter_alloc_free;
2153 alloc_line = get_temp_line;
2154 alloc_writable = FALSE;
2156 /* if someone writes to the input, we need a writable line from the
2158 if (cache->write_input)
2159 alloc_writable = TRUE;
2161 /* free leftover allocator */
2168 setup_borderline (GstVideoConverter * convert)
2172 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2173 width += convert->out_x;
2175 if (convert->fill_border && (convert->out_height < convert->out_maxheight ||
2176 convert->out_width < convert->out_maxwidth)) {
2179 const GstVideoFormatInfo *out_finfo;
2180 gpointer planes[GST_VIDEO_MAX_PLANES];
2181 gint strides[GST_VIDEO_MAX_PLANES];
2183 convert->borderline = g_malloc0 (sizeof (guint16) * width * 4);
2185 out_finfo = convert->out_info.finfo;
2187 if (GST_VIDEO_INFO_IS_YUV (&convert->out_info)) {
2192 /* Get Color matrix. */
2193 color_matrix_set_identity (&cm);
2194 compute_matrix_to_YUV (convert, &cm, TRUE);
2195 color_matrix_convert (&cm);
2197 border_val = GINT32_FROM_BE (convert->border_argb);
2199 b = (0xFF000000 & border_val) >> 24;
2200 g = (0x00FF0000 & border_val) >> 16;
2201 r = (0x0000FF00 & border_val) >> 8;
2202 a = (0x000000FF & border_val);
2204 y = 16 + ((r * cm.im[0][0] + g * cm.im[0][1] + b * cm.im[0][2]) >> 8);
2205 u = 128 + ((r * cm.im[1][0] + g * cm.im[1][1] + b * cm.im[1][2]) >> 8);
2206 v = 128 + ((r * cm.im[2][0] + g * cm.im[2][1] + b * cm.im[2][2]) >> 8);
2208 a = CLAMP (a, 0, 255);
2209 y = CLAMP (y, 0, 255);
2210 u = CLAMP (u, 0, 255);
2211 v = CLAMP (v, 0, 255);
2213 border_val = a | (y << 8) | (u << 16) | ((guint32) v << 24);
2215 border_val = GINT32_FROM_BE (convert->border_argb);
2217 if (convert->pack_bits == 8)
2218 video_orc_splat_u32 (convert->borderline, border_val, width);
2220 video_orc_splat2_u64 (convert->borderline, border_val, width);
2222 /* convert pixels */
2223 for (i = 0; i < out_finfo->n_planes; i++) {
2224 planes[i] = &convert->borders[i];
2225 strides[i] = sizeof (guint64);
2228 if (out_finfo->n_planes == 1) {
2229 /* for packed formats, convert based on subsampling so that we
2230 * get a complete group of pixels */
2231 for (i = 0; i < out_finfo->n_components; i++) {
2232 w_sub = MAX (w_sub, out_finfo->w_sub[i]);
2235 out_finfo->pack_func (out_finfo, GST_VIDEO_PACK_FLAG_NONE,
2236 convert->borderline, 0, planes, strides,
2237 GST_VIDEO_CHROMA_SITE_UNKNOWN, 0, 1 << w_sub);
2239 convert->borderline = NULL;
2244 convert_get_alpha_mode (GstVideoConverter * convert)
2246 gboolean in_alpha, out_alpha;
2248 in_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->in_info);
2249 out_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->out_info);
2251 /* no output alpha, do nothing */
2253 return ALPHA_MODE_NONE;
2257 if (CHECK_ALPHA_COPY (convert))
2258 return ALPHA_MODE_COPY;
2260 if (CHECK_ALPHA_MULT (convert)) {
2261 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2262 return ALPHA_MODE_COPY;
2264 return ALPHA_MODE_MULT;
2267 /* nothing special, this is what unpack etc does automatically */
2268 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2269 return ALPHA_MODE_NONE;
2271 /* everything else becomes SET */
2272 return ALPHA_MODE_SET;
2276 * gst_video_converter_new_with_pool: (skip)
2277 * @in_info: a #GstVideoInfo
2278 * @out_info: a #GstVideoInfo
2279 * @config: (transfer full): a #GstStructure with configuration options
2280 * @pool: (nullable): a #GstTaskPool to spawn threads from
2282 * Create a new converter object to convert between @in_info and @out_info
2285 * The optional @pool can be used to spawn threads, this is useful when
2286 * creating new converters rapidly, for example when updating cropping.
2288 * Returns: a #GstVideoConverter or %NULL if conversion is not possible.
2293 gst_video_converter_new_with_pool (const GstVideoInfo * in_info,
2294 const GstVideoInfo * out_info, GstStructure * config, GstTaskPool * pool)
2296 GstVideoConverter *convert;
2298 const GstVideoFormatInfo *fin, *fout, *finfo;
2299 gdouble alpha_value;
2301 gboolean async_tasks;
2303 g_return_val_if_fail (in_info != NULL, NULL);
2304 g_return_val_if_fail (out_info != NULL, NULL);
2305 /* we won't ever do framerate conversion */
2306 g_return_val_if_fail (in_info->fps_n == out_info->fps_n, NULL);
2307 g_return_val_if_fail (in_info->fps_d == out_info->fps_d, NULL);
2308 /* we won't ever do deinterlace */
2309 g_return_val_if_fail (in_info->interlace_mode == out_info->interlace_mode,
2312 convert = g_slice_new0 (GstVideoConverter);
2314 fin = in_info->finfo;
2315 fout = out_info->finfo;
2317 convert->in_info = *in_info;
2318 convert->out_info = *out_info;
2320 /* default config */
2321 convert->config = gst_structure_new_empty ("GstVideoConverter");
2323 gst_video_converter_set_config (convert, config);
2325 convert->in_maxwidth = GST_VIDEO_INFO_WIDTH (in_info);
2326 convert->in_maxheight = GST_VIDEO_INFO_FIELD_HEIGHT (in_info);
2327 convert->out_maxwidth = GST_VIDEO_INFO_WIDTH (out_info);
2328 convert->out_maxheight = GST_VIDEO_INFO_FIELD_HEIGHT (out_info);
2330 convert->in_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_X, 0);
2331 convert->in_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_Y, 0);
2332 convert->in_x &= ~((1 << fin->w_sub[1]) - 1);
2333 convert->in_y &= ~((1 << fin->h_sub[1]) - 1);
2335 convert->in_width = get_opt_int (convert,
2336 GST_VIDEO_CONVERTER_OPT_SRC_WIDTH, convert->in_maxwidth - convert->in_x);
2337 convert->in_height = get_opt_int (convert,
2338 GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT,
2339 convert->in_maxheight - convert->in_y);
2342 MIN (convert->in_width, convert->in_maxwidth - convert->in_x);
2343 if (convert->in_width + convert->in_x < 0 ||
2344 convert->in_width + convert->in_x > convert->in_maxwidth) {
2345 convert->in_width = 0;
2348 convert->in_height =
2349 MIN (convert->in_height, convert->in_maxheight - convert->in_y);
2350 if (convert->in_height + convert->in_y < 0 ||
2351 convert->in_height + convert->in_y > convert->in_maxheight) {
2352 convert->in_height = 0;
2355 convert->out_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_X, 0);
2356 convert->out_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_Y, 0);
2357 convert->out_x &= ~((1 << fout->w_sub[1]) - 1);
2358 convert->out_y &= ~((1 << fout->h_sub[1]) - 1);
2360 convert->out_width = get_opt_int (convert,
2361 GST_VIDEO_CONVERTER_OPT_DEST_WIDTH,
2362 convert->out_maxwidth - convert->out_x);
2363 convert->out_height =
2364 get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT,
2365 convert->out_maxheight - convert->out_y);
2367 if (convert->out_width > convert->out_maxwidth - convert->out_x)
2368 convert->out_width = convert->out_maxwidth - convert->out_x;
2369 convert->out_width = CLAMP (convert->out_width, 0, convert->out_maxwidth);
2371 /* Check if completely outside the framebuffer */
2372 if (convert->out_width + convert->out_x < 0 ||
2373 convert->out_width + convert->out_x > convert->out_maxwidth) {
2374 convert->out_width = 0;
2377 /* Same for height */
2378 if (convert->out_height > convert->out_maxheight - convert->out_y)
2379 convert->out_height = convert->out_maxheight - convert->out_y;
2380 convert->out_height = CLAMP (convert->out_height, 0, convert->out_maxheight);
2382 if (convert->out_height + convert->out_y < 0 ||
2383 convert->out_height + convert->out_y > convert->out_maxheight) {
2384 convert->out_height = 0;
2387 convert->fill_border = GET_OPT_FILL_BORDER (convert);
2388 convert->border_argb = get_opt_uint (convert,
2389 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB);
2391 alpha_value = GET_OPT_ALPHA_VALUE (convert);
2392 convert->alpha_value = 255 * alpha_value;
2393 convert->alpha_mode = convert_get_alpha_mode (convert);
2395 convert->unpack_format = in_info->finfo->unpack_format;
2396 finfo = gst_video_format_get_info (convert->unpack_format);
2397 convert->unpack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2398 convert->unpack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2399 if (convert->unpack_rgb
2400 && in_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2401 /* force identity matrix for RGB input */
2402 GST_WARNING ("invalid matrix %d for input RGB format, using RGB",
2403 in_info->colorimetry.matrix);
2404 convert->in_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2407 convert->pack_format = out_info->finfo->unpack_format;
2408 finfo = gst_video_format_get_info (convert->pack_format);
2409 convert->pack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2410 convert->pack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2412 gst_video_format_get_palette (GST_VIDEO_INFO_FORMAT (out_info),
2413 &convert->pack_palsize);
2414 if (convert->pack_rgb
2415 && out_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2416 /* force identity matrix for RGB output */
2417 GST_WARNING ("invalid matrix %d for output RGB format, using RGB",
2418 out_info->colorimetry.matrix);
2419 convert->out_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2422 n_threads = get_opt_uint (convert, GST_VIDEO_CONVERTER_OPT_THREADS, 1);
2423 if (n_threads == 0 || n_threads > g_get_num_processors ())
2424 n_threads = g_get_num_processors ();
2425 /* Magic number of 200 lines */
2426 if (MAX (convert->out_height, convert->in_height) / n_threads < 200)
2427 n_threads = (MAX (convert->out_height, convert->in_height) + 199) / 200;
2431 async_tasks = GET_OPT_ASYNC_TASKS (convert);
2432 convert->conversion_runner =
2433 gst_parallelized_task_runner_new (n_threads, pool, async_tasks);
2435 if (video_converter_lookup_fastpath (convert))
2438 if (in_info->finfo->unpack_func == NULL)
2439 goto no_unpack_func;
2441 if (out_info->finfo->pack_func == NULL)
2444 convert->convert = video_converter_generic;
2446 convert->upsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2447 convert->upsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2448 convert->downsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2449 convert->downsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2450 convert->v_scaler_p = g_new0 (GstVideoScaler *, n_threads);
2451 convert->v_scaler_i = g_new0 (GstVideoScaler *, n_threads);
2452 convert->h_scaler = g_new0 (GstVideoScaler *, n_threads);
2453 convert->unpack_lines = g_new0 (GstLineCache *, n_threads);
2454 convert->pack_lines = g_new0 (GstLineCache *, n_threads);
2455 convert->upsample_lines = g_new0 (GstLineCache *, n_threads);
2456 convert->to_RGB_lines = g_new0 (GstLineCache *, n_threads);
2457 convert->hscale_lines = g_new0 (GstLineCache *, n_threads);
2458 convert->vscale_lines = g_new0 (GstLineCache *, n_threads);
2459 convert->convert_lines = g_new0 (GstLineCache *, n_threads);
2460 convert->alpha_lines = g_new0 (GstLineCache *, n_threads);
2461 convert->to_YUV_lines = g_new0 (GstLineCache *, n_threads);
2462 convert->downsample_lines = g_new0 (GstLineCache *, n_threads);
2463 convert->dither_lines = g_new0 (GstLineCache *, n_threads);
2464 convert->dither = g_new0 (GstVideoDither *, n_threads);
2466 if (convert->in_width > 0 && convert->out_width > 0 && convert->in_height > 0
2467 && convert->out_height > 0) {
2468 for (i = 0; i < n_threads; i++) {
2469 convert->current_format = GST_VIDEO_INFO_FORMAT (in_info);
2470 convert->current_width = convert->in_width;
2471 convert->current_height = convert->in_height;
2474 prev = chain_unpack_line (convert, i);
2475 /* upsample chroma */
2476 prev = chain_upsample (convert, prev, i);
2477 /* convert to gamma decoded RGB */
2478 prev = chain_convert_to_RGB (convert, prev, i);
2479 /* do all downscaling */
2480 prev = chain_scale (convert, prev, FALSE, i);
2481 /* do conversion between color spaces */
2482 prev = chain_convert (convert, prev, i);
2483 /* do alpha channels */
2484 prev = chain_alpha (convert, prev, i);
2485 /* do all remaining (up)scaling */
2486 prev = chain_scale (convert, prev, TRUE, i);
2487 /* convert to gamma encoded Y'Cb'Cr' */
2488 prev = chain_convert_to_YUV (convert, prev, i);
2489 /* downsample chroma */
2490 prev = chain_downsample (convert, prev, i);
2492 prev = chain_dither (convert, prev, i);
2493 /* pack into final format */
2494 convert->pack_lines[i] = chain_pack (convert, prev, i);
2498 setup_borderline (convert);
2499 /* now figure out allocators */
2500 setup_allocators (convert);
2508 GST_ERROR ("no unpack_func for format %s",
2509 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
2510 gst_video_converter_free (convert);
2515 GST_ERROR ("no pack_func for format %s",
2516 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
2517 gst_video_converter_free (convert);
2523 * gst_video_converter_new: (skip)
2524 * @in_info: a #GstVideoInfo
2525 * @out_info: a #GstVideoInfo
2526 * @config: (transfer full): a #GstStructure with configuration options
2528 * Create a new converter object to convert between @in_info and @out_info
2531 * Returns: a #GstVideoConverter or %NULL if conversion is not possible.
2536 gst_video_converter_new (const GstVideoInfo * in_info,
2537 const GstVideoInfo * out_info, GstStructure * config)
2539 return gst_video_converter_new_with_pool (in_info, out_info, config, NULL);
2543 clear_matrix_data (MatrixData * data)
2551 * gst_video_converter_free:
2552 * @convert: a #GstVideoConverter
2559 gst_video_converter_free (GstVideoConverter * convert)
2563 g_return_if_fail (convert != NULL);
2565 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2566 if (convert->upsample_p && convert->upsample_p[i])
2567 gst_video_chroma_resample_free (convert->upsample_p[i]);
2568 if (convert->upsample_i && convert->upsample_i[i])
2569 gst_video_chroma_resample_free (convert->upsample_i[i]);
2570 if (convert->downsample_p && convert->downsample_p[i])
2571 gst_video_chroma_resample_free (convert->downsample_p[i]);
2572 if (convert->downsample_i && convert->downsample_i[i])
2573 gst_video_chroma_resample_free (convert->downsample_i[i]);
2574 if (convert->v_scaler_p && convert->v_scaler_p[i])
2575 gst_video_scaler_free (convert->v_scaler_p[i]);
2576 if (convert->v_scaler_i && convert->v_scaler_i[i])
2577 gst_video_scaler_free (convert->v_scaler_i[i]);
2578 if (convert->h_scaler && convert->h_scaler[i])
2579 gst_video_scaler_free (convert->h_scaler[i]);
2580 if (convert->unpack_lines && convert->unpack_lines[i])
2581 gst_line_cache_free (convert->unpack_lines[i]);
2582 if (convert->upsample_lines && convert->upsample_lines[i])
2583 gst_line_cache_free (convert->upsample_lines[i]);
2584 if (convert->to_RGB_lines && convert->to_RGB_lines[i])
2585 gst_line_cache_free (convert->to_RGB_lines[i]);
2586 if (convert->hscale_lines && convert->hscale_lines[i])
2587 gst_line_cache_free (convert->hscale_lines[i]);
2588 if (convert->vscale_lines && convert->vscale_lines[i])
2589 gst_line_cache_free (convert->vscale_lines[i]);
2590 if (convert->convert_lines && convert->convert_lines[i])
2591 gst_line_cache_free (convert->convert_lines[i]);
2592 if (convert->alpha_lines && convert->alpha_lines[i])
2593 gst_line_cache_free (convert->alpha_lines[i]);
2594 if (convert->to_YUV_lines && convert->to_YUV_lines[i])
2595 gst_line_cache_free (convert->to_YUV_lines[i]);
2596 if (convert->downsample_lines && convert->downsample_lines[i])
2597 gst_line_cache_free (convert->downsample_lines[i]);
2598 if (convert->dither_lines && convert->dither_lines[i])
2599 gst_line_cache_free (convert->dither_lines[i]);
2600 if (convert->dither && convert->dither[i])
2601 gst_video_dither_free (convert->dither[i]);
2603 g_free (convert->upsample_p);
2604 g_free (convert->upsample_i);
2605 g_free (convert->downsample_p);
2606 g_free (convert->downsample_i);
2607 g_free (convert->v_scaler_p);
2608 g_free (convert->v_scaler_i);
2609 g_free (convert->h_scaler);
2610 g_free (convert->unpack_lines);
2611 g_free (convert->pack_lines);
2612 g_free (convert->upsample_lines);
2613 g_free (convert->to_RGB_lines);
2614 g_free (convert->hscale_lines);
2615 g_free (convert->vscale_lines);
2616 g_free (convert->convert_lines);
2617 g_free (convert->alpha_lines);
2618 g_free (convert->to_YUV_lines);
2619 g_free (convert->downsample_lines);
2620 g_free (convert->dither_lines);
2621 g_free (convert->dither);
2623 g_free (convert->gamma_dec.gamma_table);
2624 g_free (convert->gamma_enc.gamma_table);
2626 if (convert->tmpline) {
2627 for (i = 0; i < convert->conversion_runner->n_threads; i++)
2628 g_free (convert->tmpline[i]);
2629 g_free (convert->tmpline);
2632 g_free (convert->borderline);
2634 if (convert->config)
2635 gst_structure_free (convert->config);
2637 for (i = 0; i < 4; i++) {
2638 for (j = 0; j < convert->conversion_runner->n_threads; j++) {
2639 if (convert->fv_scaler[i].scaler)
2640 gst_video_scaler_free (convert->fv_scaler[i].scaler[j]);
2641 if (convert->fh_scaler[i].scaler)
2642 gst_video_scaler_free (convert->fh_scaler[i].scaler[j]);
2644 g_free (convert->fv_scaler[i].scaler);
2645 g_free (convert->fh_scaler[i].scaler);
2648 if (convert->conversion_runner)
2649 gst_parallelized_task_runner_free (convert->conversion_runner);
2651 clear_matrix_data (&convert->to_RGB_matrix);
2652 clear_matrix_data (&convert->convert_matrix);
2653 clear_matrix_data (&convert->to_YUV_matrix);
2655 for (i = 0; i < 4; i++) {
2656 g_free (convert->tasks[i]);
2657 g_free (convert->tasks_p[i]);
2660 g_slice_free (GstVideoConverter, convert);
2664 copy_config (GQuark field_id, const GValue * value, gpointer user_data)
2666 GstVideoConverter *convert = user_data;
2668 gst_structure_id_set_value (convert->config, field_id, value);
2674 * gst_video_converter_set_config:
2675 * @convert: a #GstVideoConverter
2676 * @config: (transfer full): a #GstStructure
2678 * Set @config as extra configuration for @convert.
2680 * If the parameters in @config can not be set exactly, this function returns
2681 * %FALSE and will try to update as much state as possible. The new state can
2682 * then be retrieved and refined with gst_video_converter_get_config().
2684 * Look at the `GST_VIDEO_CONVERTER_OPT_*` fields to check valid configuration
2685 * option and values.
2687 * Returns: %TRUE when @config could be set.
2692 gst_video_converter_set_config (GstVideoConverter * convert,
2693 GstStructure * config)
2695 g_return_val_if_fail (convert != NULL, FALSE);
2696 g_return_val_if_fail (config != NULL, FALSE);
2698 gst_structure_foreach (config, copy_config, convert);
2699 gst_structure_free (config);
2705 * gst_video_converter_get_config:
2706 * @convert: a #GstVideoConverter
2708 * Get the current configuration of @convert.
2710 * Returns: a #GstStructure that remains valid for as long as @convert is valid
2711 * or until gst_video_converter_set_config() is called.
2713 const GstStructure *
2714 gst_video_converter_get_config (GstVideoConverter * convert)
2716 g_return_val_if_fail (convert != NULL, NULL);
2718 return convert->config;
2722 * gst_video_converter_frame:
2723 * @convert: a #GstVideoConverter
2724 * @dest: a #GstVideoFrame
2725 * @src: a #GstVideoFrame
2727 * Convert the pixels of @src into @dest using @convert.
2729 * If #GST_VIDEO_CONVERTER_OPT_ASYNC_TASKS is %TRUE then this function will
2730 * return immediately and needs to be followed by a call to
2731 * gst_video_converter_frame_finish().
2736 gst_video_converter_frame (GstVideoConverter * convert,
2737 const GstVideoFrame * src, GstVideoFrame * dest)
2739 g_return_if_fail (convert != NULL);
2740 g_return_if_fail (src != NULL);
2741 g_return_if_fail (dest != NULL);
2743 /* Check the frames we've been passed match the layout
2744 * we were configured for or we might go out of bounds */
2745 if (G_UNLIKELY (GST_VIDEO_INFO_FORMAT (&convert->in_info) !=
2746 GST_VIDEO_FRAME_FORMAT (src)
2747 || GST_VIDEO_INFO_WIDTH (&convert->in_info) >
2748 GST_VIDEO_FRAME_WIDTH (src)
2749 || GST_VIDEO_INFO_FIELD_HEIGHT (&convert->in_info) >
2750 GST_VIDEO_FRAME_HEIGHT (src))) {
2751 g_critical ("Input video frame does not match configuration");
2754 if (G_UNLIKELY (GST_VIDEO_INFO_FORMAT (&convert->out_info) !=
2755 GST_VIDEO_FRAME_FORMAT (dest)
2756 || GST_VIDEO_INFO_WIDTH (&convert->out_info) >
2757 GST_VIDEO_FRAME_WIDTH (dest)
2758 || GST_VIDEO_INFO_FIELD_HEIGHT (&convert->out_info) >
2759 GST_VIDEO_FRAME_HEIGHT (dest))) {
2760 g_critical ("Output video frame does not match configuration");
2764 if (G_UNLIKELY (convert->in_width == 0 || convert->in_height == 0 ||
2765 convert->out_width == 0 || convert->out_height == 0))
2768 convert->convert (convert, src, dest);
2772 * gst_video_converter_frame_finish:
2773 * @convert: a #GstVideoConverter
2775 * Wait for a previous async conversion performed using
2776 * gst_video_converter_frame() to complete.
2781 gst_video_converter_frame_finish (GstVideoConverter * convert)
2783 g_return_if_fail (convert);
2784 g_return_if_fail (convert->conversion_runner);
2785 g_return_if_fail (convert->conversion_runner->async_tasks);
2787 gst_parallelized_task_runner_finish (convert->conversion_runner);
2791 video_converter_compute_matrix (GstVideoConverter * convert)
2793 MatrixData *dst = &convert->convert_matrix;
2795 color_matrix_set_identity (dst);
2796 compute_matrix_to_RGB (convert, dst);
2797 compute_matrix_to_YUV (convert, dst, FALSE);
2799 convert->current_bits = 8;
2800 prepare_matrix (convert, dst);
2804 video_converter_compute_resample (GstVideoConverter * convert, gint idx)
2806 GstVideoInfo *in_info, *out_info;
2807 const GstVideoFormatInfo *sfinfo, *dfinfo;
2809 if (CHECK_CHROMA_NONE (convert))
2812 in_info = &convert->in_info;
2813 out_info = &convert->out_info;
2815 sfinfo = in_info->finfo;
2816 dfinfo = out_info->finfo;
2818 GST_DEBUG ("site: %d->%d, w_sub: %d->%d, h_sub: %d->%d", in_info->chroma_site,
2819 out_info->chroma_site, sfinfo->w_sub[2], dfinfo->w_sub[2],
2820 sfinfo->h_sub[2], dfinfo->h_sub[2]);
2822 if (sfinfo->w_sub[2] != dfinfo->w_sub[2] ||
2823 sfinfo->h_sub[2] != dfinfo->h_sub[2] ||
2824 in_info->chroma_site != out_info->chroma_site ||
2825 in_info->width != out_info->width ||
2826 in_info->height != out_info->height) {
2827 if (GST_VIDEO_INFO_IS_INTERLACED (in_info)
2828 && GST_VIDEO_INFO_INTERLACE_MODE (in_info) !=
2829 GST_VIDEO_INTERLACE_MODE_ALTERNATE) {
2830 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2831 convert->upsample_i[idx] = gst_video_chroma_resample_new (0,
2832 in_info->chroma_site, GST_VIDEO_CHROMA_FLAG_INTERLACED,
2833 sfinfo->unpack_format, sfinfo->w_sub[2], sfinfo->h_sub[2]);
2834 if (!CHECK_CHROMA_UPSAMPLE (convert))
2835 convert->downsample_i[idx] =
2836 gst_video_chroma_resample_new (0, out_info->chroma_site,
2837 GST_VIDEO_CHROMA_FLAG_INTERLACED, dfinfo->unpack_format,
2838 -dfinfo->w_sub[2], -dfinfo->h_sub[2]);
2840 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2841 convert->upsample_p[idx] = gst_video_chroma_resample_new (0,
2842 in_info->chroma_site, 0, sfinfo->unpack_format, sfinfo->w_sub[2],
2844 if (!CHECK_CHROMA_UPSAMPLE (convert))
2845 convert->downsample_p[idx] = gst_video_chroma_resample_new (0,
2846 out_info->chroma_site, 0, dfinfo->unpack_format, -dfinfo->w_sub[2],
2851 #define FRAME_GET_PLANE_STRIDE(frame, plane) \
2852 GST_VIDEO_FRAME_PLANE_STRIDE (frame, plane)
2853 #define FRAME_GET_PLANE_LINE(frame, plane, line) \
2854 (gpointer)(((guint8*)(GST_VIDEO_FRAME_PLANE_DATA (frame, plane))) + \
2855 FRAME_GET_PLANE_STRIDE (frame, plane) * (line))
2857 #define FRAME_GET_COMP_STRIDE(frame, comp) \
2858 GST_VIDEO_FRAME_COMP_STRIDE (frame, comp)
2859 #define FRAME_GET_COMP_LINE(frame, comp, line) \
2860 (gpointer)(((guint8*)(GST_VIDEO_FRAME_COMP_DATA (frame, comp))) + \
2861 FRAME_GET_COMP_STRIDE (frame, comp) * (line))
2863 #define FRAME_GET_STRIDE(frame) FRAME_GET_PLANE_STRIDE (frame, 0)
2864 #define FRAME_GET_LINE(frame,line) FRAME_GET_PLANE_LINE (frame, 0, line)
2866 #define FRAME_GET_Y_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_Y, line)
2867 #define FRAME_GET_U_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_U, line)
2868 #define FRAME_GET_V_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_V, line)
2869 #define FRAME_GET_A_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_A, line)
2871 #define FRAME_GET_Y_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_Y)
2872 #define FRAME_GET_U_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_U)
2873 #define FRAME_GET_V_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_V)
2874 #define FRAME_GET_A_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_A)
2877 #define UNPACK_FRAME(frame,dest,line,x,width) \
2878 frame->info.finfo->unpack_func (frame->info.finfo, \
2879 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2880 GST_VIDEO_PACK_FLAG_INTERLACED : \
2881 GST_VIDEO_PACK_FLAG_NONE), \
2882 dest, frame->data, frame->info.stride, x, \
2884 #define PACK_FRAME(frame,src,line,width) \
2885 frame->info.finfo->pack_func (frame->info.finfo, \
2886 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2887 GST_VIDEO_PACK_FLAG_INTERLACED : \
2888 GST_VIDEO_PACK_FLAG_NONE), \
2889 src, 0, frame->data, frame->info.stride, \
2890 frame->info.chroma_site, line, width);
2893 get_dest_line (GstLineCache * cache, gint idx, gpointer user_data)
2895 GstVideoConverter *convert = user_data;
2897 gint pstride = convert->pack_pstride;
2898 gint out_x = convert->out_x;
2901 cline = CLAMP (idx, 0, convert->out_maxheight - 1);
2903 line = FRAME_GET_LINE (convert->dest, cline);
2904 GST_DEBUG ("get dest line %d %p", cline, line);
2906 if (convert->borderline) {
2907 gint r_border = (out_x + convert->out_width) * pstride;
2908 gint rb_width = convert->out_maxwidth * pstride - r_border;
2909 gint lb_width = out_x * pstride;
2911 memcpy (line, convert->borderline, lb_width);
2912 memcpy (line + r_border, convert->borderline, rb_width);
2914 line += out_x * pstride;
2920 do_unpack_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2923 GstVideoConverter *convert = user_data;
2927 cline = CLAMP (in_line + convert->in_y, 0, convert->in_maxheight - 1);
2929 if (cache->alloc_writable || !convert->identity_unpack) {
2930 tmpline = gst_line_cache_alloc_line (cache, out_line);
2931 GST_DEBUG ("unpack line %d (%u) %p", in_line, cline, tmpline);
2932 UNPACK_FRAME (convert->src, tmpline, cline, convert->in_x,
2935 tmpline = ((guint8 *) FRAME_GET_LINE (convert->src, cline)) +
2936 convert->in_x * convert->unpack_pstride;
2937 GST_DEBUG ("get src line %d (%u) %p", in_line, cline, tmpline);
2939 gst_line_cache_add_line (cache, in_line, tmpline);
2945 do_upsample_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2948 GstVideoConverter *convert = user_data;
2950 gint i, start_line, n_lines;
2952 n_lines = convert->up_n_lines;
2953 start_line = in_line;
2954 if (start_line < n_lines + convert->up_offset) {
2955 start_line += convert->up_offset;
2956 out_line += convert->up_offset;
2959 /* get the lines needed for chroma upsample */
2961 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
2964 if (convert->upsample[idx]) {
2965 GST_DEBUG ("doing upsample %d-%d %p", start_line, start_line + n_lines - 1,
2967 gst_video_chroma_resample (convert->upsample[idx], lines,
2971 for (i = 0; i < n_lines; i++)
2972 gst_line_cache_add_line (cache, start_line + i, lines[i]);
2978 do_convert_to_RGB_lines (GstLineCache * cache, gint idx, gint out_line,
2979 gint in_line, gpointer user_data)
2981 GstVideoConverter *convert = user_data;
2982 MatrixData *data = &convert->to_RGB_matrix;
2983 gpointer *lines, destline;
2985 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2986 destline = lines[0];
2988 if (data->matrix_func) {
2989 GST_DEBUG ("to RGB line %d %p", in_line, destline);
2990 data->matrix_func (data, destline);
2992 if (convert->gamma_dec.gamma_func) {
2993 destline = gst_line_cache_alloc_line (cache, out_line);
2995 GST_DEBUG ("gamma decode line %d %p->%p", in_line, lines[0], destline);
2996 convert->gamma_dec.gamma_func (&convert->gamma_dec, destline, lines[0]);
2998 gst_line_cache_add_line (cache, in_line, destline);
3004 do_hscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3007 GstVideoConverter *convert = user_data;
3008 gpointer *lines, destline;
3010 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3012 destline = gst_line_cache_alloc_line (cache, out_line);
3014 GST_DEBUG ("hresample line %d %p->%p", in_line, lines[0], destline);
3015 gst_video_scaler_horizontal (convert->h_scaler[idx], convert->h_scale_format,
3016 lines[0], destline, 0, convert->out_width);
3018 gst_line_cache_add_line (cache, in_line, destline);
3024 do_vscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3027 GstVideoConverter *convert = user_data;
3028 gpointer *lines, destline;
3029 guint sline, n_lines;
3032 cline = CLAMP (in_line, 0, convert->out_height - 1);
3034 gst_video_scaler_get_coeff (convert->v_scaler[idx], cline, &sline, &n_lines);
3035 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, sline, n_lines);
3037 destline = gst_line_cache_alloc_line (cache, out_line);
3039 GST_DEBUG ("vresample line %d %d-%d %p->%p", in_line, sline,
3040 sline + n_lines - 1, lines[0], destline);
3041 gst_video_scaler_vertical (convert->v_scaler[idx], convert->v_scale_format,
3042 lines, destline, cline, convert->v_scale_width);
3044 gst_line_cache_add_line (cache, in_line, destline);
3050 do_convert_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3053 GstVideoConverter *convert = user_data;
3054 MatrixData *data = &convert->convert_matrix;
3055 gpointer *lines, destline;
3056 guint in_bits, out_bits;
3059 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3061 destline = lines[0];
3063 in_bits = convert->in_bits;
3064 out_bits = convert->out_bits;
3066 width = MIN (convert->in_width, convert->out_width);
3068 if (out_bits == 16 || in_bits == 16) {
3069 gpointer srcline = lines[0];
3071 if (out_bits != in_bits)
3072 destline = gst_line_cache_alloc_line (cache, out_line);
3074 /* FIXME, we can scale in the conversion matrix */
3076 GST_DEBUG ("8->16 line %d %p->%p", in_line, srcline, destline);
3077 video_orc_convert_u8_to_u16 (destline, srcline, width * 4);
3081 if (data->matrix_func) {
3082 GST_DEBUG ("matrix line %d %p", in_line, srcline);
3083 data->matrix_func (data, srcline);
3086 /* FIXME, dither here */
3087 if (out_bits == 8) {
3088 GST_DEBUG ("16->8 line %d %p->%p", in_line, srcline, destline);
3089 video_orc_convert_u16_to_u8 (destline, srcline, width * 4);
3092 if (data->matrix_func) {
3093 GST_DEBUG ("matrix line %d %p", in_line, destline);
3094 data->matrix_func (data, destline);
3097 gst_line_cache_add_line (cache, in_line, destline);
3103 do_alpha_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3106 gpointer *lines, destline;
3107 GstVideoConverter *convert = user_data;
3108 gint width = MIN (convert->in_width, convert->out_width);
3110 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3111 destline = lines[0];
3113 GST_DEBUG ("alpha line %d %p", in_line, destline);
3114 convert->alpha_func (convert, destline, width);
3116 gst_line_cache_add_line (cache, in_line, destline);
3122 do_convert_to_YUV_lines (GstLineCache * cache, gint idx, gint out_line,
3123 gint in_line, gpointer user_data)
3125 GstVideoConverter *convert = user_data;
3126 MatrixData *data = &convert->to_YUV_matrix;
3127 gpointer *lines, destline;
3129 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3130 destline = lines[0];
3132 if (convert->gamma_enc.gamma_func) {
3133 destline = gst_line_cache_alloc_line (cache, out_line);
3135 GST_DEBUG ("gamma encode line %d %p->%p", in_line, lines[0], destline);
3136 convert->gamma_enc.gamma_func (&convert->gamma_enc, destline, lines[0]);
3138 if (data->matrix_func) {
3139 GST_DEBUG ("to YUV line %d %p", in_line, destline);
3140 data->matrix_func (data, destline);
3142 gst_line_cache_add_line (cache, in_line, destline);
3148 do_downsample_lines (GstLineCache * cache, gint idx, gint out_line,
3149 gint in_line, gpointer user_data)
3151 GstVideoConverter *convert = user_data;
3153 gint i, start_line, n_lines;
3155 n_lines = convert->down_n_lines;
3156 start_line = in_line;
3157 if (start_line < n_lines + convert->down_offset)
3158 start_line += convert->down_offset;
3160 /* get the lines needed for chroma downsample */
3162 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
3165 if (convert->downsample[idx]) {
3166 GST_DEBUG ("downsample line %d %d-%d %p", in_line, start_line,
3167 start_line + n_lines - 1, lines[0]);
3168 gst_video_chroma_resample (convert->downsample[idx], lines,
3169 convert->out_width);
3172 for (i = 0; i < n_lines; i++)
3173 gst_line_cache_add_line (cache, start_line + i, lines[i]);
3179 do_dither_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3182 GstVideoConverter *convert = user_data;
3183 gpointer *lines, destline;
3185 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3186 destline = lines[0];
3188 if (convert->dither[idx]) {
3189 GST_DEBUG ("Dither line %d %p", in_line, destline);
3190 gst_video_dither_line (convert->dither[idx], destline, 0, out_line,
3191 convert->out_width);
3193 gst_line_cache_add_line (cache, in_line, destline);
3200 GstLineCache *pack_lines;
3203 gint pack_lines_count;
3205 gboolean identity_pack;
3206 gint lb_width, out_maxwidth;
3207 GstVideoFrame *dest;
3211 convert_generic_task (ConvertTask * task)
3215 for (i = task->h_0; i < task->h_1; i += task->pack_lines_count) {
3218 /* load the lines needed to pack */
3220 gst_line_cache_get_lines (task->pack_lines, task->idx, i + task->out_y,
3221 i, task->pack_lines_count);
3223 if (!task->identity_pack) {
3224 /* take away the border */
3225 guint8 *l = ((guint8 *) lines[0]) - task->lb_width;
3226 /* and pack into destination */
3227 GST_DEBUG ("pack line %d %p (%p)", i + task->out_y, lines[0], l);
3228 PACK_FRAME (task->dest, l, i + task->out_y, task->out_maxwidth);
3234 video_converter_generic (GstVideoConverter * convert, const GstVideoFrame * src,
3235 GstVideoFrame * dest)
3238 gint out_maxwidth, out_maxheight;
3239 gint out_x, out_y, out_height;
3240 gint pack_lines, pstride;
3243 ConvertTask **tasks_p;
3245 gint lines_per_thread;
3247 out_height = convert->out_height;
3248 out_maxwidth = convert->out_maxwidth;
3249 out_maxheight = convert->out_maxheight;
3251 out_x = convert->out_x;
3252 out_y = convert->out_y;
3255 convert->dest = dest;
3257 if (GST_VIDEO_FRAME_IS_INTERLACED (src)) {
3258 GST_DEBUG ("setup interlaced frame");
3259 convert->upsample = convert->upsample_i;
3260 convert->downsample = convert->downsample_i;
3261 convert->v_scaler = convert->v_scaler_i;
3263 GST_DEBUG ("setup progressive frame");
3264 convert->upsample = convert->upsample_p;
3265 convert->downsample = convert->downsample_p;
3266 convert->v_scaler = convert->v_scaler_p;
3268 if (convert->upsample[0]) {
3269 gst_video_chroma_resample_get_info (convert->upsample[0],
3270 &convert->up_n_lines, &convert->up_offset);
3272 convert->up_n_lines = 1;
3273 convert->up_offset = 0;
3275 if (convert->downsample[0]) {
3276 gst_video_chroma_resample_get_info (convert->downsample[0],
3277 &convert->down_n_lines, &convert->down_offset);
3279 convert->down_n_lines = 1;
3280 convert->down_offset = 0;
3283 pack_lines = convert->pack_nlines; /* only 1 for now */
3284 pstride = convert->pack_pstride;
3286 lb_width = out_x * pstride;
3288 if (convert->borderline) {
3289 /* FIXME we should try to avoid PACK_FRAME */
3290 for (i = 0; i < out_y; i++)
3291 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3294 n_threads = convert->conversion_runner->n_threads;
3295 tasks = convert->tasks[0] =
3296 g_renew (ConvertTask, convert->tasks[0], n_threads);
3297 tasks_p = convert->tasks_p[0] =
3298 g_renew (ConvertTask *, convert->tasks_p[0], n_threads);
3301 GST_ROUND_UP_N ((out_height + n_threads - 1) / n_threads, pack_lines);
3303 for (i = 0; i < n_threads; i++) {
3304 tasks[i].dest = dest;
3305 tasks[i].pack_lines = convert->pack_lines[i];
3307 tasks[i].pack_lines_count = pack_lines;
3308 tasks[i].out_y = out_y;
3309 tasks[i].identity_pack = convert->identity_pack;
3310 tasks[i].lb_width = lb_width;
3311 tasks[i].out_maxwidth = out_maxwidth;
3313 tasks[i].h_0 = i * lines_per_thread;
3314 tasks[i].h_1 = MIN ((i + 1) * lines_per_thread, out_height);
3316 tasks_p[i] = &tasks[i];
3319 gst_parallelized_task_runner_run (convert->conversion_runner,
3320 (GstParallelizedTaskFunc) convert_generic_task, (gpointer) tasks_p);
3322 if (convert->borderline) {
3323 for (i = out_y + out_height; i < out_maxheight; i++)
3324 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3326 if (convert->pack_pal) {
3327 memcpy (GST_VIDEO_FRAME_PLANE_DATA (dest, 1), convert->pack_pal,
3328 convert->pack_palsize);
3332 static void convert_fill_border (GstVideoConverter * convert,
3333 GstVideoFrame * dest);
3337 #define GET_LINE_OFFSETS(interlaced,line,l1,l2) \
3339 l1 = (line & 2 ? line - 1 : line); \
3348 const GstVideoFrame *src;
3349 GstVideoFrame *dest;
3350 gint height_0, height_1;
3353 gboolean interlaced;
3363 convert_I420_YUY2_task (FConvertTask * task)
3368 for (i = task->height_0; i < task->height_1; i += 2) {
3369 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3371 video_orc_convert_I420_YUY2 (FRAME_GET_LINE (task->dest, l1),
3372 FRAME_GET_LINE (task->dest, l2),
3373 FRAME_GET_Y_LINE (task->src, l1),
3374 FRAME_GET_Y_LINE (task->src, l2),
3375 FRAME_GET_U_LINE (task->src, i >> 1),
3376 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3381 convert_I420_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
3382 GstVideoFrame * dest)
3385 gint width = convert->in_width;
3386 gint height = convert->in_height;
3387 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3388 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3389 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3391 FConvertTask *tasks;
3392 FConvertTask **tasks_p;
3394 gint lines_per_thread;
3396 /* I420 has half as many chroma lines, as such we have to
3397 * always merge two into one. For non-interlaced these are
3398 * the two next to each other, for interlaced one is skipped
3401 h2 = GST_ROUND_DOWN_4 (height);
3403 h2 = GST_ROUND_DOWN_2 (height);
3405 n_threads = convert->conversion_runner->n_threads;
3406 tasks = convert->tasks[0] =
3407 g_renew (FConvertTask, convert->tasks[0], n_threads);
3408 tasks_p = convert->tasks_p[0] =
3409 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3411 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3413 for (i = 0; i < n_threads; i++) {
3415 tasks[i].dest = dest;
3417 tasks[i].interlaced = interlaced;
3418 tasks[i].width = width;
3420 tasks[i].height_0 = i * lines_per_thread;
3421 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3422 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3424 tasks_p[i] = &tasks[i];
3427 gst_parallelized_task_runner_run (convert->conversion_runner,
3428 (GstParallelizedTaskFunc) convert_I420_YUY2_task, (gpointer) tasks_p);
3430 /* now handle last lines. For interlaced these are up to 3 */
3432 for (i = h2; i < height; i++) {
3433 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3434 PACK_FRAME (dest, convert->tmpline[0], i, width);
3440 convert_I420_UYVY_task (FConvertTask * task)
3445 for (i = task->height_0; i < task->height_1; i += 2) {
3446 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3448 video_orc_convert_I420_UYVY (FRAME_GET_LINE (task->dest, l1),
3449 FRAME_GET_LINE (task->dest, l2),
3450 FRAME_GET_Y_LINE (task->src, l1),
3451 FRAME_GET_Y_LINE (task->src, l2),
3452 FRAME_GET_U_LINE (task->src, i >> 1),
3453 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3458 convert_I420_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
3459 GstVideoFrame * dest)
3462 gint width = convert->in_width;
3463 gint height = convert->in_height;
3464 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3465 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3466 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3468 FConvertTask *tasks;
3469 FConvertTask **tasks_p;
3471 gint lines_per_thread;
3473 /* I420 has half as many chroma lines, as such we have to
3474 * always merge two into one. For non-interlaced these are
3475 * the two next to each other, for interlaced one is skipped
3478 h2 = GST_ROUND_DOWN_4 (height);
3480 h2 = GST_ROUND_DOWN_2 (height);
3482 n_threads = convert->conversion_runner->n_threads;
3483 tasks = convert->tasks[0] =
3484 g_renew (FConvertTask, convert->tasks[0], n_threads);
3485 tasks_p = convert->tasks_p[0] =
3486 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3488 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3490 for (i = 0; i < n_threads; i++) {
3492 tasks[i].dest = dest;
3494 tasks[i].interlaced = interlaced;
3495 tasks[i].width = width;
3497 tasks[i].height_0 = i * lines_per_thread;
3498 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3499 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3501 tasks_p[i] = &tasks[i];
3504 gst_parallelized_task_runner_run (convert->conversion_runner,
3505 (GstParallelizedTaskFunc) convert_I420_UYVY_task, (gpointer) tasks_p);
3507 /* now handle last lines. For interlaced these are up to 3 */
3509 for (i = h2; i < height; i++) {
3510 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3511 PACK_FRAME (dest, convert->tmpline[0], i, width);
3517 convert_I420_AYUV_task (FConvertTask * task)
3522 for (i = task->height_0; i < task->height_1; i += 2) {
3523 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3525 video_orc_convert_I420_AYUV (FRAME_GET_LINE (task->dest, l1),
3526 FRAME_GET_LINE (task->dest, l2),
3527 FRAME_GET_Y_LINE (task->src, l1),
3528 FRAME_GET_Y_LINE (task->src, l2),
3529 FRAME_GET_U_LINE (task->src, i >> 1), FRAME_GET_V_LINE (task->src,
3530 i >> 1), task->alpha, task->width);
3535 convert_I420_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3536 GstVideoFrame * dest)
3539 gint width = convert->in_width;
3540 gint height = convert->in_height;
3541 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3542 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3543 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3544 guint8 alpha = MIN (convert->alpha_value, 255);
3546 FConvertTask *tasks;
3547 FConvertTask **tasks_p;
3549 gint lines_per_thread;
3551 /* I420 has half as many chroma lines, as such we have to
3552 * always merge two into one. For non-interlaced these are
3553 * the two next to each other, for interlaced one is skipped
3556 h2 = GST_ROUND_DOWN_4 (height);
3558 h2 = GST_ROUND_DOWN_2 (height);
3561 n_threads = convert->conversion_runner->n_threads;
3562 tasks = convert->tasks[0] =
3563 g_renew (FConvertTask, convert->tasks[0], n_threads);
3564 tasks_p = convert->tasks_p[0] =
3565 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3567 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3569 for (i = 0; i < n_threads; i++) {
3571 tasks[i].dest = dest;
3573 tasks[i].interlaced = interlaced;
3574 tasks[i].width = width;
3575 tasks[i].alpha = alpha;
3577 tasks[i].height_0 = i * lines_per_thread;
3578 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3579 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3581 tasks_p[i] = &tasks[i];
3584 gst_parallelized_task_runner_run (convert->conversion_runner,
3585 (GstParallelizedTaskFunc) convert_I420_AYUV_task, (gpointer) tasks_p);
3587 /* now handle last lines. For interlaced these are up to 3 */
3589 for (i = h2; i < height; i++) {
3590 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3592 convert_set_alpha_u8 (convert, convert->tmpline[0], width);
3593 PACK_FRAME (dest, convert->tmpline[0], i, width);
3599 convert_YUY2_I420_task (FConvertTask * task)
3604 for (i = task->height_0; i < task->height_1; i += 2) {
3605 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3607 video_orc_convert_YUY2_I420 (FRAME_GET_Y_LINE (task->dest, l1),
3608 FRAME_GET_Y_LINE (task->dest, l2),
3609 FRAME_GET_U_LINE (task->dest, i >> 1),
3610 FRAME_GET_V_LINE (task->dest, i >> 1),
3611 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
3612 (task->width + 1) / 2);
3617 convert_YUY2_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3618 GstVideoFrame * dest)
3621 gint width = convert->in_width;
3622 gint height = convert->in_height;
3623 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3624 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3625 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3627 FConvertTask *tasks;
3628 FConvertTask **tasks_p;
3630 gint lines_per_thread;
3632 /* I420 has half as many chroma lines, as such we have to
3633 * always merge two into one. For non-interlaced these are
3634 * the two next to each other, for interlaced one is skipped
3637 h2 = GST_ROUND_DOWN_4 (height);
3639 h2 = GST_ROUND_DOWN_2 (height);
3641 n_threads = convert->conversion_runner->n_threads;
3642 tasks = convert->tasks[0] =
3643 g_renew (FConvertTask, convert->tasks[0], n_threads);
3644 tasks_p = convert->tasks_p[0] =
3645 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3647 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3649 for (i = 0; i < n_threads; i++) {
3651 tasks[i].dest = dest;
3653 tasks[i].interlaced = interlaced;
3654 tasks[i].width = width;
3656 tasks[i].height_0 = i * lines_per_thread;
3657 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3658 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3660 tasks_p[i] = &tasks[i];
3663 gst_parallelized_task_runner_run (convert->conversion_runner,
3664 (GstParallelizedTaskFunc) convert_YUY2_I420_task, (gpointer) tasks_p);
3666 /* now handle last lines. For interlaced these are up to 3 */
3668 for (i = h2; i < height; i++) {
3669 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3670 PACK_FRAME (dest, convert->tmpline[0], i, width);
3676 convert_v210_I420_task (FConvertTask * task)
3680 guint8 *d_y1, *d_y2, *d_u, *d_v;
3681 const guint8 *s1, *s2;
3682 guint32 a0, a1, a2, a3;
3683 guint16 y0_1, y1_1, y2_1, y3_1, y4_1, y5_1;
3684 guint16 u0_1, u2_1, u4_1;
3685 guint16 v0_1, v2_1, v4_1;
3686 guint16 y0_2, y1_2, y2_2, y3_2, y4_2, y5_2;
3687 guint16 u0_2, u2_2, u4_2;
3688 guint16 v0_2, v2_2, v4_2;
3690 for (i = task->height_0; i < task->height_1; i += 2) {
3691 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3693 d_y1 = FRAME_GET_Y_LINE (task->dest, l1);
3694 d_y2 = FRAME_GET_Y_LINE (task->dest, l2);
3695 d_u = FRAME_GET_U_LINE (task->dest, i >> 1);
3696 d_v = FRAME_GET_V_LINE (task->dest, i >> 1);
3698 s1 = FRAME_GET_LINE (task->src, l1);
3699 s2 = FRAME_GET_LINE (task->src, l2);
3701 for (j = 0; j < task->width; j += 6) {
3702 a0 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 0);
3703 a1 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 4);
3704 a2 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 8);
3705 a3 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 12);
3707 u0_1 = ((a0 >> 0) & 0x3ff) >> 2;
3708 y0_1 = ((a0 >> 10) & 0x3ff) >> 2;
3709 v0_1 = ((a0 >> 20) & 0x3ff) >> 2;
3710 y1_1 = ((a1 >> 0) & 0x3ff) >> 2;
3712 u2_1 = ((a1 >> 10) & 0x3ff) >> 2;
3713 y2_1 = ((a1 >> 20) & 0x3ff) >> 2;
3714 v2_1 = ((a2 >> 0) & 0x3ff) >> 2;
3715 y3_1 = ((a2 >> 10) & 0x3ff) >> 2;
3717 u4_1 = ((a2 >> 20) & 0x3ff) >> 2;
3718 y4_1 = ((a3 >> 0) & 0x3ff) >> 2;
3719 v4_1 = ((a3 >> 10) & 0x3ff) >> 2;
3720 y5_1 = ((a3 >> 20) & 0x3ff) >> 2;
3722 a0 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 0);
3723 a1 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 4);
3724 a2 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 8);
3725 a3 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 12);
3727 u0_2 = ((a0 >> 0) & 0x3ff) >> 2;
3728 y0_2 = ((a0 >> 10) & 0x3ff) >> 2;
3729 v0_2 = ((a0 >> 20) & 0x3ff) >> 2;
3730 y1_2 = ((a1 >> 0) & 0x3ff) >> 2;
3732 u2_2 = ((a1 >> 10) & 0x3ff) >> 2;
3733 y2_2 = ((a1 >> 20) & 0x3ff) >> 2;
3734 v2_2 = ((a2 >> 0) & 0x3ff) >> 2;
3735 y3_2 = ((a2 >> 10) & 0x3ff) >> 2;
3737 u4_2 = ((a2 >> 20) & 0x3ff) >> 2;
3738 y4_2 = ((a3 >> 0) & 0x3ff) >> 2;
3739 v4_2 = ((a3 >> 10) & 0x3ff) >> 2;
3740 y5_2 = ((a3 >> 20) & 0x3ff) >> 2;
3744 d_u[j / 2] = (u0_1 + u0_2) / 2;
3745 d_v[j / 2] = (v0_1 + v0_2) / 2;
3747 if (j < task->width - 1) {
3752 if (j < task->width - 2) {
3755 d_u[j / 2 + 1] = (u2_1 + u2_2) / 2;
3756 d_v[j / 2 + 1] = (v2_1 + v2_2) / 2;
3759 if (j < task->width - 3) {
3764 if (j < task->width - 4) {
3767 d_u[j / 2 + 2] = (u4_1 + u4_2) / 2;
3768 d_v[j / 2 + 2] = (v4_1 + v4_2) / 2;
3771 if (j < task->width - 5) {
3780 convert_v210_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3781 GstVideoFrame * dest)
3784 gint width = convert->in_width;
3785 gint height = convert->in_height;
3786 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
3787 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
3788 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
3790 FConvertTask *tasks;
3791 FConvertTask **tasks_p;
3793 gint lines_per_thread;
3795 /* I420 has half as many chroma lines, as such we have to
3796 * always merge two into one. For non-interlaced these are
3797 * the two next to each other, for interlaced one is skipped
3800 h2 = GST_ROUND_DOWN_4 (height);
3802 h2 = GST_ROUND_DOWN_2 (height);
3804 n_threads = convert->conversion_runner->n_threads;
3805 tasks = convert->tasks[0] =
3806 g_renew (FConvertTask, convert->tasks[0], n_threads);
3807 tasks_p = convert->tasks_p[0] =
3808 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
3810 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3812 for (i = 0; i < n_threads; i++) {
3814 tasks[i].dest = dest;
3816 tasks[i].interlaced = interlaced;
3817 tasks[i].width = width;
3819 tasks[i].height_0 = i * lines_per_thread;
3820 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3821 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3823 tasks_p[i] = &tasks[i];
3826 gst_parallelized_task_runner_run (convert->conversion_runner,
3827 (GstParallelizedTaskFunc) convert_v210_I420_task, (gpointer) tasks_p);
3829 /* now handle last lines. For interlaced these are up to 3 */
3831 for (i = h2; i < height; i++) {
3832 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3833 PACK_FRAME (dest, convert->tmpline[0], i, width);
3840 const guint8 *s, *s2, *su, *sv;
3841 guint8 *d, *d2, *du, *dv;
3842 gint sstride, sustride, svstride;
3843 gint dstride, dustride, dvstride;
3847 } FConvertPlaneTask;
3850 convert_YUY2_AYUV_task (FConvertPlaneTask * task)
3852 video_orc_convert_YUY2_AYUV (task->d, task->dstride, task->s,
3853 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
3857 convert_YUY2_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3858 GstVideoFrame * dest)
3860 gint width = convert->in_width;
3861 gint height = convert->in_height;
3863 guint8 alpha = MIN (convert->alpha_value, 255);
3864 FConvertPlaneTask *tasks;
3865 FConvertPlaneTask **tasks_p;
3867 gint lines_per_thread;
3870 s = FRAME_GET_LINE (src, convert->in_y);
3871 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3872 d = FRAME_GET_LINE (dest, convert->out_y);
3873 d += (convert->out_x * 4);
3875 n_threads = convert->conversion_runner->n_threads;
3876 tasks = convert->tasks[0] =
3877 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
3878 tasks_p = convert->tasks_p[0] =
3879 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
3881 lines_per_thread = (height + n_threads - 1) / n_threads;
3883 for (i = 0; i < n_threads; i++) {
3884 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3885 tasks[i].sstride = FRAME_GET_STRIDE (src);
3886 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3887 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3889 tasks[i].width = width;
3890 tasks[i].height = (i + 1) * lines_per_thread;
3891 tasks[i].height = MIN (tasks[i].height, height);
3892 tasks[i].height -= i * lines_per_thread;
3893 tasks[i].alpha = alpha;
3895 tasks_p[i] = &tasks[i];
3898 gst_parallelized_task_runner_run (convert->conversion_runner,
3899 (GstParallelizedTaskFunc) convert_YUY2_AYUV_task, (gpointer) tasks_p);
3901 convert_fill_border (convert, dest);
3905 convert_YUY2_Y42B_task (FConvertPlaneTask * task)
3907 video_orc_convert_YUY2_Y42B (task->d, task->dstride, task->du,
3908 task->dustride, task->dv, task->dvstride,
3909 task->s, task->sstride, (task->width + 1) / 2, task->height);
3913 convert_YUY2_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
3914 GstVideoFrame * dest)
3916 gint width = convert->in_width;
3917 gint height = convert->in_height;
3918 guint8 *s, *dy, *du, *dv;
3919 FConvertPlaneTask *tasks;
3920 FConvertPlaneTask **tasks_p;
3922 gint lines_per_thread;
3925 s = FRAME_GET_LINE (src, convert->in_y);
3926 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3928 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3929 dy += convert->out_x;
3930 du = FRAME_GET_U_LINE (dest, convert->out_y);
3931 du += convert->out_x >> 1;
3932 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3933 dv += convert->out_x >> 1;
3935 n_threads = convert->conversion_runner->n_threads;
3936 tasks = convert->tasks[0] =
3937 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
3938 tasks_p = convert->tasks_p[0] =
3939 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
3941 lines_per_thread = (height + n_threads - 1) / n_threads;
3943 for (i = 0; i < n_threads; i++) {
3944 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3945 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3946 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3947 tasks[i].sstride = FRAME_GET_STRIDE (src);
3948 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3949 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3950 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3951 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3953 tasks[i].width = width;
3954 tasks[i].height = (i + 1) * lines_per_thread;
3955 tasks[i].height = MIN (tasks[i].height, height);
3956 tasks[i].height -= i * lines_per_thread;
3958 tasks_p[i] = &tasks[i];
3961 gst_parallelized_task_runner_run (convert->conversion_runner,
3962 (GstParallelizedTaskFunc) convert_YUY2_Y42B_task, (gpointer) tasks_p);
3964 convert_fill_border (convert, dest);
3968 convert_YUY2_Y444_task (FConvertPlaneTask * task)
3970 video_orc_convert_YUY2_Y444 (task->d,
3971 task->dstride, task->du,
3972 task->dustride, task->dv,
3973 task->dvstride, task->s,
3974 task->sstride, (task->width + 1) / 2, task->height);
3978 convert_YUY2_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
3979 GstVideoFrame * dest)
3981 gint width = convert->in_width;
3982 gint height = convert->in_height;
3983 guint8 *s, *dy, *du, *dv;
3984 FConvertPlaneTask *tasks;
3985 FConvertPlaneTask **tasks_p;
3987 gint lines_per_thread;
3990 s = FRAME_GET_LINE (src, convert->in_y);
3991 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3993 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3994 dy += convert->out_x;
3995 du = FRAME_GET_U_LINE (dest, convert->out_y);
3996 du += convert->out_x;
3997 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3998 dv += convert->out_x;
4000 n_threads = convert->conversion_runner->n_threads;
4001 tasks = convert->tasks[0] =
4002 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4003 tasks_p = convert->tasks_p[0] =
4004 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4006 lines_per_thread = (height + n_threads - 1) / n_threads;
4008 for (i = 0; i < n_threads; i++) {
4009 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4010 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4011 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4012 tasks[i].sstride = FRAME_GET_STRIDE (src);
4013 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4014 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4015 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4016 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4018 tasks[i].width = width;
4019 tasks[i].height = (i + 1) * lines_per_thread;
4020 tasks[i].height = MIN (tasks[i].height, height);
4021 tasks[i].height -= i * lines_per_thread;
4023 tasks_p[i] = &tasks[i];
4026 gst_parallelized_task_runner_run (convert->conversion_runner,
4027 (GstParallelizedTaskFunc) convert_YUY2_Y444_task, (gpointer) tasks_p);
4029 convert_fill_border (convert, dest);
4033 convert_v210_Y42B_task (FConvertPlaneTask * task)
4036 guint8 *d_y, *d_u, *d_v;
4038 guint32 a0, a1, a2, a3;
4039 guint16 y0, y1, y2, y3, y4, y5;
4043 for (i = 0; i < task->height; i++) {
4044 d_y = task->d + i * task->dstride;
4045 d_u = task->du + i * task->dustride;
4046 d_v = task->dv + i * task->dvstride;
4047 s = task->s + i * task->sstride;
4049 for (j = 0; j < task->width; j += 6) {
4050 a0 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 0);
4051 a1 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 4);
4052 a2 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 8);
4053 a3 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 12);
4055 u0 = ((a0 >> 0) & 0x3ff) >> 2;
4056 y0 = ((a0 >> 10) & 0x3ff) >> 2;
4057 v0 = ((a0 >> 20) & 0x3ff) >> 2;
4058 y1 = ((a1 >> 0) & 0x3ff) >> 2;
4060 u2 = ((a1 >> 10) & 0x3ff) >> 2;
4061 y2 = ((a1 >> 20) & 0x3ff) >> 2;
4062 v2 = ((a2 >> 0) & 0x3ff) >> 2;
4063 y3 = ((a2 >> 10) & 0x3ff) >> 2;
4065 u4 = ((a2 >> 20) & 0x3ff) >> 2;
4066 y4 = ((a3 >> 0) & 0x3ff) >> 2;
4067 v4 = ((a3 >> 10) & 0x3ff) >> 2;
4068 y5 = ((a3 >> 20) & 0x3ff) >> 2;
4074 if (j < task->width - 1) {
4078 if (j < task->width - 2) {
4080 d_u[j / 2 + 1] = u2;
4081 d_v[j / 2 + 1] = v2;
4084 if (j < task->width - 3) {
4088 if (j < task->width - 4) {
4090 d_u[j / 2 + 2] = u4;
4091 d_v[j / 2 + 2] = v4;
4094 if (j < task->width - 5) {
4102 convert_v210_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4103 GstVideoFrame * dest)
4105 gint width = convert->in_width;
4106 gint height = convert->in_height;
4107 guint8 *s, *dy, *du, *dv;
4108 FConvertPlaneTask *tasks;
4109 FConvertPlaneTask **tasks_p;
4111 gint lines_per_thread;
4114 s = FRAME_GET_LINE (src, convert->in_y);
4115 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4117 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4118 dy += convert->out_x;
4119 du = FRAME_GET_U_LINE (dest, convert->out_y);
4120 du += convert->out_x >> 1;
4121 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4122 dv += convert->out_x >> 1;
4124 n_threads = convert->conversion_runner->n_threads;
4125 tasks = convert->tasks[0] =
4126 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4127 tasks_p = convert->tasks_p[0] =
4128 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4130 lines_per_thread = (height + n_threads - 1) / n_threads;
4132 for (i = 0; i < n_threads; i++) {
4133 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4134 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4135 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4136 tasks[i].sstride = FRAME_GET_STRIDE (src);
4137 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4138 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4139 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4140 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4142 tasks[i].width = width;
4143 tasks[i].height = (i + 1) * lines_per_thread;
4144 tasks[i].height = MIN (tasks[i].height, height);
4145 tasks[i].height -= i * lines_per_thread;
4147 tasks_p[i] = &tasks[i];
4150 gst_parallelized_task_runner_run (convert->conversion_runner,
4151 (GstParallelizedTaskFunc) convert_v210_Y42B_task, (gpointer) tasks_p);
4153 convert_fill_border (convert, dest);
4157 convert_UYVY_I420_task (FConvertTask * task)
4162 for (i = task->height_0; i < task->height_1; i += 2) {
4163 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
4165 video_orc_convert_UYVY_I420 (FRAME_GET_COMP_LINE (task->dest, 0, l1),
4166 FRAME_GET_COMP_LINE (task->dest, 0, l2),
4167 FRAME_GET_COMP_LINE (task->dest, 1, i >> 1),
4168 FRAME_GET_COMP_LINE (task->dest, 2, i >> 1),
4169 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
4170 (task->width + 1) / 2);
4175 convert_UYVY_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
4176 GstVideoFrame * dest)
4179 gint width = convert->in_width;
4180 gint height = convert->in_height;
4181 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src)
4182 && (GST_VIDEO_INFO_INTERLACE_MODE (&src->info) !=
4183 GST_VIDEO_INTERLACE_MODE_ALTERNATE);
4185 FConvertTask *tasks;
4186 FConvertTask **tasks_p;
4188 gint lines_per_thread;
4190 /* I420 has half as many chroma lines, as such we have to
4191 * always merge two into one. For non-interlaced these are
4192 * the two next to each other, for interlaced one is skipped
4195 h2 = GST_ROUND_DOWN_4 (height);
4197 h2 = GST_ROUND_DOWN_2 (height);
4199 n_threads = convert->conversion_runner->n_threads;
4200 tasks = convert->tasks[0] =
4201 g_renew (FConvertTask, convert->tasks[0], n_threads);
4202 tasks_p = convert->tasks_p[0] =
4203 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
4205 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
4207 for (i = 0; i < n_threads; i++) {
4209 tasks[i].dest = dest;
4211 tasks[i].interlaced = interlaced;
4212 tasks[i].width = width;
4214 tasks[i].height_0 = i * lines_per_thread;
4215 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
4216 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
4218 tasks_p[i] = &tasks[i];
4221 gst_parallelized_task_runner_run (convert->conversion_runner,
4222 (GstParallelizedTaskFunc) convert_UYVY_I420_task, (gpointer) tasks_p);
4224 /* now handle last lines. For interlaced these are up to 3 */
4226 for (i = h2; i < height; i++) {
4227 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
4228 PACK_FRAME (dest, convert->tmpline[0], i, width);
4234 convert_UYVY_AYUV_task (FConvertPlaneTask * task)
4236 video_orc_convert_UYVY_AYUV (task->d, task->dstride, task->s,
4237 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
4241 convert_UYVY_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
4242 GstVideoFrame * dest)
4244 gint width = convert->in_width;
4245 gint height = convert->in_height;
4247 guint8 alpha = MIN (convert->alpha_value, 255);
4248 FConvertPlaneTask *tasks;
4249 FConvertPlaneTask **tasks_p;
4251 gint lines_per_thread;
4254 s = FRAME_GET_LINE (src, convert->in_y);
4255 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4256 d = FRAME_GET_LINE (dest, convert->out_y);
4257 d += (convert->out_x * 4);
4259 n_threads = convert->conversion_runner->n_threads;
4260 tasks = convert->tasks[0] =
4261 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4262 tasks_p = convert->tasks_p[0] =
4263 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4265 lines_per_thread = (height + n_threads - 1) / n_threads;
4267 for (i = 0; i < n_threads; i++) {
4268 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4269 tasks[i].sstride = FRAME_GET_STRIDE (src);
4270 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4271 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4273 tasks[i].width = width;
4274 tasks[i].height = (i + 1) * lines_per_thread;
4275 tasks[i].height = MIN (tasks[i].height, height);
4276 tasks[i].height -= i * lines_per_thread;
4277 tasks[i].alpha = alpha;
4279 tasks_p[i] = &tasks[i];
4282 gst_parallelized_task_runner_run (convert->conversion_runner,
4283 (GstParallelizedTaskFunc) convert_UYVY_AYUV_task, (gpointer) tasks_p);
4285 convert_fill_border (convert, dest);
4289 convert_UYVY_YUY2_task (FConvertPlaneTask * task)
4291 video_orc_convert_UYVY_YUY2 (task->d, task->dstride, task->s,
4292 task->sstride, (task->width + 1) / 2, task->height);
4296 convert_UYVY_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4297 GstVideoFrame * dest)
4299 gint width = convert->in_width;
4300 gint height = convert->in_height;
4302 FConvertPlaneTask *tasks;
4303 FConvertPlaneTask **tasks_p;
4305 gint lines_per_thread;
4308 s = FRAME_GET_LINE (src, convert->in_y);
4309 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4310 d = FRAME_GET_LINE (dest, convert->out_y);
4311 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4313 n_threads = convert->conversion_runner->n_threads;
4314 tasks = convert->tasks[0] =
4315 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4316 tasks_p = convert->tasks_p[0] =
4317 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4319 lines_per_thread = (height + n_threads - 1) / n_threads;
4321 for (i = 0; i < n_threads; i++) {
4322 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4323 tasks[i].sstride = FRAME_GET_STRIDE (src);
4324 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4325 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4327 tasks[i].width = width;
4328 tasks[i].height = (i + 1) * lines_per_thread;
4329 tasks[i].height = MIN (tasks[i].height, height);
4330 tasks[i].height -= i * lines_per_thread;
4332 tasks_p[i] = &tasks[i];
4335 gst_parallelized_task_runner_run (convert->conversion_runner,
4336 (GstParallelizedTaskFunc) convert_UYVY_YUY2_task, (gpointer) tasks_p);
4338 convert_fill_border (convert, dest);
4342 convert_v210_UYVY_task (FConvertPlaneTask * task)
4347 guint32 a0, a1, a2, a3;
4348 guint16 y0, y1, y2, y3, y4, y5;
4352 for (i = 0; i < task->height; i++) {
4353 d = task->d + i * task->dstride;
4354 s = task->s + i * task->sstride;
4356 for (j = 0; j < task->width; j += 6) {
4357 a0 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 0);
4358 a1 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 4);
4359 a2 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 8);
4360 a3 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 12);
4362 u0 = ((a0 >> 0) & 0x3ff) >> 2;
4363 y0 = ((a0 >> 10) & 0x3ff) >> 2;
4364 v0 = ((a0 >> 20) & 0x3ff) >> 2;
4365 y1 = ((a1 >> 0) & 0x3ff) >> 2;
4367 u2 = ((a1 >> 10) & 0x3ff) >> 2;
4368 y2 = ((a1 >> 20) & 0x3ff) >> 2;
4369 v2 = ((a2 >> 0) & 0x3ff) >> 2;
4370 y3 = ((a2 >> 10) & 0x3ff) >> 2;
4372 u4 = ((a2 >> 20) & 0x3ff) >> 2;
4373 y4 = ((a3 >> 0) & 0x3ff) >> 2;
4374 v4 = ((a3 >> 10) & 0x3ff) >> 2;
4375 y5 = ((a3 >> 20) & 0x3ff) >> 2;
4381 if (j < task->width - 1) {
4385 if (j < task->width - 2) {
4391 if (j < task->width - 3) {
4395 if (j < task->width - 4) {
4401 if (j < task->width - 5) {
4409 convert_v210_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4410 GstVideoFrame * dest)
4412 gint width = convert->in_width;
4413 gint height = convert->in_height;
4415 FConvertPlaneTask *tasks;
4416 FConvertPlaneTask **tasks_p;
4418 gint lines_per_thread;
4421 s = FRAME_GET_LINE (src, convert->in_y);
4422 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4423 d = FRAME_GET_LINE (dest, convert->out_y);
4424 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4426 n_threads = convert->conversion_runner->n_threads;
4427 tasks = convert->tasks[0] =
4428 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4429 tasks_p = convert->tasks_p[0] =
4430 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4432 lines_per_thread = (height + n_threads - 1) / n_threads;
4434 for (i = 0; i < n_threads; i++) {
4435 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4436 tasks[i].sstride = FRAME_GET_STRIDE (src);
4437 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4438 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4440 tasks[i].width = width;
4441 tasks[i].height = (i + 1) * lines_per_thread;
4442 tasks[i].height = MIN (tasks[i].height, height);
4443 tasks[i].height -= i * lines_per_thread;
4445 tasks_p[i] = &tasks[i];
4448 gst_parallelized_task_runner_run (convert->conversion_runner,
4449 (GstParallelizedTaskFunc) convert_v210_UYVY_task, (gpointer) tasks_p);
4451 convert_fill_border (convert, dest);
4455 convert_v210_YUY2_task (FConvertPlaneTask * task)
4460 guint32 a0, a1, a2, a3;
4461 guint16 y0, y1, y2, y3, y4, y5;
4465 for (i = 0; i < task->height; i++) {
4466 d = task->d + i * task->dstride;
4467 s = task->s + i * task->sstride;
4469 for (j = 0; j < task->width; j += 6) {
4470 a0 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 0);
4471 a1 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 4);
4472 a2 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 8);
4473 a3 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 12);
4475 u0 = ((a0 >> 0) & 0x3ff) >> 2;
4476 y0 = ((a0 >> 10) & 0x3ff) >> 2;
4477 v0 = ((a0 >> 20) & 0x3ff) >> 2;
4478 y1 = ((a1 >> 0) & 0x3ff) >> 2;
4480 u2 = ((a1 >> 10) & 0x3ff) >> 2;
4481 y2 = ((a1 >> 20) & 0x3ff) >> 2;
4482 v2 = ((a2 >> 0) & 0x3ff) >> 2;
4483 y3 = ((a2 >> 10) & 0x3ff) >> 2;
4485 u4 = ((a2 >> 20) & 0x3ff) >> 2;
4486 y4 = ((a3 >> 0) & 0x3ff) >> 2;
4487 v4 = ((a3 >> 10) & 0x3ff) >> 2;
4488 y5 = ((a3 >> 20) & 0x3ff) >> 2;
4494 if (j < task->width - 1) {
4498 if (j < task->width - 2) {
4504 if (j < task->width - 3) {
4508 if (j < task->width - 4) {
4514 if (j < task->width - 5) {
4522 convert_v210_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4523 GstVideoFrame * dest)
4525 gint width = convert->in_width;
4526 gint height = convert->in_height;
4528 FConvertPlaneTask *tasks;
4529 FConvertPlaneTask **tasks_p;
4531 gint lines_per_thread;
4534 s = FRAME_GET_LINE (src, convert->in_y);
4535 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4536 d = FRAME_GET_LINE (dest, convert->out_y);
4537 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4539 n_threads = convert->conversion_runner->n_threads;
4540 tasks = convert->tasks[0] =
4541 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4542 tasks_p = convert->tasks_p[0] =
4543 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4545 lines_per_thread = (height + n_threads - 1) / n_threads;
4547 for (i = 0; i < n_threads; i++) {
4548 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4549 tasks[i].sstride = FRAME_GET_STRIDE (src);
4550 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4551 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4553 tasks[i].width = width;
4554 tasks[i].height = (i + 1) * lines_per_thread;
4555 tasks[i].height = MIN (tasks[i].height, height);
4556 tasks[i].height -= i * lines_per_thread;
4558 tasks_p[i] = &tasks[i];
4561 gst_parallelized_task_runner_run (convert->conversion_runner,
4562 (GstParallelizedTaskFunc) convert_v210_YUY2_task, (gpointer) tasks_p);
4564 convert_fill_border (convert, dest);
4568 convert_UYVY_Y42B_task (FConvertPlaneTask * task)
4570 video_orc_convert_UYVY_Y42B (task->d, task->dstride, task->du,
4571 task->dustride, task->dv, task->dvstride,
4572 task->s, task->sstride, (task->width + 1) / 2, task->height);
4576 convert_UYVY_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4577 GstVideoFrame * dest)
4579 gint width = convert->in_width;
4580 gint height = convert->in_height;
4581 guint8 *s, *dy, *du, *dv;
4582 FConvertPlaneTask *tasks;
4583 FConvertPlaneTask **tasks_p;
4585 gint lines_per_thread;
4588 s = FRAME_GET_LINE (src, convert->in_y);
4589 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4591 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4592 dy += convert->out_x;
4593 du = FRAME_GET_U_LINE (dest, convert->out_y);
4594 du += convert->out_x >> 1;
4595 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4596 dv += convert->out_x >> 1;
4598 n_threads = convert->conversion_runner->n_threads;
4599 tasks = convert->tasks[0] =
4600 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4601 tasks_p = convert->tasks_p[0] =
4602 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4604 lines_per_thread = (height + n_threads - 1) / n_threads;
4606 for (i = 0; i < n_threads; i++) {
4607 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4608 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4609 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4610 tasks[i].sstride = FRAME_GET_STRIDE (src);
4611 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4612 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4613 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4614 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4616 tasks[i].width = width;
4617 tasks[i].height = (i + 1) * lines_per_thread;
4618 tasks[i].height = MIN (tasks[i].height, height);
4619 tasks[i].height -= i * lines_per_thread;
4621 tasks_p[i] = &tasks[i];
4624 gst_parallelized_task_runner_run (convert->conversion_runner,
4625 (GstParallelizedTaskFunc) convert_UYVY_Y42B_task, (gpointer) tasks_p);
4627 convert_fill_border (convert, dest);
4631 convert_UYVY_Y444_task (FConvertPlaneTask * task)
4633 video_orc_convert_UYVY_Y444 (task->d,
4634 task->dstride, task->du,
4635 task->dustride, task->dv,
4636 task->dvstride, task->s,
4637 task->sstride, (task->width + 1) / 2, task->height);
4641 convert_UYVY_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
4642 GstVideoFrame * dest)
4644 gint width = convert->in_width;
4645 gint height = convert->in_height;
4646 guint8 *s, *dy, *du, *dv;
4647 FConvertPlaneTask *tasks;
4648 FConvertPlaneTask **tasks_p;
4650 gint lines_per_thread;
4653 s = FRAME_GET_LINE (src, convert->in_y);
4654 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4656 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4657 dy += convert->out_x;
4658 du = FRAME_GET_U_LINE (dest, convert->out_y);
4659 du += convert->out_x;
4660 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4661 dv += convert->out_x;
4663 n_threads = convert->conversion_runner->n_threads;
4664 tasks = convert->tasks[0] =
4665 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4666 tasks_p = convert->tasks_p[0] =
4667 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4669 lines_per_thread = (height + n_threads - 1) / n_threads;
4671 for (i = 0; i < n_threads; i++) {
4672 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4673 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4674 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4675 tasks[i].sstride = FRAME_GET_STRIDE (src);
4676 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4677 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4678 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4679 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4681 tasks[i].width = width;
4682 tasks[i].height = (i + 1) * lines_per_thread;
4683 tasks[i].height = MIN (tasks[i].height, height);
4684 tasks[i].height -= i * lines_per_thread;
4686 tasks_p[i] = &tasks[i];
4689 gst_parallelized_task_runner_run (convert->conversion_runner,
4690 (GstParallelizedTaskFunc) convert_UYVY_Y444_task, (gpointer) tasks_p);
4692 convert_fill_border (convert, dest);
4696 convert_UYVY_GRAY8_task (FConvertPlaneTask * task)
4698 video_orc_convert_UYVY_GRAY8 (task->d, task->dstride, (guint16 *) task->s,
4699 task->sstride, task->width, task->height);
4703 convert_UYVY_GRAY8 (GstVideoConverter * convert, const GstVideoFrame * src,
4704 GstVideoFrame * dest)
4706 gint width = convert->in_width;
4707 gint height = convert->in_height;
4710 FConvertPlaneTask *tasks;
4711 FConvertPlaneTask **tasks_p;
4713 gint lines_per_thread;
4716 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
4717 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
4719 n_threads = convert->conversion_runner->n_threads;
4720 tasks = convert->tasks[0] =
4721 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4722 tasks_p = convert->tasks_p[0] =
4723 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4725 lines_per_thread = (height + n_threads - 1) / n_threads;
4727 for (i = 0; i < n_threads; i++) {
4728 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4729 tasks[i].sstride = FRAME_GET_STRIDE (src);
4730 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4731 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4733 tasks[i].width = width;
4734 tasks[i].height = (i + 1) * lines_per_thread;
4735 tasks[i].height = MIN (tasks[i].height, height);
4736 tasks[i].height -= i * lines_per_thread;
4738 tasks_p[i] = &tasks[i];
4741 gst_parallelized_task_runner_run (convert->conversion_runner,
4742 (GstParallelizedTaskFunc) convert_UYVY_GRAY8_task, (gpointer) tasks_p);
4744 convert_fill_border (convert, dest);
4748 convert_AYUV_I420_task (FConvertPlaneTask * task)
4750 video_orc_convert_AYUV_I420 (task->d,
4751 2 * task->dstride, task->d2,
4752 2 * task->dstride, task->du,
4753 task->dustride, task->dv,
4754 task->dvstride, task->s,
4755 2 * task->sstride, task->s2,
4756 2 * task->sstride, task->width / 2, task->height / 2);
4760 convert_AYUV_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
4761 GstVideoFrame * dest)
4763 gint width = convert->in_width;
4764 gint height = convert->in_height;
4765 guint8 *s1, *s2, *dy1, *dy2, *du, *dv;
4766 FConvertPlaneTask *tasks;
4767 FConvertPlaneTask **tasks_p;
4769 gint lines_per_thread;
4772 s1 = FRAME_GET_LINE (src, convert->in_y + 0);
4773 s1 += convert->in_x * 4;
4774 s2 = FRAME_GET_LINE (src, convert->in_y + 1);
4775 s2 += convert->in_x * 4;
4777 dy1 = FRAME_GET_Y_LINE (dest, convert->out_y + 0);
4778 dy1 += convert->out_x;
4779 dy2 = FRAME_GET_Y_LINE (dest, convert->out_y + 1);
4780 dy2 += convert->out_x;
4781 du = FRAME_GET_U_LINE (dest, convert->out_y >> 1);
4782 du += convert->out_x >> 1;
4783 dv = FRAME_GET_V_LINE (dest, convert->out_y >> 1);
4784 dv += convert->out_x >> 1;
4786 /* only for even width/height */
4788 n_threads = convert->conversion_runner->n_threads;
4789 tasks = convert->tasks[0] =
4790 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4791 tasks_p = convert->tasks_p[0] =
4792 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4794 lines_per_thread = GST_ROUND_UP_2 ((height + n_threads - 1) / n_threads);
4796 for (i = 0; i < n_threads; i++) {
4797 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4798 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4799 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4800 tasks[i].sstride = FRAME_GET_STRIDE (src);
4801 tasks[i].d = dy1 + i * lines_per_thread * tasks[i].dstride;
4802 tasks[i].d2 = dy2 + i * lines_per_thread * tasks[i].dstride;
4803 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride / 2;
4804 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride / 2;
4805 tasks[i].s = s1 + i * lines_per_thread * tasks[i].sstride;
4806 tasks[i].s2 = s2 + i * lines_per_thread * tasks[i].sstride;
4808 tasks[i].width = width;
4809 tasks[i].height = (i + 1) * lines_per_thread;
4810 tasks[i].height = MIN (tasks[i].height, height);
4811 tasks[i].height -= i * lines_per_thread;
4813 tasks_p[i] = &tasks[i];
4816 gst_parallelized_task_runner_run (convert->conversion_runner,
4817 (GstParallelizedTaskFunc) convert_AYUV_I420_task, (gpointer) tasks_p);
4819 convert_fill_border (convert, dest);
4823 convert_AYUV_YUY2_task (FConvertPlaneTask * task)
4825 video_orc_convert_AYUV_YUY2 (task->d, task->dstride, task->s,
4826 task->sstride, task->width / 2, task->height);
4830 convert_AYUV_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4831 GstVideoFrame * dest)
4833 gint width = convert->in_width;
4834 gint height = convert->in_height;
4836 FConvertPlaneTask *tasks;
4837 FConvertPlaneTask **tasks_p;
4839 gint lines_per_thread;
4842 s = FRAME_GET_LINE (src, convert->in_y);
4843 s += convert->in_x * 4;
4844 d = FRAME_GET_LINE (dest, convert->out_y);
4845 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4847 /* only for even width */
4848 n_threads = convert->conversion_runner->n_threads;
4849 tasks = convert->tasks[0] =
4850 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4851 tasks_p = convert->tasks_p[0] =
4852 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4854 lines_per_thread = (height + n_threads - 1) / n_threads;
4856 for (i = 0; i < n_threads; i++) {
4857 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4858 tasks[i].sstride = FRAME_GET_STRIDE (src);
4859 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4860 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4862 tasks[i].width = width;
4863 tasks[i].height = (i + 1) * lines_per_thread;
4864 tasks[i].height = MIN (tasks[i].height, height);
4865 tasks[i].height -= i * lines_per_thread;
4867 tasks_p[i] = &tasks[i];
4870 gst_parallelized_task_runner_run (convert->conversion_runner,
4871 (GstParallelizedTaskFunc) convert_AYUV_YUY2_task, (gpointer) tasks_p);
4873 convert_fill_border (convert, dest);
4877 convert_AYUV_UYVY_task (FConvertPlaneTask * task)
4879 video_orc_convert_AYUV_UYVY (task->d, task->dstride, task->s,
4880 task->sstride, task->width / 2, task->height);
4884 convert_AYUV_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4885 GstVideoFrame * dest)
4887 gint width = convert->in_width;
4888 gint height = convert->in_height;
4890 FConvertPlaneTask *tasks;
4891 FConvertPlaneTask **tasks_p;
4893 gint lines_per_thread;
4896 s = FRAME_GET_LINE (src, convert->in_y);
4897 s += convert->in_x * 4;
4898 d = FRAME_GET_LINE (dest, convert->out_y);
4899 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4901 /* only for even width */
4902 n_threads = convert->conversion_runner->n_threads;
4903 tasks = convert->tasks[0] =
4904 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4905 tasks_p = convert->tasks_p[0] =
4906 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4908 lines_per_thread = (height + n_threads - 1) / n_threads;
4910 for (i = 0; i < n_threads; i++) {
4911 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4912 tasks[i].sstride = FRAME_GET_STRIDE (src);
4913 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4914 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4916 tasks[i].width = width;
4917 tasks[i].height = (i + 1) * lines_per_thread;
4918 tasks[i].height = MIN (tasks[i].height, height);
4919 tasks[i].height -= i * lines_per_thread;
4921 tasks_p[i] = &tasks[i];
4924 gst_parallelized_task_runner_run (convert->conversion_runner,
4925 (GstParallelizedTaskFunc) convert_AYUV_UYVY_task, (gpointer) tasks_p);
4927 convert_fill_border (convert, dest);
4931 convert_AYUV_Y42B_task (FConvertPlaneTask * task)
4933 video_orc_convert_AYUV_Y42B (task->d, task->dstride, task->du,
4934 task->dustride, task->dv, task->dvstride,
4935 task->s, task->sstride, task->width / 2, task->height);
4939 convert_AYUV_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4940 GstVideoFrame * dest)
4942 gint width = convert->in_width;
4943 gint height = convert->in_height;
4944 guint8 *s, *dy, *du, *dv;
4945 FConvertPlaneTask *tasks;
4946 FConvertPlaneTask **tasks_p;
4948 gint lines_per_thread;
4951 s = FRAME_GET_LINE (src, convert->in_y);
4952 s += convert->in_x * 4;
4954 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4955 dy += convert->out_x;
4956 du = FRAME_GET_U_LINE (dest, convert->out_y);
4957 du += convert->out_x >> 1;
4958 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4959 dv += convert->out_x >> 1;
4961 /* only works for even width */
4962 n_threads = convert->conversion_runner->n_threads;
4963 tasks = convert->tasks[0] =
4964 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
4965 tasks_p = convert->tasks_p[0] =
4966 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
4968 lines_per_thread = (height + n_threads - 1) / n_threads;
4970 for (i = 0; i < n_threads; i++) {
4971 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4972 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4973 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4974 tasks[i].sstride = FRAME_GET_STRIDE (src);
4975 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4976 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4977 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4978 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4980 tasks[i].width = width;
4981 tasks[i].height = (i + 1) * lines_per_thread;
4982 tasks[i].height = MIN (tasks[i].height, height);
4983 tasks[i].height -= i * lines_per_thread;
4985 tasks_p[i] = &tasks[i];
4988 gst_parallelized_task_runner_run (convert->conversion_runner,
4989 (GstParallelizedTaskFunc) convert_AYUV_Y42B_task, (gpointer) tasks_p);
4991 convert_fill_border (convert, dest);
4995 convert_AYUV_Y444_task (FConvertPlaneTask * task)
4997 video_orc_convert_AYUV_Y444 (task->d, task->dstride, task->du,
4998 task->dustride, task->dv, task->dvstride,
4999 task->s, task->sstride, task->width, task->height);
5003 convert_AYUV_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
5004 GstVideoFrame * dest)
5006 gint width = convert->in_width;
5007 gint height = convert->in_height;
5008 guint8 *s, *dy, *du, *dv;
5009 FConvertPlaneTask *tasks;
5010 FConvertPlaneTask **tasks_p;
5012 gint lines_per_thread;
5015 s = FRAME_GET_LINE (src, convert->in_y);
5016 s += convert->in_x * 4;
5018 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
5019 dy += convert->out_x;
5020 du = FRAME_GET_U_LINE (dest, convert->out_y);
5021 du += convert->out_x;
5022 dv = FRAME_GET_V_LINE (dest, convert->out_y);
5023 dv += convert->out_x;
5025 n_threads = convert->conversion_runner->n_threads;
5026 tasks = convert->tasks[0] =
5027 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5028 tasks_p = convert->tasks_p[0] =
5029 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5031 lines_per_thread = (height + n_threads - 1) / n_threads;
5033 for (i = 0; i < n_threads; i++) {
5034 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
5035 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
5036 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
5037 tasks[i].sstride = FRAME_GET_STRIDE (src);
5038 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
5039 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
5040 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
5041 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5043 tasks[i].width = width;
5044 tasks[i].height = (i + 1) * lines_per_thread;
5045 tasks[i].height = MIN (tasks[i].height, height);
5046 tasks[i].height -= i * lines_per_thread;
5048 tasks_p[i] = &tasks[i];
5051 gst_parallelized_task_runner_run (convert->conversion_runner,
5052 (GstParallelizedTaskFunc) convert_AYUV_Y444_task, (gpointer) tasks_p);
5053 convert_fill_border (convert, dest);
5057 convert_Y42B_YUY2_task (FConvertPlaneTask * task)
5059 video_orc_convert_Y42B_YUY2 (task->d, task->dstride,
5060 task->s, task->sstride,
5061 task->su, task->sustride,
5062 task->sv, task->svstride, (task->width + 1) / 2, task->height);
5066 convert_Y42B_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
5067 GstVideoFrame * dest)
5069 gint width = convert->in_width;
5070 gint height = convert->in_height;
5071 guint8 *sy, *su, *sv, *d;
5072 FConvertPlaneTask *tasks;
5073 FConvertPlaneTask **tasks_p;
5075 gint lines_per_thread;
5078 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5079 sy += convert->in_x;
5080 su = FRAME_GET_U_LINE (src, convert->in_y);
5081 su += convert->in_x >> 1;
5082 sv = FRAME_GET_V_LINE (src, convert->in_y);
5083 sv += convert->in_x >> 1;
5085 d = FRAME_GET_LINE (dest, convert->out_y);
5086 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5088 n_threads = convert->conversion_runner->n_threads;
5089 tasks = convert->tasks[0] =
5090 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5091 tasks_p = convert->tasks_p[0] =
5092 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5094 lines_per_thread = (height + n_threads - 1) / n_threads;
5096 for (i = 0; i < n_threads; i++) {
5097 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5098 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5099 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5100 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5101 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5102 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5103 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5104 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5106 tasks[i].width = width;
5107 tasks[i].height = (i + 1) * lines_per_thread;
5108 tasks[i].height = MIN (tasks[i].height, height);
5109 tasks[i].height -= i * lines_per_thread;
5111 tasks_p[i] = &tasks[i];
5114 gst_parallelized_task_runner_run (convert->conversion_runner,
5115 (GstParallelizedTaskFunc) convert_Y42B_YUY2_task, (gpointer) tasks_p);
5117 convert_fill_border (convert, dest);
5121 convert_Y42B_UYVY_task (FConvertPlaneTask * task)
5123 video_orc_convert_Y42B_UYVY (task->d, task->dstride,
5124 task->s, task->sstride,
5125 task->su, task->sustride,
5126 task->sv, task->svstride, (task->width + 1) / 2, task->height);
5130 convert_Y42B_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
5131 GstVideoFrame * dest)
5133 gint width = convert->in_width;
5134 gint height = convert->in_height;
5135 guint8 *sy, *su, *sv, *d;
5136 FConvertPlaneTask *tasks;
5137 FConvertPlaneTask **tasks_p;
5139 gint lines_per_thread;
5142 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5143 sy += convert->in_x;
5144 su = FRAME_GET_U_LINE (src, convert->in_y);
5145 su += convert->in_x >> 1;
5146 sv = FRAME_GET_V_LINE (src, convert->in_y);
5147 sv += convert->in_x >> 1;
5149 d = FRAME_GET_LINE (dest, convert->out_y);
5150 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5152 n_threads = convert->conversion_runner->n_threads;
5153 tasks = convert->tasks[0] =
5154 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5155 tasks_p = convert->tasks_p[0] =
5156 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5158 lines_per_thread = (height + n_threads - 1) / n_threads;
5160 for (i = 0; i < n_threads; i++) {
5161 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5162 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5163 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5164 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5165 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5166 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5167 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5168 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5170 tasks[i].width = width;
5171 tasks[i].height = (i + 1) * lines_per_thread;
5172 tasks[i].height = MIN (tasks[i].height, height);
5173 tasks[i].height -= i * lines_per_thread;
5175 tasks_p[i] = &tasks[i];
5178 gst_parallelized_task_runner_run (convert->conversion_runner,
5179 (GstParallelizedTaskFunc) convert_Y42B_UYVY_task, (gpointer) tasks_p);
5181 convert_fill_border (convert, dest);
5185 convert_Y42B_AYUV_task (FConvertPlaneTask * task)
5187 video_orc_convert_Y42B_AYUV (task->d, task->dstride, task->s,
5191 task->sv, task->svstride, task->alpha, task->width / 2, task->height);
5195 convert_Y42B_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
5196 GstVideoFrame * dest)
5198 gint width = convert->in_width;
5199 gint height = convert->in_height;
5200 guint8 *sy, *su, *sv, *d;
5201 guint8 alpha = MIN (convert->alpha_value, 255);
5202 FConvertPlaneTask *tasks;
5203 FConvertPlaneTask **tasks_p;
5205 gint lines_per_thread;
5208 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5209 sy += convert->in_x;
5210 su = FRAME_GET_U_LINE (src, convert->in_y);
5211 su += convert->in_x >> 1;
5212 sv = FRAME_GET_V_LINE (src, convert->in_y);
5213 sv += convert->in_x >> 1;
5215 d = FRAME_GET_LINE (dest, convert->out_y);
5216 d += convert->out_x * 4;
5218 /* only for even width */
5219 n_threads = convert->conversion_runner->n_threads;
5220 tasks = convert->tasks[0] =
5221 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5222 tasks_p = convert->tasks_p[0] =
5223 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5225 lines_per_thread = (height + n_threads - 1) / n_threads;
5227 for (i = 0; i < n_threads; i++) {
5228 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5229 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5230 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5231 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5232 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5233 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5234 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5235 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5237 tasks[i].width = width;
5238 tasks[i].height = (i + 1) * lines_per_thread;
5239 tasks[i].height = MIN (tasks[i].height, height);
5240 tasks[i].height -= i * lines_per_thread;
5241 tasks[i].alpha = alpha;
5243 tasks_p[i] = &tasks[i];
5246 gst_parallelized_task_runner_run (convert->conversion_runner,
5247 (GstParallelizedTaskFunc) convert_Y42B_AYUV_task, (gpointer) tasks_p);
5249 convert_fill_border (convert, dest);
5253 convert_Y444_YUY2_task (FConvertPlaneTask * task)
5255 video_orc_convert_Y444_YUY2 (task->d, task->dstride, task->s,
5258 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
5262 convert_Y444_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
5263 GstVideoFrame * dest)
5265 gint width = convert->in_width;
5266 gint height = convert->in_height;
5267 guint8 *sy, *su, *sv, *d;
5268 FConvertPlaneTask *tasks;
5269 FConvertPlaneTask **tasks_p;
5271 gint lines_per_thread;
5274 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5275 sy += convert->in_x;
5276 su = FRAME_GET_U_LINE (src, convert->in_y);
5277 su += convert->in_x;
5278 sv = FRAME_GET_V_LINE (src, convert->in_y);
5279 sv += convert->in_x;
5281 d = FRAME_GET_LINE (dest, convert->out_y);
5282 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5284 n_threads = convert->conversion_runner->n_threads;
5285 tasks = convert->tasks[0] =
5286 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5287 tasks_p = convert->tasks_p[0] =
5288 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5290 lines_per_thread = (height + n_threads - 1) / n_threads;
5292 for (i = 0; i < n_threads; i++) {
5293 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5294 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5295 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5296 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5297 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5298 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5299 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5300 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5302 tasks[i].width = width;
5303 tasks[i].height = (i + 1) * lines_per_thread;
5304 tasks[i].height = MIN (tasks[i].height, height);
5305 tasks[i].height -= i * lines_per_thread;
5307 tasks_p[i] = &tasks[i];
5310 gst_parallelized_task_runner_run (convert->conversion_runner,
5311 (GstParallelizedTaskFunc) convert_Y444_YUY2_task, (gpointer) tasks_p);
5313 convert_fill_border (convert, dest);
5317 convert_Y444_UYVY_task (FConvertPlaneTask * task)
5319 video_orc_convert_Y444_UYVY (task->d, task->dstride, task->s,
5322 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
5326 convert_Y444_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
5327 GstVideoFrame * dest)
5329 gint width = convert->in_width;
5330 gint height = convert->in_height;
5331 guint8 *sy, *su, *sv, *d;
5332 FConvertPlaneTask *tasks;
5333 FConvertPlaneTask **tasks_p;
5335 gint lines_per_thread;
5338 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5339 sy += convert->in_x;
5340 su = FRAME_GET_U_LINE (src, convert->in_y);
5341 su += convert->in_x;
5342 sv = FRAME_GET_V_LINE (src, convert->in_y);
5343 sv += convert->in_x;
5345 d = FRAME_GET_LINE (dest, convert->out_y);
5346 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5348 n_threads = convert->conversion_runner->n_threads;
5349 tasks = convert->tasks[0] =
5350 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5351 tasks_p = convert->tasks_p[0] =
5352 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5354 lines_per_thread = (height + n_threads - 1) / n_threads;
5356 for (i = 0; i < n_threads; i++) {
5357 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5358 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5359 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5360 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5361 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5362 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5363 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5364 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5366 tasks[i].width = width;
5367 tasks[i].height = (i + 1) * lines_per_thread;
5368 tasks[i].height = MIN (tasks[i].height, height);
5369 tasks[i].height -= i * lines_per_thread;
5371 tasks_p[i] = &tasks[i];
5374 gst_parallelized_task_runner_run (convert->conversion_runner,
5375 (GstParallelizedTaskFunc) convert_Y444_UYVY_task, (gpointer) tasks_p);
5377 convert_fill_border (convert, dest);
5381 convert_Y444_AYUV_task (FConvertPlaneTask * task)
5383 video_orc_convert_Y444_AYUV (task->d, task->dstride, task->s,
5387 task->sv, task->svstride, task->alpha, task->width, task->height);
5391 convert_Y444_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
5392 GstVideoFrame * dest)
5394 gint width = convert->in_width;
5395 gint height = convert->in_height;
5396 guint8 *sy, *su, *sv, *d;
5397 guint8 alpha = MIN (convert->alpha_value, 255);
5398 FConvertPlaneTask *tasks;
5399 FConvertPlaneTask **tasks_p;
5401 gint lines_per_thread;
5404 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5405 sy += convert->in_x;
5406 su = FRAME_GET_U_LINE (src, convert->in_y);
5407 su += convert->in_x;
5408 sv = FRAME_GET_V_LINE (src, convert->in_y);
5409 sv += convert->in_x;
5411 d = FRAME_GET_LINE (dest, convert->out_y);
5412 d += convert->out_x * 4;
5414 n_threads = convert->conversion_runner->n_threads;
5415 tasks = convert->tasks[0] =
5416 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5417 tasks_p = convert->tasks_p[0] =
5418 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5420 lines_per_thread = (height + n_threads - 1) / n_threads;
5422 for (i = 0; i < n_threads; i++) {
5423 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5424 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5425 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5426 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5427 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5428 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5429 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5430 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5432 tasks[i].width = width;
5433 tasks[i].height = (i + 1) * lines_per_thread;
5434 tasks[i].height = MIN (tasks[i].height, height);
5435 tasks[i].height -= i * lines_per_thread;
5436 tasks[i].alpha = alpha;
5438 tasks_p[i] = &tasks[i];
5441 gst_parallelized_task_runner_run (convert->conversion_runner,
5442 (GstParallelizedTaskFunc) convert_Y444_AYUV_task, (gpointer) tasks_p);
5444 convert_fill_border (convert, dest);
5447 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5449 convert_AYUV_ARGB_task (FConvertPlaneTask * task)
5451 video_orc_convert_AYUV_ARGB (task->d, task->dstride, task->s,
5452 task->sstride, task->data->im[0][0], task->data->im[0][2],
5453 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5454 task->width, task->height);
5458 convert_AYUV_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5459 GstVideoFrame * dest)
5461 gint width = convert->in_width;
5462 gint height = convert->in_height;
5463 MatrixData *data = &convert->convert_matrix;
5465 FConvertPlaneTask *tasks;
5466 FConvertPlaneTask **tasks_p;
5468 gint lines_per_thread;
5471 s = FRAME_GET_LINE (src, convert->in_y);
5472 s += (convert->in_x * 4);
5473 d = FRAME_GET_LINE (dest, convert->out_y);
5474 d += (convert->out_x * 4);
5476 n_threads = convert->conversion_runner->n_threads;
5477 tasks = convert->tasks[0] =
5478 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5479 tasks_p = convert->tasks_p[0] =
5480 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5482 lines_per_thread = (height + n_threads - 1) / n_threads;
5484 for (i = 0; i < n_threads; i++) {
5485 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5486 tasks[i].sstride = FRAME_GET_STRIDE (src);
5487 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5488 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5490 tasks[i].width = width;
5491 tasks[i].height = (i + 1) * lines_per_thread;
5492 tasks[i].height = MIN (tasks[i].height, height);
5493 tasks[i].height -= i * lines_per_thread;
5494 tasks[i].data = data;
5496 tasks_p[i] = &tasks[i];
5499 gst_parallelized_task_runner_run (convert->conversion_runner,
5500 (GstParallelizedTaskFunc) convert_AYUV_ARGB_task, (gpointer) tasks_p);
5502 convert_fill_border (convert, dest);
5506 convert_AYUV_BGRA_task (FConvertPlaneTask * task)
5508 video_orc_convert_AYUV_BGRA (task->d, task->dstride, task->s,
5509 task->sstride, task->data->im[0][0], task->data->im[0][2],
5510 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5511 task->width, task->height);
5515 convert_AYUV_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
5516 GstVideoFrame * dest)
5518 gint width = convert->in_width;
5519 gint height = convert->in_height;
5520 MatrixData *data = &convert->convert_matrix;
5522 FConvertPlaneTask *tasks;
5523 FConvertPlaneTask **tasks_p;
5525 gint lines_per_thread;
5528 s = FRAME_GET_LINE (src, convert->in_y);
5529 s += (convert->in_x * 4);
5530 d = FRAME_GET_LINE (dest, convert->out_y);
5531 d += (convert->out_x * 4);
5533 n_threads = convert->conversion_runner->n_threads;
5534 tasks = convert->tasks[0] =
5535 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5536 tasks_p = convert->tasks_p[0] =
5537 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5539 lines_per_thread = (height + n_threads - 1) / n_threads;
5541 for (i = 0; i < n_threads; i++) {
5542 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5543 tasks[i].sstride = FRAME_GET_STRIDE (src);
5544 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5545 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5547 tasks[i].width = width;
5548 tasks[i].height = (i + 1) * lines_per_thread;
5549 tasks[i].height = MIN (tasks[i].height, height);
5550 tasks[i].height -= i * lines_per_thread;
5551 tasks[i].data = data;
5553 tasks_p[i] = &tasks[i];
5556 gst_parallelized_task_runner_run (convert->conversion_runner,
5557 (GstParallelizedTaskFunc) convert_AYUV_BGRA_task, (gpointer) tasks_p);
5559 convert_fill_border (convert, dest);
5563 convert_AYUV_ABGR_task (FConvertPlaneTask * task)
5565 video_orc_convert_AYUV_ABGR (task->d, task->dstride, task->s,
5566 task->sstride, task->data->im[0][0], task->data->im[0][2],
5567 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5568 task->width, task->height);
5572 convert_AYUV_ABGR (GstVideoConverter * convert, const GstVideoFrame * src,
5573 GstVideoFrame * dest)
5575 gint width = convert->in_width;
5576 gint height = convert->in_height;
5577 MatrixData *data = &convert->convert_matrix;
5579 FConvertPlaneTask *tasks;
5580 FConvertPlaneTask **tasks_p;
5582 gint lines_per_thread;
5585 s = FRAME_GET_LINE (src, convert->in_y);
5586 s += (convert->in_x * 4);
5587 d = FRAME_GET_LINE (dest, convert->out_y);
5588 d += (convert->out_x * 4);
5590 n_threads = convert->conversion_runner->n_threads;
5591 tasks = convert->tasks[0] =
5592 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5593 tasks_p = convert->tasks_p[0] =
5594 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5596 lines_per_thread = (height + n_threads - 1) / n_threads;
5598 for (i = 0; i < n_threads; i++) {
5599 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5600 tasks[i].sstride = FRAME_GET_STRIDE (src);
5601 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5602 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5604 tasks[i].width = width;
5605 tasks[i].height = (i + 1) * lines_per_thread;
5606 tasks[i].height = MIN (tasks[i].height, height);
5607 tasks[i].height -= i * lines_per_thread;
5608 tasks[i].data = data;
5610 tasks_p[i] = &tasks[i];
5613 gst_parallelized_task_runner_run (convert->conversion_runner,
5614 (GstParallelizedTaskFunc) convert_AYUV_ABGR_task, (gpointer) tasks_p);
5616 convert_fill_border (convert, dest);
5620 convert_AYUV_RGBA_task (FConvertPlaneTask * task)
5622 video_orc_convert_AYUV_RGBA (task->d, task->dstride, task->s,
5623 task->sstride, task->data->im[0][0], task->data->im[0][2],
5624 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5625 task->width, task->height);
5629 convert_AYUV_RGBA (GstVideoConverter * convert, const GstVideoFrame * src,
5630 GstVideoFrame * dest)
5632 gint width = convert->in_width;
5633 gint height = convert->in_height;
5634 MatrixData *data = &convert->convert_matrix;
5636 FConvertPlaneTask *tasks;
5637 FConvertPlaneTask **tasks_p;
5639 gint lines_per_thread;
5642 s = FRAME_GET_LINE (src, convert->in_y);
5643 s += (convert->in_x * 4);
5644 d = FRAME_GET_LINE (dest, convert->out_y);
5645 d += (convert->out_x * 4);
5647 n_threads = convert->conversion_runner->n_threads;
5648 tasks = convert->tasks[0] =
5649 g_renew (FConvertPlaneTask, convert->tasks[0], n_threads);
5650 tasks_p = convert->tasks_p[0] =
5651 g_renew (FConvertPlaneTask *, convert->tasks_p[0], n_threads);
5653 lines_per_thread = (height + n_threads - 1) / n_threads;
5655 for (i = 0; i < n_threads; i++) {
5656 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5657 tasks[i].sstride = FRAME_GET_STRIDE (src);
5658 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5659 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5661 tasks[i].width = width;
5662 tasks[i].height = (i + 1) * lines_per_thread;
5663 tasks[i].height = MIN (tasks[i].height, height);
5664 tasks[i].height -= i * lines_per_thread;
5665 tasks[i].data = data;
5667 tasks_p[i] = &tasks[i];
5670 gst_parallelized_task_runner_run (convert->conversion_runner,
5671 (GstParallelizedTaskFunc) convert_AYUV_RGBA_task, (gpointer) tasks_p);
5673 convert_fill_border (convert, dest);
5678 convert_I420_BGRA_task (FConvertTask * task)
5682 for (i = task->height_0; i < task->height_1; i++) {
5683 guint8 *sy, *su, *sv, *d;
5685 d = FRAME_GET_LINE (task->dest, i + task->out_y);
5686 d += (task->out_x * 4);
5687 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5689 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5690 su += (task->in_x >> 1);
5691 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5692 sv += (task->in_x >> 1);
5694 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5695 video_orc_convert_I420_BGRA (d, sy, su, sv,
5696 task->data->im[0][0], task->data->im[0][2],
5697 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5700 video_orc_convert_I420_ARGB (d, sy, su, sv,
5701 task->data->im[0][0], task->data->im[0][2],
5702 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5709 convert_I420_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
5710 GstVideoFrame * dest)
5713 gint width = convert->in_width;
5714 gint height = convert->in_height;
5715 MatrixData *data = &convert->convert_matrix;
5716 FConvertTask *tasks;
5717 FConvertTask **tasks_p;
5719 gint lines_per_thread;
5721 n_threads = convert->conversion_runner->n_threads;
5722 tasks = convert->tasks[0] =
5723 g_renew (FConvertTask, convert->tasks[0], n_threads);
5724 tasks_p = convert->tasks_p[0] =
5725 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
5727 lines_per_thread = (height + n_threads - 1) / n_threads;
5729 for (i = 0; i < n_threads; i++) {
5731 tasks[i].dest = dest;
5733 tasks[i].width = width;
5734 tasks[i].data = data;
5735 tasks[i].in_x = convert->in_x;
5736 tasks[i].in_y = convert->in_y;
5737 tasks[i].out_x = convert->out_x;
5738 tasks[i].out_y = convert->out_y;
5740 tasks[i].height_0 = i * lines_per_thread;
5741 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5742 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5744 tasks_p[i] = &tasks[i];
5747 gst_parallelized_task_runner_run (convert->conversion_runner,
5748 (GstParallelizedTaskFunc) convert_I420_BGRA_task, (gpointer) tasks_p);
5750 convert_fill_border (convert, dest);
5754 convert_I420_ARGB_task (FConvertTask * task)
5758 for (i = task->height_0; i < task->height_1; i++) {
5759 guint8 *sy, *su, *sv, *d;
5761 d = FRAME_GET_LINE (task->dest, i + task->out_y);
5762 d += (task->out_x * 4);
5763 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5765 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5766 su += (task->in_x >> 1);
5767 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5768 sv += (task->in_x >> 1);
5770 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5771 video_orc_convert_I420_ARGB (d, sy, su, sv,
5772 task->data->im[0][0], task->data->im[0][2],
5773 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5776 video_orc_convert_I420_BGRA (d, sy, su, sv,
5777 task->data->im[0][0], task->data->im[0][2],
5778 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5785 convert_I420_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5786 GstVideoFrame * dest)
5789 gint width = convert->in_width;
5790 gint height = convert->in_height;
5791 MatrixData *data = &convert->convert_matrix;
5792 FConvertTask *tasks;
5793 FConvertTask **tasks_p;
5795 gint lines_per_thread;
5797 n_threads = convert->conversion_runner->n_threads;
5798 tasks = convert->tasks[0] =
5799 g_renew (FConvertTask, convert->tasks[0], n_threads);
5800 tasks_p = convert->tasks_p[0] =
5801 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
5803 lines_per_thread = (height + n_threads - 1) / n_threads;
5805 for (i = 0; i < n_threads; i++) {
5807 tasks[i].dest = dest;
5809 tasks[i].width = width;
5810 tasks[i].data = data;
5811 tasks[i].in_x = convert->in_x;
5812 tasks[i].in_y = convert->in_y;
5813 tasks[i].out_x = convert->out_x;
5814 tasks[i].out_y = convert->out_y;
5816 tasks[i].height_0 = i * lines_per_thread;
5817 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5818 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5820 tasks_p[i] = &tasks[i];
5823 gst_parallelized_task_runner_run (convert->conversion_runner,
5824 (GstParallelizedTaskFunc) convert_I420_ARGB_task, (gpointer) tasks_p);
5826 convert_fill_border (convert, dest);
5830 convert_I420_pack_ARGB_task (FConvertTask * task)
5833 gpointer d[GST_VIDEO_MAX_PLANES];
5835 d[0] = FRAME_GET_LINE (task->dest, 0);
5838 task->out_x * GST_VIDEO_FORMAT_INFO_PSTRIDE (task->dest->info.finfo, 0);
5840 for (i = task->height_0; i < task->height_1; i++) {
5841 guint8 *sy, *su, *sv;
5843 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5845 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5846 su += (task->in_x >> 1);
5847 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5848 sv += (task->in_x >> 1);
5850 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5851 video_orc_convert_I420_ARGB (task->tmpline, sy, su, sv,
5852 task->data->im[0][0], task->data->im[0][2],
5853 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5856 video_orc_convert_I420_BGRA (task->tmpline, sy, su, sv,
5857 task->data->im[0][0], task->data->im[0][2],
5858 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5861 task->dest->info.finfo->pack_func (task->dest->info.finfo,
5862 (GST_VIDEO_FRAME_IS_INTERLACED (task->dest) ?
5863 GST_VIDEO_PACK_FLAG_INTERLACED :
5864 GST_VIDEO_PACK_FLAG_NONE),
5865 task->tmpline, 0, d, task->dest->info.stride,
5866 task->dest->info.chroma_site, i + task->out_y, task->width);
5871 convert_I420_pack_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5872 GstVideoFrame * dest)
5875 gint width = convert->in_width;
5876 gint height = convert->in_height;
5877 MatrixData *data = &convert->convert_matrix;
5878 FConvertTask *tasks;
5879 FConvertTask **tasks_p;
5881 gint lines_per_thread;
5883 n_threads = convert->conversion_runner->n_threads;
5884 tasks = convert->tasks[0] =
5885 g_renew (FConvertTask, convert->tasks[0], n_threads);
5886 tasks_p = convert->tasks_p[0] =
5887 g_renew (FConvertTask *, convert->tasks_p[0], n_threads);
5889 lines_per_thread = (height + n_threads - 1) / n_threads;
5891 for (i = 0; i < n_threads; i++) {
5893 tasks[i].dest = dest;
5895 tasks[i].width = width;
5896 tasks[i].data = data;
5897 tasks[i].in_x = convert->in_x;
5898 tasks[i].in_y = convert->in_y;
5899 tasks[i].out_x = convert->out_x;
5900 tasks[i].out_y = convert->out_y;
5901 tasks[i].tmpline = convert->tmpline[i];
5903 tasks[i].height_0 = i * lines_per_thread;
5904 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5905 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5907 tasks_p[i] = &tasks[i];
5910 gst_parallelized_task_runner_run (convert->conversion_runner,
5911 (GstParallelizedTaskFunc) convert_I420_pack_ARGB_task,
5912 (gpointer) tasks_p);
5914 convert_fill_border (convert, dest);
5918 memset_u24 (guint8 * data, guint8 col[3], unsigned int n)
5922 for (i = 0; i < n; i++) {
5931 memset_u32_16 (guint8 * data, guint8 col[4], unsigned int n)
5935 for (i = 0; i < n; i += 2) {
5946 #define MAKE_BORDER_FUNC(func) \
5947 for (i = 0; i < out_y; i++) \
5948 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
5949 if (rb_width || lb_width) { \
5950 for (i = 0; i < out_height; i++) { \
5951 guint8 *d = FRAME_GET_PLANE_LINE (dest, k, i + out_y); \
5953 func (d, col, lb_width); \
5955 func (d + (pstride * r_border), col, rb_width); \
5958 for (i = out_y + out_height; i < out_maxheight; i++) \
5959 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
5962 convert_fill_border (GstVideoConverter * convert, GstVideoFrame * dest)
5965 const GstVideoFormatInfo *out_finfo;
5967 if (!convert->fill_border || !convert->borderline)
5970 out_finfo = convert->out_info.finfo;
5972 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
5974 for (k = 0; k < n_planes; k++) {
5975 gint comp[GST_VIDEO_MAX_COMPONENTS];
5976 gint i, out_x, out_y, out_width, out_height, pstride, pgroup;
5977 gint r_border, lb_width, rb_width;
5978 gint out_maxwidth, out_maxheight;
5981 gst_video_format_info_component (out_finfo, k, comp);
5982 out_x = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, comp[0],
5984 out_y = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, comp[0],
5986 out_width = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, comp[0],
5987 convert->out_width);
5988 out_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, comp[0],
5989 convert->out_height);
5990 out_maxwidth = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, comp[0],
5991 convert->out_maxwidth);
5992 out_maxheight = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, comp[0],
5993 convert->out_maxheight);
5995 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, comp[0]);
5997 switch (GST_VIDEO_FORMAT_INFO_FORMAT (out_finfo)) {
5998 case GST_VIDEO_FORMAT_YUY2:
5999 case GST_VIDEO_FORMAT_YVYU:
6000 case GST_VIDEO_FORMAT_UYVY:
6002 out_maxwidth = GST_ROUND_UP_2 (out_maxwidth);
6009 r_border = out_x + out_width;
6010 rb_width = out_maxwidth - r_border;
6013 borders = &convert->borders[k];
6018 guint8 col = ((guint8 *) borders)[0];
6019 MAKE_BORDER_FUNC (memset);
6024 guint16 col = ((guint16 *) borders)[0];
6025 MAKE_BORDER_FUNC (video_orc_splat_u16);
6031 col[0] = ((guint8 *) borders)[0];
6032 col[1] = ((guint8 *) borders)[1];
6033 col[2] = ((guint8 *) borders)[2];
6034 MAKE_BORDER_FUNC (memset_u24);
6039 guint32 col = ((guint32 *) borders)[0];
6040 MAKE_BORDER_FUNC (video_orc_splat_u32);
6045 guint64 col = ((guint64 *) borders)[0];
6046 MAKE_BORDER_FUNC (video_orc_splat_u64);
6052 col[0] = ((guint8 *) borders)[0];
6053 col[2] = ((guint8 *) borders)[2];
6054 col[1] = ((guint8 *) borders)[r_border & 1 ? 3 : 1];
6055 col[3] = ((guint8 *) borders)[r_border & 1 ? 1 : 3];
6056 MAKE_BORDER_FUNC (memset_u32_16);
6067 const guint8 *s, *s2;
6069 gint sstride, dstride;
6075 convert_plane_fill_task (FSimpleScaleTask * task)
6077 video_orc_memset_2d (task->d, task->dstride,
6078 task->fill, task->width, task->height);
6082 convert_plane_fill (GstVideoConverter * convert,
6083 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6086 FSimpleScaleTask *tasks;
6087 FSimpleScaleTask **tasks_p;
6089 gint lines_per_thread;
6092 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6093 d += convert->fout_x[plane];
6095 n_threads = convert->conversion_runner->n_threads;
6096 tasks = convert->tasks[plane] =
6097 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6098 tasks_p = convert->tasks_p[plane] =
6099 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6100 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6102 for (i = 0; i < n_threads; i++) {
6103 tasks[i].d = d + i * lines_per_thread * convert->fout_width[plane];
6105 tasks[i].fill = convert->ffill[plane];
6106 tasks[i].width = convert->fout_width[plane];
6107 tasks[i].height = (i + 1) * lines_per_thread;
6108 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6109 tasks[i].height -= i * lines_per_thread;
6110 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
6112 tasks_p[i] = &tasks[i];
6115 gst_parallelized_task_runner_run (convert->conversion_runner,
6116 (GstParallelizedTaskFunc) convert_plane_fill_task, (gpointer) tasks_p);
6120 convert_plane_h_double_task (FSimpleScaleTask * task)
6122 video_orc_planar_chroma_422_444 (task->d,
6123 task->dstride, task->s, task->sstride, task->width / 2, task->height);
6127 convert_plane_h_double (GstVideoConverter * convert,
6128 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6131 gint splane = convert->fsplane[plane];
6132 FSimpleScaleTask *tasks;
6133 FSimpleScaleTask **tasks_p;
6135 gint lines_per_thread;
6138 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6139 s += convert->fin_x[splane];
6140 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6141 d += convert->fout_x[plane];
6143 n_threads = convert->conversion_runner->n_threads;
6144 tasks = convert->tasks[plane] =
6145 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6146 tasks_p = convert->tasks_p[plane] =
6147 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6148 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6150 for (i = 0; i < n_threads; i++) {
6151 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
6152 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6154 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
6155 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
6157 tasks[i].width = convert->fout_width[plane];
6158 tasks[i].height = (i + 1) * lines_per_thread;
6159 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6160 tasks[i].height -= i * lines_per_thread;
6162 tasks_p[i] = &tasks[i];
6165 gst_parallelized_task_runner_run (convert->conversion_runner,
6166 (GstParallelizedTaskFunc) convert_plane_h_double_task,
6167 (gpointer) tasks_p);
6171 convert_plane_h_halve_task (FSimpleScaleTask * task)
6173 video_orc_planar_chroma_444_422 (task->d,
6174 task->dstride, task->s, task->sstride, task->width, task->height);
6178 convert_plane_h_halve (GstVideoConverter * convert,
6179 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6182 gint splane = convert->fsplane[plane];
6183 FSimpleScaleTask *tasks;
6184 FSimpleScaleTask **tasks_p;
6186 gint lines_per_thread;
6189 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6190 s += convert->fin_x[splane];
6191 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6192 d += convert->fout_x[plane];
6194 n_threads = convert->conversion_runner->n_threads;
6195 tasks = convert->tasks[plane] =
6196 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6197 tasks_p = convert->tasks_p[plane] =
6198 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6199 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6201 for (i = 0; i < n_threads; i++) {
6202 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
6203 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6205 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
6206 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
6208 tasks[i].width = convert->fout_width[plane];
6209 tasks[i].height = (i + 1) * lines_per_thread;
6210 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6211 tasks[i].height -= i * lines_per_thread;
6213 tasks_p[i] = &tasks[i];
6216 gst_parallelized_task_runner_run (convert->conversion_runner,
6217 (GstParallelizedTaskFunc) convert_plane_h_halve_task, (gpointer) tasks_p);
6221 convert_plane_v_double_task (FSimpleScaleTask * task)
6223 video_orc_planar_chroma_420_422 (task->d, 2 * task->dstride, task->d2,
6224 2 * task->dstride, task->s, task->sstride, task->width, task->height / 2);
6228 convert_plane_v_double (GstVideoConverter * convert,
6229 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6231 guint8 *s, *d1, *d2;
6232 gint ds, splane = convert->fsplane[plane];
6233 FSimpleScaleTask *tasks;
6234 FSimpleScaleTask **tasks_p;
6236 gint lines_per_thread;
6239 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6240 s += convert->fin_x[splane];
6241 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6242 d1 += convert->fout_x[plane];
6243 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
6244 d2 += convert->fout_x[plane];
6245 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
6247 n_threads = convert->conversion_runner->n_threads;
6248 tasks = convert->tasks[plane] =
6249 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6250 tasks_p = convert->tasks_p[plane] =
6251 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6253 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
6256 for (i = 0; i < n_threads; i++) {
6257 tasks[i].d = d1 + i * lines_per_thread * ds;
6258 tasks[i].d2 = d2 + i * lines_per_thread * ds;
6259 tasks[i].dstride = ds;
6260 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6261 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride / 2;
6263 tasks[i].width = convert->fout_width[plane];
6264 tasks[i].height = (i + 1) * lines_per_thread;
6265 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6266 tasks[i].height -= i * lines_per_thread;
6268 tasks_p[i] = &tasks[i];
6271 gst_parallelized_task_runner_run (convert->conversion_runner,
6272 (GstParallelizedTaskFunc) convert_plane_v_double_task,
6273 (gpointer) tasks_p);
6277 convert_plane_v_halve_task (FSimpleScaleTask * task)
6279 video_orc_planar_chroma_422_420 (task->d, task->dstride, task->s,
6280 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
6285 convert_plane_v_halve (GstVideoConverter * convert,
6286 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6288 guint8 *s1, *s2, *d;
6289 gint ss, ds, splane = convert->fsplane[plane];
6290 FSimpleScaleTask *tasks;
6291 FSimpleScaleTask **tasks_p;
6293 gint lines_per_thread;
6296 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6297 s1 += convert->fin_x[splane];
6298 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
6299 s2 += convert->fin_x[splane];
6300 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6301 d += convert->fout_x[plane];
6303 ss = FRAME_GET_PLANE_STRIDE (src, splane);
6304 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
6306 n_threads = convert->conversion_runner->n_threads;
6307 tasks = convert->tasks[plane] =
6308 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6309 tasks_p = convert->tasks_p[plane] =
6310 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6311 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6313 for (i = 0; i < n_threads; i++) {
6314 tasks[i].d = d + i * lines_per_thread * ds;
6315 tasks[i].dstride = ds;
6316 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
6317 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
6318 tasks[i].sstride = ss;
6320 tasks[i].width = convert->fout_width[plane];
6321 tasks[i].height = (i + 1) * lines_per_thread;
6322 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6323 tasks[i].height -= i * lines_per_thread;
6325 tasks_p[i] = &tasks[i];
6328 gst_parallelized_task_runner_run (convert->conversion_runner,
6329 (GstParallelizedTaskFunc) convert_plane_v_halve_task, (gpointer) tasks_p);
6333 convert_plane_hv_double_task (FSimpleScaleTask * task)
6335 video_orc_planar_chroma_420_444 (task->d, 2 * task->dstride, task->d2,
6336 2 * task->dstride, task->s, task->sstride, (task->width + 1) / 2,
6341 convert_plane_hv_double (GstVideoConverter * convert,
6342 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6344 guint8 *s, *d1, *d2;
6345 gint ss, ds, splane = convert->fsplane[plane];
6346 FSimpleScaleTask *tasks;
6347 FSimpleScaleTask **tasks_p;
6349 gint lines_per_thread;
6352 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6353 s += convert->fin_x[splane];
6354 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6355 d1 += convert->fout_x[plane];
6356 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
6357 d2 += convert->fout_x[plane];
6358 ss = FRAME_GET_PLANE_STRIDE (src, splane);
6359 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
6361 n_threads = convert->conversion_runner->n_threads;
6362 tasks = convert->tasks[plane] =
6363 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6364 tasks_p = convert->tasks_p[plane] =
6365 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6367 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
6370 for (i = 0; i < n_threads; i++) {
6371 tasks[i].d = d1 + i * lines_per_thread * ds;
6372 tasks[i].d2 = d2 + i * lines_per_thread * ds;
6373 tasks[i].dstride = ds;
6374 tasks[i].sstride = ss;
6375 tasks[i].s = s + i * lines_per_thread * ss / 2;
6377 tasks[i].width = convert->fout_width[plane];
6378 tasks[i].height = (i + 1) * lines_per_thread;
6379 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6380 tasks[i].height -= i * lines_per_thread;
6382 tasks_p[i] = &tasks[i];
6385 gst_parallelized_task_runner_run (convert->conversion_runner,
6386 (GstParallelizedTaskFunc) convert_plane_hv_double_task,
6387 (gpointer) tasks_p);
6391 convert_plane_hv_halve_task (FSimpleScaleTask * task)
6393 video_orc_planar_chroma_444_420 (task->d, task->dstride, task->s,
6394 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
6399 convert_plane_hv_halve (GstVideoConverter * convert,
6400 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6402 guint8 *s1, *s2, *d;
6403 gint ss, ds, splane = convert->fsplane[plane];
6404 FSimpleScaleTask *tasks;
6405 FSimpleScaleTask **tasks_p;
6407 gint lines_per_thread;
6410 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6411 s1 += convert->fin_x[splane];
6412 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
6413 s2 += convert->fin_x[splane];
6414 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6415 d += convert->fout_x[plane];
6416 ss = FRAME_GET_PLANE_STRIDE (src, splane);
6417 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
6419 n_threads = convert->conversion_runner->n_threads;
6420 tasks = convert->tasks[plane] =
6421 g_renew (FSimpleScaleTask, convert->tasks[plane], n_threads);
6422 tasks_p = convert->tasks_p[plane] =
6423 g_renew (FSimpleScaleTask *, convert->tasks_p[plane], n_threads);
6424 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6426 for (i = 0; i < n_threads; i++) {
6427 tasks[i].d = d + i * lines_per_thread * ds;
6428 tasks[i].dstride = ds;
6429 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
6430 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
6431 tasks[i].sstride = ss;
6433 tasks[i].width = convert->fout_width[plane];
6434 tasks[i].height = (i + 1) * lines_per_thread;
6435 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6436 tasks[i].height -= i * lines_per_thread;
6438 tasks_p[i] = &tasks[i];
6441 gst_parallelized_task_runner_run (convert->conversion_runner,
6442 (GstParallelizedTaskFunc) convert_plane_hv_halve_task,
6443 (gpointer) tasks_p);
6448 GstVideoScaler *h_scaler, *v_scaler;
6449 GstVideoFormat format;
6452 gint sstride, dstride;
6457 convert_plane_hv_task (FScaleTask * task)
6459 gst_video_scaler_2d (task->h_scaler, task->v_scaler, task->format,
6460 (guint8 *) task->s, task->sstride,
6461 task->d, task->dstride, task->x, task->y, task->w, task->h);
6465 convert_plane_hv (GstVideoConverter * convert,
6466 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6468 gint in_x, in_y, out_x, out_y, out_width, out_height;
6469 GstVideoFormat format;
6470 gint splane = convert->fsplane[plane];
6472 gint sstride, dstride;
6474 FScaleTask **tasks_p;
6475 gint i, n_threads, lines_per_thread;
6477 in_x = convert->fin_x[splane];
6478 in_y = convert->fin_y[splane];
6479 out_x = convert->fout_x[plane];
6480 out_y = convert->fout_y[plane];
6481 out_width = convert->fout_width[plane];
6482 out_height = convert->fout_height[plane];
6483 format = convert->fformat[plane];
6485 s = FRAME_GET_PLANE_LINE (src, splane, in_y);
6487 d = FRAME_GET_PLANE_LINE (dest, plane, out_y);
6490 sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6491 dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
6493 n_threads = convert->conversion_runner->n_threads;
6494 tasks = convert->tasks[plane] =
6495 g_renew (FScaleTask, convert->tasks[plane], n_threads);
6496 tasks_p = convert->tasks_p[plane] =
6497 g_renew (FScaleTask *, convert->tasks_p[plane], n_threads);
6499 lines_per_thread = (out_height + n_threads - 1) / n_threads;
6501 for (i = 0; i < n_threads; i++) {
6503 convert->fh_scaler[plane].scaler ? convert->
6504 fh_scaler[plane].scaler[i] : NULL;
6506 convert->fv_scaler[plane].scaler ? convert->
6507 fv_scaler[plane].scaler[i] : NULL;
6508 tasks[i].format = format;
6511 tasks[i].sstride = sstride;
6512 tasks[i].dstride = dstride;
6515 tasks[i].w = out_width;
6517 tasks[i].y = i * lines_per_thread;
6518 tasks[i].h = tasks[i].y + lines_per_thread;
6519 tasks[i].h = MIN (out_height, tasks[i].h);
6521 tasks_p[i] = &tasks[i];
6524 gst_parallelized_task_runner_run (convert->conversion_runner,
6525 (GstParallelizedTaskFunc) convert_plane_hv_task, (gpointer) tasks_p);
6529 convert_scale_planes (GstVideoConverter * convert,
6530 const GstVideoFrame * src, GstVideoFrame * dest)
6534 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
6535 for (i = 0; i < n_planes; i++) {
6536 if (convert->fconvert[i])
6537 convert->fconvert[i] (convert, src, dest, i);
6539 convert_fill_border (convert, dest);
6542 static GstVideoFormat
6543 get_scale_format (GstVideoFormat format, gint plane)
6545 GstVideoFormat res = GST_VIDEO_FORMAT_UNKNOWN;
6548 case GST_VIDEO_FORMAT_I420:
6549 case GST_VIDEO_FORMAT_YV12:
6550 case GST_VIDEO_FORMAT_Y41B:
6551 case GST_VIDEO_FORMAT_Y42B:
6552 case GST_VIDEO_FORMAT_Y444:
6553 case GST_VIDEO_FORMAT_GRAY8:
6554 case GST_VIDEO_FORMAT_A420:
6555 case GST_VIDEO_FORMAT_YUV9:
6556 case GST_VIDEO_FORMAT_YVU9:
6557 case GST_VIDEO_FORMAT_GBR:
6558 case GST_VIDEO_FORMAT_GBRA:
6559 case GST_VIDEO_FORMAT_RGBP:
6560 case GST_VIDEO_FORMAT_BGRP:
6561 res = GST_VIDEO_FORMAT_GRAY8;
6563 case GST_VIDEO_FORMAT_GRAY16_BE:
6564 case GST_VIDEO_FORMAT_GRAY16_LE:
6565 res = GST_VIDEO_FORMAT_GRAY16_BE;
6567 case GST_VIDEO_FORMAT_YUY2:
6568 case GST_VIDEO_FORMAT_UYVY:
6569 case GST_VIDEO_FORMAT_VYUY:
6570 case GST_VIDEO_FORMAT_YVYU:
6571 case GST_VIDEO_FORMAT_AYUV:
6572 case GST_VIDEO_FORMAT_VUYA:
6573 case GST_VIDEO_FORMAT_RGBx:
6574 case GST_VIDEO_FORMAT_BGRx:
6575 case GST_VIDEO_FORMAT_xRGB:
6576 case GST_VIDEO_FORMAT_xBGR:
6577 case GST_VIDEO_FORMAT_RGBA:
6578 case GST_VIDEO_FORMAT_BGRA:
6579 case GST_VIDEO_FORMAT_ARGB:
6580 case GST_VIDEO_FORMAT_ABGR:
6581 case GST_VIDEO_FORMAT_RGB:
6582 case GST_VIDEO_FORMAT_BGR:
6583 case GST_VIDEO_FORMAT_v308:
6584 case GST_VIDEO_FORMAT_IYU2:
6585 case GST_VIDEO_FORMAT_ARGB64:
6586 case GST_VIDEO_FORMAT_AYUV64:
6589 case GST_VIDEO_FORMAT_RGB15:
6590 case GST_VIDEO_FORMAT_BGR15:
6591 case GST_VIDEO_FORMAT_RGB16:
6592 case GST_VIDEO_FORMAT_BGR16:
6593 res = GST_VIDEO_FORMAT_NV12;
6595 case GST_VIDEO_FORMAT_NV12:
6596 case GST_VIDEO_FORMAT_NV21:
6597 case GST_VIDEO_FORMAT_NV16:
6598 case GST_VIDEO_FORMAT_NV61:
6599 case GST_VIDEO_FORMAT_NV24:
6600 res = plane == 0 ? GST_VIDEO_FORMAT_GRAY8 : GST_VIDEO_FORMAT_NV12;
6602 case GST_VIDEO_FORMAT_AV12:
6604 || plane == 2) ? GST_VIDEO_FORMAT_GRAY8 : GST_VIDEO_FORMAT_NV12;
6606 case GST_VIDEO_FORMAT_UNKNOWN:
6607 case GST_VIDEO_FORMAT_ENCODED:
6608 case GST_VIDEO_FORMAT_v210:
6609 case GST_VIDEO_FORMAT_v216:
6610 case GST_VIDEO_FORMAT_Y210:
6611 case GST_VIDEO_FORMAT_Y410:
6612 case GST_VIDEO_FORMAT_UYVP:
6613 case GST_VIDEO_FORMAT_RGB8P:
6614 case GST_VIDEO_FORMAT_IYU1:
6615 case GST_VIDEO_FORMAT_r210:
6616 case GST_VIDEO_FORMAT_I420_10BE:
6617 case GST_VIDEO_FORMAT_I420_10LE:
6618 case GST_VIDEO_FORMAT_I422_10BE:
6619 case GST_VIDEO_FORMAT_I422_10LE:
6620 case GST_VIDEO_FORMAT_Y444_10BE:
6621 case GST_VIDEO_FORMAT_Y444_10LE:
6622 case GST_VIDEO_FORMAT_I420_12BE:
6623 case GST_VIDEO_FORMAT_I420_12LE:
6624 case GST_VIDEO_FORMAT_I422_12BE:
6625 case GST_VIDEO_FORMAT_I422_12LE:
6626 case GST_VIDEO_FORMAT_Y444_12BE:
6627 case GST_VIDEO_FORMAT_Y444_12LE:
6628 case GST_VIDEO_FORMAT_GBR_10BE:
6629 case GST_VIDEO_FORMAT_GBR_10LE:
6630 case GST_VIDEO_FORMAT_GBRA_10BE:
6631 case GST_VIDEO_FORMAT_GBRA_10LE:
6632 case GST_VIDEO_FORMAT_GBR_12BE:
6633 case GST_VIDEO_FORMAT_GBR_12LE:
6634 case GST_VIDEO_FORMAT_GBRA_12BE:
6635 case GST_VIDEO_FORMAT_GBRA_12LE:
6636 case GST_VIDEO_FORMAT_NV12_64Z32:
6637 case GST_VIDEO_FORMAT_NV12_4L4:
6638 case GST_VIDEO_FORMAT_NV12_32L32:
6639 case GST_VIDEO_FORMAT_A420_10BE:
6640 case GST_VIDEO_FORMAT_A420_10LE:
6641 case GST_VIDEO_FORMAT_A422_10BE:
6642 case GST_VIDEO_FORMAT_A422_10LE:
6643 case GST_VIDEO_FORMAT_A444_10BE:
6644 case GST_VIDEO_FORMAT_A444_10LE:
6645 case GST_VIDEO_FORMAT_P010_10BE:
6646 case GST_VIDEO_FORMAT_P010_10LE:
6647 case GST_VIDEO_FORMAT_GRAY10_LE32:
6648 case GST_VIDEO_FORMAT_NV12_10LE32:
6649 case GST_VIDEO_FORMAT_NV16_10LE32:
6650 case GST_VIDEO_FORMAT_NV12_10LE40:
6651 case GST_VIDEO_FORMAT_BGR10A2_LE:
6652 case GST_VIDEO_FORMAT_RGB10A2_LE:
6653 case GST_VIDEO_FORMAT_Y444_16BE:
6654 case GST_VIDEO_FORMAT_Y444_16LE:
6655 case GST_VIDEO_FORMAT_P016_BE:
6656 case GST_VIDEO_FORMAT_P016_LE:
6657 case GST_VIDEO_FORMAT_P012_BE:
6658 case GST_VIDEO_FORMAT_P012_LE:
6659 case GST_VIDEO_FORMAT_Y212_BE:
6660 case GST_VIDEO_FORMAT_Y212_LE:
6661 case GST_VIDEO_FORMAT_Y412_BE:
6662 case GST_VIDEO_FORMAT_Y412_LE:
6664 g_assert_not_reached ();
6671 is_merge_yuv (GstVideoInfo * info)
6673 switch (GST_VIDEO_INFO_FORMAT (info)) {
6674 case GST_VIDEO_FORMAT_YUY2:
6675 case GST_VIDEO_FORMAT_YVYU:
6676 case GST_VIDEO_FORMAT_UYVY:
6677 case GST_VIDEO_FORMAT_VYUY:
6685 setup_scale (GstVideoConverter * convert)
6688 gint method, cr_method, in_width, in_height, out_width, out_height;
6690 GstVideoInfo *in_info, *out_info;
6691 const GstVideoFormatInfo *in_finfo, *out_finfo;
6692 GstVideoFormat in_format, out_format;
6693 gboolean interlaced;
6694 guint n_threads = convert->conversion_runner->n_threads;
6696 in_info = &convert->in_info;
6697 out_info = &convert->out_info;
6699 in_finfo = in_info->finfo;
6700 out_finfo = out_info->finfo;
6702 n_planes = GST_VIDEO_INFO_N_PLANES (out_info);
6704 interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)
6705 && GST_VIDEO_INFO_INTERLACE_MODE (&convert->in_info) !=
6706 GST_VIDEO_INTERLACE_MODE_ALTERNATE;
6708 method = GET_OPT_RESAMPLER_METHOD (convert);
6709 if (method == GST_VIDEO_RESAMPLER_METHOD_NEAREST)
6712 cr_method = GET_OPT_CHROMA_RESAMPLER_METHOD (convert);
6713 taps = GET_OPT_RESAMPLER_TAPS (convert);
6715 in_format = GST_VIDEO_INFO_FORMAT (in_info);
6716 out_format = GST_VIDEO_INFO_FORMAT (out_info);
6718 switch (in_format) {
6719 case GST_VIDEO_FORMAT_RGB15:
6720 case GST_VIDEO_FORMAT_RGB16:
6721 case GST_VIDEO_FORMAT_BGR15:
6722 case GST_VIDEO_FORMAT_BGR16:
6723 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
6724 case GST_VIDEO_FORMAT_GRAY16_BE:
6726 case GST_VIDEO_FORMAT_GRAY16_LE:
6728 if (method != GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6729 GST_DEBUG ("%s only with nearest resampling",
6730 gst_video_format_to_string (in_format));
6738 in_width = convert->in_width;
6739 in_height = convert->in_height;
6740 out_width = convert->out_width;
6741 out_height = convert->out_height;
6743 if (n_planes == 1 && !GST_VIDEO_FORMAT_INFO_IS_GRAY (out_finfo)) {
6747 if (is_merge_yuv (in_info)) {
6748 GstVideoScaler *y_scaler, *uv_scaler;
6750 if (in_width != out_width) {
6751 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6752 for (j = 0; j < n_threads; j++) {
6754 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6755 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_Y,
6756 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
6757 GST_VIDEO_COMP_Y, out_width), convert->config);
6759 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE,
6760 gst_video_scaler_get_max_taps (y_scaler),
6761 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_U,
6762 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
6763 GST_VIDEO_COMP_U, out_width), convert->config);
6765 convert->fh_scaler[0].scaler[j] =
6766 gst_video_scaler_combine_packed_YUV (y_scaler, uv_scaler,
6767 in_format, out_format);
6769 gst_video_scaler_free (y_scaler);
6770 gst_video_scaler_free (uv_scaler);
6773 convert->fh_scaler[0].scaler = NULL;
6776 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_Y);
6777 convert->fin_x[0] = GST_ROUND_UP_2 (convert->in_x) * pstride;
6778 convert->fout_x[0] = GST_ROUND_UP_2 (convert->out_x) * pstride;
6781 if (in_width != out_width && in_width != 0 && out_width != 0) {
6782 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6783 for (j = 0; j < n_threads; j++) {
6784 convert->fh_scaler[0].scaler[j] =
6785 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6786 in_width, out_width, convert->config);
6789 convert->fh_scaler[0].scaler = NULL;
6792 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_R);
6793 convert->fin_x[0] = convert->in_x * pstride;
6794 convert->fout_x[0] = convert->out_x * pstride;
6797 if (in_height != out_height && in_height != 0 && out_height != 0) {
6798 convert->fv_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6800 for (j = 0; j < n_threads; j++) {
6801 convert->fv_scaler[0].scaler[j] =
6802 gst_video_scaler_new (method,
6804 GST_VIDEO_SCALER_FLAG_INTERLACED : GST_VIDEO_SCALER_FLAG_NONE, taps,
6805 in_height, out_height, convert->config);
6808 convert->fv_scaler[0].scaler = NULL;
6811 convert->fin_y[0] = convert->in_y;
6812 convert->fout_y[0] = convert->out_y;
6813 convert->fout_width[0] = out_width;
6814 convert->fout_height[0] = out_height;
6815 convert->fconvert[0] = convert_plane_hv;
6816 convert->fformat[0] = get_scale_format (in_format, 0);
6817 convert->fsplane[0] = 0;
6819 for (i = 0; i < n_planes; i++) {
6820 gint out_comp[GST_VIDEO_MAX_COMPONENTS];
6821 gint comp, j, iw, ih, ow, oh, pstride;
6822 gboolean need_v_scaler, need_h_scaler;
6823 GstStructure *config;
6824 gint resample_method;
6826 gst_video_format_info_component (out_finfo, i, out_comp);
6827 ow = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, out_comp[0],
6829 oh = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, out_comp[0],
6831 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, out_comp[0]);
6833 /* find the component in this plane and map it to the plane of
6835 if (out_comp[0] < GST_VIDEO_FORMAT_INFO_N_COMPONENTS (in_finfo)) {
6837 iw = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, comp, in_width);
6838 ih = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, comp, in_height);
6839 convert->fin_x[i] = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, comp,
6841 convert->fin_x[i] *= pstride;
6842 convert->fin_y[i] = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, comp,
6845 /* we will use a fill instead, setting the parameters to an invalid
6846 * size to reduce confusion */
6849 convert->fin_x[i] = -1;
6850 convert->fin_y[i] = -1;
6853 convert->fout_width[i] = ow;
6854 convert->fout_height[i] = oh;
6856 convert->fout_x[i] = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
6857 out_comp[0], convert->out_x);
6858 convert->fout_x[i] *= pstride;
6859 convert->fout_y[i] = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo,
6860 out_comp[0], convert->out_y);
6862 GST_DEBUG ("plane %d: %dx%d -> %dx%d", i, iw, ih, ow, oh);
6863 GST_DEBUG ("plane %d: pstride %d", i, pstride);
6864 GST_DEBUG ("plane %d: in_x %d, in_y %d", i, convert->fin_x[i],
6866 GST_DEBUG ("plane %d: out_x %d, out_y %d", i, convert->fout_x[i],
6867 convert->fout_y[i]);
6870 convert->fconvert[i] = convert_plane_fill;
6871 if (GST_VIDEO_INFO_IS_YUV (out_info)) {
6873 convert->ffill[i] = convert->alpha_value;
6875 convert->ffill[i] = 0x00;
6877 convert->ffill[i] = 0x80;
6880 convert->ffill[i] = convert->alpha_value;
6882 convert->ffill[i] = 0x00;
6884 GST_DEBUG ("plane %d fill %02x", i, convert->ffill[i]);
6887 convert->fsplane[i] = GST_VIDEO_FORMAT_INFO_PLANE (in_finfo, comp);
6888 GST_DEBUG ("plane %d -> %d (comp %d)", i, convert->fsplane[i], comp);
6891 config = gst_structure_copy (convert->config);
6893 resample_method = (i == 0 ? method : cr_method);
6895 need_v_scaler = FALSE;
6896 need_h_scaler = FALSE;
6898 if (!interlaced && ih == oh) {
6899 convert->fconvert[i] = convert_plane_hv;
6900 GST_DEBUG ("plane %d: copy", i);
6901 } else if (!interlaced && ih == 2 * oh && pstride == 1
6902 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6903 convert->fconvert[i] = convert_plane_v_halve;
6904 GST_DEBUG ("plane %d: vertical halve", i);
6905 } else if (!interlaced && 2 * ih == oh && pstride == 1
6906 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6907 convert->fconvert[i] = convert_plane_v_double;
6908 GST_DEBUG ("plane %d: vertical double", i);
6910 convert->fconvert[i] = convert_plane_hv;
6911 GST_DEBUG ("plane %d: vertical scale", i);
6912 need_v_scaler = TRUE;
6914 } else if (ih == oh) {
6915 if (!interlaced && iw == 2 * ow && pstride == 1
6916 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6917 convert->fconvert[i] = convert_plane_h_halve;
6918 GST_DEBUG ("plane %d: horizontal halve", i);
6919 } else if (!interlaced && 2 * iw == ow && pstride == 1
6920 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6921 convert->fconvert[i] = convert_plane_h_double;
6922 GST_DEBUG ("plane %d: horizontal double", i);
6924 convert->fconvert[i] = convert_plane_hv;
6925 GST_DEBUG ("plane %d: horizontal scale", i);
6926 need_h_scaler = TRUE;
6929 if (!interlaced && iw == 2 * ow && ih == 2 * oh && pstride == 1
6930 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6931 convert->fconvert[i] = convert_plane_hv_halve;
6932 GST_DEBUG ("plane %d: horizontal/vertical halve", i);
6933 } else if (!interlaced && 2 * iw == ow && 2 * ih == oh && pstride == 1
6934 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6935 convert->fconvert[i] = convert_plane_hv_double;
6936 GST_DEBUG ("plane %d: horizontal/vertical double", i);
6938 convert->fconvert[i] = convert_plane_hv;
6939 GST_DEBUG ("plane %d: horizontal/vertical scale", i);
6940 need_v_scaler = TRUE;
6941 need_h_scaler = TRUE;
6945 if (need_h_scaler && iw != 0 && ow != 0) {
6946 convert->fh_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
6948 for (j = 0; j < n_threads; j++) {
6949 convert->fh_scaler[i].scaler[j] =
6950 gst_video_scaler_new (resample_method, GST_VIDEO_SCALER_FLAG_NONE,
6951 taps, iw, ow, config);
6954 convert->fh_scaler[i].scaler = NULL;
6957 if (need_v_scaler && ih != 0 && oh != 0) {
6958 convert->fv_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
6960 for (j = 0; j < n_threads; j++) {
6961 convert->fv_scaler[i].scaler[j] =
6962 gst_video_scaler_new (resample_method,
6964 GST_VIDEO_SCALER_FLAG_INTERLACED : GST_VIDEO_SCALER_FLAG_NONE,
6965 taps, ih, oh, config);
6968 convert->fv_scaler[i].scaler = NULL;
6971 gst_structure_free (config);
6972 convert->fformat[i] = get_scale_format (in_format, i);
6983 GstVideoFormat in_format;
6984 GstVideoFormat out_format;
6985 gboolean keeps_interlaced;
6986 gboolean needs_color_matrix;
6987 gboolean keeps_size;
6990 gboolean alpha_copy;
6992 gboolean alpha_mult;
6993 gint width_align, height_align;
6994 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
6995 GstVideoFrame * dest);
6998 static const VideoTransform transforms[] = {
6999 /* planar -> packed */
7000 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
7001 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
7002 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
7003 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
7004 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
7005 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
7007 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
7008 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
7009 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
7010 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
7011 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
7012 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
7014 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
7015 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_YUY2},
7016 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
7017 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_UYVY},
7018 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
7019 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_Y42B_AYUV},
7021 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
7022 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_YUY2},
7023 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
7024 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_UYVY},
7025 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
7026 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_Y444_AYUV},
7028 /* packed -> packed */
7029 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, FALSE, TRUE,
7030 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7031 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
7032 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2}, /* alias */
7033 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
7034 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_YUY2_AYUV},
7036 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, FALSE, TRUE,
7037 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7038 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
7039 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2},
7040 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
7041 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_UYVY_AYUV},
7043 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, FALSE, TRUE, TRUE,
7044 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7045 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
7046 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_YUY2},
7047 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
7048 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_UYVY},
7050 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
7051 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_v210_UYVY},
7052 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
7053 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_v210_YUY2},
7055 /* packed -> planar */
7056 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
7057 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
7058 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
7059 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
7060 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
7061 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y42B},
7062 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
7063 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y444},
7064 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_GRAY8, TRUE, TRUE, TRUE, TRUE,
7065 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_GRAY8},
7067 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
7068 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
7069 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
7070 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
7071 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
7072 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y42B},
7073 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
7074 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y444},
7076 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_I420, FALSE, FALSE, TRUE, TRUE,
7077 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
7078 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, TRUE, TRUE,
7079 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
7080 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
7081 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_Y42B},
7082 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
7083 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_AYUV_Y444},
7085 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
7086 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_v210_I420},
7087 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
7088 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_v210_I420},
7089 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, FALSE,
7090 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_v210_Y42B},
7092 /* planar -> planar */
7093 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_I420, TRUE, FALSE, FALSE, TRUE,
7094 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7095 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, FALSE, TRUE,
7096 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7097 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7098 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7099 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7100 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7101 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7102 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7103 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7104 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7105 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7106 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7107 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7108 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7109 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7110 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7112 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_I420, TRUE, FALSE, FALSE, TRUE,
7113 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7114 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, FALSE, TRUE,
7115 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7116 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7117 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7118 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7119 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7120 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7121 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7122 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7123 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7124 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7125 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7126 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7127 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7128 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7129 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7131 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7132 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7133 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7134 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7135 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y41B, TRUE, FALSE, FALSE, TRUE,
7136 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7137 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7138 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7139 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7140 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7141 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7142 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7143 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7144 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7145 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7146 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7147 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7148 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7150 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7151 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7152 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7153 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7154 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7155 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7156 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, FALSE, TRUE,
7157 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7158 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7159 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7160 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7161 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7162 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7163 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7164 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7165 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7166 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7167 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7169 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7170 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7171 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7172 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7173 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7174 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7175 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7176 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7177 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, FALSE, TRUE,
7178 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7179 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7180 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7181 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7182 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7183 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7184 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7185 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7186 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7188 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7189 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7190 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7191 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7192 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7193 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7194 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7195 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7196 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7197 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7198 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_GRAY8, TRUE, FALSE, FALSE, TRUE,
7199 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7200 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7201 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7202 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7203 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7204 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7205 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7207 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7208 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7209 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7210 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7211 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7212 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7213 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7214 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7215 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7216 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7217 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7218 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7219 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_A420, TRUE, FALSE, FALSE, TRUE,
7220 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7221 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7222 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7223 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7224 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7226 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7227 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7228 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7229 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7230 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7231 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7232 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7233 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7234 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7235 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7236 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7237 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7238 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7239 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7240 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YUV9, TRUE, FALSE, FALSE, TRUE,
7241 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7242 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YVU9, TRUE, FALSE, FALSE, TRUE,
7243 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7245 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7246 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7247 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7248 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7249 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7250 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7251 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7252 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7253 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7254 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7255 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7256 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7257 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7258 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7259 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YUV9, TRUE, FALSE, FALSE, TRUE,
7260 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7261 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YVU9, TRUE, FALSE, FALSE, TRUE,
7262 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7264 /* sempiplanar -> semiplanar */
7265 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
7266 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7267 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
7268 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7269 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
7270 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7272 {GST_VIDEO_FORMAT_NV21, GST_VIDEO_FORMAT_NV21, TRUE, FALSE, FALSE, TRUE,
7273 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7275 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
7276 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7277 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
7278 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7279 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
7280 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7282 {GST_VIDEO_FORMAT_NV61, GST_VIDEO_FORMAT_NV61, TRUE, FALSE, FALSE, TRUE,
7283 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7285 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
7286 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7287 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
7288 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7289 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
7290 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7292 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
7293 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ARGB, TRUE, TRUE, TRUE, TRUE, TRUE,
7294 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB},
7295 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRA, TRUE, TRUE, TRUE, TRUE, TRUE,
7296 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA},
7297 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xRGB, TRUE, TRUE, TRUE, TRUE, TRUE,
7298 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB}, /* alias */
7299 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRx, TRUE, TRUE, TRUE, TRUE, TRUE,
7300 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA}, /* alias */
7301 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ABGR, TRUE, TRUE, TRUE, TRUE, TRUE,
7302 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR},
7303 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBA, TRUE, TRUE, TRUE, TRUE, TRUE,
7304 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA},
7305 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xBGR, TRUE, TRUE, TRUE, TRUE, TRUE,
7306 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR}, /* alias */
7307 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBx, TRUE, TRUE, TRUE, TRUE, TRUE,
7308 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA}, /* alias */
7311 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
7312 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
7313 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
7314 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
7315 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
7316 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
7317 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
7318 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
7320 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
7321 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
7322 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
7323 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
7324 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
7325 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
7326 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
7327 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
7329 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
7330 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7331 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
7332 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7333 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
7334 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7335 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
7336 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7337 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
7338 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7339 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
7340 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7341 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
7342 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7343 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
7344 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7345 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
7346 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7347 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
7348 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7350 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
7351 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7352 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
7353 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7354 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
7355 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7356 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
7357 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7358 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
7359 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7360 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
7361 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7362 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
7363 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7364 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
7365 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7366 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
7367 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7368 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
7369 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7372 {GST_VIDEO_FORMAT_GBR, GST_VIDEO_FORMAT_GBR, TRUE, FALSE, FALSE, TRUE,
7373 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7374 {GST_VIDEO_FORMAT_GBRA, GST_VIDEO_FORMAT_GBRA, TRUE, FALSE, FALSE, TRUE,
7375 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7376 {GST_VIDEO_FORMAT_RGBP, GST_VIDEO_FORMAT_RGBP, TRUE, FALSE, FALSE, TRUE,
7377 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7378 {GST_VIDEO_FORMAT_BGRP, GST_VIDEO_FORMAT_BGRP, TRUE, FALSE, FALSE, TRUE,
7379 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7381 {GST_VIDEO_FORMAT_YVYU, GST_VIDEO_FORMAT_YVYU, TRUE, FALSE, FALSE, TRUE,
7382 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7384 {GST_VIDEO_FORMAT_RGB15, GST_VIDEO_FORMAT_RGB15, TRUE, FALSE, FALSE, TRUE,
7385 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7386 {GST_VIDEO_FORMAT_RGB16, GST_VIDEO_FORMAT_RGB16, TRUE, FALSE, FALSE, TRUE,
7387 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7388 {GST_VIDEO_FORMAT_BGR15, GST_VIDEO_FORMAT_BGR15, TRUE, FALSE, FALSE, TRUE,
7389 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7390 {GST_VIDEO_FORMAT_BGR16, GST_VIDEO_FORMAT_BGR16, TRUE, FALSE, FALSE, TRUE,
7391 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7393 {GST_VIDEO_FORMAT_RGB, GST_VIDEO_FORMAT_RGB, TRUE, FALSE, FALSE, TRUE, TRUE,
7394 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7395 {GST_VIDEO_FORMAT_BGR, GST_VIDEO_FORMAT_BGR, TRUE, FALSE, FALSE, TRUE, TRUE,
7396 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7397 {GST_VIDEO_FORMAT_v308, GST_VIDEO_FORMAT_v308, TRUE, FALSE, FALSE, TRUE, TRUE,
7398 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7399 {GST_VIDEO_FORMAT_IYU2, GST_VIDEO_FORMAT_IYU2, TRUE, FALSE, FALSE, TRUE, TRUE,
7400 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7402 {GST_VIDEO_FORMAT_ARGB, GST_VIDEO_FORMAT_ARGB, TRUE, FALSE, FALSE, TRUE, TRUE,
7403 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7404 {GST_VIDEO_FORMAT_xRGB, GST_VIDEO_FORMAT_xRGB, TRUE, FALSE, FALSE, TRUE, TRUE,
7405 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7406 {GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_ABGR, TRUE, FALSE, FALSE, TRUE, TRUE,
7407 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7408 {GST_VIDEO_FORMAT_xBGR, GST_VIDEO_FORMAT_xBGR, TRUE, FALSE, FALSE, TRUE, TRUE,
7409 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7410 {GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_RGBA, TRUE, FALSE, FALSE, TRUE, TRUE,
7411 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7412 {GST_VIDEO_FORMAT_RGBx, GST_VIDEO_FORMAT_RGBx, TRUE, FALSE, FALSE, TRUE, TRUE,
7413 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7414 {GST_VIDEO_FORMAT_BGRA, GST_VIDEO_FORMAT_BGRA, TRUE, FALSE, FALSE, TRUE, TRUE,
7415 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7416 {GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_BGRx, TRUE, FALSE, FALSE, TRUE, TRUE,
7417 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7419 {GST_VIDEO_FORMAT_ARGB64, GST_VIDEO_FORMAT_ARGB64, TRUE, FALSE, FALSE, TRUE,
7420 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7421 {GST_VIDEO_FORMAT_AYUV64, GST_VIDEO_FORMAT_AYUV64, TRUE, FALSE, FALSE, TRUE,
7422 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7424 {GST_VIDEO_FORMAT_GRAY16_LE, GST_VIDEO_FORMAT_GRAY16_LE, TRUE, FALSE, FALSE,
7425 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7426 {GST_VIDEO_FORMAT_GRAY16_BE, GST_VIDEO_FORMAT_GRAY16_BE, TRUE, FALSE, FALSE,
7427 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7431 video_converter_lookup_fastpath (GstVideoConverter * convert)
7434 GstVideoFormat in_format, out_format;
7435 GstVideoTransferFunction in_transf, out_transf;
7436 gboolean interlaced, same_matrix, same_primaries, same_size, crop, border;
7437 gboolean need_copy, need_set, need_mult;
7439 guint in_bpp, out_bpp;
7441 width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
7442 height = GST_VIDEO_INFO_FIELD_HEIGHT (&convert->in_info);
7444 if (GET_OPT_DITHER_QUANTIZATION (convert) != 1)
7447 in_bpp = convert->in_info.finfo->bits;
7448 out_bpp = convert->out_info.finfo->bits;
7450 /* we don't do gamma conversion in fastpath */
7451 in_transf = convert->in_info.colorimetry.transfer;
7452 out_transf = convert->out_info.colorimetry.transfer;
7454 same_size = (width == convert->out_width && height == convert->out_height);
7456 /* fastpaths don't do gamma */
7457 if (CHECK_GAMMA_REMAP (convert) && (!same_size
7458 || !gst_video_transfer_function_is_equivalent (in_transf, in_bpp,
7459 out_transf, out_bpp)))
7462 need_copy = (convert->alpha_mode & ALPHA_MODE_COPY) == ALPHA_MODE_COPY;
7463 need_set = (convert->alpha_mode & ALPHA_MODE_SET) == ALPHA_MODE_SET;
7464 need_mult = (convert->alpha_mode & ALPHA_MODE_MULT) == ALPHA_MODE_MULT;
7465 GST_DEBUG ("alpha copy %d, set %d, mult %d", need_copy, need_set, need_mult);
7467 in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
7468 out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
7470 if (CHECK_MATRIX_NONE (convert)) {
7473 GstVideoColorMatrix in_matrix, out_matrix;
7475 in_matrix = convert->in_info.colorimetry.matrix;
7476 out_matrix = convert->out_info.colorimetry.matrix;
7477 same_matrix = in_matrix == out_matrix;
7480 if (CHECK_PRIMARIES_NONE (convert)) {
7481 same_primaries = TRUE;
7483 GstVideoColorPrimaries in_primaries, out_primaries;
7485 in_primaries = convert->in_info.colorimetry.primaries;
7486 out_primaries = convert->out_info.colorimetry.primaries;
7487 same_primaries = in_primaries == out_primaries;
7490 interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info);
7491 interlaced |= GST_VIDEO_INFO_IS_INTERLACED (&convert->out_info);
7493 crop = convert->in_x || convert->in_y
7494 || convert->in_width < convert->in_maxwidth
7495 || convert->in_height < convert->in_maxheight;
7496 border = convert->out_x || convert->out_y
7497 || convert->out_width < convert->out_maxwidth
7498 || convert->out_height < convert->out_maxheight;
7500 for (i = 0; i < G_N_ELEMENTS (transforms); i++) {
7501 if (transforms[i].in_format == in_format &&
7502 transforms[i].out_format == out_format &&
7503 (transforms[i].keeps_interlaced || !interlaced) &&
7504 (transforms[i].needs_color_matrix || (same_matrix && same_primaries))
7505 && (!transforms[i].keeps_size || same_size)
7506 && (transforms[i].width_align & width) == 0
7507 && (transforms[i].height_align & height) == 0
7508 && (transforms[i].do_crop || !crop)
7509 && (transforms[i].do_border || !border)
7510 && (transforms[i].alpha_copy || !need_copy)
7511 && (transforms[i].alpha_set || !need_set)
7512 && (transforms[i].alpha_mult || !need_mult)) {
7515 GST_DEBUG ("using fastpath");
7516 if (transforms[i].needs_color_matrix)
7517 video_converter_compute_matrix (convert);
7518 convert->convert = transforms[i].convert;
7521 g_new (guint16 *, convert->conversion_runner->n_threads);
7522 for (j = 0; j < convert->conversion_runner->n_threads; j++)
7523 convert->tmpline[j] = g_malloc0 (sizeof (guint16) * (width + 8) * 4);
7525 if (!transforms[i].keeps_size)
7526 if (!setup_scale (convert))
7529 setup_borderline (convert);
7533 GST_DEBUG ("no fastpath found");