1 /*****************************************************************************
2 * postproc.c: video postprocessing using libpostproc
3 *****************************************************************************
4 * Copyright (C) 1999-2009 VLC authors and VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Gildas Bazin <gbazin@netcourrier.com>
9 * Antoine Cellerier <dionoea at videolan dot org>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
27 * NOTA BENE: this module requires the linking against a library which is
28 * known to require licensing under the GNU General Public License version 2
29 * (or later). Therefore, the result of compiling this module will normally
30 * be subject to the terms of that later license.
31 *****************************************************************************/
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40 #include <vlc_filter.h>
41 #include <vlc_picture.h>
44 #include "filter_picture.h"
46 #ifdef HAVE_POSTPROC_POSTPROCESS_H
47 # include <postproc/postprocess.h>
49 # include <libpostproc/postprocess.h>
52 #ifndef PP_CPU_CAPS_ALTIVEC
53 # define PP_CPU_CAPS_ALTIVEC 0
56 /*****************************************************************************
58 *****************************************************************************/
59 static int OpenPostproc( vlc_object_t
* );
60 static void ClosePostproc( vlc_object_t
* );
62 static picture_t
*PostprocPict( filter_t
*, picture_t
* );
64 static int PPQCallback( vlc_object_t
*, char const *,
65 vlc_value_t
, vlc_value_t
, void * );
66 static int PPNameCallback( vlc_object_t
*, char const *,
67 vlc_value_t
, vlc_value_t
, void * );
69 #define Q_TEXT N_("Post processing quality")
70 #define Q_LONGTEXT N_( \
71 "Quality of post processing. Valid range is 0 (disabled) to 6 (highest)\n" \
72 "Higher levels require more CPU power, but produce higher quality pictures.\n" \
73 "With default filter chain, the values map to the following filters:\n" \
74 "1: hb, 2-4: hb+vb, 5-6: hb+vb+dr" )
76 #define NAME_TEXT N_("FFmpeg post processing filter chains")
77 #define NAME_LONGTEXT NAME_TEXT
79 #define FILTER_PREFIX "postproc-"
81 /*****************************************************************************
83 *****************************************************************************/
85 set_description( N_("Video post processing filter") )
86 set_shortname( N_("Postproc" ) )
87 add_shortcut( "postprocess", "pp" ) /* name is "postproc" */
88 set_category( CAT_VIDEO
)
89 set_subcategory( SUBCAT_VIDEO_VFILTER
)
91 set_capability( "video filter", 0 )
93 set_callbacks( OpenPostproc
, ClosePostproc
)
95 add_integer_with_range( FILTER_PREFIX
"q", PP_QUALITY_MAX
, 0,
96 PP_QUALITY_MAX
, Q_TEXT
, Q_LONGTEXT
, false )
98 add_string( FILTER_PREFIX
"name", "default", NAME_TEXT
,
102 static const char *const ppsz_filter_options
[] = {
106 /*****************************************************************************
107 * filter_sys_t : libpostproc video postprocessing descriptor
108 *****************************************************************************/
111 /* Never changes after init */
112 pp_context
*pp_context
;
114 /* Set to NULL if post processing is disabled */
117 /* Lock when using or changing pp_mode */
122 /*****************************************************************************
123 * OpenPostproc: probe and open the postproc
124 *****************************************************************************/
125 static int OpenPostproc( vlc_object_t
*p_this
)
127 filter_t
*p_filter
= (filter_t
*)p_this
;
129 vlc_value_t val
, val_orig
, text
;
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
);
201 text
.psz_string
= _("Post processing");
202 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_SETTEXT
, &text
, NULL
);
204 var_Get( p_filter
, FILTER_PREFIX
"q", &val_orig
);
205 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_DELCHOICE
, &val_orig
, NULL
);
207 val
.psz_string
= var_GetNonEmptyString( p_filter
, FILTER_PREFIX
"name" );
210 p_sys
->pp_mode
= pp_get_mode_by_name_and_quality( val
.psz_string
?
215 if( !p_sys
->pp_mode
)
217 msg_Err( p_filter
, "Error while creating post processing mode." );
218 free( val
.psz_string
);
219 pp_free_context( p_sys
->pp_context
);
226 p_sys
->pp_mode
= NULL
;
228 free( val
.psz_string
);
230 for( val
.i_int
= 0; val
.i_int
<= PP_QUALITY_MAX
; val
.i_int
++ )
235 text
.psz_string
= _("Disable");
238 text
.psz_string
= _("Lowest");
241 text
.psz_string
= _("Highest");
244 text
.psz_string
= NULL
;
247 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_ADDCHOICE
,
248 &val
, text
.psz_string
?&text
:NULL
);
251 vlc_mutex_init( &p_sys
->lock
);
253 /* Add the callback at the end to prevent crashes */
254 var_AddCallback( p_filter
, FILTER_PREFIX
"q", PPQCallback
, NULL
);
255 var_AddCallback( p_filter
, FILTER_PREFIX
"name", PPNameCallback
, NULL
);
257 p_filter
->pf_video_filter
= PostprocPict
;
259 msg_Warn( p_filter
, "Quantification table was not set by video decoder. "
260 "Postprocessing won't look good." );
264 /*****************************************************************************
266 *****************************************************************************/
267 static void ClosePostproc( vlc_object_t
*p_this
)
269 filter_t
*p_filter
= (filter_t
*)p_this
;
270 filter_sys_t
*p_sys
= p_filter
->p_sys
;
272 /* delete the callback before destroying the mutex */
273 var_DelCallback( p_filter
, FILTER_PREFIX
"q", PPQCallback
, NULL
);
274 var_DelCallback( p_filter
, FILTER_PREFIX
"name", PPNameCallback
, NULL
);
276 /* Destroy the resources */
277 vlc_mutex_destroy( &p_sys
->lock
);
278 pp_free_context( p_sys
->pp_context
);
279 pp_free_mode( p_sys
->pp_mode
);
283 /*****************************************************************************
285 *****************************************************************************/
286 static picture_t
*PostprocPict( filter_t
*p_filter
, picture_t
*p_pic
)
288 filter_sys_t
*p_sys
= p_filter
->p_sys
;
290 picture_t
*p_outpic
= filter_NewPicture( p_filter
);
293 picture_Release( p_pic
);
297 /* Lock to prevent issues if pp_mode is changed */
298 vlc_mutex_lock( &p_sys
->lock
);
299 if( p_sys
->pp_mode
!= NULL
)
301 const uint8_t *src
[3];
303 int i_src_stride
[3], i_dst_stride
[3];
305 for( int i_plane
= 0; i_plane
< p_pic
->i_planes
; i_plane
++ )
307 src
[i_plane
] = p_pic
->p
[i_plane
].p_pixels
;
308 dst
[i_plane
] = p_outpic
->p
[i_plane
].p_pixels
;
310 /* I'm not sure what happens if i_pitch != i_visible_pitch ...
311 * at least it shouldn't crash. */
312 i_src_stride
[i_plane
] = p_pic
->p
[i_plane
].i_pitch
;
313 i_dst_stride
[i_plane
] = p_outpic
->p
[i_plane
].i_pitch
;
316 pp_postprocess( src
, i_src_stride
, dst
, i_dst_stride
,
317 p_filter
->fmt_in
.video
.i_width
,
318 p_filter
->fmt_in
.video
.i_height
, NULL
, 0,
319 p_sys
->pp_mode
, p_sys
->pp_context
, 0 );
322 picture_CopyPixels( p_outpic
, p_pic
);
323 vlc_mutex_unlock( &p_sys
->lock
);
325 return CopyInfoAndRelease( p_outpic
, p_pic
);
328 /*****************************************************************************
329 * PPChangeMode: change the current mode and quality
330 *****************************************************************************/
331 static void PPChangeMode( filter_t
*p_filter
, const char *psz_name
,
334 filter_sys_t
*p_sys
= p_filter
->p_sys
;
335 pp_mode
*newmode
= NULL
, *oldmode
;
339 newmode
= pp_get_mode_by_name_and_quality( psz_name
? psz_name
:
340 "default", i_quality
);
341 if( newmode
== NULL
)
343 msg_Warn( p_filter
, "Error while changing post processing mode. "
344 "Keeping previous mode." );
349 vlc_mutex_lock( &p_sys
->lock
);
350 oldmode
= p_sys
->pp_mode
;
351 p_sys
->pp_mode
= newmode
;
352 vlc_mutex_unlock( &p_sys
->lock
);
354 pp_free_mode( oldmode
);
357 static int PPQCallback( vlc_object_t
*p_this
, const char *psz_var
,
358 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
360 VLC_UNUSED(psz_var
); VLC_UNUSED(oldval
); VLC_UNUSED(p_data
);
361 filter_t
*p_filter
= (filter_t
*)p_this
;
363 char *psz_name
= var_GetNonEmptyString( p_filter
, FILTER_PREFIX
"name" );
364 PPChangeMode( p_filter
, psz_name
, newval
.i_int
);
369 static int PPNameCallback( vlc_object_t
*p_this
, const char *psz_var
,
370 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
372 VLC_UNUSED(psz_var
); VLC_UNUSED(oldval
); VLC_UNUSED(p_data
);
373 filter_t
*p_filter
= (filter_t
*)p_this
;
375 int i_quality
= var_GetInteger( p_filter
, FILTER_PREFIX
"q" );
376 PPChangeMode( p_filter
, *newval
.psz_string
? newval
.psz_string
: NULL
,