blob: eb05d66a86eb6365ad2752bc1dbc248af68cbacc
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 | |
32 | static const char *framesync_name(void *ptr) |
33 | { |
34 | return "framesync"; |
35 | } |
36 | |
37 | static 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 | |
46 | enum { |
47 | STATE_BOF, |
48 | STATE_RUN, |
49 | STATE_EOF, |
50 | }; |
51 | |
52 | int 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 | |
64 | static 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 | |
80 | int 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 | |
121 | static 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 | |
179 | static 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 | |
186 | static 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 | |
205 | int 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 | |
215 | void 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 | |
227 | void ff_framesync_drop(FFFrameSync *fs) |
228 | { |
229 | fs->frame_ready = 0; |
230 | } |
231 | |
232 | int 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 | |
269 | void 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 | |
282 | int 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 | |
303 | int 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 | |
317 | int 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 | } |
344 |