1 /*****************************************************************************
2 * swscale.c: scaling and chroma conversion using libswscale
3 *****************************************************************************
4 * Copyright (C) 1999-2008 VLC authors and VideoLAN
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7 * Gildas Bazin <gbazin@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_filter.h>
35 #include <vlc_picture.h>
38 #include <libswscale/swscale.h>
39 #include <libswscale/version.h>
42 # include <TargetConditionals.h>
45 #include "../codec/avcodec/chroma.h" // Chroma Avutil <-> VLC conversion
47 /* Gruikkkkkkkkkk!!!!! */
49 #define AVPALETTE_SIZE (256 * sizeof(uint32_t))
51 /*****************************************************************************
53 *****************************************************************************/
54 static int OpenScaler( filter_t
* );
55 static void CloseScaler( filter_t
* );
57 #define SCALEMODE_TEXT N_("Scaling mode")
58 #define SCALEMODE_LONGTEXT N_("Scaling mode to use.")
60 static const int pi_mode_values
[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
61 static const char *const ppsz_mode_descriptions
[] =
62 { N_("Fast bilinear"), N_("Bilinear"), N_("Bicubic (good quality)"),
63 N_("Experimental"), N_("Nearest neighbor (bad quality)"),
64 N_("Area"), N_("Luma bicubic / chroma bilinear"), N_("Gauss"),
65 N_("SincR"), N_("Lanczos"), N_("Bicubic spline") };
68 set_description( N_("Video scaling filter") )
69 set_shortname( N_("Swscale" ) )
70 set_category( CAT_VIDEO
)
71 set_subcategory( SUBCAT_VIDEO_VFILTER
)
72 set_callback_video_converter( OpenScaler
, 150 )
73 add_integer( "swscale-mode", 2, SCALEMODE_TEXT
, SCALEMODE_LONGTEXT
, true )
74 change_integer_list( pi_mode_values
, ppsz_mode_descriptions
)
77 /* Version checking */
78 /****************************************************************************
80 ****************************************************************************/
83 * Internal swscale filter structure.
88 int i_cpu_mask
, i_sws_flags
;
90 video_format_t fmt_in
;
91 video_format_t fmt_out
;
92 const vlc_chroma_description_t
*desc_in
;
93 const vlc_chroma_description_t
*desc_out
;
95 struct SwsContext
*ctx
;
96 struct SwsContext
*ctxA
;
108 static picture_t
*Filter( filter_t
*, picture_t
* );
109 static int Init( filter_t
* );
110 static void Clean( filter_t
* );
122 } ScalerConfiguration
;
124 static int GetParameters( ScalerConfiguration
*,
125 const video_format_t
*p_fmti
,
126 const video_format_t
*p_fmto
,
127 int i_sws_flags_default
);
129 static int GetSwsCpuMask(void);
131 /* SwScaler point resize quality seems really bad, let our scale module do it
132 * (change it to true to try) */
133 #define ALLOW_YUVP (false)
134 /* SwScaler does not like too small picture */
135 #define MINIMUM_WIDTH (32)
137 /* XXX is it always 3 even for BIG_ENDIAN (blend.c seems to think so) ? */
140 static const struct vlc_filter_operations filter_ops
= {
141 .filter_video
= Filter
, .close
= CloseScaler
,
144 /*****************************************************************************
145 * OpenScaler: probe the filter and return score
146 *****************************************************************************/
147 static int OpenScaler( filter_t
*p_filter
)
153 if( GetParameters( NULL
,
154 &p_filter
->fmt_in
.video
,
155 &p_filter
->fmt_out
.video
, 0 ) )
158 /* Allocate the memory needed to store the decoder's structure */
159 if( ( p_filter
->p_sys
= p_sys
= calloc(1, sizeof(filter_sys_t
)) ) == NULL
)
162 /* Set CPU capabilities */
163 p_sys
->i_cpu_mask
= GetSwsCpuMask();
166 i_sws_mode
= var_CreateGetInteger( p_filter
, "swscale-mode" );
169 case 0: p_sys
->i_sws_flags
= SWS_FAST_BILINEAR
; break;
170 case 1: p_sys
->i_sws_flags
= SWS_BILINEAR
; break;
171 case 2: p_sys
->i_sws_flags
= SWS_BICUBIC
; break;
172 case 3: p_sys
->i_sws_flags
= SWS_X
; break;
173 case 4: p_sys
->i_sws_flags
= SWS_POINT
; break;
174 case 5: p_sys
->i_sws_flags
= SWS_AREA
; break;
175 case 6: p_sys
->i_sws_flags
= SWS_BICUBLIN
; break;
176 case 7: p_sys
->i_sws_flags
= SWS_GAUSS
; break;
177 case 8: p_sys
->i_sws_flags
= SWS_SINC
; break;
178 case 9: p_sys
->i_sws_flags
= SWS_LANCZOS
; break;
179 case 10: p_sys
->i_sws_flags
= SWS_SPLINE
; break;
180 default: p_sys
->i_sws_flags
= SWS_BICUBIC
; i_sws_mode
= 2; break;
184 memset( &p_sys
->fmt_in
, 0, sizeof(p_sys
->fmt_in
) );
185 memset( &p_sys
->fmt_out
, 0, sizeof(p_sys
->fmt_out
) );
187 if( Init( p_filter
) )
189 if( p_sys
->p_filter
)
190 sws_freeFilter( p_sys
->p_filter
);
196 p_filter
->ops
= &filter_ops
;
198 msg_Dbg( p_filter
, "%ix%i (%ix%i) chroma: %4.4s -> %ix%i (%ix%i) chroma: %4.4s with scaling using %s",
199 p_filter
->fmt_in
.video
.i_visible_width
, p_filter
->fmt_in
.video
.i_visible_height
,
200 p_filter
->fmt_in
.video
.i_width
, p_filter
->fmt_in
.video
.i_height
,
201 (char *)&p_filter
->fmt_in
.video
.i_chroma
,
202 p_filter
->fmt_out
.video
.i_visible_width
, p_filter
->fmt_out
.video
.i_visible_height
,
203 p_filter
->fmt_out
.video
.i_width
, p_filter
->fmt_out
.video
.i_height
,
204 (char *)&p_filter
->fmt_out
.video
.i_chroma
,
205 ppsz_mode_descriptions
[i_sws_mode
] );
210 /*****************************************************************************
211 * CloseFilter: clean up the filter
212 *****************************************************************************/
213 static void CloseScaler( filter_t
*p_filter
)
215 filter_sys_t
*p_sys
= p_filter
->p_sys
;
218 if( p_sys
->p_filter
)
219 sws_freeFilter( p_sys
->p_filter
);
223 /*****************************************************************************
225 *****************************************************************************/
226 static int GetSwsCpuMask(void)
230 #if LIBSWSCALE_VERSION_MAJOR < 4
231 #if defined(__i386__) || defined(__x86_64__)
233 i_sws_cpu
|= SWS_CPU_CAPS_MMX
;
234 if( vlc_CPU_MMXEXT() )
235 i_sws_cpu
|= SWS_CPU_CAPS_MMX2
;
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
;
247 static void FixParameters( int *pi_fmt
, bool *pb_has_a
, bool *pb_swap_uv
, vlc_fourcc_t fmt
)
251 case VLC_CODEC_YUV422A
:
252 *pi_fmt
= AV_PIX_FMT_YUV422P
;
255 case VLC_CODEC_YUV420A
:
256 *pi_fmt
= AV_PIX_FMT_YUV420P
;
260 *pi_fmt
= AV_PIX_FMT_YUV444P
;
264 *pi_fmt
= AV_PIX_FMT_BGR32
;
268 *pi_fmt
= AV_PIX_FMT_BGR32_1
;
272 *pi_fmt
= AV_PIX_FMT_RGB32
;
276 *pi_fmt
= AV_PIX_FMT_YUV420P
;
280 *pi_fmt
= AV_PIX_FMT_YUV410P
;
288 static int GetParameters( ScalerConfiguration
*p_cfg
,
289 const video_format_t
*p_fmti
,
290 const video_format_t
*p_fmto
,
291 int i_sws_flags_default
)
296 bool b_has_ai
= false;
297 bool b_has_ao
= false;
298 int i_sws_flags
= i_sws_flags_default
;
299 bool b_swap_uvi
= false;
300 bool b_swap_uvo
= false;
302 GetFfmpegChroma( &i_fmti
, p_fmti
);
303 GetFfmpegChroma( &i_fmto
, p_fmto
);
305 if( p_fmti
->i_chroma
== p_fmto
->i_chroma
)
307 if( p_fmti
->i_chroma
== VLC_CODEC_YUVP
&& ALLOW_YUVP
)
309 i_fmti
= i_fmto
= AV_PIX_FMT_GRAY8
;
310 i_sws_flags
= SWS_POINT
;
314 FixParameters( &i_fmti
, &b_has_ai
, &b_swap_uvi
, p_fmti
->i_chroma
);
315 FixParameters( &i_fmto
, &b_has_ao
, &b_swap_uvo
, p_fmto
->i_chroma
);
317 #if !defined (__ANDROID__) && !defined(TARGET_OS_IPHONE)
318 /* FIXME TODO removed when ffmpeg is fixed
319 * Without SWS_ACCURATE_RND the quality is really bad for some conversions */
322 case AV_PIX_FMT_ARGB
:
323 case AV_PIX_FMT_RGBA
:
324 case AV_PIX_FMT_ABGR
:
325 i_sws_flags
|= SWS_ACCURATE_RND
;
332 p_cfg
->i_fmti
= i_fmti
;
333 p_cfg
->i_fmto
= i_fmto
;
334 p_cfg
->b_has_a
= b_has_ai
&& b_has_ao
;
335 p_cfg
->b_add_a
= (!b_has_ai
) && b_has_ao
;
336 p_cfg
->b_copy
= i_fmti
== i_fmto
&&
337 p_fmti
->i_visible_width
== p_fmto
->i_visible_width
&&
338 p_fmti
->i_visible_height
== p_fmto
->i_visible_height
;
339 p_cfg
->b_swap_uvi
= b_swap_uvi
;
340 p_cfg
->b_swap_uvo
= b_swap_uvo
;
341 p_cfg
->i_sws_flags
= i_sws_flags
;
344 if( i_fmti
< 0 || i_fmto
< 0 )
350 static int Init( filter_t
*p_filter
)
352 filter_sys_t
*p_sys
= p_filter
->p_sys
;
353 const video_format_t
*p_fmti
= &p_filter
->fmt_in
.video
;
354 video_format_t
*p_fmto
= &p_filter
->fmt_out
.video
;
356 if( p_fmti
->orientation
!= p_fmto
->orientation
)
359 if( video_format_IsSimilar( p_fmti
, &p_sys
->fmt_in
) &&
360 video_format_IsSimilar( p_fmto
, &p_sys
->fmt_out
) &&
368 /* Init with new parameters */
369 ScalerConfiguration cfg
;
370 if( GetParameters( &cfg
, p_fmti
, p_fmto
, p_sys
->i_sws_flags
) )
372 msg_Err( p_filter
, "format not supported '%4.4s' %ux%u -> '%4.4s' %ux%u",
373 (const char *)&p_fmti
->i_chroma
, p_fmti
->i_visible_width
, p_fmti
->i_visible_height
,
374 (const char *)&p_fmto
->i_chroma
, p_fmto
->i_visible_width
, p_fmto
->i_visible_height
);
377 if( p_fmti
->i_visible_width
== 0 || p_fmti
->i_visible_height
== 0 ||
378 p_fmto
->i_visible_width
== 0 || p_fmto
->i_visible_height
== 0 )
380 msg_Err( p_filter
, "invalid scaling: %ix%i -> %ix%i",
381 p_fmti
->i_visible_width
, p_fmti
->i_visible_height
,
382 p_fmto
->i_visible_width
, p_fmto
->i_visible_height
);
386 p_sys
->desc_in
= vlc_fourcc_GetChromaDescription( p_fmti
->i_chroma
);
387 p_sys
->desc_out
= vlc_fourcc_GetChromaDescription( p_fmto
->i_chroma
);
388 if( p_sys
->desc_in
== NULL
|| p_sys
->desc_out
== NULL
)
391 /* swscale does not like too small width */
392 p_sys
->i_extend_factor
= 1;
393 while( __MIN( p_fmti
->i_visible_width
, p_fmto
->i_visible_width
) * p_sys
->i_extend_factor
< MINIMUM_WIDTH
)
394 p_sys
->i_extend_factor
++;
396 const unsigned i_fmti_visible_width
= p_fmti
->i_visible_width
* p_sys
->i_extend_factor
;
397 const unsigned i_fmto_visible_width
= p_fmto
->i_visible_width
* p_sys
->i_extend_factor
;
398 for( int n
= 0; n
< (cfg
.b_has_a
? 2 : 1); n
++ )
400 const int i_fmti
= n
== 0 ? cfg
.i_fmti
: AV_PIX_FMT_GRAY8
;
401 const int i_fmto
= n
== 0 ? cfg
.i_fmto
: AV_PIX_FMT_GRAY8
;
402 struct SwsContext
*ctx
;
404 ctx
= sws_getContext( i_fmti_visible_width
, p_fmti
->i_visible_height
, i_fmti
,
405 i_fmto_visible_width
, p_fmto
->i_visible_height
, i_fmto
,
406 cfg
.i_sws_flags
| p_sys
->i_cpu_mask
,
407 p_sys
->p_filter
, NULL
, 0 );
415 p_sys
->p_src_a
= picture_New( VLC_CODEC_GREY
, i_fmti_visible_width
, p_fmti
->i_visible_height
, 0, 1 );
416 p_sys
->p_dst_a
= picture_New( VLC_CODEC_GREY
, i_fmto_visible_width
, p_fmto
->i_visible_height
, 0, 1 );
418 if( p_sys
->i_extend_factor
!= 1 )
420 p_sys
->p_src_e
= picture_New( p_fmti
->i_chroma
, i_fmti_visible_width
, p_fmti
->i_visible_height
, 0, 1 );
421 p_sys
->p_dst_e
= picture_New( p_fmto
->i_chroma
, i_fmto_visible_width
, p_fmto
->i_visible_height
, 0, 1 );
424 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
);
426 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
);
430 ( cfg
.b_has_a
&& ( !p_sys
->ctxA
|| !p_sys
->p_src_a
|| !p_sys
->p_dst_a
) ) ||
431 ( p_sys
->i_extend_factor
!= 1 && ( !p_sys
->p_src_e
|| !p_sys
->p_dst_e
) ) )
433 msg_Err( p_filter
, "could not init SwScaler and/or allocate memory" );
438 if (p_filter
->b_allow_fmt_out_change
)
441 * If the transformation is not homothetic we must modify the
442 * aspect ratio of the output format in order to have the
443 * output picture displayed correctly and not stretched
444 * horizontally or vertically.
445 * WARNING: this is a hack, ideally this should not be needed
446 * and the vout should update its video format instead.
448 unsigned i_sar_num
= p_fmti
->i_sar_num
* p_fmti
->i_visible_width
;
449 unsigned i_sar_den
= p_fmti
->i_sar_den
* p_fmto
->i_visible_width
;
450 vlc_ureduce(&i_sar_num
, &i_sar_den
, i_sar_num
, i_sar_den
, 65536);
451 i_sar_num
*= p_fmto
->i_visible_height
;
452 i_sar_den
*= p_fmti
->i_visible_height
;
453 vlc_ureduce(&i_sar_num
, &i_sar_den
, i_sar_num
, i_sar_den
, 65536);
454 p_fmto
->i_sar_num
= i_sar_num
;
455 p_fmto
->i_sar_den
= i_sar_den
;
458 p_sys
->b_add_a
= cfg
.b_add_a
;
459 p_sys
->b_copy
= cfg
.b_copy
;
460 p_sys
->fmt_in
= *p_fmti
;
461 p_sys
->fmt_out
= *p_fmto
;
462 p_sys
->b_swap_uvi
= cfg
.b_swap_uvi
;
463 p_sys
->b_swap_uvo
= cfg
.b_swap_uvo
;
468 static void Clean( filter_t
*p_filter
)
470 filter_sys_t
*p_sys
= p_filter
->p_sys
;
473 picture_Release( p_sys
->p_src_e
);
475 picture_Release( p_sys
->p_dst_e
);
478 picture_Release( p_sys
->p_src_a
);
480 picture_Release( p_sys
->p_dst_a
);
483 sws_freeContext( p_sys
->ctxA
);
486 sws_freeContext( p_sys
->ctx
);
488 /* We have to set it to null has we call be called again :( */
491 p_sys
->p_src_a
= NULL
;
492 p_sys
->p_dst_a
= NULL
;
493 p_sys
->p_src_e
= NULL
;
494 p_sys
->p_dst_e
= NULL
;
497 static void GetPixels( uint8_t *pp_pixel
[4], int pi_pitch
[4],
498 const vlc_chroma_description_t
*desc
,
499 const video_format_t
*fmt
,
500 const picture_t
*p_picture
, unsigned planes
,
505 if( planes
> (unsigned)p_picture
->i_planes
)
506 planes
= p_picture
->i_planes
;
507 assert( !b_swap_uv
|| planes
>= 3 );
509 for( ; i
< planes
; i
++ )
511 const plane_t
*p
= p_picture
->p
+ i
;
512 if( b_swap_uv
&& (i
== 1 || i
== 2) )
513 p
= p_picture
->p
+ 3 - i
;
515 pp_pixel
[i
] = p
->p_pixels
516 + (((fmt
->i_x_offset
* desc
->p
[i
].w
.num
) / desc
->p
[i
].w
.den
)
518 + (((fmt
->i_y_offset
* desc
->p
[i
].h
.num
) / desc
->p
[i
].h
.den
)
520 pi_pitch
[i
] = p
->i_pitch
;
530 static void ExtractA( picture_t
*p_dst
, const picture_t
*restrict p_src
,
533 plane_t
*d
= &p_dst
->p
[0];
534 const plane_t
*s
= &p_src
->p
[0];
536 for( unsigned y
= 0; y
< p_dst
->format
.i_height
; y
++ )
537 for( unsigned x
= 0; x
< p_dst
->format
.i_width
; x
++ )
538 d
->p_pixels
[y
*d
->i_pitch
+x
] = s
->p_pixels
[y
*s
->i_pitch
+4*x
+offset
];
541 static void InjectA( picture_t
*p_dst
, const picture_t
*restrict p_src
,
544 plane_t
*d
= &p_dst
->p
[0];
545 const plane_t
*s
= &p_src
->p
[0];
547 for( unsigned y
= 0; y
< p_src
->format
.i_height
; y
++ )
548 for( unsigned x
= 0; x
< p_src
->format
.i_width
; x
++ )
549 d
->p_pixels
[y
*d
->i_pitch
+4*x
+offset
] = s
->p_pixels
[y
*s
->i_pitch
+x
];
552 static void FillA( plane_t
*d
, unsigned i_offset
)
554 for( int y
= 0; y
< d
->i_visible_lines
; y
++ )
555 for( int x
= 0; x
< d
->i_visible_pitch
; x
+= d
->i_pixel_pitch
)
556 d
->p_pixels
[y
*d
->i_pitch
+x
+i_offset
] = 0xff;
559 static void CopyPad( picture_t
*p_dst
, const picture_t
*p_src
)
561 picture_Copy( p_dst
, p_src
);
562 for( int n
= 0; n
< p_dst
->i_planes
; n
++ )
564 const plane_t
*s
= &p_src
->p
[n
];
565 plane_t
*d
= &p_dst
->p
[n
];
567 for( int y
= 0; y
< s
->i_lines
&& y
< d
->i_lines
; y
++ )
569 for( int x
= s
->i_visible_pitch
; x
< d
->i_visible_pitch
; x
+= s
->i_pixel_pitch
)
570 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
);
575 static void SwapUV( picture_t
*p_dst
, const picture_t
*p_src
)
577 picture_t tmp
= *p_src
;
578 tmp
.p
[1] = p_src
->p
[2];
579 tmp
.p
[2] = p_src
->p
[1];
581 picture_CopyPixels( p_dst
, &tmp
);
584 static void Convert( filter_t
*p_filter
, struct SwsContext
*ctx
,
585 picture_t
*p_dst
, picture_t
*p_src
, int i_height
,
586 int i_plane_count
, bool b_swap_uvi
, bool b_swap_uvo
)
588 filter_sys_t
*p_sys
= p_filter
->p_sys
;
589 uint8_t palette
[AVPALETTE_SIZE
];
590 uint8_t *src
[4], *dst
[4];
591 const uint8_t *csrc
[4];
592 int src_stride
[4], dst_stride
[4];
594 GetPixels( src
, src_stride
, p_sys
->desc_in
, &p_filter
->fmt_in
.video
,
595 p_src
, i_plane_count
, b_swap_uvi
);
596 if( p_filter
->fmt_in
.video
.i_chroma
== VLC_CODEC_RGBP
)
598 memset( palette
, 0, sizeof(palette
) );
599 if( p_filter
->fmt_in
.video
.p_palette
)
600 memcpy( palette
, p_filter
->fmt_in
.video
.p_palette
->palette
,
601 __MIN( sizeof(video_palette_t
), AVPALETTE_SIZE
) );
606 GetPixels( dst
, dst_stride
, p_sys
->desc_out
, &p_filter
->fmt_out
.video
,
607 p_dst
, i_plane_count
, b_swap_uvo
);
609 for (size_t i
= 0; i
< ARRAY_SIZE(src
); i
++)
612 #if LIBSWSCALE_VERSION_INT >= ((0<<16)+(5<<8)+0)
613 sws_scale( ctx
, csrc
, src_stride
, 0, i_height
,
616 sws_scale_ordered( ctx
, csrc
, src_stride
, 0, i_height
,
621 /****************************************************************************
622 * Filter: the whole thing
623 ****************************************************************************
624 * This function is called just after the thread is launched.
625 ****************************************************************************/
626 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
628 filter_sys_t
*p_sys
= p_filter
->p_sys
;
629 const video_format_t
*p_fmti
= &p_filter
->fmt_in
.video
;
630 const video_format_t
*p_fmto
= &p_filter
->fmt_out
.video
;
631 picture_t
*p_pic_dst
;
633 /* Check if format properties changed */
634 if( Init( p_filter
) )
636 picture_Release( p_pic
);
640 /* Request output picture */
641 p_pic_dst
= filter_NewPicture( p_filter
);
644 picture_Release( p_pic
);
649 picture_t
*p_src
= p_pic
;
650 picture_t
*p_dst
= p_pic_dst
;
651 if( p_sys
->i_extend_factor
!= 1 )
653 p_src
= p_sys
->p_src_e
;
654 p_dst
= p_sys
->p_dst_e
;
656 CopyPad( p_src
, p_pic
);
659 if( p_sys
->b_copy
&& p_sys
->b_swap_uvi
== p_sys
->b_swap_uvo
)
660 picture_CopyPixels( p_dst
, p_src
);
661 else if( p_sys
->b_copy
)
662 SwapUV( p_dst
, p_src
);
665 /* Even if alpha is unused, swscale expects the pointer to be set */
666 const int n_planes
= !p_sys
->ctxA
&& (p_src
->i_planes
== 4 ||
667 p_dst
->i_planes
== 4) ? 4 : 3;
668 Convert( p_filter
, p_sys
->ctx
, p_dst
, p_src
, p_fmti
->i_visible_height
,
669 n_planes
, p_sys
->b_swap_uvi
, p_sys
->b_swap_uvo
);
673 /* We extract the A plane to rescale it, and then we reinject it. */
674 if( p_fmti
->i_chroma
== VLC_CODEC_RGBA
|| p_fmti
->i_chroma
== VLC_CODEC_BGRA
)
675 ExtractA( p_sys
->p_src_a
, p_src
, OFFSET_A
);
676 else if( p_fmti
->i_chroma
== VLC_CODEC_ARGB
)
677 ExtractA( p_sys
->p_src_a
, p_src
, 0 );
679 plane_CopyPixels( p_sys
->p_src_a
->p
, p_src
->p
+A_PLANE
);
681 Convert( p_filter
, p_sys
->ctxA
, p_sys
->p_dst_a
, p_sys
->p_src_a
,
682 p_fmti
->i_visible_height
, 1, false, false );
683 if( p_fmto
->i_chroma
== VLC_CODEC_RGBA
|| p_fmto
->i_chroma
== VLC_CODEC_BGRA
)
684 InjectA( p_dst
, p_sys
->p_dst_a
, OFFSET_A
);
685 else if( p_fmto
->i_chroma
== VLC_CODEC_ARGB
)
686 InjectA( p_dst
, p_sys
->p_dst_a
, 0 );
688 plane_CopyPixels( p_dst
->p
+A_PLANE
, p_sys
->p_dst_a
->p
);
690 else if( p_sys
->b_add_a
)
692 /* We inject a complete opaque alpha plane */
693 if( p_fmto
->i_chroma
== VLC_CODEC_RGBA
|| p_fmto
->i_chroma
== VLC_CODEC_BGRA
)
694 FillA( &p_dst
->p
[0], OFFSET_A
);
695 else if( p_fmto
->i_chroma
== VLC_CODEC_ARGB
)
696 FillA( &p_dst
->p
[0], 0 );
698 FillA( &p_dst
->p
[A_PLANE
], 0 );
701 if( p_sys
->i_extend_factor
!= 1 )
703 picture_CopyPixels( p_pic_dst
, p_dst
);
706 picture_CopyProperties( p_pic_dst
, p_pic
);
707 picture_Release( p_pic
);