/src/mpv/demux/demux_timeline.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * This file is part of mpv. |
3 | | * |
4 | | * mpv 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 | | * mpv 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 |
12 | | * GNU 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 mpv. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | |
18 | | #include <assert.h> |
19 | | #include <limits.h> |
20 | | |
21 | | #include "common/common.h" |
22 | | #include "common/msg.h" |
23 | | |
24 | | #include "demux.h" |
25 | | #include "timeline.h" |
26 | | #include "stheader.h" |
27 | | #include "stream/stream.h" |
28 | | |
29 | | struct segment { |
30 | | int index; // index into virtual_source.segments[] (and timeline.parts[]) |
31 | | double start, end; |
32 | | double d_start; |
33 | | char *url; |
34 | | bool lazy; |
35 | | struct demuxer *d; |
36 | | // stream_map[sh_stream.index] = virtual_stream, where sh_stream is a stream |
37 | | // from the source d, and virtual_stream is a streamexported by the |
38 | | // timeline demuxer (virtual_stream.sh). It's used to map the streams of the |
39 | | // source onto the set of streams of the virtual timeline. |
40 | | // Uses NULL for streams that do not appear in the virtual timeline. |
41 | | struct virtual_stream **stream_map; |
42 | | int num_stream_map; |
43 | | }; |
44 | | |
45 | | // Information for each stream on the virtual timeline. (Mirrors streams |
46 | | // exposed by demux_timeline.) |
47 | | struct virtual_stream { |
48 | | struct sh_stream *sh; // stream exported by demux_timeline |
49 | | bool selected; // ==demux_stream_is_selected(sh) |
50 | | int eos_packets; // deal with b-frame delay |
51 | | struct virtual_source *src; // group this stream is part of |
52 | | }; |
53 | | |
54 | | // This represents a single timeline source. (See timeline.pars[]. For each |
55 | | // timeline_par struct there is a virtual_source.) |
56 | | struct virtual_source { |
57 | | struct timeline_par *tl; |
58 | | |
59 | | bool dash, no_clip, delay_open; |
60 | | |
61 | | struct segment **segments; |
62 | | int num_segments; |
63 | | struct segment *current; |
64 | | |
65 | | struct virtual_stream **streams; |
66 | | int num_streams; |
67 | | |
68 | | // Total number of packets received past end of segment. Used |
69 | | // to be clever about determining when to switch segments. |
70 | | int eos_packets; |
71 | | |
72 | | bool eof_reached; |
73 | | double dts; // highest read DTS (or PTS if no DTS available) |
74 | | bool any_selected; // at least one stream is actually selected |
75 | | |
76 | | struct demux_packet *next; |
77 | | }; |
78 | | |
79 | | struct priv { |
80 | | struct timeline *tl; |
81 | | bool owns_tl; |
82 | | |
83 | | double duration; |
84 | | |
85 | | // As the demuxer user sees it. |
86 | | struct virtual_stream **streams; |
87 | | int num_streams; |
88 | | |
89 | | struct virtual_source **sources; |
90 | | int num_sources; |
91 | | }; |
92 | | |
93 | | static void update_slave_stats(struct demuxer *demuxer, struct demuxer *slave) |
94 | 1.02M | { |
95 | 1.02M | demux_report_unbuffered_read_bytes(demuxer, demux_get_bytes_read_hack(slave)); |
96 | 1.02M | } |
97 | | |
98 | | static bool target_stream_used(struct segment *seg, struct virtual_stream *vs) |
99 | 14.7k | { |
100 | 15.7k | for (int n = 0; n < seg->num_stream_map; n++) { |
101 | 1.05k | if (seg->stream_map[n] == vs) |
102 | 124 | return true; |
103 | 1.05k | } |
104 | 14.6k | return false; |
105 | 14.7k | } |
106 | | |
107 | | // Create mapping from segment streams to virtual timeline streams. |
108 | | static void associate_streams(struct demuxer *demuxer, |
109 | | struct virtual_source *src, |
110 | | struct segment *seg) |
111 | 19.9k | { |
112 | 19.9k | if (!seg->d || seg->stream_map) |
113 | 2.64k | return; |
114 | | |
115 | 17.3k | int num_streams = demux_get_num_stream(seg->d); |
116 | 32.0k | for (int n = 0; n < num_streams; n++) { |
117 | 14.6k | struct sh_stream *sh = demux_get_stream(seg->d, n); |
118 | 14.6k | struct virtual_stream *other = NULL; |
119 | | |
120 | 31.6k | for (int i = 0; i < src->num_streams; i++) { |
121 | 16.9k | struct virtual_stream *vs = src->streams[i]; |
122 | | |
123 | | // The stream must always have the same media type. Also, a stream |
124 | | // can't be assigned multiple times. |
125 | 16.9k | if (sh->type != vs->sh->type || target_stream_used(seg, vs)) |
126 | 2.26k | continue; |
127 | | |
128 | | // By default pick the first matching stream. |
129 | 14.6k | if (!other) |
130 | 14.5k | other = vs; |
131 | | |
132 | | // Matching by demuxer ID is supposedly useful and preferable for |
133 | | // ordered chapters. |
134 | 14.6k | if (sh->demuxer_id >= 0 && sh->demuxer_id == vs->sh->demuxer_id) |
135 | 712 | other = vs; |
136 | 14.6k | } |
137 | | |
138 | 14.6k | if (!other) { |
139 | 148 | MP_WARN(demuxer, "Source stream %d (%s) unused and hidden.\n", |
140 | 148 | n, stream_type_name(sh->type)); |
141 | 148 | } |
142 | | |
143 | 14.6k | MP_TARRAY_APPEND(seg, seg->stream_map, seg->num_stream_map, other); |
144 | 14.6k | } |
145 | 17.3k | } |
146 | | |
147 | | static void reselect_streams(struct demuxer *demuxer) |
148 | 39.9k | { |
149 | 39.9k | struct priv *p = demuxer->priv; |
150 | | |
151 | 79.7k | for (int n = 0; n < p->num_streams; n++) { |
152 | 39.7k | struct virtual_stream *vs = p->streams[n]; |
153 | 39.7k | vs->selected = demux_stream_is_selected(vs->sh); |
154 | 39.7k | } |
155 | | |
156 | 79.9k | for (int x = 0; x < p->num_sources; x++) { |
157 | 39.9k | struct virtual_source *src = p->sources[x]; |
158 | | |
159 | 88.9k | for (int n = 0; n < src->num_segments; n++) { |
160 | 48.9k | struct segment *seg = src->segments[n]; |
161 | | |
162 | 48.9k | if (!seg->d) |
163 | 4.36k | continue; |
164 | | |
165 | 88.0k | for (int i = 0; i < seg->num_stream_map; i++) { |
166 | 43.5k | bool selected = |
167 | 43.5k | seg->stream_map[i] && seg->stream_map[i]->selected; |
168 | | |
169 | | // This stops demuxer readahead for inactive segments. |
170 | 43.5k | if (!src->current || seg->d != src->current->d) |
171 | 30.8k | selected = false; |
172 | 43.5k | struct sh_stream *sh = demux_get_stream(seg->d, i); |
173 | 43.5k | demuxer_select_track(seg->d, sh, MP_NOPTS_VALUE, selected); |
174 | | |
175 | 43.5k | update_slave_stats(demuxer, seg->d); |
176 | 43.5k | } |
177 | 44.5k | } |
178 | | |
179 | 39.9k | bool was_selected = src->any_selected; |
180 | 39.9k | src->any_selected = false; |
181 | | |
182 | 79.7k | for (int n = 0; n < src->num_streams; n++) |
183 | 39.7k | src->any_selected |= src->streams[n]->selected; |
184 | | |
185 | 39.9k | if (!was_selected && src->any_selected) { |
186 | 11.5k | src->eof_reached = false; |
187 | 11.5k | src->dts = MP_NOPTS_VALUE; |
188 | 11.5k | TA_FREEP(&src->next); |
189 | 11.5k | } |
190 | 39.9k | } |
191 | 39.9k | } |
192 | | |
193 | | static void close_lazy_segments(struct demuxer *demuxer, |
194 | | struct virtual_source *src) |
195 | 16.2k | { |
196 | | // unload previous segment |
197 | 35.2k | for (int n = 0; n < src->num_segments; n++) { |
198 | 18.9k | struct segment *seg = src->segments[n]; |
199 | 18.9k | if (seg != src->current && seg->d && seg->lazy) { |
200 | 373 | TA_FREEP(&src->next); // might depend on one of the sub-demuxers |
201 | 373 | demux_free(seg->d); |
202 | 373 | seg->d = NULL; |
203 | 373 | } |
204 | 18.9k | } |
205 | 16.2k | } |
206 | | |
207 | | static void reopen_lazy_segments(struct demuxer *demuxer, |
208 | | struct virtual_source *src) |
209 | 12.6k | { |
210 | 12.6k | if (src->current->d) |
211 | 11.6k | return; |
212 | | |
213 | | // Note: we must _not_ close segments during demuxing, |
214 | | // because demuxed packets have demux_packet.codec set to objects owned |
215 | | // by the segments. Closing them would create dangling pointers. |
216 | | |
217 | 1.00k | struct demuxer_params params = { |
218 | 1.00k | .init_fragment = src->tl->init_fragment, |
219 | 1.00k | .skip_lavf_probing = src->tl->dash, |
220 | 1.00k | .stream_flags = demuxer->stream_origin, |
221 | 1.00k | .depth = demuxer->depth + 1, |
222 | 1.00k | }; |
223 | 1.00k | src->current->d = demux_open_url(src->current->url, ¶ms, |
224 | 1.00k | demuxer->cancel, demuxer->global); |
225 | 1.00k | if (!src->current->d && !demux_cancel_test(demuxer)) |
226 | 1.00k | MP_ERR(demuxer, "failed to load segment\n"); |
227 | 1.00k | if (src->current->d) |
228 | 373 | update_slave_stats(demuxer, src->current->d); |
229 | 1.00k | associate_streams(demuxer, src, src->current); |
230 | 1.00k | } |
231 | | |
232 | | static void switch_segment(struct demuxer *demuxer, struct virtual_source *src, |
233 | | struct segment *new, double start_pts, int flags, |
234 | | bool init) |
235 | 12.6k | { |
236 | 12.6k | if (!(flags & SEEK_FORWARD)) |
237 | 12.6k | flags |= SEEK_HR; |
238 | | |
239 | 12.6k | MP_VERBOSE(demuxer, "switch to segment %d\n", new->index); |
240 | | |
241 | 12.6k | if (src->current && src->current->d) |
242 | 1.45k | update_slave_stats(demuxer, src->current->d); |
243 | | |
244 | 12.6k | src->current = new; |
245 | 12.6k | reopen_lazy_segments(demuxer, src); |
246 | 12.6k | if (!new->d) |
247 | 631 | return; |
248 | 12.0k | reselect_streams(demuxer); |
249 | 12.0k | if (!src->no_clip) |
250 | 11.6k | demux_set_ts_offset(new->d, new->start - new->d_start); |
251 | 12.0k | if (!src->no_clip || !init) |
252 | 11.8k | demux_seek(new->d, start_pts, flags); |
253 | | |
254 | 25.3k | for (int n = 0; n < src->num_streams; n++) { |
255 | 13.3k | struct virtual_stream *vs = src->streams[n]; |
256 | 13.3k | vs->eos_packets = 0; |
257 | 13.3k | } |
258 | | |
259 | 12.0k | src->eof_reached = false; |
260 | 12.0k | src->eos_packets = 0; |
261 | 12.0k | } |
262 | | |
263 | | static void do_read_next_packet(struct demuxer *demuxer, |
264 | | struct virtual_source *src) |
265 | 980k | { |
266 | 980k | if (src->next) |
267 | 0 | return; |
268 | | |
269 | 980k | struct segment *seg = src->current; |
270 | 980k | if (!seg || !seg->d) { |
271 | 0 | src->eof_reached = true; |
272 | 0 | return; |
273 | 0 | } |
274 | | |
275 | 980k | struct demux_packet *pkt = demux_read_any_packet(seg->d); |
276 | 980k | if (!pkt || (!src->no_clip && pkt->pts >= seg->end)) |
277 | 15.4k | src->eos_packets += 1; |
278 | | |
279 | 980k | update_slave_stats(demuxer, seg->d); |
280 | | |
281 | | // Test for EOF. Do this here to properly run into EOF even if other |
282 | | // streams are disabled etc. If it somehow doesn't manage to reach the end |
283 | | // after demuxing a high (bit arbitrary) number of packets, assume one of |
284 | | // the streams went EOF early. |
285 | 980k | bool eos_reached = src->eos_packets > 0; |
286 | 980k | if (eos_reached && src->eos_packets < 100) { |
287 | 41.6k | for (int n = 0; n < src->num_streams; n++) { |
288 | 22.5k | struct virtual_stream *vs = src->streams[n]; |
289 | 22.5k | if (vs->selected) { |
290 | 22.4k | int max_packets = 0; |
291 | 22.4k | if (vs->sh->type == STREAM_AUDIO) |
292 | 8.14k | max_packets = 1; |
293 | 22.4k | if (vs->sh->type == STREAM_VIDEO) |
294 | 14.2k | max_packets = 16; |
295 | 22.4k | eos_reached &= vs->eos_packets >= max_packets; |
296 | 22.4k | } |
297 | 22.5k | } |
298 | 19.1k | } |
299 | | |
300 | 980k | src->eof_reached = false; |
301 | | |
302 | 980k | if (eos_reached || !pkt) { |
303 | 11.7k | talloc_free(pkt); |
304 | | |
305 | 11.7k | struct segment *next = NULL; |
306 | 13.6k | for (int n = 0; n < src->num_segments - 1; n++) { |
307 | 3.33k | if (src->segments[n] == seg) { |
308 | 1.45k | next = src->segments[n + 1]; |
309 | 1.45k | break; |
310 | 1.45k | } |
311 | 3.33k | } |
312 | 11.7k | if (!next) { |
313 | 10.3k | src->eof_reached = true; |
314 | 10.3k | return; |
315 | 10.3k | } |
316 | 1.45k | switch_segment(demuxer, src, next, next->start, 0, true); |
317 | 1.45k | return; // reader will retry |
318 | 11.7k | } |
319 | | |
320 | 969k | if (pkt->stream < 0 || pkt->stream >= seg->num_stream_map) |
321 | 0 | goto drop; |
322 | | |
323 | 969k | if (!src->no_clip || src->delay_open) { |
324 | 872k | pkt->segmented = true; |
325 | 872k | if (!pkt->codec) |
326 | 852k | pkt->codec = demux_get_stream(seg->d, pkt->stream)->codec; |
327 | 872k | } |
328 | 969k | if (!src->no_clip) { |
329 | 872k | if (pkt->start == MP_NOPTS_VALUE || pkt->start < seg->start) |
330 | 853k | pkt->start = seg->start; |
331 | 872k | if (pkt->end == MP_NOPTS_VALUE || pkt->end > seg->end) |
332 | 852k | pkt->end = seg->end; |
333 | 872k | } |
334 | | |
335 | 969k | struct virtual_stream *vs = seg->stream_map[pkt->stream]; |
336 | 969k | if (!vs) |
337 | 0 | goto drop; |
338 | | |
339 | | // for refresh seeks, demux.c prefers monotonically increasing packet pos |
340 | | // since the packet pos is meaningless anyway for timeline, use it |
341 | 969k | if (pkt->pos >= 0) |
342 | 963k | pkt->pos |= (seg->index & 0x7FFFULL) << 48; |
343 | | |
344 | 969k | if (pkt->pts != MP_NOPTS_VALUE && !src->no_clip && pkt->pts >= seg->end) { |
345 | | // Trust the keyframe flag. Might not always be a good idea, but will |
346 | | // be sufficient at least with mkv. The problem is that this flag is |
347 | | // not well-defined in libavformat and is container-dependent. |
348 | 3.61k | if (pkt->keyframe || vs->eos_packets == INT_MAX) { |
349 | 2.78k | vs->eos_packets = INT_MAX; |
350 | 2.78k | goto drop; |
351 | 2.78k | } else { |
352 | 833 | vs->eos_packets += 1; |
353 | 833 | } |
354 | 3.61k | } |
355 | | |
356 | 966k | double dts = pkt->dts != MP_NOPTS_VALUE ? pkt->dts : pkt->pts; |
357 | 966k | if (src->dts == MP_NOPTS_VALUE || (dts != MP_NOPTS_VALUE && dts > src->dts)) |
358 | 779k | src->dts = dts; |
359 | | |
360 | 966k | pkt->stream = vs->sh->index; |
361 | 966k | src->next = pkt; |
362 | 966k | return; |
363 | | |
364 | 2.78k | drop: |
365 | 2.78k | talloc_free(pkt); |
366 | 2.78k | } |
367 | | |
368 | | static bool d_read_packet(struct demuxer *demuxer, struct demux_packet **out_pkt) |
369 | 991k | { |
370 | 991k | struct priv *p = demuxer->priv; |
371 | 991k | struct virtual_source *src = NULL; |
372 | | |
373 | 1.98M | for (int x = 0; x < p->num_sources; x++) { |
374 | 991k | struct virtual_source *cur = p->sources[x]; |
375 | | |
376 | 991k | if (!cur->any_selected || cur->eof_reached) |
377 | 10.3k | continue; |
378 | | |
379 | 981k | if (!cur->current) |
380 | 6.94k | switch_segment(demuxer, cur, cur->segments[0], 0, 0, true); |
381 | | |
382 | 981k | if (!cur->any_selected || !cur->current || !cur->current->d) |
383 | 631 | continue; |
384 | | |
385 | 980k | if (!src || cur->dts == MP_NOPTS_VALUE || |
386 | 980k | (src->dts != MP_NOPTS_VALUE && cur->dts < src->dts)) |
387 | 980k | src = cur; |
388 | 980k | } |
389 | | |
390 | 991k | if (!src) |
391 | 10.9k | return false; |
392 | | |
393 | 980k | do_read_next_packet(demuxer, src); |
394 | 980k | *out_pkt = src->next; |
395 | 980k | src->next = NULL; |
396 | 980k | return true; |
397 | 991k | } |
398 | | |
399 | | static void seek_source(struct demuxer *demuxer, struct virtual_source *src, |
400 | | double pts, int flags) |
401 | 4.26k | { |
402 | 4.26k | struct segment *new = src->segments[src->num_segments - 1]; |
403 | 4.79k | for (int n = 0; n < src->num_segments; n++) { |
404 | 4.43k | if (pts < src->segments[n]->end) { |
405 | 3.90k | new = src->segments[n]; |
406 | 3.90k | break; |
407 | 3.90k | } |
408 | 4.43k | } |
409 | | |
410 | 4.26k | switch_segment(demuxer, src, new, pts, flags, false); |
411 | | |
412 | 4.26k | src->dts = MP_NOPTS_VALUE; |
413 | 4.26k | TA_FREEP(&src->next); |
414 | 4.26k | } |
415 | | |
416 | | static void d_seek(struct demuxer *demuxer, double seek_pts, int flags) |
417 | 4.30k | { |
418 | 4.30k | struct priv *p = demuxer->priv; |
419 | | |
420 | 4.30k | seek_pts = seek_pts * ((flags & SEEK_FACTOR) ? p->duration : 1); |
421 | 4.30k | flags &= SEEK_FORWARD | SEEK_HR; |
422 | | |
423 | | // The intention is to seek audio streams to the same target as video |
424 | | // streams if they are separate streams. Video streams usually have more |
425 | | // coarse keyframe snapping, which could leave video without audio. |
426 | 4.30k | struct virtual_source *master = NULL; |
427 | 4.30k | bool has_slaves = false; |
428 | 8.60k | for (int x = 0; x < p->num_sources; x++) { |
429 | 4.30k | struct virtual_source *src = p->sources[x]; |
430 | | |
431 | 4.30k | bool any_audio = false, any_video = false; |
432 | 8.59k | for (int i = 0; i < src->num_streams; i++) { |
433 | 4.29k | struct virtual_stream *str = src->streams[i]; |
434 | 4.29k | if (str->selected) { |
435 | 4.26k | if (str->sh->type == STREAM_VIDEO) |
436 | 188 | any_video = true; |
437 | 4.26k | if (str->sh->type == STREAM_AUDIO) |
438 | 4.07k | any_audio = true; |
439 | 4.26k | } |
440 | 4.29k | } |
441 | | |
442 | 4.30k | if (any_video) |
443 | 188 | master = src; |
444 | | // A true slave stream is audio-only; this also prevents that the master |
445 | | // stream is considered a slave stream. |
446 | 4.30k | if (any_audio && !any_video) |
447 | 4.07k | has_slaves = true; |
448 | 4.30k | } |
449 | | |
450 | 4.30k | if (!has_slaves) |
451 | 227 | master = NULL; |
452 | | |
453 | 4.30k | if (master) { |
454 | 0 | seek_source(demuxer, master, seek_pts, flags); |
455 | 0 | do_read_next_packet(demuxer, master); |
456 | 0 | if (master->next && master->next->pts != MP_NOPTS_VALUE) { |
457 | | // Assume we got a seek target. Actually apply the heuristic. |
458 | 0 | MP_VERBOSE(demuxer, "adjust seek target from %f to %f\n", seek_pts, |
459 | 0 | master->next->pts); |
460 | 0 | seek_pts = master->next->pts; |
461 | 0 | flags &= ~(unsigned)SEEK_FORWARD; |
462 | 0 | } |
463 | 0 | } |
464 | | |
465 | 8.60k | for (int x = 0; x < p->num_sources; x++) { |
466 | 4.30k | struct virtual_source *src = p->sources[x]; |
467 | 4.30k | if (src != master && src->any_selected) |
468 | 4.26k | seek_source(demuxer, src, seek_pts, flags); |
469 | 4.30k | } |
470 | 4.30k | } |
471 | | |
472 | | static void print_timeline(struct demuxer *demuxer) |
473 | 16.2k | { |
474 | 16.2k | struct priv *p = demuxer->priv; |
475 | | |
476 | 16.2k | MP_VERBOSE(demuxer, "Timeline segments:\n"); |
477 | 32.5k | for (int x = 0; x < p->num_sources; x++) { |
478 | 16.2k | struct virtual_source *src = p->sources[x]; |
479 | | |
480 | 16.2k | if (x >= 1) |
481 | 16.2k | MP_VERBOSE(demuxer, " --- new parallel stream ---\n"); |
482 | | |
483 | 35.2k | for (int n = 0; n < src->num_segments; n++) { |
484 | 18.9k | struct segment *seg = src->segments[n]; |
485 | 18.9k | int src_num = n; |
486 | 22.4k | for (int i = 0; i < n; i++) { |
487 | 3.47k | if (seg->d && src->segments[i]->d == seg->d) { |
488 | 4 | src_num = i; |
489 | 4 | break; |
490 | 4 | } |
491 | 3.47k | } |
492 | 18.9k | MP_VERBOSE(demuxer, " %2d: %12f - %12f [%12f] (", |
493 | 18.9k | n, seg->start, seg->end, seg->d_start); |
494 | 33.3k | for (int i = 0; i < seg->num_stream_map; i++) { |
495 | 14.3k | struct virtual_stream *vs = seg->stream_map[i]; |
496 | 14.3k | MP_VERBOSE(demuxer, "%s%d", i ? " " : "", |
497 | 14.3k | vs ? vs->sh->index : -1); |
498 | 14.3k | } |
499 | 18.9k | MP_VERBOSE(demuxer, ")\n source %d:'%s'\n", src_num, seg->url); |
500 | 18.9k | } |
501 | | |
502 | 16.2k | if (src->dash) |
503 | 16.2k | MP_VERBOSE(demuxer, " (Using pseudo-DASH mode.)\n"); |
504 | 16.2k | } |
505 | 16.2k | MP_VERBOSE(demuxer, "Total duration: %f\n", p->duration); |
506 | 16.2k | } |
507 | | |
508 | | // Copy various (not all) metadata fields from src to dst, but try not to |
509 | | // overwrite fields in dst that are unset in src. |
510 | | // May keep data from src by reference. |
511 | | // Imperfect and arbitrary, only suited for EDL stuff. |
512 | | static void apply_meta(struct sh_stream *dst, struct sh_stream *src) |
513 | 13.9k | { |
514 | 13.9k | if (src->demuxer_id >= 0) |
515 | 713 | dst->demuxer_id = src->demuxer_id; |
516 | 13.9k | if (src->title) |
517 | 0 | dst->title = src->title; |
518 | 13.9k | if (src->lang) |
519 | 48 | dst->lang = src->lang; |
520 | 13.9k | dst->default_track = src->default_track; |
521 | 13.9k | dst->forced_track = src->forced_track; |
522 | 13.9k | if (src->hls_bitrate) |
523 | 0 | dst->hls_bitrate = src->hls_bitrate; |
524 | 13.9k | dst->missing_timestamps = src->missing_timestamps; |
525 | 13.9k | if (src->attached_picture) |
526 | 0 | dst->attached_picture = src->attached_picture; |
527 | 13.9k | dst->image = src->image; |
528 | 13.9k | } |
529 | | |
530 | | // This is mostly for EDL user-defined metadata. |
531 | | static struct sh_stream *find_matching_meta(struct timeline_par *tl, int index) |
532 | 13.9k | { |
533 | 13.9k | for (int n = 0; n < tl->num_sh_meta; n++) { |
534 | 1 | struct sh_stream *sh = tl->sh_meta[n]; |
535 | 1 | if (sh->index == index || sh->index < 0) |
536 | 1 | return sh; |
537 | 1 | } |
538 | 13.9k | return NULL; |
539 | 13.9k | } |
540 | | |
541 | | static bool add_tl(struct demuxer *demuxer, struct timeline_par *tl) |
542 | 16.2k | { |
543 | 16.2k | struct priv *p = demuxer->priv; |
544 | | |
545 | 16.2k | struct virtual_source *src = talloc_ptrtype(p, src); |
546 | 16.2k | *src = (struct virtual_source){ |
547 | 16.2k | .tl = tl, |
548 | 16.2k | .dash = tl->dash, |
549 | 16.2k | .delay_open = tl->delay_open, |
550 | 16.2k | .no_clip = tl->no_clip || tl->dash, |
551 | 16.2k | .dts = MP_NOPTS_VALUE, |
552 | 16.2k | }; |
553 | | |
554 | 16.2k | if (!tl->num_parts) |
555 | 0 | return false; |
556 | | |
557 | 16.2k | MP_TARRAY_APPEND(p, p->sources, p->num_sources, src); |
558 | | |
559 | 16.2k | p->duration = MPMAX(p->duration, tl->parts[tl->num_parts - 1].end); |
560 | | |
561 | 16.2k | struct demuxer *meta = tl->track_layout; |
562 | | |
563 | | // delay_open streams normally have meta==NULL, and 1 virtual stream |
564 | 16.2k | int num_streams = 0; |
565 | 16.2k | if (tl->delay_open) { |
566 | 0 | num_streams = tl->num_sh_meta; |
567 | 16.2k | } else if (meta) { |
568 | 16.2k | num_streams = demux_get_num_stream(meta); |
569 | 16.2k | } |
570 | 30.1k | for (int n = 0; n < num_streams; n++) { |
571 | 13.9k | struct sh_stream *new = NULL; |
572 | | |
573 | 13.9k | if (tl->delay_open) { |
574 | 0 | struct sh_stream *tsh = tl->sh_meta[n]; |
575 | 0 | new = demux_alloc_sh_stream(tsh->type); |
576 | 0 | new->codec = tsh->codec; |
577 | 0 | apply_meta(new, tsh); |
578 | 0 | demuxer->is_network = true; |
579 | 0 | demuxer->is_streaming = true; |
580 | 13.9k | } else { |
581 | 13.9k | struct sh_stream *sh = demux_get_stream(meta, n); |
582 | 13.9k | new = demux_alloc_sh_stream(sh->type); |
583 | 13.9k | apply_meta(new, sh); |
584 | 13.9k | new->codec = sh->codec; |
585 | 13.9k | struct sh_stream *tsh = find_matching_meta(tl, n); |
586 | 13.9k | if (tsh) |
587 | 1 | apply_meta(new, tsh); |
588 | 13.9k | } |
589 | | |
590 | 13.9k | demux_add_sh_stream(demuxer, new); |
591 | 13.9k | struct virtual_stream *vs = talloc_ptrtype(p, vs); |
592 | 13.9k | *vs = (struct virtual_stream){ |
593 | 13.9k | .src = src, |
594 | 13.9k | .sh = new, |
595 | 13.9k | }; |
596 | 13.9k | MP_TARRAY_APPEND(p, p->streams, p->num_streams, vs); |
597 | 13.9k | mp_assert(demux_get_stream(demuxer, p->num_streams - 1) == new); |
598 | 13.9k | MP_TARRAY_APPEND(src, src->streams, src->num_streams, vs); |
599 | 13.9k | } |
600 | | |
601 | 35.2k | for (int n = 0; n < tl->num_parts; n++) { |
602 | 18.9k | struct timeline_part *part = &tl->parts[n]; |
603 | | |
604 | | // demux_timeline already does caching, doing it for the sub-demuxers |
605 | | // would be pointless and wasteful. |
606 | 18.9k | if (part->source) { |
607 | 16.9k | demuxer->is_network |= part->source->is_network; |
608 | 16.9k | demuxer->is_streaming |= part->source->is_streaming; |
609 | 16.9k | } |
610 | | |
611 | 18.9k | if (!part->source) |
612 | 18.9k | mp_assert(tl->dash || tl->delay_open); |
613 | | |
614 | 18.9k | struct segment *seg = talloc_ptrtype(src, seg); |
615 | 18.9k | *seg = (struct segment){ |
616 | 18.9k | .d = part->source, |
617 | 18.9k | .url = part->source ? part->source->filename : part->url, |
618 | 18.9k | .lazy = !part->source, |
619 | 18.9k | .d_start = part->source_start, |
620 | 18.9k | .start = part->start, |
621 | 18.9k | .end = part->end, |
622 | 18.9k | }; |
623 | | |
624 | 18.9k | associate_streams(demuxer, src, seg); |
625 | | |
626 | 18.9k | seg->index = n; |
627 | 18.9k | MP_TARRAY_APPEND(src, src->segments, src->num_segments, seg); |
628 | 18.9k | } |
629 | | |
630 | 16.2k | if (tl->track_layout) { |
631 | 16.2k | demuxer->is_network |= tl->track_layout->is_network; |
632 | 16.2k | demuxer->is_streaming |= tl->track_layout->is_streaming; |
633 | 16.2k | } |
634 | 16.2k | return true; |
635 | 16.2k | } |
636 | | |
637 | | static int d_open(struct demuxer *demuxer, enum demux_check check) |
638 | 16.2k | { |
639 | 16.2k | struct priv *p = demuxer->priv = talloc_zero(demuxer, struct priv); |
640 | 16.2k | p->tl = demuxer->params ? demuxer->params->timeline : NULL; |
641 | 16.2k | if (!p->tl || p->tl->num_pars < 1) |
642 | 0 | return -1; |
643 | | |
644 | 16.2k | demuxer->chapters = p->tl->chapters; |
645 | 16.2k | demuxer->num_chapters = p->tl->num_chapters; |
646 | | |
647 | 16.2k | struct demuxer *meta = p->tl->meta; |
648 | 16.2k | if (meta) { |
649 | 16.2k | demuxer->metadata = meta->metadata; |
650 | 16.2k | demuxer->attachments = meta->attachments; |
651 | 16.2k | demuxer->num_attachments = meta->num_attachments; |
652 | 16.2k | demuxer->editions = meta->editions; |
653 | 16.2k | demuxer->num_editions = meta->num_editions; |
654 | 16.2k | demuxer->edition = meta->edition; |
655 | 16.2k | } |
656 | | |
657 | 32.5k | for (int n = 0; n < p->tl->num_pars; n++) { |
658 | 16.2k | if (!add_tl(demuxer, p->tl->pars[n])) |
659 | 0 | return -1; |
660 | 16.2k | } |
661 | | |
662 | 16.2k | if (!p->num_sources) |
663 | 0 | return -1; |
664 | | |
665 | 16.2k | demuxer->is_network |= p->tl->is_network; |
666 | 16.2k | demuxer->is_streaming |= p->tl->is_streaming; |
667 | | |
668 | 16.2k | demuxer->duration = p->duration; |
669 | | |
670 | 16.2k | print_timeline(demuxer); |
671 | | |
672 | 16.2k | demuxer->seekable = true; |
673 | 16.2k | demuxer->partially_seekable = false; |
674 | | |
675 | 16.2k | const char *format_name = "unknown"; |
676 | 16.2k | if (meta) |
677 | 16.2k | format_name = meta->filetype ? meta->filetype : meta->desc->name; |
678 | 16.2k | demuxer->filetype = talloc_asprintf(p, "%s/%s", p->tl->format, format_name); |
679 | | |
680 | 16.2k | reselect_streams(demuxer); |
681 | | |
682 | 16.2k | p->owns_tl = true; |
683 | 16.2k | return 0; |
684 | 16.2k | } |
685 | | |
686 | | static void d_close(struct demuxer *demuxer) |
687 | 16.2k | { |
688 | 16.2k | struct priv *p = demuxer->priv; |
689 | | |
690 | 32.5k | for (int x = 0; x < p->num_sources; x++) { |
691 | 16.2k | struct virtual_source *src = p->sources[x]; |
692 | | |
693 | 16.2k | src->current = NULL; |
694 | 16.2k | TA_FREEP(&src->next); |
695 | 16.2k | close_lazy_segments(demuxer, src); |
696 | 16.2k | } |
697 | | |
698 | 16.2k | if (p->owns_tl) { |
699 | 16.2k | struct demuxer *master = p->tl->demuxer; |
700 | 16.2k | timeline_destroy(p->tl); |
701 | 16.2k | demux_free(master); |
702 | 16.2k | } |
703 | 16.2k | } |
704 | | |
705 | | static void d_switched_tracks(struct demuxer *demuxer) |
706 | 11.7k | { |
707 | 11.7k | reselect_streams(demuxer); |
708 | 11.7k | } |
709 | | |
710 | | const demuxer_desc_t demuxer_desc_timeline = { |
711 | | .name = "timeline", |
712 | | .desc = "timeline segments", |
713 | | .read_packet = d_read_packet, |
714 | | .open = d_open, |
715 | | .close = d_close, |
716 | | .seek = d_seek, |
717 | | .switched_tracks = d_switched_tracks, |
718 | | }; |