modules/codec/ffmpeg/video_filter.c is img_* API only now
[vlc.git] / modules / codec / ffmpeg / video_filter.c
1 /*****************************************************************************
2  * video filter: video filter doing chroma conversion and resizing
3  *               using the ffmpeg library
4  *****************************************************************************
5  * Copyright (C) 1999-2001 the VideoLAN team
6  * $Id$
7  *
8  * Authors: Gildas Bazin <gbazin@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 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 General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <vlc/vlc.h>
29 #include <vlc_codec.h>
30 #include <vlc_vout.h>
31 #include <vlc_filter.h>
32
33 /* ffmpeg header */
34 #ifdef HAVE_FFMPEG_AVCODEC_H
35 #   include <ffmpeg/avcodec.h>
36 #else
37 #   include <avcodec.h>
38 #endif
39
40 #include "ffmpeg.h"
41
42 #if !defined(HAVE_FFMPEG_SWSCALE_H) && !defined(HAVE_LIBSWSCALE_TREE)
43 void E_(InitLibavcodec) ( vlc_object_t *p_object );
44 static int CheckInit( filter_t *p_filter );
45 static picture_t *Process( filter_t *p_filter, picture_t *p_pic );
46
47 /*****************************************************************************
48  * filter_sys_t : filter descriptor
49  *****************************************************************************/
50 struct filter_sys_t
51 {
52     vlc_bool_t b_resize;
53     vlc_bool_t b_convert;
54     vlc_bool_t b_resize_first;
55     vlc_bool_t b_enable_croppadd;
56
57     es_format_t fmt_in;
58     int i_src_ffmpeg_chroma;
59     es_format_t fmt_out;
60     int i_dst_ffmpeg_chroma;
61
62     AVPicture tmp_pic;
63
64     ImgReSampleContext *p_rsc;
65 };
66
67 /*****************************************************************************
68  * OpenFilterEx: common code to OpenFilter and OpenCropPadd
69  *****************************************************************************/
70 static int OpenFilterEx( vlc_object_t *p_this, vlc_bool_t b_enable_croppadd )
71 {
72     filter_t *p_filter = (filter_t*)p_this;
73     filter_sys_t *p_sys;
74     vlc_bool_t b_convert, b_resize;
75
76     /* Check if we can handle that formats */
77     if( E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ) < 0 ||
78         E_(GetFfmpegChroma)( p_filter->fmt_out.video.i_chroma ) < 0 )
79     {
80         return VLC_EGENERIC;
81     }
82
83     b_resize =
84         ( p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ) ||
85         ( p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height );
86
87     if ( b_enable_croppadd )
88     {
89         b_resize = b_resize ||
90            ( p_filter->fmt_in.video.i_visible_width != p_filter->fmt_in.video.i_width ) ||
91            ( p_filter->fmt_in.video.i_visible_height != p_filter->fmt_in.video.i_height ) ||
92            ( p_filter->fmt_in.video.i_x_offset != 0 ) ||
93            ( p_filter->fmt_in.video.i_y_offset != 0 ) ||
94            ( p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width ) ||
95            ( p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height ) ||
96            ( p_filter->fmt_out.video.i_x_offset != 0 ) ||
97            ( p_filter->fmt_out.video.i_y_offset != 0 );
98     }
99
100     b_convert =
101         ( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma );
102
103     if( !b_resize && !b_convert )
104     {
105         /* Nothing to do */
106         return VLC_EGENERIC;
107     }
108
109     /* Allocate the memory needed to store the decoder's structure */
110     if( ( p_filter->p_sys = p_sys =
111           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
112     {
113         msg_Err( p_filter, "out of memory" );
114         return VLC_EGENERIC;
115     }
116
117     /* Misc init */
118     p_sys->p_rsc = NULL;
119     p_sys->b_enable_croppadd = b_enable_croppadd;
120     p_sys->i_src_ffmpeg_chroma =
121         E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma );
122     p_sys->i_dst_ffmpeg_chroma =
123         E_(GetFfmpegChroma)( p_filter->fmt_out.video.i_chroma );
124     p_filter->pf_video_filter = Process;
125     es_format_Init( &p_sys->fmt_in, 0, 0 );
126     es_format_Init( &p_sys->fmt_out, 0, 0 );
127
128     /* Dummy alloc, will be reallocated in CheckInit */
129     avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma,
130                      p_filter->fmt_out.video.i_width,
131                      p_filter->fmt_out.video.i_height );
132
133     if( CheckInit( p_filter ) != VLC_SUCCESS )
134     {
135         free( p_sys );
136         return VLC_EGENERIC;
137     }
138
139     msg_Dbg( p_filter, "input: %ix%i %4.4s -> %ix%i %4.4s",
140              p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
141              (char *)&p_filter->fmt_in.video.i_chroma,
142              p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
143              (char *)&p_filter->fmt_out.video.i_chroma );
144
145     /* libavcodec needs to be initialized for some chroma conversions */
146     E_(InitLibavcodec)(p_this);
147
148     return VLC_SUCCESS;
149 }
150
151 /*****************************************************************************
152  * OpenFilter: probe the filter and return score
153  *****************************************************************************/
154 int E_(OpenFilter)( vlc_object_t *p_this )
155 {
156     return OpenFilterEx( p_this, VLC_FALSE );
157 }
158
159 /*****************************************************************************
160  * OpenCropPadd: probe the filter and return score
161  *****************************************************************************/
162 int E_(OpenCropPadd)( vlc_object_t *p_this )
163 {
164     return OpenFilterEx( p_this, VLC_TRUE );
165 }
166
167
168 /*****************************************************************************
169  * CloseFilter: clean up the filter
170  *****************************************************************************/
171 void E_(CloseFilter)( vlc_object_t *p_this )
172 {
173     filter_t *p_filter = (filter_t*)p_this;
174     filter_sys_t *p_sys = p_filter->p_sys;
175
176     if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
177     avpicture_free( &p_sys->tmp_pic );
178
179     free( p_sys );
180 }
181
182 /*****************************************************************************
183  * CheckInit: Initialise filter when necessary
184  *****************************************************************************/
185 static int CheckInit( filter_t *p_filter )
186 {
187     filter_sys_t *p_sys = p_filter->p_sys;
188     vlc_bool_t b_change;
189     int i_croptop=0;
190     int i_cropbottom=0;
191     int i_cropleft=0;
192     int i_cropright=0;
193     int i_paddtop=0;
194     int i_paddbottom=0;
195     int i_paddleft=0;
196     int i_paddright=0;
197
198     b_change = ( p_filter->fmt_in.video.i_width != p_sys->fmt_in.video.i_width ) ||
199         ( p_filter->fmt_in.video.i_height != p_sys->fmt_in.video.i_height ) ||
200         ( p_filter->fmt_out.video.i_width != p_sys->fmt_out.video.i_width ) ||
201         ( p_filter->fmt_out.video.i_height != p_sys->fmt_out.video.i_height );
202
203     if ( p_sys->b_enable_croppadd )
204     {
205         b_change = b_change ||
206             ( p_filter->fmt_in.video.i_y_offset != p_sys->fmt_in.video.i_y_offset ) ||
207             ( p_filter->fmt_in.video.i_x_offset != p_sys->fmt_in.video.i_x_offset ) ||
208             ( p_filter->fmt_in.video.i_visible_width != p_sys->fmt_in.video.i_visible_width ) ||
209             ( p_filter->fmt_in.video.i_visible_height != p_sys->fmt_in.video.i_visible_height ) ||
210             ( p_filter->fmt_out.video.i_y_offset != p_sys->fmt_out.video.i_y_offset ) ||
211             ( p_filter->fmt_out.video.i_x_offset != p_sys->fmt_out.video.i_x_offset ) ||
212             ( p_filter->fmt_out.video.i_visible_width != p_sys->fmt_out.video.i_visible_width ) ||
213             ( p_filter->fmt_out.video.i_visible_height != p_sys->fmt_out.video.i_visible_height );
214     }
215
216     if ( b_change )
217     {
218         if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
219
220         p_sys->p_rsc = NULL;
221         p_sys->b_convert =
222           ( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma );
223
224         p_sys->b_resize =
225           ( p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ) ||
226           ( p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height );
227
228         p_sys->b_resize_first =
229           ( p_filter->fmt_in.video.i_width * p_filter->fmt_in.video.i_height ) >
230           ( p_filter->fmt_out.video.i_width * p_filter->fmt_out.video.i_height );
231
232         if( p_sys->b_resize &&
233             ( p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P ) &&
234             ( p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P ) &&
235             ( p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P ) &&
236             ( p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P ) )
237         {
238             msg_Err( p_filter, "img_resample_init only deals with I420" );
239             return VLC_EGENERIC;
240         }
241         else if( ( p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P ) &&
242                  ( p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P ) )
243         {
244             p_sys->b_resize_first = VLC_FALSE;
245         }
246         else if( ( p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P ) &&
247                  ( p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P ) )
248         {
249             p_sys->b_resize_first = VLC_TRUE;
250         }
251
252         if ( p_sys->b_enable_croppadd )
253         {
254             p_sys->b_resize = p_sys->b_resize ||
255                 ( p_filter->fmt_in.video.i_visible_width != p_filter->fmt_in.video.i_width ) ||
256                 ( p_filter->fmt_in.video.i_visible_height != p_filter->fmt_in.video.i_height ) ||
257                 ( p_filter->fmt_in.video.i_x_offset != 0 ) ||
258                 ( p_filter->fmt_in.video.i_y_offset != 0 ) ||
259                 ( p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width ) ||
260                 ( p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height ) ||
261                 ( p_filter->fmt_out.video.i_x_offset != 0 ) ||
262                 ( p_filter->fmt_out.video.i_y_offset != 0 );
263         }
264
265         if( p_sys->b_resize )
266         {
267             if ( p_sys->b_enable_croppadd )
268             {
269                 i_croptop = p_filter->fmt_in.video.i_y_offset;
270                 i_cropbottom = p_filter->fmt_in.video.i_height
271                                        - p_filter->fmt_in.video.i_visible_height
272                                        - p_filter->fmt_in.video.i_y_offset;
273                 i_cropleft = p_filter->fmt_in.video.i_x_offset;
274                 i_cropright = p_filter->fmt_in.video.i_width
275                                       - p_filter->fmt_in.video.i_visible_width
276                                       - p_filter->fmt_in.video.i_x_offset;
277
278
279                 i_paddtop = p_filter->fmt_out.video.i_y_offset;
280                 i_paddbottom = p_filter->fmt_out.video.i_height
281                                        - p_filter->fmt_out.video.i_visible_height
282                                        - p_filter->fmt_out.video.i_y_offset;
283                 i_paddleft = p_filter->fmt_out.video.i_x_offset;
284                 i_paddright = p_filter->fmt_out.video.i_width
285                                       - p_filter->fmt_out.video.i_visible_width
286                                       - p_filter->fmt_out.video.i_x_offset;
287             }
288
289             p_sys->p_rsc = img_resample_full_init(
290                                p_filter->fmt_out.video.i_width,
291                                p_filter->fmt_out.video.i_height,
292                                p_filter->fmt_in.video.i_width,
293                                p_filter->fmt_in.video.i_height,
294                                i_croptop,i_cropbottom,
295                                i_cropleft,i_cropright,
296                                i_paddtop,i_paddbottom,
297                                i_paddleft,i_paddright );
298
299             if( !p_sys->p_rsc )
300             {
301                 msg_Err( p_filter, "img_resample_init failed" );
302                 return VLC_EGENERIC;
303             }
304
305             msg_Dbg( p_filter, "input: %ix%i -> %ix%i",
306                 p_filter->fmt_out.video.i_width,
307                 p_filter->fmt_out.video.i_height,
308                 p_filter->fmt_in.video.i_width,
309                 p_filter->fmt_in.video.i_height);
310
311         }
312
313         avpicture_free( &p_sys->tmp_pic );
314
315         if( p_sys->b_resize_first )
316         {
317             /* Resizing then conversion */
318             avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma,
319                              p_filter->fmt_out.video.i_width,
320                              p_filter->fmt_out.video.i_height );
321         }
322         else
323         {
324             /* Conversion then resizing */
325             avpicture_alloc( &p_sys->tmp_pic, p_sys->i_dst_ffmpeg_chroma,
326                              p_filter->fmt_in.video.i_width,
327                              p_filter->fmt_in.video.i_height );
328         }
329
330         p_sys->fmt_in = p_filter->fmt_in;
331         p_sys->fmt_out = p_filter->fmt_out;
332     }
333
334     return VLC_SUCCESS;
335 }
336
337 /* fill padd code from ffmpeg */
338 static int padcolor[3] = { 16, 128, 128 };
339
340 /* Expects img to be yuv420 */
341 static void fill_pad_region( AVPicture* img, int height, int width,
342         int padtop, int padbottom, int padleft, int padright, int *color )
343 {
344     int i, y, shift;
345     uint8_t *optr;
346
347     for ( i = 0; i < 3; i++ )
348     {
349         shift = ( i == 0 ) ? 0 : 1;
350
351         if ( padtop || padleft )
352         {
353             memset( img->data[i], color[i], ( ( ( img->linesize[i] * padtop ) +
354                             padleft ) >> shift) );
355         }
356
357         if ( padleft || padright )
358         {
359             optr = img->data[i] + ( img->linesize[i] * ( padtop >> shift ) ) +
360                 ( img->linesize[i] - ( padright >> shift ) );
361
362             for ( y = 0; y < ( ( height - ( padtop + padbottom ) ) >> shift ); y++ )
363             {
364                 memset( optr, color[i], ( padleft + padright ) >> shift );
365                 optr += img->linesize[i];
366             }
367         }
368
369         if (padbottom)
370         {
371             optr = img->data[i] + ( img->linesize[i] * ( ( height - padbottom ) >> shift ) );
372             memset( optr, color[i], ( ( img->linesize[i] * padbottom ) >> shift ) );
373         }
374     }
375 }
376
377 /* Workaround, because old libavcodec doesnt know how to padd */
378 static void img_resample_padd( ImgReSampleContext *s, AVPicture *output,
379         const AVPicture *input, int padtop, int padleft )
380 {
381     AVPicture nopadd_pic = *output;
382
383     /* shift out top and left padding for old ffmpeg */
384     nopadd_pic.data[0] += ( nopadd_pic.linesize[0] * padtop + padleft );
385     nopadd_pic.data[1] += ( nopadd_pic.linesize[1] * padtop + padleft ) >> 1;
386     nopadd_pic.data[2] += ( nopadd_pic.linesize[2] * padtop + padleft ) >> 1;
387     img_resample( s, &nopadd_pic, input );
388 }
389
390
391 /*****************************************************************************
392  * Do the processing here
393  *****************************************************************************/
394 static picture_t *Process( filter_t *p_filter, picture_t *p_pic )
395 {
396     filter_sys_t *p_sys = p_filter->p_sys;
397     AVPicture src_pic, dest_pic;
398     AVPicture *p_src, *p_dst;
399     picture_t *p_pic_dst;
400     int i;
401
402     /* Check if format properties changed */
403     if( CheckInit( p_filter ) != VLC_SUCCESS ) return 0;
404
405     /* Request output picture */
406     p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
407     if( !p_pic_dst )
408     {
409         msg_Warn( p_filter, "can't get output picture" );
410         p_pic->pf_release( p_pic );
411         return NULL;
412     }
413
414     /* Prepare the AVPictures for the conversion */
415     for( i = 0; i < p_pic->i_planes; i++ )
416     {
417         src_pic.data[i] = p_pic->p[i].p_pixels;
418         src_pic.linesize[i] = p_pic->p[i].i_pitch;
419     }
420     for( i = 0; i < p_pic_dst->i_planes; i++ )
421     {
422         dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
423         dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
424     }
425
426     /* Special cases */
427     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
428         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','U','9') )
429     {
430         /* Invert U and V */
431         src_pic.data[1] = p_pic->p[2].p_pixels;
432         src_pic.data[2] = p_pic->p[1].p_pixels;
433     }
434     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
435         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','U','9') )
436     {
437         /* Invert U and V */
438         dest_pic.data[1] = p_pic_dst->p[2].p_pixels;
439         dest_pic.data[2] = p_pic_dst->p[1].p_pixels;
440     }
441     if( p_sys->i_src_ffmpeg_chroma == PIX_FMT_RGB24 )
442         if( p_filter->fmt_in.video.i_bmask == 0x00ff0000 )
443             p_sys->i_src_ffmpeg_chroma = PIX_FMT_BGR24;
444
445     p_src = &src_pic;
446
447     if( p_sys->b_resize && p_sys->p_rsc )
448     {
449         p_dst = &dest_pic;
450         if( p_sys->b_resize_first )
451         {
452             if( p_sys->b_convert ) p_dst = &p_sys->tmp_pic;
453
454             img_resample( p_sys->p_rsc, p_dst, p_src );
455
456             if (p_sys->b_enable_croppadd)
457             {
458                 if (p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width ||
459                     p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height ||
460                     p_filter->fmt_out.video.i_x_offset != 0 ||
461                     p_filter->fmt_out.video.i_y_offset != 0)
462                 {
463                     fill_pad_region(p_dst, p_filter->fmt_out.video.i_height,
464                                     p_filter->fmt_out.video.i_width,
465                                     p_filter->fmt_out.video.i_y_offset,
466                                     p_filter->fmt_out.video.i_height
467                                       - p_filter->fmt_out.video.i_visible_height
468                                       - p_filter->fmt_out.video.i_y_offset,
469                                     p_filter->fmt_out.video.i_x_offset,
470                                     p_filter->fmt_out.video.i_width
471                                       - p_filter->fmt_out.video.i_visible_width
472                                       - p_filter->fmt_out.video.i_x_offset,
473                                     padcolor);
474                 }
475             }
476
477             p_src = p_dst;
478         }
479     }
480
481     if( p_sys->b_convert )
482     {
483         video_format_t *p_fmt = &p_filter->fmt_out.video;
484         p_dst = &dest_pic;
485         if( p_sys->b_resize && !p_sys->b_resize_first )
486         {
487             p_dst = &p_sys->tmp_pic;
488             p_fmt = &p_filter->fmt_in.video;
489         }
490
491         img_convert( p_dst, p_sys->i_dst_ffmpeg_chroma,
492                      p_src, p_sys->i_src_ffmpeg_chroma,
493                      p_fmt->i_width, p_fmt->i_height );
494
495         p_src = p_dst;
496     }
497
498     if( p_sys->b_resize && !p_sys->b_resize_first && p_sys->p_rsc )
499     {
500         p_dst = &dest_pic;
501
502         img_resample( p_sys->p_rsc, p_dst, p_src );
503
504         if (p_sys->b_enable_croppadd)
505         {
506             if (p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width ||
507                 p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height ||
508                 p_filter->fmt_out.video.i_x_offset != 0 ||
509                 p_filter->fmt_out.video.i_y_offset != 0)
510             {
511                 fill_pad_region(p_dst, p_filter->fmt_out.video.i_height,
512                                 p_filter->fmt_out.video.i_width,
513                                 p_filter->fmt_out.video.i_y_offset,
514                                 p_filter->fmt_out.video.i_height
515                                   - p_filter->fmt_out.video.i_visible_height
516                                   - p_filter->fmt_out.video.i_y_offset,
517                                 p_filter->fmt_out.video.i_x_offset,
518                                 p_filter->fmt_out.video.i_width
519                                   - p_filter->fmt_out.video.i_visible_width
520                                   - p_filter->fmt_out.video.i_x_offset,
521                                 padcolor);
522             }
523         }
524     }
525
526     /* Special case for RV32 -> YUVA */
527     if( !p_sys->b_resize &&
528         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('R','V','3','2') &&
529         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
530     {
531         uint8_t *p_src = p_pic->p[0].p_pixels;
532         int i_src_pitch = p_pic->p[0].i_pitch;
533         uint8_t *p_dst = p_pic_dst->p[3].p_pixels;
534         int i_dst_pitch = p_pic_dst->p[3].i_pitch;
535         uint32_t l,j;
536
537         for( l = 0; l < p_filter->fmt_out.video.i_height; l++ )
538         {
539             for( j = 0; j < p_filter->fmt_out.video.i_width; j++ )
540             {
541               p_dst[j] = p_src[j*4+3];
542             }
543             p_src += i_src_pitch;
544             p_dst += i_dst_pitch;
545         }
546     }
547     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
548     {
549         /* Special case for YUVA */
550         memset( p_pic_dst->p[3].p_pixels, 0xFF,
551                 p_pic_dst->p[3].i_pitch * p_pic_dst->p[3].i_lines );
552     }
553
554     p_pic_dst->date = p_pic->date;
555     p_pic_dst->b_force = p_pic->b_force;
556     p_pic_dst->i_nb_fields = p_pic->i_nb_fields;
557     p_pic_dst->b_progressive = p_pic->b_progressive;
558     p_pic_dst->b_top_field_first = p_pic->b_top_field_first;
559
560     p_pic->pf_release( p_pic );
561     return p_pic_dst;
562 }
563 #endif /* ( (defined(HAVE_FFMPEG_SWSCALE_H) || defined(HAVE_LIBSWSCALE_TREE)) */