Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
52867 views
1
/*****************************************************************************
2
* cache.c: cache 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
#include "internal.h"
28
#define NAME "cache"
29
#define LAST_FRAME (h->first_frame + h->cur_size - 1)
30
31
typedef struct
32
{
33
hnd_t prev_hnd;
34
cli_vid_filter_t prev_filter;
35
36
int max_size;
37
int first_frame; /* first cached frame */
38
cli_pic_t **cache;
39
int cur_size;
40
int eof; /* frame beyond end of the file */
41
} cache_hnd_t;
42
43
cli_vid_filter_t cache_filter;
44
45
static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string )
46
{
47
intptr_t size = (intptr_t)opt_string;
48
/* upon a <= 0 cache request, do nothing */
49
if( size <= 0 )
50
return 0;
51
cache_hnd_t *h = calloc( 1, sizeof(cache_hnd_t) );
52
if( !h )
53
return -1;
54
55
h->max_size = size;
56
h->cache = malloc( (h->max_size+1) * sizeof(cli_pic_t*) );
57
if( !h->cache )
58
return -1;
59
60
for( int i = 0; i < h->max_size; i++ )
61
{
62
h->cache[i] = malloc( sizeof(cli_pic_t) );
63
if( !h->cache[i] || x264_cli_pic_alloc( h->cache[i], info->csp, info->width, info->height ) )
64
return -1;
65
}
66
h->cache[h->max_size] = NULL; /* require null terminator for list methods */
67
68
h->prev_filter = *filter;
69
h->prev_hnd = *handle;
70
*handle = h;
71
*filter = cache_filter;
72
73
return 0;
74
}
75
76
static void fill_cache( cache_hnd_t *h, int frame )
77
{
78
/* shift frames out of the cache as the frame request is beyond the filled cache */
79
int shift = frame - LAST_FRAME;
80
/* no frames to shift or no frames left to read */
81
if( shift <= 0 || h->eof )
82
return;
83
/* the next frames to read are either
84
* A) starting at the end of the current cache, or
85
* B) starting at a new frame that has the end of the cache at the desired frame
86
* and proceeding to fill the entire cache */
87
int cur_frame = X264_MAX( h->first_frame + h->cur_size, frame - h->max_size + 1 );
88
/* the new starting point is either
89
* A) the current one shifted the number of frames entering/leaving the cache, or
90
* B) at a new frame that has the end of the cache at the desired frame. */
91
h->first_frame = X264_MIN( h->first_frame + shift, cur_frame );
92
h->cur_size = X264_MAX( h->cur_size - shift, 0 );
93
while( h->cur_size < h->max_size )
94
{
95
cli_pic_t temp;
96
/* the old front frame is going to shift off, overwrite it with the new frame */
97
cli_pic_t *cache = h->cache[0];
98
if( h->prev_filter.get_frame( h->prev_hnd, &temp, cur_frame ) ||
99
x264_cli_pic_copy( cache, &temp ) ||
100
h->prev_filter.release_frame( h->prev_hnd, &temp, cur_frame ) )
101
{
102
h->eof = cur_frame;
103
return;
104
}
105
/* the read was successful, shift the frame off the front to the end */
106
x264_frame_push( (void*)h->cache, x264_frame_shift( (void*)h->cache ) );
107
cur_frame++;
108
h->cur_size++;
109
}
110
}
111
112
static int get_frame( hnd_t handle, cli_pic_t *output, int frame )
113
{
114
cache_hnd_t *h = handle;
115
FAIL_IF_ERR( frame < h->first_frame, NAME, "frame %d is before first cached frame %d \n", frame, h->first_frame );
116
fill_cache( h, frame );
117
if( frame > LAST_FRAME ) /* eof */
118
return -1;
119
int idx = frame - (h->eof ? h->eof - h->max_size : h->first_frame);
120
*output = *h->cache[idx];
121
return 0;
122
}
123
124
static int release_frame( hnd_t handle, cli_pic_t *pic, int frame )
125
{
126
/* the parent filter's frame has already been released so do nothing here */
127
return 0;
128
}
129
130
static void free_filter( hnd_t handle )
131
{
132
cache_hnd_t *h = handle;
133
h->prev_filter.free( h->prev_hnd );
134
for( int i = 0; i < h->max_size; i++ )
135
{
136
x264_cli_pic_clean( h->cache[i] );
137
free( h->cache[i] );
138
}
139
free( h->cache );
140
free( h );
141
}
142
143
cli_vid_filter_t cache_filter = { NAME, NULL, init, get_frame, release_frame, free_filter, NULL };
144
145