Line | Branch | Exec | Source |
---|---|---|---|
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 | #include "libavutil/avassert.h" | ||
22 | #include "libavutil/opt.h" | ||
23 | #include "avfilter.h" | ||
24 | #include "filters.h" | ||
25 | #include "framesync.h" | ||
26 | #include "internal.h" | ||
27 | |||
28 | #define OFFSET(member) offsetof(FFFrameSync, member) | ||
29 | #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | ||
30 | |||
31 | ✗ | static const char *framesync_name(void *ptr) | |
32 | { | ||
33 | ✗ | return "framesync"; | |
34 | } | ||
35 | |||
36 | static const AVOption framesync_options[] = { | ||
37 | { "eof_action", "Action to take when encountering EOF from secondary input ", | ||
38 | OFFSET(opt_eof_action), AV_OPT_TYPE_INT, { .i64 = EOF_ACTION_REPEAT }, | ||
39 | EOF_ACTION_REPEAT, EOF_ACTION_PASS, .flags = FLAGS, "eof_action" }, | ||
40 | { "repeat", "Repeat the previous frame.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_REPEAT }, .flags = FLAGS, "eof_action" }, | ||
41 | { "endall", "End both streams.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_ENDALL }, .flags = FLAGS, "eof_action" }, | ||
42 | { "pass", "Pass through the main input.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_PASS }, .flags = FLAGS, "eof_action" }, | ||
43 | { "shortest", "force termination when the shortest input terminates", OFFSET(opt_shortest), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, | ||
44 | { "repeatlast", "extend last frame of secondary streams beyond EOF", OFFSET(opt_repeatlast), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, | ||
45 | { "ts_sync_mode", "How strictly to sync streams based on secondary input timestamps", | ||
46 | OFFSET(opt_ts_sync_mode), AV_OPT_TYPE_INT, { .i64 = TS_DEFAULT }, | ||
47 | TS_DEFAULT, TS_NEAREST, .flags = FLAGS, "ts_sync_mode" }, | ||
48 | { "default", "Frame from secondary input with the nearest lower or equal timestamp to the primary input frame", | ||
49 | 0, AV_OPT_TYPE_CONST, { .i64 = TS_DEFAULT }, .flags = FLAGS, "ts_sync_mode" }, | ||
50 | { "nearest", "Frame from secondary input with the absolute nearest timestamp to the primary input frame", | ||
51 | 0, AV_OPT_TYPE_CONST, { .i64 = TS_NEAREST }, .flags = FLAGS, "ts_sync_mode" }, | ||
52 | { NULL } | ||
53 | }; | ||
54 | static const AVClass framesync_class = { | ||
55 | .version = LIBAVUTIL_VERSION_INT, | ||
56 | .class_name = "framesync", | ||
57 | .item_name = framesync_name, | ||
58 | .category = AV_CLASS_CATEGORY_FILTER, | ||
59 | .option = framesync_options, | ||
60 | .parent_log_context_offset = OFFSET(parent), | ||
61 | }; | ||
62 | |||
63 | ✗ | const AVClass *ff_framesync_child_class_iterate(void **iter) | |
64 | { | ||
65 | ✗ | const AVClass *c = *iter ? NULL : &framesync_class; | |
66 | ✗ | *iter = (void *)(uintptr_t)c; | |
67 | ✗ | return c; | |
68 | } | ||
69 | |||
70 | enum { | ||
71 | STATE_BOF, | ||
72 | STATE_RUN, | ||
73 | STATE_EOF, | ||
74 | }; | ||
75 | |||
76 | static int consume_from_fifos(FFFrameSync *fs); | ||
77 | |||
78 | 112 | void ff_framesync_preinit(FFFrameSync *fs) | |
79 | { | ||
80 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 77 times.
|
112 | if (fs->class) |
81 | 35 | return; | |
82 | 77 | fs->class = &framesync_class; | |
83 | 77 | av_opt_set_defaults(fs); | |
84 | } | ||
85 | |||
86 | 42 | int ff_framesync_init(FFFrameSync *fs, AVFilterContext *parent, unsigned nb_in) | |
87 | { | ||
88 | /* For filters with several outputs, we will not be able to assume which | ||
89 | output is relevant for ff_outlink_frame_wanted() and | ||
90 | ff_outlink_set_status(). To be designed when needed. */ | ||
91 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | av_assert0(parent->nb_outputs == 1); |
92 | |||
93 | 42 | ff_framesync_preinit(fs); | |
94 | 42 | fs->parent = parent; | |
95 | 42 | fs->nb_in = nb_in; | |
96 | |||
97 | 42 | fs->in = av_calloc(nb_in, sizeof(*fs->in)); | |
98 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (!fs->in) |
99 | ✗ | return AVERROR(ENOMEM); | |
100 | 42 | return 0; | |
101 | } | ||
102 | |||
103 | 64 | static void framesync_eof(FFFrameSync *fs) | |
104 | { | ||
105 | 64 | fs->eof = 1; | |
106 | 64 | fs->frame_ready = 0; | |
107 | 64 | ff_outlink_set_status(fs->parent->outputs[0], AVERROR_EOF, AV_NOPTS_VALUE); | |
108 | 64 | } | |
109 | |||
110 | 115 | static void framesync_sync_level_update(FFFrameSync *fs) | |
111 | { | ||
112 | 115 | unsigned i, level = 0; | |
113 | |||
114 |
2/2✓ Branch 0 taken 228 times.
✓ Branch 1 taken 115 times.
|
343 | for (i = 0; i < fs->nb_in; i++) |
115 |
1/2✓ Branch 0 taken 228 times.
✗ Branch 1 not taken.
|
228 | if (fs->in[i].state != STATE_EOF) |
116 | 228 | level = FFMAX(level, fs->in[i].sync); | |
117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 115 times.
|
115 | av_assert0(level <= fs->sync_level); |
118 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 23 times.
|
115 | if (level < fs->sync_level) |
119 | 92 | av_log(fs, AV_LOG_VERBOSE, "Sync level %u\n", level); | |
120 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 115 times.
|
115 | if (fs->opt_ts_sync_mode > TS_DEFAULT) { |
121 | ✗ | for (i = 0; i < fs->nb_in; i++) { | |
122 | ✗ | if (fs->in[i].sync < level) | |
123 | ✗ | fs->in[i].ts_mode = fs->opt_ts_sync_mode; | |
124 | else | ||
125 | ✗ | fs->in[i].ts_mode = TS_DEFAULT; | |
126 | } | ||
127 | } | ||
128 |
2/2✓ Branch 0 taken 83 times.
✓ Branch 1 taken 32 times.
|
115 | if (level) |
129 | 83 | fs->sync_level = level; | |
130 | else | ||
131 | 32 | framesync_eof(fs); | |
132 | 115 | } | |
133 | |||
134 | 42 | int ff_framesync_configure(FFFrameSync *fs) | |
135 | { | ||
136 | unsigned i; | ||
137 | |||
138 |
2/4✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
|
42 | if (!fs->opt_repeatlast || fs->opt_eof_action == EOF_ACTION_PASS) { |
139 | ✗ | fs->opt_repeatlast = 0; | |
140 | ✗ | fs->opt_eof_action = EOF_ACTION_PASS; | |
141 | } | ||
142 |
2/4✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
|
42 | if (fs->opt_shortest || fs->opt_eof_action == EOF_ACTION_ENDALL) { |
143 | ✗ | fs->opt_shortest = 1; | |
144 | ✗ | fs->opt_eof_action = EOF_ACTION_ENDALL; | |
145 | } | ||
146 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (!fs->opt_repeatlast) { |
147 | ✗ | for (i = 1; i < fs->nb_in; i++) { | |
148 | ✗ | fs->in[i].after = EXT_NULL; | |
149 | ✗ | fs->in[i].sync = 0; | |
150 | } | ||
151 | } | ||
152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (fs->opt_shortest) { |
153 | ✗ | for (i = 0; i < fs->nb_in; i++) | |
154 | ✗ | fs->in[i].after = EXT_STOP; | |
155 | } | ||
156 | |||
157 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | if (!fs->time_base.num) { |
158 |
2/2✓ Branch 0 taken 83 times.
✓ Branch 1 taken 42 times.
|
125 | for (i = 0; i < fs->nb_in; i++) { |
159 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
83 | if (fs->in[i].sync) { |
160 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 42 times.
|
83 | if (fs->time_base.num) { |
161 | 41 | fs->time_base = av_gcd_q(fs->time_base, fs->in[i].time_base, | |
162 | 41 | AV_TIME_BASE / 2, AV_TIME_BASE_Q); | |
163 | } else { | ||
164 | 42 | fs->time_base = fs->in[i].time_base; | |
165 | } | ||
166 | } | ||
167 | } | ||
168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (!fs->time_base.num) { |
169 | ✗ | av_log(fs, AV_LOG_ERROR, "Impossible to set time base\n"); | |
170 | ✗ | return AVERROR(EINVAL); | |
171 | } | ||
172 | 42 | av_log(fs, AV_LOG_VERBOSE, "Selected %d/%d time base\n", | |
173 | fs->time_base.num, fs->time_base.den); | ||
174 | } | ||
175 | |||
176 |
2/2✓ Branch 0 taken 83 times.
✓ Branch 1 taken 42 times.
|
125 | for (i = 0; i < fs->nb_in; i++) |
177 | 83 | fs->in[i].pts = fs->in[i].pts_next = AV_NOPTS_VALUE; | |
178 | 42 | fs->sync_level = UINT_MAX; | |
179 | 42 | framesync_sync_level_update(fs); | |
180 | |||
181 | 42 | return 0; | |
182 | } | ||
183 | |||
184 | 3662 | static int framesync_advance(FFFrameSync *fs) | |
185 | { | ||
186 | unsigned i; | ||
187 | int64_t pts; | ||
188 | int ret; | ||
189 | |||
190 |
4/4✓ Branch 0 taken 3889 times.
✓ Branch 1 taken 1390 times.
✓ Branch 2 taken 3875 times.
✓ Branch 3 taken 14 times.
|
5279 | while (!(fs->frame_ready || fs->eof)) { |
191 | 3875 | ret = consume_from_fifos(fs); | |
192 |
2/2✓ Branch 0 taken 2227 times.
✓ Branch 1 taken 1648 times.
|
3875 | if (ret <= 0) |
193 | 2227 | return ret; | |
194 | |||
195 | 1648 | pts = INT64_MAX; | |
196 |
2/2✓ Branch 0 taken 3245 times.
✓ Branch 1 taken 1648 times.
|
4893 | for (i = 0; i < fs->nb_in; i++) |
197 |
3/4✓ Branch 0 taken 3245 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1843 times.
✓ Branch 3 taken 1402 times.
|
3245 | if (fs->in[i].have_next && fs->in[i].pts_next < pts) |
198 | 1843 | pts = fs->in[i].pts_next; | |
199 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 1617 times.
|
1648 | if (pts == INT64_MAX) { |
200 | 31 | framesync_eof(fs); | |
201 | 31 | break; | |
202 | } | ||
203 |
2/2✓ Branch 0 taken 3183 times.
✓ Branch 1 taken 1617 times.
|
4800 | for (i = 0; i < fs->nb_in; i++) { |
204 |
2/2✓ Branch 0 taken 844 times.
✓ Branch 1 taken 2339 times.
|
3183 | if (fs->in[i].pts_next == pts || |
205 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 844 times.
|
844 | (fs->in[i].ts_mode == TS_NEAREST && |
206 | ✗ | fs->in[i].have_next && | |
207 | ✗ | fs->in[i].pts_next != INT64_MAX && fs->in[i].pts != AV_NOPTS_VALUE && | |
208 | ✗ | fs->in[i].pts_next - pts < pts - fs->in[i].pts) || | |
209 |
2/2✓ Branch 0 taken 280 times.
✓ Branch 1 taken 564 times.
|
844 | (fs->in[i].before == EXT_INFINITY && |
210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
|
280 | fs->in[i].state == STATE_BOF)) { |
211 | 2339 | av_frame_free(&fs->in[i].frame); | |
212 | 2339 | fs->in[i].frame = fs->in[i].frame_next; | |
213 | 2339 | fs->in[i].pts = fs->in[i].pts_next; | |
214 | 2339 | fs->in[i].frame_next = NULL; | |
215 | 2339 | fs->in[i].pts_next = AV_NOPTS_VALUE; | |
216 | 2339 | fs->in[i].have_next = 0; | |
217 |
2/2✓ Branch 0 taken 2338 times.
✓ Branch 1 taken 1 times.
|
2339 | fs->in[i].state = fs->in[i].frame ? STATE_RUN : STATE_EOF; |
218 |
3/4✓ Branch 0 taken 1490 times.
✓ Branch 1 taken 849 times.
✓ Branch 2 taken 1490 times.
✗ Branch 3 not taken.
|
2339 | if (fs->in[i].sync == fs->sync_level && fs->in[i].frame) |
219 | 1490 | fs->frame_ready = 1; | |
220 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2338 times.
|
2339 | if (fs->in[i].state == STATE_EOF && |
221 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | fs->in[i].after == EXT_STOP) |
222 | 1 | framesync_eof(fs); | |
223 | } | ||
224 | } | ||
225 |
2/2✓ Branch 0 taken 1390 times.
✓ Branch 1 taken 227 times.
|
1617 | if (fs->frame_ready) |
226 |
2/2✓ Branch 0 taken 2730 times.
✓ Branch 1 taken 1390 times.
|
4120 | for (i = 0; i < fs->nb_in; i++) |
227 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2726 times.
|
2730 | if ((fs->in[i].state == STATE_BOF && |
228 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | fs->in[i].before == EXT_STOP)) |
229 | ✗ | fs->frame_ready = 0; | |
230 | 1617 | fs->pts = pts; | |
231 | } | ||
232 | 1435 | return 0; | |
233 | } | ||
234 | |||
235 | 1 | static int64_t framesync_pts_extrapolate(FFFrameSync *fs, unsigned in, | |
236 | int64_t pts) | ||
237 | { | ||
238 | /* Possible enhancement: use the link's frame rate */ | ||
239 | 1 | return pts + 1; | |
240 | } | ||
241 | |||
242 | 2338 | static void framesync_inject_frame(FFFrameSync *fs, unsigned in, AVFrame *frame) | |
243 | { | ||
244 | int64_t pts; | ||
245 | |||
246 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2338 times.
|
2338 | av_assert0(!fs->in[in].have_next); |
247 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2338 times.
|
2338 | av_assert0(frame); |
248 | 2338 | pts = av_rescale_q(frame->pts, fs->in[in].time_base, fs->time_base); | |
249 | 2338 | frame->pts = pts; | |
250 | 2338 | fs->in[in].frame_next = frame; | |
251 | 2338 | fs->in[in].pts_next = pts; | |
252 | 2338 | fs->in[in].have_next = 1; | |
253 | 2338 | } | |
254 | |||
255 | 73 | static void framesync_inject_status(FFFrameSync *fs, unsigned in, int status, int64_t pts) | |
256 | { | ||
257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
|
73 | av_assert0(!fs->in[in].have_next); |
258 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 72 times.
|
73 | pts = fs->in[in].state != STATE_RUN || fs->in[in].after == EXT_INFINITY |
259 |
1/2✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
|
146 | ? INT64_MAX : framesync_pts_extrapolate(fs, in, fs->in[in].pts); |
260 | 73 | fs->in[in].sync = 0; | |
261 | 73 | framesync_sync_level_update(fs); | |
262 | 73 | fs->in[in].frame_next = NULL; | |
263 | 73 | fs->in[in].pts_next = pts; | |
264 | 73 | fs->in[in].have_next = 1; | |
265 | 73 | } | |
266 | |||
267 | 2730 | int ff_framesync_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe, | |
268 | unsigned get) | ||
269 | { | ||
270 | AVFrame *frame; | ||
271 | 2730 | unsigned need_copy = 0, i; | |
272 | int64_t pts_next; | ||
273 | int ret; | ||
274 | |||
275 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2726 times.
|
2730 | if (!fs->in[in].frame) { |
276 | 4 | *rframe = NULL; | |
277 | 4 | return 0; | |
278 | } | ||
279 | 2726 | frame = fs->in[in].frame; | |
280 |
2/2✓ Branch 0 taken 1240 times.
✓ Branch 1 taken 1486 times.
|
2726 | if (get) { |
281 | /* Find out if we need to copy the frame: is there another sync | ||
282 | stream, and do we know if its current frame will outlast this one? */ | ||
283 |
2/2✓ Branch 0 taken 85 times.
✓ Branch 1 taken 1155 times.
|
1240 | pts_next = fs->in[in].have_next ? fs->in[in].pts_next : INT64_MAX; |
284 |
3/4✓ Branch 0 taken 2480 times.
✓ Branch 1 taken 1240 times.
✓ Branch 2 taken 2480 times.
✗ Branch 3 not taken.
|
3720 | for (i = 0; i < fs->nb_in && !need_copy; i++) |
285 |
4/4✓ Branch 0 taken 1240 times.
✓ Branch 1 taken 1240 times.
✓ Branch 2 taken 940 times.
✓ Branch 3 taken 300 times.
|
2480 | if (i != in && fs->in[i].sync && |
286 |
3/4✓ Branch 0 taken 233 times.
✓ Branch 1 taken 707 times.
✓ Branch 2 taken 233 times.
✗ Branch 3 not taken.
|
940 | (!fs->in[i].have_next || fs->in[i].pts_next < pts_next)) |
287 | 940 | need_copy = 1; | |
288 |
2/2✓ Branch 0 taken 940 times.
✓ Branch 1 taken 300 times.
|
1240 | if (need_copy) { |
289 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 940 times.
|
940 | if (!(frame = av_frame_clone(frame))) |
290 | ✗ | return AVERROR(ENOMEM); | |
291 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 940 times.
|
940 | if ((ret = ff_inlink_make_frame_writable(fs->parent->inputs[in], &frame) < 0)) { |
292 | ✗ | av_frame_free(&frame); | |
293 | ✗ | return ret; | |
294 | } | ||
295 | } else { | ||
296 | 300 | fs->in[in].frame = NULL; | |
297 | } | ||
298 | 1240 | fs->frame_ready = 0; | |
299 | } | ||
300 | 2726 | *rframe = frame; | |
301 | 2726 | return 0; | |
302 | } | ||
303 | |||
304 | 86 | void ff_framesync_uninit(FFFrameSync *fs) | |
305 | { | ||
306 | unsigned i; | ||
307 | |||
308 |
2/2✓ Branch 0 taken 83 times.
✓ Branch 1 taken 86 times.
|
169 | for (i = 0; i < fs->nb_in; i++) { |
309 | 83 | av_frame_free(&fs->in[i].frame); | |
310 | 83 | av_frame_free(&fs->in[i].frame_next); | |
311 | } | ||
312 | |||
313 | 86 | av_freep(&fs->in); | |
314 | 86 | } | |
315 | |||
316 | 3875 | static int consume_from_fifos(FFFrameSync *fs) | |
317 | { | ||
318 | 3875 | AVFilterContext *ctx = fs->parent; | |
319 | 3875 | AVFrame *frame = NULL; | |
320 | int64_t pts; | ||
321 | unsigned i, nb_active, nb_miss; | ||
322 | int ret, status; | ||
323 | |||
324 | 3875 | nb_active = nb_miss = 0; | |
325 |
2/2✓ Branch 0 taken 7649 times.
✓ Branch 1 taken 3875 times.
|
11524 | for (i = 0; i < fs->nb_in; i++) { |
326 |
3/4✓ Branch 0 taken 5451 times.
✓ Branch 1 taken 2198 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5451 times.
|
7649 | if (fs->in[i].have_next || fs->in[i].state == STATE_EOF) |
327 | 2198 | continue; | |
328 | 5451 | nb_active++; | |
329 | 5451 | ret = ff_inlink_consume_frame(ctx->inputs[i], &frame); | |
330 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5451 times.
|
5451 | if (ret < 0) |
331 | ✗ | return ret; | |
332 |
2/2✓ Branch 0 taken 2338 times.
✓ Branch 1 taken 3113 times.
|
5451 | if (ret) { |
333 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2338 times.
|
2338 | av_assert0(frame); |
334 | 2338 | framesync_inject_frame(fs, i, frame); | |
335 | } else { | ||
336 | 3113 | ret = ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts); | |
337 |
2/2✓ Branch 0 taken 73 times.
✓ Branch 1 taken 3040 times.
|
3113 | if (ret > 0) { |
338 | 73 | framesync_inject_status(fs, i, status, pts); | |
339 |
1/2✓ Branch 0 taken 3040 times.
✗ Branch 1 not taken.
|
3040 | } else if (!ret) { |
340 | 3040 | nb_miss++; | |
341 | } | ||
342 | } | ||
343 | } | ||
344 |
2/2✓ Branch 0 taken 2227 times.
✓ Branch 1 taken 1648 times.
|
3875 | if (nb_miss) { |
345 |
4/4✓ Branch 0 taken 1632 times.
✓ Branch 1 taken 595 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1630 times.
|
2227 | if (nb_miss == nb_active && !ff_outlink_frame_wanted(ctx->outputs[0])) |
346 | 2 | return FFERROR_NOT_READY; | |
347 |
2/2✓ Branch 0 taken 4400 times.
✓ Branch 1 taken 2225 times.
|
6625 | for (i = 0; i < fs->nb_in; i++) |
348 |
3/4✓ Branch 0 taken 3038 times.
✓ Branch 1 taken 1362 times.
✓ Branch 2 taken 3038 times.
✗ Branch 3 not taken.
|
4400 | if (!fs->in[i].have_next && fs->in[i].state != STATE_EOF) |
349 | 3038 | ff_inlink_request_frame(ctx->inputs[i]); | |
350 | 2225 | return 0; | |
351 | } | ||
352 | 1648 | return 1; | |
353 | } | ||
354 | |||
355 | 3662 | int ff_framesync_activate(FFFrameSync *fs) | |
356 | { | ||
357 | int ret; | ||
358 | |||
359 | 3662 | ret = framesync_advance(fs); | |
360 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3660 times.
|
3662 | if (ret < 0) |
361 | 2 | return ret; | |
362 |
4/4✓ Branch 0 taken 3615 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 2225 times.
✓ Branch 3 taken 1390 times.
|
3660 | if (fs->eof || !fs->frame_ready) |
363 | 2270 | return 0; | |
364 | 1390 | ret = fs->on_event(fs); | |
365 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1390 times.
|
1390 | if (ret < 0) |
366 | ✗ | return ret; | |
367 | 1390 | fs->frame_ready = 0; | |
368 | |||
369 | 1390 | return 0; | |
370 | } | ||
371 | |||
372 | 39 | int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent) | |
373 | { | ||
374 | int ret; | ||
375 | |||
376 | 39 | ret = ff_framesync_init(fs, parent, 2); | |
377 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
|
39 | if (ret < 0) |
378 | ✗ | return ret; | |
379 | 39 | fs->in[0].time_base = parent->inputs[0]->time_base; | |
380 | 39 | fs->in[1].time_base = parent->inputs[1]->time_base; | |
381 | 39 | fs->in[0].sync = 2; | |
382 | 39 | fs->in[0].before = EXT_STOP; | |
383 | 39 | fs->in[0].after = EXT_INFINITY; | |
384 | 39 | fs->in[1].sync = 1; | |
385 | 39 | fs->in[1].before = EXT_NULL; | |
386 | 39 | fs->in[1].after = EXT_INFINITY; | |
387 | 39 | return 0; | |
388 | } | ||
389 | |||
390 | 1240 | int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1) | |
391 | { | ||
392 | 1240 | AVFilterContext *ctx = fs->parent; | |
393 | 1240 | AVFrame *mainpic = NULL, *secondpic = NULL; | |
394 | int ret; | ||
395 | |||
396 |
2/4✓ Branch 1 taken 1240 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1240 times.
|
2480 | if ((ret = ff_framesync_get_frame(fs, 0, &mainpic, 1)) < 0 || |
397 | 1240 | (ret = ff_framesync_get_frame(fs, 1, &secondpic, 0)) < 0) { | |
398 | ✗ | av_frame_free(&mainpic); | |
399 | ✗ | return ret; | |
400 | } | ||
401 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1240 times.
|
1240 | av_assert0(mainpic); |
402 | 1240 | mainpic->pts = av_rescale_q(fs->pts, fs->time_base, ctx->outputs[0]->time_base); | |
403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1240 times.
|
1240 | if (ctx->is_disabled) |
404 | ✗ | secondpic = NULL; | |
405 | 1240 | *f0 = mainpic; | |
406 | 1240 | *f1 = secondpic; | |
407 | 1240 | return 0; | |
408 | } | ||
409 | |||
410 | 1216 | int ff_framesync_dualinput_get_writable(FFFrameSync *fs, AVFrame **f0, AVFrame **f1) | |
411 | { | ||
412 | int ret; | ||
413 | |||
414 | 1216 | ret = ff_framesync_dualinput_get(fs, f0, f1); | |
415 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1216 times.
|
1216 | if (ret < 0) |
416 | ✗ | return ret; | |
417 | 1216 | ret = ff_inlink_make_frame_writable(fs->parent->inputs[0], f0); | |
418 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1216 times.
|
1216 | if (ret < 0) { |
419 | ✗ | av_frame_free(f0); | |
420 | ✗ | *f1 = NULL; | |
421 | ✗ | return ret; | |
422 | } | ||
423 | 1216 | return 0; | |
424 | } | ||
425 |