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/channel_layout.h" | ||
24 | #include "libavutil/cpu.h" | ||
25 | #include "libavutil/error.h" | ||
26 | #include "libavutil/fifo.h" | ||
27 | #include "libavutil/mathematics.h" | ||
28 | #include "libavutil/mem.h" | ||
29 | #include "libavutil/samplefmt.h" | ||
30 | #include "libavutil/timestamp.h" | ||
31 | |||
32 | #include "objpool.h" | ||
33 | #include "sync_queue.h" | ||
34 | |||
35 | /* | ||
36 | * How this works: | ||
37 | * -------------- | ||
38 | * time: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 | ||
39 | * ------------------------------------------------------------------- | ||
40 | * | | | | | | | | | | | | | | | ||
41 | * | ┌───┐┌────────┐┌───┐┌─────────────┐ | ||
42 | * stream 0| │d=1││ d=2 ││d=1││ d=3 │ | ||
43 | * | └───┘└────────┘└───┘└─────────────┘ | ||
44 | * ┌───┐ ┌───────────────────────┐ | ||
45 | * stream 1│d=1│ │ d=5 │ | ||
46 | * └───┘ └───────────────────────┘ | ||
47 | * | ┌───┐┌───┐┌───┐┌───┐ | ||
48 | * stream 2| │d=1││d=1││d=1││d=1│ <- stream 2 is the head stream of the queue | ||
49 | * | └───┘└───┘└───┘└───┘ | ||
50 | * ^ ^ | ||
51 | * [stream 2 tail] [stream 2 head] | ||
52 | * | ||
53 | * We have N streams (N=3 in the diagram), each stream is a FIFO. The *tail* of | ||
54 | * each FIFO is the frame with smallest end time, the *head* is the frame with | ||
55 | * the largest end time. Frames submitted to the queue with sq_send() are placed | ||
56 | * after the head, frames returned to the caller with sq_receive() are taken | ||
57 | * from the tail. | ||
58 | * | ||
59 | * The head stream of the whole queue (SyncQueue.head_stream) is the limiting | ||
60 | * stream with the *smallest* head timestamp, i.e. the stream whose source lags | ||
61 | * furthest behind all other streams. It determines which frames can be output | ||
62 | * from the queue. | ||
63 | * | ||
64 | * In the diagram, the head stream is 2, because it head time is t=5, while | ||
65 | * streams 0 and 1 end at t=8 and t=9 respectively. All frames that _end_ at | ||
66 | * or before t=5 can be output, i.e. the first 3 frames from stream 0, first | ||
67 | * frame from stream 1, and all 4 frames from stream 2. | ||
68 | */ | ||
69 | |||
70 | typedef struct SyncQueueStream { | ||
71 | AVFifo *fifo; | ||
72 | AVRational tb; | ||
73 | |||
74 | /* number of audio samples in fifo */ | ||
75 | uint64_t samples_queued; | ||
76 | /* stream head: largest timestamp seen */ | ||
77 | int64_t head_ts; | ||
78 | int limiting; | ||
79 | /* no more frames will be sent for this stream */ | ||
80 | int finished; | ||
81 | |||
82 | uint64_t frames_sent; | ||
83 | uint64_t samples_sent; | ||
84 | uint64_t frames_max; | ||
85 | int frame_samples; | ||
86 | } SyncQueueStream; | ||
87 | |||
88 | struct SyncQueue { | ||
89 | enum SyncQueueType type; | ||
90 | |||
91 | void *logctx; | ||
92 | |||
93 | /* no more frames will be sent for any stream */ | ||
94 | int finished; | ||
95 | /* sync head: the stream with the _smallest_ head timestamp | ||
96 | * this stream determines which frames can be output */ | ||
97 | int head_stream; | ||
98 | /* the finished stream with the smallest finish timestamp or -1 */ | ||
99 | int head_finished_stream; | ||
100 | |||
101 | // maximum buffering duration in microseconds | ||
102 | int64_t buf_size_us; | ||
103 | |||
104 | SyncQueueStream *streams; | ||
105 | unsigned int nb_streams; | ||
106 | |||
107 | // pool of preallocated frames to avoid constant allocations | ||
108 | ObjPool *pool; | ||
109 | |||
110 | int have_limiting; | ||
111 | |||
112 | uintptr_t align_mask; | ||
113 | }; | ||
114 | |||
115 | 50599 | static void frame_move(const SyncQueue *sq, SyncQueueFrame dst, | |
116 | SyncQueueFrame src) | ||
117 | { | ||
118 |
2/2✓ Branch 0 taken 1638 times.
✓ Branch 1 taken 48961 times.
|
50599 | if (sq->type == SYNC_QUEUE_PACKETS) |
119 | 1638 | av_packet_move_ref(dst.p, src.p); | |
120 | else | ||
121 | 48961 | av_frame_move_ref(dst.f, src.f); | |
122 | 50599 | } | |
123 | |||
124 | /** | ||
125 | * Compute the end timestamp of a frame. If nb_samples is provided, consider | ||
126 | * the frame to have this number of audio samples, otherwise use frame duration. | ||
127 | */ | ||
128 | 217306 | static int64_t frame_end(const SyncQueue *sq, SyncQueueFrame frame, int nb_samples) | |
129 | { | ||
130 |
2/2✓ Branch 0 taken 70778 times.
✓ Branch 1 taken 146528 times.
|
217306 | if (nb_samples) { |
131 | 70778 | int64_t d = av_rescale_q(nb_samples, (AVRational){ 1, frame.f->sample_rate}, | |
132 | 70778 | frame.f->time_base); | |
133 | 70778 | return frame.f->pts + d; | |
134 | } | ||
135 | |||
136 | 146528 | return (sq->type == SYNC_QUEUE_PACKETS) ? | |
137 |
2/2✓ Branch 0 taken 4205 times.
✓ Branch 1 taken 142323 times.
|
288851 | frame.p->pts + frame.p->duration : |
138 | 142323 | frame.f->pts + frame.f->duration; | |
139 | } | ||
140 | |||
141 | 68145 | static int frame_samples(const SyncQueue *sq, SyncQueueFrame frame) | |
142 | { | ||
143 |
2/2✓ Branch 0 taken 65712 times.
✓ Branch 1 taken 2433 times.
|
68145 | return (sq->type == SYNC_QUEUE_PACKETS) ? 0 : frame.f->nb_samples; |
144 | } | ||
145 | |||
146 | 36389 | static int frame_null(const SyncQueue *sq, SyncQueueFrame frame) | |
147 | { | ||
148 |
2/2✓ Branch 0 taken 878 times.
✓ Branch 1 taken 35511 times.
|
36389 | return (sq->type == SYNC_QUEUE_PACKETS) ? (frame.p == NULL) : (frame.f == NULL); |
149 | } | ||
150 | |||
151 | 33053 | static void tb_update(const SyncQueue *sq, SyncQueueStream *st, | |
152 | const SyncQueueFrame frame) | ||
153 | { | ||
154 | 66106 | AVRational tb = (sq->type == SYNC_QUEUE_PACKETS) ? | |
155 |
2/2✓ Branch 0 taken 843 times.
✓ Branch 1 taken 32210 times.
|
33053 | frame.p->time_base : frame.f->time_base; |
156 | |||
157 |
2/4✓ Branch 0 taken 33053 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33053 times.
|
33053 | av_assert0(tb.num > 0 && tb.den > 0); |
158 | |||
159 |
4/4✓ Branch 0 taken 32937 times.
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 29910 times.
✓ Branch 3 taken 3027 times.
|
33053 | if (tb.num == st->tb.num && tb.den == st->tb.den) |
160 | 29910 | return; | |
161 | |||
162 | // timebase should not change after the first frame | ||
163 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3143 times.
|
3143 | av_assert0(!av_fifo_can_read(st->fifo)); |
164 | |||
165 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3142 times.
|
3143 | if (st->head_ts != AV_NOPTS_VALUE) |
166 | 1 | st->head_ts = av_rescale_q(st->head_ts, st->tb, tb); | |
167 | |||
168 | 3143 | st->tb = tb; | |
169 | } | ||
170 | |||
171 | 6285 | static void finish_stream(SyncQueue *sq, unsigned int stream_idx) | |
172 | { | ||
173 | 6285 | SyncQueueStream *st = &sq->streams[stream_idx]; | |
174 | |||
175 |
2/2✓ Branch 0 taken 3164 times.
✓ Branch 1 taken 3121 times.
|
6285 | if (!st->finished) |
176 | 3164 | av_log(sq->logctx, AV_LOG_DEBUG, | |
177 | "sq: finish %u; head ts %s\n", stream_idx, | ||
178 | 3164 | av_ts2timestr(st->head_ts, &st->tb)); | |
179 | |||
180 | 6285 | st->finished = 1; | |
181 | |||
182 |
4/4✓ Branch 0 taken 5927 times.
✓ Branch 1 taken 358 times.
✓ Branch 2 taken 5904 times.
✓ Branch 3 taken 23 times.
|
6285 | if (st->limiting && st->head_ts != AV_NOPTS_VALUE) { |
183 | /* check if this stream is the new finished head */ | ||
184 |
4/4✓ Branch 0 taken 2950 times.
✓ Branch 1 taken 2954 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2949 times.
|
8854 | if (sq->head_finished_stream < 0 || |
185 | 2950 | av_compare_ts(st->head_ts, st->tb, | |
186 | 2950 | sq->streams[sq->head_finished_stream].head_ts, | |
187 | 2950 | sq->streams[sq->head_finished_stream].tb) < 0) { | |
188 | 2955 | sq->head_finished_stream = stream_idx; | |
189 | } | ||
190 | |||
191 | /* mark as finished all streams that should no longer receive new frames, | ||
192 | * due to them being ahead of some finished stream */ | ||
193 | 5904 | st = &sq->streams[sq->head_finished_stream]; | |
194 |
2/2✓ Branch 0 taken 5920 times.
✓ Branch 1 taken 5904 times.
|
11824 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
195 | 5920 | SyncQueueStream *st1 = &sq->streams[i]; | |
196 |
5/6✓ Branch 0 taken 16 times.
✓ Branch 1 taken 5904 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 5 times.
|
5936 | if (st != st1 && st1->head_ts != AV_NOPTS_VALUE && |
197 | 16 | av_compare_ts(st->head_ts, st->tb, st1->head_ts, st1->tb) <= 0) { | |
198 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
|
11 | if (!st1->finished) |
199 | 2 | av_log(sq->logctx, AV_LOG_DEBUG, | |
200 | "sq: finish secondary %u; head ts %s\n", i, | ||
201 | 2 | av_ts2timestr(st1->head_ts, &st1->tb)); | |
202 | |||
203 | 11 | st1->finished = 1; | |
204 | } | ||
205 | } | ||
206 | } | ||
207 | |||
208 | /* mark the whole queue as finished if all streams are finished */ | ||
209 |
2/2✓ Branch 0 taken 6783 times.
✓ Branch 1 taken 6198 times.
|
12981 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
210 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 6696 times.
|
6783 | if (!sq->streams[i].finished) |
211 | 87 | return; | |
212 | } | ||
213 | 6198 | sq->finished = 1; | |
214 | |||
215 | 6198 | av_log(sq->logctx, AV_LOG_DEBUG, "sq: finish queue\n"); | |
216 | } | ||
217 | |||
218 | 12599 | static void queue_head_update(SyncQueue *sq) | |
219 | { | ||
220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12599 times.
|
12599 | av_assert0(sq->have_limiting); |
221 | |||
222 |
2/2✓ Branch 0 taken 3038 times.
✓ Branch 1 taken 9561 times.
|
12599 | if (sq->head_stream < 0) { |
223 | 3038 | unsigned first_limiting = UINT_MAX; | |
224 | |||
225 | /* wait for one timestamp in each stream before determining | ||
226 | * the queue head */ | ||
227 |
2/2✓ Branch 0 taken 3130 times.
✓ Branch 1 taken 2954 times.
|
6084 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
228 | 3130 | SyncQueueStream *st = &sq->streams[i]; | |
229 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3126 times.
|
3130 | if (!st->limiting) |
230 | 4 | continue; | |
231 |
2/2✓ Branch 0 taken 84 times.
✓ Branch 1 taken 3042 times.
|
3126 | if (st->head_ts == AV_NOPTS_VALUE) |
232 | 84 | return; | |
233 |
2/2✓ Branch 0 taken 3038 times.
✓ Branch 1 taken 4 times.
|
3042 | if (first_limiting == UINT_MAX) |
234 | 3038 | first_limiting = i; | |
235 | } | ||
236 | |||
237 | // placeholder value, correct one will be found below | ||
238 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2954 times.
|
2954 | av_assert0(first_limiting < UINT_MAX); |
239 | 2954 | sq->head_stream = first_limiting; | |
240 | } | ||
241 | |||
242 |
2/2✓ Branch 0 taken 12891 times.
✓ Branch 1 taken 12515 times.
|
25406 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
243 | 12891 | SyncQueueStream *st_head = &sq->streams[sq->head_stream]; | |
244 | 12891 | SyncQueueStream *st_other = &sq->streams[i]; | |
245 |
5/6✓ Branch 0 taken 12857 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 12857 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 12840 times.
|
25748 | if (st_other->limiting && st_other->head_ts != AV_NOPTS_VALUE && |
246 | 12857 | av_compare_ts(st_other->head_ts, st_other->tb, | |
247 | st_head->head_ts, st_head->tb) < 0) | ||
248 | 17 | sq->head_stream = i; | |
249 | } | ||
250 | } | ||
251 | |||
252 | /* update this stream's head timestamp */ | ||
253 | 33147 | static void stream_update_ts(SyncQueue *sq, unsigned int stream_idx, int64_t ts) | |
254 | { | ||
255 | 33147 | SyncQueueStream *st = &sq->streams[stream_idx]; | |
256 | |||
257 |
2/2✓ Branch 0 taken 33144 times.
✓ Branch 1 taken 3 times.
|
33147 | if (ts == AV_NOPTS_VALUE || |
258 |
4/4✓ Branch 0 taken 30004 times.
✓ Branch 1 taken 3140 times.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 29949 times.
|
33144 | (st->head_ts != AV_NOPTS_VALUE && st->head_ts >= ts)) |
259 | 58 | return; | |
260 | |||
261 | 33089 | st->head_ts = ts; | |
262 | |||
263 | /* if this stream is now ahead of some finished stream, then | ||
264 | * this stream is also finished */ | ||
265 |
4/4✓ Branch 0 taken 115 times.
✓ Branch 1 taken 32974 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 112 times.
|
33204 | if (sq->head_finished_stream >= 0 && |
266 | 115 | av_compare_ts(sq->streams[sq->head_finished_stream].head_ts, | |
267 | 115 | sq->streams[sq->head_finished_stream].tb, | |
268 | ts, st->tb) <= 0) | ||
269 | 3 | finish_stream(sq, stream_idx); | |
270 | |||
271 | /* update the overall head timestamp if it could have changed */ | ||
272 |
2/2✓ Branch 0 taken 13065 times.
✓ Branch 1 taken 20024 times.
|
33089 | if (st->limiting && |
273 |
4/4✓ Branch 0 taken 10027 times.
✓ Branch 1 taken 3038 times.
✓ Branch 2 taken 9561 times.
✓ Branch 3 taken 466 times.
|
13065 | (sq->head_stream < 0 || sq->head_stream == stream_idx)) |
274 | 12599 | queue_head_update(sq); | |
275 | } | ||
276 | |||
277 | /* If the queue for the given stream (or all streams when stream_idx=-1) | ||
278 | * is overflowing, trigger a fake heartbeat on lagging streams. | ||
279 | * | ||
280 | * @return 1 if heartbeat triggered, 0 otherwise | ||
281 | */ | ||
282 | 30285 | static int overflow_heartbeat(SyncQueue *sq, int stream_idx) | |
283 | { | ||
284 | SyncQueueStream *st; | ||
285 | SyncQueueFrame frame; | ||
286 | 30285 | int64_t tail_ts = AV_NOPTS_VALUE; | |
287 | |||
288 | /* if no stream specified, pick the one that is most ahead */ | ||
289 |
1/2✓ Branch 0 taken 30285 times.
✗ Branch 1 not taken.
|
30285 | if (stream_idx < 0) { |
290 | 30285 | int64_t ts = AV_NOPTS_VALUE; | |
291 | |||
292 |
2/2✓ Branch 0 taken 35183 times.
✓ Branch 1 taken 30285 times.
|
65468 | for (int i = 0; i < sq->nb_streams; i++) { |
293 | 35183 | st = &sq->streams[i]; | |
294 |
4/4✓ Branch 0 taken 34641 times.
✓ Branch 1 taken 542 times.
✓ Branch 2 taken 4359 times.
✓ Branch 3 taken 30282 times.
|
35183 | if (st->head_ts != AV_NOPTS_VALUE && |
295 |
2/2✓ Branch 0 taken 637 times.
✓ Branch 1 taken 3722 times.
|
4359 | (ts == AV_NOPTS_VALUE || |
296 | 4359 | av_compare_ts(ts, sq->streams[stream_idx].tb, | |
297 | st->head_ts, st->tb) < 0)) { | ||
298 | 30919 | ts = st->head_ts; | |
299 | 30919 | stream_idx = i; | |
300 | } | ||
301 | } | ||
302 | /* no stream has a timestamp yet -> nothing to do */ | ||
303 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30282 times.
|
30285 | if (stream_idx < 0) |
304 | 3 | return 0; | |
305 | } | ||
306 | |||
307 | 30282 | st = &sq->streams[stream_idx]; | |
308 | |||
309 | /* get the chosen stream's tail timestamp */ | ||
310 |
4/4✓ Branch 0 taken 30282 times.
✓ Branch 1 taken 15321 times.
✓ Branch 2 taken 15321 times.
✓ Branch 3 taken 14961 times.
|
75885 | for (size_t i = 0; tail_ts == AV_NOPTS_VALUE && |
311 | 45603 | av_fifo_peek(st->fifo, &frame, 1, i) >= 0; i++) | |
312 | 15321 | tail_ts = frame_end(sq, frame, 0); | |
313 | |||
314 | /* overflow triggers when the tail is over specified duration behind the head */ | ||
315 |
4/4✓ Branch 0 taken 15321 times.
✓ Branch 1 taken 14961 times.
✓ Branch 2 taken 1374 times.
✓ Branch 3 taken 13947 times.
|
30282 | if (tail_ts == AV_NOPTS_VALUE || tail_ts >= st->head_ts || |
316 |
2/2✓ Branch 0 taken 1280 times.
✓ Branch 1 taken 94 times.
|
1374 | av_rescale_q(st->head_ts - tail_ts, st->tb, AV_TIME_BASE_Q) < sq->buf_size_us) |
317 | 30188 | return 0; | |
318 | |||
319 | /* signal a fake timestamp for all streams that prevent tail_ts from being output */ | ||
320 | 94 | tail_ts++; | |
321 |
2/2✓ Branch 0 taken 188 times.
✓ Branch 1 taken 94 times.
|
282 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
322 | 188 | const SyncQueueStream *st1 = &sq->streams[i]; | |
323 | int64_t ts; | ||
324 | |||
325 |
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 || |
326 |
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 && |
327 | 93 | av_compare_ts(tail_ts, st->tb, st1->head_ts, st1->tb) <= 0)) | |
328 | 94 | continue; | |
329 | |||
330 | 94 | ts = av_rescale_q(tail_ts, st->tb, st1->tb); | |
331 |
2/2✓ Branch 0 taken 93 times.
✓ Branch 1 taken 1 times.
|
94 | if (st1->head_ts != AV_NOPTS_VALUE) |
332 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 93 times.
|
93 | ts = FFMAX(st1->head_ts + 1, ts); |
333 | |||
334 | 94 | av_log(sq->logctx, AV_LOG_DEBUG, "sq: %u overflow heardbeat %s -> %s\n", | |
335 | 94 | i, av_ts2timestr(st1->head_ts, &st1->tb), av_ts2timestr(ts, &st1->tb)); | |
336 | |||
337 | 94 | stream_update_ts(sq, i, ts); | |
338 | } | ||
339 | |||
340 | 94 | return 1; | |
341 | } | ||
342 | |||
343 | 36389 | int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame) | |
344 | { | ||
345 | SyncQueueStream *st; | ||
346 | SyncQueueFrame dst; | ||
347 | int64_t ts; | ||
348 | int ret, nb_samples; | ||
349 | |||
350 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36389 times.
|
36389 | av_assert0(stream_idx < sq->nb_streams); |
351 | 36389 | st = &sq->streams[stream_idx]; | |
352 | |||
353 |
2/2✓ Branch 1 taken 3313 times.
✓ Branch 2 taken 33076 times.
|
36389 | if (frame_null(sq, frame)) { |
354 | 3313 | av_log(sq->logctx, AV_LOG_DEBUG, "sq: %u EOF\n", stream_idx); | |
355 | 3313 | finish_stream(sq, stream_idx); | |
356 | 3313 | return 0; | |
357 | } | ||
358 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 33053 times.
|
33076 | if (st->finished) |
359 | 23 | return AVERROR_EOF; | |
360 | |||
361 | 33053 | tb_update(sq, st, frame); | |
362 | |||
363 | 33053 | ret = objpool_get(sq->pool, (void**)&dst); | |
364 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33053 times.
|
33053 | if (ret < 0) |
365 | ✗ | return ret; | |
366 | |||
367 | 33053 | frame_move(sq, dst, frame); | |
368 | |||
369 | 33053 | nb_samples = frame_samples(sq, dst); | |
370 | // make sure frame duration is consistent with sample count | ||
371 |
2/2✓ Branch 0 taken 23957 times.
✓ Branch 1 taken 9096 times.
|
33053 | if (nb_samples) { |
372 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23957 times.
|
23957 | av_assert0(dst.f->sample_rate > 0); |
373 | 23957 | dst.f->duration = av_rescale_q(nb_samples, (AVRational){ 1, dst.f->sample_rate }, | |
374 | 23957 | dst.f->time_base); | |
375 | } | ||
376 | |||
377 | 33053 | ts = frame_end(sq, dst, 0); | |
378 | |||
379 | 33053 | av_log(sq->logctx, AV_LOG_DEBUG, "sq: send %u ts %s\n", stream_idx, | |
380 | 33053 | av_ts2timestr(ts, &st->tb)); | |
381 | |||
382 | 33053 | ret = av_fifo_write(st->fifo, &dst, 1); | |
383 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33053 times.
|
33053 | if (ret < 0) { |
384 | ✗ | frame_move(sq, frame, dst); | |
385 | ✗ | objpool_release(sq->pool, (void**)&dst); | |
386 | ✗ | return ret; | |
387 | } | ||
388 | |||
389 | 33053 | stream_update_ts(sq, stream_idx, ts); | |
390 | |||
391 | 33053 | st->samples_queued += nb_samples; | |
392 | 33053 | st->samples_sent += nb_samples; | |
393 | |||
394 |
2/2✓ Branch 0 taken 19859 times.
✓ Branch 1 taken 13194 times.
|
33053 | if (st->frame_samples) |
395 | 19859 | st->frames_sent = st->samples_sent / st->frame_samples; | |
396 | else | ||
397 | 13194 | st->frames_sent++; | |
398 | |||
399 |
2/2✓ Branch 0 taken 2946 times.
✓ Branch 1 taken 30107 times.
|
33053 | if (st->frames_sent >= st->frames_max) { |
400 | 2946 | av_log(sq->logctx, AV_LOG_DEBUG, "sq: %u frames_max %"PRIu64" reached\n", | |
401 | stream_idx, st->frames_max); | ||
402 | |||
403 | 2946 | finish_stream(sq, stream_idx); | |
404 | } | ||
405 | |||
406 | 33053 | return 0; | |
407 | } | ||
408 | |||
409 | 65023 | static void offset_audio(AVFrame *f, int nb_samples) | |
410 | { | ||
411 | 65023 | const int planar = av_sample_fmt_is_planar(f->format); | |
412 |
2/2✓ Branch 0 taken 29371 times.
✓ Branch 1 taken 35652 times.
|
65023 | const int planes = planar ? f->ch_layout.nb_channels : 1; |
413 | 65023 | const int bps = av_get_bytes_per_sample(f->format); | |
414 |
2/2✓ Branch 0 taken 35652 times.
✓ Branch 1 taken 29371 times.
|
65023 | const int offset = nb_samples * bps * (planar ? 1 : f->ch_layout.nb_channels); |
415 | |||
416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65023 times.
|
65023 | av_assert0(bps > 0); |
417 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65023 times.
|
65023 | av_assert0(nb_samples < f->nb_samples); |
418 | |||
419 |
2/2✓ Branch 0 taken 93809 times.
✓ Branch 1 taken 65023 times.
|
158832 | for (int i = 0; i < planes; i++) { |
420 | 93809 | f->extended_data[i] += offset; | |
421 |
1/2✓ Branch 0 taken 93809 times.
✗ Branch 1 not taken.
|
93809 | if (i < FF_ARRAY_ELEMS(f->data)) |
422 | 93809 | f->data[i] = f->extended_data[i]; | |
423 | } | ||
424 | 65023 | f->linesize[0] -= offset; | |
425 | 65023 | f->nb_samples -= nb_samples; | |
426 | 65023 | f->duration = av_rescale_q(f->nb_samples, (AVRational){ 1, f->sample_rate }, | |
427 | f->time_base); | ||
428 | 65023 | f->pts += av_rescale_q(nb_samples, (AVRational){ 1, f->sample_rate }, | |
429 | f->time_base); | ||
430 | 65023 | } | |
431 | |||
432 | 56989 | static int frame_is_aligned(const SyncQueue *sq, const AVFrame *frame) | |
433 | { | ||
434 | // only checks linesize[0], so only works for audio | ||
435 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56989 times.
|
56989 | av_assert0(frame->nb_samples > 0); |
436 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56989 times.
|
56989 | av_assert0(sq->align_mask); |
437 | |||
438 | // only check data[0], because we always offset all data pointers | ||
439 | // by the same offset, so if one is aligned, all are | ||
440 |
2/2✓ Branch 0 taken 56441 times.
✓ Branch 1 taken 548 times.
|
56989 | if (!((uintptr_t)frame->data[0] & sq->align_mask) && |
441 |
1/2✓ Branch 0 taken 56441 times.
✗ Branch 1 not taken.
|
56441 | !(frame->linesize[0] & sq->align_mask) && |
442 |
1/2✓ Branch 0 taken 56441 times.
✗ Branch 1 not taken.
|
56441 | frame->linesize[0] > sq->align_mask) |
443 | 56441 | return 1; | |
444 | |||
445 | 548 | return 0; | |
446 | } | ||
447 | |||
448 | 66303 | static int receive_samples(SyncQueue *sq, SyncQueueStream *st, | |
449 | AVFrame *dst, int nb_samples) | ||
450 | { | ||
451 | SyncQueueFrame src; | ||
452 | int ret; | ||
453 | |||
454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66303 times.
|
66303 | av_assert0(st->samples_queued >= nb_samples); |
455 | |||
456 | 66303 | ret = av_fifo_peek(st->fifo, &src, 1, 0); | |
457 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66303 times.
|
66303 | av_assert0(ret >= 0); |
458 | |||
459 | // peeked frame has enough samples and its data is aligned | ||
460 | // -> we can just make a reference and limit its sample count | ||
461 |
4/4✓ Branch 0 taken 52588 times.
✓ Branch 1 taken 13715 times.
✓ Branch 3 taken 52041 times.
✓ Branch 4 taken 547 times.
|
66303 | if (src.f->nb_samples > nb_samples && frame_is_aligned(sq, src.f)) { |
462 | 52041 | ret = av_frame_ref(dst, src.f); | |
463 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52041 times.
|
52041 | if (ret < 0) |
464 | ✗ | return ret; | |
465 | |||
466 | 52041 | dst->nb_samples = nb_samples; | |
467 | 52041 | offset_audio(src.f, nb_samples); | |
468 | 52041 | st->samples_queued -= nb_samples; | |
469 | |||
470 | 52041 | goto finish; | |
471 | } | ||
472 | |||
473 | // otherwise allocate a new frame and copy the data | ||
474 | 14262 | ret = av_channel_layout_copy(&dst->ch_layout, &src.f->ch_layout); | |
475 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14262 times.
|
14262 | if (ret < 0) |
476 | ✗ | return ret; | |
477 | |||
478 | 14262 | dst->format = src.f->format; | |
479 | 14262 | dst->nb_samples = nb_samples; | |
480 | |||
481 | 14262 | ret = av_frame_get_buffer(dst, 0); | |
482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14262 times.
|
14262 | if (ret < 0) |
483 | ✗ | goto fail; | |
484 | |||
485 | 14262 | ret = av_frame_copy_props(dst, src.f); | |
486 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14262 times.
|
14262 | if (ret < 0) |
487 | ✗ | goto fail; | |
488 | |||
489 | 14262 | dst->nb_samples = 0; | |
490 |
2/2✓ Branch 0 taken 28433 times.
✓ Branch 1 taken 14262 times.
|
42695 | while (dst->nb_samples < nb_samples) { |
491 | int to_copy; | ||
492 | |||
493 | 28433 | ret = av_fifo_peek(st->fifo, &src, 1, 0); | |
494 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28433 times.
|
28433 | av_assert0(ret >= 0); |
495 | |||
496 | 28433 | to_copy = FFMIN(nb_samples - dst->nb_samples, src.f->nb_samples); | |
497 | |||
498 | 28433 | av_samples_copy(dst->extended_data, src.f->extended_data, dst->nb_samples, | |
499 | 28433 | 0, to_copy, dst->ch_layout.nb_channels, dst->format); | |
500 | |||
501 |
2/2✓ Branch 0 taken 12982 times.
✓ Branch 1 taken 15451 times.
|
28433 | if (to_copy < src.f->nb_samples) |
502 | 12982 | offset_audio(src.f, to_copy); | |
503 | else { | ||
504 | 15451 | av_frame_unref(src.f); | |
505 | 15451 | objpool_release(sq->pool, (void**)&src); | |
506 | 15451 | av_fifo_drain2(st->fifo, 1); | |
507 | } | ||
508 | 28433 | st->samples_queued -= to_copy; | |
509 | |||
510 | 28433 | dst->nb_samples += to_copy; | |
511 | } | ||
512 | |||
513 | 14262 | finish: | |
514 | 66303 | dst->duration = av_rescale_q(nb_samples, (AVRational){ 1, dst->sample_rate }, | |
515 | dst->time_base); | ||
516 | |||
517 | 66303 | return 0; | |
518 | |||
519 | ✗ | fail: | |
520 | ✗ | av_frame_unref(dst); | |
521 | ✗ | return ret; | |
522 | } | ||
523 | |||
524 | 127593 | static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, | |
525 | SyncQueueFrame frame) | ||
526 | { | ||
527 | 255186 | const SyncQueueStream *st_head = sq->head_stream >= 0 ? | |
528 |
2/2✓ Branch 0 taken 30234 times.
✓ Branch 1 taken 97359 times.
|
127593 | &sq->streams[sq->head_stream] : NULL; |
529 | SyncQueueStream *st; | ||
530 | |||
531 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 127593 times.
|
127593 | av_assert0(stream_idx < sq->nb_streams); |
532 | 127593 | st = &sq->streams[stream_idx]; | |
533 | |||
534 |
2/2✓ Branch 1 taken 102913 times.
✓ Branch 2 taken 24680 times.
|
127593 | if (av_fifo_can_read(st->fifo) && |
535 |
4/4✓ Branch 0 taken 17982 times.
✓ Branch 1 taken 84931 times.
✓ Branch 2 taken 152 times.
✓ Branch 3 taken 17830 times.
|
102913 | (st->frame_samples <= st->samples_queued || st->finished)) { |
536 | 85083 | int nb_samples = st->frame_samples; | |
537 | SyncQueueFrame peek; | ||
538 | int64_t ts; | ||
539 | 85083 | int cmp = 1; | |
540 | |||
541 |
2/2✓ Branch 0 taken 3417 times.
✓ Branch 1 taken 81666 times.
|
85083 | if (st->finished) |
542 | 3417 | nb_samples = FFMIN(nb_samples, st->samples_queued); | |
543 | |||
544 | 85083 | av_fifo_peek(st->fifo, &peek, 1, 0); | |
545 | 85083 | ts = frame_end(sq, peek, nb_samples); | |
546 | |||
547 | /* check if this stream's tail timestamp does not overtake | ||
548 | * the overall queue head */ | ||
549 |
4/4✓ Branch 0 taken 85080 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 14077 times.
✓ Branch 3 taken 71003 times.
|
85083 | if (ts != AV_NOPTS_VALUE && st_head) |
550 | 14077 | cmp = av_compare_ts(ts, st->tb, st_head->head_ts, st_head->tb); | |
551 | |||
552 | /* We can release frames that do not end after the queue head. | ||
553 | * Frames with no timestamps are just passed through with no conditions. | ||
554 | * Frames are also passed through when there are no limiting streams. | ||
555 | */ | ||
556 |
6/6✓ Branch 0 taken 72154 times.
✓ Branch 1 taken 12929 times.
✓ Branch 2 taken 72151 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 70917 times.
✓ Branch 5 taken 1234 times.
|
85083 | if (cmp <= 0 || ts == AV_NOPTS_VALUE || !sq->have_limiting) { |
557 |
2/2✓ Branch 0 taken 70703 times.
✓ Branch 1 taken 13146 times.
|
83849 | if (nb_samples && |
558 |
4/4✓ Branch 0 taken 4401 times.
✓ Branch 1 taken 66302 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 4400 times.
|
137006 | (nb_samples != peek.f->nb_samples || !frame_is_aligned(sq, peek.f))) { |
559 | 66303 | int ret = receive_samples(sq, st, frame.f, nb_samples); | |
560 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66303 times.
|
66303 | if (ret < 0) |
561 | ✗ | return ret; | |
562 | } else { | ||
563 | 17546 | frame_move(sq, frame, peek); | |
564 | 17546 | objpool_release(sq->pool, (void**)&peek); | |
565 | 17546 | av_fifo_drain2(st->fifo, 1); | |
566 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 17546 times.
|
17546 | av_assert0(st->samples_queued >= frame_samples(sq, frame)); |
567 | 17546 | st->samples_queued -= frame_samples(sq, frame); | |
568 | } | ||
569 | |||
570 |
2/2✓ Branch 0 taken 12929 times.
✓ Branch 1 taken 70920 times.
|
167698 | av_log(sq->logctx, AV_LOG_DEBUG, |
571 | "sq: receive %u ts %s queue head %d ts %s\n", stream_idx, | ||
572 | 83849 | av_ts2timestr(frame_end(sq, frame, 0), &st->tb), | |
573 | sq->head_stream, | ||
574 | 12929 | st_head ? av_ts2timestr(st_head->head_ts, &st_head->tb) : "N/A"); | |
575 | |||
576 | 83849 | return 0; | |
577 | } | ||
578 | } | ||
579 | |||
580 |
4/4✓ Branch 0 taken 862 times.
✓ Branch 1 taken 36411 times.
✓ Branch 3 taken 641 times.
✓ Branch 4 taken 221 times.
|
37273 | return (sq->finished || (st->finished && !av_fifo_can_read(st->fifo))) ? |
581 |
2/2✓ Branch 0 taken 37273 times.
✓ Branch 1 taken 6471 times.
|
81017 | AVERROR_EOF : AVERROR(EAGAIN); |
582 | } | ||
583 | |||
584 | 120309 | static int receive_internal(SyncQueue *sq, int stream_idx, SyncQueueFrame frame) | |
585 | { | ||
586 | 120309 | int nb_eof = 0; | |
587 | int ret; | ||
588 | |||
589 | /* read a frame for a specific stream */ | ||
590 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 120309 times.
|
120309 | if (stream_idx >= 0) { |
591 | ✗ | ret = receive_for_stream(sq, stream_idx, frame); | |
592 | ✗ | return (ret < 0) ? ret : stream_idx; | |
593 | } | ||
594 | |||
595 | /* read a frame for any stream with available output */ | ||
596 |
2/2✓ Branch 0 taken 127593 times.
✓ Branch 1 taken 36460 times.
|
164053 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
597 | 127593 | ret = receive_for_stream(sq, i, frame); | |
598 |
4/4✓ Branch 0 taken 120481 times.
✓ Branch 1 taken 7112 times.
✓ Branch 2 taken 36632 times.
✓ Branch 3 taken 83849 times.
|
127593 | if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) { |
599 | 43744 | nb_eof += (ret == AVERROR_EOF); | |
600 | 43744 | continue; | |
601 | } | ||
602 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83849 times.
|
83849 | return (ret < 0) ? ret : i; |
603 | } | ||
604 | |||
605 |
2/2✓ Branch 0 taken 6175 times.
✓ Branch 1 taken 30285 times.
|
36460 | return (nb_eof == sq->nb_streams) ? AVERROR_EOF : AVERROR(EAGAIN); |
606 | } | ||
607 | |||
608 | 120215 | int sq_receive(SyncQueue *sq, int stream_idx, SyncQueueFrame frame) | |
609 | { | ||
610 | 120215 | int ret = receive_internal(sq, stream_idx, frame); | |
611 | |||
612 | /* try again if the queue overflowed and triggered a fake heartbeat | ||
613 | * for lagging streams */ | ||
614 |
4/4✓ Branch 0 taken 30285 times.
✓ Branch 1 taken 89930 times.
✓ Branch 3 taken 94 times.
✓ Branch 4 taken 30191 times.
|
120215 | if (ret == AVERROR(EAGAIN) && overflow_heartbeat(sq, stream_idx)) |
615 | 94 | ret = receive_internal(sq, stream_idx, frame); | |
616 | |||
617 | 120215 | return ret; | |
618 | } | ||
619 | |||
620 | 3166 | int sq_add_stream(SyncQueue *sq, int limiting) | |
621 | { | ||
622 | SyncQueueStream *tmp, *st; | ||
623 | |||
624 | 3166 | tmp = av_realloc_array(sq->streams, sq->nb_streams + 1, sizeof(*sq->streams)); | |
625 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3166 times.
|
3166 | if (!tmp) |
626 | ✗ | return AVERROR(ENOMEM); | |
627 | 3166 | sq->streams = tmp; | |
628 | |||
629 | 3166 | st = &sq->streams[sq->nb_streams]; | |
630 | 3166 | memset(st, 0, sizeof(*st)); | |
631 | |||
632 | 3166 | st->fifo = av_fifo_alloc2(1, sizeof(SyncQueueFrame), AV_FIFO_FLAG_AUTO_GROW); | |
633 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3166 times.
|
3166 | if (!st->fifo) |
634 | ✗ | return AVERROR(ENOMEM); | |
635 | |||
636 | /* we set a valid default, so that a pathological stream that never | ||
637 | * receives even a real timebase (and no frames) won't stall all other | ||
638 | * streams forever; cf. overflow_heartbeat() */ | ||
639 | 3166 | st->tb = (AVRational){ 1, 1 }; | |
640 | 3166 | st->head_ts = AV_NOPTS_VALUE; | |
641 | 3166 | st->frames_max = UINT64_MAX; | |
642 | 3166 | st->limiting = limiting; | |
643 | |||
644 | 3166 | sq->have_limiting |= limiting; | |
645 | |||
646 | 3166 | return sq->nb_streams++; | |
647 | } | ||
648 | |||
649 | 2971 | void sq_limit_frames(SyncQueue *sq, unsigned int stream_idx, uint64_t frames) | |
650 | { | ||
651 | SyncQueueStream *st; | ||
652 | |||
653 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2971 times.
|
2971 | av_assert0(stream_idx < sq->nb_streams); |
654 | 2971 | st = &sq->streams[stream_idx]; | |
655 | |||
656 | 2971 | st->frames_max = frames; | |
657 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 2948 times.
|
2971 | if (st->frames_sent >= st->frames_max) |
658 | 23 | finish_stream(sq, stream_idx); | |
659 | 2971 | } | |
660 | |||
661 | 163 | void sq_frame_samples(SyncQueue *sq, unsigned int stream_idx, | |
662 | int frame_samples) | ||
663 | { | ||
664 | SyncQueueStream *st; | ||
665 | |||
666 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 163 times.
|
163 | av_assert0(sq->type == SYNC_QUEUE_FRAMES); |
667 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 163 times.
|
163 | av_assert0(stream_idx < sq->nb_streams); |
668 | 163 | st = &sq->streams[stream_idx]; | |
669 | |||
670 | 163 | st->frame_samples = frame_samples; | |
671 | |||
672 | 163 | sq->align_mask = av_cpu_max_align() - 1; | |
673 | 163 | } | |
674 | |||
675 | 3085 | SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us, void *logctx) | |
676 | { | ||
677 | 3085 | SyncQueue *sq = av_mallocz(sizeof(*sq)); | |
678 | |||
679 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3085 times.
|
3085 | if (!sq) |
680 | ✗ | return NULL; | |
681 | |||
682 | 3085 | sq->type = type; | |
683 | 3085 | sq->buf_size_us = buf_size_us; | |
684 | 3085 | sq->logctx = logctx; | |
685 | |||
686 | 3085 | sq->head_stream = -1; | |
687 | 3085 | sq->head_finished_stream = -1; | |
688 | |||
689 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 3068 times.
|
3085 | sq->pool = (type == SYNC_QUEUE_PACKETS) ? objpool_alloc_packets() : |
690 | 3068 | objpool_alloc_frames(); | |
691 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3085 times.
|
3085 | if (!sq->pool) { |
692 | ✗ | av_freep(&sq); | |
693 | ✗ | return NULL; | |
694 | } | ||
695 | |||
696 | 3085 | return sq; | |
697 | } | ||
698 | |||
699 | 10984 | void sq_free(SyncQueue **psq) | |
700 | { | ||
701 | 10984 | SyncQueue *sq = *psq; | |
702 | |||
703 |
2/2✓ Branch 0 taken 7899 times.
✓ Branch 1 taken 3085 times.
|
10984 | if (!sq) |
704 | 7899 | return; | |
705 | |||
706 |
2/2✓ Branch 0 taken 3166 times.
✓ Branch 1 taken 3085 times.
|
6251 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
707 | SyncQueueFrame frame; | ||
708 |
2/2✓ Branch 1 taken 56 times.
✓ Branch 2 taken 3166 times.
|
3222 | while (av_fifo_read(sq->streams[i].fifo, &frame, 1) >= 0) |
709 | 56 | objpool_release(sq->pool, (void**)&frame); | |
710 | |||
711 | 3166 | av_fifo_freep2(&sq->streams[i].fifo); | |
712 | } | ||
713 | |||
714 | 3085 | av_freep(&sq->streams); | |
715 | |||
716 | 3085 | objpool_free(&sq->pool); | |
717 | |||
718 | 3085 | av_freep(psq); | |
719 | } | ||
720 |