]> git.sesse.net Git - vlc/blob - modules/video_chroma/swscale.c
mediacodec: skip prerolled frames
[vlc] / modules / video_chroma / swscale.c
1 /*****************************************************************************
2  * swscale.c: scaling and chroma conversion using libswscale
3  *****************************************************************************
4  * Copyright (C) 1999-2008 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Gildas Bazin <gbazin@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #include <assert.h>
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
36 #include <vlc_cpu.h>
37
38 #include <libswscale/swscale.h>
39
40 #ifdef __APPLE__
41 # include <TargetConditionals.h>
42 #endif
43
44 #include "../codec/avcodec/chroma.h" // Chroma Avutil <-> VLC conversion
45
46 /* Gruikkkkkkkkkk!!!!! */
47 #undef AVPALETTE_SIZE
48 #define AVPALETTE_SIZE (256 * sizeof(uint32_t))
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53 static int  OpenScaler( vlc_object_t * );
54 static void CloseScaler( vlc_object_t * );
55
56 #define SCALEMODE_TEXT N_("Scaling mode")
57 #define SCALEMODE_LONGTEXT N_("Scaling mode to use.")
58
59 static const int pi_mode_values[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
60 const char *const ppsz_mode_descriptions[] =
61 { N_("Fast bilinear"), N_("Bilinear"), N_("Bicubic (good quality)"),
62   N_("Experimental"), N_("Nearest neighbour (bad quality)"),
63   N_("Area"), N_("Luma bicubic / chroma bilinear"), N_("Gauss"),
64   N_("SincR"), N_("Lanczos"), N_("Bicubic spline") };
65
66 vlc_module_begin ()
67     set_description( N_("Video scaling filter") )
68     set_shortname( N_("Swscale" ) )
69     set_capability( "video filter2", 150 )
70     set_category( CAT_VIDEO )
71     set_subcategory( SUBCAT_VIDEO_VFILTER )
72     set_callbacks( OpenScaler, CloseScaler )
73     add_integer( "swscale-mode", 2, SCALEMODE_TEXT, SCALEMODE_LONGTEXT, true )
74         change_integer_list( pi_mode_values, ppsz_mode_descriptions )
75 vlc_module_end ()
76
77 /* Version checking */
78 #if LIBSWSCALE_VERSION_INT >= ((0<<16)+(5<<8)+0)
79 /****************************************************************************
80  * Local prototypes
81  ****************************************************************************/
82
83 /**
84  * Internal swscale filter structure.
85  */
86 struct filter_sys_t
87 {
88     SwsFilter *p_filter;
89     int i_cpu_mask, i_sws_flags;
90
91     video_format_t fmt_in;
92     video_format_t fmt_out;
93     const vlc_chroma_description_t *desc_in;
94     const vlc_chroma_description_t *desc_out;
95
96     struct SwsContext *ctx;
97     struct SwsContext *ctxA;
98     picture_t *p_src_a;
99     picture_t *p_dst_a;
100     int i_extend_factor;
101     picture_t *p_src_e;
102     picture_t *p_dst_e;
103     bool b_add_a;
104     bool b_copy;
105     bool b_swap_uvi;
106     bool b_swap_uvo;
107 };
108
109 static picture_t *Filter( filter_t *, picture_t * );
110 static int  Init( filter_t * );
111 static void Clean( filter_t * );
112
113 typedef struct
114 {
115     int  i_fmti;
116     int  i_fmto;
117     bool b_has_a;
118     bool b_add_a;
119     int  i_sws_flags;
120     bool b_copy;
121     bool b_swap_uvi;
122     bool b_swap_uvo;
123 } ScalerConfiguration;
124
125 static int GetParameters( ScalerConfiguration *,
126                           const video_format_t *p_fmti,
127                           const video_format_t *p_fmto,
128                           int i_sws_flags_default );
129
130 static int GetSwsCpuMask(void);
131
132 /* SwScaler point resize quality seems really bad, let our scale module do it
133  * (change it to true to try) */
134 #define ALLOW_YUVP (false)
135 /* SwScaler does not like too small picture */
136 #define MINIMUM_WIDTH (32)
137
138 /* XXX is it always 3 even for BIG_ENDIAN (blend.c seems to think so) ? */
139 #define OFFSET_A (3)
140
141 /*****************************************************************************
142  * OpenScaler: probe the filter and return score
143  *****************************************************************************/
144 static int OpenScaler( vlc_object_t *p_this )
145 {
146     filter_t *p_filter = (filter_t*)p_this;
147     filter_sys_t *p_sys;
148
149     int i_sws_mode;
150
151     if( GetParameters( NULL,
152                        &p_filter->fmt_in.video,
153                        &p_filter->fmt_out.video, 0 ) )
154         return VLC_EGENERIC;
155
156     /* Allocate the memory needed to store the decoder's structure */
157     if( ( p_filter->p_sys = p_sys = calloc(1, sizeof(filter_sys_t)) ) == NULL )
158         return VLC_ENOMEM;
159
160     /* Set CPU capabilities */
161     p_sys->i_cpu_mask = GetSwsCpuMask();
162
163     /* */
164     i_sws_mode = var_CreateGetInteger( p_filter, "swscale-mode" );
165     switch( i_sws_mode )
166     {
167     case 0:  p_sys->i_sws_flags = SWS_FAST_BILINEAR; break;
168     case 1:  p_sys->i_sws_flags = SWS_BILINEAR; break;
169     case 2:  p_sys->i_sws_flags = SWS_BICUBIC; break;
170     case 3:  p_sys->i_sws_flags = SWS_X; break;
171     case 4:  p_sys->i_sws_flags = SWS_POINT; break;
172     case 5:  p_sys->i_sws_flags = SWS_AREA; break;
173     case 6:  p_sys->i_sws_flags = SWS_BICUBLIN; break;
174     case 7:  p_sys->i_sws_flags = SWS_GAUSS; break;
175     case 8:  p_sys->i_sws_flags = SWS_SINC; break;
176     case 9:  p_sys->i_sws_flags = SWS_LANCZOS; break;
177     case 10: p_sys->i_sws_flags = SWS_SPLINE; break;
178     default: p_sys->i_sws_flags = SWS_BICUBIC; i_sws_mode = 2; break;
179     }
180
181     /* Misc init */
182     memset( &p_sys->fmt_in,  0, sizeof(p_sys->fmt_in) );
183     memset( &p_sys->fmt_out, 0, sizeof(p_sys->fmt_out) );
184
185     if( Init( p_filter ) )
186     {
187         if( p_sys->p_filter )
188             sws_freeFilter( p_sys->p_filter );
189         free( p_sys );
190         return VLC_EGENERIC;
191     }
192
193     /* */
194     p_filter->pf_video_filter = Filter;
195
196     msg_Dbg( p_filter, "%ix%i (%ix%i) chroma: %4.4s -> %ix%i (%ix%i) chroma: %4.4s with scaling using %s",
197              p_filter->fmt_in.video.i_visible_width, p_filter->fmt_in.video.i_visible_height,
198              p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
199              (char *)&p_filter->fmt_in.video.i_chroma,
200              p_filter->fmt_out.video.i_visible_width, p_filter->fmt_out.video.i_visible_height,
201              p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
202              (char *)&p_filter->fmt_out.video.i_chroma,
203              ppsz_mode_descriptions[i_sws_mode] );
204
205     return VLC_SUCCESS;
206 }
207
208 /*****************************************************************************
209  * CloseFilter: clean up the filter
210  *****************************************************************************/
211 static void CloseScaler( vlc_object_t *p_this )
212 {
213     filter_t *p_filter = (filter_t*)p_this;
214     filter_sys_t *p_sys = p_filter->p_sys;
215
216     Clean( p_filter );
217     if( p_sys->p_filter )
218         sws_freeFilter( p_sys->p_filter );
219     free( p_sys );
220 }
221
222 /*****************************************************************************
223  * Helpers
224  *****************************************************************************/
225 static int GetSwsCpuMask(void)
226 {
227     int i_sws_cpu = 0;
228
229 #if defined(__i386__) || defined(__x86_64__)
230     if( vlc_CPU_MMX() )
231         i_sws_cpu |= SWS_CPU_CAPS_MMX;
232 #if (LIBSWSCALE_VERSION_INT >= ((0<<16)+(5<<8)+0))
233     if( vlc_CPU_MMXEXT() )
234         i_sws_cpu |= SWS_CPU_CAPS_MMX2;
235 #endif
236     if( vlc_CPU_3dNOW() )
237         i_sws_cpu |= SWS_CPU_CAPS_3DNOW;
238 #elif defined(__ppc__) || defined(__ppc64__) || defined(__powerpc__)
239     if( vlc_CPU_ALTIVEC() )
240         i_sws_cpu |= SWS_CPU_CAPS_ALTIVEC;
241 #endif
242
243     return i_sws_cpu;
244 }
245
246 static void FixParameters( int *pi_fmt, bool *pb_has_a, bool *pb_swap_uv, vlc_fourcc_t fmt )
247 {
248     switch( fmt )
249     {
250     case VLC_CODEC_YUV422A:
251         *pi_fmt = PIX_FMT_YUV422P;
252         *pb_has_a = true;
253         break;
254     case VLC_CODEC_YUV420A:
255         *pi_fmt = PIX_FMT_YUV420P;
256         *pb_has_a = true;
257         break;
258     case VLC_CODEC_YUVA:
259         *pi_fmt = PIX_FMT_YUV444P;
260         *pb_has_a = true;
261         break;
262     case VLC_CODEC_RGBA:
263         *pi_fmt = PIX_FMT_BGR32;
264         *pb_has_a = true;
265         break;
266     case VLC_CODEC_ARGB:
267         *pi_fmt = PIX_FMT_BGR32_1;
268         *pb_has_a = true;
269         break;
270     case VLC_CODEC_BGRA:
271         *pi_fmt = PIX_FMT_RGB32;
272         *pb_has_a = true;
273         break;
274     case VLC_CODEC_YV12:
275         *pi_fmt = PIX_FMT_YUV420P;
276         *pb_swap_uv = true;
277         break;
278     case VLC_CODEC_YV9:
279         *pi_fmt = PIX_FMT_YUV410P;
280         *pb_swap_uv = true;
281         break;
282     default:
283         break;
284     }
285 }
286
287 static int GetParameters( ScalerConfiguration *p_cfg,
288                           const video_format_t *p_fmti,
289                           const video_format_t *p_fmto,
290                           int i_sws_flags_default )
291 {
292     int i_fmti = -1;
293     int i_fmto = -1;
294
295     bool b_has_ai = false;
296     bool b_has_ao = false;
297     int i_sws_flags = i_sws_flags_default;
298     bool b_swap_uvi = false;
299     bool b_swap_uvo = false;
300
301     GetFfmpegChroma( &i_fmti, p_fmti );
302     GetFfmpegChroma( &i_fmto, p_fmto );
303
304     if( p_fmti->i_chroma == p_fmto->i_chroma )
305     {
306         if( p_fmti->i_chroma == VLC_CODEC_YUVP && ALLOW_YUVP )
307         {
308             i_fmti = i_fmto = PIX_FMT_GRAY8;
309             i_sws_flags = SWS_POINT;
310         }
311     }
312
313     FixParameters( &i_fmti, &b_has_ai, &b_swap_uvi, p_fmti->i_chroma );
314     FixParameters( &i_fmto, &b_has_ao, &b_swap_uvo, p_fmto->i_chroma );
315
316 #if !defined (__ANDROID__) && !defined(TARGET_OS_IPHONE)
317     /* FIXME TODO removed when ffmpeg is fixed
318      * Without SWS_ACCURATE_RND the quality is really bad for some conversions */
319     switch( i_fmto )
320     {
321     case PIX_FMT_ARGB:
322     case PIX_FMT_RGBA:
323     case PIX_FMT_ABGR:
324         i_sws_flags |= SWS_ACCURATE_RND;
325         break;
326     }
327 #endif
328
329     if( p_cfg )
330     {
331         p_cfg->i_fmti = i_fmti;
332         p_cfg->i_fmto = i_fmto;
333         p_cfg->b_has_a = b_has_ai && b_has_ao;
334         p_cfg->b_add_a = (!b_has_ai) && b_has_ao;
335         p_cfg->b_copy = i_fmti == i_fmto &&
336                         p_fmti->i_visible_width == p_fmto->i_visible_width &&
337                         p_fmti->i_visible_height == p_fmto->i_visible_height;
338         p_cfg->b_swap_uvi = b_swap_uvi;
339         p_cfg->b_swap_uvo = b_swap_uvo;
340         p_cfg->i_sws_flags = i_sws_flags;
341     }
342
343     if( i_fmti < 0 || i_fmto < 0 )
344         return VLC_EGENERIC;
345
346     return VLC_SUCCESS;
347 }
348
349 static int Init( filter_t *p_filter )
350 {
351     filter_sys_t *p_sys = p_filter->p_sys;
352     const video_format_t *p_fmti = &p_filter->fmt_in.video;
353     video_format_t       *p_fmto = &p_filter->fmt_out.video;
354
355     if( p_fmti->orientation != p_fmto->orientation )
356         return VLC_EGENERIC;
357
358     if( video_format_IsSimilar( p_fmti, &p_sys->fmt_in ) &&
359         video_format_IsSimilar( p_fmto, &p_sys->fmt_out ) &&
360         p_sys->ctx )
361     {
362         return VLC_SUCCESS;
363     }
364
365     Clean( p_filter );
366
367     /* Init with new parameters */
368     ScalerConfiguration cfg;
369     if( GetParameters( &cfg, p_fmti, p_fmto, p_sys->i_sws_flags ) )
370     {
371         msg_Err( p_filter, "format not supported" );
372         return VLC_EGENERIC;
373     }
374     if( p_fmti->i_visible_width <= 0 || p_fmti->i_visible_height <= 0 ||
375         p_fmto->i_visible_width <= 0 || p_fmto->i_visible_height <= 0 )
376     {
377         msg_Err( p_filter, "invalid scaling: %ix%i -> %ix%i",
378                  p_fmti->i_visible_width, p_fmti->i_visible_height,
379                  p_fmto->i_visible_width, p_fmto->i_visible_height);
380         return VLC_EGENERIC;
381     }
382
383     p_sys->desc_in = vlc_fourcc_GetChromaDescription( p_fmti->i_chroma );
384     p_sys->desc_out = vlc_fourcc_GetChromaDescription( p_fmto->i_chroma );
385     if( p_sys->desc_in == NULL || p_sys->desc_out == NULL )
386         return VLC_EGENERIC;
387
388     /* swscale does not like too small width */
389     p_sys->i_extend_factor = 1;
390     while( __MIN( p_fmti->i_visible_width, p_fmto->i_visible_width ) * p_sys->i_extend_factor < MINIMUM_WIDTH)
391         p_sys->i_extend_factor++;
392
393     const unsigned i_fmti_visible_width = p_fmti->i_visible_width * p_sys->i_extend_factor;
394     const unsigned i_fmto_visible_width = p_fmto->i_visible_width * p_sys->i_extend_factor;
395     for( int n = 0; n < (cfg.b_has_a ? 2 : 1); n++ )
396     {
397         const int i_fmti = n == 0 ? cfg.i_fmti : PIX_FMT_GRAY8;
398         const int i_fmto = n == 0 ? cfg.i_fmto : PIX_FMT_GRAY8;
399         struct SwsContext *ctx;
400
401         ctx = sws_getContext( i_fmti_visible_width, p_fmti->i_visible_height, i_fmti,
402                               i_fmto_visible_width, p_fmto->i_visible_height, i_fmto,
403                               cfg.i_sws_flags | p_sys->i_cpu_mask,
404                               p_sys->p_filter, NULL, 0 );
405         if( n == 0 )
406             p_sys->ctx = ctx;
407         else
408             p_sys->ctxA = ctx;
409     }
410     if( p_sys->ctxA )
411     {
412         p_sys->p_src_a = picture_New( VLC_CODEC_GREY, i_fmti_visible_width, p_fmti->i_visible_height, 0, 1 );
413         p_sys->p_dst_a = picture_New( VLC_CODEC_GREY, i_fmto_visible_width, p_fmto->i_visible_height, 0, 1 );
414     }
415     if( p_sys->i_extend_factor != 1 )
416     {
417         p_sys->p_src_e = picture_New( p_fmti->i_chroma, i_fmti_visible_width, p_fmti->i_visible_height, 0, 1 );
418         p_sys->p_dst_e = picture_New( p_fmto->i_chroma, i_fmto_visible_width, p_fmto->i_visible_height, 0, 1 );
419
420         if( p_sys->p_src_e )
421             memset( p_sys->p_src_e->p[0].p_pixels, 0, p_sys->p_src_e->p[0].i_pitch * p_sys->p_src_e->p[0].i_lines );
422         if( p_sys->p_dst_e )
423             memset( p_sys->p_dst_e->p[0].p_pixels, 0, p_sys->p_dst_e->p[0].i_pitch * p_sys->p_dst_e->p[0].i_lines );
424     }
425
426     if( !p_sys->ctx ||
427         ( cfg.b_has_a && ( !p_sys->ctxA || !p_sys->p_src_a || !p_sys->p_dst_a ) ) ||
428         ( p_sys->i_extend_factor != 1 && ( !p_sys->p_src_e || !p_sys->p_dst_e ) ) )
429     {
430         msg_Err( p_filter, "could not init SwScaler and/or allocate memory" );
431         Clean( p_filter );
432         return VLC_EGENERIC;
433     }
434
435     if (p_filter->b_allow_fmt_out_change)
436     {
437         /*
438          * If the transformation is not homothetic we must modify the
439          * aspect ratio of the output format in order to have the
440          * output picture displayed correctly and not stretched
441          * horizontally or vertically.
442          * WARNING: this is a hack, ideally this should not be needed
443          * and the vout should update its video format instead.
444          */
445         unsigned i_sar_num = p_fmti->i_sar_num * p_fmti->i_visible_width;
446         unsigned i_sar_den = p_fmti->i_sar_den * p_fmto->i_visible_width;
447         vlc_ureduce(&i_sar_num, &i_sar_den, i_sar_num, i_sar_den, 65536);
448         i_sar_num *= p_fmto->i_visible_height;
449         i_sar_den *= p_fmti->i_visible_height;
450         vlc_ureduce(&i_sar_num, &i_sar_den, i_sar_num, i_sar_den, 65536);
451         p_fmto->i_sar_num = i_sar_num;
452         p_fmto->i_sar_den = i_sar_den;
453     }
454
455     p_sys->b_add_a = cfg.b_add_a;
456     p_sys->b_copy = cfg.b_copy;
457     p_sys->fmt_in  = *p_fmti;
458     p_sys->fmt_out = *p_fmto;
459     p_sys->b_swap_uvi = cfg.b_swap_uvi;
460     p_sys->b_swap_uvo = cfg.b_swap_uvo;
461
462     return VLC_SUCCESS;
463 }
464
465 static void Clean( filter_t *p_filter )
466 {
467     filter_sys_t *p_sys = p_filter->p_sys;
468
469     if( p_sys->p_src_e )
470         picture_Release( p_sys->p_src_e );
471     if( p_sys->p_dst_e )
472         picture_Release( p_sys->p_dst_e );
473
474     if( p_sys->p_src_a )
475         picture_Release( p_sys->p_src_a );
476     if( p_sys->p_dst_a )
477         picture_Release( p_sys->p_dst_a );
478
479     if( p_sys->ctxA )
480         sws_freeContext( p_sys->ctxA );
481
482     if( p_sys->ctx )
483         sws_freeContext( p_sys->ctx );
484
485     /* We have to set it to null has we call be called again :( */
486     p_sys->ctx = NULL;
487     p_sys->ctxA = NULL;
488     p_sys->p_src_a = NULL;
489     p_sys->p_dst_a = NULL;
490     p_sys->p_src_e = NULL;
491     p_sys->p_dst_e = NULL;
492 }
493
494 static void GetPixels( uint8_t *pp_pixel[4], int pi_pitch[4],
495                        const vlc_chroma_description_t *desc,
496                        const video_format_t *fmt,
497                        const picture_t *p_picture, unsigned planes,
498                        bool b_swap_uv )
499 {
500     unsigned i = 0;
501
502     if( planes > (unsigned)p_picture->i_planes )
503         planes = p_picture->i_planes;
504     assert( !b_swap_uv || planes >= 3 );
505
506     for( ; i < planes; i++ )
507     {
508         const plane_t *p = p_picture->p + i;
509         if( b_swap_uv && (i == 1 || i== 2) )
510             p = p_picture->p + 3 - i;
511
512         pp_pixel[i] = p->p_pixels
513             + (((fmt->i_x_offset * desc->p[i].w.num) / desc->p[i].w.den)
514                 * p->i_pixel_pitch)
515             + (((fmt->i_y_offset * desc->p[i].h.num) / desc->p[i].h.den)
516                 * p->i_pitch);
517         pi_pitch[i] = p->i_pitch;
518     }
519
520     for( ; i < 4; i++ )
521     {
522         pp_pixel[i] = NULL;
523         pi_pitch[i] = 0;
524     }
525 }
526
527 static void ExtractA( picture_t *p_dst, const picture_t *restrict p_src,
528                       unsigned offset )
529 {
530     plane_t *d = &p_dst->p[0];
531     const plane_t *s = &p_src->p[0];
532
533     for( unsigned y = 0; y < p_dst->format.i_height; y++ )
534         for( unsigned x = 0; x < p_dst->format.i_width; x++ )
535             d->p_pixels[y*d->i_pitch+x] = s->p_pixels[y*s->i_pitch+4*x+offset];
536 }
537
538 static void InjectA( picture_t *p_dst, const picture_t *restrict p_src,
539                      unsigned offset )
540 {
541     plane_t *d = &p_dst->p[0];
542     const plane_t *s = &p_src->p[0];
543
544     for( unsigned y = 0; y < p_src->format.i_height; y++ )
545         for( unsigned x = 0; x < p_src->format.i_width; x++ )
546             d->p_pixels[y*d->i_pitch+4*x+offset] = s->p_pixels[y*s->i_pitch+x];
547 }
548
549 static void FillA( plane_t *d, unsigned i_offset )
550 {
551     for( int y = 0; y < d->i_visible_lines; y++ )
552         for( int x = 0; x < d->i_visible_pitch; x += d->i_pixel_pitch )
553             d->p_pixels[y*d->i_pitch+x+i_offset] = 0xff;
554 }
555
556 static void CopyPad( picture_t *p_dst, const picture_t *p_src )
557 {
558     picture_Copy( p_dst, p_src );
559     for( int n = 0; n < p_dst->i_planes; n++ )
560     {
561         const plane_t *s = &p_src->p[n];
562         plane_t *d = &p_dst->p[n];
563
564         for( int y = 0; y < s->i_lines && y < d->i_lines; y++ )
565         {
566             for( int x = s->i_visible_pitch; x < d->i_visible_pitch; x += s->i_pixel_pitch )
567                 memcpy( &d->p_pixels[y*d->i_pitch + x], &d->p_pixels[y*d->i_pitch + s->i_visible_pitch - s->i_pixel_pitch], s->i_pixel_pitch );
568         }
569     }
570 }
571
572 static void SwapUV( picture_t *p_dst, const picture_t *p_src )
573 {
574     picture_t tmp = *p_src;
575     tmp.p[1] = p_src->p[2];
576     tmp.p[2] = p_src->p[1];
577
578     picture_CopyPixels( p_dst, &tmp );
579 }
580
581 static void Convert( filter_t *p_filter, struct SwsContext *ctx,
582                      picture_t *p_dst, picture_t *p_src, int i_height,
583                      int i_plane_count, bool b_swap_uvi, bool b_swap_uvo )
584 {
585     filter_sys_t *p_sys = p_filter->p_sys;
586     uint8_t palette[AVPALETTE_SIZE];
587     uint8_t *src[4]; int src_stride[4];
588     uint8_t *dst[4]; int dst_stride[4];
589
590     GetPixels( src, src_stride, p_sys->desc_in, &p_filter->fmt_in.video,
591                p_src, i_plane_count, b_swap_uvi );
592     if( p_filter->fmt_in.video.i_chroma == VLC_CODEC_RGBP )
593     {
594         video_palette_t *src_pal =
595             p_src->format.p_palette ?
596             p_src->format.p_palette :
597             p_filter->fmt_in.video.p_palette;
598         memset( palette, 0, sizeof(palette) );
599         if( src_pal )
600             memcpy( palette, src_pal->palette,
601                     __MIN( sizeof(video_palette_t), AVPALETTE_SIZE ) );
602         src[1] = palette;
603         src_stride[1] = 4;
604     }
605
606     GetPixels( dst, dst_stride, p_sys->desc_out, &p_filter->fmt_out.video,
607                p_dst, i_plane_count, b_swap_uvo );
608
609 #if LIBSWSCALE_VERSION_INT  >= ((0<<16)+(5<<8)+0)
610     sws_scale( ctx, src, src_stride, 0, i_height,
611                dst, dst_stride );
612 #else
613     sws_scale_ordered( ctx, src, src_stride, 0, i_height,
614                        dst, dst_stride );
615 #endif
616 }
617
618 /****************************************************************************
619  * Filter: the whole thing
620  ****************************************************************************
621  * This function is called just after the thread is launched.
622  ****************************************************************************/
623 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
624 {
625     filter_sys_t *p_sys = p_filter->p_sys;
626     const video_format_t *p_fmti = &p_filter->fmt_in.video;
627     const video_format_t *p_fmto = &p_filter->fmt_out.video;
628     picture_t *p_pic_dst;
629
630     /* Check if format properties changed */
631     if( Init( p_filter ) )
632     {
633         picture_Release( p_pic );
634         return NULL;
635     }
636
637     /* Request output picture */
638     p_pic_dst = filter_NewPicture( p_filter );
639     if( !p_pic_dst )
640     {
641         picture_Release( p_pic );
642         return NULL;
643     }
644
645     /* */
646     picture_t *p_src = p_pic;
647     picture_t *p_dst = p_pic_dst;
648     if( p_sys->i_extend_factor != 1 )
649     {
650         p_src = p_sys->p_src_e;
651         p_dst = p_sys->p_dst_e;
652
653         CopyPad( p_src, p_pic );
654     }
655
656     if( p_sys->b_copy && p_sys->b_swap_uvi == p_sys->b_swap_uvo )
657         picture_CopyPixels( p_dst, p_src );
658     else if( p_sys->b_copy )
659         SwapUV( p_dst, p_src );
660     else
661         Convert( p_filter, p_sys->ctx, p_dst, p_src, p_fmti->i_visible_height,
662                  3, p_sys->b_swap_uvi, p_sys->b_swap_uvo );
663     if( p_sys->ctxA )
664     {
665         /* We extract the A plane to rescale it, and then we reinject it. */
666         if( p_fmti->i_chroma == VLC_CODEC_RGBA || p_fmti->i_chroma == VLC_CODEC_BGRA )
667             ExtractA( p_sys->p_src_a, p_src, OFFSET_A );
668         else if( p_fmti->i_chroma == VLC_CODEC_ARGB )
669             ExtractA( p_sys->p_src_a, p_src, 0 );
670         else
671             plane_CopyPixels( p_sys->p_src_a->p, p_src->p+A_PLANE );
672
673         Convert( p_filter, p_sys->ctxA, p_sys->p_dst_a, p_sys->p_src_a,
674                  p_fmti->i_visible_height, 1, false, false );
675         if( p_fmto->i_chroma == VLC_CODEC_RGBA || p_fmto->i_chroma == VLC_CODEC_BGRA )
676             InjectA( p_dst, p_sys->p_dst_a, OFFSET_A );
677         else if( p_fmto->i_chroma == VLC_CODEC_ARGB )
678             InjectA( p_dst, p_sys->p_dst_a, 0 );
679         else
680             plane_CopyPixels( p_dst->p+A_PLANE, p_sys->p_dst_a->p );
681     }
682     else if( p_sys->b_add_a )
683     {
684         /* We inject a complete opaque alpha plane */
685         if( p_fmto->i_chroma == VLC_CODEC_RGBA || p_fmto->i_chroma == VLC_CODEC_BGRA )
686             FillA( &p_dst->p[0], OFFSET_A );
687         else if( p_fmto->i_chroma == VLC_CODEC_ARGB )
688             FillA( &p_dst->p[0], 0 );
689         else
690             FillA( &p_dst->p[A_PLANE], 0 );
691     }
692
693     if( p_sys->i_extend_factor != 1 )
694     {
695         picture_CopyPixels( p_pic_dst, p_dst );
696     }
697
698     picture_CopyProperties( p_pic_dst, p_pic );
699     picture_Release( p_pic );
700     return p_pic_dst;
701 }
702
703 #else /* LIBSWSCALE_VERSION_INT >= ((0<<16)+(5<<8)+0) */
704
705 int OpenScaler( vlc_object_t *p_this )
706 {
707     return VLC_EGENERIC;
708 }
709
710 void CloseScaler( vlc_object_t *p_this )
711 {
712 }
713
714 #endif /* LIBSWSCALE_VERSION_INT >= ((0<<16)+(5<<8)+0) */