From 041c9f1782cbed4abf7793f4e72b8b29b2fd9b1b Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 29 Feb 2016 18:20:27 +0100 Subject: lavc_conv: fix Libav srt subtitles Use the mp_lavc_set_extradata() function instead of setting up the extradata manually. This takes care of the corner case when extradata_len is 0. This apparently fixes #2888. --- sub/lavc_conv.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sub/lavc_conv.c b/sub/lavc_conv.c index 3dd6097d0f..73030207ef 100644 --- a/sub/lavc_conv.c +++ b/sub/lavc_conv.c @@ -79,11 +79,8 @@ struct lavc_conv *lavc_conv_create(struct mp_log *log, const char *codec_name, avctx = avcodec_alloc_context3(codec); if (!avctx) goto error; - avctx->extradata_size = extradata_len; - avctx->extradata = av_malloc(extradata_len); - if (!avctx->extradata) + if (mp_lavc_set_extradata(avctx, extradata, extradata_len) < 0) goto error; - memcpy(avctx->extradata, extradata, extradata_len); if (strcmp(codec_name, "eia_608") == 0) av_dict_set(&opts, "real_time", "1", 0); if (avcodec_open2(avctx, codec, &opts) < 0) -- cgit v1.2.3 From 0a1e926670a5563df788f9c732a93e3230d86182 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 29 Feb 2016 20:55:44 +0100 Subject: command: export more information under track-list Export a number of container fields, which may or may not be useful in some scenarios. They are explicitly marked as originating from the demuxer, in order to make it explicit that they might be unreliable. I'd actually like to remove all other cases where container information is exported, but those numerous cases are going to be somewhat hard to deprecate. Also, not directly related, export the description of the currently active decoder. (This has been requested before.) --- DOCS/interface-changes.rst | 3 +++ DOCS/man/input.rst | 36 +++++++++++++++++++++++++++++++----- player/command.c | 24 +++++++++++++++++++++--- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 4217de86fc..1298c24d6d 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -19,6 +19,9 @@ Interface changes :: + --- mpv 0.17.0 --- + - deprecate "track-list/N/audio-channels" property (use + "track-list/N/demux-channel-count" instead) --- mpv 0.16.0 --- - change --audio-channels default to stereo (use --audio-channels=auto to get the old default) diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 11a8f0021f..9918f7384f 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -1707,10 +1707,6 @@ Property list ``track-list/N/lang`` Track language as identified by the file. Not always available. - ``track-list/N/audio-channels`` - For audio tracks, the number of audio channels in the audio stream. - Not always accurate (depends on container hints). Not always available. - ``track-list/N/albumart`` ``yes`` if this is a video track that consists of a single picture, ``no`` or unavailable otherwise. This is used for video tracks that are @@ -1746,6 +1742,29 @@ Property list match even if the default (builtin) demuxer is used, but there is no hard guarantee. + ``track-list/N/decoder-desc`` + If this track is being decoded, the human-readable decoder name, + + ``track-list/N/demux-w``, ``track-list/N/demux-h`` + Video size hint as indicated by the container. (Not always accurate.) + + ``track-list/N/demux-channel-count`` + Number of audio channels as indicated by the container. (Not always + accurate - in particular, the track could be decoded as a different + number of channels.) + + ``track-list/N/demux-channels`` + Channel layout as indicated by the container. (Not always accurate.) + + ``track-list/N/demux-samplerate`` + Audio sample rate as indicated by the container. (Not always accurate.) + + ``track-list/N/demux-fps`` + Video FPS as indicated by the container. (Not always accurate.) + + ``track-list/N/audio-channels`` (deprecated) + Deprecated alias for ``track-list/N/demux-channel-count``. + When querying the property with the client API using ``MPV_FORMAT_NODE``, or with Lua ``mp.get_property_native``, this will return a mpv_node with the following contents: @@ -1759,13 +1778,20 @@ Property list "src-id" MPV_FORMAT_INT64 "title" MPV_FORMAT_STRING "lang" MPV_FORMAT_STRING - "audio-channels" MPV_FORMAT_INT64 "albumart" MPV_FORMAT_FLAG "default" MPV_FORMAT_FLAG "forced" MPV_FORMAT_FLAG "external" MPV_FORMAT_FLAG "external-filename" MPV_FORMAT_STRING "codec" MPV_FORMAT_STRING + "decoder-desc" MPV_FORMAT_STRING + "demux-w" MPV_FORMAT_INT64 + "demux-h" MPV_FORMAT_INT64 + "demux-channel-count" MPV_FORMAT_INT64 + "demux-channels" MPV_FORMAT_STRING + "demux-samplerate" MPV_FORMAT_INT64 + "demux-fps" MPV_FORMAT_DOUBLE + "audio-channels" MPV_FORMAT_INT64 ``chapter-list`` List of chapters, current entry marked. Currently, the raw property value diff --git a/player/command.c b/player/command.c index 642330e34f..421f001573 100644 --- a/player/command.c +++ b/player/command.c @@ -1944,7 +1944,14 @@ static int get_track_entry(int item, int action, void *arg, void *ctx) struct MPContext *mpctx = ctx; struct track *track = mpctx->tracks[item]; - const char *codec = track->stream ? track->stream->codec->codec : NULL; + struct mp_codec_params p = + track->stream ? *track->stream->codec : (struct mp_codec_params){0}; + + const char *decoder_desc = NULL; + if (track->d_video) + decoder_desc = track->d_video->decoder_desc; + if (track->d_audio) + decoder_desc = track->d_audio->decoder_desc; struct m_sub_property props[] = { {"id", SUB_PROP_INT(track->user_tid)}, @@ -1965,9 +1972,20 @@ static int get_track_entry(int item, int action, void *arg, void *ctx) {"selected", SUB_PROP_FLAG(track->selected)}, {"external-filename", SUB_PROP_STR(track->external_filename), .unavailable = !track->external_filename}, - {"codec", SUB_PROP_STR(codec), - .unavailable = !codec}, {"ff-index", SUB_PROP_INT(track->ff_index)}, + {"decoder-desc", SUB_PROP_STR(decoder_desc), + .unavailable = !decoder_desc}, + {"codec", SUB_PROP_STR(p.codec), + .unavailable = !p.codec}, + {"demux-w", SUB_PROP_INT(p.disp_w), .unavailable = !p.disp_w}, + {"demux-h", SUB_PROP_INT(p.disp_h), .unavailable = !p.disp_h}, + {"demux-channel-count", SUB_PROP_INT(p.channels.num), + .unavailable = !p.channels.num}, + {"demux-channels", SUB_PROP_STR(mp_chmap_to_str(&p.channels)), + .unavailable = !p.channels.num}, + {"demux-samplerate", SUB_PROP_INT(p.samplerate), + .unavailable = !p.samplerate}, + {"demux-fps", SUB_PROP_DOUBLE(p.fps), .unavailable = p.fps <= 0}, {0} }; -- cgit v1.2.3 From d7de123110411ae02df5bb61dd960441d9a8ab90 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 29 Feb 2016 20:57:31 +0100 Subject: command: export list of all decoders Was only available via --vd=help and --ad=help (i.e. not at all via client API). Not bothering with separating audio and video codecs, since this list isn't all that useful anyway in general. If someone complains, a type field could be added. --- DOCS/man/input.rst | 32 ++++++++++++++++++++++++++++++++ player/command.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 9918f7384f..726354eafa 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -1988,6 +1988,38 @@ Property list In some cases, the protocol will not actually be supported (consider ``https`` if ffmpeg is not compiled with TLS support). +``decoder-list`` + List of decoders supported. This lists decoders which can be passed to + ``--vd`` and ``--ad``. + + ``family`` + Decoder driver. Usually ``lavc`` for libavcodec. + + ``codec`` + Canonical codec name, which identifies the format the decoder can + handle. + + ``decoder`` + The name of the decoder itself. Often, this is the same as ``codec``. + Sometimes it can be different. It is used to distinguish multiple + decoders for the same codec. + + ``description`` + Human readable description of the decoder and codec. + + When querying the property with the client API using ``MPV_FORMAT_NODE``, + or with Lua ``mp.get_property_native``, this will return a mpv_node with + the following contents: + + :: + + MPV_FORMAT_NODE_ARRAY + MPV_FORMAT_NODE_MAP (for each decoder entry) + "family" MPV_FORMAT_STRING + "codec" MPV_FORMAT_STRING + "decoder" MPV_FORMAT_STRING + "description" MPV_FORMAT_STRING + ``mpv-version`` Return the mpv version/copyright string. Depending on how the binary was built, it might contain either a release version, or just a git hash. diff --git a/player/command.c b/player/command.c index 421f001573..f4a78e11fb 100644 --- a/player/command.c +++ b/player/command.c @@ -32,6 +32,7 @@ #include "config.h" #include "mpv_talloc.h" #include "client.h" +#include "common/codecs.h" #include "common/msg.h" #include "common/msg_control.h" #include "command.h" @@ -3290,6 +3291,36 @@ static int mp_property_protocols(void *ctx, struct m_property *prop, return M_PROPERTY_NOT_IMPLEMENTED; } +static int get_decoder_entry(int item, int action, void *arg, void *ctx) +{ + struct mp_decoder_list *codecs = ctx; + struct mp_decoder_entry *c = &codecs->entries[item]; + + struct m_sub_property props[] = { + {"family", SUB_PROP_STR(c->family)}, + {"codec", SUB_PROP_STR(c->codec)}, + {"decoder", SUB_PROP_STR(c->decoder)}, + {"description", SUB_PROP_STR(c->desc)}, + {0} + }; + + return m_property_read_sub(props, action, arg); +} + +static int mp_property_decoders(void *ctx, struct m_property *prop, + int action, void *arg) +{ + struct mp_decoder_list *codecs = talloc_zero(NULL, struct mp_decoder_list); + struct mp_decoder_list *v = talloc_steal(codecs, video_decoder_list()); + struct mp_decoder_list *a = talloc_steal(codecs, audio_decoder_list()); + mp_append_decoders(codecs, v); + mp_append_decoders(codecs, a); + int r = m_property_read_list(action, arg, codecs->num_entries, + get_decoder_entry, codecs); + talloc_free(codecs); + return r; +} + static int mp_property_version(void *ctx, struct m_property *prop, int action, void *arg) { @@ -3707,6 +3738,7 @@ static const struct m_property mp_properties[] = { {"working-directory", mp_property_cwd}, {"protocol-list", mp_property_protocols}, + {"decoder-list", mp_property_decoders}, {"mpv-version", mp_property_version}, {"mpv-configuration", mp_property_configuration}, -- cgit v1.2.3 From 4bb94f13065cf2f68dc5874be86b62a6c3ef080d Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 29 Feb 2016 20:59:20 +0100 Subject: command: export canonical ffmpeg version identifier Was printed only with "mpv -h" or so. --- DOCS/man/input.rst | 7 +++++++ player/command.c | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 726354eafa..6dcf7a83e4 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -2028,6 +2028,13 @@ Property list Return the configuration arguments which were passed to the build system (typically the way ``./waf configure ...`` was invoked). +``ffmpeg-version`` + Return the contents of the ``av_version_info()`` API call. This is a string + which identifies the build in some way, either through a release version + number, or a git hash. This applies to Libav as well (the property is + still named the same.) This property is unavailable if mpv is linked against + older FFmpeg and Libav versions. + ``options/`` (RW) Read-only access to value of option ``--``. Most options can be changed at runtime by writing to this property. Note that many options diff --git a/player/command.c b/player/command.c index f4a78e11fb..9dc46900f2 100644 --- a/player/command.c +++ b/player/command.c @@ -3333,6 +3333,16 @@ static int mp_property_configuration(void *ctx, struct m_property *prop, return m_property_strdup_ro(action, arg, CONFIGURATION); } +static int mp_property_ffmpeg(void *ctx, struct m_property *prop, + int action, void *arg) +{ +#if HAVE_AV_VERSION_INFO + return m_property_strdup_ro(action, arg, av_version_info()); +#else + return M_PROPERTY_UNAVAILABLE; +#endif +} + static int mp_property_alias(void *ctx, struct m_property *prop, int action, void *arg) { @@ -3742,6 +3752,7 @@ static const struct m_property mp_properties[] = { {"mpv-version", mp_property_version}, {"mpv-configuration", mp_property_configuration}, + {"ffmpeg-version", mp_property_ffmpeg}, {"options", mp_property_options}, {"file-local-options", mp_property_local_options}, -- cgit v1.2.3 From af66fa8fa5d8e46b26a08a2b241f03d46abb3c2b Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 29 Feb 2016 21:00:18 +0100 Subject: demux_mkv: pretend waveext channel layouts by default Not much of an impact, just makes output of the "channels" "track-list" sub-property nicer. --- demux/demux_mkv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index c932b45f39..d54b8fadd6 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1641,7 +1641,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) 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); + mp_chmap_from_channels(&sh_a->channels, track->a_channels); const char *codec = sh_a->codec; if (!strcmp(codec, "mp3") || !strcmp(codec, "truehd")) { -- cgit v1.2.3 From 33774e18ed4c49857c042870099e3e3dd6fe614d Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 1 Mar 2016 21:46:49 +0100 Subject: command: add encoder-list property Also change decoder-list (for the sake of sharing the underlying code for both properties). --- DOCS/man/input.rst | 9 +++++++-- common/av_common.c | 15 +++++++++++++++ common/av_common.h | 1 + player/command.c | 15 ++++++++++++++- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 6dcf7a83e4..0cdb611583 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -1999,7 +1999,7 @@ Property list Canonical codec name, which identifies the format the decoder can handle. - ``decoder`` + ``driver`` The name of the decoder itself. Often, this is the same as ``codec``. Sometimes it can be different. It is used to distinguish multiple decoders for the same codec. @@ -2017,9 +2017,14 @@ Property list MPV_FORMAT_NODE_MAP (for each decoder entry) "family" MPV_FORMAT_STRING "codec" MPV_FORMAT_STRING - "decoder" MPV_FORMAT_STRING + "driver" MPV_FORMAT_STRING "description" MPV_FORMAT_STRING +``encoder-list`` + List of libavcodec encoders. This has the same format as ``decoder-list``. + The encoder names (``driver`` entries) can be passed to ``--ovc`` and + ``--oac`` (without the ``lavc:`` prefix required by ``--vd`` and ``--ad``). + ``mpv-version`` Return the mpv version/copyright string. Depending on how the binary was built, it might contain either a release version, or just a git hash. diff --git a/common/av_common.c b/common/av_common.c index 8b979cabba..5cb434f969 100644 --- a/common/av_common.c +++ b/common/av_common.c @@ -158,6 +158,21 @@ void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type) } } +// (Abuses the decoder list data structures.) +void mp_add_lavc_encoders(struct mp_decoder_list *list) +{ + AVCodec *cur = NULL; + for (;;) { + cur = av_codec_next(cur); + if (!cur) + break; + if (av_codec_is_encoder(cur)) { + mp_add_decoder(list, "lavc", mp_codec_from_av_codec_id(cur->id), + cur->name, cur->long_name); + } + } +} + int mp_codec_to_av_codec_id(const char *codec) { int id = AV_CODEC_ID_NONE; diff --git a/common/av_common.h b/common/av_common.h index e9df328fbf..1478adf8fb 100644 --- a/common/av_common.h +++ b/common/av_common.h @@ -36,6 +36,7 @@ int64_t mp_pts_to_av(double mp_pts, AVRational *tb); double mp_pts_from_av(int64_t av_pts, AVRational *tb); void mp_set_avcodec_threads(struct mp_log *l, AVCodecContext *avctx, int threads); void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type); +void mp_add_lavc_encoders(struct mp_decoder_list *list); int mp_codec_to_av_codec_id(const char *codec); const char *mp_codec_from_av_codec_id(int codec_id); void mp_set_avdict(struct AVDictionary **dict, char **kv); diff --git a/player/command.c b/player/command.c index 9dc46900f2..275effb5a4 100644 --- a/player/command.c +++ b/player/command.c @@ -32,6 +32,7 @@ #include "config.h" #include "mpv_talloc.h" #include "client.h" +#include "common/av_common.h" #include "common/codecs.h" #include "common/msg.h" #include "common/msg_control.h" @@ -3299,7 +3300,7 @@ static int get_decoder_entry(int item, int action, void *arg, void *ctx) struct m_sub_property props[] = { {"family", SUB_PROP_STR(c->family)}, {"codec", SUB_PROP_STR(c->codec)}, - {"decoder", SUB_PROP_STR(c->decoder)}, + {"driver" , SUB_PROP_STR(c->decoder)}, {"description", SUB_PROP_STR(c->desc)}, {0} }; @@ -3321,6 +3322,17 @@ static int mp_property_decoders(void *ctx, struct m_property *prop, return r; } +static int mp_property_encoders(void *ctx, struct m_property *prop, + int action, void *arg) +{ + struct mp_decoder_list *codecs = talloc_zero(NULL, struct mp_decoder_list); + mp_add_lavc_encoders(codecs); + int r = m_property_read_list(action, arg, codecs->num_entries, + get_decoder_entry, codecs); + talloc_free(codecs); + return r; +} + static int mp_property_version(void *ctx, struct m_property *prop, int action, void *arg) { @@ -3749,6 +3761,7 @@ static const struct m_property mp_properties[] = { {"protocol-list", mp_property_protocols}, {"decoder-list", mp_property_decoders}, + {"encoder-list", mp_property_encoders}, {"mpv-version", mp_property_version}, {"mpv-configuration", mp_property_configuration}, -- cgit v1.2.3 From e0944991973c04701c830647a3f943b43d546b20 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 1 Mar 2016 21:51:59 +0100 Subject: msg: use dynamic buffer for message formatting Until now, a rather large stack buffer was used for this, and also a static buffer in mp_log_root. The latter was added to buffer partial lines, and the stack buffer was used only for MSGL_STATUS and MSGL_STATS (I guess because these are the most likely/severe to clash with partial line buffering). Make the buffer in mp_log_root dynamically sized, so we don't get cut off log lines if the text is excessively large. (The OpenGL extension list dumped by vo_opengl is such an example.) Since we still have to support partial line buffering (FFmpeg's log callbacks leave no other choice), keep the stack buffer. But make it smaller; there's no way all ~6KB are going to be needed in any situation. --- common/msg.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/common/msg.c b/common/msg.c index 01d0bb78a0..065ef46620 100644 --- a/common/msg.c +++ b/common/msg.c @@ -41,9 +41,6 @@ #include "msg.h" #include "msg_control.h" -/* maximum message length of mp_msg */ -#define MSGSIZE_MAX 6144 - struct mp_log_root { struct mpv_global *global; // --- protected by mp_msg_lock @@ -67,7 +64,7 @@ struct mp_log_root { * synchronized mp_log tree.) */ atomic_ulong reload_counter; // --- protected by mp_msg_lock - char buffer[MSGSIZE_MAX]; + char *buffer; }; struct mp_log { @@ -337,17 +334,27 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va) pthread_mutex_lock(&mp_msg_lock); - char tmp[MSGSIZE_MAX]; + // MSGL_STATUS and MSGL_STATS use their own buffer; this prevents clashes + // with mp_msg() users which do not properly send complete lines only. + char tmp[256]; bool use_tmp = lev == MSGL_STATUS || lev == MSGL_STATS; struct mp_log_root *root = log->root; char *text = use_tmp ? tmp : root->buffer; int len = use_tmp ? 0 : strlen(text); - - if (vsnprintf(text + len, MSGSIZE_MAX - len, format, va) < 0) - snprintf(text + len, MSGSIZE_MAX - len, "[fprintf error]\n"); - text[MSGSIZE_MAX - 2] = '\n'; - text[MSGSIZE_MAX - 1] = 0; + int max_len = use_tmp ? sizeof(tmp) : talloc_get_size(text); + + va_list t; + va_copy(t, va); + int res = vsnprintf(text + len, max_len - len, format, t); + if (res >= 0 && res >= max_len - len && !use_tmp) { + root->buffer = talloc_realloc(root, root->buffer, char, res + len + 1); + text = root->buffer; + max_len = talloc_get_size(text); + res = vsnprintf(text + len, max_len - len, format, va); + } + if (res < 0) + text = "[fprintf error]\n"; if (lev == MSGL_STATS) { dump_stats(log, lev, text); @@ -376,7 +383,7 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va) if (lev == MSGL_STATUS) { if (text[0]) { len = strlen(text); - if (len < MSGSIZE_MAX - 1) { + if (len < max_len - 1) { text[len] = root->termosd ? '\r' : '\n'; text[len + 1] = '\0'; } @@ -441,6 +448,7 @@ void mp_msg_init(struct mpv_global *global) *root = (struct mp_log_root){ .global = global, .reload_counter = ATOMIC_VAR_INIT(1), + .buffer = talloc_strdup(root, ""), }; struct mp_log dummy = { .root = root }; -- cgit v1.2.3 From 4e53272376c546bac2e5c73f7ebfe456162d3663 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 1 Mar 2016 22:03:45 +0100 Subject: av_log: avoid partial lines We want to add a prefix to the ffmpeg log message, so we called mp_msg multiple times until now. But logging such partial lines is a race condition, because there's only one internal mp_msg buffer, and no external mp_msg locks. Avoid this by building the message on a stack buffer. I might make a mp_log-local partial line buffer, but even then av_log() can be called from multiple threads, while targetting the same mp_log. (Really, ffmpeg's log API needs to be fixed.) --- common/av_log.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/common/av_log.c b/common/av_log.c index 7e0b271c81..bfd9a836e8 100644 --- a/common/av_log.c +++ b/common/av_log.c @@ -131,12 +131,17 @@ static void mp_msg_av_log_callback(void *ptr, int level, const char *fmt, struct mp_log *log = get_av_log(ptr); if (mp_msg_test(log, mp_level)) { + char buffer[4096] = ""; + int pos = 0; const char *prefix = avc ? avc->item_name(ptr) : NULL; if (log_print_prefix && prefix) - mp_msg(log, mp_level, "%s: ", prefix); + pos = snprintf(buffer, sizeof(buffer), "%s: ", prefix); log_print_prefix = fmt[strlen(fmt) - 1] == '\n'; - mp_msg_va(log, mp_level, fmt, vl); + pos = MPMIN(MPMAX(pos, 0), sizeof(buffer)); + vsnprintf(buffer + pos, sizeof(buffer) - pos, fmt, vl); + + mp_msg(log, mp_level, "%s", buffer); } pthread_mutex_unlock(&log_lock); -- cgit v1.2.3 From a5eef06225f17890a0f49dc4c797ff0a3171cdd0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 1 Mar 2016 22:11:09 +0100 Subject: msg: minor simplification Instead of playing ugly tricks with the buffer to append a \r or \n to the text buffer, extend print_terminal_line() to print a second string. --- common/msg.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/common/msg.c b/common/msg.c index 065ef46620..29dd5abbf5 100644 --- a/common/msg.c +++ b/common/msg.c @@ -236,7 +236,8 @@ static bool test_terminal_level(struct mp_log *log, int lev) !(lev == MSGL_STATUS && terminal_in_background()); } -static void print_terminal_line(struct mp_log *log, int lev, char *text) +static void print_terminal_line(struct mp_log *log, int lev, + char *text, char *trail) { if (!test_terminal_level(log, lev)) return; @@ -265,7 +266,7 @@ static void print_terminal_line(struct mp_log *log, int lev, char *text) } } - fprintf(stream, "%s", text); + fprintf(stream, "%s%s", text, trail); if (root->color) set_term_color(stream, -1); @@ -373,7 +374,7 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va) char *next = &end[1]; char saved = next[0]; next[0] = '\0'; - print_terminal_line(log, lev, text); + print_terminal_line(log, lev, text, ""); write_log_file(log, lev, text); write_msg_to_buffers(log, lev, text); next[0] = saved; @@ -381,14 +382,8 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va) } if (lev == MSGL_STATUS) { - if (text[0]) { - len = strlen(text); - if (len < max_len - 1) { - text[len] = root->termosd ? '\r' : '\n'; - text[len + 1] = '\0'; - } - print_terminal_line(log, lev, text); - } + if (text[0]) + print_terminal_line(log, lev, text, root->termosd ? "\r" : "\n"); } else { int leftover = strlen(text); memmove(root->buffer, text, leftover + 1); -- cgit v1.2.3 From 46a3165cde956683e514788f625a87b3380ddf7c Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 1 Mar 2016 22:34:14 +0100 Subject: msg: introduce partial line buffers per mp_log The goal is reducing log messups (which happen surprisingly often) by buffering partial lines in mp_log. This is still not 100% reliable, but better. The extrabuffers for MSGL_STATUS and MSGL_STATS are not needed anymore, because a separate mp_log instance can be used if problems really occur. Also, give up, and replace the snprintf acrobatics with bstr. mp_log.partial has a quite subtle problem wrt. talloc: talloc parents can not be used, because there's no lock around the internal talloc structures associated with mp_log. Thus it has to be freed manually, even if this happens through a talloc destructor. --- common/msg.c | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/common/msg.c b/common/msg.c index 29dd5abbf5..534ba41cb5 100644 --- a/common/msg.c +++ b/common/msg.c @@ -31,6 +31,7 @@ #include "common/common.h" #include "common/global.h" #include "misc/ring.h" +#include "misc/bstr.h" #include "options/options.h" #include "osdep/terminal.h" #include "osdep/io.h" @@ -64,7 +65,7 @@ struct mp_log_root { * synchronized mp_log tree.) */ atomic_ulong reload_counter; // --- protected by mp_msg_lock - char *buffer; + bstr buffer; }; struct mp_log { @@ -74,6 +75,7 @@ struct mp_log { int level; // minimum log level for any outputs int terminal_level; // minimum log level for terminal output atomic_ulong reload_counter; + char *partial; }; struct mp_log_buffer { @@ -335,27 +337,17 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va) pthread_mutex_lock(&mp_msg_lock); - // MSGL_STATUS and MSGL_STATS use their own buffer; this prevents clashes - // with mp_msg() users which do not properly send complete lines only. - char tmp[256]; - bool use_tmp = lev == MSGL_STATUS || lev == MSGL_STATS; - struct mp_log_root *root = log->root; - char *text = use_tmp ? tmp : root->buffer; - int len = use_tmp ? 0 : strlen(text); - int max_len = use_tmp ? sizeof(tmp) : talloc_get_size(text); - - va_list t; - va_copy(t, va); - int res = vsnprintf(text + len, max_len - len, format, t); - if (res >= 0 && res >= max_len - len && !use_tmp) { - root->buffer = talloc_realloc(root, root->buffer, char, res + len + 1); - text = root->buffer; - max_len = talloc_get_size(text); - res = vsnprintf(text + len, max_len - len, format, va); - } - if (res < 0) - text = "[fprintf error]\n"; + + root->buffer.len = 0; + + if (log->partial[0]) + bstr_xappend_asprintf(root, &root->buffer, "%s", log->partial); + log->partial[0] = '\0'; + + bstr_xappend_vasprintf(root, &root->buffer, format, va); + + char *text = root->buffer.start; if (lev == MSGL_STATS) { dump_stats(log, lev, text); @@ -384,15 +376,25 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va) if (lev == MSGL_STATUS) { if (text[0]) print_terminal_line(log, lev, text, root->termosd ? "\r" : "\n"); - } else { - int leftover = strlen(text); - memmove(root->buffer, text, leftover + 1); + } else if (text[0]) { + int size = strlen(text) + 1; + if (talloc_get_size(log->partial) < size) + log->partial = talloc_realloc(NULL, log->partial, char, size); + memcpy(log->partial, text, size); } } pthread_mutex_unlock(&mp_msg_lock); } +static void destroy_log(void *ptr) +{ + struct mp_log *log = ptr; + // This is not managed via talloc itself, because mp_msg calls must be + // thread-safe, while talloc is not thread-safe. + talloc_free(log->partial); +} + // Create a new log context, which uses talloc_ctx as talloc parent, and parent // as logical parent. // The name is the prefix put before the output. It's usually prefixed by the @@ -409,7 +411,9 @@ struct mp_log *mp_log_new(void *talloc_ctx, struct mp_log *parent, struct mp_log *log = talloc_zero(talloc_ctx, struct mp_log); if (!parent->root) return log; // same as null_log + talloc_set_destructor(log, destroy_log); log->root = parent->root; + log->partial = talloc_strdup(NULL, ""); if (name) { if (name[0] == '!') { name = &name[1]; @@ -443,7 +447,6 @@ void mp_msg_init(struct mpv_global *global) *root = (struct mp_log_root){ .global = global, .reload_counter = ATOMIC_VAR_INIT(1), - .buffer = talloc_strdup(root, ""), }; struct mp_log dummy = { .root = root }; -- cgit v1.2.3 From a888f08b78e9b3bc1ce59fbfcd1e4b4eafb23245 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 2 Mar 2016 13:57:30 +0100 Subject: command: fix property notification for cache-buffering-state --- player/command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/player/command.c b/player/command.c index 275effb5a4..950d6dd80c 100644 --- a/player/command.c +++ b/player/command.c @@ -3820,7 +3820,7 @@ static const char *const *const mp_event_property_change[] = { E(MPV_EVENT_CHAPTER_CHANGE, "chapter", "chapter-metadata"), E(MP_EVENT_CACHE_UPDATE, "cache", "cache-free", "cache-used", "cache-idle", "demuxer-cache-duration", "demuxer-cache-idle", "paused-for-cache", - "demuxer-cache-time"), + "demuxer-cache-time", "cache-buffering-state"), E(MP_EVENT_WIN_RESIZE, "window-scale", "osd-width", "osd-height", "osd-par"), E(MP_EVENT_WIN_STATE, "window-minimized", "display-names", "display-fps", "fullscreen"), }; -- cgit v1.2.3 From fa8b2be4de852a3fc0ef340543a1f6737d611435 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 2 Mar 2016 22:20:04 +0100 Subject: av_common: explicitly exclude _vdpau deccoders from enumeration Completely pointless abominations that FFmpeg refuses to remove. They are ancient, long deprecated API which we can't use anymore. They confused users as well. Pretend that they don't exist. Due to the way --vd works, they can't even be forced anymore. The older hack which explicitly rejects these can be dropped as well. --- common/av_common.c | 7 ++++++- video/decode/vd_lavc.c | 11 ----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/common/av_common.c b/common/av_common.c index 5cb434f969..6efa1803fd 100644 --- a/common/av_common.c +++ b/common/av_common.c @@ -144,6 +144,11 @@ void mp_set_avcodec_threads(struct mp_log *l, AVCodecContext *avctx, int threads avctx->thread_count = threads; } +static bool is_crap(AVCodec *codec) +{ + return !!strstr(codec->name, "_vdpau"); +} + void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type) { AVCodec *cur = NULL; @@ -151,7 +156,7 @@ void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type) cur = av_codec_next(cur); if (!cur) break; - if (av_codec_is_decoder(cur) && cur->type == type) { + if (av_codec_is_decoder(cur) && cur->type == type && !is_crap(cur)) { mp_add_decoder(list, "lavc", mp_codec_from_av_codec_id(cur->id), cur->name, cur->long_name); } diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 0520c3a4fd..fa1d2ddf55 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -335,17 +335,6 @@ static int init(struct dec_video *vd, const char *decoder) ctx->opts = vd->opts; ctx->decoder = talloc_strdup(ctx, decoder); - if (bstr_endswith0(bstr0(decoder), "_vdpau")) { - MP_WARN(vd, "VDPAU decoder '%s' was requested. " - "This way of enabling hardware\ndecoding is not supported " - "anymore. Use --hwdec=vdpau instead.\nThe --hwdec-codec=... " - "option can be used to restrict which codecs are\nenabled, " - "otherwise all hardware decoding is tried for all codecs.\n", - decoder); - uninit(vd); - return 0; - } - reinit(vd); if (!ctx->avctx) { -- cgit v1.2.3 From a19307d598c515627192c752aa6d4341b88078c9 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 2 Mar 2016 22:28:32 +0100 Subject: Revert "demux_mkv: pretend waveext channel layouts by default" This reverts commit af66fa8fa5d8e46b26a08a2b241f03d46abb3c2b. The reverted commit caused AVCodecContext.channel_layout to be set, while requesting stereo downmix will make libavcodec output a stupid message: ac3: Channel layout '5.1' with 6 channels does not match specified number of channels 2: ignoring specified channel layout The same happens with --demuxer=lavf (without this change too). I'm not quite sure what acrobatics are required to shut up libavcodec, but for now revert the commit. It was a rather minor, almost cosmetic issue, which I consider less important than clean CLI terminal output. --- demux/demux_mkv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index d54b8fadd6..c932b45f39 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1641,7 +1641,7 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) mp_chmap_from_waveext(&sh_a->channels, chmask); if (sh_a->channels.num != track->a_channels) - mp_chmap_from_channels(&sh_a->channels, 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 3a7563a99983279394f9a4973a45f12aeb07cf7c Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 3 Mar 2016 10:08:00 +0100 Subject: cache: remove unused STREAM_CTRL_RESUME_CACHE Went way with DVD/BD menu support. --- stream/cache.c | 4 ---- stream/stream.h | 1 - 2 files changed, 5 deletions(-) diff --git a/stream/cache.c b/stream/cache.c index 8c18d18b1a..8421a6fc33 100644 --- a/stream/cache.c +++ b/stream/cache.c @@ -409,10 +409,6 @@ static int cache_get_cached_control(stream_t *cache, int cmd, void *arg) } return STREAM_UNSUPPORTED; } - case STREAM_CTRL_RESUME_CACHE: - s->idle = s->eof = false; - pthread_cond_signal(&s->wakeup); - return STREAM_OK; case STREAM_CTRL_AVSEEK: if (!s->has_avseek) return STREAM_UNSUPPORTED; diff --git a/stream/stream.h b/stream/stream.h index ab37c3b4bd..c75bb495e4 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -71,7 +71,6 @@ enum stream_ctrl { STREAM_CTRL_SET_CACHE_SIZE, STREAM_CTRL_GET_CACHE_FILL, STREAM_CTRL_GET_CACHE_IDLE, - STREAM_CTRL_RESUME_CACHE, STREAM_CTRL_SET_READAHEAD, // stream_memory.c -- cgit v1.2.3 From a4e29e67f91a24cb18443f7b21e74401781161f4 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 3 Mar 2016 11:04:32 +0100 Subject: demux_lavf: don't copy cover art picture Use the AVPacket refcounting mechanism instead. --- demux/demux_lavf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 8a92a2886f..c6430f73f0 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -577,8 +577,8 @@ static void handle_new_stream(demuxer_t *demuxer, int i) sh = demux_alloc_sh_stream(STREAM_VIDEO); if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) { - sh->attached_picture = new_demux_packet_from(st->attached_pic.data, - st->attached_pic.size); + sh->attached_picture = + new_demux_packet_from_avpacket(&st->attached_pic); if (sh->attached_picture) { sh->attached_picture->pts = 0; talloc_steal(sh, sh->attached_picture); -- cgit v1.2.3 From 5c2026336419805202fbf7a817b2960b0584ce5d Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 3 Mar 2016 15:30:28 +0100 Subject: vo_opengl: wayland: don't destroy NULL wl_egl_window The wayland client API crashes intentionally when trying to free NULL objects. (Thanks.) --- video/out/opengl/context_wayland.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/video/out/opengl/context_wayland.c b/video/out/opengl/context_wayland.c index 63a14539fe..a100073780 100644 --- a/video/out/opengl/context_wayland.c +++ b/video/out/opengl/context_wayland.c @@ -183,7 +183,8 @@ static void waylandgl_uninit(MPGLContext *ctx) if (wl->egl_context.egl.ctx) { eglReleaseThread(); - wl_egl_window_destroy(wl->egl_context.egl_window); + if (wl->egl_context.egl_window) + wl_egl_window_destroy(wl->egl_context.egl_window); eglDestroySurface(wl->egl_context.egl.dpy, wl->egl_context.egl_surface); eglMakeCurrent(wl->egl_context.egl.dpy, NULL, NULL, EGL_NO_CONTEXT); eglDestroyContext(wl->egl_context.egl.dpy, wl->egl_context.egl.ctx); -- cgit v1.2.3 From a6f8a6977ec59d314b617780c60e374b585ebaca Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 3 Mar 2016 15:30:55 +0100 Subject: demux_timeline: set correct seekable flags Tricky misleading crap. Fixes #2898. --- demux/demux.h | 2 +- demux/demux_timeline.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demux/demux.h b/demux/demux.h index e882e90da8..2c1e3a20fa 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -174,7 +174,7 @@ typedef struct demuxer { int64_t filepos; // input stream current pos. char *filename; // same as stream->url bool seekable; - bool partially_seekable; // implies seekable=true + bool partially_seekable; // true if _maybe_ seekable; implies seekable=true double start_time; // File format allows PTS resets (even if the current file is without) bool ts_resets_possible; diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c index 0c6c3986cc..92cf1e6fcf 100644 --- a/demux/demux_timeline.c +++ b/demux/demux_timeline.c @@ -344,7 +344,7 @@ static int d_open(struct demuxer *demuxer, enum demux_check check) print_timeline(demuxer); demuxer->seekable = true; - demuxer->partially_seekable = true; + demuxer->partially_seekable = false; demuxer->filetype = meta->filetype ? meta->filetype : meta->desc->name; -- cgit v1.2.3 From 3f60548df472d01387784601526e378d8ffb4659 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 3 Mar 2016 18:48:56 +0100 Subject: sub: pass all attachments to the subtitle decoder Commit 8d4a179c made subtitle decoders pick up fonts strictly from the same source file (i.e. the same demuxer). It breaks some fucked up use-case, and 2 people on this earth complained about the change because of this. Add it back. This copies all attached fonts on each subtitle init. I considered converting attachments to use refcounting, but it'd probably be much more complex. Since it's slightly harder to get a list of active demuxers with duplicate removed, the prev_demuxer variable serves as a hack to achieve almost the same thing, except in weird corner cases. (In which fonts could be added twice.) --- player/sub.c | 26 +++++++++++++++++++++++++- sub/dec_sub.c | 14 ++++++++------ sub/dec_sub.h | 10 +++++++--- sub/sd.h | 2 +- sub/sd_ass.c | 6 +++--- 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/player/sub.c b/player/sub.c index 6892ac935b..426e31bc7a 100644 --- a/player/sub.c +++ b/player/sub.c @@ -129,6 +129,29 @@ bool update_subtitles(struct MPContext *mpctx, double video_pts) return ok; } +static struct attachment_list *get_all_attachments(struct MPContext *mpctx) +{ + struct attachment_list *list = talloc_zero(NULL, struct attachment_list); + struct demuxer *prev_demuxer = NULL; + for (int n = 0; n < mpctx->num_tracks; n++) { + struct track *t = mpctx->tracks[n]; + if (!t->demuxer || prev_demuxer == t->demuxer) + continue; + prev_demuxer = t->demuxer; + for (int i = 0; i < t->demuxer->num_attachments; i++) { + struct demux_attachment *att = &t->demuxer->attachments[i]; + struct demux_attachment copy = { + .name = talloc_strdup(list, att->name), + .type = talloc_strdup(list, att->type), + .data = talloc_memdup(list, att->data, att->data_size), + .data_size = att->data_size, + }; + MP_TARRAY_APPEND(list, list->entries, list->num_entries, copy); + } + } + return list; +} + static bool init_subdec(struct MPContext *mpctx, struct track *track) { assert(!track->d_sub); @@ -136,7 +159,8 @@ static bool init_subdec(struct MPContext *mpctx, struct track *track) if (!track->demuxer || !track->stream) return false; - track->d_sub = sub_create(mpctx->global, track->demuxer, track->stream); + track->d_sub = sub_create(mpctx->global, track->stream, + get_all_attachments(mpctx)); if (!track->d_sub) return false; diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 75f5509c62..fbce829f5f 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -49,7 +49,7 @@ struct dec_sub { struct mpv_global *global; struct MPOpts *opts; - struct demuxer *demuxer; + struct attachment_list *attachments; struct sh_stream *sh; double last_pkt_pts; @@ -94,7 +94,7 @@ static struct sd *init_decoder(struct dec_sub *sub) .log = mp_log_new(sd, sub->log, driver->name), .opts = sub->opts, .driver = driver, - .demuxer = sub->demuxer, + .attachments = sub->attachments, .codec = sub->codec, }; @@ -112,10 +112,12 @@ static struct sd *init_decoder(struct dec_sub *sub) // Thread-safety of the returned object: all functions are thread-safe, // except sub_get_bitmaps() and sub_get_text(). Decoder backends (sd_*) // do not need to acquire locks. -struct dec_sub *sub_create(struct mpv_global *global, struct demuxer *demuxer, - struct sh_stream *sh) +// Ownership of attachments goes to the caller, and is released with +// talloc_free() (even on failure). +struct dec_sub *sub_create(struct mpv_global *global, struct sh_stream *sh, + struct attachment_list *attachments) { - assert(demuxer && sh && sh->type == STREAM_SUB); + assert(sh && sh->type == STREAM_SUB); struct dec_sub *sub = talloc(NULL, struct dec_sub); *sub = (struct dec_sub){ @@ -124,7 +126,7 @@ struct dec_sub *sub_create(struct mpv_global *global, struct demuxer *demuxer, .opts = global->opts, .sh = sh, .codec = sh->codec, - .demuxer = demuxer, + .attachments = talloc_steal(sub, attachments), .last_pkt_pts = MP_NOPTS_VALUE, .last_vo_pts = MP_NOPTS_VALUE, .start = MP_NOPTS_VALUE, diff --git a/sub/dec_sub.h b/sub/dec_sub.h index b3f30520e3..cedb140e79 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -6,7 +6,6 @@ #include "osd.h" -struct demuxer; struct sh_stream; struct mpv_global; struct demux_packet; @@ -22,8 +21,13 @@ enum sd_ctrl { SD_CTRL_SET_VIDEO_DEF_FPS, }; -struct dec_sub *sub_create(struct mpv_global *global, struct demuxer *demuxer, - struct sh_stream *sh); +struct attachment_list { + struct demux_attachment *entries; + int num_entries; +}; + +struct dec_sub *sub_create(struct mpv_global *global, struct sh_stream *sh, + struct attachment_list *attachments); void sub_destroy(struct dec_sub *sub); void sub_lock(struct dec_sub *sub); void sub_unlock(struct dec_sub *sub); diff --git a/sub/sd.h b/sub/sd.h index b142654ed1..92bbf906fd 100644 --- a/sub/sd.h +++ b/sub/sd.h @@ -17,7 +17,7 @@ struct sd { const struct sd_functions *driver; void *priv; - struct demuxer *demuxer; + struct attachment_list *attachments; struct mp_codec_params *codec; }; diff --git a/sub/sd_ass.c b/sub/sd_ass.c index 5c56d3e0df..4426c2ebab 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -117,10 +117,10 @@ static void add_subtitle_fonts(struct sd *sd) { struct sd_ass_priv *ctx = sd->priv; struct MPOpts *opts = sd->opts; - if (!opts->ass_enabled || !sd->demuxer) + if (!opts->ass_enabled || !sd->attachments) return; - for (int i = 0; i < sd->demuxer->num_attachments; i++) { - struct demux_attachment *f = &sd->demuxer->attachments[i]; + for (int i = 0; i < sd->attachments->num_entries; i++) { + struct demux_attachment *f = &sd->attachments->entries[i]; if (opts->use_embedded_fonts && attachment_is_font(sd->log, f)) ass_add_font(ctx->ass_library, f->name, f->data, f->data_size); } -- cgit v1.2.3 From 9972847265f760ec6d7f813750325f11f7e0077f Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 4 Mar 2016 23:51:55 +0100 Subject: demux: add null demuxer It's useless, but can be used for fancy --lavfi-complex nonsense. --- DOCS/man/mpv.rst | 4 +++- DOCS/man/options.rst | 2 ++ demux/demux.c | 2 ++ demux/demux_null.c | 34 ++++++++++++++++++++++++++++++++++ wscript_build.py | 1 + 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 demux/demux_null.c diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst index 6716c382f2..62a3a72f55 100644 --- a/DOCS/man/mpv.rst +++ b/DOCS/man/mpv.rst @@ -708,7 +708,9 @@ PROTOCOLS Stitch together parts of multiple files and play them. ``null://`` - Simulate an empty file. + Simulate an empty file. If opened for writing, it will discard all data. + The ``null`` demuxer will specifically pass autoprobing if this protocol + is used (while it's not automatically invoked for empty files). ``memory://data`` Use the ``data`` part as source data. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index ec71dd762b..eb1b1a60c0 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -3603,6 +3603,8 @@ Miscellaneous - ``--lavfi-complex='[aid1] asplit [t1] [ao] ; [t1] showvolume [t2] ; [vid1] [t2] overlay [vo]'`` Play audio track 1, and overlay the measured volume for each speaker over video track 1. + - ``null:// --lavfi-complex='life [vo]'`` + Conways' Life Game. See the FFmpeg libavfilter documentation for details on the filter. diff --git a/demux/demux.c b/demux/demux.c index 05a8551608..bd3211a74a 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -53,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_null; extern const demuxer_desc_t demuxer_desc_timeline; /* Please do not add any new demuxers here. If you want to implement a new @@ -76,6 +77,7 @@ const demuxer_desc_t *const demuxer_list[] = { &demuxer_desc_lavf, &demuxer_desc_mf, &demuxer_desc_playlist, + &demuxer_desc_null, NULL }; diff --git a/demux/demux_null.c b/demux/demux_null.c new file mode 100644 index 0000000000..c6a25b5af2 --- /dev/null +++ b/demux/demux_null.c @@ -0,0 +1,34 @@ +/* + * 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 "misc/bstr.h" +#include "stream/stream.h" +#include "demux.h" + +static int try_open_file(struct demuxer *demux, enum demux_check check) +{ + if (strcmp(demux->stream->info->name, "null") != 0 && + check != DEMUX_CHECK_REQUEST) + return -1; + return 0; +} + +const struct demuxer_desc demuxer_desc_null = { + .name = "null", + .desc = "null demuxer", + .open = try_open_file, +}; diff --git a/wscript_build.py b/wscript_build.py index 4cc35cad9e..39d0fe7362 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -175,6 +175,7 @@ def build(ctx): ( "demux/demux_mf.c" ), ( "demux/demux_mkv.c" ), ( "demux/demux_mkv_timeline.c" ), + ( "demux/demux_null.c" ), ( "demux/demux_playlist.c" ), ( "demux/demux_raw.c" ), ( "demux/demux_rar.c" ), -- cgit v1.2.3 From cda0dc907094bcc75ac00f24f05b5a577961e47e Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 4 Mar 2016 23:58:44 +0100 Subject: demux_mkv: correctly export unknown packet durations Instead of just setting the duration to 0. --- demux/demux_mkv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index c932b45f39..5e6de8619d 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -152,7 +152,7 @@ typedef struct mkv_index { struct block_info { uint64_t duration, discardpadding; - bool simple, keyframe; + bool simple, keyframe, duration_known; int64_t timecode; mkv_track_t *track; bstr data; @@ -2461,7 +2461,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info) dp->pts = current_pts + i * track->default_duration; if (stream->codec->avi_dts) MPSWAP(double, dp->pts, dp->dts); - if (i == 0) + if (i == 0 && block_info->duration_known) dp->duration = block_duration / 1e9; if (stream->type == STREAM_AUDIO) { unsigned int srate = stream->codec->samplerate; @@ -2504,6 +2504,7 @@ static int read_block_group(demuxer_t *demuxer, int64_t end, if (block->duration == EBML_UINT_INVALID) goto error; block->duration *= mkv_d->tc_scale; + block->duration_known = true; break; case MATROSKA_ID_DISCARDPADDING: -- cgit v1.2.3 From 740b7013ba827ce5a9d48138af5bd2e8f5d54710 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 5 Mar 2016 00:13:30 +0100 Subject: sd_ass: always handle subtitles with unknown duration Deals with broken mkv subtitle tracks generated by tvheadend. The subs are srt, but without packet durations. We need this logic for CCs anyway. CCs in particular will be unaffected by this change because they are also marked with unknown duration. It could be that there are actual demuxers outputting CCs - in this case, we rely on the fact that they don't set a (meaningless) packet duration (or we'd have to work that around). --- sub/sd_ass.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sub/sd_ass.c b/sub/sd_ass.c index 4426c2ebab..59336ff0ec 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -238,6 +238,8 @@ static bool check_packet_seen(struct sd *sd, int64_t pos) return false; } +#define UNKNOWN_DURATION (INT_MAX / 1000) + static void decode(struct sd *sd, struct demux_packet *packet) { struct sd_ass_priv *ctx = sd->priv; @@ -246,13 +248,22 @@ static void decode(struct sd *sd, struct demux_packet *packet) if (!sd->opts->sub_clear_on_seek && packet->pos >= 0 && check_packet_seen(sd, packet->pos)) return; + if (packet->duration < 0) { + if (!ctx->duration_unknown) { + MP_WARN(sd, "Subtitle with unknown duration.\n"); + ctx->duration_unknown = true; + } + packet->duration = UNKNOWN_DURATION; + } char **r = lavc_conv_decode(ctx->converter, packet); for (int n = 0; r && r[n]; n++) ass_process_data(track, r[n], strlen(r[n])); if (ctx->duration_unknown) { for (int n = 0; n < track->n_events - 1; n++) { - track->events[n].Duration = track->events[n + 1].Start - - track->events[n].Start; + if (track->events[n].Duration == UNKNOWN_DURATION * 1000) { + track->events[n].Duration = track->events[n + 1].Start - + track->events[n].Start; + } } } } else { @@ -440,6 +451,7 @@ static void get_bitmaps(struct sd *sd, struct mp_osd_res dim, double pts, long long ts = find_timestamp(sd, pts); if (ctx->duration_unknown && pts != MP_NOPTS_VALUE) { mp_ass_flush_old_events(track, ts); + ctx->num_seen_packets = 0; } if (no_ass) fill_plaintext(sd, pts); -- cgit v1.2.3 From fb2f8abaaab604595474e932ff888d73f6f86fc7 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 5 Mar 2016 00:56:55 +0100 Subject: demux_null: fix segfault with --cache enabled stream->info can be NULL if it's the cache wrapper. To be fair, stream->info is considered private API anyway. So don't access it, but check the URL instead. --- demux/demux_null.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demux/demux_null.c b/demux/demux_null.c index c6a25b5af2..1d4f4df794 100644 --- a/demux/demux_null.c +++ b/demux/demux_null.c @@ -21,7 +21,7 @@ static int try_open_file(struct demuxer *demux, enum demux_check check) { - if (strcmp(demux->stream->info->name, "null") != 0 && + if (!bstr_startswith0(bstr0(demux->filename), "null://") && check != DEMUX_CHECK_REQUEST) return -1; return 0; -- cgit v1.2.3 From 93546f0c2f8e4df211eb907e1247aa6f2b97721d Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Sat, 5 Mar 2016 11:29:19 +0100 Subject: vo_opengl: refactor pass_read_video and texture binding This is a pretty major rewrite of the internal texture binding mechanic, which makes it more flexible. In general, the difference between the old and current approaches is that now, all texture description is held in a struct img_tex and only explicitly bound with pass_bind. (Once bound, a texture unit is assumed to be set in stone and no longer tied to the img_tex) This approach makes the code inside pass_read_video significantly more flexible and cuts down on the number of weird special cases and spaghetti logic. It also has some improvements, e.g. cutting down greatly on the number of unnecessary conversion passes inside pass_read_video (which was previously mostly done to cope with the fact that the alternative would have resulted in a combinatorial explosion of code complexity). Some other notable changes (and potential improvements): - texture expansion is now *always* handled in pass_read_video, and the colormatrix never does this anymore. (Which means the code could probably be removed from the colormatrix generation logic, modulo some other VOs) - struct fbo_tex now stores both its "physical" and "logical" (configured) size, which cuts down on the amount of width/height baggage on some function calls - vo_opengl can now technically support textures with different bit depths (e.g. 10 bit luma, 8 bit chroma) - but the APIs it queries inside img_format.c doesn't export this (nor does ffmpeg support it, really) so the status quo of using the same tex_mul for all planes is kept. - dumb_mode is now only needed because of the indirect_fbo being in the main rendering pipeline. If we reintroduce p->use_indirect and thread a transform through the entire program this could be skipped where unnecessary, allowing for the removal of dumb_mode. But I'm not sure how to do this in a clean way. (Which is part of why it got introduced to begin with) - It would be trivial to resurrect source-shader now (it would just be one extra 'if' inside pass_read_video). --- video/img_format.c | 1 + video/img_format.h | 1 + video/out/opengl/nnedi3.c | 4 +- video/out/opengl/superxbr.c | 2 +- video/out/opengl/utils.c | 30 +- video/out/opengl/utils.h | 20 +- video/out/opengl/video.c | 806 +++++++++++++++++++++------------------ video/out/opengl/video_shaders.c | 3 +- video/out/opengl/video_shaders.h | 2 +- 9 files changed, 490 insertions(+), 379 deletions(-) diff --git a/video/img_format.c b/video/img_format.c index 82136b5192..fe2ca14bf4 100644 --- a/video/img_format.c +++ b/video/img_format.c @@ -171,6 +171,7 @@ struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt) shift = d.shift; if (shift != d.shift) shift = -1; + desc.components[d.plane] += 1; } for (int p = 0; p < 4; p++) { diff --git a/video/img_format.h b/video/img_format.h index b18a6f5d3f..a58e445ea2 100644 --- a/video/img_format.h +++ b/video/img_format.h @@ -93,6 +93,7 @@ struct mp_imgfmt_desc { int8_t component_bits; // number of bits per component (0 if uneven) int8_t component_full_bits; // number of bits per component including // internal padding (0 if uneven) + int8_t components[MP_MAX_PLANES]; // number of components for each plane // chroma shifts per plane (provided for convenience with planar formats) int8_t xs[MP_MAX_PLANES]; int8_t ys[MP_MAX_PLANES]; diff --git a/video/out/opengl/nnedi3.c b/video/out/opengl/nnedi3.c index c07731611a..702a8dd55f 100644 --- a/video/out/opengl/nnedi3.c +++ b/video/out/opengl/nnedi3.c @@ -112,8 +112,8 @@ void pass_nnedi3(GL *gl, struct gl_shader_cache *sc, int planes, int tex_num, const int offset = nnedi3_weight_offsets[conf->window * 4 + conf->neurons]; const uint32_t *weights = (const int*)(nnedi3_weights + offset * 4); - GLSLF("// nnedi3 (tex %d, step %d, neurons %d, window %dx%d, mode %d)\n", - tex_num, step + 1, neurons, width, height, conf->upload); + GLSLF("// nnedi3 (step %d, neurons %d, window %dx%d, mode %d)\n", + step, neurons, width, height, conf->upload); // This is required since each row will be encoded into vec4s assert(width % 4 == 0); diff --git a/video/out/opengl/superxbr.c b/video/out/opengl/superxbr.c index 8039e6e01d..87319aab99 100644 --- a/video/out/opengl/superxbr.c +++ b/video/out/opengl/superxbr.c @@ -76,7 +76,7 @@ void pass_superxbr(struct gl_shader_cache *sc, int planes, int tex_num, struct gl_transform *transform) { assert(0 <= step && step < 2); - GLSLF("// superxbr (tex %d, step %d)\n", tex_num, step + 1); + GLSLF("// superxbr (step %d)\n", step); if (!conf) conf = &superxbr_opts_def; diff --git a/video/out/opengl/utils.c b/video/out/opengl/utils.c index 7329240593..02f1ea6584 100644 --- a/video/out/opengl/utils.c +++ b/video/out/opengl/utils.c @@ -355,13 +355,18 @@ bool fbotex_change(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h, int cw = w, ch = h; - if ((flags & FBOTEX_FUZZY_W) && cw < fbo->w) - cw = fbo->w; - if ((flags & FBOTEX_FUZZY_H) && ch < fbo->h) - ch = fbo->h; - - if (fbo->w == cw && fbo->h == ch && fbo->iformat == iformat) + if ((flags & FBOTEX_FUZZY_W) && cw < fbo->rw) + cw = fbo->rw; + if ((flags & FBOTEX_FUZZY_H) && ch < fbo->rh) + ch = fbo->rh; + + if (fbo->rw == cw && fbo->rh == ch && fbo->iformat == iformat) { + fbo->lw = w; + fbo->lh = h; return true; + } + + int lw = w, lh = h; if (flags & FBOTEX_FUZZY_W) w = MP_ALIGN_UP(w, 256); @@ -384,12 +389,15 @@ bool fbotex_change(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h, *fbo = (struct fbotex) { .gl = gl, - .w = w, - .h = h, + .rw = w, + .rh = h, + .lw = lw, + .lh = lh, .iformat = iformat, }; - mp_verbose(log, "Create FBO: %dx%d\n", fbo->w, fbo->h); + mp_verbose(log, "Create FBO: %dx%d -> %dx%d\n", fbo->lw, fbo->lh, + fbo->rw, fbo->rh); if (!(gl->mpgl_caps & MPGL_CAP_FB)) return false; @@ -397,7 +405,7 @@ bool fbotex_change(struct fbotex *fbo, GL *gl, struct mp_log *log, int w, int h, gl->GenFramebuffers(1, &fbo->fbo); gl->GenTextures(1, &fbo->texture); gl->BindTexture(GL_TEXTURE_2D, fbo->texture); - gl->TexImage2D(GL_TEXTURE_2D, 0, format.internal_format, fbo->w, fbo->h, 0, + gl->TexImage2D(GL_TEXTURE_2D, 0, format.internal_format, fbo->rw, fbo->rh, 0, format.format, format.type, NULL); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -977,7 +985,7 @@ void gl_sc_gen_shader_and_reset(struct gl_shader_cache *sc) } ADD(frag, "void main() {\n"); // we require _all_ frag shaders to write to a "vec4 color" - ADD(frag, "vec4 color;\n"); + ADD(frag, "vec4 color = vec4(0.0, 0.0, 0.0, 1.0);\n"); ADD(frag, "%s", sc->text); if (gl->glsl_version >= 130) { ADD(frag, "out_color = color;\n"); diff --git a/video/out/opengl/utils.h b/video/out/opengl/utils.h index 3ec6077bf5..a4