]> git.sesse.net Git - x264/blob - filters/video/select_every.c
a4b0cb890e86d76cbbf699dbe390947d1558a90b
[x264] / filters / video / select_every.c
1 /*****************************************************************************
2  * select_every.c: select-every video filter
3  *****************************************************************************
4  * Copyright (C) 2010-2015 x264 project
5  *
6  * Authors: Steven Walters <kemuri9@gmail.com>
7  *
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.
12  *
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.
17  *
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.
21  *
22  * This program is also available under a commercial proprietary license.
23  * For more information, contact us at licensing@x264.com.
24  *****************************************************************************/
25
26 #include "video.h"
27 #define NAME "select_every"
28 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, NAME, __VA_ARGS__ )
29
30 #define MAX_PATTERN_SIZE 100 /* arbitrary */
31
32 typedef struct
33 {
34     hnd_t prev_hnd;
35     cli_vid_filter_t prev_filter;
36
37     int *pattern;
38     int pattern_len;
39     int step_size;
40     int vfr;
41     int64_t pts;
42 } selvry_hnd_t;
43
44 cli_vid_filter_t select_every_filter;
45
46 static void help( int longhelp )
47 {
48     printf( "      "NAME":step,offset1[,...]\n" );
49     if( !longhelp )
50         return;
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" );
55 }
56
57 static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string )
58 {
59     selvry_hnd_t *h = malloc( sizeof(selvry_hnd_t) );
60     if( !h )
61         return -1;
62     h->pattern_len = 0;
63     h->step_size = 0;
64     int offsets[MAX_PATTERN_SIZE];
65     for( char *tok, *p = opt_string; (tok = strtok( p, "," )); p = NULL )
66     {
67         int val = x264_otoi( tok, -1 );
68         if( p )
69         {
70             FAIL_IF_ERROR( val <= 0, "invalid step `%s'\n", tok )
71             h->step_size = val;
72             continue;
73         }
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;
77     }
78     FAIL_IF_ERROR( !h->step_size, "no step size provided\n" )
79     FAIL_IF_ERROR( !h->pattern_len, "no offsets supplied\n" )
80
81     h->pattern = malloc( h->pattern_len * sizeof(int) );
82     if( !h->pattern )
83         return -1;
84     memcpy( h->pattern, offsets, h->pattern_len * sizeof(int) );
85
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-- )
90     {
91          min = X264_MIN( min, offsets[i] );
92          if( 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 )
96              break;
97     }
98     if( x264_init_vid_filter( "cache", handle, filter, info, param, (void*)max_rewind ) )
99         return -1;
100
101     /* done initing, overwrite properties */
102     if( h->step_size != h->pattern_len )
103     {
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 );
108         if( info->vfr )
109         {
110             info->timebase_den *= h->pattern_len;
111             info->timebase_num *= h->step_size;
112             x264_reduce_fraction( &info->timebase_num, &info->timebase_den );
113         }
114     }
115
116     h->pts = 0;
117     h->vfr = info->vfr;
118     h->prev_filter = *filter;
119     h->prev_hnd = *handle;
120     *filter = select_every_filter;
121     *handle = h;
122
123     return 0;
124 }
125
126 static int get_frame( hnd_t handle, cli_pic_t *output, int frame )
127 {
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 ) )
131         return -1;
132     if( h->vfr )
133     {
134         output->pts = h->pts;
135         h->pts += output->duration;
136     }
137     return 0;
138 }
139
140 static int release_frame( hnd_t handle, cli_pic_t *pic, int frame )
141 {
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 );
145 }
146
147 static void free_filter( hnd_t handle )
148 {
149     selvry_hnd_t *h = handle;
150     h->prev_filter.free( h->prev_hnd );
151     free( h->pattern );
152     free( h );
153 }
154
155 cli_vid_filter_t select_every_filter = { NAME, help, init, get_frame, release_frame, free_filter, NULL };