/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 | 84.5M | { |
95 | 84.5M | demux_report_unbuffered_read_bytes(demuxer, demux_get_bytes_read_hack(slave)); |
96 | 84.5M | } |
97 | | |
98 | | static bool target_stream_used(struct segment *seg, struct virtual_stream *vs) |
99 | 145k | { |
100 | 162k | for (int n = 0; n < seg->num_stream_map; n++) { |
101 | 16.6k | if (seg->stream_map[n] == vs) |
102 | 0 | return true; |
103 | 16.6k | } |
104 | 145k | return false; |
105 | 145k | } |
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 | 275k | { |
112 | 275k | if (!seg->d || seg->stream_map) |
113 | 85.1k | return; |
114 | | |
115 | 190k | int num_streams = demux_get_num_stream(seg->d); |
116 | 341k | for (int n = 0; n < num_streams; n++) { |
117 | 150k | struct sh_stream *sh = demux_get_stream(seg->d, n); |
118 | 150k | struct virtual_stream *other = NULL; |
119 | | |
120 | 378k | for (int i = 0; i < src->num_streams; i++) { |
121 | 227k | 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 | 227k | if (sh->type != vs->sh->type || target_stream_used(seg, vs)) |
126 | 82.2k | continue; |
127 | | |
128 | | // By default pick the first matching stream. |
129 | 145k | if (!other) |
130 | 145k | other = vs; |
131 | | |
132 | | // Matching by demuxer ID is supposedly useful and preferable for |
133 | | // ordered chapters. |
134 | 145k | if (sh->demuxer_id >= 0 && sh->demuxer_id == vs->sh->demuxer_id) |
135 | 283 | other = vs; |
136 | 145k | } |
137 | | |
138 | 150k | if (!other) { |
139 | 5.27k | MP_WARN(demuxer, "Source stream %d (%s) unused and hidden.\n", |
140 | 5.27k | n, stream_type_name(sh->type)); |
141 | 5.27k | } |
142 | | |
143 | 150k | MP_TARRAY_APPEND(seg, seg->stream_map, seg->num_stream_map, other); |
144 | 150k | } |
145 | 190k | } |
146 | | |
147 | | static void reselect_streams(struct demuxer *demuxer) |
148 | 287k | { |
149 | 287k | struct priv *p = demuxer->priv; |
150 | | |
151 | 622k | for (int n = 0; n < p->num_streams; n++) { |
152 | 335k | struct virtual_stream *vs = p->streams[n]; |
153 | 335k | vs->selected = demux_stream_is_selected(vs->sh); |
154 | 335k | } |
155 | | |
156 | 574k | for (int x = 0; x < p->num_sources; x++) { |
157 | 287k | struct virtual_source *src = p->sources[x]; |
158 | | |
159 | 80.6M | for (int n = 0; n < src->num_segments; n++) { |
160 | 80.4M | struct segment *seg = src->segments[n]; |
161 | | |
162 | 80.4M | if (!seg->d) |
163 | 950k | continue; |
164 | | |
165 | 161M | for (int i = 0; i < seg->num_stream_map; i++) { |
166 | 82.4M | bool selected = |
167 | 82.4M | seg->stream_map[i] && seg->stream_map[i]->selected; |
168 | | |
169 | | // This stops demuxer readahead for inactive segments. |
170 | 82.4M | if (!src->current || seg->d != src->current->d) |
171 | 77.9M | selected = false; |
172 | 82.4M | struct sh_stream *sh = demux_get_stream(seg->d, i); |
173 | 82.4M | demuxer_select_track(seg->d, sh, MP_NOPTS_VALUE, selected); |
174 | | |
175 | 82.4M | update_slave_stats(demuxer, seg->d); |
176 | 82.4M | } |
177 | 79.4M | } |
178 | | |
179 | 287k | bool was_selected = src->any_selected; |
180 | 287k | src->any_selected = false; |
181 | | |
182 | 622k | for (int n = 0; n < src->num_streams; n++) |
183 | 335k | src->any_selected |= src->streams[n]->selected; |
184 | | |
185 | 287k | if (!was_selected && src->any_selected) { |
186 | 36.5k | src->eof_reached = false; |
187 | 36.5k | src->dts = MP_NOPTS_VALUE; |
188 | 36.5k | TA_FREEP(&src->next); |
189 | 36.5k | } |
190 | 287k | } |
191 | 287k | } |
192 | | |
193 | | static void close_lazy_segments(struct demuxer *demuxer, |
194 | | struct virtual_source *src) |
195 | 34.4k | { |
196 | | // unload previous segment |
197 | 300k | for (int n = 0; n < src->num_segments; n++) { |
198 | 266k | struct segment *seg = src->segments[n]; |
199 | 266k | if (seg != src->current && seg->d && seg->lazy) { |
200 | 8.87k | TA_FREEP(&src->next); // might depend on one of the sub-demuxers |
201 | 8.87k | demux_free(seg->d); |
202 | 8.87k | seg->d = NULL; |
203 | 8.87k | } |
204 | 266k | } |
205 | 34.4k | } |
206 | | |
207 | | static void reopen_lazy_segments(struct demuxer *demuxer, |
208 | | struct virtual_source *src) |
209 | 188k | { |
210 | 188k | if (src->current->d) |
211 | 178k | 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 | 9.44k | struct demuxer_params params = { |
218 | 9.44k | .init_fragment = src->tl->init_fragment, |
219 | 9.44k | .skip_lavf_probing = src->tl->dash, |
220 | 9.44k | .stream_flags = demuxer->stream_origin, |
221 | 9.44k | }; |
222 | 9.44k | src->current->d = demux_open_url(src->current->url, ¶ms, |
223 | 9.44k | demuxer->cancel, demuxer->global); |
224 | 9.44k | if (!src->current->d && !demux_cancel_test(demuxer)) |
225 | 9.44k | MP_ERR(demuxer, "failed to load segment\n"); |
226 | 9.44k | if (src->current->d) |
227 | 8.87k | update_slave_stats(demuxer, src->current->d); |
228 | 9.44k | associate_streams(demuxer, src, src->current); |
229 | 9.44k | } |
230 | | |
231 | | static void switch_segment(struct demuxer *demuxer, struct virtual_source *src, |
232 | | struct segment *new, double start_pts, int flags, |
233 | | bool init) |
234 | 188k | { |
235 | 188k | if (!(flags & SEEK_FORWARD)) |
236 | 188k | flags |= SEEK_HR; |
237 | | |
238 | 188k | MP_VERBOSE(demuxer, "switch to segment %d\n", new->index); |
239 | | |
240 | 188k | if (src->current && src->current->d) |
241 | 171k | update_slave_stats(demuxer, src->current->d); |
242 | | |
243 | 188k | src->current = new; |
244 | 188k | reopen_lazy_segments(demuxer, src); |
245 | 188k | if (!new->d) |
246 | 565 | return; |
247 | 187k | reselect_streams(demuxer); |
248 | 187k | if (!src->no_clip) |
249 | 178k | demux_set_ts_offset(new->d, new->start - new->d_start); |
250 | 187k | if (!src->no_clip || !init) |
251 | 178k | demux_seek(new->d, start_pts, flags); |
252 | | |
253 | 435k | for (int n = 0; n < src->num_streams; n++) { |
254 | 248k | struct virtual_stream *vs = src->streams[n]; |
255 | 248k | vs->eos_packets = 0; |
256 | 248k | } |
257 | | |
258 | 187k | src->eof_reached = false; |
259 | 187k | src->eos_packets = 0; |
260 | 187k | } |
261 | | |
262 | | static void do_read_next_packet(struct demuxer *demuxer, |
263 | | struct virtual_source *src) |
264 | 1.89M | { |
265 | 1.89M | if (src->next) |
266 | 0 | return; |
267 | | |
268 | 1.89M | struct segment *seg = src->current; |
269 | 1.89M | if (!seg || !seg->d) { |
270 | 0 | src->eof_reached = true; |
271 | 0 | return; |
272 | 0 | } |
273 | | |
274 | 1.89M | struct demux_packet *pkt = demux_read_any_packet(seg->d); |
275 | 1.89M | if (!pkt || (!src->no_clip && pkt->pts >= seg->end)) |
276 | 192k | src->eos_packets += 1; |
277 | | |
278 | 1.89M | update_slave_stats(demuxer, seg->d); |
279 | | |
280 | | // Test for EOF. Do this here to properly run into EOF even if other |
281 | | // streams are disabled etc. If it somehow doesn't manage to reach the end |
282 | | // after demuxing a high (bit arbitrary) number of packets, assume one of |
283 | | // the streams went EOF early. |
284 | 1.89M | bool eos_reached = src->eos_packets > 0; |
285 | 1.89M | if (eos_reached && src->eos_packets < 100) { |
286 | 446k | for (int n = 0; n < src->num_streams; n++) { |
287 | 253k | struct virtual_stream *vs = src->streams[n]; |
288 | 253k | if (vs->selected) { |
289 | 253k | int max_packets = 0; |
290 | 253k | if (vs->sh->type == STREAM_AUDIO) |
291 | 146k | max_packets = 1; |
292 | 253k | if (vs->sh->type == STREAM_VIDEO) |
293 | 106k | max_packets = 16; |
294 | 253k | eos_reached &= vs->eos_packets >= max_packets; |
295 | 253k | } |
296 | 253k | } |
297 | 192k | } |
298 | | |
299 | 1.89M | src->eof_reached = false; |
300 | | |
301 | 1.89M | if (eos_reached || !pkt) { |
302 | 187k | talloc_free(pkt); |
303 | | |
304 | 187k | struct segment *next = NULL; |
305 | 39.9M | for (int n = 0; n < src->num_segments - 1; n++) { |
306 | 39.9M | if (src->segments[n] == seg) { |
307 | 151k | next = src->segments[n + 1]; |
308 | 151k | break; |
309 | 151k | } |
310 | 39.9M | } |
311 | 187k | if (!next) { |
312 | 35.6k | src->eof_reached = true; |
313 | 35.6k | return; |
314 | 35.6k | } |
315 | 151k | switch_segment(demuxer, src, next, next->start, 0, true); |
316 | 151k | return; // reader will retry |
317 | 187k | } |
318 | | |
319 | 1.70M | if (pkt->stream < 0 || pkt->stream >= seg->num_stream_map) |
320 | 0 | goto drop; |
321 | | |
322 | 1.70M | if (!src->no_clip || src->delay_open) { |
323 | 1.39M | pkt->segmented = true; |
324 | 1.39M | if (!pkt->codec) |
325 | 1.17M | pkt->codec = demux_get_stream(seg->d, pkt->stream)->codec; |
326 | 1.39M | } |
327 | 1.70M | if (!src->no_clip) { |
328 | 1.39M | if (pkt->start == MP_NOPTS_VALUE || pkt->start < seg->start) |
329 | 1.17M | pkt->start = seg->start; |
330 | 1.39M | if (pkt->end == MP_NOPTS_VALUE || pkt->end > seg->end) |
331 | 1.17M | pkt->end = seg->end; |
332 | 1.39M | } |
333 | | |
334 | 1.70M | struct virtual_stream *vs = seg->stream_map[pkt->stream]; |
335 | 1.70M | if (!vs) |
336 | 0 | goto drop; |
337 | | |
338 | | // for refresh seeks, demux.c prefers monotonically increasing packet pos |
339 | | // since the packet pos is meaningless anyway for timeline, use it |
340 | 1.70M | if (pkt->pos >= 0) |
341 | 1.70M | pkt->pos |= (seg->index & 0x7FFFULL) << 48; |
342 | | |
343 | 1.70M | if (pkt->pts != MP_NOPTS_VALUE && !src->no_clip && pkt->pts >= seg->end) { |
344 | | // Trust the keyframe flag. Might not always be a good idea, but will |
345 | | // be sufficient at least with mkv. The problem is that this flag is |
346 | | // not well-defined in libavformat and is container-dependent. |
347 | 5.53k | if (pkt->keyframe || vs->eos_packets == INT_MAX) { |
348 | 5.26k | vs->eos_packets = INT_MAX; |
349 | 5.26k | goto drop; |
350 | 5.26k | } else { |
351 | 267 | vs->eos_packets += 1; |
352 | 267 | } |
353 | 5.53k | } |
354 | | |
355 | 1.70M | double dts = pkt->dts != MP_NOPTS_VALUE ? pkt->dts : pkt->pts; |
356 | 1.70M | if (src->dts == MP_NOPTS_VALUE || (dts != MP_NOPTS_VALUE && dts > src->dts)) |
357 | 1.69M | src->dts = dts; |
358 | | |
359 | 1.70M | pkt->stream = vs->sh->index; |
360 | 1.70M | src->next = pkt; |
361 | 1.70M | return; |
362 | | |
363 | 5.26k | drop: |
364 | 5.26k | talloc_free(pkt); |
365 | 5.26k | } |
366 | | |
367 | | static bool d_read_packet(struct demuxer *demuxer, struct demux_packet **out_pkt) |
368 | 1.93M | { |
369 | 1.93M | struct priv *p = demuxer->priv; |
370 | 1.93M | struct virtual_source *src = NULL; |
371 | | |
372 | 3.86M | for (int x = 0; x < p->num_sources; x++) { |
373 | 1.93M | struct virtual_source *cur = p->sources[x]; |
374 | | |
375 | 1.93M | if (!cur->any_selected || cur->eof_reached) |
376 | 35.6k | continue; |
377 | | |
378 | 1.89M | if (!cur->current) |
379 | 4.09k | switch_segment(demuxer, cur, cur->segments[0], 0, 0, true); |
380 | | |
381 | 1.89M | if (!cur->any_selected || !cur->current || !cur->current->d) |
382 | 562 | continue; |
383 | | |
384 | 1.89M | if (!src || cur->dts == MP_NOPTS_VALUE || |
385 | 1.89M | (src->dts != MP_NOPTS_VALUE && cur->dts < src->dts)) |
386 | 1.89M | src = cur; |
387 | 1.89M | } |
388 | | |
389 | 1.93M | if (!src) |
390 | 36.1k | return false; |
391 | | |
392 | 1.89M | do_read_next_packet(demuxer, src); |
393 | 1.89M | *out_pkt = src->next; |
394 | 1.89M | src->next = NULL; |
395 | 1.89M | return true; |
396 | 1.93M | } |
397 | | |
398 | | static void seek_source(struct demuxer *demuxer, struct virtual_source *src, |
399 | | double pts, int flags) |
400 | 32.2k | { |
401 | 32.2k | struct segment *new = src->segments[src->num_segments - 1]; |
402 | 73.3k | for (int n = 0; n < src->num_segments; n++) { |
403 | 73.2k | if (pts < src->segments[n]->end) { |
404 | 32.0k | new = src->segments[n]; |
405 | 32.0k | break; |
406 | 32.0k | } |
407 | 73.2k | } |
408 | | |
409 | 32.2k | switch_segment(demuxer, src, new, pts, flags, false); |
410 | | |
411 | 32.2k | src->dts = MP_NOPTS_VALUE; |
412 | 32.2k | TA_FREEP(&src->next); |
413 | 32.2k | } |
414 | | |
415 | | static void d_seek(struct demuxer *demuxer, double seek_pts, int flags) |
416 | 68.5k | { |
417 | 68.5k | struct priv *p = demuxer->priv; |
418 | | |
419 | 68.5k | seek_pts = seek_pts * ((flags & SEEK_FACTOR) ? p->duration : 1); |
420 | 68.5k | flags &= SEEK_FORWARD | SEEK_HR; |
421 | | |
422 | | // The intention is to seek audio streams to the same target as video |
423 | | // streams if they are separate streams. Video streams usually have more |
424 | | // coarse keyframe snapping, which could leave video without audio. |
425 | 68.5k | struct virtual_source *master = NULL; |
426 | 68.5k | bool has_slaves = false; |
427 | 137k | for (int x = 0; x < p->num_sources; x++) { |
428 | 68.5k | struct virtual_source *src = p->sources[x]; |
429 | | |
430 | 68.5k | bool any_audio = false, any_video = false; |
431 | 101k | for (int i = 0; i < src->num_streams; i++) { |
432 | 33.2k | struct virtual_stream *str = src->streams[i]; |
433 | 33.2k | if (str->selected) { |
434 | 32.2k | if (str->sh->type == STREAM_VIDEO) |
435 | 73 | any_video = true; |
436 | 32.2k | if (str->sh->type == STREAM_AUDIO) |
437 | 32.1k | any_audio = true; |
438 | 32.2k | } |
439 | 33.2k | } |
440 | | |
441 | 68.5k | if (any_video) |
442 | 73 | master = src; |
443 | | // A true slave stream is audio-only; this also prevents that the master |
444 | | // stream is considered a slave stream. |
445 | 68.5k | if (any_audio && !any_video) |
446 | 32.1k | has_slaves = true; |
447 | 68.5k | } |
448 | | |
449 | 68.5k | if (!has_slaves) |
450 | 36.3k | master = NULL; |
451 | | |
452 | 68.5k | if (master) { |
453 | 0 | seek_source(demuxer, master, seek_pts, flags); |
454 | 0 | do_read_next_packet(demuxer, master); |
455 | 0 | if (master->next && master->next->pts != MP_NOPTS_VALUE) { |
456 | | // Assume we got a seek target. Actually apply the heuristic. |
457 | 0 | MP_VERBOSE(demuxer, "adjust seek target from %f to %f\n", seek_pts, |
458 | 0 | master->next->pts); |
459 | 0 | seek_pts = master->next->pts; |
460 | 0 | flags &= ~(unsigned)SEEK_FORWARD; |
461 | 0 | } |
462 | 0 | } |
463 | | |
464 | 137k | for (int x = 0; x < p->num_sources; x++) { |
465 | 68.5k | struct virtual_source *src = p->sources[x]; |
466 | 68.5k | if (src != master && src->any_selected) |
467 | 32.2k | seek_source(demuxer, src, seek_pts, flags); |
468 | 68.5k | } |
469 | 68.5k | } |
470 | | |
471 | | static void print_timeline(struct demuxer *demuxer) |
472 | 34.4k | { |
473 | 34.4k | struct priv *p = demuxer->priv; |
474 | | |
475 | 34.4k | MP_VERBOSE(demuxer, "Timeline segments:\n"); |
476 | 68.9k | for (int x = 0; x < p->num_sources; x++) { |
477 | 34.4k | struct virtual_source *src = p->sources[x]; |
478 | | |
479 | 34.4k | if (x >= 1) |
480 | 34.4k | MP_VERBOSE(demuxer, " --- new parallel stream ---\n"); |
481 | | |
482 | 300k | for (int n = 0; n < src->num_segments; n++) { |
483 | 266k | struct segment *seg = src->segments[n]; |
484 | 266k | int src_num = n; |
485 | 157M | for (int i = 0; i < n; i++) { |
486 | 157M | if (seg->d && src->segments[i]->d == seg->d) { |
487 | 109k | src_num = i; |
488 | 109k | break; |
489 | 109k | } |
490 | 157M | } |
491 | 266k | MP_VERBOSE(demuxer, " %2d: %12f - %12f [%12f] (", |
492 | 266k | n, seg->start, seg->end, seg->d_start); |
493 | 410k | for (int i = 0; i < seg->num_stream_map; i++) { |
494 | 144k | struct virtual_stream *vs = seg->stream_map[i]; |
495 | 144k | MP_VERBOSE(demuxer, "%s%d", i ? " " : "", |
496 | 144k | vs ? vs->sh->index : -1); |
497 | 144k | } |
498 | 266k | MP_VERBOSE(demuxer, ")\n source %d:'%s'\n", src_num, seg->url); |
499 | 266k | } |
500 | | |
501 | 34.4k | if (src->dash) |
502 | 34.4k | MP_VERBOSE(demuxer, " (Using pseudo-DASH mode.)\n"); |
503 | 34.4k | } |
504 | 34.4k | MP_VERBOSE(demuxer, "Total duration: %f\n", p->duration); |
505 | 34.4k | } |
506 | | |
507 | | // Copy various (not all) metadata fields from src to dst, but try not to |
508 | | // overwrite fields in dst that are unset in src. |
509 | | // May keep data from src by reference. |
510 | | // Imperfect and arbitrary, only suited for EDL stuff. |
511 | | static void apply_meta(struct sh_stream *dst, struct sh_stream *src) |
512 | 21.3k | { |
513 | 21.3k | if (src->demuxer_id >= 0) |
514 | 284 | dst->demuxer_id = src->demuxer_id; |
515 | 21.3k | if (src->title) |
516 | 0 | dst->title = src->title; |
517 | 21.3k | if (src->lang) |
518 | 0 | dst->lang = src->lang; |
519 | 21.3k | dst->default_track = src->default_track; |
520 | 21.3k | dst->forced_track = src->forced_track; |
521 | 21.3k | if (src->hls_bitrate) |
522 | 0 | dst->hls_bitrate = src->hls_bitrate; |
523 | 21.3k | dst->missing_timestamps = src->missing_timestamps; |
524 | 21.3k | if (src->attached_picture) |
525 | 0 | dst->attached_picture = src->attached_picture; |
526 | 21.3k | dst->image = src->image; |
527 | 21.3k | } |
528 | | |
529 | | // This is mostly for EDL user-defined metadata. |
530 | | static struct sh_stream *find_matching_meta(struct timeline_par *tl, int index) |
531 | 21.3k | { |
532 | 21.3k | for (int n = 0; n < tl->num_sh_meta; n++) { |
533 | 4 | struct sh_stream *sh = tl->sh_meta[n]; |
534 | 4 | if (sh->index == index || sh->index < 0) |
535 | 4 | return sh; |
536 | 4 | } |
537 | 21.3k | return NULL; |
538 | 21.3k | } |
539 | | |
540 | | static bool add_tl(struct demuxer *demuxer, struct timeline_par *tl) |
541 | 34.4k | { |
542 | 34.4k | struct priv *p = demuxer->priv; |
543 | | |
544 | 34.4k | struct virtual_source *src = talloc_ptrtype(p, src); |
545 | 34.4k | *src = (struct virtual_source){ |
546 | 34.4k | .tl = tl, |
547 | 34.4k | .dash = tl->dash, |
548 | 34.4k | .delay_open = tl->delay_open, |
549 | 34.4k | .no_clip = tl->no_clip || tl->dash, |
550 | 34.4k | .dts = MP_NOPTS_VALUE, |
551 | 34.4k | }; |
552 | | |
553 | 34.4k | if (!tl->num_parts) |
554 | 0 | return false; |
555 | | |
556 | 34.4k | MP_TARRAY_APPEND(p, p->sources, p->num_sources, src); |
557 | | |
558 | 34.4k | p->duration = MPMAX(p->duration, tl->parts[tl->num_parts - 1].end); |
559 | | |
560 | 34.4k | struct demuxer *meta = tl->track_layout; |
561 | | |
562 | | // delay_open streams normally have meta==NULL, and 1 virtual stream |
563 | 34.4k | int num_streams = 0; |
564 | 34.4k | if (tl->delay_open) { |
565 | 0 | num_streams = tl->num_sh_meta; |
566 | 34.4k | } else if (meta) { |
567 | 34.4k | num_streams = demux_get_num_stream(meta); |
568 | 34.4k | } |
569 | 55.8k | for (int n = 0; n < num_streams; n++) { |
570 | 21.3k | struct sh_stream *new = NULL; |
571 | | |
572 | 21.3k | if (tl->delay_open) { |
573 | 0 | struct sh_stream *tsh = tl->sh_meta[n]; |
574 | 0 | new = demux_alloc_sh_stream(tsh->type); |
575 | 0 | new->codec = tsh->codec; |
576 | 0 | apply_meta(new, tsh); |
577 | 0 | demuxer->is_network = true; |
578 | 0 | demuxer->is_streaming = true; |
579 | 21.3k | } else { |
580 | 21.3k | struct sh_stream *sh = demux_get_stream(meta, n); |
581 | 21.3k | new = demux_alloc_sh_stream(sh->type); |
582 | 21.3k | apply_meta(new, sh); |
583 | 21.3k | new->codec = sh->codec; |
584 | 21.3k | struct sh_stream *tsh = find_matching_meta(tl, n); |
585 | 21.3k | if (tsh) |
586 | 4 | apply_meta(new, tsh); |
587 | 21.3k | } |
588 | | |
589 | 21.3k | demux_add_sh_stream(demuxer, new); |
590 | 21.3k | struct virtual_stream *vs = talloc_ptrtype(p, vs); |
591 | 21.3k | *vs = (struct virtual_stream){ |
592 | 21.3k | .src = src, |
593 | 21.3k | .sh = new, |
594 | 21.3k | }; |
595 | 21.3k | MP_TARRAY_APPEND(p, p->streams, p->num_streams, vs); |
596 | 21.3k | mp_assert(demux_get_stream(demuxer, p->num_streams - 1) == new); |
597 | 21.3k | MP_TARRAY_APPEND(src, src->streams, src->num_streams, vs); |
598 | 21.3k | } |
599 | | |
600 | 300k | for (int n = 0; n < tl->num_parts; n++) { |
601 | 266k | struct timeline_part *part = &tl->parts[n]; |
602 | | |
603 | | // demux_timeline already does caching, doing it for the sub-demuxers |
604 | | // would be pointless and wasteful. |
605 | 266k | if (part->source) { |
606 | 181k | demuxer->is_network |= part->source->is_network; |
607 | 181k | demuxer->is_streaming |= part->source->is_streaming; |
608 | 181k | } |
609 | | |
610 | 266k | if (!part->source) |
611 | 266k | mp_assert(tl->dash || tl->delay_open); |
612 | | |
613 | 266k | struct segment *seg = talloc_ptrtype(src, seg); |
614 | 266k | *seg = (struct segment){ |
615 | 266k | .d = part->source, |
616 | 266k | .url = part->source ? part->source->filename : part->url, |
617 | 266k | .lazy = !part->source, |
618 | 266k | .d_start = part->source_start, |
619 | 266k | .start = part->start, |
620 | 266k | .end = part->end, |
621 | 266k | }; |
622 | | |
623 | 266k | associate_streams(demuxer, src, seg); |
624 | | |
625 | 266k | seg->index = n; |
626 | 266k | MP_TARRAY_APPEND(src, src->segments, src->num_segments, seg); |
627 | 266k | } |
628 | | |
629 | 34.4k | if (tl->track_layout) { |
630 | 34.4k | demuxer->is_network |= tl->track_layout->is_network; |
631 | 34.4k | demuxer->is_streaming |= tl->track_layout->is_streaming; |
632 | 34.4k | } |
633 | 34.4k | return true; |
634 | 34.4k | } |
635 | | |
636 | | static int d_open(struct demuxer *demuxer, enum demux_check check) |
637 | 34.4k | { |
638 | 34.4k | struct priv *p = demuxer->priv = talloc_zero(demuxer, struct priv); |
639 | 34.4k | p->tl = demuxer->params ? demuxer->params->timeline : NULL; |
640 | 34.4k | if (!p->tl || p->tl->num_pars < 1) |
641 | 0 | return -1; |
642 | | |
643 | 34.4k | demuxer->chapters = p->tl->chapters; |
644 | 34.4k | demuxer->num_chapters = p->tl->num_chapters; |
645 | | |
646 | 34.4k | struct demuxer *meta = p->tl->meta; |
647 | 34.4k | if (meta) { |
648 | 34.4k | demuxer->metadata = meta->metadata; |
649 | 34.4k | demuxer->attachments = meta->attachments; |
650 | 34.4k | demuxer->num_attachments = meta->num_attachments; |
651 | 34.4k | demuxer->editions = meta->editions; |
652 | 34.4k | demuxer->num_editions = meta->num_editions; |
653 | 34.4k | demuxer->edition = meta->edition; |
654 | 34.4k | } |
655 | | |
656 | 68.9k | for (int n = 0; n < p->tl->num_pars; n++) { |
657 | 34.4k | if (!add_tl(demuxer, p->tl->pars[n])) |
658 | 0 | return -1; |
659 | 34.4k | } |
660 | | |
661 | 34.4k | if (!p->num_sources) |
662 | 0 | return -1; |
663 | | |
664 | 34.4k | demuxer->is_network |= p->tl->is_network; |
665 | 34.4k | demuxer->is_streaming |= p->tl->is_streaming; |
666 | | |
667 | 34.4k | demuxer->duration = p->duration; |
668 | | |
669 | 34.4k | print_timeline(demuxer); |
670 | | |
671 | 34.4k | demuxer->seekable = true; |
672 | 34.4k | demuxer->partially_seekable = false; |
673 | | |
674 | 34.4k | const char *format_name = "unknown"; |
675 | 34.4k | if (meta) |
676 | 34.4k | format_name = meta->filetype ? meta->filetype : meta->desc->name; |
677 | 34.4k | demuxer->filetype = talloc_asprintf(p, "%s/%s", p->tl->format, format_name); |
678 | | |
679 | 34.4k | reselect_streams(demuxer); |
680 | | |
681 | 34.4k | p->owns_tl = true; |
682 | 34.4k | return 0; |
683 | 34.4k | } |
684 | | |
685 | | static void d_close(struct demuxer *demuxer) |
686 | 34.4k | { |
687 | 34.4k | struct priv *p = demuxer->priv; |
688 | | |
689 | 68.9k | for (int x = 0; x < p->num_sources; x++) { |
690 | 34.4k | struct virtual_source *src = p->sources[x]; |
691 | | |
692 | 34.4k | src->current = NULL; |
693 | 34.4k | TA_FREEP(&src->next); |
694 | 34.4k | close_lazy_segments(demuxer, src); |
695 | 34.4k | } |
696 | | |
697 | 34.4k | if (p->owns_tl) { |
698 | 34.4k | struct demuxer *master = p->tl->demuxer; |
699 | 34.4k | timeline_destroy(p->tl); |
700 | 34.4k | demux_free(master); |
701 | 34.4k | } |
702 | 34.4k | } |
703 | | |
704 | | static void d_switched_tracks(struct demuxer *demuxer) |
705 | 65.2k | { |
706 | 65.2k | reselect_streams(demuxer); |
707 | 65.2k | } |
708 | | |
709 | | const demuxer_desc_t demuxer_desc_timeline = { |
710 | | .name = "timeline", |
711 | | .desc = "timeline segments", |
712 | | .read_packet = d_read_packet, |
713 | | .open = d_open, |
714 | | .close = d_close, |
715 | | .seek = d_seek, |
716 | | .switched_tracks = d_switched_tracks, |
717 | | }; |