FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/fftools/sync_queue.c
Date: 2022-10-02 18:56:10
Exec Total Coverage
Lines: 191 202 94.6%
Branches: 150 174 86.2%

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 22191 static void frame_move(const SyncQueue *sq, SyncQueueFrame dst,
67 SyncQueueFrame src)
68 {
69
2/2
✓ Branch 0 taken 1486 times.
✓ Branch 1 taken 20705 times.
22191 if (sq->type == SYNC_QUEUE_PACKETS)
70 1486 av_packet_move_ref(dst.p, src.p);
71 else
72 20705 av_frame_move_ref(dst.f, src.f);
73 22191 }
74
75 24080 static int64_t frame_ts(const SyncQueue *sq, SyncQueueFrame frame)
76 {
77 24080 return (sq->type == SYNC_QUEUE_PACKETS) ?
78
2/2
✓ Branch 0 taken 3271 times.
✓ Branch 1 taken 20809 times.
44889 frame.p->pts + frame.p->duration :
79 20809 frame.f->pts + frame.f->duration;
80 }
81
82 21468 static int frame_null(const SyncQueue *sq, SyncQueueFrame frame)
83 {
84
2/2
✓ Branch 0 taken 806 times.
✓ Branch 1 taken 20662 times.
21468 return (sq->type == SYNC_QUEUE_PACKETS) ? (frame.p == NULL) : (frame.f == NULL);
85 }
86
87 12900 static void finish_stream(SyncQueue *sq, unsigned int stream_idx)
88 {
89 12900 SyncQueueStream *st = &sq->streams[stream_idx];
90
91 12900 st->finished = 1;
92
93
4/4
✓ Branch 0 taken 12889 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 12881 times.
✓ Branch 3 taken 8 times.
12900 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 10300 times.
✓ Branch 1 taken 2581 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10299 times.
23181 if (sq->head_finished_stream < 0 ||
96 10300 av_compare_ts(st->head_ts, st->tb,
97 10300 sq->streams[sq->head_finished_stream].head_ts,
98 10300 sq->streams[sq->head_finished_stream].tb) < 0) {
99 2582 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 12881 st = &sq->streams[sq->head_finished_stream];
105
2/2
✓ Branch 0 taken 12907 times.
✓ Branch 1 taken 12881 times.
25788 for (unsigned int i = 0; i < sq->nb_streams; i++) {
106 12907 SyncQueueStream *st1 = &sq->streams[i];
107
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12881 times.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 5 times.
12933 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 12971 times.
✓ Branch 1 taken 12894 times.
25865 for (unsigned int i = 0; i < sq->nb_streams; i++) {
115
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12965 times.
12971 if (!sq->streams[i].finished)
116 6 return;
117 }
118 12894 sq->finished = 1;
119 }
120
121 10600 static void queue_head_update(SyncQueue *sq)
122 {
123
2/2
✓ Branch 0 taken 2625 times.
✓ Branch 1 taken 7975 times.
10600 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 2677 times.
✓ Branch 1 taken 2581 times.
5258 for (unsigned int i = 0; i < sq->nb_streams; i++) {
127 2677 SyncQueueStream *st = &sq->streams[i];
128
4/4
✓ Branch 0 taken 2673 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 2629 times.
2677 if (st->limiting && st->head_ts == AV_NOPTS_VALUE)
129 44 return;
130 }
131
132 // placeholder value, correct one will be found below
133 2581 sq->head_stream = 0;
134 }
135
136
2/2
✓ Branch 0 taken 10930 times.
✓ Branch 1 taken 10556 times.
21486 for (unsigned int i = 0; i < sq->nb_streams; i++) {
137 10930 SyncQueueStream *st_head = &sq->streams[sq->head_stream];
138 10930 SyncQueueStream *st_other = &sq->streams[i];
139
5/6
✓ Branch 0 taken 10912 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 10912 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 91 times.
✓ Branch 5 taken 10821 times.
21842 if (st_other->limiting && st_other->head_ts != AV_NOPTS_VALUE &&
140 10912 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 11214 static void stream_update_ts(SyncQueue *sq, unsigned int stream_idx, int64_t ts)
148 {
149 11214 SyncQueueStream *st = &sq->streams[stream_idx];
150
151
1/2
✓ Branch 0 taken 11214 times.
✗ Branch 1 not taken.
11214 if (ts == AV_NOPTS_VALUE ||
152
4/4
✓ Branch 0 taken 8625 times.
✓ Branch 1 taken 2589 times.
✓ Branch 2 taken 80 times.
✓ Branch 3 taken 8545 times.
11214 (st->head_ts != AV_NOPTS_VALUE && st->head_ts >= ts))
153 80 return;
154
155 11134 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 11102 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 29 times.
11166 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 11070 times.
✓ Branch 1 taken 64 times.
11134 if (st->limiting &&
167
4/4
✓ Branch 0 taken 8445 times.
✓ Branch 1 taken 2625 times.
✓ Branch 2 taken 7975 times.
✓ Branch 3 taken 470 times.
11070 (sq->head_stream < 0 || sq->head_stream == stream_idx))
168 10600 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 21468 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 21468 times.
21468 av_assert0(stream_idx < sq->nb_streams);
242 21468 st = &sq->streams[stream_idx];
243
244
2/4
✓ Branch 0 taken 21468 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 21468 times.
21468 av_assert0(st->tb.num > 0 && st->tb.den > 0);
245
246
2/2
✓ Branch 1 taken 10314 times.
✓ Branch 2 taken 11154 times.
21468 if (frame_null(sq, frame)) {
247 10314 finish_stream(sq, stream_idx);
248 10314 return 0;
249 }
250
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 11120 times.
11154 if (st->finished)
251 34 return AVERROR_EOF;
252
253 11120 ret = objpool_get(sq->pool, (void**)&dst);
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11120 times.
11120 if (ret < 0)
255 return ret;
256
257 11120 frame_move(sq, dst, frame);
258
259 11120 ts = frame_ts(sq, dst);
260
261 11120 ret = av_fifo_write(st->fifo, &dst, 1);
262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11120 times.
11120 if (ret < 0) {
263 frame_move(sq, frame, dst);
264 objpool_release(sq->pool, (void**)&dst);
265 return ret;
266 }
267
268 11120 stream_update_ts(sq, stream_idx, ts);
269
270 11120 st->frames_sent++;
271
2/2
✓ Branch 0 taken 2575 times.
✓ Branch 1 taken 8545 times.
11120 if (st->frames_sent >= st->frames_max)
272 2575 finish_stream(sq, stream_idx);
273
274 11120 return 0;
275 }
276
277 25903 static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx,
278 SyncQueueFrame frame)
279 {
280 51806 SyncQueueStream *st_head = sq->head_stream >= 0 ?
281
2/2
✓ Branch 0 taken 25811 times.
✓ Branch 1 taken 92 times.
25903 &sq->streams[sq->head_stream] : NULL;
282 SyncQueueStream *st;
283
284
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25903 times.
25903 av_assert0(stream_idx < sq->nb_streams);
285 25903 st = &sq->streams[stream_idx];
286
287
2/2
✓ Branch 1 taken 12100 times.
✓ Branch 2 taken 13803 times.
25903 if (av_fifo_can_read(st->fifo)) {
288 SyncQueueFrame peek;
289 int64_t ts;
290 12100 int cmp = 1;
291
292 12100 av_fifo_peek(st->fifo, &peek, 1, 0);
293 12100 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 12100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12053 times.
✓ Branch 3 taken 47 times.
12100 if (ts != AV_NOPTS_VALUE && st_head)
298 12053 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 11071 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1029 times.
12100 if (cmp <= 0 || ts == AV_NOPTS_VALUE) {
304 11071 frame_move(sq, frame, peek);
305 11071 objpool_release(sq->pool, (void**)&peek);
306 11071 av_fifo_drain2(st->fifo, 1);
307 11071 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 5165 times.
24499 AVERROR_EOF : AVERROR(EAGAIN);
313 }
314
315 24869 static int receive_internal(SyncQueue *sq, int stream_idx, SyncQueueFrame frame)
316 {
317 24869 int nb_eof = 0;
318 int ret;
319
320 /* read a frame for a specific stream */
321
2/2
✓ Branch 0 taken 23283 times.
✓ Branch 1 taken 1586 times.
24869 if (stream_idx >= 0) {
322 23283 ret = receive_for_stream(sq, stream_idx, frame);
323
2/2
✓ Branch 0 taken 12931 times.
✓ Branch 1 taken 10352 times.
23283 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 24775 int sq_receive(SyncQueue *sq, int stream_idx, SyncQueueFrame frame)
340 {
341 24775 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 16137 times.
✓ Branch 3 taken 94 times.
✓ Branch 4 taken 8544 times.
24775 if (ret == AVERROR(EAGAIN) && overflow_heartbeat(sq, stream_idx))
346 94 ret = receive_internal(sq, stream_idx, frame);
347
348 24775 return ret;
349 }
350
351 2597 int sq_add_stream(SyncQueue *sq, int limiting)
352 {
353 SyncQueueStream *tmp, *st;
354
355 2597 tmp = av_realloc_array(sq->streams, sq->nb_streams + 1, sizeof(*sq->streams));
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2597 times.
2597 if (!tmp)
357 return AVERROR(ENOMEM);
358 2597 sq->streams = tmp;
359
360 2597 st = &sq->streams[sq->nb_streams];
361 2597 memset(st, 0, sizeof(*st));
362
363 2597 st->fifo = av_fifo_alloc2(1, sizeof(SyncQueueFrame), AV_FIFO_FLAG_AUTO_GROW);
364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2597 times.
2597 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 2597 st->tb = (AVRational){ 1, 1 };
371 2597 st->head_ts = AV_NOPTS_VALUE;
372 2597 st->frames_max = UINT64_MAX;
373 2597 st->limiting = limiting;
374
375 2597 return sq->nb_streams++;
376 }
377
378 2597 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 2597 times.
2597 av_assert0(stream_idx < sq->nb_streams);
383 2597 st = &sq->streams[stream_idx];
384
385
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2597 times.
2597 av_assert0(!av_fifo_can_read(st->fifo));
386
387
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2597 times.
2597 if (st->head_ts != AV_NOPTS_VALUE)
388 st->head_ts = av_rescale_q(st->head_ts, st->tb, tb);
389
390 2597 st->tb = tb;
391 2597 }
392
393 2585 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 2585 times.
2585 av_assert0(stream_idx < sq->nb_streams);
398 2585 st = &sq->streams[stream_idx];
399
400 2585 st->frames_max = frames;
401
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2577 times.
2585 if (st->frames_sent >= st->frames_max)
402 8 finish_stream(sq, stream_idx);
403 2585 }
404
405 2582 SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us)
406 {
407 2582 SyncQueue *sq = av_mallocz(sizeof(*sq));
408
409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2582 times.
2582 if (!sq)
410 return NULL;
411
412 2582 sq->type = type;
413 2582 sq->buf_size_us = buf_size_us;
414
415 2582 sq->head_stream = -1;
416 2582 sq->head_finished_stream = -1;
417
418
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2574 times.
2582 sq->pool = (type == SYNC_QUEUE_PACKETS) ? objpool_alloc_packets() :
419 2574 objpool_alloc_frames();
420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2582 times.
2582 if (!sq->pool) {
421 av_freep(&sq);
422 return NULL;
423 }
424
425 2582 return sq;
426 }
427
428 12844 void sq_free(SyncQueue **psq)
429 {
430 12844 SyncQueue *sq = *psq;
431
432
2/2
✓ Branch 0 taken 10262 times.
✓ Branch 1 taken 2582 times.
12844 if (!sq)
433 10262 return;
434
435
2/2
✓ Branch 0 taken 2597 times.
✓ Branch 1 taken 2582 times.
5179 for (unsigned int i = 0; i < sq->nb_streams; i++) {
436 SyncQueueFrame frame;
437
2/2
✓ Branch 1 taken 49 times.
✓ Branch 2 taken 2597 times.
2646 while (av_fifo_read(sq->streams[i].fifo, &frame, 1) >= 0)
438 49 objpool_release(sq->pool, (void**)&frame);
439
440 2597 av_fifo_freep2(&sq->streams[i].fifo);
441 }
442
443 2582 av_freep(&sq->streams);
444
445 2582 objpool_free(&sq->pool);
446
447 2582 av_freep(psq);
448 }
449