1 /*****************************************************************************
2 * select_every.c: select-every video filter
3 *****************************************************************************
4 * Copyright (C) 2010-2015 x264 project
6 * Authors: Steven Walters <kemuri9@gmail.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
22 * This program is also available under a commercial proprietary license.
23 * For more information, contact us at licensing@x264.com.
24 *****************************************************************************/
27 #define NAME "select_every"
28 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, NAME, __VA_ARGS__ )
30 #define MAX_PATTERN_SIZE 100 /* arbitrary */
35 cli_vid_filter_t prev_filter;
44 cli_vid_filter_t select_every_filter;
46 static void help( int longhelp )
48 printf( " "NAME":step,offset1[,...]\n" );
51 printf( " apply a selection pattern to input frames\n"
52 " step: the number of frames in the pattern\n"
53 " offsets: the offset into the step to select a frame\n"
54 " see: http://avisynth.nl/index.php/Select#SelectEvery\n" );
57 static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string )
59 selvry_hnd_t *h = malloc( sizeof(selvry_hnd_t) );
64 int offsets[MAX_PATTERN_SIZE];
65 for( char *tok, *p = opt_string; (tok = strtok( p, "," )); p = NULL )
67 int val = x264_otoi( tok, -1 );
70 FAIL_IF_ERROR( val <= 0, "invalid step `%s'\n", tok )
74 FAIL_IF_ERROR( val < 0 || val >= h->step_size, "invalid offset `%s'\n", tok )
75 FAIL_IF_ERROR( h->pattern_len >= MAX_PATTERN_SIZE, "max pattern size %d reached\n", MAX_PATTERN_SIZE )
76 offsets[h->pattern_len++] = val;
78 FAIL_IF_ERROR( !h->step_size, "no step size provided\n" )
79 FAIL_IF_ERROR( !h->pattern_len, "no offsets supplied\n" )
81 h->pattern = malloc( h->pattern_len * sizeof(int) );
84 memcpy( h->pattern, offsets, h->pattern_len * sizeof(int) );
86 /* determine required cache size to maintain pattern. */
87 intptr_t max_rewind = 0;
88 int min = h->step_size;
89 for( int i = h->pattern_len-1; i >= 0; i-- )
91 min = X264_MIN( min, offsets[i] );
93 max_rewind = X264_MAX( max_rewind, offsets[i-1] - min + 1 );
94 /* reached maximum rewind size */
95 if( max_rewind == h->step_size )
98 if( x264_init_vid_filter( "cache", handle, filter, info, param, (void*)max_rewind ) )
101 /* done initing, overwrite properties */
102 if( h->step_size != h->pattern_len )
104 info->num_frames = (uint64_t)info->num_frames * h->pattern_len / h->step_size;
105 info->fps_den *= h->step_size;
106 info->fps_num *= h->pattern_len;
107 x264_reduce_fraction( &info->fps_num, &info->fps_den );
110 info->timebase_den *= h->pattern_len;
111 info->timebase_num *= h->step_size;
112 x264_reduce_fraction( &info->timebase_num, &info->timebase_den );
118 h->prev_filter = *filter;
119 h->prev_hnd = *handle;
120 *filter = select_every_filter;
126 static int get_frame( hnd_t handle, cli_pic_t *output, int frame )
128 selvry_hnd_t *h = handle;
129 int pat_frame = h->pattern[frame % h->pattern_len] + frame / h->pattern_len * h->step_size;
130 if( h->prev_filter.get_frame( h->prev_hnd, output, pat_frame ) )
134 output->pts = h->pts;
135 h->pts += output->duration;
140 static int release_frame( hnd_t handle, cli_pic_t *pic, int frame )
142 selvry_hnd_t *h = handle;
143 int pat_frame = h->pattern[frame % h->pattern_len] + frame / h->pattern_len * h->step_size;
144 return h->prev_filter.release_frame( h->prev_hnd, pic, pat_frame );
147 static void free_filter( hnd_t handle )
149 selvry_hnd_t *h = handle;
150 h->prev_filter.free( h->prev_hnd );
155 cli_vid_filter_t select_every_filter = { NAME, help, init, get_frame, release_frame, free_filter, NULL };