2 * Copyright (C) 2010 David Schleef <ds@schleef.org>
3 * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
32 #include "video-converter.h"
37 #include <gst/allocators/gsttizenmemory.h>
39 #include "video-orc.h"
42 * SECTION:videoconverter
43 * @title: GstVideoConverter
44 * @short_description: Generic video conversion
46 * This object is used to convert video frames from one format to another.
47 * The object can perform conversion of:
59 * (c) (convert Y'CbCr to R'G'B')
62 * (f) colorspace convert through XYZ
65 * (i) (convert R'G'B' to Y'CbCr)
66 * (j) chroma downsample
71 * (a) range truncate, range expand
72 * (b) full upsample, 1-1 non-cosited upsample, no upsample
80 * (j) 1-1 cosited downsample, no downsample
84 * 1 : a -> -> -> -> e -> f -> g -> -> -> -> k
85 * 2 : a -> -> -> -> e -> f* -> g -> -> -> -> k
86 * 3 : a -> -> -> -> e* -> f* -> g* -> -> -> -> k
87 * 4 : a -> b -> -> -> e -> f -> g -> -> -> j -> k
88 * 5 : a -> b -> -> -> e* -> f* -> g* -> -> -> j -> k
89 * 6 : a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k
90 * 7 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
92 * 8 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
93 * 9 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
94 * 10 : a -> b -> c -> d -> e* -> f* -> g* -> h -> i -> j -> k
97 #ifndef GST_DISABLE_GST_DEBUG
98 #define GST_CAT_DEFAULT ensure_debug_category()
99 static GstDebugCategory *
100 ensure_debug_category (void)
102 static gsize cat_gonce = 0;
104 if (g_once_init_enter (&cat_gonce)) {
107 cat_done = (gsize) _gst_debug_category_new ("video-converter", 0,
108 "video-converter object");
110 g_once_init_leave (&cat_gonce, cat_done);
113 return (GstDebugCategory *) cat_gonce;
116 #define ensure_debug_category() /* NOOP */
117 #endif /* GST_DISABLE_GST_DEBUG */
119 typedef void (*GstParallelizedTaskFunc) (gpointer user_data);
121 typedef struct _GstParallelizedTaskRunner GstParallelizedTaskRunner;
122 typedef struct _GstParallelizedTaskThread GstParallelizedTaskThread;
124 struct _GstParallelizedTaskThread
126 GstParallelizedTaskRunner *runner;
131 struct _GstParallelizedTaskRunner
135 GstParallelizedTaskThread *threads;
137 GstParallelizedTaskFunc func;
141 GCond cond_todo, cond_done;
147 gst_parallelized_task_thread_func (gpointer data)
149 GstParallelizedTaskThread *self = data;
154 pthread_t thread = pthread_self ();
159 CPU_SET (self->idx, &cpuset);
160 if ((r = pthread_setaffinity_np (thread, sizeof (cpuset), &cpuset)) != 0)
161 GST_ERROR ("Failed to set thread affinity for thread %d: %s", self->idx,
167 g_mutex_lock (&self->runner->lock);
168 self->runner->n_done++;
169 if (self->runner->n_done == self->runner->n_threads - 1)
170 g_cond_signal (&self->runner->cond_done);
175 while (self->runner->n_todo == -1 && !self->runner->quit)
176 g_cond_wait (&self->runner->cond_todo, &self->runner->lock);
178 if (self->runner->quit)
181 idx = self->runner->n_todo--;
182 g_assert (self->runner->n_todo >= -1);
183 g_mutex_unlock (&self->runner->lock);
185 g_assert (self->runner->func != NULL);
187 self->runner->func (self->runner->task_data[idx]);
189 g_mutex_lock (&self->runner->lock);
190 self->runner->n_done++;
191 if (self->runner->n_done == self->runner->n_threads - 1)
192 g_cond_signal (&self->runner->cond_done);
195 g_mutex_unlock (&self->runner->lock);
201 gst_parallelized_task_runner_free (GstParallelizedTaskRunner * self)
205 g_mutex_lock (&self->lock);
207 g_cond_broadcast (&self->cond_todo);
208 g_mutex_unlock (&self->lock);
210 for (i = 1; i < self->n_threads; i++) {
211 if (!self->threads[i].thread)
214 g_thread_join (self->threads[i].thread);
217 g_mutex_clear (&self->lock);
218 g_cond_clear (&self->cond_todo);
219 g_cond_clear (&self->cond_done);
220 g_free (self->threads);
224 static GstParallelizedTaskRunner *
225 gst_parallelized_task_runner_new (guint n_threads)
227 GstParallelizedTaskRunner *self;
232 n_threads = g_get_num_processors ();
234 self = g_new0 (GstParallelizedTaskRunner, 1);
235 self->n_threads = n_threads;
236 self->threads = g_new0 (GstParallelizedTaskThread, n_threads);
241 g_mutex_init (&self->lock);
242 g_cond_init (&self->cond_todo);
243 g_cond_init (&self->cond_done);
245 /* Set when scheduling a job */
247 self->task_data = NULL;
249 for (i = 0; i < n_threads; i++) {
250 self->threads[i].runner = self;
251 self->threads[i].idx = i;
253 /* First thread is the one calling run() */
255 self->threads[i].thread =
256 g_thread_try_new ("videoconvert", gst_parallelized_task_thread_func,
257 &self->threads[i], &err);
258 if (!self->threads[i].thread)
263 g_mutex_lock (&self->lock);
264 while (self->n_done < self->n_threads - 1)
265 g_cond_wait (&self->cond_done, &self->lock);
267 g_mutex_unlock (&self->lock);
273 GST_ERROR ("Failed to start thread %u: %s", i, err->message);
274 g_clear_error (&err);
276 gst_parallelized_task_runner_free (self);
282 gst_parallelized_task_runner_run (GstParallelizedTaskRunner * self,
283 GstParallelizedTaskFunc func, gpointer * task_data)
285 guint n_threads = self->n_threads;
288 self->task_data = task_data;
291 g_mutex_lock (&self->lock);
292 self->n_todo = self->n_threads - 2;
294 g_cond_broadcast (&self->cond_todo);
295 g_mutex_unlock (&self->lock);
298 self->func (self->task_data[self->n_threads - 1]);
301 g_mutex_lock (&self->lock);
302 while (self->n_done < self->n_threads - 1)
303 g_cond_wait (&self->cond_done, &self->lock);
305 g_mutex_unlock (&self->lock);
309 self->task_data = NULL;
312 typedef struct _GstLineCache GstLineCache;
315 #define SCALE_F ((float) (1 << SCALE))
317 typedef struct _MatrixData MatrixData;
332 void (*matrix_func) (MatrixData * data, gpointer pixels);
335 typedef struct _GammaData GammaData;
339 gpointer gamma_table;
341 void (*gamma_func) (GammaData * data, gpointer dest, gpointer src);
347 ALPHA_MODE_COPY = (1 << 0),
348 ALPHA_MODE_SET = (1 << 1),
349 ALPHA_MODE_MULT = (1 << 2)
359 GDestroyNotify notify;
362 typedef void (*FastConvertFunc) (GstVideoConverter * convert,
363 const GstVideoFrame * src, GstVideoFrame * dest, gint plane);
365 struct _GstVideoConverter
369 GstVideoInfo in_info;
370 GstVideoInfo out_info;
385 gint current_pstride;
388 GstVideoFormat current_format;
391 GstStructure *config;
393 GstParallelizedTaskRunner *conversion_runner;
397 gboolean fill_border;
402 AlphaMode alpha_mode;
404 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
405 GstVideoFrame * dest);
407 /* data for unpack */
408 GstLineCache **unpack_lines;
409 GstVideoFormat unpack_format;
412 gboolean identity_unpack;
415 /* chroma upsample */
416 GstLineCache **upsample_lines;
417 GstVideoChromaResample **upsample;
418 GstVideoChromaResample **upsample_p;
419 GstVideoChromaResample **upsample_i;
424 GstLineCache **to_RGB_lines;
425 MatrixData to_RGB_matrix;
430 GstLineCache **hscale_lines;
431 GstVideoScaler **h_scaler;
433 GstLineCache **vscale_lines;
434 GstVideoScaler **v_scaler;
435 GstVideoScaler **v_scaler_p;
436 GstVideoScaler **v_scaler_i;
440 /* color space conversion */
441 GstLineCache **convert_lines;
442 MatrixData convert_matrix;
446 /* alpha correction */
447 GstLineCache **alpha_lines;
448 void (*alpha_func) (GstVideoConverter * convert, gpointer pixels, gint width);
453 GstLineCache **to_YUV_lines;
454 MatrixData to_YUV_matrix;
456 /* chroma downsample */
457 GstLineCache **downsample_lines;
458 GstVideoChromaResample **downsample;
459 GstVideoChromaResample **downsample_p;
460 GstVideoChromaResample **downsample_i;
465 GstLineCache **dither_lines;
466 GstVideoDither **dither;
469 GstLineCache **pack_lines;
471 GstVideoFormat pack_format;
474 gboolean identity_pack;
476 gconstpointer pack_pal;
479 const GstVideoFrame *src;
483 GstVideoFormat fformat[4];
495 GstVideoScaler **scaler;
499 GstVideoScaler **scaler;
501 FastConvertFunc fconvert[4];
504 typedef gpointer (*GstLineCacheAllocLineFunc) (GstLineCache * cache, gint idx,
506 typedef gboolean (*GstLineCacheNeedLineFunc) (GstLineCache * cache, gint idx,
507 gint out_line, gint in_line, gpointer user_data);
516 gboolean write_input;
518 gboolean alloc_writable;
520 GstLineCacheNeedLineFunc need_line;
522 gpointer need_line_data;
523 GDestroyNotify need_line_notify;
527 GstLineCacheAllocLineFunc alloc_line;
528 gpointer alloc_line_data;
529 GDestroyNotify alloc_line_notify;
532 static GstLineCache *
533 gst_line_cache_new (GstLineCache * prev)
535 GstLineCache *result;
537 result = g_slice_new0 (GstLineCache);
538 result->lines = g_ptr_array_new ();
545 gst_line_cache_clear (GstLineCache * cache)
547 g_return_if_fail (cache != NULL);
549 g_ptr_array_set_size (cache->lines, 0);
554 gst_line_cache_free (GstLineCache * cache)
556 if (cache->need_line_notify)
557 cache->need_line_notify (cache->need_line_data);
558 if (cache->alloc_line_notify)
559 cache->alloc_line_notify (cache->alloc_line_data);
560 gst_line_cache_clear (cache);
561 g_ptr_array_unref (cache->lines);
562 g_slice_free (GstLineCache, cache);
566 gst_line_cache_set_need_line_func (GstLineCache * cache,
567 GstLineCacheNeedLineFunc need_line, gint idx, gpointer user_data,
568 GDestroyNotify notify)
570 cache->need_line = need_line;
571 cache->need_line_idx = idx;
572 cache->need_line_data = user_data;
573 cache->need_line_notify = notify;
577 gst_line_cache_set_alloc_line_func (GstLineCache * cache,
578 GstLineCacheAllocLineFunc alloc_line, gpointer user_data,
579 GDestroyNotify notify)
581 cache->alloc_line = alloc_line;
582 cache->alloc_line_data = user_data;
583 cache->alloc_line_notify = notify;
586 /* keep this much backlog for interlaced video */
590 gst_line_cache_get_lines (GstLineCache * cache, gint idx, gint out_line,
591 gint in_line, gint n_lines)
593 if (cache->first + cache->backlog < in_line) {
595 MIN (in_line - (cache->first + cache->backlog), cache->lines->len);
597 g_ptr_array_remove_range (cache->lines, 0, to_remove);
599 cache->first += to_remove;
600 } else if (in_line < cache->first) {
601 gst_line_cache_clear (cache);
602 cache->first = in_line;
608 if (cache->first <= in_line
609 && in_line + n_lines <= cache->first + (gint) cache->lines->len) {
610 return cache->lines->pdata + (in_line - cache->first);
613 if (cache->need_line == NULL)
616 oline = out_line + cache->first + cache->lines->len - in_line;
618 if (!cache->need_line (cache, idx, oline, cache->first + cache->lines->len,
619 cache->need_line_data))
622 GST_DEBUG ("no lines");
627 gst_line_cache_add_line (GstLineCache * cache, gint idx, gpointer line)
629 if (cache->first + cache->lines->len != idx) {
630 gst_line_cache_clear (cache);
633 g_ptr_array_add (cache->lines, line);
637 gst_line_cache_alloc_line (GstLineCache * cache, gint idx)
641 if (cache->alloc_line)
642 res = cache->alloc_line (cache, idx, cache->alloc_line_data);
649 static void video_converter_generic (GstVideoConverter * convert,
650 const GstVideoFrame * src, GstVideoFrame * dest);
651 static gboolean video_converter_lookup_fastpath (GstVideoConverter * convert);
652 static void video_converter_compute_matrix (GstVideoConverter * convert);
653 static void video_converter_compute_resample (GstVideoConverter * convert,
656 static gpointer get_dest_line (GstLineCache * cache, gint idx,
659 static gboolean do_unpack_lines (GstLineCache * cache, gint idx, gint out_line,
660 gint in_line, gpointer user_data);
661 static gboolean do_downsample_lines (GstLineCache * cache, gint idx,
662 gint out_line, gint in_line, gpointer user_data);
663 static gboolean do_convert_to_RGB_lines (GstLineCache * cache, gint idx,
664 gint out_line, gint in_line, gpointer user_data);
665 static gboolean do_convert_lines (GstLineCache * cache, gint idx, gint out_line,
666 gint in_line, gpointer user_data);
667 static gboolean do_alpha_lines (GstLineCache * cache, gint idx, gint out_line,
668 gint in_line, gpointer user_data);
669 static gboolean do_convert_to_YUV_lines (GstLineCache * cache, gint idx,
670 gint out_line, gint in_line, gpointer user_data);
671 static gboolean do_upsample_lines (GstLineCache * cache, gint idx,
672 gint out_line, gint in_line, gpointer user_data);
673 static gboolean do_vscale_lines (GstLineCache * cache, gint idx, gint out_line,
674 gint in_line, gpointer user_data);
675 static gboolean do_hscale_lines (GstLineCache * cache, gint idx, gint out_line,
676 gint in_line, gpointer user_data);
677 static gboolean do_dither_lines (GstLineCache * cache, gint idx, gint out_line,
678 gint in_line, gpointer user_data);
680 static ConverterAlloc *
681 converter_alloc_new (guint stride, guint n_lines, gpointer user_data,
682 GDestroyNotify notify)
684 ConverterAlloc *alloc;
686 GST_DEBUG ("stride %d, n_lines %d", stride, n_lines);
687 alloc = g_slice_new0 (ConverterAlloc);
688 alloc->data = g_malloc (stride * n_lines);
689 alloc->stride = stride;
690 alloc->n_lines = n_lines;
692 alloc->user_data = user_data;
693 alloc->notify = notify;
699 converter_alloc_free (ConverterAlloc * alloc)
702 alloc->notify (alloc->user_data);
703 g_free (alloc->data);
704 g_slice_free (ConverterAlloc, alloc);
708 setup_border_alloc (GstVideoConverter * convert, ConverterAlloc * alloc)
712 if (convert->borderline) {
713 for (i = 0; i < alloc->n_lines; i++)
714 memcpy (&alloc->data[i * alloc->stride], convert->borderline,
720 get_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
722 ConverterAlloc *alloc = user_data;
725 GST_DEBUG ("get temp line %d (%p %d)", idx, alloc, alloc->idx);
726 tmpline = &alloc->data[alloc->stride * alloc->idx];
727 alloc->idx = (alloc->idx + 1) % alloc->n_lines;
733 get_border_temp_line (GstLineCache * cache, gint idx, gpointer user_data)
735 ConverterAlloc *alloc = user_data;
736 GstVideoConverter *convert = alloc->user_data;
739 GST_DEBUG ("get temp line %d (%p %d)", idx, alloc, alloc->idx);
740 tmpline = &alloc->data[alloc->stride * alloc->idx] +
741 (convert->out_x * convert->pack_pstride);
742 alloc->idx = (alloc->idx + 1) % alloc->n_lines;
748 get_opt_int (GstVideoConverter * convert, const gchar * opt, gint def)
751 if (!gst_structure_get_int (convert->config, opt, &res))
757 get_opt_uint (GstVideoConverter * convert, const gchar * opt, guint def)
760 if (!gst_structure_get_uint (convert->config, opt, &res))
766 get_opt_double (GstVideoConverter * convert, const gchar * opt, gdouble def)
769 if (!gst_structure_get_double (convert->config, opt, &res))
775 get_opt_bool (GstVideoConverter * convert, const gchar * opt, gboolean def)
778 if (!gst_structure_get_boolean (convert->config, opt, &res))
784 get_opt_enum (GstVideoConverter * convert, const gchar * opt, GType type,
788 if (!gst_structure_get_enum (convert->config, opt, type, &res))
793 #define DEFAULT_OPT_FILL_BORDER TRUE
794 #define DEFAULT_OPT_ALPHA_VALUE 1.0
795 /* options copy, set, mult */
796 #define DEFAULT_OPT_ALPHA_MODE GST_VIDEO_ALPHA_MODE_COPY
797 #define DEFAULT_OPT_BORDER_ARGB 0xff000000
798 /* options full, input-only, output-only, none */
799 #define DEFAULT_OPT_MATRIX_MODE GST_VIDEO_MATRIX_MODE_FULL
801 #define DEFAULT_OPT_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
802 /* none, merge-only, fast */
803 #define DEFAULT_OPT_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
804 /* options full, upsample-only, downsample-only, none */
805 #define DEFAULT_OPT_CHROMA_MODE GST_VIDEO_CHROMA_MODE_FULL
806 #define DEFAULT_OPT_RESAMPLER_METHOD GST_VIDEO_RESAMPLER_METHOD_CUBIC
807 #define DEFAULT_OPT_CHROMA_RESAMPLER_METHOD GST_VIDEO_RESAMPLER_METHOD_LINEAR
808 #define DEFAULT_OPT_RESAMPLER_TAPS 0
809 #define DEFAULT_OPT_DITHER_METHOD GST_VIDEO_DITHER_BAYER
810 #define DEFAULT_OPT_DITHER_QUANTIZATION 1
812 #define GET_OPT_FILL_BORDER(c) get_opt_bool(c, \
813 GST_VIDEO_CONVERTER_OPT_FILL_BORDER, DEFAULT_OPT_FILL_BORDER)
814 #define GET_OPT_ALPHA_VALUE(c) get_opt_double(c, \
815 GST_VIDEO_CONVERTER_OPT_ALPHA_VALUE, DEFAULT_OPT_ALPHA_VALUE)
816 #define GET_OPT_ALPHA_MODE(c) get_opt_enum(c, \
817 GST_VIDEO_CONVERTER_OPT_ALPHA_MODE, GST_TYPE_VIDEO_ALPHA_MODE, DEFAULT_OPT_ALPHA_MODE)
818 #define GET_OPT_BORDER_ARGB(c) get_opt_uint(c, \
819 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB)
820 #define GET_OPT_MATRIX_MODE(c) get_opt_enum(c, \
821 GST_VIDEO_CONVERTER_OPT_MATRIX_MODE, GST_TYPE_VIDEO_MATRIX_MODE, DEFAULT_OPT_MATRIX_MODE)
822 #define GET_OPT_GAMMA_MODE(c) get_opt_enum(c, \
823 GST_VIDEO_CONVERTER_OPT_GAMMA_MODE, GST_TYPE_VIDEO_GAMMA_MODE, DEFAULT_OPT_GAMMA_MODE)
824 #define GET_OPT_PRIMARIES_MODE(c) get_opt_enum(c, \
825 GST_VIDEO_CONVERTER_OPT_PRIMARIES_MODE, GST_TYPE_VIDEO_PRIMARIES_MODE, DEFAULT_OPT_PRIMARIES_MODE)
826 #define GET_OPT_CHROMA_MODE(c) get_opt_enum(c, \
827 GST_VIDEO_CONVERTER_OPT_CHROMA_MODE, GST_TYPE_VIDEO_CHROMA_MODE, DEFAULT_OPT_CHROMA_MODE)
828 #define GET_OPT_RESAMPLER_METHOD(c) get_opt_enum(c, \
829 GST_VIDEO_CONVERTER_OPT_RESAMPLER_METHOD, GST_TYPE_VIDEO_RESAMPLER_METHOD, \
830 DEFAULT_OPT_RESAMPLER_METHOD)
831 #define GET_OPT_CHROMA_RESAMPLER_METHOD(c) get_opt_enum(c, \
832 GST_VIDEO_CONVERTER_OPT_CHROMA_RESAMPLER_METHOD, GST_TYPE_VIDEO_RESAMPLER_METHOD, \
833 DEFAULT_OPT_CHROMA_RESAMPLER_METHOD)
834 #define GET_OPT_RESAMPLER_TAPS(c) get_opt_uint(c, \
835 GST_VIDEO_CONVERTER_OPT_RESAMPLER_TAPS, DEFAULT_OPT_RESAMPLER_TAPS)
836 #define GET_OPT_DITHER_METHOD(c) get_opt_enum(c, \
837 GST_VIDEO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_VIDEO_DITHER_METHOD, \
838 DEFAULT_OPT_DITHER_METHOD)
839 #define GET_OPT_DITHER_QUANTIZATION(c) get_opt_uint(c, \
840 GST_VIDEO_CONVERTER_OPT_DITHER_QUANTIZATION, DEFAULT_OPT_DITHER_QUANTIZATION)
842 #define CHECK_ALPHA_COPY(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_COPY)
843 #define CHECK_ALPHA_SET(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_SET)
844 #define CHECK_ALPHA_MULT(c) (GET_OPT_ALPHA_MODE(c) == GST_VIDEO_ALPHA_MODE_MULT)
846 #define CHECK_MATRIX_FULL(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_FULL)
847 #define CHECK_MATRIX_INPUT(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_INPUT_ONLY)
848 #define CHECK_MATRIX_OUTPUT(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_OUTPUT_ONLY)
849 #define CHECK_MATRIX_NONE(c) (GET_OPT_MATRIX_MODE(c) == GST_VIDEO_MATRIX_MODE_NONE)
851 #define CHECK_GAMMA_NONE(c) (GET_OPT_GAMMA_MODE(c) == GST_VIDEO_GAMMA_MODE_NONE)
852 #define CHECK_GAMMA_REMAP(c) (GET_OPT_GAMMA_MODE(c) == GST_VIDEO_GAMMA_MODE_REMAP)
854 #define CHECK_PRIMARIES_NONE(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_NONE)
855 #define CHECK_PRIMARIES_MERGE(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_MERGE_ONLY)
856 #define CHECK_PRIMARIES_FAST(c) (GET_OPT_PRIMARIES_MODE(c) == GST_VIDEO_PRIMARIES_MODE_FAST)
858 #define CHECK_CHROMA_FULL(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_FULL)
859 #define CHECK_CHROMA_UPSAMPLE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_UPSAMPLE_ONLY)
860 #define CHECK_CHROMA_DOWNSAMPLE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_DOWNSAMPLE_ONLY)
861 #define CHECK_CHROMA_NONE(c) (GET_OPT_CHROMA_MODE(c) == GST_VIDEO_CHROMA_MODE_NONE)
863 static GstLineCache *
864 chain_unpack_line (GstVideoConverter * convert, gint idx)
869 info = &convert->in_info;
871 convert->current_format = convert->unpack_format;
872 convert->current_bits = convert->unpack_bits;
873 convert->current_pstride = convert->current_bits >> 1;
875 convert->unpack_pstride = convert->current_pstride;
876 convert->identity_unpack = (convert->current_format == info->finfo->format);
878 GST_DEBUG ("chain unpack line format %s, pstride %d, identity_unpack %d",
879 gst_video_format_to_string (convert->current_format),
880 convert->current_pstride, convert->identity_unpack);
882 prev = convert->unpack_lines[idx] = gst_line_cache_new (NULL);
883 prev->write_input = FALSE;
884 prev->pass_alloc = FALSE;
886 prev->stride = convert->current_pstride * convert->current_width;
887 gst_line_cache_set_need_line_func (prev, do_unpack_lines, idx, convert, NULL);
892 static GstLineCache *
893 chain_upsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
895 video_converter_compute_resample (convert, idx);
897 if (convert->upsample_p[idx] || convert->upsample_i[idx]) {
898 GST_DEBUG ("chain upsample");
899 prev = convert->upsample_lines[idx] = gst_line_cache_new (prev);
900 prev->write_input = TRUE;
901 prev->pass_alloc = TRUE;
903 prev->stride = convert->current_pstride * convert->current_width;
904 gst_line_cache_set_need_line_func (prev,
905 do_upsample_lines, idx, convert, NULL);
911 color_matrix_set_identity (MatrixData * m)
915 for (i = 0; i < 4; i++) {
916 for (j = 0; j < 4; j++) {
917 m->dm[i][j] = (i == j);
923 color_matrix_copy (MatrixData * d, const MatrixData * s)
927 for (i = 0; i < 4; i++)
928 for (j = 0; j < 4; j++)
929 d->dm[i][j] = s->dm[i][j];
932 /* Perform 4x4 matrix multiplication:
933 * - @dst@ = @a@ * @b@
934 * - @dst@ may be a pointer to @a@ andor @b@
937 color_matrix_multiply (MatrixData * dst, MatrixData * a, MatrixData * b)
942 for (i = 0; i < 4; i++) {
943 for (j = 0; j < 4; j++) {
945 for (k = 0; k < 4; k++) {
946 x += a->dm[i][k] * b->dm[k][j];
951 color_matrix_copy (dst, &tmp);
955 color_matrix_invert (MatrixData * d, MatrixData * s)
961 color_matrix_set_identity (&tmp);
962 for (j = 0; j < 3; j++) {
963 for (i = 0; i < 3; i++) {
965 s->dm[(i + 1) % 3][(j + 1) % 3] * s->dm[(i + 2) % 3][(j + 2) % 3] -
966 s->dm[(i + 1) % 3][(j + 2) % 3] * s->dm[(i + 2) % 3][(j + 1) % 3];
970 tmp.dm[0][0] * s->dm[0][0] + tmp.dm[0][1] * s->dm[1][0] +
971 tmp.dm[0][2] * s->dm[2][0];
972 for (j = 0; j < 3; j++) {
973 for (i = 0; i < 3; i++) {
977 color_matrix_copy (d, &tmp);
981 color_matrix_offset_components (MatrixData * m, double a1, double a2, double a3)
985 color_matrix_set_identity (&a);
989 color_matrix_multiply (m, &a, m);
993 color_matrix_scale_components (MatrixData * m, double a1, double a2, double a3)
997 color_matrix_set_identity (&a);
1001 color_matrix_multiply (m, &a, m);
1005 color_matrix_debug (const MatrixData * s)
1007 GST_DEBUG ("[%f %f %f %f]", s->dm[0][0], s->dm[0][1], s->dm[0][2],
1009 GST_DEBUG ("[%f %f %f %f]", s->dm[1][0], s->dm[1][1], s->dm[1][2],
1011 GST_DEBUG ("[%f %f %f %f]", s->dm[2][0], s->dm[2][1], s->dm[2][2],
1013 GST_DEBUG ("[%f %f %f %f]", s->dm[3][0], s->dm[3][1], s->dm[3][2],
1018 color_matrix_convert (MatrixData * s)
1022 for (i = 0; i < 4; i++)
1023 for (j = 0; j < 4; j++)
1024 s->im[i][j] = rint (s->dm[i][j]);
1026 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[0][0], s->im[0][1], s->im[0][2],
1028 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[1][0], s->im[1][1], s->im[1][2],
1030 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[2][0], s->im[2][1], s->im[2][2],
1032 GST_DEBUG ("[%6d %6d %6d %6d]", s->im[3][0], s->im[3][1], s->im[3][2],
1037 color_matrix_YCbCr_to_RGB (MatrixData * m, double Kr, double Kb)
1039 double Kg = 1.0 - Kr - Kb;
1042 {1., 0., 2 * (1 - Kr), 0.},
1043 {1., -2 * Kb * (1 - Kb) / Kg, -2 * Kr * (1 - Kr) / Kg, 0.},
1044 {1., 2 * (1 - Kb), 0., 0.},
1049 color_matrix_multiply (m, &k, m);
1053 color_matrix_RGB_to_YCbCr (MatrixData * m, double Kr, double Kb)
1055 double Kg = 1.0 - Kr - Kb;
1064 x = 1 / (2 * (1 - Kb));
1065 k.dm[1][0] = -x * Kr;
1066 k.dm[1][1] = -x * Kg;
1067 k.dm[1][2] = x * (1 - Kb);
1070 x = 1 / (2 * (1 - Kr));
1071 k.dm[2][0] = x * (1 - Kr);
1072 k.dm[2][1] = -x * Kg;
1073 k.dm[2][2] = -x * Kb;
1081 color_matrix_multiply (m, &k, m);
1085 color_matrix_RGB_to_XYZ (MatrixData * dst, double Rx, double Ry, double Gx,
1086 double Gy, double Bx, double By, double Wx, double Wy)
1092 color_matrix_set_identity (&m);
1096 m.dm[2][0] = (1.0 - Rx - Ry);
1099 m.dm[2][1] = (1.0 - Gx - Gy);
1102 m.dm[2][2] = (1.0 - Bx - By);
1104 color_matrix_invert (&im, &m);
1108 wz = (1.0 - Wx - Wy) / Wy;
1110 sx = im.dm[0][0] * wx + im.dm[0][1] * wy + im.dm[0][2] * wz;
1111 sy = im.dm[1][0] * wx + im.dm[1][1] * wy + im.dm[1][2] * wz;
1112 sz = im.dm[2][0] * wx + im.dm[2][1] * wy + im.dm[2][2] * wz;
1124 color_matrix_copy (dst, &m);
1128 videoconvert_convert_init_tables (MatrixData * data)
1132 data->t_r = g_new (gint64, 256);
1133 data->t_g = g_new (gint64, 256);
1134 data->t_b = g_new (gint64, 256);
1136 for (i = 0; i < 256; i++) {
1137 gint64 r = 0, g = 0, b = 0;
1139 for (j = 0; j < 3; j++) {
1140 r = (r << 16) + data->im[j][0] * i;
1141 g = (g << 16) + data->im[j][1] * i;
1142 b = (b << 16) + data->im[j][2] * i;
1148 data->t_c = ((gint64) data->im[0][3] << 32)
1149 + ((gint64) data->im[1][3] << 16)
1150 + ((gint64) data->im[2][3] << 0);
1154 _custom_video_orc_matrix8 (guint8 * ORC_RESTRICT d1,
1155 const guint8 * ORC_RESTRICT s1, orc_int64 p1, orc_int64 p2, orc_int64 p3,
1156 orc_int64 p4, int n)
1161 gint a00, a01, a02, a03;
1162 gint a10, a11, a12, a13;
1163 gint a20, a21, a22, a23;
1165 a00 = (gint16) (p1 >> 16);
1166 a01 = (gint16) (p2 >> 16);
1167 a02 = (gint16) (p3 >> 16);
1168 a03 = (gint16) (p4 >> 16);
1169 a10 = (gint16) (p1 >> 32);
1170 a11 = (gint16) (p2 >> 32);
1171 a12 = (gint16) (p3 >> 32);
1172 a13 = (gint16) (p4 >> 32);
1173 a20 = (gint16) (p1 >> 48);
1174 a21 = (gint16) (p2 >> 48);
1175 a22 = (gint16) (p3 >> 48);
1176 a23 = (gint16) (p4 >> 48);
1178 for (i = 0; i < n; i++) {
1183 y = ((a00 * r + a01 * g + a02 * b) >> SCALE) + a03;
1184 u = ((a10 * r + a11 * g + a12 * b) >> SCALE) + a13;
1185 v = ((a20 * r + a21 * g + a22 * b) >> SCALE) + a23;
1187 d1[i * 4 + 1] = CLAMP (y, 0, 255);
1188 d1[i * 4 + 2] = CLAMP (u, 0, 255);
1189 d1[i * 4 + 3] = CLAMP (v, 0, 255);
1194 video_converter_matrix8 (MatrixData * data, gpointer pixels)
1196 video_orc_matrix8 (pixels, pixels, data->orc_p1, data->orc_p2,
1197 data->orc_p3, data->orc_p4, data->width);
1201 video_converter_matrix8_table (MatrixData * data, gpointer pixels)
1203 gint i, width = data->width * 4;
1205 gint64 c = data->t_c;
1209 for (i = 0; i < width; i += 4) {
1214 x = data->t_r[r] + data->t_g[g] + data->t_b[b] + c;
1216 p[i + 1] = x >> (32 + SCALE);
1217 p[i + 2] = x >> (16 + SCALE);
1218 p[i + 3] = x >> (0 + SCALE);
1223 video_converter_matrix8_AYUV_ARGB (MatrixData * data, gpointer pixels)
1225 video_orc_convert_AYUV_ARGB (pixels, 0, pixels, 0,
1226 data->im[0][0], data->im[0][2],
1227 data->im[2][1], data->im[1][1], data->im[1][2], data->width, 1);
1231 is_ayuv_to_rgb_matrix (MatrixData * data)
1233 if (data->im[0][0] != data->im[1][0] || data->im[1][0] != data->im[2][0])
1236 if (data->im[0][1] != 0 || data->im[2][2] != 0)
1243 is_identity_matrix (MatrixData * data)
1246 gint c = data->im[0][0];
1248 /* not really checking identity because of rounding errors but given
1249 * the conversions we do we just check for anything that looks like:
1256 for (i = 0; i < 4; i++) {
1257 for (j = 0; j < 4; j++) {
1259 if (i == 3 && data->im[i][j] != 1)
1261 else if (data->im[i][j] != c)
1263 } else if (data->im[i][j] != 0)
1271 is_no_clip_matrix (MatrixData * data)
1274 static const guint8 test[8][3] = {
1285 for (i = 0; i < 8; i++) {
1293 y = (data->im[0][0] * r + data->im[0][1] * g +
1294 data->im[0][2] * b + data->im[0][3]) >> SCALE;
1295 u = (data->im[1][0] * r + data->im[1][1] * g +
1296 data->im[1][2] * b + data->im[1][3]) >> SCALE;
1297 v = (data->im[2][0] * r + data->im[2][1] * g +
1298 data->im[2][2] * b + data->im[2][3]) >> SCALE;
1300 if (y != CLAMP (y, 0, 255) || u != CLAMP (u, 0, 255)
1301 || v != CLAMP (v, 0, 255))
1308 video_converter_matrix16 (MatrixData * data, gpointer pixels)
1313 guint16 *p = pixels;
1314 gint width = data->width;
1316 for (i = 0; i < width; i++) {
1321 y = (data->im[0][0] * r + data->im[0][1] * g +
1322 data->im[0][2] * b + data->im[0][3]) >> SCALE;
1323 u = (data->im[1][0] * r + data->im[1][1] * g +
1324 data->im[1][2] * b + data->im[1][3]) >> SCALE;
1325 v = (data->im[2][0] * r + data->im[2][1] * g +
1326 data->im[2][2] * b + data->im[2][3]) >> SCALE;
1328 p[i * 4 + 1] = CLAMP (y, 0, 65535);
1329 p[i * 4 + 2] = CLAMP (u, 0, 65535);
1330 p[i * 4 + 3] = CLAMP (v, 0, 65535);
1336 prepare_matrix (GstVideoConverter * convert, MatrixData * data)
1338 if (is_identity_matrix (data))
1341 color_matrix_scale_components (data, SCALE_F, SCALE_F, SCALE_F);
1342 color_matrix_convert (data);
1344 data->width = convert->current_width;
1346 if (convert->current_bits == 8) {
1347 if (!convert->unpack_rgb && convert->pack_rgb
1348 && is_ayuv_to_rgb_matrix (data)) {
1349 GST_DEBUG ("use fast AYUV -> RGB matrix");
1350 data->matrix_func = video_converter_matrix8_AYUV_ARGB;
1351 } else if (is_no_clip_matrix (data)) {
1352 GST_DEBUG ("use 8bit table");
1353 data->matrix_func = video_converter_matrix8_table;
1354 videoconvert_convert_init_tables (data);
1358 GST_DEBUG ("use 8bit matrix");
1359 data->matrix_func = video_converter_matrix8;
1361 data->orc_p1 = (((guint64) (guint16) data->im[2][0]) << 48) |
1362 (((guint64) (guint16) data->im[1][0]) << 32) |
1363 (((guint64) (guint16) data->im[0][0]) << 16);
1364 data->orc_p2 = (((guint64) (guint16) data->im[2][1]) << 48) |
1365 (((guint64) (guint16) data->im[1][1]) << 32) |
1366 (((guint64) (guint16) data->im[0][1]) << 16);
1367 data->orc_p3 = (((guint64) (guint16) data->im[2][2]) << 48) |
1368 (((guint64) (guint16) data->im[1][2]) << 32) |
1369 (((guint64) (guint16) data->im[0][2]) << 16);
1371 a03 = data->im[0][3] >> SCALE;
1372 a13 = data->im[1][3] >> SCALE;
1373 a23 = data->im[2][3] >> SCALE;
1375 data->orc_p4 = (((guint64) (guint16) a23) << 48) |
1376 (((guint64) (guint16) a13) << 32) | (((guint64) (guint16) a03) << 16);
1379 GST_DEBUG ("use 16bit matrix");
1380 data->matrix_func = video_converter_matrix16;
1385 compute_matrix_to_RGB (GstVideoConverter * convert, MatrixData * data)
1388 gdouble Kr = 0, Kb = 0;
1390 info = &convert->in_info;
1393 const GstVideoFormatInfo *uinfo;
1394 gint offset[4], scale[4];
1396 uinfo = gst_video_format_get_info (convert->unpack_format);
1398 /* bring color components to [0..1.0] range */
1399 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1402 color_matrix_offset_components (data, -offset[0], -offset[1], -offset[2]);
1403 color_matrix_scale_components (data, 1 / ((float) scale[0]),
1404 1 / ((float) scale[1]), 1 / ((float) scale[2]));
1407 if (!convert->unpack_rgb && !CHECK_MATRIX_NONE (convert)) {
1408 if (CHECK_MATRIX_OUTPUT (convert))
1409 info = &convert->out_info;
1411 /* bring components to R'G'B' space */
1412 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
1413 color_matrix_YCbCr_to_RGB (data, Kr, Kb);
1415 color_matrix_debug (data);
1419 compute_matrix_to_YUV (GstVideoConverter * convert, MatrixData * data,
1423 gdouble Kr = 0, Kb = 0;
1425 if (force || (!convert->pack_rgb && !CHECK_MATRIX_NONE (convert))) {
1426 if (CHECK_MATRIX_INPUT (convert))
1427 info = &convert->in_info;
1429 info = &convert->out_info;
1431 /* bring components to YCbCr space */
1432 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
1433 color_matrix_RGB_to_YCbCr (data, Kr, Kb);
1436 info = &convert->out_info;
1439 const GstVideoFormatInfo *uinfo;
1440 gint offset[4], scale[4];
1442 uinfo = gst_video_format_get_info (convert->pack_format);
1444 /* bring color components to nominal range */
1445 gst_video_color_range_offsets (info->colorimetry.range, uinfo, offset,
1448 color_matrix_scale_components (data, (float) scale[0], (float) scale[1],
1450 color_matrix_offset_components (data, offset[0], offset[1], offset[2]);
1453 color_matrix_debug (data);
1458 gamma_convert_u8_u16 (GammaData * data, gpointer dest, gpointer src)
1463 guint16 *table = data->gamma_table;
1464 gint width = data->width * 4;
1466 for (i = 0; i < width; i += 4) {
1467 d[i + 0] = (s[i] << 8) | s[i];
1468 d[i + 1] = table[s[i + 1]];
1469 d[i + 2] = table[s[i + 2]];
1470 d[i + 3] = table[s[i + 3]];
1475 gamma_convert_u16_u8 (GammaData * data, gpointer dest, gpointer src)
1480 guint8 *table = data->gamma_table;
1481 gint width = data->width * 4;
1483 for (i = 0; i < width; i += 4) {
1484 d[i + 0] = s[i] >> 8;
1485 d[i + 1] = table[s[i + 1]];
1486 d[i + 2] = table[s[i + 2]];
1487 d[i + 3] = table[s[i + 3]];
1492 gamma_convert_u16_u16 (GammaData * data, gpointer dest, gpointer src)
1497 guint16 *table = data->gamma_table;
1498 gint width = data->width * 4;
1500 for (i = 0; i < width; i += 4) {
1502 d[i + 1] = table[s[i + 1]];
1503 d[i + 2] = table[s[i + 2]];
1504 d[i + 3] = table[s[i + 3]];
1509 setup_gamma_decode (GstVideoConverter * convert)
1511 GstVideoTransferFunction func;
1515 func = convert->in_info.colorimetry.transfer;
1517 convert->gamma_dec.width = convert->current_width;
1518 if (convert->current_bits == 8) {
1519 GST_DEBUG ("gamma decode 8->16: %d", func);
1520 convert->gamma_dec.gamma_func = gamma_convert_u8_u16;
1521 t = convert->gamma_dec.gamma_table = g_malloc (sizeof (guint16) * 256);
1523 for (i = 0; i < 256; i++)
1524 t[i] = rint (gst_video_color_transfer_decode (func, i / 255.0) * 65535.0);
1526 GST_DEBUG ("gamma decode 16->16: %d", func);
1527 convert->gamma_dec.gamma_func = gamma_convert_u16_u16;
1528 t = convert->gamma_dec.gamma_table = g_malloc (sizeof (guint16) * 65536);
1530 for (i = 0; i < 65536; i++)
1532 rint (gst_video_color_transfer_decode (func, i / 65535.0) * 65535.0);
1534 convert->current_bits = 16;
1535 convert->current_pstride = 8;
1536 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1540 setup_gamma_encode (GstVideoConverter * convert, gint target_bits)
1542 GstVideoTransferFunction func;
1545 func = convert->out_info.colorimetry.transfer;
1547 convert->gamma_enc.width = convert->current_width;
1548 if (target_bits == 8) {
1551 GST_DEBUG ("gamma encode 16->8: %d", func);
1552 convert->gamma_enc.gamma_func = gamma_convert_u16_u8;
1553 t = convert->gamma_enc.gamma_table = g_malloc (sizeof (guint8) * 65536);
1555 for (i = 0; i < 65536; i++)
1556 t[i] = rint (gst_video_color_transfer_encode (func, i / 65535.0) * 255.0);
1560 GST_DEBUG ("gamma encode 16->16: %d", func);
1561 convert->gamma_enc.gamma_func = gamma_convert_u16_u16;
1562 t = convert->gamma_enc.gamma_table = g_malloc (sizeof (guint16) * 65536);
1564 for (i = 0; i < 65536; i++)
1566 rint (gst_video_color_transfer_encode (func, i / 65535.0) * 65535.0);
1570 static GstLineCache *
1571 chain_convert_to_RGB (GstVideoConverter * convert, GstLineCache * prev,
1576 do_gamma = CHECK_GAMMA_REMAP (convert);
1581 if (!convert->unpack_rgb) {
1582 color_matrix_set_identity (&convert->to_RGB_matrix);
1583 compute_matrix_to_RGB (convert, &convert->to_RGB_matrix);
1585 /* matrix is in 0..1 range, scale to current bits */
1586 GST_DEBUG ("chain RGB convert");
1587 scale = 1 << convert->current_bits;
1588 color_matrix_scale_components (&convert->to_RGB_matrix,
1589 (float) scale, (float) scale, (float) scale);
1591 prepare_matrix (convert, &convert->to_RGB_matrix);
1593 if (convert->current_bits == 8)
1594 convert->current_format = GST_VIDEO_FORMAT_ARGB;
1596 convert->current_format = GST_VIDEO_FORMAT_ARGB64;
1599 prev = convert->to_RGB_lines[idx] = gst_line_cache_new (prev);
1600 prev->write_input = TRUE;
1601 prev->pass_alloc = FALSE;
1603 prev->stride = convert->current_pstride * convert->current_width;
1604 gst_line_cache_set_need_line_func (prev,
1605 do_convert_to_RGB_lines, idx, convert, NULL);
1607 GST_DEBUG ("chain gamma decode");
1608 setup_gamma_decode (convert);
1613 static GstLineCache *
1614 chain_hscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1619 method = GET_OPT_RESAMPLER_METHOD (convert);
1620 taps = GET_OPT_RESAMPLER_TAPS (convert);
1622 convert->h_scaler[idx] =
1623 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
1624 convert->in_width, convert->out_width, convert->config);
1626 gst_video_scaler_get_coeff (convert->h_scaler[idx], 0, NULL, &taps);
1628 GST_DEBUG ("chain hscale %d->%d, taps %d, method %d",
1629 convert->in_width, convert->out_width, taps, method);
1631 convert->current_width = convert->out_width;
1632 convert->h_scale_format = convert->current_format;
1634 prev = convert->hscale_lines[idx] = gst_line_cache_new (prev);
1635 prev->write_input = FALSE;
1636 prev->pass_alloc = FALSE;
1638 prev->stride = convert->current_pstride * convert->current_width;
1639 gst_line_cache_set_need_line_func (prev, do_hscale_lines, idx, convert, NULL);
1644 static GstLineCache *
1645 chain_vscale (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1648 guint taps, taps_i = 0;
1651 method = GET_OPT_RESAMPLER_METHOD (convert);
1652 taps = GET_OPT_RESAMPLER_TAPS (convert);
1654 if (GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info)) {
1655 convert->v_scaler_i[idx] =
1656 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_INTERLACED,
1657 taps, convert->in_height, convert->out_height, convert->config);
1659 gst_video_scaler_get_coeff (convert->v_scaler_i[idx], 0, NULL, &taps_i);
1662 convert->v_scaler_p[idx] =
1663 gst_video_scaler_new (method, 0, taps, convert->in_height,
1664 convert->out_height, convert->config);
1665 convert->v_scale_width = convert->current_width;
1666 convert->v_scale_format = convert->current_format;
1667 convert->current_height = convert->out_height;
1669 gst_video_scaler_get_coeff (convert->v_scaler_p[idx], 0, NULL, &taps);
1671 GST_DEBUG ("chain vscale %d->%d, taps %d, method %d, backlog %d",
1672 convert->in_height, convert->out_height, taps, method, backlog);
1674 prev->backlog = backlog;
1675 prev = convert->vscale_lines[idx] = gst_line_cache_new (prev);
1676 prev->pass_alloc = (taps == 1);
1677 prev->write_input = FALSE;
1678 prev->n_lines = MAX (taps_i, taps);
1679 prev->stride = convert->current_pstride * convert->current_width;
1680 gst_line_cache_set_need_line_func (prev, do_vscale_lines, idx, convert, NULL);
1685 static GstLineCache *
1686 chain_scale (GstVideoConverter * convert, GstLineCache * prev, gboolean force,
1689 gint s0, s1, s2, s3;
1691 s0 = convert->current_width * convert->current_height;
1692 s3 = convert->out_width * convert->out_height;
1694 GST_DEBUG ("in pixels %d <> out pixels %d", s0, s3);
1696 if (s3 <= s0 || force) {
1697 /* we are making the image smaller or are forced to resample */
1698 s1 = convert->out_width * convert->current_height;
1699 s2 = convert->current_width * convert->out_height;
1701 GST_DEBUG ("%d <> %d", s1, s2);
1704 /* h scaling first produces less pixels */
1705 if (convert->current_width != convert->out_width)
1706 prev = chain_hscale (convert, prev, idx);
1707 if (convert->current_height != convert->out_height)
1708 prev = chain_vscale (convert, prev, idx);
1710 /* v scaling first produces less pixels */
1711 if (convert->current_height != convert->out_height)
1712 prev = chain_vscale (convert, prev, idx);
1713 if (convert->current_width != convert->out_width)
1714 prev = chain_hscale (convert, prev, idx);
1720 static GstLineCache *
1721 chain_convert (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1723 gboolean do_gamma, do_conversion, pass_alloc = FALSE;
1724 gboolean same_matrix, same_primaries, same_bits;
1727 same_bits = convert->unpack_bits == convert->pack_bits;
1728 if (CHECK_MATRIX_NONE (convert)) {
1732 convert->in_info.colorimetry.matrix ==
1733 convert->out_info.colorimetry.matrix;
1736 if (CHECK_PRIMARIES_NONE (convert)) {
1737 same_primaries = TRUE;
1740 convert->in_info.colorimetry.primaries ==
1741 convert->out_info.colorimetry.primaries;
1744 GST_DEBUG ("matrix %d -> %d (%d)", convert->in_info.colorimetry.matrix,
1745 convert->out_info.colorimetry.matrix, same_matrix);
1746 GST_DEBUG ("bits %d -> %d (%d)", convert->unpack_bits, convert->pack_bits,
1748 GST_DEBUG ("primaries %d -> %d (%d)", convert->in_info.colorimetry.primaries,
1749 convert->out_info.colorimetry.primaries, same_primaries);
1751 color_matrix_set_identity (&convert->convert_matrix);
1753 if (!same_primaries) {
1754 const GstVideoColorPrimariesInfo *pi;
1756 pi = gst_video_color_primaries_get_info (convert->in_info.colorimetry.
1758 color_matrix_RGB_to_XYZ (&p1, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx,
1759 pi->By, pi->Wx, pi->Wy);
1760 GST_DEBUG ("to XYZ matrix");
1761 color_matrix_debug (&p1);
1762 GST_DEBUG ("current matrix");
1763 color_matrix_multiply (&convert->convert_matrix, &convert->convert_matrix,
1765 color_matrix_debug (&convert->convert_matrix);
1767 pi = gst_video_color_primaries_get_info (convert->out_info.colorimetry.
1769 color_matrix_RGB_to_XYZ (&p2, pi->Rx, pi->Ry, pi->Gx, pi->Gy, pi->Bx,
1770 pi->By, pi->Wx, pi->Wy);
1771 color_matrix_invert (&p2, &p2);
1772 GST_DEBUG ("to RGB matrix");
1773 color_matrix_debug (&p2);
1774 color_matrix_multiply (&convert->convert_matrix, &convert->convert_matrix,
1776 GST_DEBUG ("current matrix");
1777 color_matrix_debug (&convert->convert_matrix);
1780 do_gamma = CHECK_GAMMA_REMAP (convert);
1783 convert->in_bits = convert->unpack_bits;
1784 convert->out_bits = convert->pack_bits;
1786 if (!same_bits || !same_matrix || !same_primaries) {
1787 /* no gamma, combine all conversions into 1 */
1788 if (convert->in_bits < convert->out_bits) {
1789 gint scale = 1 << (convert->out_bits - convert->in_bits);
1790 color_matrix_scale_components (&convert->convert_matrix,
1791 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
1793 GST_DEBUG ("to RGB matrix");
1794 compute_matrix_to_RGB (convert, &convert->convert_matrix);
1795 GST_DEBUG ("current matrix");
1796 color_matrix_debug (&convert->convert_matrix);
1798 GST_DEBUG ("to YUV matrix");
1799 compute_matrix_to_YUV (convert, &convert->convert_matrix, FALSE);
1800 GST_DEBUG ("current matrix");
1801 color_matrix_debug (&convert->convert_matrix);
1802 if (convert->in_bits > convert->out_bits) {
1803 gint scale = 1 << (convert->in_bits - convert->out_bits);
1804 color_matrix_scale_components (&convert->convert_matrix,
1805 (float) scale, (float) scale, (float) scale);
1807 convert->current_bits = MAX (convert->in_bits, convert->out_bits);
1809 do_conversion = TRUE;
1810 if (!same_matrix || !same_primaries)
1811 prepare_matrix (convert, &convert->convert_matrix);
1812 if (convert->in_bits == convert->out_bits)
1815 do_conversion = FALSE;
1817 convert->current_bits = convert->pack_bits;
1818 convert->current_format = convert->pack_format;
1819 convert->current_pstride = convert->current_bits >> 1;
1821 /* we did gamma, just do colorspace conversion if needed */
1822 if (same_primaries) {
1823 do_conversion = FALSE;
1825 prepare_matrix (convert, &convert->convert_matrix);
1826 convert->in_bits = convert->out_bits = 16;
1828 do_conversion = TRUE;
1832 if (do_conversion) {
1833 GST_DEBUG ("chain conversion");
1834 prev = convert->convert_lines[idx] = gst_line_cache_new (prev);
1835 prev->write_input = TRUE;
1836 prev->pass_alloc = pass_alloc;
1838 prev->stride = convert->current_pstride * convert->current_width;
1839 gst_line_cache_set_need_line_func (prev,
1840 do_convert_lines, idx, convert, NULL);
1846 convert_set_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1849 guint8 alpha = MIN (convert->alpha_value, 255);
1852 for (i = 0; i < width; i++)
1857 convert_set_alpha_u16 (GstVideoConverter * convert, gpointer pixels, gint width)
1859 guint16 *p = pixels;
1863 alpha = MIN (convert->alpha_value, 255);
1864 alpha |= alpha << 8;
1866 for (i = 0; i < width; i++)
1871 convert_mult_alpha_u8 (GstVideoConverter * convert, gpointer pixels, gint width)
1874 guint alpha = convert->alpha_value;
1877 for (i = 0; i < width; i++) {
1878 gint a = (p[i * 4] * alpha) / 255;
1879 p[i * 4] = CLAMP (a, 0, 255);
1884 convert_mult_alpha_u16 (GstVideoConverter * convert, gpointer pixels,
1887 guint16 *p = pixels;
1888 guint alpha = convert->alpha_value;
1891 for (i = 0; i < width; i++) {
1892 gint a = (p[i * 4] * alpha) / 255;
1893 p[i * 4] = CLAMP (a, 0, 65535);
1897 static GstLineCache *
1898 chain_alpha (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1900 switch (convert->alpha_mode) {
1901 case ALPHA_MODE_NONE:
1902 case ALPHA_MODE_COPY:
1905 case ALPHA_MODE_SET:
1906 if (convert->current_bits == 8)
1907 convert->alpha_func = convert_set_alpha_u8;
1909 convert->alpha_func = convert_set_alpha_u16;
1911 case ALPHA_MODE_MULT:
1912 if (convert->current_bits == 8)
1913 convert->alpha_func = convert_mult_alpha_u8;
1915 convert->alpha_func = convert_mult_alpha_u16;
1919 GST_DEBUG ("chain alpha mode %d", convert->alpha_mode);
1920 prev = convert->alpha_lines[idx] = gst_line_cache_new (prev);
1921 prev->write_input = TRUE;
1922 prev->pass_alloc = TRUE;
1924 prev->stride = convert->current_pstride * convert->current_width;
1925 gst_line_cache_set_need_line_func (prev, do_alpha_lines, idx, convert, NULL);
1930 static GstLineCache *
1931 chain_convert_to_YUV (GstVideoConverter * convert, GstLineCache * prev,
1936 do_gamma = CHECK_GAMMA_REMAP (convert);
1941 GST_DEBUG ("chain gamma encode");
1942 setup_gamma_encode (convert, convert->pack_bits);
1944 convert->current_bits = convert->pack_bits;
1945 convert->current_pstride = convert->current_bits >> 1;
1947 if (!convert->pack_rgb) {
1948 color_matrix_set_identity (&convert->to_YUV_matrix);
1949 compute_matrix_to_YUV (convert, &convert->to_YUV_matrix, FALSE);
1951 /* matrix is in 0..255 range, scale to pack bits */
1952 GST_DEBUG ("chain YUV convert");
1953 scale = 1 << convert->pack_bits;
1954 color_matrix_scale_components (&convert->to_YUV_matrix,
1955 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
1956 prepare_matrix (convert, &convert->to_YUV_matrix);
1958 convert->current_format = convert->pack_format;
1960 prev = convert->to_YUV_lines[idx] = gst_line_cache_new (prev);
1961 prev->write_input = FALSE;
1962 prev->pass_alloc = FALSE;
1964 prev->stride = convert->current_pstride * convert->current_width;
1965 gst_line_cache_set_need_line_func (prev,
1966 do_convert_to_YUV_lines, idx, convert, NULL);
1972 static GstLineCache *
1973 chain_downsample (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1975 if (convert->downsample_p[idx] || convert->downsample_i[idx]) {
1976 GST_DEBUG ("chain downsample");
1977 prev = convert->downsample_lines[idx] = gst_line_cache_new (prev);
1978 prev->write_input = TRUE;
1979 prev->pass_alloc = TRUE;
1981 prev->stride = convert->current_pstride * convert->current_width;
1982 gst_line_cache_set_need_line_func (prev,
1983 do_downsample_lines, idx, convert, NULL);
1988 static GstLineCache *
1989 chain_dither (GstVideoConverter * convert, GstLineCache * prev, gint idx)
1992 gboolean do_dither = FALSE;
1993 GstVideoDitherFlags flags = 0;
1994 GstVideoDitherMethod method;
1995 guint quant[4], target_quant;
1997 method = GET_OPT_DITHER_METHOD (convert);
1998 if (method == GST_VIDEO_DITHER_NONE)
2001 target_quant = GET_OPT_DITHER_QUANTIZATION (convert);
2002 GST_DEBUG ("method %d, target-quantization %d", method, target_quant);
2004 if (convert->pack_pal) {
2011 for (i = 0; i < GST_VIDEO_MAX_COMPONENTS; i++) {
2014 depth = convert->out_info.finfo->depth[i];
2021 if (convert->current_bits >= depth) {
2022 quant[i] = 1 << (convert->current_bits - depth);
2023 if (target_quant > quant[i]) {
2024 flags |= GST_VIDEO_DITHER_FLAG_QUANTIZE;
2025 quant[i] = target_quant;
2036 GST_DEBUG ("chain dither");
2038 convert->dither[idx] = gst_video_dither_new (method,
2039 flags, convert->pack_format, quant, convert->current_width);
2041 prev = convert->dither_lines[idx] = gst_line_cache_new (prev);
2042 prev->write_input = TRUE;
2043 prev->pass_alloc = TRUE;
2045 prev->stride = convert->current_pstride * convert->current_width;
2046 gst_line_cache_set_need_line_func (prev, do_dither_lines, idx, convert,
2052 static GstLineCache *
2053 chain_pack (GstVideoConverter * convert, GstLineCache * prev, gint idx)
2055 convert->pack_nlines = convert->out_info.finfo->pack_lines;
2056 convert->pack_pstride = convert->current_pstride;
2057 convert->identity_pack =
2058 (convert->out_info.finfo->format ==
2059 convert->out_info.finfo->unpack_format);
2060 GST_DEBUG ("chain pack line format %s, pstride %d, identity_pack %d (%d %d)",
2061 gst_video_format_to_string (convert->current_format),
2062 convert->current_pstride, convert->identity_pack,
2063 convert->out_info.finfo->format, convert->out_info.finfo->unpack_format);
2069 setup_allocators (GstVideoConverter * convert)
2071 GstLineCache *cache;
2072 GstLineCacheAllocLineFunc alloc_line;
2073 gboolean alloc_writable;
2075 GDestroyNotify notify;
2076 gint width, n_lines;
2079 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2080 width += convert->out_x;
2082 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2085 /* start with using dest lines if we can directly write into it */
2086 if (convert->identity_pack) {
2087 alloc_line = get_dest_line;
2088 alloc_writable = TRUE;
2089 user_data = convert;
2093 converter_alloc_new (sizeof (guint16) * width * 4, 4 + BACKLOG,
2095 setup_border_alloc (convert, user_data);
2096 notify = (GDestroyNotify) converter_alloc_free;
2097 alloc_line = get_border_temp_line;
2098 /* when we add a border, we need to write */
2099 alloc_writable = convert->borderline != NULL;
2102 /* now walk backwards, we try to write into the dest lines directly
2103 * and keep track if the source needs to be writable */
2104 for (cache = convert->pack_lines[i]; cache; cache = cache->prev) {
2105 gst_line_cache_set_alloc_line_func (cache, alloc_line, user_data, notify);
2106 cache->alloc_writable = alloc_writable;
2107 n_lines = MAX (n_lines, cache->n_lines);
2109 /* make sure only one cache frees the allocator */
2112 if (!cache->pass_alloc) {
2113 /* can't pass allocator, make new temp line allocator */
2115 converter_alloc_new (sizeof (guint16) * width * 4,
2116 n_lines + cache->backlog, convert, NULL);
2117 notify = (GDestroyNotify) converter_alloc_free;
2118 alloc_line = get_temp_line;
2119 alloc_writable = FALSE;
2120 n_lines = cache->n_lines;
2122 /* if someone writes to the input, we need a writable line from the
2124 if (cache->write_input)
2125 alloc_writable = TRUE;
2127 /* free leftover allocator */
2134 setup_borderline (GstVideoConverter * convert)
2138 width = MAX (convert->in_maxwidth, convert->out_maxwidth);
2139 width += convert->out_x;
2141 if (convert->fill_border && (convert->out_height < convert->out_maxheight ||
2142 convert->out_width < convert->out_maxwidth)) {
2145 const GstVideoFormatInfo *out_finfo;
2146 gpointer planes[GST_VIDEO_MAX_PLANES];
2147 gint strides[GST_VIDEO_MAX_PLANES];
2149 convert->borderline = g_malloc0 (sizeof (guint16) * width * 4);
2151 out_finfo = convert->out_info.finfo;
2153 if (GST_VIDEO_INFO_IS_YUV (&convert->out_info)) {
2158 /* Get Color matrix. */
2159 color_matrix_set_identity (&cm);
2160 compute_matrix_to_YUV (convert, &cm, TRUE);
2161 color_matrix_convert (&cm);
2163 border_val = GINT32_FROM_BE (convert->border_argb);
2165 b = (0xFF000000 & border_val) >> 24;
2166 g = (0x00FF0000 & border_val) >> 16;
2167 r = (0x0000FF00 & border_val) >> 8;
2168 a = (0x000000FF & border_val);
2170 y = 16 + ((r * cm.im[0][0] + g * cm.im[0][1] + b * cm.im[0][2]) >> 8);
2171 u = 128 + ((r * cm.im[1][0] + g * cm.im[1][1] + b * cm.im[1][2]) >> 8);
2172 v = 128 + ((r * cm.im[2][0] + g * cm.im[2][1] + b * cm.im[2][2]) >> 8);
2174 a = CLAMP (a, 0, 255);
2175 y = CLAMP (y, 0, 255);
2176 u = CLAMP (u, 0, 255);
2177 v = CLAMP (v, 0, 255);
2179 border_val = a | (y << 8) | (u << 16) | (v << 24);
2181 border_val = GINT32_FROM_BE (convert->border_argb);
2183 if (convert->pack_bits == 8)
2184 video_orc_splat_u32 (convert->borderline, border_val, width);
2186 video_orc_splat2_u64 (convert->borderline, border_val, width);
2188 /* convert pixels */
2189 for (i = 0; i < out_finfo->n_planes; i++) {
2190 planes[i] = &convert->borders[i];
2191 strides[i] = sizeof (guint64);
2194 if (out_finfo->n_planes == 1) {
2195 /* for packed formats, convert based on subsampling so that we
2196 * get a complete group of pixels */
2197 for (i = 0; i < out_finfo->n_components; i++) {
2198 w_sub = MAX (w_sub, out_finfo->w_sub[i]);
2201 out_finfo->pack_func (out_finfo, GST_VIDEO_PACK_FLAG_NONE,
2202 convert->borderline, 0, planes, strides,
2203 GST_VIDEO_CHROMA_SITE_UNKNOWN, 0, 1 << w_sub);
2205 convert->borderline = NULL;
2210 convert_get_alpha_mode (GstVideoConverter * convert)
2212 gboolean in_alpha, out_alpha;
2214 in_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->in_info);
2215 out_alpha = GST_VIDEO_INFO_HAS_ALPHA (&convert->out_info);
2217 /* no output alpha, do nothing */
2219 return ALPHA_MODE_NONE;
2223 if (CHECK_ALPHA_COPY (convert))
2224 return ALPHA_MODE_COPY;
2226 if (CHECK_ALPHA_MULT (convert)) {
2227 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2228 return ALPHA_MODE_COPY;
2230 return ALPHA_MODE_MULT;
2233 /* nothing special, this is what unpack etc does automatically */
2234 if (GET_OPT_ALPHA_VALUE (convert) == 1.0)
2235 return ALPHA_MODE_NONE;
2237 /* everything else becomes SET */
2238 return ALPHA_MODE_SET;
2242 * gst_video_converter_new: (skip)
2243 * @in_info: a #GstVideoInfo
2244 * @out_info: a #GstVideoInfo
2245 * @config: (transfer full): a #GstStructure with configuration options
2247 * Create a new converter object to convert between @in_info and @out_info
2250 * Returns: a #GstVideoConverter or %NULL if conversion is not possible.
2255 gst_video_converter_new (GstVideoInfo * in_info, GstVideoInfo * out_info,
2256 GstStructure * config)
2258 GstVideoConverter *convert;
2260 const GstVideoFormatInfo *fin, *fout, *finfo;
2261 gdouble alpha_value;
2264 g_return_val_if_fail (in_info != NULL, NULL);
2265 g_return_val_if_fail (out_info != NULL, NULL);
2266 /* we won't ever do framerate conversion */
2267 g_return_val_if_fail (in_info->fps_n == out_info->fps_n, NULL);
2268 g_return_val_if_fail (in_info->fps_d == out_info->fps_d, NULL);
2269 /* we won't ever do deinterlace */
2270 g_return_val_if_fail (in_info->interlace_mode == out_info->interlace_mode,
2273 convert = g_slice_new0 (GstVideoConverter);
2275 fin = in_info->finfo;
2276 fout = out_info->finfo;
2278 convert->in_info = *in_info;
2279 convert->out_info = *out_info;
2281 /* default config */
2282 convert->config = gst_structure_new_empty ("GstVideoConverter");
2284 gst_video_converter_set_config (convert, config);
2286 convert->in_maxwidth = GST_VIDEO_INFO_WIDTH (in_info);
2287 convert->in_maxheight = GST_VIDEO_INFO_HEIGHT (in_info);
2288 convert->out_maxwidth = GST_VIDEO_INFO_WIDTH (out_info);
2289 convert->out_maxheight = GST_VIDEO_INFO_HEIGHT (out_info);
2291 convert->in_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_X, 0);
2292 convert->in_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_SRC_Y, 0);
2293 convert->in_x &= ~((1 << fin->w_sub[1]) - 1);
2294 convert->in_y &= ~((1 << fin->h_sub[1]) - 1);
2296 convert->in_width = get_opt_int (convert,
2297 GST_VIDEO_CONVERTER_OPT_SRC_WIDTH, convert->in_maxwidth - convert->in_x);
2298 convert->in_height = get_opt_int (convert,
2299 GST_VIDEO_CONVERTER_OPT_SRC_HEIGHT,
2300 convert->in_maxheight - convert->in_y);
2303 MIN (convert->in_width, convert->in_maxwidth - convert->in_x);
2304 convert->in_height =
2305 MIN (convert->in_height, convert->in_maxheight - convert->in_y);
2307 convert->out_x = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_X, 0);
2308 convert->out_y = get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_Y, 0);
2309 convert->out_x &= ~((1 << fout->w_sub[1]) - 1);
2310 convert->out_y &= ~((1 << fout->h_sub[1]) - 1);
2312 convert->out_width = get_opt_int (convert,
2313 GST_VIDEO_CONVERTER_OPT_DEST_WIDTH,
2314 convert->out_maxwidth - convert->out_x);
2315 convert->out_height =
2316 get_opt_int (convert, GST_VIDEO_CONVERTER_OPT_DEST_HEIGHT,
2317 convert->out_maxheight - convert->out_y);
2319 convert->out_width =
2320 MIN (convert->out_width, convert->out_maxwidth - convert->out_x);
2321 convert->out_height =
2322 MIN (convert->out_height, convert->out_maxheight - convert->out_y);
2324 convert->fill_border = GET_OPT_FILL_BORDER (convert);
2325 convert->border_argb = get_opt_uint (convert,
2326 GST_VIDEO_CONVERTER_OPT_BORDER_ARGB, DEFAULT_OPT_BORDER_ARGB);
2328 alpha_value = GET_OPT_ALPHA_VALUE (convert);
2329 convert->alpha_value = 255 * alpha_value;
2330 convert->alpha_mode = convert_get_alpha_mode (convert);
2332 convert->unpack_format = in_info->finfo->unpack_format;
2333 finfo = gst_video_format_get_info (convert->unpack_format);
2334 convert->unpack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2335 convert->unpack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2336 if (convert->unpack_rgb
2337 && in_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2338 /* force identity matrix for RGB input */
2339 GST_WARNING ("invalid matrix %d for input RGB format, using RGB",
2340 in_info->colorimetry.matrix);
2341 convert->in_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2344 convert->pack_format = out_info->finfo->unpack_format;
2345 finfo = gst_video_format_get_info (convert->pack_format);
2346 convert->pack_bits = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, 0);
2347 convert->pack_rgb = GST_VIDEO_FORMAT_INFO_IS_RGB (finfo);
2349 gst_video_format_get_palette (GST_VIDEO_INFO_FORMAT (out_info),
2350 &convert->pack_palsize);
2351 if (convert->pack_rgb
2352 && out_info->colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
2353 /* force identity matrix for RGB output */
2354 GST_WARNING ("invalid matrix %d for output RGB format, using RGB",
2355 out_info->colorimetry.matrix);
2356 convert->out_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
2359 n_threads = get_opt_uint (convert, GST_VIDEO_CONVERTER_OPT_THREADS, 1);
2360 if (n_threads == 0 || n_threads > g_get_num_processors ())
2361 n_threads = g_get_num_processors ();
2362 /* Magic number of 200 lines */
2363 if (MAX (convert->out_height, convert->in_height) / n_threads < 200)
2364 n_threads = (MAX (convert->out_height, convert->in_height) + 199) / 200;
2365 convert->conversion_runner = gst_parallelized_task_runner_new (n_threads);
2367 if (video_converter_lookup_fastpath (convert))
2370 if (in_info->finfo->unpack_func == NULL)
2371 goto no_unpack_func;
2373 if (out_info->finfo->pack_func == NULL)
2376 convert->convert = video_converter_generic;
2378 convert->upsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2379 convert->upsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2380 convert->downsample_p = g_new0 (GstVideoChromaResample *, n_threads);
2381 convert->downsample_i = g_new0 (GstVideoChromaResample *, n_threads);
2382 convert->v_scaler_p = g_new0 (GstVideoScaler *, n_threads);
2383 convert->v_scaler_i = g_new0 (GstVideoScaler *, n_threads);
2384 convert->h_scaler = g_new0 (GstVideoScaler *, n_threads);
2385 convert->unpack_lines = g_new0 (GstLineCache *, n_threads);
2386 convert->pack_lines = g_new0 (GstLineCache *, n_threads);
2387 convert->upsample_lines = g_new0 (GstLineCache *, n_threads);
2388 convert->to_RGB_lines = g_new0 (GstLineCache *, n_threads);
2389 convert->hscale_lines = g_new0 (GstLineCache *, n_threads);
2390 convert->vscale_lines = g_new0 (GstLineCache *, n_threads);
2391 convert->convert_lines = g_new0 (GstLineCache *, n_threads);
2392 convert->alpha_lines = g_new0 (GstLineCache *, n_threads);
2393 convert->to_YUV_lines = g_new0 (GstLineCache *, n_threads);
2394 convert->downsample_lines = g_new0 (GstLineCache *, n_threads);
2395 convert->dither_lines = g_new0 (GstLineCache *, n_threads);
2396 convert->dither = g_new0 (GstVideoDither *, n_threads);
2398 for (i = 0; i < n_threads; i++) {
2399 convert->current_format = GST_VIDEO_INFO_FORMAT (in_info);
2400 convert->current_width = convert->in_width;
2401 convert->current_height = convert->in_height;
2404 prev = chain_unpack_line (convert, i);
2405 /* upsample chroma */
2406 prev = chain_upsample (convert, prev, i);
2407 /* convert to gamma decoded RGB */
2408 prev = chain_convert_to_RGB (convert, prev, i);
2409 /* do all downscaling */
2410 prev = chain_scale (convert, prev, FALSE, i);
2411 /* do conversion between color spaces */
2412 prev = chain_convert (convert, prev, i);
2413 /* do alpha channels */
2414 prev = chain_alpha (convert, prev, i);
2415 /* do all remaining (up)scaling */
2416 prev = chain_scale (convert, prev, TRUE, i);
2417 /* convert to gamma encoded Y'Cb'Cr' */
2418 prev = chain_convert_to_YUV (convert, prev, i);
2419 /* downsample chroma */
2420 prev = chain_downsample (convert, prev, i);
2422 prev = chain_dither (convert, prev, i);
2423 /* pack into final format */
2424 convert->pack_lines[i] = chain_pack (convert, prev, i);
2427 setup_borderline (convert);
2428 /* now figure out allocators */
2429 setup_allocators (convert);
2437 GST_ERROR ("no unpack_func for format %s",
2438 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
2439 gst_video_converter_free (convert);
2444 GST_ERROR ("no pack_func for format %s",
2445 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
2446 gst_video_converter_free (convert);
2452 clear_matrix_data (MatrixData * data)
2460 * gst_video_converter_free:
2461 * @convert: a #GstVideoConverter
2468 gst_video_converter_free (GstVideoConverter * convert)
2472 g_return_if_fail (convert != NULL);
2474 for (i = 0; i < convert->conversion_runner->n_threads; i++) {
2475 if (convert->upsample_p && convert->upsample_p[i])
2476 gst_video_chroma_resample_free (convert->upsample_p[i]);
2477 if (convert->upsample_i && convert->upsample_i[i])
2478 gst_video_chroma_resample_free (convert->upsample_i[i]);
2479 if (convert->downsample_p && convert->downsample_p[i])
2480 gst_video_chroma_resample_free (convert->downsample_p[i]);
2481 if (convert->downsample_i && convert->downsample_i[i])
2482 gst_video_chroma_resample_free (convert->downsample_i[i]);
2483 if (convert->v_scaler_p && convert->v_scaler_p[i])
2484 gst_video_scaler_free (convert->v_scaler_p[i]);
2485 if (convert->v_scaler_i && convert->v_scaler_i[i])
2486 gst_video_scaler_free (convert->v_scaler_i[i]);
2487 if (convert->h_scaler && convert->h_scaler[i])
2488 gst_video_scaler_free (convert->h_scaler[i]);
2489 if (convert->unpack_lines && convert->unpack_lines[i])
2490 gst_line_cache_free (convert->unpack_lines[i]);
2491 if (convert->upsample_lines && convert->upsample_lines[i])
2492 gst_line_cache_free (convert->upsample_lines[i]);
2493 if (convert->to_RGB_lines && convert->to_RGB_lines[i])
2494 gst_line_cache_free (convert->to_RGB_lines[i]);
2495 if (convert->hscale_lines && convert->hscale_lines[i])
2496 gst_line_cache_free (convert->hscale_lines[i]);
2497 if (convert->vscale_lines && convert->vscale_lines[i])
2498 gst_line_cache_free (convert->vscale_lines[i]);
2499 if (convert->convert_lines && convert->convert_lines[i])
2500 gst_line_cache_free (convert->convert_lines[i]);
2501 if (convert->alpha_lines && convert->alpha_lines[i])
2502 gst_line_cache_free (convert->alpha_lines[i]);
2503 if (convert->to_YUV_lines && convert->to_YUV_lines[i])
2504 gst_line_cache_free (convert->to_YUV_lines[i]);
2505 if (convert->downsample_lines && convert->downsample_lines[i])
2506 gst_line_cache_free (convert->downsample_lines[i]);
2507 if (convert->dither_lines && convert->dither_lines[i])
2508 gst_line_cache_free (convert->dither_lines[i]);
2509 if (convert->dither && convert->dither[i])
2510 gst_video_dither_free (convert->dither[i]);
2512 g_free (convert->upsample_p);
2513 g_free (convert->upsample_i);
2514 g_free (convert->downsample_p);
2515 g_free (convert->downsample_i);
2516 g_free (convert->v_scaler_p);
2517 g_free (convert->v_scaler_i);
2518 g_free (convert->h_scaler);
2519 g_free (convert->unpack_lines);
2520 g_free (convert->pack_lines);
2521 g_free (convert->upsample_lines);
2522 g_free (convert->to_RGB_lines);
2523 g_free (convert->hscale_lines);
2524 g_free (convert->vscale_lines);
2525 g_free (convert->convert_lines);
2526 g_free (convert->alpha_lines);
2527 g_free (convert->to_YUV_lines);
2528 g_free (convert->downsample_lines);
2529 g_free (convert->dither_lines);
2530 g_free (convert->dither);
2532 g_free (convert->gamma_dec.gamma_table);
2533 g_free (convert->gamma_enc.gamma_table);
2535 if (convert->tmpline) {
2536 for (i = 0; i < convert->conversion_runner->n_threads; i++)
2537 g_free (convert->tmpline[i]);
2538 g_free (convert->tmpline);
2541 g_free (convert->borderline);
2543 if (convert->config)
2544 gst_structure_free (convert->config);
2546 for (i = 0; i < 4; i++) {
2547 for (j = 0; j < convert->conversion_runner->n_threads; j++) {
2548 if (convert->fv_scaler[i].scaler)
2549 gst_video_scaler_free (convert->fv_scaler[i].scaler[j]);
2550 if (convert->fh_scaler[i].scaler)
2551 gst_video_scaler_free (convert->fh_scaler[i].scaler[j]);
2553 g_free (convert->fv_scaler[i].scaler);
2554 g_free (convert->fh_scaler[i].scaler);
2557 if (convert->conversion_runner)
2558 gst_parallelized_task_runner_free (convert->conversion_runner);
2560 clear_matrix_data (&convert->to_RGB_matrix);
2561 clear_matrix_data (&convert->convert_matrix);
2562 clear_matrix_data (&convert->to_YUV_matrix);
2564 g_slice_free (GstVideoConverter, convert);
2568 copy_config (GQuark field_id, const GValue * value, gpointer user_data)
2570 GstVideoConverter *convert = user_data;
2572 gst_structure_id_set_value (convert->config, field_id, value);
2578 * gst_video_converter_set_config:
2579 * @convert: a #GstVideoConverter
2580 * @config: (transfer full): a #GstStructure
2582 * Set @config as extra configuraion for @convert.
2584 * If the parameters in @config can not be set exactly, this function returns
2585 * %FALSE and will try to update as much state as possible. The new state can
2586 * then be retrieved and refined with gst_video_converter_get_config().
2588 * Look at the #GST_VIDEO_CONVERTER_OPT_* fields to check valid configuration
2589 * option and values.
2591 * Returns: %TRUE when @config could be set.
2596 gst_video_converter_set_config (GstVideoConverter * convert,
2597 GstStructure * config)
2599 g_return_val_if_fail (convert != NULL, FALSE);
2600 g_return_val_if_fail (config != NULL, FALSE);
2602 gst_structure_foreach (config, copy_config, convert);
2603 gst_structure_free (config);
2609 * gst_video_converter_get_config:
2610 * @convert: a #GstVideoConverter
2612 * Get the current configuration of @convert.
2614 * Returns: a #GstStructure that remains valid for as long as @convert is valid
2615 * or until gst_video_converter_set_config() is called.
2617 const GstStructure *
2618 gst_video_converter_get_config (GstVideoConverter * convert)
2620 g_return_val_if_fail (convert != NULL, NULL);
2622 return convert->config;
2626 * gst_video_converter_frame:
2627 * @convert: a #GstVideoConverter
2628 * @dest: a #GstVideoFrame
2629 * @src: a #GstVideoFrame
2631 * Convert the pixels of @src into @dest using @convert.
2636 gst_video_converter_frame (GstVideoConverter * convert,
2637 const GstVideoFrame * src, GstVideoFrame * dest)
2639 g_return_if_fail (convert != NULL);
2640 g_return_if_fail (src != NULL);
2641 g_return_if_fail (dest != NULL);
2643 convert->convert (convert, src, dest);
2647 video_converter_compute_matrix (GstVideoConverter * convert)
2649 MatrixData *dst = &convert->convert_matrix;
2651 color_matrix_set_identity (dst);
2652 compute_matrix_to_RGB (convert, dst);
2653 compute_matrix_to_YUV (convert, dst, FALSE);
2655 convert->current_bits = 8;
2656 prepare_matrix (convert, dst);
2660 video_converter_compute_resample (GstVideoConverter * convert, gint idx)
2662 GstVideoInfo *in_info, *out_info;
2663 const GstVideoFormatInfo *sfinfo, *dfinfo;
2665 if (CHECK_CHROMA_NONE (convert))
2668 in_info = &convert->in_info;
2669 out_info = &convert->out_info;
2671 sfinfo = in_info->finfo;
2672 dfinfo = out_info->finfo;
2674 GST_DEBUG ("site: %d->%d, w_sub: %d->%d, h_sub: %d->%d", in_info->chroma_site,
2675 out_info->chroma_site, sfinfo->w_sub[2], dfinfo->w_sub[2],
2676 sfinfo->h_sub[2], dfinfo->h_sub[2]);
2678 if (sfinfo->w_sub[2] != dfinfo->w_sub[2] ||
2679 sfinfo->h_sub[2] != dfinfo->h_sub[2] ||
2680 in_info->chroma_site != out_info->chroma_site ||
2681 in_info->width != out_info->width ||
2682 in_info->height != out_info->height) {
2683 if (GST_VIDEO_INFO_IS_INTERLACED (in_info)) {
2684 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2685 convert->upsample_i[idx] = gst_video_chroma_resample_new (0,
2686 in_info->chroma_site, GST_VIDEO_CHROMA_FLAG_INTERLACED,
2687 sfinfo->unpack_format, sfinfo->w_sub[2], sfinfo->h_sub[2]);
2688 if (!CHECK_CHROMA_UPSAMPLE (convert))
2689 convert->downsample_i[idx] =
2690 gst_video_chroma_resample_new (0, out_info->chroma_site,
2691 GST_VIDEO_CHROMA_FLAG_INTERLACED, dfinfo->unpack_format,
2692 -dfinfo->w_sub[2], -dfinfo->h_sub[2]);
2694 if (!CHECK_CHROMA_DOWNSAMPLE (convert))
2695 convert->upsample_p[idx] = gst_video_chroma_resample_new (0,
2696 in_info->chroma_site, 0, sfinfo->unpack_format, sfinfo->w_sub[2],
2698 if (!CHECK_CHROMA_UPSAMPLE (convert))
2699 convert->downsample_p[idx] = gst_video_chroma_resample_new (0,
2700 out_info->chroma_site, 0, dfinfo->unpack_format, -dfinfo->w_sub[2],
2705 #define FRAME_GET_PLANE_STRIDE(frame, plane) \
2706 GST_VIDEO_FRAME_PLANE_STRIDE (frame, plane)
2707 #define FRAME_GET_PLANE_LINE(frame, plane, line) \
2708 (gpointer)(((guint8*)(GST_VIDEO_FRAME_PLANE_DATA (frame, plane))) + \
2709 FRAME_GET_PLANE_STRIDE (frame, plane) * (line))
2711 #define FRAME_GET_COMP_STRIDE(frame, comp) \
2712 GST_VIDEO_FRAME_COMP_STRIDE (frame, comp)
2713 #define FRAME_GET_COMP_LINE(frame, comp, line) \
2714 (gpointer)(((guint8*)(GST_VIDEO_FRAME_COMP_DATA (frame, comp))) + \
2715 FRAME_GET_COMP_STRIDE (frame, comp) * (line))
2717 #define FRAME_GET_STRIDE(frame) FRAME_GET_PLANE_STRIDE (frame, 0)
2718 #define FRAME_GET_LINE(frame,line) FRAME_GET_PLANE_LINE (frame, 0, line)
2720 #define FRAME_GET_Y_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_Y, line)
2721 #define FRAME_GET_U_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_U, line)
2722 #define FRAME_GET_V_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_V, line)
2723 #define FRAME_GET_A_LINE(frame,line) FRAME_GET_COMP_LINE(frame, GST_VIDEO_COMP_A, line)
2725 #define FRAME_GET_Y_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_Y)
2726 #define FRAME_GET_U_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_U)
2727 #define FRAME_GET_V_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_V)
2728 #define FRAME_GET_A_STRIDE(frame) FRAME_GET_COMP_STRIDE(frame, GST_VIDEO_COMP_A)
2731 #define UNPACK_FRAME(frame,dest,line,x,width) \
2732 frame->info.finfo->unpack_func (frame->info.finfo, \
2733 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2734 GST_VIDEO_PACK_FLAG_INTERLACED : \
2735 GST_VIDEO_PACK_FLAG_NONE), \
2736 dest, frame->data, frame->info.stride, x, \
2738 #define PACK_FRAME(frame,src,line,width) \
2739 frame->info.finfo->pack_func (frame->info.finfo, \
2740 (GST_VIDEO_FRAME_IS_INTERLACED (frame) ? \
2741 GST_VIDEO_PACK_FLAG_INTERLACED : \
2742 GST_VIDEO_PACK_FLAG_NONE), \
2743 src, 0, frame->data, frame->info.stride, \
2744 frame->info.chroma_site, line, width);
2747 get_dest_line (GstLineCache * cache, gint idx, gpointer user_data)
2749 GstVideoConverter *convert = user_data;
2751 gint pstride = convert->pack_pstride;
2752 gint out_x = convert->out_x;
2755 cline = CLAMP (idx, 0, convert->out_maxheight - 1);
2757 line = FRAME_GET_LINE (convert->dest, cline);
2758 GST_DEBUG ("get dest line %d %p", cline, line);
2760 if (convert->borderline) {
2761 gint r_border = (out_x + convert->out_width) * pstride;
2762 gint rb_width = convert->out_maxwidth * pstride - r_border;
2763 gint lb_width = out_x * pstride;
2765 memcpy (line, convert->borderline, lb_width);
2766 memcpy (line + r_border, convert->borderline, rb_width);
2768 line += out_x * pstride;
2774 do_unpack_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2777 GstVideoConverter *convert = user_data;
2781 cline = CLAMP (in_line + convert->in_y, 0, convert->in_maxheight - 1);
2783 if (cache->alloc_writable || !convert->identity_unpack) {
2784 tmpline = gst_line_cache_alloc_line (cache, out_line);
2785 GST_DEBUG ("unpack line %d (%u) %p", in_line, cline, tmpline);
2786 UNPACK_FRAME (convert->src, tmpline, cline, convert->in_x,
2789 tmpline = ((guint8 *) FRAME_GET_LINE (convert->src, cline)) +
2790 convert->in_x * convert->unpack_pstride;
2791 GST_DEBUG ("get src line %d (%u) %p", in_line, cline, tmpline);
2793 gst_line_cache_add_line (cache, in_line, tmpline);
2799 do_upsample_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2802 GstVideoConverter *convert = user_data;
2804 gint i, start_line, n_lines;
2806 n_lines = convert->up_n_lines;
2807 start_line = in_line;
2808 if (start_line < n_lines + convert->up_offset) {
2809 start_line += convert->up_offset;
2810 out_line += convert->up_offset;
2813 /* get the lines needed for chroma upsample */
2815 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
2818 if (convert->upsample) {
2819 GST_DEBUG ("doing upsample %d-%d %p", start_line, start_line + n_lines - 1,
2821 gst_video_chroma_resample (convert->upsample[idx], lines,
2825 for (i = 0; i < n_lines; i++)
2826 gst_line_cache_add_line (cache, start_line + i, lines[i]);
2832 do_convert_to_RGB_lines (GstLineCache * cache, gint idx, gint out_line,
2833 gint in_line, gpointer user_data)
2835 GstVideoConverter *convert = user_data;
2836 MatrixData *data = &convert->to_RGB_matrix;
2837 gpointer *lines, destline;
2839 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2840 destline = lines[0];
2842 if (data->matrix_func) {
2843 GST_DEBUG ("to RGB line %d %p", in_line, destline);
2844 data->matrix_func (data, destline);
2846 if (convert->gamma_dec.gamma_func) {
2847 destline = gst_line_cache_alloc_line (cache, out_line);
2849 GST_DEBUG ("gamma decode line %d %p->%p", in_line, lines[0], destline);
2850 convert->gamma_dec.gamma_func (&convert->gamma_dec, destline, lines[0]);
2852 gst_line_cache_add_line (cache, in_line, destline);
2858 do_hscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2861 GstVideoConverter *convert = user_data;
2862 gpointer *lines, destline;
2864 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2866 destline = gst_line_cache_alloc_line (cache, out_line);
2868 GST_DEBUG ("hresample line %d %p->%p", in_line, lines[0], destline);
2869 gst_video_scaler_horizontal (convert->h_scaler[idx], convert->h_scale_format,
2870 lines[0], destline, 0, convert->out_width);
2872 gst_line_cache_add_line (cache, in_line, destline);
2878 do_vscale_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2881 GstVideoConverter *convert = user_data;
2882 gpointer *lines, destline;
2883 guint sline, n_lines;
2886 cline = CLAMP (in_line, 0, convert->out_height - 1);
2888 gst_video_scaler_get_coeff (convert->v_scaler[idx], cline, &sline, &n_lines);
2889 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, sline, n_lines);
2891 destline = gst_line_cache_alloc_line (cache, out_line);
2893 GST_DEBUG ("vresample line %d %d-%d %p->%p", in_line, sline,
2894 sline + n_lines - 1, lines[0], destline);
2895 gst_video_scaler_vertical (convert->v_scaler[idx], convert->v_scale_format,
2896 lines, destline, cline, convert->v_scale_width);
2898 gst_line_cache_add_line (cache, in_line, destline);
2904 do_convert_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2907 GstVideoConverter *convert = user_data;
2908 MatrixData *data = &convert->convert_matrix;
2909 gpointer *lines, destline;
2910 guint in_bits, out_bits;
2913 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2915 destline = lines[0];
2917 in_bits = convert->in_bits;
2918 out_bits = convert->out_bits;
2920 width = MIN (convert->in_width, convert->out_width);
2922 if (out_bits == 16 || in_bits == 16) {
2923 gpointer srcline = lines[0];
2925 if (out_bits != in_bits)
2926 destline = gst_line_cache_alloc_line (cache, out_line);
2928 /* FIXME, we can scale in the conversion matrix */
2930 GST_DEBUG ("8->16 line %d %p->%p", in_line, srcline, destline);
2931 video_orc_convert_u8_to_u16 (destline, srcline, width * 4);
2935 if (data->matrix_func) {
2936 GST_DEBUG ("matrix line %d %p", in_line, srcline);
2937 data->matrix_func (data, srcline);
2940 /* FIXME, dither here */
2941 if (out_bits == 8) {
2942 GST_DEBUG ("16->8 line %d %p->%p", in_line, srcline, destline);
2943 video_orc_convert_u16_to_u8 (destline, srcline, width * 4);
2946 if (data->matrix_func) {
2947 GST_DEBUG ("matrix line %d %p", in_line, destline);
2948 data->matrix_func (data, destline);
2951 gst_line_cache_add_line (cache, in_line, destline);
2957 do_alpha_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
2960 gpointer *lines, destline;
2961 GstVideoConverter *convert = user_data;
2962 gint width = MIN (convert->in_width, convert->out_width);
2964 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2965 destline = lines[0];
2967 GST_DEBUG ("alpha line %d %p", in_line, destline);
2968 convert->alpha_func (convert, destline, width);
2970 gst_line_cache_add_line (cache, in_line, destline);
2976 do_convert_to_YUV_lines (GstLineCache * cache, gint idx, gint out_line,
2977 gint in_line, gpointer user_data)
2979 GstVideoConverter *convert = user_data;
2980 MatrixData *data = &convert->to_YUV_matrix;
2981 gpointer *lines, destline;
2983 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
2984 destline = lines[0];
2986 if (convert->gamma_enc.gamma_func) {
2987 destline = gst_line_cache_alloc_line (cache, out_line);
2989 GST_DEBUG ("gamma encode line %d %p->%p", in_line, lines[0], destline);
2990 convert->gamma_enc.gamma_func (&convert->gamma_enc, destline, lines[0]);
2992 if (data->matrix_func) {
2993 GST_DEBUG ("to YUV line %d %p", in_line, destline);
2994 data->matrix_func (data, destline);
2996 gst_line_cache_add_line (cache, in_line, destline);
3002 do_downsample_lines (GstLineCache * cache, gint idx, gint out_line,
3003 gint in_line, gpointer user_data)
3005 GstVideoConverter *convert = user_data;
3007 gint i, start_line, n_lines;
3009 n_lines = convert->down_n_lines;
3010 start_line = in_line;
3011 if (start_line < n_lines + convert->down_offset)
3012 start_line += convert->down_offset;
3014 /* get the lines needed for chroma downsample */
3016 gst_line_cache_get_lines (cache->prev, idx, out_line, start_line,
3019 if (convert->downsample) {
3020 GST_DEBUG ("downsample line %d %d-%d %p", in_line, start_line,
3021 start_line + n_lines - 1, lines[0]);
3022 gst_video_chroma_resample (convert->downsample[idx], lines,
3023 convert->out_width);
3026 for (i = 0; i < n_lines; i++)
3027 gst_line_cache_add_line (cache, start_line + i, lines[i]);
3033 do_dither_lines (GstLineCache * cache, gint idx, gint out_line, gint in_line,
3036 GstVideoConverter *convert = user_data;
3037 gpointer *lines, destline;
3039 lines = gst_line_cache_get_lines (cache->prev, idx, out_line, in_line, 1);
3040 destline = lines[0];
3042 if (convert->dither) {
3043 GST_DEBUG ("Dither line %d %p", in_line, destline);
3044 gst_video_dither_line (convert->dither[idx], destline, 0, out_line,
3045 convert->out_width);
3047 gst_line_cache_add_line (cache, in_line, destline);
3054 GstLineCache *pack_lines;
3057 gint pack_lines_count;
3059 gboolean identity_pack;
3060 gint lb_width, out_maxwidth;
3061 GstVideoFrame *dest;
3065 convert_generic_task (ConvertTask * task)
3069 for (i = task->h_0; i < task->h_1; i += task->pack_lines_count) {
3072 /* load the lines needed to pack */
3074 gst_line_cache_get_lines (task->pack_lines, task->idx, i + task->out_y,
3075 i, task->pack_lines_count);
3077 if (!task->identity_pack) {
3078 /* take away the border */
3079 guint8 *l = ((guint8 *) lines[0]) - task->lb_width;
3080 /* and pack into destination */
3081 GST_DEBUG ("pack line %d %p (%p)", i + task->out_y, lines[0], l);
3082 PACK_FRAME (task->dest, l, i + task->out_y, task->out_maxwidth);
3088 video_converter_generic (GstVideoConverter * convert, const GstVideoFrame * src,
3089 GstVideoFrame * dest)
3092 gint out_maxwidth, out_maxheight;
3093 gint out_x, out_y, out_height;
3094 gint pack_lines, pstride;
3097 ConvertTask **tasks_p;
3099 gint lines_per_thread;
3101 out_height = convert->out_height;
3102 out_maxwidth = convert->out_maxwidth;
3103 out_maxheight = convert->out_maxheight;
3105 out_x = convert->out_x;
3106 out_y = convert->out_y;
3109 convert->dest = dest;
3111 if (GST_VIDEO_FRAME_IS_INTERLACED (src)) {
3112 GST_DEBUG ("setup interlaced frame");
3113 convert->upsample = convert->upsample_i;
3114 convert->downsample = convert->downsample_i;
3115 convert->v_scaler = convert->v_scaler_i;
3117 GST_DEBUG ("setup progressive frame");
3118 convert->upsample = convert->upsample_p;
3119 convert->downsample = convert->downsample_p;
3120 convert->v_scaler = convert->v_scaler_p;
3122 if (convert->upsample[0]) {
3123 gst_video_chroma_resample_get_info (convert->upsample[0],
3124 &convert->up_n_lines, &convert->up_offset);
3126 convert->up_n_lines = 1;
3127 convert->up_offset = 0;
3129 if (convert->downsample[0]) {
3130 gst_video_chroma_resample_get_info (convert->downsample[0],
3131 &convert->down_n_lines, &convert->down_offset);
3133 convert->down_n_lines = 1;
3134 convert->down_offset = 0;
3137 pack_lines = convert->pack_nlines; /* only 1 for now */
3138 pstride = convert->pack_pstride;
3140 lb_width = out_x * pstride;
3142 if (convert->borderline) {
3143 /* FIXME we should try to avoid PACK_FRAME */
3144 for (i = 0; i < out_y; i++)
3145 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3148 n_threads = convert->conversion_runner->n_threads;
3149 tasks = g_newa (ConvertTask, n_threads);
3150 tasks_p = g_newa (ConvertTask *, n_threads);
3153 GST_ROUND_UP_N ((out_height + n_threads - 1) / n_threads, pack_lines);
3155 for (i = 0; i < n_threads; i++) {
3156 tasks[i].dest = dest;
3157 tasks[i].pack_lines = convert->pack_lines[i];
3159 tasks[i].pack_lines_count = pack_lines;
3160 tasks[i].out_y = out_y;
3161 tasks[i].identity_pack = convert->identity_pack;
3162 tasks[i].lb_width = lb_width;
3163 tasks[i].out_maxwidth = out_maxwidth;
3165 tasks[i].h_0 = i * lines_per_thread;
3166 tasks[i].h_1 = MIN ((i + 1) * lines_per_thread, out_height);
3168 tasks_p[i] = &tasks[i];
3171 gst_parallelized_task_runner_run (convert->conversion_runner,
3172 (GstParallelizedTaskFunc) convert_generic_task, (gpointer) tasks_p);
3174 if (convert->borderline) {
3175 for (i = out_y + out_height; i < out_maxheight; i++)
3176 PACK_FRAME (dest, convert->borderline, i, out_maxwidth);
3178 if (convert->pack_pal) {
3179 memcpy (GST_VIDEO_FRAME_PLANE_DATA (dest, 1), convert->pack_pal,
3180 convert->pack_palsize);
3184 static void convert_fill_border (GstVideoConverter * convert,
3185 GstVideoFrame * dest);
3189 #define GET_LINE_OFFSETS(interlaced,line,l1,l2) \
3191 l1 = (line & 2 ? line - 1 : line); \
3200 const GstVideoFrame *src;
3201 GstVideoFrame *dest;
3202 gint height_0, height_1;
3205 gboolean interlaced;
3215 convert_I420_YUY2_task (FConvertTask * task)
3220 for (i = task->height_0; i < task->height_1; i += 2) {
3221 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3223 video_orc_convert_I420_YUY2 (FRAME_GET_LINE (task->dest, l1),
3224 FRAME_GET_LINE (task->dest, l2),
3225 FRAME_GET_Y_LINE (task->src, l1),
3226 FRAME_GET_Y_LINE (task->src, l2),
3227 FRAME_GET_U_LINE (task->src, i >> 1),
3228 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3233 convert_I420_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
3234 GstVideoFrame * dest)
3237 gint width = convert->in_width;
3238 gint height = convert->in_height;
3239 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3241 FConvertTask *tasks;
3242 FConvertTask **tasks_p;
3244 gint lines_per_thread;
3246 /* I420 has half as many chroma lines, as such we have to
3247 * always merge two into one. For non-interlaced these are
3248 * the two next to each other, for interlaced one is skipped
3251 h2 = GST_ROUND_DOWN_4 (height);
3253 h2 = GST_ROUND_DOWN_2 (height);
3255 n_threads = convert->conversion_runner->n_threads;
3256 tasks = g_newa (FConvertTask, n_threads);
3257 tasks_p = g_newa (FConvertTask *, n_threads);
3259 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3261 for (i = 0; i < n_threads; i++) {
3263 tasks[i].dest = dest;
3265 tasks[i].interlaced = interlaced;
3266 tasks[i].width = width;
3268 tasks[i].height_0 = i * lines_per_thread;
3269 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3270 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3272 tasks_p[i] = &tasks[i];
3275 gst_parallelized_task_runner_run (convert->conversion_runner,
3276 (GstParallelizedTaskFunc) convert_I420_YUY2_task, (gpointer) tasks_p);
3278 /* now handle last lines. For interlaced these are up to 3 */
3280 for (i = h2; i < height; i++) {
3281 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3282 PACK_FRAME (dest, convert->tmpline[0], i, width);
3288 convert_I420_UYVY_task (FConvertTask * task)
3293 for (i = task->height_0; i < task->height_1; i += 2) {
3294 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3296 video_orc_convert_I420_UYVY (FRAME_GET_LINE (task->dest, l1),
3297 FRAME_GET_LINE (task->dest, l2),
3298 FRAME_GET_Y_LINE (task->src, l1),
3299 FRAME_GET_Y_LINE (task->src, l2),
3300 FRAME_GET_U_LINE (task->src, i >> 1),
3301 FRAME_GET_V_LINE (task->src, i >> 1), (task->width + 1) / 2);
3306 convert_I420_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
3307 GstVideoFrame * dest)
3310 gint width = convert->in_width;
3311 gint height = convert->in_height;
3312 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3314 FConvertTask *tasks;
3315 FConvertTask **tasks_p;
3317 gint lines_per_thread;
3319 /* I420 has half as many chroma lines, as such we have to
3320 * always merge two into one. For non-interlaced these are
3321 * the two next to each other, for interlaced one is skipped
3324 h2 = GST_ROUND_DOWN_4 (height);
3326 h2 = GST_ROUND_DOWN_2 (height);
3328 n_threads = convert->conversion_runner->n_threads;
3329 tasks = g_newa (FConvertTask, n_threads);
3330 tasks_p = g_newa (FConvertTask *, n_threads);
3332 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3334 for (i = 0; i < n_threads; i++) {
3336 tasks[i].dest = dest;
3338 tasks[i].interlaced = interlaced;
3339 tasks[i].width = width;
3341 tasks[i].height_0 = i * lines_per_thread;
3342 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3343 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3345 tasks_p[i] = &tasks[i];
3348 gst_parallelized_task_runner_run (convert->conversion_runner,
3349 (GstParallelizedTaskFunc) convert_I420_UYVY_task, (gpointer) tasks_p);
3351 /* now handle last lines. For interlaced these are up to 3 */
3353 for (i = h2; i < height; i++) {
3354 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3355 PACK_FRAME (dest, convert->tmpline[0], i, width);
3361 convert_I420_AYUV_task (FConvertTask * task)
3366 for (i = task->height_0; i < task->height_1; i += 2) {
3367 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3369 video_orc_convert_I420_AYUV (FRAME_GET_LINE (task->dest, l1),
3370 FRAME_GET_LINE (task->dest, l2),
3371 FRAME_GET_Y_LINE (task->src, l1),
3372 FRAME_GET_Y_LINE (task->src, l2),
3373 FRAME_GET_U_LINE (task->src, i >> 1), FRAME_GET_V_LINE (task->src,
3374 i >> 1), task->alpha, task->width);
3379 convert_I420_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3380 GstVideoFrame * dest)
3383 gint width = convert->in_width;
3384 gint height = convert->in_height;
3385 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3386 guint8 alpha = MIN (convert->alpha_value, 255);
3388 FConvertTask *tasks;
3389 FConvertTask **tasks_p;
3391 gint lines_per_thread;
3393 /* I420 has half as many chroma lines, as such we have to
3394 * always merge two into one. For non-interlaced these are
3395 * the two next to each other, for interlaced one is skipped
3398 h2 = GST_ROUND_DOWN_4 (height);
3400 h2 = GST_ROUND_DOWN_2 (height);
3403 n_threads = convert->conversion_runner->n_threads;
3404 tasks = g_newa (FConvertTask, n_threads);
3405 tasks_p = g_newa (FConvertTask *, n_threads);
3407 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3409 for (i = 0; i < n_threads; i++) {
3411 tasks[i].dest = dest;
3413 tasks[i].interlaced = interlaced;
3414 tasks[i].width = width;
3415 tasks[i].alpha = alpha;
3417 tasks[i].height_0 = i * lines_per_thread;
3418 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3419 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3421 tasks_p[i] = &tasks[i];
3424 gst_parallelized_task_runner_run (convert->conversion_runner,
3425 (GstParallelizedTaskFunc) convert_I420_AYUV_task, (gpointer) tasks_p);
3427 /* now handle last lines. For interlaced these are up to 3 */
3429 for (i = h2; i < height; i++) {
3430 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3432 convert_set_alpha_u8 (convert, convert->tmpline[0], width);
3433 PACK_FRAME (dest, convert->tmpline[0], i, width);
3439 convert_YUY2_I420_task (FConvertTask * task)
3444 for (i = task->height_0; i < task->height_1; i += 2) {
3445 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3447 video_orc_convert_YUY2_I420 (FRAME_GET_Y_LINE (task->dest, l1),
3448 FRAME_GET_Y_LINE (task->dest, l2),
3449 FRAME_GET_U_LINE (task->dest, i >> 1),
3450 FRAME_GET_V_LINE (task->dest, i >> 1),
3451 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
3452 (task->width + 1) / 2);
3457 convert_YUY2_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3458 GstVideoFrame * dest)
3461 gint width = convert->in_width;
3462 gint height = convert->in_height;
3463 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3465 FConvertTask *tasks;
3466 FConvertTask **tasks_p;
3468 gint lines_per_thread;
3470 /* I420 has half as many chroma lines, as such we have to
3471 * always merge two into one. For non-interlaced these are
3472 * the two next to each other, for interlaced one is skipped
3475 h2 = GST_ROUND_DOWN_4 (height);
3477 h2 = GST_ROUND_DOWN_2 (height);
3479 n_threads = convert->conversion_runner->n_threads;
3480 tasks = g_newa (FConvertTask, n_threads);
3481 tasks_p = g_newa (FConvertTask *, n_threads);
3483 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3485 for (i = 0; i < n_threads; i++) {
3487 tasks[i].dest = dest;
3489 tasks[i].interlaced = interlaced;
3490 tasks[i].width = width;
3492 tasks[i].height_0 = i * lines_per_thread;
3493 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3494 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3496 tasks_p[i] = &tasks[i];
3499 gst_parallelized_task_runner_run (convert->conversion_runner,
3500 (GstParallelizedTaskFunc) convert_YUY2_I420_task, (gpointer) tasks_p);
3502 /* now handle last lines. For interlaced these are up to 3 */
3504 for (i = h2; i < height; i++) {
3505 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3506 PACK_FRAME (dest, convert->tmpline[0], i, width);
3513 const guint8 *s, *s2, *su, *sv;
3514 guint8 *d, *d2, *du, *dv;
3515 gint sstride, sustride, svstride;
3516 gint dstride, dustride, dvstride;
3520 } FConvertPlaneTask;
3523 convert_YUY2_AYUV_task (FConvertPlaneTask * task)
3525 video_orc_convert_YUY2_AYUV (task->d, task->dstride, task->s,
3526 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
3530 convert_YUY2_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3531 GstVideoFrame * dest)
3533 gint width = convert->in_width;
3534 gint height = convert->in_height;
3536 guint8 alpha = MIN (convert->alpha_value, 255);
3537 FConvertPlaneTask *tasks;
3538 FConvertPlaneTask **tasks_p;
3540 gint lines_per_thread;
3543 s = FRAME_GET_LINE (src, convert->in_y);
3544 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3545 d = FRAME_GET_LINE (dest, convert->out_y);
3546 d += (convert->out_x * 4);
3548 n_threads = convert->conversion_runner->n_threads;
3549 tasks = g_newa (FConvertPlaneTask, n_threads);
3550 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3552 lines_per_thread = (height + n_threads - 1) / n_threads;
3554 for (i = 0; i < n_threads; i++) {
3555 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3556 tasks[i].sstride = FRAME_GET_STRIDE (src);
3557 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3558 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3560 tasks[i].width = width;
3561 tasks[i].height = (i + 1) * lines_per_thread;
3562 tasks[i].height = MIN (tasks[i].height, height);
3563 tasks[i].height -= i * lines_per_thread;
3564 tasks[i].alpha = alpha;
3566 tasks_p[i] = &tasks[i];
3569 gst_parallelized_task_runner_run (convert->conversion_runner,
3570 (GstParallelizedTaskFunc) convert_YUY2_AYUV_task, (gpointer) tasks_p);
3572 convert_fill_border (convert, dest);
3576 convert_YUY2_Y42B_task (FConvertPlaneTask * task)
3578 video_orc_convert_YUY2_Y42B (task->d, task->dstride, task->du,
3579 task->dustride, task->dv, task->dvstride,
3580 task->s, task->sstride, (task->width + 1) / 2, task->height);
3584 convert_YUY2_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
3585 GstVideoFrame * dest)
3587 gint width = convert->in_width;
3588 gint height = convert->in_height;
3589 guint8 *s, *dy, *du, *dv;
3590 FConvertPlaneTask *tasks;
3591 FConvertPlaneTask **tasks_p;
3593 gint lines_per_thread;
3596 s = FRAME_GET_LINE (src, convert->in_y);
3597 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3599 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3600 dy += convert->out_x;
3601 du = FRAME_GET_U_LINE (dest, convert->out_y);
3602 du += convert->out_x >> 1;
3603 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3604 dv += convert->out_x >> 1;
3606 n_threads = convert->conversion_runner->n_threads;
3607 tasks = g_newa (FConvertPlaneTask, n_threads);
3608 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3610 lines_per_thread = (height + n_threads - 1) / n_threads;
3612 for (i = 0; i < n_threads; i++) {
3613 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3614 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3615 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3616 tasks[i].sstride = FRAME_GET_STRIDE (src);
3617 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3618 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3619 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3620 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3622 tasks[i].width = width;
3623 tasks[i].height = (i + 1) * lines_per_thread;
3624 tasks[i].height = MIN (tasks[i].height, height);
3625 tasks[i].height -= i * lines_per_thread;
3627 tasks_p[i] = &tasks[i];
3630 gst_parallelized_task_runner_run (convert->conversion_runner,
3631 (GstParallelizedTaskFunc) convert_YUY2_Y42B_task, (gpointer) tasks_p);
3633 convert_fill_border (convert, dest);
3637 convert_YUY2_Y444_task (FConvertPlaneTask * task)
3639 video_orc_convert_YUY2_Y444 (task->d,
3640 task->dstride, task->du,
3641 task->dustride, task->dv,
3642 task->dvstride, task->s,
3643 task->sstride, (task->width + 1) / 2, task->height);
3647 convert_YUY2_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
3648 GstVideoFrame * dest)
3650 gint width = convert->in_width;
3651 gint height = convert->in_height;
3652 guint8 *s, *dy, *du, *dv;
3653 FConvertPlaneTask *tasks;
3654 FConvertPlaneTask **tasks_p;
3656 gint lines_per_thread;
3659 s = FRAME_GET_LINE (src, convert->in_y);
3660 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3662 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3663 dy += convert->out_x;
3664 du = FRAME_GET_U_LINE (dest, convert->out_y);
3665 du += convert->out_x;
3666 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3667 dv += convert->out_x;
3669 n_threads = convert->conversion_runner->n_threads;
3670 tasks = g_newa (FConvertPlaneTask, n_threads);
3671 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3673 lines_per_thread = (height + n_threads - 1) / n_threads;
3675 for (i = 0; i < n_threads; i++) {
3676 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3677 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3678 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3679 tasks[i].sstride = FRAME_GET_STRIDE (src);
3680 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3681 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3682 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3683 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3685 tasks[i].width = width;
3686 tasks[i].height = (i + 1) * lines_per_thread;
3687 tasks[i].height = MIN (tasks[i].height, height);
3688 tasks[i].height -= i * lines_per_thread;
3690 tasks_p[i] = &tasks[i];
3693 gst_parallelized_task_runner_run (convert->conversion_runner,
3694 (GstParallelizedTaskFunc) convert_YUY2_Y444_task, (gpointer) tasks_p);
3696 convert_fill_border (convert, dest);
3700 convert_UYVY_I420_task (FConvertTask * task)
3705 for (i = task->height_0; i < task->height_1; i += 2) {
3706 GET_LINE_OFFSETS (task->interlaced, i, l1, l2);
3708 video_orc_convert_UYVY_I420 (FRAME_GET_COMP_LINE (task->dest, 0, l1),
3709 FRAME_GET_COMP_LINE (task->dest, 0, l2),
3710 FRAME_GET_COMP_LINE (task->dest, 1, i >> 1),
3711 FRAME_GET_COMP_LINE (task->dest, 2, i >> 1),
3712 FRAME_GET_LINE (task->src, l1), FRAME_GET_LINE (task->src, l2),
3713 (task->width + 1) / 2);
3718 convert_UYVY_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
3719 GstVideoFrame * dest)
3722 gint width = convert->in_width;
3723 gint height = convert->in_height;
3724 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
3726 FConvertTask *tasks;
3727 FConvertTask **tasks_p;
3729 gint lines_per_thread;
3731 /* I420 has half as many chroma lines, as such we have to
3732 * always merge two into one. For non-interlaced these are
3733 * the two next to each other, for interlaced one is skipped
3736 h2 = GST_ROUND_DOWN_4 (height);
3738 h2 = GST_ROUND_DOWN_2 (height);
3740 n_threads = convert->conversion_runner->n_threads;
3741 tasks = g_newa (FConvertTask, n_threads);
3742 tasks_p = g_newa (FConvertTask *, n_threads);
3744 lines_per_thread = GST_ROUND_UP_2 ((h2 + n_threads - 1) / n_threads);
3746 for (i = 0; i < n_threads; i++) {
3748 tasks[i].dest = dest;
3750 tasks[i].interlaced = interlaced;
3751 tasks[i].width = width;
3753 tasks[i].height_0 = i * lines_per_thread;
3754 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
3755 tasks[i].height_1 = MIN (h2, tasks[i].height_1);
3757 tasks_p[i] = &tasks[i];
3760 gst_parallelized_task_runner_run (convert->conversion_runner,
3761 (GstParallelizedTaskFunc) convert_UYVY_I420_task, (gpointer) tasks_p);
3763 /* now handle last lines. For interlaced these are up to 3 */
3765 for (i = h2; i < height; i++) {
3766 UNPACK_FRAME (src, convert->tmpline[0], i, convert->in_x, width);
3767 PACK_FRAME (dest, convert->tmpline[0], i, width);
3773 convert_UYVY_AYUV_task (FConvertPlaneTask * task)
3775 video_orc_convert_UYVY_AYUV (task->d, task->dstride, task->s,
3776 task->sstride, task->alpha, (task->width + 1) / 2, task->height);
3780 convert_UYVY_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
3781 GstVideoFrame * dest)
3783 gint width = convert->in_width;
3784 gint height = convert->in_height;
3786 guint8 alpha = MIN (convert->alpha_value, 255);
3787 FConvertPlaneTask *tasks;
3788 FConvertPlaneTask **tasks_p;
3790 gint lines_per_thread;
3793 s = FRAME_GET_LINE (src, convert->in_y);
3794 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3795 d = FRAME_GET_LINE (dest, convert->out_y);
3796 d += (convert->out_x * 4);
3798 n_threads = convert->conversion_runner->n_threads;
3799 tasks = g_newa (FConvertPlaneTask, n_threads);
3800 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3802 lines_per_thread = (height + n_threads - 1) / n_threads;
3804 for (i = 0; i < n_threads; i++) {
3805 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3806 tasks[i].sstride = FRAME_GET_STRIDE (src);
3807 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3808 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3810 tasks[i].width = width;
3811 tasks[i].height = (i + 1) * lines_per_thread;
3812 tasks[i].height = MIN (tasks[i].height, height);
3813 tasks[i].height -= i * lines_per_thread;
3814 tasks[i].alpha = alpha;
3816 tasks_p[i] = &tasks[i];
3819 gst_parallelized_task_runner_run (convert->conversion_runner,
3820 (GstParallelizedTaskFunc) convert_UYVY_AYUV_task, (gpointer) tasks_p);
3822 convert_fill_border (convert, dest);
3826 convert_UYVY_YUY2_task (FConvertPlaneTask * task)
3828 video_orc_convert_UYVY_YUY2 (task->d, task->dstride, task->s,
3829 task->sstride, (task->width + 1) / 2, task->height);
3833 convert_UYVY_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
3834 GstVideoFrame * dest)
3836 gint width = convert->in_width;
3837 gint height = convert->in_height;
3839 FConvertPlaneTask *tasks;
3840 FConvertPlaneTask **tasks_p;
3842 gint lines_per_thread;
3845 s = FRAME_GET_LINE (src, convert->in_y);
3846 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3847 d = FRAME_GET_LINE (dest, convert->out_y);
3848 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
3850 n_threads = convert->conversion_runner->n_threads;
3851 tasks = g_newa (FConvertPlaneTask, n_threads);
3852 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3854 lines_per_thread = (height + n_threads - 1) / n_threads;
3856 for (i = 0; i < n_threads; i++) {
3857 tasks[i].dstride = FRAME_GET_STRIDE (dest);
3858 tasks[i].sstride = FRAME_GET_STRIDE (src);
3859 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
3860 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3862 tasks[i].width = width;
3863 tasks[i].height = (i + 1) * lines_per_thread;
3864 tasks[i].height = MIN (tasks[i].height, height);
3865 tasks[i].height -= i * lines_per_thread;
3867 tasks_p[i] = &tasks[i];
3870 gst_parallelized_task_runner_run (convert->conversion_runner,
3871 (GstParallelizedTaskFunc) convert_UYVY_YUY2_task, (gpointer) tasks_p);
3873 convert_fill_border (convert, dest);
3877 convert_UYVY_Y42B_task (FConvertPlaneTask * task)
3879 video_orc_convert_UYVY_Y42B (task->d, task->dstride, task->du,
3880 task->dustride, task->dv, task->dvstride,
3881 task->s, task->sstride, (task->width + 1) / 2, task->height);
3885 convert_UYVY_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
3886 GstVideoFrame * dest)
3888 gint width = convert->in_width;
3889 gint height = convert->in_height;
3890 guint8 *s, *dy, *du, *dv;
3891 FConvertPlaneTask *tasks;
3892 FConvertPlaneTask **tasks_p;
3894 gint lines_per_thread;
3897 s = FRAME_GET_LINE (src, convert->in_y);
3898 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3900 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3901 dy += convert->out_x;
3902 du = FRAME_GET_U_LINE (dest, convert->out_y);
3903 du += convert->out_x >> 1;
3904 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3905 dv += convert->out_x >> 1;
3907 n_threads = convert->conversion_runner->n_threads;
3908 tasks = g_newa (FConvertPlaneTask, n_threads);
3909 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3911 lines_per_thread = (height + n_threads - 1) / n_threads;
3913 for (i = 0; i < n_threads; i++) {
3914 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3915 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3916 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3917 tasks[i].sstride = FRAME_GET_STRIDE (src);
3918 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3919 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3920 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3921 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3923 tasks[i].width = width;
3924 tasks[i].height = (i + 1) * lines_per_thread;
3925 tasks[i].height = MIN (tasks[i].height, height);
3926 tasks[i].height -= i * lines_per_thread;
3928 tasks_p[i] = &tasks[i];
3931 gst_parallelized_task_runner_run (convert->conversion_runner,
3932 (GstParallelizedTaskFunc) convert_UYVY_Y42B_task, (gpointer) tasks_p);
3934 convert_fill_border (convert, dest);
3938 convert_UYVY_Y444_task (FConvertPlaneTask * task)
3940 video_orc_convert_UYVY_Y444 (task->d,
3941 task->dstride, task->du,
3942 task->dustride, task->dv,
3943 task->dvstride, task->s,
3944 task->sstride, (task->width + 1) / 2, task->height);
3948 convert_UYVY_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
3949 GstVideoFrame * dest)
3951 gint width = convert->in_width;
3952 gint height = convert->in_height;
3953 guint8 *s, *dy, *du, *dv;
3954 FConvertPlaneTask *tasks;
3955 FConvertPlaneTask **tasks_p;
3957 gint lines_per_thread;
3960 s = FRAME_GET_LINE (src, convert->in_y);
3961 s += (GST_ROUND_UP_2 (convert->in_x) * 2);
3963 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
3964 dy += convert->out_x;
3965 du = FRAME_GET_U_LINE (dest, convert->out_y);
3966 du += convert->out_x;
3967 dv = FRAME_GET_V_LINE (dest, convert->out_y);
3968 dv += convert->out_x;
3970 n_threads = convert->conversion_runner->n_threads;
3971 tasks = g_newa (FConvertPlaneTask, n_threads);
3972 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
3974 lines_per_thread = (height + n_threads - 1) / n_threads;
3976 for (i = 0; i < n_threads; i++) {
3977 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
3978 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
3979 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
3980 tasks[i].sstride = FRAME_GET_STRIDE (src);
3981 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
3982 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
3983 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
3984 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
3986 tasks[i].width = width;
3987 tasks[i].height = (i + 1) * lines_per_thread;
3988 tasks[i].height = MIN (tasks[i].height, height);
3989 tasks[i].height -= i * lines_per_thread;
3991 tasks_p[i] = &tasks[i];
3994 gst_parallelized_task_runner_run (convert->conversion_runner,
3995 (GstParallelizedTaskFunc) convert_UYVY_Y444_task, (gpointer) tasks_p);
3997 convert_fill_border (convert, dest);
4001 convert_UYVY_GRAY8_task (FConvertPlaneTask * task)
4003 video_orc_convert_UYVY_GRAY8 (task->d, task->dstride, (guint16 *) task->s,
4004 task->sstride, task->width, task->height);
4008 convert_UYVY_GRAY8 (GstVideoConverter * convert, const GstVideoFrame * src,
4009 GstVideoFrame * dest)
4011 gint width = convert->in_width;
4012 gint height = convert->in_height;
4015 FConvertPlaneTask *tasks;
4016 FConvertPlaneTask **tasks_p;
4018 gint lines_per_thread;
4021 s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
4022 d = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
4024 n_threads = convert->conversion_runner->n_threads;
4025 tasks = g_newa (FConvertPlaneTask, n_threads);
4026 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4028 lines_per_thread = (height + n_threads - 1) / n_threads;
4030 for (i = 0; i < n_threads; i++) {
4031 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4032 tasks[i].sstride = FRAME_GET_STRIDE (src);
4033 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4034 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4036 tasks[i].width = width;
4037 tasks[i].height = (i + 1) * lines_per_thread;
4038 tasks[i].height = MIN (tasks[i].height, height);
4039 tasks[i].height -= i * lines_per_thread;
4041 tasks_p[i] = &tasks[i];
4044 gst_parallelized_task_runner_run (convert->conversion_runner,
4045 (GstParallelizedTaskFunc) convert_UYVY_GRAY8_task, (gpointer) tasks_p);
4047 convert_fill_border (convert, dest);
4051 convert_AYUV_I420_task (FConvertPlaneTask * task)
4053 video_orc_convert_AYUV_I420 (task->d,
4054 2 * task->dstride, task->d2,
4055 2 * task->dstride, task->du,
4056 task->dustride, task->dv,
4057 task->dvstride, task->s,
4058 2 * task->sstride, task->s2,
4059 2 * task->sstride, task->width / 2, task->height / 2);
4063 convert_AYUV_I420 (GstVideoConverter * convert, const GstVideoFrame * src,
4064 GstVideoFrame * dest)
4066 gint width = convert->in_width;
4067 gint height = convert->in_height;
4068 guint8 *s1, *s2, *dy1, *dy2, *du, *dv;
4069 FConvertPlaneTask *tasks;
4070 FConvertPlaneTask **tasks_p;
4072 gint lines_per_thread;
4075 s1 = FRAME_GET_LINE (src, convert->in_y + 0);
4076 s1 += convert->in_x * 4;
4077 s2 = FRAME_GET_LINE (src, convert->in_y + 1);
4078 s2 += convert->in_x * 4;
4080 dy1 = FRAME_GET_Y_LINE (dest, convert->out_y + 0);
4081 dy1 += convert->out_x;
4082 dy2 = FRAME_GET_Y_LINE (dest, convert->out_y + 1);
4083 dy2 += convert->out_x;
4084 du = FRAME_GET_U_LINE (dest, convert->out_y >> 1);
4085 du += convert->out_x >> 1;
4086 dv = FRAME_GET_V_LINE (dest, convert->out_y >> 1);
4087 dv += convert->out_x >> 1;
4089 /* only for even width/height */
4091 n_threads = convert->conversion_runner->n_threads;
4092 tasks = g_newa (FConvertPlaneTask, n_threads);
4093 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4095 lines_per_thread = GST_ROUND_UP_2 ((height + n_threads - 1) / n_threads);
4097 for (i = 0; i < n_threads; i++) {
4098 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4099 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4100 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4101 tasks[i].sstride = FRAME_GET_STRIDE (src);
4102 tasks[i].d = dy1 + i * lines_per_thread * tasks[i].dstride;
4103 tasks[i].d2 = dy2 + i * lines_per_thread * tasks[i].dstride;
4104 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride / 2;
4105 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride / 2;
4106 tasks[i].s = s1 + i * lines_per_thread * tasks[i].sstride;
4107 tasks[i].s2 = s2 + i * lines_per_thread * tasks[i].sstride;
4109 tasks[i].width = width;
4110 tasks[i].height = (i + 1) * lines_per_thread;
4111 tasks[i].height = MIN (tasks[i].height, height);
4112 tasks[i].height -= i * lines_per_thread;
4114 tasks_p[i] = &tasks[i];
4117 gst_parallelized_task_runner_run (convert->conversion_runner,
4118 (GstParallelizedTaskFunc) convert_AYUV_I420_task, (gpointer) tasks_p);
4120 convert_fill_border (convert, dest);
4124 convert_AYUV_YUY2_task (FConvertPlaneTask * task)
4126 video_orc_convert_AYUV_YUY2 (task->d, task->dstride, task->s,
4127 task->sstride, task->width / 2, task->height);
4131 convert_AYUV_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4132 GstVideoFrame * dest)
4134 gint width = convert->in_width;
4135 gint height = convert->in_height;
4137 FConvertPlaneTask *tasks;
4138 FConvertPlaneTask **tasks_p;
4140 gint lines_per_thread;
4143 s = FRAME_GET_LINE (src, convert->in_y);
4144 s += convert->in_x * 4;
4145 d = FRAME_GET_LINE (dest, convert->out_y);
4146 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4148 /* only for even width */
4149 n_threads = convert->conversion_runner->n_threads;
4150 tasks = g_newa (FConvertPlaneTask, n_threads);
4151 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4153 lines_per_thread = (height + n_threads - 1) / n_threads;
4155 for (i = 0; i < n_threads; i++) {
4156 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4157 tasks[i].sstride = FRAME_GET_STRIDE (src);
4158 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4159 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4161 tasks[i].width = width;
4162 tasks[i].height = (i + 1) * lines_per_thread;
4163 tasks[i].height = MIN (tasks[i].height, height);
4164 tasks[i].height -= i * lines_per_thread;
4166 tasks_p[i] = &tasks[i];
4169 gst_parallelized_task_runner_run (convert->conversion_runner,
4170 (GstParallelizedTaskFunc) convert_AYUV_YUY2_task, (gpointer) tasks_p);
4172 convert_fill_border (convert, dest);
4176 convert_AYUV_UYVY_task (FConvertPlaneTask * task)
4178 video_orc_convert_AYUV_UYVY (task->d, task->dstride, task->s,
4179 task->sstride, task->width / 2, task->height);
4183 convert_AYUV_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4184 GstVideoFrame * dest)
4186 gint width = convert->in_width;
4187 gint height = convert->in_height;
4189 FConvertPlaneTask *tasks;
4190 FConvertPlaneTask **tasks_p;
4192 gint lines_per_thread;
4195 s = FRAME_GET_LINE (src, convert->in_y);
4196 s += convert->in_x * 4;
4197 d = FRAME_GET_LINE (dest, convert->out_y);
4198 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4200 /* only for even width */
4201 n_threads = convert->conversion_runner->n_threads;
4202 tasks = g_newa (FConvertPlaneTask, n_threads);
4203 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4205 lines_per_thread = (height + n_threads - 1) / n_threads;
4207 for (i = 0; i < n_threads; i++) {
4208 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4209 tasks[i].sstride = FRAME_GET_STRIDE (src);
4210 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4211 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4213 tasks[i].width = width;
4214 tasks[i].height = (i + 1) * lines_per_thread;
4215 tasks[i].height = MIN (tasks[i].height, height);
4216 tasks[i].height -= i * lines_per_thread;
4218 tasks_p[i] = &tasks[i];
4221 gst_parallelized_task_runner_run (convert->conversion_runner,
4222 (GstParallelizedTaskFunc) convert_AYUV_UYVY_task, (gpointer) tasks_p);
4224 convert_fill_border (convert, dest);
4228 convert_AYUV_Y42B_task (FConvertPlaneTask * task)
4230 video_orc_convert_AYUV_Y42B (task->d, task->dstride, task->du,
4231 task->dustride, task->dv, task->dvstride,
4232 task->s, task->sstride, task->width / 2, task->height);
4236 convert_AYUV_Y42B (GstVideoConverter * convert, const GstVideoFrame * src,
4237 GstVideoFrame * dest)
4239 gint width = convert->in_width;
4240 gint height = convert->in_height;
4241 guint8 *s, *dy, *du, *dv;
4242 FConvertPlaneTask *tasks;
4243 FConvertPlaneTask **tasks_p;
4245 gint lines_per_thread;
4248 s = FRAME_GET_LINE (src, convert->in_y);
4249 s += convert->in_x * 4;
4251 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4252 dy += convert->out_x;
4253 du = FRAME_GET_U_LINE (dest, convert->out_y);
4254 du += convert->out_x >> 1;
4255 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4256 dv += convert->out_x >> 1;
4258 /* only works for even width */
4259 n_threads = convert->conversion_runner->n_threads;
4260 tasks = g_newa (FConvertPlaneTask, n_threads);
4261 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4263 lines_per_thread = (height + n_threads - 1) / n_threads;
4265 for (i = 0; i < n_threads; i++) {
4266 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4267 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4268 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4269 tasks[i].sstride = FRAME_GET_STRIDE (src);
4270 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4271 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4272 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4273 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4275 tasks[i].width = width;
4276 tasks[i].height = (i + 1) * lines_per_thread;
4277 tasks[i].height = MIN (tasks[i].height, height);
4278 tasks[i].height -= i * lines_per_thread;
4280 tasks_p[i] = &tasks[i];
4283 gst_parallelized_task_runner_run (convert->conversion_runner,
4284 (GstParallelizedTaskFunc) convert_AYUV_Y42B_task, (gpointer) tasks_p);
4286 convert_fill_border (convert, dest);
4290 convert_AYUV_Y444_task (FConvertPlaneTask * task)
4292 video_orc_convert_AYUV_Y444 (task->d, task->dstride, task->du,
4293 task->dustride, task->dv, task->dvstride,
4294 task->s, task->sstride, task->width, task->height);
4298 convert_AYUV_Y444 (GstVideoConverter * convert, const GstVideoFrame * src,
4299 GstVideoFrame * dest)
4301 gint width = convert->in_width;
4302 gint height = convert->in_height;
4303 guint8 *s, *dy, *du, *dv;
4304 FConvertPlaneTask *tasks;
4305 FConvertPlaneTask **tasks_p;
4307 gint lines_per_thread;
4310 s = FRAME_GET_LINE (src, convert->in_y);
4311 s += convert->in_x * 4;
4313 dy = FRAME_GET_Y_LINE (dest, convert->out_y);
4314 dy += convert->out_x;
4315 du = FRAME_GET_U_LINE (dest, convert->out_y);
4316 du += convert->out_x;
4317 dv = FRAME_GET_V_LINE (dest, convert->out_y);
4318 dv += convert->out_x;
4320 n_threads = convert->conversion_runner->n_threads;
4321 tasks = g_newa (FConvertPlaneTask, n_threads);
4322 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4324 lines_per_thread = (height + n_threads - 1) / n_threads;
4326 for (i = 0; i < n_threads; i++) {
4327 tasks[i].dstride = FRAME_GET_Y_STRIDE (dest);
4328 tasks[i].dustride = FRAME_GET_U_STRIDE (dest);
4329 tasks[i].dvstride = FRAME_GET_V_STRIDE (dest);
4330 tasks[i].sstride = FRAME_GET_STRIDE (src);
4331 tasks[i].d = dy + i * lines_per_thread * tasks[i].dstride;
4332 tasks[i].du = du + i * lines_per_thread * tasks[i].dustride;
4333 tasks[i].dv = dv + i * lines_per_thread * tasks[i].dvstride;
4334 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4336 tasks[i].width = width;
4337 tasks[i].height = (i + 1) * lines_per_thread;
4338 tasks[i].height = MIN (tasks[i].height, height);
4339 tasks[i].height -= i * lines_per_thread;
4341 tasks_p[i] = &tasks[i];
4344 gst_parallelized_task_runner_run (convert->conversion_runner,
4345 (GstParallelizedTaskFunc) convert_AYUV_Y444_task, (gpointer) tasks_p);
4346 convert_fill_border (convert, dest);
4350 convert_Y42B_YUY2_task (FConvertPlaneTask * task)
4352 video_orc_convert_Y42B_YUY2 (task->d, task->dstride,
4353 task->s, task->sstride,
4354 task->su, task->sustride,
4355 task->sv, task->svstride, (task->width + 1) / 2, task->height);
4359 convert_Y42B_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4360 GstVideoFrame * dest)
4362 gint width = convert->in_width;
4363 gint height = convert->in_height;
4364 guint8 *sy, *su, *sv, *d;
4365 FConvertPlaneTask *tasks;
4366 FConvertPlaneTask **tasks_p;
4368 gint lines_per_thread;
4371 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4372 sy += convert->in_x;
4373 su = FRAME_GET_U_LINE (src, convert->in_y);
4374 su += convert->in_x >> 1;
4375 sv = FRAME_GET_V_LINE (src, convert->in_y);
4376 sv += convert->in_x >> 1;
4378 d = FRAME_GET_LINE (dest, convert->out_y);
4379 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4381 n_threads = convert->conversion_runner->n_threads;
4382 tasks = g_newa (FConvertPlaneTask, n_threads);
4383 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4385 lines_per_thread = (height + n_threads - 1) / n_threads;
4387 for (i = 0; i < n_threads; i++) {
4388 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4389 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4390 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4391 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4392 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4393 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4394 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4395 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4397 tasks[i].width = width;
4398 tasks[i].height = (i + 1) * lines_per_thread;
4399 tasks[i].height = MIN (tasks[i].height, height);
4400 tasks[i].height -= i * lines_per_thread;
4402 tasks_p[i] = &tasks[i];
4405 gst_parallelized_task_runner_run (convert->conversion_runner,
4406 (GstParallelizedTaskFunc) convert_Y42B_YUY2_task, (gpointer) tasks_p);
4408 convert_fill_border (convert, dest);
4412 convert_Y42B_UYVY_task (FConvertPlaneTask * task)
4414 video_orc_convert_Y42B_UYVY (task->d, task->dstride,
4415 task->s, task->sstride,
4416 task->su, task->sustride,
4417 task->sv, task->svstride, (task->width + 1) / 2, task->height);
4421 convert_Y42B_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4422 GstVideoFrame * dest)
4424 gint width = convert->in_width;
4425 gint height = convert->in_height;
4426 guint8 *sy, *su, *sv, *d;
4427 FConvertPlaneTask *tasks;
4428 FConvertPlaneTask **tasks_p;
4430 gint lines_per_thread;
4433 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4434 sy += convert->in_x;
4435 su = FRAME_GET_U_LINE (src, convert->in_y);
4436 su += convert->in_x >> 1;
4437 sv = FRAME_GET_V_LINE (src, convert->in_y);
4438 sv += convert->in_x >> 1;
4440 d = FRAME_GET_LINE (dest, convert->out_y);
4441 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4443 n_threads = convert->conversion_runner->n_threads;
4444 tasks = g_newa (FConvertPlaneTask, n_threads);
4445 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4447 lines_per_thread = (height + n_threads - 1) / n_threads;
4449 for (i = 0; i < n_threads; i++) {
4450 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4451 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4452 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4453 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4454 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4455 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4456 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4457 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4459 tasks[i].width = width;
4460 tasks[i].height = (i + 1) * lines_per_thread;
4461 tasks[i].height = MIN (tasks[i].height, height);
4462 tasks[i].height -= i * lines_per_thread;
4464 tasks_p[i] = &tasks[i];
4467 gst_parallelized_task_runner_run (convert->conversion_runner,
4468 (GstParallelizedTaskFunc) convert_Y42B_UYVY_task, (gpointer) tasks_p);
4470 convert_fill_border (convert, dest);
4474 convert_Y42B_AYUV_task (FConvertPlaneTask * task)
4476 video_orc_convert_Y42B_AYUV (task->d, task->dstride, task->s,
4480 task->sv, task->svstride, task->alpha, task->width / 2, task->height);
4484 convert_Y42B_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
4485 GstVideoFrame * dest)
4487 gint width = convert->in_width;
4488 gint height = convert->in_height;
4489 guint8 *sy, *su, *sv, *d;
4490 guint8 alpha = MIN (convert->alpha_value, 255);
4491 FConvertPlaneTask *tasks;
4492 FConvertPlaneTask **tasks_p;
4494 gint lines_per_thread;
4497 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4498 sy += convert->in_x;
4499 su = FRAME_GET_U_LINE (src, convert->in_y);
4500 su += convert->in_x >> 1;
4501 sv = FRAME_GET_V_LINE (src, convert->in_y);
4502 sv += convert->in_x >> 1;
4504 d = FRAME_GET_LINE (dest, convert->out_y);
4505 d += convert->out_x * 4;
4507 /* only for even width */
4508 n_threads = convert->conversion_runner->n_threads;
4509 tasks = g_newa (FConvertPlaneTask, n_threads);
4510 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4512 lines_per_thread = (height + n_threads - 1) / n_threads;
4514 for (i = 0; i < n_threads; i++) {
4515 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4516 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4517 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4518 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4519 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4520 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4521 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4522 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4524 tasks[i].width = width;
4525 tasks[i].height = (i + 1) * lines_per_thread;
4526 tasks[i].height = MIN (tasks[i].height, height);
4527 tasks[i].height -= i * lines_per_thread;
4528 tasks[i].alpha = alpha;
4530 tasks_p[i] = &tasks[i];
4533 gst_parallelized_task_runner_run (convert->conversion_runner,
4534 (GstParallelizedTaskFunc) convert_Y42B_AYUV_task, (gpointer) tasks_p);
4536 convert_fill_border (convert, dest);
4540 convert_Y444_YUY2_task (FConvertPlaneTask * task)
4542 video_orc_convert_Y444_YUY2 (task->d, task->dstride, task->s,
4545 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
4549 convert_Y444_YUY2 (GstVideoConverter * convert, const GstVideoFrame * src,
4550 GstVideoFrame * dest)
4552 gint width = convert->in_width;
4553 gint height = convert->in_height;
4554 guint8 *sy, *su, *sv, *d;
4555 FConvertPlaneTask *tasks;
4556 FConvertPlaneTask **tasks_p;
4558 gint lines_per_thread;
4561 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4562 sy += convert->in_x;
4563 su = FRAME_GET_U_LINE (src, convert->in_y);
4564 su += convert->in_x;
4565 sv = FRAME_GET_V_LINE (src, convert->in_y);
4566 sv += convert->in_x;
4568 d = FRAME_GET_LINE (dest, convert->out_y);
4569 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4571 n_threads = convert->conversion_runner->n_threads;
4572 tasks = g_newa (FConvertPlaneTask, n_threads);
4573 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4575 lines_per_thread = (height + n_threads - 1) / n_threads;
4577 for (i = 0; i < n_threads; i++) {
4578 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4579 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4580 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4581 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4582 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4583 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4584 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4585 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4587 tasks[i].width = width;
4588 tasks[i].height = (i + 1) * lines_per_thread;
4589 tasks[i].height = MIN (tasks[i].height, height);
4590 tasks[i].height -= i * lines_per_thread;
4592 tasks_p[i] = &tasks[i];
4595 gst_parallelized_task_runner_run (convert->conversion_runner,
4596 (GstParallelizedTaskFunc) convert_Y444_YUY2_task, (gpointer) tasks_p);
4598 convert_fill_border (convert, dest);
4602 convert_Y444_UYVY_task (FConvertPlaneTask * task)
4604 video_orc_convert_Y444_UYVY (task->d, task->dstride, task->s,
4607 task->sustride, task->sv, task->svstride, task->width / 2, task->height);
4611 convert_Y444_UYVY (GstVideoConverter * convert, const GstVideoFrame * src,
4612 GstVideoFrame * dest)
4614 gint width = convert->in_width;
4615 gint height = convert->in_height;
4616 guint8 *sy, *su, *sv, *d;
4617 FConvertPlaneTask *tasks;
4618 FConvertPlaneTask **tasks_p;
4620 gint lines_per_thread;
4623 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4624 sy += convert->in_x;
4625 su = FRAME_GET_U_LINE (src, convert->in_y);
4626 su += convert->in_x;
4627 sv = FRAME_GET_V_LINE (src, convert->in_y);
4628 sv += convert->in_x;
4630 d = FRAME_GET_LINE (dest, convert->out_y);
4631 d += (GST_ROUND_UP_2 (convert->out_x) * 2);
4633 n_threads = convert->conversion_runner->n_threads;
4634 tasks = g_newa (FConvertPlaneTask, n_threads);
4635 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4637 lines_per_thread = (height + n_threads - 1) / n_threads;
4639 for (i = 0; i < n_threads; i++) {
4640 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4641 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4642 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4643 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4644 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4645 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4646 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4647 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4649 tasks[i].width = width;
4650 tasks[i].height = (i + 1) * lines_per_thread;
4651 tasks[i].height = MIN (tasks[i].height, height);
4652 tasks[i].height -= i * lines_per_thread;
4654 tasks_p[i] = &tasks[i];
4657 gst_parallelized_task_runner_run (convert->conversion_runner,
4658 (GstParallelizedTaskFunc) convert_Y444_UYVY_task, (gpointer) tasks_p);
4660 convert_fill_border (convert, dest);
4664 convert_Y444_AYUV_task (FConvertPlaneTask * task)
4666 video_orc_convert_Y444_AYUV (task->d, task->dstride, task->s,
4670 task->sv, task->svstride, task->alpha, task->width, task->height);
4674 convert_Y444_AYUV (GstVideoConverter * convert, const GstVideoFrame * src,
4675 GstVideoFrame * dest)
4677 gint width = convert->in_width;
4678 gint height = convert->in_height;
4679 guint8 *sy, *su, *sv, *d;
4680 guint8 alpha = MIN (convert->alpha_value, 255);
4681 FConvertPlaneTask *tasks;
4682 FConvertPlaneTask **tasks_p;
4684 gint lines_per_thread;
4687 sy = FRAME_GET_Y_LINE (src, convert->in_y);
4688 sy += convert->in_x;
4689 su = FRAME_GET_U_LINE (src, convert->in_y);
4690 su += convert->in_x;
4691 sv = FRAME_GET_V_LINE (src, convert->in_y);
4692 sv += convert->in_x;
4694 d = FRAME_GET_LINE (dest, convert->out_y);
4695 d += convert->out_x * 4;
4697 n_threads = convert->conversion_runner->n_threads;
4698 tasks = g_newa (FConvertPlaneTask, n_threads);
4699 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4701 lines_per_thread = (height + n_threads - 1) / n_threads;
4703 for (i = 0; i < n_threads; i++) {
4704 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4705 tasks[i].sstride = FRAME_GET_Y_STRIDE (src);
4706 tasks[i].sustride = FRAME_GET_U_STRIDE (src);
4707 tasks[i].svstride = FRAME_GET_V_STRIDE (src);
4708 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4709 tasks[i].s = sy + i * lines_per_thread * tasks[i].sstride;
4710 tasks[i].su = su + i * lines_per_thread * tasks[i].sustride;
4711 tasks[i].sv = sv + i * lines_per_thread * tasks[i].svstride;
4713 tasks[i].width = width;
4714 tasks[i].height = (i + 1) * lines_per_thread;
4715 tasks[i].height = MIN (tasks[i].height, height);
4716 tasks[i].height -= i * lines_per_thread;
4717 tasks[i].alpha = alpha;
4719 tasks_p[i] = &tasks[i];
4722 gst_parallelized_task_runner_run (convert->conversion_runner,
4723 (GstParallelizedTaskFunc) convert_Y444_AYUV_task, (gpointer) tasks_p);
4725 convert_fill_border (convert, dest);
4728 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4730 convert_AYUV_ARGB_task (FConvertPlaneTask * task)
4732 video_orc_convert_AYUV_ARGB (task->d, task->dstride, task->s,
4733 task->sstride, task->data->im[0][0], task->data->im[0][2],
4734 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4735 task->width, task->height);
4739 convert_AYUV_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
4740 GstVideoFrame * dest)
4742 gint width = convert->in_width;
4743 gint height = convert->in_height;
4744 MatrixData *data = &convert->convert_matrix;
4746 FConvertPlaneTask *tasks;
4747 FConvertPlaneTask **tasks_p;
4749 gint lines_per_thread;
4752 s = FRAME_GET_LINE (src, convert->in_y);
4753 s += (convert->in_x * 4);
4754 d = FRAME_GET_LINE (dest, convert->out_y);
4755 d += (convert->out_x * 4);
4757 n_threads = convert->conversion_runner->n_threads;
4758 tasks = g_newa (FConvertPlaneTask, n_threads);
4759 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4761 lines_per_thread = (height + n_threads - 1) / n_threads;
4763 for (i = 0; i < n_threads; i++) {
4764 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4765 tasks[i].sstride = FRAME_GET_STRIDE (src);
4766 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4767 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4769 tasks[i].width = width;
4770 tasks[i].height = (i + 1) * lines_per_thread;
4771 tasks[i].height = MIN (tasks[i].height, height);
4772 tasks[i].height -= i * lines_per_thread;
4773 tasks[i].data = data;
4775 tasks_p[i] = &tasks[i];
4778 gst_parallelized_task_runner_run (convert->conversion_runner,
4779 (GstParallelizedTaskFunc) convert_AYUV_ARGB_task, (gpointer) tasks_p);
4781 convert_fill_border (convert, dest);
4785 convert_AYUV_BGRA_task (FConvertPlaneTask * task)
4787 video_orc_convert_AYUV_BGRA (task->d, task->dstride, task->s,
4788 task->sstride, task->data->im[0][0], task->data->im[0][2],
4789 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4790 task->width, task->height);
4794 convert_AYUV_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
4795 GstVideoFrame * dest)
4797 gint width = convert->in_width;
4798 gint height = convert->in_height;
4799 MatrixData *data = &convert->convert_matrix;
4801 FConvertPlaneTask *tasks;
4802 FConvertPlaneTask **tasks_p;
4804 gint lines_per_thread;
4807 s = FRAME_GET_LINE (src, convert->in_y);
4808 s += (convert->in_x * 4);
4809 d = FRAME_GET_LINE (dest, convert->out_y);
4810 d += (convert->out_x * 4);
4812 n_threads = convert->conversion_runner->n_threads;
4813 tasks = g_newa (FConvertPlaneTask, n_threads);
4814 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4816 lines_per_thread = (height + n_threads - 1) / n_threads;
4818 for (i = 0; i < n_threads; i++) {
4819 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4820 tasks[i].sstride = FRAME_GET_STRIDE (src);
4821 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4822 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4824 tasks[i].width = width;
4825 tasks[i].height = (i + 1) * lines_per_thread;
4826 tasks[i].height = MIN (tasks[i].height, height);
4827 tasks[i].height -= i * lines_per_thread;
4828 tasks[i].data = data;
4830 tasks_p[i] = &tasks[i];
4833 gst_parallelized_task_runner_run (convert->conversion_runner,
4834 (GstParallelizedTaskFunc) convert_AYUV_BGRA_task, (gpointer) tasks_p);
4836 convert_fill_border (convert, dest);
4840 convert_AYUV_ABGR_task (FConvertPlaneTask * task)
4842 video_orc_convert_AYUV_ABGR (task->d, task->dstride, task->s,
4843 task->sstride, task->data->im[0][0], task->data->im[0][2],
4844 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4845 task->width, task->height);
4849 convert_AYUV_ABGR (GstVideoConverter * convert, const GstVideoFrame * src,
4850 GstVideoFrame * dest)
4852 gint width = convert->in_width;
4853 gint height = convert->in_height;
4854 MatrixData *data = &convert->convert_matrix;
4856 FConvertPlaneTask *tasks;
4857 FConvertPlaneTask **tasks_p;
4859 gint lines_per_thread;
4862 s = FRAME_GET_LINE (src, convert->in_y);
4863 s += (convert->in_x * 4);
4864 d = FRAME_GET_LINE (dest, convert->out_y);
4865 d += (convert->out_x * 4);
4867 n_threads = convert->conversion_runner->n_threads;
4868 tasks = g_newa (FConvertPlaneTask, n_threads);
4869 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4871 lines_per_thread = (height + n_threads - 1) / n_threads;
4873 for (i = 0; i < n_threads; i++) {
4874 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4875 tasks[i].sstride = FRAME_GET_STRIDE (src);
4876 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4877 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4879 tasks[i].width = width;
4880 tasks[i].height = (i + 1) * lines_per_thread;
4881 tasks[i].height = MIN (tasks[i].height, height);
4882 tasks[i].height -= i * lines_per_thread;
4883 tasks[i].data = data;
4885 tasks_p[i] = &tasks[i];
4888 gst_parallelized_task_runner_run (convert->conversion_runner,
4889 (GstParallelizedTaskFunc) convert_AYUV_ABGR_task, (gpointer) tasks_p);
4891 convert_fill_border (convert, dest);
4895 convert_AYUV_RGBA_task (FConvertPlaneTask * task)
4897 video_orc_convert_AYUV_RGBA (task->d, task->dstride, task->s,
4898 task->sstride, task->data->im[0][0], task->data->im[0][2],
4899 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4900 task->width, task->height);
4904 convert_AYUV_RGBA (GstVideoConverter * convert, const GstVideoFrame * src,
4905 GstVideoFrame * dest)
4907 gint width = convert->in_width;
4908 gint height = convert->in_height;
4909 MatrixData *data = &convert->convert_matrix;
4911 FConvertPlaneTask *tasks;
4912 FConvertPlaneTask **tasks_p;
4914 gint lines_per_thread;
4917 s = FRAME_GET_LINE (src, convert->in_y);
4918 s += (convert->in_x * 4);
4919 d = FRAME_GET_LINE (dest, convert->out_y);
4920 d += (convert->out_x * 4);
4922 n_threads = convert->conversion_runner->n_threads;
4923 tasks = g_newa (FConvertPlaneTask, n_threads);
4924 tasks_p = g_newa (FConvertPlaneTask *, n_threads);
4926 lines_per_thread = (height + n_threads - 1) / n_threads;
4928 for (i = 0; i < n_threads; i++) {
4929 tasks[i].dstride = FRAME_GET_STRIDE (dest);
4930 tasks[i].sstride = FRAME_GET_STRIDE (src);
4931 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
4932 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
4934 tasks[i].width = width;
4935 tasks[i].height = (i + 1) * lines_per_thread;
4936 tasks[i].height = MIN (tasks[i].height, height);
4937 tasks[i].height -= i * lines_per_thread;
4938 tasks[i].data = data;
4940 tasks_p[i] = &tasks[i];
4943 gst_parallelized_task_runner_run (convert->conversion_runner,
4944 (GstParallelizedTaskFunc) convert_AYUV_RGBA_task, (gpointer) tasks_p);
4946 convert_fill_border (convert, dest);
4951 convert_I420_BGRA_task (FConvertTask * task)
4955 for (i = task->height_0; i < task->height_1; i++) {
4956 guint8 *sy, *su, *sv, *d;
4958 d = FRAME_GET_LINE (task->dest, i + task->out_y);
4959 d += (task->out_x * 4);
4960 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
4962 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
4963 su += (task->in_x >> 1);
4964 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
4965 sv += (task->in_x >> 1);
4967 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4968 video_orc_convert_I420_BGRA (d, sy, su, sv,
4969 task->data->im[0][0], task->data->im[0][2],
4970 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4973 video_orc_convert_I420_ARGB (d, sy, su, sv,
4974 task->data->im[0][0], task->data->im[0][2],
4975 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
4982 convert_I420_BGRA (GstVideoConverter * convert, const GstVideoFrame * src,
4983 GstVideoFrame * dest)
4986 gint width = convert->in_width;
4987 gint height = convert->in_height;
4988 MatrixData *data = &convert->convert_matrix;
4989 FConvertTask *tasks;
4990 FConvertTask **tasks_p;
4992 gint lines_per_thread;
4994 n_threads = convert->conversion_runner->n_threads;
4995 tasks = g_newa (FConvertTask, n_threads);
4996 tasks_p = g_newa (FConvertTask *, n_threads);
4998 lines_per_thread = (height + n_threads - 1) / n_threads;
5000 for (i = 0; i < n_threads; i++) {
5002 tasks[i].dest = dest;
5004 tasks[i].width = width;
5005 tasks[i].data = data;
5006 tasks[i].in_x = convert->in_x;
5007 tasks[i].in_y = convert->in_y;
5008 tasks[i].out_x = convert->out_x;
5009 tasks[i].out_y = convert->out_y;
5011 tasks[i].height_0 = i * lines_per_thread;
5012 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5013 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5015 tasks_p[i] = &tasks[i];
5018 gst_parallelized_task_runner_run (convert->conversion_runner,
5019 (GstParallelizedTaskFunc) convert_I420_BGRA_task, (gpointer) tasks_p);
5021 convert_fill_border (convert, dest);
5025 convert_I420_ARGB_task (FConvertTask * task)
5029 for (i = task->height_0; i < task->height_1; i++) {
5030 guint8 *sy, *su, *sv, *d;
5032 d = FRAME_GET_LINE (task->dest, i + task->out_y);
5033 d += (task->out_x * 4);
5034 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5036 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5037 su += (task->in_x >> 1);
5038 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5039 sv += (task->in_x >> 1);
5041 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5042 video_orc_convert_I420_ARGB (d, sy, su, sv,
5043 task->data->im[0][0], task->data->im[0][2],
5044 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5047 video_orc_convert_I420_BGRA (d, sy, su, sv,
5048 task->data->im[0][0], task->data->im[0][2],
5049 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5056 convert_I420_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5057 GstVideoFrame * dest)
5060 gint width = convert->in_width;
5061 gint height = convert->in_height;
5062 MatrixData *data = &convert->convert_matrix;
5063 FConvertTask *tasks;
5064 FConvertTask **tasks_p;
5066 gint lines_per_thread;
5068 n_threads = convert->conversion_runner->n_threads;
5069 tasks = g_newa (FConvertTask, n_threads);
5070 tasks_p = g_newa (FConvertTask *, n_threads);
5072 lines_per_thread = (height + n_threads - 1) / n_threads;
5074 for (i = 0; i < n_threads; i++) {
5076 tasks[i].dest = dest;
5078 tasks[i].width = width;
5079 tasks[i].data = data;
5080 tasks[i].in_x = convert->in_x;
5081 tasks[i].in_y = convert->in_y;
5082 tasks[i].out_x = convert->out_x;
5083 tasks[i].out_y = convert->out_y;
5085 tasks[i].height_0 = i * lines_per_thread;
5086 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5087 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5089 tasks_p[i] = &tasks[i];
5092 gst_parallelized_task_runner_run (convert->conversion_runner,
5093 (GstParallelizedTaskFunc) convert_I420_ARGB_task, (gpointer) tasks_p);
5095 convert_fill_border (convert, dest);
5099 convert_I420_pack_ARGB_task (FConvertTask * task)
5102 gpointer d[GST_VIDEO_MAX_PLANES];
5104 d[0] = FRAME_GET_LINE (task->dest, 0);
5107 task->out_x * GST_VIDEO_FORMAT_INFO_PSTRIDE (task->dest->info.finfo, 0);
5109 for (i = task->height_0; i < task->height_1; i++) {
5110 guint8 *sy, *su, *sv;
5112 sy = FRAME_GET_Y_LINE (task->src, i + task->in_y);
5114 su = FRAME_GET_U_LINE (task->src, (i + task->in_y) >> 1);
5115 su += (task->in_x >> 1);
5116 sv = FRAME_GET_V_LINE (task->src, (i + task->in_y) >> 1);
5117 sv += (task->in_x >> 1);
5119 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5120 video_orc_convert_I420_ARGB (task->tmpline, sy, su, sv,
5121 task->data->im[0][0], task->data->im[0][2],
5122 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5125 video_orc_convert_I420_BGRA (task->tmpline, sy, su, sv,
5126 task->data->im[0][0], task->data->im[0][2],
5127 task->data->im[2][1], task->data->im[1][1], task->data->im[1][2],
5130 task->dest->info.finfo->pack_func (task->dest->info.finfo,
5131 (GST_VIDEO_FRAME_IS_INTERLACED (task->dest) ?
5132 GST_VIDEO_PACK_FLAG_INTERLACED :
5133 GST_VIDEO_PACK_FLAG_NONE),
5134 task->tmpline, 0, d, task->dest->info.stride,
5135 task->dest->info.chroma_site, i + task->out_y, task->width);
5140 convert_I420_pack_ARGB (GstVideoConverter * convert, const GstVideoFrame * src,
5141 GstVideoFrame * dest)
5144 gint width = convert->in_width;
5145 gint height = convert->in_height;
5146 MatrixData *data = &convert->convert_matrix;
5147 FConvertTask *tasks;
5148 FConvertTask **tasks_p;
5150 gint lines_per_thread;
5152 n_threads = convert->conversion_runner->n_threads;
5153 tasks = g_newa (FConvertTask, n_threads);
5154 tasks_p = g_newa (FConvertTask *, n_threads);
5156 lines_per_thread = (height + n_threads - 1) / n_threads;
5158 for (i = 0; i < n_threads; i++) {
5160 tasks[i].dest = dest;
5162 tasks[i].width = width;
5163 tasks[i].data = data;
5164 tasks[i].in_x = convert->in_x;
5165 tasks[i].in_y = convert->in_y;
5166 tasks[i].out_x = convert->out_x;
5167 tasks[i].out_y = convert->out_y;
5168 tasks[i].tmpline = convert->tmpline[i];
5170 tasks[i].height_0 = i * lines_per_thread;
5171 tasks[i].height_1 = tasks[i].height_0 + lines_per_thread;
5172 tasks[i].height_1 = MIN (height, tasks[i].height_1);
5174 tasks_p[i] = &tasks[i];
5177 gst_parallelized_task_runner_run (convert->conversion_runner,
5178 (GstParallelizedTaskFunc) convert_I420_pack_ARGB_task,
5179 (gpointer) tasks_p);
5181 convert_fill_border (convert, dest);
5185 memset_u24 (guint8 * data, guint8 col[3], unsigned int n)
5189 for (i = 0; i < n; i++) {
5198 memset_u32_16 (guint8 * data, guint8 col[4], unsigned int n)
5202 for (i = 0; i < n; i += 2) {
5213 #define MAKE_BORDER_FUNC(func) \
5214 for (i = 0; i < out_y; i++) \
5215 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
5216 if (rb_width || lb_width) { \
5217 for (i = 0; i < out_height; i++) { \
5218 guint8 *d = FRAME_GET_PLANE_LINE (dest, k, i + out_y); \
5220 func (d, col, lb_width); \
5222 func (d + (pstride * r_border), col, rb_width); \
5225 for (i = out_y + out_height; i < out_maxheight; i++) \
5226 func (FRAME_GET_PLANE_LINE (dest, k, i), col, out_maxwidth); \
5229 convert_fill_border (GstVideoConverter * convert, GstVideoFrame * dest)
5232 const GstVideoFormatInfo *out_finfo;
5234 if (!convert->fill_border || !convert->borderline)
5237 out_finfo = convert->out_info.finfo;
5239 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
5241 for (k = 0; k < n_planes; k++) {
5242 gint i, out_x, out_y, out_width, out_height, pstride, pgroup;
5243 gint r_border, lb_width, rb_width;
5244 gint out_maxwidth, out_maxheight;
5247 out_x = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_x);
5248 out_y = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k, convert->out_y);
5250 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_width);
5252 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k, convert->out_height);
5254 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, k, convert->out_maxwidth);
5256 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, k,
5257 convert->out_maxheight);
5259 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, k);
5261 switch (GST_VIDEO_FORMAT_INFO_FORMAT (out_finfo)) {
5262 case GST_VIDEO_FORMAT_YUY2:
5263 case GST_VIDEO_FORMAT_YVYU:
5264 case GST_VIDEO_FORMAT_UYVY:
5266 out_maxwidth = GST_ROUND_UP_2 (out_maxwidth);
5273 r_border = out_x + out_width;
5274 rb_width = out_maxwidth - r_border;
5277 borders = &convert->borders[k];
5282 guint8 col = ((guint8 *) borders)[0];
5283 MAKE_BORDER_FUNC (memset);
5288 guint16 col = ((guint16 *) borders)[0];
5289 MAKE_BORDER_FUNC (video_orc_splat_u16);
5295 col[0] = ((guint8 *) borders)[0];
5296 col[1] = ((guint8 *) borders)[1];
5297 col[2] = ((guint8 *) borders)[2];
5298 MAKE_BORDER_FUNC (memset_u24);
5303 guint32 col = ((guint32 *) borders)[0];
5304 MAKE_BORDER_FUNC (video_orc_splat_u32);
5309 guint64 col = ((guint64 *) borders)[0];
5310 MAKE_BORDER_FUNC (video_orc_splat_u64);
5316 col[0] = ((guint8 *) borders)[0];
5317 col[2] = ((guint8 *) borders)[2];
5318 col[1] = ((guint8 *) borders)[r_border & 1 ? 3 : 1];
5319 col[3] = ((guint8 *) borders)[r_border & 1 ? 1 : 3];
5320 MAKE_BORDER_FUNC (memset_u32_16);
5331 const guint8 *s, *s2;
5333 gint sstride, dstride;
5339 convert_plane_fill_task (FSimpleScaleTask * task)
5341 video_orc_memset_2d (task->d, task->dstride,
5342 task->fill, task->width, task->height);
5346 convert_plane_fill (GstVideoConverter * convert,
5347 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5350 FSimpleScaleTask *tasks;
5351 FSimpleScaleTask **tasks_p;
5353 gint lines_per_thread;
5356 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5357 d += convert->fout_x[plane];
5359 n_threads = convert->conversion_runner->n_threads;
5360 tasks = g_newa (FSimpleScaleTask, n_threads);
5361 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5362 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5364 for (i = 0; i < n_threads; i++) {
5365 tasks[i].d = d + i * lines_per_thread * convert->fout_width[plane];
5367 tasks[i].fill = convert->ffill[plane];
5368 tasks[i].width = convert->fout_width[plane];
5369 tasks[i].height = (i + 1) * lines_per_thread;
5370 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5371 tasks[i].height -= i * lines_per_thread;
5372 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5374 tasks_p[i] = &tasks[i];
5377 gst_parallelized_task_runner_run (convert->conversion_runner,
5378 (GstParallelizedTaskFunc) convert_plane_fill_task, (gpointer) tasks_p);
5382 convert_plane_h_double_task (FSimpleScaleTask * task)
5384 video_orc_planar_chroma_422_444 (task->d,
5385 task->dstride, task->s, task->sstride, task->width / 2, task->height);
5389 convert_plane_h_double (GstVideoConverter * convert,
5390 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5393 gint splane = convert->fsplane[plane];
5394 FSimpleScaleTask *tasks;
5395 FSimpleScaleTask **tasks_p;
5397 gint lines_per_thread;
5400 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5401 s += convert->fin_x[splane];
5402 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5403 d += convert->fout_x[plane];
5405 n_threads = convert->conversion_runner->n_threads;
5406 tasks = g_newa (FSimpleScaleTask, n_threads);
5407 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5408 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5410 for (i = 0; i < n_threads; i++) {
5411 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5412 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5414 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5415 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5417 tasks[i].width = convert->fout_width[plane];
5418 tasks[i].height = (i + 1) * lines_per_thread;
5419 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5420 tasks[i].height -= i * lines_per_thread;
5422 tasks_p[i] = &tasks[i];
5425 gst_parallelized_task_runner_run (convert->conversion_runner,
5426 (GstParallelizedTaskFunc) convert_plane_h_double_task,
5427 (gpointer) tasks_p);
5431 convert_plane_h_halve_task (FSimpleScaleTask * task)
5433 video_orc_planar_chroma_444_422 (task->d,
5434 task->dstride, task->s, task->sstride, task->width, task->height);
5438 convert_plane_h_halve (GstVideoConverter * convert,
5439 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5442 gint splane = convert->fsplane[plane];
5443 FSimpleScaleTask *tasks;
5444 FSimpleScaleTask **tasks_p;
5446 gint lines_per_thread;
5449 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5450 s += convert->fin_x[splane];
5451 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5452 d += convert->fout_x[plane];
5454 n_threads = convert->conversion_runner->n_threads;
5455 tasks = g_newa (FSimpleScaleTask, n_threads);
5456 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5457 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5459 for (i = 0; i < n_threads; i++) {
5460 tasks[i].dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5461 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5463 tasks[i].d = d + i * lines_per_thread * tasks[i].dstride;
5464 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride;
5466 tasks[i].width = convert->fout_width[plane];
5467 tasks[i].height = (i + 1) * lines_per_thread;
5468 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5469 tasks[i].height -= i * lines_per_thread;
5471 tasks_p[i] = &tasks[i];
5474 gst_parallelized_task_runner_run (convert->conversion_runner,
5475 (GstParallelizedTaskFunc) convert_plane_h_halve_task, (gpointer) tasks_p);
5479 convert_plane_v_double_task (FSimpleScaleTask * task)
5481 video_orc_planar_chroma_420_422 (task->d, 2 * task->dstride, task->d2,
5482 2 * task->dstride, task->s, task->sstride, task->width, task->height / 2);
5486 convert_plane_v_double (GstVideoConverter * convert,
5487 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5489 guint8 *s, *d1, *d2;
5490 gint ds, splane = convert->fsplane[plane];
5491 FSimpleScaleTask *tasks;
5492 FSimpleScaleTask **tasks_p;
5494 gint lines_per_thread;
5497 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5498 s += convert->fin_x[splane];
5499 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5500 d1 += convert->fout_x[plane];
5501 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
5502 d2 += convert->fout_x[plane];
5503 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5505 n_threads = convert->conversion_runner->n_threads;
5506 tasks = g_newa (FSimpleScaleTask, n_threads);
5507 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5509 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
5512 for (i = 0; i < n_threads; i++) {
5513 tasks[i].d = d1 + i * lines_per_thread * ds;
5514 tasks[i].d2 = d2 + i * lines_per_thread * ds;
5515 tasks[i].dstride = ds;
5516 tasks[i].sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5517 tasks[i].s = s + i * lines_per_thread * tasks[i].sstride / 2;
5519 tasks[i].width = convert->fout_width[plane];
5520 tasks[i].height = (i + 1) * lines_per_thread;
5521 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5522 tasks[i].height -= i * lines_per_thread;
5524 tasks_p[i] = &tasks[i];
5527 gst_parallelized_task_runner_run (convert->conversion_runner,
5528 (GstParallelizedTaskFunc) convert_plane_v_double_task,
5529 (gpointer) tasks_p);
5533 convert_plane_v_halve_task (FSimpleScaleTask * task)
5535 video_orc_planar_chroma_422_420 (task->d, task->dstride, task->s,
5536 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
5541 convert_plane_v_halve (GstVideoConverter * convert,
5542 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5544 guint8 *s1, *s2, *d;
5545 gint ss, ds, splane = convert->fsplane[plane];
5546 FSimpleScaleTask *tasks;
5547 FSimpleScaleTask **tasks_p;
5549 gint lines_per_thread;
5552 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5553 s1 += convert->fin_x[splane];
5554 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
5555 s2 += convert->fin_x[splane];
5556 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5557 d += convert->fout_x[plane];
5559 ss = FRAME_GET_PLANE_STRIDE (src, splane);
5560 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5562 n_threads = convert->conversion_runner->n_threads;
5563 tasks = g_newa (FSimpleScaleTask, n_threads);
5564 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5565 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5567 for (i = 0; i < n_threads; i++) {
5568 tasks[i].d = d + i * lines_per_thread * ds;
5569 tasks[i].dstride = ds;
5570 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
5571 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
5572 tasks[i].sstride = ss;
5574 tasks[i].width = convert->fout_width[plane];
5575 tasks[i].height = (i + 1) * lines_per_thread;
5576 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5577 tasks[i].height -= i * lines_per_thread;
5579 tasks_p[i] = &tasks[i];
5582 gst_parallelized_task_runner_run (convert->conversion_runner,
5583 (GstParallelizedTaskFunc) convert_plane_v_halve_task, (gpointer) tasks_p);
5587 convert_plane_hv_double_task (FSimpleScaleTask * task)
5589 video_orc_planar_chroma_420_444 (task->d, 2 * task->dstride, task->d2,
5590 2 * task->dstride, task->s, task->sstride, (task->width + 1) / 2,
5595 convert_plane_hv_double (GstVideoConverter * convert,
5596 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5598 guint8 *s, *d1, *d2;
5599 gint ss, ds, splane = convert->fsplane[plane];
5600 FSimpleScaleTask *tasks;
5601 FSimpleScaleTask **tasks_p;
5603 gint lines_per_thread;
5606 s = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5607 s += convert->fin_x[splane];
5608 d1 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5609 d1 += convert->fout_x[plane];
5610 d2 = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane] + 1);
5611 d2 += convert->fout_x[plane];
5612 ss = FRAME_GET_PLANE_STRIDE (src, splane);
5613 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5615 n_threads = convert->conversion_runner->n_threads;
5616 tasks = g_newa (FSimpleScaleTask, n_threads);
5617 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5619 GST_ROUND_UP_2 ((convert->fout_height[plane] + n_threads -
5622 for (i = 0; i < n_threads; i++) {
5623 tasks[i].d = d1 + i * lines_per_thread * ds;
5624 tasks[i].d2 = d2 + i * lines_per_thread * ds;
5625 tasks[i].dstride = ds;
5626 tasks[i].sstride = ss;
5627 tasks[i].s = s + i * lines_per_thread * ss / 2;
5629 tasks[i].width = convert->fout_width[plane];
5630 tasks[i].height = (i + 1) * lines_per_thread;
5631 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5632 tasks[i].height -= i * lines_per_thread;
5634 tasks_p[i] = &tasks[i];
5637 gst_parallelized_task_runner_run (convert->conversion_runner,
5638 (GstParallelizedTaskFunc) convert_plane_hv_double_task,
5639 (gpointer) tasks_p);
5643 convert_plane_hv_halve_task (FSimpleScaleTask * task)
5645 video_orc_planar_chroma_444_420 (task->d, task->dstride, task->s,
5646 2 * task->sstride, task->s2, 2 * task->sstride, task->width,
5651 convert_plane_hv_halve (GstVideoConverter * convert,
5652 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5654 guint8 *s1, *s2, *d;
5655 gint ss, ds, splane = convert->fsplane[plane];
5656 FSimpleScaleTask *tasks;
5657 FSimpleScaleTask **tasks_p;
5659 gint lines_per_thread;
5662 s1 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane]);
5663 s1 += convert->fin_x[splane];
5664 s2 = FRAME_GET_PLANE_LINE (src, splane, convert->fin_y[splane] + 1);
5665 s2 += convert->fin_x[splane];
5666 d = FRAME_GET_PLANE_LINE (dest, plane, convert->fout_y[plane]);
5667 d += convert->fout_x[plane];
5668 ss = FRAME_GET_PLANE_STRIDE (src, splane);
5669 ds = FRAME_GET_PLANE_STRIDE (dest, plane);
5671 n_threads = convert->conversion_runner->n_threads;
5672 tasks = g_newa (FSimpleScaleTask, n_threads);
5673 tasks_p = g_newa (FSimpleScaleTask *, n_threads);
5674 lines_per_thread = (convert->fout_height[plane] + n_threads - 1) / n_threads;
5676 for (i = 0; i < n_threads; i++) {
5677 tasks[i].d = d + i * lines_per_thread * ds;
5678 tasks[i].dstride = ds;
5679 tasks[i].s = s1 + i * lines_per_thread * ss * 2;
5680 tasks[i].s2 = s2 + i * lines_per_thread * ss * 2;
5681 tasks[i].sstride = ss;
5683 tasks[i].width = convert->fout_width[plane];
5684 tasks[i].height = (i + 1) * lines_per_thread;
5685 tasks[i].height = MIN (tasks[i].height, convert->fout_height[plane]);
5686 tasks[i].height -= i * lines_per_thread;
5688 tasks_p[i] = &tasks[i];
5691 gst_parallelized_task_runner_run (convert->conversion_runner,
5692 (GstParallelizedTaskFunc) convert_plane_hv_halve_task,
5693 (gpointer) tasks_p);
5698 GstVideoScaler *h_scaler, *v_scaler;
5699 GstVideoFormat format;
5702 gint sstride, dstride;
5707 convert_plane_hv_task (FScaleTask * task)
5709 gst_video_scaler_2d (task->h_scaler, task->v_scaler, task->format,
5710 (guint8 *) task->s, task->sstride,
5711 task->d, task->dstride, task->x, task->y, task->w, task->h);
5715 convert_plane_hv (GstVideoConverter * convert,
5716 const GstVideoFrame * src, GstVideoFrame * dest, gint plane)
5718 gint in_x, in_y, out_x, out_y, out_width, out_height;
5719 GstVideoFormat format;
5720 gint splane = convert->fsplane[plane];
5722 gint sstride, dstride;
5724 FScaleTask **tasks_p;
5725 gint i, n_threads, lines_per_thread;
5727 in_x = convert->fin_x[splane];
5728 in_y = convert->fin_y[splane];
5729 out_x = convert->fout_x[plane];
5730 out_y = convert->fout_y[plane];
5731 out_width = convert->fout_width[plane];
5732 out_height = convert->fout_height[plane];
5733 format = convert->fformat[plane];
5735 s = FRAME_GET_PLANE_LINE (src, splane, in_y);
5737 d = FRAME_GET_PLANE_LINE (dest, plane, out_y);
5740 sstride = FRAME_GET_PLANE_STRIDE (src, splane);
5741 dstride = FRAME_GET_PLANE_STRIDE (dest, plane);
5743 n_threads = convert->conversion_runner->n_threads;
5744 tasks = g_newa (FScaleTask, n_threads);
5745 tasks_p = g_newa (FScaleTask *, n_threads);
5747 lines_per_thread = (out_height + n_threads - 1) / n_threads;
5749 for (i = 0; i < n_threads; i++) {
5751 convert->fh_scaler[plane].scaler ? convert->
5752 fh_scaler[plane].scaler[i] : NULL;
5754 convert->fv_scaler[plane].scaler ? convert->
5755 fv_scaler[plane].scaler[i] : NULL;
5756 tasks[i].format = format;
5759 tasks[i].sstride = sstride;
5760 tasks[i].dstride = dstride;
5763 tasks[i].w = out_width;
5765 tasks[i].y = i * lines_per_thread;
5766 tasks[i].h = tasks[i].y + lines_per_thread;
5767 tasks[i].h = MIN (out_height, tasks[i].h);
5769 tasks_p[i] = &tasks[i];
5772 gst_parallelized_task_runner_run (convert->conversion_runner,
5773 (GstParallelizedTaskFunc) convert_plane_hv_task, (gpointer) tasks_p);
5777 convert_scale_planes (GstVideoConverter * convert,
5778 const GstVideoFrame * src, GstVideoFrame * dest)
5782 n_planes = GST_VIDEO_FRAME_N_PLANES (dest);
5783 for (i = 0; i < n_planes; i++) {
5784 if (convert->fconvert[i])
5785 convert->fconvert[i] (convert, src, dest, i);
5787 convert_fill_border (convert, dest);
5791 convert_I420_SN12 (GstVideoConverter * convert, const GstVideoFrame * src,
5792 GstVideoFrame * dest )
5794 guint8 *mY, *mUV, *Y, *U, *V;
5797 gboolean interlaced = GST_VIDEO_FRAME_IS_INTERLACED (src);
5799 gint width = convert->in_width;
5800 gint height = convert->in_height;
5802 mY = mUV = Y = U = V = NULL;
5803 mY = GST_VIDEO_FRAME_PLANE_DATA (dest, 0);
5804 mUV = GST_VIDEO_FRAME_PLANE_DATA (dest, 1);
5806 for (i = 0; i < GST_ROUND_DOWN_2 (height); i += 2) {
5807 GET_LINE_OFFSETS (interlaced, i, l1, l2);
5809 Y = FRAME_GET_Y_LINE (src, l1);
5810 memcpy(mY, Y, width);
5812 Y = FRAME_GET_Y_LINE (src, l2);
5813 memcpy(mY, Y, width);
5816 U = FRAME_GET_U_LINE (src, i >> 1);
5817 V = FRAME_GET_V_LINE (src, i >> 1);
5818 for (j = 0; j < (width + 1) / 2; j++) {
5825 static GstVideoFormat
5826 get_scale_format (GstVideoFormat format, gint plane)
5828 GstVideoFormat res = GST_VIDEO_FORMAT_UNKNOWN;
5831 case GST_VIDEO_FORMAT_I420:
5832 case GST_VIDEO_FORMAT_YV12:
5833 case GST_VIDEO_FORMAT_Y41B:
5834 case GST_VIDEO_FORMAT_Y42B:
5835 case GST_VIDEO_FORMAT_Y444:
5836 case GST_VIDEO_FORMAT_GRAY8:
5837 case GST_VIDEO_FORMAT_A420:
5838 case GST_VIDEO_FORMAT_YUV9:
5839 case GST_VIDEO_FORMAT_YVU9:
5840 case GST_VIDEO_FORMAT_GBR:
5841 case GST_VIDEO_FORMAT_GBRA:
5842 res = GST_VIDEO_FORMAT_GRAY8;
5844 case GST_VIDEO_FORMAT_GRAY16_BE:
5845 case GST_VIDEO_FORMAT_GRAY16_LE:
5846 res = GST_VIDEO_FORMAT_GRAY16_BE;
5848 case GST_VIDEO_FORMAT_YUY2:
5849 case GST_VIDEO_FORMAT_UYVY:
5850 case GST_VIDEO_FORMAT_VYUY:
5851 case GST_VIDEO_FORMAT_YVYU:
5852 case GST_VIDEO_FORMAT_AYUV:
5853 case GST_VIDEO_FORMAT_RGBx:
5854 case GST_VIDEO_FORMAT_BGRx:
5855 case GST_VIDEO_FORMAT_xRGB:
5856 case GST_VIDEO_FORMAT_xBGR:
5857 case GST_VIDEO_FORMAT_RGBA:
5858 case GST_VIDEO_FORMAT_BGRA:
5859 case GST_VIDEO_FORMAT_ARGB:
5860 case GST_VIDEO_FORMAT_ABGR:
5861 case GST_VIDEO_FORMAT_RGB:
5862 case GST_VIDEO_FORMAT_BGR:
5863 case GST_VIDEO_FORMAT_v308:
5864 case GST_VIDEO_FORMAT_IYU2:
5865 case GST_VIDEO_FORMAT_ARGB64:
5866 case GST_VIDEO_FORMAT_AYUV64:
5869 case GST_VIDEO_FORMAT_RGB15:
5870 case GST_VIDEO_FORMAT_BGR15:
5871 case GST_VIDEO_FORMAT_RGB16:
5872 case GST_VIDEO_FORMAT_BGR16:
5873 res = GST_VIDEO_FORMAT_NV12;
5875 case GST_VIDEO_FORMAT_NV12:
5876 case GST_VIDEO_FORMAT_NV21:
5877 case GST_VIDEO_FORMAT_NV16:
5878 case GST_VIDEO_FORMAT_NV61:
5879 case GST_VIDEO_FORMAT_NV24:
5880 res = plane == 0 ? GST_VIDEO_FORMAT_GRAY8 : GST_VIDEO_FORMAT_NV12;
5882 case GST_VIDEO_FORMAT_UNKNOWN:
5883 case GST_VIDEO_FORMAT_ENCODED:
5884 case GST_VIDEO_FORMAT_v210:
5885 case GST_VIDEO_FORMAT_v216:
5886 case GST_VIDEO_FORMAT_UYVP:
5887 case GST_VIDEO_FORMAT_RGB8P:
5888 case GST_VIDEO_FORMAT_IYU1:
5889 case GST_VIDEO_FORMAT_r210:
5890 case GST_VIDEO_FORMAT_I420_10BE:
5891 case GST_VIDEO_FORMAT_I420_10LE:
5892 case GST_VIDEO_FORMAT_I422_10BE:
5893 case GST_VIDEO_FORMAT_I422_10LE:
5894 case GST_VIDEO_FORMAT_Y444_10BE:
5895 case GST_VIDEO_FORMAT_Y444_10LE:
5896 case GST_VIDEO_FORMAT_I420_12BE:
5897 case GST_VIDEO_FORMAT_I420_12LE:
5898 case GST_VIDEO_FORMAT_I422_12BE:
5899 case GST_VIDEO_FORMAT_I422_12LE:
5900 case GST_VIDEO_FORMAT_Y444_12BE:
5901 case GST_VIDEO_FORMAT_Y444_12LE:
5902 case GST_VIDEO_FORMAT_GBR_10BE:
5903 case GST_VIDEO_FORMAT_GBR_10LE:
5904 case GST_VIDEO_FORMAT_GBRA_10BE:
5905 case GST_VIDEO_FORMAT_GBRA_10LE:
5906 case GST_VIDEO_FORMAT_GBR_12BE:
5907 case GST_VIDEO_FORMAT_GBR_12LE:
5908 case GST_VIDEO_FORMAT_GBRA_12BE:
5909 case GST_VIDEO_FORMAT_GBRA_12LE:
5910 case GST_VIDEO_FORMAT_NV12_64Z32:
5911 case GST_VIDEO_FORMAT_A420_10BE:
5912 case GST_VIDEO_FORMAT_A420_10LE:
5913 case GST_VIDEO_FORMAT_A422_10BE:
5914 case GST_VIDEO_FORMAT_A422_10LE:
5915 case GST_VIDEO_FORMAT_A444_10BE:
5916 case GST_VIDEO_FORMAT_A444_10LE:
5917 case GST_VIDEO_FORMAT_P010_10BE:
5918 case GST_VIDEO_FORMAT_P010_10LE:
5919 case GST_VIDEO_FORMAT_SN12:
5920 case GST_VIDEO_FORMAT_ST12:
5922 g_assert_not_reached ();
5924 #ifdef TIZEN_FEATURE_VIDEO_MODIFICATION
5934 is_merge_yuv (GstVideoInfo * info)
5936 switch (GST_VIDEO_INFO_FORMAT (info)) {
5937 case GST_VIDEO_FORMAT_YUY2:
5938 case GST_VIDEO_FORMAT_YVYU:
5939 case GST_VIDEO_FORMAT_UYVY:
5940 case GST_VIDEO_FORMAT_VYUY:
5948 setup_scale (GstVideoConverter * convert)
5951 gint method, cr_method, stride, in_width, in_height, out_width, out_height;
5953 GstVideoInfo *in_info, *out_info;
5954 const GstVideoFormatInfo *in_finfo, *out_finfo;
5955 GstVideoFormat in_format, out_format;
5956 guint n_threads = convert->conversion_runner->n_threads;
5958 in_info = &convert->in_info;
5959 out_info = &convert->out_info;
5961 in_finfo = in_info->finfo;
5962 out_finfo = out_info->finfo;
5964 n_planes = GST_VIDEO_INFO_N_PLANES (out_info);
5966 method = GET_OPT_RESAMPLER_METHOD (convert);
5967 if (method == GST_VIDEO_RESAMPLER_METHOD_NEAREST)
5970 cr_method = GET_OPT_CHROMA_RESAMPLER_METHOD (convert);
5971 taps = GET_OPT_RESAMPLER_TAPS (convert);
5973 in_format = GST_VIDEO_INFO_FORMAT (in_info);
5974 out_format = GST_VIDEO_INFO_FORMAT (out_info);
5976 if(out_format == GST_VIDEO_FORMAT_SN12) {
5977 /* do nothing for SN12 output format */
5981 switch (in_format) {
5982 case GST_VIDEO_FORMAT_RGB15:
5983 case GST_VIDEO_FORMAT_RGB16:
5984 case GST_VIDEO_FORMAT_BGR15:
5985 case GST_VIDEO_FORMAT_BGR16:
5986 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
5987 case GST_VIDEO_FORMAT_GRAY16_BE:
5989 case GST_VIDEO_FORMAT_GRAY16_LE:
5991 if (method != GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
5992 GST_DEBUG ("%s only with nearest resampling",
5993 gst_video_format_to_string (in_format));
5997 case GST_VIDEO_FORMAT_SN12:
5998 return TRUE; /* do nothing for SN12 format */
6003 in_width = convert->in_width;
6004 in_height = convert->in_height;
6005 out_width = convert->out_width;
6006 out_height = convert->out_height;
6010 if (n_planes == 1 && !GST_VIDEO_FORMAT_INFO_IS_GRAY (out_finfo)) {
6014 if (is_merge_yuv (in_info)) {
6015 GstVideoScaler *y_scaler, *uv_scaler;
6017 if (in_width != out_width) {
6018 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6019 for (j = 0; j < n_threads; j++) {
6021 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6022 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_Y,
6023 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
6024 GST_VIDEO_COMP_Y, out_width), convert->config);
6026 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE,
6027 gst_video_scaler_get_max_taps (y_scaler),
6028 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, GST_VIDEO_COMP_U,
6029 in_width), GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo,
6030 GST_VIDEO_COMP_U, out_width), convert->config);
6032 convert->fh_scaler[0].scaler[j] =
6033 gst_video_scaler_combine_packed_YUV (y_scaler, uv_scaler,
6034 in_format, out_format);
6036 gst_video_scaler_free (y_scaler);
6037 gst_video_scaler_free (uv_scaler);
6040 convert->fh_scaler[0].scaler = NULL;
6043 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_Y);
6044 convert->fin_x[0] = GST_ROUND_UP_2 (convert->in_x) * pstride;
6045 convert->fout_x[0] = GST_ROUND_UP_2 (convert->out_x) * pstride;
6048 if (in_width != out_width && in_width != 0 && out_width != 0) {
6049 convert->fh_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6050 for (j = 0; j < n_threads; j++) {
6051 convert->fh_scaler[0].scaler[j] =
6052 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6053 in_width, out_width, convert->config);
6056 convert->fh_scaler[0].scaler = NULL;
6059 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, GST_VIDEO_COMP_R);
6060 convert->fin_x[0] = convert->in_x * pstride;
6061 convert->fout_x[0] = convert->out_x * pstride;
6064 stride = MAX (stride, GST_VIDEO_INFO_PLANE_STRIDE (in_info, 0));
6065 stride = MAX (stride, GST_VIDEO_INFO_PLANE_STRIDE (out_info, 0));
6067 if (in_height != out_height && in_height != 0 && out_height != 0) {
6068 convert->fv_scaler[0].scaler = g_new (GstVideoScaler *, n_threads);
6070 for (j = 0; j < n_threads; j++) {
6071 convert->fv_scaler[0].scaler[j] =
6072 gst_video_scaler_new (method, GST_VIDEO_SCALER_FLAG_NONE, taps,
6073 in_height, out_height, convert->config);
6076 convert->fv_scaler[0].scaler = NULL;
6079 convert->fin_y[0] = convert->in_y;
6080 convert->fout_y[0] = convert->out_y;
6081 convert->fout_width[0] = out_width;
6082 convert->fout_height[0] = out_height;
6083 convert->fconvert[0] = convert_plane_hv;
6084 convert->fformat[0] = get_scale_format (in_format, 0);
6085 convert->fsplane[0] = 0;
6087 for (i = 0; i < n_planes; i++) {
6088 gint comp, n_comp, j, iw, ih, ow, oh, pstride;
6089 gboolean need_v_scaler, need_h_scaler;
6090 GstStructure *config;
6091 gint resample_method;
6093 n_comp = GST_VIDEO_FORMAT_INFO_N_COMPONENTS (in_finfo);
6095 /* find the component in this plane and map it to the plane of
6098 for (j = 0; j < n_comp; j++) {
6099 if (GST_VIDEO_FORMAT_INFO_PLANE (out_finfo, j) == i) {
6105 stride = MAX (stride, GST_VIDEO_INFO_COMP_STRIDE (in_info, i));
6106 stride = MAX (stride, GST_VIDEO_INFO_COMP_STRIDE (out_info, i));
6108 iw = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, i, in_width);
6109 ih = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, i, in_height);
6110 ow = GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, i, out_width);
6111 oh = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, i, out_height);
6113 GST_DEBUG ("plane %d: %dx%d -> %dx%d", i, iw, ih, ow, oh);
6115 convert->fout_width[i] = ow;
6116 convert->fout_height[i] = oh;
6118 pstride = GST_VIDEO_FORMAT_INFO_PSTRIDE (out_finfo, i);
6120 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (in_finfo, i, convert->in_x);
6121 convert->fin_x[i] *= pstride;
6123 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (in_finfo, i, convert->in_y);
6124 convert->fout_x[i] =
6125 GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (out_finfo, i, convert->out_x);
6126 convert->fout_x[i] *= pstride;
6127 convert->fout_y[i] =
6128 GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_finfo, i, convert->out_y);
6130 GST_DEBUG ("plane %d: pstride %d", i, pstride);
6131 GST_DEBUG ("plane %d: in_x %d, in_y %d", i, convert->fin_x[i],
6133 GST_DEBUG ("plane %d: out_x %d, out_y %d", i, convert->fout_x[i],
6134 convert->fout_y[i]);
6137 convert->fconvert[i] = convert_plane_fill;
6138 if (GST_VIDEO_INFO_IS_YUV (out_info)) {
6140 convert->ffill[i] = convert->alpha_value;
6142 convert->ffill[i] = 0x00;
6144 convert->ffill[i] = 0x80;
6147 convert->ffill[i] = convert->alpha_value;
6149 convert->ffill[i] = 0x00;
6151 GST_DEBUG ("plane %d fill %02x", i, convert->ffill[i]);
6154 convert->fsplane[i] = GST_VIDEO_FORMAT_INFO_PLANE (in_finfo, comp);
6155 GST_DEBUG ("plane %d -> %d (comp %d)", i, convert->fsplane[i], comp);
6158 config = gst_structure_copy (convert->config);
6160 resample_method = (i == 0 ? method : cr_method);
6162 need_v_scaler = FALSE;
6163 need_h_scaler = FALSE;
6166 convert->fconvert[i] = convert_plane_hv;
6167 GST_DEBUG ("plane %d: copy", i);
6168 } else if (ih == 2 * oh && pstride == 1
6169 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6170 convert->fconvert[i] = convert_plane_v_halve;
6171 GST_DEBUG ("plane %d: vertical halve", i);
6172 } else if (2 * ih == oh && pstride == 1
6173 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6174 convert->fconvert[i] = convert_plane_v_double;
6175 GST_DEBUG ("plane %d: vertical double", i);
6177 convert->fconvert[i] = convert_plane_hv;
6178 GST_DEBUG ("plane %d: vertical scale", i);
6179 need_v_scaler = TRUE;
6181 } else if (ih == oh) {
6182 if (iw == 2 * ow && pstride == 1
6183 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6184 convert->fconvert[i] = convert_plane_h_halve;
6185 GST_DEBUG ("plane %d: horizontal halve", i);
6186 } else if (2 * iw == ow && pstride == 1
6187 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6188 convert->fconvert[i] = convert_plane_h_double;
6189 GST_DEBUG ("plane %d: horizontal double", i);
6191 convert->fconvert[i] = convert_plane_hv;
6192 GST_DEBUG ("plane %d: horizontal scale", i);
6193 need_h_scaler = TRUE;
6196 if (iw == 2 * ow && ih == 2 * oh && pstride == 1
6197 && resample_method == GST_VIDEO_RESAMPLER_METHOD_LINEAR) {
6198 convert->fconvert[i] = convert_plane_hv_halve;
6199 GST_DEBUG ("plane %d: horizontal/vertical halve", i);
6200 } else if (2 * iw == ow && 2 * ih == oh && pstride == 1
6201 && resample_method == GST_VIDEO_RESAMPLER_METHOD_NEAREST) {
6202 convert->fconvert[i] = convert_plane_hv_double;
6203 GST_DEBUG ("plane %d: horizontal/vertical double", i);
6205 convert->fconvert[i] = convert_plane_hv;
6206 GST_DEBUG ("plane %d: horizontal/vertical scale", i);
6207 need_v_scaler = TRUE;
6208 need_h_scaler = TRUE;
6212 if (need_h_scaler && iw != 0 && ow != 0) {
6213 convert->fh_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
6215 for (j = 0; j < n_threads; j++) {
6216 convert->fh_scaler[i].scaler[j] =
6217 gst_video_scaler_new (resample_method, GST_VIDEO_SCALER_FLAG_NONE,
6218 taps, iw, ow, config);
6221 convert->fh_scaler[i].scaler = NULL;
6224 if (need_v_scaler && ih != 0 && oh != 0) {
6225 convert->fv_scaler[i].scaler = g_new (GstVideoScaler *, n_threads);
6227 for (j = 0; j < n_threads; j++) {
6228 convert->fv_scaler[i].scaler[j] =
6229 gst_video_scaler_new (resample_method, GST_VIDEO_SCALER_FLAG_NONE,
6230 taps, ih, oh, config);
6233 convert->fv_scaler[i].scaler = NULL;
6236 gst_structure_free (config);
6237 convert->fformat[i] = get_scale_format (in_format, i);
6248 GstVideoFormat in_format;
6249 GstVideoFormat out_format;
6250 gboolean keeps_interlaced;
6251 gboolean needs_color_matrix;
6252 gboolean keeps_size;
6255 gboolean alpha_copy;
6257 gboolean alpha_mult;
6258 gint width_align, height_align;
6259 void (*convert) (GstVideoConverter * convert, const GstVideoFrame * src,
6260 GstVideoFrame * dest);
6263 static const VideoTransform transforms[] = {
6264 /* planar -> packed */
6265 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
6266 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
6267 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
6268 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
6269 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
6270 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
6272 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, FALSE,
6273 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_YUY2},
6274 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, FALSE,
6275 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_I420_UYVY},
6276 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, FALSE,
6277 FALSE, FALSE, TRUE, FALSE, 0, 0, convert_I420_AYUV},
6279 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6280 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_YUY2},
6281 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6282 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_Y42B_UYVY},
6283 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6284 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_Y42B_AYUV},
6286 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6287 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_YUY2},
6288 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6289 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_Y444_UYVY},
6290 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6291 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_Y444_AYUV},
6293 /* packed -> packed */
6294 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, FALSE, TRUE,
6295 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6296 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6297 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2}, /* alias */
6298 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6299 TRUE, FALSE, TRUE, FALSE, 1, 0, convert_YUY2_AYUV},
6301 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, FALSE, TRUE,
6302 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6303 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6304 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_YUY2},
6305 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, TRUE, TRUE,
6306 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_UYVY_AYUV},
6308 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_AYUV, TRUE, FALSE, FALSE, TRUE, TRUE,
6309 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6310 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YUY2, TRUE, FALSE, TRUE, TRUE,
6311 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_YUY2},
6312 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_UYVY, TRUE, FALSE, TRUE, TRUE,
6313 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_UYVY},
6315 /* packed -> planar */
6316 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
6317 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
6318 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
6319 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_I420},
6320 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6321 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y42B},
6322 {GST_VIDEO_FORMAT_YUY2, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6323 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_YUY2_Y444},
6324 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_GRAY8, TRUE, TRUE, TRUE, TRUE,
6325 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_GRAY8},
6327 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_I420, TRUE, FALSE, TRUE, FALSE,
6328 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
6329 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_YV12, TRUE, FALSE, TRUE, FALSE,
6330 FALSE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_I420},
6331 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6332 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y42B},
6333 {GST_VIDEO_FORMAT_UYVY, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6334 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_UYVY_Y444},
6336 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_I420, FALSE, FALSE, TRUE, TRUE,
6337 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
6338 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, TRUE, TRUE,
6339 TRUE, FALSE, FALSE, FALSE, 1, 1, convert_AYUV_I420},
6340 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y42B, TRUE, FALSE, TRUE, TRUE,
6341 TRUE, FALSE, FALSE, FALSE, 1, 0, convert_AYUV_Y42B},
6342 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_Y444, TRUE, FALSE, TRUE, TRUE,
6343 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_AYUV_Y444},
6345 /* planar -> planar */
6346 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6347 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6348 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6349 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6350 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6351 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6352 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6353 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6354 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6355 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6356 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_SN12, FALSE, FALSE, FALSE, TRUE,
6357 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_SN12},
6358 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6359 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6360 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6361 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6362 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6363 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6364 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6365 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6367 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6368 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6369 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6370 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6371 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6372 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6373 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6374 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6375 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6376 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6377 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6378 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6379 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6380 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6381 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6382 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6383 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6384 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6386 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6387 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6388 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6389 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6390 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6391 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6392 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6393 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6394 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6395 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6396 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6397 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6398 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6399 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6400 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6401 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6402 {GST_VIDEO_FORMAT_Y41B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6403 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6405 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6406 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6407 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6408 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6409 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6410 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6411 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6412 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6413 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6414 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6415 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6416 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6417 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6418 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6419 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6420 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6421 {GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6422 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6424 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6425 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6426 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6427 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6428 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6429 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6430 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6431 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6432 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6433 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6434 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6435 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6436 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6437 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6438 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6439 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6440 {GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6441 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6443 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6444 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6445 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6446 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6447 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6448 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6449 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6450 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6451 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6452 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6453 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6454 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6455 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6456 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6457 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6458 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6459 {GST_VIDEO_FORMAT_GRAY8, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6460 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6462 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6463 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6464 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6465 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6466 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6467 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6468 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6469 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6470 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6471 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6472 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6473 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6474 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6475 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6476 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6477 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6478 {GST_VIDEO_FORMAT_A420, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6479 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6481 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6482 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6483 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6484 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6485 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6486 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6487 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6488 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6489 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6490 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6491 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6492 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6493 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6494 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6495 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6496 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6497 {GST_VIDEO_FORMAT_YUV9, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6498 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6500 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_I420, FALSE, FALSE, FALSE, TRUE,
6501 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6502 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YV12, FALSE, FALSE, FALSE, TRUE,
6503 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6504 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y41B, FALSE, FALSE, FALSE, TRUE,
6505 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6506 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y42B, FALSE, FALSE, FALSE, TRUE,
6507 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6508 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_Y444, FALSE, FALSE, FALSE, TRUE,
6509 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6510 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_GRAY8, FALSE, FALSE, FALSE, TRUE,
6511 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6512 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_A420, FALSE, FALSE, FALSE, TRUE,
6513 TRUE, FALSE, TRUE, FALSE, 0, 0, convert_scale_planes},
6514 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YUV9, FALSE, FALSE, FALSE, TRUE,
6515 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6516 {GST_VIDEO_FORMAT_YVU9, GST_VIDEO_FORMAT_YVU9, FALSE, FALSE, FALSE, TRUE,
6517 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6519 /* sempiplanar -> semiplanar */
6520 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
6521 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6522 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
6523 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6524 {GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
6525 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6527 {GST_VIDEO_FORMAT_NV21, GST_VIDEO_FORMAT_NV21, TRUE, FALSE, FALSE, TRUE,
6528 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6530 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
6531 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6532 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
6533 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6534 {GST_VIDEO_FORMAT_NV16, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
6535 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6537 {GST_VIDEO_FORMAT_NV61, GST_VIDEO_FORMAT_NV61, TRUE, FALSE, FALSE, TRUE,
6538 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6540 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV12, TRUE, FALSE, FALSE, TRUE,
6541 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6542 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV16, TRUE, FALSE, FALSE, TRUE,
6543 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6544 {GST_VIDEO_FORMAT_NV24, GST_VIDEO_FORMAT_NV24, TRUE, FALSE, FALSE, TRUE,
6545 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6547 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
6548 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ARGB, TRUE, TRUE, TRUE, TRUE, TRUE,
6549 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB},
6550 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRA, TRUE, TRUE, TRUE, TRUE, TRUE,
6551 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA},
6552 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xRGB, TRUE, TRUE, TRUE, TRUE, TRUE,
6553 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ARGB}, /* alias */
6554 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_BGRx, TRUE, TRUE, TRUE, TRUE, TRUE,
6555 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_BGRA}, /* alias */
6556 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_ABGR, TRUE, TRUE, TRUE, TRUE, TRUE,
6557 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR},
6558 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBA, TRUE, TRUE, TRUE, TRUE, TRUE,
6559 TRUE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA},
6560 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_xBGR, TRUE, TRUE, TRUE, TRUE, TRUE,
6561 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_ABGR}, /* alias */
6562 {GST_VIDEO_FORMAT_AYUV, GST_VIDEO_FORMAT_RGBx, TRUE, TRUE, TRUE, TRUE, TRUE,
6563 FALSE, FALSE, FALSE, 0, 0, convert_AYUV_RGBA}, /* alias */
6566 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
6567 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6568 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
6569 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6570 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRA, FALSE, TRUE, TRUE, TRUE,
6571 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6572 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGRx, FALSE, TRUE, TRUE, TRUE,
6573 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_BGRA},
6575 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
6576 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6577 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
6578 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6579 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ARGB, FALSE, TRUE, TRUE, TRUE,
6580 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6581 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xRGB, FALSE, TRUE, TRUE, TRUE,
6582 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_ARGB},
6584 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
6585 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6586 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
6587 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6588 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
6589 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6590 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
6591 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6592 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
6593 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6594 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
6595 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6596 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
6597 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6598 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
6599 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6600 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
6601 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6602 {GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
6603 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6605 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_ABGR, FALSE, TRUE, TRUE, TRUE,
6606 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6607 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_xBGR, FALSE, TRUE, TRUE, TRUE,
6608 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6609 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBA, FALSE, TRUE, TRUE, TRUE,
6610 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6611 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGBx, FALSE, TRUE, TRUE, TRUE,
6612 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6613 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB, FALSE, TRUE, TRUE, TRUE,
6614 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6615 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR, FALSE, TRUE, TRUE, TRUE,
6616 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6617 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB15, FALSE, TRUE, TRUE, TRUE,
6618 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6619 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR15, FALSE, TRUE, TRUE, TRUE,
6620 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6621 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_RGB16, FALSE, TRUE, TRUE, TRUE,
6622 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6623 {GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_BGR16, FALSE, TRUE, TRUE, TRUE,
6624 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_I420_pack_ARGB},
6627 {GST_VIDEO_FORMAT_GBR, GST_VIDEO_FORMAT_GBR, TRUE, FALSE, FALSE, TRUE,
6628 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6630 {GST_VIDEO_FORMAT_YVYU, GST_VIDEO_FORMAT_YVYU, TRUE, FALSE, FALSE, TRUE,
6631 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6633 {GST_VIDEO_FORMAT_RGB15, GST_VIDEO_FORMAT_RGB15, TRUE, FALSE, FALSE, TRUE,
6634 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6635 {GST_VIDEO_FORMAT_RGB16, GST_VIDEO_FORMAT_RGB16, TRUE, FALSE, FALSE, TRUE,
6636 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6637 {GST_VIDEO_FORMAT_BGR15, GST_VIDEO_FORMAT_BGR15, TRUE, FALSE, FALSE, TRUE,
6638 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6639 {GST_VIDEO_FORMAT_BGR16, GST_VIDEO_FORMAT_BGR16, TRUE, FALSE, FALSE, TRUE,
6640 TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6642 {GST_VIDEO_FORMAT_RGB, GST_VIDEO_FORMAT_RGB, TRUE, FALSE, FALSE, TRUE, TRUE,
6643 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6644 {GST_VIDEO_FORMAT_BGR, GST_VIDEO_FORMAT_BGR, TRUE, FALSE, FALSE, TRUE, TRUE,
6645 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6646 {GST_VIDEO_FORMAT_v308, GST_VIDEO_FORMAT_v308, TRUE, FALSE, FALSE, TRUE, TRUE,
6647 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6648 {GST_VIDEO_FORMAT_IYU2, GST_VIDEO_FORMAT_IYU2, TRUE, FALSE, FALSE, TRUE, TRUE,
6649 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6651 {GST_VIDEO_FORMAT_ARGB, GST_VIDEO_FORMAT_ARGB, TRUE, FALSE, FALSE, TRUE, TRUE,
6652 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6653 {GST_VIDEO_FORMAT_xRGB, GST_VIDEO_FORMAT_xRGB, TRUE, FALSE, FALSE, TRUE, TRUE,
6654 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6655 {GST_VIDEO_FORMAT_ABGR, GST_VIDEO_FORMAT_ABGR, TRUE, FALSE, FALSE, TRUE, TRUE,
6656 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6657 {GST_VIDEO_FORMAT_xBGR, GST_VIDEO_FORMAT_xBGR, TRUE, FALSE, FALSE, TRUE, TRUE,
6658 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6659 {GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FORMAT_RGBA, TRUE, FALSE, FALSE, TRUE, TRUE,
6660 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6661 {GST_VIDEO_FORMAT_RGBx, GST_VIDEO_FORMAT_RGBx, TRUE, FALSE, FALSE, TRUE, TRUE,
6662 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6663 {GST_VIDEO_FORMAT_BGRA, GST_VIDEO_FORMAT_BGRA, TRUE, FALSE, FALSE, TRUE, TRUE,
6664 TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6665 {GST_VIDEO_FORMAT_BGRx, GST_VIDEO_FORMAT_BGRx, TRUE, FALSE, FALSE, TRUE, TRUE,
6666 FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6668 {GST_VIDEO_FORMAT_ARGB64, GST_VIDEO_FORMAT_ARGB64, TRUE, FALSE, FALSE, TRUE,
6669 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6670 {GST_VIDEO_FORMAT_AYUV64, GST_VIDEO_FORMAT_AYUV64, TRUE, FALSE, FALSE, TRUE,
6671 TRUE, TRUE, FALSE, FALSE, 0, 0, convert_scale_planes},
6673 {GST_VIDEO_FORMAT_GRAY16_LE, GST_VIDEO_FORMAT_GRAY16_LE, TRUE, FALSE, FALSE,
6674 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6675 {GST_VIDEO_FORMAT_GRAY16_BE, GST_VIDEO_FORMAT_GRAY16_BE, TRUE, FALSE, FALSE,
6676 TRUE, TRUE, FALSE, FALSE, FALSE, 0, 0, convert_scale_planes},
6680 video_converter_lookup_fastpath (GstVideoConverter * convert)
6683 GstVideoFormat in_format, out_format;
6684 GstVideoTransferFunction in_transf, out_transf;
6685 gboolean interlaced, same_matrix, same_primaries, same_size, crop, border;
6686 gboolean need_copy, need_set, need_mult;
6689 width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
6690 height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);
6692 if (GET_OPT_DITHER_QUANTIZATION (convert) != 1)
6695 /* we don't do gamma conversion in fastpath */
6696 in_transf = convert->in_info.colorimetry.transfer;
6697 out_transf = convert->out_info.colorimetry.transfer;
6699 same_size = (width == convert->out_width && height == convert->out_height);
6701 /* fastpaths don't do gamma */
6702 if (CHECK_GAMMA_REMAP (convert) && (!same_size || in_transf != out_transf))
6705 need_copy = (convert->alpha_mode & ALPHA_MODE_COPY) == ALPHA_MODE_COPY;
6706 need_set = (convert->alpha_mode & ALPHA_MODE_SET) == ALPHA_MODE_SET;
6707 need_mult = (convert->alpha_mode & ALPHA_MODE_MULT) == ALPHA_MODE_MULT;
6708 GST_DEBUG ("alpha copy %d, set %d, mult %d", need_copy, need_set, need_mult);
6710 in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
6711 out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
6713 if (CHECK_MATRIX_NONE (convert)) {
6716 GstVideoColorMatrix in_matrix, out_matrix;
6718 in_matrix = convert->in_info.colorimetry.matrix;
6719 out_matrix = convert->out_info.colorimetry.matrix;
6720 same_matrix = in_matrix == out_matrix;
6723 if (CHECK_PRIMARIES_NONE (convert)) {
6724 same_primaries = TRUE;
6726 GstVideoColorPrimaries in_primaries, out_primaries;
6728 in_primaries = convert->in_info.colorimetry.primaries;
6729 out_primaries = convert->out_info.colorimetry.primaries;
6730 same_primaries = in_primaries == out_primaries;
6733 interlaced = GST_VIDEO_INFO_IS_INTERLACED (&convert->in_info);
6734 interlaced |= GST_VIDEO_INFO_IS_INTERLACED (&convert->out_info);
6736 crop = convert->in_x || convert->in_y
6737 || convert->in_width < convert->in_maxwidth
6738 || convert->in_height < convert->in_maxheight;
6739 border = convert->out_x || convert->out_y
6740 || convert->out_width < convert->out_maxwidth
6741 || convert->out_height < convert->out_maxheight;
6743 for (i = 0; i < sizeof (transforms) / sizeof (transforms[0]); i++) {
6744 if (transforms[i].in_format == in_format &&
6745 transforms[i].out_format == out_format &&
6746 (transforms[i].keeps_interlaced || !interlaced) &&
6747 (transforms[i].needs_color_matrix || (same_matrix && same_primaries))
6748 && (!transforms[i].keeps_size || same_size)
6749 && (transforms[i].width_align & width) == 0
6750 && (transforms[i].height_align & height) == 0
6751 && (transforms[i].do_crop || !crop)
6752 && (transforms[i].do_border || !border)
6753 && (transforms[i].alpha_copy || !need_copy)
6754 && (transforms[i].alpha_set || !need_set)
6755 && (transforms[i].alpha_mult || !need_mult)) {
6758 GST_DEBUG ("using fastpath");
6759 if (transforms[i].needs_color_matrix)
6760 video_converter_compute_matrix (convert);
6761 convert->convert = transforms[i].convert;
6764 g_new (guint16 *, convert->conversion_runner->n_threads);
6765 for (j = 0; j < convert->conversion_runner->n_threads; j++)
6766 convert->tmpline[j] = g_malloc0 (sizeof (guint16) * (width + 8) * 4);
6768 if (!transforms[i].keeps_size)
6769 if (!setup_scale (convert))
6772 setup_borderline (convert);
6776 GST_DEBUG ("no fastpath found");