From 93ea3df0a9f091ff17e463d3bfcf6e480a36bdb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Mon, 17 Feb 2025 23:22:13 +0100 Subject: [PATCH] player: add `mpv://` protocol This is useful to run mpv from URL handler. Can be used to start mpv from you web browser or anything that would trigger url handler for given protocol. Only safe protocols are allowed. Current solutions to run mpv in such context are to spawn IPC proxy and run mpv when requested, but this is in most cases not necessary. Currently the protocol is added in mpv.desktop. Windows related registration will follow in future changes. --- DOCS/interface-changes/mpv-protocol.txt | 1 + DOCS/man/mpv.rst | 6 ++++ demux/demux.c | 6 ++-- demux/demux_mpv.c | 45 +++++++++++++++++++++++ etc/mpv.desktop | 2 +- meson.build | 2 ++ stream/stream.c | 2 ++ stream/stream_mpv.c | 48 +++++++++++++++++++++++++ 8 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 DOCS/interface-changes/mpv-protocol.txt create mode 100644 demux/demux_mpv.c create mode 100644 stream/stream_mpv.c diff --git a/DOCS/interface-changes/mpv-protocol.txt b/DOCS/interface-changes/mpv-protocol.txt new file mode 100644 index 0000000000..5238d2e6f6 --- /dev/null +++ b/DOCS/interface-changes/mpv-protocol.txt @@ -0,0 +1 @@ +add `mpv://` protocol diff --git a/DOCS/man/mpv.rst b/DOCS/man/mpv.rst index 3ec696f7f9..6fd8ab74fe 100644 --- a/DOCS/man/mpv.rst +++ b/DOCS/man/mpv.rst @@ -1280,6 +1280,12 @@ More options to configure this functionality are listed in `Watch Later`_. PROTOCOLS ========= +``mpv://...`` + + mpv protocol. This is used for starting mpv from URL handler. The protocol + is stripped and the rest is passed to the player as a normal open argument. + Only safe protocols are allowed to be opened this way. + ``http://...``, ``https://``, ... Many network protocols are supported, but the protocol prefix must always diff --git a/demux/demux.c b/demux/demux.c index a35d62bcaf..6b36ed0c12 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -50,8 +50,9 @@ #include "cue.h" // Demuxer list -extern const struct demuxer_desc demuxer_desc_edl; -extern const struct demuxer_desc demuxer_desc_cue; +extern const demuxer_desc_t demuxer_desc_mpv; +extern const demuxer_desc_t demuxer_desc_edl; +extern const demuxer_desc_t demuxer_desc_cue; extern const demuxer_desc_t demuxer_desc_rawaudio; extern const demuxer_desc_t demuxer_desc_rawvideo; extern const demuxer_desc_t demuxer_desc_mf; @@ -80,6 +81,7 @@ static const demuxer_desc_t *const demuxer_list[] = { &demuxer_desc_mf, &demuxer_desc_playlist, &demuxer_desc_null, + &demuxer_desc_mpv, NULL }; diff --git a/demux/demux_mpv.c b/demux/demux_mpv.c new file mode 100644 index 0000000000..b1338744ee --- /dev/null +++ b/demux/demux_mpv.c @@ -0,0 +1,45 @@ +/* + * 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 "demux.h" + +#include +#include + +static int open_mpv(struct demuxer *demuxer, enum demux_check check) +{ + if (check != DEMUX_CHECK_REQUEST) + return -1; + + struct stream *s = demuxer->stream; + if (!s->info || strcmp(s->info->name, "mpv")) + return -1; + + demuxer->playlist = talloc_zero(demuxer, struct playlist); + playlist_append_file(demuxer->playlist, s->path); + playlist_set_stream_flags(demuxer->playlist, demuxer->stream_origin); + demuxer->fully_read = true; + demux_close_stream(demuxer); + + return 0; +} + +const struct demuxer_desc demuxer_desc_mpv = { + .name = "mpv", + .desc = "mpv protocol", + .open = open_mpv, +}; diff --git a/etc/mpv.desktop b/etc/mpv.desktop index baef395de4..6fba23f626 100644 --- a/etc/mpv.desktop +++ b/etc/mpv.desktop @@ -45,7 +45,7 @@ Exec=mpv --player-operation-mode=pseudo-gui -- %U Terminal=false Categories=AudioVideo;Audio;Video;Player;TV; MimeType=application/ogg;application/x-ogg;application/mxf;application/sdp;application/smil;application/x-smil;application/streamingmedia;application/x-streamingmedia;application/vnd.rn-realmedia;application/vnd.rn-realmedia-vbr;audio/aac;audio/x-aac;audio/vnd.dolby.heaac.1;audio/vnd.dolby.heaac.2;audio/aiff;audio/x-aiff;audio/m4a;audio/x-m4a;application/x-extension-m4a;audio/mp1;audio/x-mp1;audio/mp2;audio/x-mp2;audio/mp3;audio/x-mp3;audio/mpeg;audio/mpeg2;audio/mpeg3;audio/mpegurl;audio/x-mpegurl;audio/mpg;audio/x-mpg;audio/rn-mpeg;audio/musepack;audio/x-musepack;audio/ogg;audio/scpls;audio/x-scpls;audio/vnd.rn-realaudio;audio/wav;audio/x-pn-wav;audio/x-pn-windows-pcm;audio/x-realaudio;audio/x-pn-realaudio;audio/x-ms-wma;audio/x-pls;audio/x-wav;video/mpeg;video/x-mpeg2;video/x-mpeg3;video/mp4v-es;video/x-m4v;video/mp4;application/x-extension-mp4;video/divx;video/vnd.divx;video/msvideo;video/x-msvideo;video/ogg;video/quicktime;video/vnd.rn-realvideo;video/x-ms-afs;video/x-ms-asf;audio/x-ms-asf;application/vnd.ms-asf;video/x-ms-wmv;video/x-ms-wmx;video/x-ms-wvxvideo;video/x-avi;video/avi;video/x-flic;video/fli;video/x-flc;video/flv;video/x-flv;video/x-theora;video/x-theora+ogg;video/x-matroska;video/mkv;audio/x-matroska;application/x-matroska;video/webm;audio/webm;audio/vorbis;audio/x-vorbis;audio/x-vorbis+ogg;video/x-ogm;video/x-ogm+ogg;application/x-ogm;application/x-ogm-audio;application/x-ogm-video;application/x-shorten;audio/x-shorten;audio/x-ape;audio/x-wavpack;audio/x-tta;audio/AMR;audio/ac3;audio/eac3;audio/amr-wb;video/mp2t;audio/flac;audio/mp4;application/x-mpegurl;video/vnd.mpegurl;application/vnd.apple.mpegurl;audio/x-pn-au;video/3gp;video/3gpp;video/3gpp2;audio/3gpp;audio/3gpp2;video/dv;audio/dv;audio/opus;audio/vnd.dts;audio/vnd.dts.hd;audio/x-adpcm;application/x-cue;audio/m3u;audio/vnd.wave;video/vnd.avi; -X-KDE-Protocols=appending,file,ftp,hls,http,https,mms,rist,rtmp,rtmps,rtmpt,rtmpts,rtp,rtsp,rtsps,sftp,smb,srt,srtp,webdav,webdavs +X-KDE-Protocols=appending,file,ftp,hls,http,https,mms,mpv,rist,rtmp,rtmps,rtmpt,rtmpts,rtp,rtsp,rtsps,sftp,smb,srt,srtp,webdav,webdavs StartupWMClass=mpv Keywords=mpv;media;player;video;audio;tv; Keywords[ar]=mpv;إم بي في;ام بي في;وسائط;مشغل;فيديو;مرئية;صوتي;تلفاز; diff --git a/meson.build b/meson.build index c1d42d3fbb..620c19f1f2 100644 --- a/meson.build +++ b/meson.build @@ -100,6 +100,7 @@ sources = files( 'demux/demux_mf.c', 'demux/demux_mkv.c', 'demux/demux_mkv_timeline.c', + 'demux/demux_mpv.c', 'demux/demux_null.c', 'demux/demux_playlist.c', 'demux/demux_raw.c', @@ -189,6 +190,7 @@ sources = files( 'stream/stream_lavf.c', 'stream/stream_memory.c', 'stream/stream_mf.c', + 'stream/stream_mpv.c', 'stream/stream_null.c', 'stream/stream_slice.c', diff --git a/stream/stream.c b/stream/stream.c index f0cd52d8b0..20fae4a20e 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -42,6 +42,7 @@ #include "options/m_option.h" #include "options/m_config.h" +extern const stream_info_t stream_info_mpv; extern const stream_info_t stream_info_cdda; extern const stream_info_t stream_info_dvb; extern const stream_info_t stream_info_null; @@ -63,6 +64,7 @@ extern const stream_info_t stream_info_libarchive; extern const stream_info_t stream_info_cb; static const stream_info_t *const stream_list[] = { + &stream_info_mpv, #if HAVE_CDDA &stream_info_cdda, #endif diff --git a/stream/stream_mpv.c b/stream/stream_mpv.c new file mode 100644 index 0000000000..dd0e6e25c0 --- /dev/null +++ b/stream/stream_mpv.c @@ -0,0 +1,48 @@ +/* + * 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 "stream.h" + +#include +#include + +static int open_mpv(stream_t *st) +{ + bstr proto = mp_split_proto(bstr0(st->path), NULL); + if (proto.len) { + if (!bstrcasecmp0(proto, "mpv")) { + MP_ERR(st, "Nested mpv:// is not allowed.\n"); + return STREAM_NO_MATCH; + } + char **safe_protocols = stream_get_proto_list(true); + bool safe = str_in_list(proto, safe_protocols); + talloc_free(safe_protocols); + if (!safe) { + MP_ERR(st, "Unsafe protocol '%.*s' opened with mpv://.\n", BSTR_P(proto)); + return STREAM_NO_MATCH; + } + } + + st->demuxer = "mpv"; + return STREAM_OK; +} + +const stream_info_t stream_info_mpv = { + .name = "mpv", + .open = open_mpv, + .protocols = (const char*const[]){"mpv", NULL}, +};