Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * This file is part of FFmpeg. | ||
3 | * | ||
4 | * FFmpeg is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU Lesser General Public | ||
6 | * License as published by the Free Software Foundation; either | ||
7 | * version 2.1 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * FFmpeg is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * Lesser General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU Lesser General Public | ||
15 | * License along with FFmpeg; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | |||
19 | #include <stdint.h> | ||
20 | #include <string.h> | ||
21 | |||
22 | #include "libavutil/avassert.h" | ||
23 | #include "libavutil/error.h" | ||
24 | #include "libavutil/fifo.h" | ||
25 | #include "libavutil/mathematics.h" | ||
26 | #include "libavutil/mem.h" | ||
27 | |||
28 | #include "objpool.h" | ||
29 | #include "sync_queue.h" | ||
30 | |||
31 | typedef struct SyncQueueStream { | ||
32 | AVFifo *fifo; | ||
33 | AVRational tb; | ||
34 | |||
35 | /* stream head: largest timestamp seen */ | ||
36 | int64_t head_ts; | ||
37 | int limiting; | ||
38 | /* no more frames will be sent for this stream */ | ||
39 | int finished; | ||
40 | |||
41 | uint64_t frames_sent; | ||
42 | uint64_t frames_max; | ||
43 | } SyncQueueStream; | ||
44 | |||
45 | struct SyncQueue { | ||
46 | enum SyncQueueType type; | ||
47 | |||
48 | /* no more frames will be sent for any stream */ | ||
49 | int finished; | ||
50 | /* sync head: the stream with the _smallest_ head timestamp | ||
51 | * this stream determines which frames can be output */ | ||
52 | int head_stream; | ||
53 | /* the finished stream with the smallest finish timestamp or -1 */ | ||
54 | int head_finished_stream; | ||
55 | |||
56 | // maximum buffering duration in microseconds | ||
57 | int64_t buf_size_us; | ||
58 | |||
59 | SyncQueueStream *streams; | ||
60 | unsigned int nb_streams; | ||
61 | |||
62 | // pool of preallocated frames to avoid constant allocations | ||
63 | ObjPool *pool; | ||
64 | }; | ||
65 | |||
66 | 22195 | static void frame_move(const SyncQueue *sq, SyncQueueFrame dst, | |
67 | SyncQueueFrame src) | ||
68 | { | ||
69 |
2/2✓ Branch 0 taken 1486 times.
✓ Branch 1 taken 20709 times.
|
22195 | if (sq->type == SYNC_QUEUE_PACKETS) |
70 | 1486 | av_packet_move_ref(dst.p, src.p); | |
71 | else | ||
72 | 20709 | av_frame_move_ref(dst.f, src.f); | |
73 | 22195 | } | |
74 | |||
75 | 24084 | static int64_t frame_ts(const SyncQueue *sq, SyncQueueFrame frame) | |
76 | { | ||
77 | 24084 | return (sq->type == SYNC_QUEUE_PACKETS) ? | |
78 |
2/2✓ Branch 0 taken 3271 times.
✓ Branch 1 taken 20813 times.
|
44897 | frame.p->pts + frame.p->duration : |
79 | 20813 | frame.f->pts + frame.f->duration; | |
80 | } | ||
81 | |||
82 | 21483 | static int frame_null(const SyncQueue *sq, SyncQueueFrame frame) | |
83 | { | ||
84 |
2/2✓ Branch 0 taken 811 times.
✓ Branch 1 taken 20672 times.
|
21483 | return (sq->type == SYNC_QUEUE_PACKETS) ? (frame.p == NULL) : (frame.f == NULL); |
85 | } | ||
86 | |||
87 | 12910 | static void finish_stream(SyncQueue *sq, unsigned int stream_idx) | |
88 | { | ||
89 | 12910 | SyncQueueStream *st = &sq->streams[stream_idx]; | |
90 | |||
91 | 12910 | st->finished = 1; | |
92 | |||
93 |
4/4✓ Branch 0 taken 12899 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 12891 times.
✓ Branch 3 taken 8 times.
|
12910 | if (st->limiting && st->head_ts != AV_NOPTS_VALUE) { |
94 | /* check if this stream is the new finished head */ | ||
95 |
4/4✓ Branch 0 taken 10308 times.
✓ Branch 1 taken 2583 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10307 times.
|
23199 | if (sq->head_finished_stream < 0 || |
96 | 10308 | av_compare_ts(st->head_ts, st->tb, | |
97 | 10308 | sq->streams[sq->head_finished_stream].head_ts, | |
98 | 10308 | sq->streams[sq->head_finished_stream].tb) < 0) { | |
99 | 2584 | sq->head_finished_stream = stream_idx; | |
100 | } | ||
101 | |||
102 | /* mark as finished all streams that should no longer receive new frames, | ||
103 | * due to them being ahead of some finished stream */ | ||
104 | 12891 | st = &sq->streams[sq->head_finished_stream]; | |
105 |
2/2✓ Branch 0 taken 12917 times.
✓ Branch 1 taken 12891 times.
|
25808 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
106 | 12917 | SyncQueueStream *st1 = &sq->streams[i]; | |
107 |
5/6✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12891 times.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 5 times.
|
12943 | if (st != st1 && st1->head_ts != AV_NOPTS_VALUE && |
108 | 26 | av_compare_ts(st->head_ts, st->tb, st1->head_ts, st1->tb) <= 0) | |
109 | 21 | st1->finished = 1; | |
110 | } | ||
111 | } | ||
112 | |||
113 | /* mark the whole queue as finished if all streams are finished */ | ||
114 |
2/2✓ Branch 0 taken 12981 times.
✓ Branch 1 taken 12904 times.
|
25885 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
115 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12975 times.
|
12981 | if (!sq->streams[i].finished) |
116 | 6 | return; | |
117 | } | ||
118 | 12904 | sq->finished = 1; | |
119 | } | ||
120 | |||
121 | 10602 | static void queue_head_update(SyncQueue *sq) | |
122 | { | ||
123 |
2/2✓ Branch 0 taken 2627 times.
✓ Branch 1 taken 7975 times.
|
10602 | if (sq->head_stream < 0) { |
124 | /* wait for one timestamp in each stream before determining | ||
125 | * the queue head */ | ||
126 |
2/2✓ Branch 0 taken 2679 times.
✓ Branch 1 taken 2583 times.
|
5262 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
127 | 2679 | SyncQueueStream *st = &sq->streams[i]; | |
128 |
4/4✓ Branch 0 taken 2675 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 2631 times.
|
2679 | if (st->limiting && st->head_ts == AV_NOPTS_VALUE) |
129 | 44 | return; | |
130 | } | ||
131 | |||
132 | // placeholder value, correct one will be found below | ||
133 | 2583 | sq->head_stream = 0; | |
134 | } | ||
135 | |||
136 |
2/2✓ Branch 0 taken 10932 times.
✓ Branch 1 taken 10558 times.
|
21490 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
137 | 10932 | SyncQueueStream *st_head = &sq->streams[sq->head_stream]; | |
138 | 10932 | SyncQueueStream *st_other = &sq->streams[i]; | |
139 |
5/6✓ Branch 0 taken 10914 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 10914 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 91 times.
✓ Branch 5 taken 10823 times.
|
21846 | if (st_other->limiting && st_other->head_ts != AV_NOPTS_VALUE && |
140 | 10914 | av_compare_ts(st_other->head_ts, st_other->tb, | |
141 | st_head->head_ts, st_head->tb) < 0) | ||
142 | 91 | sq->head_stream = i; | |
143 | } | ||
144 | } | ||
145 | |||
146 | /* update this stream's head timestamp */ | ||
147 | 11216 | static void stream_update_ts(SyncQueue *sq, unsigned int stream_idx, int64_t ts) | |
148 | { | ||
149 | 11216 | SyncQueueStream *st = &sq->streams[stream_idx]; | |
150 | |||
151 |
1/2✓ Branch 0 taken 11216 times.
✗ Branch 1 not taken.
|
11216 | if (ts == AV_NOPTS_VALUE || |
152 |
4/4✓ Branch 0 taken 8625 times.
✓ Branch 1 taken 2591 times.
✓ Branch 2 taken 80 times.
✓ Branch 3 taken 8545 times.
|
11216 | (st->head_ts != AV_NOPTS_VALUE && st->head_ts >= ts)) |
153 | 80 | return; | |
154 | |||
155 | 11136 | st->head_ts = ts; | |
156 | |||
157 | /* if this stream is now ahead of some finished stream, then | ||
158 | * this stream is also finished */ | ||
159 |
4/4✓ Branch 0 taken 32 times.
✓ Branch 1 taken 11104 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 29 times.
|
11168 | if (sq->head_finished_stream >= 0 && |
160 | 32 | av_compare_ts(sq->streams[sq->head_finished_stream].head_ts, | |
161 | 32 | sq->streams[sq->head_finished_stream].tb, | |
162 | ts, st->tb) <= 0) | ||
163 | 3 | finish_stream(sq, stream_idx); | |
164 | |||
165 | /* update the overall head timestamp if it could have changed */ | ||
166 |
2/2✓ Branch 0 taken 11072 times.
✓ Branch 1 taken 64 times.
|
11136 | if (st->limiting && |
167 |
4/4✓ Branch 0 taken 8445 times.
✓ Branch 1 taken 2627 times.
✓ Branch 2 taken 7975 times.
✓ Branch 3 taken 470 times.
|
11072 | (sq->head_stream < 0 || sq->head_stream == stream_idx)) |
168 | 10602 | queue_head_update(sq); | |
169 | } | ||
170 | |||
171 | /* If the queue for the given stream (or all streams when stream_idx=-1) | ||
172 | * is overflowing, trigger a fake heartbeat on lagging streams. | ||
173 | * | ||
174 | * @return 1 if heartbeat triggered, 0 otherwise | ||
175 | */ | ||
176 | 8638 | static int overflow_heartbeat(SyncQueue *sq, int stream_idx) | |
177 | { | ||
178 | SyncQueueStream *st; | ||
179 | SyncQueueFrame frame; | ||
180 | 8638 | int64_t tail_ts = AV_NOPTS_VALUE; | |
181 | |||
182 | /* if no stream specified, pick the one that is most ahead */ | ||
183 |
2/2✓ Branch 0 taken 858 times.
✓ Branch 1 taken 7780 times.
|
8638 | if (stream_idx < 0) { |
184 | 858 | int64_t ts = AV_NOPTS_VALUE; | |
185 | |||
186 |
2/2✓ Branch 0 taken 1683 times.
✓ Branch 1 taken 858 times.
|
2541 | for (int i = 0; i < sq->nb_streams; i++) { |
187 | 1683 | st = &sq->streams[i]; | |
188 |
4/4✓ Branch 0 taken 1638 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 780 times.
✓ Branch 3 taken 858 times.
|
1683 | if (st->head_ts != AV_NOPTS_VALUE && |
189 |
2/2✓ Branch 0 taken 93 times.
✓ Branch 1 taken 687 times.
|
780 | (ts == AV_NOPTS_VALUE || |
190 | 780 | av_compare_ts(ts, sq->streams[stream_idx].tb, | |
191 | st->head_ts, st->tb) < 0)) { | ||
192 | 951 | ts = st->head_ts; | |
193 | 951 | stream_idx = i; | |
194 | } | ||
195 | } | ||
196 | /* no stream has a timestamp yet -> nothing to do */ | ||
197 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 858 times.
|
858 | if (stream_idx < 0) |
198 | ✗ | return 0; | |
199 | } | ||
200 | |||
201 | 8638 | st = &sq->streams[stream_idx]; | |
202 | |||
203 | /* get the chosen stream's tail timestamp */ | ||
204 |
4/4✓ Branch 0 taken 8638 times.
✓ Branch 1 taken 860 times.
✓ Branch 2 taken 860 times.
✓ Branch 3 taken 7778 times.
|
18136 | for (size_t i = 0; tail_ts == AV_NOPTS_VALUE && |
205 | 9498 | av_fifo_peek(st->fifo, &frame, 1, i) >= 0; i++) | |
206 | 860 | tail_ts = frame_ts(sq, frame); | |
207 | |||
208 | /* overflow triggers when the tail is over specified duration behind the head */ | ||
209 |
4/4✓ Branch 0 taken 860 times.
✓ Branch 1 taken 7778 times.
✓ Branch 2 taken 665 times.
✓ Branch 3 taken 195 times.
|
8638 | if (tail_ts == AV_NOPTS_VALUE || tail_ts >= st->head_ts || |
210 |
2/2✓ Branch 0 taken 571 times.
✓ Branch 1 taken 94 times.
|
665 | av_rescale_q(st->head_ts - tail_ts, st->tb, AV_TIME_BASE_Q) < sq->buf_size_us) |
211 | 8544 | return 0; | |
212 | |||
213 | /* signal a fake timestamp for all streams that prevent tail_ts from being output */ | ||
214 | 94 | tail_ts++; | |
215 |
2/2✓ Branch 0 taken 188 times.
✓ Branch 1 taken 94 times.
|
282 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
216 | 188 | SyncQueueStream *st1 = &sq->streams[i]; | |
217 | int64_t ts; | ||
218 | |||
219 |
3/4✓ Branch 0 taken 94 times.
✓ Branch 1 taken 94 times.
✓ Branch 2 taken 94 times.
✗ Branch 3 not taken.
|
188 | if (st == st1 || st1->finished || |
220 |
3/4✓ Branch 0 taken 93 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 93 times.
|
187 | (st1->head_ts != AV_NOPTS_VALUE && |
221 | 93 | av_compare_ts(tail_ts, st->tb, st1->head_ts, st1->tb) <= 0)) | |
222 | 94 | continue; | |
223 | |||
224 | 94 | ts = av_rescale_q(tail_ts, st->tb, st1->tb); | |
225 |
2/2✓ Branch 0 taken 93 times.
✓ Branch 1 taken 1 times.
|
94 | if (st1->head_ts != AV_NOPTS_VALUE) |
226 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 93 times.
|
93 | ts = FFMAX(st1->head_ts + 1, ts); |
227 | |||
228 | 94 | stream_update_ts(sq, i, ts); | |
229 | } | ||
230 | |||
231 | 94 | return 1; | |
232 | } | ||
233 | |||
234 | 21483 | int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame) | |
235 | { | ||
236 | SyncQueueStream *st; | ||
237 | SyncQueueFrame dst; | ||
238 | int64_t ts; | ||
239 | int ret; | ||
240 | |||
241 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21483 times.
|
21483 | av_assert0(stream_idx < sq->nb_streams); |
242 | 21483 | st = &sq->streams[stream_idx]; | |
243 | |||
244 |
2/4✓ Branch 0 taken 21483 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 21483 times.
|
21483 | av_assert0(st->tb.num > 0 && st->tb.den > 0); |
245 | |||
246 |
2/2✓ Branch 1 taken 10322 times.
✓ Branch 2 taken 11161 times.
|
21483 | if (frame_null(sq, frame)) { |
247 | 10322 | finish_stream(sq, stream_idx); | |
248 | 10322 | return 0; | |
249 | } | ||
250 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 11122 times.
|
11161 | if (st->finished) |
251 | 39 | return AVERROR_EOF; | |
252 | |||
253 | 11122 | ret = objpool_get(sq->pool, (void**)&dst); | |
254 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11122 times.
|
11122 | if (ret < 0) |
255 | ✗ | return ret; | |
256 | |||
257 | 11122 | frame_move(sq, dst, frame); | |
258 | |||
259 | 11122 | ts = frame_ts(sq, dst); | |
260 | |||
261 | 11122 | ret = av_fifo_write(st->fifo, &dst, 1); | |
262 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11122 times.
|
11122 | if (ret < 0) { |
263 | ✗ | frame_move(sq, frame, dst); | |
264 | ✗ | objpool_release(sq->pool, (void**)&dst); | |
265 | ✗ | return ret; | |
266 | } | ||
267 | |||
268 | 11122 | stream_update_ts(sq, stream_idx, ts); | |
269 | |||
270 | 11122 | st->frames_sent++; | |
271 |
2/2✓ Branch 0 taken 2577 times.
✓ Branch 1 taken 8545 times.
|
11122 | if (st->frames_sent >= st->frames_max) |
272 | 2577 | finish_stream(sq, stream_idx); | |
273 | |||
274 | 11122 | return 0; | |
275 | } | ||
276 | |||
277 | 25909 | static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, | |
278 | SyncQueueFrame frame) | ||
279 | { | ||
280 | 51818 | SyncQueueStream *st_head = sq->head_stream >= 0 ? | |
281 |
2/2✓ Branch 0 taken 25817 times.
✓ Branch 1 taken 92 times.
|
25909 | &sq->streams[sq->head_stream] : NULL; |
282 | SyncQueueStream *st; | ||
283 | |||
284 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25909 times.
|
25909 | av_assert0(stream_idx < sq->nb_streams); |
285 | 25909 | st = &sq->streams[stream_idx]; | |
286 | |||
287 |
2/2✓ Branch 1 taken 12102 times.
✓ Branch 2 taken 13807 times.
|
25909 | if (av_fifo_can_read(st->fifo)) { |
288 | SyncQueueFrame peek; | ||
289 | int64_t ts; | ||
290 | 12102 | int cmp = 1; | |
291 | |||
292 | 12102 | av_fifo_peek(st->fifo, &peek, 1, 0); | |
293 | 12102 | ts = frame_ts(sq, peek); | |
294 | |||
295 | /* check if this stream's tail timestamp does not overtake | ||
296 | * the overall queue head */ | ||
297 |
3/4✓ Branch 0 taken 12102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12055 times.
✓ Branch 3 taken 47 times.
|
12102 | if (ts != AV_NOPTS_VALUE && st_head) |
298 | 12055 | cmp = av_compare_ts(ts, st->tb, st_head->head_ts, st_head->tb); | |
299 | |||
300 | /* We can release frames that do not end after the queue head. | ||
301 | * Frames with no timestamps are just passed through with no conditions. | ||
302 | */ | ||
303 |
3/4✓ Branch 0 taken 1029 times.
✓ Branch 1 taken 11073 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1029 times.
|
12102 | if (cmp <= 0 || ts == AV_NOPTS_VALUE) { |
304 | 11073 | frame_move(sq, frame, peek); | |
305 | 11073 | objpool_release(sq->pool, (void**)&peek); | |
306 | 11073 | av_fifo_drain2(st->fifo, 1); | |
307 | 11073 | return 0; | |
308 | } | ||
309 | } | ||
310 | |||
311 |
4/4✓ Branch 0 taken 62 times.
✓ Branch 1 taken 9605 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 60 times.
|
9667 | return (sq->finished || (st->finished && !av_fifo_can_read(st->fifo))) ? |
312 |
2/2✓ Branch 0 taken 9667 times.
✓ Branch 1 taken 5169 times.
|
24503 | AVERROR_EOF : AVERROR(EAGAIN); |
313 | } | ||
314 | |||
315 | 24875 | static int receive_internal(SyncQueue *sq, int stream_idx, SyncQueueFrame frame) | |
316 | { | ||
317 | 24875 | int nb_eof = 0; | |
318 | int ret; | ||
319 | |||
320 | /* read a frame for a specific stream */ | ||
321 |
2/2✓ Branch 0 taken 23289 times.
✓ Branch 1 taken 1586 times.
|
24875 | if (stream_idx >= 0) { |
322 | 23289 | ret = receive_for_stream(sq, stream_idx, frame); | |
323 |
2/2✓ Branch 0 taken 12935 times.
✓ Branch 1 taken 10354 times.
|
23289 | return (ret < 0) ? ret : stream_idx; |
324 | } | ||
325 | |||
326 | /* read a frame for any stream with available output */ | ||
327 |
2/2✓ Branch 0 taken 2620 times.
✓ Branch 1 taken 867 times.
|
3487 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
328 | 2620 | ret = receive_for_stream(sq, i, frame); | |
329 |
4/4✓ Branch 0 taken 2604 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1885 times.
✓ Branch 3 taken 719 times.
|
2620 | if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) { |
330 | 1901 | nb_eof += (ret == AVERROR_EOF); | |
331 | 1901 | continue; | |
332 | } | ||
333 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 719 times.
|
719 | return (ret < 0) ? ret : i; |
334 | } | ||
335 | |||
336 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 858 times.
|
867 | return (nb_eof == sq->nb_streams) ? AVERROR_EOF : AVERROR(EAGAIN); |
337 | } | ||
338 | |||
339 | 24781 | int sq_receive(SyncQueue *sq, int stream_idx, SyncQueueFrame frame) | |
340 | { | ||
341 | 24781 | int ret = receive_internal(sq, stream_idx, frame); | |
342 | |||
343 | /* try again if the queue overflowed and triggered a fake heartbeat | ||
344 | * for lagging streams */ | ||
345 |
4/4✓ Branch 0 taken 8638 times.
✓ Branch 1 taken 16143 times.
✓ Branch 3 taken 94 times.
✓ Branch 4 taken 8544 times.
|
24781 | if (ret == AVERROR(EAGAIN) && overflow_heartbeat(sq, stream_idx)) |
346 | 94 | ret = receive_internal(sq, stream_idx, frame); | |
347 | |||
348 | 24781 | return ret; | |
349 | } | ||
350 | |||
351 | 2599 | int sq_add_stream(SyncQueue *sq, int limiting) | |
352 | { | ||
353 | SyncQueueStream *tmp, *st; | ||
354 | |||
355 | 2599 | tmp = av_realloc_array(sq->streams, sq->nb_streams + 1, sizeof(*sq->streams)); | |
356 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2599 times.
|
2599 | if (!tmp) |
357 | ✗ | return AVERROR(ENOMEM); | |
358 | 2599 | sq->streams = tmp; | |
359 | |||
360 | 2599 | st = &sq->streams[sq->nb_streams]; | |
361 | 2599 | memset(st, 0, sizeof(*st)); | |
362 | |||
363 | 2599 | st->fifo = av_fifo_alloc2(1, sizeof(SyncQueueFrame), AV_FIFO_FLAG_AUTO_GROW); | |
364 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2599 times.
|
2599 | if (!st->fifo) |
365 | ✗ | return AVERROR(ENOMEM); | |
366 | |||
367 | /* we set a valid default, so that a pathological stream that never | ||
368 | * receives even a real timebase (and no frames) won't stall all other | ||
369 | * streams forever; cf. overflow_heartbeat() */ | ||
370 | 2599 | st->tb = (AVRational){ 1, 1 }; | |
371 | 2599 | st->head_ts = AV_NOPTS_VALUE; | |
372 | 2599 | st->frames_max = UINT64_MAX; | |
373 | 2599 | st->limiting = limiting; | |
374 | |||
375 | 2599 | return sq->nb_streams++; | |
376 | } | ||
377 | |||
378 | 2599 | void sq_set_tb(SyncQueue *sq, unsigned int stream_idx, AVRational tb) | |
379 | { | ||
380 | SyncQueueStream *st; | ||
381 | |||
382 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2599 times.
|
2599 | av_assert0(stream_idx < sq->nb_streams); |
383 | 2599 | st = &sq->streams[stream_idx]; | |
384 | |||
385 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2599 times.
|
2599 | av_assert0(!av_fifo_can_read(st->fifo)); |
386 | |||
387 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2599 times.
|
2599 | if (st->head_ts != AV_NOPTS_VALUE) |
388 | ✗ | st->head_ts = av_rescale_q(st->head_ts, st->tb, tb); | |
389 | |||
390 | 2599 | st->tb = tb; | |
391 | 2599 | } | |
392 | |||
393 | 2587 | void sq_limit_frames(SyncQueue *sq, unsigned int stream_idx, uint64_t frames) | |
394 | { | ||
395 | SyncQueueStream *st; | ||
396 | |||
397 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2587 times.
|
2587 | av_assert0(stream_idx < sq->nb_streams); |
398 | 2587 | st = &sq->streams[stream_idx]; | |
399 | |||
400 | 2587 | st->frames_max = frames; | |
401 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2579 times.
|
2587 | if (st->frames_sent >= st->frames_max) |
402 | 8 | finish_stream(sq, stream_idx); | |
403 | 2587 | } | |
404 | |||
405 | 2584 | SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us) | |
406 | { | ||
407 | 2584 | SyncQueue *sq = av_mallocz(sizeof(*sq)); | |
408 | |||
409 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2584 times.
|
2584 | if (!sq) |
410 | ✗ | return NULL; | |
411 | |||
412 | 2584 | sq->type = type; | |
413 | 2584 | sq->buf_size_us = buf_size_us; | |
414 | |||
415 | 2584 | sq->head_stream = -1; | |
416 | 2584 | sq->head_finished_stream = -1; | |
417 | |||
418 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2576 times.
|
2584 | sq->pool = (type == SYNC_QUEUE_PACKETS) ? objpool_alloc_packets() : |
419 | 2576 | objpool_alloc_frames(); | |
420 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2584 times.
|
2584 | if (!sq->pool) { |
421 | ✗ | av_freep(&sq); | |
422 | ✗ | return NULL; | |
423 | } | ||
424 | |||
425 | 2584 | return sq; | |
426 | } | ||
427 | |||
428 | 12924 | void sq_free(SyncQueue **psq) | |
429 | { | ||
430 | 12924 | SyncQueue *sq = *psq; | |
431 | |||
432 |
2/2✓ Branch 0 taken 10340 times.
✓ Branch 1 taken 2584 times.
|
12924 | if (!sq) |
433 | 10340 | return; | |
434 | |||
435 |
2/2✓ Branch 0 taken 2599 times.
✓ Branch 1 taken 2584 times.
|
5183 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
436 | SyncQueueFrame frame; | ||
437 |
2/2✓ Branch 1 taken 49 times.
✓ Branch 2 taken 2599 times.
|
2648 | while (av_fifo_read(sq->streams[i].fifo, &frame, 1) >= 0) |
438 | 49 | objpool_release(sq->pool, (void**)&frame); | |
439 | |||
440 | 2599 | av_fifo_freep2(&sq->streams[i].fifo); | |
441 | } | ||
442 | |||
443 | 2584 | av_freep(&sq->streams); | |
444 | |||
445 | 2584 | objpool_free(&sq->pool); | |
446 | |||
447 | 2584 | av_freep(psq); | |
448 | } | ||
449 |