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/container_fifo.h" | ||
24 | #include "libavutil/channel_layout.h" | ||
25 | #include "libavutil/cpu.h" | ||
26 | #include "libavutil/error.h" | ||
27 | #include "libavutil/mathematics.h" | ||
28 | #include "libavutil/mem.h" | ||
29 | #include "libavutil/samplefmt.h" | ||
30 | #include "libavutil/timestamp.h" | ||
31 | |||
32 | #include "sync_queue.h" | ||
33 | |||
34 | /* | ||
35 | * How this works: | ||
36 | * -------------- | ||
37 | * time: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 | ||
38 | * ------------------------------------------------------------------- | ||
39 | * | | | | | | | | | | | | | | | ||
40 | * | ┌───┐┌────────┐┌───┐┌─────────────┐ | ||
41 | * stream 0| │d=1││ d=2 ││d=1││ d=3 │ | ||
42 | * | └───┘└────────┘└───┘└─────────────┘ | ||
43 | * ┌───┐ ┌───────────────────────┐ | ||
44 | * stream 1│d=1│ │ d=5 │ | ||
45 | * └───┘ └───────────────────────┘ | ||
46 | * | ┌───┐┌───┐┌───┐┌───┐ | ||
47 | * stream 2| │d=1││d=1││d=1││d=1│ <- stream 2 is the head stream of the queue | ||
48 | * | └───┘└───┘└───┘└───┘ | ||
49 | * ^ ^ | ||
50 | * [stream 2 tail] [stream 2 head] | ||
51 | * | ||
52 | * We have N streams (N=3 in the diagram), each stream is a FIFO. The *tail* of | ||
53 | * each FIFO is the frame with smallest end time, the *head* is the frame with | ||
54 | * the largest end time. Frames submitted to the queue with sq_send() are placed | ||
55 | * after the head, frames returned to the caller with sq_receive() are taken | ||
56 | * from the tail. | ||
57 | * | ||
58 | * The head stream of the whole queue (SyncQueue.head_stream) is the limiting | ||
59 | * stream with the *smallest* head timestamp, i.e. the stream whose source lags | ||
60 | * furthest behind all other streams. It determines which frames can be output | ||
61 | * from the queue. | ||
62 | * | ||
63 | * In the diagram, the head stream is 2, because it head time is t=5, while | ||
64 | * streams 0 and 1 end at t=8 and t=9 respectively. All frames that _end_ at | ||
65 | * or before t=5 can be output, i.e. the first 3 frames from stream 0, first | ||
66 | * frame from stream 1, and all 4 frames from stream 2. | ||
67 | */ | ||
68 | |||
69 | #define SQPTR(sq, frame) ((sq->type == SYNC_QUEUE_FRAMES) ? \ | ||
70 | (void*)frame.f : (void*)frame.p) | ||
71 | |||
72 | typedef struct SyncQueueStream { | ||
73 | AVContainerFifo *fifo; | ||
74 | AVRational tb; | ||
75 | |||
76 | /* number of audio samples in fifo */ | ||
77 | uint64_t samples_queued; | ||
78 | /* stream head: largest timestamp seen */ | ||
79 | int64_t head_ts; | ||
80 | int limiting; | ||
81 | /* no more frames will be sent for this stream */ | ||
82 | int finished; | ||
83 | |||
84 | uint64_t frames_sent; | ||
85 | uint64_t samples_sent; | ||
86 | uint64_t frames_max; | ||
87 | int frame_samples; | ||
88 | } SyncQueueStream; | ||
89 | |||
90 | struct SyncQueue { | ||
91 | enum SyncQueueType type; | ||
92 | |||
93 | void *logctx; | ||
94 | |||
95 | /* no more frames will be sent for any stream */ | ||
96 | int finished; | ||
97 | /* sync head: the stream with the _smallest_ head timestamp | ||
98 | * this stream determines which frames can be output */ | ||
99 | int head_stream; | ||
100 | /* the finished stream with the smallest finish timestamp or -1 */ | ||
101 | int head_finished_stream; | ||
102 | |||
103 | // maximum buffering duration in microseconds | ||
104 | int64_t buf_size_us; | ||
105 | |||
106 | SyncQueueStream *streams; | ||
107 | unsigned int nb_streams; | ||
108 | |||
109 | int have_limiting; | ||
110 | |||
111 | uintptr_t align_mask; | ||
112 | }; | ||
113 | |||
114 | /** | ||
115 | * Compute the end timestamp of a frame. If nb_samples is provided, consider | ||
116 | * the frame to have this number of audio samples, otherwise use frame duration. | ||
117 | */ | ||
118 | 217574 | static int64_t frame_end(const SyncQueue *sq, SyncQueueFrame frame, int nb_samples) | |
119 | { | ||
120 |
2/2✓ Branch 0 taken 70804 times.
✓ Branch 1 taken 146770 times.
|
217574 | if (nb_samples) { |
121 | 70804 | int64_t d = av_rescale_q(nb_samples, (AVRational){ 1, frame.f->sample_rate}, | |
122 | 70804 | frame.f->time_base); | |
123 | 70804 | return frame.f->pts + d; | |
124 | } | ||
125 | |||
126 | 146770 | return (sq->type == SYNC_QUEUE_PACKETS) ? | |
127 |
2/2✓ Branch 0 taken 4205 times.
✓ Branch 1 taken 142565 times.
|
289335 | frame.p->pts + frame.p->duration : |
128 | 142565 | frame.f->pts + frame.f->duration; | |
129 | } | ||
130 | |||
131 | 68266 | static int frame_samples(const SyncQueue *sq, SyncQueueFrame frame) | |
132 | { | ||
133 |
2/2✓ Branch 0 taken 65833 times.
✓ Branch 1 taken 2433 times.
|
68266 | return (sq->type == SYNC_QUEUE_PACKETS) ? 0 : frame.f->nb_samples; |
134 | } | ||
135 | |||
136 | 36510 | static int frame_null(const SyncQueue *sq, SyncQueueFrame frame) | |
137 | { | ||
138 |
2/2✓ Branch 0 taken 878 times.
✓ Branch 1 taken 35632 times.
|
36510 | return (sq->type == SYNC_QUEUE_PACKETS) ? (frame.p == NULL) : (frame.f == NULL); |
139 | } | ||
140 | |||
141 | 33154 | static void tb_update(const SyncQueue *sq, SyncQueueStream *st, | |
142 | const SyncQueueFrame frame) | ||
143 | { | ||
144 | 66308 | AVRational tb = (sq->type == SYNC_QUEUE_PACKETS) ? | |
145 |
2/2✓ Branch 0 taken 843 times.
✓ Branch 1 taken 32311 times.
|
33154 | frame.p->time_base : frame.f->time_base; |
146 | |||
147 |
2/4✓ Branch 0 taken 33154 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33154 times.
|
33154 | av_assert0(tb.num > 0 && tb.den > 0); |
148 | |||
149 |
4/4✓ Branch 0 taken 33038 times.
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 30001 times.
✓ Branch 3 taken 3037 times.
|
33154 | if (tb.num == st->tb.num && tb.den == st->tb.den) |
150 | 30001 | return; | |
151 | |||
152 | // timebase should not change after the first frame | ||
153 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3153 times.
|
3153 | av_assert0(!av_container_fifo_can_read(st->fifo)); |
154 | |||
155 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3152 times.
|
3153 | if (st->head_ts != AV_NOPTS_VALUE) |
156 | 1 | st->head_ts = av_rescale_q(st->head_ts, st->tb, tb); | |
157 | |||
158 | 3153 | st->tb = tb; | |
159 | } | ||
160 | |||
161 | 6305 | static void finish_stream(SyncQueue *sq, unsigned int stream_idx) | |
162 | { | ||
163 | 6305 | SyncQueueStream *st = &sq->streams[stream_idx]; | |
164 | |||
165 |
2/2✓ Branch 0 taken 3173 times.
✓ Branch 1 taken 3132 times.
|
6305 | if (!st->finished) |
166 | 3173 | av_log(sq->logctx, AV_LOG_DEBUG, | |
167 | "sq: finish %u; head ts %s\n", stream_idx, | ||
168 | 3173 | av_ts2timestr(st->head_ts, &st->tb)); | |
169 | |||
170 | 6305 | st->finished = 1; | |
171 | |||
172 |
4/4✓ Branch 0 taken 5928 times.
✓ Branch 1 taken 377 times.
✓ Branch 2 taken 5904 times.
✓ Branch 3 taken 24 times.
|
6305 | if (st->limiting && st->head_ts != AV_NOPTS_VALUE) { |
173 | /* check if this stream is the new finished head */ | ||
174 |
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 || |
175 | 2950 | av_compare_ts(st->head_ts, st->tb, | |
176 | 2950 | sq->streams[sq->head_finished_stream].head_ts, | |
177 | 2950 | sq->streams[sq->head_finished_stream].tb) < 0) { | |
178 | 2955 | sq->head_finished_stream = stream_idx; | |
179 | } | ||
180 | |||
181 | /* mark as finished all streams that should no longer receive new frames, | ||
182 | * due to them being ahead of some finished stream */ | ||
183 | 5904 | st = &sq->streams[sq->head_finished_stream]; | |
184 |
2/2✓ Branch 0 taken 5920 times.
✓ Branch 1 taken 5904 times.
|
11824 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
185 | 5920 | SyncQueueStream *st1 = &sq->streams[i]; | |
186 |
5/6✓ Branch 0 taken 16 times.
✓ Branch 1 taken 5904 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 7 times.
|
5936 | if (st != st1 && st1->head_ts != AV_NOPTS_VALUE && |
187 | 16 | av_compare_ts(st->head_ts, st->tb, st1->head_ts, st1->tb) <= 0) { | |
188 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
|
9 | if (!st1->finished) |
189 | 3 | av_log(sq->logctx, AV_LOG_DEBUG, | |
190 | "sq: finish secondary %u; head ts %s\n", i, | ||
191 | 3 | av_ts2timestr(st1->head_ts, &st1->tb)); | |
192 | |||
193 | 9 | st1->finished = 1; | |
194 | } | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* mark the whole queue as finished if all streams are finished */ | ||
199 |
2/2✓ Branch 0 taken 6952 times.
✓ Branch 1 taken 6210 times.
|
13162 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
200 |
2/2✓ Branch 0 taken 95 times.
✓ Branch 1 taken 6857 times.
|
6952 | if (!sq->streams[i].finished) |
201 | 95 | return; | |
202 | } | ||
203 | 6210 | sq->finished = 1; | |
204 | |||
205 | 6210 | av_log(sq->logctx, AV_LOG_DEBUG, "sq: finish queue\n"); | |
206 | } | ||
207 | |||
208 | 12578 | static void queue_head_update(SyncQueue *sq) | |
209 | { | ||
210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12578 times.
|
12578 | av_assert0(sq->have_limiting); |
211 | |||
212 |
2/2✓ Branch 0 taken 3018 times.
✓ Branch 1 taken 9560 times.
|
12578 | if (sq->head_stream < 0) { |
213 | 3018 | unsigned first_limiting = UINT_MAX; | |
214 | |||
215 | /* wait for one timestamp in each stream before determining | ||
216 | * the queue head */ | ||
217 |
2/2✓ Branch 0 taken 3090 times.
✓ Branch 1 taken 2954 times.
|
6044 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
218 | 3090 | SyncQueueStream *st = &sq->streams[i]; | |
219 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3086 times.
|
3090 | if (!st->limiting) |
220 | 4 | continue; | |
221 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 3022 times.
|
3086 | if (st->head_ts == AV_NOPTS_VALUE) |
222 | 64 | return; | |
223 |
2/2✓ Branch 0 taken 3018 times.
✓ Branch 1 taken 4 times.
|
3022 | if (first_limiting == UINT_MAX) |
224 | 3018 | first_limiting = i; | |
225 | } | ||
226 | |||
227 | // placeholder value, correct one will be found below | ||
228 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2954 times.
|
2954 | av_assert0(first_limiting < UINT_MAX); |
229 | 2954 | sq->head_stream = first_limiting; | |
230 | } | ||
231 | |||
232 |
2/2✓ Branch 0 taken 12892 times.
✓ Branch 1 taken 12514 times.
|
25406 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
233 | 12892 | SyncQueueStream *st_head = &sq->streams[sq->head_stream]; | |
234 | 12892 | SyncQueueStream *st_other = &sq->streams[i]; | |
235 |
5/6✓ Branch 0 taken 12858 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 12858 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 12843 times.
|
25750 | if (st_other->limiting && st_other->head_ts != AV_NOPTS_VALUE && |
236 | 12858 | av_compare_ts(st_other->head_ts, st_other->tb, | |
237 | st_head->head_ts, st_head->tb) < 0) | ||
238 | 15 | sq->head_stream = i; | |
239 | } | ||
240 | } | ||
241 | |||
242 | /* update this stream's head timestamp */ | ||
243 | 33248 | static void stream_update_ts(SyncQueue *sq, unsigned int stream_idx, int64_t ts) | |
244 | { | ||
245 | 33248 | SyncQueueStream *st = &sq->streams[stream_idx]; | |
246 | |||
247 |
2/2✓ Branch 0 taken 33245 times.
✓ Branch 1 taken 3 times.
|
33248 | if (ts == AV_NOPTS_VALUE || |
248 |
4/4✓ Branch 0 taken 30095 times.
✓ Branch 1 taken 3150 times.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 30040 times.
|
33245 | (st->head_ts != AV_NOPTS_VALUE && st->head_ts >= ts)) |
249 | 58 | return; | |
250 | |||
251 | 33190 | st->head_ts = ts; | |
252 | |||
253 | /* if this stream is now ahead of some finished stream, then | ||
254 | * this stream is also finished */ | ||
255 |
4/4✓ Branch 0 taken 141 times.
✓ Branch 1 taken 33049 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 137 times.
|
33331 | if (sq->head_finished_stream >= 0 && |
256 | 141 | av_compare_ts(sq->streams[sq->head_finished_stream].head_ts, | |
257 | 141 | sq->streams[sq->head_finished_stream].tb, | |
258 | ts, st->tb) <= 0) | ||
259 | 4 | finish_stream(sq, stream_idx); | |
260 | |||
261 | /* update the overall head timestamp if it could have changed */ | ||
262 |
2/2✓ Branch 0 taken 13062 times.
✓ Branch 1 taken 20128 times.
|
33190 | if (st->limiting && |
263 |
4/4✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 3018 times.
✓ Branch 2 taken 9560 times.
✓ Branch 3 taken 484 times.
|
13062 | (sq->head_stream < 0 || sq->head_stream == stream_idx)) |
264 | 12578 | queue_head_update(sq); | |
265 | } | ||
266 | |||
267 | /* If the queue for the given stream (or all streams when stream_idx=-1) | ||
268 | * is overflowing, trigger a fake heartbeat on lagging streams. | ||
269 | * | ||
270 | * @return 1 if heartbeat triggered, 0 otherwise | ||
271 | */ | ||
272 | 30393 | static int overflow_heartbeat(SyncQueue *sq, int stream_idx) | |
273 | { | ||
274 | SyncQueueStream *st; | ||
275 | SyncQueueFrame frame; | ||
276 | 30393 | int64_t tail_ts = AV_NOPTS_VALUE; | |
277 | |||
278 | /* if no stream specified, pick the one that is most ahead */ | ||
279 |
1/2✓ Branch 0 taken 30393 times.
✗ Branch 1 not taken.
|
30393 | if (stream_idx < 0) { |
280 | 30393 | int64_t ts = AV_NOPTS_VALUE; | |
281 | |||
282 |
2/2✓ Branch 0 taken 36346 times.
✓ Branch 1 taken 30393 times.
|
66739 | for (int i = 0; i < sq->nb_streams; i++) { |
283 | 36346 | st = &sq->streams[i]; | |
284 |
4/4✓ Branch 0 taken 35748 times.
✓ Branch 1 taken 598 times.
✓ Branch 2 taken 5358 times.
✓ Branch 3 taken 30390 times.
|
36346 | if (st->head_ts != AV_NOPTS_VALUE && |
285 |
2/2✓ Branch 0 taken 555 times.
✓ Branch 1 taken 4803 times.
|
5358 | (ts == AV_NOPTS_VALUE || |
286 | 5358 | av_compare_ts(ts, sq->streams[stream_idx].tb, | |
287 | st->head_ts, st->tb) < 0)) { | ||
288 | 30945 | ts = st->head_ts; | |
289 | 30945 | stream_idx = i; | |
290 | } | ||
291 | } | ||
292 | /* no stream has a timestamp yet -> nothing to do */ | ||
293 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30390 times.
|
30393 | if (stream_idx < 0) |
294 | 3 | return 0; | |
295 | } | ||
296 | |||
297 | 30390 | st = &sq->streams[stream_idx]; | |
298 | |||
299 | /* get the chosen stream's tail timestamp */ | ||
300 |
4/4✓ Branch 0 taken 30390 times.
✓ Branch 1 taken 15364 times.
✓ Branch 2 taken 15364 times.
✓ Branch 3 taken 15026 times.
|
76144 | for (size_t i = 0; tail_ts == AV_NOPTS_VALUE && |
301 | 45754 | av_container_fifo_peek(st->fifo, (void**)&frame, i) >= 0; i++) | |
302 | 15364 | tail_ts = frame_end(sq, frame, 0); | |
303 | |||
304 | /* overflow triggers when the tail is over specified duration behind the head */ | ||
305 |
4/4✓ Branch 0 taken 15364 times.
✓ Branch 1 taken 15026 times.
✓ Branch 2 taken 1346 times.
✓ Branch 3 taken 14018 times.
|
30390 | if (tail_ts == AV_NOPTS_VALUE || tail_ts >= st->head_ts || |
306 |
2/2✓ Branch 0 taken 1252 times.
✓ Branch 1 taken 94 times.
|
1346 | av_rescale_q(st->head_ts - tail_ts, st->tb, AV_TIME_BASE_Q) < sq->buf_size_us) |
307 | 30296 | return 0; | |
308 | |||
309 | /* signal a fake timestamp for all streams that prevent tail_ts from being output */ | ||
310 | 94 | tail_ts++; | |
311 |
2/2✓ Branch 0 taken 188 times.
✓ Branch 1 taken 94 times.
|
282 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
312 | 188 | const SyncQueueStream *st1 = &sq->streams[i]; | |
313 | int64_t ts; | ||
314 | |||
315 |
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 || |
316 |
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 && |
317 | 93 | av_compare_ts(tail_ts, st->tb, st1->head_ts, st1->tb) <= 0)) | |
318 | 94 | continue; | |
319 | |||
320 | 94 | ts = av_rescale_q(tail_ts, st->tb, st1->tb); | |
321 |
2/2✓ Branch 0 taken 93 times.
✓ Branch 1 taken 1 times.
|
94 | if (st1->head_ts != AV_NOPTS_VALUE) |
322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 93 times.
|
93 | ts = FFMAX(st1->head_ts + 1, ts); |
323 | |||
324 | 94 | av_log(sq->logctx, AV_LOG_DEBUG, "sq: %u overflow heardbeat %s -> %s\n", | |
325 | 94 | i, av_ts2timestr(st1->head_ts, &st1->tb), av_ts2timestr(ts, &st1->tb)); | |
326 | |||
327 | 94 | stream_update_ts(sq, i, ts); | |
328 | } | ||
329 | |||
330 | 94 | return 1; | |
331 | } | ||
332 | |||
333 | 36510 | int sq_send(SyncQueue *sq, unsigned int stream_idx, SyncQueueFrame frame) | |
334 | { | ||
335 | SyncQueueStream *st; | ||
336 | int64_t ts; | ||
337 | int ret, nb_samples; | ||
338 | |||
339 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36510 times.
|
36510 | av_assert0(stream_idx < sq->nb_streams); |
340 | 36510 | st = &sq->streams[stream_idx]; | |
341 | |||
342 |
2/2✓ Branch 1 taken 3332 times.
✓ Branch 2 taken 33178 times.
|
36510 | if (frame_null(sq, frame)) { |
343 | 3332 | av_log(sq->logctx, AV_LOG_DEBUG, "sq: %u EOF\n", stream_idx); | |
344 | 3332 | finish_stream(sq, stream_idx); | |
345 | 3332 | return 0; | |
346 | } | ||
347 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 33154 times.
|
33178 | if (st->finished) |
348 | 24 | return AVERROR_EOF; | |
349 | |||
350 | 33154 | tb_update(sq, st, frame); | |
351 | |||
352 | 33154 | nb_samples = frame_samples(sq, frame); | |
353 | // make sure frame duration is consistent with sample count | ||
354 |
2/2✓ Branch 0 taken 24058 times.
✓ Branch 1 taken 9096 times.
|
33154 | if (nb_samples) { |
355 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24058 times.
|
24058 | av_assert0(frame.f->sample_rate > 0); |
356 | 24058 | frame.f->duration = av_rescale_q(nb_samples, (AVRational){ 1, frame.f->sample_rate }, | |
357 | 24058 | frame.f->time_base); | |
358 | } | ||
359 | |||
360 | 33154 | ts = frame_end(sq, frame, 0); | |
361 | |||
362 | 33154 | av_log(sq->logctx, AV_LOG_DEBUG, "sq: send %u ts %s\n", stream_idx, | |
363 | 33154 | av_ts2timestr(ts, &st->tb)); | |
364 | |||
365 |
2/2✓ Branch 0 taken 32311 times.
✓ Branch 1 taken 843 times.
|
33154 | ret = av_container_fifo_write(st->fifo, SQPTR(sq, frame), 0); |
366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33154 times.
|
33154 | if (ret < 0) |
367 | ✗ | return ret; | |
368 | |||
369 | 33154 | stream_update_ts(sq, stream_idx, ts); | |
370 | |||
371 | 33154 | st->samples_queued += nb_samples; | |
372 | 33154 | st->samples_sent += nb_samples; | |
373 | |||
374 |
2/2✓ Branch 0 taken 19960 times.
✓ Branch 1 taken 13194 times.
|
33154 | if (st->frame_samples) |
375 | 19960 | st->frames_sent = st->samples_sent / st->frame_samples; | |
376 | else | ||
377 | 13194 | st->frames_sent++; | |
378 | |||
379 |
2/2✓ Branch 0 taken 2946 times.
✓ Branch 1 taken 30208 times.
|
33154 | if (st->frames_sent >= st->frames_max) { |
380 | 2946 | av_log(sq->logctx, AV_LOG_DEBUG, "sq: %u frames_max %"PRIu64" reached\n", | |
381 | stream_idx, st->frames_max); | ||
382 | |||
383 | 2946 | finish_stream(sq, stream_idx); | |
384 | } | ||
385 | |||
386 | 33154 | return 0; | |
387 | } | ||
388 | |||
389 | 65102 | static void offset_audio(AVFrame *f, int nb_samples) | |
390 | { | ||
391 | 65102 | const int planar = av_sample_fmt_is_planar(f->format); | |
392 |
2/2✓ Branch 0 taken 29370 times.
✓ Branch 1 taken 35732 times.
|
65102 | const int planes = planar ? f->ch_layout.nb_channels : 1; |
393 | 65102 | const int bps = av_get_bytes_per_sample(f->format); | |
394 |
2/2✓ Branch 0 taken 35732 times.
✓ Branch 1 taken 29370 times.
|
65102 | const int offset = nb_samples * bps * (planar ? 1 : f->ch_layout.nb_channels); |
395 | |||
396 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65102 times.
|
65102 | av_assert0(bps > 0); |
397 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65102 times.
|
65102 | av_assert0(nb_samples < f->nb_samples); |
398 | |||
399 |
2/2✓ Branch 0 taken 93888 times.
✓ Branch 1 taken 65102 times.
|
158990 | for (int i = 0; i < planes; i++) { |
400 | 93888 | f->extended_data[i] += offset; | |
401 |
1/2✓ Branch 0 taken 93888 times.
✗ Branch 1 not taken.
|
93888 | if (i < FF_ARRAY_ELEMS(f->data)) |
402 | 93888 | f->data[i] = f->extended_data[i]; | |
403 | } | ||
404 | 65102 | f->linesize[0] -= offset; | |
405 | 65102 | f->nb_samples -= nb_samples; | |
406 | 65102 | f->duration = av_rescale_q(f->nb_samples, (AVRational){ 1, f->sample_rate }, | |
407 | f->time_base); | ||
408 | 65102 | f->pts += av_rescale_q(nb_samples, (AVRational){ 1, f->sample_rate }, | |
409 | f->time_base); | ||
410 | 65102 | } | |
411 | |||
412 | 56999 | static int frame_is_aligned(const SyncQueue *sq, const AVFrame *frame) | |
413 | { | ||
414 | // only checks linesize[0], so only works for audio | ||
415 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56999 times.
|
56999 | av_assert0(frame->nb_samples > 0); |
416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56999 times.
|
56999 | av_assert0(sq->align_mask); |
417 | |||
418 | // only check data[0], because we always offset all data pointers | ||
419 | // by the same offset, so if one is aligned, all are | ||
420 |
2/2✓ Branch 0 taken 56451 times.
✓ Branch 1 taken 548 times.
|
56999 | if (!((uintptr_t)frame->data[0] & sq->align_mask) && |
421 |
1/2✓ Branch 0 taken 56451 times.
✗ Branch 1 not taken.
|
56451 | !(frame->linesize[0] & sq->align_mask) && |
422 |
1/2✓ Branch 0 taken 56451 times.
✗ Branch 1 not taken.
|
56451 | frame->linesize[0] > sq->align_mask) |
423 | 56451 | return 1; | |
424 | |||
425 | 548 | return 0; | |
426 | } | ||
427 | |||
428 | 66391 | static int receive_samples(SyncQueue *sq, SyncQueueStream *st, | |
429 | AVFrame *dst, int nb_samples) | ||
430 | { | ||
431 | SyncQueueFrame src; | ||
432 | int ret; | ||
433 | |||
434 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66391 times.
|
66391 | av_assert0(st->samples_queued >= nb_samples); |
435 | |||
436 | 66391 | ret = av_container_fifo_peek(st->fifo, (void**)&src, 0); | |
437 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66391 times.
|
66391 | av_assert0(ret >= 0); |
438 | |||
439 | // peeked frame has enough samples and its data is aligned | ||
440 | // -> we can just make a reference and limit its sample count | ||
441 |
4/4✓ Branch 0 taken 52588 times.
✓ Branch 1 taken 13803 times.
✓ Branch 3 taken 52041 times.
✓ Branch 4 taken 547 times.
|
66391 | if (src.f->nb_samples > nb_samples && frame_is_aligned(sq, src.f)) { |
442 | 52041 | ret = av_frame_ref(dst, src.f); | |
443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52041 times.
|
52041 | if (ret < 0) |
444 | ✗ | return ret; | |
445 | |||
446 | 52041 | dst->nb_samples = nb_samples; | |
447 | 52041 | offset_audio(src.f, nb_samples); | |
448 | 52041 | st->samples_queued -= nb_samples; | |
449 | |||
450 | 52041 | goto finish; | |
451 | } | ||
452 | |||
453 | // otherwise allocate a new frame and copy the data | ||
454 | 14350 | ret = av_channel_layout_copy(&dst->ch_layout, &src.f->ch_layout); | |
455 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14350 times.
|
14350 | if (ret < 0) |
456 | ✗ | return ret; | |
457 | |||
458 | 14350 | dst->format = src.f->format; | |
459 | 14350 | dst->nb_samples = nb_samples; | |
460 | |||
461 | 14350 | ret = av_frame_get_buffer(dst, 0); | |
462 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14350 times.
|
14350 | if (ret < 0) |
463 | ✗ | goto fail; | |
464 | |||
465 | 14350 | ret = av_frame_copy_props(dst, src.f); | |
466 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14350 times.
|
14350 | if (ret < 0) |
467 | ✗ | goto fail; | |
468 | |||
469 | 14350 | dst->nb_samples = 0; | |
470 |
2/2✓ Branch 0 taken 28609 times.
✓ Branch 1 taken 14350 times.
|
42959 | while (dst->nb_samples < nb_samples) { |
471 | int to_copy; | ||
472 | |||
473 | 28609 | ret = av_container_fifo_peek(st->fifo, (void**)&src, 0); | |
474 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28609 times.
|
28609 | av_assert0(ret >= 0); |
475 | |||
476 | 28609 | to_copy = FFMIN(nb_samples - dst->nb_samples, src.f->nb_samples); | |
477 | |||
478 | 28609 | av_samples_copy(dst->extended_data, src.f->extended_data, dst->nb_samples, | |
479 | 28609 | 0, to_copy, dst->ch_layout.nb_channels, dst->format); | |
480 | |||
481 |
2/2✓ Branch 0 taken 13061 times.
✓ Branch 1 taken 15548 times.
|
28609 | if (to_copy < src.f->nb_samples) |
482 | 13061 | offset_audio(src.f, to_copy); | |
483 | else | ||
484 | 15548 | av_container_fifo_drain(st->fifo, 1); | |
485 | |||
486 | 28609 | st->samples_queued -= to_copy; | |
487 | |||
488 | 28609 | dst->nb_samples += to_copy; | |
489 | } | ||
490 | |||
491 | 14350 | finish: | |
492 | 66391 | dst->duration = av_rescale_q(nb_samples, (AVRational){ 1, dst->sample_rate }, | |
493 | dst->time_base); | ||
494 | |||
495 | 66391 | return 0; | |
496 | |||
497 | ✗ | fail: | |
498 | ✗ | av_frame_unref(dst); | |
499 | ✗ | return ret; | |
500 | } | ||
501 | |||
502 | 129415 | static int receive_for_stream(SyncQueue *sq, unsigned int stream_idx, | |
503 | SyncQueueFrame frame) | ||
504 | { | ||
505 | 258830 | const SyncQueueStream *st_head = sq->head_stream >= 0 ? | |
506 |
2/2✓ Branch 0 taken 30248 times.
✓ Branch 1 taken 99167 times.
|
129415 | &sq->streams[sq->head_stream] : NULL; |
507 | SyncQueueStream *st; | ||
508 | |||
509 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 129415 times.
|
129415 | av_assert0(stream_idx < sq->nb_streams); |
510 | 129415 | st = &sq->streams[stream_idx]; | |
511 | |||
512 |
2/2✓ Branch 1 taken 104300 times.
✓ Branch 2 taken 25115 times.
|
129415 | if (av_container_fifo_can_read(st->fifo) && |
513 |
4/4✓ Branch 0 taken 19353 times.
✓ Branch 1 taken 84947 times.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 19191 times.
|
104300 | (st->frame_samples <= st->samples_queued || st->finished)) { |
514 | 85109 | int nb_samples = st->frame_samples; | |
515 | SyncQueueFrame peek; | ||
516 | int64_t ts; | ||
517 | 85109 | int cmp = 1; | |
518 | |||
519 |
2/2✓ Branch 0 taken 3452 times.
✓ Branch 1 taken 81657 times.
|
85109 | if (st->finished) |
520 | 3452 | nb_samples = FFMIN(nb_samples, st->samples_queued); | |
521 | |||
522 | 85109 | av_container_fifo_peek(st->fifo, (void**)&peek, 0); | |
523 | 85109 | ts = frame_end(sq, peek, nb_samples); | |
524 | |||
525 | /* check if this stream's tail timestamp does not overtake | ||
526 | * the overall queue head */ | ||
527 |
4/4✓ Branch 0 taken 85106 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 14023 times.
✓ Branch 3 taken 71083 times.
|
85109 | if (ts != AV_NOPTS_VALUE && st_head) |
528 | 14023 | cmp = av_compare_ts(ts, st->tb, st_head->head_ts, st_head->tb); | |
529 | |||
530 | /* We can release frames that do not end after the queue head. | ||
531 | * Frames with no timestamps are just passed through with no conditions. | ||
532 | * Frames are also passed through when there are no limiting streams. | ||
533 | */ | ||
534 |
6/6✓ Branch 0 taken 72182 times.
✓ Branch 1 taken 12927 times.
✓ Branch 2 taken 72179 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 71017 times.
✓ Branch 5 taken 1162 times.
|
85109 | if (cmp <= 0 || ts == AV_NOPTS_VALUE || !sq->have_limiting) { |
535 |
2/2✓ Branch 0 taken 70801 times.
✓ Branch 1 taken 13146 times.
|
83947 | if (nb_samples && |
536 |
4/4✓ Branch 0 taken 4411 times.
✓ Branch 1 taken 66390 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 4410 times.
|
137192 | (nb_samples != peek.f->nb_samples || !frame_is_aligned(sq, peek.f))) { |
537 | 66391 | int ret = receive_samples(sq, st, frame.f, nb_samples); | |
538 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66391 times.
|
66391 | if (ret < 0) |
539 | ✗ | return ret; | |
540 | } else { | ||
541 |
2/2✓ Branch 0 taken 16761 times.
✓ Branch 1 taken 795 times.
|
17556 | int ret = av_container_fifo_read(st->fifo, SQPTR(sq, frame), 0); |
542 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17556 times.
|
17556 | av_assert0(ret >= 0); |
543 | |||
544 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 17556 times.
|
17556 | av_assert0(st->samples_queued >= frame_samples(sq, frame)); |
545 | 17556 | st->samples_queued -= frame_samples(sq, frame); | |
546 | } | ||
547 | |||
548 |
2/2✓ Branch 0 taken 12927 times.
✓ Branch 1 taken 71020 times.
|
167894 | av_log(sq->logctx, AV_LOG_DEBUG, |
549 | "sq: receive %u ts %s queue head %d ts %s\n", stream_idx, | ||
550 | 83947 | av_ts2timestr(frame_end(sq, frame, 0), &st->tb), | |
551 | sq->head_stream, | ||
552 | 12927 | st_head ? av_ts2timestr(st_head->head_ts, &st_head->tb) : "N/A"); | |
553 | |||
554 | 83947 | return 0; | |
555 | } | ||
556 | } | ||
557 | |||
558 |
4/4✓ Branch 0 taken 1015 times.
✓ Branch 1 taken 37862 times.
✓ Branch 3 taken 773 times.
✓ Branch 4 taken 242 times.
|
38877 | return (sq->finished || (st->finished && !av_container_fifo_can_read(st->fifo))) ? |
559 |
2/2✓ Branch 0 taken 38877 times.
✓ Branch 1 taken 6591 times.
|
84345 | AVERROR_EOF : AVERROR(EAGAIN); |
560 | } | ||
561 | |||
562 | 120527 | static int receive_internal(SyncQueue *sq, int stream_idx, SyncQueueFrame frame) | |
563 | { | ||
564 | 120527 | int nb_eof = 0; | |
565 | int ret; | ||
566 | |||
567 | /* read a frame for a specific stream */ | ||
568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 120527 times.
|
120527 | if (stream_idx >= 0) { |
569 | ✗ | ret = receive_for_stream(sq, stream_idx, frame); | |
570 | ✗ | return (ret < 0) ? ret : stream_idx; | |
571 | } | ||
572 | |||
573 | /* read a frame for any stream with available output */ | ||
574 |
2/2✓ Branch 0 taken 129415 times.
✓ Branch 1 taken 36580 times.
|
165995 | for (unsigned int i = 0; i < sq->nb_streams; i++) { |
575 | 129415 | ret = receive_for_stream(sq, i, frame); | |
576 |
4/4✓ Branch 0 taken 122051 times.
✓ Branch 1 taken 7364 times.
✓ Branch 2 taken 38104 times.
✓ Branch 3 taken 83947 times.
|
129415 | if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) { |
577 | 45468 | nb_eof += (ret == AVERROR_EOF); | |
578 | 45468 | continue; | |
579 | } | ||
580 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83947 times.
|
83947 | return (ret < 0) ? ret : i; |
581 | } | ||
582 | |||
583 |
2/2✓ Branch 0 taken 6187 times.
✓ Branch 1 taken 30393 times.
|
36580 | return (nb_eof == sq->nb_streams) ? AVERROR_EOF : AVERROR(EAGAIN); |
584 | } | ||
585 | |||
586 | 120433 | int sq_receive(SyncQueue *sq, int stream_idx, SyncQueueFrame frame) | |
587 | { | ||
588 | 120433 | int ret = receive_internal(sq, stream_idx, frame); | |
589 | |||
590 | /* try again if the queue overflowed and triggered a fake heartbeat | ||
591 | * for lagging streams */ | ||
592 |
4/4✓ Branch 0 taken 30393 times.
✓ Branch 1 taken 90040 times.
✓ Branch 3 taken 94 times.
✓ Branch 4 taken 30299 times.
|
120433 | if (ret == AVERROR(EAGAIN) && overflow_heartbeat(sq, stream_idx)) |
593 | 94 | ret = receive_internal(sq, stream_idx, frame); | |
594 | |||
595 | 120433 | return ret; | |
596 | } | ||
597 | |||
598 | 3176 | int sq_add_stream(SyncQueue *sq, int limiting) | |
599 | { | ||
600 | SyncQueueStream *tmp, *st; | ||
601 | |||
602 | 3176 | tmp = av_realloc_array(sq->streams, sq->nb_streams + 1, sizeof(*sq->streams)); | |
603 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3176 times.
|
3176 | if (!tmp) |
604 | ✗ | return AVERROR(ENOMEM); | |
605 | 3176 | sq->streams = tmp; | |
606 | |||
607 | 3176 | st = &sq->streams[sq->nb_streams]; | |
608 | 3176 | memset(st, 0, sizeof(*st)); | |
609 | |||
610 | 6352 | st->fifo = (sq->type == SYNC_QUEUE_FRAMES) ? | |
611 |
2/2✓ Branch 0 taken 3131 times.
✓ Branch 1 taken 45 times.
|
3176 | av_container_fifo_alloc_avframe(0) : av_container_fifo_alloc_avpacket(0); |
612 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3176 times.
|
3176 | if (!st->fifo) |
613 | ✗ | return AVERROR(ENOMEM); | |
614 | |||
615 | /* we set a valid default, so that a pathological stream that never | ||
616 | * receives even a real timebase (and no frames) won't stall all other | ||
617 | * streams forever; cf. overflow_heartbeat() */ | ||
618 | 3176 | st->tb = (AVRational){ 1, 1 }; | |
619 | 3176 | st->head_ts = AV_NOPTS_VALUE; | |
620 | 3176 | st->frames_max = UINT64_MAX; | |
621 | 3176 | st->limiting = limiting; | |
622 | |||
623 | 3176 | sq->have_limiting |= limiting; | |
624 | |||
625 | 3176 | return sq->nb_streams++; | |
626 | } | ||
627 | |||
628 | 2971 | void sq_limit_frames(SyncQueue *sq, unsigned int stream_idx, uint64_t frames) | |
629 | { | ||
630 | SyncQueueStream *st; | ||
631 | |||
632 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2971 times.
|
2971 | av_assert0(stream_idx < sq->nb_streams); |
633 | 2971 | st = &sq->streams[stream_idx]; | |
634 | |||
635 | 2971 | st->frames_max = frames; | |
636 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 2948 times.
|
2971 | if (st->frames_sent >= st->frames_max) |
637 | 23 | finish_stream(sq, stream_idx); | |
638 | 2971 | } | |
639 | |||
640 | 173 | void sq_frame_samples(SyncQueue *sq, unsigned int stream_idx, | |
641 | int frame_samples) | ||
642 | { | ||
643 | SyncQueueStream *st; | ||
644 | |||
645 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
|
173 | av_assert0(sq->type == SYNC_QUEUE_FRAMES); |
646 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
|
173 | av_assert0(stream_idx < sq->nb_streams); |
647 | 173 | st = &sq->streams[stream_idx]; | |
648 | |||
649 | 173 | st->frame_samples = frame_samples; | |
650 | |||
651 | 173 | sq->align_mask = av_cpu_max_align() - 1; | |
652 | 173 | } | |
653 | |||
654 | 3086 | SyncQueue *sq_alloc(enum SyncQueueType type, int64_t buf_size_us, void *logctx) | |
655 | { | ||
656 | 3086 | SyncQueue *sq = av_mallocz(sizeof(*sq)); | |
657 | |||
658 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3086 times.
|
3086 | if (!sq) |
659 | ✗ | return NULL; | |
660 | |||
661 | 3086 | sq->type = type; | |
662 | 3086 | sq->buf_size_us = buf_size_us; | |
663 | 3086 | sq->logctx = logctx; | |
664 | |||
665 | 3086 | sq->head_stream = -1; | |
666 | 3086 | sq->head_finished_stream = -1; | |
667 | |||
668 | 3086 | return sq; | |
669 | } | ||
670 | |||
671 | 10994 | void sq_free(SyncQueue **psq) | |
672 | { | ||
673 | 10994 | SyncQueue *sq = *psq; | |
674 | |||
675 |
2/2✓ Branch 0 taken 7908 times.
✓ Branch 1 taken 3086 times.
|
10994 | if (!sq) |
676 | 7908 | return; | |
677 | |||
678 |
2/2✓ Branch 0 taken 3176 times.
✓ Branch 1 taken 3086 times.
|
6262 | for (unsigned int i = 0; i < sq->nb_streams; i++) |
679 | 3176 | av_container_fifo_free(&sq->streams[i].fifo); | |
680 | |||
681 | 3086 | av_freep(&sq->streams); | |
682 | |||
683 | 3086 | av_freep(psq); | |
684 | } | ||
685 |