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>
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 filter2", 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
, text
;
131 if( p_filter
->fmt_in
.video
.i_chroma
!= p_filter
->fmt_out
.video
.i_chroma
||
132 p_filter
->fmt_in
.video
.i_height
!= p_filter
->fmt_out
.video
.i_height
||
133 p_filter
->fmt_in
.video
.i_width
!= p_filter
->fmt_out
.video
.i_width
)
135 msg_Err( p_filter
, "Filter input and output formats must be identical" );
139 /* Set CPU capabilities */
140 #if defined(__i386__) || defined(__x86_64__)
142 i_flags
|= PP_CPU_CAPS_MMX
;
143 if( vlc_CPU_MMXEXT() )
144 i_flags
|= PP_CPU_CAPS_MMX2
;
145 if( vlc_CPU_3dNOW() )
146 i_flags
|= PP_CPU_CAPS_3DNOW
;
147 #elif defined(__ppc__) || defined(__ppc64__) || defined(__powerpc__)
148 if( vlc_CPU_ALTIVEC() )
149 i_flags
|= PP_CPU_CAPS_ALTIVEC
;
152 switch( p_filter
->fmt_in
.video
.i_chroma
)
156 /* case VLC_CODEC_YUVA:
157 FIXME: Should work but alpha plane needs to be copied manually and
158 I'm kind of feeling too lazy to write the code to do that ATM
159 (i_pitch vs i_visible_pitch...). */
160 i_flags
|= PP_FORMAT_444
;
164 i_flags
|= PP_FORMAT_422
;
167 i_flags
|= PP_FORMAT_411
;
172 i_flags
|= PP_FORMAT_420
;
175 msg_Err( p_filter
, "Unsupported input chroma (%4.4s)",
176 (char*)&p_filter
->fmt_in
.video
.i_chroma
);
180 p_sys
= malloc( sizeof( filter_sys_t
) );
181 if( !p_sys
) return VLC_ENOMEM
;
182 p_filter
->p_sys
= p_sys
;
184 p_sys
->pp_context
= pp_get_context( p_filter
->fmt_in
.video
.i_width
,
185 p_filter
->fmt_in
.video
.i_height
,
187 if( !p_sys
->pp_context
)
189 msg_Err( p_filter
, "Error while creating post processing context." );
194 config_ChainParse( p_filter
, FILTER_PREFIX
, ppsz_filter_options
,
197 var_Create( p_filter
, FILTER_PREFIX
"q", VLC_VAR_INTEGER
|
198 VLC_VAR_HASCHOICE
| VLC_VAR_DOINHERIT
| VLC_VAR_ISCOMMAND
);
200 text
.psz_string
= _("Post processing");
201 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_SETTEXT
, &text
, NULL
);
203 var_Get( p_filter
, FILTER_PREFIX
"q", &val_orig
);
204 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_DELCHOICE
, &val_orig
, NULL
);
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
++ )
234 text
.psz_string
= _("Disable");
237 text
.psz_string
= _("Lowest");
240 text
.psz_string
= _("Highest");
243 text
.psz_string
= NULL
;
246 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_ADDCHOICE
,
247 &val
, text
.psz_string
?&text
:NULL
);
250 vlc_mutex_init( &p_sys
->lock
);
252 /* Add the callback at the end to prevent crashes */
253 var_AddCallback( p_filter
, FILTER_PREFIX
"q", PPQCallback
, NULL
);
254 var_AddCallback( p_filter
, FILTER_PREFIX
"name", PPNameCallback
, NULL
);
256 p_filter
->pf_video_filter
= PostprocPict
;
258 msg_Warn( p_filter
, "Quantification table was not set by video decoder. "
259 "Postprocessing won't look good." );
263 /*****************************************************************************
265 *****************************************************************************/
266 static void ClosePostproc( vlc_object_t
*p_this
)
268 filter_t
*p_filter
= (filter_t
*)p_this
;
269 filter_sys_t
*p_sys
= p_filter
->p_sys
;
271 /* delete the callback before destroying the mutex */
272 var_DelCallback( p_filter
, FILTER_PREFIX
"q", PPQCallback
, NULL
);
273 var_DelCallback( p_filter
, FILTER_PREFIX
"name", PPNameCallback
, NULL
);
275 /* Destroy the resources */
276 vlc_mutex_destroy( &p_sys
->lock
);
277 pp_free_context( p_sys
->pp_context
);
278 pp_free_mode( p_sys
->pp_mode
);
282 /*****************************************************************************
284 *****************************************************************************/
285 static picture_t
*PostprocPict( filter_t
*p_filter
, picture_t
*p_pic
)
287 filter_sys_t
*p_sys
= p_filter
->p_sys
;
289 picture_t
*p_outpic
= filter_NewPicture( p_filter
);
292 picture_Release( p_pic
);
296 /* Lock to prevent issues if pp_mode is changed */
297 vlc_mutex_lock( &p_sys
->lock
);
298 if( p_sys
->pp_mode
!= NULL
)
300 const uint8_t *src
[3];
302 int i_src_stride
[3], i_dst_stride
[3];
304 for( int i_plane
= 0; i_plane
< p_pic
->i_planes
; i_plane
++ )
306 src
[i_plane
] = p_pic
->p
[i_plane
].p_pixels
;
307 dst
[i_plane
] = p_outpic
->p
[i_plane
].p_pixels
;
309 /* I'm not sure what happens if i_pitch != i_visible_pitch ...
310 * at least it shouldn't crash. */
311 i_src_stride
[i_plane
] = p_pic
->p
[i_plane
].i_pitch
;
312 i_dst_stride
[i_plane
] = p_outpic
->p
[i_plane
].i_pitch
;
315 pp_postprocess( src
, i_src_stride
, dst
, i_dst_stride
,
316 p_filter
->fmt_in
.video
.i_width
,
317 p_filter
->fmt_in
.video
.i_height
, NULL
, 0,
318 p_sys
->pp_mode
, p_sys
->pp_context
, 0 );
321 picture_CopyPixels( p_outpic
, p_pic
);
322 vlc_mutex_unlock( &p_sys
->lock
);
324 return CopyInfoAndRelease( p_outpic
, p_pic
);
327 /*****************************************************************************
328 * PPChangeMode: change the current mode and quality
329 *****************************************************************************/
330 static void PPChangeMode( filter_t
*p_filter
, const char *psz_name
,
333 filter_sys_t
*p_sys
= p_filter
->p_sys
;
334 pp_mode
*newmode
= NULL
, *oldmode
;
338 newmode
= pp_get_mode_by_name_and_quality( psz_name
? psz_name
:
339 "default", i_quality
);
340 if( newmode
== NULL
)
342 msg_Warn( p_filter
, "Error while changing post processing mode. "
343 "Keeping previous mode." );
348 vlc_mutex_lock( &p_sys
->lock
);
349 oldmode
= p_sys
->pp_mode
;
350 p_sys
->pp_mode
= newmode
;
351 vlc_mutex_unlock( &p_sys
->lock
);
353 pp_free_mode( oldmode
);
356 static int PPQCallback( vlc_object_t
*p_this
, const char *psz_var
,
357 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
359 VLC_UNUSED(psz_var
); VLC_UNUSED(oldval
); VLC_UNUSED(p_data
);
360 filter_t
*p_filter
= (filter_t
*)p_this
;
362 char *psz_name
= var_GetNonEmptyString( p_filter
, FILTER_PREFIX
"name" );
363 PPChangeMode( p_filter
, psz_name
, newval
.i_int
);
368 static int PPNameCallback( vlc_object_t
*p_this
, const char *psz_var
,
369 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
371 VLC_UNUSED(psz_var
); VLC_UNUSED(oldval
); VLC_UNUSED(p_data
);
372 filter_t
*p_filter
= (filter_t
*)p_this
;
374 int i_quality
= var_GetInteger( p_filter
, FILTER_PREFIX
"q" );
375 PPChangeMode( p_filter
, *newval
.psz_string
? newval
.psz_string
: NULL
,