From b39a7fddb556ec9b56eb1a66b5f333b884d0b4d8 Mon Sep 17 00:00:00 2001 From: Ricardo Constantino Date: Mon, 21 Nov 2016 18:20:53 +0000 Subject: [PATCH 01/83] osc: fix possible race condition in right timecode --- player/lua/osc.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/player/lua/osc.lua b/player/lua/osc.lua index 643f32faafa7a..53860d355d651 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -1755,8 +1755,7 @@ function osc_init() -- tc_right (total/remaining time) ne = new_element("tc_right", "button") - ne.visible = (not (mp.get_property("duration") == nil)) - and (mp.get_property_number("duration") > 0) + ne.visible = (mp.get_property_number("duration", 0) > 0) ne.content = function () if (state.rightTC_trem) then if state.tc_ms then From fcba41e2e4752d6391c76ef4e2c9f0c8c5734159 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 21 Nov 2016 18:31:32 +0100 Subject: [PATCH 02/83] audio: fix --audio-stream-silence with ao_alsa ao_alsa.c calls this before the common code sets ao->sstride. Other than this, I'm still not sure whether this works. Seems like no, or depends. --- audio/out/push.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/audio/out/push.c b/audio/out/push.c index 68606386f2775..555a7867dab68 100644 --- a/audio/out/push.c +++ b/audio/out/push.c @@ -453,8 +453,9 @@ int ao_play_silence(struct ao *ao, int samples) assert(ao->api == &ao_api_push); if (samples <= 0 || !af_fmt_is_pcm(ao->format) || !ao->driver->play) return 0; - char *p = talloc_size(NULL, samples * ao->sstride); - af_fill_silence(p, samples * ao->sstride, ao->format); + int bytes = af_fmt_to_bytes(ao->format) * samples * ao->channels.num; + char *p = talloc_size(NULL, bytes); + af_fill_silence(p, bytes, ao->format); void *tmp[MP_NUM_CHANNELS]; for (int n = 0; n < MP_NUM_CHANNELS; n++) tmp[n] = p; From de37c5b1cbdc8a8c1fd6a4e3494396fb9608fd8b Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 21 Nov 2016 19:33:31 +0100 Subject: [PATCH 03/83] audio: fix --audio-stream-silence with ao_wasapi Seems like wasapi will restart the HDMI stream if resume is called during playback. --- audio/out/pull.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/audio/out/pull.c b/audio/out/pull.c index 44f6ab3355ebc..a656de6fdd4d8 100644 --- a/audio/out/pull.c +++ b/audio/out/pull.c @@ -101,7 +101,8 @@ static int play(struct ao *ao, void **data, int samples, int flags) int state = atomic_load(&p->state); if (!IS_PLAYING(state)) { set_state(ao, AO_STATE_PLAY); - ao->driver->resume(ao); + if (!ao->stream_silence) + ao->driver->resume(ao); } return write_samples; @@ -203,7 +204,8 @@ static void pause(struct ao *ao) static void resume(struct ao *ao) { set_state(ao, AO_STATE_PLAY); - ao->driver->resume(ao); + if (!ao->stream_silence) + ao->driver->resume(ao); } static bool get_eof(struct ao *ao) From f843ae9983b62f81d0aa79a333e594855fe4ccf3 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 21 Nov 2016 20:17:41 +0100 Subject: [PATCH 04/83] Fix some future release version numbers Since the recent release was named 0.22.0 instead of 0.21.1, bump all mentions of 0.22.0 to 0.23.0. These were planned removals of deprecated versions, which obviously didn't happen in 0.22.0. --- DOCS/client-api-changes.rst | 2 +- DOCS/interface-changes.rst | 10 +++++----- DOCS/man/vo.rst | 4 ++-- libmpv/client.h | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst index 94b39bd58d083..1dacbb2c32274 100644 --- a/DOCS/client-api-changes.rst +++ b/DOCS/client-api-changes.rst @@ -38,7 +38,7 @@ API changes - do not override the SIGPIPE signal handler anymore. This was done as workaround for the FFmpeg TLS code, which has been fixed long ago. - deprecate mpv_suspend() and mpv_resume(). They will be stubbed out - in mpv 0.22.0. + in mpv 0.23.0. - make mpv_set_property() work to some degree before mpv_initialize(). It can now be used instead of mpv_set_option(). - semi-deprecate mpv_set_option()/mpv_set_option_string(). You should diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 7868f0a8e267d..ec4c6b8da052b 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -67,7 +67,7 @@ Interface changes - "fps" -> "container-fps" - "idle" -> "idle-active" - "cache" -> "cache-percent" - the old names are deprecated and will change behavior in mpv 0.22.0. + the old names are deprecated and will change behavior in mpv 0.23.0. - remove deprecated "hwdec-active" and "hwdec-detected" properties - deprecate the ao and vo auto-profiles (they never made any sense) - deprecate "--vo=direct3d_shaders" - use "--vo=direct3d" instead. @@ -81,17 +81,17 @@ Interface changes now always sets the device, not the span or speed to be played. No separating extra "/" is needed. The hidden --cdda-device options is also deleted (it was redundant with the documented --cdrom-device). - - deprecate --vo=rpi. It will be removed in mpv 0.22.0. Its functionality + - deprecate --vo=rpi. It will be removed in mpv 0.23.0. Its functionality was folded into --vo=opengl, which now uses RPI hardware decoding by treating it as a hardware overlay (without applying GL filtering). Also - to be changed in 0.22.0: the --fs flag will be reset to "no" by default + to be changed in 0.23.0: the --fs flag will be reset to "no" by default (like on the other platforms). - deprecate --mute=auto (informally has been since 0.18.1) - deprecate "resume" and "suspend" IPC commands. They will be completely - removed in 0.22.0. + removed in 0.23.0. - deprecate mp.suspend(), mp.resume(), mp.resume_all() Lua scripting commands, as well as setting mp.use_suspend. They will be completely - removed in 0.22.0. + removed in 0.23.0. - the "seek" command's absolute seek mode will now interpret negative seek times as relative from the end of the file (and clamps seeks that still go before 0) diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index 593dc9a1bae4a..f695ba0f6f1b5 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -483,9 +483,9 @@ Available video output drivers are: This is deprecated. Use ``--vo=opengl`` instead, which is the default and provides the same functionality. The ``rpi`` VO will be removed in - mpv 0.22.0. Its functionality was folded into --vo=opengl, which now uses + mpv 0.23.0. Its functionality was folded into --vo=opengl, which now uses RPI hardware decoding by treating it as a hardware overlay (without applying - GL filtering). Also to be changed in 0.22.0: the --fs flag will be reset to + GL filtering). Also to be changed in 0.23.0: the --fs flag will be reset to "no" by default (like on the other platforms). The following deprecated global options are supported by this video output: diff --git a/libmpv/client.h b/libmpv/client.h index 788b4f2e5701d..28f86051a6996 100644 --- a/libmpv/client.h +++ b/libmpv/client.h @@ -815,7 +815,7 @@ void mpv_free_node_contents(mpv_node *node); * - deprecated options shadowed by properties: * - chapter (option deprecated in 0.21.0) * - playlist-pos (option deprecated in 0.21.0) - * The deprecated properties will be removed in mpv 0.22.0. + * The deprecated properties will be removed in mpv 0.23.0. * * @param name Option name. This is the same as on the mpv command line, but * without the leading "--". @@ -929,7 +929,7 @@ int mpv_command_node_async(mpv_handle *ctx, uint64_t reply_userdata, * In some cases, properties and options still conflict. In these cases, * mpv_set_property() accesses the options before mpv_initialize(), and * the properties after mpv_initialize(). These conflicts will be removed - * in mpv 0.22.0. See mpv_set_option() for further remarks. + * in mpv 0.23.0. See mpv_set_option() for further remarks. * * @param name The property name. See input.rst for a list of properties. * @param format see enum mpv_format. From 745862131f2e03bfb7b8fae4499d84522f0cc1a2 Mon Sep 17 00:00:00 2001 From: James Ross-Gowan Date: Wed, 23 Nov 2016 00:55:20 +1100 Subject: [PATCH 05/83] d3d11va: unconditionally load D3D DLLs At least with Nvidia drivers, some thread tries to access D3D11 objects after ANGLE unloads d3d11.dll. Fix this by holding a reference to d3d11.dll ourselves. Might fix the crash in #3348. (I wish I knew why though.) --- video/decode/d3d11va.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/video/decode/d3d11va.c b/video/decode/d3d11va.c index 8ce07880e7996..e31582d37c5a7 100644 --- a/video/decode/d3d11va.c +++ b/video/decode/d3d11va.c @@ -429,7 +429,6 @@ static bool create_device(struct lavc_ctx *s, BOOL thread_safe) HRESULT hr; struct priv *p = s->hwdec_priv; - d3d_load_dlls(); if (!d3d11_dll) { MP_ERR(p, "Failed to load D3D11 library\n"); return false; @@ -492,6 +491,11 @@ static int d3d11va_init(struct lavc_ctx *s) if (!p) return -1; + // Unconditionally load Direct3D DLLs, even when using a VO-supplied D3D11 + // device. This prevents a crash that occurs at least with NVIDIA drivers, + // where D3D objects are accessed after ANGLE unloads d3d11.dll. + d3d_load_dlls(); + s->hwdec_priv = p; p->log = mp_log_new(s, s->log, "d3d11va"); if (s->hwdec->type == HWDEC_D3D11VA_COPY) { From f30c5d09f4478ca40ceabc90d57fea68965778df Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 22 Nov 2016 14:47:50 +0100 Subject: [PATCH 06/83] client API: turn mpv_suspend() and mpv_resume() into stubs As threatened by the API changes document. This commit also removes or stubs equivalent calls in IPC and Lua scripting. The stubs are left to maintain ABI compatibility. The semantics of the API functions have been close enough to doing nothing that this probably won't even break existing API users. Probably. --- DOCS/client-api-changes.rst | 2 ++ DOCS/man/ipc.rst | 14 ---------- DOCS/man/lua.rst | 28 ++++++-------------- input/ipc.c | 6 ----- libmpv/client.h | 5 +++- player/client.c | 52 +------------------------------------ player/client.h | 2 -- player/core.h | 1 - player/lua.c | 12 +-------- player/lua/defaults.lua | 12 ++++----- player/playloop.c | 3 --- 11 files changed, 22 insertions(+), 115 deletions(-) diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst index 1dacbb2c32274..5e6e1d3180d90 100644 --- a/DOCS/client-api-changes.rst +++ b/DOCS/client-api-changes.rst @@ -32,6 +32,8 @@ API changes :: + --- mpv 0.23.0 --- + 1.24 - the deprecated mpv_suspend() and mpv_resume() APIs now do nothing. --- mpv 0.22.0 --- 1.23 - deprecate setting "no-" options via mpv_set_option*(). For example, instead of "no-video=" you should set "video=no". diff --git a/DOCS/man/ipc.rst b/DOCS/man/ipc.rst index 732056ee01fa3..03be027a200fb 100644 --- a/DOCS/man/ipc.rst +++ b/DOCS/man/ipc.rst @@ -241,20 +241,6 @@ extra commands can also be used as part of the protocol: By default, most events are enabled, and there is not much use for this command. -``suspend`` - Deprecated, will be removed completely in 0.21.0. - - Suspend the mpv main loop. There is a long-winded explanation of this in - the C API function ``mpv_suspend()``. In short, this prevents the player - from displaying the next video frame, so that you don't get blocked when - trying to access the player. - -``resume`` - Deprecated, will be removed completely in 0.21.0. - - Undo one ``suspend`` call. ``suspend`` increments an internal counter, and - ``resume`` decrements it. When 0 is reached, the player is actually resumed. - ``get_version`` Returns the client API version the C API of the remote mpv instance provides. diff --git a/DOCS/man/lua.rst b/DOCS/man/lua.rst index f1d9945055b16..7d91090ca8e2c 100644 --- a/DOCS/man/lua.rst +++ b/DOCS/man/lua.rst @@ -43,9 +43,8 @@ timers added with ``mp.add_timeout`` or similar. When the player quits, all scripts will be asked to terminate. This happens via a ``shutdown`` event, which by default will make the event loop return. If your -script got into an endless loop, mpv will probably behave fine during playback -(unless the player is suspended, see ``mp.suspend``), but it won't terminate -when quitting, because it's waiting on your script. +script got into an endless loop, mpv will probably behave fine during playback, +but it won't terminate when quitting, because it's waiting on your script. Internally, the C code will call the Lua function ``mp_event_loop`` after loading a Lua script. This function is normally defined by the default prelude @@ -412,27 +411,16 @@ These also live in the ``mp`` module, but are documented separately as they are useful only in special situations. ``mp.suspend()`` - This function has been deprecated in mpv 0.21.0 (no replacement). - - Suspend the mpv main loop. There is a long-winded explanation of this in - the C API function ``mpv_suspend()``. In short, this prevents the player - from displaying the next video frame, so that you don't get blocked when - trying to access the player. - - Before mpv 0.17.0, this was automatically called by the event handler. + This function has been deprecated in mpv 0.21.0 and does nothing starting + with mpv 0.23.0 (no replacement). ``mp.resume()`` - This function has been deprecated in mpv 0.21.0 (no replacement). - - Undo one ``mp.suspend()`` call. ``mp.suspend()`` increments an internal - counter, and ``mp.resume()`` decrements it. When 0 is reached, the player - is actually resumed. + This function has been deprecated in mpv 0.21.0 and does nothing starting + with mpv 0.23.0 (no replacement). ``mp.resume_all()`` - This function has been deprecated in mpv 0.21.0 (no replacement). - - This resets the internal suspend counter and resumes the player. (It's - like calling ``mp.resume()`` until the player is actually resumed.) + This function has been deprecated in mpv 0.21.0 and does nothing starting + with mpv 0.23.0 (no replacement). ``mp.get_wakeup_pipe()`` Calls ``mpv_get_wakeup_pipe()`` and returns the read end of the wakeup diff --git a/input/ipc.c b/input/ipc.c index c7563e30d8b9d..f15f24d2296aa 100644 --- a/input/ipc.c +++ b/input/ipc.c @@ -384,12 +384,6 @@ static char *json_execute_command(struct mpv_handle *client, void *ta_parent, rc = mpv_request_log_messages(client, cmd_node->u.list->values[1].u.string); - } else if (!strcmp("suspend", cmd)) { - mpv_suspend(client); - rc = MPV_ERROR_SUCCESS; - } else if (!strcmp("resume", cmd)) { - mpv_resume(client); - rc = MPV_ERROR_SUCCESS; } else if (!strcmp("enable_event", cmd) || !strcmp("disable_event", cmd)) { diff --git a/libmpv/client.h b/libmpv/client.h index 28f86051a6996..51f5c24d593e7 100644 --- a/libmpv/client.h +++ b/libmpv/client.h @@ -211,7 +211,7 @@ extern "C" { * relational operators (<, >, <=, >=). */ #define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL) -#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 23) +#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 24) /** * Return the MPV_CLIENT_API_VERSION the mpv source has been compiled with. @@ -506,6 +506,9 @@ mpv_handle *mpv_create_client(mpv_handle *ctx, const char *name); int mpv_load_config_file(mpv_handle *ctx, const char *filename); /** + * This does nothing since mpv 0.23.0 (API version 1.24). Below is the + * description of the old behavior. + * * Stop the playback thread. This means the core will stop doing anything, and * only run and answer to client API requests. This is sometimes useful; for * example, no new frame will be queued to the video output, so doing requests diff --git a/player/client.c b/player/client.c index 774a4e05c0a2f..85e3c4021c83f 100644 --- a/player/client.c +++ b/player/client.c @@ -329,59 +329,11 @@ void mpv_set_wakeup_callback(mpv_handle *ctx, void (*cb)(void *d), void *d) void mpv_suspend(mpv_handle *ctx) { - bool do_suspend = false; - - MP_WARN(ctx, "warning: mpv_suspend() is deprecated.\n"); - - pthread_mutex_lock(&ctx->lock); - if (ctx->suspend_count == INT_MAX) { - MP_ERR(ctx, "suspend counter overflow"); - } else { - do_suspend = ctx->suspend_count == 0; - ctx->suspend_count++; - } - pthread_mutex_unlock(&ctx->lock); - - if (do_suspend) { - mp_dispatch_lock(ctx->mpctx->dispatch); - ctx->mpctx->suspend_count++; - mp_dispatch_unlock(ctx->mpctx->dispatch); - } + MP_ERR(ctx, "mpv_suspend() is deprecated and does nothing.\n"); } void mpv_resume(mpv_handle *ctx) { - bool do_resume = false; - - pthread_mutex_lock(&ctx->lock); - if (ctx->suspend_count == 0) { - MP_ERR(ctx, "suspend counter underflow"); - } else { - do_resume = ctx->suspend_count == 1; - ctx->suspend_count--; - } - pthread_mutex_unlock(&ctx->lock); - - if (do_resume) { - mp_dispatch_lock(ctx->mpctx->dispatch); - ctx->mpctx->suspend_count--; - mp_dispatch_unlock(ctx->mpctx->dispatch); - mp_dispatch_interrupt(ctx->mpctx->dispatch); - } -} - -void mp_resume_all(mpv_handle *ctx) -{ - pthread_mutex_lock(&ctx->lock); - bool do_resume = ctx->suspend_count > 0; - ctx->suspend_count = 0; - pthread_mutex_unlock(&ctx->lock); - - if (do_resume) { - mp_dispatch_lock(ctx->mpctx->dispatch); - ctx->mpctx->suspend_count--; - mp_dispatch_unlock(ctx->mpctx->dispatch); - } } static void lock_core(mpv_handle *ctx) @@ -396,8 +348,6 @@ static void unlock_core(mpv_handle *ctx) void mpv_wait_async_requests(mpv_handle *ctx) { - mp_resume_all(ctx); - pthread_mutex_lock(&ctx->lock); while (ctx->reserved_events || ctx->properties_updating) wait_wakeup(ctx, INT64_MAX); diff --git a/player/client.h b/player/client.h index e39d0e676ac42..67b287b67fa5b 100644 --- a/player/client.h +++ b/player/client.h @@ -35,8 +35,6 @@ struct mp_log *mp_client_get_log(struct mpv_handle *ctx); struct MPContext *mp_client_get_core(struct mpv_handle *ctx); struct MPContext *mp_client_api_get_core(struct mp_client_api *api); -void mp_resume_all(struct mpv_handle *ctx); - // m_option.c void *node_get_alloc(struct mpv_node *node); diff --git a/player/core.h b/player/core.h index b33d367cec81f..9a71ce33de08c 100644 --- a/player/core.h +++ b/player/core.h @@ -226,7 +226,6 @@ enum playback_status { typedef struct MPContext { bool initialized; bool autodetach; - int suspend_count; struct mpv_global *global; struct MPOpts *opts; struct mp_log *log; diff --git a/player/lua.c b/player/lua.c index 442a2ba073043..e76dc46fca118 100644 --- a/player/lua.c +++ b/player/lua.c @@ -393,7 +393,6 @@ static int load_lua(struct mpv_handle *client, const char *fname) r = 0; error_out: - mp_resume_all(client); if (ctx->state) lua_close(ctx->state); talloc_free(ctx); @@ -451,22 +450,17 @@ static int script_find_config_file(lua_State *L) static int script_suspend(lua_State *L) { struct script_ctx *ctx = get_ctx(L); - MP_WARN(ctx, "mp.suspend() (possibly triggered by mp.use_suspend) is " - "deprecated.\n"); - mpv_suspend(ctx->client); + MP_ERR(ctx, "mp.suspend() is deprecated and does nothing.\n"); return 0; } static int script_resume(lua_State *L) { - struct script_ctx *ctx = get_ctx(L); - mpv_resume(ctx->client); return 0; } static int script_resume_all(lua_State *L) { - mp_resume_all(get_ctx(L)->client); return 0; } @@ -1134,8 +1128,6 @@ static int script_subprocess(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); void *tmp = mp_lua_PITA(L); - mp_resume_all(ctx->client); - lua_getfield(L, 1, "args"); // args int num_args = mp_lua_len(L, -1); char *args[256]; @@ -1193,8 +1185,6 @@ static int script_subprocess_detached(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); void *tmp = mp_lua_PITA(L); - mp_resume_all(ctx->client); - lua_getfield(L, 1, "args"); // args int num_args = mp_lua_len(L, -1); char *args[256]; diff --git a/player/lua/defaults.lua b/player/lua/defaults.lua index c65fda7c9bcb3..08616c5638704 100644 --- a/player/lua/defaults.lua +++ b/player/lua/defaults.lua @@ -452,10 +452,15 @@ end mp.use_suspend = false +local suspend_warned = false + function mp.dispatch_events(allow_wait) local more_events = true if mp.use_suspend then - mp.suspend() + if not suspend_warned then + mp.msg.error("mp.use_suspend is now ignored.") + suspend_warned = true + end end while mp.keep_running do local wait = 0 @@ -475,11 +480,6 @@ function mp.dispatch_events(allow_wait) end end local e = mp.wait_event(wait) - -- Empty the event queue while suspended; otherwise, each - -- event will keep us waiting until the core suspends again. - if mp.use_suspend then - mp.suspend() - end more_events = false if e.event ~= "none" then call_event_handlers(e) diff --git a/player/playloop.c b/player/playloop.c index f72994e8a98c4..9db9396f95015 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -62,9 +62,6 @@ void mp_wait_events(struct MPContext *mpctx) mp_dispatch_queue_process(mpctx->dispatch, mpctx->sleeptime); - while (mpctx->suspend_count) - mp_dispatch_queue_process(mpctx->dispatch, 100); - mpctx->in_dispatch = false; mpctx->sleeptime = INFINITY; From 07b6969ba428078dbd22581bad495d7b64b758e8 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 22 Nov 2016 14:57:34 +0100 Subject: [PATCH 07/83] vf_vdpaurb: remove this filter Was deprecated, superseded by --hwdec=vdpau-copy. --- DOCS/interface-changes.rst | 2 + DOCS/man/vf.rst | 9 --- video/filter/vf.c | 2 - video/filter/vf_vdpaurb.c | 110 ------------------------------------- wscript_build.py | 1 - 5 files changed, 2 insertions(+), 122 deletions(-) delete mode 100644 video/filter/vf_vdpaurb.c diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index ec4c6b8da052b..5021bded6621d 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -19,6 +19,8 @@ Interface changes :: + --- mpv 0.23.0 --- + - remove deprecated vf_vdpaurb (use "--hwdec=vdpau-copy" instead) --- mpv 0.22.0 --- - the "audio-device-list" property now sets empty device description to the device name as a fallback diff --git a/DOCS/man/vf.rst b/DOCS/man/vf.rst index fd155bb91d198..22423513a00d8 100644 --- a/DOCS/man/vf.rst +++ b/DOCS/man/vf.rst @@ -806,15 +806,6 @@ Available filters are: 1-9 Apply high quality VDPAU scaling (needs capable hardware). -``vdpaurb`` - This filter is deprecated. Use ``--hwdec=vdpau-copy`` instead. - - VDPAU video read back. Works with ``--vo=vdpau`` and ``--vo=opengl`` only. - This filter will read back frames decoded by VDPAU so that other filters, - which are not normally compatible with VDPAU, can be used like normal. - This filter must be specified before ``vdpaupp`` in the filter chain if - ``vdpaupp`` is used. - ``d3d11vpp`` Direct3D 11 video post processing. Currently requires D3D11 hardware decoding for use. diff --git a/video/filter/vf.c b/video/filter/vf.c index 93b886e69c6a6..41fbe9b208777 100644 --- a/video/filter/vf.c +++ b/video/filter/vf.c @@ -59,7 +59,6 @@ extern const vf_info_t vf_info_vaapi; extern const vf_info_t vf_info_vapoursynth; extern const vf_info_t vf_info_vapoursynth_lazy; extern const vf_info_t vf_info_vdpaupp; -extern const vf_info_t vf_info_vdpaurb; extern const vf_info_t vf_info_buffer; extern const vf_info_t vf_info_d3d11vpp; @@ -98,7 +97,6 @@ static const vf_info_t *const filter_list[] = { #endif #if HAVE_VDPAU &vf_info_vdpaupp, - &vf_info_vdpaurb, #endif #if HAVE_D3D_HWACCEL &vf_info_d3d11vpp, diff --git a/video/filter/vf_vdpaurb.c b/video/filter/vf_vdpaurb.c deleted file mode 100644 index 59067b54bf409..0000000000000 --- a/video/filter/vf_vdpaurb.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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 "video/vdpau.h" -#include "video/vdpau_mixer.h" -#include "vf.h" - -// This filter will read back decoded frames that have been decoded by vdpau -// so they can be post-processed by regular filters. As vdpau is still doing -// the decoding, a vdpau compatible vo must always be used. -// -// NB: This filter assumes the video surface will have a 420 chroma type and -// can always be read back in NV12 format. This is a safe assumption at the -// time of writing, but may not always remain true. - -struct vf_priv_s { - struct mp_vdpau_ctx *ctx; -}; - -static int filter_ext(struct vf_instance *vf, struct mp_image *mpi) -{ - struct vf_priv_s *p = vf->priv; - - if (!mpi) { - return 0; - } - - // Pass-through anything that's not been decoded by VDPAU - if (mpi->imgfmt != IMGFMT_VDPAU) { - vf_add_output_frame(vf, mpi); - return 0; - } - - if (mp_vdpau_mixed_frame_get(mpi)) { - MP_ERR(vf, "Can't apply vdpaurb filter after vdpaupp filter.\n"); - mp_image_unrefp(&mpi); - return -1; - } - - struct mp_hwdec_ctx *hwctx = &p->ctx->hwctx; - - struct mp_image *out = hwctx->download_image(hwctx, mpi, vf->out_pool); - if (!out || out->imgfmt != IMGFMT_NV12) { - mp_image_unrefp(&mpi); - mp_image_unrefp(&out); - return -1; - } - - vf_add_output_frame(vf, out); - mp_image_unrefp(&mpi); - return 0; -} - -static int reconfig(struct vf_instance *vf, struct mp_image_params *in, - struct mp_image_params *out) -{ - *out = *in; - if (in->imgfmt == IMGFMT_VDPAU) { - out->imgfmt = IMGFMT_NV12; - out->hw_subfmt = 0; - } - return 0; -} - -static int query_format(struct vf_instance *vf, unsigned int fmt) -{ - return vf_next_query_format(vf, fmt == IMGFMT_VDPAU ? IMGFMT_NV12 : fmt); -} - -static int vf_open(vf_instance_t *vf) -{ - struct vf_priv_s *p = vf->priv; - - MP_WARN(vf, "This filter is deprecated and will be removed.\n"); - MP_WARN(vf, "Use --hwdec=vdpau-copy instead.\n"); - - vf->filter_ext = filter_ext; - vf->filter = NULL; - vf->reconfig = reconfig; - vf->query_format = query_format; - - p->ctx = hwdec_devices_load(vf->hwdec_devs, HWDEC_VDPAU); - if (!p->ctx) - return 0; - - return 1; -} - -const vf_info_t vf_info_vdpaurb = { - .description = "vdpau readback", - .name = "vdpaurb", - .open = vf_open, - .priv_size = sizeof(struct vf_priv_s), -}; diff --git a/wscript_build.py b/wscript_build.py index ac7e0b12dbf93..924b45ecadd2c 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -324,7 +324,6 @@ def build(ctx): ( "video/filter/vf_vapoursynth.c", "vapoursynth-core" ), ( "video/filter/vf_vavpp.c", "vaapi"), ( "video/filter/vf_vdpaupp.c", "vdpau" ), - ( "video/filter/vf_vdpaurb.c", "vdpau" ), ( "video/filter/vf_yadif.c" ), ( "video/out/aspect.c" ), ( "video/out/bitmap_packer.c" ), From c731513efaf27f18654089884c825d3fb1054873 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 22 Nov 2016 14:58:31 +0100 Subject: [PATCH 08/83] wscript: fix typo --- wscript_build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript_build.py b/wscript_build.py index 924b45ecadd2c..bce1ceb3fdc69 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -322,7 +322,7 @@ def build(ctx): ( "video/filter/vf_stereo3d.c" ), ( "video/filter/vf_sub.c" ), ( "video/filter/vf_vapoursynth.c", "vapoursynth-core" ), - ( "video/filter/vf_vavpp.c", "vaapi"), + ( "video/filter/vf_vavpp.c", "vaapi" ), ( "video/filter/vf_vdpaupp.c", "vdpau" ), ( "video/filter/vf_yadif.c" ), ( "video/out/aspect.c" ), From 78f76bdddd1df33fb76d9779d156bab66b5a81c1 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 22 Nov 2016 15:28:47 +0100 Subject: [PATCH 09/83] tv: fix option type It appears this makes it actually compatible with the property. It was an ancient MPlayer artifact all along. --- stream/tv.c | 4 ++-- stream/tv.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stream/tv.c b/stream/tv.c index b2bf150e1fcb7..0b34b566d8839 100644 --- a/stream/tv.c +++ b/stream/tv.c @@ -74,7 +74,7 @@ const struct m_sub_options tv_params_conf = { OPT_INT("audiorate", audiorate, 0), OPT_STRING("driver", driver, 0), OPT_STRING("device", device, 0), - OPT_STRING("freq", freq, 0), + OPT_FLOAT("freq", freq, 0), OPT_STRING("channel", channel, 0), OPT_STRING("chanlist", chanlist, 0), OPT_STRING("norm", norm, 0), @@ -602,7 +602,7 @@ int open_tv(tvi_handle_t *tvh) /* we need to set frequency */ if (tvh->tv_param->freq) { - unsigned long freq = atof(tvh->tv_param->freq)*16; + unsigned long freq = tvh->tv_param->freq * 16; /* set freq in MHz */ funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_FREQ, &freq); diff --git a/stream/tv.h b/stream/tv.h index d22b5b7076db4..434a52d4fdb41 100644 --- a/stream/tv.h +++ b/stream/tv.h @@ -27,7 +27,7 @@ struct mp_log; typedef struct tv_params { - char *freq; + float freq; char *channel; char *chanlist; char *norm; From 7201fd7d08dd7f240e6f7c2584809bb4a723ab21 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 22 Nov 2016 15:38:01 +0100 Subject: [PATCH 10/83] command: redefine some deprecated properties As threatened by the API changes document. We can actually keep the deprecated --playlist-pos and --cache options, since they are aliases and not used by the corresponding properties. They are inconsistent, but do no harm. Keep them for now for the sake of the command line user. mpv_identify.sh partially stopped working, because it was never updated. The shell magic can't deal with property names that contain "/", so we can't replace "samplerate" with "audio-params/samplerate" - just remove these properties. (How about you use ffprobe?) --- DOCS/interface-changes.rst | 9 +++++++++ DOCS/man/input.rst | 7 +++---- TOOLS/mpv_identify.sh | 4 +--- player/command.c | 37 ------------------------------------- 4 files changed, 13 insertions(+), 44 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 5021bded6621d..e082b36a9d7ff 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -21,6 +21,15 @@ Interface changes --- mpv 0.23.0 --- - remove deprecated vf_vdpaurb (use "--hwdec=vdpau-copy" instead) + - the following properties now have new semantics: + - "demuxer" (use "current-demuxer") + - "fps" (use "container-fps") + - "idle" (use "idle-active") + - "cache" (use "cache-percent") + - "audio-samplerate" (use "audio-params/samplerate") + - "audio-channels" (use "audio-params/channel-count") + - "audio-format" (use "audio-codec-name") + (the properties equivalent to the old semantics are in parentheses) --- mpv 0.22.0 --- - the "audio-device-list" property now sets empty device description to the device name as a fallback diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 508e7dd252cd6..70a05dcaefe17 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -2147,10 +2147,9 @@ caveats with some properties (due to historical reasons): Strictly speaking, option access via API (e.g. ``mpv_set_option_string()``) has the same problem, and it's only a difference between CLI/API. -``demuxer``, ``idle``, ``length``, ``audio-samplerate``, ``audio-channels``, ``audio-format``, ``fps``, ``cache``, ``playlist-pos``, ``chapter`` - These behave completely different as property, but are deprecated (newer - aliases which don't conflict have been added). After the deprecation period - they will be changed to the proper option behavior. +``playlist-pos``, ``chapter`` + These properties behave different from the deprecated options with the same + names. Property Expansion ------------------ diff --git a/TOOLS/mpv_identify.sh b/TOOLS/mpv_identify.sh index 2bda6e57537b7..42cd41fe435ca 100755 --- a/TOOLS/mpv_identify.sh +++ b/TOOLS/mpv_identify.sh @@ -71,9 +71,7 @@ EOF audio audio-bitrate audio-codec - audio-format - channels - samplerate + audio-codec-name video angle diff --git a/player/command.c b/player/command.c index 7c1a6f3a6e99d..1f112fdf65d48 100644 --- a/player/command.c +++ b/player/command.c @@ -277,26 +277,6 @@ int mp_on_set_option(void *ctx, struct m_config_option *co, void *data, int flag { struct MPContext *mpctx = ctx; - // These options are too inconsistent as they could be pulled through the - // property layer. Ideally we'd remove these inconsistencies in the future, - // though the actual problem is compatibility to user-expected behavior. - // What matters is whether _write_ access is different - property read - // access is not used here. - // We're also fine with cases where the property restricts the writable - // value range if playback is active, but not otherwise. - // OK, restrict during playback: vid, aid, sid, deinterlace, video-aspect, - // vf*, af*, chapter - // OK, is handled separately: playlist - // OK, does not conflict on low level: audio-file, sub-file, external-file - // OK, different value ranges, but happens to work for now: volume, edition - // Incompatible: tv-freq - // All the other properties are deprecated in their current form. - static const char *const no_property[] = { - "demuxer", "idle", "length", "audio-samplerate", "audio-channels", - "audio-format", "fps", "cache", "playlist-pos", "chapter", "tv-freq", - NULL - }; - // Normalize "vf*" to "vf" const char *name = co->name; bstr bname = bstr0(name); @@ -306,11 +286,6 @@ int mp_on_set_option(void *ctx, struct m_config_option *co, void *data, int flag name = tmp; } - for (int n = 0; no_property[n]; n++) { - if (strcmp(co->name, no_property[n]) == 0) - goto direct_option; - } - struct m_option type = {0}; int r = mp_property_do_silent(name, M_PROPERTY_GET_TYPE, &type, mpctx); @@ -3824,13 +3799,10 @@ static const struct m_property mp_properties_base[] = { {"stream-path", mp_property_stream_path}, {"stream-capture", mp_property_stream_capture}, {"current-demuxer", mp_property_demuxer}, - // conflicts with option - M_PROPERTY_DEPRECATED_ALIAS("demuxer", "current-demuxer"), {"file-format", mp_property_file_format}, {"stream-pos", mp_property_stream_pos}, {"stream-end", mp_property_stream_end}, {"duration", mp_property_duration}, - M_PROPERTY_DEPRECATED_ALIAS("length", "duration"), // conflicts with option {"avsync", mp_property_avsync}, {"total-avsync-change", mp_property_total_avsync_change}, {"drop-frame-count", mp_property_drop_frame_cnt}, @@ -3863,7 +3835,6 @@ static const struct m_property mp_properties_base[] = { {"seeking", mp_property_seeking}, {"playback-abort", mp_property_playback_abort}, {"cache-percent", mp_property_cache}, - M_PROPERTY_DEPRECATED_ALIAS("cache", "cache-percent"), // conflicts with option {"cache-free", mp_property_cache_free}, {"cache-used", mp_property_cache_used}, {"cache-size", mp_property_cache_size}, @@ -3878,7 +3849,6 @@ static const struct m_property mp_properties_base[] = { {"seekable", mp_property_seekable}, {"partially-seekable", mp_property_partially_seekable}, {"idle-active", mp_property_idle}, - M_PROPERTY_DEPRECATED_ALIAS("idle", "idle-active"), // conflicts with option {"chapter-list", mp_property_list_chapters}, {"track-list", property_list_tracks}, @@ -3901,9 +3871,6 @@ static const struct m_property mp_properties_base[] = { {"audio-codec", mp_property_audio_codec}, {"audio-params", mp_property_audio_params}, {"audio-out-params", mp_property_audio_out_params}, - // conflicts with option - M_PROPERTY_DEPRECATED_ALIAS("audio-samplerate", "audio-params/samplerate"), - M_PROPERTY_DEPRECATED_ALIAS("audio-channels", "audio-params/channel-count"), {"aid", mp_property_audio}, {"balance", mp_property_balance}, {"audio-device", mp_property_audio_device}, @@ -3940,7 +3907,6 @@ static const struct m_property mp_properties_base[] = { {"vo-performance", mp_property_vo_performance}, {"current-vo", mp_property_vo}, {"container-fps", mp_property_fps}, - M_PROPERTY_DEPRECATED_ALIAS("fps", "container-fps"), // conflicts with option {"estimated-vf-fps", mp_property_vf_fps}, {"video-aspect", mp_property_aspect}, {"vid", mp_property_video}, @@ -4036,9 +4002,6 @@ static const struct m_property mp_properties_base[] = { M_PROPERTY_ALIAS("colormatrix-input-range", "video-params/colorlevels"), M_PROPERTY_ALIAS("colormatrix-primaries", "video-params/primaries"), M_PROPERTY_ALIAS("colormatrix-gamma", "video-params/gamma"), - - // conflicts with option - M_PROPERTY_DEPRECATED_ALIAS("audio-format", "audio-codec-name"), }; // Each entry describes which properties an event (possibly) changes. From 5087816a7431caf27a5a8a9e00d0004d8322cdaa Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 22 Nov 2016 15:52:55 +0100 Subject: [PATCH 11/83] options: remove legacy global sub-option syntax A bit of sanity, although a very small one. --vo sub-options are not affected by this yet. --- DOCS/interface-changes.rst | 2 ++ options/m_config.c | 57 ++------------------------------------ options/m_config.h | 6 ---- 3 files changed, 5 insertions(+), 60 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index e082b36a9d7ff..6504db556a7df 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -30,6 +30,8 @@ Interface changes - "audio-channels" (use "audio-params/channel-count") - "audio-format" (use "audio-codec-name") (the properties equivalent to the old semantics are in parentheses) + - remove deprecated global sub-options (like -demuxer-rawaudio format=...), + use flat options (like --demuxer-rawaudio-format=...) --- mpv 0.22.0 --- - the "audio-device-list" property now sets empty device description to the device name as a fallback diff --git a/options/m_config.c b/options/m_config.c index 1c5fe01293f37..dea7a4dd10e11 100644 --- a/options/m_config.c +++ b/options/m_config.c @@ -745,9 +745,6 @@ int m_config_set_option_raw(struct m_config *config, struct m_config_option *co, } } -static int parse_subopts(struct m_config *config, char *name, char *prefix, - struct bstr param, int flags); - // Used to turn "--no-foo" into "--foo=no". static struct m_config_option *m_config_find_negation_opt(struct m_config *config, struct bstr *name) @@ -813,15 +810,9 @@ static int m_config_parse_option(struct m_config *config, struct bstr name, // Option with children are a bit different to parse if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) { - char prefix[110]; - if (!config->subopt_deprecation_warning) { - MP_WARN(config, "Suboptions (--%.*s=...) are deprecated. Use " - "flat options instead.\n", BSTR_P(name)); - config->subopt_deprecation_warning = true; - } - assert(strlen(co->name) < 100); - sprintf(prefix, "%s-", co->name); - return parse_subopts(config, (char *)co->name, prefix, param, flags); + MP_FATAL(config, "Suboptions (--%.*s=...) have been removed. Use " + "flat options instead.\n", BSTR_P(name)); + return M_OPT_INVALID; } union m_option_value val = {0}; @@ -841,48 +832,6 @@ static int m_config_parse_option(struct m_config *config, struct bstr name, return r; } -static int parse_subopts(struct m_config *config, char *name, char *prefix, - struct bstr param, int flags) -{ - char **lst = NULL; - // Split the argument into child options - int r = m_option_type_subconfig.parse(config->log, NULL, bstr0(""), param, &lst); - if (r < 0) - return r; - // Parse the child options - for (int i = 0; lst && lst[2 * i]; i++) { - // Build the full name - char n[110]; - if (snprintf(n, 110, "%s%s", prefix, lst[2 * i]) > 100) - abort(); - r = m_config_parse_option(config,bstr0(n), bstr0(lst[2 * i + 1]), flags); - if (r < 0) { - if (r != M_OPT_EXIT) { - MP_ERR(config, "Error parsing suboption %s/%s (%s)\n", - name, lst[2 * i], m_option_strerror(r)); - r = M_OPT_INVALID; - } - break; - } - } - talloc_free(lst); - return r; -} - -int m_config_parse_suboptions(struct m_config *config, char *name, - char *subopts) -{ - if (!subopts || !*subopts) - return 0; - int r = parse_subopts(config, name, "", bstr0(subopts), 0); - if (r < 0 && r != M_OPT_EXIT) { - MP_ERR(config, "Error parsing suboption %s (%s)\n", - name, m_option_strerror(r)); - r = M_OPT_INVALID; - } - return r; -} - int m_config_set_option_ext(struct m_config *config, struct bstr name, struct bstr param, int flags) { diff --git a/options/m_config.h b/options/m_config.h index 94a6c9e6ee988..16eba317f0a0f 100644 --- a/options/m_config.h +++ b/options/m_config.h @@ -92,8 +92,6 @@ typedef struct m_config { // For the command line parser int recursion_depth; - bool subopt_deprecation_warning; - void *optstruct; // struct mpopts or other int shadow_size; @@ -197,10 +195,6 @@ struct mpv_node; int m_config_set_option_node(struct m_config *config, bstr name, struct mpv_node *data, int flags); - -int m_config_parse_suboptions(struct m_config *config, char *name, - char *subopts); - struct m_config_option *m_config_get_co_raw(const struct m_config *config, struct bstr name); struct m_config_option *m_config_get_co(const struct m_config *config, From 585c5c34f1195007beb012668aa9a22cb47b1f37 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sat, 19 Nov 2016 13:57:23 -0800 Subject: [PATCH 12/83] vo_opengl: hwdec_cuda: Support P016 output surfaces The latest 375.xx nvidia drivers add support for P016 output surfaces. In combination with an ffmpeg change to return those surfaces, we can display them. The bulk of the work is related to knowing which format you're dealing with at the right time. Once you know, it's straight forward. --- DOCS/man/options.rst | 4 +-- video/decode/cuda.c | 3 +- video/fmt-conversion.c | 3 ++ video/img_format.h | 4 ++- video/out/opengl/hwdec_cuda.c | 53 +++++++++++++++++++++++++++++------ 5 files changed, 55 insertions(+), 12 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index bf98370eeee0f..82c51fc503e23 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -703,8 +703,8 @@ Video mechanism in the opengl output path. To use this deinterlacing you must pass the option: ``vd-lavc-o=deint=[weave|bob|adaptive]``. Pass ``weave`` to not attempt any deinterlacing. - 10bit HEVC is available if the hardware supports it but it will be - rounded down to 8 bits. + 10 and 12bit HEVC is available if the hardware supports it and a + sufficiently new driver (> 375.xx) is used. ``cuda-copy`` has the same behaviour as ``cuda`` - including the ability to deinterlace inside the decoder. However, traditional deinterlacing diff --git a/video/decode/cuda.c b/video/decode/cuda.c index f9dd418fd5e13..b60631590670b 100644 --- a/video/decode/cuda.c +++ b/video/decode/cuda.c @@ -21,6 +21,7 @@ #include #include "common/av_common.h" +#include "video/fmt-conversion.h" #include "video/decode/lavc.h" typedef struct CUVIDContext { @@ -114,7 +115,7 @@ static void uninit(struct lavc_ctx *ctx) static struct mp_image *process_image(struct lavc_ctx *ctx, struct mp_image *img) { if (img->imgfmt == IMGFMT_CUDA) - img->params.hw_subfmt = IMGFMT_NV12; + img->params.hw_subfmt = pixfmt2imgfmt(ctx->avctx->sw_pix_fmt); return img; } diff --git a/video/fmt-conversion.c b/video/fmt-conversion.c index 32330ddeb1cdd..8b991c5d19f9c 100644 --- a/video/fmt-conversion.c +++ b/video/fmt-conversion.c @@ -112,6 +112,9 @@ static const struct { #ifdef AV_PIX_FMT_P010 {IMGFMT_P010, AV_PIX_FMT_P010}, #endif +#ifdef AV_PIX_FMT_P016 + {IMGFMT_P016, AV_PIX_FMT_P016}, +#endif {0, AV_PIX_FMT_NONE} }; diff --git a/video/img_format.h b/video/img_format.h index a91dcf865c2ab..ee731aa51cc1f 100644 --- a/video/img_format.h +++ b/video/img_format.h @@ -151,8 +151,10 @@ enum mp_imgfmt { IMGFMT_NV12, IMGFMT_NV21, - // Like IMGFMT_NV12, but with 16 bits per component + // Like IMGFMT_NV12, but with 10 bits per component (and 6 bits of padding) IMGFMT_P010, + // Like IMGFMT_NV12, but with 16 bits per component + IMGFMT_P016, // RGB/BGR Formats diff --git a/video/out/opengl/hwdec_cuda.c b/video/out/opengl/hwdec_cuda.c index 539acbd4bab46..4dc842706cf9f 100644 --- a/video/out/opengl/hwdec_cuda.c +++ b/video/out/opengl/hwdec_cuda.c @@ -42,7 +42,7 @@ struct priv { GLuint gl_textures[2]; CUgraphicsResource cu_res[2]; CUarray cu_array[2]; - bool mapped; + int sample_width; CUcontext cuda_ctx; }; @@ -81,7 +81,21 @@ static struct mp_image *cuda_download_image(struct mp_hwdec_ctx *ctx, if (hw_image->imgfmt != IMGFMT_CUDA) return NULL; - struct mp_image *out = mp_image_pool_get(swpool, IMGFMT_NV12, + int sample_width; + switch (hw_image->params.hw_subfmt) { + case IMGFMT_NV12: + sample_width = 1; + break; + case IMGFMT_P010: + case IMGFMT_P016: + sample_width = 2; + break; + default: + return NULL; + } + + struct mp_image *out = mp_image_pool_get(swpool, + hw_image->params.hw_subfmt, hw_image->w, hw_image->h); if (!out) return NULL; @@ -101,7 +115,8 @@ static struct mp_image *cuda_download_image(struct mp_hwdec_ctx *ctx, .dstHost = out->planes[n], .srcPitch = hw_image->stride[n], .dstPitch = out->stride[n], - .WidthInBytes = mp_image_plane_w(out, n) * (n + 1), + .WidthInBytes = mp_image_plane_w(out, n) * + (n + 1) * sample_width, .Height = mp_image_plane_h(out, n), }; @@ -176,11 +191,32 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) int ret = 0, eret = 0; assert(params->imgfmt == hw->driver->imgfmt); - params->imgfmt = IMGFMT_NV12; + params->imgfmt = params->hw_subfmt; params->hw_subfmt = 0; mp_image_set_params(&p->layout, params); + GLint luma_format, chroma_format; + GLenum type; + switch (params->imgfmt) { + case IMGFMT_NV12: + luma_format = GL_R8; + chroma_format = GL_RG8; + type = GL_UNSIGNED_BYTE; + p->sample_width = 1; + break; + case IMGFMT_P010: + case IMGFMT_P016: + luma_format = GL_R16; + chroma_format = GL_RG16; + type = GL_UNSIGNED_SHORT; + p->sample_width = 2; + break; + default: + MP_ERR(hw, "Unsupported format: %s\n", mp_imgfmt_to_name(params->imgfmt)); + return -1; + } + ret = CHECK_CU(cuCtxPushCurrent(p->cuda_ctx)); if (ret < 0) return ret; @@ -193,10 +229,10 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); 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); - gl->TexImage2D(GL_TEXTURE_2D, 0, n == 0 ? GL_R8 : GL_RG8, + gl->TexImage2D(GL_TEXTURE_2D, 0, n == 0 ? luma_format : chroma_format, mp_image_plane_w(&p->layout, n), mp_image_plane_h(&p->layout, n), - 0, n == 0 ? GL_RED : GL_RG, GL_UNSIGNED_BYTE, NULL); + 0, n == 0 ? GL_RED : GL_RG, type, NULL); gl->BindTexture(GL_TEXTURE_2D, 0); ret = CHECK_CU(cuGraphicsGLRegisterImage(&p->cu_res[n], p->gl_textures[n], @@ -261,7 +297,7 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, for (int n = 0; n < 2; n++) { // widthInBytes must account for the chroma plane - // elements being two bytes wide. + // elements being two samples wide. CUDA_MEMCPY2D cpy = { .srcMemoryType = CU_MEMORYTYPE_DEVICE, .dstMemoryType = CU_MEMORYTYPE_ARRAY, @@ -269,7 +305,8 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, .srcPitch = hw_image->stride[n], .srcY = 0, .dstArray = p->cu_array[n], - .WidthInBytes = mp_image_plane_w(&p->layout, n) * (n + 1), + .WidthInBytes = mp_image_plane_w(&p->layout, n) * + (n + 1) * p->sample_width, .Height = mp_image_plane_h(&p->layout, n), }; ret = CHECK_CU(cuMemcpy2D(&cpy)); From ebd9ce9fca557eb0e1388c944dc2438442785e95 Mon Sep 17 00:00:00 2001 From: Ricardo Constantino Date: Tue, 22 Nov 2016 21:00:04 +0000 Subject: [PATCH 13/83] osc: fix use of deprecated idle property Fixes regression since 7201fd7d --- player/lua/osc.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/player/lua/osc.lua b/player/lua/osc.lua index 53860d355d651..bfbdcaa229586 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -2213,7 +2213,7 @@ mp.observe_property("fullscreen", "bool", request_init() end ) -mp.observe_property("idle", "bool", +mp.observe_property("idle-active", "bool", function(name, val) state.idle = val tick() From f5e82d5ed345dbb894ff75591abc4b262b65d0dd Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sat, 8 Oct 2016 16:51:15 -0700 Subject: [PATCH 14/83] vo_opengl: hwdec_cuda: Use dynamic loading for cuda functions This change applies the pattern used in ffmpeg to dynamically load cuda, to avoid requiring the CUDA SDK at build time. --- video/decode/cuda.c | 30 ++----- video/hwdec.h | 1 + video/out/opengl/cuda_dynamic.c | 63 +++++++++++++++ video/out/opengl/cuda_dynamic.h | 139 ++++++++++++++++++++++++++++++++ video/out/opengl/hwdec_cuda.c | 11 ++- wscript | 6 +- wscript_build.py | 1 + 7 files changed, 222 insertions(+), 29 deletions(-) create mode 100644 video/out/opengl/cuda_dynamic.c create mode 100644 video/out/opengl/cuda_dynamic.h diff --git a/video/decode/cuda.c b/video/decode/cuda.c index b60631590670b..cad02b23535d2 100644 --- a/video/decode/cuda.c +++ b/video/decode/cuda.c @@ -17,6 +17,10 @@ * License along with mpv. If not, see . */ +// This define and typedef prevent hwcontext_cuda.h trying to include cuda.h +#define CUDA_VERSION 7050 +typedef void * CUcontext; + #include #include @@ -24,16 +28,6 @@ #include "video/fmt-conversion.h" #include "video/decode/lavc.h" -typedef struct CUVIDContext { - CUcontext cuda_ctx; -} CUVIDContext; - -static void cuvid_ctx_free(AVHWDeviceContext *ctx) -{ - AVCUDADeviceContext *hwctx = ctx->hwctx; - cuCtxDestroy(hwctx->cuda_ctx); -} - static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, const char *codec) { @@ -44,12 +38,7 @@ static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, static int init(struct lavc_ctx *ctx) { - struct CUVIDContext *p = talloc_ptrtype(NULL, p); - - *p = (struct CUVIDContext) { - .cuda_ctx = hwdec_devices_get(ctx->hwdec_devs, HWDEC_CUDA)->ctx, - }; - ctx->hwdec_priv = p; + ctx->hwdec_priv = hwdec_devices_get(ctx->hwdec_devs, HWDEC_CUDA)->ctx; return 0; } @@ -59,7 +48,6 @@ static int init_decoder(struct lavc_ctx *ctx, int w, int h) AVCUDADeviceContext *device_hwctx; AVHWDeviceContext *device_ctx; AVHWFramesContext *hwframe_ctx; - CUVIDContext *priv = ctx->hwdec_priv; int ret = 0; if (avctx->hw_frames_ctx) { @@ -74,10 +62,9 @@ static int init_decoder(struct lavc_ctx *ctx, int w, int h) } device_ctx = (AVHWDeviceContext*)hw_device_ctx->data; - device_ctx->free = cuvid_ctx_free; device_hwctx = device_ctx->hwctx; - device_hwctx->cuda_ctx = priv->cuda_ctx; + device_hwctx->cuda_ctx = ctx->hwdec_priv; ret = av_hwdevice_ctx_init(hw_device_ctx); if (ret < 0) { @@ -104,11 +91,6 @@ static int init_decoder(struct lavc_ctx *ctx, int w, int h) static void uninit(struct lavc_ctx *ctx) { - struct CUVIDContext *p = ctx->hwdec_priv; - if (!p) - return; - - talloc_free(p); ctx->hwdec_priv = NULL; } diff --git a/video/hwdec.h b/video/hwdec.h index 857d07c894b54..f2fa7943afdc1 100644 --- a/video/hwdec.h +++ b/video/hwdec.h @@ -44,6 +44,7 @@ struct mp_hwdec_ctx { // HWDEC_D3D11VA: ID3D11Device* // HWDEC_DXVA2: IDirect3DDevice9* // HWDEC_DXVA2_COPY: IDirect3DDevice9* + // HWDEC_CUDA: CUcontext* void *ctx; // Optional. diff --git a/video/out/opengl/cuda_dynamic.c b/video/out/opengl/cuda_dynamic.c new file mode 100644 index 0000000000000..112e81a52151c --- /dev/null +++ b/video/out/opengl/cuda_dynamic.c @@ -0,0 +1,63 @@ +/* + * 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 "cuda_dynamic.h" + +#include + +#if defined(_WIN32) +# include +# define dlopen(filename, flags) LoadLibrary(TEXT(filename)) +# define dlsym(handle, symbol) GetProcAddress(handle, symbol) +# define dlclose(handle) FreeLibrary(handle) +#else +# include +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +# define CUDA_LIBNAME "nvcuda.dll" +#else +# define CUDA_LIBNAME "libcuda.so.1" +#endif + +#define CUDA_DECL(NAME, TYPE) \ + TYPE *NAME; +CUDA_FNS(CUDA_DECL) + +static bool cuda_loaded = false; +static pthread_once_t cuda_load_once = PTHREAD_ONCE_INIT; + +static void cuda_do_load(void) +{ + void *lib = dlopen(CUDA_LIBNAME, RTLD_LAZY); + if (!lib) { + return; + } + +#define CUDA_LOAD_SYMBOL(NAME, TYPE) \ + NAME = dlsym(lib, #NAME); if (!NAME) return; + + CUDA_FNS(CUDA_LOAD_SYMBOL) + + cuda_loaded = true; +} + +bool cuda_load(void) +{ + pthread_once(&cuda_load_once, cuda_do_load); + return cuda_loaded; +} diff --git a/video/out/opengl/cuda_dynamic.h b/video/out/opengl/cuda_dynamic.h new file mode 100644 index 0000000000000..d906b6787ffe4 --- /dev/null +++ b/video/out/opengl/cuda_dynamic.h @@ -0,0 +1,139 @@ +/* + * This file is part of mpv. + * + * It is based on an equivalent file in ffmpeg that was + * constructed from documentation, rather than from any + * original cuda headers. + * + * 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 . + */ + +#if !defined(MPV_CUDA_DYNAMIC_H) && !defined(CUDA_VERSION) +#define MPV_CUDA_DYNAMIC_H + +#include +#include + +#define CUDA_VERSION 7050 + +#if defined(_WIN32) || defined(__CYGWIN__) +#define CUDAAPI __stdcall +#else +#define CUDAAPI +#endif + +#define CU_CTX_SCHED_BLOCKING_SYNC 4 + +typedef int CUdevice; + +typedef struct CUarray_st *CUarray; +typedef struct CUgraphicsResource_st *CUgraphicsResource; +typedef struct CUstream_st *CUstream; + +typedef void* CUcontext; +#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) +typedef unsigned long long CUdeviceptr; +#else +typedef unsigned int CUdeviceptr; +#endif + +typedef enum cudaError_enum { + CUDA_SUCCESS = 0 +} CUresult; + +typedef enum CUmemorytype_enum { + CU_MEMORYTYPE_HOST = 1, + CU_MEMORYTYPE_DEVICE = 2, + CU_MEMORYTYPE_ARRAY = 3 +} CUmemorytype; + +typedef struct CUDA_MEMCPY2D_st { + size_t srcXInBytes; + size_t srcY; + CUmemorytype srcMemoryType; + const void *srcHost; + CUdeviceptr srcDevice; + CUarray srcArray; + size_t srcPitch; + + size_t dstXInBytes; + size_t dstY; + CUmemorytype dstMemoryType; + void *dstHost; + CUdeviceptr dstDevice; + CUarray dstArray; + size_t dstPitch; + + size_t WidthInBytes; + size_t Height; +} CUDA_MEMCPY2D; + +typedef enum CUGLDeviceList_enum { + CU_GL_DEVICE_LIST_ALL = 1, + CU_GL_DEVICE_LIST_CURRENT_FRAME = 2, + CU_GL_DEVICE_LIST_NEXT_FRAME = 3, +} CUGLDeviceList; + +typedef unsigned int GLenum; +typedef unsigned int GLuint; + +#define CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD 2 + +typedef CUresult CUDAAPI tcuInit(unsigned int Flags); +typedef CUresult CUDAAPI tcuCtxCreate_v2(CUcontext *pctx, unsigned int flags, CUdevice dev); +typedef CUresult CUDAAPI tcuCtxPushCurrent_v2(CUcontext *pctx); +typedef CUresult CUDAAPI tcuCtxPopCurrent_v2(CUcontext *pctx); +typedef CUresult CUDAAPI tcuCtxDestroy_v2(CUcontext ctx); +typedef CUresult CUDAAPI tcuMemcpy2D_v2(const CUDA_MEMCPY2D *pcopy); +typedef CUresult CUDAAPI tcuGetErrorName(CUresult error, const char** pstr); +typedef CUresult CUDAAPI tcuGetErrorString(CUresult error, const char** pstr); +typedef CUresult CUDAAPI tcuGLGetDevices_v2(unsigned int* pCudaDeviceCount, CUdevice* pCudaDevices, unsigned int cudaDeviceCount, CUGLDeviceList deviceList); +typedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource* pCudaResource, GLuint image, GLenum target, unsigned int Flags); +typedef CUresult CUDAAPI tcuGraphicsUnregisterResource(CUgraphicsResource resource); +typedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream); +typedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned int count, CUgraphicsResource* resources, CUstream hStream); +typedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray* pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel); + +#define CUDA_FNS(FN) \ + FN(cuInit, tcuInit) \ + FN(cuCtxCreate_v2, tcuCtxCreate_v2) \ + FN(cuCtxPushCurrent_v2, tcuCtxPushCurrent_v2) \ + FN(cuCtxPopCurrent_v2, tcuCtxPopCurrent_v2) \ + FN(cuCtxDestroy_v2, tcuCtxDestroy_v2) \ + FN(cuMemcpy2D_v2, tcuMemcpy2D_v2) \ + FN(cuGetErrorName, tcuGetErrorName) \ + FN(cuGetErrorString, tcuGetErrorString) \ + FN(cuGLGetDevices_v2, tcuGLGetDevices_v2) \ + FN(cuGraphicsGLRegisterImage, tcuGraphicsGLRegisterImage) \ + FN(cuGraphicsUnregisterResource, tcuGraphicsUnregisterResource) \ + FN(cuGraphicsMapResources, tcuGraphicsMapResources) \ + FN(cuGraphicsUnmapResources, tcuGraphicsUnmapResources) \ + FN(cuGraphicsUnmapResources, tcuGraphicsUnmapResources) \ + FN(cuGraphicsSubResourceGetMappedArray, tcuGraphicsSubResourceGetMappedArray) \ + +#define CUDA_EXT_DECL(NAME, TYPE) \ + extern TYPE *NAME; + +CUDA_FNS(CUDA_EXT_DECL) + +#define cuCtxCreate cuCtxCreate_v2 +#define cuCtxPushCurrent cuCtxPushCurrent_v2 +#define cuCtxPopCurrent cuCtxPopCurrent_v2 +#define cuCtxDestroy cuCtxDestroy_v2 +#define cuMemcpy2D cuMemcpy2D_v2 +#define cuGLGetDevices cuGLGetDevices_v2 + +bool cuda_load(void); + +#endif // MPV_CUDA_DYNAMIC_H diff --git a/video/out/opengl/hwdec_cuda.c b/video/out/opengl/hwdec_cuda.c index 4dc842706cf9f..266714a972af6 100644 --- a/video/out/opengl/hwdec_cuda.c +++ b/video/out/opengl/hwdec_cuda.c @@ -28,13 +28,13 @@ */ #include -#include +#include "cuda_dynamic.h" #include "video/mp_image_pool.h" #include "hwdec.h" #include "video.h" -#include +#include struct priv { struct mp_hwdec_ctx hwctx; @@ -152,6 +152,11 @@ static int cuda_create(struct gl_hwdec *hw) struct priv *p = talloc_zero(hw, struct priv); hw->priv = p; + bool loaded = cuda_load(); + if (!loaded) { + MP_ERR(hw, "Failed to load CUDA symbols\n"); + } + ret = CHECK_CU(cuInit(0)); if (ret < 0) goto error; @@ -277,6 +282,8 @@ static void destroy(struct gl_hwdec *hw) } CHECK_CU(cuCtxPopCurrent(&dummy)); + CHECK_CU(cuCtxDestroy(p->cuda_ctx)); + gl->DeleteTextures(2, p->gl_textures); hwdec_devices_remove(hw->devs, &p->hwctx); diff --git a/wscript b/wscript index 2b0de8bcd539a..f9090bf4eef43 100644 --- a/wscript +++ b/wscript @@ -913,9 +913,9 @@ hwaccel_features = [ }, { 'name': '--cuda-hwaccel', 'desc': 'CUDA hwaccel', - 'func': compose_checks( - check_cc(lib="cuda"), - check_headers('libavutil/hwcontext_cuda.h', use='libav')), + 'func': check_statement('libavutil/hwcontext_cuda.h', + 'AVCUDADeviceContextInternal* foo', + use='libav'), }, { 'name': 'sse4-intrinsics', 'desc': 'GCC SSE4 intrinsics for GPU memcpy', diff --git a/wscript_build.py b/wscript_build.py index bce1ceb3fdc69..43e3dd8c9cba0 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -346,6 +346,7 @@ def build(ctx): ( "video/out/opengl/context_w32.c", "gl-win32" ), ( "video/out/opengl/context_x11.c", "gl-x11" ), ( "video/out/opengl/context_x11egl.c", "egl-x11" ), + ( "video/out/opengl/cuda_dynamic.c", "cuda-hwaccel" ), ( "video/out/opengl/egl_helpers.c", "egl-helpers" ), ( "video/out/opengl/formats.c", "gl" ), ( "video/out/opengl/hwdec.c", "gl" ), From 6b3d682f4e898226bf1d0dc25042ee237bdc1a9b Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 23 Nov 2016 01:09:19 +0100 Subject: [PATCH 15/83] vo_opengl: hwdec_d3d11egl: fix ANGLE fallback define This was a typo in the extensiuon spec and was probably always broken. Could have led to broken builds when used with ancient ANGLE headers (or possibly generic EGL headers). --- video/out/opengl/hwdec_d3d11egl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/out/opengl/hwdec_d3d11egl.c b/video/out/opengl/hwdec_d3d11egl.c index 690609b5b9ed5..0ca954b046d79 100644 --- a/video/out/opengl/hwdec_d3d11egl.c +++ b/video/out/opengl/hwdec_d3d11egl.c @@ -32,7 +32,7 @@ #include "video/decode/d3d.h" #ifndef EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE -#define EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x3AAB +#define EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x33AB #endif struct priv { From 535e180b9ec4ac26a91b384f793b1411440214a1 Mon Sep 17 00:00:00 2001 From: Martin Herkt Date: Wed, 23 Nov 2016 01:18:21 +0100 Subject: [PATCH 16/83] DOCS/compile-windows: be more specific about the D3D compiler DLL Also provide a more useful link to _43 and _47. --- DOCS/compile-windows.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/DOCS/compile-windows.md b/DOCS/compile-windows.md index f0d0dca50dcd4..6fd5ed79b2ab4 100644 --- a/DOCS/compile-windows.md +++ b/DOCS/compile-windows.md @@ -205,11 +205,10 @@ DLLs in that folder. The simplest solution is to add ``C:\msys64\mingw64\bin`` to the windows system ``%PATH%``. Beware though that this can cause problems or confusion in Cygwin if that is also installed on the machine. -Use of the ANGLE OpenGL backend requires a copy of ``d3dcompiler_43.dll`` (yes, -exactly 43) in the path or in the same folder as mpv. It must be of the same -architecture (x86_64 / i686) as the mpv you compiled. You can find a copy in the -official mpv builds: +Use of the ANGLE OpenGL backend requires a copy of the D3D compiler DLL that +matches the version of the D3D SDK that ANGLE was built with +(``d3dcompiler_43.dll`` in case of MinGW-built ANGLE) in the path or in the +same folder as mpv. It must be of the same architecture (x86_64 / i686) as the +mpv you compiled. You can find copies here: -https://mpv.srsfckn.biz/mpv-x86_64-20160118.7z - -https://mpv.srsfckn.biz/mpv-i686-20160118.7z +https://mpv.srsfckn.biz/d3dcompiler.7z From f9668f55968f925d21fd98ff11842ea61e9890c4 Mon Sep 17 00:00:00 2001 From: Martin Herkt Date: Tue, 22 Nov 2016 23:26:43 +0100 Subject: [PATCH 17/83] Support linking ANGLE --- video/out/opengl/angle_dynamic.c | 5 +++++ wscript | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/video/out/opengl/angle_dynamic.c b/video/out/opengl/angle_dynamic.c index f4540c473a24c..3c5a9ba036a0d 100644 --- a/video/out/opengl/angle_dynamic.c +++ b/video/out/opengl/angle_dynamic.c @@ -4,6 +4,7 @@ #define ANGLE_NO_ALIASES #include "angle_dynamic.h" +#include "config.h" #include "common/common.h" #define ANGLE_DECL(NAME, VAR) \ @@ -28,6 +29,10 @@ static void angle_do_load(void) bool angle_load(void) { +#if !HAVE_EGL_ANGLE_LIB pthread_once(&angle_load_once, angle_do_load); return angle_loaded; +#else + return true; +#endif } diff --git a/wscript b/wscript index f9090bf4eef43..056ac1048debc 100644 --- a/wscript +++ b/wscript @@ -735,6 +735,15 @@ video_output_features = [ 'groups': [ 'gl' ], 'func': check_statement(['EGL/egl.h', 'EGL/eglext.h'], 'int x = EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE') + } , { + 'name': '--egl-angle-lib', + 'desc': 'OpenGL Win32 ANGLE Library', + 'deps': [ 'egl-angle' ], + 'groups': [ 'gl' ], + 'func': check_statement(['EGL/egl.h'], + 'eglCreateWindowSurface(0, 0, 0, 0)', + cflags="-DGL_APICALL= -DEGLAPI= -DANGLE_NO_ALIASES", + lib=['EGL', 'GLESv2', 'dxguid', 'd3d9', 'gdi32', 'stdc++']) } , { 'name': '--vdpau', 'desc': 'VDPAU acceleration', From 79d99bd264d53aac2fe7a3c07cf36b3710a5b726 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 23 Nov 2016 15:55:22 +0100 Subject: [PATCH 18/83] demux_mkv: distinguish mp2 and mp3 demux_mkv.c has returned mp3 for mp2 since the initial commit. Normally not a problem. --- demux/demux_mkv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 63b58cdb152b9..5598cf8374196 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1511,7 +1511,7 @@ static void parse_flac_chmap(struct mp_chmap *channels, unsigned char *data, } static const char *const mkv_audio_tags[][2] = { - { "A_MPEG/L2", "mp3" }, + { "A_MPEG/L2", "mp2" }, { "A_MPEG/L3", "mp3" }, { "A_AC3", "ac3" }, { "A_EAC3", "eac3" }, @@ -1701,7 +1701,9 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) mp_chmap_set_unknown(&sh_a->channels, track->a_channels); const char *codec = sh_a->codec; - if (!strcmp(codec, "mp3") || !strcmp(codec, "truehd")) { + if (!strcmp(codec, "mp2") || !strcmp(codec, "mp3") || + !strcmp(codec, "truehd")) + { track->parse = true; } else if (!strcmp(codec, "flac")) { unsigned char *ptr = extradata; From f696975fe371a0c98cdcaa20bce33b55b48f5c37 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 23 Nov 2016 16:01:28 +0100 Subject: [PATCH 19/83] angle_dynamic: minor simplification Remove the inverted condition by swapping if branches. --- video/out/opengl/angle_dynamic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/video/out/opengl/angle_dynamic.c b/video/out/opengl/angle_dynamic.c index 3c5a9ba036a0d..872b9f3001ed1 100644 --- a/video/out/opengl/angle_dynamic.c +++ b/video/out/opengl/angle_dynamic.c @@ -29,10 +29,10 @@ static void angle_do_load(void) bool angle_load(void) { -#if !HAVE_EGL_ANGLE_LIB +#if HAVE_EGL_ANGLE_LIB + return true; +#else pthread_once(&angle_load_once, angle_do_load); return angle_loaded; -#else - return true; #endif } From 755e9fad2985fbaaa0c23243521ab4c90a3ceb7e Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 23 Nov 2016 17:30:46 +0100 Subject: [PATCH 20/83] command: warn against deprecated properties in all cases For some reason, some types of accesses didn't warn, for example when using mp.observe_property() in Lua. This was because the deprecation handling code explicitly checks certain accesses. I'm not quite certain why it was done this way. Just make it warn always. This could be backported to the current release, if we cared. --- player/command.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/player/command.c b/player/command.c index 1f112fdf65d48..3d56a56fca41b 100644 --- a/player/command.c +++ b/player/command.c @@ -3589,20 +3589,16 @@ static int mp_property_deprecated_alias(void *ctx, struct m_property *prop, MPContext *mpctx = ctx; struct command_ctx *cmd = mpctx->command_ctx; const char *real_property = prop->priv; - if (action == M_PROPERTY_SET || action == M_PROPERTY_GET || - action == M_PROPERTY_PRINT) - { - for (int n = 0; n < cmd->num_warned_deprecated; n++) { - if (strcmp(cmd->warned_deprecated[n], prop->name) == 0) - goto done; - } - MP_WARN(mpctx, "Warning: property '%s' was replaced with '%s' and " - "might be removed in the future.\n", prop->name, real_property); - MP_TARRAY_APPEND(cmd, cmd->warned_deprecated, cmd->num_warned_deprecated, - (char *)prop->name); - - done:; + for (int n = 0; n < cmd->num_warned_deprecated; n++) { + if (strcmp(cmd->warned_deprecated[n], prop->name) == 0) + goto done; } + MP_WARN(mpctx, "Warning: property '%s' was replaced with '%s' and " + "might be removed in the future.\n", prop->name, real_property); + MP_TARRAY_APPEND(cmd, cmd->warned_deprecated, cmd->num_warned_deprecated, + (char *)prop->name); + +done: return mp_property_do(real_property, action, arg, ctx); } From 3abb6f1fefadc5e8e84966e07857d248a07a7b29 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Wed, 23 Nov 2016 10:14:32 -0800 Subject: [PATCH 21/83] wscript: Fix cuda test to actually work when cuda SDK is not present The test ended up failing if cuda.h wasn't present, even if cuda.h isn't used during the actual build. This test is attempting to establish if the ffmpeg being built against has dynlink_cuda support. While it might theoretically be possible to build against the older normally-linked-cuda version of ffmpeg, it seems more trouble than it's worth. --- video/out/opengl/cuda_dynamic.h | 2 +- waftools/fragments/cuda.c | 12 ++++++++++++ wscript | 5 ++--- 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 waftools/fragments/cuda.c diff --git a/video/out/opengl/cuda_dynamic.h b/video/out/opengl/cuda_dynamic.h index d906b6787ffe4..bdac626be5062 100644 --- a/video/out/opengl/cuda_dynamic.h +++ b/video/out/opengl/cuda_dynamic.h @@ -19,7 +19,7 @@ * License along with mpv. If not, see . */ -#if !defined(MPV_CUDA_DYNAMIC_H) && !defined(CUDA_VERSION) +#ifndef MPV_CUDA_DYNAMIC_H #define MPV_CUDA_DYNAMIC_H #include diff --git a/waftools/fragments/cuda.c b/waftools/fragments/cuda.c new file mode 100644 index 0000000000000..c63ec2945d441 --- /dev/null +++ b/waftools/fragments/cuda.c @@ -0,0 +1,12 @@ +#define CUDA_VERSION 7050 + +typedef void * CUcontext; + +#include +#include + +int main(int argc, char *argv[]) { + enum AVHWDeviceType type = AV_HWDEVICE_TYPE_CUDA; + AVCUDADeviceContextInternal *foo; + return 0; +} diff --git a/wscript b/wscript index 056ac1048debc..2fe82e1afc401 100644 --- a/wscript +++ b/wscript @@ -922,9 +922,8 @@ hwaccel_features = [ }, { 'name': '--cuda-hwaccel', 'desc': 'CUDA hwaccel', - 'func': check_statement('libavutil/hwcontext_cuda.h', - 'AVCUDADeviceContextInternal* foo', - use='libav'), + 'func': check_cc(fragment=load_fragment('cuda.c'), + use='libav'), }, { 'name': 'sse4-intrinsics', 'desc': 'GCC SSE4 intrinsics for GPU memcpy', From 7eacaf51f80a081177b74580105cb22d5ad0c877 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Wed, 23 Nov 2016 15:01:17 -0800 Subject: [PATCH 22/83] vo_opengl/cuda_dynamic: Use explicit cast to silence warnings on windows Fixes #3834 --- video/out/opengl/cuda_dynamic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/out/opengl/cuda_dynamic.c b/video/out/opengl/cuda_dynamic.c index 112e81a52151c..f37baca6d0b1c 100644 --- a/video/out/opengl/cuda_dynamic.c +++ b/video/out/opengl/cuda_dynamic.c @@ -49,7 +49,7 @@ static void cuda_do_load(void) } #define CUDA_LOAD_SYMBOL(NAME, TYPE) \ - NAME = dlsym(lib, #NAME); if (!NAME) return; + NAME = (TYPE *)dlsym(lib, #NAME); if (!NAME) return; CUDA_FNS(CUDA_LOAD_SYMBOL) From e89382f5f6c42cc5f4872aa4135b69bc3f09cccf Mon Sep 17 00:00:00 2001 From: pavelxdd Date: Thu, 24 Nov 2016 15:11:44 +0300 Subject: [PATCH 23/83] vo_opengl: hwdec_cuda: fix crash when trying to use hwdec=cuda if cuda SDK is not present If CUDA SDK wasn't installed, mpv crashed immediately with the message "Failed to load CUDA symbols" --- video/out/opengl/hwdec_cuda.c | 1 + 1 file changed, 1 insertion(+) diff --git a/video/out/opengl/hwdec_cuda.c b/video/out/opengl/hwdec_cuda.c index 266714a972af6..dfb55e8ce03fb 100644 --- a/video/out/opengl/hwdec_cuda.c +++ b/video/out/opengl/hwdec_cuda.c @@ -155,6 +155,7 @@ static int cuda_create(struct gl_hwdec *hw) bool loaded = cuda_load(); if (!loaded) { MP_ERR(hw, "Failed to load CUDA symbols\n"); + return -1; } ret = CHECK_CU(cuInit(0)); From 5aab17f833c9b6bb24bd6d5369fbca5c1efab1c7 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 24 Nov 2016 18:14:55 +0100 Subject: [PATCH 24/83] vo_opengl: hwdec_cuda: make some init errors verbose Improves autoprobe behavior. This is equivalent to other hwdec interop wrappers. If CUDA is just not available, it should remain silent. --- video/out/opengl/hwdec_cuda.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/video/out/opengl/hwdec_cuda.c b/video/out/opengl/hwdec_cuda.c index dfb55e8ce03fb..c3d2e34ae361c 100644 --- a/video/out/opengl/hwdec_cuda.c +++ b/video/out/opengl/hwdec_cuda.c @@ -145,7 +145,7 @@ static int cuda_create(struct gl_hwdec *hw) int ret = 0, eret = 0; if (hw->gl->version < 210 && hw->gl->es < 300) { - MP_ERR(hw, "need OpenGL >= 2.1 or OpenGL-ES >= 3.0\n"); + MP_VERBOSE(hw, "need OpenGL >= 2.1 or OpenGL-ES >= 3.0\n"); return -1; } @@ -154,7 +154,7 @@ static int cuda_create(struct gl_hwdec *hw) bool loaded = cuda_load(); if (!loaded) { - MP_ERR(hw, "Failed to load CUDA symbols\n"); + MP_VERBOSE(hw, "Failed to load CUDA symbols\n"); return -1; } From 48a7c4be3a8ea97ddc2150c20b5cf4db4f1b8e85 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Thu, 24 Nov 2016 11:07:21 -0800 Subject: [PATCH 25/83] vo_opengl: hwdec_cuda: Prefix cuda symbols to avoid collisions We want to avoid causing problems if libmpv is used in an application that links cuda, or if the libav* libraries are linked with cuda, as might happen if the scale_npp filter is used. --- video/out/opengl/cuda_dynamic.c | 6 +++--- video/out/opengl/cuda_dynamic.h | 23 +++++++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/video/out/opengl/cuda_dynamic.c b/video/out/opengl/cuda_dynamic.c index f37baca6d0b1c..1135a1f077a14 100644 --- a/video/out/opengl/cuda_dynamic.c +++ b/video/out/opengl/cuda_dynamic.c @@ -22,7 +22,7 @@ #if defined(_WIN32) # include # define dlopen(filename, flags) LoadLibrary(TEXT(filename)) -# define dlsym(handle, symbol) GetProcAddress(handle, symbol) +# define dlsym(handle, symbol) (void *)GetProcAddress(handle, symbol) # define dlclose(handle) FreeLibrary(handle) #else # include @@ -35,7 +35,7 @@ #endif #define CUDA_DECL(NAME, TYPE) \ - TYPE *NAME; + TYPE *mpv_ ## NAME; CUDA_FNS(CUDA_DECL) static bool cuda_loaded = false; @@ -49,7 +49,7 @@ static void cuda_do_load(void) } #define CUDA_LOAD_SYMBOL(NAME, TYPE) \ - NAME = (TYPE *)dlsym(lib, #NAME); if (!NAME) return; + mpv_ ## NAME = dlsym(lib, #NAME); if (!mpv_ ## NAME) return; CUDA_FNS(CUDA_LOAD_SYMBOL) diff --git a/video/out/opengl/cuda_dynamic.h b/video/out/opengl/cuda_dynamic.h index bdac626be5062..ecf212aa821e6 100644 --- a/video/out/opengl/cuda_dynamic.h +++ b/video/out/opengl/cuda_dynamic.h @@ -119,20 +119,27 @@ typedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray* pArray, C FN(cuGraphicsUnregisterResource, tcuGraphicsUnregisterResource) \ FN(cuGraphicsMapResources, tcuGraphicsMapResources) \ FN(cuGraphicsUnmapResources, tcuGraphicsUnmapResources) \ - FN(cuGraphicsUnmapResources, tcuGraphicsUnmapResources) \ FN(cuGraphicsSubResourceGetMappedArray, tcuGraphicsSubResourceGetMappedArray) \ #define CUDA_EXT_DECL(NAME, TYPE) \ - extern TYPE *NAME; + extern TYPE *mpv_ ## NAME; CUDA_FNS(CUDA_EXT_DECL) -#define cuCtxCreate cuCtxCreate_v2 -#define cuCtxPushCurrent cuCtxPushCurrent_v2 -#define cuCtxPopCurrent cuCtxPopCurrent_v2 -#define cuCtxDestroy cuCtxDestroy_v2 -#define cuMemcpy2D cuMemcpy2D_v2 -#define cuGLGetDevices cuGLGetDevices_v2 +#define cuInit mpv_cuInit +#define cuCtxCreate mpv_cuCtxCreate_v2 +#define cuCtxPushCurrent mpv_cuCtxPushCurrent_v2 +#define cuCtxPopCurrent mpv_cuCtxPopCurrent_v2 +#define cuCtxDestroy mpv_cuCtxDestroy_v2 +#define cuMemcpy2D mpv_cuMemcpy2D_v2 +#define cuGetErrorName mpv_cuGetErrorName +#define cuGetErrorString mpv_cuGetErrorString +#define cuGLGetDevices mpv_cuGLGetDevices_v2 +#define cuGraphicsGLRegisterImage mpv_cuGraphicsGLRegisterImage +#define cuGraphicsUnregisterResource mpv_cuGraphicsUnregisterResource +#define cuGraphicsMapResources mpv_cuGraphicsMapResources +#define cuGraphicsUnmapResources mpv_cuGraphicsUnmapResources +#define cuGraphicsSubResourceGetMappedArray mpv_cuGraphicsSubResourceGetMappedArray bool cuda_load(void); From c03a67c37c149134a25d400a62b7706386136379 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 24 Nov 2016 20:50:09 +0100 Subject: [PATCH 26/83] audio/out/push: play silence on --audio-stream-silence Until now, this was only implemented for ao_alsa and AOs not using push.c. ao_alsa.c relied on enabling funny underrun semantics for avoiding resets on lower levels, while other AOs using push.c didn't do anything. Change this and at least make push.c copy silent data to the AO. This still isn't perfect as keeping track of how much silence was played when seems complex, so we don't do it. The consequence is that frame-stepping will essentially randomize the A/V offset (it'll recover immediately when unpausing, but still ugly). Also, in order to empty the currently buffered audio on seeks etc., we still call ao_driver->reset and so on, so the AO driver will still need to handle this specially. The intent is to make behavior with ALSA less weird (for one we can remove the code in ao_alsa.c that tries to trigger an initial underflow). Also might help with #3754. --- audio/out/ao_alsa.c | 6 ------ audio/out/push.c | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 201557697d0bd..91c8e2d3fcf3a 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -845,12 +845,6 @@ static int init_device(struct ao *ao, int mode) ao->device_buffer = p->buffersize; - // ao_alsa implements this by relying on underrun behavior (no data means - // underrun, during which silence is played). Trigger by playing some - // initial silence. - if (ao->stream_silence) - ao_play_silence(ao, p->outburst); - return 0; alsa_error: diff --git a/audio/out/push.c b/audio/out/push.c index 555a7867dab68..a4a6808d7f15f 100644 --- a/audio/out/push.c +++ b/audio/out/push.c @@ -49,6 +49,8 @@ struct ao_push_state { struct mp_audio_buffer *buffer; + struct mp_audio *silence; + bool terminate; bool wait_on_ao; bool still_playing; @@ -259,15 +261,38 @@ static int play(struct ao *ao, void **data, int samples, int flags) return write_samples; } +static void ao_get_silence(struct ao *ao, struct mp_audio *data, int size) +{ + struct ao_push_state *p = ao->api_priv; + if (!p->silence) { + p->silence = talloc_zero(p, struct mp_audio); + mp_audio_set_format(p->silence, ao->format); + mp_audio_set_channels(p->silence, &ao->channels); + p->silence->rate = ao->samplerate; + } + if (p->silence->samples < size) { + mp_audio_realloc_min(p->silence, size); + p->silence->samples = size; + mp_audio_fill_silence(p->silence, 0, size); + } + *data = *p->silence; + data->samples = size; +} + // called locked static void ao_play_data(struct ao *ao) { struct ao_push_state *p = ao->api_priv; - struct mp_audio data; - mp_audio_buffer_peek(p->buffer, &data); - int max = data.samples; int space = ao->driver->get_space(ao); + bool play_silence = p->paused || (ao->stream_silence && !p->still_playing); space = MPMAX(space, 0); + struct mp_audio data; + if (play_silence) { + ao_get_silence(ao, &data, space); + } else { + mp_audio_buffer_peek(p->buffer, &data); + } + int max = data.samples; if (data.samples > space) data.samples = space; int flags = 0; @@ -289,7 +314,8 @@ static void ao_play_data(struct ao *ao) MP_ERR(ao, "Audio output driver seems to ignore AOPLAY_FINAL_CHUNK.\n"); r = max; } - mp_audio_buffer_skip(p->buffer, r); + if (!play_silence) + mp_audio_buffer_skip(p->buffer, r); if (r > 0) p->expected_end_time = 0; // Nothing written, but more input data than space - this must mean the @@ -300,7 +326,7 @@ static void ao_play_data(struct ao *ao) // Wait until space becomes available. Also wait if we actually wrote data, // so the AO wakes us up properly if it needs more data. p->wait_on_ao = space == 0 || r > 0 || stuck; - p->still_playing |= r > 0; + p->still_playing |= r > 0 && !play_silence; // If we just filled the AO completely (r == space), don't refill for a // while. Prevents wakeup feedback with byte-granular AOs. int needed = unlocked_get_space(ao); @@ -319,12 +345,13 @@ static void *playthread(void *arg) mpthread_set_name("ao"); pthread_mutex_lock(&p->lock); while (!p->terminate) { - if (!p->paused) + bool playing = !p->paused || ao->stream_silence; + if (playing) ao_play_data(ao); if (!p->need_wakeup) { MP_STATS(ao, "start audio wait"); - if (!p->wait_on_ao || p->paused) { + if (!p->wait_on_ao || !playing) { // Avoid busy waiting, because the audio API will still report // that it needs new data, even if we're not ready yet, or if // get_space() decides that the amount of audio buffered in the From 98a257b3a871587a97f51ef1b09800959a94ed1e Mon Sep 17 00:00:00 2001 From: pavelxdd Date: Fri, 25 Nov 2016 00:41:09 +0300 Subject: [PATCH 27/83] angle_dynamic: silence warnings during compilation If Angle is statically linked there were some warnings during compilation. Fixes #3834 --- video/out/opengl/angle_dynamic.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/video/out/opengl/angle_dynamic.c b/video/out/opengl/angle_dynamic.c index 872b9f3001ed1..1ff3cc8c6e47e 100644 --- a/video/out/opengl/angle_dynamic.c +++ b/video/out/opengl/angle_dynamic.c @@ -1,12 +1,21 @@ #include #include +#ifndef ANGLE_NO_ALIASES #define ANGLE_NO_ALIASES +#endif + #include "angle_dynamic.h" #include "config.h" #include "common/common.h" +#if HAVE_EGL_ANGLE_LIB +bool angle_load(void) +{ + return true; +} +#else #define ANGLE_DECL(NAME, VAR) \ VAR; ANGLE_FNS(ANGLE_DECL) @@ -29,10 +38,7 @@ static void angle_do_load(void) bool angle_load(void) { -#if HAVE_EGL_ANGLE_LIB - return true; -#else pthread_once(&angle_load_once, angle_do_load); return angle_loaded; -#endif } +#endif From 1a2319f3e4cc42c680e2fd3ba30022c7a9adf3fe Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 25 Nov 2016 21:00:39 +0100 Subject: [PATCH 28/83] options: remove deprecated sub-option handling for --vo and --ao Long planned. Leads to some sanity. There still are some rather gross things. Especially g_groups is ugly, and a hack that can hopefully be removed. (There is a plan for it, but whether it's implemented depends on how much energy is left.) --- DOCS/interface-changes.rst | 4 + DOCS/man/ao.rst | 5 -- DOCS/man/vo.rst | 5 -- audio/out/ao.c | 23 +++-- audio/out/ao_alsa.c | 10 --- audio/out/ao_audiounit.m | 3 - audio/out/ao_coreaudio.c | 9 +- audio/out/ao_jack.c | 8 -- audio/out/ao_null.c | 2 +- audio/out/ao_openal.c | 2 +- audio/out/ao_opensles.c | 2 +- audio/out/ao_oss.c | 2 +- audio/out/ao_pcm.c | 2 +- audio/out/ao_pulse.c | 2 +- audio/out/ao_rsound.c | 2 +- audio/out/ao_sdl.c | 2 +- audio/out/ao_sndio.c | 2 +- audio/out/ao_wasapi.c | 7 -- audio/out/ao_wasapi.h | 2 - audio/out/ao_wasapi_utils.c | 5 +- audio/out/internal.h | 2 +- options/m_config.c | 165 ++++++++++++++++++++++-------------- options/m_config.h | 3 + options/m_option.c | 17 +++- options/m_option.h | 15 ++-- options/options.c | 4 - options/options.h | 4 +- video/out/opengl/video.c | 89 ------------------- video/out/opengl/video.h | 1 - video/out/vo.c | 16 ++-- video/out/vo.h | 16 ++-- video/out/vo_direct3d.c | 2 +- video/out/vo_drm.c | 1 - video/out/vo_image.c | 12 --- video/out/vo_null.c | 2 +- video/out/vo_opengl.c | 110 ++++++++++-------------- video/out/vo_opengl_cb.c | 10 +-- video/out/vo_rpi.c | 2 +- video/out/vo_sdl.c | 2 +- video/out/vo_vaapi.c | 2 +- video/out/vo_vdpau.c | 2 +- video/out/vo_wayland.c | 2 +- video/out/vo_xv.c | 2 +- 43 files changed, 219 insertions(+), 361 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 6504db556a7df..cf53a934a19e8 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -30,6 +30,10 @@ Interface changes - "audio-channels" (use "audio-params/channel-count") - "audio-format" (use "audio-codec-name") (the properties equivalent to the old semantics are in parentheses) + - remove deprecated --vo and --ao sub-options (like --vo=opengl:...), and + replace them with global options. A somewhat complete list can be found + here: https://github.com/mpv-player/mpv/wiki/Option-replacement-list#mpv-0210 + - remove --vo-defaults and --ao-defaults as well - remove deprecated global sub-options (like -demuxer-rawaudio format=...), use flat options (like --demuxer-rawaudio-format=...) --- mpv 0.22.0 --- diff --git a/DOCS/man/ao.rst b/DOCS/man/ao.rst index 0e45b1e96e8e4..5984abaa1cbd3 100644 --- a/DOCS/man/ao.rst +++ b/DOCS/man/ao.rst @@ -10,11 +10,6 @@ syntax is: If the list has a trailing ',', mpv will fall back on drivers not contained in the list. -``--ao-defaults=`` - Set defaults for each driver. - - Deprecated. No replacement. - .. note:: See ``--ao=help`` for a list of compiled-in audio output drivers. The diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index f695ba0f6f1b5..6ff4b42604708 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -10,11 +10,6 @@ syntax is: If the list has a trailing ``,``, mpv will fall back on drivers not contained in the list. -``--vo-defaults=`` - Set defaults for each driver. - - Deprecated. No replacement. - .. note:: See ``--vo=help`` for a list of compiled-in video output drivers. diff --git a/audio/out/ao.c b/audio/out/ao.c index b624f4196c24f..6cf8de2d88197 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -112,8 +112,8 @@ static bool get_desc(struct m_obj_desc *dst, int index) .priv_size = ao->priv_size, .priv_defaults = ao->priv_defaults, .options = ao->options, + .options_prefix = ao->options_prefix, .global_opts = ao->global_opts, - .legacy_prefix = ao->legacy_prefix, .hidden = ao->encode, .p = ao, }; @@ -127,11 +127,12 @@ const struct m_obj_list ao_obj_list = { .allow_unknown_entries = true, .allow_trailer = true, .disallow_positional_parameters = true, + .use_global_options = true, }; static struct ao *ao_alloc(bool probing, struct mpv_global *global, void (*wakeup_cb)(void *ctx), void *wakeup_ctx, - char *name, char **args) + char *name) { assert(wakeup_cb); @@ -155,12 +156,9 @@ static struct ao *ao_alloc(bool probing, struct mpv_global *global, .def_buffer = opts->audio_buffer, .client_name = talloc_strdup(ao, opts->audio_client_name), }; - struct m_config *config = - m_config_from_obj_desc_and_args(ao, ao->log, global, &desc, - name, opts->ao_defs, args); - if (!config) + ao->priv = m_config_group_from_desc(ao, ao->log, global, &desc, name); + if (!ao->priv) goto error; - ao->priv = config->optstruct; return ao; error: talloc_free(ao); @@ -171,9 +169,9 @@ static struct ao *ao_init(bool probing, struct mpv_global *global, void (*wakeup_cb)(void *ctx), void *wakeup_ctx, struct encode_lavc_context *encode_lavc_ctx, int flags, int samplerate, int format, struct mp_chmap channels, - char *dev, char *name, char **args) + char *dev, char *name) { - struct ao *ao = ao_alloc(probing, global, wakeup_cb, wakeup_ctx, name, args); + struct ao *ao = ao_alloc(probing, global, wakeup_cb, wakeup_ctx, name); if (!ao) return NULL; ao->samplerate = samplerate; @@ -206,7 +204,7 @@ static struct ao *ao_init(bool probing, struct mpv_global *global, talloc_free(ao); return ao_init(probing, global, wakeup_cb, wakeup_ctx, encode_lavc_ctx, flags, samplerate, format, channels, - rdevice, redirect, NULL); + rdevice, redirect); } goto fail; } @@ -313,8 +311,7 @@ struct ao *ao_init_best(struct mpv_global *global, mp_verbose(log, "Using preferred device '%s'\n", dev); } ao = ao_init(probing, global, wakeup_cb, wakeup_ctx, encode_lavc_ctx, - init_flags, samplerate, format, channels, dev, - entry->name, entry->attribs); + init_flags, samplerate, format, channels, dev, entry->name); if (ao) break; if (!probing) @@ -571,7 +568,7 @@ struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp) break; // don't add unsafe/special entries struct ao *ao = ao_alloc(true, hp->global, hp->wakeup_cb, hp->wakeup_ctx, - (char *)d->name, NULL); + (char *)d->name); if (!ao) continue; diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 91c8e2d3fcf3a..d63a760d73aa3 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -1196,15 +1196,5 @@ const struct ao_driver audio_out_alsa = { .wakeup = ao_wakeup_poll, .list_devs = list_devs, .priv_size = sizeof(struct priv), - .options = (const struct m_option[]) { - OPT_SUBOPT_LEGACY("device", "alsa-device"), - OPT_SUBOPT_LEGACY("resample", "alsa-resample"), - OPT_SUBOPT_LEGACY("mixer-device", "alsa-mixer-device"), - OPT_SUBOPT_LEGACY("mixer-name", "alsa-mixer-name"), - OPT_SUBOPT_LEGACY("mixer-index", "alsa-mixer-index"), - OPT_SUBOPT_LEGACY("non-interleaved", "alsa-non-interleaved"), - OPT_SUBOPT_LEGACY("ignore-chmap", "alsa-ignore-chmap"), - {0} - }, .global_opts = &ao_alsa_conf, }; diff --git a/audio/out/ao_audiounit.m b/audio/out/ao_audiounit.m index 7411a1a1dd4ba..31703525a9e7c 100644 --- a/audio/out/ao_audiounit.m +++ b/audio/out/ao_audiounit.m @@ -195,7 +195,4 @@ static int init(struct ao *ao) .pause = stop, .resume = start, .priv_size = sizeof(struct priv), - .options = (const struct m_option[]){ - {0} - }, }; diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c index 3a7aa2eac17ee..ba0dd9b0bad46 100644 --- a/audio/out/ao_coreaudio.c +++ b/audio/out/ao_coreaudio.c @@ -39,7 +39,6 @@ struct priv { AudioStreamID original_asbd_stream; int change_physical_format; - int exclusive; }; static int64_t ca_get_hardware_latency(struct ao *ao) { @@ -143,9 +142,7 @@ static int init(struct ao *ao) { struct priv *p = ao->priv; - p->exclusive |= ao->init_flags & AO_INIT_EXCLUSIVE; - - if (!af_fmt_is_pcm(ao->format) || p->exclusive) { + if (!af_fmt_is_pcm(ao->format) || (ao->init_flags & AO_INIT_EXCLUSIVE)) { MP_VERBOSE(ao, "redirecting to coreaudio_exclusive\n"); ao->redirect = "coreaudio_exclusive"; return CONTROL_ERROR; @@ -429,9 +426,7 @@ const struct ao_driver audio_out_coreaudio = { .priv_size = sizeof(struct priv), .options = (const struct m_option[]){ OPT_FLAG("change-physical-format", change_physical_format, 0), - OPT_FLAG("exclusive", exclusive, 0, - .deprecation_message = "use --audio-exclusive"), {0} }, - .legacy_prefix = "coreaudio", + .options_prefix = "coreaudio", }; diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c index 56c7e28544b26..2ad3cad5865d2 100644 --- a/audio/out/ao_jack.c +++ b/audio/out/ao_jack.c @@ -246,13 +246,5 @@ const struct ao_driver audio_out_jack = { .uninit = uninit, .resume = resume, .priv_size = sizeof(struct priv), - .options = (const struct m_option[]) { - OPT_SUBOPT_LEGACY("port", "jack-port"), - OPT_SUBOPT_LEGACY("name", "jack-name"), - OPT_SUBOPT_LEGACY("autostart", "jack-autostart"), - OPT_SUBOPT_LEGACY("connect", "jack-connect"), - OPT_SUBOPT_LEGACY("std-channel-layout", "jack-std-channel-layout"), - {0} - }, .global_opts = &ao_jack_conf, }; diff --git a/audio/out/ao_null.c b/audio/out/ao_null.c index 7c0c745b12cd4..7b288a8245aac 100644 --- a/audio/out/ao_null.c +++ b/audio/out/ao_null.c @@ -241,5 +241,5 @@ const struct ao_driver audio_out_null = { OPT_CHANNELS("channel-layouts", channel_layouts, 0), {0} }, - .legacy_prefix = "ao-null", + .options_prefix = "ao-null", }; diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c index aba049445d664..a1fd95ab18bfa 100644 --- a/audio/out/ao_openal.c +++ b/audio/out/ao_openal.c @@ -374,5 +374,5 @@ const struct ao_driver audio_out_openal = { DEVICE_OPT_DEPRECATION), {0} }, - .legacy_prefix = "ao-openal", + .options_prefix = "ao-openal", }; diff --git a/audio/out/ao_opensles.c b/audio/out/ao_opensles.c index dd20dbf1d0f31..5357ab49200f6 100644 --- a/audio/out/ao_opensles.c +++ b/audio/out/ao_opensles.c @@ -246,5 +246,5 @@ const struct ao_driver audio_out_opensles = { OPT_INTRANGE("sample-rate", cfg_sample_rate, 0, 1000, 100000), {0} }, - .legacy_prefix = "opensles", + .options_prefix = "opensles", }; diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c index 5bf5fec29b484..c0446eb2aad4b 100644 --- a/audio/out/ao_oss.c +++ b/audio/out/ao_oss.c @@ -653,5 +653,5 @@ const struct ao_driver audio_out_oss = { OPT_STRING("mixer-channel", cfg_oss_mixer_channel, 0), {0} }, - .legacy_prefix = "oss", + .options_prefix = "oss", }; diff --git a/audio/out/ao_pcm.c b/audio/out/ao_pcm.c index 169a1b94a1e7f..4e5ec0a319cd4 100644 --- a/audio/out/ao_pcm.c +++ b/audio/out/ao_pcm.c @@ -224,5 +224,5 @@ const struct ao_driver audio_out_pcm = { OPT_FLAG("append", append, 0), {0} }, - .legacy_prefix = "ao-pcm", + .options_prefix = "ao-pcm", }; diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c index 5a68553e88b18..6c6a517f2a55c 100644 --- a/audio/out/ao_pulse.c +++ b/audio/out/ao_pulse.c @@ -841,5 +841,5 @@ const struct ao_driver audio_out_pulse = { OPT_FLAG("latency-hacks", cfg_latency_hacks, 0), {0} }, - .legacy_prefix = "pulse", + .options_prefix = "pulse", }; diff --git a/audio/out/ao_rsound.c b/audio/out/ao_rsound.c index 5ecb39b9d3b36..9689a9e0b8eef 100644 --- a/audio/out/ao_rsound.c +++ b/audio/out/ao_rsound.c @@ -162,6 +162,6 @@ const struct ao_driver audio_out_rsound = { .deprecation_message = "request --audio-device support on issue tracker"), {0} }, - .legacy_prefix = "rsound", + .options_prefix = "rsound", }; diff --git a/audio/out/ao_sdl.c b/audio/out/ao_sdl.c index d9d00628b6d41..1564e26120082 100644 --- a/audio/out/ao_sdl.c +++ b/audio/out/ao_sdl.c @@ -212,5 +212,5 @@ const struct ao_driver audio_out_sdl = { OPT_FLOAT("buflen", buflen, 0), {0} }, - .legacy_prefix = "sdl", + .options_prefix = "sdl", }; diff --git a/audio/out/ao_sndio.c b/audio/out/ao_sndio.c index f60fa303e585c..e0fd9f0296c53 100644 --- a/audio/out/ao_sndio.c +++ b/audio/out/ao_sndio.c @@ -324,5 +324,5 @@ const struct ao_driver audio_out_sndio = { DEVICE_OPT_DEPRECATION), {0} }, - .legacy_prefix = "ao-sndio", + .options_prefix = "ao-sndio", }; diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c index 17f3e98653ec0..b2e035d3dca25 100644 --- a/audio/out/ao_wasapi.c +++ b/audio/out/ao_wasapi.c @@ -496,11 +496,4 @@ const struct ao_driver audio_out_wasapi = { .hotplug_init = hotplug_init, .hotplug_uninit = hotplug_uninit, .priv_size = sizeof(wasapi_state), - .options = (const struct m_option[]) { - OPT_FLAG("exclusive", opt_exclusive, 0, - .deprecation_message = "use --audio-exclusive"), - OPT_STRING("device", opt_device, 0, DEVICE_OPT_DEPRECATION), - {NULL}, - }, - .legacy_prefix = "ao-wasapi", }; diff --git a/audio/out/ao_wasapi.h b/audio/out/ao_wasapi.h index 6dd130b50ff3d..ea9f5c2badc77 100644 --- a/audio/out/ao_wasapi.h +++ b/audio/out/ao_wasapi.h @@ -92,8 +92,6 @@ typedef struct wasapi_state { // ao options int opt_exclusive; - int opt_list; - char *opt_device; // format info WAVEFORMATEXTENSIBLE format; diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c index 320bb6767be2b..8b12ef4d5c64c 100644 --- a/audio/out/ao_wasapi_utils.c +++ b/audio/out/ao_wasapi_utils.c @@ -858,10 +858,7 @@ static LPWSTR select_device(struct mp_log *l, struct device_desc *d) bstr wasapi_get_specified_device_string(struct ao *ao) { struct wasapi_state *state = ao->priv; - bstr device = bstr_strip(bstr0(state->opt_device)); - if (!device.len) - device = bstr_strip(bstr0(ao->device)); - return device; + return bstr_strip(bstr0(ao->device)); } LPWSTR wasapi_find_deviceID(struct ao *ao) diff --git a/audio/out/internal.h b/audio/out/internal.h index 3ddc1becb9598..b35f20fba2275 100644 --- a/audio/out/internal.h +++ b/audio/out/internal.h @@ -182,8 +182,8 @@ struct ao_driver { int priv_size; const void *priv_defaults; const struct m_option *options; + const char *options_prefix; const struct m_sub_options *global_opts; - const char *legacy_prefix; }; // These functions can be called by AOs. diff --git a/options/m_config.c b/options/m_config.c index dea7a4dd10e11..256e4653e70a2 100644 --- a/options/m_config.c +++ b/options/m_config.c @@ -39,6 +39,7 @@ #include "m_config.h" #include "options/m_option.h" +#include "common/common.h" #include "common/global.h" #include "common/msg.h" #include "common/msg_control.h" @@ -268,6 +269,39 @@ struct m_config *m_config_from_obj_desc_noalloc(void *talloc_ctx, return m_config_new(talloc_ctx, log, 0, desc->priv_defaults, desc->options); } +static struct m_config_group *find_group(struct mpv_global *global, + const struct m_option *cfg) +{ + struct m_config_shadow *shadow = global->config; + struct m_config *root = shadow->root; + + for (int n = 0; n < root->num_groups; n++) { + if (cfg && root->groups[n].group && root->groups[n].group->opts == cfg) + return &root->groups[n]; + } + + return NULL; +} + +// Allocate a priv struct that is backed by global options (like AOs and VOs, +// anything that uses m_obj_list.use_global_options == true). +// The result contains a snapshot of the current option values of desc->options. +// For convenience, desc->options can be NULL; then priv struct is allocated +// with just zero (or priv_defaults if set). +void *m_config_group_from_desc(void *ta_parent, struct mp_log *log, + struct mpv_global *global, struct m_obj_desc *desc, const char *name) +{ + struct m_config_group *group = find_group(global, desc->options); + if (group) { + return mp_get_config_group(ta_parent, global, group->group); + } else { + void *d = talloc_zero_size(ta_parent, desc->priv_size); + if (desc->priv_defaults) + memcpy(d, desc->priv_defaults, desc->priv_size); + return d; + } +} + static struct m_config_option *m_config_find_negation_opt(struct m_config *config, struct bstr *name); @@ -277,40 +311,8 @@ static int m_config_set_obj_params(struct m_config *config, struct mp_log *log, { for (int n = 0; args && args[n * 2 + 0]; n++) { bstr opt = bstr0(args[n * 2 + 0]); - const char *val = args[n * 2 + 1]; - struct m_config_option *co = m_config_get_co(config, opt); - if (!co) { - co = m_config_find_negation_opt(config, &opt); - if (!co) - continue; - - if (val && val[0]) - return -1; // no parameter allowed - - val = "no"; - } - struct m_config *target = config; - bool is_legacy = co->opt->type == &m_option_type_subopt_legacy; - bool force_legacy = !!desc->legacy_prefix; - if (is_legacy || force_legacy) { - // Legacy: redirect deprecated sub-options to global ones. - char tmp[100]; - const char *newopt; - if (is_legacy) { - newopt = co->opt->priv; - } else { - snprintf(tmp, sizeof(tmp), "%s-%.*s", desc->legacy_prefix, - BSTR_P(opt)); - newopt = tmp; - } - assert(global); - target = mp_get_root_config(global); - mp_warn(log, "Using suboptions is deprecated. Use the global '--%s' " - "option instead of '%.*s' suboption.\n", newopt, - BSTR_P(opt)); - opt = bstr0(newopt); - } - if (m_config_set_option(target, opt, bstr0(val)) < 0) + bstr val = bstr0(args[n * 2 + 1]); + if (m_config_set_option(config, opt, val) < 0) return -1; } @@ -334,21 +336,6 @@ struct m_config *m_config_from_obj_desc_and_args(void *ta_parent, if (m_config_set_obj_params(config, log, global, desc, args) < 0) goto error; - if (desc->legacy_prefix) { - assert(global); - struct m_config *root = mp_get_root_config(global); - // In this mode, the AO/VO will still access the options via its priv - // struct (like with real sub-options). We have to copy them over. - for (int n = 0; n < config->num_opts; n++) { - struct m_config_option *co = &config->opts[n]; - char opt[100]; - snprintf(opt, sizeof(opt), "%s-%s", desc->legacy_prefix, co->name); - struct m_config_option *g = m_config_get_co_raw(root, bstr0(opt)); - assert(g); - m_option_copy(co->opt, co->data, g->data); - } - } - return config; error: talloc_free(config); @@ -457,34 +444,83 @@ static void add_sub_options(struct m_config *config, }; struct m_config_option next = { - .name = parent ? parent->name : "", + .name = "", .group = group, }; + if (parent && parent->name && parent->name[0]) + next.name = parent->name; + if (subopts->prefix && subopts->prefix[0]) { + assert(next.name); + next.name = subopts->prefix; + } add_options(config, &next, new_optstruct, new_optstruct_def, subopts->opts); } -static void add_global_subopts(struct m_config *config, - const struct m_obj_list *list) +#define MAX_VO_AO 16 + +struct group_entry { + const struct m_obj_list *entry; + struct m_sub_options subs[MAX_VO_AO]; + bool initialized; +}; + +static struct group_entry g_groups[2]; // limited by max. m_obj_list overall +static int g_num_groups = 0; +static pthread_mutex_t g_group_mutex = PTHREAD_MUTEX_INITIALIZER; + +static const struct m_sub_options *get_cached_group(const struct m_obj_list *list, + int n, struct m_sub_options *v) +{ + pthread_mutex_lock(&g_group_mutex); + + struct group_entry *group = NULL; + for (int i = 0; i < g_num_groups; i++) { + if (g_groups[i].entry == list) { + group = &g_groups[i]; + break; + } + } + if (!group) { + assert(g_num_groups < MP_ARRAY_SIZE(g_groups)); + group = &g_groups[g_num_groups++]; + group->entry = list; + } + + if (!group->initialized) { + if (!v) { + n = -1; + group->initialized = true; + } else { + assert(n < MAX_VO_AO); // simply increase this if it fails + group->subs[n] = *v; + } + } + + pthread_mutex_unlock(&g_group_mutex); + + return n >= 0 ? &group->subs[n] : NULL; +} + +static void init_obj_settings_list(struct m_config *config, + const struct m_obj_list *list) { struct m_obj_desc desc; for (int n = 0; ; n++) { - if (!list->get_desc(&desc, n)) + if (!list->get_desc(&desc, n)) { + if (list->use_global_options) + get_cached_group(list, n, NULL); break; + } if (desc.global_opts) add_sub_options(config, NULL, desc.global_opts); - if (desc.legacy_prefix && desc.options) { - // Legacy: auto-add sub-options as global options (using the prefix). - struct m_config_option parent = { - .name = desc.legacy_prefix, - .group = 0, - }; - struct m_sub_options *conf = talloc(config, struct m_sub_options); - *conf = (struct m_sub_options){ + if (list->use_global_options && desc.options) { + struct m_sub_options conf = { + .prefix = desc.options_prefix, .opts = desc.options, .defaults = desc.priv_defaults, .size = desc.priv_size, }; - add_sub_options(config, &parent, conf); + add_sub_options(config, NULL, get_cached_group(list, n, &conf)); } } } @@ -560,9 +596,8 @@ static void m_config_add_option(struct m_config *config, init_opt_inplace(arg, co.data, co.default_data); } - // (The deprecation_message check is a hack to exclude --vo-defaults etc.) - if (arg->type == &m_option_type_obj_settings_list && !arg->deprecation_message) - add_global_subopts(config, (const struct m_obj_list *)arg->priv); + if (arg->type == &m_option_type_obj_settings_list) + init_obj_settings_list(config, (const struct m_obj_list *)arg->priv); if (arg->name[0]) // no own name -> hidden MP_TARRAY_APPEND(config, config->opts, config->num_opts, co); diff --git a/options/m_config.h b/options/m_config.h index 16eba317f0a0f..1e199cacd9651 100644 --- a/options/m_config.h +++ b/options/m_config.h @@ -134,6 +134,9 @@ struct m_config *m_config_from_obj_desc_and_args(void *ta_parent, struct mp_log *log, struct mpv_global *global, struct m_obj_desc *desc, const char *name, struct m_obj_settings *defaults, char **args); +void *m_config_group_from_desc(void *ta_parent, struct mp_log *log, + struct mpv_global *global, struct m_obj_desc *desc, const char *name); + // Make sure the option is backed up. If it's already backed up, do nothing. // All backed up options can be restored with m_config_restore_backups(). void m_config_backup_opt(struct m_config *config, const char *opt); diff --git a/options/m_option.c b/options/m_option.c index 4ef5481ceb219..6baa87c16349f 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -2719,7 +2719,8 @@ static int get_obj_param(struct mp_log *log, bstr opt_name, bstr obj_name, static int m_obj_parse_sub_config(struct mp_log *log, struct bstr opt_name, struct bstr name, struct bstr *pstr, struct m_config *config, int flags, bool nopos, - struct m_obj_desc *desc, char ***ret) + struct m_obj_desc *desc, + const struct m_obj_list *list, char ***ret) { int nold = 0; char **args = NULL; @@ -2737,6 +2738,16 @@ static int m_obj_parse_sub_config(struct mp_log *log, struct bstr opt_name, r = split_subconf(log, opt_name, pstr, &fname, &fval); if (r < 0) goto exit; + + if (list->use_global_options) { + mp_err(log, "Option %.*s: this option does not accept sub-options.\n", + BSTR_P(opt_name)); + mp_err(log, "Sub-options for --vo and --ao were removed from mpv in " + "release 0.23.0.\nSee https://0x0.st/uM for details.\n"); + r = M_OPT_INVALID; + goto exit; + } + if (bstr_equals0(fname, "help")) goto print_help; r = get_obj_param(log, opt_name, name, config, fname, fval, flags, @@ -2831,7 +2842,7 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt, struct m_config *config = m_config_from_obj_desc_noalloc(NULL, log, &desc); bstr s = bstr0(desc.init_options); m_obj_parse_sub_config(log, opt, str, &s, config, - M_SETOPT_CHECK_ONLY, nopos, NULL, &plist); + M_SETOPT_CHECK_ONLY, nopos, NULL, list, &plist); assert(s.len == 0); talloc_free(config); } @@ -2841,7 +2852,7 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt, if (!skip) config = m_config_from_obj_desc_noalloc(NULL, log, &desc); r = m_obj_parse_sub_config(log, opt, str, pstr, config, - M_SETOPT_CHECK_ONLY, nopos, &desc, + M_SETOPT_CHECK_ONLY, nopos, &desc, list, _ret ? &plist : NULL); talloc_free(config); if (r < 0) diff --git a/options/m_option.h b/options/m_option.h index d784d8f54d20e..8faaad21339a7 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -117,6 +117,8 @@ struct m_obj_desc { const void *priv_defaults; // Options which refer to members in the private struct const struct m_option *options; + // Prefix for each of the above options (none if NULL). + const char *options_prefix; // For free use by the implementer of m_obj_list.get_desc const void *p; // If not NULL, options which should be set before applying other options. @@ -132,10 +134,6 @@ struct m_obj_desc { const char *replaced_name; // For convenience: these are added as global command-line options. const struct m_sub_options *global_opts; - // Evil hack to essentially force-move .options to global_opts. All options - // will be added as global options with the given prefix, and using - // sub-options will be treated as deprecated and redirected. - const char *legacy_prefix; }; // Extra definition needed for \ref m_option_type_obj_settings_list options. @@ -151,6 +149,8 @@ struct m_obj_list { bool allow_unknown_entries; // This helps with confusing error messages if unknown flag options are used. bool disallow_positional_parameters; + // Each sub-item is backed by global options (for AOs and VOs). + bool use_global_options; }; // Find entry by name @@ -188,6 +188,7 @@ typedef int (*m_opt_string_validate_fn)(struct mp_log *log, const m_option_t *op // m_option.priv points to this if OPT_SUBSTRUCT is used struct m_sub_options { + const char *prefix; const struct m_option *opts; size_t size; const void *defaults; @@ -714,12 +715,6 @@ extern const char m_option_path_separator; .type = &m_option_type_subconfig, \ .priv = (void*)&subconf) -// Same as above, but for legacy suboption usage, which have no associated -// field (no actual data anywhere). -#define OPT_SUBSTRUCT_LEGACY(optname, subconf) \ - {.name = optname, .offset = -1, .type = &m_option_type_subconfig, \ - .priv = (void*)&subconf} - // Provide a another name for the option. #define OPT_ALIAS(optname, newname) \ {.name = optname, .type = &m_option_type_alias, .priv = newname, \ diff --git a/options/options.c b/options/options.c index 442c29297afe9..c57847bc284cd 100644 --- a/options/options.c +++ b/options/options.c @@ -150,8 +150,6 @@ const struct m_sub_options stream_cache_conf = { static const m_option_t mp_vo_opt_list[] = { OPT_SETTINGSLIST("vo", video_driver_list, 0, &vo_obj_list, ), - OPT_SETTINGSLIST("vo-defaults", vo_defs, 0, &vo_obj_list, - .deprecation_message = "deprecated, use global options"), OPT_CHOICE_C("hwdec-preload", hwdec_preload_api, 0, mp_hwdec_names), OPT_SUBSTRUCT("sws", sws_opts, sws_conf, 0), OPT_FLAG("taskbar-progress", taskbar_progress, 0), @@ -510,8 +508,6 @@ const m_option_t mp_opts[] = { //---------------------- libao/libvo options ------------------------ OPT_SETTINGSLIST("ao", audio_driver_list, 0, &ao_obj_list, ), - OPT_SETTINGSLIST("ao-defaults", ao_defs, 0, &ao_obj_list, - .deprecation_message = "deprecated, use global options"), OPT_STRING("audio-device", audio_device, UPDATE_AUDIO), OPT_FLAG("audio-exclusive", audio_exclusive, UPDATE_AUDIO), OPT_STRING("audio-client-name", audio_client_name, UPDATE_AUDIO), diff --git a/options/options.h b/options/options.h index 4ddf9d14905ad..fa2a96c3b2654 100644 --- a/options/options.h +++ b/options/options.h @@ -7,7 +7,7 @@ #include "common/common.h" typedef struct mp_vo_opts { - struct m_obj_settings *video_driver_list, *vo_defs; + struct m_obj_settings *video_driver_list; int taskbar_progress; int ontop; @@ -90,7 +90,7 @@ typedef struct MPOpts { int auto_load_scripts; - struct m_obj_settings *audio_driver_list, *ao_defs; + struct m_obj_settings *audio_driver_list; char *audio_device; int audio_exclusive; char *audio_client_name; diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 498d89259e391..3bd67c29fe102 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -428,95 +428,6 @@ const struct m_sub_options gl_video_conf = { .change_flags = UPDATE_RENDERER, }; -#define LEGACY_SCALER_OPTS(n) \ - OPT_SUBOPT_LEGACY(n, n), \ - OPT_SUBOPT_LEGACY(n"-param1", n"-param1"), \ - OPT_SUBOPT_LEGACY(n"-param2", n"-param2"), \ - OPT_SUBOPT_LEGACY(n"-blur", n"-blur"), \ - OPT_SUBOPT_LEGACY(n"-wparam", n"-wparam"), \ - OPT_SUBOPT_LEGACY(n"-clamp", n"-clamp"), \ - OPT_SUBOPT_LEGACY(n"-radius", n"-radius"), \ - OPT_SUBOPT_LEGACY(n"-antiring", n"-antiring"), \ - OPT_SUBOPT_LEGACY(n"-window", n"-window") - -const struct m_sub_options gl_video_conf_legacy = { - .opts = (const m_option_t[]) { - OPT_SUBOPT_LEGACY("dumb-mode", "opengl-dumb-mode"), - OPT_SUBOPT_LEGACY("gamma", "opengl-gamma"), - OPT_SUBOPT_LEGACY("gamma-auto", "gamma-auto"), - OPT_SUBOPT_LEGACY("target-prim", "target-prim"), - OPT_SUBOPT_LEGACY("target-trc", "target-trc"), - OPT_SUBOPT_LEGACY("target-brightness", "target-brightness"), - OPT_SUBOPT_LEGACY("hdr-tone-mapping", "hdr-tone-mapping"), - OPT_SUBOPT_LEGACY("tone-mapping-param", "tone-mapping-param"), - OPT_SUBOPT_LEGACY("pbo", "opengl-pbo"), - LEGACY_SCALER_OPTS("scale"), - LEGACY_SCALER_OPTS("dscale"), - LEGACY_SCALER_OPTS("cscale"), - LEGACY_SCALER_OPTS("tscale"), - OPT_SUBOPT_LEGACY("scaler-lut-size", "scaler-lut-size"), - OPT_SUBOPT_LEGACY("scaler-resizes-only", "scaler-resizes-only"), - OPT_SUBOPT_LEGACY("linear-scaling", "linear-scaling"), - OPT_SUBOPT_LEGACY("correct-downscaling", "correct-downscaling"), - OPT_SUBOPT_LEGACY("sigmoid-upscaling", "sigmoid-upscaling"), - OPT_SUBOPT_LEGACY("sigmoid-center", "sigmoid-center"), - OPT_SUBOPT_LEGACY("sigmoid-slope", "sigmoid-slope"), - OPT_SUBOPT_LEGACY("fbo-format", "opengl-fbo-format"), - OPT_SUBOPT_LEGACY("dither-depth", "dither-depth"), - OPT_SUBOPT_LEGACY("dither", "dither"), - OPT_SUBOPT_LEGACY("dither-size-fruit", "dither-size-fruit"), - OPT_SUBOPT_LEGACY("temporal-dither", "temporal-dither"), - OPT_SUBOPT_LEGACY("temporal-dither-period", "temporal-dither-period"), - OPT_SUBOPT_LEGACY("alpha", "alpha"), - OPT_SUBOPT_LEGACY("rectangle-textures", "opengl-rectangle-textures"), - OPT_SUBOPT_LEGACY("background", "background"), - OPT_SUBOPT_LEGACY("interpolation", "interpolation"), - OPT_SUBOPT_LEGACY("interpolation-threshold", "interpolation-threshold"), - OPT_SUBOPT_LEGACY("blend-subtitles", "blend-subtitles"), - OPT_SUBOPT_LEGACY("user-shaders", "opengl-shaders"), - OPT_SUBOPT_LEGACY("deband", "deband"), - OPT_SUBOPT_LEGACY("deband-iterations", "deband-iterations"), - OPT_SUBOPT_LEGACY("deband-threshold", "deband-threshold"), - OPT_SUBOPT_LEGACY("deband-range", "deband-range"), - OPT_SUBOPT_LEGACY("deband-grain", "deband-grain"), - OPT_SUBOPT_LEGACY("sharpen", "sharpen"), - OPT_SUBOPT_LEGACY("icc-profile", "icc-profile"), - OPT_SUBOPT_LEGACY("icc-profile-auto", "icc-profile-auto"), - OPT_SUBOPT_LEGACY("icc-cache-dir", "icc-cache-dir"), - OPT_SUBOPT_LEGACY("icc-intent", "icc-intent"), - OPT_SUBOPT_LEGACY("icc-contrast", "icc-contrast"), - OPT_SUBOPT_LEGACY("3dlut-size", "icc-3dlut-size"), - - OPT_REMOVED("approx-gamma", "this is always enabled now"), - OPT_REMOVED("cscale-down", "chroma is never downscaled"), - OPT_REMOVED("scale-sep", "this is set automatically whenever sane"), - OPT_REMOVED("indirect", "this is set automatically whenever sane"), - OPT_REMOVED("srgb", "use target-prim=bt709:target-trc=srgb instead"), - OPT_REMOVED("source-shader", "use :deband to enable debanding"), - OPT_REMOVED("prescale-luma", "use opengl-shaders for prescaling"), - OPT_REMOVED("scale-shader", "use opengl-shaders instead"), - OPT_REMOVED("pre-shaders", "use opengl-shaders instead"), - OPT_REMOVED("post-shaders", "use opengl-shaders instead"), - - OPT_SUBOPT_LEGACY("lscale", "scale"), - OPT_SUBOPT_LEGACY("lscale-down", "scale-down"), - OPT_SUBOPT_LEGACY("lparam1", "scale-param1"), - OPT_SUBOPT_LEGACY("lparam2", "scale-param2"), - OPT_SUBOPT_LEGACY("lradius", "scale-radius"), - OPT_SUBOPT_LEGACY("lantiring", "scale-antiring"), - OPT_SUBOPT_LEGACY("cparam1", "cscale-param1"), - OPT_SUBOPT_LEGACY("cparam2", "cscale-param2"), - OPT_SUBOPT_LEGACY("cradius", "cscale-radius"), - OPT_SUBOPT_LEGACY("cantiring", "cscale-antiring"), - OPT_SUBOPT_LEGACY("smoothmotion", "interpolation"), - OPT_SUBOPT_LEGACY("smoothmotion-threshold", "tscale-param1"), - OPT_SUBOPT_LEGACY("scale-down", "dscale"), - OPT_SUBOPT_LEGACY("fancy-downscaling", "correct-downscaling"), - - {0} - }, -}; - static void uninit_rendering(struct gl_video *p); static void uninit_scaler(struct gl_video *p, struct scaler *scaler); static void check_gl_features(struct gl_video *p); diff --git a/video/out/opengl/video.h b/video/out/opengl/video.h index 54b7022f2773d..3b5f452bf4257 100644 --- a/video/out/opengl/video.h +++ b/video/out/opengl/video.h @@ -137,7 +137,6 @@ struct gl_video_opts { }; extern const struct m_sub_options gl_video_conf; -extern const struct m_sub_options gl_video_conf_legacy; struct gl_video; struct vo_frame; diff --git a/video/out/vo.c b/video/out/vo.c index cbd2ca87c80b1..72a47af227d64 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -176,8 +176,8 @@ static bool get_desc(struct m_obj_desc *dst, int index) .priv_size = vo->priv_size, .priv_defaults = vo->priv_defaults, .options = vo->options, + .options_prefix = vo->options_prefix, .global_opts = vo->global_opts, - .legacy_prefix = vo->legacy_prefix, .hidden = vo->encode || !strcmp(vo->name, "opengl-cb"), .p = vo, }; @@ -196,6 +196,7 @@ const struct m_obj_list vo_obj_list = { .allow_unknown_entries = true, .allow_trailer = true, .disallow_positional_parameters = true, + .use_global_options = true, }; static void dispatch_wakeup_cb(void *ptr) @@ -214,7 +215,7 @@ static void dealloc_vo(struct vo *vo) } static struct vo *vo_create(bool probing, struct mpv_global *global, - struct vo_extra *ex, char *name, char **args) + struct vo_extra *ex, char *name) { assert(ex->wakeup_cb); @@ -254,11 +255,9 @@ static struct vo *vo_create(bool probing, struct mpv_global *global, mp_input_set_mouse_transform(vo->input_ctx, NULL, NULL); if (vo->driver->encode != !!vo->encode_lavc_ctx) goto error; - vo->config = m_config_from_obj_desc_and_args(vo, vo->log, global, &desc, - name, vo->opts->vo_defs, args); - if (!vo->config) + vo->priv = m_config_group_from_desc(vo, vo->log, global, &desc, name); + if (!vo->priv) goto error; - vo->priv = vo->config->optstruct; if (pthread_create(&vo->in->thread, NULL, vo_thread, vo)) goto error; @@ -283,8 +282,7 @@ struct vo *init_best_video_out(struct mpv_global *global, struct vo_extra *ex) if (strlen(vo_list[n].name) == 0) goto autoprobe; bool p = !!vo_list[n + 1].name; - struct vo *vo = vo_create(p, global, ex, vo_list[n].name, - vo_list[n].attribs); + struct vo *vo = vo_create(p, global, ex, vo_list[n].name); if (vo) return vo; } @@ -296,7 +294,7 @@ struct vo *init_best_video_out(struct mpv_global *global, struct vo_extra *ex) const struct vo_driver *driver = video_out_drivers[i]; if (driver == &video_out_null) break; - struct vo *vo = vo_create(true, global, ex, (char *)driver->name, NULL); + struct vo *vo = vo_create(true, global, ex, (char *)driver->name); if (vo) return vo; } diff --git a/video/out/vo.h b/video/out/vo.h index 99e6ccabae0e0..724e03ca41318 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -312,17 +312,16 @@ struct vo_driver { const void *priv_defaults; // List of options to parse into priv struct (requires priv_size to be set) - // Deprecated. Use global options or global_opts instead. + // This will register them as global options (with options_prefix), and + // copy the current value at VO creation time to the priv struct. const struct m_option *options; - // Global options to register if the VO is compiled in. - // mp_get_config_group() or other function can be used to access them. - const struct m_sub_options *global_opts; + // All options in the above array are prefixed with this string. (It's just + // for convenience and makes no difference in semantics.) + const char *options_prefix; - // Evil hack: add .options as global options, using the provided prefix. - // For further evilness, the options will be copied to the priv struct - // like with normal .options behavior. - const char *legacy_prefix; + // Registers global options that go to a separate options struct. + const struct m_sub_options *global_opts; }; struct vo { @@ -356,7 +355,6 @@ struct vo { struct m_config_cache *opts_cache; // cache for ->opts struct mp_vo_opts *opts; - struct m_config *config; // config for ->priv bool want_redraw; // redraw as soon as possible diff --git a/video/out/vo_direct3d.c b/video/out/vo_direct3d.c index c99ea372f6274..63de6fee4a645 100644 --- a/video/out/vo_direct3d.c +++ b/video/out/vo_direct3d.c @@ -1747,5 +1747,5 @@ const struct vo_driver video_out_direct3d = { .priv_size = sizeof(d3d_priv), .priv_defaults = &defaults, .options = opts, - .legacy_prefix = "vo-direct3d", + .options_prefix = "vo-direct3d", }; diff --git a/video/out/vo_drm.c b/video/out/vo_drm.c index 7e642e391cbc8..92357587c5d5e 100644 --- a/video/out/vo_drm.c +++ b/video/out/vo_drm.c @@ -490,5 +490,4 @@ const struct vo_driver video_out_drm = { .wait_events = wait_events, .wakeup = wakeup, .priv_size = sizeof(struct priv), - .legacy_prefix = "drm", }; diff --git a/video/out/vo_image.c b/video/out/vo_image.c index f799a97fe9a36..e1bc1aab201f1 100644 --- a/video/out/vo_image.c +++ b/video/out/vo_image.c @@ -160,18 +160,6 @@ const struct vo_driver video_out_image = .name = "image", .untimed = true, .priv_size = sizeof(struct priv), - .options = (const struct m_option[]) { - OPT_SUBOPT_LEGACY("jpeg-quality", "vo-image-jpeg-quality"), - OPT_SUBOPT_LEGACY("jpeg-smooth", "vo-image-jpeg-smooth"), - OPT_SUBOPT_LEGACY("jpeg-source-chroma", "vo-image-jpeg-source-chroma"), - OPT_SUBOPT_LEGACY("png-compression", "vo-image-png-compression"), - OPT_SUBOPT_LEGACY("png-filter", "vo-image-png-filter"), - OPT_SUBOPT_LEGACY("format", "vo-image-format"), - OPT_SUBOPT_LEGACY("high-bit-depth", "vo-image-high-bit-depth"), - OPT_SUBOPT_LEGACY("tag-colorspace", "vo-image-tag-colorspace"), - OPT_SUBOPT_LEGACY("outdir", "vo-image-outdir"), - {0}, - }, .preinit = preinit, .query_format = query_format, .reconfig = reconfig, diff --git a/video/out/vo_null.c b/video/out/vo_null.c index 39c1bf63611d8..fcf8dc9051bfa 100644 --- a/video/out/vo_null.c +++ b/video/out/vo_null.c @@ -101,5 +101,5 @@ const struct vo_driver video_out_null = { OPT_DOUBLE("fps", cfg_fps, M_OPT_RANGE, .min = 0, .max = 10000), {0}, }, - .legacy_prefix = "vo-null", + .options_prefix = "vo-null", }; diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c index 2517ba741277e..508ba9cda937b 100644 --- a/video/out/vo_opengl.c +++ b/video/out/vo_opengl.c @@ -62,40 +62,13 @@ struct vo_opengl_opts { int pattern[2]; }; -#define OPT_BASE_STRUCT struct vo_opengl_opts -static const struct m_sub_options vo_opengl_conf = { - .opts = (const m_option_t[]) { - OPT_FLAG("opengl-glfinish", use_glFinish, 0), - OPT_FLAG("opengl-waitvsync", waitvsync, 0), - OPT_INT("opengl-swapinterval", swap_interval, 0), - OPT_CHOICE("opengl-dwmflush", dwm_flush, 0, - ({"no", -1}, {"auto", 0}, {"windowed", 1}, {"yes", 2})), - OPT_FLAG("opengl-dcomposition", allow_direct_composition, 0), - OPT_FLAG("opengl-debug", use_gl_debug, 0), - OPT_STRING_VALIDATE("opengl-backend", backend, 0, - mpgl_validate_backend_opt), - OPT_FLAG("opengl-sw", allow_sw, 0), - OPT_CHOICE("opengl-es", es, 0, ({"no", -1}, {"auto", 0}, {"yes", 1})), - OPT_INTPAIR("opengl-check-pattern", pattern, 0), - OPT_INTRANGE("opengl-vsync-fences", vsync_fences, 0, - 0, NUM_VSYNC_FENCES), - - {0} - }, - .defaults = &(const struct vo_opengl_opts){ - .swap_interval = 1, - .allow_direct_composition = 1, - }, - .size = sizeof(struct vo_opengl_opts), -}; - struct gl_priv { struct vo *vo; struct mp_log *log; MPGLContext *glctx; GL *gl; - struct vo_opengl_opts *opts; + struct vo_opengl_opts opts; struct gl_video *renderer; @@ -133,7 +106,7 @@ static void resize(struct gl_priv *p) static void check_pattern(struct vo *vo, int item) { struct gl_priv *p = vo->priv; - int expected = p->opts->pattern[p->last_pattern]; + int expected = p->opts.pattern[p->last_pattern]; if (item == expected) { p->last_pattern++; if (p->last_pattern >= 2) @@ -151,7 +124,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) struct gl_priv *p = vo->priv; GL *gl = p->gl; - if (gl->FenceSync && p->num_vsync_fences < p->opts->vsync_fences) { + if (gl->FenceSync && p->num_vsync_fences < p->opts.vsync_fences) { GLsync fence = gl->FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);; if (fence) p->vsync_fences[p->num_vsync_fences++] = fence; @@ -159,7 +132,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) gl_video_render_frame(p->renderer, frame, gl->main_fb); - if (p->opts->use_glFinish) + if (p->opts.use_glFinish) gl->Finish(); } @@ -171,30 +144,30 @@ static void flip_page(struct vo *vo) mpgl_swap_buffers(p->glctx); p->frames_rendered++; - if (p->frames_rendered > 5 && !p->opts->use_gl_debug) + if (p->frames_rendered > 5 && !p->opts.use_gl_debug) gl_video_set_debug(p->renderer, false); - if (p->opts->use_glFinish) + if (p->opts.use_glFinish) gl->Finish(); - if (p->opts->waitvsync || p->opts->pattern[0]) { + if (p->opts.waitvsync || p->opts.pattern[0]) { if (gl->GetVideoSync) { unsigned int n1 = 0, n2 = 0; gl->GetVideoSync(&n1); - if (p->opts->waitvsync) + if (p->opts.waitvsync) gl->WaitVideoSync(2, (n1 + 1) % 2, &n2); int step = n1 - p->prev_sgi_sync_count; p->prev_sgi_sync_count = n1; MP_DBG(vo, "Flip counts: %u->%u, step=%d\n", n1, n2, step); - if (p->opts->pattern[0]) + if (p->opts.pattern[0]) check_pattern(vo, step); } else { MP_WARN(vo, "GLX_SGI_video_sync not available, disabling.\n"); - p->opts->waitvsync = 0; - p->opts->pattern[0] = 0; + p->opts.waitvsync = 0; + p->opts.pattern[0] = 0; } } - while (p->opts->vsync_fences > 0 && p->num_vsync_fences >= p->opts->vsync_fences) { + while (p->opts.vsync_fences > 0 && p->num_vsync_fences >= p->opts.vsync_fences) { gl->ClientWaitSync(p->vsync_fences[0], GL_SYNC_FLUSH_COMMANDS_BIT, 1e9); gl->DeleteSync(p->vsync_fences[0]); MP_TARRAY_REMOVE_AT(p->vsync_fences, p->num_vsync_fences, 0); @@ -389,7 +362,6 @@ static int preinit(struct vo *vo) struct gl_priv *p = vo->priv; p->vo = vo; p->log = vo->log; - p->opts = mp_get_config_group(vo, vo->global, &vo_opengl_conf); int vo_flags = 0; @@ -399,29 +371,29 @@ static int preinit(struct vo *vo) if (alpha_mode == 1) vo_flags |= VOFLAG_ALPHA; - if (p->opts->use_gl_debug) + if (p->opts.use_gl_debug) vo_flags |= VOFLAG_GL_DEBUG; - if (p->opts->es == 1) + if (p->opts.es == 1) vo_flags |= VOFLAG_GLES; - if (p->opts->es == -1) + if (p->opts.es == -1) vo_flags |= VOFLAG_NO_GLES; - if (p->opts->allow_sw) + if (p->opts.allow_sw) vo_flags |= VOFLAG_SW; - if (p->opts->allow_direct_composition) + if (p->opts.allow_direct_composition) vo_flags |= VOFLAG_ANGLE_DCOMP; - p->glctx = mpgl_init(vo, p->opts->backend, vo_flags); + p->glctx = mpgl_init(vo, p->opts.backend, vo_flags); if (!p->glctx) goto err_out; p->gl = p->glctx->gl; - p->glctx->dwm_flush_opt = p->opts->dwm_flush; + p->glctx->dwm_flush_opt = p->opts.dwm_flush; if (p->gl->SwapInterval) { - p->gl->SwapInterval(p->opts->swap_interval); + p->gl->SwapInterval(p->opts.swap_interval); } else { MP_VERBOSE(vo, "swap_control extension missing.\n"); } @@ -454,21 +426,7 @@ static int preinit(struct vo *vo) return -1; } -static const struct m_option legacy_options[] = { - OPT_SUBOPT_LEGACY("glfinish", "opengl-glfinish"), - OPT_SUBOPT_LEGACY("waitvsync", "opengl-waitvsync"), - OPT_SUBOPT_LEGACY("swapinterval", "opengl-swapinterval"), - OPT_SUBOPT_LEGACY("dwmflush", "opengl-dwmflush"), - OPT_SUBOPT_LEGACY("dcomposition", "opengl-dcomposition"), - OPT_SUBOPT_LEGACY("debug", "opengl-debug"), - OPT_SUBOPT_LEGACY("backend", "opengl-backend"), - OPT_SUBOPT_LEGACY("sw", "opengl-sw"), - OPT_SUBOPT_LEGACY("es", "opengl-es"), - OPT_SUBOPT_LEGACY("check-pattern", "opengl-check-pattern"), - OPT_SUBOPT_LEGACY("vsync-fences", "opengl-vsync-fences"), - OPT_SUBSTRUCT_LEGACY("", gl_video_conf_legacy), - {0}, -}; +#define OPT_BASE_STRUCT struct gl_priv const struct vo_driver video_out_opengl = { .description = "Extended OpenGL Renderer", @@ -484,6 +442,28 @@ const struct vo_driver video_out_opengl = { .wakeup = wakeup, .uninit = uninit, .priv_size = sizeof(struct gl_priv), - .options = legacy_options, - .global_opts = &vo_opengl_conf, + .options = (const m_option_t[]) { + OPT_FLAG("opengl-glfinish", opts.use_glFinish, 0), + OPT_FLAG("opengl-waitvsync", opts.waitvsync, 0), + OPT_INT("opengl-swapinterval", opts.swap_interval, 0), + OPT_CHOICE("opengl-dwmflush", opts.dwm_flush, 0, + ({"no", -1}, {"auto", 0}, {"windowed", 1}, {"yes", 2})), + OPT_FLAG("opengl-dcomposition", opts.allow_direct_composition, 0), + OPT_FLAG("opengl-debug", opts.use_gl_debug, 0), + OPT_STRING_VALIDATE("opengl-backend", opts.backend, 0, + mpgl_validate_backend_opt), + OPT_FLAG("opengl-sw", opts.allow_sw, 0), + OPT_CHOICE("opengl-es", opts.es, 0, ({"no", -1}, {"auto", 0}, {"yes", 1})), + OPT_INTPAIR("opengl-check-pattern", opts.pattern, 0), + OPT_INTRANGE("opengl-vsync-fences", opts.vsync_fences, 0, + 0, NUM_VSYNC_FENCES), + + {0} + }, + .priv_defaults = &(const struct gl_priv){ + .opts = { + .swap_interval = 1, + .allow_direct_composition = 1, + }, + }, }; diff --git a/video/out/vo_opengl_cb.c b/video/out/vo_opengl_cb.c index c66f6d434c386..85e06ff598ba1 100644 --- a/video/out/vo_opengl_cb.c +++ b/video/out/vo_opengl_cb.c @@ -144,7 +144,7 @@ static void copy_vo_opts(struct vo *vo) // copy the struct with an assignment. // Just remove all the dynamic data to avoid confusion. struct mp_vo_opts opts = *vo->opts; - opts.video_driver_list = opts.vo_defs = NULL; + opts.video_driver_list = NULL; opts.winname = NULL; opts.sws_opts = NULL; p->ctx->vo_opts = opts; @@ -529,13 +529,6 @@ static int preinit(struct vo *vo) return 0; } -#define OPT_BASE_STRUCT struct vo_priv -static const struct m_option options[] = { - OPT_SUBOPT_LEGACY("debug", "opengl-debug"), - OPT_SUBSTRUCT_LEGACY("", gl_video_conf_legacy), - {0}, -}; - const struct vo_driver video_out_opengl_cb = { .description = "OpenGL Callbacks for libmpv", .name = "opengl-cb", @@ -548,5 +541,4 @@ const struct vo_driver video_out_opengl_cb = { .flip_page = flip_page, .uninit = uninit, .priv_size = sizeof(struct vo_priv), - .options = options, }; diff --git a/video/out/vo_rpi.c b/video/out/vo_rpi.c index acec865c6bd7f..4824ac2616f20 100644 --- a/video/out/vo_rpi.c +++ b/video/out/vo_rpi.c @@ -933,5 +933,5 @@ const struct vo_driver video_out_rpi = { .uninit = uninit, .priv_size = sizeof(struct priv), .options = options, - .legacy_prefix = "rpi", + .options_prefix = "rpi", }; diff --git a/video/out/vo_sdl.c b/video/out/vo_sdl.c index 76f336ffebe09..e32e89aaf3ec6 100644 --- a/video/out/vo_sdl.c +++ b/video/out/vo_sdl.c @@ -1032,5 +1032,5 @@ const struct vo_driver video_out_sdl = { .flip_page = flip_page, .wait_events = wait_events, .wakeup = wakeup, - .legacy_prefix = "sdl", + .options_prefix = "sdl", }; diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c index 0b741850b0156..4aa1ef37df8bb 100644 --- a/video/out/vo_vaapi.c +++ b/video/out/vo_vaapi.c @@ -696,5 +696,5 @@ const struct vo_driver video_out_vaapi = { OPT_FLAG("scaled-osd", force_scaled_osd, 0), {0} }, - .legacy_prefix = "vo-vaapi", + .options_prefix = "vo-vaapi", }; diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c index 757c31e32f555..eb89301e94d5c 100644 --- a/video/out/vo_vdpau.c +++ b/video/out/vo_vdpau.c @@ -1164,5 +1164,5 @@ const struct vo_driver video_out_vdpau = { OPT_REPLACED("output_surfaces", "output-surfaces"), {NULL}, }, - .legacy_prefix = "vo-vdpau", + .options_prefix = "vo-vdpau", }; diff --git a/video/out/vo_wayland.c b/video/out/vo_wayland.c index 6a7b18a6c52c2..37ab4c7858401 100644 --- a/video/out/vo_wayland.c +++ b/video/out/vo_wayland.c @@ -677,6 +677,6 @@ const struct vo_driver video_out_wayland = { OPT_FLAG("rgb565", use_rgb565, 0), {0} }, - .legacy_prefix = "vo-wayland", + .options_prefix = "vo-wayland", }; diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c index 1cc5b0197b3ee..cbc64433ee91d 100644 --- a/video/out/vo_xv.c +++ b/video/out/vo_xv.c @@ -933,5 +933,5 @@ const struct vo_driver video_out_xv = { OPT_REMOVED("no-colorkey", "use ck-method=none instead"), {0} }, - .legacy_prefix = "xv", + .options_prefix = "xv", }; From 89837523b5d18ad0f923a937ec11527c58f558cd Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sun, 27 Nov 2016 02:01:14 +0000 Subject: [PATCH 29/83] wayland: destroy input before closing the display connection. Fixes a segfault introduced in libwayland e8ad23266f36521215dcd7cfcc524e0ef67d66dd, where a poison value has been introduced to catch this kind of use-after-free bug. --- video/out/wayland_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index 480f29638b238..a41fb6680a545 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -946,8 +946,8 @@ void vo_wayland_uninit(struct vo *vo) struct vo_wayland_state *wl = vo->wayland; destroy_cursor(wl); destroy_window(wl); - destroy_display(wl); destroy_input(wl); + destroy_display(wl); for (int n = 0; n < 2; n++) close(wl->wakeup_pipe[n]); talloc_free(wl); From 3203d6003c8e308b2ba4e277a64e717696b1b8b7 Mon Sep 17 00:00:00 2001 From: pavelxdd Date: Sun, 27 Nov 2016 07:31:33 +0300 Subject: [PATCH 30/83] ao_wasapi_utils: remove unused variable Introduced in 1a2319f3e4cc42c680e2fd3ba30022c7a9adf3fe Produced a warning during compilation on Windows. --- audio/out/ao_wasapi_utils.c | 1 - 1 file changed, 1 deletion(-) diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c index 8b12ef4d5c64c..ce3f5da887efe 100644 --- a/audio/out/ao_wasapi_utils.c +++ b/audio/out/ao_wasapi_utils.c @@ -857,7 +857,6 @@ static LPWSTR select_device(struct mp_log *l, struct device_desc *d) bstr wasapi_get_specified_device_string(struct ao *ao) { - struct wasapi_state *state = ao->priv; return bstr_strip(bstr0(ao->device)); } From 4958c1a556fa4f3bc4e4b3b36e04a056d90f69e1 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 29 Nov 2016 15:18:40 +0100 Subject: [PATCH 31/83] options: some simplifications Remove more stuff that was needed only for legacy suboptions. One user-visible change is that parent-options like --tv are now not visible anymore. They lead to a special error message when used before, but now they're simply not part of the option list anymore. --- options/m_config.c | 53 ++++++++++++++---------------------------- options/m_option.c | 58 ++-------------------------------------------- options/m_option.h | 19 +-------------- player/command.c | 3 +-- 4 files changed, 21 insertions(+), 112 deletions(-) diff --git a/options/m_config.c b/options/m_config.c index 256e4653e70a2..2dc3eb569dee5 100644 --- a/options/m_config.c +++ b/options/m_config.c @@ -344,8 +344,6 @@ struct m_config *m_config_from_obj_desc_and_args(void *ta_parent, static void ensure_backup(struct m_config *config, struct m_config_option *co) { - if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) - return; if (!co->data) return; for (struct m_opt_backup *cur = config->backup_opts; cur; cur = cur->next) { @@ -553,6 +551,8 @@ static void m_config_add_option(struct m_config *config, .name = arg->name, .shadow_offset = -1, .group = parent ? parent->group : 0, + .default_data = &default_value, + .is_hidden = !!arg->deprecation_message, }; if (arg->offset >= 0) { @@ -560,22 +560,11 @@ static void m_config_add_option(struct m_config *config, co.data = (char *)optstruct + arg->offset; if (optstruct_def) co.default_data = (char *)optstruct_def + arg->offset; - int size = arg->type->size; - if (optstruct && size) { - // The required alignment is unknown, so go with the minimum C - // could require. Slightly wasteful, but not that much. - int align = (size - config->shadow_size % size) % size; - co.shadow_offset = config->shadow_size + align; - config->shadow_size = co.shadow_offset + size; - } } if (arg->defval) co.default_data = arg->defval; - if (!co.default_data) - co.default_data = &default_value; - // Fill in the full name if (!co.name[0]) { co.name = parent_name; @@ -583,24 +572,28 @@ static void m_config_add_option(struct m_config *config, co.name = talloc_asprintf(config, "%s-%s", parent_name, co.name); } - if (co.opt->deprecation_message) - co.is_hidden = true; - - // Option with children -> add them - if (arg->type->flags & M_OPT_TYPE_HAS_CHILD) { + if (arg->type == &m_option_type_subconfig) { const struct m_sub_options *subopts = arg->priv; add_sub_options(config, &co, subopts); } else { + int size = arg->type->size; + if (optstruct && size) { + // The required alignment is unknown, so go with the maximum C + // could require. Slightly wasteful, but not that much. + int align = (size - config->shadow_size % size) % size; + co.shadow_offset = config->shadow_size + align; + config->shadow_size = co.shadow_offset + size; + } + // Initialize options if (co.data && co.default_data) init_opt_inplace(arg, co.data, co.default_data); - } - - if (arg->type == &m_option_type_obj_settings_list) - init_obj_settings_list(config, (const struct m_obj_list *)arg->priv); - if (arg->name[0]) // no own name -> hidden MP_TARRAY_APPEND(config, config->opts, config->num_opts, co); + + if (arg->type == &m_option_type_obj_settings_list) + init_obj_settings_list(config, (const struct m_obj_list *)arg->priv); + } } struct m_config_option *m_config_get_co_raw(const struct m_config *config, @@ -843,16 +836,9 @@ static int m_config_parse_option(struct m_config *config, struct bstr name, if (bstr_equals0(name, "list-options")) return list_options(config, bstr0("*"), false); - // Option with children are a bit different to parse - if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) { - MP_FATAL(config, "Suboptions (--%.*s=...) have been removed. Use " - "flat options instead.\n", BSTR_P(name)); - return M_OPT_INVALID; - } - union m_option_value val = {0}; - // Some option tpyes are "impure" and work on the existing data. + // Some option types are "impure" and work on the existing data. // (Prime examples: --vf-add, --sub-file) if (co->data) m_option_copy(co->opt, &val, co->data); @@ -968,8 +954,6 @@ void m_config_print_option_list(const struct m_config *config, const char *name) for (int i = 0; i < config->num_opts; i++) { struct m_config_option *co = &sorted[i]; const struct m_option *opt = co->opt; - if (opt->type->flags & M_OPT_TYPE_HAS_CHILD) - continue; if (co->is_hidden) continue; #if HAVE_FNMATCH @@ -1022,9 +1006,6 @@ char **m_config_list_options(void *ta_parent, const struct m_config *config) int count = 0; for (int i = 0; i < config->num_opts; i++) { struct m_config_option *co = &config->opts[i]; - const struct m_option *opt = co->opt; - if (opt->type->flags & M_OPT_TYPE_HAS_CHILD) - continue; if (co->is_hidden) continue; // For use with CONF_TYPE_STRING_LIST, it's important not to set list diff --git a/options/m_option.c b/options/m_option.c index 6baa87c16349f..11bb677b971aa 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -1662,10 +1662,7 @@ const m_option_type_t m_option_type_print_fn = { .parse = parse_print, }; - -/////////////////////// Subconfig #undef VAL -#define VAL(x) (*(char ***)(x)) // Read s sub-option name, or a positional sub-opt value. // termset is a string containing the set of chars that terminate an option. @@ -1750,50 +1747,6 @@ static int split_subconf(struct mp_log *log, bstr optname, bstr *str, return 0; } -static int parse_subconf(struct mp_log *log, const m_option_t *opt, - struct bstr name, struct bstr param, void *dst) -{ - int nr = 0; - char **lst = NULL; - - if (param.len == 0) - return M_OPT_MISSING_PARAM; - - struct bstr p = param; - - while (p.len) { - bstr subopt, subparam; - int r = split_subconf(log, name, &p, &subopt, &subparam); - if (r < 0) - return r; - if (bstr_startswith0(p, ":")) - p = bstr_cut(p, 1); - else if (p.len > 0) { - mp_err(log, "Incorrect termination for '%.*s'\n", BSTR_P(subopt)); - return M_OPT_INVALID; - } - - if (dst) { - lst = talloc_realloc(NULL, lst, char *, 2 * (nr + 2)); - lst[2 * nr] = bstrto0(lst, subopt); - lst[2 * nr + 1] = bstrto0(lst, subparam); - memset(&lst[2 * (nr + 1)], 0, 2 * sizeof(char *)); - nr++; - } - } - - if (dst) - VAL(dst) = lst; - - return 1; -} - -const m_option_type_t m_option_type_subconfig = { - .name = "Subconfig", - .flags = M_OPT_TYPE_HAS_CHILD, - .parse = parse_subconf, -}; - #undef VAL // Split the string on the given split character. @@ -3370,13 +3323,6 @@ const m_option_type_t m_option_type_alias = { const m_option_type_t m_option_type_removed = { .name = "removed", }; - -static int parse_dummy(struct mp_log *log, const m_option_t *opt, - struct bstr name, struct bstr param, void *dst) -{ - return 1; -} -const m_option_type_t m_option_type_subopt_legacy = { - .name = "legacy suboption", - .parse = parse_dummy, +const m_option_type_t m_option_type_subconfig = { + .name = "Subconfig", }; diff --git a/options/m_option.h b/options/m_option.h index 8faaad21339a7..8709d20bb2b03 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -53,7 +53,6 @@ extern const m_option_type_t m_option_type_choice; extern const m_option_type_t m_option_type_flags; extern const m_option_type_t m_option_type_msglevels; extern const m_option_type_t m_option_type_print_fn; -extern const m_option_type_t m_option_type_subconfig; extern const m_option_type_t m_option_type_imgfmt; extern const m_option_type_t m_option_type_fourcc; extern const m_option_type_t m_option_type_afmt; @@ -63,11 +62,11 @@ extern const m_option_type_t m_option_type_size_box; extern const m_option_type_t m_option_type_channels; extern const m_option_type_t m_option_type_aspect; extern const m_option_type_t m_option_type_node; -extern const m_option_type_t m_option_type_subopt_legacy; // Used internally by m_config.c extern const m_option_type_t m_option_type_alias; extern const m_option_type_t m_option_type_removed; +extern const m_option_type_t m_option_type_subconfig; // Callback used by m_option_type_print_fn options. typedef void (*m_opt_print_fn)(struct mp_log *log); @@ -407,16 +406,6 @@ struct m_option { // These flags are used to describe special parser capabilities or behavior. -// Suboption parser flag. -/** When this flag is set, m_option::p should point to another m_option - * array. Only the parse function will be called. If dst is set, it should - * create/update an array of char* containg opt/val pairs. The options in - * the child array will then be set automatically by the \ref Config. - * Also note that suboptions may be directly accessed by using - * -option:subopt blah. - */ -#define M_OPT_TYPE_HAS_CHILD (1 << 0) - // Wildcard matching flag. /** If set the option type has a use for option names ending with a * * (used for -aa*), this only affects the option name matching. @@ -731,10 +720,4 @@ extern const char m_option_path_separator; {.name = optname, .type = &m_option_type_removed, .priv = msg, \ .deprecation_message = "", .offset = -1} -// Redirect a suboption (e.g. from --vo) to a global option. The redirection -// is handled as a special case instead of being applied automatically. -#define OPT_SUBOPT_LEGACY(optname, globalname) \ - {.name = optname, .type = &m_option_type_subopt_legacy, .priv = globalname, \ - .offset = -1} - #endif /* MPLAYER_M_OPTION_H */ diff --git a/player/command.c b/player/command.c index 3d56a56fca41b..36850a2c5128a 100644 --- a/player/command.c +++ b/player/command.c @@ -5552,8 +5552,7 @@ void command_init(struct MPContext *mpctx) for (int n = 0; n < num_opts; n++) { struct m_config_option *co = m_config_get_co_index(mpctx->mconfig, n); assert(co->name[0]); - if ((co->opt->flags & M_OPT_NOPROP) || - (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD)) + if (co->opt->flags & M_OPT_NOPROP) continue; struct m_property prop = {0}; From 20f02229cd4263b350897bed1d4d2b18b6a51a25 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 29 Nov 2016 17:16:22 +0100 Subject: [PATCH 32/83] player: don't print format detection error when aborting loading The way playback/loading is stopped on the demuxer layer makes it report an error to the higher levels of the player. But if playback/loading was explicitly aborted, printing such an error is confusing and misleading. This was probably just an oversight anyway. Fix it by using the libmpv API reported error field instead, which handles this better. --- player/loadfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/player/loadfile.c b/player/loadfile.c index 6ea4479d7ad88..b94ce8af43daf 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -1231,7 +1231,7 @@ static void play_current_file(struct MPContext *mpctx) MP_VERBOSE(mpctx, "finished playback, %s (reason %d)\n", mpv_error_string(end_event.error), end_event.reason); - if (mpctx->error_playing == MPV_ERROR_UNKNOWN_FORMAT) + if (end_event.error == MPV_ERROR_UNKNOWN_FORMAT) MP_ERR(mpctx, "Failed to recognize file format.\n"); MP_INFO(mpctx, "\n"); From ec74a79e1240eeda7b0bb195b484420052ea0ad8 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 30 Nov 2016 17:44:59 +0100 Subject: [PATCH 33/83] ao_wasapi: log return code when probing audio formats We log a large number of formats, but we rarely log the result of the probing. Change this. The logic in try_format_exclusive() changes slightly, but should be equivalent. EXIT_ON_ERROR() checks for FAILED(), which should be exclusive to SUCCEEDED(). --- audio/out/ao_wasapi.h | 4 ++++ audio/out/ao_wasapi_utils.c | 18 +++++------------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/audio/out/ao_wasapi.h b/audio/out/ao_wasapi.h index ea9f5c2badc77..65f16d11c1b06 100644 --- a/audio/out/ao_wasapi.h +++ b/audio/out/ao_wasapi.h @@ -50,6 +50,10 @@ void wasapi_change_uninit(struct ao* ao); #define SAFE_RELEASE(unk, release) \ do { if ((unk) != NULL) { release; (unk) = NULL; } } while(0) +#define mp_format_res_str(hres) \ + (SUCCEEDED(hres) ? "ok" : ((hres) == AUDCLNT_E_UNSUPPORTED_FORMAT) \ + ? "unsupported" : mp_HRESULT_to_str(hres)) + enum wasapi_thread_state { WASAPI_THREAD_FEED = 0, WASAPI_THREAD_RESUME, diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c index ce3f5da887efe..4667b57ae87ca 100644 --- a/audio/out/ao_wasapi_utils.c +++ b/audio/out/ao_wasapi_utils.c @@ -289,18 +289,12 @@ static bool set_ao_format(struct ao *ao, WAVEFORMATEX *wf, static bool try_format_exclusive(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat) { struct wasapi_state *state = ao->priv; - MP_VERBOSE(ao, "Trying %s (exclusive)\n", - waveformat_to_str(&wformat->Format)); HRESULT hr = IAudioClient_IsFormatSupported(state->pAudioClient, AUDCLNT_SHAREMODE_EXCLUSIVE, &wformat->Format, NULL); - if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT) - EXIT_ON_ERROR(hr); - + MP_VERBOSE(ao, "Trying %s (exclusive) -> %s\n", + waveformat_to_str(&wformat->Format), mp_format_res_str(hr)); return SUCCEEDED(hr); -exit_label: - MP_ERR(state, "Error testing exclusive format: %s\n", mp_HRESULT_to_str(hr)); - return false; } // This works like try_format_exclusive(), but will try to fallback to the AC3 @@ -393,11 +387,8 @@ static bool search_channels(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat) for (int j = 0; channel_layouts[j]; j++) { mp_chmap_from_str(&entry, bstr0(channel_layouts[j])); if (!wformat->Format.nSamplesPerSec) { - if (search_samplerates(ao, wformat, &entry)) { + if (search_samplerates(ao, wformat, &entry)) mp_chmap_sel_add_map(&chmap_sel, &entry); - MP_VERBOSE(ao, "%s is supported\n", - waveformat_to_str(&wformat->Format)); - } } else { change_waveformat_channels(wformat, &entry); if (try_format_exclusive(ao, wformat)) @@ -442,11 +433,12 @@ static bool find_formats_shared(struct ao *ao) WAVEFORMATEXTENSIBLE wformat; set_waveformat_with_ao(&wformat, ao); - MP_VERBOSE(ao, "Trying %s (shared)\n", waveformat_to_str(&wformat.Format)); WAVEFORMATEX *closestMatch; HRESULT hr = IAudioClient_IsFormatSupported(state->pAudioClient, AUDCLNT_SHAREMODE_SHARED, &wformat.Format, &closestMatch); + MP_VERBOSE(ao, "Trying %s (shared) -> %s\n", + waveformat_to_str(&wformat.Format), mp_format_res_str(hr)); if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT) EXIT_ON_ERROR(hr); From 09238a9bb536982e79b60a264b1d8a4fc0302975 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 2 Dec 2016 15:26:45 +0100 Subject: [PATCH 34/83] vo_opengl: don't rely on viewport to contain window dimensions Apparently we don't always set the viewport to window dimensions anymore, e.g. if nothing is actually rendered. This means the viewport can contain old values. The window screenshot code uses the viewport values to guess the default framebuffer dimensions. With --force-window --idle --no-osc (which draws nothing and issues a glClear() command only), taking a screenshot would yield an image with the wrong size and possibly garbage in it. Fix this by explicitly passing the currently known window dimensions. Abusing the values stored in the viewport was questionable anyway. --- video/out/opengl/utils.c | 11 ++++------- video/out/opengl/utils.h | 2 +- video/out/vo_opengl.c | 3 ++- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/video/out/opengl/utils.c b/video/out/opengl/utils.c index 6c879fd535168..aa43728cb8bd5 100644 --- a/video/out/opengl/utils.c +++ b/video/out/opengl/utils.c @@ -100,13 +100,11 @@ void gl_upload_tex(GL *gl, GLenum target, GLenum format, GLenum type, gl->PixelStorei(GL_UNPACK_ALIGNMENT, 4); } -mp_image_t *gl_read_window_contents(GL *gl) +mp_image_t *gl_read_window_contents(GL *gl, int w, int h) { if (gl->es) return NULL; // ES can't read from front buffer - GLint vp[4]; //x, y, w, h - gl->GetIntegerv(GL_VIEWPORT, vp); - mp_image_t *image = mp_image_alloc(IMGFMT_RGB24, vp[2], vp[3]); + mp_image_t *image = mp_image_alloc(IMGFMT_RGB24, w, h); if (!image) return NULL; gl->BindFramebuffer(GL_FRAMEBUFFER, gl->main_fb); @@ -114,9 +112,8 @@ mp_image_t *gl_read_window_contents(GL *gl) gl->PixelStorei(GL_PACK_ALIGNMENT, 1); gl->ReadBuffer(obj); //flip image while reading (and also avoid stride-related trouble) - for (int y = 0; y < vp[3]; y++) { - gl->ReadPixels(vp[0], vp[1] + vp[3] - y - 1, vp[2], 1, - GL_RGB, GL_UNSIGNED_BYTE, + for (int y = 0; y < h; y++) { + gl->ReadPixels(0, h - y - 1, w, 1, GL_RGB, GL_UNSIGNED_BYTE, image->planes[0] + y * image->stride[0]); } gl->PixelStorei(GL_PACK_ALIGNMENT, 4); diff --git a/video/out/opengl/utils.h b/video/out/opengl/utils.h index 33c2daa5bed58..f4e522cdf7114 100644 --- a/video/out/opengl/utils.h +++ b/video/out/opengl/utils.h @@ -30,7 +30,7 @@ void gl_upload_tex(GL *gl, GLenum target, GLenum format, GLenum type, const void *dataptr, int stride, int x, int y, int w, int h); -mp_image_t *gl_read_window_contents(GL *gl); +mp_image_t *gl_read_window_contents(GL *gl, int w, int h); const char* mp_sampler_type(GLenum texture_target); diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c index 508ba9cda937b..7f65a1eafca4b 100644 --- a/video/out/vo_opengl.c +++ b/video/out/vo_opengl.c @@ -272,7 +272,8 @@ static int control(struct vo *vo, uint32_t request, void *data) return VO_NOTIMPL; } case VOCTRL_SCREENSHOT_WIN: { - struct mp_image *screen = gl_read_window_contents(p->gl); + struct mp_image *screen = + gl_read_window_contents(p->gl, vo->dwidth, vo->dheight); if (!screen) break; // redirect to backend // set image parameters according to the display, if possible From a89785f2971273b3c0592a5819f9618aaabf19f9 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 2 Dec 2016 16:06:16 +0100 Subject: [PATCH 35/83] vdpau: fix vaapi probing if libvdpau-va-gl1 is present Needs explicit logic. Fixes a pretty bad regression which prefers vdpau-copy over native vaapi with direct rendering (with --hwdec=auto) if libvdpau-va-gl1 is present. The reason is that vdpau-copy is above vaapi, simply because all vdpau hwdecs are grouped and happened to be listed before vaapi. Although this is not that bad for copy-mode (unlike the case described above), it's still a good idea to use our native vaapi code instead. --- video/decode/vdpau.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/video/decode/vdpau.c b/video/decode/vdpau.c index 93a1e6d9a343d..a6b6210804cf9 100644 --- a/video/decode/vdpau.c +++ b/video/decode/vdpau.c @@ -146,12 +146,14 @@ static int probe_copy(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, const char *codec) { assert(!ctx->hwdec_priv); - int r = init_copy(ctx); - if (ctx->hwdec_priv) - uninit(ctx); - ctx->hwdec_priv = NULL; - return r < 0 ? HWDEC_ERR_NO_CTX : 0; + int r = HWDEC_ERR_NO_CTX; + if (init_copy(ctx) >=0 ) { + struct priv *p = ctx->hwdec_priv; + r = mp_vdpau_guess_if_emulated(p->mpvdp) ? HWDEC_ERR_EMULATED : 0; + uninit(ctx); + } + return r; } static struct mp_image *copy_image(struct lavc_ctx *ctx, struct mp_image *img) From a7a919f93f966f5ba5b4c5a9117ad136b8447d4d Mon Sep 17 00:00:00 2001 From: Ricardo Constantino Date: Thu, 1 Dec 2016 19:29:04 +0000 Subject: [PATCH 36/83] osc: topbar: use same styles as bottombar --- player/lua/osc.lua | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/player/lua/osc.lua b/player/lua/osc.lua index bfbdcaa229586..fffbbc5e9bab0 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -1356,17 +1356,17 @@ layouts["topbar"] = function() w = buttonW, h = 36 - padY*2 } lo = add_layout("playpause") lo.geometry = geo - lo.style = osc_styles.smallButtonsL + lo.style = osc_styles.smallButtonsBar geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } lo = add_layout("ch_prev") lo.geometry = geo - lo.style = osc_styles.smallButtonsL + lo.style = osc_styles.smallButtonsBar geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } lo = add_layout("ch_next") lo.geometry = geo - lo.style = osc_styles.smallButtonsL + lo.style = osc_styles.smallButtonsBar -- Left timecode @@ -1374,7 +1374,7 @@ layouts["topbar"] = function() w = tcW, h = geo.h } lo = add_layout("tc_left") lo.geometry = geo - lo.style = osc_styles.timecodes + lo.style = osc_styles.timecodesBar local sb_l = geo.x + padX @@ -1384,12 +1384,12 @@ layouts["topbar"] = function() w = tsW, h = geo.h } lo = add_layout("cy_sub") lo.geometry = geo - lo.style = osc_styles.smallButtonsL + lo.style = osc_styles.smallButtonsBar geo = { x = geo.x - geo.w - padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } lo = add_layout("cy_audio") lo.geometry = geo - lo.style = osc_styles.smallButtonsL + lo.style = osc_styles.smallButtonsBar -- Right timecode @@ -1397,7 +1397,7 @@ layouts["topbar"] = function() w = tcW, h = geo.h } lo = add_layout("tc_right") lo.geometry = geo - lo.style = osc_styles.timecodes + lo.style = osc_styles.timecodesBar local sb_r = geo.x - padX @@ -1409,13 +1409,13 @@ layouts["topbar"] = function() lo.geometry = geo lo.layer = 15 - lo.style = osc_styles.timecodes + lo.style = osc_styles.timecodesBar lo.alpha[1] = math.min(255, user_opts.boxalpha + (255 - user_opts.boxalpha)*0.8) lo = add_layout("seekbar") lo.geometry = geo - lo.style = osc_styles.timecodes + lo.style = osc_styles.timecodesBar lo.slider.border = 0 lo.slider.tooltip_style = osc_styles.timePosBar lo.slider.stype = user_opts["seekbarstyle"] @@ -1426,12 +1426,12 @@ layouts["topbar"] = function() geo = { x = osc_geo.x + padX, y = line2, an = 4, w = 18, h = 18 - padY } lo = add_layout("pl_prev") lo.geometry = geo - lo.style = osc_styles.topButtons + lo.style = osc_styles.topButtonsBar geo = { x = geo.x + geo.w + padX, y = geo.y, an = geo.an, w = geo.w, h = geo.h } lo = add_layout("pl_next") lo.geometry = geo - lo.style = osc_styles.topButtons + lo.style = osc_styles.topButtonsBar local t_l = geo.x + geo.w + padX @@ -1440,7 +1440,7 @@ layouts["topbar"] = function() an = 6, w = 150, h = geo.h } lo = add_layout("cache") lo.geometry = geo - lo.style = osc_styles.vidtitle + lo.style = osc_styles.vidtitleBar local t_r = geo.x - geo.w - padX*2 @@ -1449,7 +1449,7 @@ layouts["topbar"] = function() w = t_r - t_l, h = geo.h } lo = add_layout("title") lo.geometry = geo - lo.style = osc_styles.vidtitle + lo.style = osc_styles.vidtitleBar lo.button.maxchars = math.floor(geo.w/7) end From 796b48b2a32219cfd82a8eab11bb5996dcbc40ca Mon Sep 17 00:00:00 2001 From: Ricardo Constantino Date: Thu, 1 Dec 2016 21:59:27 +0000 Subject: [PATCH 37/83] osc: don't hide playlist buttons, just disable Having empty space before the title in layout=*bar looks worse than the floating buttons in layout=box. Also disable both playlist buttons selectively according to the current position. --- player/lua/osc.lua | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/player/lua/osc.lua b/player/lua/osc.lua index fffbbc5e9bab0..63d0740c6a60a 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -1502,8 +1502,9 @@ function osc_init() elements = {} -- some often needed stuff - local pl_count = mp.get_property_number("playlist-count") + local pl_count = mp.get_property_number("playlist-count", 0) local have_pl = (pl_count > 1) + local pl_pos = mp.get_property_number("playlist-pos", 0) + 1 local have_ch = (mp.get_property_number("chapters", 0) > 0) local ne @@ -1523,8 +1524,8 @@ function osc_init() ne.eventresponder["mouse_btn0_up"] = function () local title = mp.get_property_osd("media-title") if (have_pl) then - local pl_pos = countone(mp.get_property_number("playlist-pos")) - title = "[" .. pl_pos .. "/" .. pl_count .. "] " .. title + title = string.format("[%d/%d] %s", countone(pl_pos - 1), + pl_count, title) end show_message(title) end @@ -1538,7 +1539,7 @@ function osc_init() ne = new_element("pl_prev", "button") ne.content = "\238\132\144" - ne.visible = have_pl + ne.enabled = (pl_pos > 1) ne.eventresponder["mouse_btn0_up"] = function () mp.commandv("playlist-prev", "weak") @@ -1553,7 +1554,7 @@ function osc_init() ne = new_element("pl_next", "button") ne.content = "\238\132\129" - ne.visible = have_pl + ne.enabled = (have_pl) and (pl_pos < pl_count) ne.eventresponder["mouse_btn0_up"] = function () mp.commandv("playlist-next", "weak") From 5544ffecd92d898715b95f2d1913db3586eed855 Mon Sep 17 00:00:00 2001 From: shinchiro Date: Sat, 3 Dec 2016 06:47:17 +0800 Subject: [PATCH 38/83] wscript: add ANGLE_EXPORT definition It always needed when linking ANGLE libs --- wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript b/wscript index 2fe82e1afc401..caa5570dd551c 100644 --- a/wscript +++ b/wscript @@ -742,7 +742,7 @@ video_output_features = [ 'groups': [ 'gl' ], 'func': check_statement(['EGL/egl.h'], 'eglCreateWindowSurface(0, 0, 0, 0)', - cflags="-DGL_APICALL= -DEGLAPI= -DANGLE_NO_ALIASES", + cflags="-DGL_APICALL= -DEGLAPI= -DANGLE_NO_ALIASES -DANGLE_EXPORT=", lib=['EGL', 'GLESv2', 'dxguid', 'd3d9', 'gdi32', 'stdc++']) } , { 'name': '--vdpau', From f53b2952ebfc109da9cedba4b26323222c1a7500 Mon Sep 17 00:00:00 2001 From: pavelxdd Date: Sun, 4 Dec 2016 11:10:58 +0300 Subject: [PATCH 39/83] osc: replace length property with duration Length property is deprecated and no longer works. This fixes a bug when the total file duration wasn't visible if the option to display milliseconds was activated. --- player/lua/osc.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/player/lua/osc.lua b/player/lua/osc.lua index 63d0740c6a60a..4ad69298000df 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -1766,7 +1766,7 @@ function osc_init() end else if state.tc_ms then - return (mp.get_property_osd("length/full")) + return (mp.get_property_osd("duration/full")) else return (mp.get_property_osd("duration")) end From 47f974a39528ce08a6278e790666fa283175a79a Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 4 Dec 2016 13:18:48 +0100 Subject: [PATCH 40/83] demux_lavf: blacklist ffm (ffserver) --- demux/demux_lavf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 7857934642648..d5598a942bb89 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -167,6 +167,8 @@ static const struct format_hack format_hacks[] = { BLACKLIST("bin"), // Useless, does not work with custom streams. BLACKLIST("image2"), + // Probably a security risk. + BLACKLIST("ffm"), // Image demuxers ("_pipe" is detected explicitly) {"image2pipe", .image_format = true}, {0} From 83c5f704e7d483e2db6df90dacd24896d45fe39a Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Sun, 4 Dec 2016 11:00:54 -0800 Subject: [PATCH 41/83] vo_opengl: hwdec_cuda: Don't include hwcontext headers After various simplifications, these includes simply aren't needed now. --- video/out/opengl/hwdec_cuda.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/video/out/opengl/hwdec_cuda.c b/video/out/opengl/hwdec_cuda.c index c3d2e34ae361c..4edad96c7a4f1 100644 --- a/video/out/opengl/hwdec_cuda.c +++ b/video/out/opengl/hwdec_cuda.c @@ -27,15 +27,11 @@ * when decoding 10bit streams (there is some hardware dithering going on). */ -#include - #include "cuda_dynamic.h" #include "video/mp_image_pool.h" #include "hwdec.h" #include "video.h" -#include - struct priv { struct mp_hwdec_ctx hwctx; struct mp_image layout; From ceb2e1026d4295d3831d080dc18f8ca5db56bc5c Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 4 Dec 2016 23:15:31 +0100 Subject: [PATCH 42/83] demux, stream: add option to prevent opening referenced files Quite irresponsibly hacked together. Sue me. --- DOCS/man/options.rst | 20 ++++++++++++++++++++ demux/demux.c | 7 +++++-- demux/demux.h | 1 + demux/demux_cue.c | 3 +++ demux/demux_edl.c | 3 +++ demux/demux_lavf.c | 15 +++++++++++++++ demux/demux_libarchive.c | 3 +++ demux/demux_mkv_timeline.c | 2 +- demux/demux_playlist.c | 5 +++++ demux/demux_rar.c | 3 +++ stream/stream.c | 6 ++++++ stream/stream.h | 1 + stream/stream_bluray.c | 3 +++ stream/stream_dvd.c | 3 +++ stream/stream_dvdnav.c | 3 +++ wscript | 6 ++++++ 16 files changed, 81 insertions(+), 3 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 82c51fc503e23..d4cef55bf38eb 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -267,6 +267,26 @@ Playback Control Note that ``--playlist`` always loads all entries, so you use that instead if you really have the need for this functionality. +``--access-references=`` + Follow any references in the file being opened (default: yes). Disabling + this is helpful if the file is automatically scanned (e.g. thumbnail + generation). If the thumbnail scanner for example encounters a playlist + file, which contains network URLs, and the scanner should not open these, + enabling this option will prevent it. This option also disables ordered + chapters, mov reference files, opening of archives, and a number of other + features. + + On older FFmpeg versions, this will not work in some cases. Some FFmpeg + demuxers might not respect this option. + + This option does not prevent opening of paired subtitle files and such. Use + ``--autoload-files=no`` to prevent this. + + This option does not always work if you open non-files (for example using + ``dvd://directory`` would open a whole bunch of files in the given + directory). Prefixing the filename with ``./`` if it doesn't start with + a ``/`` will avoid this. + ``--loop-file=`` Loop a single file N times. ``inf`` means forever, ``no`` means normal playback. For compatibility, ``--loop-file`` and ``--loop-file=yes`` are diff --git a/demux/demux.c b/demux/demux.c index 8aa9989de347a..18c9b3b5c1dc0 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -89,6 +89,7 @@ struct demux_opts { double min_secs; int force_seekable; double min_secs_cache; + int access_references; }; #define OPT_BASE_STRUCT struct demux_opts @@ -100,6 +101,7 @@ const struct m_sub_options demux_conf = { OPT_INTRANGE("demuxer-max-bytes", max_bytes, 0, 0, INT_MAX), OPT_FLAG("force-seekable", force_seekable, 0), OPT_DOUBLE("cache-secs", min_secs_cache, M_OPT_MIN, .min = 0), + OPT_FLAG("access-references", access_references, 0), {0} }, .size = sizeof(struct demux_opts), @@ -108,6 +110,7 @@ const struct m_sub_options demux_conf = { .max_bytes = 400 * 1024 * 1024, .min_secs = 1.0, .min_secs_cache = 10.0, + .access_references = 1, }, }; @@ -1213,6 +1216,7 @@ static struct demuxer *open_given_type(struct mpv_global *global, return NULL; struct demuxer *demuxer = talloc_ptrtype(NULL, demuxer); + struct demux_opts *opts = mp_get_config_group(demuxer, global, &demux_conf); *demuxer = (struct demuxer) { .desc = desc, .stream = stream, @@ -1223,6 +1227,7 @@ static struct demuxer *open_given_type(struct mpv_global *global, .glog = log, .filename = talloc_strdup(demuxer, stream->url), .is_network = stream->is_network, + .access_references = opts->access_references, .events = DEMUX_EVENT_ALL, }; demuxer->seekable = stream->seekable; @@ -1230,8 +1235,6 @@ static struct demuxer *open_given_type(struct mpv_global *global, !demuxer->stream->uncached_stream->seekable) demuxer->seekable = false; - struct demux_opts *opts = mp_get_config_group(demuxer, global, &demux_conf); - struct demux_internal *in = demuxer->in = talloc_ptrtype(demuxer, in); *in = (struct demux_internal){ .log = demuxer->log, diff --git a/demux/demux.h b/demux/demux.h index 18f52d463de06..0e5a5e15c6d2e 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -186,6 +186,7 @@ typedef struct demuxer { // Typical examples: text subtitles, playlists bool fully_read; bool is_network; // opened directly from a network stream + bool access_references; // allow opening other files/URLs // Bitmask of DEMUX_EVENT_* int events; diff --git a/demux/demux_cue.c b/demux/demux_cue.c index 673e8b9f27e0e..ba97ca0c1bf2f 100644 --- a/demux/demux_cue.c +++ b/demux/demux_cue.c @@ -253,6 +253,9 @@ static void build_timeline(struct timeline *tl) static int try_open_file(struct demuxer *demuxer, enum demux_check check) { + if (!demuxer->access_references) + return -1; + struct stream *s = demuxer->stream; if (check >= DEMUX_CHECK_UNSAFE) { bstr d = stream_peek(s, PROBE_SIZE); diff --git a/demux/demux_edl.c b/demux/demux_edl.c index 67a4290303333..623cae35b39f8 100644 --- a/demux/demux_edl.c +++ b/demux/demux_edl.c @@ -295,6 +295,9 @@ static void build_mpv_edl_timeline(struct timeline *tl) static int try_open_file(struct demuxer *demuxer, enum demux_check check) { + if (!demuxer->access_references) + return -1; + struct priv *p = talloc_zero(demuxer, struct priv); demuxer->priv = p; demuxer->fully_read = true; diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index d5598a942bb89..94bcd3fff649a 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "config.h" @@ -754,6 +755,14 @@ static int interrupt_cb(void *ctx) return mp_cancel_test(priv->stream->cancel); } +static int block_io_open(struct AVFormatContext *s, AVIOContext **pb, + const char *url, int flags, AVDictionary **options) +{ + struct demuxer *demuxer = s->opaque; + MP_ERR(demuxer, "Not opening '%s' due to --access-references=no.\n", url); + return AVERROR(EACCES); +} + static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) { AVFormatContext *avfc; @@ -855,6 +864,12 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) .opaque = demuxer, }; +#if HAVE_AVFORMAT_IOOPEN + avfc->opaque = demuxer; + if (!demuxer->access_references) + avfc->io_open = block_io_open; +#endif + mp_set_avdict(&dopts, lavfdopts->avopts); if (avformat_open_input(&avfc, priv->filename, priv->avif, &dopts) < 0) { diff --git a/demux/demux_libarchive.c b/demux/demux_libarchive.c index dcdbe65fc07fb..41b05368ca1ed 100644 --- a/demux/demux_libarchive.c +++ b/demux/demux_libarchive.c @@ -32,6 +32,9 @@ static int cmp_filename(const void *a, const void *b) static int open_file(struct demuxer *demuxer, enum demux_check check) { + if (!demuxer->access_references) + return -1; + int flags = 0; int probe_size = STREAM_BUFFER_SIZE; if (check <= DEMUX_CHECK_REQUEST) { diff --git a/demux/demux_mkv_timeline.c b/demux/demux_mkv_timeline.c index 15f9a5d594fb3..476551c58b6a7 100644 --- a/demux/demux_mkv_timeline.c +++ b/demux/demux_mkv_timeline.c @@ -519,7 +519,7 @@ void build_ordered_chapter_timeline(struct timeline *tl) .opts = mp_get_config_group(ctx, tl->global, NULL), }; - if (!ctx->opts->ordered_chapters) { + if (!ctx->opts->ordered_chapters || !demuxer->access_references) { MP_INFO(demuxer, "File uses ordered chapters, but " "you have disabled support for them. Ignoring.\n"); talloc_free(ctx); diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index 7479db149f4d6..0f2ebedd76efc 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -283,6 +283,8 @@ static int parse_dir(struct pl_parser *p) return 0; char *path = mp_file_get_path(p, bstr0(p->real_stream->url)); + if (!path) + return -1; char **files = NULL; int num_files = 0; @@ -339,6 +341,9 @@ static const struct pl_format *probe_pl(struct pl_parser *p) static int open_file(struct demuxer *demuxer, enum demux_check check) { + if (!demuxer->access_references) + return -1; + bool force = check < DEMUX_CHECK_UNSAFE || check == DEMUX_CHECK_REQUEST; struct pl_parser *p = talloc_zero(NULL, struct pl_parser); diff --git a/demux/demux_rar.c b/demux/demux_rar.c index f35c2ccf66498..7d9adfc28ac2c 100644 --- a/demux/demux_rar.c +++ b/demux/demux_rar.c @@ -23,6 +23,9 @@ static int open_file(struct demuxer *demuxer, enum demux_check check) { + if (!demuxer->access_references) + return -1; + if (RarProbe(demuxer->stream)) return -1; diff --git a/stream/stream.c b/stream/stream.c index c936c5c77e3d7..4c7aa04844afc 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -230,6 +230,12 @@ static int open_internal(const stream_info_t *sinfo, const char *url, int flags, s->is_network = sinfo->is_network; s->mode = flags & (STREAM_READ | STREAM_WRITE); + if (global->config) { + int opt; + mp_read_option_raw(global, "access-references", &m_option_type_flag, &opt); + s->access_references = opt; + } + MP_VERBOSE(s, "Opening %s\n", url); if ((s->mode & STREAM_WRITE) && !sinfo->can_write) { diff --git a/stream/stream.h b/stream/stream.h index 4444da8ed3942..7d44e30eaeaa7 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -197,6 +197,7 @@ typedef struct stream { bool fast_skip : 1; // consider stream fast enough to fw-seek by skipping bool is_network : 1; // original stream_info_t.is_network flag bool allow_caching : 1; // stream cache makes sense + bool access_references : 1; // open other streams struct mp_log *log; struct mpv_global *global; diff --git a/stream/stream_bluray.c b/stream/stream_bluray.c index 26a78e5f21343..5f083954c2282 100644 --- a/stream/stream_bluray.c +++ b/stream/stream_bluray.c @@ -569,6 +569,9 @@ static int bdmv_dir_stream_open(stream_t *stream) .cfg_title = BLURAY_DEFAULT_TITLE, }; + if (!stream->access_references) + goto unsupported; + char *path = mp_file_get_path(priv, bstr0(stream->url)); if (!path) goto unsupported; diff --git a/stream/stream_dvd.c b/stream/stream_dvd.c index 4b423de630b24..338c23633c59e 100644 --- a/stream/stream_dvd.c +++ b/stream/stream_dvd.c @@ -951,6 +951,9 @@ static int ifo_stream_open(stream_t *stream) dvd_priv_t *priv = talloc_zero(stream, dvd_priv_t); stream->priv = priv; + if (!stream->access_references) + goto unsupported; + char *path = mp_file_get_path(priv, bstr0(stream->url)); if (!path) goto unsupported; diff --git a/stream/stream_dvdnav.c b/stream/stream_dvdnav.c index ec15c83b20e36..1178f50857053 100644 --- a/stream/stream_dvdnav.c +++ b/stream/stream_dvdnav.c @@ -562,6 +562,9 @@ static int ifo_dvdnav_stream_open(stream_t *stream) struct priv *priv = talloc_zero(stream, struct priv); stream->priv = priv; + if (!stream->access_references) + goto unsupported; + priv->track = TITLE_LONGEST; char *path = mp_file_get_path(priv, bstr0(stream->url)); diff --git a/wscript b/wscript index caa5570dd551c..b098099cc1449 100644 --- a/wscript +++ b/wscript @@ -528,6 +528,12 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_ 'func': check_statement('libavutil/frame.h', 'AV_FRAME_DATA_MASTERING_DISPLAY_METADATA', use='libav'), + }, { + 'name': 'avformat-ioopen', + 'desc': 'libavformat io_open callback', + 'func': check_statement('libavformat/avformat.h', + 'offsetof(AVFormatContext, io_open)', + use='libav'), } ] From b60817f9ddd3acdc92fafd10633ef73c274235a3 Mon Sep 17 00:00:00 2001 From: Ricardo Constantino Date: Mon, 5 Dec 2016 21:09:28 +0000 Subject: [PATCH 43/83] TOOLS/autoload: allow disabling through script-opts This allows leaving autoload in auto-loaded scripts and to be used in a special profile like "pseudo-gui" without being troublesome to disable the behavior in profiles that get applied after pseudo-gui. Ex: [someprofile] script-opts=autoload-disabled=yes --- TOOLS/lua/autoload.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/TOOLS/lua/autoload.lua b/TOOLS/lua/autoload.lua index fa56a3de4cd8d..5f8faa3ad2abd 100644 --- a/TOOLS/lua/autoload.lua +++ b/TOOLS/lua/autoload.lua @@ -7,6 +7,13 @@ -- Add at most 5000 * 2 files when starting a file (before + after). MAXENTRIES = 5000 +local options = require 'mp.options' + +o = { + disabled = false +} +options.read_options(o) + function Set (t) local set = {} for _, v in pairs(t) do set[v] = true end @@ -49,7 +56,7 @@ end function find_and_add_entries() local path = mp.get_property("path", "") local dir, filename = mputils.split_path(path) - if #dir == 0 then + if o.disabled or #dir == 0 then return end local pl_count = mp.get_property_number("playlist-count", 1) From 42799005dc8397fbe4ad56659a00542fbe2a15cb Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 7 Dec 2016 12:51:17 +0100 Subject: [PATCH 44/83] ao_alsa: print certain ALSA errors as string instead as number --- audio/out/ao_alsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index d63a760d73aa3..ac29905f5a539 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -603,8 +603,8 @@ static int try_open_device(struct ao *ao, const char *device, int mode) const char *const fallbacks[] = {"hdmi", "iec958", NULL}; for (int n = 0; fallbacks[n]; n++) { char *ndev = append_params(tmp, fallbacks[n], params); - MP_VERBOSE(ao, "got error %d; opening iec fallback " - "device '%s'\n", err, ndev); + MP_VERBOSE(ao, "got error '%s'; opening iec fallback " + "device '%s'\n", snd_strerror(err), ndev); err = snd_pcm_open (&p->alsa, ndev, SND_PCM_STREAM_PLAYBACK, mode); if (err >= 0) From 2b1d150a53d328db092c8f3799667cd72ef89634 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 7 Dec 2016 13:26:30 +0100 Subject: [PATCH 45/83] manpage: move the --opengl-dumb-mode option down It's horribly obscure - why would it be the first option to be listed? Also might fix the --scale option formatting/anchor in the HTML rendering. --- DOCS/man/options.rst | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index d4cef55bf38eb..84d417fb1d4f4 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -3819,20 +3819,6 @@ OpenGL renderer options The following video options are currently all specific to ``--vo=opengl`` and ``-vo=opengl-cb`` only, which are the only VOs that implement them. -``--opengl-dumb-mode=`` - This mode is extremely restricted, and will disable most extended OpenGL - features. This includes high quality scalers and custom shaders! - - It is intended for hardware that does not support FBOs (including GLES, - which supports it insufficiently), or to get some more performance out of - bad or old hardware. - - This mode is forced automatically if needed, and this option is mostly - useful for debugging. It's also enabled automatically if nothing uses - features which require FBOs. - - This option might be silently removed in the future. - ``--scale=`` ``bilinear`` @@ -4636,6 +4622,20 @@ The following video options are currently all specific to ``--vo=opengl`` and flipping GL front and backbuffers immediately (i.e. it doesn't call it in display-sync mode). +``--opengl-dumb-mode=`` + This mode is extremely restricted, and will disable most extended OpenGL + features. This includes high quality scalers and custom shaders! + + It is intended for hardware that does not support FBOs (including GLES, + which supports it insufficiently), or to get some more performance out of + bad or old hardware. + + This mode is forced automatically if needed, and this option is mostly + useful for debugging. It's also enabled automatically if nothing uses + features which require FBOs. + + This option might be silently removed in the future. + Miscellaneous ------------- From a660e15c9b96bd46209e78b3c3d4cf136a039a50 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 7 Dec 2016 18:17:41 +0100 Subject: [PATCH 46/83] build: bump required minimum versions to FFmpeg 3.2.2 and Libav 12 Fixes the build with Libav 11 (not). --- README.md | 2 +- TOOLS/travis-deps | 4 ++-- wscript | 33 ++++++++++++++++++++++++--------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 41f0213cef5c0..d2b678c5c938a 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Essential dependencies (incomplete list): - Audio output development headers (libasound/ALSA, pulseaudio) - FFmpeg libraries (libavutil libavcodec libavformat libswscale libavfilter and either libswresample or libavresample) - At least FFmpeg 2.4.0 or Libav 11 is required. + At least FFmpeg 3.2.2 or Libav 12 is required. - zlib - iconv (normally provided by the system libc) - libass (OSD, OSC, text subtitles) diff --git a/TOOLS/travis-deps b/TOOLS/travis-deps index 20825568b095a..1d97f446b9cd2 100755 --- a/TOOLS/travis-deps +++ b/TOOLS/travis-deps @@ -89,7 +89,7 @@ class Libav < TravisDepsBuilder { "libav-stable" => { :action => :stable, - :url => 'http://libav.org/releases/libav-11.tar.gz' + :url => 'http://libav.org/releases/libav-12.tar.gz' }, "libav-git" => { :action => :git, @@ -97,7 +97,7 @@ class Libav < TravisDepsBuilder }, "ffmpeg-stable" => { :action => :stable, - :url => 'http://www.ffmpeg.org/releases/ffmpeg-2.4.tar.gz' + :url => 'http://www.ffmpeg.org/releases/ffmpeg-3.2.2.tar.gz' }, "ffmpeg-git" => { :action => :git, diff --git a/wscript b/wscript index b098099cc1449..37114fafb4325 100644 --- a/wscript +++ b/wscript @@ -401,13 +401,28 @@ iconv support use --disable-iconv.", } ] +# Libav 12: +# libavutil 55.20.0 +# libavcodec 57.25.0 +# libavformat 57.7.2 +# libswscale 4.0.0 +# libavfilter 6.7.0 +# libavresample 3.0.0 +# FFmpeg 3.2.2: +# libavutil 55.34.100 +# libavcodec 57.64.101 +# libavformat 57.56.100 +# libswscale 4.2.100 +# libavfilter 6.65.100 +# libswresample 2.3.100 + libav_pkg_config_checks = [ - 'libavutil', '>= 54.02.0', - 'libavcodec', '>= 56.1.0', - 'libavformat', '>= 56.01.0', - 'libswscale', '>= 2.1.3' + 'libavutil', '>= 55.20.0', + 'libavcodec', '>= 57.25.0', + 'libavformat', '>= 57.07.0', + 'libswscale', '>= 4.0.0' ] -libav_versions_string = "FFmpeg 2.4 or Libav 11" +libav_versions_string = "FFmpeg 3.2.2 or Libav 12" libav_dependencies = [ { @@ -420,11 +435,11 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_ }, { 'name': '--libswresample', 'desc': 'libswresample', - 'func': check_pkg_config('libswresample', '>= 1.1.100'), + 'func': check_pkg_config('libswresample', '>= 2.3.100'), }, { 'name': '--libavresample', 'desc': 'libavresample', - 'func': check_pkg_config('libavresample', '>= 2.1.0'), + 'func': check_pkg_config('libavresample', '>= 3.0.0'), 'deps_neg': ['libswresample'], }, { 'name': 'resampler', @@ -436,13 +451,13 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_ }, { 'name': 'libavfilter', 'desc': 'libavfilter', - 'func': check_pkg_config('libavfilter', '>= 5.0.0'), + 'func': check_pkg_config('libavfilter', '>= 6.7.0'), 'req': True, 'fmsg': 'libavfilter is a required dependency.', }, { 'name': '--libavdevice', 'desc': 'libavdevice', - 'func': check_pkg_config('libavdevice', '>= 55.0.0'), + 'func': check_pkg_config('libavdevice', '>= 57.0.0'), }, { 'name': 'avcodec-chroma-pos-api', 'desc': 'libavcodec avcodec_enum_to_chroma_pos API', From 3eceac2eab0b42ee082a0b615ebf40a21f0fb915 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 7 Dec 2016 19:44:29 +0100 Subject: [PATCH 47/83] Remove compatibility things Possible with bumped FFmpeg/Libav. These are just the simple cases. --- audio/decode/ad_lavc.c | 22 +---------- audio/decode/ad_spdif.c | 10 ----- audio/filter/af_lavcac3enc.c | 16 -------- audio/filter/af_lavrresample.c | 5 --- audio/out/ao_lavc.c | 23 ------------ common/av_common.c | 5 --- common/av_common.h | 9 ----- common/av_log.c | 2 - common/encode_lavc.c | 18 --------- demux/demux_lavf.c | 28 +------------- demux/stheader.h | 2 - player/command.c | 4 -- sub/lavc_conv.c | 3 -- sub/sd_lavc.c | 5 --- video/csputils.c | 4 -- video/decode/vd_lavc.c | 9 +---- video/fmt-conversion.c | 8 ---- video/image_writer.c | 6 --- video/img_format.c | 17 +++------ video/mp_image.c | 4 -- video/out/vo_lavc.c | 19 ---------- wscript | 69 +--------------------------------- 22 files changed, 10 insertions(+), 278 deletions(-) diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index e28558414df87..276ce69739e9e 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -207,7 +207,6 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt, if (priv->needs_reset) control(da, ADCTRL_RESET, NULL); -#if HAVE_AVCODEC_NEW_CODEC_API int ret = avcodec_send_packet(avctx, &pkt); if (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { if (ret >= 0 && mpkt) @@ -220,24 +219,6 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt, if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) ret = 0; } -#else - int ret = avcodec_decode_audio4(avctx, priv->avframe, &got_frame, &pkt); - if (mpkt) { - // At least "shorten" decodes sub-frames, instead of the whole packet. - // At least "mpc8" can return 0 and wants the packet again next time. - if (ret >= 0) { - ret = FFMIN(ret, mpkt->len); // sanity check against decoder overreads - mpkt->buffer += ret; - mpkt->len -= ret; - mpkt->pts = MP_NOPTS_VALUE; // don't reset PTS next time - } - // LATM may need many packets to find mux info - if (ret == AVERROR(EAGAIN)) { - mpkt->len = 0; - return 0; - } - } -#endif if (ret < 0) { MP_ERR(da, "Error decoding audio.\n"); return -1; @@ -245,8 +226,7 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt, if (!got_frame) return 0; - double out_pts = mp_pts_from_av(MP_AVFRAME_DEC_PTS(priv->avframe), - &priv->codec_timebase); + double out_pts = mp_pts_from_av(priv->avframe->pts, &priv->codec_timebase); struct mp_audio *mpframe = mp_audio_from_avframe(priv->avframe); if (!mpframe) diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c index 56e4a8102de1c..e15aca5c535c6 100644 --- a/audio/decode/ad_spdif.c +++ b/audio/decode/ad_spdif.c @@ -116,16 +116,10 @@ static int determine_codec_profile(struct dec_audio *da, AVPacket *pkt) goto done; } -#if HAVE_AVCODEC_NEW_CODEC_API if (avcodec_send_packet(ctx, pkt) < 0) goto done; if (avcodec_receive_frame(ctx, frame) < 0) goto done; -#else - int got_frame = 0; - if (avcodec_decode_audio4(ctx, frame, &got_frame, pkt) < 1 || !got_frame) - goto done; -#endif profile = ctx->profile; @@ -178,11 +172,7 @@ static int init_filter(struct dec_audio *da, AVPacket *pkt) if (!stream) goto fail; -#if HAVE_AVCODEC_HAS_CODECPAR stream->codecpar->codec_id = spdif_ctx->codec_id; -#else - stream->codec->codec_id = spdif_ctx->codec_id; -#endif AVDictionary *format_opts = NULL; diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c index 0a7c5d4440d37..9df5adb96f47b 100644 --- a/audio/filter/af_lavcac3enc.c +++ b/audio/filter/af_lavcac3enc.c @@ -280,7 +280,6 @@ static int filter_out(struct af_instance *af) AVPacket pkt = {0}; av_init_packet(&pkt); -#if HAVE_AVCODEC_NEW_CODEC_API // Send input as long as it wants. while (1) { err = read_input_frame(af, frame); @@ -310,21 +309,6 @@ static int filter_out(struct af_instance *af) MP_FATAL(af, "Encode failed.\n"); goto done; } -#else - err = read_input_frame(af, frame); - if (err < 0) - goto done; - if (err == 0) - goto done; - err = -1; - int ok; - int lavc_ret = avcodec_encode_audio2(s->lavc_actx, &pkt, frame, &ok); - s->input->samples = 0; - if (lavc_ret < 0 || !ok) { - MP_FATAL(af, "Encode failed.\n"); - goto done; - } -#endif MP_DBG(af, "avcodec_encode_audio got %d, pending %d.\n", pkt.size, s->pending->samples + s->input->samples); diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c index dc5d1a0d235ef..828be66247e28 100644 --- a/audio/filter/af_lavrresample.c +++ b/audio/filter/af_lavrresample.c @@ -111,12 +111,7 @@ static double get_delay(struct af_resample *s) } static int get_out_samples(struct af_resample *s, int in_samples) { -#if LIBSWRESAMPLE_VERSION_MAJOR > 1 || LIBSWRESAMPLE_VERSION_MINOR >= 2 return swr_get_out_samples(s->avrctx, in_samples); -#else - return av_rescale_rnd(in_samples, s->out_rate, s->in_rate, AV_ROUND_UP) - + swr_get_delay(s->avrctx, s->out_rate); -#endif } #endif diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c index 8ae1317407689..4dbc55a369888 100644 --- a/audio/out/ao_lavc.c +++ b/audio/out/ao_lavc.c @@ -258,7 +258,6 @@ static void encode_audio_and_write(struct ao *ao, AVFrame *frame) struct priv *ac = ao->priv; AVPacket packet = {0}; -#if HAVE_AVCODEC_NEW_CODEC_API int status = avcodec_send_frame(ac->codec, frame); if (status < 0) { MP_ERR(ao, "error encoding at %d %d/%d\n", @@ -297,28 +296,6 @@ static void encode_audio_and_write(struct ao *ao, AVFrame *frame) write_packet(ao, &packet); av_packet_unref(&packet); } -#else - av_init_packet(&packet); - int got_packet = 0; - int status = avcodec_encode_audio2(ac->codec, &packet, frame, &got_packet); - if (status < 0) { - MP_ERR(ao, "error encoding at %d %d/%d\n", - frame ? (int) frame->pts : -1, - ac->codec->time_base.num, - ac->codec->time_base.den); - return; - } - if (!got_packet) { - return; - } - if (frame) { - if (ac->savepts == AV_NOPTS_VALUE) - ac->savepts = frame->pts; - } - encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec); - write_packet(ao, &packet); - av_packet_unref(&packet); -#endif } // must get exactly ac->aframesize amount of data diff --git a/common/av_common.c b/common/av_common.c index 27a331927a93d..f2f43498e3622 100644 --- a/common/av_common.c +++ b/common/av_common.c @@ -77,13 +77,8 @@ void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st) // other demuxers must be handled manually. void mp_set_lav_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c) { -#if HAVE_AVCODEC_HAS_CODECPAR if (c->lav_codecpar) avcodec_parameters_to_context(avctx, c->lav_codecpar); -#else - if (c->lav_headers) - mp_copy_lav_codec_headers(avctx, c->lav_headers); -#endif } // Pick a "good" timebase, which will be used to convert double timestamps diff --git a/common/av_common.h b/common/av_common.h index b5ca034def3e4..4b13dcdd0caaf 100644 --- a/common/av_common.h +++ b/common/av_common.h @@ -46,13 +46,4 @@ void mp_set_avdict(struct AVDictionary **dict, char **kv); void mp_avdict_print_unset(struct mp_log *log, int msgl, struct AVDictionary *d); int mp_set_avopts(struct mp_log *log, void *avobj, char **kv); -#if (LIBAVCODEC_VERSION_MICRO >= 100 && \ - LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 61, 100)) || \ - (LIBAVCODEC_VERSION_MICRO < 100 && \ - LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 0)) -#define MP_AVFRAME_DEC_PTS(frame) ((frame)->pts) -#else -#define MP_AVFRAME_DEC_PTS(frame) ((frame)->pkt_pts) -#endif - #endif diff --git a/common/av_log.c b/common/av_log.c index 64ce26d85348b..e2a4c3316e87d 100644 --- a/common/av_log.c +++ b/common/av_log.c @@ -218,9 +218,7 @@ bool print_libav_versions(struct mp_log *log, int v) mp_msg(log, v, "\n"); } -#if HAVE_AV_VERSION_INFO mp_msg(log, v, "%s version: %s\n", LIB_PREFIX, av_version_info()); -#endif return !mismatch; } diff --git a/common/encode_lavc.c b/common/encode_lavc.c index d0523857ee5bc..7e116e3b0c335 100644 --- a/common/encode_lavc.c +++ b/common/encode_lavc.c @@ -595,12 +595,7 @@ int encode_lavc_alloc_stream(struct encode_lavc_context *ctx, } return -1; } -#if HAVE_AVCODEC_HAS_CODECPAR ctx->vcc = avcodec_alloc_context3(ctx->vc); -#else - avcodec_get_context_defaults3(ctx->vst->codec, ctx->vc); - ctx->vcc = ctx->vst->codec; -#endif // Using codec->time_base is deprecated, but needed for older lavf. ctx->vst->time_base = ctx->timebase; @@ -635,12 +630,7 @@ int encode_lavc_alloc_stream(struct encode_lavc_context *ctx, } return -1; } -#if HAVE_AVCODEC_HAS_CODECPAR ctx->acc = avcodec_alloc_context3(ctx->ac); -#else - avcodec_get_context_defaults3(ctx->ast->codec, ctx->ac); - ctx->acc = ctx->ast->codec; -#endif // Using codec->time_base is deprecated, but needed for older lavf. ctx->ast->time_base = ctx->timebase; @@ -708,10 +698,8 @@ int encode_lavc_open_codec(struct encode_lavc_context *ctx, } ret = avcodec_open2(codec, ctx->vc, &ctx->voptions); -#if HAVE_AVCODEC_HAS_CODECPAR if (ret >= 0) ret = avcodec_parameters_from_context(ctx->vst->codecpar, codec); -#endif // complain about all remaining options, then free the dict for (de = NULL; (de = av_dict_get(ctx->voptions, "", de, @@ -747,10 +735,8 @@ int encode_lavc_open_codec(struct encode_lavc_context *ctx, } ret = avcodec_open2(codec, ctx->ac, &ctx->aoptions); -#if HAVE_AVCODEC_HAS_CODECPAR if (ret >= 0) ret = avcodec_parameters_from_context(ctx->ast->codecpar, codec); -#endif // complain about all remaining options, then free the dict for (de = NULL; (de = av_dict_get(ctx->aoptions, "", de, @@ -826,11 +812,7 @@ int encode_lavc_write_frame(struct encode_lavc_context *ctx, AVStream *stream, (int)packet->size); -#if HAVE_AVCODEC_HAS_CODECPAR switch (stream->codecpar->codec_type) { -#else - switch (stream->codec->codec_type) { -#endif case AVMEDIA_TYPE_VIDEO: ctx->vbytes += packet->size; ++ctx->frames; diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 94bcd3fff649a..124956378c1a1 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -577,13 +577,8 @@ static void handle_new_stream(demuxer_t *demuxer, int i) AVFormatContext *avfc = priv->avfc; AVStream *st = avfc->streams[i]; struct sh_stream *sh = NULL; -#if HAVE_AVCODEC_HAS_CODECPAR AVCodecParameters *codec = st->codecpar; int lavc_delay = codec->initial_padding; -#else - AVCodecContext *codec = st->codec; - int lavc_delay = codec->delay; -#endif switch (codec->codec_type) { case AVMEDIA_TYPE_AUDIO: { @@ -679,17 +674,9 @@ static void handle_new_stream(demuxer_t *demuxer, int i) sh->ff_index = st->index; sh->codec->codec = mp_codec_from_av_codec_id(codec->codec_id); sh->codec->codec_tag = codec->codec_tag; -#if HAVE_AVCODEC_HAS_CODECPAR sh->codec->lav_codecpar = avcodec_parameters_alloc(); if (sh->codec->lav_codecpar) avcodec_parameters_copy(sh->codec->lav_codecpar, codec); -#else - sh->codec->codec = mp_codec_from_av_codec_id(codec->codec_id); - sh->codec->codec_tag = codec->codec_tag; - sh->codec->lav_headers = avcodec_alloc_context3(NULL); - if (sh->codec->lav_headers) - mp_copy_lav_codec_headers(sh->codec->lav_headers, codec); -#endif sh->codec->native_tb_num = st->time_base.num; sh->codec->native_tb_den = st->time_base.den; @@ -864,11 +851,9 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) .opaque = demuxer, }; -#if HAVE_AVFORMAT_IOOPEN avfc->opaque = demuxer; if (!demuxer->access_references) avfc->io_open = block_io_open; -#endif mp_set_avdict(&dopts, lavfdopts->avopts); @@ -953,14 +938,9 @@ static int demux_lavf_fill_buffer(demuxer_t *demux) if (pkt->dts != AV_NOPTS_VALUE) dp->dts = pkt->dts * av_q2d(st->time_base); dp->duration = pkt->duration * av_q2d(st->time_base); -#if !HAVE_AV_AVPACKET_INT64_DURATION - if (pkt->convergence_duration > 0) - dp->duration = pkt->convergence_duration * av_q2d(st->time_base); -#endif dp->pos = pkt->pos; dp->keyframe = pkt->flags & AV_PKT_FLAG_KEY; -#if LIBAVFORMAT_VERSION_MICRO >= 100 && \ - LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 50, 100) +#if LIBAVFORMAT_VERSION_MICRO >= 100 if (pkt->flags & AV_PKT_FLAG_DISCARD) MP_ERR(demux, "Edit lists are not correctly supported (FFmpeg issue).\n"); #endif @@ -1141,12 +1121,8 @@ static void demux_close_lavf(demuxer_t *demuxer) av_freep(&priv->pb->buffer); av_freep(&priv->pb); for (int n = 0; n < priv->num_streams; n++) { - if (priv->streams[n]) { - avcodec_free_context(&priv->streams[n]->codec->lav_headers); -#if HAVE_AVCODEC_HAS_CODECPAR + if (priv->streams[n]) avcodec_parameters_free(&priv->streams[n]->codec->lav_codecpar); -#endif - } } if (priv->own_stream) free_stream(priv->stream); diff --git a/demux/stheader.h b/demux/stheader.h index 240be72a46fcf..26c1246d66c04 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -71,8 +71,6 @@ struct mp_codec_params { int extradata_size; // Codec specific header data (set by demux_lavf.c only) - // Which one is in use depends on HAVE_AVCODEC_HAS_CODECPAR. - struct AVCodecContext *lav_headers; struct AVCodecParameters *lav_codecpar; // Timestamp granularity for converting double<->rational timestamps. diff --git a/player/command.c b/player/command.c index 36850a2c5128a..74c7e26966bc1 100644 --- a/player/command.c +++ b/player/command.c @@ -3569,11 +3569,7 @@ static int mp_property_configuration(void *ctx, struct m_property *prop, 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, diff --git a/sub/lavc_conv.c b/sub/lavc_conv.c index 3e0165a84cee4..3ff350c5907f7 100644 --- a/sub/lavc_conv.c +++ b/sub/lavc_conv.c @@ -210,9 +210,6 @@ static int parse_webvtt(AVPacket *in, AVPacket *pkt) pkt->pts = in->pts; pkt->duration = in->duration; -#if !HAVE_AV_AVPACKET_INT64_DURATION - pkt->convergence_duration = in->convergence_duration; -#endif return 0; } diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index 2c1b327b38df5..4ce8c5588c9d8 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -263,13 +263,8 @@ static void read_sub_bitmaps(struct sd *sd, struct sub *sub) struct sub_bitmap *b = &sub->inbitmaps[i]; struct pos pos = priv->packer->result[i]; struct AVSubtitleRect *r = b->bitmap; -#if HAVE_AV_SUBTITLE_NOPICT uint8_t **data = r->data; int *linesize = r->linesize; -#else - uint8_t **data = r->pict.data; - int *linesize = r->pict.linesize; -#endif b->w = r->w; b->h = r->h; b->x = r->x; diff --git a/video/csputils.c b/video/csputils.c index 8f6a9e351e62c..6835aeed2026f 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -190,10 +190,8 @@ enum mp_csp_trc avcol_trc_to_mp_csp_trc(int avtrc) case AVCOL_TRC_LINEAR: return MP_CSP_TRC_LINEAR; case AVCOL_TRC_GAMMA22: return MP_CSP_TRC_GAMMA22; case AVCOL_TRC_GAMMA28: return MP_CSP_TRC_GAMMA28; -#if HAVE_AVUTIL_HDR case AVCOL_TRC_SMPTEST2084: return MP_CSP_TRC_SMPTE_ST2084; case AVCOL_TRC_ARIB_STD_B67: return MP_CSP_TRC_ARIB_STD_B67; -#endif default: return MP_CSP_TRC_AUTO; } } @@ -242,10 +240,8 @@ int mp_csp_trc_to_avcol_trc(enum mp_csp_trc trc) case MP_CSP_TRC_LINEAR: return AVCOL_TRC_LINEAR; case MP_CSP_TRC_GAMMA22: return AVCOL_TRC_GAMMA22; case MP_CSP_TRC_GAMMA28: return AVCOL_TRC_GAMMA28; -#if HAVE_AVUTIL_HDR case MP_CSP_TRC_SMPTE_ST2084: return AVCOL_TRC_SMPTEST2084; case MP_CSP_TRC_ARIB_STD_B67: return AVCOL_TRC_ARIB_STD_B67; -#endif default: return AVCOL_TRC_UNSPECIFIED; } } diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index d25c99981e573..4a250600812d4 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -663,11 +663,9 @@ static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx, MP_VERBOSE(vd, " %s", av_get_pix_fmt_name(fmt[i])); MP_VERBOSE(vd, "\n"); -#if HAVE_AVCODEC_PROFILE_NAME const char *profile = avcodec_profile_name(avctx->codec_id, avctx->profile); MP_VERBOSE(vd, "Codec profile: %s (0x%x)\n", profile ? profile : "unknown", avctx->profile); -#endif assert(ctx->hwdec); @@ -794,7 +792,6 @@ static void decode(struct dec_video *vd, struct demux_packet *packet, reset_avctx(vd); hwdec_lock(ctx); -#if HAVE_AVCODEC_NEW_CODEC_API ret = avcodec_send_packet(avctx, packet ? &pkt : NULL); if (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { if (ret >= 0) @@ -807,10 +804,6 @@ static void decode(struct dec_video *vd, struct demux_packet *packet, } else { consumed = true; } -#else - ret = avcodec_decode_video2(avctx, ctx->pic, &got_picture, &pkt); - consumed = true; -#endif hwdec_unlock(ctx); // Reset decoder if it was fully flushed. Caller might send more flush @@ -864,7 +857,7 @@ static void decode(struct dec_video *vd, struct demux_packet *packet, return; } assert(mpi->planes[0] || mpi->planes[3]); - mpi->pts = mp_pts_from_av(MP_AVFRAME_DEC_PTS(ctx->pic), &ctx->codec_timebase); + mpi->pts = mp_pts_from_av(ctx->pic->pts, &ctx->codec_timebase); mpi->dts = mp_pts_from_av(ctx->pic->pkt_dts, &ctx->codec_timebase); struct mp_image_params params; diff --git a/video/fmt-conversion.c b/video/fmt-conversion.c index 8b991c5d19f9c..7a9e2088f82fc 100644 --- a/video/fmt-conversion.c +++ b/video/fmt-conversion.c @@ -73,10 +73,8 @@ static const struct { {IMGFMT_XYZ12, AV_PIX_FMT_XYZ12}, -#ifdef AV_PIX_FMT_RGBA64 {IMGFMT_RGBA64, AV_PIX_FMT_RGBA64}, {IMGFMT_BGRA64, AV_PIX_FMT_BGRA64}, -#endif #if LIBAVUTIL_VERSION_MICRO >= 100 {IMGFMT_BGR0, AV_PIX_FMT_BGR0}, @@ -90,9 +88,7 @@ static const struct { {IMGFMT_0BGR, AV_PIX_FMT_ABGR}, #endif -#ifdef AV_PIX_FMT_YA16 {IMGFMT_YA16, AV_PIX_FMT_YA16}, -#endif {IMGFMT_VDPAU, AV_PIX_FMT_VDPAU}, #if HAVE_VIDEOTOOLBOX_HWACCEL @@ -103,15 +99,11 @@ static const struct { #if HAVE_D3D_HWACCEL {IMGFMT_D3D11VA, AV_PIX_FMT_D3D11VA_VLD}, #endif -#if HAVE_AV_PIX_FMT_MMAL {IMGFMT_MMAL, AV_PIX_FMT_MMAL}, -#endif #if HAVE_CUDA_HWACCEL {IMGFMT_CUDA, AV_PIX_FMT_CUDA}, #endif -#ifdef AV_PIX_FMT_P010 {IMGFMT_P010, AV_PIX_FMT_P010}, -#endif #ifdef AV_PIX_FMT_P016 {IMGFMT_P016, AV_PIX_FMT_P016}, #endif diff --git a/video/image_writer.c b/video/image_writer.c index 8a5980c98e012..59d986f3fc465 100644 --- a/video/image_writer.c +++ b/video/image_writer.c @@ -133,7 +133,6 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp pic->color_trc = mp_csp_trc_to_avcol_trc(image->params.color.gamma); } -#if HAVE_AVCODEC_NEW_CODEC_API int ret = avcodec_send_frame(avctx, pic); if (ret < 0) goto error_exit; @@ -142,11 +141,6 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp if (ret < 0) goto error_exit; got_output = 1; -#else - int ret = avcodec_encode_video2(avctx, &pkt, pic, &got_output); - if (ret < 0) - goto error_exit; -#endif fwrite(pkt.data, pkt.size, 1, fp); diff --git a/video/img_format.c b/video/img_format.c index 24545a85017c2..0232f53890071 100644 --- a/video/img_format.c +++ b/video/img_format.c @@ -161,21 +161,14 @@ struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt) int shift = -1; // shift for all components, or -1 if not uniform for (int c = 0; c < pd->nb_components; c++) { AVComponentDescriptor d = pd->comp[c]; -#if HAVE_AV_NEW_PIXDESC - int depth = d.depth; - int step = d.step; -#else - int depth = d.depth_minus1 + 1; - int step = d.step_minus1 + 1; -#endif // multiple components per plane -> Y is definitive, ignore chroma if (!desc.bpp[d.plane]) - desc.bpp[d.plane] = step * el_size; - planedepth[d.plane] += depth; - need_endian |= (depth + d.shift) > 8; + desc.bpp[d.plane] = d.step * el_size; + planedepth[d.plane] += d.depth; + need_endian |= (d.depth + d.shift) > 8; if (c == 0) - desc.component_bits = depth; - if (depth != desc.component_bits) + desc.component_bits = d.depth; + if (d.depth != desc.component_bits) desc.component_bits = 0; if (c == 0) shift = d.shift; diff --git a/video/mp_image.c b/video/mp_image.c index b56c9e60b3bad..ee1ab4104eb47 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -744,9 +744,7 @@ struct mp_image *mp_image_from_av_frame(struct AVFrame *av_frame) mp_image_copy_fields_from_av_frame(&t, av_frame); for (int p = 0; p < MP_MAX_PLANES; p++) t.bufs[p] = av_frame->buf[p]; -#if HAVE_AVUTIL_HAS_HWCONTEXT t.hwctx = av_frame->hw_frames_ctx; -#endif return mp_image_new_ref(&t); } @@ -763,9 +761,7 @@ struct AVFrame *mp_image_to_av_frame(struct mp_image *img) mp_image_copy_fields_to_av_frame(frame, new_ref); for (int p = 0; p < MP_MAX_PLANES; p++) frame->buf[p] = new_ref->bufs[p]; -#if HAVE_AVUTIL_HAS_HWCONTEXT frame->hw_frames_ctx = new_ref->hwctx; -#endif *new_ref = (struct mp_image){0}; talloc_free(new_ref); return frame; diff --git a/video/out/vo_lavc.c b/video/out/vo_lavc.c index 1721136f8ba2e..5c7406d4b9cfb 100644 --- a/video/out/vo_lavc.c +++ b/video/out/vo_lavc.c @@ -241,7 +241,6 @@ static void encode_video_and_write(struct vo *vo, AVFrame *frame) struct priv *vc = vo->priv; AVPacket packet = {0}; -#if HAVE_AVCODEC_NEW_CODEC_API int status = avcodec_send_frame(vc->codec, frame); if (status < 0) { MP_ERR(vo, "error encoding at %d %d/%d\n", @@ -276,24 +275,6 @@ static void encode_video_and_write(struct vo *vo, AVFrame *frame) write_packet(vo, &packet); av_packet_unref(&packet); } -#else - av_init_packet(&packet); - int got_packet = 0; - int status = avcodec_encode_video2(vc->codec, &packet, frame, &got_packet); - if (status < 0) { - MP_ERR(vo, "error encoding at %d %d/%d\n", - frame ? (int) frame->pts : -1, - vc->codec->time_base.num, - vc->codec->time_base.den); - return; - } - if (!got_packet) { - return; - } - encode_lavc_write_stats(vo->encode_lavc_ctx, vc->codec); - write_packet(vo, &packet); - av_packet_unref(&packet); -#endif } static void draw_image_unlocked(struct vo *vo, mp_image_t *mpi) diff --git a/wscript b/wscript index 37114fafb4325..83d74c5f21ecd 100644 --- a/wscript +++ b/wscript @@ -476,80 +476,13 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_ 'func': check_statement('libavutil/frame.h', 'enum AVFrameSideDataType type = AV_FRAME_DATA_SKIP_SAMPLES', use='libav') - }, { - 'name': 'av-pix-fmt-mmal', - 'desc': 'libavutil AV_PIX_FMT_MMAL', - 'func': check_statement('libavutil/pixfmt.h', - 'int x = AV_PIX_FMT_MMAL', - use='libav'), - }, { - 'name': 'av-version-info', - 'desc': 'libavtuil av_version_info()', - 'func': check_statement('libavutil/avutil.h', - 'const char *x = av_version_info()', - use='libav'), - }, { - 'name': 'av-new-pixdesc', - 'desc': 'libavutil new pixdesc fields', - 'func': check_statement('libavutil/pixdesc.h', - 'AVComponentDescriptor d; int x = d.depth', - use='libav'), - }, { - 'name': 'av-avpacket-int64-duration', - 'desc': 'libavcodec 64 bit AVPacket.duration', - 'func': check_statement('libavcodec/avcodec.h', - 'int x[(int)sizeof(((AVPacket){0}).duration) - 7]', - use='libav'), - }, { - 'name': 'av-subtitle-nopict', - 'desc': 'libavcodec AVSubtitleRect AVPicture removal', - 'func': check_statement('libavcodec/avcodec.h', - 'AVSubtitleRect r = {.linesize={0}}', - use='libav'), - }, { - 'name': 'avcodec-profile-name', - 'desc': 'libavcodec avcodec_profile_name()', - 'func': check_statement('libavcodec/avcodec.h', - 'avcodec_profile_name(0,0)', - use='libav'), - }, { - 'name': 'avcodec-new-codec-api', - 'desc': 'libavcodec decode/encode API', - 'func': check_statement('libavcodec/avcodec.h', - 'avcodec_send_packet(0,0)', - use='libav'), - }, { - 'name': 'avcodec-has-codecpar', - 'desc': 'libavcodec AVCodecParameters API', - 'func': check_statement('libavformat/avformat.h', - '(void)offsetof(AVStream, codecpar)', - use='libav'), - }, { - 'name': 'avutil-has-hwcontext', - 'desc': 'libavutil AVHWFramesContext API', - 'func': check_statement('libavutil/frame.h', - '(void)offsetof(AVFrame, hw_frames_ctx)', - use='libav'), - }, { - 'name': 'avutil-hdr', - 'desc': 'libavutil HDR TRCs', - 'func': check_statement('libavutil/pixfmt.h', - 'AVCOL_TRC_SMPTEST2084,' - 'AVCOL_TRC_ARIB_STD_B67', - use='libav'), }, { 'name': 'avutil-mastering-metadata', 'desc': 'libavutil mastering display metadata struct', 'func': check_statement('libavutil/frame.h', 'AV_FRAME_DATA_MASTERING_DISPLAY_METADATA', use='libav'), - }, { - 'name': 'avformat-ioopen', - 'desc': 'libavformat io_open callback', - 'func': check_statement('libavformat/avformat.h', - 'offsetof(AVFormatContext, io_open)', - use='libav'), - } + }, ] audio_output_features = [ From 51fd8f6fe16ef0a8fa35aec89cab82d435e4d4d9 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 8 Dec 2016 10:59:50 +0100 Subject: [PATCH 48/83] vo_rpi: partially undeprecate Using vo_opengl + MMAL overlay didn't quite work out. --- video/out/vo.c | 6 +++--- video/out/vo_rpi.c | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/video/out/vo.c b/video/out/vo.c index 72a47af227d64..64bf7ab0512e3 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -63,6 +63,9 @@ extern const struct vo_driver video_out_tct; const struct vo_driver *const video_out_drivers[] = { +#if HAVE_RPI + &video_out_rpi, +#endif #if HAVE_GL &video_out_opengl, #endif @@ -102,9 +105,6 @@ const struct vo_driver *const video_out_drivers[] = #endif #if HAVE_GL &video_out_opengl_cb, -#endif -#if HAVE_RPI - &video_out_rpi, #endif NULL }; diff --git a/video/out/vo_rpi.c b/video/out/vo_rpi.c index 4824ac2616f20..139da95ed94f5 100644 --- a/video/out/vo_rpi.c +++ b/video/out/vo_rpi.c @@ -869,9 +869,6 @@ static void uninit(struct vo *vo) static int preinit(struct vo *vo) { - MP_WARN(vo, "This VO is deprecated! Use --vo=opengl instead (which has " - "the same features and which is the default).\n"); - struct priv *p = vo->priv; p->background_layer = p->layer; From a8b8295f8d15b12d95ae25827831c4fc05a53bfa Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 8 Dec 2016 12:39:49 +0100 Subject: [PATCH 49/83] options: remove weird RPI-only fullscreen default As announced by interface-changes.rst. --- options/options.c | 1 - 1 file changed, 1 deletion(-) diff --git a/options/options.c b/options/options.c index c57847bc284cd..08037b42fe464 100644 --- a/options/options.c +++ b/options/options.c @@ -223,7 +223,6 @@ const struct m_sub_options vo_sub_opts = { .window_scale = 1.0, .x11_bypass_compositor = 2, .mmcss_profile = "Playback", - .fullscreen = HAVE_RPI ? 1 : 0, }, }; From 736cd7336a2147ef9955510b0a006184cfbaeb84 Mon Sep 17 00:00:00 2001 From: Akemi Date: Mon, 5 Dec 2016 03:53:18 +0100 Subject: [PATCH 50/83] manpage: remove mention of window alpha (OSX) This is not implemented and i don't even know if it ever was. Also remove a trailing whitespace. Fixes #3866 --- DOCS/man/mpv.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst index 4ceae1ca27e93..e40acdcff1086 100644 --- a/DOCS/man/mpv.rst +++ b/DOCS/man/mpv.rst @@ -208,9 +208,6 @@ Alt+2 (and command+2 on OSX) command + f (OSX only) Toggle fullscreen (see also ``--fs``). -command + [ and command + ] (OSX only) - Set video window alpha. - (The following keys are valid if you have a keyboard with multimedia keys.) PAUSE @@ -431,7 +428,7 @@ tree and play the longest title. a bitmap video stream which can be superimposed over the main movie. mpv's subtitle styling and positioning options and keyboard shortcuts generally do not work with image-based subtitles. - Exceptions include options like ``--stretch-dvd-subs`` and + Exceptions include options like ``--stretch-dvd-subs`` and ``--stretch-image-subs-to-screen``. From 2aebf3e482a7b9ee7bc4e46e3c72b3a20278f5b4 Mon Sep 17 00:00:00 2001 From: Douglas Christman Date: Thu, 8 Dec 2016 12:08:04 -0500 Subject: [PATCH 51/83] manpage: replace `-vo` with `--vo` --- DOCS/man/options.rst | 4 ++-- player/video.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 84d417fb1d4f4..3f7eb35b15173 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -2325,7 +2325,7 @@ Window ensure it does not cause security problems (e.g. make sure to use full paths if "." is in your path like on Windows). It also only works when playing video (i.e. not with ``--no-video`` but works with - ``-vo=null``). + ``--vo=null``). This can be "misused" to disable screensavers that do not support the proper X API (see also ``--stop-screensaver``). If you think this is too @@ -3817,7 +3817,7 @@ OpenGL renderer options ----------------------- The following video options are currently all specific to ``--vo=opengl`` and -``-vo=opengl-cb`` only, which are the only VOs that implement them. +``--vo=opengl-cb`` only, which are the only VOs that implement them. ``--scale=`` diff --git a/player/video.c b/player/video.c index 847a5b56d9c34..03dd5aeabec58 100644 --- a/player/video.c +++ b/player/video.c @@ -473,7 +473,7 @@ int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src) mpctx->video_out = init_best_video_out(mpctx->global, &ex); if (!mpctx->video_out) { MP_FATAL(mpctx, "Error opening/initializing " - "the selected video_out (-vo) device.\n"); + "the selected video_out (--vo) device.\n"); mpctx->error_playing = MPV_ERROR_VO_INIT_FAILED; goto err_out; } From 0eb87e1baff89e7a979df23f31ca918f9d107e44 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 9 Dec 2016 19:48:47 +0100 Subject: [PATCH 52/83] charset_conv: drop enca and libguess support Enca is dead. libguess is relatively useless due to not having an universal detection mode. On the other hand, libuchardet is actively developed. Manpages changes in the following commit. --- misc/charset_conv.c | 67 --------------------------------------------- wscript | 10 ------- 2 files changed, 77 deletions(-) diff --git a/misc/charset_conv.c b/misc/charset_conv.c index 48e4e9a5aeabc..53e3a9db69d22 100644 --- a/misc/charset_conv.c +++ b/misc/charset_conv.c @@ -28,14 +28,6 @@ #include "common/msg.h" -#if HAVE_ENCA -#include -#endif - -#if HAVE_LIBGUESS -#include -#endif - #if HAVE_UCHARDET #include #endif @@ -111,57 +103,6 @@ static const char *ms_bom_guess(bstr buf) return NULL; } -#if HAVE_ENCA -static const char *enca_guess(struct mp_log *log, bstr buf, const char *language) -{ - // Do our own UTF-8 detection, because ENCA seems to get it wrong sometimes - // (suggested by divVerent). Explicitly allow cut-off UTF-8. - if (bstr_validate_utf8(buf) > -8) - return "UTF-8"; - - if (!language || !language[0]) - language = "__"; // neutral language - - const char *detected_cp = NULL; - - EncaAnalyser analyser = enca_analyser_alloc(language); - if (analyser) { - enca_set_termination_strictness(analyser, 0); - EncaEncoding enc = enca_analyse_const(analyser, buf.start, buf.len); - const char *tmp = enca_charset_name(enc.charset, ENCA_NAME_STYLE_ICONV); - if (tmp && enc.charset != ENCA_CS_UNKNOWN) - detected_cp = tmp; - enca_analyser_free(analyser); - } else { - mp_err(log, "ENCA doesn't know language '%s'\n", language); - size_t langcnt; - const char **languages = enca_get_languages(&langcnt); - mp_err(log, "ENCA supported languages:"); - for (int i = 0; i < langcnt; i++) - mp_err(log, " %s", languages[i]); - mp_err(log, "\n"); - free(languages); - } - - return detected_cp; -} -#endif - -#if HAVE_LIBGUESS -static const char *libguess_guess(struct mp_log *log, bstr buf, - const char *language) -{ - if (!language || !language[0] || strcmp(language, "help") == 0) { - mp_err(log, "libguess needs a language: " - "japanese taiwanese chinese korean russian arabic turkish " - "greek hebrew polish baltic\n"); - return NULL; - } - - return libguess_determine_encoding(buf.start, buf.len, language); -} -#endif - #if HAVE_UCHARDET static const char *mp_uchardet(void *talloc_ctx, struct mp_log *log, bstr buf) { @@ -232,14 +173,6 @@ const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf, type = bstr0("auto"); } -#if HAVE_ENCA - if (bstrcasecmp0(type, "enca") == 0) - res = enca_guess(log, buf, lang); -#endif -#if HAVE_LIBGUESS - if (bstrcasecmp0(type, "guess") == 0) - res = libguess_guess(log, buf, lang); -#endif #if HAVE_UCHARDET if (bstrcasecmp0(type, "uchardet") == 0) res = mp_uchardet(talloc_ctx, log, buf); diff --git a/wscript b/wscript index 83d74c5f21ecd..9d9c6a8047623 100644 --- a/wscript +++ b/wscript @@ -355,16 +355,6 @@ iconv support use --disable-iconv.", 'name': '--cdda', 'desc': 'cdda support (libcdio)', 'func': check_pkg_config('libcdio_paranoia'), - }, { - 'name': '--enca', - 'desc': 'ENCA support', - 'deps': [ 'iconv' ], - 'func': check_statement('enca.h', 'enca_get_languages(NULL)', lib='enca'), - }, { - 'name': '--libguess', - 'desc': 'libguess support', - 'deps': [ 'iconv' ], - 'func': check_pkg_config('libguess', '>= 1.0'), }, { 'name': '--uchardet', 'desc': 'uchardet support', From c324bfab594cc9228f699d86c74e2b0da049bf58 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 9 Dec 2016 19:51:29 +0100 Subject: [PATCH 53/83] charset_conv: simplify and change --sub-codepage option As documented in interface-changes.rst. This makes it much easier to follow what the heck is going on. Whether this is adequate for real-world use is unknown. --- DOCS/interface-changes.rst | 6 +++ DOCS/man/options.rst | 69 +++++++--------------------- misc/charset_conv.c | 93 ++++++++++++++++++++------------------ misc/charset_conv.h | 1 - 4 files changed, 72 insertions(+), 97 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index cf53a934a19e8..a33968307e614 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -36,6 +36,12 @@ Interface changes - remove --vo-defaults and --ao-defaults as well - remove deprecated global sub-options (like -demuxer-rawaudio format=...), use flat options (like --demuxer-rawaudio-format=...) + - the --sub-codepage option changes in incompatible ways: + - detector-selection and fallback syntax is deprecated + - enca/libguess are removed and deprecated (behaves as if they hadn't + been compiled-in) + - --sub-codepage= does not force the codepage anymore + (this requires different and new syntax) --- mpv 0.22.0 --- - the "audio-device-list" property now sets empty device description to the device name as a fallback diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 3f7eb35b15173..e5703cfca251f 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -1754,66 +1754,31 @@ Subtitles :all: Load all subs in the current and ``--sub-paths`` directories. ``--sub-codepage=`` - If your system supports ``iconv(3)``, you can use this option to specify - the subtitle codepage. By default, uchardet will be used to guess the - charset. If mpv is not compiled with uchardet, enca will be used. - If mpv is compiled with neither uchardet nor enca, ``UTF-8:UTF-8-BROKEN`` - is the default, which means it will try to use UTF-8, otherwise the - ``UTF-8-BROKEN`` pseudo codepage (see below). + You can use this option to specify the subtitle codepage. uchardet will be + used to guess the charset. (If mpv was not compiled with uchardet, then + ``utf-8`` is the effective default.) - The default value for this option is ``auto``, whose actual effect depends - on whether ENCA is compiled. + The default value for this option is ``auto``, which enables autodetection. - .. admonition:: Warning - - If you force the charset, even subtitles that are known to be - UTF-8 will be recoded, which is perhaps not what you expect. Prefix - codepages with ``utf8:`` if you want the codepage to be used only if the - input is not valid UTF-8. - - .. admonition:: Examples - - - ``--sub-codepage=utf8:latin2`` Use Latin 2 if input is not UTF-8. - - ``--sub-codepage=cp1250`` Always force recoding to cp1250. - - The pseudo codepage ``UTF-8-BROKEN`` is used internally. When it - is the codepage, subtitles are interpreted as UTF-8 with "Latin 1" as - fallback for bytes which are not valid UTF-8 sequences. iconv is - never involved in this mode. + The following steps are taken to determine the final codepage, in order: - If the player was compiled with ENCA support, you can control it with the - following syntax: - - ``--sub-codepage=enca::`` - - Language is specified using a two letter code to help ENCA detect - the codepage automatically. If an invalid language code is - entered, mpv will complain and list valid languages. (Note - however that this list will only be printed when the conversion code is actually - called, for example when loading an external subtitle). The - fallback codepage is used if autodetection fails. If no fallback - is specified, ``UTF-8-BROKEN`` is used. + - if the specific codepage has a ``+``, use that codepage + - if the data looks like UTF-8, assume it is UTF-8 + - if ``--sub-codepage`` is set to a specific codepage, use that + - run uchardet, and if successful, use that + - otherwise, use ``UTF-8-BROKEN`` .. admonition:: Examples - - ``--sub-codepage=enca:pl:cp1250`` guess the encoding, assuming the subtitles - are Polish, fall back on cp1250 - - ``--sub-codepage=enca:pl`` guess the encoding for Polish, fall back on UTF-8. - - ``--sub-codepage=enca`` try universal detection, fall back on UTF-8. - - If the player was compiled with libguess support, you can use it with: - - ``--sub-codepage=guess::`` - - libguess always needs a language. There is no universal detection - mode. Use ``--sub-codepage=guess:help`` to get a list of - languages subject to the same caveat as with ENCA above. - - If the player was compiled with uchardet support you can use it with: + - ``--sub-codepage=latin2`` Use Latin 2 if input is not UTF-8. + - ``--sub-codepage=+cp1250`` Always force recoding to cp1250. - ``--sub-codepage=uchardet`` + The pseudo codepage ``UTF-8-BROKEN`` is used internally. If it's set, + subtitles are interpreted as UTF-8 with "Latin 1" as fallback for bytes + which are not valid UTF-8 sequences. iconv is never involved in this mode. - This mode doesn't take language or fallback codepage. + This option changed in mpv 0.23.0. The old syntax is still emulated to some + degree. ``--sub-fix-timing``, ``--no-sub-fix-timing`` By default, subtitle timing is adjusted to remove minor gaps or overlaps diff --git a/misc/charset_conv.c b/misc/charset_conv.c index 53e3a9db69d22..1758223f1a277 100644 --- a/misc/charset_conv.c +++ b/misc/charset_conv.c @@ -73,24 +73,6 @@ static int split_colon(const char *user_cp, int max, bstr *out_arr) return count; } -// Returns true if user_cp implies that calling mp_charset_guess() on the -// input data is required to determine the real codepage. This is the case -// if user_cp is not a real iconv codepage, but a magic value that requests -// for example ENCA charset auto-detection. -bool mp_charset_requires_guess(const char *user_cp) -{ - bstr res[2] = {{0}}; - int r = split_colon(user_cp, 2, res); - // Note that "utf8" is the UTF-8 codepage, while "utf8:..." specifies UTF-8 - // by default, plus a codepage that is used if the input is not UTF-8. - return bstrcasecmp0(res[0], "enca") == 0 || - bstrcasecmp0(res[0], "uchardet") == 0 || - bstrcasecmp0(res[0], "auto") == 0 || - bstrcasecmp0(res[0], "guess") == 0 || - (r > 1 && bstrcasecmp0(res[0], "utf-8") == 0) || - (r > 1 && bstrcasecmp0(res[0], "utf8") == 0); -} - static const char *const utf_bom[3] = {"\xEF\xBB\xBF", "\xFF\xFE", "\xFE\xFF"}; static const char *const utf_enc[3] = {"utf-8", "utf-16le", "utf-16be"}; @@ -118,17 +100,15 @@ static const char *mp_uchardet(void *talloc_ctx, struct mp_log *log, bstr buf) if (res && !res[0]) res = NULL; if (res) { + mp_verbose(log, "libuchardet detected charset as %s\n", res); iconv_t icdsc = iconv_open("UTF-8", res); if (icdsc == (iconv_t)(-1)) { - mp_warn(log, "Charset detected as %s, but not supported by iconv.\n", - res); + mp_warn(log, "Charset '%s' not supported by iconv.\n", res); res = NULL; } else { iconv_close(icdsc); } } - if (!res && bstr_validate_utf8(buf) >= 0) - res = "utf-8"; uchardet_delete(det); return res; } @@ -140,22 +120,11 @@ static const char *mp_uchardet(void *talloc_ctx, struct mp_log *log, bstr buf) // it's a real iconv codepage), user_cp is returned without even looking at // the buf data. // The return value may (but doesn't have to) be allocated under talloc_ctx. -const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf, - const char *user_cp, int flags) +static const char *mp_charset_guess_compat(void *talloc_ctx, struct mp_log *log, + bstr buf, const char *user_cp, + int flags) { - if (!mp_charset_requires_guess(user_cp)) - return user_cp; - - bool use_auto = strcasecmp(user_cp, "auto") == 0; - if (use_auto) { -#if HAVE_UCHARDET - user_cp = "uchardet"; -#elif HAVE_ENCA - user_cp = "enca"; -#else - user_cp = "UTF-8:UTF-8-BROKEN"; -#endif - } + mp_warn(log, "This syntax for the --sub-codepage option is deprecated.\n"); bstr params[3] = {{0}}; split_colon(user_cp, 3, params); @@ -167,15 +136,12 @@ const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf, const char *res = NULL; - if (use_auto) { - res = ms_bom_guess(buf); - if (res) - type = bstr0("auto"); - } - #if HAVE_UCHARDET - if (bstrcasecmp0(type, "uchardet") == 0) + if (bstrcasecmp0(type, "uchardet") == 0) { res = mp_uchardet(talloc_ctx, log, buf); + if (!res && bstr_validate_utf8(buf) >= 0) + res = "utf-8"; + } #endif if (bstrcasecmp0(type, "utf8") == 0 || bstrcasecmp0(type, "utf-8") == 0) { @@ -201,6 +167,45 @@ const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf, return res; } +const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf, + const char *user_cp, int flags) +{ + if (strcasecmp(user_cp, "enca") == 0 || strcasecmp(user_cp, "guess") == 0 || + strcasecmp(user_cp, "uchardet") == 0 || strchr(user_cp, ':')) + return mp_charset_guess_compat(talloc_ctx, log, buf, user_cp, flags); + + if (user_cp[0] == '+') { + mp_verbose(log, "Forcing charset '%s'.\n", user_cp + 1); + return user_cp + 1; + } + + const char *bom_cp = ms_bom_guess(buf); + if (bom_cp) { + mp_verbose(log, "Data has a BOM, assuming %s as charset.\n", bom_cp); + return bom_cp; + } + + int r = bstr_validate_utf8(buf); + if (r >= 0 || (r > -8 && (flags & MP_ICONV_ALLOW_CUTOFF))) { + mp_verbose(log, "Data looks like UTF-8, ignoring user-provided charset.\n"); + return "utf-8"; + } + + const char *res = user_cp; + if (strcasecmp(user_cp, "auto") == 0) { +#if HAVE_UCHARDET + res = mp_uchardet(talloc_ctx, log, buf); +#endif + if (!res) { + mp_verbose(log, "Charset auto-detection failed.\n"); + res = "UTF-8-BROKEN"; + } + } + + mp_verbose(log, "Using charset '%s'.\n", res); + return res; +} + // Use iconv to convert buf to UTF-8. // Returns buf.start==NULL on error. Returns buf if cp is NULL, or if there is // obviously no conversion required (e.g. if cp is "UTF-8"). diff --git a/misc/charset_conv.h b/misc/charset_conv.h index ddfabbe49e84b..9be7a5096119c 100644 --- a/misc/charset_conv.h +++ b/misc/charset_conv.h @@ -14,7 +14,6 @@ enum { bool mp_charset_is_utf8(const char *user_cp); bool mp_charset_is_utf16(const char *user_cp); -bool mp_charset_requires_guess(const char *user_cp); const char *mp_charset_guess(void *talloc_ctx, struct mp_log *log, bstr buf, const char *user_cp, int flags); bstr mp_iconv_to_utf8(struct mp_log *log, bstr buf, const char *cp, int flags); From 82855bec5036817f64ec90bae48135f5589ed1a5 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 9 Dec 2016 21:31:45 +0100 Subject: [PATCH 54/83] client API: allow passing NULL to mpv_opengl_cb_uninit_gl() In which case it does nothing. --- video/out/vo_opengl_cb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/video/out/vo_opengl_cb.c b/video/out/vo_opengl_cb.c index 85e06ff598ba1..852b7900dab78 100644 --- a/video/out/vo_opengl_cb.c +++ b/video/out/vo_opengl_cb.c @@ -204,6 +204,9 @@ int mpv_opengl_cb_init_gl(struct mpv_opengl_cb_context *ctx, const char *exts, int mpv_opengl_cb_uninit_gl(struct mpv_opengl_cb_context *ctx) { + if (!ctx) + return 0; + // Bring down the decoder etc., which still might be using the hwdec // context. Setting initialized=false guarantees it can't come back. From 0aa9b2a46973699ae0eb5aa2f8eed16311bdab2d Mon Sep 17 00:00:00 2001 From: shinchiro Date: Sun, 11 Dec 2016 08:01:42 +0800 Subject: [PATCH 55/83] wscript_build: rst2pdf: increase section break level This fix broken pdf build and hopefully less fragile in future --- wscript_build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wscript_build.py b/wscript_build.py index 43e3dd8c9cba0..461e971f66f6b 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -38,7 +38,7 @@ def _build_pdf(ctx): name = 'rst2pdf', target = 'DOCS/man/mpv.pdf', source = 'DOCS/man/mpv.rst', - rule = '${RST2PDF} -c --repeat-table-rows ${SRC} -o ${TGT}', + rule = '${RST2PDF} -c -b 1 --repeat-table-rows ${SRC} -o ${TGT}', install_path = ctx.env.DOCDIR) _add_rst_manual_dependencies(ctx) From 2d9b6ff7cd51c352533e13bb24624c387415dbfb Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Sun, 3 Jul 2016 17:41:45 -0700 Subject: [PATCH 56/83] ad_spdif: Fix crash when spdif muxer is not available Currently, if init_filter fails after lavf_ctx is allocated, uninit is called which frees lavf_ctx, but doesn't clear the pointer in spdif_ctx. So, on the next call of decode_packet, it thinks it is already initialized and uses it, resulting in a crash on my system. --- audio/decode/ad_spdif.c | 1 + 1 file changed, 1 insertion(+) diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c index e15aca5c535c6..60aef3b18f1d3 100644 --- a/audio/decode/ad_spdif.c +++ b/audio/decode/ad_spdif.c @@ -71,6 +71,7 @@ static void uninit(struct dec_audio *da) av_freep(&lavf_ctx->pb->buffer); av_freep(&lavf_ctx->pb); avformat_free_context(lavf_ctx); + spdif_ctx->lavf_ctx = NULL; } } From c21c68edd48ab45af1dd33c09ec809d1ee100ce1 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 11 Dec 2016 18:09:44 +0100 Subject: [PATCH 57/83] bstr: change to LGPL Was started by Uoti Urpala in commit 5f631d1c. Although it was made part of demux_mkv.c, it's quite obvious that it's not based on any pre-existing demux_mkv.c code (or ebml.c/.h for that matter). Anyone else who has touched this code every since has already agreed to LGPL relicensing. --- misc/bstr.c | 14 +++++++------- misc/bstr.h | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/misc/bstr.c b/misc/bstr.c index 0ef0c357e8c95..8c47b447d4f8c 100644 --- a/misc/bstr.c +++ b/misc/bstr.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/misc/bstr.h b/misc/bstr.h index 4aba35e965105..69dbce20ebd08 100644 --- a/misc/bstr.h +++ b/misc/bstr.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 MPLAYER_BSTR_H From 4399be5b624805ef70848ff010fb6ee6ad920e9f Mon Sep 17 00:00:00 2001 From: pavelxdd Date: Sun, 11 Dec 2016 00:50:11 +0300 Subject: [PATCH 58/83] win32: update winapi functions names According to MSDN, GetWindowLong and SetWindowLong have been superseded by GetWindowLongPtr and SetWindowLongPtr. It's a cosmetic code change in this case. --- video/out/w32_common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/video/out/w32_common.c b/video/out/w32_common.c index f4fbb20ea93b5..5149339b6a391 100644 --- a/video/out/w32_common.c +++ b/video/out/w32_common.c @@ -320,7 +320,7 @@ static void DropTarget_Init(DropTarget* This, struct vo_w32_state *w32) static void add_window_borders(HWND hwnd, RECT *rc) { - AdjustWindowRect(rc, GetWindowLong(hwnd, GWL_STYLE), 0); + AdjustWindowRect(rc, GetWindowLongPtrW(hwnd, GWL_STYLE), 0); } // basically a reverse AdjustWindowRect (win32 doesn't appear to have this) @@ -1137,7 +1137,7 @@ static void reinit_window_state(struct vo_w32_state *w32) w32->window, w32->current_fs); } - DWORD style = update_style(w32, GetWindowLong(w32->window, GWL_STYLE)); + DWORD style = update_style(w32, GetWindowLongPtrW(w32->window, GWL_STYLE)); if (w32->opts->ontop) layer = HWND_TOPMOST; @@ -1180,7 +1180,7 @@ static void reinit_window_state(struct vo_w32_state *w32) r.top = w32->window_y; r.bottom = r.top + w32->dh; - SetWindowLong(w32->window, GWL_STYLE, style); + SetWindowLongPtrW(w32->window, GWL_STYLE, style); RECT cr = r; add_window_borders(w32->window, &r); From ed7e650d3a95a1d80d976ec4e2aa378e30c9db25 Mon Sep 17 00:00:00 2001 From: Akemi Date: Sun, 11 Dec 2016 23:35:48 +0100 Subject: [PATCH 59/83] osx: update the menu and remove conflicting item Remove 'Quit mpv & remember playback position' from the menu because it conflicts with the global logout shortcut. add separator between 'Hide' and 'Quit' for consistency with other Apps. also rename the 'Movie' menu to 'Video'. it's a bit more generic. Fixes #3865 --- osdep/macosx_application.m | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m index bf415d9576c5f..8808caa0a42df 100644 --- a/osdep/macosx_application.m +++ b/osdep/macosx_application.m @@ -50,7 +50,7 @@ - (NSMenuItem *)mainMenuItemWithParent:(NSMenu *)parent child:(NSMenu *)child; - (void)registerMenuItem:(NSMenuItem*)menuItem forKey:(MPMenuKey)key; - (NSMenu *)appleMenuWithMainMenu:(NSMenu *)mainMenu; -- (NSMenu *)movieMenu; +- (NSMenu *)videoMenu; - (NSMenu *)windowMenu; @end @@ -117,17 +117,15 @@ - (NSMenu *)appleMenuWithMainMenu:(NSMenu *)mainMenu [self mainMenuItemWithParent:mainMenu child:menu]; [self menuItemWithParent:menu title:@"Hide mpv" action:@selector(hide:) keyEquivalent: @"h"]; + [menu addItem:[NSMenuItem separatorItem]]; [self menuItemWithParent:menu title:@"Quit mpv" action:@selector(stopPlayback) keyEquivalent: @"q"]; - [self menuItemWithParent:menu title:@"Quit mpv & remember position" - action:@selector(stopPlaybackAndRememberPosition) - keyEquivalent: @"Q"]; return [menu autorelease]; } -- (NSMenu *)movieMenu +- (NSMenu *)videoMenu { - NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Movie"]; + NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Video"]; _R(menu, @"Half Size", @"0", MPM_H_SIZE) _R(menu, @"Normal Size", @"1", MPM_N_SIZE) _R(menu, @"Double Size", @"2", MPM_D_SIZE) @@ -148,7 +146,7 @@ - (void)initialize_menu [NSApp setMainMenu:main_menu]; [NSApp setAppleMenu:[self appleMenuWithMainMenu:main_menu]]; - [NSApp mainMenuItemWithParent:main_menu child:[self movieMenu]]; + [NSApp mainMenuItemWithParent:main_menu child:[self videoMenu]]; [NSApp mainMenuItemWithParent:main_menu child:[self windowMenu]]; } From 6b6789a47a3a5d872e6016625dd8609f8c632ebc Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 12 Dec 2016 12:02:13 +0100 Subject: [PATCH 60/83] manpage: clarify --loop option Fixes #3899. --- DOCS/man/options.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index e5703cfca251f..72eff0334d92d 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -134,11 +134,11 @@ Playback Control speed higher than normal automatically inserts the ``scaletempo`` audio filter. -``--loop=`` +``--loop=``, ``--loop`` Loops playback ``N`` times. A value of ``1`` plays it one time (default), ``2`` two times, etc. ``inf`` means forever. ``no`` is the same as ``1`` and disables looping. If several files are specified on command line, the - entire playlist is looped. + entire playlist is looped. ``--loop`` is the same as ``--loop=inf``. The ``force`` mode is like ``inf``, but does not skip playlist entries which have been marked as failing. This means the player might waste CPU From 765a7228d1815622ab0533cf2f1ffb3de04f24bc Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 12 Dec 2016 12:03:25 +0100 Subject: [PATCH 61/83] manpage: document current and legacy option syntax better I thought it ewas already documented, but I'm not seeing it anywhere. Maybe it did exist, but was deleted. See #3899. --- DOCS/man/mpv.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst index e40acdcff1086..aa68bee896aff 100644 --- a/DOCS/man/mpv.rst +++ b/DOCS/man/mpv.rst @@ -241,6 +241,16 @@ button 5 and button 6 USAGE ===== +Command line arguments starting with ``-`` are interpreted as options, +everything else as filenames or URLs. All options except *flag* options (or +choice options which include ``yes``) require a parameter in the form +``--option=value``. + +One exception is the lone ``-`` (without anything else), which means media data +will be read from stdin. Also, ``--`` (without anything else) will make the +player interpret all following arguments as filenames, even if they start with +``-``. (To play a file named ``-``, you need to use ``./-``.) + Every *flag* option has a *no-flag* counterpart, e.g. the opposite of the ``--fs`` option is ``--no-fs``. ``--fs=yes`` is same as ``--fs``, ``--fs=no`` is the same as ``--no-fs``. @@ -248,6 +258,24 @@ is the same as ``--no-fs``. If an option is marked as *(XXX only)*, it will only work in combination with the *XXX* option or if *XXX* is compiled in. +Legacy option syntax +-------------------- + +The ``--option=value`` syntax is not strictly enforced, and the alternative +legacy syntax ``-option value`` and ``--option value`` will also work. This is +mostly for compatibility with MPlayer. Using these should be avoided. Their +semantics can change any time in the future. + +For example, the alternative syntax will consider an argument following the +option a filename. ``mpv -fs no`` will attempt to play a file named ``no``, +because ``--fs`` is a flag option that requires no parameter. If an option +changes and its parameter becomes optional, then a command line using the +alternative syntax will break. + +Currently, the parser makes no difference whether an option starts with ``--`` +or a single ``-``. This might also change in the future, and ``--option value`` +might always interpret ``value`` as filename in order to reduce ambiguities. + Escaping spaces and other special characters -------------------------------------------- From bf5727a60fbae12510238c23a38b89822b128baa Mon Sep 17 00:00:00 2001 From: pavelxdd Date: Sun, 11 Dec 2016 00:01:39 +0300 Subject: [PATCH 62/83] win32: window styles improvements Allow minimizing the borderless/fullscreen window by clicking on the taskbar button or pressing Win+Down hotkey. Also fixes #2229 and probably fixes #2451 --- video/out/w32_common.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/video/out/w32_common.c b/video/out/w32_common.c index 5149339b6a391..5754a670de278 100644 --- a/video/out/w32_common.c +++ b/video/out/w32_common.c @@ -1112,10 +1112,15 @@ static void update_screen_rect(struct vo_w32_state *w32) static DWORD update_style(struct vo_w32_state *w32, DWORD style) { - const DWORD NO_FRAME = WS_OVERLAPPED; - const DWORD FRAME = WS_OVERLAPPEDWINDOW | WS_SIZEBOX; - style &= ~(NO_FRAME | FRAME); - style |= (w32->opts->border && !w32->current_fs) ? FRAME : NO_FRAME; + const DWORD NO_FRAME = WS_OVERLAPPED | WS_MINIMIZEBOX; + const DWORD FRAME = WS_OVERLAPPEDWINDOW; + const DWORD FULLSCREEN = NO_FRAME | WS_SYSMENU; + style &= ~(NO_FRAME | FRAME | FULLSCREEN); + if (w32->current_fs) { + style |= FULLSCREEN; + } else { + style |= w32->opts->border ? FRAME : NO_FRAME; + } return style; } From 3bb06155c9c02fb662aa012bf3873782f9256d4a Mon Sep 17 00:00:00 2001 From: Akemi Date: Tue, 13 Dec 2016 18:44:57 +0100 Subject: [PATCH 63/83] cocoa: support append file to paylist on drop When dropping a file on mpv, either on the window or the App bundle icon, while holding the shift key the dropped files will be appended to the playlist. Fixes #2166 --- osdep/macosx_events.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osdep/macosx_events.m b/osdep/macosx_events.m index 6ad22584dc996..c493c58c96a86 100644 --- a/osdep/macosx_events.m +++ b/osdep/macosx_events.m @@ -462,6 +462,9 @@ - (NSEvent*)handleKey:(NSEvent *)event - (void)handleFilesArray:(NSArray *)files { + enum mp_dnd_action action = [NSEvent modifierFlags] & + NSEventModifierFlagShift ? DND_APPEND : DND_REPLACE; + size_t num_files = [files count]; char **files_utf8 = talloc_array(NULL, char*, num_files); [files enumerateObjectsUsingBlock:^(NSString *p, NSUInteger i, BOOL *_){ @@ -473,7 +476,7 @@ - (void)handleFilesArray:(NSArray *)files }]; [_input_lock lock]; if (_inputContext) - mp_event_drop_files(_inputContext, num_files, files_utf8, DND_REPLACE); + mp_event_drop_files(_inputContext, num_files, files_utf8, action); [_input_lock unlock]; talloc_free(files_utf8); } From a6035439a9abc531f9229842708b89750fec82fd Mon Sep 17 00:00:00 2001 From: Akemi Date: Tue, 13 Dec 2016 21:37:05 +0100 Subject: [PATCH 64/83] cocoa: fix dropping of certain urls on the window the 'path' of an youtube url (youtube.com/watch?v=x) would just be '/watch'. obviously this fails to load. --- video/out/cocoa/events_view.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/video/out/cocoa/events_view.m b/video/out/cocoa/events_view.m index 4a0c4bfe04419..5de4a99eec23c 100644 --- a/video/out/cocoa/events_view.m +++ b/video/out/cocoa/events_view.m @@ -362,7 +362,12 @@ - (BOOL)performDragOperation:(id )sender options:@{}]; NSMutableArray* ar = [[[NSMutableArray alloc] init] autorelease]; for (NSURL* url in pbitems) { - [ar addObject:[url path]]; + if (url.fileURL) { + [ar addObject:[url path]]; + } + else { + [ar addObject:[url absoluteString]]; + } } [self.adapter handleFilesArray:ar]; return YES; From 544110bf430f34b75d86dd0ea416f8c5e5f9386d Mon Sep 17 00:00:00 2001 From: pavelxdd Date: Mon, 12 Dec 2016 19:39:00 +0300 Subject: [PATCH 65/83] win32: change the log level of 'move window' msg It does more harm than good, since it spams terminal a lot --- video/out/w32_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/out/w32_common.c b/video/out/w32_common.c index 5754a670de278..0de91482571ab 100644 --- a/video/out/w32_common.c +++ b/video/out/w32_common.c @@ -727,7 +727,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, signal_events(w32, VO_EVENT_WIN_STATE); update_display_info(w32); // if we moved between monitors - MP_VERBOSE(w32, "move window: %d:%d\n", w32->window_x, w32->window_y); + MP_DBG(w32, "move window: %d:%d\n", w32->window_x, w32->window_y); break; } case WM_SIZE: { From 870a6a11d99d67e5fcf1a1cb28c3de3167494470 Mon Sep 17 00:00:00 2001 From: Zhiming Wang Date: Tue, 13 Dec 2016 19:21:30 -0500 Subject: [PATCH 66/83] manpage: add table of contents to the HTML version The reST contents directive is added to mpv.rst. In wscript_build.py, the --strip-elements-with-class=contents option is needed for the rst2man call in order to prevent the TOC from appearing in mpv.1. --- DOCS/man/mpv.rst | 2 ++ wscript_build.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst index aa68bee896aff..71083060082cd 100644 --- a/DOCS/man/mpv.rst +++ b/DOCS/man/mpv.rst @@ -9,6 +9,8 @@ a media player :Manual section: 1 :Manual group: multimedia +.. contents:: Table of Contents + SYNOPSIS ======== diff --git a/wscript_build.py b/wscript_build.py index 461e971f66f6b..b7c7b39464b34 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -28,7 +28,7 @@ def _build_man(ctx): name = 'rst2man', target = 'DOCS/man/mpv.1', source = 'DOCS/man/mpv.rst', - rule = '${RST2MAN} ${SRC} ${TGT}', + rule = '${RST2MAN} --strip-elements-with-class=contents ${SRC} ${TGT}', install_path = ctx.env.MANDIR + '/man1') _add_rst_manual_dependencies(ctx) From a8347eb9ba9e09177da50592fde7f3ae7261ce59 Mon Sep 17 00:00:00 2001 From: Akemi Date: Sun, 4 Dec 2016 22:52:14 +0100 Subject: [PATCH 67/83] cocoa: fullscreen refactoring this replaces the old fullscreen with the native macOS fullscreen. additional the --fs-black-out-screens was removed since the new API doesn't support it in a way the old one did. it can possibly be re-added if done manually. Fixes #2857 #3272 #1352 #2062 #3864 --- DOCS/interface-changes.rst | 1 + DOCS/man/options.rst | 4 - options/options.c | 2 +- options/options.h | 1 - osdep/macosx_compat.h | 1 + video/out/cocoa/events_view.h | 2 - video/out/cocoa/events_view.m | 71 --------- video/out/cocoa/mpvadapter.h | 6 +- video/out/cocoa/window.m | 173 +++++++++++++++++++-- video/out/cocoa_common.m | 280 ++++++++++++++-------------------- 10 files changed, 281 insertions(+), 260 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index a33968307e614..fae6605dae7c2 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -42,6 +42,7 @@ Interface changes been compiled-in) - --sub-codepage= does not force the codepage anymore (this requires different and new syntax) + - remove --fs-black-out-screens option for macOS --- mpv 0.22.0 --- - the "audio-device-list" property now sets empty device description to the device name as a fallback diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 72eff0334d92d..e355d933d97c8 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -2026,10 +2026,6 @@ Window See also ``--screen``. -``--fs-black-out-screens`` - - OS X only. Black out other displays when going fullscreen. - ``--keep-open=`` Do not terminate when playing or seeking beyond the end of the file, and there is not next file to be played (and ``--loop`` is not used). diff --git a/options/options.c b/options/options.c index 08037b42fe464..76fabca256190 100644 --- a/options/options.c +++ b/options/options.c @@ -182,7 +182,6 @@ static const m_option_t mp_vo_opt_list[] = { ({"default", -1})), OPT_CHOICE_OR_INT("fs-screen", fsscreen_id, 0, 0, 32, ({"all", -2}, {"current", -1})), - OPT_FLAG("fs-black-out-screens", fs_black_out_screens, 0), OPT_FLAG("keepaspect", keepaspect, UPDATE_VIDEOPOS), OPT_FLAG("keepaspect-window", keepaspect_window, 0), OPT_FLAG("hidpi-window-scale", hidpi_window_scale, 0), @@ -796,6 +795,7 @@ const m_option_t mp_opts[] = { OPT_REPLACED("ass-shaper", "sub-ass-shaper"), OPT_REPLACED("ass-style-override", "sub-ass-style-override"), OPT_REPLACED("ass-scale-with-window", "sub-ass-scale-with-window"), + OPT_REMOVED("fs-black-out-screens", NULL), {0} }; diff --git a/options/options.h b/options/options.h index fa2a96c3b2654..fc37e98f8a234 100644 --- a/options/options.h +++ b/options/options.h @@ -18,7 +18,6 @@ typedef struct mp_vo_opts { int screen_id; int fsscreen_id; - int fs_black_out_screens; char *winname; int x11_netwm; int x11_bypass_compositor; diff --git a/osdep/macosx_compat.h b/osdep/macosx_compat.h index 76308c6f98ae1..9ef422be2fa16 100644 --- a/osdep/macosx_compat.h +++ b/osdep/macosx_compat.h @@ -31,6 +31,7 @@ static const NSWindowStyleMask NSWindowStyleMaskTitled = NSTitledWindowMask; static const NSWindowStyleMask NSWindowStyleMaskMiniaturizable = NSMiniaturizableWindowMask; static const NSWindowStyleMask NSWindowStyleMaskResizable = NSResizableWindowMask; static const NSWindowStyleMask NSWindowStyleMaskBorderless = NSBorderlessWindowMask; +static const NSWindowStyleMask NSWindowStyleMaskFullScreen = NSFullScreenWindowMask; static const NSEventType NSEventTypeSystemDefined = NSSystemDefined; static const NSEventType NSEventTypeKeyDown = NSKeyDown; diff --git a/video/out/cocoa/events_view.h b/video/out/cocoa/events_view.h index 3429563b4defd..6ad51cc133221 100644 --- a/video/out/cocoa/events_view.h +++ b/video/out/cocoa/events_view.h @@ -20,8 +20,6 @@ @interface MpvEventsView : NSView @property(nonatomic, retain) MpvCocoaAdapter *adapter; -- (void)setFullScreen:(BOOL)willBeFullscreen; -- (void)clear; - (BOOL)canHideCursor; - (void)signalMousePosition; @end diff --git a/video/out/cocoa/events_view.m b/video/out/cocoa/events_view.m index 5de4a99eec23c..53d1da86ff1cc 100644 --- a/video/out/cocoa/events_view.m +++ b/video/out/cocoa/events_view.m @@ -28,8 +28,6 @@ @interface MpvEventsView() @property(nonatomic, assign) BOOL clearing; @property(nonatomic, assign) BOOL hasMouseDown; @property(nonatomic, retain) NSTrackingArea *tracker; -- (BOOL)hasDock:(NSScreen*)screen; -- (BOOL)hasMenubar:(NSScreen*)screen; - (int)mpvButtonNumber:(NSEvent*)event; - (void)mouseDownEvent:(NSEvent *)event; - (void)mouseUpEvent:(NSEvent *)event; @@ -51,54 +49,6 @@ - (id)initWithFrame:(NSRect)frame { return self; } -- (void)setFullScreen:(BOOL)willBeFullscreen -{ - if (willBeFullscreen && ![self isInFullScreenMode]) { - NSApplicationPresentationOptions popts = - NSApplicationPresentationDefault; - - if ([self hasMenubar:[self.adapter fsScreen]]) - // Cocoa raises an exception when autohiding the menubar but - // not the dock. They probably got bored while programming the - // multi screen support and took some shortcuts (tested on 10.8). - popts |= NSApplicationPresentationAutoHideMenuBar | - NSApplicationPresentationAutoHideDock; - - if ([self hasDock:[self.adapter fsScreen]]) - popts |= NSApplicationPresentationAutoHideDock; - - NSDictionary *fsopts = @{ - NSFullScreenModeAllScreens : @([self.adapter fsModeAllScreens]), - NSFullScreenModeApplicationPresentationOptions : @(popts) - }; - - // The original "windowed" window will stay around since sending a - // view fullscreen wraps it in another window. This is noticeable when - // sending the View fullscreen to another screen. Make it go away - // manually. - [self.window orderOut:self]; - - [self enterFullScreenMode:[self.adapter fsScreen] - withOptions:fsopts]; - } - - if (!willBeFullscreen && [self isInFullScreenMode]) { - [self exitFullScreenModeWithOptions:nil]; - - // Show the "windowed" window again. - [self.window makeKeyAndOrderFront:self]; - [self.window makeFirstResponder:self]; - } -} - -- (void)clear -{ - if ([self isInFullScreenMode]) { - self.clearing = YES; - [self exitFullScreenModeWithOptions:nil]; - } -} - // mpv uses flipped coordinates, because X11 uses those. So let's just use them // as well without having to do any coordinate conversion of mouse positions. - (BOOL)isFlipped { return YES; } @@ -379,27 +329,6 @@ - (BOOL)performDragOperation:(id )sender return NO; } -- (BOOL)hasDock:(NSScreen*)screen -{ - NSRect vF = [screen visibleFrame]; - NSRect f = [screen frame]; - return - // The visible frame's width is smaller: dock is on left or right end - // of this method's receiver. - vF.size.width < f.size.width || - // The visible frame's veritical origin is bigger: dock is - // on the bottom of this method's receiver. - vF.origin.y > f.origin.y; - -} - -- (BOOL)hasMenubar:(NSScreen*)screen -{ - NSRect vF = [screen visibleFrame]; - NSRect f = [screen frame]; - return f.size.height + f.origin.y > vF.size.height + vF.origin.y; -} - - (int)mpvButtonNumber:(NSEvent*)event { int buttonNumber = [event buttonNumber]; diff --git a/video/out/cocoa/mpvadapter.h b/video/out/cocoa/mpvadapter.h index 5b87e89d04bc0..e547708e1719a 100644 --- a/video/out/cocoa/mpvadapter.h +++ b/video/out/cocoa/mpvadapter.h @@ -26,14 +26,14 @@ - (void)putAxis:(int)mpkey delta:(float)delta; - (void)putCommand:(char*)cmd; - (void)handleFilesArray:(NSArray *)files; -- (void)didChangeWindowedScreenProfile:(NSScreen *)screen; +- (void)didChangeWindowedScreenProfile:(NSNotification *)notification; - (void)performAsyncResize:(NSSize)size; - (void)didChangeMousePosition; - (BOOL)isInFullScreenMode; - (BOOL)keyboardEnabled; - (BOOL)mouseEnabled; -- (NSScreen *)fsScreen; -- (BOOL)fsModeAllScreens; + +- (NSScreen *)getTargetScreen; @property(nonatomic, assign) struct vo *vout; @end diff --git a/video/out/cocoa/window.m b/video/out/cocoa/window.m index d89e296b40e36..6d63263cb43e8 100644 --- a/video/out/cocoa/window.m +++ b/video/out/cocoa/window.m @@ -26,15 +26,25 @@ #include "window.h" @interface MpvVideoWindow() +@property(nonatomic, retain) NSScreen *targetScreen; +@property(nonatomic, retain) NSScreen *previousScreen; +@property(nonatomic, retain) NSScreen *currentScreen; + - (NSRect)frameRect:(NSRect)frameRect forCenteredContentSize:(NSSize)newSize; - (void)setCenteredContentSize:(NSSize)newSize; @end @implementation MpvVideoWindow { NSSize _queued_video_size; + NSRect _unfs_content_frame; + NSRect _unfs_screen_frame; + int _is_animating; } @synthesize adapter = _adapter; +@synthesize targetScreen = _target_screen; +@synthesize previousScreen = _previous_screen; +@synthesize currentScreen = _current_screen; - (id)initWithContentRect:(NSRect)content_rect styleMask:(NSUInteger)style_mask backing:(NSBackingStoreType)buffering_type @@ -46,10 +56,96 @@ - (id)initWithContentRect:(NSRect)content_rect defer:flag]) { [self setBackgroundColor:[NSColor blackColor]]; [self setMinSize:NSMakeSize(50,50)]; + [self setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary]; + + self.targetScreen = [self screen]; + self.currentScreen = [self screen]; + _is_animating = 0; + _unfs_content_frame = [self convertRectToScreen:[[self contentView] frame]]; + _unfs_screen_frame = [[self screen] frame]; } return self; } +- (void)toggleFullScreen:(id)sender +{ + if (_is_animating) + return; + + _is_animating = 1; + + self.targetScreen = [self.adapter getTargetScreen]; + if(![self targetScreen] && ![self previousScreen]) { + self.targetScreen = [self screen]; + } else if (![self targetScreen]) { + self.targetScreen = self.previousScreen; + self.previousScreen = nil; + } else { + self.previousScreen = [self screen]; + } + + if (![self.adapter isInFullScreenMode]) { + _unfs_content_frame = [self convertRectToScreen:[[self contentView] frame]]; + _unfs_screen_frame = [[self screen] frame]; + } + + //move window to target screen when going to fullscreen + if (![self.adapter isInFullScreenMode] && ![[self targetScreen] isEqual:[self screen]]) { + [self setFrame:[self calculateWindowPositionForScreen:[self targetScreen]] display:YES]; + } + + [super toggleFullScreen:sender]; + + if (![self.adapter isInFullScreenMode]) { + [self setStyleMask:([self styleMask] | NSWindowStyleMaskFullScreen)]; + NSRect frame = [[self targetScreen] frame]; + [self setFrame:frame display:YES]; + } else { + [self setStyleMask:([self styleMask] & ~NSWindowStyleMaskFullScreen)]; + NSRect frame = [self calculateWindowPositionForScreen:[self targetScreen]]; + [self setFrame:frame display:YES]; + [self setContentAspectRatio:_unfs_content_frame.size]; + [self setCenteredContentSize:_unfs_content_frame.size]; + } +} + +- (NSArray *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window +{ + return [NSArray arrayWithObject:window]; +} + +- (NSArray*)customWindowsToExitFullScreenForWindow:(NSWindow*)window +{ + return [NSArray arrayWithObject:window]; +} + +// we still need to keep those around or it will use the standard animation +- (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration {} + +- (void)window:(NSWindow *)window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration {} + +- (void)windowDidEnterFullScreen:(NSNotification *)notification +{ + _is_animating = 0; + [self.adapter windowDidEnterFullScreen:notification]; +} + +- (void)windowDidExitFullScreen:(NSNotification *)notification +{ + _is_animating = 0; + [self.adapter windowDidExitFullScreen:notification]; +} + +- (void)windowDidFailToEnterFullScreen:(NSWindow *)window +{ + _is_animating = 0; +} + +- (void)windowDidFailToExitFullScreen:(NSWindow *)window +{ + _is_animating = 0; +} + - (void)windowDidChangeBackingProperties:(NSNotification *)notification { // XXX: we maybe only need expose for this @@ -58,12 +154,18 @@ - (void)windowDidChangeBackingProperties:(NSNotification *)notification - (void)windowDidChangeScreen:(NSNotification *)notification { + //this event doesn't exclusively trigger on screen change + //examples: screen reconfigure, toggling fullscreen + if (!_is_animating && ![[self currentScreen] isEqual:[self screen]]) { + self.previousScreen = [self screen]; + } + self.currentScreen = [self screen]; [self.adapter windowDidChangeScreen:notification]; } - (void)windowDidChangeScreenProfile:(NSNotification *)notification { - [self.adapter didChangeWindowedScreenProfile:[self screen]]; + [self.adapter didChangeWindowedScreenProfile:notification]; } - (void)windowDidResignKey:(NSNotification *)notification @@ -125,8 +227,41 @@ - (void)setCenteredContentSize:(NSSize)ns animate:NO]; } +- (NSRect)calculateWindowPositionForScreen:(NSScreen *)screen +{ + NSRect frame = [self frameRectForContentRect:_unfs_content_frame]; + NSRect targetFrame = [screen frame]; + + CGFloat x_per = (_unfs_screen_frame.size.width - frame.size.width); + CGFloat y_per = (_unfs_screen_frame.size.height - frame.size.height); + if (x_per > 0) x_per = (frame.origin.x - _unfs_screen_frame.origin.x)/x_per; + if (y_per > 0) y_per = (frame.origin.y - _unfs_screen_frame.origin.y)/y_per; + + frame.origin.x = targetFrame.origin.x + + (targetFrame.size.width - frame.size.width)*x_per; + frame.origin.y = targetFrame.origin.y + + (targetFrame.size.height - frame.size.height)*y_per; + + //screen bounds right and left + if (frame.origin.x + frame.size.width > targetFrame.origin.x + targetFrame.size.width) + frame.origin.x = targetFrame.origin.x + targetFrame.size.width - frame.size.width; + if (frame.origin.x < targetFrame.origin.x) + frame.origin.x = targetFrame.origin.x; + + //screen bounds top and bottom + if (frame.origin.y + frame.size.height > targetFrame.origin.y + targetFrame.size.height) + frame.origin.y = targetFrame.origin.y + targetFrame.size.height - frame.size.height; + if (frame.origin.y < targetFrame.origin.y) + frame.origin.y = targetFrame.origin.y; + + return frame; +} + - (NSRect)constrainFrameRect:(NSRect)nf toScreen:(NSScreen *)screen { + if (_is_animating) + screen = [self targetScreen]; + NSRect of = [self frame]; NSRect vf = [screen ?: self.screen ?: [NSScreen mainScreen] visibleFrame]; NSRect ncf = [self contentRectForFrameRect:nf]; @@ -136,7 +271,7 @@ - (NSRect)constrainFrameRect:(NSRect)nf toScreen:(NSScreen *)screen if (NSMaxY(nf) > NSMaxY(vf)) nf.origin.y = NSMaxY(vf) - NSHeight(nf); - // Prevent the window's titlebar from exiting the screen on the top edge. + // Prevent the window's titlebar from exiting the screen on the bottom edge. if (NSMaxY(ncf) < NSMinY(vf)) nf.origin.y = NSMinY(vf) + NSMinY(ncf) - NSMaxY(ncf); @@ -157,30 +292,42 @@ - (NSRect)constrainFrameRect:(NSRect)nf toScreen:(NSScreen *)screen return nf; } +- (void)windowWillStartLiveResize:(NSNotification *)notification +{ + [self.adapter windowWillStartLiveResize:notification]; +} + - (void)windowDidEndLiveResize:(NSNotification *)notification { + [self.adapter windowDidEndLiveResize:notification]; [self setFrame:[self constrainFrameRect:self.frame toScreen:self.screen] display:NO]; } +- (void)updateWindowFrame:(NSSize)newSize +{ + _unfs_content_frame = [self frameRect:_unfs_content_frame forCenteredContentSize:newSize]; +} + - (void)tryDequeueSize { if (_queued_video_size.width <= 0.0 || _queued_video_size.height <= 0.0) return; - // XXX find a way to kill this state - if (![self.adapter isInFullScreenMode]) { - [self setContentAspectRatio:_queued_video_size]; - [self setCenteredContentSize:_queued_video_size]; - _queued_video_size = NSZeroSize; - } + [self setContentAspectRatio:_queued_video_size]; + [self setCenteredContentSize:_queued_video_size]; + _queued_video_size = NSZeroSize; } -- (void)queueNewVideoSize:(NSSize)new_size +- (void)queueNewVideoSize:(NSSize)newSize { - if (NSEqualSizes(_queued_video_size, new_size)) - return; - _queued_video_size = new_size; - [self tryDequeueSize]; + if ([self.adapter isInFullScreenMode]) { + [self updateWindowFrame:newSize]; + } else { + if (NSEqualSizes(_queued_video_size, newSize)) + return; + _queued_video_size = newSize; + [self tryDequeueSize]; + } } - (void)windowDidBecomeMain:(NSNotification *)notification { diff --git a/video/out/cocoa_common.m b/video/out/cocoa_common.m index 719169df48813..c1a65ef2eec21 100644 --- a/video/out/cocoa_common.m +++ b/video/out/cocoa_common.m @@ -49,11 +49,10 @@ #include "common/msg.h" -static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, - const CVTimeStamp* outputTime, CVOptionFlags flagsIn, +static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, + const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext); static int vo_cocoa_fullscreen(struct vo *vo); -static void cocoa_rm_fs_screen_profile_observer(struct vo_cocoa_state *s); static void cocoa_add_screen_reconfiguration_observer(struct vo *vo); static void cocoa_rm_screen_reconfiguration_observer(struct vo *vo); @@ -70,15 +69,13 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt NSOpenGLContext *nsgl_ctx; NSScreen *current_screen; - NSScreen *fs_screen; double screen_fps; NSInteger window_level; + int fullscreen; bool embedded; // wether we are embedding in another GUI - atomic_bool waiting_frame; - IOPMAssertionID power_mgmt_assertion; io_connect_t light_sensor; uint64_t last_lmuvalue; @@ -90,8 +87,6 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt uint32_t old_dwidth; uint32_t old_dheight; - id fs_icc_changed_ns_observer; - pthread_mutex_t lock; pthread_cond_t wakeup; @@ -122,14 +117,11 @@ static void queue_new_video_size(struct vo *vo, int w, int h) { struct vo_cocoa_state *s = vo->cocoa; struct mp_vo_opts *opts = vo->opts; - if ([s->window conformsToProtocol: @protocol(MpvSizing)]) { - id win = (id) s->window; - NSRect r = NSMakeRect(0, 0, w, h); - if(!opts->hidpi_window_scale) { - r = [s->current_screen convertRectFromBacking:r]; - } - [win queueNewVideoSize:NSMakeSize(r.size.width, r.size.height)]; - } + id win = (id) s->window; + NSRect r = NSMakeRect(0, 0, w, h); + if(!opts->hidpi_window_scale) + r = [s->current_screen convertRectFromBacking:r]; + [win queueNewVideoSize:NSMakeSize(r.size.width, r.size.height)]; } static void flag_events(struct vo *vo, int events) @@ -258,6 +250,39 @@ static void cocoa_uninit_light_sensor(struct vo_cocoa_state *s) } } +static NSScreen *get_screen_by_id(struct vo *vo, int screen_id) +{ + struct vo_cocoa_state *s = vo->cocoa; + + NSArray *screens = [NSScreen screens]; + int n_of_displays = [screens count]; + if (screen_id >= n_of_displays) { + MP_INFO(s, "Screen ID %d does not exist, falling back to main " + "device\n", screen_id); + return nil; + } else if (screen_id < 0) { + return nil; + } + return [screens objectAtIndex:(screen_id)]; +} + +static void vo_cocoa_update_screen_info(struct vo *vo) +{ + struct vo_cocoa_state *s = vo->cocoa; + struct mp_vo_opts *opts = vo->opts; + + if (s->embedded) + return; + + if (s->current_screen && s->window) { + s->current_screen = [s->window screen]; + } else if (!s->current_screen) { + s->current_screen = get_screen_by_id(vo, opts->screen_id); + if (!s->current_screen) + s->current_screen = [NSScreen mainScreen]; + } +} + void vo_cocoa_init(struct vo *vo) { struct vo_cocoa_state *s = talloc_zero(NULL, struct vo_cocoa_state); @@ -265,6 +290,7 @@ void vo_cocoa_init(struct vo *vo) .power_mgmt_assertion = kIOPMNullAssertionID, .log = mp_log_new(s, vo->log, "cocoa"), .embedded = vo->opts->WinID >= 0, + .fullscreen = 0, }; if (!s->embedded) { NSImage* blankImage = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)]; @@ -274,6 +300,7 @@ void vo_cocoa_init(struct vo *vo) pthread_mutex_init(&s->lock, NULL); pthread_cond_init(&s->wakeup, NULL); vo->cocoa = s; + vo_cocoa_update_screen_info(vo); cocoa_init_light_sensor(vo); cocoa_add_screen_reconfiguration_observer(vo); if (!s->embedded) { @@ -314,7 +341,6 @@ void vo_cocoa_uninit(struct vo *vo) run_on_main_thread(vo, ^{ enable_power_management(s); cocoa_uninit_light_sensor(s); - cocoa_rm_fs_screen_profile_observer(s); cocoa_rm_screen_reconfiguration_observer(vo); [s->nsgl_ctx release]; @@ -325,12 +351,13 @@ void vo_cocoa_uninit(struct vo *vo) [s->video removeFromSuperview]; [s->view removeFromSuperview]; - [(MpvEventsView *)s->view clear]; [s->view release]; // if using --wid + libmpv there's no window to release - if (s->window) - [s->window release]; + if (s->window) { + [s->window setDelegate:nil]; + [s->window close]; + } if (!s->embedded) [s->blankCursor release]; @@ -341,44 +368,11 @@ void vo_cocoa_uninit(struct vo *vo) }); } -static int get_screen_handle(struct vo *vo, int identifier, NSWindow *window, - NSScreen **screen) { - struct vo_cocoa_state *s = vo->cocoa; - NSArray *screens = [NSScreen screens]; - int n_of_displays = [screens count]; - - if (identifier >= n_of_displays) { // check if the identifier is out of bounds - MP_INFO(s, "Screen ID %d does not exist, falling back to main " - "device\n", identifier); - identifier = -1; - } - - if (identifier < 0) { - // default behaviour gets either the window screen or the main screen - // if window is not available - if (! (*screen = [window screen]) ) - *screen = [screens objectAtIndex:0]; - return 0; - } else { - *screen = [screens objectAtIndex:(identifier)]; - return 1; - } -} - -static void vo_cocoa_update_screens_pointers(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - struct mp_vo_opts *opts = vo->opts; - get_screen_handle(vo, opts->screen_id, s->window, &s->current_screen); - get_screen_handle(vo, opts->fsscreen_id, s->window, &s->fs_screen); -} - static void vo_cocoa_update_screen_fps(struct vo *vo) { struct vo_cocoa_state *s = vo->cocoa; - NSScreen *screen = vo->opts->fullscreen ? s->fs_screen : s->current_screen; - NSDictionary* sinfo = [screen deviceDescription]; + NSDictionary* sinfo = [s->current_screen deviceDescription]; NSNumber* sid = [sinfo objectForKey:@"NSScreenNumber"]; CGDirectDisplayID did = [sid longValue]; @@ -416,21 +410,6 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt return kCVReturnSuccess; } -static void vo_cocoa_update_screen_info(struct vo *vo, struct mp_rect *out_rc) -{ - struct vo_cocoa_state *s = vo->cocoa; - - if (s->embedded) - return; - - vo_cocoa_update_screens_pointers(vo); - - if (out_rc) { - NSRect r = [s->current_screen frame]; - *out_rc = (struct mp_rect){0, 0, r.size.width, r.size.height}; - } -} - static void vo_set_level(struct vo *vo, int ontop) { struct vo_cocoa_state *s = vo->cocoa; @@ -553,40 +532,12 @@ static int cocoa_set_window_title(struct vo *vo) return VO_TRUE; } -static void cocoa_rm_fs_screen_profile_observer(struct vo_cocoa_state *s) -{ - [[NSNotificationCenter defaultCenter] - removeObserver:s->fs_icc_changed_ns_observer]; -} - -static void cocoa_add_fs_screen_profile_observer(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - - if (s->fs_icc_changed_ns_observer) - cocoa_rm_fs_screen_profile_observer(s); - - if (vo->opts->fsscreen_id < 0) - return; - - void (^nblock)(NSNotification *n) = ^(NSNotification *n) { - flag_events(vo, VO_EVENT_ICC_PROFILE_CHANGED); - }; - - s->fs_icc_changed_ns_observer = [[NSNotificationCenter defaultCenter] - addObserverForName:NSScreenColorSpaceDidChangeNotification - object:s->fs_screen - queue:nil - usingBlock:nblock]; -} - static void cocoa_screen_reconfiguration_observer( CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *ctx) { if (flags & kCGDisplaySetModeFlag) { struct vo *vo = ctx; MP_WARN(vo, "detected display mode change, updating screen info\n"); - vo_cocoa_update_screen_info(vo, NULL); vo_cocoa_update_screen_fps(vo); } } @@ -615,11 +566,13 @@ void vo_cocoa_set_opengl_ctx(struct vo *vo, CGLContextObj ctx) int vo_cocoa_config_window(struct vo *vo) { struct vo_cocoa_state *s = vo->cocoa; + struct mp_vo_opts *opts = vo->opts; + run_on_main_thread(vo, ^{ - struct mp_rect screenrc; - vo_cocoa_update_screen_info(vo, &screenrc); vo_cocoa_update_screen_fps(vo); + NSRect r = [s->current_screen frame]; + struct mp_rect screenrc = {0, 0, r.size.width, r.size.height}; struct vo_win_geometry geo; vo_calc_window_geometry(vo, &screenrc, &geo); vo_apply_window_geometry(vo, &geo); @@ -638,10 +591,10 @@ int vo_cocoa_config_window(struct vo *vo) if (!s->embedded && s->window) { if (reset_size) queue_new_video_size(vo, width, height); - vo_cocoa_fullscreen(vo); - cocoa_add_fs_screen_profile_observer(vo); + if (opts->fullscreen && !s->fullscreen) + vo_cocoa_fullscreen(vo); cocoa_set_window_title(vo); - vo_set_level(vo, vo->opts->ontop); + vo_set_level(vo, opts->ontop); GLint o; if (!CGLGetParameter(s->cgl_ctx, kCGLCPSurfaceOpacity, &o) && !o) { @@ -691,9 +644,6 @@ static void vo_cocoa_resize_redraw(struct vo *vo, int width, int height) pthread_mutex_lock(&s->lock); - // Make vo.c not do video timing, which would slow down resizing. - vo_event(vo, VO_EVENT_LIVE_RESIZING); - // Wait until a new frame with the new size was rendered. For some reason, // Cocoa requires this to be done before drawRect() returns. struct timespec e = mp_time_us_to_timespec(mp_add_timeout(mp_time_us(), 0.1)); @@ -702,18 +652,9 @@ static void vo_cocoa_resize_redraw(struct vo *vo, int width, int height) break; } - vo_query_and_reset_events(vo, VO_EVENT_LIVE_RESIZING); - pthread_mutex_unlock(&s->lock); } -static void draw_changes_after_next_frame(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - if (atomic_compare_exchange_strong(&s->waiting_frame, &(bool){false}, true)) - NSDisableScreenUpdates(); -} - void vo_cocoa_swap_buffers(struct vo *vo) { struct vo_cocoa_state *s = vo->cocoa; @@ -730,9 +671,6 @@ void vo_cocoa_swap_buffers(struct vo *vo) s->frame_h = vo->dheight; pthread_cond_signal(&s->wakeup); pthread_mutex_unlock(&s->lock); - - if (atomic_compare_exchange_strong(&s->waiting_frame, &(bool){true}, false)) - NSEnableScreenUpdates(); } static int vo_cocoa_check_events(struct vo *vo) @@ -754,25 +692,14 @@ static int vo_cocoa_check_events(struct vo *vo) static int vo_cocoa_fullscreen(struct vo *vo) { struct vo_cocoa_state *s = vo->cocoa; - struct mp_vo_opts *opts = vo->opts; if (s->embedded) return VO_NOTIMPL; - vo_cocoa_update_screen_info(vo, NULL); - - draw_changes_after_next_frame(vo); - [(MpvEventsView *)s->view setFullScreen:opts->fullscreen]; - - if ([s->view window] != s->window) { - // cocoa implements fullscreen views by moving the view to a fullscreen - // window. Set that window delegate to the cocoa adapter to trigger - // calls to -windowDidResignKey: and -windowDidBecomeKey: - [[s->view window] setDelegate:s->adapter]; - } - - flag_events(vo, VO_EVENT_ICC_PROFILE_CHANGED); - resize_event(vo); + [s->window toggleFullScreen:nil]; + // for whatever reason sometimes cocoa doesn't create an up event on + // the fullscreen input key + cocoa_put_key(MP_INPUT_RELEASE_ALL); return VO_TRUE; } @@ -782,10 +709,7 @@ static void vo_cocoa_control_get_icc_profile(struct vo *vo, void *arg) struct vo_cocoa_state *s = vo->cocoa; bstr *p = arg; - vo_cocoa_update_screen_info(vo, NULL); - - NSScreen *screen = vo->opts->fullscreen ? s->fs_screen : s->current_screen; - NSData *profile = [[screen colorSpace] ICCProfileData]; + NSData *profile = [[s->current_screen colorSpace] ICCProfileData]; p->start = talloc_memdup(NULL, (void *)[profile bytes], [profile length]); p->len = [profile length]; @@ -793,59 +717,61 @@ static void vo_cocoa_control_get_icc_profile(struct vo *vo, void *arg) static int vo_cocoa_control_on_main_thread(struct vo *vo, int request, void *arg) { - struct mp_vo_opts *opts = vo->opts; + struct vo_cocoa_state *s = vo->cocoa; switch (request) { case VOCTRL_FULLSCREEN: return vo_cocoa_fullscreen(vo); + case VOCTRL_GET_FULLSCREEN: + *(int *)arg = s->fullscreen; + return VO_TRUE; case VOCTRL_ONTOP: return vo_cocoa_ontop(vo); case VOCTRL_GET_UNFS_WINDOW_SIZE: { - int *s = arg; - NSSize size = [vo->cocoa->view frame].size; - s[0] = size.width; - s[1] = size.height; + int *sz = arg; + NSSize size = [s->view frame].size; + sz[0] = size.width; + sz[1] = size.height; return VO_TRUE; } case VOCTRL_SET_UNFS_WINDOW_SIZE: { - int *s = arg; + int *sz = arg; int w, h; - w = s[0]; - h = s[1]; + w = sz[0]; + h = sz[1]; queue_new_video_size(vo, w, h); return VO_TRUE; } case VOCTRL_GET_WIN_STATE: { - const bool minimized = [[vo->cocoa->view window] isMiniaturized]; + const bool minimized = [[s->view window] isMiniaturized]; *(int *)arg = minimized ? VO_WIN_STATE_MINIMIZED : 0; return VO_TRUE; } case VOCTRL_SET_CURSOR_VISIBILITY: return vo_cocoa_set_cursor_visibility(vo, arg); case VOCTRL_UPDATE_WINDOW_TITLE: { - struct vo_cocoa_state *s = vo->cocoa; talloc_free(s->window_title); s->window_title = talloc_strdup(s, (char *) arg); return cocoa_set_window_title(vo); } case VOCTRL_RESTORE_SCREENSAVER: - enable_power_management(vo->cocoa); + enable_power_management(s); return VO_TRUE; case VOCTRL_KILL_SCREENSAVER: - disable_power_management(vo->cocoa); + disable_power_management(s); return VO_TRUE; case VOCTRL_GET_ICC_PROFILE: vo_cocoa_control_get_icc_profile(vo, arg); return VO_TRUE; case VOCTRL_GET_DISPLAY_FPS: - if (vo->cocoa->screen_fps > 0.0) { - *(double *)arg = vo->cocoa->screen_fps; + if (s->screen_fps > 0.0) { + *(double *)arg = s->screen_fps; return VO_TRUE; } break; case VOCTRL_GET_AMBIENT_LUX: - if (vo->cocoa->light_sensor != IO_OBJECT_NULL) { - *(int *)arg = vo->cocoa->last_lux; + if (s->light_sensor != IO_OBJECT_NULL) { + *(int *)arg = s->last_lux; return VO_TRUE; } break; @@ -879,8 +805,7 @@ @implementation MpvCocoaAdapter - (void)performAsyncResize:(NSSize)size { struct vo_cocoa_state *s = self.vout->cocoa; - if (!atomic_load(&s->waiting_frame)) - vo_cocoa_resize_redraw(self.vout, size.width, size.height); + vo_cocoa_resize_redraw(self.vout, size.width, size.height); } - (BOOL)keyboardEnabled { @@ -898,7 +823,7 @@ - (void)setNeedsResize { - (void)recalcMovableByWindowBackground:(NSPoint)p { BOOL movable = NO; - if (![self isInFullScreenMode]) { + if (!self.vout->cocoa->fullscreen) { movable = !mp_input_test_dragging(self.vout->input_ctx, p.x, p.y); } @@ -933,18 +858,18 @@ - (void)putCommand:(char*)cmd ta_free(cmd_); } -- (BOOL)isInFullScreenMode { - return self.vout->opts->fullscreen; +- (BOOL)isInFullScreenMode +{ + return self.vout->cocoa->fullscreen; } -- (NSScreen *)fsScreen { +- (NSScreen *)getTargetScreen +{ struct vo_cocoa_state *s = self.vout->cocoa; - return s->fs_screen; -} + struct mp_vo_opts *opts = self.vout->opts; -- (BOOL)fsModeAllScreens -{ - return self.vout->opts->fs_black_out_screens; + int screen_id = s->fullscreen ? opts->screen_id : opts->fsscreen_id; + return get_screen_by_id(self.vout, screen_id); } - (void)handleFilesArray:(NSArray *)files @@ -954,11 +879,36 @@ - (void)handleFilesArray:(NSArray *)files - (void)windowDidChangeScreen:(NSNotification *)notification { - vo_cocoa_update_screen_info(self.vout, NULL); + vo_cocoa_update_screen_info(self.vout); vo_cocoa_update_screen_fps(self.vout); } -- (void)didChangeWindowedScreenProfile:(NSScreen *)screen +- (void)windowDidEnterFullScreen:(NSNotification *)notification +{ + struct vo_cocoa_state *s = self.vout->cocoa; + s->fullscreen = 1; + s->pending_events |= VO_EVENT_FULLSCREEN_STATE; +} + +- (void)windowDidExitFullScreen:(NSNotification *)notification +{ + struct vo_cocoa_state *s = self.vout->cocoa; + s->fullscreen = 0; + s->pending_events |= VO_EVENT_FULLSCREEN_STATE; +} + +- (void)windowWillStartLiveResize:(NSNotification *)notification +{ + // Make vo.c not do video timing, which would slow down resizing. + vo_event(self.vout, VO_EVENT_LIVE_RESIZING); +} + +- (void)windowDidEndLiveResize:(NSNotification *)notification +{ + vo_query_and_reset_events(self.vout, VO_EVENT_LIVE_RESIZING); +} + +- (void)didChangeWindowedScreenProfile:(NSNotification *)notification { flag_events(self.vout, VO_EVENT_ICC_PROFILE_CHANGED); } From aab98776f602a4bec1a74ee87eb829aadf6437ea Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 16 Dec 2016 16:09:10 +0100 Subject: [PATCH 68/83] options: change --h=... behavior Does not match a shell pattern anymore. Instead, a simple sub-string search is done. --- DOCS/man/options.rst | 7 ++++--- options/m_config.c | 8 +------- player/main.c | 2 +- wscript | 4 ---- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index e355d933d97c8..0dd3aad59bf84 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -350,9 +350,10 @@ Program Behavior ``--help``, ``--h`` Show short summary of options. - You can also pass a shell pattern to this option, which will list all - matching top-level options, e.g. ``--h=*scale*`` for all options that - contain the word "scale". + You can also pass a string to this option, which will list all top-level + options which contain the string in the name, e.g. ``--h=scale`` for all + options that contain the word ``scale``. The special string ``*`` lists + all top-level options. ``-v`` Increment verbosity level, one level for each ``-v`` found on the command diff --git a/options/m_config.c b/options/m_config.c index 2dc3eb569dee5..14aa56da51cf7 100644 --- a/options/m_config.c +++ b/options/m_config.c @@ -29,10 +29,6 @@ #include #include -#if HAVE_FNMATCH -#include -#endif - #include "libmpv/client.h" #include "mpv_talloc.h" @@ -956,10 +952,8 @@ void m_config_print_option_list(const struct m_config *config, const char *name) const struct m_option *opt = co->opt; if (co->is_hidden) continue; -#if HAVE_FNMATCH - if (fnmatch(name, co->name, 0)) + if (strcmp(name, "*") != 0 && !strstr(co->name, name)) continue; -#endif MP_INFO(config, " %s%-30s", prefix, co->name); if (opt->type == &m_option_type_choice) { MP_INFO(config, " Choices:"); diff --git a/player/main.c b/player/main.c index 1f32d375bd5a3..8ebfc357a27f6 100644 --- a/player/main.c +++ b/player/main.c @@ -96,7 +96,7 @@ const char mp_help_text[] = " --playlist= specify playlist file\n" "\n" " --list-options list all mpv options\n" -" --h= print options which match the given shell pattern\n" +" --h= print options which contain the given string in their name\n" "\n"; static pthread_mutex_t terminal_owner_lock = PTHREAD_MUTEX_INITIALIZER; diff --git a/wscript b/wscript index 9d9c6a8047623..f47f9652658e1 100644 --- a/wscript +++ b/wscript @@ -127,10 +127,6 @@ main_dependencies = [ # This should be good enough. 'func': check_statement(['poll.h', 'unistd.h', 'sys/mman.h'], 'struct pollfd pfd; poll(&pfd, 1, 0); fork(); int f[2]; pipe(f); munmap(f,0)'), - }, { - 'name': 'fnmatch', - 'desc': 'fnmatch()', - 'func': check_statement('fnmatch.h', 'fnmatch("", "", 0)') }, { 'name': 'posix-or-mingw', 'desc': 'development environment', From 2b8b17402ed59815019b309051b277ba4de82f3b Mon Sep 17 00:00:00 2001 From: Akemi Date: Thu, 15 Dec 2016 23:06:04 +0100 Subject: [PATCH 69/83] cocoa: cosmetic fixes --- osdep/macosx_application.m | 3 ++- osdep/macosx_events.m | 14 +++++++++----- video/out/cocoa/events_view.m | 23 ++++++++++++++--------- video/out/cocoa/video_view.m | 3 ++- video/out/cocoa/window.m | 6 ++++-- video/out/cocoa_common.m | 15 ++++++++++----- waftools/fragments/cocoa.m | 3 ++- 7 files changed, 43 insertions(+), 24 deletions(-) diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m index 8808caa0a42df..d31269279edb1 100644 --- a/osdep/macosx_application.m +++ b/osdep/macosx_application.m @@ -206,7 +206,8 @@ - (NSMenuItem *)mainMenuItemWithParent:(NSMenu *)parent return [item autorelease]; } -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)theApp { +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)theApp +{ return NSTerminateNow; } diff --git a/osdep/macosx_events.m b/osdep/macosx_events.m index c493c58c96a86..494c9aa88c5b2 100644 --- a/osdep/macosx_events.m +++ b/osdep/macosx_events.m @@ -142,7 +142,8 @@ static int mk_flags(NSEvent *event) return ([event data1] & 0x0000FFFF); } -static int mk_down(NSEvent *event) { +static int mk_down(NSEvent *event) +{ return (((mk_flags(event) & 0xFF00) >> 8)) == 0xA; } @@ -178,11 +179,13 @@ static CGEventRef tap_event_callback(CGEventTapProxy proxy, CGEventType type, } } -void cocoa_init_media_keys(void) { +void cocoa_init_media_keys(void) +{ [[EventsResponder sharedInstance] startMediaKeys]; } -void cocoa_uninit_media_keys(void) { +void cocoa_uninit_media_keys(void) +{ [[EventsResponder sharedInstance] stopMediaKeys]; } @@ -446,10 +449,11 @@ - (NSEvent*)handleKey:(NSEvent *)event NSString *chars; - if ([self useAltGr] && RightAltPressed([event modifierFlags])) + if ([self useAltGr] && RightAltPressed([event modifierFlags])) { chars = [event characters]; - else + } else { chars = [event charactersIgnoringModifiers]; + } struct bstr t = bstr0([chars UTF8String]); int key = convert_key([event keyCode], bstr_decode_utf8(t, &t)); diff --git a/video/out/cocoa/events_view.m b/video/out/cocoa/events_view.m index 53d1da86ff1cc..d377597006921 100644 --- a/video/out/cocoa/events_view.m +++ b/video/out/cocoa/events_view.m @@ -39,7 +39,8 @@ @implementation MpvEventsView @synthesize tracker = _tracker; @synthesize hasMouseDown = _mouse_down; -- (id)initWithFrame:(NSRect)frame { +- (id)initWithFrame:(NSRect)frame +{ self = [super initWithFrame:frame]; if (self) { [self registerForDraggedTypes:@[NSFilenamesPboardType, @@ -96,21 +97,25 @@ - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { return [self.adapter mouseEnabled]; } -- (BOOL)acceptsFirstResponder { +- (BOOL)acceptsFirstResponder +{ return [self.adapter keyboardEnabled] || [self.adapter mouseEnabled]; } -- (BOOL)becomeFirstResponder { +- (BOOL)becomeFirstResponder +{ return [self.adapter keyboardEnabled] || [self.adapter mouseEnabled]; } - (BOOL)resignFirstResponder { return YES; } -- (void)keyDown:(NSEvent *)event { +- (void)keyDown:(NSEvent *)event +{ [self.adapter putKeyEvent:event]; } -- (void)keyUp:(NSEvent *)event { +- (void)keyUp:(NSEvent *)event +{ [self.adapter putKeyEvent:event]; } @@ -298,10 +303,11 @@ - (NSDragOperation)draggingEntered:(id )sender NSPasteboard *pboard = [sender draggingPasteboard]; NSArray *types = [pboard types]; if ([types containsObject:NSFilenamesPboardType] || - [types containsObject:NSURLPboardType]) + [types containsObject:NSURLPboardType]) { return NSDragOperationCopy; - else + } else { return NSDragOperationNone; + } } - (BOOL)performDragOperation:(id )sender @@ -314,8 +320,7 @@ - (BOOL)performDragOperation:(id )sender for (NSURL* url in pbitems) { if (url.fileURL) { [ar addObject:[url path]]; - } - else { + } else { [ar addObject:[url absoluteString]]; } } diff --git a/video/out/cocoa/video_view.m b/video/out/cocoa/video_view.m index 786c6ef4da791..cb09dc8b9f80c 100644 --- a/video/out/cocoa/video_view.m +++ b/video/out/cocoa/video_view.m @@ -22,7 +22,8 @@ @implementation MpvVideoView @synthesize adapter = _adapter; -- (id)initWithFrame:(NSRect)frame { +- (id)initWithFrame:(NSRect)frame +{ self = [super initWithFrame:frame]; if (self) { [self setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; diff --git a/video/out/cocoa/window.m b/video/out/cocoa/window.m index 6d63263cb43e8..68e5222a032ba 100644 --- a/video/out/cocoa/window.m +++ b/video/out/cocoa/window.m @@ -309,7 +309,8 @@ - (void)updateWindowFrame:(NSSize)newSize _unfs_content_frame = [self frameRect:_unfs_content_frame forCenteredContentSize:newSize]; } -- (void)tryDequeueSize { +- (void)tryDequeueSize +{ if (_queued_video_size.width <= 0.0 || _queued_video_size.height <= 0.0) return; @@ -330,7 +331,8 @@ - (void)queueNewVideoSize:(NSSize)newSize } } -- (void)windowDidBecomeMain:(NSNotification *)notification { +- (void)windowDidBecomeMain:(NSNotification *)notification +{ [self tryDequeueSize]; } @end diff --git a/video/out/cocoa_common.m b/video/out/cocoa_common.m index c1a65ef2eec21..164663c3326cb 100644 --- a/video/out/cocoa_common.m +++ b/video/out/cocoa_common.m @@ -803,20 +803,24 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg) @implementation MpvCocoaAdapter @synthesize vout = _video_output; -- (void)performAsyncResize:(NSSize)size { +- (void)performAsyncResize:(NSSize)size +{ struct vo_cocoa_state *s = self.vout->cocoa; vo_cocoa_resize_redraw(self.vout, size.width, size.height); } -- (BOOL)keyboardEnabled { +- (BOOL)keyboardEnabled +{ return !!mp_input_vo_keyboard_enabled(self.vout->input_ctx); } -- (BOOL)mouseEnabled { +- (BOOL)mouseEnabled +{ return !!mp_input_mouse_enabled(self.vout->input_ctx); } -- (void)setNeedsResize { +- (void)setNeedsResize +{ resize_event(self.vout); } @@ -830,7 +834,8 @@ - (void)recalcMovableByWindowBackground:(NSPoint)p [self.vout->cocoa->window setMovableByWindowBackground:movable]; } -- (void)signalMouseMovement:(NSPoint)point { +- (void)signalMouseMovement:(NSPoint)point +{ mp_input_set_mouse_pos(self.vout->input_ctx, point.x, point.y); [self recalcMovableByWindowBackground:point]; } diff --git a/waftools/fragments/cocoa.m b/waftools/fragments/cocoa.m index 3c6230401d8e9..91b3aaa585f6e 100644 --- a/waftools/fragments/cocoa.m +++ b/waftools/fragments/cocoa.m @@ -4,7 +4,8 @@ #include "osdep/macosx_compat.h" -int main(int argc, char **argv) { +int main(int argc, char **argv) +{ @autoreleasepool { NSArray *ary = @[@1, @2, @3]; NSLog(@"test subscripting: %@", ary[0]); From ff9f5e06ff203c055d968087956026ef9204218b Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 17 Dec 2016 13:24:05 +0100 Subject: [PATCH 70/83] Revert "Port several python scripts to Perl" This reverts commit fae73079310eef9dce9737f2e37ff4b80c8830ee. Before the waf build system was used, we had a configure script written in shell. To drop the build dependency on Python, someone rewrote the Python scripts we had to Perl. Now the shell configure script is gone, and it makes no sense to have a build dependency on both Perl and Python. This isn't just a straight revert. It adds the new Matroska EBML elements to the old Python scripts, adjusts the waf build system, and of course doesn't add anything back needed by the old build system. It would be better if this used matroska.py/file2string.py directly by importing them as modules, instead of calling them via "python". But for now this is simpler. --- TOOLS/file2string.pl | 24 -- TOOLS/file2string.py | 27 ++ TOOLS/lib/Parse/Matroska.pm | 30 -- TOOLS/lib/Parse/Matroska/Definitions.pm | 384 -------------------- TOOLS/lib/Parse/Matroska/Element.pm | 331 ----------------- TOOLS/lib/Parse/Matroska/Reader.pm | 426 ---------------------- TOOLS/lib/Parse/Matroska/Utils.pm | 37 -- TOOLS/matroska.pl | 169 --------- TOOLS/matroska.py | 463 ++++++++++++++++++++++++ waftools/generators/sources.py | 4 +- wscript | 4 +- 11 files changed, 495 insertions(+), 1404 deletions(-) delete mode 100755 TOOLS/file2string.pl create mode 100755 TOOLS/file2string.py delete mode 100644 TOOLS/lib/Parse/Matroska.pm delete mode 100644 TOOLS/lib/Parse/Matroska/Definitions.pm delete mode 100644 TOOLS/lib/Parse/Matroska/Element.pm delete mode 100644 TOOLS/lib/Parse/Matroska/Reader.pm delete mode 100644 TOOLS/lib/Parse/Matroska/Utils.pm delete mode 100755 TOOLS/matroska.pl create mode 100755 TOOLS/matroska.py diff --git a/TOOLS/file2string.pl b/TOOLS/file2string.pl deleted file mode 100755 index 341bb06fd6be1..0000000000000 --- a/TOOLS/file2string.pl +++ /dev/null @@ -1,24 +0,0 @@ -#! /usr/bin/env perl - -use strict; -use warnings; - -# Convert the contents of a file into a C string constant. -# Note that the compiler will implicitly add an extra 0 byte at the end -# of every string, so code using the string may need to remove that to get -# the exact contents of the original file. -# FIXME: why not a char array? - -# treat only alphanumeric and punctuations (excluding " and ?) as safe -my $unsafe_chars = qr{[^][A-Za-z0-9!#%&'()*+,./:;<=>^_{|}~ -]}; - -for my $file (@ARGV) { - open my $fh, '<:raw', $file or next; - print "/* Generated from $file */\n"; - while (<$fh>) { - # replace unsafe chars with their equivalent octal escapes - s/($unsafe_chars)/\\@{[sprintf '%03o', ord($1)]}/gos; - print "\"$_\"\n" - } - close $fh; -} diff --git a/TOOLS/file2string.py b/TOOLS/file2string.py new file mode 100755 index 0000000000000..6cdd1a72aebcd --- /dev/null +++ b/TOOLS/file2string.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +# Convert the contents of a file into a C string constant. +# Note that the compiler will implicitly add an extra 0 byte at the end +# of every string, so code using the string may need to remove that to get +# the exact contents of the original file. + +import sys + +# Indexing a byte string yields int on Python 3.x, and a str on Python 2.x +def pord(c): + return ord(c) if type(c) == str else c + +def main(infile): + conv = ['\\' + ("%03o" % c) for c in range(256)] + safe_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" \ + "0123456789!#%&'()*+,-./:;<=>?[]^_{|}~ " + for c in safe_chars: + conv[ord(c)] = c + for c, esc in ("\nn", "\tt", r"\\", '""'): + conv[ord(c)] = '\\' + esc + for line in infile: + sys.stdout.write('"' + ''.join(conv[pord(c)] for c in line) + '"\n') + +with open(sys.argv[1], 'rb') as infile: + sys.stdout.write("// Generated from %s\n\n" % sys.argv[1]) + main(infile) diff --git a/TOOLS/lib/Parse/Matroska.pm b/TOOLS/lib/Parse/Matroska.pm deleted file mode 100644 index e1c08c9814708..0000000000000 --- a/TOOLS/lib/Parse/Matroska.pm +++ /dev/null @@ -1,30 +0,0 @@ -use 5.008; -use strict; -use warnings; - -# ABSTRACT: Module collection to parse Matroska files. -package Parse::Matroska; - -=head1 DESCRIPTION - -Cs L. See the documentation -of the modules mentioned in L for more information -in how to use this module. - -It's intended for this module to contain high-level interfaces -to the other modules in the distribution. - -=head1 SOURCE CODE - -L - -=head1 SEE ALSO - -L, L, -L. - -=cut - -use Parse::Matroska::Reader; - -1; diff --git a/TOOLS/lib/Parse/Matroska/Definitions.pm b/TOOLS/lib/Parse/Matroska/Definitions.pm deleted file mode 100644 index 5a5adcd6de4a7..0000000000000 --- a/TOOLS/lib/Parse/Matroska/Definitions.pm +++ /dev/null @@ -1,384 +0,0 @@ -use 5.008; -use strict; -use warnings; - -# ABSTRACT: internal EBML grammar definitions -package Parse::Matroska::Definitions; - -use Parse::Matroska::Utils qw{uniq uncamelize}; - -use Exporter; -our @ISA = qw{Exporter}; -our @EXPORT_OK = qw{elem_by_hexid %EBML_DEFINITION %MATROSKA_DEFINITION}; - -=head1 SYNOPSIS - - use Parse::Matroska::Definitions qw{elem_by_hexid}; - my $ebml_id = elem_by_hexid('1a45dfa3'); - print "EBML ID $ebml_id->{elid}'s name: $ebml_id->{name}"; - -=head1 DESCRIPTION - -Contains the definition of the EBML grammar as expected in -Matroska files. This module is meant mostly for internal use. - -As this was extended from a script in mpv-player, some data -generated is apparently useless for regular module users -but is still relevant to the mpv-player script. Such data -is annotated as being for mpv compatibility. - -=head1 NOTE - -The API of this module is not yet considered stable. - -=head1 GLOBALS - -These global variables are considered B. - -=head2 @Parse::Matroska::Definitions::global_elem_list - -A global list of known matroska elements. Useful for -mpv's matroska script, used for generating C headers -that parse matroska. - -=head2 %Parse::Matroska::Definitions::global_elem_dict - -A global hash of known matroska elements. Used internally -by L. - -=cut - -@Parse::Matroska::Definitions::global_elem_list = (); -%Parse::Matroska::Definitions::global_elem_dict = (); - -=head2 %EBML_DEFINITION - -Optionally-importable hash of known EBML IDs belonging -to the EBML generic grammar. - -=head2 %MATROSKA_DEFINITION - -Optionally-importable hash of known EBML IDs belonging -to the Matroska-specific grammar. - -=cut - -our %EBML_DEFINITION = define_ebml(); -our %MATROSKA_DEFINITION = define_matroska(); - -=method elem_by_hexid($id) - -Returns an EBML Element Definition corresponding to the provided -hexadecimal string. Returns C if the element is unknown. - -=cut -sub elem_by_hexid { - my ($elid) = @_; - return $Parse::Matroska::Definitions::global_elem_dict{$elid}; -} - -################################################ -### Helper functions for document definition ### -################################################ - -# used by elem when setting the 'valname' key -use constant TYPE_MAP => { - uint => 'uint64_t', - str => 'char *', - binary => 'struct bstr', - ebml_id => 'uint32_t', - float => 'double', - sint => 'int64_t', -}; - -# this will be localized to "MATROSKA" or "EBML" on the elem declarations -our $ELEM_DEFINE_TYPE = undef; - -=method elem($name,$elid,$valtype) - -NOTE: never call this function yourself; it changes data structures -that are considered immutable outside of this package. - -Internal API function that generates the EBML Element Definitions. - -This API function returns an array which first element is C<$elid> -and the second is a generated hash. The generated hash is stored -in the @global_elem_list and %global_elem_dict. - -The generated hash contains: - -=for :list -= name -The EBML Element's name, given through C<$name>. -= elid -The EBML Element's hex id, given through C<$elid>. Used for lookups by L. -= valtype -The EBML Element's type, given through C<$valtype>, except when C<$valtype> is an arrayref. -= multiple -If C<$name> ends with a C<*>, this is set as true and strips the C<*> from L. Used to -mark elements that may be repeated. -= subelements -An arrayref of elements that may be children of this element, given through C<$valtype> if it -is an arrayref. Sets L to C if there are subelements. -= subids -An arrayref listing all the Ls of subelements, Cified. - -The following elements are for mpv compatibility: - -=for :list -= definename -Name used for generating C #defines. -= fieldname -Name used for generating C struct fields. -= structname -Name used for generating C struct names. -= ebmltype -A pre-#defined constant to describe the element's type. -= valname -Typename used when declaring a struct field referring to this element. - -=cut -sub elem { - my %e = (name => shift, elid => shift, valtype => shift); - - # strip * from name, set 'multiple' if there was one - $e{multiple} = scalar $e{name} =~ s/\*$//; - - # ELEM_DEFINE_TYPE is either MATROSKA or EBML - $e{definename} = "${ELEM_DEFINE_TYPE}_ID_".uc($e{name}); - $e{fieldname} = uncamelize $e{name}; - $e{structname} = "ebml_$e{fieldname}"; - - if (ref $e{valtype} eq 'HASH') { - $e{subelements} = $e{valtype}; - $e{subids} = uniq map { $_->{elid} } values %{$e{subelements}}; - $e{valtype} = 'sub'; - $e{ebmltype} = 'EBML_TYPE_SUBELEMENTS'; - $e{valname} = "struct $e{structname}"; - } else { - $e{ebmltype} = "EBML_TYPE_\U$e{valtype}"; - die "Unrecognized value type $e{valtype}" unless - defined ($e{valname} = TYPE_MAP->{$e{valtype}}); - } - my $e = \%e; - push @Parse::Matroska::Definitions::global_elem_list, $e; - $Parse::Matroska::Definitions::global_elem_dict{$e{elid}} = $e; - return ($e{elid}, $e); -} - -############################################# -### EBML and Matroska document definitons ### -############################################# - -=method define_ebml - -Internal function that defines the EBML generic grammar. - -Must not be called from outside the package. - -=cut -sub define_ebml { - local $ELEM_DEFINE_TYPE = 'EBML'; - return ( - elem('EBML', '1a45dfa3', { - elem('EBMLVersion', '4286', 'uint'), - elem('EBMLReadVersion', '42f7', 'uint'), - elem('EBMLMaxIDLength', '42f2', 'uint'), - elem('EBMLMaxSizeLength', '42f3', 'uint'), - elem('DocType', '4282', 'str'), - elem('DocTypeVersion', '4287', 'uint'), - elem('DocTypeReadVersion', '4285', 'uint'), - }), - - elem('CRC32', 'bf', 'binary'), - elem('Void', 'ec', 'binary'), - ); -} - - -=method define_matroska - -Internal function that defines the Matroska-specific EBML grammar. - -Must not be called from outside the package. - -=cut -sub define_matroska { - local $ELEM_DEFINE_TYPE = 'MATROSKA'; - return ( - elem('Segment', '18538067', { - elem('SeekHead*', '114d9b74', { - elem('Seek*', '4dbb', { - elem('SeekID', '53ab', 'ebml_id'), - elem('SeekPosition', '53ac', 'uint'), - }), - }), - - elem('Info*', '1549a966', { - elem('SegmentUID', '73a4', 'binary'), - elem('PrevUID', '3cb923', 'binary'), - elem('NextUID', '3eb923', 'binary'), - elem('TimecodeScale', '2ad7b1', 'uint'), - elem('DateUTC', '4461', 'sint'), - elem('Title', '7ba9', 'str'), - elem('MuxingApp', '4d80', 'str'), - elem('WritingApp', '5741', 'str'), - elem('Duration', '4489', 'float'), - }), - - elem('Cluster*', '1f43b675', { - elem('Timecode', 'e7', 'uint'), - elem('BlockGroup*', 'a0', { - elem('Block', 'a1', 'binary'), - elem('BlockDuration', '9b', 'uint'), - elem('ReferenceBlock*', 'fb', 'sint'), - elem('DiscardPadding', '75A2', 'sint'), - }), - elem('SimpleBlock*', 'a3', 'binary'), - }), - - elem('Tracks*', '1654ae6b', { - elem('TrackEntry*', 'ae', { - elem('TrackNumber', 'd7', 'uint'), - elem('TrackUID', '73c5', 'uint'), - elem('TrackType', '83', 'uint'), - elem('FlagEnabled', 'b9', 'uint'), - elem('FlagDefault', '88', 'uint'), - elem('FlagForced', '55aa', 'uint'), - elem('FlagLacing', '9c', 'uint'), - elem('MinCache', '6de7', 'uint'), - elem('MaxCache', '6df8', 'uint'), - elem('DefaultDuration', '23e383', 'uint'), - elem('TrackTimecodeScale', '23314f', 'float'), - elem('MaxBlockAdditionID', '55ee', 'uint'), - elem('Name', '536e', 'str'), - elem('Language', '22b59c', 'str'), - elem('CodecID', '86', 'str'), - elem('CodecPrivate', '63a2', 'binary'), - elem('CodecName', '258688', 'str'), - elem('CodecDecodeAll', 'aa', 'uint'), - elem('CodecDelay', '56AA', 'uint'), - elem('SeekPreRoll', '56BB', 'uint'), - elem('Video', 'e0', { - elem('FlagInterlaced', '9a', 'uint'), - elem('PixelWidth', 'b0', 'uint'), - elem('PixelHeight', 'ba', 'uint'), - elem('DisplayWidth', '54b0', 'uint'), - elem('DisplayHeight', '54ba', 'uint'), - elem('DisplayUnit', '54b2', 'uint'), - elem('FrameRate', '2383e3', 'float'), - elem('ColourSpace', '2eb524', 'binary'), - elem('StereoMode', '53b8', 'uint'), - elem('Colour', '55B0', { - elem('MatrixCoefficients', '55B1', 'uint'), - elem('BitsPerChannel', '55B2', 'uint'), - elem('ChromaSubsamplingHorz', '55B3', 'uint'), - elem('ChromaSubsamplingVert', '55B4', 'uint'), - elem('CbSubsamplingHorz', '55B5', 'uint'), - elem('CbSubsamplingVert', '55B6', 'uint'), - elem('ChromaSitingHorz', '55B7', 'uint'), - elem('ChromaSitingVert', '55B8', 'uint'), - elem('Range', '55B9', 'uint'), - elem('TransferCharacteristics', '55BA', 'uint'), - elem('Primaries', '55BB', 'uint'), - elem('MaxCLL', '55BC', 'uint'), - elem('MaxFALL', '55BD', 'uint'), - elem('MasteringMetadata', '55D0', { - elem('PrimaryRChromaticityX', '55D1', 'float'), - elem('PrimaryRChromaticityY', '55D2', 'float'), - elem('PrimaryGChromaticityX', '55D3', 'float'), - elem('PrimaryGChromaticityY', '55D4', 'float'), - elem('PrimaryBChromaticityX', '55D5', 'float'), - elem('PrimaryBChromaticityY', '55D6', 'float'), - elem('WhitePointChromaticityX', '55D7', 'float'), - elem('WhitePointChromaticityY', '55D8', 'float'), - elem('LuminanceMax', '55D9', 'float'), - elem('LuminanceMin', '55DA', 'float'), - }), - }), - }), - elem('Audio', 'e1', { - elem('SamplingFrequency', 'b5', 'float'), - elem('OutputSamplingFrequency', '78b5', 'float'), - elem('Channels', '9f', 'uint'), - elem('BitDepth', '6264', 'uint'), - }), - elem('ContentEncodings', '6d80', { - elem('ContentEncoding*', '6240', { - elem('ContentEncodingOrder', '5031', 'uint'), - elem('ContentEncodingScope', '5032', 'uint'), - elem('ContentEncodingType', '5033', 'uint'), - elem('ContentCompression', '5034', { - elem('ContentCompAlgo', '4254', 'uint'), - elem('ContentCompSettings', '4255', 'binary'), - }), - }), - }), - }), - }), - - elem('Cues', '1c53bb6b', { - elem('CuePoint*', 'bb', { - elem('CueTime', 'b3', 'uint'), - elem('CueTrackPositions*', 'b7', { - elem('CueTrack', 'f7', 'uint'), - elem('CueClusterPosition', 'f1', 'uint'), - elem('CueRelativePosition','f0', 'uint'), - elem('CueDuration', 'b2', 'uint'), - }), - }), - }), - - elem('Attachments', '1941a469', { - elem('AttachedFile*', '61a7', { - elem('FileDescription', '467e', 'str'), - elem('FileName', '466e', 'str'), - elem('FileMimeType', '4660', 'str'), - elem('FileData', '465c', 'binary'), - elem('FileUID', '46ae', 'uint'), - }), - }), - - elem('Chapters', '1043a770', { - elem('EditionEntry*', '45b9', { - elem('EditionUID', '45bc', 'uint'), - elem('EditionFlagHidden', '45bd', 'uint'), - elem('EditionFlagDefault', '45db', 'uint'), - elem('EditionFlagOrdered', '45dd', 'uint'), - elem('ChapterAtom*', 'b6', { - elem('ChapterUID', '73c4', 'uint'), - elem('ChapterTimeStart', '91', 'uint'), - elem('ChapterTimeEnd', '92', 'uint'), - elem('ChapterFlagHidden', '98', 'uint'), - elem('ChapterFlagEnabled', '4598', 'uint'), - elem('ChapterSegmentUID', '6e67', 'binary'), - elem('ChapterSegmentEditionUID', '6ebc', 'uint'), - elem('ChapterDisplay*', '80', { - elem('ChapString', '85', 'str'), - elem('ChapLanguage*', '437c', 'str'), - elem('ChapCountry*', '437e', 'str'), - }), - }), - }), - }), - elem('Tags*', '1254c367', { - elem('Tag*', '7373', { - elem('Targets', '63c0', { - elem('TargetTypeValue', '68ca', 'uint'), - elem('TargetTrackUID', '63c5', 'uint'), - elem('TargetEditionUID', '63c9', 'uint'), - elem('TargetChapterUID', '63c4', 'uint'), - elem('TargetAttachmentUID', '63c6', 'uint'), - }), - elem('SimpleTag*', '67c8', { - elem('TagName', '45a3', 'str'), - elem('TagLanguage', '447a', 'str'), - elem('TagString', '4487', 'str'), - }), - }), - }), - }), - ); -} - -1; diff --git a/TOOLS/lib/Parse/Matroska/Element.pm b/TOOLS/lib/Parse/Matroska/Element.pm deleted file mode 100644 index fa0830c11e198..0000000000000 --- a/TOOLS/lib/Parse/Matroska/Element.pm +++ /dev/null @@ -1,331 +0,0 @@ -use 5.008; -use strict; -use warnings; - -# ABSTRACT: a mid-level representation of an EBML element -package Parse::Matroska::Element; - -use Carp; -use List::Util qw{first}; - -=head1 SYNOPSIS - - use Parse::Matroska::Reader; - my $reader = Parse::Matroska::Reader->new($path); - my $elem = $reader->read_element; - - print "ID: $elem->{elid}\n"; - print "Name: $elem->{name}\n"; - print "Length: $elem->{content_len}\n"; - print "Type: $elem->{type}\n"; - print "Child count: ", scalar(@{$elem->all_children}), "\n"; - if ($elem->{type} eq 'sub') { - while (my $chld = $elem->next_child) { - print "Child Name: $chld->{name}\n"; - } - } else { - print "Value: ", $elem->get_value, "\n"; - } - -=head1 DESCRIPTION - -Represents a single Matroska element as decoded by -L. This is essentially a hash -augmented with functions for delay-loading of binary -values and children elements. - -=head1 NOTE - -The API of this module is not yet considered stable. - -=attr elid - -The EBML Element ID, suitable for passing to -L. - -=attr name - -The EBML Element's name. - -=attr type - -The EBML Element's type. Can be C, C, -C, C, C or C. See L -for details. - -Equivalent to -C{value})-E{valtype}>. - -=attr value - -The EBML Element's value. Should be obtained through -L. - -Is an unicode string if the L is C, that is, -the string has already been decoded by L. - -Is C if the L is C and the contents -were delay-loaded and not yet read. L will -do the delayed load if needed. - -Is an arrayref if the L is C, containing -the children nodes that were already loaded. - -Is a hashref if the L is C, containing -the referred element's information as defined in -L. Calling -C{value}-E{elid})> will -return the same object as $elem->{value}. - -=attr full_len - -The entire length of this EBML Element, including -the header's. - -=attr size_len - -The length of the size marker. Used when calculating -L from L - -=attr content_len - -The length of the contents of this EBML Element, -which excludes the header. - -=attr reader - -A weakened reference to the associated -L. - -=method new(%hash) - -Creates a new Element initialized with the hash -given as argument. - -=cut -sub new { - my $class = shift; - my $self = {}; - bless $self, $class; - - $self->initialize(@_); - return $self; -} - -=method initialize(%hash) - -Called by L on initialization. - -=cut -sub initialize { - my ($self, %args) = @_; - for (keys %args) { - $self->{$_} = $args{$_}; - } - $self->{depth} = 0 unless $self->{depth}; -} - -=method skip - -Called by the user to ignore the contents of this EBML node. -Needed when ignoring the children of a node. - -=cut -sub skip { - my ($self) = @_; - my $reader = $self->{reader}; - return unless $reader; # we don't have to skip if there's no reader - my $pos = $reader->getpos; - croak "Too late to skip, reads were already done" - if $pos ne $self->{data_pos}; - $reader->skip($self->{content_len}); -} - -=method get_value($keep_bin) - -Returns the value contained by this EBML element. - -If the element has children, returns an arrayref to -the children elements that were already encountered. - -If the element's type is C and the value was -delay-loaded, does the reading now. - -If $keep_bin is true, the delay-loaded data is kept -as the L, otherwise, further calls to -C will reread the data from the L. - -=cut -sub get_value { - my ($self, $keep_bin) = @_; - - return undef if $self->{type} eq 'skip'; - return $self->{value} if $self->{value}; - - my $reader = $self->{reader} or - croak "The associated Reader has been deleted"; - - # delay-loaded 'binary' - if ($self->{type} eq 'binary') { - croak "Cannot seek in the current Reader" unless $self->{data_pos}; - # seek to the data position... - $reader->setpos($self->{data_pos}); - # read the data, keeping it in value if requested - if ($keep_bin) { - $self->{value} = $reader->readlen($self->{content_len}); - return $self->{value}; - } else { - return $reader->readlen($self->{content_len}); - } - } -} - -=method next_child($read_bin) - -Builtin iterator; reads and returns the next child element. -Always returns undef if the type isn't C. - -Returns undef at the end of the iterator and resets itself to -point to the first element; so calling L -after the iterator returned C will return the first child. - -The optional C<$read_bin> parameter has the children elements -not delay-load their value if their type is C. - -If all children elements have already been read, return -each element in-order as would be given by -L. - -=cut -sub next_child { - my ($self, $read_bin) = @_; - return unless $self->{type} eq 'sub'; - - if ($self->{_all_children_read}) { - my $idx = $self->{_last_child} ||= 0; - if ($idx == @{$self->{value}}) { - # reset the iterator, returning undef once - $self->{_last_child} = 0; - return; - } - my $ret = $self->{value}->[$idx]; - - ++$idx; - $self->{_last_child} = $idx; - return $ret; - } - - my $len = defined $self->{remaining_len} - ? $self->{remaining_len} - : $self->{content_len}; - - if ($len == 0) { - # we've read all children; switch into $self->{value} iteration mode - $self->{_all_children_read} = 1; - # return undef since the iterator will reset - return; - } - - $self->{pos_offset} ||= 0; - my $pos = $self->{data_pos}; - my $reader = $self->{reader} or croak "The associated reader has been deleted"; - $reader->setpos($pos); - $reader->{fh}->seek($self->{pos_offset}, 1) if $pos; - - my $chld = $reader->read_element($read_bin); - return undef unless defined $chld; - $self->{pos_offset} += $chld->{full_len}; - - $self->{remaining_len} = $len - $chld->{full_len}; - - if ($self->{remaining_len} < 0) { - croak "Child elements consumed $self->{remaining_len} more bytes than parent $self->{name} contained"; - } - - $chld->{depth} = $self->{depth} + 1; - $self->{value} ||= []; - - push @{$self->{value}}, $chld; - - return $chld; -} - -=method all_children($recurse,$read_bin) - -Calls L on self -and returns an arrayref with the children nodes. - -Both C<$recurse> and C<$read_bin> are optional and default -to false. - -=cut -sub all_children { - my ($self, $recurse, $read_bin) = @_; - $self->populate_children($recurse, $read_bin); - return $self->{value}; -} - -=method children_by_name($name) - -Searches in the already read children elements for all -elements with the EBML name C<$name>. Returns an array -containing all found elements. On scalar context, -returns only the first element found. - -Croaks if the element's C isn't C. - -=cut -sub children_by_name { - my ($self, $name) = @_; - return unless defined wantarray; # don't do work if work isn't wanted - croak "Element can't have children" unless $self->{type} eq 'sub'; - - my @found = grep { $_->{name} eq $name } @{$self->{value}}; - return @found if wantarray; # list - return shift @found if defined wantarray; # scalar -} - -=method populate_children($recurse,$read_bin) - -Populates the internal array of children elements, that is, -requests that the associated L reads -all children elements. Returns itself. - -Returns false if the element's C isn't C. - -If C<$recurse> is provided and is true, the method will call -itself in the children elements with the same parameters it -received; this will build a full EBML tree. - -If C<$read_bin> is provided and is true, disables delay-loading -of the contents of C-type nodes, reading the contents -to memory. - -If both C<$recurse> and C<$read_bin> are true, entire EBML trees -can be loaded without requiring seeks, thus behaving correctly -on unseekable streams. If C<$read_bin> is false, the entire EBML -tree is still loaded, but calling L on C-type -nodes will produce an error on unseekable streams. - -=cut -sub populate_children { - my ($self, $recurse, $read_bin) = @_; - - return unless $self->{type} eq 'sub'; - - if (@{$self->{value}} && $recurse) { - # only recurse - foreach (@{$self->{value}}) { - $_->populate_children($recurse, $read_bin); - } - return $self; - } - - while (my $chld = $self->next_child($read_bin)) { - $chld->populate_children($recurse, $read_bin) if $recurse; - } - - return $self; -} - -1; diff --git a/TOOLS/lib/Parse/Matroska/Reader.pm b/TOOLS/lib/Parse/Matroska/Reader.pm deleted file mode 100644 index 614b7b12c0590..0000000000000 --- a/TOOLS/lib/Parse/Matroska/Reader.pm +++ /dev/null @@ -1,426 +0,0 @@ -use 5.008; -use strict; -use warnings; - -# ABSTRACT: a low-level reader for EBML files -package Parse::Matroska::Reader; - -use Parse::Matroska::Definitions qw{elem_by_hexid}; -use Parse::Matroska::Element; - -use Carp; -use Scalar::Util qw{openhandle weaken}; -use IO::Handle; -use IO::File; -use List::Util qw{first}; -use Encode; - -use constant BIGINT_TRY => 'Pari,GMP,FastCalc'; -use Math::BigInt try => BIGINT_TRY; -use Math::BigRat try => BIGINT_TRY; - -=head1 SYNOPSIS - - use Parse::Matroska::Reader; - my $reader = Parse::Matroska::Reader->new($path); - $reader->close; - $reader->open(\$string_with_matroska_data); - - my $elem = $reader->read_element; - print "Element ID: $elem->{elid}\n"; - print "Element name: $elem->{name}\n"; - if ($elem->{type} ne 'sub') { - print "Element value: $elem->get_value\n"; - } else { - while (my $child = $elem->next_child) { - print "Child element: $child->{name}\n"; - } - } - $reader->close; - -=head1 DESCRIPTION - -Reads EBML data, which is used in Matroska files. -This is a low-level reader which is meant to be used as a backend -for higher level readers. TODO: write the high level readers :) - -=head1 NOTE - -The API of this module is not yet considered stable. - -=method new - -Creates a new reader. -Calls L with its arguments if provided. - -=cut -sub new { - my $class = shift; - my $self = {}; - bless $self, $class; - - $self->open(@_) if @_; - return $self; -} - -=method open($arg) - -Creates the internal filehandle. The argument can be: - -=for :list -* An open filehandle or L object. -The filehandle is not Ced, so calling L in this -object will close the given filehandle as well. -* A scalar containing a path to a file. -* On perl v5.14 or newer, a scalarref pointing to EBML data. -For similar functionality in older perls, give an L object -or the handle to an already Ced scalarref. - -=cut -sub open { - my ($self, $arg) = @_; - $self->{fh} = openhandle($arg) || IO::File->new($arg, "<:raw") - or croak "Can't open $arg: $!"; -} - -=method close - -Closes the internal filehandle. - -=cut -sub close { - my ($self) = @_; - $self->{fh}->close; - delete $self->{fh}; -} - -# equivalent to $self->readlen(1), possibly faster -sub _getc { - my ($self) = @_; - my $c = $self->{fh}->getc; - croak "Can't do read of length 1: $!" if !defined $c && $!; - return $c; -} - -=method readlen($length) - -Reads C<$length> bytes from the internal filehandle. - -=cut -sub readlen { - my ($self, $len) = @_; - my $data; - my $readlen = $self->{fh}->read($data, $len); - croak "Can't do read of length $len: $!" - unless defined $readlen; - return $data; -} - -# converts a byte string into an integer -# we do so by converting the integer into a hex string (big-endian) -# and then reading the hex-string into an integer -sub _bin2int($) { - my ($bin) = @_; - # if the length is larger than 3 - # the resulting integer might be larger than INT_MAX - if (length($bin) > 3) { - return Math::BigInt->from_hex(unpack("H*", $bin)); - } - return hex(unpack("H*", $bin)); -} - -# creates a floating-point number with the given mantissa and exponent -sub _ldexp { - my ($mantissa, $exponent) = @_; - my $r = new Math::BigRat($mantissa); - return $r * Math::BigRat->new(2)**$exponent; -} - -# NOTE: the read_* functions are hard to read because they're ports -# of even harder to read python functions. -# TODO: make them readable - -=method read_id - -Reads an EBML ID atom in hexadecimal string format, suitable -for passing to L. - -=cut -sub read_id { - my ($self) = @_; - my $t = $self->_getc; - return undef unless defined $t; - my $i = 0; - my $mask = 1<<7; - - if (ord($t) == 0) { - croak "Matroska Syntax error: first byte of ID was \\0" - } - until (ord($t) & $mask) { - ++$i; - $mask >>= 1; - } - # return hex string of the bytes we just read - return unpack "H*", ($t . $self->readlen($i)); -} - -=method read_size - -Reads an EBML Data Size atom, which immediately follows -an EBML ID atom. - -This returns an array consisting of: - -=for :list -0. The length of the Data Size atom. -1. The value encoded in the Data Size atom, which is the length of all the data following it. - -=cut -sub read_size { - my ($self) = @_; - my $t = $self->_getc; - my $i = 0; - my $mask = 1<<7; - - if (ord($t) == 0) { - croak "Matroska Syntax error: first byte of data size was \\0" - } - until (ord($t) & $mask) { - ++$i; - $mask >>= 1; - } - $t = $t & chr($mask-1); # strip length bits (keep only significant bits) - return ($i+1, _bin2int $t . $self->readlen($i)); -} - -=method read_str($length) - -Reads a string of length C<$length> bytes from the internal filehandle. -The string is already Ld from C, which is the -standard Matroska string encoding. - -=cut -{ - my $utf8 = find_encoding("UTF-8"); - sub read_str { - my ($self, $length) = @_; - return $utf8->decode($self->readlen($length)); - } -} - -=method read_uint($length) - -Reads an unsigned integer of length C<$length> bytes -from the internal filehandle. - -Returns a L object if C<$length> is greater -than 4. - -=cut -sub read_uint { - my ($self, $length) = @_; - return _bin2int $self->readlen($length); -} - -=method read_sint($length) - -Reads a signed integer of length C<$length> bytes -from the internal filehandle. - -Returns a L object if C<$length> is greater -than 4. - -=cut -sub read_sint { - my ($self, $length) = @_; - my $i = $self->read_uint($length); - - # Apply 2's complement to the unsigned int - my $mask = int(2 ** ($length * 8 - 1)); - # if the most significant bit is set... - if ($i & $mask) { - # subtract the MSB twice - $i -= 2 * $mask; - } - return $i; -} - -=method read_float($length) - -Reads an IEEE floating point number of length C<$length> -bytes from the internal filehandle. - -Only lengths C<4> and C<8> are supported (C C and C). - -=cut -{ - my $b1 = new Math::BigInt 1; - - sub read_float { - my ($self, $length) = @_; - my $i = new Math::BigInt $self->read_uint($length)->bstr; - my $f; - - # These evil expressions reinterpret an unsigned int as IEEE binary floats - if ($length == 4) { - $f = _ldexp(($i & ((1<<23) - 1)) + (1<<23), ($i>>23 & ((1<<8) - 1)) - 150); - $f = -$f if $i & ($b1<<31); - } elsif ($length == 8) { - $f = _ldexp(($i & (($b1<<52) - 1)) + ($b1<<52), ($i>>52 & ((1<<12) - 1)) - 1075); - $f = -$f if $i & ($b1<<63); - } else { - croak "Matroska Syntax error: unsupported IEEE float byte size $length"; - } - - return $f; - } -} - -=method read_ebml_id($length) - -Reads an EBML ID when it's encoded as the data inside another -EBML element, that is, when the enclosing element's C is -C. - -This returns a hashref with the EBML element description as -defined in L. - -=cut -sub read_ebml_id { - my ($self, $length) = @_; - return elem_by_hexid(unpack("H*", $self->readlen($length))); -} - -=method skip($length) - -Skips C<$length> bytes in the internal filehandle. - -=cut -sub skip { - my ($self, $len) = @_; - return if $self->{fh}->can('seek') && $self->{fh}->seek($len, 1); - $self->readlen($len); - return; -} - -=method getpos - -Wrapper for Lgetpos> in the internal filehandle. - -Returns undef if the internal filehandle can't C. - -=cut -sub getpos { - my ($self) = @_; - return undef unless $self->{fh}->can('getpos'); - return $self->{fh}->getpos; -} - -=method setpos($pos) - -Wrapper for Lsetpos> in the internal filehandle. - -Returns C if the internal filehandle can't C. - -Croaks if C does not seek to the requested position, -that is, if calling C does not yield the same object -as the C<$pos> argument. - -=cut -sub setpos { - my ($self, $pos) = @_; - return undef unless $pos && $self->{fh}->can('setpos'); - - my $ret = $self->{fh}->setpos($pos); - croak "Cannot seek to correct position" - unless $self->getpos eq $pos; - return $ret; -} - -=method read_element($read_bin) - -Reads a full EBML element from the internal filehandle. - -Returns a L object initialized with -the read data. If C is not present or is false, will -delay-load the contents of C type elements, that is, -they will only be loaded when calling C on the -returned L object. - -Does not read the children of the element if its type is -C. Look into the L interface -for details in how to read children elements. - -Pass a true C<$read_bin> if the stream being read is not -seekable (C is undef) and the contents of C -elements is desired, otherwise seeking errors or internal -filehandle corruption might occur. - -=cut -sub read_element { - my ($self, $read_bin) = @_; - return undef if $self->{fh}->eof; - - my $elem_pos = $self->getpos; - - my $elid = $self->read_id; - my $elem_def = elem_by_hexid($elid); - my ($size_len, $content_len) = $self->read_size; - my $full_len = length($elid)/2 + $size_len + $content_len; - - my $elem = Parse::Matroska::Element->new( - elid => $elid, - name => $elem_def && $elem_def->{name}, - type => $elem_def && $elem_def->{valtype}, - size_len => $size_len, - content_len => $content_len, - full_len => $full_len, - reader => $self, - elem_pos => $elem_pos, - data_pos => $self->getpos, - ); - weaken($elem->{reader}); - - if (defined $elem_def) { - if ($elem->{type} eq 'sub') { - $elem->{value} = []; - } elsif ($elem->{type} eq 'str') { - $elem->{value} = $self->read_str($content_len); - } elsif ($elem->{type} eq 'ebml_id') { - $elem->{value} = $self->read_ebml_id($content_len); - } elsif ($elem->{type} eq 'uint') { - $elem->{value} = $self->read_uint($content_len); - } elsif ($elem->{type} eq 'sint') { - $elem->{value} = $self->read_sint($content_len); - } elsif ($elem->{type} eq 'float') { - $elem->{value} = $self->read_float($content_len); - } elsif ($elem->{type} eq 'skip') { - $self->skip($content_len); - } elsif ($elem->{type} eq 'binary') { - if ($read_bin) { - $elem->{value} = $self->readlen($content_len); - } else { - $self->skip($content_len); - } - } else { - die "Matroska Definition error: type $elem->{valtype} unknown" - } - } else { - $self->skip($content_len); - } - return $elem; -} - -1; - -=head1 CAVEATS - -Children elements have to be processed as soon as an element -with children is found, or their children ignored with -L. Not doing so doesn't cause -errors but results in an invalid structure, with constant C<0> -depth. - -To work correctly in unseekable streams, either the contents -of C-type elements has to be ignored or the C -flag to C has to be true. diff --git a/TOOLS/lib/Parse/Matroska/Utils.pm b/TOOLS/lib/Parse/Matroska/Utils.pm deleted file mode 100644 index 127d626cb129a..0000000000000 --- a/TOOLS/lib/Parse/Matroska/Utils.pm +++ /dev/null @@ -1,37 +0,0 @@ -use strict; -use warnings; - -# ABSTRACT: internally-used helper functions -package Parse::Matroska::Utils; - -use Exporter; -our @ISA = qw{Exporter}; -our @EXPORT_OK = qw{uniq uncamelize}; - -=method uniq(@array) - -The same as L. -Included to avoid depending on it since it's -not a core module. - -=cut -sub uniq(@) { - my %seen; - return grep { !$seen{$_}++ } @_; -} - -=method uncamelize($string) - -Converts a "StringLikeTHIS" into a -"string_like_this". - -=cut -sub uncamelize($) { - local $_ = shift; - # lc followed by UC: lc_UC - s/(?<=[a-z])([A-Z])/_\L$1/g; - # UC followed by two lc: _UClclc - s/([A-Z])(?=[a-z]{2})/_\L$1/g; - # strip leading _ that the second regexp might add; lowercase all - s/^_//; lc -} diff --git a/TOOLS/matroska.pl b/TOOLS/matroska.pl deleted file mode 100755 index 41e4f6aa81765..0000000000000 --- a/TOOLS/matroska.pl +++ /dev/null @@ -1,169 +0,0 @@ -#! /usr/bin/env perl - -# Generate C definitions for parsing Matroska files. - -use strict; -use warnings; - -use FindBin; -use lib "$FindBin::Bin/lib"; -use Parse::Matroska::Definitions; -use Parse::Matroska::Reader; - -use Getopt::Long; -use List::Util qw{max}; - -my @global_elem_list = @Parse::Matroska::Definitions::global_elem_list; - -Getopt::Long::Configure(qw{auto_version auto_help}); -my %opt; -GetOptions(\%opt, - "generate-header", - "generate-definitions", - "full", - ); - -if ($opt{"generate-header"}) { - generate_c_header(); -} elsif ($opt{"generate-definitions"}) { - generate_c_definitions(); -} else { - for (@ARGV) { - my $reader = Parse::Matroska::Reader->new($_ eq '-' ? \*STDIN : $_) or die $!; - while (my $elem = $reader->read_element($_ eq '-')) { - process_elem($elem, $_ eq '-'); - } - } -} - -# Generate declarations for libmpdemux/ebml_types.h -sub generate_c_header { - print "/* Generated by TOOLS/matroska.pl, do not edit manually */\n\n"; - - # Write a #define for the ElementID of each known element - for my $el (@global_elem_list) { - printf "#define %-40s 0x%s\n", $el->{definename}, $el->{elid}; - } - print "\n"; - - # Define a struct for each ElementID that has child elements - for my $el (@global_elem_list) { - next unless $el->{subelements}; - print "\nstruct $el->{structname} {\n"; - - # Figure out the length of the longest variable name - # Used for pretty-printing in the next step - my $l = max(map { length $_->{valname} } values %{$el->{subelements}}); - - # Output each variable, with pointers for array (multiple) elements - for my $subel (sort { $a->{definename} cmp $b->{definename} } values %{$el->{subelements}}) { - printf " %-${l}s %s%s;\n", - $subel->{valname}, $subel->{multiple}?'*':' ', $subel->{fieldname}; - } - print "\n"; - - # Output a counter variable for each element - # (presence/absence for scalars, item count for arrays) - for my $subel (sort values %{$el->{subelements}}) { - print " int n_$subel->{fieldname};\n" - } - print "};\n"; - } - print "\n"; - - # Output extern references for ebml_elem_desc structs for each of the elements - # These are defined by generate_c_definitions - for my $el (@global_elem_list) { - next unless $el->{subelements}; - print "extern const struct ebml_elem_desc $el->{structname}_desc;\n"; - } - print "\n"; - - # Output the max number of sub-elements a known element might have - printf "#define MAX_EBML_SUBELEMENTS %d\n", - max(map { scalar keys %{$_->{subelements}} } - grep { $_->{subelements} } @global_elem_list); -} - -# Generate definitions for libmpdemux/ebml_defs.c -sub generate_c_definitions { - print "/* Generated by TOOLS/matroska.pl, do not edit manually */\n\n"; - # ebml_defs.c uses macros declared in ebml.c - for my $el (@global_elem_list) { - print "\n"; - if ($el->{subelements}) { - # set N for the next macros - print "#define N $el->{fieldname}\n"; - - # define a struct ebml_$N_desc and gets ready to define fields - # this secretly opens two scopes; hence the }}; at the end - print "E_S(\"$el->{name}\", ".scalar(keys %{$el->{subelements}}).")\n"; - - # define a field for each subelement - # also does lots of macro magic, but doesn't open a scope - for my $subel (sort { $a->{definename} cmp $b->{definename} } values %{$el->{subelements}}) { - print "F($subel->{definename}, $subel->{fieldname}, ". - ($subel->{multiple}?'1':'0').")\n"; - } - # close the struct - print "}};\n"; - - # unset N since we've used it - print "#undef N\n"; - } else { - print "E(\"$el->{name}\", $el->{fieldname}, $el->{ebmltype})\n"; - } - } -} - -sub repr { - my @ret; - foreach (@_) { - if (/'/) { - s/"/\\"/g; - push @ret, "\"$_\""; - } else { - push @ret, "'$_'"; - } - } - return @ret if wantarray; - return pop @ret if defined wantarray; - return; -} - -sub process_elem { - my ($elem, $read_bin) = @_; - unless ($opt{full}) { - if ($elem->{name} eq 'Cluster' || $elem->{name} eq 'Cues') { - $elem->skip; - return; - } - } - die unless $elem; - - if ($elem->{type} ne 'skip') { - print "$elem->{depth} $elem->{elid} $elem->{name} size: $elem->{content_len} value: "; - } - - if ($elem->{type} eq 'sub') { - print "subelements:\n"; - while (my $chld = $elem->next_child($read_bin)) { - process_elem($chld); - } - } elsif ($elem->{type} eq 'binary') { - my $t = "{content_len} bytes>"; - if ($elem->{content_len} < 20) { - $t = unpack "H*", $elem->get_value; - } - print "binary $t\n"; - delete $elem->{value}; - } elsif ($elem->{type} eq 'ebml_id') { - print "binary $elem->{value}->{elid} (".($elem->{value}->{name}||"UNKNOWN").")\n"; - } elsif ($elem->{type} eq 'skip') { - # skip - } elsif ($elem->{type} eq 'str') { - print "string ". repr($elem->get_value) . "\n"; - } else { - print "$elem->{type} ". $elem->get_value ."\n"; - } -} diff --git a/TOOLS/matroska.py b/TOOLS/matroska.py new file mode 100755 index 0000000000000..91e65a26b36fd --- /dev/null +++ b/TOOLS/matroska.py @@ -0,0 +1,463 @@ +#!/usr/bin/env python +""" +Generate C definitions for parsing Matroska files. +Can also be used to directly parse Matroska files and display their contents. +""" + +# +# This file is part of MPlayer. +# +# MPlayer 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. +# +# MPlayer 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. +# +# You should have received a copy of the GNU General Public License along +# with MPlayer; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +# for compatibility with Python 2.x +from __future__ import print_function + +elements_ebml = ( + 'EBML, 1a45dfa3, sub', ( + 'EBMLVersion, 4286, uint', + 'EBMLReadVersion, 42f7, uint', + 'EBMLMaxIDLength, 42f2, uint', + 'EBMLMaxSizeLength, 42f3, uint', + 'DocType, 4282, str', + 'DocTypeVersion, 4287, uint', + 'DocTypeReadVersion, 4285, uint', + ), + + 'CRC32, bf, binary', + 'Void, ec, binary', +) + +elements_matroska = ( + 'Segment, 18538067, sub', ( + + 'SeekHead*, 114d9b74, sub', ( + 'Seek*, 4dbb, sub', ( + 'SeekID, 53ab, ebml_id', + 'SeekPosition, 53ac, uint', + ), + ), + + 'Info*, 1549a966, sub', ( + 'SegmentUID, 73a4, binary', + 'PrevUID, 3cb923, binary', + 'NextUID, 3eb923, binary', + 'TimecodeScale, 2ad7b1, uint', + 'DateUTC, 4461, sint', + 'Title, 7ba9, str', + 'MuxingApp, 4d80, str', + 'WritingApp, 5741, str', + 'Duration, 4489, float', + ), + + 'Cluster*, 1f43b675, sub', ( + 'Timecode, e7, uint', + 'BlockGroup*, a0, sub', ( + 'Block, a1, binary', + 'BlockDuration, 9b, uint', + 'ReferenceBlock*, fb, sint', + 'DiscardPadding, 75A2, sint', + ), + 'SimpleBlock*, a3, binary', + ), + + 'Tracks*, 1654ae6b, sub', ( + 'TrackEntry*, ae, sub', ( + 'TrackNumber, d7, uint', + 'TrackUID, 73c5, uint', + 'TrackType, 83, uint', + 'FlagEnabled, b9, uint', + 'FlagDefault, 88, uint', + 'FlagForced, 55aa, uint', + 'FlagLacing, 9c, uint', + 'MinCache, 6de7, uint', + 'MaxCache, 6df8, uint', + 'DefaultDuration, 23e383, uint', + 'TrackTimecodeScale, 23314f, float', + 'MaxBlockAdditionID, 55ee, uint', + 'Name, 536e, str', + 'Language, 22b59c, str', + 'CodecID, 86, str', + 'CodecPrivate, 63a2, binary', + 'CodecName, 258688, str', + 'CodecDecodeAll, aa, uint', + 'CodecDelay, 56aa, uint', + 'SeekPreRoll, 56bb, uint', + 'Video, e0, sub', ( + 'FlagInterlaced, 9a, uint', + 'PixelWidth, b0, uint', + 'PixelHeight, ba, uint', + 'DisplayWidth, 54b0, uint', + 'DisplayHeight, 54ba, uint', + 'DisplayUnit, 54b2, uint', + 'FrameRate, 2383e3, float', + 'ColourSpace, 2eb524, binary', + 'StereoMode, 53b8, uint', + 'Colour, 55b0, sub', ( + 'MatrixCoefficients, 55B1, uint', + 'BitsPerChannel, 55B2, uint', + 'ChromaSubsamplingHorz, 55B3, uint', + 'ChromaSubsamplingVert, 55B4, uint', + 'CbSubsamplingHorz, 55B5, uint', + 'CbSubsamplingVert, 55B6, uint', + 'ChromaSitingHorz, 55B7, uint', + 'ChromaSitingVert, 55B8, uint', + 'Range, 55B9, uint', + 'TransferCharacteristics, 55BA, uint', + 'Primaries, 55BB, uint', + 'MaxCLL, 55BC, uint', + 'MaxFALL, 55BD, uint', + 'MasteringMetadata, 55D0, sub', ( + 'PrimaryRChromaticityX, 55D1, float', + 'PrimaryRChromaticityY, 55D2, float', + 'PrimaryGChromaticityX, 55D3, float', + 'PrimaryGChromaticityY, 55D4, float', + 'PrimaryBChromaticityX, 55D5, float', + 'PrimaryBChromaticityY, 55D6, float', + 'WhitePointChromaticityX, 55D7, float', + 'WhitePointChromaticityY, 55D8, float', + 'LuminanceMax, 55D9, float', + 'LuminanceMin, 55DA, float', + ), + ), + ), + 'Audio, e1, sub', ( + 'SamplingFrequency, b5, float', + 'OutputSamplingFrequency, 78b5, float', + 'Channels, 9f, uint', + 'BitDepth, 6264, uint', + ), + 'ContentEncodings, 6d80, sub', ( + 'ContentEncoding*, 6240, sub', ( + 'ContentEncodingOrder, 5031, uint', + 'ContentEncodingScope, 5032, uint', + 'ContentEncodingType, 5033, uint', + 'ContentCompression, 5034, sub', ( + 'ContentCompAlgo, 4254, uint', + 'ContentCompSettings, 4255, binary', + ), + ), + ), + ), + ), + + 'Cues, 1c53bb6b, sub', ( + 'CuePoint*, bb, sub', ( + 'CueTime, b3, uint', + 'CueTrackPositions*, b7, sub', ( + 'CueTrack, f7, uint', + 'CueClusterPosition, f1, uint', + 'CueRelativePosition, f0, uint', + 'CueDuration, b2, uint', + ), + ), + ), + + 'Attachments, 1941a469, sub', ( + 'AttachedFile*, 61a7, sub', ( + 'FileDescription, 467e, str', + 'FileName, 466e, str', + 'FileMimeType, 4660, str', + 'FileData, 465c, binary', + 'FileUID, 46ae, uint', + ), + ), + + 'Chapters, 1043a770, sub', ( + 'EditionEntry*, 45b9, sub', ( + 'EditionUID, 45bc, uint', + 'EditionFlagHidden, 45bd, uint', + 'EditionFlagDefault, 45db, uint', + 'EditionFlagOrdered, 45dd, uint', + 'ChapterAtom*, b6, sub', ( + 'ChapterUID, 73c4, uint', + 'ChapterTimeStart, 91, uint', + 'ChapterTimeEnd, 92, uint', + 'ChapterFlagHidden, 98, uint', + 'ChapterFlagEnabled, 4598, uint', + 'ChapterSegmentUID, 6e67, binary', + 'ChapterSegmentEditionUID, 6ebc, uint', + 'ChapterDisplay*, 80, sub', ( + 'ChapString, 85, str', + 'ChapLanguage*, 437c, str', + 'ChapCountry*, 437e, str', + ), + ), + ), + ), + 'Tags*, 1254c367, sub', ( + 'Tag*, 7373, sub', ( + 'Targets, 63c0, sub', ( + 'TargetTypeValue, 68ca, uint', + 'TargetTrackUID, 63c5, uint', + 'TargetEditionUID, 63c9, uint', + 'TargetChapterUID, 63c4, uint', + 'TargetAttachmentUID, 63c6, uint', + ), + 'SimpleTag*, 67c8, sub', ( + 'TagName, 45a3, str', + 'TagLanguage, 447a, str', + 'TagString, 4487, str' + ), + ), + ), + ), +) + + +import sys +from math import ldexp +from binascii import hexlify + +def byte2num(s): + return int(hexlify(s), 16) + +class EOF(Exception): pass + +def camelcase_to_words(name): + parts = [] + start = 0 + for i in range(1, len(name)): + if name[i].isupper() and (name[i-1].islower() or + name[i+1:i+2].islower()): + parts.append(name[start:i]) + start = i + parts.append(name[start:]) + return '_'.join(parts).lower() + +class MatroskaElement(object): + + def __init__(self, name, elid, valtype, namespace): + self.name = name + self.definename = '{0}_ID_{1}'.format(namespace, name.upper()) + self.fieldname = camelcase_to_words(name) + self.structname = 'ebml_' + self.fieldname + self.elid = elid + self.valtype = valtype + if valtype == 'sub': + self.ebmltype = 'EBML_TYPE_SUBELEMENTS' + self.valname = 'struct ' + self.structname + else: + self.ebmltype = 'EBML_TYPE_' + valtype.upper() + try: + self.valname = {'uint': 'uint64_t', 'str': 'char *', + 'binary': 'bstr', 'ebml_id': 'uint32_t', + 'float': 'double', 'sint': 'int64_t', + }[valtype] + except KeyError: + raise SyntaxError('Unrecognized value type ' + valtype) + self.subelements = () + + def add_subelements(self, subelements): + self.subelements = subelements + self.subids = set(x[0].elid for x in subelements) + +elementd = {} +elementlist = [] +def parse_elems(l, namespace): + subelements = [] + for el in l: + if isinstance(el, str): + name, hexid, eltype = [x.strip() for x in el.split(',')] + multiple = name.endswith('*') + name = name.strip('*') + new = MatroskaElement(name, hexid, eltype, namespace) + elementd[hexid] = new + elementlist.append(new) + subelements.append((new, multiple)) + else: + new.add_subelements(parse_elems(el, namespace)) + return subelements + +parse_elems(elements_ebml, 'EBML') +parse_elems(elements_matroska, 'MATROSKA') + +def generate_C_header(): + print('// Generated by TOOLS/matroska.py, do not edit manually') + print() + + for el in elementlist: + print('#define {0.definename:40} 0x{0.elid}'.format(el)) + + print() + + for el in reversed(elementlist): + if not el.subelements: + continue + print() + print('struct {0.structname} {{'.format(el)) + l = max(len(subel.valname) for subel, multiple in el.subelements)+1 + for subel, multiple in el.subelements: + print(' {e.valname:{l}} {star}{e.fieldname};'.format( + e=subel, l=l, star=' *'[multiple])) + print() + for subel, multiple in el.subelements: + print(' int n_{0.fieldname};'.format(subel)) + print('};') + + for el in elementlist: + if not el.subelements: + continue + print('extern const struct ebml_elem_desc {0.structname}_desc;'.format( + el)) + + print() + print('#define MAX_EBML_SUBELEMENTS', max(len(el.subelements) + for el in elementlist)) + + + +def generate_C_definitions(): + print('// Generated by TOOLS/matroska.py, do not edit manually') + print() + for el in reversed(elementlist): + print() + if el.subelements: + print('#define N', el.fieldname) + print('E_S("{0}", {1})'.format(el.name, len(el.subelements))) + for subel, multiple in el.subelements: + print('F({0.definename}, {0.fieldname}, {1})'.format( + subel, int(multiple))) + print('}};') + print('#undef N') + else: + print('E("{0.name}", {0.fieldname}, {0.ebmltype})'.format(el)) + +def read(s, length): + t = s.read(length) + if len(t) != length: + raise EOF + return t + +def read_id(s): + t = read(s, 1) + i = 0 + mask = 128 + if ord(t) == 0: + raise SyntaxError + while not ord(t) & mask: + i += 1 + mask >>= 1 + t += read(s, i) + return t + +def read_vint(s): + t = read(s, 1) + i = 0 + mask = 128 + if ord(t) == 0: + raise SyntaxError + while not ord(t) & mask: + i += 1 + mask >>= 1 + t = bytes((ord(t) & (mask - 1),)) + t += read(s, i) + return i+1, byte2num(t) + +def read_str(s, length): + return read(s, length) + +def read_uint(s, length): + t = read(s, length) + return byte2num(t) + +def read_sint(s, length): + i = read_uint(s, length) + mask = 1 << (length * 8 - 1) + if i & mask: + i -= 2 * mask + return i + +def read_float(s, length): + t = read(s, length) + i = byte2num(t) + if length == 4: + f = ldexp((i & 0x7fffff) + (1 << 23), (i >> 23 & 0xff) - 150) + if i & (1 << 31): + f = -f + elif length == 8: + f = ldexp((i & ((1 << 52) - 1)) + (1 << 52), (i >> 52 & 0x7ff) - 1075) + if i & (1 << 63): + f = -f + else: + raise SyntaxError + return f + +def parse_one(s, depth, parent, maxlen): + elid = hexlify(read_id(s)).decode('ascii') + elem = elementd.get(elid) + if parent is not None and elid not in parent.subids and elid not in ('ec', 'bf'): + print('Unexpected:', elid) + if 1: + raise NotImplementedError + size, length = read_vint(s) + this_length = len(elid) / 2 + size + length + if elem is not None: + if elem.valtype != 'skip': + print(depth, elid, elem.name, 'size:', length, 'value:', end=' ') + if elem.valtype == 'sub': + print('subelements:') + while length > 0: + length -= parse_one(s, depth + 1, elem, length) + if length < 0: + raise SyntaxError + elif elem.valtype == 'str': + print('string', repr(read_str(s, length).decode('utf8', 'replace'))) + elif elem.valtype in ('binary', 'ebml_id'): + t = read_str(s, length) + dec = '' + if elem.valtype == 'ebml_id': + idelem = elementd.get(hexlify(t).decode('ascii')) + if idelem is None: + dec = '(UNKNOWN)' + else: + dec = '({0.name})'.format(idelem) + if len(t) < 20: + t = hexlify(t).decode('ascii') + else: + t = ''.format(len(t)) + print('binary', t, dec) + elif elem.valtype == 'uint': + print('uint', read_uint(s, length)) + elif elem.valtype == 'sint': + print('sint', read_sint(s, length)) + elif elem.valtype == 'float': + print('float', read_float(s, length)) + elif elem.valtype == 'skip': + read(s, length) + else: + raise NotImplementedError + else: + print(depth, 'Unknown element:', elid, 'size:', length) + read(s, length) + return this_length + +def parse_toplevel(s): + parse_one(s, 0, None, 1 << 63) + +if sys.argv[1] == '--generate-header': + generate_C_header() +elif sys.argv[1] == '--generate-definitions': + generate_C_definitions() +else: + s = open(sys.argv[1], "rb") + while 1: + start = s.tell() + try: + parse_toplevel(s) + except EOF: + if s.tell() != start: + raise Exception("Unexpected end of file") + break diff --git a/waftools/generators/sources.py b/waftools/generators/sources.py index 6f1521036a469..b6af693e65503 100644 --- a/waftools/generators/sources.py +++ b/waftools/generators/sources.py @@ -2,11 +2,11 @@ import os def __file2string_cmd__(ctx): - return '"${{BIN_PERL}}" "{0}/TOOLS/file2string.pl" "${{SRC}}" > "${{TGT}}"' \ + return '"${{BIN_PYTHON}}" "{0}/TOOLS/file2string.py" "${{SRC}}" > "${{TGT}}"' \ .format(ctx.srcnode.abspath()) def __matroska_cmd__(ctx, argument): - return '"${{BIN_PERL}}" "{0}/TOOLS/matroska.pl" "{1}" "${{SRC}}" > "${{TGT}}"' \ + return '"${{BIN_PYTHON}}" "{0}/TOOLS/matroska.py" "{1}" "${{SRC}}" > "${{TGT}}"' \ .format(ctx.srcnode.abspath(), argument) def __zshcomp_cmd__(ctx, argument): diff --git a/wscript b/wscript index f47f9652658e1..94db7e296f714 100644 --- a/wscript +++ b/wscript @@ -81,6 +81,7 @@ build_options = [ }, { 'name': '--zsh-comp', 'desc': 'zsh completion', + 'func': check_ctx_vars('BIN_PERL'), 'func': check_true, 'default': 'disable', }, { @@ -995,11 +996,12 @@ def configure(ctx): ctx.find_program(cc, var='CC') ctx.find_program(pkg_config, var='PKG_CONFIG') ctx.find_program(ar, var='AR') - ctx.find_program('perl', var='BIN_PERL') + ctx.find_program('python', var='BIN_PYTHON') ctx.find_program('rst2html', var='RST2HTML', mandatory=False) ctx.find_program('rst2man', var='RST2MAN', mandatory=False) ctx.find_program('rst2pdf', var='RST2PDF', mandatory=False) ctx.find_program(windres, var='WINDRES', mandatory=False) + ctx.find_program('perl', var='BIN_PERL', mandatory=False) ctx.load('compiler_c') ctx.load('waf_customizations') From a61eb8114161f427c760e19ec7a6e01c9e03c59a Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 17 Dec 2016 16:05:51 +0100 Subject: [PATCH 71/83] TOOLS/matroska.py: allow using as module Don't force CLI usage. It can be imported, and generate_C_header() and generate_C_definitions() can be called with a file argument instead of writing to stdout always. --- TOOLS/matroska.py | 95 ++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/TOOLS/matroska.py b/TOOLS/matroska.py index 91e65a26b36fd..0ff0d468629e0 100755 --- a/TOOLS/matroska.py +++ b/TOOLS/matroska.py @@ -284,56 +284,58 @@ def parse_elems(l, namespace): parse_elems(elements_ebml, 'EBML') parse_elems(elements_matroska, 'MATROSKA') -def generate_C_header(): - print('// Generated by TOOLS/matroska.py, do not edit manually') - print() +def printf(out, *args): + out.write(' '.join([str(x) for x in args])) + out.write('\n') + +def generate_C_header(out): + printf(out, '// Generated by TOOLS/matroska.py, do not edit manually') + printf(out) for el in elementlist: - print('#define {0.definename:40} 0x{0.elid}'.format(el)) + printf(out, '#define {0.definename:40} 0x{0.elid}'.format(el)) - print() + printf(out) for el in reversed(elementlist): if not el.subelements: continue - print() - print('struct {0.structname} {{'.format(el)) + printf(out) + printf(out, 'struct {0.structname} {{'.format(el)) l = max(len(subel.valname) for subel, multiple in el.subelements)+1 for subel, multiple in el.subelements: - print(' {e.valname:{l}} {star}{e.fieldname};'.format( - e=subel, l=l, star=' *'[multiple])) - print() + printf(out, ' {e.valname:{l}} {star}{e.fieldname};'.format( + e=subel, l=l, star=' *'[multiple])) + printf(out) for subel, multiple in el.subelements: - print(' int n_{0.fieldname};'.format(subel)) - print('};') + printf(out, ' int n_{0.fieldname};'.format(subel)) + printf(out, '};') for el in elementlist: if not el.subelements: continue - print('extern const struct ebml_elem_desc {0.structname}_desc;'.format( - el)) - - print() - print('#define MAX_EBML_SUBELEMENTS', max(len(el.subelements) - for el in elementlist)) + printf(out, 'extern const struct ebml_elem_desc {0.structname}_desc;'.format(el)) + printf(out) + printf(out, '#define MAX_EBML_SUBELEMENTS', max(len(el.subelements) + for el in elementlist)) -def generate_C_definitions(): - print('// Generated by TOOLS/matroska.py, do not edit manually') - print() +def generate_C_definitions(out): + printf(out, '// Generated by TOOLS/matroska.py, do not edit manually') + printf(out) for el in reversed(elementlist): - print() + printf(out) if el.subelements: - print('#define N', el.fieldname) - print('E_S("{0}", {1})'.format(el.name, len(el.subelements))) + printf(out, '#define N', el.fieldname) + printf(out, 'E_S("{0}", {1})'.format(el.name, len(el.subelements))) for subel, multiple in el.subelements: - print('F({0.definename}, {0.fieldname}, {1})'.format( - subel, int(multiple))) - print('}};') - print('#undef N') + printf(out, 'F({0.definename}, {0.fieldname}, {1})'.format( + subel, int(multiple))) + printf(out, '}};') + printf(out, '#undef N') else: - print('E("{0.name}", {0.fieldname}, {0.ebmltype})'.format(el)) + printf(out, 'E("{0.name}", {0.fieldname}, {0.ebmltype})'.format(el)) def read(s, length): t = s.read(length) @@ -444,20 +446,21 @@ def parse_one(s, depth, parent, maxlen): read(s, length) return this_length -def parse_toplevel(s): - parse_one(s, 0, None, 1 << 63) - -if sys.argv[1] == '--generate-header': - generate_C_header() -elif sys.argv[1] == '--generate-definitions': - generate_C_definitions() -else: - s = open(sys.argv[1], "rb") - while 1: - start = s.tell() - try: - parse_toplevel(s) - except EOF: - if s.tell() != start: - raise Exception("Unexpected end of file") - break +if __name__ == "__main__": + def parse_toplevel(s): + parse_one(s, 0, None, 1 << 63) + + if sys.argv[1] == '--generate-header': + generate_C_header(sys.stdout) + elif sys.argv[1] == '--generate-definitions': + generate_C_definitions(sys.stdout) + else: + s = open(sys.argv[1], "rb") + while 1: + start = s.tell() + try: + parse_toplevel(s) + except EOF: + if s.tell() != start: + raise Exception("Unexpected end of file") + break From 1ef9876b7d3973ceb6702ccbfd706eb3e73dec26 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 17 Dec 2016 17:30:13 +0100 Subject: [PATCH 72/83] TOOLS/matroska.py: format file dumper output slightly nicer --- TOOLS/matroska.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TOOLS/matroska.py b/TOOLS/matroska.py index 0ff0d468629e0..6e843560daf25 100755 --- a/TOOLS/matroska.py +++ b/TOOLS/matroska.py @@ -408,7 +408,7 @@ def parse_one(s, depth, parent, maxlen): this_length = len(elid) / 2 + size + length if elem is not None: if elem.valtype != 'skip': - print(depth, elid, elem.name, 'size:', length, 'value:', end=' ') + print(" " * depth, '[' + elid + ']', elem.name, 'size:', length, 'value:', end=' ') if elem.valtype == 'sub': print('subelements:') while length > 0: @@ -429,7 +429,7 @@ def parse_one(s, depth, parent, maxlen): if len(t) < 20: t = hexlify(t).decode('ascii') else: - t = ''.format(len(t)) + t = '<{0} bytes>'.format(len(t)) print('binary', t, dec) elif elem.valtype == 'uint': print('uint', read_uint(s, length)) From 4bfec4279f758272e6d50b79edbcf2825f7afc56 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Sat, 17 Dec 2016 15:59:09 -0500 Subject: [PATCH 73/83] mpv_identify.sh: add "duration" property to the list. --- TOOLS/mpv_identify.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/TOOLS/mpv_identify.sh b/TOOLS/mpv_identify.sh index 42cd41fe435ca..980e79a431ccc 100755 --- a/TOOLS/mpv_identify.sh +++ b/TOOLS/mpv_identify.sh @@ -67,6 +67,7 @@ EOF chapters editions titles + duration audio audio-bitrate From e57037dc952def5c2b2d2be7535052f94dfb9294 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 18 Dec 2016 12:27:47 +0100 Subject: [PATCH 74/83] ad_lavc, vd_lavc: don't set AVCodecContext.refcounted_frames This field is (or should be) deprecated, and there's no need to set it with the new API. --- audio/decode/ad_lavc.c | 1 - video/decode/vd_lavc.c | 1 - 2 files changed, 2 deletions(-) diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index 276ce69739e9e..c4d3a2ae7b05f 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -100,7 +100,6 @@ static int init(struct dec_audio *da, const char *decoder) lavc_context = avcodec_alloc_context3(lavc_codec); ctx->avctx = lavc_context; ctx->avframe = av_frame_alloc(); - lavc_context->refcounted_frames = 1; lavc_context->codec_type = AVMEDIA_TYPE_AUDIO; lavc_context->codec_id = lavc_codec->id; diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 4a250600812d4..cd3c611ebd30b 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -501,7 +501,6 @@ static void init_avctx(struct dec_video *vd, const char *decoder, avctx->pkt_timebase = ctx->codec_timebase; #endif - avctx->refcounted_frames = 1; ctx->pic = av_frame_alloc(); if (!ctx->pic) goto error; From 3b5777d86a62b9975c4c0fd224140e494db66ada Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 19 Dec 2016 21:29:46 +0100 Subject: [PATCH 75/83] demux_mkv: fix seeking in some broken files Some files have audio tracks with packets that do not have a keyframe flag set at all. I don't think there's any audio codec which actually needs keyframe flags, so always assume an audio packet is a keyframe (which, in Matroska terminology, means it can start decoding from that packet). The file in question had these set: | + Multiplexing application: Lavf57.56.100 at 313 | + Writing application: Lavf57.56.100 at 329 Garbage produced by garbage... There are other such files produced by mkvmerge, though. It's not perfectly sure whether these have been produced by FFmpeg as well (mkvmerge often trusts the information in the source file, even if it's wrong - so other samples could have been remuxed from FFmpeg). Fixes #3920. --- demux/demux_mkv.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 5598cf8374196..d127e517dca04 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -128,6 +128,8 @@ typedef struct mkv_track { AVCodecParserContext *av_parser; AVCodecContext *av_parser_codec; + bool require_keyframes; + /* stuff for realaudio braincancer */ double ra_pts; /* previous audio timestamp */ uint32_t sub_packet_size; ///< sub packet size, per stream @@ -200,7 +202,7 @@ typedef struct mkv_demuxer { bool index_has_durations; - bool eof_warning; + bool eof_warning, keyframe_warning; struct block_info tmp_block; } mkv_demuxer_t; @@ -1752,6 +1754,10 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) if (sh_a->samplerate == 8000 && strcmp(codec, "ac3") == 0) track->default_duration = 0; + // Deal with some FFmpeg-produced garbage, and assume all audio codecs can + // start decoding from anywhere. + track->require_keyframes = true; + sh_a->extradata = extradata; sh_a->extradata_size = extradata_len; @@ -2474,6 +2480,15 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info) current_pts = tc / 1e9 - track->codec_delay; + if (track->require_keyframes && !keyframe) { + keyframe = true; + if (!mkv_d->keyframe_warning) { + MP_WARN(demuxer, "This is a broken file! Packets with incorrect " + "keyframe flag found. Enabling workaround.\n"); + mkv_d->keyframe_warning = true; + } + } + if (track->type == MATROSKA_TRACK_AUDIO) { if (mkv_d->a_skip_to_keyframe) use_this_block &= keyframe; From 99a4be4127a14fa757b1f39314d192c74a2a4722 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 20 Dec 2016 14:28:29 +0100 Subject: [PATCH 76/83] demux_mkv: trust keyframe flags for TrueHD TrueHD is a fucked up audio codec with extremely small frame sizes. Some of these frames start with full headers, which are usually marked as keyframes, and from which decoding can be started (or at least that's what you'd expect). So for such tracks we should probably trust the keyframe flags. Doesn't really improve seek behavior, though. --- demux/demux_mkv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index d127e517dca04..ddda2ecb61dc8 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1756,7 +1756,8 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track) // Deal with some FFmpeg-produced garbage, and assume all audio codecs can // start decoding from anywhere. - track->require_keyframes = true; + if (strcmp(codec, "truehd") != 0) + track->require_keyframes = true; sh_a->extradata = extradata; sh_a->extradata_size = extradata_len; From 1ba352581687548ffc2664b94f831a3dd12d05fa Mon Sep 17 00:00:00 2001 From: Dario Russo Date: Tue, 20 Dec 2016 10:18:45 -0500 Subject: [PATCH 77/83] Fix mistakes in spelling and grammar --- DOCS/man/options.rst | 2 +- video/out/wayland_common.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 0dd3aad59bf84..a81646f6a46a9 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -2164,7 +2164,7 @@ Window ``50%x50%`` Forces the window width and height to half the screen width and height. Will show black borders to compensate for the video aspect - ration (with most VOs and without ``--no-keepaspect``). + ratio (with most VOs and without ``--no-keepaspect``). ``50%+10+10`` Sets the window to half the screen widths, and positions it 10 pixels below/left of the top left corner of the screen. diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index a41fb6680a545..35d0dfed51ee8 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -675,9 +675,9 @@ static void schedule_resize(struct vo_wayland_state *wl, height = MPMIN(height, wl->display.current_output->height/scale); } - // don't keep the aspect ration in fullscreen mode, because the compositor - // shows the desktop in the border regions if the video has not the same - // aspect ration as the screen + // don't keep the aspect ratio in fullscreen mode because the compositor + // shows the desktop in the border regions if the video does not have the same + // aspect ratio as the screen /* if only the height is changed we have to calculate the width * in any other case we calculate the height */ switch (edges) { From b1c0bbe8b8b9d25c2682f29af66ad243e0072897 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 21 Dec 2016 18:18:24 +0100 Subject: [PATCH 78/83] video: use demuxer-signaled duration for last video frame Helps with gif, probably does unwanted things with other formats. This doesn't handle --end quite correctly, but this could be added later. Fixes #3924. --- player/core.h | 3 +++ player/video.c | 6 ++++++ video/decode/vd_lavc.c | 5 +++++ video/mp_image.c | 1 + video/mp_image.h | 2 +- 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/player/core.h b/player/core.h index 9a71ce33de08c..5d055482a5723 100644 --- a/player/core.h +++ b/player/core.h @@ -353,6 +353,9 @@ typedef struct MPContext { // As video_pts, but is not reset when seeking away. (For the very short // period of time until a new frame is decoded and shown.) double last_vo_pts; + // Frame duration field from demuxer. Only used for duration of the last + // video frame. + double last_frame_duration; // Video PTS, or audio PTS if video has ended. double playback_pts; // audio stats only diff --git a/player/video.c b/player/video.c index 03dd5aeabec58..4621d19cb4412 100644 --- a/player/video.c +++ b/player/video.c @@ -343,6 +343,7 @@ void reset_video_state(struct MPContext *mpctx) mpctx->delay = 0; mpctx->time_frame = 0; mpctx->video_pts = MP_NOPTS_VALUE; + mpctx->last_frame_duration = 0; mpctx->num_past_frames = 0; mpctx->total_avsync_change = 0; mpctx->last_av_difference = 0; @@ -1369,6 +1370,9 @@ void write_video(struct MPContext *mpctx) { MP_VERBOSE(mpctx, "assuming this is an image\n"); mpctx->time_frame += opts->image_display_duration; + } else if (mpctx->last_frame_duration > 0) { + MP_VERBOSE(mpctx, "using demuxer frame duration for last frame\n"); + mpctx->time_frame += mpctx->last_frame_duration; } else { mpctx->time_frame = 0; } @@ -1482,6 +1486,8 @@ void write_video(struct MPContext *mpctx) mpctx->video_pts = mpctx->next_frames[0]->pts; mpctx->last_vo_pts = mpctx->video_pts; + mpctx->last_frame_duration = + mpctx->next_frames[0]->pkt_duration / mpctx->video_speed; shift_frames(mpctx); diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index cd3c611ebd30b..78d34bbb47943 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -859,6 +859,11 @@ static void decode(struct dec_video *vd, struct demux_packet *packet, mpi->pts = mp_pts_from_av(ctx->pic->pts, &ctx->codec_timebase); mpi->dts = mp_pts_from_av(ctx->pic->pkt_dts, &ctx->codec_timebase); +#if LIBAVCODEC_VERSION_MICRO >= 100 + mpi->pkt_duration = + mp_pts_from_av(av_frame_get_pkt_duration(ctx->pic), &ctx->codec_timebase); +#endif + struct mp_image_params params; update_image_params(vd, ctx->pic, ¶ms); mp_image_set_params(mpi, ¶ms); diff --git a/video/mp_image.c b/video/mp_image.c index ee1ab4104eb47..2c4627c33e797 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -386,6 +386,7 @@ void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src) dst->fields = src->fields; dst->pts = src->pts; dst->dts = src->dts; + dst->pkt_duration = src->pkt_duration; dst->params.rotate = src->params.rotate; dst->params.stereo_in = src->params.stereo_in; dst->params.stereo_out = src->params.stereo_out; diff --git a/video/mp_image.h b/video/mp_image.h index 7c0f7bad7ea56..6606f19c90a6b 100644 --- a/video/mp_image.h +++ b/video/mp_image.h @@ -85,7 +85,7 @@ typedef struct mp_image { /* only inside filter chain */ double pts; /* only after decoder */ - double dts; + double dts, pkt_duration; /* for private use */ void* priv; From 17d6ba7f776d6fd0ebc7a9881a999299c3fa9471 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 22 Dec 2016 18:40:17 +0100 Subject: [PATCH 79/83] vd_lavc: use AVFrame fields directly instead of AVCodecContext Conceptually cleaner, although the API claims this is equivalent. Originally, AVCodecContext fields were used, because not all supported libavcodec/libavutil versions had the AVFrame fields. This is not done for chroma_sample_location - it has no AVFrame field. --- video/decode/vd_lavc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 78d34bbb47943..cc3bbc86c7867 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -638,10 +638,10 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame, .p_w = frame->sample_aspect_ratio.num, .p_h = frame->sample_aspect_ratio.den, .color = { - .space = avcol_spc_to_mp_csp(ctx->avctx->colorspace), - .levels = avcol_range_to_mp_csp_levels(ctx->avctx->color_range), - .primaries = avcol_pri_to_mp_csp_prim(ctx->avctx->color_primaries), - .gamma = avcol_trc_to_mp_csp_trc(ctx->avctx->color_trc), + .space = avcol_spc_to_mp_csp(frame->colorspace), + .levels = avcol_range_to_mp_csp_levels(frame->color_range), + .primaries = avcol_pri_to_mp_csp_prim(frame->color_primaries), + .gamma = avcol_trc_to_mp_csp_trc(frame->color_trc), .sig_peak = ctx->cached_hdr_peak, }, .chroma_location = From c560f6ff0ab9aec70e53a268e2ff388a85ec3ca0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 23 Dec 2016 18:03:16 +0100 Subject: [PATCH 80/83] audio: change how spdif codecs are selected Remove ad_spdif from the normal codec list, and select it explicitly. One goal was to decouple this from the normal codec selection, so they're less entangled and the decoder selection code can be simplified in the far future. This means spdif codec selection is now done explicitly via select_spdif_codec(). We can also remove the weird requirements on "dts" and "dts-hd" for the --audio-spdif option, and it can just do the right thing. Now both video and audio codecs consist of a single codec family each, vd_lavc and ad_lavc. --- DOCS/interface-changes.rst | 2 ++ DOCS/man/options.rst | 7 +++--- audio/decode/ad_spdif.c | 49 ++++++++++++++++++++++++++++++-------- audio/decode/dec_audio.c | 9 ++++--- audio/decode/dec_audio.h | 3 +++ common/codecs.c | 16 ------------- common/codecs.h | 5 ---- options/options.c | 2 +- 8 files changed, 54 insertions(+), 39 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index fae6605dae7c2..d2c8536fd4367 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -43,6 +43,8 @@ Interface changes - --sub-codepage= does not force the codepage anymore (this requires different and new syntax) - remove --fs-black-out-screens option for macOS + - change how spdif codecs are selected. You can't enable spdif passthrough + with --ad anymore. This was deprecated; use --audio-spdif instead. --- mpv 0.22.0 --- - the "audio-device-list" property now sets empty device description to the device name as a fallback diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index a81646f6a46a9..bc33edc13d635 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -1121,11 +1121,10 @@ Audio Possible codecs are ``ac3``, ``dts``, ``dts-hd``. Multiple codecs can be specified by separating them with ``,``. ``dts`` refers to low bitrate DTS core, while ``dts-hd`` refers to DTS MA (receiver and OS support varies). - You should only use either ``dts`` or ``dts-hd`` (if both are specified, - and ``dts`` comes first, only ``dts`` will be used). + If both ``dts`` and ``dts-hd`` are specified, it behaves equivalent to + specifying ``dts-hd`` only. - In general, all codecs in the ``spdif`` family listed with ``--ad=help`` - are supported in theory. + In earlier mpv versions .. admonition:: Warning diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c index 60aef3b18f1d3..30c7883bf4abd 100644 --- a/audio/decode/ad_spdif.c +++ b/audio/decode/ad_spdif.c @@ -83,12 +83,10 @@ static int init(struct dec_audio *da, const char *decoder) spdif_ctx->use_dts_hd = da->opts->dtshd; spdif_ctx->pool = mp_audio_pool_create(spdif_ctx); - if (strcmp(decoder, "dts-hd") == 0) { - decoder = "dts"; + if (strcmp(decoder, "spdif_dts_hd") == 0) spdif_ctx->use_dts_hd = true; - } - spdif_ctx->codec_id = mp_codec_to_av_codec_id(decoder); + spdif_ctx->codec_id = mp_codec_to_av_codec_id(da->codec->codec); return spdif_ctx->codec_id != AV_CODEC_ID_NONE; } @@ -296,22 +294,53 @@ static const int codecs[] = { AV_CODEC_ID_NONE }; -static void add_decoders(struct mp_decoder_list *list) +static bool find_codec(const char *name) { for (int n = 0; codecs[n] != AV_CODEC_ID_NONE; n++) { const char *format = mp_codec_from_av_codec_id(codecs[n]); - if (format) { - mp_add_decoder(list, "spdif", format, format, - "libavformat/spdifenc audio pass-through decoder"); + if (format && name && strcmp(format, name) == 0) + return true; + } + return false; +} + +// codec is the libavcodec name of the source audio codec. +// pref is a ","-separated list of names, some of them which do not match with +// libavcodec names (like dts-hd). +struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref) +{ + struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list); + + if (!find_codec(codec)) + return list; + + bool spdif_allowed = false, dts_hd_allowed = false; + bstr sel = bstr0(pref); + while (sel.len) { + bstr decoder; + bstr_split_tok(sel, ",", &decoder, &sel); + if (decoder.len) { + if (bstr_equals0(decoder, codec)) + spdif_allowed = true; + if (bstr_equals0(decoder, "dts-hd") && strcmp(codec, "dts") == 0) + spdif_allowed = dts_hd_allowed = true; } } - mp_add_decoder(list, "spdif", "dts", "dts-hd", + + if (!spdif_allowed) + return list; + + const char *suffix_name = dts_hd_allowed ? "dts_hd" : codec; + char name[80]; + snprintf(name, sizeof(name), "spdif_%s", suffix_name); + mp_add_decoder(list, "spdif", codec, name, "libavformat/spdifenc audio pass-through decoder"); + return list; } const struct ad_functions ad_spdif = { .name = "spdif", - .add_decoders = add_decoders, + .add_decoders = NULL, .init = init, .uninit = uninit, .control = control, diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index 39e867cf42947..c98d42f5567cc 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -43,11 +43,12 @@ #include "audio/filter/af.h" extern const struct ad_functions ad_lavc; + +// Not a real codec - specially treated. extern const struct ad_functions ad_spdif; static const struct ad_functions * const ad_drivers[] = { &ad_lavc, - &ad_spdif, NULL }; @@ -91,9 +92,9 @@ static struct mp_decoder_list *audio_select_decoders(struct dec_audio *d_audio) struct mp_decoder_list *list = audio_decoder_list(); struct mp_decoder_list *new = mp_select_decoders(list, codec, opts->audio_decoders); - if (d_audio->try_spdif) { + if (d_audio->try_spdif && codec) { struct mp_decoder_list *spdif = - mp_select_decoder_list(list, codec, "spdif", opts->audio_spdif); + select_spdif_codec(codec, opts->audio_spdif); mp_append_decoders(spdif, new); talloc_free(new); new = spdif; @@ -108,6 +109,8 @@ static const struct ad_functions *find_driver(const char *name) if (strcmp(ad_drivers[i]->name, name) == 0) return ad_drivers[i]; } + if (strcmp(name, "spdif") == 0) + return &ad_spdif; return NULL; } diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h index 7bc8b00b0f672..ebe7c8ae5bc5d 100644 --- a/audio/decode/dec_audio.h +++ b/audio/decode/dec_audio.h @@ -59,4 +59,7 @@ int audio_get_frame(struct dec_audio *d_audio, struct mp_audio **out_frame); void audio_reset_decoding(struct dec_audio *d_audio); +// ad_spdif.c +struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref); + #endif /* MPLAYER_DEC_AUDIO_H */ diff --git a/common/codecs.c b/common/codecs.c index c0d99eb959ef6..463811066c8db 100644 --- a/common/codecs.c +++ b/common/codecs.c @@ -130,22 +130,6 @@ struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all, return list; } -// selection is a ","-separated list of decoders, all in the given family. -struct mp_decoder_list *mp_select_decoder_list(struct mp_decoder_list *all, - const char *codec, - const char *family, - const char *selection) -{ - struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list); - bstr sel = bstr0(selection); - while (sel.len) { - bstr decoder; - bstr_split_tok(sel, ",", &decoder, &sel); - add_new(list, find_decoder(all, bstr0(family), decoder), codec); - } - return list; -} - void mp_append_decoders(struct mp_decoder_list *list, struct mp_decoder_list *a) { for (int n = 0; n < a->num_entries; n++) diff --git a/common/codecs.h b/common/codecs.h index 17316c85e9bf5..3e9408eaad478 100644 --- a/common/codecs.h +++ b/common/codecs.h @@ -37,11 +37,6 @@ struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all, const char *codec, const char *selection); -struct mp_decoder_list *mp_select_decoder_list(struct mp_decoder_list *all, - const char *codec, - const char *family, - const char *selection); - void mp_append_decoders(struct mp_decoder_list *list, struct mp_decoder_list *a); struct mp_log; diff --git a/options/options.c b/options/options.c index 76fabca256190..108c805de70e6 100644 --- a/options/options.c +++ b/options/options.c @@ -804,7 +804,7 @@ const struct MPOpts mp_default_opts = { .use_terminal = 1, .msg_color = 1, .audio_driver_list = NULL, - .audio_decoders = "-spdif:*", // never select spdif by default + .audio_decoders = NULL, .video_decoders = NULL, .deinterlace = -1, .softvol = SOFTVOL_AUTO, From 9d21f2503f28a7be0e493ab18a4acbaae02c3d0a Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 23 Dec 2016 18:12:29 +0100 Subject: [PATCH 81/83] options: deprecate codec family selection in --vd/--ad Useless now, so get rid of it. Also affects some user-visible display things (like reported codec in use). --- DOCS/interface-changes.rst | 1 + DOCS/man/options.rst | 19 +++++++++++-------- audio/decode/dec_audio.c | 11 ++++------- common/codecs.c | 27 ++++++++++++++++----------- common/codecs.h | 5 ++++- video/decode/dec_video.c | 19 +++++++++---------- 6 files changed, 45 insertions(+), 37 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index d2c8536fd4367..9f61a13e59426 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -45,6 +45,7 @@ Interface changes - remove --fs-black-out-screens option for macOS - change how spdif codecs are selected. You can't enable spdif passthrough with --ad anymore. This was deprecated; use --audio-spdif instead. + - deprecate the "family" selection with --ad/--vd --- mpv 0.22.0 --- - the "audio-device-list" property now sets empty device description to the device name as a fallback diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index bc33edc13d635..f1101f27f858f 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -555,7 +555,7 @@ Video Specify the video output backend to be used. See `VIDEO OUTPUT DRIVERS`_ for details and descriptions of available drivers. -``--vd=<[+|-]family1:(*|decoder1),[+|-]family2:(*|decoder2),...[-]>`` +``--vd=<...>`` Specify a priority list of video decoders to be used, according to their family and name. See ``--ad`` for further details. Both of these options use the same syntax and semantics; the only difference is that they @@ -1134,12 +1134,14 @@ Audio ``--ad=<[+|-]family1:(*|decoder1),[+|-]family2:(*|decoder2),...[-]>`` Specify a priority list of audio decoders to be used, according to their - family and decoder name. Entries like ``family:*`` prioritize all decoders - of the given family. When determining which decoder to use, the first - decoder that matches the audio format is selected. If that is unavailable, - the next decoder is used. Finally, it tries all other decoders that are not + decoder name. When determining which decoder to use, the first decoder that + matches the audio format is selected. If that is unavailable, the next + decoder is used. Finally, it tries all other decoders that are not explicitly selected or rejected by the option. + Specifying family names is deprecated. Entries like ``family:*`` prioritize + all decoders of the given family. + ``-`` at the end of the list suppresses fallback on other available decoders not on the ``--ad`` list. ``+`` in front of an entry forces the decoder. Both of these should not normally be used, because they break @@ -1149,12 +1151,13 @@ Audio .. admonition:: Examples - ``--ad=lavc:mp3float`` + ``--ad=mp3float`` Prefer the FFmpeg/Libav ``mp3float`` decoder over all other MP3 decoders. - ``--ad=spdif:ac3,lavc:*`` - Always prefer spdif AC3 over FFmpeg/Libav over anything else. + ``--ad=lavc:mp3float`` + Prefer the FFmpeg/Libav ``mp3float`` decoder over all other MP3 + decoders. (Using deprecated family syntax.) ``--ad=help`` List all available decoders. diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index c98d42f5567cc..9f28302bd5c96 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -91,7 +91,7 @@ static struct mp_decoder_list *audio_select_decoders(struct dec_audio *d_audio) struct mp_decoder_list *list = audio_decoder_list(); struct mp_decoder_list *new = - mp_select_decoders(list, codec, opts->audio_decoders); + mp_select_decoders(d_audio->log, list, codec, opts->audio_decoders); if (d_audio->try_spdif && codec) { struct mp_decoder_list *spdif = select_spdif_codec(codec, opts->audio_spdif); @@ -129,21 +129,18 @@ int audio_init_best_codec(struct dec_audio *d_audio) const struct ad_functions *driver = find_driver(sel->family); if (!driver) continue; - MP_VERBOSE(d_audio, "Opening audio decoder %s:%s\n", - sel->family, sel->decoder); + MP_VERBOSE(d_audio, "Opening audio decoder %s\n", sel->decoder); d_audio->ad_driver = driver; if (init_audio_codec(d_audio, sel->decoder)) { decoder = sel; break; } - MP_WARN(d_audio, "Audio decoder init failed for " - "%s:%s\n", sel->family, sel->decoder); + MP_WARN(d_audio, "Audio decoder init failed for %s\n", sel->decoder); } if (d_audio->ad_driver) { d_audio->decoder_desc = - talloc_asprintf(d_audio, "%s [%s:%s]", decoder->desc, decoder->family, - decoder->decoder); + talloc_asprintf(d_audio, "%s (%s)", decoder->decoder, decoder->desc); MP_VERBOSE(d_audio, "Selected audio codec: %s\n", d_audio->decoder_desc); } else { MP_ERR(d_audio, "Failed to initialize an audio decoder for codec '%s'.\n", diff --git a/common/codecs.c b/common/codecs.c index 463811066c8db..7a0afe466eac6 100644 --- a/common/codecs.c +++ b/common/codecs.c @@ -45,9 +45,10 @@ static struct mp_decoder_entry *find_decoder(struct mp_decoder_list *list, { for (int n = 0; n < list->num_entries; n++) { struct mp_decoder_entry *cur = &list->entries[n]; - if (bstr_equals0(decoder, cur->decoder) && - bstr_equals0(family, cur->family)) - return cur; + if (bstr_equals0(decoder, cur->decoder)) { + if (bstr_equals0(family, "*") || bstr_equals0(family, cur->family)) + return cur; + } } return NULL; } @@ -70,13 +71,14 @@ static void add_new(struct mp_decoder_list *to, struct mp_decoder_entry *entry, // The selection string corresponds to --vd/--ad directly, and has the // following syntax: // selection = [ ("," )*] -// entry = ":" // prefer decoder +// entry = [ ":"] // prefer decoder // entry = ":*" // prefer all decoders -// entry = "+" ":" // force a decoder -// entry = "-" ":" // exclude a decoder +// entry = "+" [ ":"] // force a decoder +// entry = "-" [ ":"] // exclude a decoder // entry = "-" // don't add fallback decoders // Forcing a decoder means it's added even if the codec mismatches. -struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all, +struct mp_decoder_list *mp_select_decoders(struct mp_log *log, + struct mp_decoder_list *all, const char *codec, const char *selection) { @@ -97,9 +99,12 @@ struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all, bool exclude = !force && bstr_eatstart0(&entry, "-"); struct mp_decoder_list *dest = exclude ? remove : list; bstr family, decoder; - if (!bstr_split_tok(entry, ":", &family, &decoder)) { - family = entry; - decoder = bstr0("*"); + if (bstr_split_tok(entry, ":", &family, &decoder)) { + mp_warn(log, "Codec family selection is deprecated. " + "Pass the codec name directly.\n"); + } else { + family = bstr0("*"); + decoder = entry; } if (bstr_equals0(decoder, "*")) { for (int n = 0; n < all->num_entries; n++) { @@ -142,7 +147,7 @@ void mp_print_decoders(struct mp_log *log, int msgl, const char *header, mp_msg(log, msgl, "%s\n", header); for (int n = 0; n < list->num_entries; n++) { struct mp_decoder_entry *entry = &list->entries[n]; - mp_msg(log, msgl, " %s:%s", entry->family, entry->decoder); + mp_msg(log, msgl, " %s", entry->decoder); if (strcmp(entry->decoder, entry->codec) != 0) mp_msg(log, msgl, " (%s)", entry->codec); mp_msg(log, msgl, " - %s\n", entry->desc); diff --git a/common/codecs.h b/common/codecs.h index 3e9408eaad478..bed5c4690555f 100644 --- a/common/codecs.h +++ b/common/codecs.h @@ -18,6 +18,8 @@ #ifndef MP_CODECS_H #define MP_CODECS_H +struct mp_log; + struct mp_decoder_entry { const char *family; // decoder module (e.g. ad_lavc => "lavc") const char *codec; // name of the codec (e.g. "mp3") @@ -33,7 +35,8 @@ struct mp_decoder_list { void mp_add_decoder(struct mp_decoder_list *list, const char *family, const char *codec, const char *decoder, const char *desc); -struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all, +struct mp_decoder_list *mp_select_decoders(struct mp_log *log, + struct mp_decoder_list *all, const char *codec, const char *selection); diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c index dea5b594c769b..d9dbf0f326ef2 100644 --- a/video/decode/dec_video.c +++ b/video/decode/dec_video.c @@ -116,11 +116,12 @@ struct mp_decoder_list *video_decoder_list(void) return list; } -static struct mp_decoder_list *mp_select_video_decoders(const char *codec, +static struct mp_decoder_list *mp_select_video_decoders(struct mp_log *log, + const char *codec, char *selection) { struct mp_decoder_list *list = video_decoder_list(); - struct mp_decoder_list *new = mp_select_decoders(list, codec, selection); + struct mp_decoder_list *new = mp_select_decoders(log, list, codec, selection); talloc_free(list); return new; } @@ -143,8 +144,9 @@ bool video_init_best_codec(struct dec_video *d_video) d_video->has_broken_packet_pts = -10; // needs 10 packets to reach decision struct mp_decoder_entry *decoder = NULL; - struct mp_decoder_list *list = - mp_select_video_decoders(d_video->codec->codec, opts->video_decoders); + struct mp_decoder_list *list = mp_select_video_decoders(d_video->log, + d_video->codec->codec, + opts->video_decoders); mp_print_decoders(d_video->log, MSGL_V, "Codec list:", list); @@ -153,22 +155,19 @@ bool video_init_best_codec(struct dec_video *d_video) const struct vd_functions *driver = find_driver(sel->family); if (!driver) continue; - MP_VERBOSE(d_video, "Opening video decoder %s:%s\n", - sel->family, sel->decoder); + MP_VERBOSE(d_video, "Opening video decoder %s\n", sel->decoder); d_video->vd_driver = driver; if (init_video_codec(d_video, sel->decoder)) { decoder = sel; break; } d_video->vd_driver = NULL; - MP_WARN(d_video, "Video decoder init failed for " - "%s:%s\n", sel->family, sel->decoder); + MP_WARN(d_video, "Video decoder init failed for %s\n", sel->decoder); } if (d_video->vd_driver) { d_video->decoder_desc = - talloc_asprintf(d_video, "%s [%s:%s]", decoder->desc, decoder->family, - decoder->decoder); + talloc_asprintf(d_video, "%s (%s)", decoder->decoder, decoder->desc); MP_VERBOSE(d_video, "Selected video codec: %s\n", d_video->decoder_desc); } else { MP_ERR(d_video, "Failed to initialize a video decoder for codec '%s'.\n", From 1d5e95783e0bf05149fa6d5dc8a8aed3d02ff2e9 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 23 Dec 2016 18:12:54 +0100 Subject: [PATCH 82/83] options: explicitly deprecate --ad-spdif-dtshd Has been less formally deprecated for a longer time. --- DOCS/interface-changes.rst | 2 ++ options/options.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 9f61a13e59426..7756aceb856f4 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -46,6 +46,8 @@ Interface changes - change how spdif codecs are selected. You can't enable spdif passthrough with --ad anymore. This was deprecated; use --audio-spdif instead. - deprecate the "family" selection with --ad/--vd + - explicitly mark --ad-spdif-dtshd as deprecated (it was done so a long time + ago, but it didn't complain when using the option) --- mpv 0.22.0 --- - the "audio-device-list" property now sets empty device description to the device name as a fallback diff --git a/options/options.c b/options/options.c index 108c805de70e6..f79df7d82f62d 100644 --- a/options/options.c +++ b/options/options.c @@ -426,7 +426,8 @@ const m_option_t mp_opts[] = { OPT_STRING("audio-spdif", audio_spdif, 0), - OPT_FLAG("ad-spdif-dtshd", dtshd, 0), + OPT_FLAG("ad-spdif-dtshd", dtshd, 0, + .deprecation_message = "use --audio-spdif instead"), OPT_CHOICE_C("hwdec", hwdec_api, 0, mp_hwdec_names), OPT_STRING("hwdec-codecs", hwdec_codecs, 0), From 1c761bd6f59c369e45037e80f781429da65734c3 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 23 Dec 2016 18:18:17 +0100 Subject: [PATCH 83/83] options: deprecate some other complex --ad/--vd features Who even needs those? Once these deprecations are gone, --ad/--vd are simple lists without any kind of complex matching. --- DOCS/interface-changes.rst | 1 + DOCS/man/options.rst | 5 +++-- common/codecs.c | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 7756aceb856f4..a6133a3848361 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -46,6 +46,7 @@ Interface changes - change how spdif codecs are selected. You can't enable spdif passthrough with --ad anymore. This was deprecated; use --audio-spdif instead. - deprecate the "family" selection with --ad/--vd + forcing/excluding codecs with "+", "-", "-" is deprecated as well - explicitly mark --ad-spdif-dtshd as deprecated (it was done so a long time ago, but it didn't complain when using the option) --- mpv 0.22.0 --- diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index f1101f27f858f..eab9f8fefdf67 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -1145,9 +1145,10 @@ Audio ``-`` at the end of the list suppresses fallback on other available decoders not on the ``--ad`` list. ``+`` in front of an entry forces the decoder. Both of these should not normally be used, because they break - normal decoder auto-selection! + normal decoder auto-selection! Both of these methods are deprecated. - ``-`` in front of an entry disables selection of the decoder. + ``-`` in front of an entry disables selection of the decoder. This is + deprecated. .. admonition:: Examples diff --git a/common/codecs.c b/common/codecs.c index 7a0afe466eac6..5e744da5deb13 100644 --- a/common/codecs.c +++ b/common/codecs.c @@ -92,11 +92,14 @@ struct mp_decoder_list *mp_select_decoders(struct mp_log *log, bstr entry; bstr_split_tok(sel, ",", &entry, &sel); if (bstr_equals0(entry, "-")) { + mp_warn(log, "Excluding codecs is deprecated.\n"); stop = true; break; } bool force = bstr_eatstart0(&entry, "+"); bool exclude = !force && bstr_eatstart0(&entry, "-"); + if (exclude || force) + mp_warn(log, "Forcing or excluding codecs is deprecated.\n"); struct mp_decoder_list *dest = exclude ? remove : list; bstr family, decoder; if (bstr_split_tok(entry, ":", &family, &decoder)) {