1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
/*****************************************************************************
* fps.c : fps conversion plugin for vlc
*****************************************************************************
* Copyright (C) 2014 VLC authors and VideoLAN
*
* Author: Ilkka Ollakka <ileoo at videolan dot org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_filter.h>
#include <vlc_picture.h>
static int Open( vlc_object_t *p_this);
static void Close( vlc_object_t *p_this);
static picture_t *Filter( filter_t *p_filter, picture_t *p_picture);
#define CFG_PREFIX "fps-"
#define FPS_TEXT N_( "Frame rate" )
vlc_module_begin ()
set_description( N_("FPS conversion video filter") )
set_shortname( N_("FPS Converter" ))
set_capability( "video filter", 0 )
set_category( CAT_VIDEO )
set_subcategory( SUBCAT_VIDEO_VFILTER )
add_shortcut( "fps" )
add_string( CFG_PREFIX "fps", NULL, FPS_TEXT, FPS_TEXT, false )
set_callbacks( Open, Close )
vlc_module_end ()
static const char *const ppsz_filter_options[] = {
"fps",
NULL
};
/* We'll store pointer for previous picture we have received
and copy that if needed on framerate increase (not preferred)*/
struct filter_sys_t
{
date_t next_output_pts; /**< output calculated PTS */
picture_t *p_previous_pic;
int i_output_frame_interval;
};
static picture_t *Filter( filter_t *p_filter, picture_t *p_picture)
{
filter_sys_t *p_sys = p_filter->p_sys;
/* If input picture doesn't have actual valid timestamp,
we don't really have currently a way to know what else
to do with it other than drop it for now*/
if( unlikely( p_picture->date < VLC_TICK_0) )
{
msg_Dbg( p_filter, "skipping non-dated picture");
picture_Release( p_picture );
return NULL;
}
p_picture->format.i_frame_rate = p_filter->fmt_out.video.i_frame_rate;
p_picture->format.i_frame_rate_base = p_filter->fmt_out.video.i_frame_rate_base;
/* First time we get some valid timestamp, we'll take it as base for output
later on we retake new timestamp if it has jumped too much */
if( unlikely( ( date_Get( &p_sys->next_output_pts ) == VLC_TICK_INVALID ) ||
( p_picture->date > ( date_Get( &p_sys->next_output_pts ) + (vlc_tick_t)p_sys->i_output_frame_interval ) )
) )
{
msg_Dbg( p_filter, "Resetting timestamps" );
date_Set( &p_sys->next_output_pts, p_picture->date );
if( p_sys->p_previous_pic )
picture_Release( p_sys->p_previous_pic );
p_sys->p_previous_pic = picture_Hold( p_picture );
date_Increment( &p_sys->next_output_pts, 1 );
return p_picture;
}
/* Check if we can skip input as better should follow */
if( p_picture->date <
( date_Get( &p_sys->next_output_pts ) - (vlc_tick_t)p_sys->i_output_frame_interval ) )
{
if( p_sys->p_previous_pic )
picture_Release( p_sys->p_previous_pic );
p_sys->p_previous_pic = p_picture;
return NULL;
}
p_sys->p_previous_pic->date = date_Get( &p_sys->next_output_pts );
date_Increment( &p_sys->next_output_pts, 1 );
picture_t *last_pic = p_sys->p_previous_pic;
/* Duplicating pictures are not that effective and framerate increase
should be avoided, it's only here as filter should work in that direction too*/
while( unlikely( (date_Get( &p_sys->next_output_pts ) + p_sys->i_output_frame_interval ) < p_picture->date ) )
{
picture_t *p_tmp = NULL;
p_tmp = picture_NewFromFormat( &p_filter->fmt_out.video );
picture_Copy( p_tmp, p_sys->p_previous_pic);
p_tmp->date = date_Get( &p_sys->next_output_pts );
p_tmp->p_next = NULL;
last_pic->p_next = p_tmp;
last_pic = p_tmp;
date_Increment( &p_sys->next_output_pts, 1 );
}
last_pic = p_sys->p_previous_pic;
p_sys->p_previous_pic = p_picture;
return last_pic;
}
static int Open( vlc_object_t *p_this)
{
filter_t *p_filter = (filter_t*)p_this;
filter_sys_t *p_sys;
p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
if( unlikely( !p_sys ) )
return VLC_ENOMEM;
config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
p_filter->p_cfg );
const unsigned int i_out_frame_rate = p_filter->fmt_out.video.i_frame_rate;
const unsigned int i_out_frame_rate_base = p_filter->fmt_out.video.i_frame_rate_base;
video_format_Clean( &p_filter->fmt_out.video );
video_format_Copy( &p_filter->fmt_out.video, &p_filter->fmt_in.video );
/* If we don't have fps option, use filter output values */
if( var_InheritURational( p_filter, &p_filter->fmt_out.video.i_frame_rate,
&p_filter->fmt_out.video.i_frame_rate_base, CFG_PREFIX "fps" ) )
{
p_filter->fmt_out.video.i_frame_rate = i_out_frame_rate;
p_filter->fmt_out.video.i_frame_rate_base = i_out_frame_rate_base;
}
if( p_filter->fmt_out.video.i_frame_rate == 0 ) {
msg_Err( p_filter, "Invalid output frame rate" );
free( p_sys );
return VLC_EGENERIC;
}
msg_Dbg( p_filter, "Converting fps from %d/%d -> %d/%d",
p_filter->fmt_in.video.i_frame_rate, p_filter->fmt_in.video.i_frame_rate_base,
p_filter->fmt_out.video.i_frame_rate, p_filter->fmt_out.video.i_frame_rate_base );
p_sys->i_output_frame_interval = p_filter->fmt_out.video.i_frame_rate_base * CLOCK_FREQ / p_filter->fmt_out.video.i_frame_rate;
date_Init( &p_sys->next_output_pts,
p_filter->fmt_out.video.i_frame_rate, p_filter->fmt_out.video.i_frame_rate_base );
date_Set( &p_sys->next_output_pts, VLC_TICK_INVALID );
p_sys->p_previous_pic = NULL;
p_filter->pf_video_filter = Filter;
return VLC_SUCCESS;
}
static void Close( vlc_object_t *p_this )
{
filter_t *p_filter = (filter_t*)p_this;
if( p_filter->p_sys->p_previous_pic )
picture_Release( p_filter->p_sys->p_previous_pic );
free( p_filter->p_sys );
}
|