History

lavfi: copy framesync into framesync2.

framesync2 will be the base for the version using activate. Most of the logic will be the same, but the code cannot be shared. Copying the file initially without change will make the diff easier to read.

Nicolas George committed 9 years ago

Commit cffea1b1 parent 1daacba2 files · +640 −0Browse files

Showing the changes to libavfilter/framesync2.c (1 of 2 files). Show all

Unified · Split

libavfilter/framesync2.c+343−0
@@ -0,0 +1,343 @@
1/*
2 * Copyright (c) 2013 Nicolas George
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#define FF_INTERNAL_FIELDS 1
22#include "framequeue.h"
23
24#include "libavutil/avassert.h"
25#include "avfilter.h"
26#include "bufferqueue.h"
27#include "framesync.h"
28#include "internal.h"
29
30#define OFFSET(member) offsetof(FFFrameSync, member)
31
32static const char *framesync_name(void *ptr)
33{
34 return "framesync";
35}
36
37static const AVClass framesync_class = {
38 .version = LIBAVUTIL_VERSION_INT,
39 .class_name = "framesync",
40 .item_name = framesync_name,
41 .category = AV_CLASS_CATEGORY_FILTER,
42 .option = NULL,
43 .parent_log_context_offset = OFFSET(parent),
44};
45
46enum {
47 STATE_BOF,
48 STATE_RUN,
49 STATE_EOF,
50};
51
52int ff_framesync_init(FFFrameSync *fs, void *parent, unsigned nb_in)
53{
54 fs->class = &framesync_class;
55 fs->parent = parent;
56 fs->nb_in = nb_in;
57
58 fs->in = av_calloc(nb_in, sizeof(*fs->in));
59 if (!fs->in)
60 return AVERROR(ENOMEM);
61 return 0;
62}
63
64static void framesync_sync_level_update(FFFrameSync *fs)
65{
66 unsigned i, level = 0;
67
68 for (i = 0; i < fs->nb_in; i++)
69 if (fs->in[i].state != STATE_EOF)
70 level = FFMAX(level, fs->in[i].sync);
71 av_assert0(level <= fs->sync_level);
72 if (level < fs->sync_level)
73 av_log(fs, AV_LOG_VERBOSE, "Sync level %u\n", level);
74 if (level)
75 fs->sync_level = level;
76 else
77 fs->eof = 1;
78}
79
80int ff_framesync_configure(FFFrameSync *fs)
81{
82 unsigned i;
83 int64_t gcd, lcm;
84
85 if (!fs->time_base.num) {
86 for (i = 0; i < fs->nb_in; i++) {
87 if (fs->in[i].sync) {
88 if (fs->time_base.num) {
89 gcd = av_gcd(fs->time_base.den, fs->in[i].time_base.den);
90 lcm = (fs->time_base.den / gcd) * fs->in[i].time_base.den;
91 if (lcm < AV_TIME_BASE / 2) {
92 fs->time_base.den = lcm;
93 fs->time_base.num = av_gcd(fs->time_base.num,
94 fs->in[i].time_base.num);
95 } else {
96 fs->time_base.num = 1;
97 fs->time_base.den = AV_TIME_BASE;
98 break;
99 }
100 } else {
101 fs->time_base = fs->in[i].time_base;
102 }
103 }
104 }
105 if (!fs->time_base.num) {
106 av_log(fs, AV_LOG_ERROR, "Impossible to set time base\n");
107 return AVERROR(EINVAL);
108 }
109 av_log(fs, AV_LOG_VERBOSE, "Selected %d/%d time base\n",
110 fs->time_base.num, fs->time_base.den);
111 }
112
113 for (i = 0; i < fs->nb_in; i++)
114 fs->in[i].pts = fs->in[i].pts_next = AV_NOPTS_VALUE;
115 fs->sync_level = UINT_MAX;
116 framesync_sync_level_update(fs);
117
118 return 0;
119}
120
121static void framesync_advance(FFFrameSync *fs)
122{
123 int latest;
124 unsigned i;
125 int64_t pts;
126
127 if (fs->eof)
128 return;
129 while (!fs->frame_ready) {
130 latest = -1;
131 for (i = 0; i < fs->nb_in; i++) {
132 if (!fs->in[i].have_next) {
133 if (latest < 0 || fs->in[i].pts < fs->in[latest].pts)
134 latest = i;
135 }
136 }
137 if (latest >= 0) {
138 fs->in_request = latest;
139 break;
140 }
141
142 pts = fs->in[0].pts_next;
143 for (i = 1; i < fs->nb_in; i++)
144 if (fs->in[i].pts_next < pts)
145 pts = fs->in[i].pts_next;
146 if (pts == INT64_MAX) {
147 fs->eof = 1;
148 break;
149 }
150 for (i = 0; i < fs->nb_in; i++) {
151 if (fs->in[i].pts_next == pts ||
152 (fs->in[i].before == EXT_INFINITY &&
153 fs->in[i].state == STATE_BOF)) {
154 av_frame_free(&fs->in[i].frame);
155 fs->in[i].frame = fs->in[i].frame_next;
156 fs->in[i].pts = fs->in[i].pts_next;
157 fs->in[i].frame_next = NULL;
158 fs->in[i].pts_next = AV_NOPTS_VALUE;
159 fs->in[i].have_next = 0;
160 fs->in[i].state = fs->in[i].frame ? STATE_RUN : STATE_EOF;
161 if (fs->in[i].sync == fs->sync_level && fs->in[i].frame)
162 fs->frame_ready = 1;
163 if (fs->in[i].state == STATE_EOF &&
164 fs->in[i].after == EXT_STOP)
165 fs->eof = 1;
166 }
167 }
168 if (fs->eof)
169 fs->frame_ready = 0;
170 if (fs->frame_ready)
171 for (i = 0; i < fs->nb_in; i++)
172 if ((fs->in[i].state == STATE_BOF &&
173 fs->in[i].before == EXT_STOP))
174 fs->frame_ready = 0;
175 fs->pts = pts;
176 }
177}
178
179static int64_t framesync_pts_extrapolate(FFFrameSync *fs, unsigned in,
180 int64_t pts)
181{
182 /* Possible enhancement: use the link's frame rate */
183 return pts + 1;
184}
185
186static void framesync_inject_frame(FFFrameSync *fs, unsigned in, AVFrame *frame)
187{
188 int64_t pts;
189
190 av_assert0(!fs->in[in].have_next);
191 if (frame) {
192 pts = av_rescale_q(frame->pts, fs->in[in].time_base, fs->time_base);
193 frame->pts = pts;
194 } else {
195 pts = fs->in[in].state != STATE_RUN || fs->in[in].after == EXT_INFINITY
196 ? INT64_MAX : framesync_pts_extrapolate(fs, in, fs->in[in].pts);
197 fs->in[in].sync = 0;
198 framesync_sync_level_update(fs);
199 }
200 fs->in[in].frame_next = frame;
201 fs->in[in].pts_next = pts;
202 fs->in[in].have_next = 1;
203}
204
205int ff_framesync_add_frame(FFFrameSync *fs, unsigned in, AVFrame *frame)
206{
207 av_assert1(in < fs->nb_in);
208 if (!fs->in[in].have_next)
209 framesync_inject_frame(fs, in, frame);
210 else
211 ff_bufqueue_add(fs, &fs->in[in].queue, frame);
212 return 0;
213}
214
215void ff_framesync_next(FFFrameSync *fs)
216{
217 unsigned i;
218
219 av_assert0(!fs->frame_ready);
220 for (i = 0; i < fs->nb_in; i++)
221 if (!fs->in[i].have_next && fs->in[i].queue.available)
222 framesync_inject_frame(fs, i, ff_bufqueue_get(&fs->in[i].queue));
223 fs->frame_ready = 0;
224 framesync_advance(fs);
225}
226
227void ff_framesync_drop(FFFrameSync *fs)
228{
229 fs->frame_ready = 0;
230}
231
232int ff_framesync_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe,
233 unsigned get)
234{
235 AVFrame *frame;
236 unsigned need_copy = 0, i;
237 int64_t pts_next;
238 int ret;
239
240 if (!fs->in[in].frame) {
241 *rframe = NULL;
242 return 0;
243 }
244 frame = fs->in[in].frame;
245 if (get) {
246 /* Find out if we need to copy the frame: is there another sync
247 stream, and do we know if its current frame will outlast this one? */
248 pts_next = fs->in[in].have_next ? fs->in[in].pts_next : INT64_MAX;
249 for (i = 0; i < fs->nb_in && !need_copy; i++)
250 if (i != in && fs->in[i].sync &&
251 (!fs->in[i].have_next || fs->in[i].pts_next < pts_next))
252 need_copy = 1;
253 if (need_copy) {
254 if (!(frame = av_frame_clone(frame)))
255 return AVERROR(ENOMEM);
256 if ((ret = av_frame_make_writable(frame)) < 0) {
257 av_frame_free(&frame);
258 return ret;
259 }
260 } else {
261 fs->in[in].frame = NULL;
262 }
263 fs->frame_ready = 0;
264 }
265 *rframe = frame;
266 return 0;
267}
268
269void ff_framesync_uninit(FFFrameSync *fs)
270{
271 unsigned i;
272
273 for (i = 0; i < fs->nb_in; i++) {
274 av_frame_free(&fs->in[i].frame);
275 av_frame_free(&fs->in[i].frame_next);
276 ff_bufqueue_discard_all(&fs->in[i].queue);
277 }
278
279 av_freep(&fs->in);
280}
281
282int ff_framesync_process_frame(FFFrameSync *fs, unsigned all)
283{
284 int ret, count = 0;
285
286 av_assert0(fs->on_event);
287 while (1) {
288 ff_framesync_next(fs);
289 if (fs->eof || !fs->frame_ready)
290 break;
291 if ((ret = fs->on_event(fs)) < 0)
292 return ret;
293 ff_framesync_drop(fs);
294 count++;
295 if (!all)
296 break;
297 }
298 if (!count && fs->eof)
299 return AVERROR_EOF;
300 return count;
301}
302
303int ff_framesync_filter_frame(FFFrameSync *fs, AVFilterLink *inlink,
304 AVFrame *in)
305{
306 int ret;
307
308 if ((ret = ff_framesync_process_frame(fs, 1)) < 0)
309 return ret;
310 if ((ret = ff_framesync_add_frame(fs, FF_INLINK_IDX(inlink), in)) < 0)
311 return ret;
312 if ((ret = ff_framesync_process_frame(fs, 0)) < 0)
313 return ret;
314 return 0;
315}
316
317int ff_framesync_request_frame(FFFrameSync *fs, AVFilterLink *outlink)
318{
319 AVFilterContext *ctx = outlink->src;
320 int input, ret, i;
321
322 if ((ret = ff_framesync_process_frame(fs, 0)) < 0)
323 return ret;
324 if (ret > 0)
325 return 0;
326 if (fs->eof)
327 return AVERROR_EOF;
328 input = fs->in_request;
329 /* Detect status change early */
330 for (i = 0; i < fs->nb_in; i++)
331 if (!ff_framequeue_queued_frames(&ctx->inputs[i]->fifo) &&
332 ctx->inputs[i]->status_in && !ctx->inputs[i]->status_out)
333 input = i;
334 ret = ff_request_frame(ctx->inputs[input]);
335 if (ret == AVERROR_EOF) {
336 if ((ret = ff_framesync_add_frame(fs, input, NULL)) < 0)
337 return ret;
338 if ((ret = ff_framesync_process_frame(fs, 0)) < 0)
339 return ret;
340 ret = 0;
341 }
342 return ret;
343}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t