1 /*****************************************************************************
2 * postproc.c: video postprocessing using libpostproc
3 *****************************************************************************
4 * Copyright (C) 1999-2009 the VideoLAN team
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
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 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 General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_filter.h>
35 #include "filter_picture.h"
37 #ifdef HAVE_POSTPROC_POSTPROCESS_H
38 # include <postproc/postprocess.h>
40 # include <libpostproc/postprocess.h>
43 #ifndef PP_CPU_CAPS_ALTIVEC
44 # define PP_CPU_CAPS_ALTIVEC 0
47 /*****************************************************************************
49 *****************************************************************************/
50 static int OpenPostproc( vlc_object_t
* );
51 static void ClosePostproc( vlc_object_t
* );
53 static picture_t
*PostprocPict( filter_t
*, picture_t
* );
55 static int PPQCallback( vlc_object_t
*, char const *,
56 vlc_value_t
, vlc_value_t
, void * );
57 static int PPNameCallback( vlc_object_t
*, char const *,
58 vlc_value_t
, vlc_value_t
, void * );
60 #define Q_TEXT N_("Post processing quality")
61 #define Q_LONGTEXT N_( \
62 "Quality of post processing. Valid range is 0 to 6\n" \
63 "Higher levels require considerable more CPU power, but produce " \
64 "better looking pictures." )
66 #define NAME_TEXT N_("FFmpeg post processing filter chains")
67 #define NAME_LONGTEXT NAME_TEXT
69 #define FILTER_PREFIX "postproc-"
71 /*****************************************************************************
73 *****************************************************************************/
75 set_description( N_("Video post processing filter") )
76 set_shortname( N_("Postproc" ) )
77 add_shortcut( "postprocess", "pp" ) /* name is "postproc" */
78 set_category( CAT_VIDEO
)
79 set_subcategory( SUBCAT_VIDEO_VFILTER
)
81 set_capability( "video filter2", 0 )
83 set_callbacks( OpenPostproc
, ClosePostproc
)
85 add_integer_with_range( FILTER_PREFIX
"q", PP_QUALITY_MAX
, 0,
86 PP_QUALITY_MAX
, NULL
, Q_TEXT
, Q_LONGTEXT
, false )
87 add_deprecated_alias( "ffmpeg-pp-q" )
89 add_string( FILTER_PREFIX
"name", "default", NULL
, NAME_TEXT
,
91 add_deprecated_alias( "ffmpeg-pp-name" )
94 static const char *const ppsz_filter_options
[] = {
98 /*****************************************************************************
99 * filter_sys_t : libpostproc video postprocessing descriptor
100 *****************************************************************************/
103 /* Never changes after init */
104 pp_context_t
*pp_context
;
106 /* Set to NULL if post processing is disabled */
109 /* Set to true if previous pic had a quant matrix
110 (used to prevent spamming warning messages) */
113 /* Lock when using or changing pp_mode */
118 /*****************************************************************************
119 * OpenPostproc: probe and open the postproc
120 *****************************************************************************/
121 static int OpenPostproc( vlc_object_t
*p_this
)
123 filter_t
*p_filter
= (filter_t
*)p_this
;
125 vlc_value_t val
, val_orig
, text
;
126 unsigned i_cpu
= vlc_CPU();
129 if( p_filter
->fmt_in
.video
.i_chroma
!= p_filter
->fmt_out
.video
.i_chroma
||
130 p_filter
->fmt_in
.video
.i_height
!= p_filter
->fmt_out
.video
.i_height
||
131 p_filter
->fmt_in
.video
.i_width
!= p_filter
->fmt_out
.video
.i_width
)
133 msg_Err( p_filter
, "Filter input and output formats must be identical" );
137 /* Set CPU capabilities */
138 if( i_cpu
& CPU_CAPABILITY_MMX
)
139 i_flags
|= PP_CPU_CAPS_MMX
;
140 if( i_cpu
& CPU_CAPABILITY_MMXEXT
)
141 i_flags
|= PP_CPU_CAPS_MMX2
;
142 if( i_cpu
& CPU_CAPABILITY_3DNOW
)
143 i_flags
|= PP_CPU_CAPS_3DNOW
;
144 if( i_cpu
& CPU_CAPABILITY_ALTIVEC
)
145 i_flags
|= PP_CPU_CAPS_ALTIVEC
;
147 switch( p_filter
->fmt_in
.video
.i_chroma
)
151 /* case VLC_CODEC_YUVA:
152 FIXME: Should work but alpha plane needs to be copied manually and
153 I'm kind of feeling too lazy to write the code to do that ATM
154 (i_pitch vs i_visible_pitch...). */
155 i_flags
|= PP_FORMAT_444
;
159 i_flags
|= PP_FORMAT_422
;
162 i_flags
|= PP_FORMAT_411
;
167 i_flags
|= PP_FORMAT_420
;
170 msg_Err( p_filter
, "Unsupported input chroma (%4.4s)",
171 (char*)&p_filter
->fmt_in
.video
.i_chroma
);
175 p_sys
= malloc( sizeof( filter_sys_t
) );
176 if( !p_sys
) return VLC_ENOMEM
;
177 p_filter
->p_sys
= p_sys
;
179 p_sys
->pp_context
= pp_get_context( p_filter
->fmt_in
.video
.i_width
,
180 p_filter
->fmt_in
.video
.i_height
,
182 if( !p_sys
->pp_context
)
184 msg_Err( p_filter
, "Error while creating post processing context." );
189 config_ChainParse( p_filter
, FILTER_PREFIX
, ppsz_filter_options
,
192 var_Create( p_filter
, FILTER_PREFIX
"q", VLC_VAR_INTEGER
|
193 VLC_VAR_HASCHOICE
| VLC_VAR_DOINHERIT
| VLC_VAR_ISCOMMAND
);
195 text
.psz_string
= _("Post processing");
196 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_SETTEXT
, &text
, NULL
);
198 var_Get( p_filter
, FILTER_PREFIX
"q", &val_orig
);
199 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_DELCHOICE
, &val_orig
, NULL
);
201 val
.psz_string
= var_GetNonEmptyString( p_filter
, FILTER_PREFIX
"name" );
204 p_sys
->pp_mode
= pp_get_mode_by_name_and_quality( val
.psz_string
?
209 if( !p_sys
->pp_mode
)
211 msg_Err( p_filter
, "Error while creating post processing mode." );
212 free( val
.psz_string
);
213 pp_free_context( p_sys
->pp_context
);
220 p_sys
->pp_mode
= NULL
;
222 free( val
.psz_string
);
224 for( val
.i_int
= 0; val
.i_int
<= PP_QUALITY_MAX
; val
.i_int
++ )
229 text
.psz_string
= _("Disable");
232 text
.psz_string
= _("Lowest");
235 text
.psz_string
= _("Highest");
238 text
.psz_string
= NULL
;
241 var_Change( p_filter
, FILTER_PREFIX
"q", VLC_VAR_ADDCHOICE
,
242 &val
, text
.psz_string
?&text
:NULL
);
245 vlc_mutex_init( &p_sys
->lock
);
247 /* Add the callback at the end to prevent crashes */
248 var_AddCallback( p_filter
, FILTER_PREFIX
"q", PPQCallback
, NULL
);
249 var_AddCallback( p_filter
, FILTER_PREFIX
"name", PPNameCallback
, NULL
);
251 p_filter
->pf_video_filter
= PostprocPict
;
252 p_sys
->b_had_matrix
= true;
257 /*****************************************************************************
259 *****************************************************************************/
260 static void ClosePostproc( vlc_object_t
*p_this
)
262 filter_t
*p_filter
= (filter_t
*)p_this
;
263 filter_sys_t
*p_sys
= p_filter
->p_sys
;
265 /* delete the callback before destroying the mutex */
266 var_DelCallback( p_filter
, FILTER_PREFIX
"q", PPQCallback
, NULL
);
267 var_DelCallback( p_filter
, FILTER_PREFIX
"name", PPNameCallback
, NULL
);
269 /* Destroy the resources */
270 vlc_mutex_destroy( &p_sys
->lock
);
271 pp_free_context( p_sys
->pp_context
);
272 if( p_sys
->pp_mode
) pp_free_mode( p_sys
->pp_mode
);
276 /*****************************************************************************
278 *****************************************************************************/
279 static picture_t
*PostprocPict( filter_t
*p_filter
, picture_t
*p_pic
)
281 filter_sys_t
*p_sys
= p_filter
->p_sys
;
283 const uint8_t *src
[3];
286 int i_src_stride
[3], i_dst_stride
[3];
288 picture_t
*p_outpic
= filter_NewPicture( p_filter
);
291 picture_Release( p_pic
);
295 /* Lock to prevent issues if pp_mode is changed */
296 vlc_mutex_lock( &p_sys
->lock
);
297 if( !p_sys
->pp_mode
)
299 vlc_mutex_unlock( &p_sys
->lock
);
300 picture_CopyPixels( p_outpic
, p_pic
);
301 return CopyInfoAndRelease( p_outpic
, p_pic
);
305 for( 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 if( !p_pic
->p_q
&& p_sys
->b_had_matrix
)
318 msg_Warn( p_filter
, "Quantification table was not set by video decoder. Postprocessing won't look good." );
319 p_sys
->b_had_matrix
= false;
321 else if( p_pic
->p_q
)
323 p_sys
->b_had_matrix
= true;
326 pp_postprocess( src
, i_src_stride
, dst
, i_dst_stride
,
327 p_filter
->fmt_in
.video
.i_width
,
328 p_filter
->fmt_in
.video
.i_height
,
329 p_pic
->p_q
, p_pic
->i_qstride
,
330 p_sys
->pp_mode
, p_sys
->pp_context
,
331 p_pic
->i_qtype
== QTYPE_MPEG2
? PP_PICT_TYPE_QP2
: 0 );
332 vlc_mutex_unlock( &p_sys
->lock
);
334 return CopyInfoAndRelease( p_outpic
, p_pic
);
337 /*****************************************************************************
338 * PPChangeMode: change the current mode and quality
339 *****************************************************************************/
340 static void PPChangeMode( filter_t
*p_filter
, const char *psz_name
,
343 filter_sys_t
*p_sys
= p_filter
->p_sys
;
344 vlc_mutex_lock( &p_sys
->lock
);
347 pp_mode_t
*pp_mode
= pp_get_mode_by_name_and_quality( psz_name
?
353 pp_free_mode( p_sys
->pp_mode
);
354 p_sys
->pp_mode
= pp_mode
;
357 msg_Warn( p_filter
, "Error while changing post processing mode. "
358 "Keeping previous mode." );
362 pp_free_mode( p_sys
->pp_mode
);
363 p_sys
->pp_mode
= NULL
;
365 vlc_mutex_unlock( &p_sys
->lock
);
368 static int PPQCallback( 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 char *psz_name
= var_GetNonEmptyString( p_filter
, FILTER_PREFIX
"name" );
375 PPChangeMode( p_filter
, psz_name
, newval
.i_int
);
380 static int PPNameCallback( vlc_object_t
*p_this
, const char *psz_var
,
381 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
383 VLC_UNUSED(psz_var
); VLC_UNUSED(oldval
); VLC_UNUSED(p_data
);
384 filter_t
*p_filter
= (filter_t
*)p_this
;
386 int i_quality
= var_GetInteger( p_filter
, FILTER_PREFIX
"q" );
387 PPChangeMode( p_filter
, *newval
.psz_string
? newval
.psz_string
: NULL
,