From 0ed170ec0b7483568ad82c936afee7803a533908 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 18 Jan 2016 11:46:28 +0100 Subject: sub: fix memory leaks demux_lavf.c leaked the complete subtitle data if it was put through iconv. lavc_conv.c leaked AVCodecContext.subtitle_header (set by libavcodec), which is fixed by using avcodec_free_context(). It also leaked the subtitle that was decoded last. --- demux/demux_lavf.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'demux') diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 1b3105170d..8cd525b685 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -282,6 +282,8 @@ static void convert_charset(struct demuxer *demuxer) // libavformat transparently converts UTF-16 to UTF-8 if (!mp_charset_is_utf16(cp) && !mp_charset_is_utf8(cp)) { bstr conv = mp_iconv_to_utf8(demuxer->log, data, cp, MP_ICONV_VERBOSE); + if (conv.start && conv.start != data.start) + talloc_steal(alloc, conv.start); if (conv.start) data = conv; } -- cgit v1.2.3 From 2bbed8013563e07e3fb5468c41f4d014b33fb887 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 18 Jan 2016 17:42:34 +0100 Subject: demux: remove unused flag --- demux/demux.h | 1 - 1 file changed, 1 deletion(-) (limited to 'demux') diff --git a/demux/demux.h b/demux/demux.h index d274be5ae7..7a24230cc8 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -160,7 +160,6 @@ struct demuxer_params { struct matroska_segment_uid *matroska_wanted_uids; int matroska_wanted_segment; bool *matroska_was_valid; - bool expect_subtitle; // -- demux_open_url() only int stream_flags; bool allow_capture; -- cgit v1.2.3 From 488f569d9956d12e8ac5db79cf5959f015b4f8d0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 18 Jan 2016 18:21:29 +0100 Subject: demux: unify codepaths for threaded/unthreaded track switching Well, not that the unthreaded case is important, or even works properly. --- demux/demux.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index 19ad6970b0..4fedc69e60 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -1273,19 +1273,21 @@ void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream, { struct demux_internal *in = demuxer->in; pthread_mutex_lock(&in->lock); - bool update = false; // don't flush buffers if stream is already selected / unselected if (stream->ds->selected != selected) { stream->ds->selected = selected; stream->ds->active = false; ds_flush(stream->ds); - if (selected && in->refresh_seeks_enabled && in->threading) - in->start_refresh_seek = true; - update = true; + in->tracks_switched = true; + if (in->threading) { + if (selected && in->refresh_seeks_enabled) + in->start_refresh_seek = true; + pthread_cond_signal(&in->wakeup); + } else { + execute_trackswitch(in); + } } pthread_mutex_unlock(&in->lock); - if (update) - demux_control(demuxer, DEMUXER_CTRL_SWITCHED_TRACKS, NULL); } void demux_set_stream_autoselect(struct demuxer *demuxer, bool autoselect) @@ -1456,10 +1458,6 @@ static int cached_demux_control(struct demux_internal *in, int cmd, void *arg) c->res = r; return DEMUXER_CTRL_OK; } - case DEMUXER_CTRL_SWITCHED_TRACKS: - in->tracks_switched = true; - pthread_cond_signal(&in->wakeup); - return DEMUXER_CTRL_OK; case DEMUXER_CTRL_GET_BITRATE_STATS: { double *rates = arg; for (int n = 0; n < STREAM_TYPE_COUNT; n++) -- cgit v1.2.3 From f15a79d14467d8c30dcaffa53d8871ef01b9328e Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 18 Jan 2016 18:25:14 +0100 Subject: demux: fix interleaved subtitle reading in unthreaded mode Meh. Why are there even two code paths. This adds an additional check; the big function is only moved. --- demux/demux.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index 4fedc69e60..de59a6dc28 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -667,6 +667,21 @@ static struct demux_packet *dequeue_packet(struct demux_stream *ds) return pkt; } +// Sparse packets (Subtitles) interleaved with other non-sparse packets (video, +// audio) should never be read actively, meaning the demuxer thread does not +// try to exceed default readahead in order to find a new packet. +static bool use_lazy_subtitle_reading(struct demux_stream *ds) +{ + if (ds->type != STREAM_SUB) + return false; + for (int n = 0; n < ds->in->num_streams; n++) { + struct demux_stream *s = ds->in->streams[n]->ds; + if (s->type != STREAM_SUB && s->selected && !s->eof) + return true; + } + return false; +} + // Read a packet from the given stream. The returned packet belongs to the // caller, who has to free it with talloc_free(). Might block. Returns NULL // on EOF. @@ -676,7 +691,8 @@ struct demux_packet *demux_read_packet(struct sh_stream *sh) struct demux_packet *pkt = NULL; if (ds) { pthread_mutex_lock(&ds->in->lock); - ds_get_packets(ds); + if (!use_lazy_subtitle_reading(ds)) + ds_get_packets(ds); pkt = dequeue_packet(ds); pthread_cond_signal(&ds->in->wakeup); // possibly read more pthread_mutex_unlock(&ds->in->lock); @@ -684,21 +700,6 @@ struct demux_packet *demux_read_packet(struct sh_stream *sh) return pkt; } -// Sparse packets (Subtitles) interleaved with other non-sparse packets (video, -// audio) should never be read actively, meaning the demuxer thread does not -// try to exceed default readahead in order to find a new packet. -static bool use_lazy_subtitle_reading(struct demux_stream *ds) -{ - if (ds->type != STREAM_SUB) - return false; - for (int n = 0; n < ds->in->num_streams; n++) { - struct demux_stream *s = ds->in->streams[n]->ds; - if (s->type != STREAM_SUB && s->selected && !s->eof) - return true; - } - return false; -} - // Poll the demuxer queue, and if there's a packet, return it. Otherwise, just // make the demuxer thread read packets for this stream, and if there's at // least one packet, call the wakeup callback. -- cgit v1.2.3 From 5986861c9cbe33509b9a18ad048bbc0de7ba8dbe Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 18 Jan 2016 18:26:14 +0100 Subject: demux: remove unused function --- demux/demux.c | 13 ------------- demux/demux.h | 2 -- 2 files changed, 15 deletions(-) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index de59a6dc28..1991ad216b 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -1256,19 +1256,6 @@ struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d, return NULL; } -void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type, - struct sh_stream *stream) -{ - assert(!stream || stream->type == type); - - int num = demux_get_num_stream(demuxer); - for (int n = 0; n < num; n++) { - struct sh_stream *cur = demux_get_stream(demuxer, n); - if (cur->type == type) - demuxer_select_track(demuxer, cur, cur == stream); - } -} - void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream, bool selected) { diff --git a/demux/demux.h b/demux/demux.h index 7a24230cc8..33cbe0f3b1 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -272,8 +272,6 @@ void demux_set_ts_offset(struct demuxer *demuxer, double offset); int demux_control(struct demuxer *demuxer, int cmd, void *arg); -void demuxer_switch_track(struct demuxer *demuxer, enum stream_type type, - struct sh_stream *stream); void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream, bool selected); void demux_set_stream_autoselect(struct demuxer *demuxer, bool autoselect); -- cgit v1.2.3 From 46bcdb7039cdf146966075f268c68b0fcee5ebbf Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 18 Jan 2016 18:34:44 +0100 Subject: demux: disable stream cache if no tracks are selected Slightly helps with timeline stuff, like EDL. There is no need to keep network (or even just disk I/O) busy for all segments at the same time, because 1. the data won't be needed any time soon, and 2. will probably be discarded anyway if the stream is seeked when segment is resumed. Partially fixes #2692. --- demux/demux.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index 1991ad216b..e286bf0e32 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -558,11 +558,18 @@ static void execute_trackswitch(struct demux_internal *in) { in->tracks_switched = false; + bool any_selected = false; + for (int n = 0; n < in->num_streams; n++) + any_selected |= in->streams[n]->ds->selected; + pthread_mutex_unlock(&in->lock); if (in->d_thread->desc->control) in->d_thread->desc->control(in->d_thread, DEMUXER_CTRL_SWITCHED_TRACKS, 0); + stream_control(in->d_thread->stream, STREAM_CTRL_SET_READAHEAD, + &(int){any_selected}); + pthread_mutex_lock(&in->lock); if (in->start_refresh_seek) @@ -1077,6 +1084,7 @@ static struct demuxer *open_given_type(struct mpv_global *global, demux_init_cache(demuxer); demux_changed(in->d_thread, DEMUX_EVENT_ALL); demux_update(demuxer); + stream_control(demuxer->stream, STREAM_CTRL_SET_READAHEAD, &(int){false}); return demuxer; } -- cgit v1.2.3 From f9cefbfec4d7bfec44991d4372aad4fc1b3167a5 Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Mon, 21 Dec 2015 17:35:15 -0800 Subject: vd_lavc: feed A53_CC side data packets into the demuxer for eia_608 decoding --- demux/demux.c | 25 +++++++++++++++++++++++++ demux/demux.h | 1 + 2 files changed, 26 insertions(+) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index e286bf0e32..af0a93c03d 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -160,6 +160,10 @@ struct demux_stream { int64_t last_pos; struct demux_packet *head; struct demux_packet *tail; + + // for closed captions (demuxer_feed_caption) + struct sh_stream *cc; + }; // Return "a", or if that is NOPTS, return "def". @@ -361,6 +365,27 @@ const char *stream_type_name(enum stream_type type) } } +void demuxer_feed_caption(struct sh_stream *stream, demux_packet_t *dp) +{ + struct demuxer *demuxer = stream->ds->in->d_thread; + struct sh_stream *sh = stream->ds->cc; + + if (!sh) { + sh = demux_alloc_sh_stream(STREAM_SUB); + if (!sh) + return; + sh->codec->codec = "eia_608"; + stream->ds->cc = sh; + demux_add_sh_stream(demuxer, sh); + } + + if (demux_stream_is_selected(sh)) { + dp->pts = MP_ADD_PTS(dp->pts, -stream->ds->in->ts_offset); + dp->dts = MP_ADD_PTS(dp->dts, -stream->ds->in->ts_offset); + demux_add_packet(sh, dp); + } +} + void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp) { struct demux_stream *ds = stream ? stream->ds : NULL; diff --git a/demux/demux.h b/demux/demux.h index 33cbe0f3b1..72ed15888b 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -237,6 +237,7 @@ void free_demuxer(struct demuxer *demuxer); void free_demuxer_and_stream(struct demuxer *demuxer); void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp); +void demuxer_feed_caption(struct sh_stream *stream, demux_packet_t *dp); struct demux_packet *demux_read_packet(struct sh_stream *sh); int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt); -- cgit v1.2.3 From ae4b0f3f7ce31e1f9f5ea51422cd21c900179d52 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 19 Jan 2016 14:19:50 +0100 Subject: demux: fix leaking closed captions packets with unselected sub stream Calling demux_add_packet() unconditonally frees the packet if the stream is not selected. --- demux/demux.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index af0a93c03d..d0a37b9d83 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -372,18 +372,18 @@ void demuxer_feed_caption(struct sh_stream *stream, demux_packet_t *dp) if (!sh) { sh = demux_alloc_sh_stream(STREAM_SUB); - if (!sh) + if (!sh) { + talloc_free(dp); return; + } sh->codec->codec = "eia_608"; stream->ds->cc = sh; demux_add_sh_stream(demuxer, sh); } - if (demux_stream_is_selected(sh)) { - dp->pts = MP_ADD_PTS(dp->pts, -stream->ds->in->ts_offset); - dp->dts = MP_ADD_PTS(dp->dts, -stream->ds->in->ts_offset); - demux_add_packet(sh, dp); - } + dp->pts = MP_ADD_PTS(dp->pts, -stream->ds->in->ts_offset); + dp->dts = MP_ADD_PTS(dp->dts, -stream->ds->in->ts_offset); + demux_add_packet(sh, dp); } void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp) -- cgit v1.2.3 From 6fafdd51428dced8553f8545ce1a88fe88614b2a Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 19 Jan 2016 14:21:02 +0100 Subject: demux: remove a minor difference between threaded/unthreaded modes This difference was unnecessary. --- demux/demux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index d0a37b9d83..c00f5bf3c8 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -1300,9 +1300,9 @@ void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream, stream->ds->active = false; ds_flush(stream->ds); in->tracks_switched = true; + if (selected && in->refresh_seeks_enabled) + in->start_refresh_seek = true; if (in->threading) { - if (selected && in->refresh_seeks_enabled) - in->start_refresh_seek = true; pthread_cond_signal(&in->wakeup); } else { execute_trackswitch(in); -- cgit v1.2.3 From 8a9b64329c0e387dc59a1fca477a43c50f59ff34 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 19 Jan 2016 18:36:06 +0100 Subject: Relicense some non-MPlayer source files to LGPL 2.1 or later This covers source files which were added in mplayer2 and mpv times only, and where all code is covered by LGPL relicensing agreements. There are probably more files to which this applies, but I'm being conservative here. A file named ao_sdl.c exists in MPlayer too, but the mpv one is a complete rewrite, and was added some time after the original ao_sdl.c was removed. The same applies to vo_sdl.c, for which the SDL2 API is radically different in addition (MPlayer supports SDL 1.2 only). common.c contains only code written by me. But common.h is a strange case: although it originally was named mp_common.h and exists in MPlayer too, by now it contains only definitions written by uau and me. The exceptions are the CONTROL_ defines - thus not changing the license of common.h yet. codec_tags.c contained once large tables generated from MPlayer's codecs.conf, but all of these tables were removed. From demux_playlist.c I'm removing a code fragment from someone who was not asked; this probably could be done later (see commit 15dccc37). misc.c is a bit complicated to reason about (it was split off mplayer.c and thus contains random functions out of this file), but actually all functions have been added post-MPlayer. Except get_relative_time(), which was written by uau, but looks similar to 3 different versions of something similar in each of the Unix/win32/OSX timer source files. I'm not sure what that means in regards to copyright, so I've just moved it into another still-GPL source file for now. screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but they're all gone. --- demux/codec_tags.c | 14 +++++++------- demux/codec_tags.h | 14 +++++++------- demux/cue.c | 14 +++++++------- demux/cue.h | 14 +++++++------- demux/demux_cue.c | 14 +++++++------- demux/demux_disc.c | 14 +++++++------- demux/demux_edl.c | 14 +++++++------- demux/demux_mkv_timeline.c | 14 +++++++------- demux/demux_playlist.c | 32 +++++++------------------------- demux/demux_rar.c | 14 +++++++------- 10 files changed, 70 insertions(+), 88 deletions(-) (limited to 'demux') diff --git a/demux/codec_tags.c b/demux/codec_tags.c index 7e91291e9e..5f4f569435 100644 --- a/demux/codec_tags.c +++ b/demux/codec_tags.c @@ -1,18 +1,18 @@ /* * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #include diff --git a/demux/codec_tags.h b/demux/codec_tags.h index 294759a299..147760b0fe 100644 --- a/demux/codec_tags.h +++ b/demux/codec_tags.h @@ -1,18 +1,18 @@ /* * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #ifndef MP_CODEC_TAGS_H diff --git a/demux/cue.c b/demux/cue.c index 4a84107db7..69f30f4871 100644 --- a/demux/cue.c +++ b/demux/cue.c @@ -1,18 +1,18 @@ /* * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #include diff --git a/demux/cue.h b/demux/cue.h index 1ae5f0a203..61f18e6fa5 100644 --- a/demux/cue.h +++ b/demux/cue.h @@ -1,18 +1,18 @@ /* * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #ifndef MP_CUE_H_ diff --git a/demux/demux_cue.c b/demux/demux_cue.c index bef1516057..673e8b9f27 100644 --- a/demux/demux_cue.c +++ b/demux/demux_cue.c @@ -3,18 +3,18 @@ * * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #include diff --git a/demux/demux_disc.c b/demux/demux_disc.c index dcc3e7c79f..7feec6ca72 100644 --- a/demux/demux_disc.c +++ b/demux/demux_disc.c @@ -1,18 +1,18 @@ /* * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #include diff --git a/demux/demux_edl.c b/demux/demux_edl.c index 74ce7aef66..aeccab406f 100644 --- a/demux/demux_edl.c +++ b/demux/demux_edl.c @@ -3,18 +3,18 @@ * * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #include diff --git a/demux/demux_mkv_timeline.c b/demux/demux_mkv_timeline.c index 681f0b0760..8affe13ac2 100644 --- a/demux/demux_mkv_timeline.c +++ b/demux/demux_mkv_timeline.c @@ -1,18 +1,18 @@ /* * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #include diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index 25ad22bddb..a5e9ca4ea1 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -1,18 +1,18 @@ /* * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #include @@ -169,23 +169,6 @@ static int parse_ref_init(struct pl_parser *p) return 0; } -static int parse_mov_rtsptext(struct pl_parser *p) -{ - bstr line = pl_get_line(p); - if (!bstr_eatstart(&line, bstr0("RTSPtext"))) - return -1; - if (p->probing) - return 0; - line = bstr_strip(line); - do { - if (bstr_case_startswith(line, bstr0("rtsp://"))) { - pl_add(p, line); - return 0; - } - } while (!pl_eof(p) && (line = bstr_strip(pl_get_line(p))).len); - return -1; -} - static int parse_pls(struct pl_parser *p) { bstr line = {0}; @@ -285,7 +268,6 @@ static const struct pl_format formats[] = { {"m3u", parse_m3u, MIME_TYPES("audio/mpegurl", "audio/x-mpegurl", "application/x-mpegurl")}, {"ini", parse_ref_init}, - {"mov", parse_mov_rtsptext}, {"pls", parse_pls, MIME_TYPES("audio/x-scpls")}, {"txt", parse_txt}, diff --git a/demux/demux_rar.c b/demux/demux_rar.c index 46311bce65..f35c2ccf66 100644 --- a/demux/demux_rar.c +++ b/demux/demux_rar.c @@ -1,18 +1,18 @@ /* * This file is part of mpv. * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . */ #include "common/common.h" -- cgit v1.2.3 From a18aa9e6321058f96f2a4a26df19abd73567e360 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 27 Jan 2016 21:08:53 +0100 Subject: demux_mkv: allow negative timestamps FFmpeg can generate such files. It's unclear whether they're allowed by Matroska. mkvinfo shows packet timestamps in both forms (one of them must be a bug), and at last libavformat's demuxer treats timestamps as signed. --- demux/demux_mkv.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'demux') diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 024f7e7e6e..9e8346e6ac 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -146,14 +146,14 @@ typedef struct mkv_track { typedef struct mkv_index { int tnum; - uint64_t timecode, duration; + int64_t timecode, duration; uint64_t filepos; // position of the cluster which contains the packet } mkv_index_t; struct block_info { uint64_t duration, discardpadding; bool simple, keyframe; - uint64_t timecode; + int64_t timecode; mkv_track_t *track; bstr data; void *alloc; @@ -170,7 +170,7 @@ typedef struct mkv_demuxer { struct ebml_tags *tags; - uint64_t tc_scale, cluster_tc; + int64_t tc_scale, cluster_tc; uint64_t cluster_start; uint64_t cluster_end; @@ -186,7 +186,7 @@ typedef struct mkv_demuxer { } *headers; int num_headers; - uint64_t skip_to_timecode; + int64_t skip_to_timecode; int v_skip_to_keyframe, a_skip_to_keyframe; int a_skip_preroll; int subtitle_preroll; @@ -706,7 +706,7 @@ static int demux_mkv_read_tracks(demuxer_t *demuxer) } static void cue_index_add(demuxer_t *demuxer, int track_id, uint64_t filepos, - uint64_t timecode, uint64_t duration) + int64_t timecode, int64_t duration) { mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; @@ -724,7 +724,7 @@ static void cue_index_add(demuxer_t *demuxer, int track_id, uint64_t filepos, static void add_block_position(demuxer_t *demuxer, struct mkv_track *track, uint64_t filepos, - uint64_t timecode, uint64_t duration) + int64_t timecode, int64_t duration) { mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; @@ -788,8 +788,8 @@ static int demux_mkv_read_cues(demuxer_t *demuxer) time, trackpos->cue_duration); mkv_d->index_has_durations |= trackpos->n_cue_duration > 0; MP_DBG(demuxer, "|+ found cue point for track %" PRIu64 - ": timecode %" PRIu64 ", filepos: %" PRIu64 - " offset %" PRIu64 ", duration %" PRIu64 "\n", + ": timecode %" PRId64 ", filepos: %" PRIu64 + " offset %" PRIu64 ", duration %" PRId64 "\n", trackpos->cue_track, time, pos, trackpos->cue_relative_position, trackpos->cue_duration); } @@ -1854,6 +1854,7 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check) mkv_d->segment_start = stream_tell(s); mkv_d->segment_end = end_pos; mkv_d->a_skip_preroll = 1; + mkv_d->skip_to_timecode = INT64_MIN; if (demuxer->params && demuxer->params->matroska_was_valid) *demuxer->params->matroska_was_valid = true; @@ -2128,6 +2129,8 @@ static void mkv_seek_reset(demuxer_t *demuxer) } free_block(&mkv_d->tmp_block); + + mkv_d->skip_to_timecode = INT64_MIN; } // Copied from libavformat/matroskadec.c (FFmpeg 310f9dd / 2013-05-30) @@ -2379,7 +2382,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info) bstr data = block_info->data; bool keyframe = block_info->keyframe; uint64_t block_duration = block_info->duration; - uint64_t tc = block_info->timecode; + int64_t tc = block_info->timecode; mkv_track_t *track = block_info->track; struct sh_stream *stream = track->stream; uint32_t lace_size[MAX_NUM_LACES]; @@ -2466,7 +2469,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info) if (stream->type == STREAM_VIDEO) { mkv_d->v_skip_to_keyframe = 0; - mkv_d->skip_to_timecode = 0; + mkv_d->skip_to_timecode = INT64_MIN; mkv_d->subtitle_preroll = 0; } else if (stream->type == STREAM_AUDIO) { mkv_d->a_skip_to_keyframe = 0; @@ -2658,7 +2661,7 @@ static mkv_index_t *get_highest_index_entry(struct demuxer *demuxer) return index; } -static int create_index_until(struct demuxer *demuxer, uint64_t timecode) +static int create_index_until(struct demuxer *demuxer, int64_t timecode) { struct mkv_demuxer *mkv_d = demuxer->priv; struct stream *s = demuxer->stream; @@ -2672,7 +2675,7 @@ static int create_index_until(struct demuxer *demuxer, uint64_t timecode) if (!index || index->timecode * mkv_d->tc_scale < timecode) { stream_seek(s, index ? index->filepos : mkv_d->cluster_start); - MP_VERBOSE(demuxer, "creating index until TC %" PRIu64 "\n", timecode); + MP_VERBOSE(demuxer, "creating index until TC %" PRId64 "\n", timecode); for (;;) { int res; struct block_info block; @@ -2708,8 +2711,7 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id, for (size_t i = 0; i < mkv_d->num_indexes; i++) { if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) { int64_t diff = - target_timecode - - (int64_t) (mkv_d->indexes[i].timecode * mkv_d->tc_scale); + target_timecode - mkv_d->indexes[i].timecode * mkv_d->tc_scale; if (flags & FLAG_BACKWARD) diff = -diff; if (min_diff != INT64_MIN) { @@ -2732,10 +2734,10 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id, double secs = opts->demux_mkv->subtitle_preroll_secs; if (mkv_d->index_has_durations) secs = MPMAX(secs, opts->demux_mkv->subtitle_preroll_secs_index); - uint64_t pre = MPMIN(INT64_MAX, secs * 1e9 / mkv_d->tc_scale); - uint64_t min_tc = pre < index->timecode ? index->timecode - pre : 0; + int64_t pre = MPMIN(INT64_MAX, secs * 1e9 / mkv_d->tc_scale); + int64_t min_tc = pre < index->timecode ? index->timecode - pre : 0; uint64_t prev_target = 0; - uint64_t prev_tc = 0; + int64_t prev_tc = 0; for (size_t i = 0; i < mkv_d->num_indexes; i++) { if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) { struct mkv_index *cur = &mkv_d->indexes[i]; @@ -2826,7 +2828,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags) mkv_d->skip_to_timecode = target_timecode; } else { mkv_d->skip_to_timecode = index ? index->timecode * mkv_d->tc_scale - : 0; + : INT64_MIN; } } else { stream_t *s = demuxer->stream; -- cgit v1.2.3 From a75f40e0d73d8d3686477aedbb51462c72d693fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Ekstr=C3=B6m?= Date: Tue, 9 Feb 2016 02:09:21 +0200 Subject: demux_mf: only use glob() if it is available The only other place where glob() is used is windows-specific and for windows mpv includes its own glob wrapper. --- demux/demux_mf.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'demux') diff --git a/demux/demux_mf.c b/demux/demux_mf.c index a91d13dff2..c60f5c6307 100644 --- a/demux/demux_mf.c +++ b/demux/demux_mf.c @@ -108,6 +108,7 @@ static mf_t *open_mf_pattern(void *talloc_ctx, struct mp_log *log, char *filenam char *fname = talloc_size(mf, strlen(filename) + 32); +#if HAVE_GLOB || HAVE_GLOB_WIN32_REPLACEMENT if (!strchr(filename, '%')) { strcpy(fname, filename); if (!strchr(filename, '*')) @@ -130,6 +131,7 @@ static mf_t *open_mf_pattern(void *talloc_ctx, struct mp_log *log, char *filenam globfree(&gg); goto exit_mf; } +#endif mp_info(log, "search expr: %s\n", filename); -- cgit v1.2.3 From dccda5189d82306db64f1b810807f8a13c328bb0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 11 Feb 2016 20:54:44 +0100 Subject: demux: reduce verbosity Tired of seeing all these useless pseudo-demuxers in the log. --- demux/demux.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index c00f5bf3c8..41b0f8f910 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -1079,8 +1079,8 @@ static struct demuxer *open_given_type(struct mpv_global *global, in->d_user->metadata = talloc_zero(in->d_user, struct mp_tags); in->d_buffer->metadata = talloc_zero(in->d_buffer, struct mp_tags); - mp_verbose(log, "Trying demuxer: %s (force-level: %s)\n", - desc->name, d_level(check)); + mp_dbg(log, "Trying demuxer: %s (force-level: %s)\n", + desc->name, d_level(check)); if (stream->seekable) // not for DVD/BD/DVB in particular stream_seek(stream, 0); @@ -1153,6 +1153,7 @@ struct demuxer *demux_open(struct stream *stream, struct demuxer_params *params, // Test demuxers from first to last, one pass for each check_levels[] entry for (int pass = 0; check_levels[pass] != -1; pass++) { enum demux_check level = check_levels[pass]; + mp_verbose(log, "Trying demuxers for level=%s.\n", d_level(level)); for (int n = 0; demuxer_list[n]; n++) { const struct demuxer_desc *desc = demuxer_list[n]; if (!check_desc || desc == check_desc) { -- cgit v1.2.3 From fa821de8b2b11c0c5e378342e0d56d16366cd96f Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 14 Feb 2016 12:42:24 +0100 Subject: demux_mkv: support channel layout in VfW muxed PCM Fixes #2820. --- demux/demux_mkv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'demux') diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 9e8346e6ac..4eb4df260f 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1484,6 +1484,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) unsigned char *extradata = track->private_data; unsigned int extradata_len = track->private_size; + uint64_t chmask = 0; if (!track->a_osfreq) track->a_osfreq = track->a_sfreq; @@ -1516,6 +1517,9 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) extradata_len = track->private_size - 18; sh_a->bits_per_coded_sample = track->a_bps; mp_set_codec_from_tag(sh_a); + // WAVEFORMATEXTENSIBLE.dwChannelMask + if (sh_a->codec_tag == 0xfffe && extradata_len >= 6) + chmask = AV_RL32(extradata + 2); } else if (!strcmp(track->codec_id, "A_PCM/INT/LIT")) { bool sign = sh_a->bits_per_coded_sample > 8; mp_set_pcm_codec(sh_a, sign, false, sh_a->bits_per_coded_sample, false); @@ -1635,7 +1639,9 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) if (!sh_a->codec) goto error; - mp_chmap_set_unknown(&sh_a->channels, track->a_channels); + mp_chmap_from_waveext(&sh_a->channels, chmask); + if (sh_a->channels.num != track->a_channels) + mp_chmap_set_unknown(&sh_a->channels, track->a_channels); const char *codec = sh_a->codec; if (!strcmp(codec, "mp3") || !strcmp(codec, "truehd")) { -- cgit v1.2.3 From 65f9af1d406de4625b79c369bc642c0ff6739673 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 15 Feb 2016 20:39:17 +0100 Subject: packet: cosmetics: reorder fields --- demux/packet.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'demux') diff --git a/demux/packet.h b/demux/packet.h index 784a1de405..82dad6f90f 100644 --- a/demux/packet.h +++ b/demux/packet.h @@ -25,15 +25,19 @@ // Holds one packet/frame/whatever typedef struct demux_packet { int len; + unsigned char *buffer; + double pts; double dts; double duration; - int64_t pos; // position in source file byte stream - unsigned char *buffer; bool keyframe; - int stream; // source stream index + + int64_t pos; // position in source file byte stream + int stream; // source stream index + + // private struct demux_packet *next; - struct AVPacket *avpacket; // keep the buffer allocation + struct AVPacket *avpacket; // keep the buffer allocation and sidedata } demux_packet_t; struct demux_packet *new_demux_packet(size_t len); -- cgit v1.2.3 From 0af5335383887cda7650d4b33bc42759c1a5891f Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 15 Feb 2016 21:04:07 +0100 Subject: Rewrite ordered chapters and timeline stuff This uses a different method to piece segments together. The old approach basically changes to a new file (with a new start offset) any time a segment ends. This meant waiting for audio/video end on segment end, and then changing to the new segment all at once. It had a very weird impact on the playback core, and some things (like truly gapless segment transitions, or frame backstepping) just didn't work. The new approach adds the demux_timeline pseudo-demuxer, which presents an uniform packet stream from the many segments. This is pretty similar to how ordered chapters are implemented everywhere else. It also reminds of the FFmpeg concat pseudo-demuxer. The "pure" version of this approach doesn't work though. Segments can actually have different codec configurations (different extradata), and subtitles are most likely broken too. (Subtitles have multiple corner cases which break the pure stream-concatenation approach completely.) To counter this, we do two things: - Reinit the decoder with each segment. We go as far as allowing concatenating files with completely different codecs for the sake of EDL (which also uses the timeline infrastructure). A "lighter" approach would try to make use of decoder mechanism to update e.g. the extradata, but that seems fragile. - Clip decoded data to segment boundaries. This is equivalent to normal playback core mechanisms like hr-seek, but now the playback core doesn't need to care about these things. These two mechanisms are equivalent to what happened in the old implementation, except they don't happen in the playback core anymore. In other words, the playback core is completely relieved from timeline implementation details. (Which honestly is exactly what I'm trying to do here. I don't think ordered chapter behavior deserves improvement, even if it's bad - but I want to get it out from the playback core.) There is code duplication between audio and video decoder common code. This is awful and could be shareable - but this will happen later. Note that the audio path has some code to clip audio frames for the purpose of codec preroll/gapless handling, but it's not shared as sharing it would cause more pain than it would help. --- demux/demux.c | 17 ++- demux/demux.h | 1 + demux/demux_timeline.c | 392 +++++++++++++++++++++++++++++++++++++++++++++++++ demux/packet.c | 5 + demux/packet.h | 5 + 5 files changed, 418 insertions(+), 2 deletions(-) create mode 100644 demux/demux_timeline.c (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index 41b0f8f910..61becd7f04 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -36,6 +36,7 @@ #include "stream/stream.h" #include "demux.h" +#include "timeline.h" #include "stheader.h" #include "cue.h" @@ -52,6 +53,7 @@ extern const demuxer_desc_t demuxer_desc_playlist; extern const demuxer_desc_t demuxer_desc_disc; extern const demuxer_desc_t demuxer_desc_rar; extern const demuxer_desc_t demuxer_desc_libarchive; +extern const demuxer_desc_t demuxer_desc_timeline; /* Please do not add any new demuxers here. If you want to implement a new * demuxer, add it to libavformat, except for wrappers around external @@ -782,7 +784,7 @@ bool demux_has_packet(struct sh_stream *sh) return has_packet; } -// Read and return any packet we find. +// Read and return any packet we find. NULL means EOF. struct demux_packet *demux_read_any_packet(struct demuxer *demuxer) { struct demux_internal *in = demuxer->in; @@ -1082,7 +1084,8 @@ static struct demuxer *open_given_type(struct mpv_global *global, mp_dbg(log, "Trying demuxer: %s (force-level: %s)\n", desc->name, d_level(check)); - if (stream->seekable) // not for DVD/BD/DVB in particular + // not for DVD/BD/DVB in particular + if (stream->seekable && (!params || !params->timeline)) stream_seek(stream, 0); // Peek this much data to avoid that stream_read() run by some demuxers @@ -1110,6 +1113,16 @@ static struct demuxer *open_given_type(struct mpv_global *global, demux_changed(in->d_thread, DEMUX_EVENT_ALL); demux_update(demuxer); stream_control(demuxer->stream, STREAM_CTRL_SET_READAHEAD, &(int){false}); + struct timeline *tl = timeline_load(global, log, demuxer); + if (tl) { + struct demuxer_params params2 = {0}; + params2.timeline = tl; + struct demuxer *sub = open_given_type(global, log, + &demuxer_desc_timeline, stream, + ¶ms2, DEMUX_CHECK_FORCE); + if (sub) + return sub; + } return demuxer; } diff --git a/demux/demux.h b/demux/demux.h index 72ed15888b..05e645f728 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -160,6 +160,7 @@ struct demuxer_params { struct matroska_segment_uid *matroska_wanted_uids; int matroska_wanted_segment; bool *matroska_was_valid; + struct timeline *timeline; // -- demux_open_url() only int stream_flags; bool allow_capture; diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c new file mode 100644 index 0000000000..9dbbff2158 --- /dev/null +++ b/demux/demux_timeline.c @@ -0,0 +1,392 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . + */ + +#include +#include + +#include "common/common.h" +#include "common/msg.h" + +#include "demux.h" +#include "timeline.h" +#include "stheader.h" + +struct segment { + int index; + double start, end; + double d_start; + struct demuxer *d; + // stream_map[sh_stream.index] = index into priv.streams, where sh_stream + // is a stream from the source d. It's used to map the streams of the + // source onto the set of streams of the virtual timeline. + // Uses -1 for streams that do not appear in the virtual timeline. + int *stream_map; + int num_stream_map; +}; + +// Information for each stream on the virtual timeline. (Mirrors streams +// exposed by demux_timeline.) +struct virtual_stream { + struct sh_stream *sh; // stream exported by demux_timeline + bool selected; // ==demux_stream_is_selected(sh) + bool new_segment; // whether a new segment needs to be signaled + int eos_packets; // deal with b-frame delay +}; + +struct priv { + struct timeline *tl; + + double duration; + + struct segment **segments; + int num_segments; + struct segment *current; + + // As the demuxer user sees it. + struct virtual_stream *streams; + int num_streams; + + // Total number of packets received past end of segment. Used + // to be clever about determining when to switch segments. + int eos_packets; + + double seek_pts; +}; + +static void switch_segment(struct demuxer *demuxer, struct segment *new, + double start_pts, int flags) +{ + struct priv *p = demuxer->priv; + + if (p->current == new) + return; + + if (!(flags & (SEEK_FORWARD | SEEK_BACKWARD))) + flags |= SEEK_BACKWARD; + + MP_VERBOSE(demuxer, "switch to segment %d\n", new->index); + + p->current = new; + demux_set_ts_offset(new->d, new->start - new->d_start); + demux_seek(new->d, start_pts, flags | SEEK_ABSOLUTE); + + for (int n = 0; n < p->num_streams; n++) { + struct virtual_stream *vs = &p->streams[n]; + vs->new_segment = true; + vs->eos_packets = 0; + } + + p->eos_packets = 0; +} + +static void d_seek(struct demuxer *demuxer, double rel_seek_secs, int flags) +{ + struct priv *p = demuxer->priv; + + double pts = p->seek_pts; + if (flags & SEEK_ABSOLUTE) + pts = 0.0f; + + if (flags & SEEK_FACTOR) { + pts += p->duration * rel_seek_secs; + } else { + pts += rel_seek_secs; + } + + flags &= SEEK_FORWARD | SEEK_BACKWARD | SEEK_HR; + + struct segment *new = p->segments[p->num_segments - 1]; + for (int n = 0; n < p->num_segments; n++) { + if (pts < p->segments[n]->end) { + new = p->segments[n]; + break; + } + } + + p->current = NULL; // force seek + switch_segment(demuxer, new, pts, flags); + + p->seek_pts = pts; +} + +static int d_fill_buffer(struct demuxer *demuxer) +{ + struct priv *p = demuxer->priv; + + if (!p->current) + switch_segment(demuxer, p->segments[0], 0, 0); + + struct segment *seg = p->current; + + struct demux_packet *pkt = demux_read_any_packet(seg->d); + if (!pkt || pkt->pts >= seg->end) + p->eos_packets += 1; + + // Test for EOF. Do this here to properly run into EOF even if other + // streams are disabled etc. If it somehow doesn't manage to reach the end + // after demuxing a high (bit arbitrary) number of packets, assume one of + // the streams went EOF early. + bool eos_reached = p->eos_packets > 0; + if (eos_reached && p->eos_packets < 100) { + for (int n = 0; n < p->num_streams; n++) { + struct virtual_stream *vs = &p->streams[n]; + if (vs->selected) { + int max_packets = 0; + if (vs->sh->type == STREAM_AUDIO) + max_packets = 1; + if (vs->sh->type == STREAM_VIDEO) + max_packets = 16; + eos_reached &= vs->eos_packets >= max_packets; + } + } + } + + if (eos_reached || !pkt) { + talloc_free(pkt); + + struct segment *next = NULL; + for (int n = 0; n < p->num_segments - 1; n++) { + if (p->segments[n] == seg) { + next = p->segments[n + 1]; + break; + } + } + if (!next) + return 0; + switch_segment(demuxer, next, next->start, 0); + return 1; // reader will retry + } + + if (pkt->stream < 0 || pkt->stream > seg->num_stream_map) + goto drop; + + if (!pkt->codec) + pkt->codec = demux_get_stream(seg->d, pkt->stream)->codec; + + if (pkt->start == MP_NOPTS_VALUE || pkt->start < seg->start) + pkt->start = seg->start; + if (pkt->end == MP_NOPTS_VALUE || pkt->end > seg->end) + pkt->end = seg->end; + + pkt->stream = seg->stream_map[pkt->stream]; + if (pkt->stream < 0) + goto drop; + + struct virtual_stream *vs = &p->streams[pkt->stream]; + + if (pkt->pts != MP_NOPTS_VALUE && pkt->pts >= seg->end) { + // Trust the keyframe flag. Might not always be a good idea, but will + // be sufficient at least with mkv. The problem is that this flag is + // not well-defined in libavformat and is container-dependent. + if (pkt->keyframe || vs->eos_packets == INT_MAX) { + vs->eos_packets = INT_MAX; + goto drop; + } else { + vs->eos_packets += 1; + } + } + + pkt->new_segment = vs->new_segment; + vs->new_segment = false; + + demux_add_packet(vs->sh, pkt); + return 1; + +drop: + talloc_free(pkt); + return 1; +} + +static void print_timeline(struct demuxer *demuxer) +{ + struct priv *p = demuxer->priv; + + MP_VERBOSE(demuxer, "Timeline segments:\n"); + for (int n = 0; n < p->num_segments; n++) { + struct segment *seg = p->segments[n]; + int src_num = -1; + for (int i = 0; i < p->tl->num_sources; i++) { + if (p->tl->sources[i] == seg->d) { + src_num = i; + break; + } + } + MP_VERBOSE(demuxer, " %2d: %12f [%12f] (", n, seg->start, seg->d_start); + for (int i = 0; i < seg->num_stream_map; i++) + MP_VERBOSE(demuxer, "%s%d", i ? " " : "", seg->stream_map[i]); + MP_VERBOSE(demuxer, ") %d:'%s'\n", src_num, seg->d->filename); + } + MP_VERBOSE(demuxer, "Total duration: %f\n", p->duration); +} + +static bool target_stream_used(struct segment *seg, int target_index) +{ + for (int n = 0; n < seg->num_stream_map; n++) { + if (seg->stream_map[n] == target_index) + return true; + } + return false; +} + +// Create mapping from segment streams to virtual timeline streams. +static void associate_streams(struct demuxer *demuxer, struct segment *seg) +{ + struct priv *p = demuxer->priv; + + int counts[STREAM_TYPE_COUNT] = {0}; + + int num_streams = demux_get_num_stream(seg->d); + for (int n = 0; n < num_streams; n++) { + struct sh_stream *sh = demux_get_stream(seg->d, n); + // Try associating by demuxer ID (supposedly useful for ordered chapters). + struct sh_stream *other = + demuxer_stream_by_demuxer_id(demuxer, sh->type, sh->demuxer_id); + if (!other || !target_stream_used(seg, other->index)) { + // Try to associate the first unused stream with matching media type. + for (int i = 0; i < p->num_streams; i++) { + struct sh_stream *cur = p->streams[i].sh; + if (cur->type == sh->type && !target_stream_used(seg, cur->index)) + { + other = cur; + break; + } + } + } + + MP_TARRAY_APPEND(seg, seg->stream_map, seg->num_stream_map, + other ? other->index : -1); + + counts[sh->type] += 1; + } +} + +static int d_open(struct demuxer *demuxer, enum demux_check check) +{ + struct priv *p = demuxer->priv = talloc_zero(demuxer, struct priv); + p->tl = demuxer->params ? demuxer->params->timeline : NULL; + if (!p->tl || p->tl->num_parts < 1) + return -1; + + p->duration = p->tl->parts[p->tl->num_parts].start; + + demuxer->chapters = p->tl->chapters; + demuxer->num_chapters = p->tl->num_chapters; + + struct demuxer *meta = p->tl->track_layout; + demuxer->metadata = meta->metadata; + demuxer->attachments = meta->attachments; + demuxer->num_attachments = meta->num_attachments; + + int num_streams = demux_get_num_stream(meta); + for (int n = 0; n < num_streams; n++) { + struct sh_stream *sh = demux_get_stream(meta, n); + struct sh_stream *new = demux_alloc_sh_stream(sh->type); + new->demuxer_id = sh->demuxer_id; + new->codec = sh->codec; + new->title = sh->title; + new->lang = sh->lang; + new->default_track = sh->default_track; + new->forced_track = sh->forced_track; + new->hls_bitrate = sh->hls_bitrate; + new->missing_timestamps = sh->missing_timestamps; + demux_add_sh_stream(demuxer, new); + struct virtual_stream vs = { + .sh = new, + }; + MP_TARRAY_APPEND(p, p->streams, p->num_streams, vs); + } + + for (int n = 0; n < p->tl->num_parts; n++) { + struct timeline_part *part = &p->tl->parts[n]; + struct timeline_part *next = &p->tl->parts[n + 1]; + + struct segment *seg = talloc_ptrtype(p, seg); + *seg = (struct segment){ + .d = part->source, + .d_start = part->source_start, + .start = part->start, + .end = next->start, + }; + + associate_streams(demuxer, seg); + + seg->index = n; + MP_TARRAY_APPEND(p, p->segments, p->num_segments, seg); + } + + print_timeline(demuxer); + + demuxer->seekable = true; + demuxer->partially_seekable = true; + + return 0; +} + +static void d_close(struct demuxer *demuxer) +{ + struct priv *p = demuxer->priv; + struct demuxer *master = p->tl->demuxer; + timeline_destroy(p->tl); + free_demuxer(master); +} + +static void reselect_streams(struct demuxer *demuxer) +{ + struct priv *p = demuxer->priv; + + for (int n = 0; n < p->num_streams; n++) { + struct virtual_stream *vs = &p->streams[n]; + vs->selected = demux_stream_is_selected(vs->sh); + } + + for (int n = 0; n < p->num_segments; n++) { + struct segment *seg = p->segments[n]; + for (int i = 0; i < seg->num_stream_map; i++) { + struct sh_stream *sh = demux_get_stream(seg->d, i); + bool selected = false; + if (seg->stream_map[i] >= 0) + selected = p->streams[seg->stream_map[i]].selected; + demuxer_select_track(seg->d, sh, selected); + } + } +} + +static int d_control(struct demuxer *demuxer, int cmd, void *arg) +{ + struct priv *p = demuxer->priv; + + switch (cmd) { + case DEMUXER_CTRL_GET_TIME_LENGTH: { + *(double *)arg = p->duration; + return DEMUXER_CTRL_OK; + } + case DEMUXER_CTRL_SWITCHED_TRACKS: + reselect_streams(demuxer); + return DEMUXER_CTRL_OK; + } + return DEMUXER_CTRL_NOTIMPL; +} + +const demuxer_desc_t demuxer_desc_timeline = { + .name = "timeline", + .desc = "timeline segment merging wrapper", + .fill_buffer = d_fill_buffer, + .open = d_open, + .close = d_close, + .seek = d_seek, + .control = d_control, +}; diff --git a/demux/packet.c b/demux/packet.c index 22b111b0ce..32fabc4f78 100644 --- a/demux/packet.c +++ b/demux/packet.c @@ -49,6 +49,8 @@ struct demux_packet *new_demux_packet_from_avpacket(struct AVPacket *avpkt) .dts = MP_NOPTS_VALUE, .duration = -1, .pos = -1, + .start = MP_NOPTS_VALUE, + .end = MP_NOPTS_VALUE, .stream = -1, .avpacket = talloc_zero(dp, AVPacket), }; @@ -106,6 +108,9 @@ void demux_packet_copy_attribs(struct demux_packet *dst, struct demux_packet *sr dst->dts = src->dts; dst->duration = src->duration; dst->pos = src->pos; + dst->start = src->start; + dst->end = src->end; + dst->new_segment = src->new_segment; dst->keyframe = src->keyframe; dst->stream = src->stream; } diff --git a/demux/packet.h b/demux/packet.h index 82dad6f90f..723dbc7e54 100644 --- a/demux/packet.h +++ b/demux/packet.h @@ -35,6 +35,11 @@ typedef struct demux_packet { int64_t pos; // position in source file byte stream int stream; // source stream index + // segmentation (ordered chapters, EDL) + struct mp_codec_params *codec; + double start, end; + bool new_segment; + // private struct demux_packet *next; struct AVPacket *avpacket; // keep the buffer allocation and sidedata -- cgit v1.2.3 From 3c3cd0c540a1ecd11b6a2d633b8e4c963802386d Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 16 Feb 2016 21:05:18 +0100 Subject: demux_timeline: disable cache for inactive segments This is achieved indirectly by deslecting all streams for the non- current segment (and if the segment doesn't share the demuxer with the currently active one). Restores functionality added with commit 46bcdb70. --- demux/demux_timeline.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'demux') diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c index 9dbbff2158..ef6e5a3890 100644 --- a/demux/demux_timeline.c +++ b/demux/demux_timeline.c @@ -25,6 +25,8 @@ #include "timeline.h" #include "stheader.h" +static void reselect_streams(struct demuxer *demuxer); + struct segment { int index; double start, end; @@ -81,6 +83,7 @@ static void switch_segment(struct demuxer *demuxer, struct segment *new, MP_VERBOSE(demuxer, "switch to segment %d\n", new->index); p->current = new; + reselect_streams(demuxer); demux_set_ts_offset(new->d, new->start - new->d_start); demux_seek(new->d, start_pts, flags | SEEK_ABSOLUTE); @@ -333,6 +336,8 @@ static int d_open(struct demuxer *demuxer, enum demux_check check) demuxer->seekable = true; demuxer->partially_seekable = true; + reselect_streams(demuxer); + return 0; } @@ -360,6 +365,9 @@ static void reselect_streams(struct demuxer *demuxer) bool selected = false; if (seg->stream_map[i] >= 0) selected = p->streams[seg->stream_map[i]].selected; + // This stops demuxer readahead for inactive segments. + if (!p->current || seg->d != p->current->d) + selected = false; demuxer_select_track(seg->d, sh, selected); } } -- cgit v1.2.3 From ce0b99314bf309af2d0dc869527f03854abc0d2e Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 16 Feb 2016 21:06:02 +0100 Subject: demux_timeline: cosmetics: move a function Gets rid of a forward declaration. --- demux/demux_timeline.c | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) (limited to 'demux') diff --git a/demux/demux_timeline.c b/demux/demux_