Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
52867 views
1
/*****************************************************************************
2
* select_every.c: select-every video filter
3
*****************************************************************************
4
* Copyright (C) 2010-2016 x264 project
5
*
6
* Authors: Steven Walters <[email protected]>
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 [email protected].
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 };
156
157