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 /* We may be able to skip ahead to the earliest line needed */
616 if (cache->lines->len == 0 && cache->first + cache->backlog < in_line)
617 cache->first = in_line - cache->backlog;
619 oline = out_line + cache->first + cache->lines->len - in_line;
621 if (!cache->need_line (cache, idx, oline, cache->first + cache->lines->len,
622 cache->need_line_data))
625 GST_DEBUG ("no lines");
630 gst_line_cache_add_line (GstLineCache * cache, gint idx, gpointer line)
632 if (cache->first + cache->lines->len != idx) {
633 gst_line_cache_clear (cache);
636 g_ptr_array_add (cache->lines, line);
640 gst_line_cache_alloc_line (GstLineCache * cache, gint idx)
644 if (cache->alloc_line)
645 res = cache->alloc_line (cache, idx, cache->alloc_line_data);
652 static void video_converter_generic (GstVideoConverter * convert,
653 const GstVideoFrame * src, GstVideoFrame * dest);
654 static gboolean video_converter_lookup_fastpath (GstVideoConverter * convert);
655 static void video_converter_compute_matrix (GstVideoConverter * convert);
656 static void video_converter_compute_resample (GstVideoConverter * convert,
659 static gpointer get_dest_line (GstLineCache * cache, gint idx,
662 static gboolean do_unpack_lines (GstLineCache * cache, gint idx, gint out_line,
663 gint in_line, gpointer user_data);
664 static gboolean do_downsample_lines (GstLineCache * cache, gint idx,
665 gint out_line, gint in_line, gpointer user_data);
666 static gboolean do_convert_to_RGB_lines (GstLineCache * cache, gint idx,
667 gint out_line, gint in_line, gpointer user_data);
668 static gboolean do_convert_lines (GstLineCache * cache, gint idx, gint out_line,
669 gint in_line, gpointer user_data);
670 static gboolean do_alpha_lines (GstLineCache * cache, gint idx, gint out_line,
671 gint in_line, gpointer user_data);
672 static gboolean do_convert_to_YUV_lines (GstLineCache * cache, gint idx,
673 gint out_line, gint in_line, gpointer user_data);
674 static gboolean do_upsample_lines (GstLineCache * cache, gint idx,
675 gint out_line, gint in_line, gpointer user_data);
676 static gboolean do_vscale_lines (GstLineCache * cache, gint idx, gint out_line,
677 gint in_line, gpointer user_data);
678 static gboolean do_hscale_lines (GstLineCache * cache, gint idx, gint out_line,
679 gint in_line, gpointer user_data);
680 static gboolean do_dither_lines (GstLineCache * cache, gint idx, gint out_line,
681 gint in_line, gpointer user_data);
683 static ConverterAlloc *
684 converter_alloc_new (guint stride, guint n_lines, gpointer user_data,
685 GDestroyNotify notify)
687 ConverterAlloc *alloc;
689 GST_DEBUG ("stride %d, n_lines %d", stride, n_lines);
690 alloc = g_slice_new0 (ConverterAlloc);
691 alloc->data = g_malloc (stride * n_lines);
692 alloc->stride = stride;
693 alloc->n_lines = n_lines;
695 alloc->user_data = user_data;
696 alloc->notify = notify;
702 converter_alloc_free (ConverterAlloc * alloc)
705 alloc->notify (alloc->user_data);
706 g_free (alloc->data);
707 g_slice_free (ConverterAlloc, alloc);
711 setup_border_alloc (GstVideoConverter * convert, ConverterAlloc * alloc)
715 if (convert->borderline) {
716 for (i = 0; i < alloc->n_lines; i++)
717 memcpy (&alloc->data[i * alloc->stride], convert->borderline,
723 get_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
725 ConverterAlloc *alloc = user_data;
728 GST_DEBUG ("get temp line %d (%p %d)", idx, alloc, alloc->idx);
729 tmpline = &alloc->data[alloc->stride * alloc->idx];
730 alloc->idx = (alloc->idx + 1) % alloc->n_lines;
736 get_border_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
738 ConverterAlloc *alloc = user_data;
739 GstVideoConverter *convert = alloc->user_data;
742 GST_DEBUG ("get temp line %d (%p %d)", idx, alloc, alloc->idx);
743 tmpline = &alloc->data[alloc->stride * alloc->idx] +
744 (convert->out_x * convert->pack_pstride);
745 alloc->idx = (alloc->idx + 1) % alloc->n_lines;
751 get_opt_int (GstVideoConverter * convert, const gchar * opt, gint def)
754 if (!gst_structure_get_int (convert->config, opt, &res))
760 get_opt_uint (GstVideoConverter * convert, const gchar * opt, guint def)
763 if (!gst_structure_get_uint (convert->config, opt, &res))
769 get_opt_double (GstVideoConverter * convert, const gchar * opt, gdouble def)
772 if (!gst_structure_get_double (convert->config, opt, &res))
778 get_opt_bool (GstVideoConverter * convert, const gchar * opt, gboolean def)
781 if (!gst_structure_get_boolean (convert->config, opt, &res))
787 get_opt_enum (GstVideoConverter * convert, const gchar * opt, GType type,
791 if (!gst_structure_get_enum (convert->config, opt, type, &res))
796 #define DEFAULT_OPT_FILL_BORDER TRUE
797 #define DEFAULT_OPT_ALPHA_VALUE 1.0
798 /* options copy, set, mult */
799 #define DEFAULT_OPT_ALPHA_MODE GST_VIDEO_ALPHA_MODE_COPY
800 #define DEFAULT_OPT_BORDER_ARGB 0xff000000
801 /* options full, input-only, output-only, none */
802 #define DEFAULT_OPT_MATRIX_MODE GST_VIDEO_MATRIX_MODE_FULL
804 #define DEFAULT_OPT_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
805 /* none, merge-only, fast */
806 #define DEFAULT_OPT_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
807 /* options full, upsample-only, downsample-only, none */
808 #define DEFAULT_OPT_CHROMA_MODE GST_VIDEO_CHROMA_MODE_FULL
809 #define DEFAULT_OPT_RESAMPLER_METHOD GST_VIDEO_RESAMPLER_METHOD_CUBIC
810 #define DEFAULT_OPT_CHROMA_RESAMPLER_METHOD GST_VIDEO_RESAMPLER_METHOD_LINEAR
811 #define DEFAULT_OPT_RESAMPLER_TAPS 0
812 #define DEFAULT_OPT_DITHER_METHOD GST_VIDEO_DITHER_BAYER
813 #define DEFAULT_OPT_DITHER_QUANTIZATION 1
815 #define GET_OPT_FILL_BORDER(c) get_opt_bool(c, \
816 GST_VIDEO_CONVERTER_OPT_FILL_BORDER, DEFAULT_OPT_FILL_BORDER)
817 #define GET_OPT_ALPHA_VALUE(c) get_opt_double(c, \
818 GST_VIDEO_CONVERTER_OPT_ALPHA_VALUE, DEFAULT_OPT_ALPHA_VALUE)
819 #define GET_OPT_ALPHA_MODE(c) get_opt_enum(c, \
820 GST_VIDEO_CONVERTER_OPT_ALPHA_MODE, GST_TYPE_VIDEO_ALPHA_MODE, DEFAULT_OPT_ALPHA_MODE)
821 #define GET_OPT_BORDER_ARGB(c) get_opt_uint(c, \
822 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB)
823 #define GET_OPT_MATRIX_MODE(c) get_opt_enum(c, \
824 GST_VIDEO_CONVERTER_OPT_MATRIX_MODE, GST_TYPE_VIDEO_MATRIX_MODE, DEFAULT_OPT_MATRIX_MODE)
825 #define GET_OPT_GAMMA_MODE(c) get_opt_enum(c, \
826 GST_VIDEO_CONVERTER_OPT_GAMMA_MODE, GST_TYPE_VIDEO_GAMMA_MODE, DEFAULT_OPT_GAMMA_MODE)
827 #define GET_OPT_PRIMARIES_MODE(c) get_opt_enum(c, \
828 GST_VIDEO_CONVERTER_OPT_PRIMARIES_MODE, GST_TYPE_VIDEO_PRIMARIES_MODE, DEFAULT_OPT_PRIMARIES_MODE)
829 #define GET_OPT_CHROMA_MODE(c) get_opt_enum(c, \
830 GST_VIDEO_CONVERTER_OPT_CHROMA_MODE, GST_TYPE_VIDEO_CHROMA_MODE, DEFAULT_OPT_CHROMA_MODE)
831 #define GET_OPT_RESAMPLER_METHOD(c) get_opt_enum(c, \
832 GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD, GST_TYPE_VIDEO_RESAMPLER_METHOD, \
833 DEFAULT_OPT_RESAMPLER_METHOD)
834 #define GET_OPT_CHROMA_RESAMPLER_METHOD(c) get_opt_enum(c, \
835 GST_VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD, GST_TYPE_VIDEO_RESAMPLER_METHOD, \
836 DEFAULT_OPT_CHROMA_RESAMPLER_METHOD)
837 #define GET_OPT_RESAMPLER_TAPS(c) get_opt_uint(c, \
838 GST_VIDEO_CONVERTER_OPT_RESAMPLER_TAPS, DEFAULT_OPT_RESAMPLER_TAPS)
839 #define GET_OPT_DITHER_METHOD(c) get_opt_enum(c, \
840 GST_VIDEO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_VIDEO_DITHER_METHOD, \
841 DEFAULT_OPT_DITHER_METHOD)
842 #define GET_OPT_DITHER_QUANTIZATION(c) get_opt_uint(c, \
843 GST_VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, DEFAULT_OPT_DITHER_QUANTIZATION)
845 #define CHECK_ALPHA_COPY(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_COPY)
846 #define CHECK_ALPHA_SET(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_SET)
847 #define CHECK_ALPHA_MULT(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_MULT)
849 #define CHECK_MATRIX_FULL(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_FULL)
850 #define CHECK_MATRIX_INPUT(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_INPUT_ONLY)
851 #define CHECK_MATRIX_OUTPUT(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_OUTPUT_ONLY)
852 #define CHECK_MATRIX_NONE(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_NONE)
854 #define CHECK_GAMMA_NONE(c) (GET_OPT_GAMMA_MODE(c) == GST_VIDEO_GAMMA_MODE_NONE)
855 #define CHECK_GAMMA_REMAP(c) (GET_OPT_GAMMA_MODE(c) == GST_VIDEO_GAMMA_MODE_REMAP)
857 #define CHECK_PRIMARIES_NONE(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_NONE)
858 #define CHECK_PRIMARIES_MERGE(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_MERGE_ONLY)
859 #define CHECK_PRIMARIES_FAST(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_FAST)
861 #define CHECK_CHROMA_FULL(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_FULL)
862 #define CHECK_CHROMA_UPSAMPLE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_UPSAMPLE_ONLY)
863 #define CHECK_CHROMA_DOWNSAMPLE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_DOWNSAMPLE_ONLY)
864 #define CHECK_CHROMA_NONE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_NONE)
866 static GstLineCache *
867 chain_unpack_line (GstVideoConverter * convert, gint idx)
872 info = &convert->in_info;
874 convert->current_format = convert->unpack_format;
875 convert->current_bits = convert->unpack_bits;
876 convert->current_pstride = convert->current_bits >> 1;
878 convert->unpack_pstride = convert->current_pstride;
879 convert->identity_unpack = (convert->current_format == info->finfo->format);
881 GST_DEBUG ("chain unpack line format %s, pstride %d, identity_unpack %d",
882 gst_video_format_to_string (convert->current_format),
883 convert->current_pstride, convert->identity_unpack);
885 prev = convert->unpack_lines[idx] = gst_line_cache_new (NULL);
886 prev->write_input = FALSE;
887 prev->pass_alloc = FALSE;
889 prev->stride = convert->current_pstride * convert->current_width;
890 gst_line_cache_set_need_line_func (prev, do_unpack_lines, idx, convert, NULL);
895 static GstLineCache *
896 chain_upsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
898 video_converter_compute_resample (convert, idx);
900 if (convert->upsample_p[idx] || convert->upsample_i[idx]) {
901 GST_DEBUG ("chain upsample");
902 prev = convert->upsample_lines[idx] = gst_line_cache_new (prev);
903 prev->write_input = TRUE;
904 prev->pass_alloc = TRUE;
906 prev->stride = convert->current_pstride * convert->current_width;
907 gst_line_cache_set_need_line_func (prev,
908 do_upsample_lines, idx, convert, NULL);
914 color_matrix_set_identity (MatrixData * m)
918 for (i = 0; i < 4; i++) {
919 for (j = 0; j < 4; j++) {
920 m->dm[i][j] = (i == j);
926 color_matrix_copy (MatrixData * d, const MatrixData * s)
930 for (i = 0; i < 4; i++)
931 for (j = 0; j < 4; j++)
932 d->dm[i][j] = s->dm[i][j];
935 /* Perform 4x4 matrix multiplication:
936 * - @dst@ = @a@ * @b@
937 * - @dst@ may be a pointer to @a@ andor @b@
940 color_matrix_multiply (MatrixData * dst, MatrixData * a, MatrixData * b)
945 for (i = 0; i < 4; i++) {
946 for (j = 0; j < 4; j++) {
948 for (k = 0; k < 4; k++) {
949 x += a->dm[i][k] * b->dm[k][j];
954 color_matrix_copy (dst, &tmp);
958 color_matrix_invert (MatrixData * d, MatrixData * s)
964 color_matrix_set_identity (&tmp);
965 for (j = 0; j < 3; j++) {
966 for (i = 0; i < 3; i++) {
968 s->dm[(i + 1) % 3][(j + 1) % 3] * s->dm[(i + 2) % 3][(j + 2) % 3] -
969 s->dm[(i + 1) % 3][(j + 2) % 3] * s->dm[(i + 2) % 3][(j + 1) % 3];
973 tmp.dm[0][0] * s->dm[0][0] + tmp.dm[0][1] * s->dm[1][0] +
974 tmp.dm[0][2] * s->dm[2][0];
975 for (j = 0; j < 3; j++) {
976 for (i = 0; i < 3; i++) {
980 color_matrix_copy (d, &tmp);
984 color_matrix_offset_components (MatrixData * m, double a1, double a2, double a3)
988 color_matrix_set_identity (&a);
992 color_matrix_multiply (m, &a, m);
996 color_matrix_scale_components (MatrixData * m, double a1, double a2, double a3)
1000 color_matrix_set_identity (&a);
1004 color_matrix_multiply (m, &a, m);
1008 color_matrix_debug (const MatrixData * s)
1010 GST_DEBUG ("[%f %f %f %f]", s->dm[0][0], s->dm[0][1], s->dm[0][2],
1012 GST_DEBUG ("[%f %f %f %f]", s->dm[1][0], s->dm[1][1], s->dm[1][2],
1014 GST_DEBUG ("[%f %f %f %f]", s->dm[2][0], s->dm[2][1], s->dm[2][2],
1016 GST_DEBUG ("[%f %f %f %f]", s->dm[3][0], s->dm[3][1], s->dm[3][2],
1021 color_matrix_convert (MatrixData * s)
1025 for (i = 0; i < 4; i++)
1026 for (j = 0; j < 4; j++)
1027 s->im[i][j] = rint (s->dm[i][j]);
1029 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[0][0], s->im[0][1], s->im[0][2],
1031 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[1][0], s->im[1][1], s->im[1][2],
1033 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[2][0], s->im[2][1], s->im[2][2],
1035 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[3][0], s->im[3][1], s->im[3][2],
1040 color_matrix_YCbCr_to_RGB (MatrixData * m, double Kr, double Kb)
1042 double Kg = 1.0 - Kr - Kb;
1045 {1., 0., 2 * (1 - Kr), 0.},
1046 {1., -2 * Kb * (1 - Kb) / Kg, -2 * Kr * (1 - Kr) / Kg, 0.},
1047 {1., 2 * (1 - Kb), 0., 0.},
1052 color_matrix_multiply (m, &k, m);
1056 color_matrix_RGB_to_YCbCr (MatrixData * m, double Kr, double Kb)
1058 double Kg = 1.0 - Kr - Kb;
1067 x = 1 / (2 * (1 - Kb));
1068 k.dm[1][0] = -x * Kr;
1069 k.dm[1][1] = -x * Kg;
1070 k.dm[1][2] = x * (1 - Kb);
1073 x = 1 / (2 * (1 - Kr));
1074 k.dm[2][0] = x * (1 - Kr);
1075 k.dm[2][1] = -x * Kg;
1076 k.dm[2][2] = -x * Kb;
1084 color_matrix_multiply (m, &k, m);
1088 color_matrix_RGB_to_XYZ (MatrixData * dst, double Rx, double Ry, double Gx,
1089 double Gy, double Bx, double By, double Wx, double Wy)
1095 color_matrix_set_identity (&m);
1099 m.dm[2][0] = (1.0 - Rx - Ry);
1102 m.dm[2][1] = (1.0 - Gx - Gy);
1105 m.dm[2][2] = (1.0 - Bx - By);
1107 color_matrix_invert (&im, &m);
1111 wz = (1.0 - Wx - Wy) / Wy;
1113 sx = im.dm[0][0] * wx + im.dm[0][1] * wy + im.dm[0][2] * wz;
1114 sy = im.dm[1][0] * wx + im.dm[1][1] * wy + im.dm[1][2] * wz;
1115 sz = im.dm[2][0] * wx + im.dm[2][1] * wy + im.dm[2][2] * wz;
1127 color_matrix_copy (dst, &m);
1131 videoconvert_convert_init_tables (MatrixData * data)
1135 data->t_r = g_new (gint64, 256);
1136 data->t_g = g_new (gint64, 256);
1137 data->t_b = g_new (gint64, 256);
1139 for (i = 0; i < 256; i++) {
1140 gint64 r = 0, g = 0, b = 0;
1142 for (j = 0; j < 3; j++) {
1143 r = (r << 16) + data->im[j][0] * i;
1144 g = (g << 16) + data->im[j][1] * i;
1145 b = (b << 16) + data->im[j][2] * i;
1151 data->t_c = ((gint64) data->im[0][3] << 32)
1152 + ((gint64) data->im[1][3] << 16)
1153 + ((gint64) data->im[2][3] << 0);
1157 _custom_video_orc_matrix8 (guint8 * ORC_RESTRICT d1,
1158 const guint8 * ORC_RESTRICT s1, orc_int64 p1, orc_int64 p2, orc_int64 p3,
1159 orc_int64 p4, int n)
1164 gint a00, a01, a02, a03;
1165 gint a10, a11, a12, a13;
1166 gint a20, a21, a22, a23;
1168 a00 = (gint16) (p1 >> 16);
1169 a01 = (gint16) (p2 >> 16);
1170 a02 = (gint16) (p3 >> 16);
1171 a03 = (gint16) (p4 >> 16);
1172 a10 = (gint16) (p1 >> 32);
1173 a11 = (gint16) (p2 >> 32);
1174 a12 = (gint16) (p3 >> 32);
1175 a13 = (gint16) (p4 >> 32);
1176 a20 = (gint16) (p1 >> 48);
1177 a21 = (gint16) (p2 >> 48);
1178 a22 = (gint16) (p3 >> 48);
1179 a23 = (gint16) (p4 >> 48);
1181 for (i = 0; i < n; i++) {
1186 y = ((a00 * r + a01 * g + a02 * b) >> SCALE) + a03;
1187 u = ((a10 * r + a11 * g + a12 * b) >> SCALE) + a13;
1188 v = ((a20 * r + a21 * g + a22 * b) >> SCALE) + a23;
1190 d1[i * 4 + 1] = CLAMP (y, 0, 255);
1191 d1[i * 4 + 2] = CLAMP (u, 0, 255);
1192 d1[i * 4 + 3] = CLAMP (v, 0, 255);
1197 video_converter_matrix8 (MatrixData * data, gpointer pixels)
1199 gpointer d = pixels;
1200 video_orc_matrix8 (d, pixels, data->orc_p1, data->orc_p2,
1201 data->orc_p3, data->orc_p4, data->width);
1205 video_converter_matrix8_table (MatrixData * data, gpointer pixels)
1207 gint i, width = data->width * 4;
1209 gint64 c = data->t_c;
1213 for (i = 0; i < width; i += 4) {
1218 x = data->t_r[r] + data->t_g[g] + data->t_b[b] + c;
1220 p[i + 1] = x >> (32 + SCALE);
1221 p[i + 2] = x >> (16 + SCALE);
1222 p[i + 3] = x >> (0 + SCALE);
1227 video_converter_matrix8_AYUV_ARGB (MatrixData * data, gpointer pixels)
1229 gpointer d = pixels;
1231 video_orc_convert_AYUV_ARGB (d, 0, pixels, 0,
1232 data->im[0][0], data->im[0][2],
1233 data->im[2][1], data->im[1][1], data->im[1][2], data->width, 1);
1237 is_ayuv_to_rgb_matrix (MatrixData * data)
1239 if (data->im[0][0] != data->im[1][0] || data->im[1][0] != data->im[2][0])
1242 if (data->im[0][1] != 0 || data->im[2][2] != 0)
1249 is_identity_matrix (MatrixData * data)
1252 gint c = data->im[0][0];
1254 /* not really checking identity because of rounding errors but given
1255 * the conversions we do we just check for anything that looks like:
1262 for (i = 0; i < 4; i++) {
1263 for (j = 0; j < 4; j++) {
1265 if (i == 3 && data->im[i][j] != 1)
1267 else if (data->im[i][j] != c)
1269 } else if (data->im[i][j] != 0)
1277 is_no_clip_matrix (MatrixData * data)
1280 static const guint8 test[8][3] = {
1291 for (i = 0; i < 8; i++) {
1299 y = (data->im[0][0] * r + data->im[0][1] * g +
1300 data->im[0][2] * b + data->im[0][3]) >> SCALE;
1301 u = (data->im[1][0] * r + data->im[1][1] * g +
1302 data->im[1][2] * b + data->im[1][3]) >> SCALE;
1303 v = (data->im[2][0] * r + data->im[2][1] * g +
1304 data->im[2][2] * b + data->im[2][3]) >> SCALE;
1306 if (y != CLAMP (y, 0, 255) || u != CLAMP (u, 0, 255)
1307 || v != CLAMP (v, 0, 255))
1314 video_converter_matrix16 (MatrixData * data, gpointer pixels)
1319 guint16 *p = pixels;
1320 gint width = data->width;
1322 for (i = 0; i < width; i++) {
1327 y = (data->im[0][0] * r + data->im[0][1] * g +
1328 data->im[0][2] * b + data->im[0][3]) >> SCALE;
1329 u = (data->im[1][0] * r + data->im[1][1] * g +
1330 data->im[1][2] * b + data->im[1][3]) >> SCALE;
1331 v = (data->im[2][0] * r + data->im[2][1] * g +
1332 data->im[2][2] * b + data->im[2][3]) >> SCALE;
1334 p[i * 4 + 1] = CLAMP (y, 0, 65535);
1335 p[i * 4 + 2] = CLAMP (u, 0, 65535);
1336 p[i * 4 + 3] = CLAMP (v, 0, 65535);
1342 prepare_matrix (GstVideoConverter * convert, MatrixData * data)
1344 if (is_identity_matrix (data))
1347 color_matrix_scale_components (data, SCALE_F, SCALE_F, SCALE_F);
1348 color_matrix_convert (data);
1350 data->width = convert->current_width;
1352 if (convert->current_bits == 8) {
1353 if (!convert->unpack_rgb && convert->pack_rgb
1354 && is_ayuv_to_rgb_matrix (data)) {
1355 GST_DEBUG ("use fast AYUV -> RGB matrix");
1356 data->matrix_func = video_converter_matrix8_AYUV_ARGB;
1357 } else if (is_no_clip_matrix (data)) {
1358 GST_DEBUG ("use 8bit table");
1359 data->matrix_func = video_converter_matrix8_table;
1360 videoconvert_convert_init_tables (data);
1364 GST_DEBUG ("use 8bit matrix");
1365 data->matrix_func = video_converter_matrix8;
1367 data->orc_p1 = (((guint64) (guint16) data->im[2][0]) << 48) |
1368 (((guint64) (guint16) data->im[1][0]) << 32) |
1369 (((guint64) (guint16) data->im[0][0]) << 16);
1370 data->orc_p2 = (((guint64) (guint16) data->im[2][1]) << 48) |
1371 (((guint64) (guint16) data->im[1][1]) << 32) |
1372 (((guint64) (guint16) data->im[0][1]) << 16);
1373 data->orc_p3 = (((guint64) (guint16) data->im[2][2]) << 48) |
1374 (((guint64) (guint16) data->im[1][2]) << 32) |
1375 (((guint64) (guint16) data->im[0][2]) << 16);
1377 a03 = data->im[0][3] >> SCALE;
1378 a13 = data->im[1][3] >> SCALE;
1379 a23 = data->im[2][3] >> SCALE;
1381 data->orc_p4 = (((guint64) (guint16) a23) << 48) |
1382 (((guint64) (guint16) a13) << 32) | (((guint64) (guint16) a03) << 16);
1385 GST_DEBUG ("use 16bit matrix");
1386 data->matrix_func = video_converter_matrix16;
1391 compute_matrix_to_RGB (GstVideoConverter * convert, MatrixData * data)
1394 gdouble Kr = 0, Kb = 0;
1396 info = &convert->in_info;
1399 const GstVideoFormatInfo *uinfo;
1400 gint offset[4], scale[4];
1402 uinfo = gst_video_format_get_info (convert->unpack_format);
1404 /* bring color components to [0..1.0] range */
1405 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1408 color_matrix_offset_components (data, -offset[0], -offset[1], -offset[2]);
1409 color_matrix_scale_components (data, 1 / ((float) scale[0]),
1410 1 / ((float) scale[1]), 1 / ((float) scale[2]));
1413 if (!convert->unpack_rgb && !CHECK_MATRIX_NONE (convert)) {
1414 if (CHECK_MATRIX_OUTPUT (convert))
1415 info = &convert->out_info;
1417 /* bring components to R'G'B' space */
1418 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
1419 color_matrix_YCbCr_to_RGB (data, Kr, Kb);
1421 color_matrix_debug (data);
1425 compute_matrix_to_YUV (GstVideoConverter * convert, MatrixData * data,
1429 gdouble Kr = 0, Kb = 0;
1431 if (force || (!convert->pack_rgb && !CHECK_MATRIX_NONE (convert))) {
1432 if (CHECK_MATRIX_INPUT (convert))
1433 info = &convert->in_info;
1435 info = &convert->out_info;
1437 /* bring components to YCbCr space */
1438 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
1439 color_matrix_RGB_to_YCbCr (data, Kr, Kb);
1442 info = &convert->out_info;
1445 const GstVideoFormatInfo *uinfo;
1446 gint offset[4], scale[4];
1448 uinfo = gst_video_format_get_info (convert->pack_format);
1450 /* bring color components to nominal range */
1451 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1454 color_matrix_scale_components (data, (float) scale[0], (float) scale[1],
1456 color_matrix_offset_components (data, offset[0], offset[1], offset[2]);
1459 color_matrix_debug (data);
1464 gamma_convert_u8_u16 (GammaData * data, gpointer dest, gpointer src)
1469 guint16 *table = data->gamma_table;
1470 gint width = data->width * 4;
1472 for (i = 0; i < width; i += 4) {
1473 d[i + 0] = (s[i] << 8) | s[i];
1474 d[i + 1] = table[s[i + 1]];
1475 d[i + 2] = table[s[i + 2]];
1476 d[i + 3] = table[s[i + 3]];
1481 gamma_convert_u16_u8 (GammaData * data, gpointer dest, gpointer src)
1486 guint8 *table = data->gamma_table;
1487 gint width = data->width * 4;
1489 for (i = 0; i < width; i += 4) {
1490 d[i + 0] = s[i] >> 8;
1491 d[i + 1] = table[s[i + 1]];
1492 d[i + 2] = table[s[i + 2]];
1493 d[i + 3] = table[s[i + 3]];
1498 gamma_convert_u16_u16 (GammaData * data, gpointer dest, gpointer src)
1503 guint16 *table = data->gamma_table;
1504 gint width = data->width * 4;
1506 for (i = 0; i < width; i += 4) {
1508 d[i + 1] = table[s[i + 1]];
1509 d[i + 2] = table[s[i + 2]];
1510 d[i + 3] = table[s[i + 3]];
1515 setup_gamma_decode (GstVideoConverter * convert)
1517 GstVideoTransferFunction func;
1521 func = convert->in_info.colorimetry.transfer;
1523 convert->gamma_dec.width = convert->current_width;
1524 if (convert->current_bits == 8) {
1525 GST_DEBUG ("gamma decode 8->16: %d", func);
1526 convert->gamma_dec.gamma_func = gamma_convert_u8_u16;
1527 t = convert->gamma_dec.gamma_table = g_malloc (sizeof (guint16) * 256);
1529 for (i = 0; i < 256; i++)
1531 rint (gst_video_transfer_function_decode (func, i / 255.0) * 65535.0);
1533 GST_DEBUG ("gamma decode 16->16: %d", func);
1534 convert->gamma_dec.gamma_func = gamma_convert_u16_u16;
1535 t = convert->gamma_dec.gamma_table = g_malloc (sizeof (guint16) * 65536);
1537 for (i = 0; i < 65536; i++)
1539 rint (gst_video_transfer_function_decode (func,
1540 i / 65535.0) * 65535.0);
1542 convert->current_bits = 16;
1543 convert->current_pstride = 8;
1544 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1548 setup_gamma_encode (GstVideoConverter * convert, gint target_bits)
1550 GstVideoTransferFunction func;
1553 func = convert->out_info.colorimetry.transfer;
1555 convert->gamma_enc.width = convert->current_width;
1556 if (target_bits == 8) {
1559 GST_DEBUG ("gamma encode 16->8: %d", func);
1560 convert->gamma_enc.gamma_func = gamma_convert_u16_u8;
1561 t = convert->gamma_enc.gamma_table = g_malloc (sizeof (guint8) * 65536);
1563 for (i = 0; i < 65536; i++)
1565 rint (gst_video_transfer_function_encode (func, i / 65535.0) * 255.0);
1569 GST_DEBUG ("gamma encode 16->16: %d", func);
1570 convert->gamma_enc.gamma_func = gamma_convert_u16_u16;
1571 t = convert->gamma_enc.gamma_table = g_malloc (sizeof (guint16) * 65536);
1573 for (i = 0; i < 65536; i++)
1575 rint (gst_video_transfer_function_encode (func,
1576 i / 65535.0) * 65535.0);
1580 static GstLineCache *
1581 chain_convert_to_RGB (GstVideoConverter * convert, GstLineCache * prev,
1586 do_gamma = CHECK_GAMMA_REMAP (convert);
1591 if (!convert->unpack_rgb) {
1592 color_matrix_set_identity (&convert->to_RGB_matrix);
1593 compute_matrix_to_RGB (convert, &convert->to_RGB_matrix);
1595 /* matrix is in 0..1 range, scale to current bits */
1596 GST_DEBUG ("chain RGB convert");
1597 scale = 1 << convert->current_bits;
1598 color_matrix_scale_components (&convert->to_RGB_matrix,
1599 (float) scale, (float) scale, (float) scale);
1601 prepare_matrix (convert, &convert->to_RGB_matrix);
1603 if (convert->current_bits == 8)
1604 convert->current_format = GST_VIDEO_FORMAT_ARGB;
1606 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1609 prev = convert->to_RGB_lines[idx] = gst_line_cache_new (prev);
1610 prev->write_input = TRUE;
1611 prev->pass_alloc = FALSE;
1613 prev->stride = convert->current_pstride * convert->current_width;
1614 gst_line_cache_set_need_line_func (prev,
1615 do_convert_to_RGB_lines, idx, convert, NULL);
1617 GST_DEBUG ("chain gamma decode");
1618 setup_gamma_decode (convert);
1623 static GstLineCache *
1624 chain_hscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1629 method = GET_OPT_RESAMPLER_METHOD (convert);
1630 taps = GET_OPT_RESAMPLER_TAPS (convert);
1632 convert->h_scaler[idx] =
1633 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
1634 convert->in_width, convert->out_width, convert->config);
1636 gst_video_scaler_get_coeff (convert->h_scaler[idx], 0, NULL, &taps);
1638 GST_DEBUG ("chain hscale %d->%d, taps %d, method %d",
1639 convert->in_width, convert->out_width, taps, method);
1641 convert->current_width = convert->out_width;
1642 convert->h_scale_format = convert->current_format;
1644 prev = convert->hscale_lines[idx] = gst_line_cache_new (prev);
1645 prev->write_input = FALSE;
1646 prev->pass_alloc = FALSE;
1648 prev->stride = convert->current_pstride * convert->current_width;
1649 gst_line_cache_set_need_line_func (prev, do_hscale_lines, idx, convert, NULL);
1654 static GstLineCache *
1655 chain_vscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1658 guint taps, taps_i = 0;
1661 method = GET_OPT_RESAMPLER_METHOD (convert);
1662 taps = GET_OPT_RESAMPLER_TAPS (convert);
1664 if (GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)) {
1665 convert->v_scaler_i[idx] =
1666 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_INTERLACED,
1667 taps, convert->in_height, convert->out_height, convert->config);
1669 gst_video_scaler_get_coeff (convert->v_scaler_i[idx], 0, NULL, &taps_i);
1672 convert->v_scaler_p[idx] =
1673 gst_video_scaler_new (method, 0, taps, convert->in_height,
1674 convert->out_height, convert->config);
1675 convert->v_scale_width = convert->current_width;
1676 convert->v_scale_format = convert->current_format;
1677 convert->current_height = convert->out_height;
1679 gst_video_scaler_get_coeff (convert->v_scaler_p[idx], 0, NULL, &taps);
1681 GST_DEBUG ("chain vscale %d->%d, taps %d, method %d, backlog %d",
1682 convert->in_height, convert->out_height, taps, method, backlog);
1684 prev->backlog = backlog;
1685 prev = convert->vscale_lines[idx] = gst_line_cache_new (prev);
1686 prev->pass_alloc = (taps == 1);
1687 prev->write_input = FALSE;
1688 prev->n_lines = MAX (taps_i, taps);
1689 prev->stride = convert->current_pstride * convert->current_width;
1690 gst_line_cache_set_need_line_func (prev, do_vscale_lines, idx, convert, NULL);
1695 static GstLineCache *
1696 chain_scale (GstVideoConverter * convert, GstLineCache * prev, gboolean force,
1699 gint s0, s1, s2, s3;
1701 s0 = convert->current_width * convert->current_height;
1702 s3 = convert->out_width * convert->out_height;
1704 GST_DEBUG ("in pixels %d <> out pixels %d", s0, s3);
1706 if (s3 <= s0 || force) {
1707 /* we are making the image smaller or are forced to resample */
1708 s1 = convert->out_width * convert->current_height;
1709 s2 = convert->current_width * convert->out_height;
1711 GST_DEBUG ("%d <> %d", s1, s2);
1714 /* h scaling first produces less pixels */
1715 if (convert->current_width != convert->out_width)
1716 prev = chain_hscale (convert, prev, idx);
1717 if (convert->current_height != convert->out_height)
1718 prev = chain_vscale (convert, prev, idx);
1720 /* v scaling first produces less pixels */
1721 if (convert->current_height != convert->out_height)
1722 prev = chain_vscale (convert, prev, idx);
1723 if (convert->current_width != convert->out_width)
1724 prev = chain_hscale (convert, prev, idx);
1730 static GstLineCache *
1731 chain_convert (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1733 gboolean do_gamma, do_conversion, pass_alloc = FALSE;
1734 gboolean same_matrix, same_primaries, same_bits;
1737 same_bits = convert->unpack_bits == convert->pack_bits;
1738 if (CHECK_MATRIX_NONE (convert)) {
1742 convert->in_info.colorimetry.matrix ==
1743 convert->out_info.colorimetry.matrix;
1746 if (CHECK_PRIMARIES_NONE (convert)) {
1747 same_primaries = TRUE;
1750 convert->in_info.colorimetry.primaries ==
1751 convert->out_info.colorimetry.primaries;
1754 GST_DEBUG ("matrix %d -> %d (%d)", convert->in_info.colorimetry.matrix,
1755 convert->out_info.colorimetry.matrix, same_matrix);
1756 GST_DEBUG ("bits %d -> %d (%d)", convert->unpack_bits, convert->pack_bits,
1758 GST_DEBUG ("primaries %d -> %d (%d)", convert->in_info.colorimetry.primaries,
1759 convert->out_info.colorimetry.primaries, same_primaries);
1761 color_matrix_set_identity (&convert->convert_matrix);
1763 if (!same_primaries) {
1764 const GstVideoColorPrimariesInfo *pi;
1766 /* Convert from RGB_input to RGB_output via XYZ
1767 * res = XYZ_to_RGB_output ( RGB_to_XYZ_input ( input ) )
1768 * or in matricial form:
1769 * RGB_output = XYZ_to_RGB_output_matrix * RGB_TO_XYZ_input_matrix * RGB_input
1771 * The RGB_input is the pre-existing convert_matrix
1772 * The convert_matrix will become the RGB_output
1775 /* Convert input RGB to XYZ */
1776 pi = gst_video_color_primaries_get_info (convert->in_info.colorimetry.
1778 /* Get the RGB_TO_XYZ_input_matrix */
1779 color_matrix_RGB_to_XYZ (&p1, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx,
1780 pi->By, pi->Wx, pi->Wy);
1781 GST_DEBUG ("to XYZ matrix");
1782 color_matrix_debug (&p1);
1783 GST_DEBUG ("current matrix");
1784 /* convert_matrix = RGB_TO_XYZ_input_matrix * input_RGB */
1785 color_matrix_multiply (&convert->convert_matrix, &convert->convert_matrix,
1787 color_matrix_debug (&convert->convert_matrix);
1789 /* Convert XYZ to output RGB */
1790 pi = gst_video_color_primaries_get_info (convert->out_info.colorimetry.
1792 /* Calculate the XYZ_to_RGB_output_matrix
1793 * * Get the RGB_TO_XYZ_output_matrix
1797 color_matrix_RGB_to_XYZ (&p2, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx,
1798 pi->By, pi->Wx, pi->Wy);
1799 color_matrix_invert (&p2, &p2);
1800 GST_DEBUG ("to RGB matrix");
1801 color_matrix_debug (&p2);
1803 * convert_matrix = XYZ_to_RGB_output_matrix * RGB_TO_XYZ_input_matrix * RGB_input
1804 * = XYZ_to_RGB_output_matrix * convert_matrix
1805 * = p2 * convert_matrix
1807 color_matrix_multiply (&convert->convert_matrix, &p2,
1808 &convert->convert_matrix);
1809 GST_DEBUG ("current matrix");
1810 color_matrix_debug (&convert->convert_matrix);
1813 do_gamma = CHECK_GAMMA_REMAP (convert);
1816 convert->in_bits = convert->unpack_bits;
1817 convert->out_bits = convert->pack_bits;
1819 if (!same_bits || !same_matrix || !same_primaries) {
1820 /* no gamma, combine all conversions into 1 */
1821 if (convert->in_bits < convert->out_bits) {
1822 gint scale = 1 << (convert->out_bits - convert->in_bits);
1823 color_matrix_scale_components (&convert->convert_matrix,
1824 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
1826 GST_DEBUG ("to RGB matrix");
1827 compute_matrix_to_RGB (convert, &convert->convert_matrix);
1828 GST_DEBUG ("current matrix");
1829 color_matrix_debug (&convert->convert_matrix);
1831 GST_DEBUG ("to YUV matrix");
1832 compute_matrix_to_YUV (convert, &convert->convert_matrix, FALSE);
1833 GST_DEBUG ("current matrix");
1834 color_matrix_debug (&convert->convert_matrix);
1835 if (convert->in_bits > convert->out_bits) {
1836 gint scale = 1 << (convert->in_bits - convert->out_bits);
1837 color_matrix_scale_components (&convert->convert_matrix,
1838 (float) scale, (float) scale, (float) scale);
1840 convert->current_bits = MAX (convert->in_bits, convert->out_bits);
1842 do_conversion = TRUE;
1843 if (!same_matrix || !same_primaries)
1844 prepare_matrix (convert, &convert->convert_matrix);
1845 if (convert->in_bits == convert->out_bits)
1848 do_conversion = FALSE;
1850 convert->current_bits = convert->pack_bits;
1851 convert->current_format = convert->pack_format;
1852 convert->current_pstride = convert->current_bits >> 1;
1854 /* we did gamma, just do colorspace conversion if needed */
1855 if (same_primaries) {
1856 do_conversion = FALSE;
1858 prepare_matrix (convert, &convert->convert_matrix);
1859 convert->in_bits = convert->out_bits = 16;
1861 do_conversion = TRUE;
1865 if (do_conversion) {
1866 GST_DEBUG ("chain conversion");
1867 prev = convert->convert_lines[idx] = gst_line_cache_new (prev);
1868 prev->write_input = TRUE;
1869 prev->pass_alloc = pass_alloc;
1871 prev->stride = convert->current_pstride * convert->current_width;
1872 gst_line_cache_set_need_line_func (prev,
1873 do_convert_lines, idx, convert, NULL);
1879 convert_set_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1882 guint8 alpha = MIN (convert->alpha_value, 255);
1885 for (i = 0; i < width; i++)
1890 convert_set_alpha_u16 (GstVideoConverter * convert, gpointer pixels, gint width)
1892 guint16 *p = pixels;
1896 alpha = MIN (convert->alpha_value, 255);
1897 alpha |= alpha << 8;
1899 for (i = 0; i < width; i++)
1904 convert_mult_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1907 guint alpha = convert->alpha_value;
1910 for (i = 0; i < width; i++) {
1911 gint a = (p[i * 4] * alpha) / 255;
1912 p[i * 4] = CLAMP (a, 0, 255);
1917 convert_mult_alpha_u16 (GstVideoConverter * convert, gpointer pixels,
1920 guint16 *p = pixels;
1921 guint alpha = convert->alpha_value;
1924 for (i = 0; i < width; i++) {
1925 gint a = (p[i * 4] * alpha) / 255;
1926 p[i * 4] = CLAMP (a, 0, 65535);
1930 static GstLineCache *
1931 chain_alpha (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1933 switch (convert->alpha_mode) {
1934 case ALPHA_MODE_NONE:
1935 case ALPHA_MODE_COPY:
1938 case ALPHA_MODE_SET:
1939 if (convert->current_bits == 8)
1940 convert->alpha_func = convert_set_alpha_u8;
1942 convert->alpha_func = convert_set_alpha_u16;
1944 case ALPHA_MODE_MULT:
1945 if (convert->current_bits == 8)
1946 convert->alpha_func = convert_mult_alpha_u8;
1948 convert->alpha_func = convert_mult_alpha_u16;
1952 GST_DEBUG ("chain alpha mode %d", convert->alpha_mode);
1953 prev = convert->alpha_lines[idx] = gst_line_cache_new (prev);
1954 prev->write_input = TRUE;
1955 prev->pass_alloc = TRUE;
1957 prev->stride = convert->current_pstride * convert->current_width;
1958 gst_line_cache_set_need_line_func (prev, do_alpha_lines, idx, convert, NULL);
1963 static GstLineCache *
1964 chain_convert_to_YUV (GstVideoConverter * convert, GstLineCache * prev,
1969 do_gamma = CHECK_GAMMA_REMAP (convert);
1974 GST_DEBUG ("chain gamma encode");
1975 setup_gamma_encode (convert, convert->pack_bits);
1977 convert->current_bits = convert->pack_bits;
1978 convert->current_pstride = convert->current_bits >> 1;
1980 if (!convert->pack_rgb) {
1981 color_matrix_set_identity (&convert->to_YUV_matrix);
1982 compute_matrix_to_YUV (convert, &convert->to_YUV_matrix, FALSE);
1984 /* matrix is in 0..255 range, scale to pack bits */
1985 GST_DEBUG ("chain YUV convert");
1986 scale = 1 << convert->pack_bits;
1987 color_matrix_scale_components (&convert->to_YUV_matrix,
1988 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
1989 prepare_matrix (convert, &convert->to_YUV_matrix);
1991 convert->current_format = convert->pack_format;
1993 prev = convert->to_YUV_lines[idx] = gst_line_cache_new (prev);
1994 prev->write_input = FALSE;
1995 prev->pass_alloc = FALSE;
1997 prev->stride = convert->current_pstride * convert->current_width;
1998 gst_line_cache_set_need_line_func (prev,
1999 do_convert_to_YUV_lines, idx, convert, NULL);
2005 static GstLineCache *
2006 chain_downsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2008 if (convert->downsample_p[idx] || convert->downsample_i[idx]) {
2009 GST_DEBUG ("chain downsample");
2010 prev = convert->downsample_lines[idx] = gst_line_cache_new (prev);
2011 prev->write_input = TRUE;
2012 prev->pass_alloc = TRUE;
2014 prev->stride = convert->current_pstride * convert->current_width;
2015 gst_line_cache_set_need_line_func (prev,
2016 do_downsample_lines, idx, convert, NULL);
2021 static GstLineCache *
2022 chain_dither (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2025 gboolean do_dither = FALSE;
2026 GstVideoDitherFlags flags = 0;
2027 GstVideoDitherMethod method;
2028 guint quant[4], target_quant;
2030 method = GET_OPT_DITHER_METHOD (convert);
2031 if (method == GST_VIDEO_DITHER_NONE)
2034 target_quant = GET_OPT_DITHER_QUANTIZATION (convert);
2035 GST_DEBUG ("method %d, target-quantization %d", method, target_quant);
2037 if (convert->pack_pal) {
2044 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++) {
2047 depth = convert->out_info.finfo->depth[i];
2054 if (convert->current_bits >= depth) {
2055 quant[i] = 1 << (convert->current_bits - depth);
2056 if (target_quant > quant[i]) {
2057 flags |= GST_VIDEO_DITHER_FLAG_QUANTIZE;
2058 quant[i] = target_quant;
2069 GST_DEBUG ("chain dither");
2071 convert->dither[idx] = gst_video_dither_new (method,
2072 flags, convert->pack_format, quant, convert->current_width);
2074 prev = convert->dither_lines[idx] = gst_line_cache_new (prev);
2075 prev->write_input = TRUE;
2076 prev->pass_alloc = TRUE;
2078 prev->stride = convert->current_pstride * convert->current_width;
2079 gst_line_cache_set_need_line_func (prev, do_dither_lines, idx, convert,
2085 static GstLineCache *
2086 chain_pack (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2088 convert->pack_nlines = convert->out_info.finfo->pack_lines;
2089 convert->pack_pstride = convert->current_pstride;
2090 convert->identity_pack =
2091 (convert->out_info.finfo->format ==
2092 convert->out_info.finfo->unpack_format);
2093 GST_DEBUG ("chain pack line format %s, pstride %d, identity_pack %d (%d %d)",
2094 gst_video_format_to_string (convert->current_format),
2095 convert->current_pstride, convert->identity_pack,
2096 convert->out_info.finfo->format, convert->out_info.finfo->unpack_format);
2102 setup_allocators (GstVideoConverter * convert)
2104 GstLineCache *cache, *prev;
2105 GstLineCacheAllocLineFunc alloc_line;
2106 gboolean alloc_writable;
2108 GDestroyNotify notify;
2112 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2113 width += convert->out_x;
2115 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2116 /* start with using dest lines if we can directly write into it */
2117 if (convert->identity_pack) {
2118 alloc_line = get_dest_line;
2119 alloc_writable = TRUE;
2120 user_data = convert;
2124 converter_alloc_new (sizeof (guint16) * width * 4, 4 + BACKLOG,
2126 setup_border_alloc (convert, user_data);
2127 notify = (GDestroyNotify) converter_alloc_free;
2128 alloc_line = get_border_temp_line;
2129 /* when we add a border, we need to write */
2130 alloc_writable = convert->borderline != NULL;
2133 /* First step, try to calculate how many temp lines we need. Go backwards,
2134 * keep track of the maximum number of lines we need for each intermediate
2136 for (prev = cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2137 GST_DEBUG ("looking at cache %p, %d lines, %d backlog", cache,
2138 cache->n_lines, cache->backlog);
2139 prev->n_lines = MAX (prev->n_lines, cache->n_lines);
2140 if (!cache->pass_alloc) {
2141 GST_DEBUG ("cache %p, needs %d lines", prev, prev->n_lines);
2146 /* now walk backwards, we try to write into the dest lines directly
2147 * and keep track if the source needs to be writable */
2148 for (cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2149 gst_line_cache_set_alloc_line_func (cache, alloc_line, user_data, notify);
2150 cache->alloc_writable = alloc_writable;
2152 /* make sure only one cache frees the allocator */
2155 if (!cache->pass_alloc) {
2156 /* can't pass allocator, make new temp line allocator */
2158 converter_alloc_new (sizeof (guint16) * width * 4,
2159 cache->n_lines + cache->backlog, convert, NULL);
2160 notify = (GDestroyNotify) converter_alloc_free;
2161 alloc_line = get_temp_line;
2162 alloc_writable = FALSE;
2164 /* if someone writes to the input, we need a writable line from the
2166 if (cache->write_input)
2167 alloc_writable = TRUE;
2169 /* free leftover allocator */
2176 setup_borderline (GstVideoConverter * convert)
2180 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2181 width += convert->out_x;
2183 if (convert->fill_border && (convert->out_height < convert->out_maxheight ||
2184 convert->out_width < convert->out_maxwidth)) {
2187 const GstVideoFormatInfo *out_finfo;
2188 gpointer planes[GST_VIDEO_MAX_PLANES];
2189 gint strides[GST_VIDEO_MAX_PLANES];
2191 convert->borderline = g_malloc0 (sizeof (guint16) * width * 4);
2193 out_finfo = convert->out_info.finfo;
2195 if (GST_VIDEO_INFO_IS_YUV (&convert->out_info)) {
2200 /* Get Color matrix. */
2201 color_matrix_set_identity (&cm);
2202 compute_matrix_to_YUV (convert, &cm, TRUE);
2203 color_matrix_convert (&cm);
2205 border_val = GINT32_FROM_BE (convert->border_argb);
2207 b = (0xFF000000 & border_val) >> 24;
2208 g = (0x00FF0000 & border_val) >> 16;
2209 r = (0x0000FF00 & border_val) >> 8;
2210 a = (0x000000FF & border_val);
2212 y = 16 + ((r * cm.im[0][0] + g * cm.im[0][1] + b * cm.im[0][2]) >> 8);
2213 u = 128 + ((r * cm.im[1][0] + g * cm.im[1][1] + b * cm.im[1][2]) >> 8);
2214 v = 128 + ((r * cm.im[2][0] + g * cm.im[2][1] + b * cm.im[2][2]) >> 8);
2216 a = CLAMP (a, 0, 255);
2217 y = CLAMP (y, 0, 255);
2218 u = CLAMP (u, 0, 255);
2219 v = CLAMP (v, 0, 255);
2221 border_val = a | (y << 8) | (u << 16) | ((guint32) v << 24);
2223 border_val = GINT32_FROM_BE (convert->border_argb);
2225 if (convert->pack_bits == 8)
2226 video_orc_splat_u32 (convert->borderline, border_val, width);
2228 video_orc_splat2_u64 (convert->borderline, border_val, width);
2230 /* convert pixels */
2231 for (i = 0; i < out_finfo->n_planes; i++) {
2232 planes[i] = &convert->borders[i];
2233 strides[i] = sizeof (guint64);
2236 if (out_finfo->n_planes == 1) {
2237 /* for packed formats, convert based on subsampling so that we
2238 * get a complete group of pixels */
2239 for (i = 0; i < out_finfo->n_components; i++) {
2240 w_sub = MAX (w_sub, out_finfo->w_sub[i]);
2243 out_finfo->pack_func (out_finfo, GST_VIDEO_PACK_FLAG_NONE,
2244 convert->borderline, 0, planes, strides,
2245 GST_VIDEO_CHROMA_SITE_UNKNOWN, 0, 1 << w_sub);
2247 convert->borderline = NULL;
2252 convert_get_alpha_mode (GstVideoConverter * convert)
2254 gboolean in_alpha, out_alpha;
2256 in_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->in_info);
2257 out_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->out_info);
2259 /* no output alpha, do nothing */
2261 return ALPHA_MODE_NONE;
2265 if (CHECK_ALPHA_COPY (convert))
2266 return ALPHA_MODE_COPY;
2268 if (CHECK_ALPHA_MULT (convert)) {
2269 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2270 return ALPHA_MODE_COPY;
2272 return ALPHA_MODE_MULT;
2275 /* nothing special, this is what unpack etc does automatically */
2276 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2277 return ALPHA_MODE_NONE;
2279 /* everything else becomes SET */
2280 return ALPHA_MODE_SET;
2284 * gst_video_converter_new: (skip)
2285 * @in_info: a #GstVideoInfo
2286 * @out_info: a #GstVideoInfo
2287 * @config: (transfer full): a #GstStructure with configuration options
2289 * Create a new converter object to convert between @in_info and @out_info
2292 * Returns: a #GstVideoConverter or %NULL if conversion is not possible.
2297 gst_video_converter_new (GstVideoInfo * in_info, GstVideoInfo * out_info,
2298 GstStructure * config)
2300 GstVideoConverter *convert;
2302 const GstVideoFormatInfo *fin, *fout, *finfo;
2303 gdouble alpha_value;
2306 g_return_val_if_fail (in_info != NULL, NULL);
2307 g_return_val_if_fail (out_info != NULL, NULL);
2308 /* we won't ever do framerate conversion */
2309 g_return_val_if_fail (in_info->fps_n == out_info->fps_n, NULL);
2310 g_return_val_if_fail (in_info->fps_d == out_info->fps_d, NULL);
2311 /* we won't ever do deinterlace */
2312 g_return_val_if_fail (in_info->interlace_mode == out_info->interlace_mode,
2315 convert = g_slice_new0 (GstVideoConverter);
2317 fin = in_info->finfo;
2318 fout = out_info->finfo;
2320 convert->in_info = *in_info;
2321 convert->out_info = *out_info;
2323 /* default config */
2324 convert->config = gst_structure_new_empty ("GstVideoConverter");
2326 gst_video_converter_set_config (convert, config);
2328 convert->in_maxwidth = GST_VIDEO_INFO_WIDTH (in_info);
2329 convert->in_maxheight = GST_VIDEO_INFO_HEIGHT (in_info);
2330 convert->out_maxwidth = GST_VIDEO_INFO_WIDTH (out_info);
2331 convert->out_maxheight = GST_VIDEO_INFO_HEIGHT (out_info);
2333 convert->in_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_X, 0);
2334 convert->in_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_Y, 0);
2335 convert->in_x &= ~((1 << fin->w_sub[1]) - 1);
2336 convert->in_y &= ~((1 << fin->h_sub[1]) - 1);
2338 convert->in_width = get_opt_int (convert,
2339 GST_VIDEO_CONVERTER_OPT_SRC_WIDTH, convert->in_maxwidth - convert->in_x);
2340 convert->in_height = get_opt_int (convert,
2341 GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT,
2342 convert->in_maxheight - convert->in_y);
2345 MIN (convert->in_width, convert->in_maxwidth - convert->in_x);
2346 if (convert->in_width + convert->in_x < 0 ||
2347 convert->in_width + convert->in_x > convert->in_maxwidth) {
2348 convert->in_width = 0;
2351 convert->in_height =
2352 MIN (convert->in_height, convert->in_maxheight - convert->in_y);
2353 if (convert->in_height + convert->in_y < 0 ||
2354 convert->in_height + convert->in_y > convert->in_maxheight) {
2355 convert->in_height = 0;
2358 convert->out_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_X, 0);
2359 convert->out_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_Y, 0);
2360 convert->out_x &= ~((1 << fout->w_sub[1]) - 1);
2361 convert->out_y &= ~((1 << fout->h_sub[1]) - 1);
2363 convert->out_width = get_opt_int (convert,
2364 GST_VIDEO_CONVERTER_OPT_DEST_WIDTH,
2365 convert->out_maxwidth - convert->out_x);
2366 convert->out_height =
2367 get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT,
2368 convert->out_maxheight - convert->out_y);
2370 if (convert->out_width > convert->out_maxwidth - convert->out_x)
2371 convert->out_width = convert->out_maxwidth - convert->out_x;
2372 convert->out_width = CLAMP (convert->out_width, 0, convert->out_maxwidth);
2374 /* Check if completely outside the framebuffer */
2375 if (convert->out_width + convert->out_x < 0 ||
2376 convert->out_width + convert->out_x > convert->out_maxwidth) {
2377 convert->out_width = 0;
2380 /* Same for height */
2381 if (convert->out_height > convert->out_maxheight - convert->out_y)
2382 convert->out_height = convert->out_maxheight - convert->out_y;
2383 convert->out_height = CLAMP (convert->out_height, 0, convert->out_maxheight);
2385 if (convert->out_height + convert->out_y < 0 ||
2386 convert->out_height + convert->out_y > convert->out_maxheight) {
2387 convert->out_height = 0;
2390 convert->fill_border = GET_OPT_FILL_BORDER (convert);
2391 convert->border_argb = get_opt_uint (convert,
2392 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB);
2394 alpha_value = GET_OPT_ALPHA_VALUE (convert);
2395 convert->alpha_value = 255 * alpha_value;
2396 convert->alpha_mode = convert_get_alpha_mode (convert);
2398 convert->unpack_format = in_info->finfo->unpack_format;
2399 finfo = gst_video_format_get_info (convert->unpack_format);
2400 convert->unpack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2401 convert->unpack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2402 if (convert->unpack_rgb
2403 && in_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2404 /* force identity matrix for RGB input */
2405 GST_WARNING ("invalid matrix %d for input RGB format, using RGB",
2406 in_info->colorimetry.matrix);
2407 convert->in_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2410 convert->pack_format = out_info->finfo->unpack_format;
2411 finfo = gst_video_format_get_info (convert->pack_format);
2412 convert->pack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2413 convert->pack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2415 gst_video_format_get_palette (GST_VIDEO_INFO_FORMAT (out_info),
2416 &convert->pack_palsize);
2417 if (convert->pack_rgb
2418 && out_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2419 /* force identity matrix for RGB output */
2420 GST_WARNING ("invalid matrix %d for output RGB format, using RGB",
2421 out_info->colorimetry.matrix);
2422 convert->out_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2425 n_threads = get_opt_uint (convert, GST_VIDEO_CONVERTER_OPT_THREADS, 1);
2426 if (n_threads == 0 || n_threads > g_get_num_processors ())
2427 n_threads = g_get_num_processors ();
2428 /* Magic number of 200 lines */
2429 if (MAX (convert->out_height, convert->in_height) / n_threads < 200)
2430 n_threads = (MAX (convert->out_height, convert->in_height) + 199) / 200;
2434 convert->conversion_runner = gst_parallelized_task_runner_new (n_threads);
2436 if (video_converter_lookup_fastpath (convert))
2439 if (in_info->finfo->unpack_func == NULL)
2440 goto no_unpack_func;
2442 if (out_info->finfo->pack_func == NULL)
2445 convert->convert = video_converter_generic;
2447 convert->upsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2448 convert->upsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2449 convert->downsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2450 convert->downsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2451 convert->v_scaler_p = g_new0 (GstVideoScaler *, n_threads);
2452 convert->v_scaler_i = g_new0 (GstVideoScaler *, n_threads);
2453 convert->h_scaler = g_new0 (GstVideoScaler *, n_threads);
2454 convert->unpack_lines = g_new0 (GstLineCache *, n_threads);
2455 convert->pack_lines = g_new0 (GstLineCache *, n_threads);
2456 convert->upsample_lines = g_new0 (GstLineCache *, n_threads);
2457 convert->to_RGB_lines = g_new0 (GstLineCache *, n_threads);
2458 convert->hscale_lines = g_new0 (GstLineCache *, n_threads);
2459 convert->vscale_lines = g_new0 (GstLineCache *, n_threads);
2460 convert->convert_lines = g_new0 (GstLineCache *, n_threads);
2461 convert->alpha_lines = g_new0 (GstLineCache *, n_threads);
2462 convert->to_YUV_lines = g_new0 (GstLineCache *, n_threads);
2463 convert->downsample_lines = g_new0 (GstLineCache *, n_threads);
2464 convert->dither_lines = g_new0 (GstLineCache *, n_threads);
2465 convert->dither = g_new0 (GstVideoDither *, n_threads);
2467 if (convert->in_width > 0 && convert->out_width > 0 && convert->in_height > 0
2468 && convert->out_height > 0) {
2469 for (i = 0; i < n_threads; i++) {
2470 convert->current_format = GST_VIDEO_INFO_FORMAT (in_info);
2471 convert->current_width = convert->in_width;
2472 convert->current_height = convert->in_height;
2475 prev = chain_unpack_line (convert, i);
2476 /* upsample chroma */
2477 prev = chain_upsample (convert, prev, i);
2478 /* convert to gamma decoded RGB */
2479 prev = chain_convert_to_RGB (convert, prev, i);
2480 /* do all downscaling */
2481 prev = chain_scale (convert, prev, FALSE, i);
2482 /* do conversion between color spaces */
2483 prev = chain_convert (convert, prev, i);
2484 /* do alpha channels */
2485 prev = chain_alpha (convert, prev, i);
2486 /* do all remaining (up)scaling */
2487 prev = chain_scale (convert, prev, TRUE, i);
2488 /* convert to gamma encoded Y'Cb'Cr' */
2489 prev = chain_convert_to_YUV (convert, prev, i);
2490 /* downsample chroma */
2491 prev = chain_downsample (convert, prev, i);
2493 prev = chain_dither (convert, prev, i);
2494 /* pack into final format */
2495 convert->pack_lines[i] = chain_pack (convert, prev, i);
2499 setup_borderline (convert);
2500 /* now figure out allocators */
2501 setup_allocators (convert);
2509 GST_ERROR ("no unpack_func for format %s",
2510 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
2511 gst_video_converter_free (convert);
2516 GST_ERROR ("no pack_func for format %s",
2517 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
2518 gst_video_converter_free (convert);
2524 clear_matrix_data (MatrixData * data)
2532 * gst_video_converter_free:
2533 * @convert: a #GstVideoConverter
2540 gst_video_converter_free (GstVideoConverter * convert)
2544 g_return_if_fail (convert != NULL);
2546 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2547 if (convert->upsample_p && convert->upsample_p[i])
2548 gst_video_chroma_resample_free (convert->upsample_p[i]);
2549 if (convert->upsample_i && convert->upsample_i[i])
2550 gst_video_chroma_resample_free (convert->upsample_i[i]);
2551 if (convert->downsample_p && convert->downsample_p[i])
2552 gst_video_chroma_resample_free (convert->downsample_p[i]);
2553 if (convert->downsample_i && convert->downsample_i[i])
2554 gst_video_chroma_resample_free (convert->downsample_i[i]);
2555 if (convert->v_scaler_p && convert->v_scaler_p[i])
2556 gst_video_scaler_free (convert->v_scaler_p[i]);
2557 if (convert->v_scaler_i && convert->v_scaler_i[i])
2558 gst_video_scaler_free (convert->v_scaler_i[i]);
2559 if (convert->h_scaler && convert->h_scaler[i])
2560 gst_video_scaler_free (convert->h_scaler[i]);
2561 if (convert->unpack_lines && convert->unpack_lines[i])
2562 gst_line_cache_free (convert->unpack_lines[i]);
2563 if (convert->upsample_lines && convert->upsample_lines[i])
2564 gst_line_cache_free (convert->upsample_lines[i]);
2565 if (convert->to_RGB_lines && convert->to_RGB_lines[i])
2566 gst_line_cache_free (convert->to_RGB_lines[i]);
2567 if (convert->hscale_lines && convert->hscale_lines[i])
2568 gst_line_cache_free (convert->hscale_lines[i]);
2569 if (convert->vscale_lines && convert->vscale_lines[i])
2570 gst_line_cache_free (convert->vscale_lines[i]);
2571 if (convert->convert_lines && convert->convert_lines[i])
2572 gst_line_cache_free (convert->convert_lines[i]);
2573 if (convert->alpha_lines && convert->alpha_lines[i])
2574 gst_line_cache_free (convert->alpha_lines[i]);
2575 if (convert->to_YUV_lines && convert->to_YUV_lines[i])
2576 gst_line_cache_free (convert->to_YUV_lines[i]);
2577 if (convert->downsample_lines && convert->downsample_lines[i])
2578 gst_line_cache_free (convert->downsample_lines[i]);
2579 if (convert->dither_lines && convert->dither_lines[i])
2580 gst_line_cache_free (convert->dither_lines[i]);
2581 if (convert->dither && convert->dither[i])
2582 gst_video_dither_free (convert->dither[i]);
2584 g_free (convert->upsample_p);
2585 g_free (convert->upsample_i);
2586 g_free (convert->downsample_p);
2587 g_free (convert->downsample_i);
2588 g_free (convert->v_scaler_p);
2589 g_free (convert->v_scaler_i);
2590 g_free (convert->h_scaler);
2591 g_free (convert->unpack_lines);
2592 g_free (convert->pack_lines);
2593 g_free (convert->upsample_lines);
2594 g_free (convert->to_RGB_lines);
2595 g_free (convert->hscale_lines);
2596 g_free (convert->vscale_lines);
2597 g_free (convert->convert_lines);
2598 g_free (convert->alpha_lines);
2599 g_free (convert->to_YUV_lines);
2600 g_free (convert->downsample_lines);
2601 g_free (convert->dither_lines);
2602 g_free (convert->dither);
2604 g_free (convert->gamma_dec.gamma_table);
2605 g_free (convert->gamma_enc.gamma_table);
2607 if (convert->tmpline) {
2608 for (i = 0; i < convert->conversion_runner->n_threads; i++)
2609 g_free (convert->tmpline[i]);
2610 g_free (convert->tmpline);
2613 g_free (convert->borderline);
2615 if (convert->config)
2616 gst_structure_free (convert->config);
2618 for (i = 0; i < 4; i++) {
2619 for (j = 0; j < convert->conversion_runner->n_threads; j++) {
2620 if (convert->fv_scaler[i].scaler)
2621 gst_video_scaler_free (convert->fv_scaler[i].scaler[j]);
2622 if (convert->fh_scaler[i].scaler)
2623 gst_video_scaler_free (convert->fh_scaler[i].scaler[j]);
2625 g_free (convert->fv_scaler[i].scaler);
2626 g_free (convert->fh_scaler[i].scaler);
2629 if (convert->conversion_runner)
2630 gst_parallelized_task_runner_free (convert->conversion_runner);
2632 clear_matrix_data (&convert->to_RGB_matrix);
2633 clear_matrix_data (&convert->convert_matrix);
2634 clear_matrix_data (&convert->to_YUV_matrix);
2636 g_slice_free (GstVideoConverter, convert);
2640 copy_config (GQuark field_id, const GValue * value, gpointer user_data)
2642 GstVideoConverter *convert = user_data;
2644 gst_structure_id_set_value (convert->config, field_id, value);
2650 * gst_video_converter_set_config:
2651 * @convert: a #GstVideoConverter
2652 * @config: (transfer full): a #GstStructure
2654 * Set @config as extra configuration for @convert.
2656 * If the parameters in @config can not be set exactly, this function returns
2657 * %FALSE and will try to update as much state as possible. The new state can
2658 * then be retrieved and refined with gst_video_converter_get_config().
2660 * Look at the `GST_VIDEO_CONVERTER_OPT_*` fields to check valid configuration
2661 * option and values.
2663 * Returns: %TRUE when @config could be set.
2668 gst_video_converter_set_config (GstVideoConverter * convert,
2669 GstStructure * config)
2671 g_return_val_if_fail (convert != NULL, FALSE);
2672 g_return_val_if_fail (config != NULL, FALSE);
2674 gst_structure_foreach (config, copy_config, convert);
2675 gst_structure_free (config);
2681 * gst_video_converter_get_config:
2682 * @convert: a #GstVideoConverter
2684 * Get the current configuration of @convert.
2686 * Returns: a #GstStructure that remains valid for as long as @convert is valid
2687 * or until gst_video_converter_set_config() is called.
2689 const GstStructure *
2690 gst_video_converter_get_config (GstVideoConverter * convert)
2692 g_return_val_if_fail (convert != NULL, NULL);
2694 return convert->config;
2698 * gst_video_converter_frame:
2699 * @convert: a #GstVideoConverter
2700 * @dest: a #GstVideoFrame
2701 * @src: a #GstVideoFrame
2703 * Convert the pixels of @src into @dest using @convert.
2708 gst_video_converter_frame (GstVideoConverter * convert,
2709 const GstVideoFrame * src, GstVideoFrame * dest)
2711 g_return_if_fail (convert != NULL);
2712 g_return_if_fail (src != NULL);
2713 g_return_if_fail (dest != NULL);
2715 /* Check the frames we've been passed match the layout
2716 * we were configured for or we might go out of bounds */
2717 if (G_UNLIKELY (GST_VIDEO_INFO_FORMAT (&convert->in_info) !=
2718 GST_VIDEO_FRAME_FORMAT (src)
2719 || GST_VIDEO_INFO_WIDTH (&convert->in_info) >
2720 GST_VIDEO_FRAME_WIDTH (src)
2721 || GST_VIDEO_INFO_HEIGHT (&convert->in_info) >
2722 GST_VIDEO_FRAME_HEIGHT (src))) {
2723 g_critical ("Input video frame does not match configuration");
2726 if (G_UNLIKELY (GST_VIDEO_INFO_FORMAT (&convert->out_info) !=
2727 GST_VIDEO_FRAME_FORMAT (dest)
2728 || GST_VIDEO_INFO_WIDTH (&convert->out_info) >
2729 GST_VIDEO_FRAME_WIDTH (dest)
2730 || GST_VIDEO_INFO_HEIGHT (&convert->out_info) >
2731 GST_VIDEO_FRAME_HEIGHT (dest))) {
2732 g_critical ("Output video frame does not match configuration");
2736 if (G_UNLIKELY (convert->in_width == 0 || convert->in_height == 0 ||
2737 convert->out_width == 0 || convert->out_height == 0))
2740 convert->convert (convert, src, dest);
2744 video_converter_compute_matrix (GstVideoConverter * convert)
2746 MatrixData *dst = &convert->convert_matrix;
2748 color_matrix_set_identity (dst);
2749 compute_matrix_to_RGB (convert, dst);
2750 compute_matrix_to_YUV (convert, dst, FALSE);
2752 convert->current_bits = 8;
2753 prepare_matrix (convert, dst);
2757 video_converter_compute_resample (GstVideoConverter * convert, gint idx)
2759 GstVideoInfo *in_info, *out_info;
2760 const GstVideoFormatInfo *sfinfo, *dfinfo;
2762 if (CHECK_CHROMA_NONE (convert))
2765 in_info = &convert->in_info;
2766 out_info = &convert->out_info;
2768 sfinfo = in_info->finfo;
2769 dfinfo = out_info->finfo;
2771 GST_DEBUG ("site: %d->%d, w_sub: %d->%d, h_sub: %d->%d", in_info->chroma_site,
2772 out_info->chroma_site, sfinfo->w_sub[2], dfinfo->w_sub[2],
2773 sfinfo->h_sub[2], dfinfo->h_sub[2]);
2775 if (sfinfo->w_sub[2] != dfinfo->w_sub[2] ||
2776 sfinfo->h_sub[2] != dfinfo->h_sub[2] ||
2777 in_info->chroma_site != out_info->chroma_site ||
2778 in_info->width != out_info->width ||
2779 in_info->height != out_info->height) {
2780 if (GST_VIDEO_INFO_IS_INTERLACED (in_info)) {
2781 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2782 convert->upsample_i[idx] = gst_video_chroma_resample_new (0,
2783 in_info->chroma_site, GST_VIDEO_CHROMA_FLAG_INTERLACED,
2784 sfinfo->unpack_format, sfinfo->w_sub[2], sfinfo->h_sub[2]);
2785 if (!CHECK_CHROMA_UPSAMPLE (convert))
2786 convert->downsample_i[idx] =
2787 gst_video_chroma_resample_new (0, out_info->chroma_site,
2788 GST_VIDEO_CHROMA_FLAG_INTERLACED, dfinfo->unpack_format,
2789 -dfinfo->w_sub[2], -dfinfo->h_sub[2]);
2791 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2792 convert->upsample_p[idx] = gst_video_chroma_resample_new (0,
2793 in_info->chroma_site, 0, sfinfo->unpack_format, sfinfo->w_sub[2],
2795 if (!CHECK_CHROMA_UPSAMPLE (convert))
2796 convert->downsample_p[idx] = gst_video_chroma_resample_new (0,
2797 out_info->chroma_site, 0, dfinfo->unpack_format, -dfinfo->w_sub[2],
2802 #define FRAME_GET_PLANE_STRIDE(frame, plane) \
2803 GST_VIDEO_FRAME_PLANE_STRIDE (frame, plane)
2804 #define FRAME_GET_PLANE_LINE(frame, plane, line) \
2805 (gpointer)(((guint8*)(GST_VIDEO_FRAME_PLANE_DATA (frame, plane))) + \
2806 FRAME_GET_PLANE_STRIDE (frame, plane) * (line))
2808 #define FRAME_GET_COMP_STRIDE(frame, comp) \
2809 GST_VIDEO_FRAME_COMP_STRIDE (frame, comp)
2810 #define FRAME_GET_COMP_LINE(frame, comp, line) \
2811 (gpointer)(((guint8*)(GST_VIDEO_FRAME_COMP_DATA (frame, comp))) + \
2812 FRAME_GET_COMP_STRIDE (frame, comp) * (line))
2814 #define FRAME_GET_STRIDE(frame) FRAME_GET_PLANE_STRIDE (frame, 0)
2815 #define FRAME_GET_LINE(frame,line) FRAME_GET_PLANE_LINE (frame, 0, line)
2817 #define FRAME_GET_Y_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_Y, line)
2818 #define FRAME_GET_U_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_U, line)
2819 #define FRAME_GET_V_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_V, line)
2820 #define FRAME_GET_A_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_A, line)
2822 #define FRAME_GET_Y_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_Y)
2823 #define FRAME_GET_U_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_U)
2824 #define FRAME_GET_V_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_V)
2825 #define FRAME_GET_A_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_A)
2828 #define UNPACK_FRAME(frame,dest,line,x,width) \
2829 frame->info.finfo->unpack_func (frame->info.finfo, \
2830 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2831 GST_VIDEO_PACK_FLAG_INTERLACED : \
2832 GST_VIDEO_PACK_FLAG_NONE), \
2833 dest, frame->data, frame->info.stride, x, \
2835 #define PACK_FRAME(frame,src,line,width) \
2836 frame->info.finfo->pack_func (frame->info.finfo, \
2837 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2838 GST_VIDEO_PACK_FLAG_INTERLACED : \
2839 GST_VIDEO_PACK_FLAG_NONE), \
2840 src, 0, frame->data, frame->info.stride, \
2841 frame->info.chroma_site, line, width);
2844 get_dest_line (GstLineCache * cache, gint idx, gpointer user_data)
2846 GstVideoConverter *convert = user_data;
2848 gint pstride = convert->pack_pstride;
2849 gint out_x = convert->out_x;
2852 cline = CLAMP (idx, 0, convert->out_maxheight - 1);
2854 line = FRAME_GET_LINE (convert->dest, cline);
2855 GST_DEBUG ("get dest line %d %p", cline, line);
2857 if (convert->borderline) {
2858 gint r_border = (out_x + convert->out_width) * pstride;
2859 gint rb_width = convert->out_maxwidth * pstride - r_border;
2860 gint lb_width = out_x * pstride;
2862 memcpy (line, convert->borderline, lb_width);
2863 memcpy (line + r_border, convert->borderline, rb_width);
2865 line += out_x * pstride;
2871 do_unpack_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2874 GstVideoConverter *convert = user_data;
2878 cline = CLAMP (in_line + convert->in_y, 0, convert->in_maxheight - 1);
2880 if (cache->alloc_writable || !convert->identity_unpack) {
2881 tmpline = gst_line_cache_alloc_line (cache, out_line);
2882 GST_DEBUG ("unpack line %d (%u) %p", in_line, cline, tmpline);
2883 UNPACK_FRAME (convert->src, tmpline, cline, convert->in_x,
2886 tmpline = ((guint8 *) FRAME_GET_LINE (convert->src, cline)) +
2887 convert->in_x * convert->unpack_pstride;
2888 GST_DEBUG ("get src line %d (%u) %p", in_line, cline, tmpline);
2890 gst_line_cache_add_line (cache, in_line, tmpline);
2896 do_upsample_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2899 GstVideoConverter *convert = user_data;
2901 gint i, start_line, n_lines;
2903 n_lines = convert->up_n_lines;
2904 start_line = in_line;
2905 if (start_line < n_lines + convert->up_offset) {
2906 start_line += convert->up_offset;
2907 out_line += convert->up_offset;
2910 /* get the lines needed for chroma upsample */
2912 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
2915 if (convert->upsample) {
2916 GST_DEBUG ("doing upsample %d-%d %p", start_line, start_line + n_lines - 1,
2918 gst_video_chroma_resample (convert->upsample[idx], lines,
2922 for (i = 0; i < n_lines; i++)
2923 gst_line_cache_add_line (cache, start_line + i, lines[i]);
2929 do_convert_to_RGB_lines (GstLineCache * cache, gint idx, gint out_line,
2930 gint in_line, gpointer user_data)
2932 GstVideoConverter *convert = user_data;
2933 MatrixData *data = &convert->to_RGB_matrix;
2934 gpointer *lines, destline;
2936 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2937 destline = lines[0];
2939 if (data->matrix_func) {
2940 GST_DEBUG ("to RGB line %d %p", in_line, destline);
2941 data->matrix_func (data, destline);
2943 if (convert->gamma_dec.gamma_func) {
2944 destline = gst_line_cache_alloc_line (cache, out_line);
2946 GST_DEBUG ("gamma decode line %d %p->%p", in_line, lines[0], destline);
2947 convert->gamma_dec.gamma_func (&convert->gamma_dec, destline, lines[0]);
2949 gst_line_cache_add_line (cache, in_line, destline);
2955 do_hscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2958 GstVideoConverter *convert = user_data;
2959 gpointer *lines, destline;
2961 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2963 destline = gst_line_cache_alloc_line (cache, out_line);
2965 GST_DEBUG ("hresample line %d %p->%p", in_line, lines[0], destline);
2966 gst_video_scaler_horizontal (convert->h_scaler[idx], convert->h_scale_format,
2967 lines[0], destline, 0, convert->out_width);
2969 gst_line_cache_add_line (cache, in_line, destline);
2975 do_vscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2978 GstVideoConverter *convert = user_data;
2979 gpointer *lines, destline;
2980 guint sline, n_lines;
2983 cline = CLAMP (in_line, 0, convert->out_height - 1);
2985 gst_video_scaler_get_coeff (convert->v_scaler[idx], cline, &sline, &n_lines);
2986 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, sline, n_lines);
2988 destline = gst_line_cache_alloc_line (cache, out_line);
2990 GST_DEBUG ("vresample line %d %d-%d %p->%p", in_line, sline,
2991 sline + n_lines - 1, lines[0], destline);
2992 gst_video_scaler_vertical (convert->v_scaler[idx], convert->v_scale_format,
2993 lines, destline, cline, convert->v_scale_width);
2995 gst_line_cache_add_line (cache, in_line, destline);
3001 do_convert_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3004 GstVideoConverter *convert = user_data;
3005 MatrixData *data = &convert->convert_matrix;
3006 gpointer *lines, destline;
3007 guint in_bits, out_bits;
3010 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3012 destline = lines[0];
3014 in_bits = convert->in_bits;
3015 out_bits = convert->out_bits;
3017 width = MIN (convert->in_width, convert->out_width);
3019 if (out_bits == 16 || in_bits == 16) {
3020 gpointer srcline = lines[0];
3022 if (out_bits != in_bits)
3023 destline = gst_line_cache_alloc_line (cache, out_line);
3025 /* FIXME, we can scale in the conversion matrix */
3027 GST_DEBUG ("8->16 line %d %p->%p", in_line, srcline, destline);
3028 video_orc_convert_u8_to_u16 (destline, srcline, width * 4);
3032 if (data->matrix_func) {
3033 GST_DEBUG ("matrix line %d %p", in_line, srcline);
3034 data->matrix_func (data, srcline);
3037 /* FIXME, dither here */
3038 if (out_bits == 8) {
3039 GST_DEBUG ("16->8 line %d %p->%p", in_line, srcline, destline);
3040 video_orc_convert_u16_to_u8 (destline, srcline, width * 4);
3043 if (data->matrix_func) {
3044 GST_DEBUG ("matrix line %d %p", in_line, destline);
3045 data->matrix_func (data, destline);
3048 gst_line_cache_add_line (cache, in_line, destline);
3054 do_alpha_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3057 gpointer *lines, destline;
3058 GstVideoConverter *convert = user_data;
3059 gint width = MIN (convert->in_width, convert->out_width);
3061 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3062 destline = lines[0];
3064 GST_DEBUG ("alpha line %d %p", in_line, destline);
3065 convert->alpha_func (convert, destline, width);
3067 gst_line_cache_add_line (cache, in_line, destline);
3073 do_convert_to_YUV_lines (GstLineCache * cache, gint idx, gint out_line,
3074 gint in_line, gpointer user_data)
3076 GstVideoConverter *convert = user_data;
3077 MatrixData *data = &convert->to_YUV_matrix;
3078 gpointer *lines, destline;
3080 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3081 destline = lines[0];
3083 if (convert->gamma_enc.gamma_func) {
3084 destline = gst_line_cache_alloc_line (cache, out_line);
3086 GST_DEBUG ("gamma encode line %d %p->%p", in_line, lines[0], destline);
3087 convert->gamma_enc.gamma_func (&convert->gamma_enc, destline, lines[0]);
3089 if (data->matrix_func) {
3090 GST_DEBUG ("to YUV line %d %p", in_line, destline);
3091 data->matrix_func (data, destline);
3093 gst_line_cache_add_line (cache, in_line, destline);
3099 do_downsample_lines (GstLineCache * cache, gint idx, gint out_line,
3100 gint in_line, gpointer user_data)
3102 GstVideoConverter *convert = user_data;
3104 gint i, start_line, n_lines;
3106 n_lines = convert->down_n_lines;
3107 start_line = in_line;
3108 if (start_line < n_lines + convert->down_offset)
3109 start_line += convert->down_offset;
3111 /* get the lines needed for chroma downsample */
3113 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
3116 if (convert->downsample) {
3117 GST_DEBUG ("downsample line %d %d-%d %p", in_line, start_line,
3118 start_line + n_lines - 1, lines[0]);
3119 gst_video_chroma_resample (convert->downsample[idx], lines,
3120 convert->out_width);
3123 for (i = 0; i < n_lines; i++)
3124 gst_line_cache_add_line (cache, start_line + i, lines[i]);
3130 do_dither_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3133 GstVideoConverter *convert = user_data;
3134 gpointer *lines, destline;
3136 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3137 destline = lines[0];
3139 if (convert->dither) {
3140 GST_DEBUG ("Dither line %d %p", in_line, destline);
3141 gst_video_dither_line (convert->dither[idx], destline, 0, out_line,
3142 convert->out_width);
3144 gst_line_cache_add_line (cache, in_line, destline);
3151 GstLineCache *pack_lines;
3154 gint pack_lines_count;
3156 gboolean identity_pack;
3157 gint lb_width, out_maxwidth;
3158 GstVideoFrame *dest;
3162 convert_generic_task (ConvertTask * task)
3166 for (i = task->h_0; i < task->h_1; i += task->pack_lines_count) {
3169 /* load the lines needed to pack */
3171 gst_line_cache_get_lines (task->pack_lines, task->idx, i + task->out_y,
3172 i, task->pack_lines_count);
3174 if (!task->identity_pack) {
3175 /* take away the border */
3176 guint8 *l = ((guint8 *) lines[0]) - task->lb_width;
3177 /* and pack into destination */
3178 GST_DEBUG ("pack line %d %p (%p)", i + task->out_y, lines[0], l);
3179 PACK_FRAME (task->dest, l, i + task->out_y, task->out_maxwidth);
3185 video_converter_generic (GstVideoConverter * convert, const GstVideoFrame * src,
3186 GstVideoFrame * dest)
3189 gint out_maxwidth, out_maxheight;
3190 gint out_x, out_y, out_height;
3191 gint pack_lines, pstride;
3194 ConvertTask **tasks_p;
3196 gint lines_per_thread;
3198 out_height = convert->out_height;
3199 out_maxwidth = convert->out_maxwidth;
3200 out_maxheight = convert->out_maxheight;
3202 out_x = convert->out_x;
3203 out_y = convert->out_y;
3206 convert->dest = dest;
3208 if (GST_VIDEO_FRAME_IS_INTERLACED (src)) {
3209 GST_DEBUG ("setup interlaced frame");
3210 convert->upsample = convert->upsample_i;
3211 convert->downsample = convert->downsample_i;
3212 convert->v_scaler = convert->v_scaler_i;
3214 GST_DEBUG ("setup progressive frame");
3215 convert->upsample = convert->upsample_p;
3216 convert->downsample = convert->downsample_p;
3217 convert->v_scaler = convert->v_scaler_p;
3219 if (convert->upsample[0]) {
3220 gst_video_chroma_resample_get_info (convert->upsample[0],
3221 &convert->up_n_lines, &convert->up_offset);
3223 convert->up_n_lines = 1;
3224 convert->up_offset = 0;
3226 if (convert->downsample[0]) {
3227 gst_video_chroma_resample_get_info (convert->downsample[0],
3228 &convert->down_n_lines, &convert->down_offset);
3230 convert->down_n_lines = 1;
3231 convert->down_offset = 0;
3234 pack_lines = convert->pack_nlines; /* only 1 for now */
3235 pstride = convert->pack_pstride;
3237 lb_width = out_x * pstride;
3239 if (convert->borderline) {
3240 /* FIXME we should try to avoid PACK_FRAME */
3241 for (i = 0; i < out_y; i++)
3242 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3245 n_threads = convert->conversion_runner->n_threads;
3246 tasks = g_newa (ConvertTask, n_threads);
3247 tasks_p = g_newa (ConvertTask *, n_threads);
3250 GST_ROUND_UP_N ((out_height + n_threads - 1) / n_threads, pack_lines);
3252 for (i = 0; i < n_threads; i++) {
3253 tasks[i].dest = dest;
3254 tasks[i].pack_lines = convert->pack_lines[i];
3256 tasks[i].pack_lines_count = pack_lines;
3257 tasks[i].out_y = out_y;
3258 tasks[i].identity_pack = convert->identity_pack;
3259 tasks[i].lb_width = lb_width;
3260 tasks[i].out_maxwidth = out_maxwidth;
3262 tasks[i].h_0 = i * lines_per_thread;
3263 tasks[i].h_1 = MIN ((i + 1) * lines_per_thread, out_height);
3265 tasks_p[i] = &tasks[i];
3268 gst_parallelized_task_runner_run (convert->conversion_runner,
3269 (GstParallelizedTaskFunc) convert_generic_task, (gpointer) tasks_p);
3271 if (convert->borderline) {
3272 for (i = out_y + out_height; i < out_maxheight; i++)
3273 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3275 if (convert->pack_pal) {
3276 memcpy (GST_VIDEO_FRAME_PLANE_DATA (dest, 1), convert->pack_pal,
3277 convert->pack_palsize);
3281 static void convert_fill_border (GstVideoConverter * convert,
3282 GstVideoFrame * dest);
3286 #define GET_LINE_OFFSETS(interlaced,line,l1,l2) \
3288 l1 = (line & 2 ? line - 1 : line); \
3297 const GstVideoFrame *src;
3298 GstVideoFrame *dest;
3299 gint height_0, height_1;
3302 gboolean interlaced;
3312 convert_I420_YUY2_task (FConvertTask * task)
3317 for (i = task->height_0; i < task->height_1; i += 2) {
3318 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3320 video_orc_convert_I420_YUY2 (FRAME_GET_LINE (task->dest, l1),
3321 FRAME_GET_LINE (task->dest, l2),
3322 FRAME_GET_Y_LINE (task->src, l1),
3323 FRAME_GET_Y_LINE (task->src, l2),
3324 FRAME_GET_U_LINE (task->src, i >> 1),
3325 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3330 convert_I420_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
3331 GstVideoFrame * dest)
3334 gint width = convert->in_width;
3335 gint height = convert->in_height;
3336 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3338 FConvertTask *tasks;
3339 FConvertTask **tasks_p;
3341 gint lines_per_thread;
3343 /* I420 has half as many chroma lines, as such we have to
3344 * always merge two into one. For non-interlaced these are
3345 * the two next to each other, for interlaced one is skipped
3348 h2 = GST_ROUND_DOWN_4 (height);
3350 h2 = GST_ROUND_DOWN_2 (height);
3352 n_threads = convert->conversion_runner->n_threads;
3353 tasks = g_newa (FConvertTask, n_threads);
3354 tasks_p = g_newa (FConvertTask *, n_threads);
3356 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3358 for (i = 0; i < n_threads; i++) {
3360 tasks[i].dest = dest;
3362 tasks[i].interlaced = interlaced;
3363 tasks[i].width = width;
3365 tasks[i].height_0 = i * lines_per_thread;
3366 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3367 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3369 tasks_p[i] = &tasks[i];
3372 gst_parallelized_task_runner_run (convert->conversion_runner,
3373 (GstParallelizedTaskFunc) convert_I420_YUY2_task, (gpointer) tasks_p);
3375 /* now handle last lines. For interlaced these are up to 3 */
3377 for (i = h2; i < height; i++) {
3378 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3379 PACK_FRAME (dest, convert->tmpline[0], i, width);
3385 convert_I420_UYVY_task (FConvertTask * task)
3390 for (i = task->height_0; i < task->height_1; i += 2) {
3391 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3393 video_orc_convert_I420_UYVY (FRAME_GET_LINE (task->dest, l1),
3394 FRAME_GET_LINE (task->dest, l2),
3395 FRAME_GET_Y_LINE (task->src, l1),
3396 FRAME_GET_Y_LINE (task->src, l2),
3397 FRAME_GET_U_LINE (task->src, i >> 1),
3398 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3403 convert_I420_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
3404 GstVideoFrame * dest)
3407 gint width = convert->in_width;
3408 gint height = convert->in_height;
3409 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3411 FConvertTask *tasks;
3412 FConvertTask **tasks_p;
3414 gint lines_per_thread;
3416 /* I420 has half as many chroma lines, as such we have to
3417 * always merge two into one. For non-interlaced these are
3418 * the two next to each other, for interlaced one is skipped
3421 h2 = GST_ROUND_DOWN_4 (height);
3423 h2 = GST_ROUND_DOWN_2 (height);
3425 n_threads = convert->conversion_runner->n_threads;
3426 tasks = g_newa (FConvertTask, n_threads);
3427 tasks_p = g_newa (FConvertTask *, n_threads);
3429 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3431 for (i = 0; i < n_threads; i++) {
3433 tasks[i].dest = dest;
3435 tasks[i].interlaced = interlaced;
3436 tasks[i].width = width;
3438 tasks[i].height_0 = i * lines_per_thread;
3439 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3440 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3442 tasks_p[i] = &tasks[i];
3445 gst_parallelized_task_runner_run (convert->conversion_runner,
3446 (GstParallelizedTaskFunc) convert_I420_UYVY_task, (gpointer) tasks_p);
3448 /* now handle last lines. For interlaced these are up to 3 */
3450 for (i = h2; i < height; i++) {
3451 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3452 PACK_FRAME (dest, convert->tmpline[0], i, width);
3458 convert_I420_AYUV_task (FConvertTask * task)
3463 for (i = task->height_0; i < task->height_1; i += 2) {
3464 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3466 video_orc_convert_I420_AYUV (FRAME_GET_LINE (task->dest, l1),
3467 FRAME_GET_LINE (task->dest, l2),
3468 FRAME_GET_Y_LINE (task->src, l1),
3469 FRAME_GET_Y_LINE (task->src, l2),
3470 FRAME_GET_U_LINE (task->src, i >> 1), FRAME_GET_V_LINE (task->src,
3471 i >> 1), task->alpha, task->width);
3476 convert_I420_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3477 GstVideoFrame * dest)
3480 gint width = convert->in_width;
3481 gint height = convert->in_height;
3482 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3483 guint8 alpha = MIN (convert->alpha_value, 255);
3485 FConvertTask *tasks;
3486 FConvertTask **tasks_p;
3488 gint lines_per_thread;
3490 /* I420 has half as many chroma lines, as such we have to
3491 * always merge two into one. For non-interlaced these are
3492 * the two next to each other, for interlaced one is skipped
3495 h2 = GST_ROUND_DOWN_4 (height);
3497 h2 = GST_ROUND_DOWN_2 (height);
3500 n_threads = convert->conversion_runner->n_threads;
3501 tasks = g_newa (FConvertTask, n_threads);
3502 tasks_p = g_newa (FConvertTask *, n_threads);
3504 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3506 for (i = 0; i < n_threads; i++) {
3508 tasks[i].dest = dest;
3510 tasks[i].interlaced = interlaced;
3511 tasks[i].width = width;
3512 tasks[i].alpha = alpha;
3514 tasks[i].height_0 = i * lines_per_thread;
3515 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3516 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3518 tasks_p[i] = &tasks[i];
3521 gst_parallelized_task_runner_run (convert->conversion_runner,
3522 (GstParallelizedTaskFunc) convert_I420_AYUV_task, (gpointer) tasks_p);
3524 /* now handle last lines. For interlaced these are up to 3 */
3526 for (i = h2; i < height; i++) {
3527 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3529 convert_set_alpha_u8 (convert, convert->tmpline[0], width);
3530 PACK_FRAME (dest, convert->tmpline[0], i, width);
3536 convert_YUY2_I420_task (FConvertTask * task)
3541 for (i = task->height_0; i < task->height_1; i += 2) {
3542 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3544 video_orc_convert_YUY2_I420 (FRAME_GET_Y_LINE (task->dest, l1),
3545 FRAME_GET_Y_LINE (task->dest, l2),
3546 FRAME_GET_U_LINE (task->dest, i >> 1),
3547 FRAME_GET_V_LINE (task->dest, i >> 1),
3548 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
3549 (task->width + 1) / 2);
3554 convert_YUY2_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3555 GstVideoFrame * dest)
3558 gint width = convert->in_width;
3559 gint height = convert->in_height;
3560 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3562 FConvertTask *tasks;
3563 FConvertTask **tasks_p;
3565 gint lines_per_thread;
3567 /* I420 has half as many chroma lines, as such we have to
3568 * always merge two into one. For non-interlaced these are
3569 * the two next to each other, for interlaced one is skipped
3572 h2 = GST_ROUND_DOWN_4 (height);
3574 h2 = GST_ROUND_DOWN_2 (height);
3576 n_threads = convert->conversion_runner->n_threads;
3577 tasks = g_newa (FConvertTask, n_threads);
3578 tasks_p = g_newa (FConvertTask *, n_threads);
3580 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3582 for (i = 0; i < n_threads; i++) {
3584 tasks[i].dest = dest;
3586 tasks[i].interlaced = interlaced;
3587 tasks[i].width = width;
3589 tasks[i].height_0 = i * lines_per_thread;
3590 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3591 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3593 tasks_p[i] = &tasks[i];
3596 gst_parallelized_task_runner_run (convert->conversion_runner,
3597 (GstParallelizedTaskFunc) convert_YUY2_I420_task, (gpointer) tasks_p);
3599 /* now handle last lines. For interlaced these are up to 3 */
3601 for (i = h2; i < height; i++) {
3602 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3603 PACK_FRAME (dest, convert->tmpline[0], i, width);
3609 convert_v210_I420_task (FConvertTask * task)
3613 guint8 *d_y1, *d_y2, *d_u, *d_v;
3614 const guint8 *s1, *s2;
3615 guint32 a0, a1, a2, a3;
3616 guint16 y0_1, y1_1, y2_1, y3_1, y4_1, y5_1;
3617 guint16 u0_1, u2_1, u4_1;
3618 guint16 v0_1, v2_1, v4_1;
3619 guint16 y0_2, y1_2, y2_2, y3_2, y4_2, y5_2;
3620 guint16 u0_2, u2_2, u4_2;
3621 guint16 v0_2, v2_2, v4_2;
3623 for (i = task->height_0; i < task->height_1; i += 2) {
3624 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3626 d_y1 = FRAME_GET_Y_LINE (task->dest, l1);
3627 d_y2 = FRAME_GET_Y_LINE (task->dest, l2);
3628 d_u = FRAME_GET_U_LINE (task->dest, i >> 1);
3629 d_v = FRAME_GET_V_LINE (task->dest, i >> 1);
3631 s1 = FRAME_GET_LINE (task->src, l1);
3632 s2 = FRAME_GET_LINE (task->src, l2);
3634 for (j = 0; j < task->width; j += 6) {
3635 a0 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 0);
3636 a1 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 4);
3637 a2 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 8);
3638 a3 = GST_READ_UINT32_LE (s1 + (j / 6) * 16 + 12);
3640 u0_1 = ((a0 >> 0) & 0x3ff) >> 2;
3641 y0_1 = ((a0 >> 10) & 0x3ff) >> 2;
3642 v0_1 = ((a0 >> 20) & 0x3ff) >> 2;
3643 y1_1 = ((a1 >> 0) & 0x3ff) >> 2;
3645 u2_1 = ((a1 >> 10) & 0x3ff) >> 2;
3646 y2_1 = ((a1 >> 20) & 0x3ff) >> 2;
3647 v2_1 = ((a2 >> 0) & 0x3ff) >> 2;
3648 y3_1 = ((a2 >> 10) & 0x3ff) >> 2;
3650 u4_1 = ((a2 >> 20) & 0x3ff) >> 2;
3651 y4_1 = ((a3 >> 0) & 0x3ff) >> 2;
3652 v4_1 = ((a3 >> 10) & 0x3ff) >> 2;
3653 y5_1 = ((a3 >> 20) & 0x3ff) >> 2;
3655 a0 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 0);
3656 a1 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 4);
3657 a2 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 8);
3658 a3 = GST_READ_UINT32_LE (s2 + (j / 6) * 16 + 12);
3660 u0_2 = ((a0 >> 0) & 0x3ff) >> 2;
3661 y0_2 = ((a0 >> 10) & 0x3ff) >> 2;
3662 v0_2 = ((a0 >> 20) & 0x3ff) >> 2;
3663 y1_2 = ((a1 >> 0) & 0x3ff) >> 2;
3665 u2_2 = ((a1 >> 10) & 0x3ff) >> 2;
3666 y2_2 = ((a1 >> 20) & 0x3ff) >> 2;
3667 v2_2 = ((a2 >> 0) & 0x3ff) >> 2;
3668 y3_2 = ((a2 >> 10) & 0x3ff) >> 2;
3670 u4_2 = ((a2 >> 20) & 0x3ff) >> 2;
3671 y4_2 = ((a3 >> 0) & 0x3ff) >> 2;
3672 v4_2 = ((a3 >> 10) & 0x3ff) >> 2;
3673 y5_2 = ((a3 >> 20) & 0x3ff) >> 2;
3677 d_u[j / 2] = (u0_1 + u0_2) / 2;
3678 d_v[j / 2] = (v0_1 + v0_2) / 2;
3680 if (j < task->width - 1) {
3685 if (j < task->width - 2) {
3688 d_u[j / 2 + 1] = (u2_1 + u2_2) / 2;
3689 d_v[j / 2 + 1] = (v2_1 + v2_2) / 2;
3692 if (j < task->width - 3) {
3697 if (j < task->width - 4) {
3700 d_u[j / 2 + 2] = (u4_1 + u4_2) / 2;
3701 d_v[j / 2 + 2] = (v4_1 + v4_2) / 2;
3704 if (j < task->width - 5) {
3713 convert_v210_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3714 GstVideoFrame * dest)
3717 gint width = convert->in_width;
3718 gint height = convert->in_height;
3719 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3721 FConvertTask *tasks;
3722 FConvertTask **tasks_p;
3724 gint lines_per_thread;
3726 /* I420 has half as many chroma lines, as such we have to
3727 * always merge two into one. For non-interlaced these are
3728 * the two next to each other, for interlaced one is skipped
3731 h2 = GST_ROUND_DOWN_4 (height);
3733 h2 = GST_ROUND_DOWN_2 (height);
3735 n_threads = convert->conversion_runner->n_threads;
3736 tasks = g_newa (FConvertTask, n_threads);
3737 tasks_p = g_newa (FConvertTask *, n_threads);
3739 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3741 for (i = 0; i < n_threads; i++) {
3743 tasks[i].dest = dest;
3745 tasks[i].interlaced = interlaced;
3746 tasks[i].width = width;
3748 tasks[i].height_0 = i * lines_per_thread;
3749 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3750 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3752 tasks_p[i] = &tasks[i];
3755 gst_parallelized_task_runner_run (convert->conversion_runner,
3756 (GstParallelizedTaskFunc) convert_v210_I420_task, (gpointer) tasks_p);
3758 /* now handle last lines. For interlaced these are up to 3 */
3760 for (i = h2; i < height; i++) {
3761 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3762 PACK_FRAME (dest, convert->tmpline[0], i, width);
3769 const guint8 *s, *s2, *su, *sv;
3770 guint8 *d, *d2, *du, *dv;
3771 gint sstride, sustride, svstride;
3772 gint dstride, dustride, dvstride;
3776 } FConvertPlaneTask;
3779 convert_YUY2_AYUV_task (FConvertPlaneTask * task)
3781 video_orc_convert_YUY2_AYUV (task->d, task->dstride, task->s,
3782 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
3786 convert_YUY2_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3787 GstVideoFrame * dest)
3789 gint width = convert->in_width;
3790 gint height = convert->in_height;
3792 guint8 alpha = MIN (convert->alpha_value, 255);
3793 FConvertPlaneTask *tasks;
3794 FConvertPlaneTask **tasks_p;
3796 gint lines_per_thread;
3799 s = FRAME_GET_LINE (src, convert->in_y);
3800 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3801 d = FRAME_GET_LINE (dest, convert->out_y);
3802 d += (convert->out_x * 4);
3804 n_threads = convert->conversion_runner->n_threads;
3805 tasks = g_newa (FConvertPlaneTask, n_threads);
3806 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3808 lines_per_thread = (height + n_threads - 1) / n_threads;
3810 for (i = 0; i < n_threads; i++) {
3811 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3812 tasks[i].sstride = FRAME_GET_STRIDE (src);
3813 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3814 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3816 tasks[i].width = width;
3817 tasks[i].height = (i + 1) * lines_per_thread;
3818 tasks[i].height = MIN (tasks[i].height, height);
3819 tasks[i].height -= i * lines_per_thread;
3820 tasks[i].alpha = alpha;
3822 tasks_p[i] = &tasks[i];
3825 gst_parallelized_task_runner_run (convert->conversion_runner,
3826 (GstParallelizedTaskFunc) convert_YUY2_AYUV_task, (gpointer) tasks_p);
3828 convert_fill_border (convert, dest);
3832 convert_YUY2_Y42B_task (FConvertPlaneTask * task)
3834 video_orc_convert_YUY2_Y42B (task->d, task->dstride, task->du,
3835 task->dustride, task->dv, task->dvstride,
3836 task->s, task->sstride, (task->width + 1) / 2, task->height);
3840 convert_YUY2_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
3841 GstVideoFrame * dest)
3843 gint width = convert->in_width;
3844 gint height = convert->in_height;
3845 guint8 *s, *dy, *du, *dv;
3846 FConvertPlaneTask *tasks;
3847 FConvertPlaneTask **tasks_p;
3849 gint lines_per_thread;
3852 s = FRAME_GET_LINE (src, convert->in_y);
3853 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3855 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3856 dy += convert->out_x;
3857 du = FRAME_GET_U_LINE (dest, convert->out_y);
3858 du += convert->out_x >> 1;
3859 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3860 dv += convert->out_x >> 1;
3862 n_threads = convert->conversion_runner->n_threads;
3863 tasks = g_newa (FConvertPlaneTask, n_threads);
3864 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3866 lines_per_thread = (height + n_threads - 1) / n_threads;
3868 for (i = 0; i < n_threads; i++) {
3869 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3870 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3871 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3872 tasks[i].sstride = FRAME_GET_STRIDE (src);
3873 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3874 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3875 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3876 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3878 tasks[i].width = width;
3879 tasks[i].height = (i + 1) * lines_per_thread;
3880 tasks[i].height = MIN (tasks[i].height, height);
3881 tasks[i].height -= i * lines_per_thread;
3883 tasks_p[i] = &tasks[i];
3886 gst_parallelized_task_runner_run (convert->conversion_runner,
3887 (GstParallelizedTaskFunc) convert_YUY2_Y42B_task, (gpointer) tasks_p);
3889 convert_fill_border (convert, dest);
3893 convert_YUY2_Y444_task (FConvertPlaneTask * task)
3895 video_orc_convert_YUY2_Y444 (task->d,
3896 task->dstride, task->du,
3897 task->dustride, task->dv,
3898 task->dvstride, task->s,
3899 task->sstride, (task->width + 1) / 2, task->height);
3903 convert_YUY2_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
3904 GstVideoFrame * dest)
3906 gint width = convert->in_width;
3907 gint height = convert->in_height;
3908 guint8 *s, *dy, *du, *dv;
3909 FConvertPlaneTask *tasks;
3910 FConvertPlaneTask **tasks_p;
3912 gint lines_per_thread;
3915 s = FRAME_GET_LINE (src, convert->in_y);
3916 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3918 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3919 dy += convert->out_x;
3920 du = FRAME_GET_U_LINE (dest, convert->out_y);
3921 du += convert->out_x;
3922 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3923 dv += convert->out_x;
3925 n_threads = convert->conversion_runner->n_threads;
3926 tasks = g_newa (FConvertPlaneTask, n_threads);
3927 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3929 lines_per_thread = (height + n_threads - 1) / n_threads;
3931 for (i = 0; i < n_threads; i++) {
3932 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3933 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3934 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3935 tasks[i].sstride = FRAME_GET_STRIDE (src);
3936 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3937 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3938 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3939 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3941 tasks[i].width = width;
3942 tasks[i].height = (i + 1) * lines_per_thread;
3943 tasks[i].height = MIN (tasks[i].height, height);
3944 tasks[i].height -= i * lines_per_thread;
3946 tasks_p[i] = &tasks[i];
3949 gst_parallelized_task_runner_run (convert->conversion_runner,
3950 (GstParallelizedTaskFunc) convert_YUY2_Y444_task, (gpointer) tasks_p);
3952 convert_fill_border (convert, dest);
3956 convert_v210_Y42B_task (FConvertPlaneTask * task)
3959 guint8 *d_y, *d_u, *d_v;
3961 guint32 a0, a1, a2, a3;
3962 guint16 y0, y1, y2, y3, y4, y5;
3966 for (i = 0; i < task->height; i++) {
3967 d_y = task->d + i * task->dstride;
3968 d_u = task->du + i * task->dustride;
3969 d_v = task->dv + i * task->dvstride;
3970 s = task->s + i * task->sstride;
3972 for (j = 0; j < task->width; j += 6) {
3973 a0 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 0);
3974 a1 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 4);
3975 a2 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 8);
3976 a3 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 12);
3978 u0 = ((a0 >> 0) & 0x3ff) >> 2;
3979 y0 = ((a0 >> 10) & 0x3ff) >> 2;
3980 v0 = ((a0 >> 20) & 0x3ff) >> 2;
3981 y1 = ((a1 >> 0) & 0x3ff) >> 2;
3983 u2 = ((a1 >> 10) & 0x3ff) >> 2;
3984 y2 = ((a1 >> 20) & 0x3ff) >> 2;
3985 v2 = ((a2 >> 0) & 0x3ff) >> 2;
3986 y3 = ((a2 >> 10) & 0x3ff) >> 2;
3988 u4 = ((a2 >> 20) & 0x3ff) >> 2;
3989 y4 = ((a3 >> 0) & 0x3ff) >> 2;
3990 v4 = ((a3 >> 10) & 0x3ff) >> 2;
3991 y5 = ((a3 >> 20) & 0x3ff) >> 2;
3997 if (j < task->width - 1) {
4001 if (j < task->width - 2) {
4003 d_u[j / 2 + 1] = u2;
4004 d_v[j / 2 + 1] = v2;
4007 if (j < task->width - 3) {
4011 if (j < task->width - 4) {
4013 d_u[j / 2 + 2] = u4;
4014 d_v[j / 2 + 2] = v4;
4017 if (j < task->width - 5) {
4025 convert_v210_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4026 GstVideoFrame * dest)
4028 gint width = convert->in_width;
4029 gint height = convert->in_height;
4030 guint8 *s, *dy, *du, *dv;
4031 FConvertPlaneTask *tasks;
4032 FConvertPlaneTask **tasks_p;
4034 gint lines_per_thread;
4037 s = FRAME_GET_LINE (src, convert->in_y);
4038 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4040 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4041 dy += convert->out_x;
4042 du = FRAME_GET_U_LINE (dest, convert->out_y);
4043 du += convert->out_x >> 1;
4044 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4045 dv += convert->out_x >> 1;
4047 n_threads = convert->conversion_runner->n_threads;
4048 tasks = g_newa (FConvertPlaneTask, n_threads);
4049 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4051 lines_per_thread = (height + n_threads - 1) / n_threads;
4053 for (i = 0; i < n_threads; i++) {
4054 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4055 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4056 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4057 tasks[i].sstride = FRAME_GET_STRIDE (src);
4058 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4059 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4060 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4061 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4063 tasks[i].width = width;
4064 tasks[i].height = (i + 1) * lines_per_thread;
4065 tasks[i].height = MIN (tasks[i].height, height);
4066 tasks[i].height -= i * lines_per_thread;
4068 tasks_p[i] = &tasks[i];
4071 gst_parallelized_task_runner_run (convert->conversion_runner,
4072 (GstParallelizedTaskFunc) convert_v210_Y42B_task, (gpointer) tasks_p);
4074 convert_fill_border (convert, dest);
4078 convert_UYVY_I420_task (FConvertTask * task)
4083 for (i = task->height_0; i < task->height_1; i += 2) {
4084 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
4086 video_orc_convert_UYVY_I420 (FRAME_GET_COMP_LINE (task->dest, 0, l1),
4087 FRAME_GET_COMP_LINE (task->dest, 0, l2),
4088 FRAME_GET_COMP_LINE (task->dest, 1, i >> 1),
4089 FRAME_GET_COMP_LINE (task->dest, 2, i >> 1),
4090 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
4091 (task->width + 1) / 2);
4096 convert_UYVY_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
4097 GstVideoFrame * dest)
4100 gint width = convert->in_width;
4101 gint height = convert->in_height;
4102 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
4104 FConvertTask *tasks;
4105 FConvertTask **tasks_p;
4107 gint lines_per_thread;
4109 /* I420 has half as many chroma lines, as such we have to
4110 * always merge two into one. For non-interlaced these are
4111 * the two next to each other, for interlaced one is skipped
4114 h2 = GST_ROUND_DOWN_4 (height);
4116 h2 = GST_ROUND_DOWN_2 (height);
4118 n_threads = convert->conversion_runner->n_threads;
4119 tasks = g_newa (FConvertTask, n_threads);
4120 tasks_p = g_newa (FConvertTask *, n_threads);
4122 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
4124 for (i = 0; i < n_threads; i++) {
4126 tasks[i].dest = dest;
4128 tasks[i].interlaced = interlaced;
4129 tasks[i].width = width;
4131 tasks[i].height_0 = i * lines_per_thread;
4132 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
4133 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
4135 tasks_p[i] = &tasks[i];
4138 gst_parallelized_task_runner_run (convert->conversion_runner,
4139 (GstParallelizedTaskFunc) convert_UYVY_I420_task, (gpointer) tasks_p);
4141 /* now handle last lines. For interlaced these are up to 3 */
4143 for (i = h2; i < height; i++) {
4144 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
4145 PACK_FRAME (dest, convert->tmpline[0], i, width);
4151 convert_UYVY_AYUV_task (FConvertPlaneTask * task)
4153 video_orc_convert_UYVY_AYUV (task->d, task->dstride, task->s,
4154 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
4158 convert_UYVY_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
4159 GstVideoFrame * dest)
4161 gint width = convert->in_width;
4162 gint height = convert->in_height;
4164 guint8 alpha = MIN (convert->alpha_value, 255);
4165 FConvertPlaneTask *tasks;
4166 FConvertPlaneTask **tasks_p;
4168 gint lines_per_thread;
4171 s = FRAME_GET_LINE (src, convert->in_y);
4172 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4173 d = FRAME_GET_LINE (dest, convert->out_y);
4174 d += (convert->out_x * 4);
4176 n_threads = convert->conversion_runner->n_threads;
4177 tasks = g_newa (FConvertPlaneTask, n_threads);
4178 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4180 lines_per_thread = (height + n_threads - 1) / n_threads;
4182 for (i = 0; i < n_threads; i++) {
4183 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4184 tasks[i].sstride = FRAME_GET_STRIDE (src);
4185 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4186 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4188 tasks[i].width = width;
4189 tasks[i].height = (i + 1) * lines_per_thread;
4190 tasks[i].height = MIN (tasks[i].height, height);
4191 tasks[i].height -= i * lines_per_thread;
4192 tasks[i].alpha = alpha;
4194 tasks_p[i] = &tasks[i];
4197 gst_parallelized_task_runner_run (convert->conversion_runner,
4198 (GstParallelizedTaskFunc) convert_UYVY_AYUV_task, (gpointer) tasks_p);
4200 convert_fill_border (convert, dest);
4204 convert_UYVY_YUY2_task (FConvertPlaneTask * task)
4206 video_orc_convert_UYVY_YUY2 (task->d, task->dstride, task->s,
4207 task->sstride, (task->width + 1) / 2, task->height);
4211 convert_UYVY_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4212 GstVideoFrame * dest)
4214 gint width = convert->in_width;
4215 gint height = convert->in_height;
4217 FConvertPlaneTask *tasks;
4218 FConvertPlaneTask **tasks_p;
4220 gint lines_per_thread;
4223 s = FRAME_GET_LINE (src, convert->in_y);
4224 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4225 d = FRAME_GET_LINE (dest, convert->out_y);
4226 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4228 n_threads = convert->conversion_runner->n_threads;
4229 tasks = g_newa (FConvertPlaneTask, n_threads);
4230 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4232 lines_per_thread = (height + n_threads - 1) / n_threads;
4234 for (i = 0; i < n_threads; i++) {
4235 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4236 tasks[i].sstride = FRAME_GET_STRIDE (src);
4237 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4238 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4240 tasks[i].width = width;
4241 tasks[i].height = (i + 1) * lines_per_thread;
4242 tasks[i].height = MIN (tasks[i].height, height);
4243 tasks[i].height -= i * lines_per_thread;
4245 tasks_p[i] = &tasks[i];
4248 gst_parallelized_task_runner_run (convert->conversion_runner,
4249 (GstParallelizedTaskFunc) convert_UYVY_YUY2_task, (gpointer) tasks_p);
4251 convert_fill_border (convert, dest);
4255 convert_v210_UYVY_task (FConvertPlaneTask * task)
4260 guint32 a0, a1, a2, a3;
4261 guint16 y0, y1, y2, y3, y4, y5;
4265 for (i = 0; i < task->height; i++) {
4266 d = task->d + i * task->dstride;
4267 s = task->s + i * task->sstride;
4269 for (j = 0; j < task->width; j += 6) {
4270 a0 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 0);
4271 a1 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 4);
4272 a2 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 8);
4273 a3 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 12);
4275 u0 = ((a0 >> 0) & 0x3ff) >> 2;
4276 y0 = ((a0 >> 10) & 0x3ff) >> 2;
4277 v0 = ((a0 >> 20) & 0x3ff) >> 2;
4278 y1 = ((a1 >> 0) & 0x3ff) >> 2;
4280 u2 = ((a1 >> 10) & 0x3ff) >> 2;
4281 y2 = ((a1 >> 20) & 0x3ff) >> 2;
4282 v2 = ((a2 >> 0) & 0x3ff) >> 2;
4283 y3 = ((a2 >> 10) & 0x3ff) >> 2;
4285 u4 = ((a2 >> 20) & 0x3ff) >> 2;
4286 y4 = ((a3 >> 0) & 0x3ff) >> 2;
4287 v4 = ((a3 >> 10) & 0x3ff) >> 2;
4288 y5 = ((a3 >> 20) & 0x3ff) >> 2;
4294 if (j < task->width - 1) {
4298 if (j < task->width - 2) {
4304 if (j < task->width - 3) {
4308 if (j < task->width - 4) {
4314 if (j < task->width - 5) {
4322 convert_v210_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4323 GstVideoFrame * dest)
4325 gint width = convert->in_width;
4326 gint height = convert->in_height;
4328 FConvertPlaneTask *tasks;
4329 FConvertPlaneTask **tasks_p;
4331 gint lines_per_thread;
4334 s = FRAME_GET_LINE (src, convert->in_y);
4335 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4336 d = FRAME_GET_LINE (dest, convert->out_y);
4337 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4339 n_threads = convert->conversion_runner->n_threads;
4340 tasks = g_newa (FConvertPlaneTask, n_threads);
4341 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4343 lines_per_thread = (height + n_threads - 1) / n_threads;
4345 for (i = 0; i < n_threads; i++) {
4346 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4347 tasks[i].sstride = FRAME_GET_STRIDE (src);
4348 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4349 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4351 tasks[i].width = width;
4352 tasks[i].height = (i + 1) * lines_per_thread;
4353 tasks[i].height = MIN (tasks[i].height, height);
4354 tasks[i].height -= i * lines_per_thread;
4356 tasks_p[i] = &tasks[i];
4359 gst_parallelized_task_runner_run (convert->conversion_runner,
4360 (GstParallelizedTaskFunc) convert_v210_UYVY_task, (gpointer) tasks_p);
4362 convert_fill_border (convert, dest);
4366 convert_v210_YUY2_task (FConvertPlaneTask * task)
4371 guint32 a0, a1, a2, a3;
4372 guint16 y0, y1, y2, y3, y4, y5;
4376 for (i = 0; i < task->height; i++) {
4377 d = task->d + i * task->dstride;
4378 s = task->s + i * task->sstride;
4380 for (j = 0; j < task->width; j += 6) {
4381 a0 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 0);
4382 a1 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 4);
4383 a2 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 8);
4384 a3 = GST_READ_UINT32_LE (s + (j / 6) * 16 + 12);
4386 u0 = ((a0 >> 0) & 0x3ff) >> 2;
4387 y0 = ((a0 >> 10) & 0x3ff) >> 2;
4388 v0 = ((a0 >> 20) & 0x3ff) >> 2;
4389 y1 = ((a1 >> 0) & 0x3ff) >> 2;
4391 u2 = ((a1 >> 10) & 0x3ff) >> 2;
4392 y2 = ((a1 >> 20) & 0x3ff) >> 2;
4393 v2 = ((a2 >> 0) & 0x3ff) >> 2;
4394 y3 = ((a2 >> 10) & 0x3ff) >> 2;
4396 u4 = ((a2 >> 20) & 0x3ff) >> 2;
4397 y4 = ((a3 >> 0) & 0x3ff) >> 2;
4398 v4 = ((a3 >> 10) & 0x3ff) >> 2;
4399 y5 = ((a3 >> 20) & 0x3ff) >> 2;
4405 if (j < task->width - 1) {
4409 if (j < task->width - 2) {
4415 if (j < task->width - 3) {
4419 if (j < task->width - 4) {
4425 if (j < task->width - 5) {
4433 convert_v210_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4434 GstVideoFrame * dest)
4436 gint width = convert->in_width;
4437 gint height = convert->in_height;
4439 FConvertPlaneTask *tasks;
4440 FConvertPlaneTask **tasks_p;
4442 gint lines_per_thread;
4445 s = FRAME_GET_LINE (src, convert->in_y);
4446 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4447 d = FRAME_GET_LINE (dest, convert->out_y);
4448 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4450 n_threads = convert->conversion_runner->n_threads;
4451 tasks = g_newa (FConvertPlaneTask, n_threads);
4452 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4454 lines_per_thread = (height + n_threads - 1) / n_threads;
4456 for (i = 0; i < n_threads; i++) {
4457 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4458 tasks[i].sstride = FRAME_GET_STRIDE (src);
4459 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4460 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4462 tasks[i].width = width;
4463 tasks[i].height = (i + 1) * lines_per_thread;
4464 tasks[i].height = MIN (tasks[i].height, height);
4465 tasks[i].height -= i * lines_per_thread;
4467 tasks_p[i] = &tasks[i];
4470 gst_parallelized_task_runner_run (convert->conversion_runner,
4471 (GstParallelizedTaskFunc) convert_v210_YUY2_task, (gpointer) tasks_p);
4473 convert_fill_border (convert, dest);
4477 convert_UYVY_Y42B_task (FConvertPlaneTask * task)
4479 video_orc_convert_UYVY_Y42B (task->d, task->dstride, task->du,
4480 task->dustride, task->dv, task->dvstride,
4481 task->s, task->sstride, (task->width + 1) / 2, task->height);
4485 convert_UYVY_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4486 GstVideoFrame * dest)
4488 gint width = convert->in_width;
4489 gint height = convert->in_height;
4490 guint8 *s, *dy, *du, *dv;
4491 FConvertPlaneTask *tasks;
4492 FConvertPlaneTask **tasks_p;
4494 gint lines_per_thread;
4497 s = FRAME_GET_LINE (src, convert->in_y);
4498 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4500 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4501 dy += convert->out_x;
4502 du = FRAME_GET_U_LINE (dest, convert->out_y);
4503 du += convert->out_x >> 1;
4504 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4505 dv += convert->out_x >> 1;
4507 n_threads = convert->conversion_runner->n_threads;
4508 tasks = g_newa (FConvertPlaneTask, n_threads);
4509 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4511 lines_per_thread = (height + n_threads - 1) / n_threads;
4513 for (i = 0; i < n_threads; i++) {
4514 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4515 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4516 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4517 tasks[i].sstride = FRAME_GET_STRIDE (src);
4518 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4519 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4520 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4521 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4523 tasks[i].width = width;
4524 tasks[i].height = (i + 1) * lines_per_thread;
4525 tasks[i].height = MIN (tasks[i].height, height);
4526 tasks[i].height -= i * lines_per_thread;
4528 tasks_p[i] = &tasks[i];
4531 gst_parallelized_task_runner_run (convert->conversion_runner,
4532 (GstParallelizedTaskFunc) convert_UYVY_Y42B_task, (gpointer) tasks_p);
4534 convert_fill_border (convert, dest);
4538 convert_UYVY_Y444_task (FConvertPlaneTask * task)
4540 video_orc_convert_UYVY_Y444 (task->d,
4541 task->dstride, task->du,
4542 task->dustride, task->dv,
4543 task->dvstride, task->s,
4544 task->sstride, (task->width + 1) / 2, task->height);
4548 convert_UYVY_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
4549 GstVideoFrame * dest)
4551 gint width = convert->in_width;
4552 gint height = convert->in_height;
4553 guint8 *s, *dy, *du, *dv;
4554 FConvertPlaneTask *tasks;
4555 FConvertPlaneTask **tasks_p;
4557 gint lines_per_thread;
4560 s = FRAME_GET_LINE (src, convert->in_y);
4561 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
4563 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4564 dy += convert->out_x;
4565 du = FRAME_GET_U_LINE (dest, convert->out_y);
4566 du += convert->out_x;
4567 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4568 dv += convert->out_x;
4570 n_threads = convert->conversion_runner->n_threads;
4571 tasks = g_newa (FConvertPlaneTask, n_threads);
4572 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4574 lines_per_thread = (height + n_threads - 1) / n_threads;
4576 for (i = 0; i < n_threads; i++) {
4577 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4578 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4579 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4580 tasks[i].sstride = FRAME_GET_STRIDE (src);
4581 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4582 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4583 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4584 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4586 tasks[i].width = width;
4587 tasks[i].height = (i + 1) * lines_per_thread;
4588 tasks[i].height = MIN (tasks[i].height, height);
4589 tasks[i].height -= i * lines_per_thread;
4591 tasks_p[i] = &tasks[i];
4594 gst_parallelized_task_runner_run (convert->conversion_runner,
4595 (GstParallelizedTaskFunc) convert_UYVY_Y444_task, (gpointer) tasks_p);
4597 convert_fill_border (convert, dest);
4601 convert_UYVY_GRAY8_task (FConvertPlaneTask * task)
4603 video_orc_convert_UYVY_GRAY8 (task->d, task->dstride, (guint16 *) task->s,
4604 task->sstride, task->width, task->height);
4608 convert_UYVY_GRAY8 (GstVideoConverter * convert, const GstVideoFrame * src,
4609 GstVideoFrame * dest)
4611 gint width = convert->in_width;
4612 gint height = convert->in_height;
4615 FConvertPlaneTask *tasks;
4616 FConvertPlaneTask **tasks_p;
4618 gint lines_per_thread;
4621 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
4622 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
4624 n_threads = convert->conversion_runner->n_threads;
4625 tasks = g_newa (FConvertPlaneTask, n_threads);
4626 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4628 lines_per_thread = (height + n_threads - 1) / n_threads;
4630 for (i = 0; i < n_threads; i++) {
4631 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4632 tasks[i].sstride = FRAME_GET_STRIDE (src);
4633 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4634 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4636 tasks[i].width = width;
4637 tasks[i].height = (i + 1) * lines_per_thread;
4638 tasks[i].height = MIN (tasks[i].height, height);
4639 tasks[i].height -= i * lines_per_thread;
4641 tasks_p[i] = &tasks[i];
4644 gst_parallelized_task_runner_run (convert->conversion_runner,
4645 (GstParallelizedTaskFunc) convert_UYVY_GRAY8_task, (gpointer) tasks_p);
4647 convert_fill_border (convert, dest);
4651 convert_AYUV_I420_task (FConvertPlaneTask * task)
4653 video_orc_convert_AYUV_I420 (task->d,
4654 2 * task->dstride, task->d2,
4655 2 * task->dstride, task->du,
4656 task->dustride, task->dv,
4657 task->dvstride, task->s,
4658 2 * task->sstride, task->s2,
4659 2 * task->sstride, task->width / 2, task->height / 2);
4663 convert_AYUV_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
4664 GstVideoFrame * dest)
4666 gint width = convert->in_width;
4667 gint height = convert->in_height;
4668 guint8 *s1, *s2, *dy1, *dy2, *du, *dv;
4669 FConvertPlaneTask *tasks;
4670 FConvertPlaneTask **tasks_p;
4672 gint lines_per_thread;
4675 s1 = FRAME_GET_LINE (src, convert->in_y + 0);
4676 s1 += convert->in_x * 4;
4677 s2 = FRAME_GET_LINE (src, convert->in_y + 1);
4678 s2 += convert->in_x * 4;
4680 dy1 = FRAME_GET_Y_LINE (dest, convert->out_y + 0);
4681 dy1 += convert->out_x;
4682 dy2 = FRAME_GET_Y_LINE (dest, convert->out_y + 1);
4683 dy2 += convert->out_x;
4684 du = FRAME_GET_U_LINE (dest, convert->out_y >> 1);
4685 du += convert->out_x >> 1;
4686 dv = FRAME_GET_V_LINE (dest, convert->out_y >> 1);
4687 dv += convert->out_x >> 1;
4689 /* only for even width/height */
4691 n_threads = convert->conversion_runner->n_threads;
4692 tasks = g_newa (FConvertPlaneTask, n_threads);
4693 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4695 lines_per_thread = GST_ROUND_UP_2 ((height + n_threads - 1) / n_threads);
4697 for (i = 0; i < n_threads; i++) {
4698 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4699 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4700 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4701 tasks[i].sstride = FRAME_GET_STRIDE (src);
4702 tasks[i].d = dy1 + i * lines_per_thread * tasks[i].dstride;
4703 tasks[i].d2 = dy2 + i * lines_per_thread * tasks[i].dstride;
4704 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride / 2;
4705 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride / 2;
4706 tasks[i].s = s1 + i * lines_per_thread * tasks[i].sstride;
4707 tasks[i].s2 = s2 + i * lines_per_thread * tasks[i].sstride;
4709 tasks[i].width = width;
4710 tasks[i].height = (i + 1) * lines_per_thread;
4711 tasks[i].height = MIN (tasks[i].height, height);
4712 tasks[i].height -= i * lines_per_thread;
4714 tasks_p[i] = &tasks[i];
4717 gst_parallelized_task_runner_run (convert->conversion_runner,
4718 (GstParallelizedTaskFunc) convert_AYUV_I420_task, (gpointer) tasks_p);
4720 convert_fill_border (convert, dest);
4724 convert_AYUV_YUY2_task (FConvertPlaneTask * task)
4726 video_orc_convert_AYUV_YUY2 (task->d, task->dstride, task->s,
4727 task->sstride, task->width / 2, task->height);
4731 convert_AYUV_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4732 GstVideoFrame * dest)
4734 gint width = convert->in_width;
4735 gint height = convert->in_height;
4737 FConvertPlaneTask *tasks;
4738 FConvertPlaneTask **tasks_p;
4740 gint lines_per_thread;
4743 s = FRAME_GET_LINE (src, convert->in_y);
4744 s += convert->in_x * 4;
4745 d = FRAME_GET_LINE (dest, convert->out_y);
4746 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4748 /* only for even width */
4749 n_threads = convert->conversion_runner->n_threads;
4750 tasks = g_newa (FConvertPlaneTask, n_threads);
4751 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4753 lines_per_thread = (height + n_threads - 1) / n_threads;
4755 for (i = 0; i < n_threads; i++) {
4756 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4757 tasks[i].sstride = FRAME_GET_STRIDE (src);
4758 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4759 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4761 tasks[i].width = width;
4762 tasks[i].height = (i + 1) * lines_per_thread;
4763 tasks[i].height = MIN (tasks[i].height, height);
4764 tasks[i].height -= i * lines_per_thread;
4766 tasks_p[i] = &tasks[i];
4769 gst_parallelized_task_runner_run (convert->conversion_runner,
4770 (GstParallelizedTaskFunc) convert_AYUV_YUY2_task, (gpointer) tasks_p);
4772 convert_fill_border (convert, dest);
4776 convert_AYUV_UYVY_task (FConvertPlaneTask * task)
4778 video_orc_convert_AYUV_UYVY (task->d, task->dstride, task->s,
4779 task->sstride, task->width / 2, task->height);
4783 convert_AYUV_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4784 GstVideoFrame * dest)
4786 gint width = convert->in_width;
4787 gint height = convert->in_height;
4789 FConvertPlaneTask *tasks;
4790 FConvertPlaneTask **tasks_p;
4792 gint lines_per_thread;
4795 s = FRAME_GET_LINE (src, convert->in_y);
4796 s += convert->in_x * 4;
4797 d = FRAME_GET_LINE (dest, convert->out_y);
4798 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4800 /* only for even width */
4801 n_threads = convert->conversion_runner->n_threads;
4802 tasks = g_newa (FConvertPlaneTask, n_threads);
4803 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4805 lines_per_thread = (height + n_threads - 1) / n_threads;
4807 for (i = 0; i < n_threads; i++) {
4808 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4809 tasks[i].sstride = FRAME_GET_STRIDE (src);
4810 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4811 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4813 tasks[i].width = width;
4814 tasks[i].height = (i + 1) * lines_per_thread;
4815 tasks[i].height = MIN (tasks[i].height, height);
4816 tasks[i].height -= i * lines_per_thread;
4818 tasks_p[i] = &tasks[i];
4821 gst_parallelized_task_runner_run (convert->conversion_runner,
4822 (GstParallelizedTaskFunc) convert_AYUV_UYVY_task, (gpointer) tasks_p);
4824 convert_fill_border (convert, dest);
4828 convert_AYUV_Y42B_task (FConvertPlaneTask * task)
4830 video_orc_convert_AYUV_Y42B (task->d, task->dstride, task->du,
4831 task->dustride, task->dv, task->dvstride,
4832 task->s, task->sstride, task->width / 2, task->height);
4836 convert_AYUV_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4837 GstVideoFrame * dest)
4839 gint width = convert->in_width;
4840 gint height = convert->in_height;
4841 guint8 *s, *dy, *du, *dv;
4842 FConvertPlaneTask *tasks;
4843 FConvertPlaneTask **tasks_p;
4845 gint lines_per_thread;
4848 s = FRAME_GET_LINE (src, convert->in_y);
4849 s += convert->in_x * 4;
4851 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4852 dy += convert->out_x;
4853 du = FRAME_GET_U_LINE (dest, convert->out_y);
4854 du += convert->out_x >> 1;
4855 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4856 dv += convert->out_x >> 1;
4858 /* only works for even width */
4859 n_threads = convert->conversion_runner->n_threads;
4860 tasks = g_newa (FConvertPlaneTask, n_threads);
4861 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4863 lines_per_thread = (height + n_threads - 1) / n_threads;
4865 for (i = 0; i < n_threads; i++) {
4866 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4867 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4868 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4869 tasks[i].sstride = FRAME_GET_STRIDE (src);
4870 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4871 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4872 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4873 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4875 tasks[i].width = width;
4876 tasks[i].height = (i + 1) * lines_per_thread;
4877 tasks[i].height = MIN (tasks[i].height, height);
4878 tasks[i].height -= i * lines_per_thread;
4880 tasks_p[i] = &tasks[i];
4883 gst_parallelized_task_runner_run (convert->conversion_runner,
4884 (GstParallelizedTaskFunc) convert_AYUV_Y42B_task, (gpointer) tasks_p);
4886 convert_fill_border (convert, dest);
4890 convert_AYUV_Y444_task (FConvertPlaneTask * task)
4892 video_orc_convert_AYUV_Y444 (task->d, task->dstride, task->du,
4893 task->dustride, task->dv, task->dvstride,
4894 task->s, task->sstride, task->width, task->height);
4898 convert_AYUV_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
4899 GstVideoFrame * dest)
4901 gint width = convert->in_width;
4902 gint height = convert->in_height;
4903 guint8 *s, *dy, *du, *dv;
4904 FConvertPlaneTask *tasks;
4905 FConvertPlaneTask **tasks_p;
4907 gint lines_per_thread;
4910 s = FRAME_GET_LINE (src, convert->in_y);
4911 s += convert->in_x * 4;
4913 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4914 dy += convert->out_x;
4915 du = FRAME_GET_U_LINE (dest, convert->out_y);
4916 du += convert->out_x;
4917 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4918 dv += convert->out_x;
4920 n_threads = convert->conversion_runner->n_threads;
4921 tasks = g_newa (FConvertPlaneTask, n_threads);
4922 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4924 lines_per_thread = (height + n_threads - 1) / n_threads;
4926 for (i = 0; i < n_threads; i++) {
4927 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4928 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4929 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4930 tasks[i].sstride = FRAME_GET_STRIDE (src);
4931 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4932 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4933 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4934 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4936 tasks[i].width = width;
4937 tasks[i].height = (i + 1) * lines_per_thread;
4938 tasks[i].height = MIN (tasks[i].height, height);
4939 tasks[i].height -= i * lines_per_thread;
4941 tasks_p[i] = &tasks[i];
4944 gst_parallelized_task_runner_run (convert->conversion_runner,
4945 (GstParallelizedTaskFunc) convert_AYUV_Y444_task, (gpointer) tasks_p);
4946 convert_fill_border (convert, dest);
4950 convert_Y42B_YUY2_task (FConvertPlaneTask * task)
4952 video_orc_convert_Y42B_YUY2 (task->d, task->dstride,
4953 task->s, task->sstride,
4954 task->su, task->sustride,
4955 task->sv, task->svstride, (task->width + 1) / 2, task->height);
4959 convert_Y42B_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4960 GstVideoFrame * dest)
4962 gint width = convert->in_width;
4963 gint height = convert->in_height;
4964 guint8 *sy, *su, *sv, *d;
4965 FConvertPlaneTask *tasks;
4966 FConvertPlaneTask **tasks_p;
4968 gint lines_per_thread;
4971 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4972 sy += convert->in_x;
4973 su = FRAME_GET_U_LINE (src, convert->in_y);
4974 su += convert->in_x >> 1;
4975 sv = FRAME_GET_V_LINE (src, convert->in_y);
4976 sv += convert->in_x >> 1;
4978 d = FRAME_GET_LINE (dest, convert->out_y);
4979 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4981 n_threads = convert->conversion_runner->n_threads;
4982 tasks = g_newa (FConvertPlaneTask, n_threads);
4983 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4985 lines_per_thread = (height + n_threads - 1) / n_threads;
4987 for (i = 0; i < n_threads; i++) {
4988 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4989 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4990 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4991 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4992 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4993 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4994 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4995 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4997 tasks[i].width = width;
4998 tasks[i].height = (i + 1) * lines_per_thread;
4999 tasks[i].height = MIN (tasks[i].height, height);
5000 tasks[i].height -= i * lines_per_thread;
5002 tasks_p[i] = &tasks[i];
5005 gst_parallelized_task_runner_run (convert->conversion_runner,
5006 (GstParallelizedTaskFunc) convert_Y42B_YUY2_task, (gpointer) tasks_p);
5008 convert_fill_border (convert, dest);
5012 convert_Y42B_UYVY_task (FConvertPlaneTask * task)
5014 video_orc_convert_Y42B_UYVY (task->d, task->dstride,
5015 task->s, task->sstride,
5016 task->su, task->sustride,
5017 task->sv, task->svstride, (task->width + 1) / 2, task->height);
5021 convert_Y42B_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
5022 GstVideoFrame * dest)
5024 gint width = convert->in_width;
5025 gint height = convert->in_height;
5026 guint8 *sy, *su, *sv, *d;
5027 FConvertPlaneTask *tasks;
5028 FConvertPlaneTask **tasks_p;
5030 gint lines_per_thread;
5033 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5034 sy += convert->in_x;
5035 su = FRAME_GET_U_LINE (src, convert->in_y);
5036 su += convert->in_x >> 1;
5037 sv = FRAME_GET_V_LINE (src, convert->in_y);
5038 sv += convert->in_x >> 1;
5040 d = FRAME_GET_LINE (dest, convert->out_y);
5041 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5043 n_threads = convert->conversion_runner->n_threads;
5044 tasks = g_newa (FConvertPlaneTask, n_threads);
5045 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
5047 lines_per_thread = (height + n_threads - 1) / n_threads;
5049 for (i = 0; i < n_threads; i++) {
5050 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5051 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5052 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5053 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5054 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5055 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5056 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5057 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5059 tasks[i].width = width;
5060 tasks[i].height = (i + 1) * lines_per_thread;
5061 tasks[i].height = MIN (tasks[i].height, height);
5062 tasks[i].height -= i * lines_per_thread;
5064 tasks_p[i] = &tasks[i];
5067 gst_parallelized_task_runner_run (convert->conversion_runner,
5068 (GstParallelizedTaskFunc) convert_Y42B_UYVY_task, (gpointer) tasks_p);
5070 convert_fill_border (convert, dest);
5074 convert_Y42B_AYUV_task (FConvertPlaneTask * task)
5076 video_orc_convert_Y42B_AYUV (task->d, task->dstride, task->s,
5080 task->sv, task->svstride, task->alpha, task->width / 2, task->height);
5084 convert_Y42B_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
5085 GstVideoFrame * dest)
5087 gint width = convert->in_width;
5088 gint height = convert->in_height;
5089 guint8 *sy, *su, *sv, *d;
5090 guint8 alpha = MIN (convert->alpha_value, 255);
5091 FConvertPlaneTask *tasks;
5092 FConvertPlaneTask **tasks_p;
5094 gint lines_per_thread;
5097 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5098 sy += convert->in_x;
5099 su = FRAME_GET_U_LINE (src, convert->in_y);
5100 su += convert->in_x >> 1;
5101 sv = FRAME_GET_V_LINE (src, convert->in_y);
5102 sv += convert->in_x >> 1;
5104 d = FRAME_GET_LINE (dest, convert->out_y);
5105 d += convert->out_x * 4;
5107 /* only for even width */
5108 n_threads = convert->conversion_runner->n_threads;
5109 tasks = g_newa (FConvertPlaneTask, n_threads);
5110 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
5112 lines_per_thread = (height + n_threads - 1) / n_threads;
5114 for (i = 0; i < n_threads; i++) {
5115 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5116 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5117 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5118 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5119 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5120 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5121 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5122 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5124 tasks[i].width = width;
5125 tasks[i].height = (i + 1) * lines_per_thread;
5126 tasks[i].height = MIN (tasks[i].height, height);
5127 tasks[i].height -= i * lines_per_thread;
5128 tasks[i].alpha = alpha;
5130 tasks_p[i] = &tasks[i];
5133 gst_parallelized_task_runner_run (convert->conversion_runner,
5134 (GstParallelizedTaskFunc) convert_Y42B_AYUV_task, (gpointer) tasks_p);
5136 convert_fill_border (convert, dest);
5140 convert_Y444_YUY2_task (FConvertPlaneTask * task)
5142 video_orc_convert_Y444_YUY2 (task->d, task->dstride, task->s,
5145 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
5149 convert_Y444_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
5150 GstVideoFrame * dest)
5152 gint width = convert->in_width;
5153 gint height = convert->in_height;
5154 guint8 *sy, *su, *sv, *d;
5155 FConvertPlaneTask *tasks;
5156 FConvertPlaneTask **tasks_p;
5158 gint lines_per_thread;
5161 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5162 sy += convert->in_x;
5163 su = FRAME_GET_U_LINE (src, convert->in_y);
5164 su += convert->in_x;
5165 sv = FRAME_GET_V_LINE (src, convert->in_y);
5166 sv += convert->in_x;
5168 d = FRAME_GET_LINE (dest, convert->out_y);
5169 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5171 n_threads = convert->conversion_runner->n_threads;
5172 tasks = g_newa (FConvertPlaneTask, n_threads);
5173 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
5175 lines_per_thread = (height + n_threads - 1) / n_threads;
5177 for (i = 0; i < n_threads; i++) {
5178 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5179 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5180 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5181 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5182 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5183 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5184 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5185 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5187 tasks[i].width = width;
5188 tasks[i].height = (i + 1) * lines_per_thread;
5189 tasks[i].height = MIN (tasks[i].height, height);
5190 tasks[i].height -= i * lines_per_thread;
5192 tasks_p[i] = &tasks[i];
5195 gst_parallelized_task_runner_run (convert->conversion_runner,
5196 (GstParallelizedTaskFunc) convert_Y444_YUY2_task, (gpointer) tasks_p);
5198 convert_fill_border (convert, dest);
5202 convert_Y444_UYVY_task (FConvertPlaneTask * task)
5204 video_orc_convert_Y444_UYVY (task->d, task->dstride, task->s,
5207 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
5211 convert_Y444_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
5212 GstVideoFrame * dest)
5214 gint width = convert->in_width;
5215 gint height = convert->in_height;
5216 guint8 *sy, *su, *sv, *d;
5217 FConvertPlaneTask *tasks;
5218 FConvertPlaneTask **tasks_p;
5220 gint lines_per_thread;
5223 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5224 sy += convert->in_x;
5225 su = FRAME_GET_U_LINE (src, convert->in_y);
5226 su += convert->in_x;
5227 sv = FRAME_GET_V_LINE (src, convert->in_y);
5228 sv += convert->in_x;
5230 d = FRAME_GET_LINE (dest, convert->out_y);
5231 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
5233 n_threads = convert->conversion_runner->n_threads;
5234 tasks = g_newa (FConvertPlaneTask, n_threads);
5235 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
5237 lines_per_thread = (height + n_threads - 1) / n_threads;
5239 for (i = 0; i < n_threads; i++) {
5240 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5241 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5242 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5243 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5244 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5245 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5246 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5247 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5249 tasks[i].width = width;
5250 tasks[i].height = (i + 1) * lines_per_thread;
5251 tasks[i].height = MIN (tasks[i].height, height);
5252 tasks[i].height -= i * lines_per_thread;
5254 tasks_p[i] = &tasks[i];
5257 gst_parallelized_task_runner_run (convert->conversion_runner,
5258 (GstParallelizedTaskFunc) convert_Y444_UYVY_task, (gpointer) tasks_p);
5260 convert_fill_border (convert, dest);
5264 convert_Y444_AYUV_task (FConvertPlaneTask * task)
5266 video_orc_convert_Y444_AYUV (task->d, task->dstride, task->s,
5270 task->sv, task->svstride, task->alpha, task->width, task->height);
5274 convert_Y444_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
5275 GstVideoFrame * dest)
5277 gint width = convert->in_width;
5278 gint height = convert->in_height;
5279 guint8 *sy, *su, *sv, *d;
5280 guint8 alpha = MIN (convert->alpha_value, 255);
5281 FConvertPlaneTask *tasks;
5282 FConvertPlaneTask **tasks_p;
5284 gint lines_per_thread;
5287 sy = FRAME_GET_Y_LINE (src, convert->in_y);
5288 sy += convert->in_x;
5289 su = FRAME_GET_U_LINE (src, convert->in_y);
5290 su += convert->in_x;
5291 sv = FRAME_GET_V_LINE (src, convert->in_y);
5292 sv += convert->in_x;
5294 d = FRAME_GET_LINE (dest, convert->out_y);
5295 d += convert->out_x * 4;
5297 n_threads = convert->conversion_runner->n_threads;
5298 tasks = g_newa (FConvertPlaneTask, n_threads);
5299 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
5301 lines_per_thread = (height + n_threads - 1) / n_threads;
5303 for (i = 0; i < n_threads; i++) {
5304 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5305 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
5306 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
5307 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
5308 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5309 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
5310 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
5311 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
5313 tasks[i].width = width;
5314 tasks[i].height = (i + 1) * lines_per_thread;
5315 tasks[i].height = MIN (tasks[i].height, height);
5316 tasks[i].height -= i * lines_per_thread;
5317 tasks[i].alpha = alpha;
5319 tasks_p[i] = &tasks[i];
5322 gst_parallelized_task_runner_run (convert->conversion_runner,
5323 (GstParallelizedTaskFunc) convert_Y444_AYUV_task, (gpointer) tasks_p);
5325 convert_fill_border (convert, dest);
5328 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5330 convert_AYUV_ARGB_task (FConvertPlaneTask * task)
5332 video_orc_convert_AYUV_ARGB (task->d, task->dstride, task->s,
5333 task->sstride, task->data->im[0][0], task->data->im[0][2],
5334 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5335 task->width, task->height);
5339 convert_AYUV_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5340 GstVideoFrame * dest)
5342 gint width = convert->in_width;
5343 gint height = convert->in_height;
5344 MatrixData *data = &convert->convert_matrix;
5346 FConvertPlaneTask *tasks;
5347 FConvertPlaneTask **tasks_p;
5349 gint lines_per_thread;
5352 s = FRAME_GET_LINE (src, convert->in_y);
5353 s += (convert->in_x * 4);
5354 d = FRAME_GET_LINE (dest, convert->out_y);
5355 d += (convert->out_x * 4);
5357 n_threads = convert->conversion_runner->n_threads;
5358 tasks = g_newa (FConvertPlaneTask, n_threads);
5359 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
5361 lines_per_thread = (height + n_threads - 1) / n_threads;
5363 for (i = 0; i < n_threads; i++) {
5364 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5365 tasks[i].sstride = FRAME_GET_STRIDE (src);
5366 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5367 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5369 tasks[i].width = width;
5370 tasks[i].height = (i + 1) * lines_per_thread;
5371 tasks[i].height = MIN (tasks[i].height, height);
5372 tasks[i].height -= i * lines_per_thread;
5373 tasks[i].data = data;
5375 tasks_p[i] = &tasks[i];
5378 gst_parallelized_task_runner_run (convert->conversion_runner,
5379 (GstParallelizedTaskFunc) convert_AYUV_ARGB_task, (gpointer) tasks_p);
5381 convert_fill_border (convert, dest);
5385 convert_AYUV_BGRA_task (FConvertPlaneTask * task)
5387 video_orc_convert_AYUV_BGRA (task->d, task->dstride, task->s,
5388 task->sstride, task->data->im[0][0], task->data->im[0][2],
5389 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5390 task->width, task->height);
5394 convert_AYUV_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
5395 GstVideoFrame * dest)
5397 gint width = convert->in_width;
5398 gint height = convert->in_height;
5399 MatrixData *data = &convert->convert_matrix;
5401 FConvertPlaneTask *tasks;
5402 FConvertPlaneTask **tasks_p;
5404 gint lines_per_thread;
5407 s = FRAME_GET_LINE (src, convert->in_y);
5408 s += (convert->in_x * 4);
5409 d = FRAME_GET_LINE (dest, convert->out_y);
5410 d += (convert->out_x * 4);
5412 n_threads = convert->conversion_runner->n_threads;
5413 tasks = g_newa (FConvertPlaneTask, n_threads);
5414 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
5416 lines_per_thread = (height + n_threads - 1) / n_threads;
5418 for (i = 0; i < n_threads; i++) {
5419 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5420 tasks[i].sstride = FRAME_GET_STRIDE (src);
5421 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5422 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5424 tasks[i].width = width;
5425 tasks[i].height = (i + 1) * lines_per_thread;
5426 tasks[i].height = MIN (tasks[i].height, height);
5427 tasks[i].height -= i * lines_per_thread;
5428 tasks[i].data = data;
5430 tasks_p[i] = &tasks[i];
5433 gst_parallelized_task_runner_run (convert->conversion_runner,
5434 (GstParallelizedTaskFunc) convert_AYUV_BGRA_task, (gpointer) tasks_p);
5436 convert_fill_border (convert, dest);
5440 convert_AYUV_ABGR_task (FConvertPlaneTask * task)
5442 video_orc_convert_AYUV_ABGR (task->d, task->dstride, task->s,
5443 task->sstride, task->data->im[0][0], task->data->im[0][2],
5444 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5445 task->width, task->height);
5449 convert_AYUV_ABGR (GstVideoConverter * convert, const GstVideoFrame * src,
5450 GstVideoFrame * dest)
5452 gint width = convert->in_width;
5453 gint height = convert->in_height;
5454 MatrixData *data = &convert->convert_matrix;
5456 FConvertPlaneTask *tasks;
5457 FConvertPlaneTask **tasks_p;
5459 gint lines_per_thread;
5462 s = FRAME_GET_LINE (src, convert->in_y);
5463 s += (convert->in_x * 4);
5464 d = FRAME_GET_LINE (dest, convert->out_y);
5465 d += (convert->out_x * 4);
5467 n_threads = convert->conversion_runner->n_threads;
5468 tasks = g_newa (FConvertPlaneTask, n_threads);
5469 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
5471 lines_per_thread = (height + n_threads - 1) / n_threads;
5473 for (i = 0; i < n_threads; i++) {
5474 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5475 tasks[i].sstride = FRAME_GET_STRIDE (src);
5476 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5477 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5479 tasks[i].width = width;
5480 tasks[i].height = (i + 1) * lines_per_thread;
5481 tasks[i].height = MIN (tasks[i].height, height);
5482 tasks[i].height -= i * lines_per_thread;
5483 tasks[i].data = data;
5485 tasks_p[i] = &tasks[i];
5488 gst_parallelized_task_runner_run (convert->conversion_runner,
5489 (GstParallelizedTaskFunc) convert_AYUV_ABGR_task, (gpointer) tasks_p);
5491 convert_fill_border (convert, dest);
5495 convert_AYUV_RGBA_task (FConvertPlaneTask * task)
5497 video_orc_convert_AYUV_RGBA (task->d, task->dstride, task->s,
5498 task->sstride, task->data->im[0][0], task->data->im[0][2],
5499 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5500 task->width, task->height);
5504 convert_AYUV_RGBA (GstVideoConverter * convert, const GstVideoFrame * src,
5505 GstVideoFrame * dest)
5507 gint width = convert->in_width;
5508 gint height = convert->in_height;
5509 MatrixData *data = &convert->convert_matrix;
5511 FConvertPlaneTask *tasks;
5512 FConvertPlaneTask **tasks_p;
5514 gint lines_per_thread;
5517 s = FRAME_GET_LINE (src, convert->in_y);
5518 s += (convert->in_x * 4);
5519 d = FRAME_GET_LINE (dest, convert->out_y);
5520 d += (convert->out_x * 4);
5522 n_threads = convert->conversion_runner->n_threads;
5523 tasks = g_newa (FConvertPlaneTask, n_threads);
5524 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
5526 lines_per_thread = (height + n_threads - 1) / n_threads;
5528 for (i = 0; i < n_threads; i++) {
5529 tasks[i].dstride = FRAME_GET_STRIDE (dest);
5530 tasks[i].sstride = FRAME_GET_STRIDE (src);
5531 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5532 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5534 tasks[i].width = width;
5535 tasks[i].height = (i + 1) * lines_per_thread;
5536 tasks[i].height = MIN (tasks[i].height, height);
5537 tasks[i].height -= i * lines_per_thread;
5538 tasks[i].data = data;
5540 tasks_p[i] = &tasks[i];
5543 gst_parallelized_task_runner_run (convert->conversion_runner,
5544 (GstParallelizedTaskFunc) convert_AYUV_RGBA_task, (gpointer) tasks_p);
5546 convert_fill_border (convert, dest);
5551 convert_I420_BGRA_task (FConvertTask * task)
5555 for (i = task->height_0; i < task->height_1; i++) {
5556 guint8 *sy, *su, *sv, *d;
5558 d = FRAME_GET_LINE (task->dest, i + task->out_y);
5559 d += (task->out_x * 4);
5560 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5562 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5563 su += (task->in_x >> 1);
5564 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5565 sv += (task->in_x >> 1);
5567 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5568 video_orc_convert_I420_BGRA (d, sy, su, sv,
5569 task->data->im[0][0], task->data->im[0][2],
5570 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5573 video_orc_convert_I420_ARGB (d, sy, su, sv,
5574 task->data->im[0][0], task->data->im[0][2],
5575 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5582 convert_I420_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
5583 GstVideoFrame * dest)
5586 gint width = convert->in_width;
5587 gint height = convert->in_height;
5588 MatrixData *data = &convert->convert_matrix;
5589 FConvertTask *tasks;
5590 FConvertTask **tasks_p;
5592 gint lines_per_thread;
5594 n_threads = convert->conversion_runner->n_threads;
5595 tasks = g_newa (FConvertTask, n_threads);
5596 tasks_p = g_newa (FConvertTask *, n_threads);
5598 lines_per_thread = (height + n_threads - 1) / n_threads;
5600 for (i = 0; i < n_threads; i++) {
5602 tasks[i].dest = dest;
5604 tasks[i].width = width;
5605 tasks[i].data = data;
5606 tasks[i].in_x = convert->in_x;
5607 tasks[i].in_y = convert->in_y;
5608 tasks[i].out_x = convert->out_x;
5609 tasks[i].out_y = convert->out_y;
5611 tasks[i].height_0 = i * lines_per_thread;
5612 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5613 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5615 tasks_p[i] = &tasks[i];
5618 gst_parallelized_task_runner_run (convert->conversion_runner,
5619 (GstParallelizedTaskFunc) convert_I420_BGRA_task, (gpointer) tasks_p);
5621 convert_fill_border (convert, dest);
5625 convert_I420_ARGB_task (FConvertTask * task)
5629 for (i = task->height_0; i < task->height_1; i++) {
5630 guint8 *sy, *su, *sv, *d;
5632 d = FRAME_GET_LINE (task->dest, i + task->out_y);
5633 d += (task->out_x * 4);
5634 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5636 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5637 su += (task->in_x >> 1);
5638 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5639 sv += (task->in_x >> 1);
5641 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5642 video_orc_convert_I420_ARGB (d, sy, su, sv,
5643 task->data->im[0][0], task->data->im[0][2],
5644 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5647 video_orc_convert_I420_BGRA (d, sy, su, sv,
5648 task->data->im[0][0], task->data->im[0][2],
5649 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5656 convert_I420_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5657 GstVideoFrame * dest)
5660 gint width = convert->in_width;
5661 gint height = convert->in_height;
5662 MatrixData *data = &convert->convert_matrix;
5663 FConvertTask *tasks;
5664 FConvertTask **tasks_p;
5666 gint lines_per_thread;
5668 n_threads = convert->conversion_runner->n_threads;
5669 tasks = g_newa (FConvertTask, n_threads);
5670 tasks_p = g_newa (FConvertTask *, n_threads);
5672 lines_per_thread = (height + n_threads - 1) / n_threads;
5674 for (i = 0; i < n_threads; i++) {
5676 tasks[i].dest = dest;
5678 tasks[i].width = width;
5679 tasks[i].data = data;
5680 tasks[i].in_x = convert->in_x;
5681 tasks[i].in_y = convert->in_y;
5682 tasks[i].out_x = convert->out_x;
5683 tasks[i].out_y = convert->out_y;
5685 tasks[i].height_0 = i * lines_per_thread;
5686 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5687 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5689 tasks_p[i] = &tasks[i];
5692 gst_parallelized_task_runner_run (convert->conversion_runner,
5693 (GstParallelizedTaskFunc) convert_I420_ARGB_task, (gpointer) tasks_p);
5695 convert_fill_border (convert, dest);
5699 convert_I420_pack_ARGB_task (FConvertTask * task)
5702 gpointer d[GST_VIDEO_MAX_PLANES];
5704 d[0] = FRAME_GET_LINE (task->dest, 0);
5707 task->out_x * GST_VIDEO_FORMAT_INFO_PSTRIDE (task->dest->info.finfo, 0);
5709 for (i = task->height_0; i < task->height_1; i++) {
5710 guint8 *sy, *su, *sv;
5712 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5714 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5715 su += (task->in_x >> 1);
5716 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5717 sv += (task->in_x >> 1);
5719 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5720 video_orc_convert_I420_ARGB (task->tmpline, sy, su, sv,
5721 task->data->im[0][0], task->data->im[0][2],
5722 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5725 video_orc_convert_I420_BGRA (task->tmpline, sy, su, sv,
5726 task->data->im[0][0], task->data->im[0][2],
5727 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5730 task->dest->info.finfo->pack_func (task->dest->info.finfo,
5731 (GST_VIDEO_FRAME_IS_INTERLACED (task->dest) ?
5732 GST_VIDEO_PACK_FLAG_INTERLACED :
5733 GST_VIDEO_PACK_FLAG_NONE),
5734 task->tmpline, 0, d, task->dest->info.stride,
5735 task->dest->info.chroma_site, i + task->out_y, task->width);
5740 convert_I420_pack_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5741 GstVideoFrame * dest)
5744 gint width = convert->in_width;
5745 gint height = convert->in_height;
5746 MatrixData *data = &convert->convert_matrix;
5747 FConvertTask *tasks;
5748 FConvertTask **tasks_p;
5750 gint lines_per_thread;
5752 n_threads = convert->conversion_runner->n_threads;
5753 tasks = g_newa (FConvertTask, n_threads);
5754 tasks_p = g_newa (FConvertTask *, n_threads);
5756 lines_per_thread = (height + n_threads - 1) / n_threads;
5758 for (i = 0; i < n_threads; i++) {
5760 tasks[i].dest = dest;
5762 tasks[i].width = width;
5763 tasks[i].data = data;
5764 tasks[i].in_x = convert->in_x;
5765 tasks[i].in_y = convert->in_y;
5766 tasks[i].out_x = convert->out_x;
5767 tasks[i].out_y = convert->out_y;
5768 tasks[i].tmpline = convert->tmpline[i];
5770 tasks[i].height_0 = i * lines_per_thread;
5771 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5772 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5774 tasks_p[i] = &tasks[i];
5777 gst_parallelized_task_runner_run (convert->conversion_runner,
5778 (GstParallelizedTaskFunc) convert_I420_pack_ARGB_task,
5779 (gpointer) tasks_p);
5781 convert_fill_border (convert, dest);
5785 memset_u24 (guint8 * data, guint8 col[3], unsigned int n)
5789 for (i = 0; i < n; i++) {
5798 memset_u32_16 (guint8 * data, guint8 col[4], unsigned int n)
5802 for (i = 0; i < n; i += 2) {
5813 #define MAKE_BORDER_FUNC(func) \
5814 for (i = 0; i < out_y; i++) \
5815 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
5816 if (rb_width || lb_width) { \
5817 for (i = 0; i < out_height; i++) { \
5818 guint8 *d = FRAME_GET_PLANE_LINE (dest, k, i + out_y); \
5820 func (d, col, lb_width); \
5822 func (d + (pstride * r_border), col, rb_width); \
5825 for (i = out_y + out_height; i < out_maxheight; i++) \
5826 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
5829 convert_fill_border (GstVideoConverter * convert, GstVideoFrame * dest)
5832 const GstVideoFormatInfo *out_finfo;
5834 if (!convert->fill_border || !convert->borderline)
5837 out_finfo = convert->out_info.finfo;
5839 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
5841 for (k = 0; k < n_planes; k++) {
5842 gint i, out_x, out_y, out_width, out_height, pstride, pgroup;
5843 gint r_border, lb_width, rb_width;
5844 gint out_maxwidth, out_maxheight;
5847 out_x = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_x);
5848 out_y = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k, convert->out_y);
5850 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_width);
5852 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k, convert->out_height);
5854 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_maxwidth);
5856 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k,
5857 convert->out_maxheight);
5859 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, k);
5861 switch (GST_VIDEO_FORMAT_INFO_FORMAT (out_finfo)) {
5862 case GST_VIDEO_FORMAT_YUY2:
5863 case GST_VIDEO_FORMAT_YVYU:
5864 case GST_VIDEO_FORMAT_UYVY:
5866 out_maxwidth = GST_ROUND_UP_2 (out_maxwidth);
5873 r_border = out_x + out_width;
5874 rb_width = out_maxwidth - r_border;
5877 borders = &convert->borders[k];
5882 guint8 col = ((guint8 *) borders)[0];
5883 MAKE_BORDER_FUNC (memset);
5888 guint16 col = ((guint16 *) borders)[0];
5889 MAKE_BORDER_FUNC (video_orc_splat_u16);
5895 col[0] = ((guint8 *) borders)[0];
5896 col[1] = ((guint8 *) borders)[1];
5897 col[2] = ((guint8 *) borders)[2];
5898 MAKE_BORDER_FUNC (memset_u24);
5903 guint32 col = ((guint32 *) borders)[0];
5904 MAKE_BORDER_FUNC (video_orc_splat_u32);
5909 guint64 col = ((guint64 *) borders)[0];
5910 MAKE_BORDER_FUNC (video_orc_splat_u64);
5916 col[0] = ((guint8 *) borders)[0];
5917 col[2] = ((guint8 *) borders)[2];
5918 col[1] = ((guint8 *) borders)[r_border & 1 ? 3 : 1];
5919 col[3] = ((guint8 *) borders)[r_border & 1 ? 1 : 3];
5920 MAKE_BORDER_FUNC (memset_u32_16);
5931 const guint8 *s, *s2;
5933 gint sstride, dstride;
5939 convert_plane_fill_task (FSimpleScaleTask * task)
5941 video_orc_memset_2d (task->d, task->dstride,
5942 task->fill, task->width, task->height);
5946 convert_plane_fill (GstVideoConverter * convert,
5947 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5950 FSimpleScaleTask *tasks;
5951 FSimpleScaleTask **tasks_p;
5953 gint lines_per_thread;
5956 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5957 d += convert->fout_x[plane];
5959 n_threads = convert->conversion_runner->n_threads;
5960 tasks = g_newa (FSimpleScaleTask, n_threads);
5961 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5962 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5964 for (i = 0; i < n_threads; i++) {
5965 tasks[i].d = d + i * lines_per_thread * convert->fout_width[plane];
5967 tasks[i].fill = convert->ffill[plane];
5968 tasks[i].width = convert->fout_width[plane];
5969 tasks[i].height = (i + 1) * lines_per_thread;
5970 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5971 tasks[i].height -= i * lines_per_thread;
5972 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5974 tasks_p[i] = &tasks[i];
5977 gst_parallelized_task_runner_run (convert->conversion_runner,
5978 (GstParallelizedTaskFunc) convert_plane_fill_task, (gpointer) tasks_p);
5982 convert_plane_h_double_task (FSimpleScaleTask * task)
5984 video_orc_planar_chroma_422_444 (task->d,
5985 task->dstride, task->s, task->sstride, task->width / 2, task->height);
5989 convert_plane_h_double (GstVideoConverter * convert,
5990 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5993 gint splane = convert->fsplane[plane];
5994 FSimpleScaleTask *tasks;
5995 FSimpleScaleTask **tasks_p;
5997 gint lines_per_thread;
6000 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6001 s += convert->fin_x[splane];
6002 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6003 d += convert->fout_x[plane];
6005 n_threads = convert->conversion_runner->n_threads;
6006 tasks = g_newa (FSimpleScaleTask, n_threads);
6007 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
6008 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6010 for (i = 0; i < n_threads; i++) {
6011 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
6012 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6014 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
6015 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
6017 tasks[i].width = convert->fout_width[plane];
6018 tasks[i].height = (i + 1) * lines_per_thread;
6019 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6020 tasks[i].height -= i * lines_per_thread;
6022 tasks_p[i] = &tasks[i];
6025 gst_parallelized_task_runner_run (convert->conversion_runner,
6026 (GstParallelizedTaskFunc) convert_plane_h_double_task,
6027 (gpointer) tasks_p);
6031 convert_plane_h_halve_task (FSimpleScaleTask * task)
6033 video_orc_planar_chroma_444_422 (task->d,
6034 task->dstride, task->s, task->sstride, task->width, task->height);
6038 convert_plane_h_halve (GstVideoConverter * convert,
6039 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6042 gint splane = convert->fsplane[plane];
6043 FSimpleScaleTask *tasks;
6044 FSimpleScaleTask **tasks_p;
6046 gint lines_per_thread;
6049 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6050 s += convert->fin_x[splane];
6051 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6052 d += convert->fout_x[plane];
6054 n_threads = convert->conversion_runner->n_threads;
6055 tasks = g_newa (FSimpleScaleTask, n_threads);
6056 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
6057 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6059 for (i = 0; i < n_threads; i++) {
6060 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
6061 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6063 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
6064 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
6066 tasks[i].width = convert->fout_width[plane];
6067 tasks[i].height = (i + 1) * lines_per_thread;
6068 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6069 tasks[i].height -= i * lines_per_thread;
6071 tasks_p[i] = &tasks[i];
6074 gst_parallelized_task_runner_run (convert->conversion_runner,
6075 (GstParallelizedTaskFunc) convert_plane_h_halve_task, (gpointer) tasks_p);
6079 convert_plane_v_double_task (FSimpleScaleTask * task)
6081 video_orc_planar_chroma_420_422 (task->d, 2 * task->dstride, task->d2,
6082 2 * task->dstride, task->s, task->sstride, task->width, task->height / 2);
6086 convert_plane_v_double (GstVideoConverter * convert,
6087 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6089 guint8 *s, *d1, *d2;
6090 gint ds, splane = convert->fsplane[plane];
6091 FSimpleScaleTask *tasks;
6092 FSimpleScaleTask **tasks_p;
6094 gint lines_per_thread;
6097 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6098 s += convert->fin_x[splane];
6099 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6100 d1 += convert->fout_x[plane];
6101 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
6102 d2 += convert->fout_x[plane];
6103 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
6105 n_threads = convert->conversion_runner->n_threads;
6106 tasks = g_newa (FSimpleScaleTask, n_threads);
6107 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
6109 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
6112 for (i = 0; i < n_threads; i++) {
6113 tasks[i].d = d1 + i * lines_per_thread * ds;
6114 tasks[i].d2 = d2 + i * lines_per_thread * ds;
6115 tasks[i].dstride = ds;
6116 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6117 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride / 2;
6119 tasks[i].width = convert->fout_width[plane];
6120 tasks[i].height = (i + 1) * lines_per_thread;
6121 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6122 tasks[i].height -= i * lines_per_thread;
6124 tasks_p[i] = &tasks[i];
6127 gst_parallelized_task_runner_run (convert->conversion_runner,
6128 (GstParallelizedTaskFunc) convert_plane_v_double_task,
6129 (gpointer) tasks_p);
6133 convert_plane_v_halve_task (FSimpleScaleTask * task)
6135 video_orc_planar_chroma_422_420 (task->d, task->dstride, task->s,
6136 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
6141 convert_plane_v_halve (GstVideoConverter * convert,
6142 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6144 guint8 *s1, *s2, *d;
6145 gint ss, ds, splane = convert->fsplane[plane];
6146 FSimpleScaleTask *tasks;
6147 FSimpleScaleTask **tasks_p;
6149 gint lines_per_thread;
6152 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6153 s1 += convert->fin_x[splane];
6154 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
6155 s2 += convert->fin_x[splane];
6156 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6157 d += convert->fout_x[plane];
6159 ss = FRAME_GET_PLANE_STRIDE (src, splane);
6160 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
6162 n_threads = convert->conversion_runner->n_threads;
6163 tasks = g_newa (FSimpleScaleTask, n_threads);
6164 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
6165 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6167 for (i = 0; i < n_threads; i++) {
6168 tasks[i].d = d + i * lines_per_thread * ds;
6169 tasks[i].dstride = ds;
6170 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
6171 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
6172 tasks[i].sstride = ss;
6174 tasks[i].width = convert->fout_width[plane];
6175 tasks[i].height = (i + 1) * lines_per_thread;
6176 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6177 tasks[i].height -= i * lines_per_thread;
6179 tasks_p[i] = &tasks[i];
6182 gst_parallelized_task_runner_run (convert->conversion_runner,
6183 (GstParallelizedTaskFunc) convert_plane_v_halve_task, (gpointer) tasks_p);
6187 convert_plane_hv_double_task (FSimpleScaleTask * task)
6189 video_orc_planar_chroma_420_444 (task->d, 2 * task->dstride, task->d2,
6190 2 * task->dstride, task->s, task->sstride, (task->width + 1) / 2,
6195 convert_plane_hv_double (GstVideoConverter * convert,
6196 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6198 guint8 *s, *d1, *d2;
6199 gint ss, ds, splane = convert->fsplane[plane];
6200 FSimpleScaleTask *tasks;
6201 FSimpleScaleTask **tasks_p;
6203 gint lines_per_thread;
6206 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6207 s += convert->fin_x[splane];
6208 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6209 d1 += convert->fout_x[plane];
6210 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
6211 d2 += convert->fout_x[plane];
6212 ss = FRAME_GET_PLANE_STRIDE (src, splane);
6213 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
6215 n_threads = convert->conversion_runner->n_threads;
6216 tasks = g_newa (FSimpleScaleTask, n_threads);
6217 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
6219 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
6222 for (i = 0; i < n_threads; i++) {
6223 tasks[i].d = d1 + i * lines_per_thread * ds;
6224 tasks[i].d2 = d2 + i * lines_per_thread * ds;
6225 tasks[i].dstride = ds;
6226 tasks[i].sstride = ss;
6227 tasks[i].s = s + i * lines_per_thread * ss / 2;
6229 tasks[i].width = convert->fout_width[plane];
6230 tasks[i].height = (i + 1) * lines_per_thread;
6231 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6232 tasks[i].height -= i * lines_per_thread;
6234 tasks_p[i] = &tasks[i];
6237 gst_parallelized_task_runner_run (convert->conversion_runner,
6238 (GstParallelizedTaskFunc) convert_plane_hv_double_task,
6239 (gpointer) tasks_p);
6243 convert_plane_hv_halve_task (FSimpleScaleTask * task)
6245 video_orc_planar_chroma_444_420 (task->d, task->dstride, task->s,
6246 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
6251 convert_plane_hv_halve (GstVideoConverter * convert,
6252 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6254 guint8 *s1, *s2, *d;
6255 gint ss, ds, splane = convert->fsplane[plane];
6256 FSimpleScaleTask *tasks;
6257 FSimpleScaleTask **tasks_p;
6259 gint lines_per_thread;
6262 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
6263 s1 += convert->fin_x[splane];
6264 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
6265 s2 += convert->fin_x[splane];
6266 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
6267 d += convert->fout_x[plane];
6268 ss = FRAME_GET_PLANE_STRIDE (src, splane);
6269 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
6271 n_threads = convert->conversion_runner->n_threads;
6272 tasks = g_newa (FSimpleScaleTask, n_threads);
6273 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
6274 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
6276 for (i = 0; i < n_threads; i++) {
6277 tasks[i].d = d + i * lines_per_thread * ds;
6278 tasks[i].dstride = ds;
6279 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
6280 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
6281 tasks[i].sstride = ss;
6283 tasks[i].width = convert->fout_width[plane];
6284 tasks[i].height = (i + 1) * lines_per_thread;
6285 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
6286 tasks[i].height -= i * lines_per_thread;
6288 tasks_p[i] = &tasks[i];
6291 gst_parallelized_task_runner_run (convert->conversion_runner,
6292 (GstParallelizedTaskFunc) convert_plane_hv_halve_task,
6293 (gpointer) tasks_p);
6298 GstVideoScaler *h_scaler, *v_scaler;
6299 GstVideoFormat format;
6302 gint sstride, dstride;
6307 convert_plane_hv_task (FScaleTask * task)
6309 gst_video_scaler_2d (task->h_scaler, task->v_scaler, task->format,
6310 (guint8 *) task->s, task->sstride,
6311 task->d, task->dstride, task->x, task->y, task->w, task->h);
6315 convert_plane_hv (GstVideoConverter * convert,
6316 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
6318 gint in_x, in_y, out_x, out_y, out_width, out_height;
6319 GstVideoFormat format;
6320 gint splane = convert->fsplane[plane];
6322 gint sstride, dstride;
6324 FScaleTask **tasks_p;
6325 gint i, n_threads, lines_per_thread;
6327 in_x = convert->fin_x[splane];
6328 in_y = convert->fin_y[splane];
6329 out_x = convert->fout_x[plane];
6330 out_y = convert->fout_y[plane];
6331 out_width = convert->fout_width[plane];
6332 out_height = convert->fout_height[plane];
6333 format = convert->fformat[plane];
6335 s = FRAME_GET_PLANE_LINE (src, splane, in_y);
6337 d = FRAME_GET_PLANE_LINE (dest, plane, out_y);
6340 sstride = FRAME_GET_PLANE_STRIDE (src, splane);
6341 dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
6343 n_threads = convert->conversion_runner->n_threads;
6344 tasks = g_newa (FScaleTask, n_threads);
6345 tasks_p = g_newa (FScaleTask *, n_threads);
6347 lines_per_thread = (out_height + n_threads - 1) / n_threads;
6349 for (i = 0; i < n_threads; i++) {
6351 convert->fh_scaler[plane].scaler ? convert->
6352 fh_scaler[plane].scaler[i] : NULL;
6354 convert->fv_scaler[plane].scaler ? convert->
6355 fv_scaler[plane].scaler[i] : NULL;
6356 tasks[i].format = format;
6359 tasks[i].sstride = sstride;
6360 tasks[i].dstride = dstride;
6363 tasks[i].w = out_width;
6365 tasks[i].y = i * lines_per_thread;
6366 tasks[i].h = tasks[i].y + lines_per_thread;
6367 tasks[i].h = MIN (out_height, tasks[i].h);
6369 tasks_p[i] = &tasks[i];
6372 gst_parallelized_task_runner_run (convert->conversion_runner,
6373 (GstParallelizedTaskFunc) convert_plane_hv_task, (gpointer) tasks_p);
6377 convert_scale_planes (GstVideoConverter * convert,
6378 const GstVideoFrame * src, GstVideoFrame * dest)
6382 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
6383 for (i = 0; i < n_planes; i++) {
6384 if (convert->fconvert[i])
6385 convert->fconvert[i] (convert, src, dest, i);
6387 convert_fill_border (convert, dest);
6390 static GstVideoFormat
6391 get_scale_format (GstVideoFormat format, gint plane)
6393 GstVideoFormat res = GST_VIDEO_FORMAT_UNKNOWN;
6396 case GST_VIDEO_FORMAT_I420:
6397 case GST_VIDEO_FORMAT_YV12:
6398 case GST_VIDEO_FORMAT_Y41B:
6399 case GST_VIDEO_FORMAT_Y42B:
6400 case GST_VIDEO_FORMAT_Y444:
6401 case GST_VIDEO_FORMAT_GRAY8:
6402 case GST_VIDEO_FORMAT_A420:
6403 case GST_VIDEO_FORMAT_YUV9:
6404 case GST_VIDEO_FORMAT_YVU9:
6405 case GST_VIDEO_FORMAT_GBR:
6406 case GST_VIDEO_FORMAT_GBRA:
6407 res = GST_VIDEO_FORMAT_GRAY8;
6409 case GST_VIDEO_FORMAT_GRAY16_BE:
6410 case GST_VIDEO_FORMAT_GRAY16_LE:
6411 res = GST_VIDEO_FORMAT_GRAY16_BE;
6413 case GST_VIDEO_FORMAT_YUY2:
6414 case GST_VIDEO_FORMAT_UYVY:
6415 case GST_VIDEO_FORMAT_VYUY:
6416 case GST_VIDEO_FORMAT_YVYU:
6417 case GST_VIDEO_FORMAT_AYUV:
6418 case GST_VIDEO_FORMAT_VUYA:
6419 case GST_VIDEO_FORMAT_RGBx:
6420 case GST_VIDEO_FORMAT_BGRx:
6421 case GST_VIDEO_FORMAT_xRGB:
6422 case GST_VIDEO_FORMAT_xBGR:
6423 case GST_VIDEO_FORMAT_RGBA:
6424 case GST_VIDEO_FORMAT_BGRA:
6425 case GST_VIDEO_FORMAT_ARGB:
6426 case GST_VIDEO_FORMAT_ABGR:
6427 case GST_VIDEO_FORMAT_RGB:
6428 case GST_VIDEO_FORMAT_BGR:
6429 case GST_VIDEO_FORMAT_v308:
6430 case GST_VIDEO_FORMAT_IYU2:
6431 case GST_VIDEO_FORMAT_ARGB64:
6432 case GST_VIDEO_FORMAT_AYUV64:
6435 case GST_VIDEO_FORMAT_RGB15:
6436 case GST_VIDEO_FORMAT_BGR15:
6437 case GST_VIDEO_FORMAT_RGB16:
6438 case GST_VIDEO_FORMAT_BGR16:
6439 res = GST_VIDEO_FORMAT_NV12;
6441 case GST_VIDEO_FORMAT_NV12:
6442 case GST_VIDEO_FORMAT_NV21:
6443 case GST_VIDEO_FORMAT_NV16:
6444 case GST_VIDEO_FORMAT_NV61:
6445 case GST_VIDEO_FORMAT_NV24:
6446 res = plane == 0 ? GST_VIDEO_FORMAT_GRAY8 : GST_VIDEO_FORMAT_NV12;
6448 case GST_VIDEO_FORMAT_UNKNOWN:
6449 case GST_VIDEO_FORMAT_ENCODED:
6450 case GST_VIDEO_FORMAT_v210:
6451 case GST_VIDEO_FORMAT_v216:
6452 case GST_VIDEO_FORMAT_Y210:
6453 case GST_VIDEO_FORMAT_Y410:
6454 case GST_VIDEO_FORMAT_UYVP:
6455 case GST_VIDEO_FORMAT_RGB8P:
6456 case GST_VIDEO_FORMAT_IYU1:
6457 case GST_VIDEO_FORMAT_r210:
6458 case GST_VIDEO_FORMAT_I420_10BE:
6459 case GST_VIDEO_FORMAT_I420_10LE:
6460 case GST_VIDEO_FORMAT_I422_10BE:
6461 case GST_VIDEO_FORMAT_I422_10LE:
6462 case GST_VIDEO_FORMAT_Y444_10BE:
6463 case GST_VIDEO_FORMAT_Y444_10LE:
6464 case GST_VIDEO_FORMAT_I420_12BE:
6465 case GST_VIDEO_FORMAT_I420_12LE:
6466 case GST_VIDEO_FORMAT_I422_12BE:
6467 case GST_VIDEO_FORMAT_I422_12LE:
6468 case GST_VIDEO_FORMAT_Y444_12BE:
6469 case GST_VIDEO_FORMAT_Y444_12LE:
6470 case GST_VIDEO_FORMAT_GBR_10BE:
6471 case GST_VIDEO_FORMAT_GBR_10LE:
6472 case GST_VIDEO_FORMAT_GBRA_10BE:
6473 case GST_VIDEO_FORMAT_GBRA_10LE:
6474 case GST_VIDEO_FORMAT_GBR_12BE:
6475 case GST_VIDEO_FORMAT_GBR_12LE:
6476 case GST_VIDEO_FORMAT_GBRA_12BE:
6477 case GST_VIDEO_FORMAT_GBRA_12LE:
6478 case GST_VIDEO_FORMAT_NV12_64Z32:
6479 case GST_VIDEO_FORMAT_NV12_4L4:
6480 case GST_VIDEO_FORMAT_NV12_32L32:
6481 case GST_VIDEO_FORMAT_A420_10BE:
6482 case GST_VIDEO_FORMAT_A420_10LE:
6483 case GST_VIDEO_FORMAT_A422_10BE:
6484 case GST_VIDEO_FORMAT_A422_10LE:
6485 case GST_VIDEO_FORMAT_A444_10BE:
6486 case GST_VIDEO_FORMAT_A444_10LE:
6487 case GST_VIDEO_FORMAT_P010_10BE:
6488 case GST_VIDEO_FORMAT_P010_10LE:
6489 case GST_VIDEO_FORMAT_GRAY10_LE32:
6490 case GST_VIDEO_FORMAT_NV12_10LE32:
6491 case GST_VIDEO_FORMAT_NV16_10LE32:
6492 case GST_VIDEO_FORMAT_NV12_10LE40:
6493 case GST_VIDEO_FORMAT_BGR10A2_LE:
6494 case GST_VIDEO_FORMAT_RGB10A2_LE:
6495 case GST_VIDEO_FORMAT_Y444_16BE:
6496 case GST_VIDEO_FORMAT_Y444_16LE:
6497 case GST_VIDEO_FORMAT_P016_BE:
6498 case GST_VIDEO_FORMAT_P016_LE:
6499 case GST_VIDEO_FORMAT_P012_BE:
6500 case GST_VIDEO_FORMAT_P012_LE:
6501 case GST_VIDEO_FORMAT_Y212_BE:
6502 case GST_VIDEO_FORMAT_Y212_LE:
6503 case GST_VIDEO_FORMAT_Y412_BE:
6504 case GST_VIDEO_FORMAT_Y412_LE:
6506 g_assert_not_reached ();
6513 is_merge_yuv (GstVideoInfo * info)
6515 switch (GST_VIDEO_INFO_FORMAT (info)) {
6516 case GST_VIDEO_FORMAT_YUY2:
6517 case GST_VIDEO_FORMAT_YVYU:
6518 case GST_VIDEO_FORMAT_UYVY:
6519 case GST_VIDEO_FORMAT_VYUY:
6527 setup_scale (GstVideoConverter * convert)
6530 gint method, cr_method, in_width, in_height, out_width, out_height;
6532 GstVideoInfo *in_info, *out_info;
6533 const GstVideoFormatInfo *in_finfo, *out_finfo;
6534 GstVideoFormat in_format, out_format;
6535 gboolean interlaced;
6536 guint n_threads = convert->conversion_runner->n_threads;
6538 in_info = &convert->in_info;
6539 out_info = &convert->out_info;
6541 in_finfo = in_info->finfo;
6542 out_finfo = out_info->finfo;
6544 n_planes = GST_VIDEO_INFO_N_PLANES (out_info);
6546 interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info);
6548 method = GET_OPT_RESAMPLER_METHOD (convert);
6549 if (method == GST_VIDEO_RESAMPLER_METHOD_NEAREST)
6552 cr_method = GET_OPT_CHROMA_RESAMPLER_METHOD (convert);
6553 taps = GET_OPT_RESAMPLER_TAPS (convert);
6555 in_format = GST_VIDEO_INFO_FORMAT (in_info);
6556 out_format = GST_VIDEO_INFO_FORMAT (out_info);
6558 switch (in_format) {
6559 case GST_VIDEO_FORMAT_RGB15:
6560 case GST_VIDEO_FORMAT_RGB16:
6561 case GST_VIDEO_FORMAT_BGR15:
6562 case GST_VIDEO_FORMAT_BGR16:
6563 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
6564 case GST_VIDEO_FORMAT_GRAY16_BE:
6566 case GST_VIDEO_FORMAT_GRAY16_LE:
6568 if (method != GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6569 GST_DEBUG ("%s only with nearest resampling",
6570 gst_video_format_to_string (in_format));
6578 in_width = convert->in_width;
6579 in_height = convert->in_height;
6580 out_width = convert->out_width;
6581 out_height = convert->out_height;
6583 if (n_planes == 1 && !GST_VIDEO_FORMAT_INFO_IS_GRAY (out_finfo)) {
6587 if (is_merge_yuv (in_info)) {
6588 GstVideoScaler *y_scaler, *uv_scaler;
6590 if (in_width != out_width) {
6591 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6592 for (j = 0; j < n_threads; j++) {
6594 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6595 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_Y,
6596 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
6597 GST_VIDEO_COMP_Y, out_width), convert->config);
6599 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE,
6600 gst_video_scaler_get_max_taps (y_scaler),
6601 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_U,
6602 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
6603 GST_VIDEO_COMP_U, out_width), convert->config);
6605 convert->fh_scaler[0].scaler[j] =
6606 gst_video_scaler_combine_packed_YUV (y_scaler, uv_scaler,
6607 in_format, out_format);
6609 gst_video_scaler_free (y_scaler);
6610 gst_video_scaler_free (uv_scaler);
6613 convert->fh_scaler[0].scaler = NULL;
6616 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_Y);
6617 convert->fin_x[0] = GST_ROUND_UP_2 (convert->in_x) * pstride;
6618 convert->fout_x[0] = GST_ROUND_UP_2 (convert->out_x) * pstride;
6621 if (in_width != out_width && in_width != 0 && out_width != 0) {
6622 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6623 for (j = 0; j < n_threads; j++) {
6624 convert->fh_scaler[0].scaler[j] =
6625 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6626 in_width, out_width, convert->config);
6629 convert->fh_scaler[0].scaler = NULL;
6632 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_R);
6633 convert->fin_x[0] = convert->in_x * pstride;
6634 convert->fout_x[0] = convert->out_x * pstride;
6637 if (in_height != out_height && in_height != 0 && out_height != 0) {
6638 convert->fv_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6640 for (j = 0; j < n_threads; j++) {
6641 convert->fv_scaler[0].scaler[j] =
6642 gst_video_scaler_new (method,
6644 GST_VIDEO_SCALER_FLAG_INTERLACED : GST_VIDEO_SCALER_FLAG_NONE, taps,
6645 in_height, out_height, convert->config);
6648 convert->fv_scaler[0].scaler = NULL;
6651 convert->fin_y[0] = convert->in_y;
6652 convert->fout_y[0] = convert->out_y;
6653 convert->fout_width[0] = out_width;
6654 convert->fout_height[0] = out_height;
6655 convert->fconvert[0] = convert_plane_hv;
6656 convert->fformat[0] = get_scale_format (in_format, 0);
6657 convert->fsplane[0] = 0;
6659 for (i = 0; i < n_planes; i++) {
6660 gint comp, n_comp, j, iw, ih, ow, oh, pstride;
6661 gboolean need_v_scaler, need_h_scaler;
6662 GstStructure *config;
6663 gint resample_method;
6665 n_comp = GST_VIDEO_FORMAT_INFO_N_COMPONENTS (in_finfo);
6667 /* find the component in this plane and map it to the plane of
6670 for (j = 0; j < n_comp; j++) {
6671 if (GST_VIDEO_FORMAT_INFO_PLANE (out_finfo, j) == i) {
6677 iw = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, i, in_width);
6678 ih = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, i, in_height);
6679 ow = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, i, out_width);
6680 oh = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, i, out_height);
6682 GST_DEBUG ("plane %d: %dx%d -> %dx%d", i, iw, ih, ow, oh);
6684 convert->fout_width[i] = ow;
6685 convert->fout_height[i] = oh;
6687 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, i);
6689 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, i, convert->in_x);
6690 convert->fin_x[i] *= pstride;
6692 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, i, convert->in_y);
6693 convert->fout_x[i] =
6694 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, i, convert->out_x);
6695 convert->fout_x[i] *= pstride;
6696 convert->fout_y[i] =
6697 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, i, convert->out_y);
6699 GST_DEBUG ("plane %d: pstride %d", i, pstride);
6700 GST_DEBUG ("plane %d: in_x %d, in_y %d", i, convert->fin_x[i],
6702 GST_DEBUG ("plane %d: out_x %d, out_y %d", i, convert->fout_x[i],
6703 convert->fout_y[i]);
6706 convert->fconvert[i] = convert_plane_fill;
6707 if (GST_VIDEO_INFO_IS_YUV (out_info)) {
6709 convert->ffill[i] = convert->alpha_value;
6711 convert->ffill[i] = 0x00;
6713 convert->ffill[i] = 0x80;
6716 convert->ffill[i] = convert->alpha_value;
6718 convert->ffill[i] = 0x00;
6720 GST_DEBUG ("plane %d fill %02x", i, convert->ffill[i]);
6723 convert->fsplane[i] = GST_VIDEO_FORMAT_INFO_PLANE (in_finfo, comp);
6724 GST_DEBUG ("plane %d -> %d (comp %d)", i, convert->fsplane[i], comp);
6727 config = gst_structure_copy (convert->config);
6729 resample_method = (i == 0 ? method : cr_method);
6731 need_v_scaler = FALSE;
6732 need_h_scaler = FALSE;
6734 if (!interlaced && ih == oh) {
6735 convert->fconvert[i] = convert_plane_hv;
6736 GST_DEBUG ("plane %d: copy", i);
6737 } else if (!interlaced && ih == 2 * oh && pstride == 1
6738 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6739 convert->fconvert[i] = convert_plane_v_halve;
6740 GST_DEBUG ("plane %d: vertical halve", i);
6741 } else if (!interlaced && 2 * ih == oh && pstride == 1
6742 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6743 convert->fconvert[i] = convert_plane_v_double;
6744 GST_DEBUG ("plane %d: vertical double", i);
6746 convert->fconvert[i] = convert_plane_hv;
6747 GST_DEBUG ("plane %d: vertical scale", i);
6748 need_v_scaler = TRUE;
6750 } else if (ih == oh) {
6751 if (!interlaced && iw == 2 * ow && pstride == 1
6752 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6753 convert->fconvert[i] = convert_plane_h_halve;
6754 GST_DEBUG ("plane %d: horizontal halve", i);
6755 } else if (!interlaced && 2 * iw == ow && pstride == 1
6756 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6757 convert->fconvert[i] = convert_plane_h_double;
6758 GST_DEBUG ("plane %d: horizontal double", i);
6760 convert->fconvert[i] = convert_plane_hv;
6761 GST_DEBUG ("plane %d: horizontal scale", i);
6762 need_h_scaler = TRUE;
6765 if (!interlaced && iw == 2 * ow && ih == 2 * oh && pstride == 1
6766 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6767 convert->fconvert[i] = convert_plane_hv_halve;
6768 GST_DEBUG ("plane %d: horizontal/vertical halve", i);
6769 } else if (!interlaced && 2 * iw == ow && 2 * ih == oh && pstride == 1
6770 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6771 convert->fconvert[i] = convert_plane_hv_double;
6772 GST_DEBUG ("plane %d: horizontal/vertical double", i);
6774 convert->fconvert[i] = convert_plane_hv;
6775 GST_DEBUG ("plane %d: horizontal/vertical scale", i);
6776 need_v_scaler = TRUE;
6777 need_h_scaler = TRUE;
6781 if (need_h_scaler && iw != 0 && ow != 0) {
6782 convert->fh_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
6784 for (j = 0; j < n_threads; j++) {
6785 convert->fh_scaler[i].scaler[j] =
6786 gst_video_scaler_new (resample_method, GST_VIDEO_SCALER_FLAG_NONE,
6787 taps, iw, ow, config);
6790 convert->fh_scaler[i].scaler = NULL;
6793 if (need_v_scaler && ih != 0 && oh != 0) {
6794 convert->fv_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
6796 for (j = 0; j < n_threads; j++) {
6797 convert->fv_scaler[i].scaler[j] =
6798 gst_video_scaler_new (resample_method,
6800 GST_VIDEO_SCALER_FLAG_INTERLACED : GST_VIDEO_SCALER_FLAG_NONE,
6801 taps, ih, oh, config);
6804 convert->fv_scaler[i].scaler = NULL;
6807 gst_structure_free (config);
6808 convert->fformat[i] = get_scale_format (in_format, i);
6819 GstVideoFormat in_format;
6820 GstVideoFormat out_format;
6821 gboolean keeps_interlaced;
6822 gboolean needs_color_matrix;
6823 gboolean keeps_size;
6826 gboolean alpha_copy;
6828 gboolean alpha_mult;
6829 gint width_align, height_align;
6830 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
6831 GstVideoFrame * dest);
6834 static const VideoTransform transforms[] = {
6835 /* planar -> packed */
6836 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
6837 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
6838 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
6839 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
6840 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
6841 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
6843 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
6844 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
6845 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
6846 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
6847 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
6848 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
6850 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6851 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_YUY2},
6852 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6853 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_UYVY},
6854 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6855 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_Y42B_AYUV},
6857 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6858 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_YUY2},
6859 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6860 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_UYVY},
6861 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6862 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_Y444_AYUV},
6864 /* packed -> packed */
6865 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, FALSE, TRUE,
6866 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6867 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6868 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2}, /* alias */
6869 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6870 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_YUY2_AYUV},
6872 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, FALSE, TRUE,
6873 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6874 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6875 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2},
6876 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6877 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_UYVY_AYUV},
6879 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, FALSE, TRUE, TRUE,
6880 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6881 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6882 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_YUY2},
6883 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6884 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_UYVY},
6886 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
6887 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_v210_UYVY},
6888 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
6889 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_v210_YUY2},
6891 /* packed -> planar */
6892 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
6893 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
6894 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
6895 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
6896 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6897 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y42B},
6898 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6899 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y444},
6900 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_GRAY8, TRUE, TRUE, TRUE, TRUE,
6901 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_GRAY8},
6903 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
6904 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
6905 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
6906 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
6907 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6908 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y42B},
6909 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6910 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y444},
6912 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_I420, FALSE, FALSE, TRUE, TRUE,
6913 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
6914 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, TRUE, TRUE,
6915 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
6916 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6917 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_Y42B},
6918 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6919 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_AYUV_Y444},
6921 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
6922 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_v210_I420},
6923 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
6924 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_v210_I420},
6925 {GST_VIDEO_FORMAT_v210, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, FALSE,
6926 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_v210_Y42B},
6928 /* planar -> planar */
6929 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_I420, TRUE, FALSE, FALSE, TRUE,
6930 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6931 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, FALSE, TRUE,
6932 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6933 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6934 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6935 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6936 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6937 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6938 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6939 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6940 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6941 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6942 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6943 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6944 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6945 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6946 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6948 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_I420, TRUE, FALSE, FALSE, TRUE,
6949 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6950 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, FALSE, TRUE,
6951 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6952 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6953 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6954 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6955 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6956 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6957 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6958 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6959 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6960 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6961 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6962 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6963 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6964 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6965 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6967 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6968 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6969 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6970 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6971 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y41B, TRUE, FALSE, FALSE, TRUE,
6972 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6973 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6974 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6975 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6976 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6977 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6978 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6979 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6980 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6981 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6982 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6983 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6984 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6986 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6987 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6988 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6989 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6990 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6991 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6992 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, FALSE, TRUE,
6993 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6994 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6995 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6996 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6997 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6998 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6999 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7000 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7001 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7002 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7003 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7005 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7006 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7007 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7008 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7009 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7010 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7011 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7012 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7013 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, FALSE, TRUE,
7014 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7015 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7016 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7017 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7018 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7019 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7020 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7021 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7022 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7024 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7025 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7026 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7027 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7028 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7029 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7030 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7031 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7032 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7033 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7034 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_GRAY8, TRUE, FALSE, FALSE, TRUE,
7035 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7036 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7037 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7038 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7039 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7040 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7041 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7043 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7044 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7045 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7046 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7047 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7048 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7049 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7050 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7051 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7052 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7053 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7054 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7055 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_A420, TRUE, FALSE, FALSE, TRUE,
7056 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7057 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
7058 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7059 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
7060 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7062 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7063 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7064 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7065 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7066 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7067 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7068 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7069 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7070 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7071 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7072 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7073 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7074 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7075 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7076 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YUV9, TRUE, FALSE, FALSE, TRUE,
7077 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7078 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YVU9, TRUE, FALSE, FALSE, TRUE,
7079 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7081 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
7082 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7083 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
7084 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7085 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
7086 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7087 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
7088 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7089 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
7090 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7091 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
7092 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7093 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
7094 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
7095 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YUV9, TRUE, FALSE, FALSE, TRUE,
7096 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7097 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YVU9, TRUE, FALSE, FALSE, TRUE,
7098 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7100 /* sempiplanar -> semiplanar */
7101 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
7102 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7103 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
7104 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7105 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
7106 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7108 {GST_VIDEO_FORMAT_NV21, GST_VIDEO_FORMAT_NV21, TRUE, FALSE, FALSE, TRUE,
7109 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7111 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
7112 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7113 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
7114 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7115 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
7116 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7118 {GST_VIDEO_FORMAT_NV61, GST_VIDEO_FORMAT_NV61, TRUE, FALSE, FALSE, TRUE,
7119 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7121 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
7122 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7123 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
7124 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7125 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
7126 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7128 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
7129 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ARGB, TRUE, TRUE, TRUE, TRUE, TRUE,
7130 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB},
7131 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRA, TRUE, TRUE, TRUE, TRUE, TRUE,
7132 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA},
7133 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xRGB, TRUE, TRUE, TRUE, TRUE, TRUE,
7134 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB}, /* alias */
7135 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRx, TRUE, TRUE, TRUE, TRUE, TRUE,
7136 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA}, /* alias */
7137 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ABGR, TRUE, TRUE, TRUE, TRUE, TRUE,
7138 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR},
7139 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBA, TRUE, TRUE, TRUE, TRUE, TRUE,
7140 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA},
7141 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xBGR, TRUE, TRUE, TRUE, TRUE, TRUE,
7142 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR}, /* alias */
7143 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBx, TRUE, TRUE, TRUE, TRUE, TRUE,
7144 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA}, /* alias */
7147 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
7148 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
7149 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
7150 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
7151 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
7152 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
7153 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
7154 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
7156 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
7157 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
7158 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
7159 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
7160 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
7161 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
7162 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
7163 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
7165 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
7166 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7167 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
7168 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7169 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
7170 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7171 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
7172 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7173 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
7174 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7175 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
7176 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7177 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
7178 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7179 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
7180 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7181 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
7182 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7183 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
7184 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7186 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
7187 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7188 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
7189 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7190 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
7191 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7192 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
7193 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7194 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
7195 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7196 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
7197 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7198 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
7199 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7200 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
7201 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7202 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
7203 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7204 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
7205 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
7208 {GST_VIDEO_FORMAT_GBR, GST_VIDEO_FORMAT_GBR, TRUE, FALSE, FALSE, TRUE,
7209 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7210 {GST_VIDEO_FORMAT_GBRA, GST_VIDEO_FORMAT_GBRA, TRUE, FALSE, FALSE, TRUE,
7211 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7213 {GST_VIDEO_FORMAT_YVYU, GST_VIDEO_FORMAT_YVYU, TRUE, FALSE, FALSE, TRUE,
7214 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7216 {GST_VIDEO_FORMAT_RGB15, GST_VIDEO_FORMAT_RGB15, TRUE, FALSE, FALSE, TRUE,
7217 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7218 {GST_VIDEO_FORMAT_RGB16, GST_VIDEO_FORMAT_RGB16, TRUE, FALSE, FALSE, TRUE,
7219 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7220 {GST_VIDEO_FORMAT_BGR15, GST_VIDEO_FORMAT_BGR15, TRUE, FALSE, FALSE, TRUE,
7221 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7222 {GST_VIDEO_FORMAT_BGR16, GST_VIDEO_FORMAT_BGR16, TRUE, FALSE, FALSE, TRUE,
7223 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7225 {GST_VIDEO_FORMAT_RGB, GST_VIDEO_FORMAT_RGB, TRUE, FALSE, FALSE, TRUE, TRUE,
7226 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7227 {GST_VIDEO_FORMAT_BGR, GST_VIDEO_FORMAT_BGR, TRUE, FALSE, FALSE, TRUE, TRUE,
7228 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7229 {GST_VIDEO_FORMAT_v308, GST_VIDEO_FORMAT_v308, TRUE, FALSE, FALSE, TRUE, TRUE,
7230 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7231 {GST_VIDEO_FORMAT_IYU2, GST_VIDEO_FORMAT_IYU2, TRUE, FALSE, FALSE, TRUE, TRUE,
7232 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7234 {GST_VIDEO_FORMAT_ARGB, GST_VIDEO_FORMAT_ARGB, TRUE, FALSE, FALSE, TRUE, TRUE,
7235 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7236 {GST_VIDEO_FORMAT_xRGB, GST_VIDEO_FORMAT_xRGB, TRUE, FALSE, FALSE, TRUE, TRUE,
7237 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7238 {GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_ABGR, TRUE, FALSE, FALSE, TRUE, TRUE,
7239 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7240 {GST_VIDEO_FORMAT_xBGR, GST_VIDEO_FORMAT_xBGR, TRUE, FALSE, FALSE, TRUE, TRUE,
7241 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7242 {GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_RGBA, TRUE, FALSE, FALSE, TRUE, TRUE,
7243 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7244 {GST_VIDEO_FORMAT_RGBx, GST_VIDEO_FORMAT_RGBx, TRUE, FALSE, FALSE, TRUE, TRUE,
7245 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7246 {GST_VIDEO_FORMAT_BGRA, GST_VIDEO_FORMAT_BGRA, TRUE, FALSE, FALSE, TRUE, TRUE,
7247 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7248 {GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_BGRx, TRUE, FALSE, FALSE, TRUE, TRUE,
7249 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7251 {GST_VIDEO_FORMAT_ARGB64, GST_VIDEO_FORMAT_ARGB64, TRUE, FALSE, FALSE, TRUE,
7252 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7253 {GST_VIDEO_FORMAT_AYUV64, GST_VIDEO_FORMAT_AYUV64, TRUE, FALSE, FALSE, TRUE,
7254 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
7256 {GST_VIDEO_FORMAT_GRAY16_LE, GST_VIDEO_FORMAT_GRAY16_LE, TRUE, FALSE, FALSE,
7257 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7258 {GST_VIDEO_FORMAT_GRAY16_BE, GST_VIDEO_FORMAT_GRAY16_BE, TRUE, FALSE, FALSE,
7259 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
7263 video_converter_lookup_fastpath (GstVideoConverter * convert)
7266 GstVideoFormat in_format, out_format;
7267 GstVideoTransferFunction in_transf, out_transf;
7268 gboolean interlaced, same_matrix, same_primaries, same_size, crop, border;
7269 gboolean need_copy, need_set, need_mult;
7271 guint in_bpp, out_bpp;
7273 width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
7274 height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);
7276 if (GET_OPT_DITHER_QUANTIZATION (convert) != 1)
7279 in_bpp = convert->in_info.finfo->bits;
7280 out_bpp = convert->out_info.finfo->bits;
7282 /* we don't do gamma conversion in fastpath */
7283 in_transf = convert->in_info.colorimetry.transfer;
7284 out_transf = convert->out_info.colorimetry.transfer;
7286 same_size = (width == convert->out_width && height == convert->out_height);
7288 /* fastpaths don't do gamma */
7289 if (CHECK_GAMMA_REMAP (convert) && (!same_size
7290 || !gst_video_transfer_function_is_equivalent (in_transf, in_bpp,
7291 out_transf, out_bpp)))
7294 need_copy = (convert->alpha_mode & ALPHA_MODE_COPY) == ALPHA_MODE_COPY;
7295 need_set = (convert->alpha_mode & ALPHA_MODE_SET) == ALPHA_MODE_SET;
7296 need_mult = (convert->alpha_mode & ALPHA_MODE_MULT) == ALPHA_MODE_MULT;
7297 GST_DEBUG ("alpha copy %d, set %d, mult %d", need_copy, need_set, need_mult);
7299 in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
7300 out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
7302 if (CHECK_MATRIX_NONE (convert)) {
7305 GstVideoColorMatrix in_matrix, out_matrix;
7307 in_matrix = convert->in_info.colorimetry.matrix;
7308 out_matrix = convert->out_info.colorimetry.matrix;
7309 same_matrix = in_matrix == out_matrix;
7312 if (CHECK_PRIMARIES_NONE (convert)) {
7313 same_primaries = TRUE;
7315 GstVideoColorPrimaries in_primaries, out_primaries;
7317 in_primaries = convert->in_info.colorimetry.primaries;
7318 out_primaries = convert->out_info.colorimetry.primaries;
7319 same_primaries = in_primaries == out_primaries;
7322 interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info);
7323 interlaced |= GST_VIDEO_INFO_IS_INTERLACED (&convert->out_info);
7325 crop = convert->in_x || convert->in_y
7326 || convert->in_width < convert->in_maxwidth
7327 || convert->in_height < convert->in_maxheight;
7328 border = convert->out_x || convert->out_y
7329 || convert->out_width < convert->out_maxwidth
7330 || convert->out_height < convert->out_maxheight;
7332 for (i = 0; i < G_N_ELEMENTS (transforms); i++) {
7333 if (transforms[i].in_format == in_format &&
7334 transforms[i].out_format == out_format &&
7335 (transforms[i].keeps_interlaced || !interlaced) &&
7336 (transforms[i].needs_color_matrix || (same_matrix && same_primaries))
7337 && (!transforms[i].keeps_size || same_size)
7338 && (transforms[i].width_align & width) == 0
7339 && (transforms[i].height_align & height) == 0
7340 && (transforms[i].do_crop || !crop)
7341 && (transforms[i].do_border || !border)
7342 && (transforms[i].alpha_copy || !need_copy)
7343 && (transforms[i].alpha_set || !need_set)
7344 && (transforms[i].alpha_mult || !need_mult)) {
7347 GST_DEBUG ("using fastpath");
7348 if (transforms[i].needs_color_matrix)
7349 video_converter_compute_matrix (convert);
7350 convert->convert = transforms[i].convert;
7353 g_new (guint16 *, convert->conversion_runner->n_threads);
7354 for (j = 0; j < convert->conversion_runner->n_threads; j++)
7355 convert->tmpline[j] = g_malloc0 (sizeof (guint16) * (width + 8) * 4);
7357 if (!transforms[i].keeps_size)
7358 if (!setup_scale (convert))
7361 setup_borderline (convert);
7365 GST_DEBUG ("no fastpath found");