1 /*****************************************************************************
2 * postproc.c: video postprocessing using libpostproc
3 *****************************************************************************
4 * Copyright (C) 1999-2009 VLC authors and VideoLAN
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7 * Gildas Bazin <gbazin@netcourrier.com>
8 * Antoine Cellerier <dionoea at videolan dot org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
26 * NOTA BENE: this module requires the linking against a library which is
27 * known to require licensing under the GNU General Public License version 2
28 * (or later). Therefore, the result of compiling this module will normally
29 * be subject to the terms of that later license.
30 *****************************************************************************/
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
39 #include <vlc_filter.h>
40 #include <vlc_picture.h>
43 #include "filter_picture.h"
45 #ifdef HAVE_POSTPROC_POSTPROCESS_H
46 # include <postproc/postprocess.h>
48 # include <libpostproc/postprocess.h>
51 #ifndef PP_CPU_CAPS_ALTIVEC
52 # define PP_CPU_CAPS_ALTIVEC 0
55 /*****************************************************************************
57 *****************************************************************************/
58 static int OpenPostproc( vlc_object_t
* );
59 static void ClosePostproc( vlc_object_t
* );
61 static picture_t
*PostprocPict( filter_t
*, picture_t
* );
63 static int PPQCallback( vlc_object_t
*, char const *,
64 vlc_value_t
, vlc_value_t
, void * );
65 static int PPNameCallback( vlc_object_t
*, char const *,
66 vlc_value_t
, vlc_value_t
, void * );
68 #define Q_TEXT N_("Post processing quality")
69 #define Q_LONGTEXT N_( \
70 "Quality of post processing. Valid range is 0 (disabled) to 6 (highest)\n" \
71 "Higher levels require more CPU power, but produce higher quality pictures.\n" \
72 "With default filter chain, the values map to the following filters:\n" \
73 "1: hb, 2-4: hb+vb, 5-6: hb+vb+dr" )
75 #define NAME_TEXT N_("FFmpeg post processing filter chains")
76 #define NAME_LONGTEXT NAME_TEXT
78 #define FILTER_PREFIX "postproc-"
80 /*****************************************************************************
82 *****************************************************************************/
84 set_description( N_("Video post processing filter") )
85 set_shortname( N_("Postproc" ) )
86 add_shortcut( "postprocess", "pp" ) /* name is "postproc" */
87 set_category( CAT_VIDEO
)
88 set_subcategory( SUBCAT_VIDEO_VFILTER
)
90 set_capability( "video filter", 0 )
92 set_callbacks( OpenPostproc
, ClosePostproc
)
94 add_integer_with_range( FILTER_PREFIX
"q", PP_QUALITY_MAX
, 0,
95 PP_QUALITY_MAX
, Q_TEXT
, Q_LONGTEXT
, false )
97 add_string( FILTER_PREFIX
"name", "default", NAME_TEXT
,
101 static const char *const ppsz_filter_options
[] = {
105 /*****************************************************************************
106 * filter_sys_t : libpostproc video postprocessing descriptor
107 *****************************************************************************/
110 /* Never changes after init */
111 pp_context
*pp_context
;
113 /* Set to NULL if post processing is disabled */
116 /* Lock when using or changing pp_mode */
121 /*****************************************************************************
122 * OpenPostproc: probe and open the postproc
123 *****************************************************************************/
124 static int OpenPostproc( vlc_object_t
*p_this
)
126 filter_t
*p_filter
= (filter_t
*)p_this
;
128 vlc_value_t val
, val_orig
;
132 if( p_filter
->fmt_in
.video
.i_chroma
!= p_filter
->fmt_out
.video
.i_chroma
||
133 p_filter
->fmt_in
.video
.i_height
!= p_filter
->fmt_out
.video
.i_height
||
134 p_filter
->fmt_in
.video
.i_width
!= p_filter
->fmt_out
.video
.i_width
)
136 msg_Err( p_filter
, "Filter input and output formats must be identical" );
140 /* Set CPU capabilities */
141 #if defined(__i386__) || defined(__x86_64__)
143 i_flags
|= PP_CPU_CAPS_MMX
;
144 if( vlc_CPU_MMXEXT() )
145 i_flags
|= PP_CPU_CAPS_MMX2
;
146 if( vlc_CPU_3dNOW() )
147 i_flags
|= PP_CPU_CAPS_3DNOW
;
148 #elif defined(__ppc__) || defined(__ppc64__) || defined(__powerpc__)
149 if( vlc_CPU_ALTIVEC() )
150 i_flags
|= PP_CPU_CAPS_ALTIVEC
;
153 switch( p_filter
->fmt_in
.video
.i_chroma
)
157 /* case VLC_CODEC_YUVA:
158 FIXME: Should work but alpha plane needs to be copied manually and
159 I'm kind of feeling too lazy to write the code to do that ATM
160 (i_pitch vs i_visible_pitch...). */
161 i_flags
|= PP_FORMAT_444
;
165 i_flags
|= PP_FORMAT_422
;
168 i_flags
|= PP_FORMAT_411
;
173 i_flags
|= PP_FORMAT_420
;
176 msg_Err( p_filter
, "Unsupported input chroma (%4.4s)",
177 (char*)&p_filter
->fmt_in
.video
.i_chroma
);
181 p_sys
= malloc( sizeof( filter_sys_t
) );
182 if( !p_sys
) return VLC_ENOMEM
;
183 p_filter
->p_sys
= p_sys
;
185 p_sys
->pp_context
= pp_get_context( p_filter
->fmt_in
.video
.i_width
,
186 p_filter
->fmt_in
.video
.i_height
,
188 if( !p_sys
->pp_context
)
190 msg_Err( p_filter
, "Error while creating post processing context." );
195 config_ChainParse( p_filter
, FILTER_PREFIX
, ppsz_filter_options
,
198 var_Create( p_filter
, FILTER_PREFIX
"q", VLC_VAR_INTEGER
|
199 VLC_VAR_DOINHERIT
| VLC_VAR_ISCOMMAND
);
200 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_SETTEXT
,
201 _("Post processing") );
203 var_Get( p_filter
, FILTER_PREFIX
"q", &val_orig
);
204 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_DELCHOICE
, val_orig
);
206 val
.psz_string
= var_GetNonEmptyString( p_filter
, FILTER_PREFIX
"name" );
209 p_sys
->pp_mode
= pp_get_mode_by_name_and_quality( val
.psz_string
?
214 if( !p_sys
->pp_mode
)
216 msg_Err( p_filter
, "Error while creating post processing mode." );
217 free( val
.psz_string
);
218 pp_free_context( p_sys
->pp_context
);
225 p_sys
->pp_mode
= NULL
;
227 free( val
.psz_string
);
229 for( val
.i_int
= 0; val
.i_int
<= PP_QUALITY_MAX
; val
.i_int
++ )
246 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_ADDCHOICE
, val
, desc
);
249 vlc_mutex_init( &p_sys
->lock
);
251 /* Add the callback at the end to prevent crashes */
252 var_AddCallback( p_filter
, FILTER_PREFIX
"q", PPQCallback
, NULL
);
253 var_AddCallback( p_filter
, FILTER_PREFIX
"name", PPNameCallback
, NULL
);
255 p_filter
->pf_video_filter
= PostprocPict
;
257 msg_Warn( p_filter
, "Quantification table was not set by video decoder. "
258 "Postprocessing won't look good." );
262 /*****************************************************************************
264 *****************************************************************************/
265 static void ClosePostproc( vlc_object_t
*p_this
)
267 filter_t
*p_filter
= (filter_t
*)p_this
;
268 filter_sys_t
*p_sys
= p_filter
->p_sys
;
270 /* delete the callback before destroying the mutex */
271 var_DelCallback( p_filter
, FILTER_PREFIX
"q", PPQCallback
, NULL
);
272 var_DelCallback( p_filter
, FILTER_PREFIX
"name", PPNameCallback
, NULL
);
274 /* Destroy the resources */
275 pp_free_context( p_sys
->pp_context
);
276 pp_free_mode( p_sys
->pp_mode
);
280 /*****************************************************************************
282 *****************************************************************************/
283 static picture_t
*PostprocPict( filter_t
*p_filter
, picture_t
*p_pic
)
285 filter_sys_t
*p_sys
= p_filter
->p_sys
;
287 picture_t
*p_outpic
= filter_NewPicture( p_filter
);
290 picture_Release( p_pic
);
294 /* Lock to prevent issues if pp_mode is changed */
295 vlc_mutex_lock( &p_sys
->lock
);
296 if( p_sys
->pp_mode
!= NULL
)
298 const uint8_t *src
[3];
300 int i_src_stride
[3], i_dst_stride
[3];
302 for( int i_plane
= 0; i_plane
< p_pic
->i_planes
; i_plane
++ )
304 src
[i_plane
] = p_pic
->p
[i_plane
].p_pixels
;
305 dst
[i_plane
] = p_outpic
->p
[i_plane
].p_pixels
;
307 /* I'm not sure what happens if i_pitch != i_visible_pitch ...
308 * at least it shouldn't crash. */
309 i_src_stride
[i_plane
] = p_pic
->p
[i_plane
].i_pitch
;
310 i_dst_stride
[i_plane
] = p_outpic
->p
[i_plane
].i_pitch
;
313 pp_postprocess( src
, i_src_stride
, dst
, i_dst_stride
,
314 p_filter
->fmt_in
.video
.i_width
,
315 p_filter
->fmt_in
.video
.i_height
, NULL
, 0,
316 p_sys
->pp_mode
, p_sys
->pp_context
, 0 );
319 picture_CopyPixels( p_outpic
, p_pic
);
320 vlc_mutex_unlock( &p_sys
->lock
);
322 return CopyInfoAndRelease( p_outpic
, p_pic
);
325 /*****************************************************************************
326 * PPChangeMode: change the current mode and quality
327 *****************************************************************************/
328 static void PPChangeMode( filter_t
*p_filter
, const char *psz_name
,
331 filter_sys_t
*p_sys
= p_filter
->p_sys
;
332 pp_mode
*newmode
= NULL
, *oldmode
;
336 newmode
= pp_get_mode_by_name_and_quality( psz_name
? psz_name
:
337 "default", i_quality
);
338 if( newmode
== NULL
)
340 msg_Warn( p_filter
, "Error while changing post processing mode. "
341 "Keeping previous mode." );
346 vlc_mutex_lock( &p_sys
->lock
);
347 oldmode
= p_sys
->pp_mode
;
348 p_sys
->pp_mode
= newmode
;
349 vlc_mutex_unlock( &p_sys
->lock
);
351 pp_free_mode( oldmode
);
354 static int PPQCallback( vlc_object_t
*p_this
, const char *psz_var
,
355 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
357 VLC_UNUSED(psz_var
); VLC_UNUSED(oldval
); VLC_UNUSED(p_data
);
358 filter_t
*p_filter
= (filter_t
*)p_this
;
360 char *psz_name
= var_GetNonEmptyString( p_filter
, FILTER_PREFIX
"name" );
361 PPChangeMode( p_filter
, psz_name
, newval
.i_int
);
366 static int PPNameCallback( vlc_object_t
*p_this
, const char *psz_var
,
367 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
369 VLC_UNUSED(psz_var
); VLC_UNUSED(oldval
); VLC_UNUSED(p_data
);
370 filter_t
*p_filter
= (filter_t
*)p_this
;
372 int i_quality
= var_GetInteger( p_filter
, FILTER_PREFIX
"q" );
373 PPChangeMode( p_filter
, *newval
.psz_string
? newval
.psz_string
: NULL
,