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"
38 #include "video-orc.h"
41 * SECTION:videoconverter
42 * @title: GstVideoConverter
43 * @short_description: Generic video conversion
45 * This object is used to convert video frames from one format to another.
46 * The object can perform conversion of:
58 * (c) (convert Y'CbCr to R'G'B')
61 * (f) colorspace convert through XYZ
64 * (i) (convert R'G'B' to Y'CbCr)
65 * (j) chroma downsample
70 * (a) range truncate, range expand
71 * (b) full upsample, 1-1 non-cosited upsample, no upsample
79 * (j) 1-1 cosited downsample, no downsample
83 * 1 : a -> -> -> -> e -> f -> g -> -> -> -> k
84 * 2 : a -> -> -> -> e -> f* -> g -> -> -> -> k
85 * 3 : a -> -> -> -> e* -> f* -> g* -> -> -> -> k
86 * 4 : a -> b -> -> -> e -> f -> g -> -> -> j -> k
87 * 5 : a -> b -> -> -> e* -> f* -> g* -> -> -> j -> k
88 * 6 : a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k
89 * 7 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
91 * 8 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
92 * 9 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
93 * 10 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
96 #ifndef GST_DISABLE_GST_DEBUG
97 #define GST_CAT_DEFAULT ensure_debug_category()
98 static GstDebugCategory *
99 ensure_debug_category (void)
101 static gsize cat_gonce = 0;
103 if (g_once_init_enter (&cat_gonce)) {
106 cat_done = (gsize) _gst_debug_category_new ("video-converter", 0,
107 "video-converter object");
109 g_once_init_leave (&cat_gonce, cat_done);
112 return (GstDebugCategory *) cat_gonce;
115 #define ensure_debug_category() /* NOOP */
116 #endif /* GST_DISABLE_GST_DEBUG */
118 typedef void (*GstParallelizedTaskFunc) (gpointer user_data);
120 typedef struct _GstParallelizedTaskRunner GstParallelizedTaskRunner;
121 typedef struct _GstParallelizedTaskThread GstParallelizedTaskThread;
123 struct _GstParallelizedTaskThread
125 GstParallelizedTaskRunner *runner;
130 struct _GstParallelizedTaskRunner
134 GstParallelizedTaskThread *threads;
136 GstParallelizedTaskFunc func;
140 GCond cond_todo, cond_done;
146 gst_parallelized_task_thread_func (gpointer data)
148 GstParallelizedTaskThread *self = data;
153 pthread_t thread = pthread_self ();
158 CPU_SET (self->idx, &cpuset);
159 if ((r = pthread_setaffinity_np (thread, sizeof (cpuset), &cpuset)) != 0)
160 GST_ERROR ("Failed to set thread affinity for thread %d: %s", self->idx,
166 g_mutex_lock (&self->runner->lock);
167 self->runner->n_done++;
168 if (self->runner->n_done == self->runner->n_threads - 1)
169 g_cond_signal (&self->runner->cond_done);
174 while (self->runner->n_todo == -1 && !self->runner->quit)
175 g_cond_wait (&self->runner->cond_todo, &self->runner->lock);
177 if (self->runner->quit)
180 idx = self->runner->n_todo--;
181 g_assert (self->runner->n_todo >= -1);
182 g_mutex_unlock (&self->runner->lock);
184 g_assert (self->runner->func != NULL);
186 self->runner->func (self->runner->task_data[idx]);
188 g_mutex_lock (&self->runner->lock);
189 self->runner->n_done++;
190 if (self->runner->n_done == self->runner->n_threads - 1)
191 g_cond_signal (&self->runner->cond_done);
194 g_mutex_unlock (&self->runner->lock);
200 gst_parallelized_task_runner_free (GstParallelizedTaskRunner * self)
204 g_mutex_lock (&self->lock);
206 g_cond_broadcast (&self->cond_todo);
207 g_mutex_unlock (&self->lock);
209 for (i = 1; i < self->n_threads; i++) {
210 if (!self->threads[i].thread)
213 g_thread_join (self->threads[i].thread);
216 g_mutex_clear (&self->lock);
217 g_cond_clear (&self->cond_todo);
218 g_cond_clear (&self->cond_done);
219 g_free (self->threads);
223 static GstParallelizedTaskRunner *
224 gst_parallelized_task_runner_new (guint n_threads)
226 GstParallelizedTaskRunner *self;
231 n_threads = g_get_num_processors ();
233 self = g_new0 (GstParallelizedTaskRunner, 1);
234 self->n_threads = n_threads;
235 self->threads = g_new0 (GstParallelizedTaskThread, n_threads);
240 g_mutex_init (&self->lock);
241 g_cond_init (&self->cond_todo);
242 g_cond_init (&self->cond_done);
244 /* Set when scheduling a job */
246 self->task_data = NULL;
248 for (i = 0; i < n_threads; i++) {
249 self->threads[i].runner = self;
250 self->threads[i].idx = i;
252 /* First thread is the one calling run() */
254 self->threads[i].thread =
255 g_thread_try_new ("videoconvert", gst_parallelized_task_thread_func,
256 &self->threads[i], &err);
257 if (!self->threads[i].thread)
262 g_mutex_lock (&self->lock);
263 while (self->n_done < self->n_threads - 1)
264 g_cond_wait (&self->cond_done, &self->lock);
266 g_mutex_unlock (&self->lock);
272 GST_ERROR ("Failed to start thread %u: %s", i, err->message);
273 g_clear_error (&err);
275 gst_parallelized_task_runner_free (self);
281 gst_parallelized_task_runner_run (GstParallelizedTaskRunner * self,
282 GstParallelizedTaskFunc func, gpointer * task_data)
284 guint n_threads = self->n_threads;
287 self->task_data = task_data;
290 g_mutex_lock (&self->lock);
291 self->n_todo = self->n_threads - 2;
293 g_cond_broadcast (&self->cond_todo);
294 g_mutex_unlock (&self->lock);
297 self->func (self->task_data[self->n_threads - 1]);
300 g_mutex_lock (&self->lock);
301 while (self->n_done < self->n_threads - 1)
302 g_cond_wait (&self->cond_done, &self->lock);
304 g_mutex_unlock (&self->lock);
308 self->task_data = NULL;
311 typedef struct _GstLineCache GstLineCache;
314 #define SCALE_F ((float) (1 << SCALE))
316 typedef struct _MatrixData MatrixData;
331 void (*matrix_func) (MatrixData * data, gpointer pixels);
334 typedef struct _GammaData GammaData;
338 gpointer gamma_table;
340 void (*gamma_func) (GammaData * data, gpointer dest, gpointer src);
346 ALPHA_MODE_COPY = (1 << 0),
347 ALPHA_MODE_SET = (1 << 1),
348 ALPHA_MODE_MULT = (1 << 2)
358 GDestroyNotify notify;
361 typedef void (*FastConvertFunc) (GstVideoConverter * convert,
362 const GstVideoFrame * src, GstVideoFrame * dest, gint plane);
364 struct _GstVideoConverter
368 GstVideoInfo in_info;
369 GstVideoInfo out_info;
384 gint current_pstride;
387 GstVideoFormat current_format;
390 GstStructure *config;
392 GstParallelizedTaskRunner *conversion_runner;
396 gboolean fill_border;
401 AlphaMode alpha_mode;
403 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
404 GstVideoFrame * dest);
406 /* data for unpack */
407 GstLineCache **unpack_lines;
408 GstVideoFormat unpack_format;
411 gboolean identity_unpack;
414 /* chroma upsample */
415 GstLineCache **upsample_lines;
416 GstVideoChromaResample **upsample;
417 GstVideoChromaResample **upsample_p;
418 GstVideoChromaResample **upsample_i;
423 GstLineCache **to_RGB_lines;
424 MatrixData to_RGB_matrix;
429 GstLineCache **hscale_lines;
430 GstVideoScaler **h_scaler;
432 GstLineCache **vscale_lines;
433 GstVideoScaler **v_scaler;
434 GstVideoScaler **v_scaler_p;
435 GstVideoScaler **v_scaler_i;
439 /* color space conversion */
440 GstLineCache **convert_lines;
441 MatrixData convert_matrix;
445 /* alpha correction */
446 GstLineCache **alpha_lines;
447 void (*alpha_func) (GstVideoConverter * convert, gpointer pixels, gint width);
452 GstLineCache **to_YUV_lines;
453 MatrixData to_YUV_matrix;
455 /* chroma downsample */
456 GstLineCache **downsample_lines;
457 GstVideoChromaResample **downsample;
458 GstVideoChromaResample **downsample_p;
459 GstVideoChromaResample **downsample_i;
464 GstLineCache **dither_lines;
465 GstVideoDither **dither;
468 GstLineCache **pack_lines;
470 GstVideoFormat pack_format;
473 gboolean identity_pack;
475 gconstpointer pack_pal;
478 const GstVideoFrame *src;
482 GstVideoFormat fformat[4];
494 GstVideoScaler **scaler;
498 GstVideoScaler **scaler;
500 FastConvertFunc fconvert[4];
503 typedef gpointer (*GstLineCacheAllocLineFunc) (GstLineCache * cache, gint idx,
505 typedef gboolean (*GstLineCacheNeedLineFunc) (GstLineCache * cache, gint idx,
506 gint out_line, gint in_line, gpointer user_data);
515 gboolean write_input;
517 gboolean alloc_writable;
519 GstLineCacheNeedLineFunc need_line;
521 gpointer need_line_data;
522 GDestroyNotify need_line_notify;
526 GstLineCacheAllocLineFunc alloc_line;
527 gpointer alloc_line_data;
528 GDestroyNotify alloc_line_notify;
531 static GstLineCache *
532 gst_line_cache_new (GstLineCache * prev)
534 GstLineCache *result;
536 result = g_slice_new0 (GstLineCache);
537 result->lines = g_ptr_array_new ();
544 gst_line_cache_clear (GstLineCache * cache)
546 g_return_if_fail (cache != NULL);
548 g_ptr_array_set_size (cache->lines, 0);
553 gst_line_cache_free (GstLineCache * cache)
555 if (cache->need_line_notify)
556 cache->need_line_notify (cache->need_line_data);
557 if (cache->alloc_line_notify)
558 cache->alloc_line_notify (cache->alloc_line_data);
559 gst_line_cache_clear (cache);
560 g_ptr_array_unref (cache->lines);
561 g_slice_free (GstLineCache, cache);
565 gst_line_cache_set_need_line_func (GstLineCache * cache,
566 GstLineCacheNeedLineFunc need_line, gint idx, gpointer user_data,
567 GDestroyNotify notify)
569 cache->need_line = need_line;
570 cache->need_line_idx = idx;
571 cache->need_line_data = user_data;
572 cache->need_line_notify = notify;
576 gst_line_cache_set_alloc_line_func (GstLineCache * cache,
577 GstLineCacheAllocLineFunc alloc_line, gpointer user_data,
578 GDestroyNotify notify)
580 cache->alloc_line = alloc_line;
581 cache->alloc_line_data = user_data;
582 cache->alloc_line_notify = notify;
585 /* keep this much backlog for interlaced video */
589 gst_line_cache_get_lines (GstLineCache * cache, gint idx, gint out_line,
590 gint in_line, gint n_lines)
592 if (cache->first + cache->backlog < in_line) {
594 MIN (in_line - (cache->first + cache->backlog), cache->lines->len);
596 g_ptr_array_remove_range (cache->lines, 0, to_remove);
598 cache->first += to_remove;
599 } else if (in_line < cache->first) {
600 gst_line_cache_clear (cache);
601 cache->first = in_line;
607 if (cache->first <= in_line
608 && in_line + n_lines <= cache->first + (gint) cache->lines->len) {
609 return cache->lines->pdata + (in_line - cache->first);
612 if (cache->need_line == NULL)
615 oline = out_line + cache->first + cache->lines->len - in_line;
617 if (!cache->need_line (cache, idx, oline, cache->first + cache->lines->len,
618 cache->need_line_data))
621 GST_DEBUG ("no lines");
626 gst_line_cache_add_line (GstLineCache * cache, gint idx, gpointer line)
628 if (cache->first + cache->lines->len != idx) {
629 gst_line_cache_clear (cache);
632 g_ptr_array_add (cache->lines, line);
636 gst_line_cache_alloc_line (GstLineCache * cache, gint idx)
640 if (cache->alloc_line)
641 res = cache->alloc_line (cache, idx, cache->alloc_line_data);
648 static void video_converter_generic (GstVideoConverter * convert,
649 const GstVideoFrame * src, GstVideoFrame * dest);
650 static gboolean video_converter_lookup_fastpath (GstVideoConverter * convert);
651 static void video_converter_compute_matrix (GstVideoConverter * convert);
652 static void video_converter_compute_resample (GstVideoConverter * convert,
655 static gpointer get_dest_line (GstLineCache * cache, gint idx,
658 static gboolean do_unpack_lines (GstLineCache * cache, gint idx, gint out_line,
659 gint in_line, gpointer user_data);
660 static gboolean do_downsample_lines (GstLineCache * cache, gint idx,
661 gint out_line, gint in_line, gpointer user_data);
662 static gboolean do_convert_to_RGB_lines (GstLineCache * cache, gint idx,
663 gint out_line, gint in_line, gpointer user_data);
664 static gboolean do_convert_lines (GstLineCache * cache, gint idx, gint out_line,
665 gint in_line, gpointer user_data);
666 static gboolean do_alpha_lines (GstLineCache * cache, gint idx, gint out_line,
667 gint in_line, gpointer user_data);
668 static gboolean do_convert_to_YUV_lines (GstLineCache * cache, gint idx,
669 gint out_line, gint in_line, gpointer user_data);
670 static gboolean do_upsample_lines (GstLineCache * cache, gint idx,
671 gint out_line, gint in_line, gpointer user_data);
672 static gboolean do_vscale_lines (GstLineCache * cache, gint idx, gint out_line,
673 gint in_line, gpointer user_data);
674 static gboolean do_hscale_lines (GstLineCache * cache, gint idx, gint out_line,
675 gint in_line, gpointer user_data);
676 static gboolean do_dither_lines (GstLineCache * cache, gint idx, gint out_line,
677 gint in_line, gpointer user_data);
679 static ConverterAlloc *
680 converter_alloc_new (guint stride, guint n_lines, gpointer user_data,
681 GDestroyNotify notify)
683 ConverterAlloc *alloc;
685 GST_DEBUG ("stride %d, n_lines %d", stride, n_lines);
686 alloc = g_slice_new0 (ConverterAlloc);
687 alloc->data = g_malloc (stride * n_lines);
688 alloc->stride = stride;
689 alloc->n_lines = n_lines;
691 alloc->user_data = user_data;
692 alloc->notify = notify;
698 converter_alloc_free (ConverterAlloc * alloc)
701 alloc->notify (alloc->user_data);
702 g_free (alloc->data);
703 g_slice_free (ConverterAlloc, alloc);
707 setup_border_alloc (GstVideoConverter * convert, ConverterAlloc * alloc)
711 if (convert->borderline) {
712 for (i = 0; i < alloc->n_lines; i++)
713 memcpy (&alloc->data[i * alloc->stride], convert->borderline,
719 get_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
721 ConverterAlloc *alloc = user_data;
724 GST_DEBUG ("get temp line %d (%p %d)", idx, alloc, alloc->idx);
725 tmpline = &alloc->data[alloc->stride * alloc->idx];
726 alloc->idx = (alloc->idx + 1) % alloc->n_lines;
732 get_border_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
734 ConverterAlloc *alloc = user_data;
735 GstVideoConverter *convert = alloc->user_data;
738 GST_DEBUG ("get temp line %d (%p %d)", idx, alloc, alloc->idx);
739 tmpline = &alloc->data[alloc->stride * alloc->idx] +
740 (convert->out_x * convert->pack_pstride);
741 alloc->idx = (alloc->idx + 1) % alloc->n_lines;
747 get_opt_int (GstVideoConverter * convert, const gchar * opt, gint def)
750 if (!gst_structure_get_int (convert->config, opt, &res))
756 get_opt_uint (GstVideoConverter * convert, const gchar * opt, guint def)
759 if (!gst_structure_get_uint (convert->config, opt, &res))
765 get_opt_double (GstVideoConverter * convert, const gchar * opt, gdouble def)
768 if (!gst_structure_get_double (convert->config, opt, &res))
774 get_opt_bool (GstVideoConverter * convert, const gchar * opt, gboolean def)
777 if (!gst_structure_get_boolean (convert->config, opt, &res))
783 get_opt_enum (GstVideoConverter * convert, const gchar * opt, GType type,
787 if (!gst_structure_get_enum (convert->config, opt, type, &res))
792 #define DEFAULT_OPT_FILL_BORDER TRUE
793 #define DEFAULT_OPT_ALPHA_VALUE 1.0
794 /* options copy, set, mult */
795 #define DEFAULT_OPT_ALPHA_MODE GST_VIDEO_ALPHA_MODE_COPY
796 #define DEFAULT_OPT_BORDER_ARGB 0xff000000
797 /* options full, input-only, output-only, none */
798 #define DEFAULT_OPT_MATRIX_MODE GST_VIDEO_MATRIX_MODE_FULL
800 #define DEFAULT_OPT_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
801 /* none, merge-only, fast */
802 #define DEFAULT_OPT_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
803 /* options full, upsample-only, downsample-only, none */
804 #define DEFAULT_OPT_CHROMA_MODE GST_VIDEO_CHROMA_MODE_FULL
805 #define DEFAULT_OPT_RESAMPLER_METHOD GST_VIDEO_RESAMPLER_METHOD_CUBIC
806 #define DEFAULT_OPT_CHROMA_RESAMPLER_METHOD GST_VIDEO_RESAMPLER_METHOD_LINEAR
807 #define DEFAULT_OPT_RESAMPLER_TAPS 0
808 #define DEFAULT_OPT_DITHER_METHOD GST_VIDEO_DITHER_BAYER
809 #define DEFAULT_OPT_DITHER_QUANTIZATION 1
811 #define GET_OPT_FILL_BORDER(c) get_opt_bool(c, \
812 GST_VIDEO_CONVERTER_OPT_FILL_BORDER, DEFAULT_OPT_FILL_BORDER)
813 #define GET_OPT_ALPHA_VALUE(c) get_opt_double(c, \
814 GST_VIDEO_CONVERTER_OPT_ALPHA_VALUE, DEFAULT_OPT_ALPHA_VALUE)
815 #define GET_OPT_ALPHA_MODE(c) get_opt_enum(c, \
816 GST_VIDEO_CONVERTER_OPT_ALPHA_MODE, GST_TYPE_VIDEO_ALPHA_MODE, DEFAULT_OPT_ALPHA_MODE)
817 #define GET_OPT_BORDER_ARGB(c) get_opt_uint(c, \
818 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB)
819 #define GET_OPT_MATRIX_MODE(c) get_opt_enum(c, \
820 GST_VIDEO_CONVERTER_OPT_MATRIX_MODE, GST_TYPE_VIDEO_MATRIX_MODE, DEFAULT_OPT_MATRIX_MODE)
821 #define GET_OPT_GAMMA_MODE(c) get_opt_enum(c, \
822 GST_VIDEO_CONVERTER_OPT_GAMMA_MODE, GST_TYPE_VIDEO_GAMMA_MODE, DEFAULT_OPT_GAMMA_MODE)
823 #define GET_OPT_PRIMARIES_MODE(c) get_opt_enum(c, \
824 GST_VIDEO_CONVERTER_OPT_PRIMARIES_MODE, GST_TYPE_VIDEO_PRIMARIES_MODE, DEFAULT_OPT_PRIMARIES_MODE)
825 #define GET_OPT_CHROMA_MODE(c) get_opt_enum(c, \
826 GST_VIDEO_CONVERTER_OPT_CHROMA_MODE, GST_TYPE_VIDEO_CHROMA_MODE, DEFAULT_OPT_CHROMA_MODE)
827 #define GET_OPT_RESAMPLER_METHOD(c) get_opt_enum(c, \
828 GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD, GST_TYPE_VIDEO_RESAMPLER_METHOD, \
829 DEFAULT_OPT_RESAMPLER_METHOD)
830 #define GET_OPT_CHROMA_RESAMPLER_METHOD(c) get_opt_enum(c, \
831 GST_VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD, GST_TYPE_VIDEO_RESAMPLER_METHOD, \
832 DEFAULT_OPT_CHROMA_RESAMPLER_METHOD)
833 #define GET_OPT_RESAMPLER_TAPS(c) get_opt_uint(c, \
834 GST_VIDEO_CONVERTER_OPT_RESAMPLER_TAPS, DEFAULT_OPT_RESAMPLER_TAPS)
835 #define GET_OPT_DITHER_METHOD(c) get_opt_enum(c, \
836 GST_VIDEO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_VIDEO_DITHER_METHOD, \
837 DEFAULT_OPT_DITHER_METHOD)
838 #define GET_OPT_DITHER_QUANTIZATION(c) get_opt_uint(c, \
839 GST_VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, DEFAULT_OPT_DITHER_QUANTIZATION)
841 #define CHECK_ALPHA_COPY(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_COPY)
842 #define CHECK_ALPHA_SET(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_SET)
843 #define CHECK_ALPHA_MULT(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_MULT)
845 #define CHECK_MATRIX_FULL(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_FULL)
846 #define CHECK_MATRIX_INPUT(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_INPUT_ONLY)
847 #define CHECK_MATRIX_OUTPUT(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_OUTPUT_ONLY)
848 #define CHECK_MATRIX_NONE(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_NONE)
850 #define CHECK_GAMMA_NONE(c) (GET_OPT_GAMMA_MODE(c) == GST_VIDEO_GAMMA_MODE_NONE)
851 #define CHECK_GAMMA_REMAP(c) (GET_OPT_GAMMA_MODE(c) == GST_VIDEO_GAMMA_MODE_REMAP)
853 #define CHECK_PRIMARIES_NONE(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_NONE)
854 #define CHECK_PRIMARIES_MERGE(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_MERGE_ONLY)
855 #define CHECK_PRIMARIES_FAST(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_FAST)
857 #define CHECK_CHROMA_FULL(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_FULL)
858 #define CHECK_CHROMA_UPSAMPLE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_UPSAMPLE_ONLY)
859 #define CHECK_CHROMA_DOWNSAMPLE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_DOWNSAMPLE_ONLY)
860 #define CHECK_CHROMA_NONE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_NONE)
862 static GstLineCache *
863 chain_unpack_line (GstVideoConverter * convert, gint idx)
868 info = &convert->in_info;
870 convert->current_format = convert->unpack_format;
871 convert->current_bits = convert->unpack_bits;
872 convert->current_pstride = convert->current_bits >> 1;
874 convert->unpack_pstride = convert->current_pstride;
875 convert->identity_unpack = (convert->current_format == info->finfo->format);
877 GST_DEBUG ("chain unpack line format %s, pstride %d, identity_unpack %d",
878 gst_video_format_to_string (convert->current_format),
879 convert->current_pstride, convert->identity_unpack);
881 prev = convert->unpack_lines[idx] = gst_line_cache_new (NULL);
882 prev->write_input = FALSE;
883 prev->pass_alloc = FALSE;
885 prev->stride = convert->current_pstride * convert->current_width;
886 gst_line_cache_set_need_line_func (prev, do_unpack_lines, idx, convert, NULL);
891 static GstLineCache *
892 chain_upsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
894 video_converter_compute_resample (convert, idx);
896 if (convert->upsample_p[idx] || convert->upsample_i[idx]) {
897 GST_DEBUG ("chain upsample");
898 prev = convert->upsample_lines[idx] = gst_line_cache_new (prev);
899 prev->write_input = TRUE;
900 prev->pass_alloc = TRUE;
902 prev->stride = convert->current_pstride * convert->current_width;
903 gst_line_cache_set_need_line_func (prev,
904 do_upsample_lines, idx, convert, NULL);
910 color_matrix_set_identity (MatrixData * m)
914 for (i = 0; i < 4; i++) {
915 for (j = 0; j < 4; j++) {
916 m->dm[i][j] = (i == j);
922 color_matrix_copy (MatrixData * d, const MatrixData * s)
926 for (i = 0; i < 4; i++)
927 for (j = 0; j < 4; j++)
928 d->dm[i][j] = s->dm[i][j];
931 /* Perform 4x4 matrix multiplication:
932 * - @dst@ = @a@ * @b@
933 * - @dst@ may be a pointer to @a@ andor @b@
936 color_matrix_multiply (MatrixData * dst, MatrixData * a, MatrixData * b)
941 for (i = 0; i < 4; i++) {
942 for (j = 0; j < 4; j++) {
944 for (k = 0; k < 4; k++) {
945 x += a->dm[i][k] * b->dm[k][j];
950 color_matrix_copy (dst, &tmp);
954 color_matrix_invert (MatrixData * d, MatrixData * s)
960 color_matrix_set_identity (&tmp);
961 for (j = 0; j < 3; j++) {
962 for (i = 0; i < 3; i++) {
964 s->dm[(i + 1) % 3][(j + 1) % 3] * s->dm[(i + 2) % 3][(j + 2) % 3] -
965 s->dm[(i + 1) % 3][(j + 2) % 3] * s->dm[(i + 2) % 3][(j + 1) % 3];
969 tmp.dm[0][0] * s->dm[0][0] + tmp.dm[0][1] * s->dm[1][0] +
970 tmp.dm[0][2] * s->dm[2][0];
971 for (j = 0; j < 3; j++) {
972 for (i = 0; i < 3; i++) {
976 color_matrix_copy (d, &tmp);
980 color_matrix_offset_components (MatrixData * m, double a1, double a2, double a3)
984 color_matrix_set_identity (&a);
988 color_matrix_multiply (m, &a, m);
992 color_matrix_scale_components (MatrixData * m, double a1, double a2, double a3)
996 color_matrix_set_identity (&a);
1000 color_matrix_multiply (m, &a, m);
1004 color_matrix_debug (const MatrixData * s)
1006 GST_DEBUG ("[%f %f %f %f]", s->dm[0][0], s->dm[0][1], s->dm[0][2],
1008 GST_DEBUG ("[%f %f %f %f]", s->dm[1][0], s->dm[1][1], s->dm[1][2],
1010 GST_DEBUG ("[%f %f %f %f]", s->dm[2][0], s->dm[2][1], s->dm[2][2],
1012 GST_DEBUG ("[%f %f %f %f]", s->dm[3][0], s->dm[3][1], s->dm[3][2],
1017 color_matrix_convert (MatrixData * s)
1021 for (i = 0; i < 4; i++)
1022 for (j = 0; j < 4; j++)
1023 s->im[i][j] = rint (s->dm[i][j]);
1025 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[0][0], s->im[0][1], s->im[0][2],
1027 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[1][0], s->im[1][1], s->im[1][2],
1029 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[2][0], s->im[2][1], s->im[2][2],
1031 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[3][0], s->im[3][1], s->im[3][2],
1036 color_matrix_YCbCr_to_RGB (MatrixData * m, double Kr, double Kb)
1038 double Kg = 1.0 - Kr - Kb;
1041 {1., 0., 2 * (1 - Kr), 0.},
1042 {1., -2 * Kb * (1 - Kb) / Kg, -2 * Kr * (1 - Kr) / Kg, 0.},
1043 {1., 2 * (1 - Kb), 0., 0.},
1048 color_matrix_multiply (m, &k, m);
1052 color_matrix_RGB_to_YCbCr (MatrixData * m, double Kr, double Kb)
1054 double Kg = 1.0 - Kr - Kb;
1063 x = 1 / (2 * (1 - Kb));
1064 k.dm[1][0] = -x * Kr;
1065 k.dm[1][1] = -x * Kg;
1066 k.dm[1][2] = x * (1 - Kb);
1069 x = 1 / (2 * (1 - Kr));
1070 k.dm[2][0] = x * (1 - Kr);
1071 k.dm[2][1] = -x * Kg;
1072 k.dm[2][2] = -x * Kb;
1080 color_matrix_multiply (m, &k, m);
1084 color_matrix_RGB_to_XYZ (MatrixData * dst, double Rx, double Ry, double Gx,
1085 double Gy, double Bx, double By, double Wx, double Wy)
1091 color_matrix_set_identity (&m);
1095 m.dm[2][0] = (1.0 - Rx - Ry);
1098 m.dm[2][1] = (1.0 - Gx - Gy);
1101 m.dm[2][2] = (1.0 - Bx - By);
1103 color_matrix_invert (&im, &m);
1107 wz = (1.0 - Wx - Wy) / Wy;
1109 sx = im.dm[0][0] * wx + im.dm[0][1] * wy + im.dm[0][2] * wz;
1110 sy = im.dm[1][0] * wx + im.dm[1][1] * wy + im.dm[1][2] * wz;
1111 sz = im.dm[2][0] * wx + im.dm[2][1] * wy + im.dm[2][2] * wz;
1123 color_matrix_copy (dst, &m);
1127 videoconvert_convert_init_tables (MatrixData * data)
1131 data->t_r = g_new (gint64, 256);
1132 data->t_g = g_new (gint64, 256);
1133 data->t_b = g_new (gint64, 256);
1135 for (i = 0; i < 256; i++) {
1136 gint64 r = 0, g = 0, b = 0;
1138 for (j = 0; j < 3; j++) {
1139 r = (r << 16) + data->im[j][0] * i;
1140 g = (g << 16) + data->im[j][1] * i;
1141 b = (b << 16) + data->im[j][2] * i;
1147 data->t_c = ((gint64) data->im[0][3] << 32)
1148 + ((gint64) data->im[1][3] << 16)
1149 + ((gint64) data->im[2][3] << 0);
1153 _custom_video_orc_matrix8 (guint8 * ORC_RESTRICT d1,
1154 const guint8 * ORC_RESTRICT s1, orc_int64 p1, orc_int64 p2, orc_int64 p3,
1155 orc_int64 p4, int n)
1160 gint a00, a01, a02, a03;
1161 gint a10, a11, a12, a13;
1162 gint a20, a21, a22, a23;
1164 a00 = (gint16) (p1 >> 16);
1165 a01 = (gint16) (p2 >> 16);
1166 a02 = (gint16) (p3 >> 16);
1167 a03 = (gint16) (p4 >> 16);
1168 a10 = (gint16) (p1 >> 32);
1169 a11 = (gint16) (p2 >> 32);
1170 a12 = (gint16) (p3 >> 32);
1171 a13 = (gint16) (p4 >> 32);
1172 a20 = (gint16) (p1 >> 48);
1173 a21 = (gint16) (p2 >> 48);
1174 a22 = (gint16) (p3 >> 48);
1175 a23 = (gint16) (p4 >> 48);
1177 for (i = 0; i < n; i++) {
1182 y = ((a00 * r + a01 * g + a02 * b) >> SCALE) + a03;
1183 u = ((a10 * r + a11 * g + a12 * b) >> SCALE) + a13;
1184 v = ((a20 * r + a21 * g + a22 * b) >> SCALE) + a23;
1186 d1[i * 4 + 1] = CLAMP (y, 0, 255);
1187 d1[i * 4 + 2] = CLAMP (u, 0, 255);
1188 d1[i * 4 + 3] = CLAMP (v, 0, 255);
1193 video_converter_matrix8 (MatrixData * data, gpointer pixels)
1195 gpointer d = pixels;
1196 video_orc_matrix8 (d, pixels, data->orc_p1, data->orc_p2,
1197 data->orc_p3, data->orc_p4, data->width);
1201 video_converter_matrix8_table (MatrixData * data, gpointer pixels)
1203 gint i, width = data->width * 4;
1205 gint64 c = data->t_c;
1209 for (i = 0; i < width; i += 4) {
1214 x = data->t_r[r] + data->t_g[g] + data->t_b[b] + c;
1216 p[i + 1] = x >> (32 + SCALE);
1217 p[i + 2] = x >> (16 + SCALE);
1218 p[i + 3] = x >> (0 + SCALE);
1223 video_converter_matrix8_AYUV_ARGB (MatrixData * data, gpointer pixels)
1225 gpointer d = pixels;
1227 video_orc_convert_AYUV_ARGB (d, 0, pixels, 0,
1228 data->im[0][0], data->im[0][2],
1229 data->im[2][1], data->im[1][1], data->im[1][2], data->width, 1);
1233 is_ayuv_to_rgb_matrix (MatrixData * data)
1235 if (data->im[0][0] != data->im[1][0] || data->im[1][0] != data->im[2][0])
1238 if (data->im[0][1] != 0 || data->im[2][2] != 0)
1245 is_identity_matrix (MatrixData * data)
1248 gint c = data->im[0][0];
1250 /* not really checking identity because of rounding errors but given
1251 * the conversions we do we just check for anything that looks like:
1258 for (i = 0; i < 4; i++) {
1259 for (j = 0; j < 4; j++) {
1261 if (i == 3 && data->im[i][j] != 1)
1263 else if (data->im[i][j] != c)
1265 } else if (data->im[i][j] != 0)
1273 is_no_clip_matrix (MatrixData * data)
1276 static const guint8 test[8][3] = {
1287 for (i = 0; i < 8; i++) {
1295 y = (data->im[0][0] * r + data->im[0][1] * g +
1296 data->im[0][2] * b + data->im[0][3]) >> SCALE;
1297 u = (data->im[1][0] * r + data->im[1][1] * g +
1298 data->im[1][2] * b + data->im[1][3]) >> SCALE;
1299 v = (data->im[2][0] * r + data->im[2][1] * g +
1300 data->im[2][2] * b + data->im[2][3]) >> SCALE;
1302 if (y != CLAMP (y, 0, 255) || u != CLAMP (u, 0, 255)
1303 || v != CLAMP (v, 0, 255))
1310 video_converter_matrix16 (MatrixData * data, gpointer pixels)
1315 guint16 *p = pixels;
1316 gint width = data->width;
1318 for (i = 0; i < width; i++) {
1323 y = (data->im[0][0] * r + data->im[0][1] * g +
1324 data->im[0][2] * b + data->im[0][3]) >> SCALE;
1325 u = (data->im[1][0] * r + data->im[1][1] * g +
1326 data->im[1][2] * b + data->im[1][3]) >> SCALE;
1327 v = (data->im[2][0] * r + data->im[2][1] * g +
1328 data->im[2][2] * b + data->im[2][3]) >> SCALE;
1330 p[i * 4 + 1] = CLAMP (y, 0, 65535);
1331 p[i * 4 + 2] = CLAMP (u, 0, 65535);
1332 p[i * 4 + 3] = CLAMP (v, 0, 65535);
1338 prepare_matrix (GstVideoConverter * convert, MatrixData * data)
1340 if (is_identity_matrix (data))
1343 color_matrix_scale_components (data, SCALE_F, SCALE_F, SCALE_F);
1344 color_matrix_convert (data);
1346 data->width = convert->current_width;
1348 if (convert->current_bits == 8) {
1349 if (!convert->unpack_rgb && convert->pack_rgb
1350 && is_ayuv_to_rgb_matrix (data)) {
1351 GST_DEBUG ("use fast AYUV -> RGB matrix");
1352 data->matrix_func = video_converter_matrix8_AYUV_ARGB;
1353 } else if (is_no_clip_matrix (data)) {
1354 GST_DEBUG ("use 8bit table");
1355 data->matrix_func = video_converter_matrix8_table;
1356 videoconvert_convert_init_tables (data);
1360 GST_DEBUG ("use 8bit matrix");
1361 data->matrix_func = video_converter_matrix8;
1363 data->orc_p1 = (((guint64) (guint16) data->im[2][0]) << 48) |
1364 (((guint64) (guint16) data->im[1][0]) << 32) |
1365 (((guint64) (guint16) data->im[0][0]) << 16);
1366 data->orc_p2 = (((guint64) (guint16) data->im[2][1]) << 48) |
1367 (((guint64) (guint16) data->im[1][1]) << 32) |
1368 (((guint64) (guint16) data->im[0][1]) << 16);
1369 data->orc_p3 = (((guint64) (guint16) data->im[2][2]) << 48) |
1370 (((guint64) (guint16) data->im[1][2]) << 32) |
1371 (((guint64) (guint16) data->im[0][2]) << 16);
1373 a03 = data->im[0][3] >> SCALE;
1374 a13 = data->im[1][3] >> SCALE;
1375 a23 = data->im[2][3] >> SCALE;
1377 data->orc_p4 = (((guint64) (guint16) a23) << 48) |
1378 (((guint64) (guint16) a13) << 32) | (((guint64) (guint16) a03) << 16);
1381 GST_DEBUG ("use 16bit matrix");
1382 data->matrix_func = video_converter_matrix16;
1387 compute_matrix_to_RGB (GstVideoConverter * convert, MatrixData * data)
1390 gdouble Kr = 0, Kb = 0;
1392 info = &convert->in_info;
1395 const GstVideoFormatInfo *uinfo;
1396 gint offset[4], scale[4];
1398 uinfo = gst_video_format_get_info (convert->unpack_format);
1400 /* bring color components to [0..1.0] range */
1401 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1404 color_matrix_offset_components (data, -offset[0], -offset[1], -offset[2]);
1405 color_matrix_scale_components (data, 1 / ((float) scale[0]),
1406 1 / ((float) scale[1]), 1 / ((float) scale[2]));
1409 if (!convert->unpack_rgb && !CHECK_MATRIX_NONE (convert)) {
1410 if (CHECK_MATRIX_OUTPUT (convert))
1411 info = &convert->out_info;
1413 /* bring components to R'G'B' space */
1414 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
1415 color_matrix_YCbCr_to_RGB (data, Kr, Kb);
1417 color_matrix_debug (data);
1421 compute_matrix_to_YUV (GstVideoConverter * convert, MatrixData * data,
1425 gdouble Kr = 0, Kb = 0;
1427 if (force || (!convert->pack_rgb && !CHECK_MATRIX_NONE (convert))) {
1428 if (CHECK_MATRIX_INPUT (convert))
1429 info = &convert->in_info;
1431 info = &convert->out_info;
1433 /* bring components to YCbCr space */
1434 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
1435 color_matrix_RGB_to_YCbCr (data, Kr, Kb);
1438 info = &convert->out_info;
1441 const GstVideoFormatInfo *uinfo;
1442 gint offset[4], scale[4];
1444 uinfo = gst_video_format_get_info (convert->pack_format);
1446 /* bring color components to nominal range */
1447 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1450 color_matrix_scale_components (data, (float) scale[0], (float) scale[1],
1452 color_matrix_offset_components (data, offset[0], offset[1], offset[2]);
1455 color_matrix_debug (data);
1460 gamma_convert_u8_u16 (GammaData * data, gpointer dest, gpointer src)
1465 guint16 *table = data->gamma_table;
1466 gint width = data->width * 4;
1468 for (i = 0; i < width; i += 4) {
1469 d[i + 0] = (s[i] << 8) | s[i];
1470 d[i + 1] = table[s[i + 1]];
1471 d[i + 2] = table[s[i + 2]];
1472 d[i + 3] = table[s[i + 3]];
1477 gamma_convert_u16_u8 (GammaData * data, gpointer dest, gpointer src)
1482 guint8 *table = data->gamma_table;
1483 gint width = data->width * 4;
1485 for (i = 0; i < width; i += 4) {
1486 d[i + 0] = s[i] >> 8;
1487 d[i + 1] = table[s[i + 1]];
1488 d[i + 2] = table[s[i + 2]];
1489 d[i + 3] = table[s[i + 3]];
1494 gamma_convert_u16_u16 (GammaData * data, gpointer dest, gpointer src)
1499 guint16 *table = data->gamma_table;
1500 gint width = data->width * 4;
1502 for (i = 0; i < width; i += 4) {
1504 d[i + 1] = table[s[i + 1]];
1505 d[i + 2] = table[s[i + 2]];
1506 d[i + 3] = table[s[i + 3]];
1511 setup_gamma_decode (GstVideoConverter * convert)
1513 GstVideoTransferFunction func;
1517 func = convert->in_info.colorimetry.transfer;
1519 convert->gamma_dec.width = convert->current_width;
1520 if (convert->current_bits == 8) {
1521 GST_DEBUG ("gamma decode 8->16: %d", func);
1522 convert->gamma_dec.gamma_func = gamma_convert_u8_u16;
1523 t = convert->gamma_dec.gamma_table = g_malloc (sizeof (guint16) * 256);
1525 for (i = 0; i < 256; i++)
1526 t[i] = rint (gst_video_color_transfer_decode (func, i / 255.0) * 65535.0);
1528 GST_DEBUG ("gamma decode 16->16: %d", func);
1529 convert->gamma_dec.gamma_func = gamma_convert_u16_u16;
1530 t = convert->gamma_dec.gamma_table = g_malloc (sizeof (guint16) * 65536);
1532 for (i = 0; i < 65536; i++)
1534 rint (gst_video_color_transfer_decode (func, i / 65535.0) * 65535.0);
1536 convert->current_bits = 16;
1537 convert->current_pstride = 8;
1538 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1542 setup_gamma_encode (GstVideoConverter * convert, gint target_bits)
1544 GstVideoTransferFunction func;
1547 func = convert->out_info.colorimetry.transfer;
1549 convert->gamma_enc.width = convert->current_width;
1550 if (target_bits == 8) {
1553 GST_DEBUG ("gamma encode 16->8: %d", func);
1554 convert->gamma_enc.gamma_func = gamma_convert_u16_u8;
1555 t = convert->gamma_enc.gamma_table = g_malloc (sizeof (guint8) * 65536);
1557 for (i = 0; i < 65536; i++)
1558 t[i] = rint (gst_video_color_transfer_encode (func, i / 65535.0) * 255.0);
1562 GST_DEBUG ("gamma encode 16->16: %d", func);
1563 convert->gamma_enc.gamma_func = gamma_convert_u16_u16;
1564 t = convert->gamma_enc.gamma_table = g_malloc (sizeof (guint16) * 65536);
1566 for (i = 0; i < 65536; i++)
1568 rint (gst_video_color_transfer_encode (func, i / 65535.0) * 65535.0);
1572 static GstLineCache *
1573 chain_convert_to_RGB (GstVideoConverter * convert, GstLineCache * prev,
1578 do_gamma = CHECK_GAMMA_REMAP (convert);
1583 if (!convert->unpack_rgb) {
1584 color_matrix_set_identity (&convert->to_RGB_matrix);
1585 compute_matrix_to_RGB (convert, &convert->to_RGB_matrix);
1587 /* matrix is in 0..1 range, scale to current bits */
1588 GST_DEBUG ("chain RGB convert");
1589 scale = 1 << convert->current_bits;
1590 color_matrix_scale_components (&convert->to_RGB_matrix,
1591 (float) scale, (float) scale, (float) scale);
1593 prepare_matrix (convert, &convert->to_RGB_matrix);
1595 if (convert->current_bits == 8)
1596 convert->current_format = GST_VIDEO_FORMAT_ARGB;
1598 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1601 prev = convert->to_RGB_lines[idx] = gst_line_cache_new (prev);
1602 prev->write_input = TRUE;
1603 prev->pass_alloc = FALSE;
1605 prev->stride = convert->current_pstride * convert->current_width;
1606 gst_line_cache_set_need_line_func (prev,
1607 do_convert_to_RGB_lines, idx, convert, NULL);
1609 GST_DEBUG ("chain gamma decode");
1610 setup_gamma_decode (convert);
1615 static GstLineCache *
1616 chain_hscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1621 method = GET_OPT_RESAMPLER_METHOD (convert);
1622 taps = GET_OPT_RESAMPLER_TAPS (convert);
1624 convert->h_scaler[idx] =
1625 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
1626 convert->in_width, convert->out_width, convert->config);
1628 gst_video_scaler_get_coeff (convert->h_scaler[idx], 0, NULL, &taps);
1630 GST_DEBUG ("chain hscale %d->%d, taps %d, method %d",
1631 convert->in_width, convert->out_width, taps, method);
1633 convert->current_width = convert->out_width;
1634 convert->h_scale_format = convert->current_format;
1636 prev = convert->hscale_lines[idx] = gst_line_cache_new (prev);
1637 prev->write_input = FALSE;
1638 prev->pass_alloc = FALSE;
1640 prev->stride = convert->current_pstride * convert->current_width;
1641 gst_line_cache_set_need_line_func (prev, do_hscale_lines, idx, convert, NULL);
1646 static GstLineCache *
1647 chain_vscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1650 guint taps, taps_i = 0;
1653 method = GET_OPT_RESAMPLER_METHOD (convert);
1654 taps = GET_OPT_RESAMPLER_TAPS (convert);
1656 if (GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)) {
1657 convert->v_scaler_i[idx] =
1658 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_INTERLACED,
1659 taps, convert->in_height, convert->out_height, convert->config);
1661 gst_video_scaler_get_coeff (convert->v_scaler_i[idx], 0, NULL, &taps_i);
1664 convert->v_scaler_p[idx] =
1665 gst_video_scaler_new (method, 0, taps, convert->in_height,
1666 convert->out_height, convert->config);
1667 convert->v_scale_width = convert->current_width;
1668 convert->v_scale_format = convert->current_format;
1669 convert->current_height = convert->out_height;
1671 gst_video_scaler_get_coeff (convert->v_scaler_p[idx], 0, NULL, &taps);
1673 GST_DEBUG ("chain vscale %d->%d, taps %d, method %d, backlog %d",
1674 convert->in_height, convert->out_height, taps, method, backlog);
1676 prev->backlog = backlog;
1677 prev = convert->vscale_lines[idx] = gst_line_cache_new (prev);
1678 prev->pass_alloc = (taps == 1);
1679 prev->write_input = FALSE;
1680 prev->n_lines = MAX (taps_i, taps);
1681 prev->stride = convert->current_pstride * convert->current_width;
1682 gst_line_cache_set_need_line_func (prev, do_vscale_lines, idx, convert, NULL);
1687 static GstLineCache *
1688 chain_scale (GstVideoConverter * convert, GstLineCache * prev, gboolean force,
1691 gint s0, s1, s2, s3;
1693 s0 = convert->current_width * convert->current_height;
1694 s3 = convert->out_width * convert->out_height;
1696 GST_DEBUG ("in pixels %d <> out pixels %d", s0, s3);
1698 if (s3 <= s0 || force) {
1699 /* we are making the image smaller or are forced to resample */
1700 s1 = convert->out_width * convert->current_height;
1701 s2 = convert->current_width * convert->out_height;
1703 GST_DEBUG ("%d <> %d", s1, s2);
1706 /* h scaling first produces less pixels */
1707 if (convert->current_width != convert->out_width)
1708 prev = chain_hscale (convert, prev, idx);
1709 if (convert->current_height != convert->out_height)
1710 prev = chain_vscale (convert, prev, idx);
1712 /* v scaling first produces less pixels */
1713 if (convert->current_height != convert->out_height)
1714 prev = chain_vscale (convert, prev, idx);
1715 if (convert->current_width != convert->out_width)
1716 prev = chain_hscale (convert, prev, idx);
1722 static GstLineCache *
1723 chain_convert (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1725 gboolean do_gamma, do_conversion, pass_alloc = FALSE;
1726 gboolean same_matrix, same_primaries, same_bits;
1729 same_bits = convert->unpack_bits == convert->pack_bits;
1730 if (CHECK_MATRIX_NONE (convert)) {
1734 convert->in_info.colorimetry.matrix ==
1735 convert->out_info.colorimetry.matrix;
1738 if (CHECK_PRIMARIES_NONE (convert)) {
1739 same_primaries = TRUE;
1742 convert->in_info.colorimetry.primaries ==
1743 convert->out_info.colorimetry.primaries;
1746 GST_DEBUG ("matrix %d -> %d (%d)", convert->in_info.colorimetry.matrix,
1747 convert->out_info.colorimetry.matrix, same_matrix);
1748 GST_DEBUG ("bits %d -> %d (%d)", convert->unpack_bits, convert->pack_bits,
1750 GST_DEBUG ("primaries %d -> %d (%d)", convert->in_info.colorimetry.primaries,
1751 convert->out_info.colorimetry.primaries, same_primaries);
1753 color_matrix_set_identity (&convert->convert_matrix);
1755 if (!same_primaries) {
1756 const GstVideoColorPrimariesInfo *pi;
1758 pi = gst_video_color_primaries_get_info (convert->in_info.colorimetry.
1760 color_matrix_RGB_to_XYZ (&p1, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx,
1761 pi->By, pi->Wx, pi->Wy);
1762 GST_DEBUG ("to XYZ matrix");
1763 color_matrix_debug (&p1);
1764 GST_DEBUG ("current matrix");
1765 color_matrix_multiply (&convert->convert_matrix, &convert->convert_matrix,
1767 color_matrix_debug (&convert->convert_matrix);
1769 pi = gst_video_color_primaries_get_info (convert->out_info.colorimetry.
1771 color_matrix_RGB_to_XYZ (&p2, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx,
1772 pi->By, pi->Wx, pi->Wy);
1773 color_matrix_invert (&p2, &p2);
1774 GST_DEBUG ("to RGB matrix");
1775 color_matrix_debug (&p2);
1776 color_matrix_multiply (&convert->convert_matrix, &convert->convert_matrix,
1778 GST_DEBUG ("current matrix");
1779 color_matrix_debug (&convert->convert_matrix);
1782 do_gamma = CHECK_GAMMA_REMAP (convert);
1785 convert->in_bits = convert->unpack_bits;
1786 convert->out_bits = convert->pack_bits;
1788 if (!same_bits || !same_matrix || !same_primaries) {
1789 /* no gamma, combine all conversions into 1 */
1790 if (convert->in_bits < convert->out_bits) {
1791 gint scale = 1 << (convert->out_bits - convert->in_bits);
1792 color_matrix_scale_components (&convert->convert_matrix,
1793 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
1795 GST_DEBUG ("to RGB matrix");
1796 compute_matrix_to_RGB (convert, &convert->convert_matrix);
1797 GST_DEBUG ("current matrix");
1798 color_matrix_debug (&convert->convert_matrix);
1800 GST_DEBUG ("to YUV matrix");
1801 compute_matrix_to_YUV (convert, &convert->convert_matrix, FALSE);
1802 GST_DEBUG ("current matrix");
1803 color_matrix_debug (&convert->convert_matrix);
1804 if (convert->in_bits > convert->out_bits) {
1805 gint scale = 1 << (convert->in_bits - convert->out_bits);
1806 color_matrix_scale_components (&convert->convert_matrix,
1807 (float) scale, (float) scale, (float) scale);
1809 convert->current_bits = MAX (convert->in_bits, convert->out_bits);
1811 do_conversion = TRUE;
1812 if (!same_matrix || !same_primaries)
1813 prepare_matrix (convert, &convert->convert_matrix);
1814 if (convert->in_bits == convert->out_bits)
1817 do_conversion = FALSE;
1819 convert->current_bits = convert->pack_bits;
1820 convert->current_format = convert->pack_format;
1821 convert->current_pstride = convert->current_bits >> 1;
1823 /* we did gamma, just do colorspace conversion if needed */
1824 if (same_primaries) {
1825 do_conversion = FALSE;
1827 prepare_matrix (convert, &convert->convert_matrix);
1828 convert->in_bits = convert->out_bits = 16;
1830 do_conversion = TRUE;
1834 if (do_conversion) {
1835 GST_DEBUG ("chain conversion");
1836 prev = convert->convert_lines[idx] = gst_line_cache_new (prev);
1837 prev->write_input = TRUE;
1838 prev->pass_alloc = pass_alloc;
1840 prev->stride = convert->current_pstride * convert->current_width;
1841 gst_line_cache_set_need_line_func (prev,
1842 do_convert_lines, idx, convert, NULL);
1848 convert_set_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1851 guint8 alpha = MIN (convert->alpha_value, 255);
1854 for (i = 0; i < width; i++)
1859 convert_set_alpha_u16 (GstVideoConverter * convert, gpointer pixels, gint width)
1861 guint16 *p = pixels;
1865 alpha = MIN (convert->alpha_value, 255);
1866 alpha |= alpha << 8;
1868 for (i = 0; i < width; i++)
1873 convert_mult_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1876 guint alpha = convert->alpha_value;
1879 for (i = 0; i < width; i++) {
1880 gint a = (p[i * 4] * alpha) / 255;
1881 p[i * 4] = CLAMP (a, 0, 255);
1886 convert_mult_alpha_u16 (GstVideoConverter * convert, gpointer pixels,
1889 guint16 *p = pixels;
1890 guint alpha = convert->alpha_value;
1893 for (i = 0; i < width; i++) {
1894 gint a = (p[i * 4] * alpha) / 255;
1895 p[i * 4] = CLAMP (a, 0, 65535);
1899 static GstLineCache *
1900 chain_alpha (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1902 switch (convert->alpha_mode) {
1903 case ALPHA_MODE_NONE:
1904 case ALPHA_MODE_COPY:
1907 case ALPHA_MODE_SET:
1908 if (convert->current_bits == 8)
1909 convert->alpha_func = convert_set_alpha_u8;
1911 convert->alpha_func = convert_set_alpha_u16;
1913 case ALPHA_MODE_MULT:
1914 if (convert->current_bits == 8)
1915 convert->alpha_func = convert_mult_alpha_u8;
1917 convert->alpha_func = convert_mult_alpha_u16;
1921 GST_DEBUG ("chain alpha mode %d", convert->alpha_mode);
1922 prev = convert->alpha_lines[idx] = gst_line_cache_new (prev);
1923 prev->write_input = TRUE;
1924 prev->pass_alloc = TRUE;
1926 prev->stride = convert->current_pstride * convert->current_width;
1927 gst_line_cache_set_need_line_func (prev, do_alpha_lines, idx, convert, NULL);
1932 static GstLineCache *
1933 chain_convert_to_YUV (GstVideoConverter * convert, GstLineCache * prev,
1938 do_gamma = CHECK_GAMMA_REMAP (convert);
1943 GST_DEBUG ("chain gamma encode");
1944 setup_gamma_encode (convert, convert->pack_bits);
1946 convert->current_bits = convert->pack_bits;
1947 convert->current_pstride = convert->current_bits >> 1;
1949 if (!convert->pack_rgb) {
1950 color_matrix_set_identity (&convert->to_YUV_matrix);
1951 compute_matrix_to_YUV (convert, &convert->to_YUV_matrix, FALSE);
1953 /* matrix is in 0..255 range, scale to pack bits */
1954 GST_DEBUG ("chain YUV convert");
1955 scale = 1 << convert->pack_bits;
1956 color_matrix_scale_components (&convert->to_YUV_matrix,
1957 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
1958 prepare_matrix (convert, &convert->to_YUV_matrix);
1960 convert->current_format = convert->pack_format;
1962 prev = convert->to_YUV_lines[idx] = gst_line_cache_new (prev);
1963 prev->write_input = FALSE;
1964 prev->pass_alloc = FALSE;
1966 prev->stride = convert->current_pstride * convert->current_width;
1967 gst_line_cache_set_need_line_func (prev,
1968 do_convert_to_YUV_lines, idx, convert, NULL);
1974 static GstLineCache *
1975 chain_downsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1977 if (convert->downsample_p[idx] || convert->downsample_i[idx]) {
1978 GST_DEBUG ("chain downsample");
1979 prev = convert->downsample_lines[idx] = gst_line_cache_new (prev);
1980 prev->write_input = TRUE;
1981 prev->pass_alloc = TRUE;
1983 prev->stride = convert->current_pstride * convert->current_width;
1984 gst_line_cache_set_need_line_func (prev,
1985 do_downsample_lines, idx, convert, NULL);
1990 static GstLineCache *
1991 chain_dither (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1994 gboolean do_dither = FALSE;
1995 GstVideoDitherFlags flags = 0;
1996 GstVideoDitherMethod method;
1997 guint quant[4], target_quant;
1999 method = GET_OPT_DITHER_METHOD (convert);
2000 if (method == GST_VIDEO_DITHER_NONE)
2003 target_quant = GET_OPT_DITHER_QUANTIZATION (convert);
2004 GST_DEBUG ("method %d, target-quantization %d", method, target_quant);
2006 if (convert->pack_pal) {
2013 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++) {
2016 depth = convert->out_info.finfo->depth[i];
2023 if (convert->current_bits >= depth) {
2024 quant[i] = 1 << (convert->current_bits - depth);
2025 if (target_quant > quant[i]) {
2026 flags |= GST_VIDEO_DITHER_FLAG_QUANTIZE;
2027 quant[i] = target_quant;
2038 GST_DEBUG ("chain dither");
2040 convert->dither[idx] = gst_video_dither_new (method,
2041 flags, convert->pack_format, quant, convert->current_width);
2043 prev = convert->dither_lines[idx] = gst_line_cache_new (prev);
2044 prev->write_input = TRUE;
2045 prev->pass_alloc = TRUE;
2047 prev->stride = convert->current_pstride * convert->current_width;
2048 gst_line_cache_set_need_line_func (prev, do_dither_lines, idx, convert,
2054 static GstLineCache *
2055 chain_pack (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2057 convert->pack_nlines = convert->out_info.finfo->pack_lines;
2058 convert->pack_pstride = convert->current_pstride;
2059 convert->identity_pack =
2060 (convert->out_info.finfo->format ==
2061 convert->out_info.finfo->unpack_format);
2062 GST_DEBUG ("chain pack line format %s, pstride %d, identity_pack %d (%d %d)",
2063 gst_video_format_to_string (convert->current_format),
2064 convert->current_pstride, convert->identity_pack,
2065 convert->out_info.finfo->format, convert->out_info.finfo->unpack_format);
2071 setup_allocators (GstVideoConverter * convert)
2073 GstLineCache *cache, *prev;
2074 GstLineCacheAllocLineFunc alloc_line;
2075 gboolean alloc_writable;
2077 GDestroyNotify notify;
2081 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2082 width += convert->out_x;
2084 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2085 /* start with using dest lines if we can directly write into it */
2086 if (convert->identity_pack) {
2087 alloc_line = get_dest_line;
2088 alloc_writable = TRUE;
2089 user_data = convert;
2093 converter_alloc_new (sizeof (guint16) * width * 4, 4 + BACKLOG,
2095 setup_border_alloc (convert, user_data);
2096 notify = (GDestroyNotify) converter_alloc_free;
2097 alloc_line = get_border_temp_line;
2098 /* when we add a border, we need to write */
2099 alloc_writable = convert->borderline != NULL;
2102 /* First step, try to calculate how many temp lines we need. Go backwards,
2103 * keep track of the maximum number of lines we need for each intermediate
2105 for (prev = cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2106 GST_DEBUG ("looking at cache %p, %d lines, %d backlog", cache,
2107 cache->n_lines, cache->backlog);
2108 prev->n_lines = MAX (prev->n_lines, cache->n_lines);
2109 if (!cache->pass_alloc) {
2110 GST_DEBUG ("cache %p, needs %d lines", prev, prev->n_lines);
2115 /* now walk backwards, we try to write into the dest lines directly
2116 * and keep track if the source needs to be writable */
2117 for (cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2118 gst_line_cache_set_alloc_line_func (cache, alloc_line, user_data, notify);
2119 cache->alloc_writable = alloc_writable;
2121 /* make sure only one cache frees the allocator */
2124 if (!cache->pass_alloc) {
2125 /* can't pass allocator, make new temp line allocator */
2127 converter_alloc_new (sizeof (guint16) * width * 4,
2128 cache->n_lines + cache->backlog, convert, NULL);
2129 notify = (GDestroyNotify) converter_alloc_free;
2130 alloc_line = get_temp_line;
2131 alloc_writable = FALSE;
2133 /* if someone writes to the input, we need a writable line from the
2135 if (cache->write_input)
2136 alloc_writable = TRUE;
2138 /* free leftover allocator */
2145 setup_borderline (GstVideoConverter * convert)
2149 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2150 width += convert->out_x;
2152 if (convert->fill_border && (convert->out_height < convert->out_maxheight ||
2153 convert->out_width < convert->out_maxwidth)) {
2156 const GstVideoFormatInfo *out_finfo;
2157 gpointer planes[GST_VIDEO_MAX_PLANES];
2158 gint strides[GST_VIDEO_MAX_PLANES];
2160 convert->borderline = g_malloc0 (sizeof (guint16) * width * 4);
2162 out_finfo = convert->out_info.finfo;
2164 if (GST_VIDEO_INFO_IS_YUV (&convert->out_info)) {
2169 /* Get Color matrix. */
2170 color_matrix_set_identity (&cm);
2171 compute_matrix_to_YUV (convert, &cm, TRUE);
2172 color_matrix_convert (&cm);
2174 border_val = GINT32_FROM_BE (convert->border_argb);
2176 b = (0xFF000000 & border_val) >> 24;
2177 g = (0x00FF0000 & border_val) >> 16;
2178 r = (0x0000FF00 & border_val) >> 8;
2179 a = (0x000000FF & border_val);
2181 y = 16 + ((r * cm.im[0][0] + g * cm.im[0][1] + b * cm.im[0][2]) >> 8);
2182 u = 128 + ((r * cm.im[1][0] + g * cm.im[1][1] + b * cm.im[1][2]) >> 8);
2183 v = 128 + ((r * cm.im[2][0] + g * cm.im[2][1] + b * cm.im[2][2]) >> 8);
2185 a = CLAMP (a, 0, 255);
2186 y = CLAMP (y, 0, 255);
2187 u = CLAMP (u, 0, 255);
2188 v = CLAMP (v, 0, 255);
2190 border_val = a | (y << 8) | (u << 16) | ((guint32) v << 24);
2192 border_val = GINT32_FROM_BE (convert->border_argb);
2194 if (convert->pack_bits == 8)
2195 video_orc_splat_u32 (convert->borderline, border_val, width);
2197 video_orc_splat2_u64 (convert->borderline, border_val, width);
2199 /* convert pixels */
2200 for (i = 0; i < out_finfo->n_planes; i++) {
2201 planes[i] = &convert->borders[i];
2202 strides[i] = sizeof (guint64);
2205 if (out_finfo->n_planes == 1) {
2206 /* for packed formats, convert based on subsampling so that we
2207 * get a complete group of pixels */
2208 for (i = 0; i < out_finfo->n_components; i++) {
2209 w_sub = MAX (w_sub, out_finfo->w_sub[i]);
2212 out_finfo->pack_func (out_finfo, GST_VIDEO_PACK_FLAG_NONE,
2213 convert->borderline, 0, planes, strides,
2214 GST_VIDEO_CHROMA_SITE_UNKNOWN, 0, 1 << w_sub);
2216 convert->borderline = NULL;
2221 convert_get_alpha_mode (GstVideoConverter * convert)
2223 gboolean in_alpha, out_alpha;
2225 in_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->in_info);
2226 out_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->out_info);
2228 /* no output alpha, do nothing */
2230 return ALPHA_MODE_NONE;
2234 if (CHECK_ALPHA_COPY (convert))
2235 return ALPHA_MODE_COPY;
2237 if (CHECK_ALPHA_MULT (convert)) {
2238 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2239 return ALPHA_MODE_COPY;
2241 return ALPHA_MODE_MULT;
2244 /* nothing special, this is what unpack etc does automatically */
2245 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2246 return ALPHA_MODE_NONE;
2248 /* everything else becomes SET */
2249 return ALPHA_MODE_SET;
2253 * gst_video_converter_new: (skip)
2254 * @in_info: a #GstVideoInfo
2255 * @out_info: a #GstVideoInfo
2256 * @config: (transfer full): a #GstStructure with configuration options
2258 * Create a new converter object to convert between @in_info and @out_info
2261 * Returns: a #GstVideoConverter or %NULL if conversion is not possible.
2266 gst_video_converter_new (GstVideoInfo * in_info, GstVideoInfo * out_info,
2267 GstStructure * config)
2269 GstVideoConverter *convert;
2271 const GstVideoFormatInfo *fin, *fout, *finfo;
2272 gdouble alpha_value;
2275 g_return_val_if_fail (in_info != NULL, NULL);
2276 g_return_val_if_fail (out_info != NULL, NULL);
2277 /* we won't ever do framerate conversion */
2278 g_return_val_if_fail (in_info->fps_n == out_info->fps_n, NULL);
2279 g_return_val_if_fail (in_info->fps_d == out_info->fps_d, NULL);
2280 /* we won't ever do deinterlace */
2281 g_return_val_if_fail (in_info->interlace_mode == out_info->interlace_mode,
2284 convert = g_slice_new0 (GstVideoConverter);
2286 fin = in_info->finfo;
2287 fout = out_info->finfo;
2289 convert->in_info = *in_info;
2290 convert->out_info = *out_info;
2292 /* default config */
2293 convert->config = gst_structure_new_empty ("GstVideoConverter");
2295 gst_video_converter_set_config (convert, config);
2297 convert->in_maxwidth = GST_VIDEO_INFO_WIDTH (in_info);
2298 convert->in_maxheight = GST_VIDEO_INFO_HEIGHT (in_info);
2299 convert->out_maxwidth = GST_VIDEO_INFO_WIDTH (out_info);
2300 convert->out_maxheight = GST_VIDEO_INFO_HEIGHT (out_info);
2302 convert->in_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_X, 0);
2303 convert->in_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_Y, 0);
2304 convert->in_x &= ~((1 << fin->w_sub[1]) - 1);
2305 convert->in_y &= ~((1 << fin->h_sub[1]) - 1);
2307 convert->in_width = get_opt_int (convert,
2308 GST_VIDEO_CONVERTER_OPT_SRC_WIDTH, convert->in_maxwidth - convert->in_x);
2309 convert->in_height = get_opt_int (convert,
2310 GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT,
2311 convert->in_maxheight - convert->in_y);
2314 MIN (convert->in_width, convert->in_maxwidth - convert->in_x);
2315 convert->in_height =
2316 MIN (convert->in_height, convert->in_maxheight - convert->in_y);
2318 convert->out_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_X, 0);
2319 convert->out_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_Y, 0);
2320 convert->out_x &= ~((1 << fout->w_sub[1]) - 1);
2321 convert->out_y &= ~((1 << fout->h_sub[1]) - 1);
2323 convert->out_width = get_opt_int (convert,
2324 GST_VIDEO_CONVERTER_OPT_DEST_WIDTH,
2325 convert->out_maxwidth - convert->out_x);
2326 convert->out_height =
2327 get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT,
2328 convert->out_maxheight - convert->out_y);
2330 convert->out_width =
2331 MIN (convert->out_width, convert->out_maxwidth - convert->out_x);
2332 convert->out_height =
2333 MIN (convert->out_height, convert->out_maxheight - convert->out_y);
2335 convert->fill_border = GET_OPT_FILL_BORDER (convert);
2336 convert->border_argb = get_opt_uint (convert,
2337 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB);
2339 alpha_value = GET_OPT_ALPHA_VALUE (convert);
2340 convert->alpha_value = 255 * alpha_value;
2341 convert->alpha_mode = convert_get_alpha_mode (convert);
2343 convert->unpack_format = in_info->finfo->unpack_format;
2344 finfo = gst_video_format_get_info (convert->unpack_format);
2345 convert->unpack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2346 convert->unpack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2347 if (convert->unpack_rgb
2348 && in_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2349 /* force identity matrix for RGB input */
2350 GST_WARNING ("invalid matrix %d for input RGB format, using RGB",
2351 in_info->colorimetry.matrix);
2352 convert->in_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2355 convert->pack_format = out_info->finfo->unpack_format;
2356 finfo = gst_video_format_get_info (convert->pack_format);
2357 convert->pack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2358 convert->pack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2360 gst_video_format_get_palette (GST_VIDEO_INFO_FORMAT (out_info),
2361 &convert->pack_palsize);
2362 if (convert->pack_rgb
2363 && out_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2364 /* force identity matrix for RGB output */
2365 GST_WARNING ("invalid matrix %d for output RGB format, using RGB",
2366 out_info->colorimetry.matrix);
2367 convert->out_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2370 n_threads = get_opt_uint (convert, GST_VIDEO_CONVERTER_OPT_THREADS, 1);
2371 if (n_threads == 0 || n_threads > g_get_num_processors ())
2372 n_threads = g_get_num_processors ();
2373 /* Magic number of 200 lines */
2374 if (MAX (convert->out_height, convert->in_height) / n_threads < 200)
2375 n_threads = (MAX (convert->out_height, convert->in_height) + 199) / 200;
2376 convert->conversion_runner = gst_parallelized_task_runner_new (n_threads);
2378 if (video_converter_lookup_fastpath (convert))
2381 if (in_info->finfo->unpack_func == NULL)
2382 goto no_unpack_func;
2384 if (out_info->finfo->pack_func == NULL)
2387 convert->convert = video_converter_generic;
2389 convert->upsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2390 convert->upsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2391 convert->downsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2392 convert->downsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2393 convert->v_scaler_p = g_new0 (GstVideoScaler *, n_threads);
2394 convert->v_scaler_i = g_new0 (GstVideoScaler *, n_threads);
2395 convert->h_scaler = g_new0 (GstVideoScaler *, n_threads);
2396 convert->unpack_lines = g_new0 (GstLineCache *, n_threads);
2397 convert->pack_lines = g_new0 (GstLineCache *, n_threads);
2398 convert->upsample_lines = g_new0 (GstLineCache *, n_threads);
2399 convert->to_RGB_lines = g_new0 (GstLineCache *, n_threads);
2400 convert->hscale_lines = g_new0 (GstLineCache *, n_threads);
2401 convert->vscale_lines = g_new0 (GstLineCache *, n_threads);
2402 convert->convert_lines = g_new0 (GstLineCache *, n_threads);
2403 convert->alpha_lines = g_new0 (GstLineCache *, n_threads);
2404 convert->to_YUV_lines = g_new0 (GstLineCache *, n_threads);
2405 convert->downsample_lines = g_new0 (GstLineCache *, n_threads);
2406 convert->dither_lines = g_new0 (GstLineCache *, n_threads);
2407 convert->dither = g_new0 (GstVideoDither *, n_threads);
2409 for (i = 0; i < n_threads; i++) {
2410 convert->current_format = GST_VIDEO_INFO_FORMAT (in_info);
2411 convert->current_width = convert->in_width;
2412 convert->current_height = convert->in_height;
2415 prev = chain_unpack_line (convert, i);
2416 /* upsample chroma */
2417 prev = chain_upsample (convert, prev, i);
2418 /* convert to gamma decoded RGB */
2419 prev = chain_convert_to_RGB (convert, prev, i);
2420 /* do all downscaling */
2421 prev = chain_scale (convert, prev, FALSE, i);
2422 /* do conversion between color spaces */
2423 prev = chain_convert (convert, prev, i);
2424 /* do alpha channels */
2425 prev = chain_alpha (convert, prev, i);
2426 /* do all remaining (up)scaling */
2427 prev = chain_scale (convert, prev, TRUE, i);
2428 /* convert to gamma encoded Y'Cb'Cr' */
2429 prev = chain_convert_to_YUV (convert, prev, i);
2430 /* downsample chroma */
2431 prev = chain_downsample (convert, prev, i);
2433 prev = chain_dither (convert, prev, i);
2434 /* pack into final format */
2435 convert->pack_lines[i] = chain_pack (convert, prev, i);
2438 setup_borderline (convert);
2439 /* now figure out allocators */
2440 setup_allocators (convert);
2448 GST_ERROR ("no unpack_func for format %s",
2449 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
2450 gst_video_converter_free (convert);
2455 GST_ERROR ("no pack_func for format %s",
2456 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
2457 gst_video_converter_free (convert);
2463 clear_matrix_data (MatrixData * data)
2471 * gst_video_converter_free:
2472 * @convert: a #GstVideoConverter
2479 gst_video_converter_free (GstVideoConverter * convert)
2483 g_return_if_fail (convert != NULL);
2485 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2486 if (convert->upsample_p && convert->upsample_p[i])
2487 gst_video_chroma_resample_free (convert->upsample_p[i]);
2488 if (convert->upsample_i && convert->upsample_i[i])
2489 gst_video_chroma_resample_free (convert->upsample_i[i]);
2490 if (convert->downsample_p && convert->downsample_p[i])
2491 gst_video_chroma_resample_free (convert->downsample_p[i]);
2492 if (convert->downsample_i && convert->downsample_i[i])
2493 gst_video_chroma_resample_free (convert->downsample_i[i]);
2494 if (convert->v_scaler_p && convert->v_scaler_p[i])
2495 gst_video_scaler_free (convert->v_scaler_p[i]);
2496 if (convert->v_scaler_i && convert->v_scaler_i[i])
2497 gst_video_scaler_free (convert->v_scaler_i[i]);
2498 if (convert->h_scaler && convert->h_scaler[i])
2499 gst_video_scaler_free (convert->h_scaler[i]);
2500 if (convert->unpack_lines && convert->unpack_lines[i])
2501 gst_line_cache_free (convert->unpack_lines[i]);
2502 if (convert->upsample_lines && convert->upsample_lines[i])
2503 gst_line_cache_free (convert->upsample_lines[i]);
2504 if (convert->to_RGB_lines && convert->to_RGB_lines[i])
2505 gst_line_cache_free (convert->to_RGB_lines[i]);
2506 if (convert->hscale_lines && convert->hscale_lines[i])
2507 gst_line_cache_free (convert->hscale_lines[i]);
2508 if (convert->vscale_lines && convert->vscale_lines[i])
2509 gst_line_cache_free (convert->vscale_lines[i]);
2510 if (convert->convert_lines && convert->convert_lines[i])
2511 gst_line_cache_free (convert->convert_lines[i]);
2512 if (convert->alpha_lines && convert->alpha_lines[i])
2513 gst_line_cache_free (convert->alpha_lines[i]);
2514 if (convert->to_YUV_lines && convert->to_YUV_lines[i])
2515 gst_line_cache_free (convert->to_YUV_lines[i]);
2516 if (convert->downsample_lines && convert->downsample_lines[i])
2517 gst_line_cache_free (convert->downsample_lines[i]);
2518 if (convert->dither_lines && convert->dither_lines[i])
2519 gst_line_cache_free (convert->dither_lines[i]);
2520 if (convert->dither && convert->dither[i])
2521 gst_video_dither_free (convert->dither[i]);
2523 g_free (convert->upsample_p);
2524 g_free (convert->upsample_i);
2525 g_free (convert->downsample_p);
2526 g_free (convert->downsample_i);
2527 g_free (convert->v_scaler_p);
2528 g_free (convert->v_scaler_i);
2529 g_free (convert->h_scaler);
2530 g_free (convert->unpack_lines);
2531 g_free (convert->pack_lines);
2532 g_free (convert->upsample_lines);
2533 g_free (convert->to_RGB_lines);
2534 g_free (convert->hscale_lines);
2535 g_free (convert->vscale_lines);
2536 g_free (convert->convert_lines);
2537 g_free (convert->alpha_lines);
2538 g_free (convert->to_YUV_lines);
2539 g_free (convert->downsample_lines);
2540 g_free (convert->dither_lines);
2541 g_free (convert->dither);
2543 g_free (convert->gamma_dec.gamma_table);
2544 g_free (convert->gamma_enc.gamma_table);
2546 if (convert->tmpline) {
2547 for (i = 0; i < convert->conversion_runner->n_threads; i++)
2548 g_free (convert->tmpline[i]);
2549 g_free (convert->tmpline);
2552 g_free (convert->borderline);
2554 if (convert->config)
2555 gst_structure_free (convert->config);
2557 for (i = 0; i < 4; i++) {
2558 for (j = 0; j < convert->conversion_runner->n_threads; j++) {
2559 if (convert->fv_scaler[i].scaler)
2560 gst_video_scaler_free (convert->fv_scaler[i].scaler[j]);
2561 if (convert->fh_scaler[i].scaler)
2562 gst_video_scaler_free (convert->fh_scaler[i].scaler[j]);
2564 g_free (convert->fv_scaler[i].scaler);
2565 g_free (convert->fh_scaler[i].scaler);
2568 if (convert->conversion_runner)
2569 gst_parallelized_task_runner_free (convert->conversion_runner);
2571 clear_matrix_data (&convert->to_RGB_matrix);
2572 clear_matrix_data (&convert->convert_matrix);
2573 clear_matrix_data (&convert->to_YUV_matrix);
2575 g_slice_free (GstVideoConverter, convert);
2579 copy_config (GQuark field_id, const GValue * value, gpointer user_data)
2581 GstVideoConverter *convert = user_data;
2583 gst_structure_id_set_value (convert->config, field_id, value);
2589 * gst_video_converter_set_config:
2590 * @convert: a #GstVideoConverter
2591 * @config: (transfer full): a #GstStructure
2593 * Set @config as extra configuraion for @convert.
2595 * If the parameters in @config can not be set exactly, this function returns
2596 * %FALSE and will try to update as much state as possible. The new state can
2597 * then be retrieved and refined with gst_video_converter_get_config().
2599 * Look at the `GST_VIDEO_CONVERTER_OPT_*` fields to check valid configuration
2600 * option and values.
2602 * Returns: %TRUE when @config could be set.
2607 gst_video_converter_set_config (GstVideoConverter * convert,
2608 GstStructure * config)
2610 g_return_val_if_fail (convert != NULL, FALSE);
2611 g_return_val_if_fail (config != NULL, FALSE);
2613 gst_structure_foreach (config, copy_config, convert);
2614 gst_structure_free (config);
2620 * gst_video_converter_get_config:
2621 * @convert: a #GstVideoConverter
2623 * Get the current configuration of @convert.
2625 * Returns: a #GstStructure that remains valid for as long as @convert is valid
2626 * or until gst_video_converter_set_config() is called.
2628 const GstStructure *
2629 gst_video_converter_get_config (GstVideoConverter * convert)
2631 g_return_val_if_fail (convert != NULL, NULL);
2633 return convert->config;
2637 * gst_video_converter_frame:
2638 * @convert: a #GstVideoConverter
2639 * @dest: a #GstVideoFrame
2640 * @src: a #GstVideoFrame
2642 * Convert the pixels of @src into @dest using @convert.
2647 gst_video_converter_frame (GstVideoConverter * convert,
2648 const GstVideoFrame * src, GstVideoFrame * dest)
2650 g_return_if_fail (convert != NULL);
2651 g_return_if_fail (src != NULL);
2652 g_return_if_fail (dest != NULL);
2654 convert->convert (convert, src, dest);
2658 video_converter_compute_matrix (GstVideoConverter * convert)
2660 MatrixData *dst = &convert->convert_matrix;
2662 color_matrix_set_identity (dst);
2663 compute_matrix_to_RGB (convert, dst);
2664 compute_matrix_to_YUV (convert, dst, FALSE);
2666 convert->current_bits = 8;
2667 prepare_matrix (convert, dst);
2671 video_converter_compute_resample (GstVideoConverter * convert, gint idx)
2673 GstVideoInfo *in_info, *out_info;
2674 const GstVideoFormatInfo *sfinfo, *dfinfo;
2676 if (CHECK_CHROMA_NONE (convert))
2679 in_info = &convert->in_info;
2680 out_info = &convert->out_info;
2682 sfinfo = in_info->finfo;
2683 dfinfo = out_info->finfo;
2685 GST_DEBUG ("site: %d->%d, w_sub: %d->%d, h_sub: %d->%d", in_info->chroma_site,
2686 out_info->chroma_site, sfinfo->w_sub[2], dfinfo->w_sub[2],
2687 sfinfo->h_sub[2], dfinfo->h_sub[2]);
2689 if (sfinfo->w_sub[2] != dfinfo->w_sub[2] ||
2690 sfinfo->h_sub[2] != dfinfo->h_sub[2] ||
2691 in_info->chroma_site != out_info->chroma_site ||
2692 in_info->width != out_info->width ||
2693 in_info->height != out_info->height) {
2694 if (GST_VIDEO_INFO_IS_INTERLACED (in_info)) {
2695 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2696 convert->upsample_i[idx] = gst_video_chroma_resample_new (0,
2697 in_info->chroma_site, GST_VIDEO_CHROMA_FLAG_INTERLACED,
2698 sfinfo->unpack_format, sfinfo->w_sub[2], sfinfo->h_sub[2]);
2699 if (!CHECK_CHROMA_UPSAMPLE (convert))
2700 convert->downsample_i[idx] =
2701 gst_video_chroma_resample_new (0, out_info->chroma_site,
2702 GST_VIDEO_CHROMA_FLAG_INTERLACED, dfinfo->unpack_format,
2703 -dfinfo->w_sub[2], -dfinfo->h_sub[2]);
2705 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2706 convert->upsample_p[idx] = gst_video_chroma_resample_new (0,
2707 in_info->chroma_site, 0, sfinfo->unpack_format, sfinfo->w_sub[2],
2709 if (!CHECK_CHROMA_UPSAMPLE (convert))
2710 convert->downsample_p[idx] = gst_video_chroma_resample_new (0,
2711 out_info->chroma_site, 0, dfinfo->unpack_format, -dfinfo->w_sub[2],
2716 #define FRAME_GET_PLANE_STRIDE(frame, plane) \
2717 GST_VIDEO_FRAME_PLANE_STRIDE (frame, plane)
2718 #define FRAME_GET_PLANE_LINE(frame, plane, line) \
2719 (gpointer)(((guint8*)(GST_VIDEO_FRAME_PLANE_DATA (frame, plane))) + \
2720 FRAME_GET_PLANE_STRIDE (frame, plane) * (line))
2722 #define FRAME_GET_COMP_STRIDE(frame, comp) \
2723 GST_VIDEO_FRAME_COMP_STRIDE (frame, comp)
2724 #define FRAME_GET_COMP_LINE(frame, comp, line) \
2725 (gpointer)(((guint8*)(GST_VIDEO_FRAME_COMP_DATA (frame, comp))) + \
2726 FRAME_GET_COMP_STRIDE (frame, comp) * (line))
2728 #define FRAME_GET_STRIDE(frame) FRAME_GET_PLANE_STRIDE (frame, 0)
2729 #define FRAME_GET_LINE(frame,line) FRAME_GET_PLANE_LINE (frame, 0, line)
2731 #define FRAME_GET_Y_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_Y, line)
2732 #define FRAME_GET_U_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_U, line)
2733 #define FRAME_GET_V_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_V, line)
2734 #define FRAME_GET_A_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_A, line)
2736 #define FRAME_GET_Y_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_Y)
2737 #define FRAME_GET_U_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_U)
2738 #define FRAME_GET_V_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_V)
2739 #define FRAME_GET_A_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_A)
2742 #define UNPACK_FRAME(frame,dest,line,x,width) \
2743 frame->info.finfo->unpack_func (frame->info.finfo, \
2744 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2745 GST_VIDEO_PACK_FLAG_INTERLACED : \
2746 GST_VIDEO_PACK_FLAG_NONE), \
2747 dest, frame->data, frame->info.stride, x, \
2749 #define PACK_FRAME(frame,src,line,width) \
2750 frame->info.finfo->pack_func (frame->info.finfo, \
2751 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2752 GST_VIDEO_PACK_FLAG_INTERLACED : \
2753 GST_VIDEO_PACK_FLAG_NONE), \
2754 src, 0, frame->data, frame->info.stride, \
2755 frame->info.chroma_site, line, width);
2758 get_dest_line (GstLineCache * cache, gint idx, gpointer user_data)
2760 GstVideoConverter *convert = user_data;
2762 gint pstride = convert->pack_pstride;
2763 gint out_x = convert->out_x;
2766 cline = CLAMP (idx, 0, convert->out_maxheight - 1);
2768 line = FRAME_GET_LINE (convert->dest, cline);
2769 GST_DEBUG ("get dest line %d %p", cline, line);
2771 if (convert->borderline) {
2772 gint r_border = (out_x + convert->out_width) * pstride;
2773 gint rb_width = convert->out_maxwidth * pstride - r_border;
2774 gint lb_width = out_x * pstride;
2776 memcpy (line, convert->borderline, lb_width);
2777 memcpy (line + r_border, convert->borderline, rb_width);
2779 line += out_x * pstride;
2785 do_unpack_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2788 GstVideoConverter *convert = user_data;
2792 cline = CLAMP (in_line + convert->in_y, 0, convert->in_maxheight - 1);
2794 if (cache->alloc_writable || !convert->identity_unpack) {
2795 tmpline = gst_line_cache_alloc_line (cache, out_line);
2796 GST_DEBUG ("unpack line %d (%u) %p", in_line, cline, tmpline);
2797 UNPACK_FRAME (convert->src, tmpline, cline, convert->in_x,
2800 tmpline = ((guint8 *) FRAME_GET_LINE (convert->src, cline)) +
2801 convert->in_x * convert->unpack_pstride;
2802 GST_DEBUG ("get src line %d (%u) %p", in_line, cline, tmpline);
2804 gst_line_cache_add_line (cache, in_line, tmpline);
2810 do_upsample_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2813 GstVideoConverter *convert = user_data;
2815 gint i, start_line, n_lines;
2817 n_lines = convert->up_n_lines;
2818 start_line = in_line;
2819 if (start_line < n_lines + convert->up_offset) {
2820 start_line += convert->up_offset;
2821 out_line += convert->up_offset;
2824 /* get the lines needed for chroma upsample */
2826 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
2829 if (convert->upsample) {
2830 GST_DEBUG ("doing upsample %d-%d %p", start_line, start_line + n_lines - 1,
2832 gst_video_chroma_resample (convert->upsample[idx], lines,
2836 for (i = 0; i < n_lines; i++)
2837 gst_line_cache_add_line (cache, start_line + i, lines[i]);
2843 do_convert_to_RGB_lines (GstLineCache * cache, gint idx, gint out_line,
2844 gint in_line, gpointer user_data)
2846 GstVideoConverter *convert = user_data;
2847 MatrixData *data = &convert->to_RGB_matrix;
2848 gpointer *lines, destline;
2850 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2851 destline = lines[0];
2853 if (data->matrix_func) {
2854 GST_DEBUG ("to RGB line %d %p", in_line, destline);
2855 data->matrix_func (data, destline);
2857 if (convert->gamma_dec.gamma_func) {
2858 destline = gst_line_cache_alloc_line (cache, out_line);
2860 GST_DEBUG ("gamma decode line %d %p->%p", in_line, lines[0], destline);
2861 convert->gamma_dec.gamma_func (&convert->gamma_dec, destline, lines[0]);
2863 gst_line_cache_add_line (cache, in_line, destline);
2869 do_hscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2872 GstVideoConverter *convert = user_data;
2873 gpointer *lines, destline;
2875 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2877 destline = gst_line_cache_alloc_line (cache, out_line);
2879 GST_DEBUG ("hresample line %d %p->%p", in_line, lines[0], destline);
2880 gst_video_scaler_horizontal (convert->h_scaler[idx], convert->h_scale_format,
2881 lines[0], destline, 0, convert->out_width);
2883 gst_line_cache_add_line (cache, in_line, destline);
2889 do_vscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2892 GstVideoConverter *convert = user_data;
2893 gpointer *lines, destline;
2894 guint sline, n_lines;
2897 cline = CLAMP (in_line, 0, convert->out_height - 1);
2899 gst_video_scaler_get_coeff (convert->v_scaler[idx], cline, &sline, &n_lines);
2900 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, sline, n_lines);
2902 destline = gst_line_cache_alloc_line (cache, out_line);
2904 GST_DEBUG ("vresample line %d %d-%d %p->%p", in_line, sline,
2905 sline + n_lines - 1, lines[0], destline);
2906 gst_video_scaler_vertical (convert->v_scaler[idx], convert->v_scale_format,
2907 lines, destline, cline, convert->v_scale_width);
2909 gst_line_cache_add_line (cache, in_line, destline);
2915 do_convert_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2918 GstVideoConverter *convert = user_data;
2919 MatrixData *data = &convert->convert_matrix;
2920 gpointer *lines, destline;
2921 guint in_bits, out_bits;
2924 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2926 destline = lines[0];
2928 in_bits = convert->in_bits;
2929 out_bits = convert->out_bits;
2931 width = MIN (convert->in_width, convert->out_width);
2933 if (out_bits == 16 || in_bits == 16) {
2934 gpointer srcline = lines[0];
2936 if (out_bits != in_bits)
2937 destline = gst_line_cache_alloc_line (cache, out_line);
2939 /* FIXME, we can scale in the conversion matrix */
2941 GST_DEBUG ("8->16 line %d %p->%p", in_line, srcline, destline);
2942 video_orc_convert_u8_to_u16 (destline, srcline, width * 4);
2946 if (data->matrix_func) {
2947 GST_DEBUG ("matrix line %d %p", in_line, srcline);
2948 data->matrix_func (data, srcline);
2951 /* FIXME, dither here */
2952 if (out_bits == 8) {
2953 GST_DEBUG ("16->8 line %d %p->%p", in_line, srcline, destline);
2954 video_orc_convert_u16_to_u8 (destline, srcline, width * 4);
2957 if (data->matrix_func) {
2958 GST_DEBUG ("matrix line %d %p", in_line, destline);
2959 data->matrix_func (data, destline);
2962 gst_line_cache_add_line (cache, in_line, destline);
2968 do_alpha_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2971 gpointer *lines, destline;
2972 GstVideoConverter *convert = user_data;
2973 gint width = MIN (convert->in_width, convert->out_width);
2975 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2976 destline = lines[0];
2978 GST_DEBUG ("alpha line %d %p", in_line, destline);
2979 convert->alpha_func (convert, destline, width);
2981 gst_line_cache_add_line (cache, in_line, destline);
2987 do_convert_to_YUV_lines (GstLineCache * cache, gint idx, gint out_line,
2988 gint in_line, gpointer user_data)
2990 GstVideoConverter *convert = user_data;
2991 MatrixData *data = &convert->to_YUV_matrix;
2992 gpointer *lines, destline;
2994 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2995 destline = lines[0];
2997 if (convert->gamma_enc.gamma_func) {
2998 destline = gst_line_cache_alloc_line (cache, out_line);
3000 GST_DEBUG ("gamma encode line %d %p->%p", in_line, lines[0], destline);
3001 convert->gamma_enc.gamma_func (&convert->gamma_enc, destline, lines[0]);
3003 if (data->matrix_func) {
3004 GST_DEBUG ("to YUV line %d %p", in_line, destline);
3005 data->matrix_func (data, destline);
3007 gst_line_cache_add_line (cache, in_line, destline);
3013 do_downsample_lines (GstLineCache * cache, gint idx, gint out_line,
3014 gint in_line, gpointer user_data)
3016 GstVideoConverter *convert = user_data;
3018 gint i, start_line, n_lines;
3020 n_lines = convert->down_n_lines;
3021 start_line = in_line;
3022 if (start_line < n_lines + convert->down_offset)
3023 start_line += convert->down_offset;
3025 /* get the lines needed for chroma downsample */
3027 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
3030 if (convert->downsample) {
3031 GST_DEBUG ("downsample line %d %d-%d %p", in_line, start_line,
3032 start_line + n_lines - 1, lines[0]);
3033 gst_video_chroma_resample (convert->downsample[idx], lines,
3034 convert->out_width);
3037 for (i = 0; i < n_lines; i++)
3038 gst_line_cache_add_line (cache, start_line + i, lines[i]);
3044 do_dither_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3047 GstVideoConverter *convert = user_data;
3048 gpointer *lines, destline;
3050 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3051 destline = lines[0];
3053 if (convert->dither) {
3054 GST_DEBUG ("Dither line %d %p", in_line, destline);
3055 gst_video_dither_line (convert->dither[idx], destline, 0, out_line,
3056 convert->out_width);
3058 gst_line_cache_add_line (cache, in_line, destline);
3065 GstLineCache *pack_lines;
3068 gint pack_lines_count;
3070 gboolean identity_pack;
3071 gint lb_width, out_maxwidth;
3072 GstVideoFrame *dest;
3076 convert_generic_task (ConvertTask * task)
3080 for (i = task->h_0; i < task->h_1; i += task->pack_lines_count) {
3083 /* load the lines needed to pack */
3085 gst_line_cache_get_lines (task->pack_lines, task->idx, i + task->out_y,
3086 i, task->pack_lines_count);
3088 if (!task->identity_pack) {
3089 /* take away the border */
3090 guint8 *l = ((guint8 *) lines[0]) - task->lb_width;
3091 /* and pack into destination */
3092 GST_DEBUG ("pack line %d %p (%p)", i + task->out_y, lines[0], l);
3093 PACK_FRAME (task->dest, l, i + task->out_y, task->out_maxwidth);
3099 video_converter_generic (GstVideoConverter * convert, const GstVideoFrame * src,
3100 GstVideoFrame * dest)
3103 gint out_maxwidth, out_maxheight;
3104 gint out_x, out_y, out_height;
3105 gint pack_lines, pstride;
3108 ConvertTask **tasks_p;
3110 gint lines_per_thread;
3112 out_height = convert->out_height;
3113 out_maxwidth = convert->out_maxwidth;
3114 out_maxheight = convert->out_maxheight;
3116 out_x = convert->out_x;
3117 out_y = convert->out_y;
3120 convert->dest = dest;
3122 if (GST_VIDEO_FRAME_IS_INTERLACED (src)) {
3123 GST_DEBUG ("setup interlaced frame");
3124 convert->upsample = convert->upsample_i;
3125 convert->downsample = convert->downsample_i;
3126 convert->v_scaler = convert->v_scaler_i;
3128 GST_DEBUG ("setup progressive frame");
3129 convert->upsample = convert->upsample_p;
3130 convert->downsample = convert->downsample_p;
3131 convert->v_scaler = convert->v_scaler_p;
3133 if (convert->upsample[0]) {
3134 gst_video_chroma_resample_get_info (convert->upsample[0],
3135 &convert->up_n_lines, &convert->up_offset);
3137 convert->up_n_lines = 1;
3138 convert->up_offset = 0;
3140 if (convert->downsample[0]) {
3141 gst_video_chroma_resample_get_info (convert->downsample[0],
3142 &convert->down_n_lines, &convert->down_offset);
3144 convert->down_n_lines = 1;
3145 convert->down_offset = 0;
3148 pack_lines = convert->pack_nlines; /* only 1 for now */
3149 pstride = convert->pack_pstride;
3151 lb_width = out_x * pstride;
3153 if (convert->borderline) {
3154 /* FIXME we should try to avoid PACK_FRAME */
3155 for (i = 0; i < out_y; i++)
3156 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3159 n_threads = convert->conversion_runner->n_threads;
3160 tasks = g_newa (ConvertTask, n_threads);
3161 tasks_p = g_newa (ConvertTask *, n_threads);
3164 GST_ROUND_UP_N ((out_height + n_threads - 1) / n_threads, pack_lines);
3166 for (i = 0; i < n_threads; i++) {
3167 tasks[i].dest = dest;
3168 tasks[i].pack_lines = convert->pack_lines[i];
3170 tasks[i].pack_lines_count = pack_lines;
3171 tasks[i].out_y = out_y;
3172 tasks[i].identity_pack = convert->identity_pack;
3173 tasks[i].lb_width = lb_width;
3174 tasks[i].out_maxwidth = out_maxwidth;
3176 tasks[i].h_0 = i * lines_per_thread;
3177 tasks[i].h_1 = MIN ((i + 1) * lines_per_thread, out_height);
3179 tasks_p[i] = &tasks[i];
3182 gst_parallelized_task_runner_run (convert->conversion_runner,
3183 (GstParallelizedTaskFunc) convert_generic_task, (gpointer) tasks_p);
3185 if (convert->borderline) {
3186 for (i = out_y + out_height; i < out_maxheight; i++)
3187 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3189 if (convert->pack_pal) {
3190 memcpy (GST_VIDEO_FRAME_PLANE_DATA (dest, 1), convert->pack_pal,
3191 convert->pack_palsize);
3195 static void convert_fill_border (GstVideoConverter * convert,
3196 GstVideoFrame * dest);
3200 #define GET_LINE_OFFSETS(interlaced,line,l1,l2) \
3202 l1 = (line & 2 ? line - 1 : line); \
3211 const GstVideoFrame *src;
3212 GstVideoFrame *dest;
3213 gint height_0, height_1;
3216 gboolean interlaced;
3226 convert_I420_YUY2_task (FConvertTask * task)
3231 for (i = task->height_0; i < task->height_1; i += 2) {
3232 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3234 video_orc_convert_I420_YUY2 (FRAME_GET_LINE (task->dest, l1),
3235 FRAME_GET_LINE (task->dest, l2),
3236 FRAME_GET_Y_LINE (task->src, l1),
3237 FRAME_GET_Y_LINE (task->src, l2),
3238 FRAME_GET_U_LINE (task->src, i >> 1),
3239 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3244 convert_I420_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
3245 GstVideoFrame * dest)
3248 gint width = convert->in_width;
3249 gint height = convert->in_height;
3250 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3252 FConvertTask *tasks;
3253 FConvertTask **tasks_p;
3255 gint lines_per_thread;
3257 /* I420 has half as many chroma lines, as such we have to
3258 * always merge two into one. For non-interlaced these are
3259 * the two next to each other, for interlaced one is skipped
3262 h2 = GST_ROUND_DOWN_4 (height);
3264 h2 = GST_ROUND_DOWN_2 (height);
3266 n_threads = convert->conversion_runner->n_threads;
3267 tasks = g_newa (FConvertTask, n_threads);
3268 tasks_p = g_newa (FConvertTask *, n_threads);
3270 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3272 for (i = 0; i < n_threads; i++) {
3274 tasks[i].dest = dest;
3276 tasks[i].interlaced = interlaced;
3277 tasks[i].width = width;
3279 tasks[i].height_0 = i * lines_per_thread;
3280 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3281 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3283 tasks_p[i] = &tasks[i];
3286 gst_parallelized_task_runner_run (convert->conversion_runner,
3287 (GstParallelizedTaskFunc) convert_I420_YUY2_task, (gpointer) tasks_p);
3289 /* now handle last lines. For interlaced these are up to 3 */
3291 for (i = h2; i < height; i++) {
3292 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3293 PACK_FRAME (dest, convert->tmpline[0], i, width);
3299 convert_I420_UYVY_task (FConvertTask * task)
3304 for (i = task->height_0; i < task->height_1; i += 2) {
3305 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3307 video_orc_convert_I420_UYVY (FRAME_GET_LINE (task->dest, l1),
3308 FRAME_GET_LINE (task->dest, l2),
3309 FRAME_GET_Y_LINE (task->src, l1),
3310 FRAME_GET_Y_LINE (task->src, l2),
3311 FRAME_GET_U_LINE (task->src, i >> 1),
3312 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3317 convert_I420_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
3318 GstVideoFrame * dest)
3321 gint width = convert->in_width;
3322 gint height = convert->in_height;
3323 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3325 FConvertTask *tasks;
3326 FConvertTask **tasks_p;
3328 gint lines_per_thread;
3330 /* I420 has half as many chroma lines, as such we have to
3331 * always merge two into one. For non-interlaced these are
3332 * the two next to each other, for interlaced one is skipped
3335 h2 = GST_ROUND_DOWN_4 (height);
3337 h2 = GST_ROUND_DOWN_2 (height);
3339 n_threads = convert->conversion_runner->n_threads;
3340 tasks = g_newa (FConvertTask, n_threads);
3341 tasks_p = g_newa (FConvertTask *, n_threads);
3343 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3345 for (i = 0; i < n_threads; i++) {
3347 tasks[i].dest = dest;
3349 tasks[i].interlaced = interlaced;
3350 tasks[i].width = width;
3352 tasks[i].height_0 = i * lines_per_thread;
3353 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3354 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3356 tasks_p[i] = &tasks[i];
3359 gst_parallelized_task_runner_run (convert->conversion_runner,
3360 (GstParallelizedTaskFunc) convert_I420_UYVY_task, (gpointer) tasks_p);
3362 /* now handle last lines. For interlaced these are up to 3 */
3364 for (i = h2; i < height; i++) {
3365 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3366 PACK_FRAME (dest, convert->tmpline[0], i, width);
3372 convert_I420_AYUV_task (FConvertTask * task)
3377 for (i = task->height_0; i < task->height_1; i += 2) {
3378 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3380 video_orc_convert_I420_AYUV (FRAME_GET_LINE (task->dest, l1),
3381 FRAME_GET_LINE (task->dest, l2),
3382 FRAME_GET_Y_LINE (task->src, l1),
3383 FRAME_GET_Y_LINE (task->src, l2),
3384 FRAME_GET_U_LINE (task->src, i >> 1), FRAME_GET_V_LINE (task->src,
3385 i >> 1), task->alpha, task->width);
3390 convert_I420_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3391 GstVideoFrame * dest)
3394 gint width = convert->in_width;
3395 gint height = convert->in_height;
3396 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3397 guint8 alpha = MIN (convert->alpha_value, 255);
3399 FConvertTask *tasks;
3400 FConvertTask **tasks_p;
3402 gint lines_per_thread;
3404 /* I420 has half as many chroma lines, as such we have to
3405 * always merge two into one. For non-interlaced these are
3406 * the two next to each other, for interlaced one is skipped
3409 h2 = GST_ROUND_DOWN_4 (height);
3411 h2 = GST_ROUND_DOWN_2 (height);
3414 n_threads = convert->conversion_runner->n_threads;
3415 tasks = g_newa (FConvertTask, n_threads);
3416 tasks_p = g_newa (FConvertTask *, n_threads);
3418 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3420 for (i = 0; i < n_threads; i++) {
3422 tasks[i].dest = dest;
3424 tasks[i].interlaced = interlaced;
3425 tasks[i].width = width;
3426 tasks[i].alpha = alpha;
3428 tasks[i].height_0 = i * lines_per_thread;
3429 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3430 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3432 tasks_p[i] = &tasks[i];
3435 gst_parallelized_task_runner_run (convert->conversion_runner,
3436 (GstParallelizedTaskFunc) convert_I420_AYUV_task, (gpointer) tasks_p);
3438 /* now handle last lines. For interlaced these are up to 3 */
3440 for (i = h2; i < height; i++) {
3441 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3443 convert_set_alpha_u8 (convert, convert->tmpline[0], width);
3444 PACK_FRAME (dest, convert->tmpline[0], i, width);
3450 convert_YUY2_I420_task (FConvertTask * task)
3455 for (i = task->height_0; i < task->height_1; i += 2) {
3456 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3458 video_orc_convert_YUY2_I420 (FRAME_GET_Y_LINE (task->dest, l1),
3459 FRAME_GET_Y_LINE (task->dest, l2),
3460 FRAME_GET_U_LINE (task->dest, i >> 1),
3461 FRAME_GET_V_LINE (task->dest, i >> 1),
3462 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
3463 (task->width + 1) / 2);
3468 convert_YUY2_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3469 GstVideoFrame * dest)
3472 gint width = convert->in_width;
3473 gint height = convert->in_height;
3474 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3476 FConvertTask *tasks;
3477 FConvertTask **tasks_p;
3479 gint lines_per_thread;
3481 /* I420 has half as many chroma lines, as such we have to
3482 * always merge two into one. For non-interlaced these are
3483 * the two next to each other, for interlaced one is skipped
3486 h2 = GST_ROUND_DOWN_4 (height);
3488 h2 = GST_ROUND_DOWN_2 (height);
3490 n_threads = convert->conversion_runner->n_threads;
3491 tasks = g_newa (FConvertTask, n_threads);
3492 tasks_p = g_newa (FConvertTask *, n_threads);
3494 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3496 for (i = 0; i < n_threads; i++) {
3498 tasks[i].dest = dest;
3500 tasks[i].interlaced = interlaced;
3501 tasks[i].width = width;
3503 tasks[i].height_0 = i * lines_per_thread;
3504 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3505 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3507 tasks_p[i] = &tasks[i];
3510 gst_parallelized_task_runner_run (convert->conversion_runner,
3511 (GstParallelizedTaskFunc) convert_YUY2_I420_task, (gpointer) tasks_p);
3513 /* now handle last lines. For interlaced these are up to 3 */
3515 for (i = h2; i < height; i++) {
3516 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3517 PACK_FRAME (dest, convert->tmpline[0], i, width);
3524 const guint8 *s, *s2, *su, *sv;
3525 guint8 *d, *d2, *du, *dv;
3526 gint sstride, sustride, svstride;
3527 gint dstride, dustride, dvstride;
3531 } FConvertPlaneTask;
3534 convert_YUY2_AYUV_task (FConvertPlaneTask * task)
3536 video_orc_convert_YUY2_AYUV (task->d, task->dstride, task->s,
3537 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
3541 convert_YUY2_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3542 GstVideoFrame * dest)
3544 gint width = convert->in_width;
3545 gint height = convert->in_height;
3547 guint8 alpha = MIN (convert->alpha_value, 255);
3548 FConvertPlaneTask *tasks;
3549 FConvertPlaneTask **tasks_p;
3551 gint lines_per_thread;
3554 s = FRAME_GET_LINE (src, convert->in_y);
3555 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3556 d = FRAME_GET_LINE (dest, convert->out_y);
3557 d += (convert->out_x * 4);
3559 n_threads = convert->conversion_runner->n_threads;
3560 tasks = g_newa (FConvertPlaneTask, n_threads);
3561 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3563 lines_per_thread = (height + n_threads - 1) / n_threads;
3565 for (i = 0; i < n_threads; i++) {
3566 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3567 tasks[i].sstride = FRAME_GET_STRIDE (src);
3568 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3569 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3571 tasks[i].width = width;
3572 tasks[i].height = (i + 1) * lines_per_thread;
3573 tasks[i].height = MIN (tasks[i].height, height);
3574 tasks[i].height -= i * lines_per_thread;
3575 tasks[i].alpha = alpha;
3577 tasks_p[i] = &tasks[i];
3580 gst_parallelized_task_runner_run (convert->conversion_runner,
3581 (GstParallelizedTaskFunc) convert_YUY2_AYUV_task, (gpointer) tasks_p);
3583 convert_fill_border (convert, dest);
3587 convert_YUY2_Y42B_task (FConvertPlaneTask * task)
3589 video_orc_convert_YUY2_Y42B (task->d, task->dstride, task->du,
3590 task->dustride, task->dv, task->dvstride,
3591 task->s, task->sstride, (task->width + 1) / 2, task->height);
3595 convert_YUY2_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
3596 GstVideoFrame * dest)
3598 gint width = convert->in_width;
3599 gint height = convert->in_height;
3600 guint8 *s, *dy, *du, *dv;
3601 FConvertPlaneTask *tasks;
3602 FConvertPlaneTask **tasks_p;
3604 gint lines_per_thread;
3607 s = FRAME_GET_LINE (src, convert->in_y);
3608 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3610 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3611 dy += convert->out_x;
3612 du = FRAME_GET_U_LINE (dest, convert->out_y);
3613 du += convert->out_x >> 1;
3614 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3615 dv += convert->out_x >> 1;
3617 n_threads = convert->conversion_runner->n_threads;
3618 tasks = g_newa (FConvertPlaneTask, n_threads);
3619 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3621 lines_per_thread = (height + n_threads - 1) / n_threads;
3623 for (i = 0; i < n_threads; i++) {
3624 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3625 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3626 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3627 tasks[i].sstride = FRAME_GET_STRIDE (src);
3628 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3629 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3630 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3631 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3633 tasks[i].width = width;
3634 tasks[i].height = (i + 1) * lines_per_thread;
3635 tasks[i].height = MIN (tasks[i].height, height);
3636 tasks[i].height -= i * lines_per_thread;
3638 tasks_p[i] = &tasks[i];
3641 gst_parallelized_task_runner_run (convert->conversion_runner,
3642 (GstParallelizedTaskFunc) convert_YUY2_Y42B_task, (gpointer) tasks_p);
3644 convert_fill_border (convert, dest);
3648 convert_YUY2_Y444_task (FConvertPlaneTask * task)
3650 video_orc_convert_YUY2_Y444 (task->d,
3651 task->dstride, task->du,
3652 task->dustride, task->dv,
3653 task->dvstride, task->s,
3654 task->sstride, (task->width + 1) / 2, task->height);
3658 convert_YUY2_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
3659 GstVideoFrame * dest)
3661 gint width = convert->in_width;
3662 gint height = convert->in_height;
3663 guint8 *s, *dy, *du, *dv;
3664 FConvertPlaneTask *tasks;
3665 FConvertPlaneTask **tasks_p;
3667 gint lines_per_thread;
3670 s = FRAME_GET_LINE (src, convert->in_y);
3671 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3673 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3674 dy += convert->out_x;
3675 du = FRAME_GET_U_LINE (dest, convert->out_y);
3676 du += convert->out_x;
3677 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3678 dv += convert->out_x;
3680 n_threads = convert->conversion_runner->n_threads;
3681 tasks = g_newa (FConvertPlaneTask, n_threads);
3682 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3684 lines_per_thread = (height + n_threads - 1) / n_threads;
3686 for (i = 0; i < n_threads; i++) {
3687 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3688 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3689 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3690 tasks[i].sstride = FRAME_GET_STRIDE (src);
3691 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3692 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3693 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3694 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3696 tasks[i].width = width;
3697 tasks[i].height = (i + 1) * lines_per_thread;
3698 tasks[i].height = MIN (tasks[i].height, height);
3699 tasks[i].height -= i * lines_per_thread;
3701 tasks_p[i] = &tasks[i];
3704 gst_parallelized_task_runner_run (convert->conversion_runner,
3705 (GstParallelizedTaskFunc) convert_YUY2_Y444_task, (gpointer) tasks_p);
3707 convert_fill_border (convert, dest);
3711 convert_UYVY_I420_task (FConvertTask * task)
3716 for (i = task->height_0; i < task->height_1; i += 2) {
3717 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3719 video_orc_convert_UYVY_I420 (FRAME_GET_COMP_LINE (task->dest, 0, l1),
3720 FRAME_GET_COMP_LINE (task->dest, 0, l2),
3721 FRAME_GET_COMP_LINE (task->dest, 1, i >> 1),
3722 FRAME_GET_COMP_LINE (task->dest, 2, i >> 1),
3723 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
3724 (task->width + 1) / 2);
3729 convert_UYVY_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3730 GstVideoFrame * dest)
3733 gint width = convert->in_width;
3734 gint height = convert->in_height;
3735 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3737 FConvertTask *tasks;
3738 FConvertTask **tasks_p;
3740 gint lines_per_thread;
3742 /* I420 has half as many chroma lines, as such we have to
3743 * always merge two into one. For non-interlaced these are
3744 * the two next to each other, for interlaced one is skipped
3747 h2 = GST_ROUND_DOWN_4 (height);
3749 h2 = GST_ROUND_DOWN_2 (height);
3751 n_threads = convert->conversion_runner->n_threads;
3752 tasks = g_newa (FConvertTask, n_threads);
3753 tasks_p = g_newa (FConvertTask *, n_threads);
3755 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3757 for (i = 0; i < n_threads; i++) {
3759 tasks[i].dest = dest;
3761 tasks[i].interlaced = interlaced;
3762 tasks[i].width = width;
3764 tasks[i].height_0 = i * lines_per_thread;
3765 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3766 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3768 tasks_p[i] = &tasks[i];
3771 gst_parallelized_task_runner_run (convert->conversion_runner,
3772 (GstParallelizedTaskFunc) convert_UYVY_I420_task, (gpointer) tasks_p);
3774 /* now handle last lines. For interlaced these are up to 3 */
3776 for (i = h2; i < height; i++) {
3777 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3778 PACK_FRAME (dest, convert->tmpline[0], i, width);
3784 convert_UYVY_AYUV_task (FConvertPlaneTask * task)
3786 video_orc_convert_UYVY_AYUV (task->d, task->dstride, task->s,
3787 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
3791 convert_UYVY_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3792 GstVideoFrame * dest)
3794 gint width = convert->in_width;
3795 gint height = convert->in_height;
3797 guint8 alpha = MIN (convert->alpha_value, 255);
3798 FConvertPlaneTask *tasks;
3799 FConvertPlaneTask **tasks_p;
3801 gint lines_per_thread;
3804 s = FRAME_GET_LINE (src, convert->in_y);
3805 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3806 d = FRAME_GET_LINE (dest, convert->out_y);
3807 d += (convert->out_x * 4);
3809 n_threads = convert->conversion_runner->n_threads;
3810 tasks = g_newa (FConvertPlaneTask, n_threads);
3811 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3813 lines_per_thread = (height + n_threads - 1) / n_threads;
3815 for (i = 0; i < n_threads; i++) {
3816 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3817 tasks[i].sstride = FRAME_GET_STRIDE (src);
3818 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3819 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3821 tasks[i].width = width;
3822 tasks[i].height = (i + 1) * lines_per_thread;
3823 tasks[i].height = MIN (tasks[i].height, height);
3824 tasks[i].height -= i * lines_per_thread;
3825 tasks[i].alpha = alpha;
3827 tasks_p[i] = &tasks[i];
3830 gst_parallelized_task_runner_run (convert->conversion_runner,
3831 (GstParallelizedTaskFunc) convert_UYVY_AYUV_task, (gpointer) tasks_p);
3833 convert_fill_border (convert, dest);
3837 convert_UYVY_YUY2_task (FConvertPlaneTask * task)
3839 video_orc_convert_UYVY_YUY2 (task->d, task->dstride, task->s,
3840 task->sstride, (task->width + 1) / 2, task->height);
3844 convert_UYVY_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
3845 GstVideoFrame * dest)
3847 gint width = convert->in_width;
3848 gint height = convert->in_height;
3850 FConvertPlaneTask *tasks;
3851 FConvertPlaneTask **tasks_p;
3853 gint lines_per_thread;
3856 s = FRAME_GET_LINE (src, convert->in_y);
3857 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3858 d = FRAME_GET_LINE (dest, convert->out_y);
3859 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
3861 n_threads = convert->conversion_runner->n_threads;
3862 tasks = g_newa (FConvertPlaneTask, n_threads);
3863 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3865 lines_per_thread = (height + n_threads - 1) / n_threads;
3867 for (i = 0; i < n_threads; i++) {
3868 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3869 tasks[i].sstride = FRAME_GET_STRIDE (src);
3870 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3871 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3873 tasks[i].width = width;
3874 tasks[i].height = (i + 1) * lines_per_thread;
3875 tasks[i].height = MIN (tasks[i].height, height);
3876 tasks[i].height -= i * lines_per_thread;
3878 tasks_p[i] = &tasks[i];
3881 gst_parallelized_task_runner_run (convert->conversion_runner,
3882 (GstParallelizedTaskFunc) convert_UYVY_YUY2_task, (gpointer) tasks_p);
3884 convert_fill_border (convert, dest);
3888 convert_UYVY_Y42B_task (FConvertPlaneTask * task)
3890 video_orc_convert_UYVY_Y42B (task->d, task->dstride, task->du,
3891 task->dustride, task->dv, task->dvstride,
3892 task->s, task->sstride, (task->width + 1) / 2, task->height);
3896 convert_UYVY_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
3897 GstVideoFrame * dest)
3899 gint width = convert->in_width;
3900 gint height = convert->in_height;
3901 guint8 *s, *dy, *du, *dv;
3902 FConvertPlaneTask *tasks;
3903 FConvertPlaneTask **tasks_p;
3905 gint lines_per_thread;
3908 s = FRAME_GET_LINE (src, convert->in_y);
3909 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3911 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3912 dy += convert->out_x;
3913 du = FRAME_GET_U_LINE (dest, convert->out_y);
3914 du += convert->out_x >> 1;
3915 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3916 dv += convert->out_x >> 1;
3918 n_threads = convert->conversion_runner->n_threads;
3919 tasks = g_newa (FConvertPlaneTask, n_threads);
3920 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3922 lines_per_thread = (height + n_threads - 1) / n_threads;
3924 for (i = 0; i < n_threads; i++) {
3925 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3926 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3927 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3928 tasks[i].sstride = FRAME_GET_STRIDE (src);
3929 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3930 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3931 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3932 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3934 tasks[i].width = width;
3935 tasks[i].height = (i + 1) * lines_per_thread;
3936 tasks[i].height = MIN (tasks[i].height, height);
3937 tasks[i].height -= i * lines_per_thread;
3939 tasks_p[i] = &tasks[i];
3942 gst_parallelized_task_runner_run (convert->conversion_runner,
3943 (GstParallelizedTaskFunc) convert_UYVY_Y42B_task, (gpointer) tasks_p);
3945 convert_fill_border (convert, dest);
3949 convert_UYVY_Y444_task (FConvertPlaneTask * task)
3951 video_orc_convert_UYVY_Y444 (task->d,
3952 task->dstride, task->du,
3953 task->dustride, task->dv,
3954 task->dvstride, task->s,
3955 task->sstride, (task->width + 1) / 2, task->height);
3959 convert_UYVY_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
3960 GstVideoFrame * dest)
3962 gint width = convert->in_width;
3963 gint height = convert->in_height;
3964 guint8 *s, *dy, *du, *dv;
3965 FConvertPlaneTask *tasks;
3966 FConvertPlaneTask **tasks_p;
3968 gint lines_per_thread;
3971 s = FRAME_GET_LINE (src, convert->in_y);
3972 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3974 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3975 dy += convert->out_x;
3976 du = FRAME_GET_U_LINE (dest, convert->out_y);
3977 du += convert->out_x;
3978 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3979 dv += convert->out_x;
3981 n_threads = convert->conversion_runner->n_threads;
3982 tasks = g_newa (FConvertPlaneTask, n_threads);
3983 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3985 lines_per_thread = (height + n_threads - 1) / n_threads;
3987 for (i = 0; i < n_threads; i++) {
3988 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3989 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3990 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3991 tasks[i].sstride = FRAME_GET_STRIDE (src);
3992 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3993 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3994 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3995 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3997 tasks[i].width = width;
3998 tasks[i].height = (i + 1) * lines_per_thread;
3999 tasks[i].height = MIN (tasks[i].height, height);
4000 tasks[i].height -= i * lines_per_thread;
4002 tasks_p[i] = &tasks[i];
4005 gst_parallelized_task_runner_run (convert->conversion_runner,
4006 (GstParallelizedTaskFunc) convert_UYVY_Y444_task, (gpointer) tasks_p);
4008 convert_fill_border (convert, dest);
4012 convert_UYVY_GRAY8_task (FConvertPlaneTask * task)
4014 video_orc_convert_UYVY_GRAY8 (task->d, task->dstride, (guint16 *) task->s,
4015 task->sstride, task->width, task->height);
4019 convert_UYVY_GRAY8 (GstVideoConverter * convert, const GstVideoFrame * src,
4020 GstVideoFrame * dest)
4022 gint width = convert->in_width;
4023 gint height = convert->in_height;
4026 FConvertPlaneTask *tasks;
4027 FConvertPlaneTask **tasks_p;
4029 gint lines_per_thread;
4032 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
4033 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
4035 n_threads = convert->conversion_runner->n_threads;
4036 tasks = g_newa (FConvertPlaneTask, n_threads);
4037 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4039 lines_per_thread = (height + n_threads - 1) / n_threads;
4041 for (i = 0; i < n_threads; i++) {
4042 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4043 tasks[i].sstride = FRAME_GET_STRIDE (src);
4044 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4045 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4047 tasks[i].width = width;
4048 tasks[i].height = (i + 1) * lines_per_thread;
4049 tasks[i].height = MIN (tasks[i].height, height);
4050 tasks[i].height -= i * lines_per_thread;
4052 tasks_p[i] = &tasks[i];
4055 gst_parallelized_task_runner_run (convert->conversion_runner,
4056 (GstParallelizedTaskFunc) convert_UYVY_GRAY8_task, (gpointer) tasks_p);
4058 convert_fill_border (convert, dest);
4062 convert_AYUV_I420_task (FConvertPlaneTask * task)
4064 video_orc_convert_AYUV_I420 (task->d,
4065 2 * task->dstride, task->d2,
4066 2 * task->dstride, task->du,
4067 task->dustride, task->dv,
4068 task->dvstride, task->s,
4069 2 * task->sstride, task->s2,
4070 2 * task->sstride, task->width / 2, task->height / 2);
4074 convert_AYUV_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
4075 GstVideoFrame * dest)
4077 gint width = convert->in_width;
4078 gint height = convert->in_height;
4079 guint8 *s1, *s2, *dy1, *dy2, *du, *dv;
4080 FConvertPlaneTask *tasks;
4081 FConvertPlaneTask **tasks_p;
4083 gint lines_per_thread;
4086 s1 = FRAME_GET_LINE (src, convert->in_y + 0);
4087 s1 += convert->in_x * 4;
4088 s2 = FRAME_GET_LINE (src, convert->in_y + 1);
4089 s2 += convert->in_x * 4;
4091 dy1 = FRAME_GET_Y_LINE (dest, convert->out_y + 0);
4092 dy1 += convert->out_x;
4093 dy2 = FRAME_GET_Y_LINE (dest, convert->out_y + 1);
4094 dy2 += convert->out_x;
4095 du = FRAME_GET_U_LINE (dest, convert->out_y >> 1);
4096 du += convert->out_x >> 1;
4097 dv = FRAME_GET_V_LINE (dest, convert->out_y >> 1);
4098 dv += convert->out_x >> 1;
4100 /* only for even width/height */
4102 n_threads = convert->conversion_runner->n_threads;
4103 tasks = g_newa (FConvertPlaneTask, n_threads);
4104 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4106 lines_per_thread = GST_ROUND_UP_2 ((height + n_threads - 1) / n_threads);
4108 for (i = 0; i < n_threads; i++) {
4109 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4110 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4111 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4112 tasks[i].sstride = FRAME_GET_STRIDE (src);
4113 tasks[i].d = dy1 + i * lines_per_thread * tasks[i].dstride;
4114 tasks[i].d2 = dy2 + i * lines_per_thread * tasks[i].dstride;
4115 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride / 2;
4116 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride / 2;
4117 tasks[i].s = s1 + i * lines_per_thread * tasks[i].sstride;
4118 tasks[i].s2 = s2 + i * lines_per_thread * tasks[i].sstride;
4120 tasks[i].width = width;
4121 tasks[i].height = (i + 1) * lines_per_thread;
4122 tasks[i].height = MIN (tasks[i].height, height);
4123 tasks[i].height -= i * lines_per_thread;
4125 tasks_p[i] = &tasks[i];
4128 gst_parallelized_task_runner_run (convert->conversion_runner,
4129 (GstParallelizedTaskFunc) convert_AYUV_I420_task, (gpointer) tasks_p);
4131 convert_fill_border (convert, dest);
4135 convert_AYUV_YUY2_task (FConvertPlaneTask * task)
4137 video_orc_convert_AYUV_YUY2 (task->d, task->dstride, task->s,
4138 task->sstride, task->width / 2, task->height);
4142 convert_AYUV_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4143 GstVideoFrame * dest)
4145 gint width = convert->in_width;
4146 gint height = convert->in_height;
4148 FConvertPlaneTask *tasks;
4149 FConvertPlaneTask **tasks_p;
4151 gint lines_per_thread;
4154 s = FRAME_GET_LINE (src, convert->in_y);
4155 s += convert->in_x * 4;
4156 d = FRAME_GET_LINE (dest, convert->out_y);
4157 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4159 /* only for even width */
4160 n_threads = convert->conversion_runner->n_threads;
4161 tasks = g_newa (FConvertPlaneTask, n_threads);
4162 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4164 lines_per_thread = (height + n_threads - 1) / n_threads;
4166 for (i = 0; i < n_threads; i++) {
4167 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4168 tasks[i].sstride = FRAME_GET_STRIDE (src);
4169 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4170 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4172 tasks[i].width = width;
4173 tasks[i].height = (i + 1) * lines_per_thread;
4174 tasks[i].height = MIN (tasks[i].height, height);
4175 tasks[i].height -= i * lines_per_thread;
4177 tasks_p[i] = &tasks[i];
4180 gst_parallelized_task_runner_run (convert->conversion_runner,
4181 (GstParallelizedTaskFunc) convert_AYUV_YUY2_task, (gpointer) tasks_p);
4183 convert_fill_border (convert, dest);
4187 convert_AYUV_UYVY_task (FConvertPlaneTask * task)
4189 video_orc_convert_AYUV_UYVY (task->d, task->dstride, task->s,
4190 task->sstride, task->width / 2, task->height);
4194 convert_AYUV_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4195 GstVideoFrame * dest)
4197 gint width = convert->in_width;
4198 gint height = convert->in_height;
4200 FConvertPlaneTask *tasks;
4201 FConvertPlaneTask **tasks_p;
4203 gint lines_per_thread;
4206 s = FRAME_GET_LINE (src, convert->in_y);
4207 s += convert->in_x * 4;
4208 d = FRAME_GET_LINE (dest, convert->out_y);
4209 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4211 /* only for even width */
4212 n_threads = convert->conversion_runner->n_threads;
4213 tasks = g_newa (FConvertPlaneTask, n_threads);
4214 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4216 lines_per_thread = (height + n_threads - 1) / n_threads;
4218 for (i = 0; i < n_threads; i++) {
4219 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4220 tasks[i].sstride = FRAME_GET_STRIDE (src);
4221 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4222 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4224 tasks[i].width = width;
4225 tasks[i].height = (i + 1) * lines_per_thread;
4226 tasks[i].height = MIN (tasks[i].height, height);
4227 tasks[i].height -= i * lines_per_thread;
4229 tasks_p[i] = &tasks[i];
4232 gst_parallelized_task_runner_run (convert->conversion_runner,
4233 (GstParallelizedTaskFunc) convert_AYUV_UYVY_task, (gpointer) tasks_p);
4235 convert_fill_border (convert, dest);
4239 convert_AYUV_Y42B_task (FConvertPlaneTask * task)
4241 video_orc_convert_AYUV_Y42B (task->d, task->dstride, task->du,
4242 task->dustride, task->dv, task->dvstride,
4243 task->s, task->sstride, task->width / 2, task->height);
4247 convert_AYUV_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4248 GstVideoFrame * dest)
4250 gint width = convert->in_width;
4251 gint height = convert->in_height;
4252 guint8 *s, *dy, *du, *dv;
4253 FConvertPlaneTask *tasks;
4254 FConvertPlaneTask **tasks_p;
4256 gint lines_per_thread;
4259 s = FRAME_GET_LINE (src, convert->in_y);
4260 s += convert->in_x * 4;
4262 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4263 dy += convert->out_x;
4264 du = FRAME_GET_U_LINE (dest, convert->out_y);
4265 du += convert->out_x >> 1;
4266 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4267 dv += convert->out_x >> 1;
4269 /* only works for even width */
4270 n_threads = convert->conversion_runner->n_threads;
4271 tasks = g_newa (FConvertPlaneTask, n_threads);
4272 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4274 lines_per_thread = (height + n_threads - 1) / n_threads;
4276 for (i = 0; i < n_threads; i++) {
4277 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4278 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4279 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4280 tasks[i].sstride = FRAME_GET_STRIDE (src);
4281 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4282 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4283 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4284 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4286 tasks[i].width = width;
4287 tasks[i].height = (i + 1) * lines_per_thread;
4288 tasks[i].height = MIN (tasks[i].height, height);
4289 tasks[i].height -= i * lines_per_thread;
4291 tasks_p[i] = &tasks[i];
4294 gst_parallelized_task_runner_run (convert->conversion_runner,
4295 (GstParallelizedTaskFunc) convert_AYUV_Y42B_task, (gpointer) tasks_p);
4297 convert_fill_border (convert, dest);
4301 convert_AYUV_Y444_task (FConvertPlaneTask * task)
4303 video_orc_convert_AYUV_Y444 (task->d, task->dstride, task->du,
4304 task->dustride, task->dv, task->dvstride,
4305 task->s, task->sstride, task->width, task->height);
4309 convert_AYUV_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
4310 GstVideoFrame * dest)
4312 gint width = convert->in_width;
4313 gint height = convert->in_height;
4314 guint8 *s, *dy, *du, *dv;
4315 FConvertPlaneTask *tasks;
4316 FConvertPlaneTask **tasks_p;
4318 gint lines_per_thread;
4321 s = FRAME_GET_LINE (src, convert->in_y);
4322 s += convert->in_x * 4;
4324 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4325 dy += convert->out_x;
4326 du = FRAME_GET_U_LINE (dest, convert->out_y);
4327 du += convert->out_x;
4328 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4329 dv += convert->out_x;
4331 n_threads = convert->conversion_runner->n_threads;
4332 tasks = g_newa (FConvertPlaneTask, n_threads);
4333 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4335 lines_per_thread = (height + n_threads - 1) / n_threads;
4337 for (i = 0; i < n_threads; i++) {
4338 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4339 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4340 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4341 tasks[i].sstride = FRAME_GET_STRIDE (src);
4342 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4343 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4344 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4345 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4347 tasks[i].width = width;
4348 tasks[i].height = (i + 1) * lines_per_thread;
4349 tasks[i].height = MIN (tasks[i].height, height);
4350 tasks[i].height -= i * lines_per_thread;
4352 tasks_p[i] = &tasks[i];
4355 gst_parallelized_task_runner_run (convert->conversion_runner,
4356 (GstParallelizedTaskFunc) convert_AYUV_Y444_task, (gpointer) tasks_p);
4357 convert_fill_border (convert, dest);
4361 convert_Y42B_YUY2_task (FConvertPlaneTask * task)
4363 video_orc_convert_Y42B_YUY2 (task->d, task->dstride,
4364 task->s, task->sstride,
4365 task->su, task->sustride,
4366 task->sv, task->svstride, (task->width + 1) / 2, task->height);
4370 convert_Y42B_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4371 GstVideoFrame * dest)
4373 gint width = convert->in_width;
4374 gint height = convert->in_height;
4375 guint8 *sy, *su, *sv, *d;
4376 FConvertPlaneTask *tasks;
4377 FConvertPlaneTask **tasks_p;
4379 gint lines_per_thread;
4382 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4383 sy += convert->in_x;
4384 su = FRAME_GET_U_LINE (src, convert->in_y);
4385 su += convert->in_x >> 1;
4386 sv = FRAME_GET_V_LINE (src, convert->in_y);
4387 sv += convert->in_x >> 1;
4389 d = FRAME_GET_LINE (dest, convert->out_y);
4390 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4392 n_threads = convert->conversion_runner->n_threads;
4393 tasks = g_newa (FConvertPlaneTask, n_threads);
4394 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4396 lines_per_thread = (height + n_threads - 1) / n_threads;
4398 for (i = 0; i < n_threads; i++) {
4399 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4400 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4401 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4402 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4403 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4404 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4405 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4406 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4408 tasks[i].width = width;
4409 tasks[i].height = (i + 1) * lines_per_thread;
4410 tasks[i].height = MIN (tasks[i].height, height);
4411 tasks[i].height -= i * lines_per_thread;
4413 tasks_p[i] = &tasks[i];
4416 gst_parallelized_task_runner_run (convert->conversion_runner,
4417 (GstParallelizedTaskFunc) convert_Y42B_YUY2_task, (gpointer) tasks_p);
4419 convert_fill_border (convert, dest);
4423 convert_Y42B_UYVY_task (FConvertPlaneTask * task)
4425 video_orc_convert_Y42B_UYVY (task->d, task->dstride,
4426 task->s, task->sstride,
4427 task->su, task->sustride,
4428 task->sv, task->svstride, (task->width + 1) / 2, task->height);
4432 convert_Y42B_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4433 GstVideoFrame * dest)
4435 gint width = convert->in_width;
4436 gint height = convert->in_height;
4437 guint8 *sy, *su, *sv, *d;
4438 FConvertPlaneTask *tasks;
4439 FConvertPlaneTask **tasks_p;
4441 gint lines_per_thread;
4444 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4445 sy += convert->in_x;
4446 su = FRAME_GET_U_LINE (src, convert->in_y);
4447 su += convert->in_x >> 1;
4448 sv = FRAME_GET_V_LINE (src, convert->in_y);
4449 sv += convert->in_x >> 1;
4451 d = FRAME_GET_LINE (dest, convert->out_y);
4452 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4454 n_threads = convert->conversion_runner->n_threads;
4455 tasks = g_newa (FConvertPlaneTask, n_threads);
4456 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4458 lines_per_thread = (height + n_threads - 1) / n_threads;
4460 for (i = 0; i < n_threads; i++) {
4461 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4462 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4463 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4464 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4465 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4466 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4467 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4468 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4470 tasks[i].width = width;
4471 tasks[i].height = (i + 1) * lines_per_thread;
4472 tasks[i].height = MIN (tasks[i].height, height);
4473 tasks[i].height -= i * lines_per_thread;
4475 tasks_p[i] = &tasks[i];
4478 gst_parallelized_task_runner_run (convert->conversion_runner,
4479 (GstParallelizedTaskFunc) convert_Y42B_UYVY_task, (gpointer) tasks_p);
4481 convert_fill_border (convert, dest);
4485 convert_Y42B_AYUV_task (FConvertPlaneTask * task)
4487 video_orc_convert_Y42B_AYUV (task->d, task->dstride, task->s,
4491 task->sv, task->svstride, task->alpha, task->width / 2, task->height);
4495 convert_Y42B_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
4496 GstVideoFrame * dest)
4498 gint width = convert->in_width;
4499 gint height = convert->in_height;
4500 guint8 *sy, *su, *sv, *d;
4501 guint8 alpha = MIN (convert->alpha_value, 255);
4502 FConvertPlaneTask *tasks;
4503 FConvertPlaneTask **tasks_p;
4505 gint lines_per_thread;
4508 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4509 sy += convert->in_x;
4510 su = FRAME_GET_U_LINE (src, convert->in_y);
4511 su += convert->in_x >> 1;
4512 sv = FRAME_GET_V_LINE (src, convert->in_y);
4513 sv += convert->in_x >> 1;
4515 d = FRAME_GET_LINE (dest, convert->out_y);
4516 d += convert->out_x * 4;
4518 /* only for even width */
4519 n_threads = convert->conversion_runner->n_threads;
4520 tasks = g_newa (FConvertPlaneTask, n_threads);
4521 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4523 lines_per_thread = (height + n_threads - 1) / n_threads;
4525 for (i = 0; i < n_threads; i++) {
4526 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4527 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4528 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4529 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4530 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4531 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4532 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4533 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4535 tasks[i].width = width;
4536 tasks[i].height = (i + 1) * lines_per_thread;
4537 tasks[i].height = MIN (tasks[i].height, height);
4538 tasks[i].height -= i * lines_per_thread;
4539 tasks[i].alpha = alpha;
4541 tasks_p[i] = &tasks[i];
4544 gst_parallelized_task_runner_run (convert->conversion_runner,
4545 (GstParallelizedTaskFunc) convert_Y42B_AYUV_task, (gpointer) tasks_p);
4547 convert_fill_border (convert, dest);
4551 convert_Y444_YUY2_task (FConvertPlaneTask * task)
4553 video_orc_convert_Y444_YUY2 (task->d, task->dstride, task->s,
4556 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
4560 convert_Y444_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4561 GstVideoFrame * dest)
4563 gint width = convert->in_width;
4564 gint height = convert->in_height;
4565 guint8 *sy, *su, *sv, *d;
4566 FConvertPlaneTask *tasks;
4567 FConvertPlaneTask **tasks_p;
4569 gint lines_per_thread;
4572 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4573 sy += convert->in_x;
4574 su = FRAME_GET_U_LINE (src, convert->in_y);
4575 su += convert->in_x;
4576 sv = FRAME_GET_V_LINE (src, convert->in_y);
4577 sv += convert->in_x;
4579 d = FRAME_GET_LINE (dest, convert->out_y);
4580 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4582 n_threads = convert->conversion_runner->n_threads;
4583 tasks = g_newa (FConvertPlaneTask, n_threads);
4584 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4586 lines_per_thread = (height + n_threads - 1) / n_threads;
4588 for (i = 0; i < n_threads; i++) {
4589 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4590 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4591 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4592 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4593 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4594 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4595 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4596 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4598 tasks[i].width = width;
4599 tasks[i].height = (i + 1) * lines_per_thread;
4600 tasks[i].height = MIN (tasks[i].height, height);
4601 tasks[i].height -= i * lines_per_thread;
4603 tasks_p[i] = &tasks[i];
4606 gst_parallelized_task_runner_run (convert->conversion_runner,
4607 (GstParallelizedTaskFunc) convert_Y444_YUY2_task, (gpointer) tasks_p);
4609 convert_fill_border (convert, dest);
4613 convert_Y444_UYVY_task (FConvertPlaneTask * task)
4615 video_orc_convert_Y444_UYVY (task->d, task->dstride, task->s,
4618 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
4622 convert_Y444_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4623 GstVideoFrame * dest)
4625 gint width = convert->in_width;
4626 gint height = convert->in_height;
4627 guint8 *sy, *su, *sv, *d;
4628 FConvertPlaneTask *tasks;
4629 FConvertPlaneTask **tasks_p;
4631 gint lines_per_thread;
4634 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4635 sy += convert->in_x;
4636 su = FRAME_GET_U_LINE (src, convert->in_y);
4637 su += convert->in_x;
4638 sv = FRAME_GET_V_LINE (src, convert->in_y);
4639 sv += convert->in_x;
4641 d = FRAME_GET_LINE (dest, convert->out_y);
4642 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4644 n_threads = convert->conversion_runner->n_threads;
4645 tasks = g_newa (FConvertPlaneTask, n_threads);
4646 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4648 lines_per_thread = (height + n_threads - 1) / n_threads;
4650 for (i = 0; i < n_threads; i++) {
4651 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4652 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4653 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4654 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4655 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4656 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4657 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4658 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4660 tasks[i].width = width;
4661 tasks[i].height = (i + 1) * lines_per_thread;
4662 tasks[i].height = MIN (tasks[i].height, height);
4663 tasks[i].height -= i * lines_per_thread;
4665 tasks_p[i] = &tasks[i];
4668 gst_parallelized_task_runner_run (convert->conversion_runner,
4669 (GstParallelizedTaskFunc) convert_Y444_UYVY_task, (gpointer) tasks_p);
4671 convert_fill_border (convert, dest);
4675 convert_Y444_AYUV_task (FConvertPlaneTask * task)
4677 video_orc_convert_Y444_AYUV (task->d, task->dstride, task->s,
4681 task->sv, task->svstride, task->alpha, task->width, task->height);
4685 convert_Y444_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
4686 GstVideoFrame * dest)
4688 gint width = convert->in_width;
4689 gint height = convert->in_height;
4690 guint8 *sy, *su, *sv, *d;
4691 guint8 alpha = MIN (convert->alpha_value, 255);
4692 FConvertPlaneTask *tasks;
4693 FConvertPlaneTask **tasks_p;
4695 gint lines_per_thread;
4698 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4699 sy += convert->in_x;
4700 su = FRAME_GET_U_LINE (src, convert->in_y);
4701 su += convert->in_x;
4702 sv = FRAME_GET_V_LINE (src, convert->in_y);
4703 sv += convert->in_x;
4705 d = FRAME_GET_LINE (dest, convert->out_y);
4706 d += convert->out_x * 4;
4708 n_threads = convert->conversion_runner->n_threads;
4709 tasks = g_newa (FConvertPlaneTask, n_threads);
4710 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4712 lines_per_thread = (height + n_threads - 1) / n_threads;
4714 for (i = 0; i < n_threads; i++) {
4715 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4716 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4717 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4718 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4719 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4720 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4721 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4722 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4724 tasks[i].width = width;
4725 tasks[i].height = (i + 1) * lines_per_thread;
4726 tasks[i].height = MIN (tasks[i].height, height);
4727 tasks[i].height -= i * lines_per_thread;
4728 tasks[i].alpha = alpha;
4730 tasks_p[i] = &tasks[i];
4733 gst_parallelized_task_runner_run (convert->conversion_runner,
4734 (GstParallelizedTaskFunc) convert_Y444_AYUV_task, (gpointer) tasks_p);
4736 convert_fill_border (convert, dest);
4739 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4741 convert_AYUV_ARGB_task (FConvertPlaneTask * task)
4743 video_orc_convert_AYUV_ARGB (task->d, task->dstride, task->s,
4744 task->sstride, task->data->im[0][0], task->data->im[0][2],
4745 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4746 task->width, task->height);
4750 convert_AYUV_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
4751 GstVideoFrame * dest)
4753 gint width = convert->in_width;
4754 gint height = convert->in_height;
4755 MatrixData *data = &convert->convert_matrix;
4757 FConvertPlaneTask *tasks;
4758 FConvertPlaneTask **tasks_p;
4760 gint lines_per_thread;
4763 s = FRAME_GET_LINE (src, convert->in_y);
4764 s += (convert->in_x * 4);
4765 d = FRAME_GET_LINE (dest, convert->out_y);
4766 d += (convert->out_x * 4);
4768 n_threads = convert->conversion_runner->n_threads;
4769 tasks = g_newa (FConvertPlaneTask, n_threads);
4770 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4772 lines_per_thread = (height + n_threads - 1) / n_threads;
4774 for (i = 0; i < n_threads; i++) {
4775 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4776 tasks[i].sstride = FRAME_GET_STRIDE (src);
4777 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4778 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4780 tasks[i].width = width;
4781 tasks[i].height = (i + 1) * lines_per_thread;
4782 tasks[i].height = MIN (tasks[i].height, height);
4783 tasks[i].height -= i * lines_per_thread;
4784 tasks[i].data = data;
4786 tasks_p[i] = &tasks[i];
4789 gst_parallelized_task_runner_run (convert->conversion_runner,
4790 (GstParallelizedTaskFunc) convert_AYUV_ARGB_task, (gpointer) tasks_p);
4792 convert_fill_border (convert, dest);
4796 convert_AYUV_BGRA_task (FConvertPlaneTask * task)
4798 video_orc_convert_AYUV_BGRA (task->d, task->dstride, task->s,
4799 task->sstride, task->data->im[0][0], task->data->im[0][2],
4800 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4801 task->width, task->height);
4805 convert_AYUV_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
4806 GstVideoFrame * dest)
4808 gint width = convert->in_width;
4809 gint height = convert->in_height;
4810 MatrixData *data = &convert->convert_matrix;
4812 FConvertPlaneTask *tasks;
4813 FConvertPlaneTask **tasks_p;
4815 gint lines_per_thread;
4818 s = FRAME_GET_LINE (src, convert->in_y);
4819 s += (convert->in_x * 4);
4820 d = FRAME_GET_LINE (dest, convert->out_y);
4821 d += (convert->out_x * 4);
4823 n_threads = convert->conversion_runner->n_threads;
4824 tasks = g_newa (FConvertPlaneTask, n_threads);
4825 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4827 lines_per_thread = (height + n_threads - 1) / n_threads;
4829 for (i = 0; i < n_threads; i++) {
4830 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4831 tasks[i].sstride = FRAME_GET_STRIDE (src);
4832 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4833 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4835 tasks[i].width = width;
4836 tasks[i].height = (i + 1) * lines_per_thread;
4837 tasks[i].height = MIN (tasks[i].height, height);
4838 tasks[i].height -= i * lines_per_thread;
4839 tasks[i].data = data;
4841 tasks_p[i] = &tasks[i];
4844 gst_parallelized_task_runner_run (convert->conversion_runner,
4845 (GstParallelizedTaskFunc) convert_AYUV_BGRA_task, (gpointer) tasks_p);
4847 convert_fill_border (convert, dest);
4851 convert_AYUV_ABGR_task (FConvertPlaneTask * task)
4853 video_orc_convert_AYUV_ABGR (task->d, task->dstride, task->s,
4854 task->sstride, task->data->im[0][0], task->data->im[0][2],
4855 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4856 task->width, task->height);
4860 convert_AYUV_ABGR (GstVideoConverter * convert, const GstVideoFrame * src,
4861 GstVideoFrame * dest)
4863 gint width = convert->in_width;
4864 gint height = convert->in_height;
4865 MatrixData *data = &convert->convert_matrix;
4867 FConvertPlaneTask *tasks;
4868 FConvertPlaneTask **tasks_p;
4870 gint lines_per_thread;
4873 s = FRAME_GET_LINE (src, convert->in_y);
4874 s += (convert->in_x * 4);
4875 d = FRAME_GET_LINE (dest, convert->out_y);
4876 d += (convert->out_x * 4);
4878 n_threads = convert->conversion_runner->n_threads;
4879 tasks = g_newa (FConvertPlaneTask, n_threads);
4880 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4882 lines_per_thread = (height + n_threads - 1) / n_threads;
4884 for (i = 0; i < n_threads; i++) {
4885 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4886 tasks[i].sstride = FRAME_GET_STRIDE (src);
4887 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4888 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4890 tasks[i].width = width;
4891 tasks[i].height = (i + 1) * lines_per_thread;
4892 tasks[i].height = MIN (tasks[i].height, height);
4893 tasks[i].height -= i * lines_per_thread;
4894 tasks[i].data = data;
4896 tasks_p[i] = &tasks[i];
4899 gst_parallelized_task_runner_run (convert->conversion_runner,
4900 (GstParallelizedTaskFunc) convert_AYUV_ABGR_task, (gpointer) tasks_p);
4902 convert_fill_border (convert, dest);
4906 convert_AYUV_RGBA_task (FConvertPlaneTask * task)
4908 video_orc_convert_AYUV_RGBA (task->d, task->dstride, task->s,
4909 task->sstride, task->data->im[0][0], task->data->im[0][2],
4910 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4911 task->width, task->height);
4915 convert_AYUV_RGBA (GstVideoConverter * convert, const GstVideoFrame * src,
4916 GstVideoFrame * dest)
4918 gint width = convert->in_width;
4919 gint height = convert->in_height;
4920 MatrixData *data = &convert->convert_matrix;
4922 FConvertPlaneTask *tasks;
4923 FConvertPlaneTask **tasks_p;
4925 gint lines_per_thread;
4928 s = FRAME_GET_LINE (src, convert->in_y);
4929 s += (convert->in_x * 4);
4930 d = FRAME_GET_LINE (dest, convert->out_y);
4931 d += (convert->out_x * 4);
4933 n_threads = convert->conversion_runner->n_threads;
4934 tasks = g_newa (FConvertPlaneTask, n_threads);
4935 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4937 lines_per_thread = (height + n_threads - 1) / n_threads;
4939 for (i = 0; i < n_threads; i++) {
4940 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4941 tasks[i].sstride = FRAME_GET_STRIDE (src);
4942 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4943 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4945 tasks[i].width = width;
4946 tasks[i].height = (i + 1) * lines_per_thread;
4947 tasks[i].height = MIN (tasks[i].height, height);
4948 tasks[i].height -= i * lines_per_thread;
4949 tasks[i].data = data;
4951 tasks_p[i] = &tasks[i];
4954 gst_parallelized_task_runner_run (convert->conversion_runner,
4955 (GstParallelizedTaskFunc) convert_AYUV_RGBA_task, (gpointer) tasks_p);
4957 convert_fill_border (convert, dest);
4962 convert_I420_BGRA_task (FConvertTask * task)
4966 for (i = task->height_0; i < task->height_1; i++) {
4967 guint8 *sy, *su, *sv, *d;
4969 d = FRAME_GET_LINE (task->dest, i + task->out_y);
4970 d += (task->out_x * 4);
4971 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
4973 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
4974 su += (task->in_x >> 1);
4975 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
4976 sv += (task->in_x >> 1);
4978 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4979 video_orc_convert_I420_BGRA (d, sy, su, sv,
4980 task->data->im[0][0], task->data->im[0][2],
4981 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4984 video_orc_convert_I420_ARGB (d, sy, su, sv,
4985 task->data->im[0][0], task->data->im[0][2],
4986 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4993 convert_I420_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
4994 GstVideoFrame * dest)
4997 gint width = convert->in_width;
4998 gint height = convert->in_height;
4999 MatrixData *data = &convert->convert_matrix;
5000 FConvertTask *tasks;
5001 FConvertTask **tasks_p;
5003 gint lines_per_thread;
5005 n_threads = convert->conversion_runner->n_threads;
5006 tasks = g_newa (FConvertTask, n_threads);
5007 tasks_p = g_newa (FConvertTask *, n_threads);
5009 lines_per_thread = (height + n_threads - 1) / n_threads;
5011 for (i = 0; i < n_threads; i++) {
5013 tasks[i].dest = dest;
5015 tasks[i].width = width;
5016 tasks[i].data = data;
5017 tasks[i].in_x = convert->in_x;
5018 tasks[i].in_y = convert->in_y;
5019 tasks[i].out_x = convert->out_x;
5020 tasks[i].out_y = convert->out_y;
5022 tasks[i].height_0 = i * lines_per_thread;
5023 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5024 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5026 tasks_p[i] = &tasks[i];
5029 gst_parallelized_task_runner_run (convert->conversion_runner,
5030 (GstParallelizedTaskFunc) convert_I420_BGRA_task, (gpointer) tasks_p);
5032 convert_fill_border (convert, dest);
5036 convert_I420_ARGB_task (FConvertTask * task)
5040 for (i = task->height_0; i < task->height_1; i++) {
5041 guint8 *sy, *su, *sv, *d;
5043 d = FRAME_GET_LINE (task->dest, i + task->out_y);
5044 d += (task->out_x * 4);
5045 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5047 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5048 su += (task->in_x >> 1);
5049 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5050 sv += (task->in_x >> 1);
5052 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5053 video_orc_convert_I420_ARGB (d, sy, su, sv,
5054 task->data->im[0][0], task->data->im[0][2],
5055 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5058 video_orc_convert_I420_BGRA (d, sy, su, sv,
5059 task->data->im[0][0], task->data->im[0][2],
5060 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5067 convert_I420_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5068 GstVideoFrame * dest)
5071 gint width = convert->in_width;
5072 gint height = convert->in_height;
5073 MatrixData *data = &convert->convert_matrix;
5074 FConvertTask *tasks;
5075 FConvertTask **tasks_p;
5077 gint lines_per_thread;
5079 n_threads = convert->conversion_runner->n_threads;
5080 tasks = g_newa (FConvertTask, n_threads);
5081 tasks_p = g_newa (FConvertTask *, n_threads);
5083 lines_per_thread = (height + n_threads - 1) / n_threads;
5085 for (i = 0; i < n_threads; i++) {
5087 tasks[i].dest = dest;
5089 tasks[i].width = width;
5090 tasks[i].data = data;
5091 tasks[i].in_x = convert->in_x;
5092 tasks[i].in_y = convert->in_y;
5093 tasks[i].out_x = convert->out_x;
5094 tasks[i].out_y = convert->out_y;
5096 tasks[i].height_0 = i * lines_per_thread;
5097 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5098 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5100 tasks_p[i] = &tasks[i];
5103 gst_parallelized_task_runner_run (convert->conversion_runner,
5104 (GstParallelizedTaskFunc) convert_I420_ARGB_task, (gpointer) tasks_p);
5106 convert_fill_border (convert, dest);
5110 convert_I420_pack_ARGB_task (FConvertTask * task)
5113 gpointer d[GST_VIDEO_MAX_PLANES];
5115 d[0] = FRAME_GET_LINE (task->dest, 0);
5118 task->out_x * GST_VIDEO_FORMAT_INFO_PSTRIDE (task->dest->info.finfo, 0);
5120 for (i = task->height_0; i < task->height_1; i++) {
5121 guint8 *sy, *su, *sv;
5123 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5125 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5126 su += (task->in_x >> 1);
5127 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5128 sv += (task->in_x >> 1);
5130 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5131 video_orc_convert_I420_ARGB (task->tmpline, sy, su, sv,
5132 task->data->im[0][0], task->data->im[0][2],
5133 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5136 video_orc_convert_I420_BGRA (task->tmpline, sy, su, sv,
5137 task->data->im[0][0], task->data->im[0][2],
5138 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5141 task->dest->info.finfo->pack_func (task->dest->info.finfo,
5142 (GST_VIDEO_FRAME_IS_INTERLACED (task->dest) ?
5143 GST_VIDEO_PACK_FLAG_INTERLACED :
5144 GST_VIDEO_PACK_FLAG_NONE),
5145 task->tmpline, 0, d, task->dest->info.stride,
5146 task->dest->info.chroma_site, i + task->out_y, task->width);
5151 convert_I420_pack_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5152 GstVideoFrame * dest)
5155 gint width = convert->in_width;
5156 gint height = convert->in_height;
5157 MatrixData *data = &convert->convert_matrix;
5158 FConvertTask *tasks;
5159 FConvertTask **tasks_p;
5161 gint lines_per_thread;
5163 n_threads = convert->conversion_runner->n_threads;
5164 tasks = g_newa (FConvertTask, n_threads);
5165 tasks_p = g_newa (FConvertTask *, n_threads);
5167 lines_per_thread = (height + n_threads - 1) / n_threads;
5169 for (i = 0; i < n_threads; i++) {
5171 tasks[i].dest = dest;
5173 tasks[i].width = width;
5174 tasks[i].data = data;
5175 tasks[i].in_x = convert->in_x;
5176 tasks[i].in_y = convert->in_y;
5177 tasks[i].out_x = convert->out_x;
5178 tasks[i].out_y = convert->out_y;
5179 tasks[i].tmpline = convert->tmpline[i];
5181 tasks[i].height_0 = i * lines_per_thread;
5182 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5183 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5185 tasks_p[i] = &tasks[i];
5188 gst_parallelized_task_runner_run (convert->conversion_runner,
5189 (GstParallelizedTaskFunc) convert_I420_pack_ARGB_task,
5190 (gpointer) tasks_p);
5192 convert_fill_border (convert, dest);
5196 memset_u24 (guint8 * data, guint8 col[3], unsigned int n)
5200 for (i = 0; i < n; i++) {
5209 memset_u32_16 (guint8 * data, guint8 col[4], unsigned int n)
5213 for (i = 0; i < n; i += 2) {
5224 #define MAKE_BORDER_FUNC(func) \
5225 for (i = 0; i < out_y; i++) \
5226 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
5227 if (rb_width || lb_width) { \
5228 for (i = 0; i < out_height; i++) { \
5229 guint8 *d = FRAME_GET_PLANE_LINE (dest, k, i + out_y); \
5231 func (d, col, lb_width); \
5233 func (d + (pstride * r_border), col, rb_width); \
5236 for (i = out_y + out_height; i < out_maxheight; i++) \
5237 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
5240 convert_fill_border (GstVideoConverter * convert, GstVideoFrame * dest)
5243 const GstVideoFormatInfo *out_finfo;
5245 if (!convert->fill_border || !convert->borderline)
5248 out_finfo = convert->out_info.finfo;
5250 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
5252 for (k = 0; k < n_planes; k++) {
5253 gint i, out_x, out_y, out_width, out_height, pstride, pgroup;
5254 gint r_border, lb_width, rb_width;
5255 gint out_maxwidth, out_maxheight;
5258 out_x = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_x);
5259 out_y = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k, convert->out_y);
5261 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_width);
5263 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k, convert->out_height);
5265 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_maxwidth);
5267 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k,
5268 convert->out_maxheight);
5270 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, k);
5272 switch (GST_VIDEO_FORMAT_INFO_FORMAT (out_finfo)) {
5273 case GST_VIDEO_FORMAT_YUY2:
5274 case GST_VIDEO_FORMAT_YVYU:
5275 case GST_VIDEO_FORMAT_UYVY:
5277 out_maxwidth = GST_ROUND_UP_2 (out_maxwidth);
5284 r_border = out_x + out_width;
5285 rb_width = out_maxwidth - r_border;
5288 borders = &convert->borders[k];
5293 guint8 col = ((guint8 *) borders)[0];
5294 MAKE_BORDER_FUNC (memset);
5299 guint16 col = ((guint16 *) borders)[0];
5300 MAKE_BORDER_FUNC (video_orc_splat_u16);
5306 col[0] = ((guint8 *) borders)[0];
5307 col[1] = ((guint8 *) borders)[1];
5308 col[2] = ((guint8 *) borders)[2];
5309 MAKE_BORDER_FUNC (memset_u24);
5314 guint32 col = ((guint32 *) borders)[0];
5315 MAKE_BORDER_FUNC (video_orc_splat_u32);
5320 guint64 col = ((guint64 *) borders)[0];
5321 MAKE_BORDER_FUNC (video_orc_splat_u64);
5327 col[0] = ((guint8 *) borders)[0];
5328 col[2] = ((guint8 *) borders)[2];
5329 col[1] = ((guint8 *) borders)[r_border & 1 ? 3 : 1];
5330 col[3] = ((guint8 *) borders)[r_border & 1 ? 1 : 3];
5331 MAKE_BORDER_FUNC (memset_u32_16);
5342 const guint8 *s, *s2;
5344 gint sstride, dstride;
5350 convert_plane_fill_task (FSimpleScaleTask * task)
5352 video_orc_memset_2d (task->d, task->dstride,
5353 task->fill, task->width, task->height);
5357 convert_plane_fill (GstVideoConverter * convert,
5358 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5361 FSimpleScaleTask *tasks;
5362 FSimpleScaleTask **tasks_p;
5364 gint lines_per_thread;
5367 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5368 d += convert->fout_x[plane];
5370 n_threads = convert->conversion_runner->n_threads;
5371 tasks = g_newa (FSimpleScaleTask, n_threads);
5372 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5373 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5375 for (i = 0; i < n_threads; i++) {
5376 tasks[i].d = d + i * lines_per_thread * convert->fout_width[plane];
5378 tasks[i].fill = convert->ffill[plane];
5379 tasks[i].width = convert->fout_width[plane];
5380 tasks[i].height = (i + 1) * lines_per_thread;
5381 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5382 tasks[i].height -= i * lines_per_thread;
5383 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5385 tasks_p[i] = &tasks[i];
5388 gst_parallelized_task_runner_run (convert->conversion_runner,
5389 (GstParallelizedTaskFunc) convert_plane_fill_task, (gpointer) tasks_p);
5393 convert_plane_h_double_task (FSimpleScaleTask * task)
5395 video_orc_planar_chroma_422_444 (task->d,
5396 task->dstride, task->s, task->sstride, task->width / 2, task->height);
5400 convert_plane_h_double (GstVideoConverter * convert,
5401 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5404 gint splane = convert->fsplane[plane];
5405 FSimpleScaleTask *tasks;
5406 FSimpleScaleTask **tasks_p;
5408 gint lines_per_thread;
5411 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5412 s += convert->fin_x[splane];
5413 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5414 d += convert->fout_x[plane];
5416 n_threads = convert->conversion_runner->n_threads;
5417 tasks = g_newa (FSimpleScaleTask, n_threads);
5418 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5419 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5421 for (i = 0; i < n_threads; i++) {
5422 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5423 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5425 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5426 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5428 tasks[i].width = convert->fout_width[plane];
5429 tasks[i].height = (i + 1) * lines_per_thread;
5430 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5431 tasks[i].height -= i * lines_per_thread;
5433 tasks_p[i] = &tasks[i];
5436 gst_parallelized_task_runner_run (convert->conversion_runner,
5437 (GstParallelizedTaskFunc) convert_plane_h_double_task,
5438 (gpointer) tasks_p);
5442 convert_plane_h_halve_task (FSimpleScaleTask * task)
5444 video_orc_planar_chroma_444_422 (task->d,
5445 task->dstride, task->s, task->sstride, task->width, task->height);
5449 convert_plane_h_halve (GstVideoConverter * convert,
5450 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5453 gint splane = convert->fsplane[plane];
5454 FSimpleScaleTask *tasks;
5455 FSimpleScaleTask **tasks_p;
5457 gint lines_per_thread;
5460 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5461 s += convert->fin_x[splane];
5462 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5463 d += convert->fout_x[plane];
5465 n_threads = convert->conversion_runner->n_threads;
5466 tasks = g_newa (FSimpleScaleTask, n_threads);
5467 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5468 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5470 for (i = 0; i < n_threads; i++) {
5471 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5472 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5474 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5475 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5477 tasks[i].width = convert->fout_width[plane];
5478 tasks[i].height = (i + 1) * lines_per_thread;
5479 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5480 tasks[i].height -= i * lines_per_thread;
5482 tasks_p[i] = &tasks[i];
5485 gst_parallelized_task_runner_run (convert->conversion_runner,
5486 (GstParallelizedTaskFunc) convert_plane_h_halve_task, (gpointer) tasks_p);
5490 convert_plane_v_double_task (FSimpleScaleTask * task)
5492 video_orc_planar_chroma_420_422 (task->d, 2 * task->dstride, task->d2,
5493 2 * task->dstride, task->s, task->sstride, task->width, task->height / 2);
5497 convert_plane_v_double (GstVideoConverter * convert,
5498 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5500 guint8 *s, *d1, *d2;
5501 gint ds, splane = convert->fsplane[plane];
5502 FSimpleScaleTask *tasks;
5503 FSimpleScaleTask **tasks_p;
5505 gint lines_per_thread;
5508 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5509 s += convert->fin_x[splane];
5510 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5511 d1 += convert->fout_x[plane];
5512 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
5513 d2 += convert->fout_x[plane];
5514 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5516 n_threads = convert->conversion_runner->n_threads;
5517 tasks = g_newa (FSimpleScaleTask, n_threads);
5518 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5520 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
5523 for (i = 0; i < n_threads; i++) {
5524 tasks[i].d = d1 + i * lines_per_thread * ds;
5525 tasks[i].d2 = d2 + i * lines_per_thread * ds;
5526 tasks[i].dstride = ds;
5527 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5528 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride / 2;
5530 tasks[i].width = convert->fout_width[plane];
5531 tasks[i].height = (i + 1) * lines_per_thread;
5532 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5533 tasks[i].height -= i * lines_per_thread;
5535 tasks_p[i] = &tasks[i];
5538 gst_parallelized_task_runner_run (convert->conversion_runner,
5539 (GstParallelizedTaskFunc) convert_plane_v_double_task,
5540 (gpointer) tasks_p);
5544 convert_plane_v_halve_task (FSimpleScaleTask * task)
5546 video_orc_planar_chroma_422_420 (task->d, task->dstride, task->s,
5547 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
5552 convert_plane_v_halve (GstVideoConverter * convert,
5553 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5555 guint8 *s1, *s2, *d;
5556 gint ss, ds, splane = convert->fsplane[plane];
5557 FSimpleScaleTask *tasks;
5558 FSimpleScaleTask **tasks_p;
5560 gint lines_per_thread;
5563 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5564 s1 += convert->fin_x[splane];
5565 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
5566 s2 += convert->fin_x[splane];
5567 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5568 d += convert->fout_x[plane];
5570 ss = FRAME_GET_PLANE_STRIDE (src, splane);
5571 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5573 n_threads = convert->conversion_runner->n_threads;
5574 tasks = g_newa (FSimpleScaleTask, n_threads);
5575 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5576 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5578 for (i = 0; i < n_threads; i++) {
5579 tasks[i].d = d + i * lines_per_thread * ds;
5580 tasks[i].dstride = ds;
5581 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
5582 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
5583 tasks[i].sstride = ss;
5585 tasks[i].width = convert->fout_width[plane];
5586 tasks[i].height = (i + 1) * lines_per_thread;
5587 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5588 tasks[i].height -= i * lines_per_thread;
5590 tasks_p[i] = &tasks[i];
5593 gst_parallelized_task_runner_run (convert->conversion_runner,
5594 (GstParallelizedTaskFunc) convert_plane_v_halve_task, (gpointer) tasks_p);
5598 convert_plane_hv_double_task (FSimpleScaleTask * task)
5600 video_orc_planar_chroma_420_444 (task->d, 2 * task->dstride, task->d2,
5601 2 * task->dstride, task->s, task->sstride, (task->width + 1) / 2,
5606 convert_plane_hv_double (GstVideoConverter * convert,
5607 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5609 guint8 *s, *d1, *d2;
5610 gint ss, ds, splane = convert->fsplane[plane];
5611 FSimpleScaleTask *tasks;
5612 FSimpleScaleTask **tasks_p;
5614 gint lines_per_thread;
5617 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5618 s += convert->fin_x[splane];
5619 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5620 d1 += convert->fout_x[plane];
5621 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
5622 d2 += convert->fout_x[plane];
5623 ss = FRAME_GET_PLANE_STRIDE (src, splane);
5624 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5626 n_threads = convert->conversion_runner->n_threads;
5627 tasks = g_newa (FSimpleScaleTask, n_threads);
5628 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5630 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
5633 for (i = 0; i < n_threads; i++) {
5634 tasks[i].d = d1 + i * lines_per_thread * ds;
5635 tasks[i].d2 = d2 + i * lines_per_thread * ds;
5636 tasks[i].dstride = ds;
5637 tasks[i].sstride = ss;
5638 tasks[i].s = s + i * lines_per_thread * ss / 2;
5640 tasks[i].width = convert->fout_width[plane];
5641 tasks[i].height = (i + 1) * lines_per_thread;
5642 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5643 tasks[i].height -= i * lines_per_thread;
5645 tasks_p[i] = &tasks[i];
5648 gst_parallelized_task_runner_run (convert->conversion_runner,
5649 (GstParallelizedTaskFunc) convert_plane_hv_double_task,
5650 (gpointer) tasks_p);
5654 convert_plane_hv_halve_task (FSimpleScaleTask * task)
5656 video_orc_planar_chroma_444_420 (task->d, task->dstride, task->s,
5657 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
5662 convert_plane_hv_halve (GstVideoConverter * convert,
5663 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5665 guint8 *s1, *s2, *d;
5666 gint ss, ds, splane = convert->fsplane[plane];
5667 FSimpleScaleTask *tasks;
5668 FSimpleScaleTask **tasks_p;
5670 gint lines_per_thread;
5673 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5674 s1 += convert->fin_x[splane];
5675 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
5676 s2 += convert->fin_x[splane];
5677 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5678 d += convert->fout_x[plane];
5679 ss = FRAME_GET_PLANE_STRIDE (src, splane);
5680 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5682 n_threads = convert->conversion_runner->n_threads;
5683 tasks = g_newa (FSimpleScaleTask, n_threads);
5684 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5685 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5687 for (i = 0; i < n_threads; i++) {
5688 tasks[i].d = d + i * lines_per_thread * ds;
5689 tasks[i].dstride = ds;
5690 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
5691 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
5692 tasks[i].sstride = ss;
5694 tasks[i].width = convert->fout_width[plane];
5695 tasks[i].height = (i + 1) * lines_per_thread;
5696 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5697 tasks[i].height -= i * lines_per_thread;
5699 tasks_p[i] = &tasks[i];
5702 gst_parallelized_task_runner_run (convert->conversion_runner,
5703 (GstParallelizedTaskFunc) convert_plane_hv_halve_task,
5704 (gpointer) tasks_p);
5709 GstVideoScaler *h_scaler, *v_scaler;
5710 GstVideoFormat format;
5713 gint sstride, dstride;
5718 convert_plane_hv_task (FScaleTask * task)
5720 gst_video_scaler_2d (task->h_scaler, task->v_scaler, task->format,
5721 (guint8 *) task->s, task->sstride,
5722 task->d, task->dstride, task->x, task->y, task->w, task->h);
5726 convert_plane_hv (GstVideoConverter * convert,
5727 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5729 gint in_x, in_y, out_x, out_y, out_width, out_height;
5730 GstVideoFormat format;
5731 gint splane = convert->fsplane[plane];
5733 gint sstride, dstride;
5735 FScaleTask **tasks_p;
5736 gint i, n_threads, lines_per_thread;
5738 in_x = convert->fin_x[splane];
5739 in_y = convert->fin_y[splane];
5740 out_x = convert->fout_x[plane];
5741 out_y = convert->fout_y[plane];
5742 out_width = convert->fout_width[plane];
5743 out_height = convert->fout_height[plane];
5744 format = convert->fformat[plane];
5746 s = FRAME_GET_PLANE_LINE (src, splane, in_y);
5748 d = FRAME_GET_PLANE_LINE (dest, plane, out_y);
5751 sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5752 dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5754 n_threads = convert->conversion_runner->n_threads;
5755 tasks = g_newa (FScaleTask, n_threads);
5756 tasks_p = g_newa (FScaleTask *, n_threads);
5758 lines_per_thread = (out_height + n_threads - 1) / n_threads;
5760 for (i = 0; i < n_threads; i++) {
5762 convert->fh_scaler[plane].scaler ? convert->
5763 fh_scaler[plane].scaler[i] : NULL;
5765 convert->fv_scaler[plane].scaler ? convert->
5766 fv_scaler[plane].scaler[i] : NULL;
5767 tasks[i].format = format;
5770 tasks[i].sstride = sstride;
5771 tasks[i].dstride = dstride;
5774 tasks[i].w = out_width;
5776 tasks[i].y = i * lines_per_thread;
5777 tasks[i].h = tasks[i].y + lines_per_thread;
5778 tasks[i].h = MIN (out_height, tasks[i].h);
5780 tasks_p[i] = &tasks[i];
5783 gst_parallelized_task_runner_run (convert->conversion_runner,
5784 (GstParallelizedTaskFunc) convert_plane_hv_task, (gpointer) tasks_p);
5788 convert_scale_planes (GstVideoConverter * convert,
5789 const GstVideoFrame * src, GstVideoFrame * dest)
5793 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
5794 for (i = 0; i < n_planes; i++) {
5795 if (convert->fconvert[i])
5796 convert->fconvert[i] (convert, src, dest, i);
5798 convert_fill_border (convert, dest);
5801 static GstVideoFormat
5802 get_scale_format (GstVideoFormat format, gint plane)
5804 GstVideoFormat res = GST_VIDEO_FORMAT_UNKNOWN;
5807 case GST_VIDEO_FORMAT_I420:
5808 case GST_VIDEO_FORMAT_YV12:
5809 case GST_VIDEO_FORMAT_Y41B:
5810 case GST_VIDEO_FORMAT_Y42B:
5811 case GST_VIDEO_FORMAT_Y444:
5812 case GST_VIDEO_FORMAT_GRAY8:
5813 case GST_VIDEO_FORMAT_A420:
5814 case GST_VIDEO_FORMAT_YUV9:
5815 case GST_VIDEO_FORMAT_YVU9:
5816 case GST_VIDEO_FORMAT_GBR:
5817 case GST_VIDEO_FORMAT_GBRA:
5818 res = GST_VIDEO_FORMAT_GRAY8;
5820 case GST_VIDEO_FORMAT_GRAY16_BE:
5821 case GST_VIDEO_FORMAT_GRAY16_LE:
5822 res = GST_VIDEO_FORMAT_GRAY16_BE;
5824 case GST_VIDEO_FORMAT_YUY2:
5825 case GST_VIDEO_FORMAT_UYVY:
5826 case GST_VIDEO_FORMAT_VYUY:
5827 case GST_VIDEO_FORMAT_YVYU:
5828 case GST_VIDEO_FORMAT_AYUV:
5829 case GST_VIDEO_FORMAT_VUYA:
5830 case GST_VIDEO_FORMAT_RGBx:
5831 case GST_VIDEO_FORMAT_BGRx:
5832 case GST_VIDEO_FORMAT_xRGB:
5833 case GST_VIDEO_FORMAT_xBGR:
5834 case GST_VIDEO_FORMAT_RGBA:
5835 case GST_VIDEO_FORMAT_BGRA:
5836 case GST_VIDEO_FORMAT_ARGB:
5837 case GST_VIDEO_FORMAT_ABGR:
5838 case GST_VIDEO_FORMAT_RGB:
5839 case GST_VIDEO_FORMAT_BGR:
5840 case GST_VIDEO_FORMAT_v308:
5841 case GST_VIDEO_FORMAT_IYU2:
5842 case GST_VIDEO_FORMAT_ARGB64:
5843 case GST_VIDEO_FORMAT_AYUV64:
5846 case GST_VIDEO_FORMAT_RGB15:
5847 case GST_VIDEO_FORMAT_BGR15:
5848 case GST_VIDEO_FORMAT_RGB16:
5849 case GST_VIDEO_FORMAT_BGR16:
5850 res = GST_VIDEO_FORMAT_NV12;
5852 case GST_VIDEO_FORMAT_NV12:
5853 case GST_VIDEO_FORMAT_NV21:
5854 case GST_VIDEO_FORMAT_NV16:
5855 case GST_VIDEO_FORMAT_NV61:
5856 case GST_VIDEO_FORMAT_NV24:
5857 res = plane == 0 ? GST_VIDEO_FORMAT_GRAY8 : GST_VIDEO_FORMAT_NV12;
5859 case GST_VIDEO_FORMAT_UNKNOWN:
5860 case GST_VIDEO_FORMAT_ENCODED:
5861 case GST_VIDEO_FORMAT_v210:
5862 case GST_VIDEO_FORMAT_v216:
5863 case GST_VIDEO_FORMAT_Y210:
5864 case GST_VIDEO_FORMAT_Y410:
5865 case GST_VIDEO_FORMAT_UYVP:
5866 case GST_VIDEO_FORMAT_RGB8P:
5867 case GST_VIDEO_FORMAT_IYU1:
5868 case GST_VIDEO_FORMAT_r210:
5869 case GST_VIDEO_FORMAT_I420_10BE:
5870 case GST_VIDEO_FORMAT_I420_10LE:
5871 case GST_VIDEO_FORMAT_I422_10BE:
5872 case GST_VIDEO_FORMAT_I422_10LE:
5873 case GST_VIDEO_FORMAT_Y444_10BE:
5874 case GST_VIDEO_FORMAT_Y444_10LE:
5875 case GST_VIDEO_FORMAT_I420_12BE:
5876 case GST_VIDEO_FORMAT_I420_12LE:
5877 case GST_VIDEO_FORMAT_I422_12BE:
5878 case GST_VIDEO_FORMAT_I422_12LE:
5879 case GST_VIDEO_FORMAT_Y444_12BE:
5880 case GST_VIDEO_FORMAT_Y444_12LE:
5881 case GST_VIDEO_FORMAT_GBR_10BE:
5882 case GST_VIDEO_FORMAT_GBR_10LE:
5883 case GST_VIDEO_FORMAT_GBRA_10BE:
5884 case GST_VIDEO_FORMAT_GBRA_10LE:
5885 case GST_VIDEO_FORMAT_GBR_12BE:
5886 case GST_VIDEO_FORMAT_GBR_12LE:
5887 case GST_VIDEO_FORMAT_GBRA_12BE:
5888 case GST_VIDEO_FORMAT_GBRA_12LE:
5889 case GST_VIDEO_FORMAT_NV12_64Z32:
5890 case GST_VIDEO_FORMAT_A420_10BE:
5891 case GST_VIDEO_FORMAT_A420_10LE:
5892 case GST_VIDEO_FORMAT_A422_10BE:
5893 case GST_VIDEO_FORMAT_A422_10LE:
5894 case GST_VIDEO_FORMAT_A444_10BE:
5895 case GST_VIDEO_FORMAT_A444_10LE:
5896 case GST_VIDEO_FORMAT_P010_10BE:
5897 case GST_VIDEO_FORMAT_P010_10LE:
5898 case GST_VIDEO_FORMAT_GRAY10_LE32:
5899 case GST_VIDEO_FORMAT_NV12_10LE32:
5900 case GST_VIDEO_FORMAT_NV16_10LE32:
5901 case GST_VIDEO_FORMAT_NV12_10LE40:
5902 case GST_VIDEO_FORMAT_BGR10A2_LE:
5903 case GST_VIDEO_FORMAT_RGB10A2_LE:
5904 case GST_VIDEO_FORMAT_Y444_16BE:
5905 case GST_VIDEO_FORMAT_Y444_16LE:
5907 g_assert_not_reached ();
5914 is_merge_yuv (GstVideoInfo * info)
5916 switch (GST_VIDEO_INFO_FORMAT (info)) {
5917 case GST_VIDEO_FORMAT_YUY2:
5918 case GST_VIDEO_FORMAT_YVYU:
5919 case GST_VIDEO_FORMAT_UYVY:
5920 case GST_VIDEO_FORMAT_VYUY:
5928 setup_scale (GstVideoConverter * convert)
5931 gint method, cr_method, in_width, in_height, out_width, out_height;
5933 GstVideoInfo *in_info, *out_info;
5934 const GstVideoFormatInfo *in_finfo, *out_finfo;
5935 GstVideoFormat in_format, out_format;
5936 guint n_threads = convert->conversion_runner->n_threads;
5938 in_info = &convert->in_info;
5939 out_info = &convert->out_info;
5941 in_finfo = in_info->finfo;
5942 out_finfo = out_info->finfo;
5944 n_planes = GST_VIDEO_INFO_N_PLANES (out_info);
5946 method = GET_OPT_RESAMPLER_METHOD (convert);
5947 if (method == GST_VIDEO_RESAMPLER_METHOD_NEAREST)
5950 cr_method = GET_OPT_CHROMA_RESAMPLER_METHOD (convert);
5951 taps = GET_OPT_RESAMPLER_TAPS (convert);
5953 in_format = GST_VIDEO_INFO_FORMAT (in_info);
5954 out_format = GST_VIDEO_INFO_FORMAT (out_info);
5956 switch (in_format) {
5957 case GST_VIDEO_FORMAT_RGB15:
5958 case GST_VIDEO_FORMAT_RGB16:
5959 case GST_VIDEO_FORMAT_BGR15:
5960 case GST_VIDEO_FORMAT_BGR16:
5961 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5962 case GST_VIDEO_FORMAT_GRAY16_BE:
5964 case GST_VIDEO_FORMAT_GRAY16_LE:
5966 if (method != GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
5967 GST_DEBUG ("%s only with nearest resampling",
5968 gst_video_format_to_string (in_format));
5976 in_width = convert->in_width;
5977 in_height = convert->in_height;
5978 out_width = convert->out_width;
5979 out_height = convert->out_height;
5981 if (n_planes == 1 && !GST_VIDEO_FORMAT_INFO_IS_GRAY (out_finfo)) {
5985 if (is_merge_yuv (in_info)) {
5986 GstVideoScaler *y_scaler, *uv_scaler;
5988 if (in_width != out_width) {
5989 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
5990 for (j = 0; j < n_threads; j++) {
5992 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
5993 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_Y,
5994 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
5995 GST_VIDEO_COMP_Y, out_width), convert->config);
5997 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE,
5998 gst_video_scaler_get_max_taps (y_scaler),
5999 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_U,
6000 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
6001 GST_VIDEO_COMP_U, out_width), convert->config);
6003 convert->fh_scaler[0].scaler[j] =
6004 gst_video_scaler_combine_packed_YUV (y_scaler, uv_scaler,
6005 in_format, out_format);
6007 gst_video_scaler_free (y_scaler);
6008 gst_video_scaler_free (uv_scaler);
6011 convert->fh_scaler[0].scaler = NULL;
6014 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_Y);
6015 convert->fin_x[0] = GST_ROUND_UP_2 (convert->in_x) * pstride;
6016 convert->fout_x[0] = GST_ROUND_UP_2 (convert->out_x) * pstride;
6019 if (in_width != out_width && in_width != 0 && out_width != 0) {
6020 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6021 for (j = 0; j < n_threads; j++) {
6022 convert->fh_scaler[0].scaler[j] =
6023 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6024 in_width, out_width, convert->config);
6027 convert->fh_scaler[0].scaler = NULL;
6030 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_R);
6031 convert->fin_x[0] = convert->in_x * pstride;
6032 convert->fout_x[0] = convert->out_x * pstride;
6035 if (in_height != out_height && in_height != 0 && out_height != 0) {
6036 convert->fv_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6038 for (j = 0; j < n_threads; j++) {
6039 convert->fv_scaler[0].scaler[j] =
6040 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6041 in_height, out_height, convert->config);
6044 convert->fv_scaler[0].scaler = NULL;
6047 convert->fin_y[0] = convert->in_y;
6048 convert->fout_y[0] = convert->out_y;
6049 convert->fout_width[0] = out_width;
6050 convert->fout_height[0] = out_height;
6051 convert->fconvert[0] = convert_plane_hv;
6052 convert->fformat[0] = get_scale_format (in_format, 0);
6053 convert->fsplane[0] = 0;
6055 for (i = 0; i < n_planes; i++) {
6056 gint comp, n_comp, j, iw, ih, ow, oh, pstride;
6057 gboolean need_v_scaler, need_h_scaler;
6058 GstStructure *config;
6059 gint resample_method;
6061 n_comp = GST_VIDEO_FORMAT_INFO_N_COMPONENTS (in_finfo);
6063 /* find the component in this plane and map it to the plane of
6066 for (j = 0; j < n_comp; j++) {
6067 if (GST_VIDEO_FORMAT_INFO_PLANE (out_finfo, j) == i) {
6073 iw = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, i, in_width);
6074 ih = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, i, in_height);
6075 ow = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, i, out_width);
6076 oh = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, i, out_height);
6078 GST_DEBUG ("plane %d: %dx%d -> %dx%d", i, iw, ih, ow, oh);
6080 convert->fout_width[i] = ow;
6081 convert->fout_height[i] = oh;
6083 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, i);
6085 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, i, convert->in_x);
6086 convert->fin_x[i] *= pstride;
6088 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, i, convert->in_y);
6089 convert->fout_x[i] =
6090 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, i, convert->out_x);
6091 convert->fout_x[i] *= pstride;
6092 convert->fout_y[i] =
6093 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, i, convert->out_y);
6095 GST_DEBUG ("plane %d: pstride %d", i, pstride);
6096 GST_DEBUG ("plane %d: in_x %d, in_y %d", i, convert->fin_x[i],
6098 GST_DEBUG ("plane %d: out_x %d, out_y %d", i, convert->fout_x[i],
6099 convert->fout_y[i]);
6102 convert->fconvert[i] = convert_plane_fill;
6103 if (GST_VIDEO_INFO_IS_YUV (out_info)) {
6105 convert->ffill[i] = convert->alpha_value;
6107 convert->ffill[i] = 0x00;
6109 convert->ffill[i] = 0x80;
6112 convert->ffill[i] = convert->alpha_value;
6114 convert->ffill[i] = 0x00;
6116 GST_DEBUG ("plane %d fill %02x", i, convert->ffill[i]);
6119 convert->fsplane[i] = GST_VIDEO_FORMAT_INFO_PLANE (in_finfo, comp);
6120 GST_DEBUG ("plane %d -> %d (comp %d)", i, convert->fsplane[i], comp);
6123 config = gst_structure_copy (convert->config);
6125 resample_method = (i == 0 ? method : cr_method);
6127 need_v_scaler = FALSE;
6128 need_h_scaler = FALSE;
6131 convert->fconvert[i] = convert_plane_hv;
6132 GST_DEBUG ("plane %d: copy", i);
6133 } else if (ih == 2 * oh && pstride == 1
6134 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6135 convert->fconvert[i] = convert_plane_v_halve;
6136 GST_DEBUG ("plane %d: vertical halve", i);
6137 } else if (2 * ih == oh && pstride == 1
6138 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6139 convert->fconvert[i] = convert_plane_v_double;
6140 GST_DEBUG ("plane %d: vertical double", i);
6142 convert->fconvert[i] = convert_plane_hv;
6143 GST_DEBUG ("plane %d: vertical scale", i);
6144 need_v_scaler = TRUE;
6146 } else if (ih == oh) {
6147 if (iw == 2 * ow && pstride == 1
6148 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6149 convert->fconvert[i] = convert_plane_h_halve;
6150 GST_DEBUG ("plane %d: horizontal halve", i);
6151 } else if (2 * iw == ow && pstride == 1
6152 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6153 convert->fconvert[i] = convert_plane_h_double;
6154 GST_DEBUG ("plane %d: horizontal double", i);
6156 convert->fconvert[i] = convert_plane_hv;
6157 GST_DEBUG ("plane %d: horizontal scale", i);
6158 need_h_scaler = TRUE;
6161 if (iw == 2 * ow && ih == 2 * oh && pstride == 1
6162 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6163 convert->fconvert[i] = convert_plane_hv_halve;
6164 GST_DEBUG ("plane %d: horizontal/vertical halve", i);
6165 } else if (2 * iw == ow && 2 * ih == oh && pstride == 1
6166 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6167 convert->fconvert[i] = convert_plane_hv_double;
6168 GST_DEBUG ("plane %d: horizontal/vertical double", i);
6170 convert->fconvert[i] = convert_plane_hv;
6171 GST_DEBUG ("plane %d: horizontal/vertical scale", i);
6172 need_v_scaler = TRUE;
6173 need_h_scaler = TRUE;
6177 if (need_h_scaler && iw != 0 && ow != 0) {
6178 convert->fh_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
6180 for (j = 0; j < n_threads; j++) {
6181 convert->fh_scaler[i].scaler[j] =
6182 gst_video_scaler_new (resample_method, GST_VIDEO_SCALER_FLAG_NONE,
6183 taps, iw, ow, config);
6186 convert->fh_scaler[i].scaler = NULL;
6189 if (need_v_scaler && ih != 0 && oh != 0) {
6190 convert->fv_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
6192 for (j = 0; j < n_threads; j++) {
6193 convert->fv_scaler[i].scaler[j] =
6194 gst_video_scaler_new (resample_method, GST_VIDEO_SCALER_FLAG_NONE,
6195 taps, ih, oh, config);
6198 convert->fv_scaler[i].scaler = NULL;
6201 gst_structure_free (config);
6202 convert->fformat[i] = get_scale_format (in_format, i);
6213 GstVideoFormat in_format;
6214 GstVideoFormat out_format;
6215 gboolean keeps_interlaced;
6216 gboolean needs_color_matrix;
6217 gboolean keeps_size;
6220 gboolean alpha_copy;
6222 gboolean alpha_mult;
6223 gint width_align, height_align;
6224 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
6225 GstVideoFrame * dest);
6228 static const VideoTransform transforms[] = {
6229 /* planar -> packed */
6230 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
6231 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
6232 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
6233 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
6234 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
6235 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
6237 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
6238 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
6239 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
6240 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
6241 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
6242 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
6244 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6245 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_YUY2},
6246 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6247 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_UYVY},
6248 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6249 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_Y42B_AYUV},
6251 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6252 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_YUY2},
6253 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6254 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_UYVY},
6255 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6256 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_Y444_AYUV},
6258 /* packed -> packed */
6259 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, FALSE, TRUE,
6260 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6261 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6262 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2}, /* alias */
6263 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6264 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_YUY2_AYUV},
6266 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, FALSE, TRUE,
6267 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6268 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6269 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2},
6270 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6271 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_UYVY_AYUV},
6273 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, FALSE, TRUE, TRUE,
6274 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6275 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6276 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_YUY2},
6277 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6278 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_UYVY},
6280 /* packed -> planar */
6281 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
6282 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
6283 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
6284 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
6285 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6286 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y42B},
6287 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6288 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y444},
6289 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_GRAY8, TRUE, TRUE, TRUE, TRUE,
6290 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_GRAY8},
6292 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
6293 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
6294 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
6295 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
6296 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6297 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y42B},
6298 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6299 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y444},
6301 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_I420, FALSE, FALSE, TRUE, TRUE,
6302 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
6303 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, TRUE, TRUE,
6304 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
6305 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6306 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_Y42B},
6307 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6308 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_AYUV_Y444},
6310 /* planar -> planar */
6311 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6312 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6313 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6314 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6315 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6316 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6317 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6318 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6319 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6320 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6321 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6322 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6323 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6324 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6325 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6326 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6327 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6328 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6330 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6331 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6332 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6333 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6334 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6335 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6336 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6337 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6338 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6339 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6340 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6341 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6342 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6343 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6344 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6345 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6346 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6347 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6349 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6350 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6351 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6352 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6353 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6354 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6355 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6356 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6357 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6358 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6359 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6360 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6361 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6362 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6363 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6364 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6365 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6366 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6368 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6369 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6370 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6371 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6372 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6373 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6374 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6375 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6376 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6377 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6378 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6379 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6380 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6381 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6382 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6383 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6384 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6385 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6387 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6388 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6389 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6390 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6391 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6392 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6393 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6394 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6395 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6396 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6397 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6398 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6399 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6400 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6401 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6402 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6403 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6404 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6406 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6407 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6408 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6409 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6410 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6411 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6412 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6413 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6414 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6415 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6416 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6417 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6418 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6419 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6420 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6421 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6422 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6423 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6425 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6426 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6427 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6428 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6429 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6430 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6431 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6432 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6433 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6434 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6435 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6436 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6437 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6438 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6439 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6440 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6441 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6442 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6444 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6445 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6446 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6447 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6448 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6449 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6450 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6451 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6452 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6453 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6454 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6455 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6456 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6457 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6458 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6459 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6460 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6461 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6463 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6464 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6465 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6466 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6467 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6468 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6469 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6470 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6471 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6472 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6473 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6474 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6475 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6476 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6477 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6478 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6479 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6480 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6482 /* sempiplanar -> semiplanar */
6483 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
6484 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6485 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
6486 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6487 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
6488 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6490 {GST_VIDEO_FORMAT_NV21, GST_VIDEO_FORMAT_NV21, TRUE, FALSE, FALSE, TRUE,
6491 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6493 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
6494 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6495 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
6496 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6497 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
6498 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6500 {GST_VIDEO_FORMAT_NV61, GST_VIDEO_FORMAT_NV61, TRUE, FALSE, FALSE, TRUE,
6501 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6503 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
6504 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6505 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
6506 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6507 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
6508 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6510 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
6511 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ARGB, TRUE, TRUE, TRUE, TRUE, TRUE,
6512 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB},
6513 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRA, TRUE, TRUE, TRUE, TRUE, TRUE,
6514 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA},
6515 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xRGB, TRUE, TRUE, TRUE, TRUE, TRUE,
6516 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB}, /* alias */
6517 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRx, TRUE, TRUE, TRUE, TRUE, TRUE,
6518 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA}, /* alias */
6519 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ABGR, TRUE, TRUE, TRUE, TRUE, TRUE,
6520 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR},
6521 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBA, TRUE, TRUE, TRUE, TRUE, TRUE,
6522 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA},
6523 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xBGR, TRUE, TRUE, TRUE, TRUE, TRUE,
6524 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR}, /* alias */
6525 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBx, TRUE, TRUE, TRUE, TRUE, TRUE,
6526 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA}, /* alias */
6529 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
6530 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6531 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
6532 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6533 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
6534 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6535 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
6536 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6538 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
6539 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6540 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
6541 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6542 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
6543 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6544 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
6545 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6547 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
6548 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6549 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
6550 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6551 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
6552 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6553 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
6554 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6555 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
6556 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6557 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
6558 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6559 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
6560 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6561 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
6562 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6563 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
6564 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6565 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
6566 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6568 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
6569 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6570 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
6571 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6572 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
6573 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6574 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
6575 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6576 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
6577 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6578 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
6579 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6580 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
6581 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6582 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
6583 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6584 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
6585 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6586 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
6587 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6590 {GST_VIDEO_FORMAT_GBR, GST_VIDEO_FORMAT_GBR, TRUE, FALSE, FALSE, TRUE,
6591 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6593 {GST_VIDEO_FORMAT_YVYU, GST_VIDEO_FORMAT_YVYU, TRUE, FALSE, FALSE, TRUE,
6594 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6596 {GST_VIDEO_FORMAT_RGB15, GST_VIDEO_FORMAT_RGB15, TRUE, FALSE, FALSE, TRUE,
6597 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6598 {GST_VIDEO_FORMAT_RGB16, GST_VIDEO_FORMAT_RGB16, TRUE, FALSE, FALSE, TRUE,
6599 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6600 {GST_VIDEO_FORMAT_BGR15, GST_VIDEO_FORMAT_BGR15, TRUE, FALSE, FALSE, TRUE,
6601 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6602 {GST_VIDEO_FORMAT_BGR16, GST_VIDEO_FORMAT_BGR16, TRUE, FALSE, FALSE, TRUE,
6603 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6605 {GST_VIDEO_FORMAT_RGB, GST_VIDEO_FORMAT_RGB, TRUE, FALSE, FALSE, TRUE, TRUE,
6606 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6607 {GST_VIDEO_FORMAT_BGR, GST_VIDEO_FORMAT_BGR, TRUE, FALSE, FALSE, TRUE, TRUE,
6608 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6609 {GST_VIDEO_FORMAT_v308, GST_VIDEO_FORMAT_v308, TRUE, FALSE, FALSE, TRUE, TRUE,
6610 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6611 {GST_VIDEO_FORMAT_IYU2, GST_VIDEO_FORMAT_IYU2, TRUE, FALSE, FALSE, TRUE, TRUE,
6612 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6614 {GST_VIDEO_FORMAT_ARGB, GST_VIDEO_FORMAT_ARGB, TRUE, FALSE, FALSE, TRUE, TRUE,
6615 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6616 {GST_VIDEO_FORMAT_xRGB, GST_VIDEO_FORMAT_xRGB, TRUE, FALSE, FALSE, TRUE, TRUE,
6617 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6618 {GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_ABGR, TRUE, FALSE, FALSE, TRUE, TRUE,
6619 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6620 {GST_VIDEO_FORMAT_xBGR, GST_VIDEO_FORMAT_xBGR, TRUE, FALSE, FALSE, TRUE, TRUE,
6621 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6622 {GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_RGBA, TRUE, FALSE, FALSE, TRUE, TRUE,
6623 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6624 {GST_VIDEO_FORMAT_RGBx, GST_VIDEO_FORMAT_RGBx, TRUE, FALSE, FALSE, TRUE, TRUE,
6625 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6626 {GST_VIDEO_FORMAT_BGRA, GST_VIDEO_FORMAT_BGRA, TRUE, FALSE, FALSE, TRUE, TRUE,
6627 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6628 {GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_BGRx, TRUE, FALSE, FALSE, TRUE, TRUE,
6629 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6631 {GST_VIDEO_FORMAT_ARGB64, GST_VIDEO_FORMAT_ARGB64, TRUE, FALSE, FALSE, TRUE,
6632 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6633 {GST_VIDEO_FORMAT_AYUV64, GST_VIDEO_FORMAT_AYUV64, TRUE, FALSE, FALSE, TRUE,
6634 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6636 {GST_VIDEO_FORMAT_GRAY16_LE, GST_VIDEO_FORMAT_GRAY16_LE, TRUE, FALSE, FALSE,
6637 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6638 {GST_VIDEO_FORMAT_GRAY16_BE, GST_VIDEO_FORMAT_GRAY16_BE, TRUE, FALSE, FALSE,
6639 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6643 video_converter_lookup_fastpath (GstVideoConverter * convert)
6646 GstVideoFormat in_format, out_format;
6647 GstVideoTransferFunction in_transf, out_transf;
6648 gboolean interlaced, same_matrix, same_primaries, same_size, crop, border;
6649 gboolean need_copy, need_set, need_mult;
6652 width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
6653 height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);
6655 if (GET_OPT_DITHER_QUANTIZATION (convert) != 1)
6658 /* we don't do gamma conversion in fastpath */
6659 in_transf = convert->in_info.colorimetry.transfer;
6660 out_transf = convert->out_info.colorimetry.transfer;
6662 same_size = (width == convert->out_width && height == convert->out_height);
6664 /* fastpaths don't do gamma */
6665 if (CHECK_GAMMA_REMAP (convert) && (!same_size || in_transf != out_transf))
6668 need_copy = (convert->alpha_mode & ALPHA_MODE_COPY) == ALPHA_MODE_COPY;
6669 need_set = (convert->alpha_mode & ALPHA_MODE_SET) == ALPHA_MODE_SET;
6670 need_mult = (convert->alpha_mode & ALPHA_MODE_MULT) == ALPHA_MODE_MULT;
6671 GST_DEBUG ("alpha copy %d, set %d, mult %d", need_copy, need_set, need_mult);
6673 in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
6674 out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
6676 if (CHECK_MATRIX_NONE (convert)) {
6679 GstVideoColorMatrix in_matrix, out_matrix;
6681 in_matrix = convert->in_info.colorimetry.matrix;
6682 out_matrix = convert->out_info.colorimetry.matrix;
6683 same_matrix = in_matrix == out_matrix;
6686 if (CHECK_PRIMARIES_NONE (convert)) {
6687 same_primaries = TRUE;
6689 GstVideoColorPrimaries in_primaries, out_primaries;
6691 in_primaries = convert->in_info.colorimetry.primaries;
6692 out_primaries = convert->out_info.colorimetry.primaries;
6693 same_primaries = in_primaries == out_primaries;
6696 interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info);
6697 interlaced |= GST_VIDEO_INFO_IS_INTERLACED (&convert->out_info);
6699 crop = convert->in_x || convert->in_y
6700 || convert->in_width < convert->in_maxwidth
6701 || convert->in_height < convert->in_maxheight;
6702 border = convert->out_x || convert->out_y
6703 || convert->out_width < convert->out_maxwidth
6704 || convert->out_height < convert->out_maxheight;
6706 for (i = 0; i < sizeof (transforms) / sizeof (transforms[0]); i++) {
6707 if (transforms[i].in_format == in_format &&
6708 transforms[i].out_format == out_format &&
6709 (transforms[i].keeps_interlaced || !interlaced) &&
6710 (transforms[i].needs_color_matrix || (same_matrix && same_primaries))
6711 && (!transforms[i].keeps_size || same_size)
6712 && (transforms[i].width_align & width) == 0
6713 && (transforms[i].height_align & height) == 0
6714 && (transforms[i].do_crop || !crop)
6715 && (transforms[i].do_border || !border)
6716 && (transforms[i].alpha_copy || !need_copy)
6717 && (transforms[i].alpha_set || !need_set)
6718 && (transforms[i].alpha_mult || !need_mult)) {
6721 GST_DEBUG ("using fastpath");
6722 if (transforms[i].needs_color_matrix)
6723 video_converter_compute_matrix (convert);
6724 convert->convert = transforms[i].convert;
6727 g_new (guint16 *, convert->conversion_runner->n_threads);
6728 for (j = 0; j < convert->conversion_runner->n_threads; j++)
6729 convert->tmpline[j] = g_malloc0 (sizeof (guint16) * (width + 8) * 4);
6731 if (!transforms[i].keeps_size)
6732 if (!setup_scale (convert))
6735 setup_borderline (convert);
6739 GST_DEBUG ("no fastpath found");