History

stream: implement get_protocols method for stream_lavf

Previously, all stream protocols were a static list in mpv. This is okay for own builtin stuff, but for protocols that depend on ffmpeg it's not so great. Support for certain protocols may or may not be enabled in a user's ffmpeg and the protocol list that mpv generates should ideally match this. Fix this by implementing a get_protocols method for stream_lavf that will have different results depending on the ffmpeg mpv is built against. We keep the safe and unsafe protocols separation. The former is essentially a whitelist. Any protocol that is found in ffmpeg but is not in the safe whitelist is considered unsafe. In the stream list, ffmpeg is moved to the bottom so any possible protocols that are added in the future don't automatically take precedence over any builtin mpv ones.

Dudemanguy committed 2 years ago

Commit f921b641 parent 406301f5 files · +136 −25Browse files

Unified · Split

5 files
  1. common/av_common.c +12 −0
  2. common/av_common.h +1 −0
  3. stream/stream.c +29 −15
  4. stream/stream.h +2 −0
  5. stream/stream_lavf.c +92 −10
common/av_common.c+12−0
@@ -271,6 +271,18 @@ char **mp_get_lavf_demuxers(void) · 270 unmodified lines
271271 return list;
272272 }
273273
274+char **mp_get_lavf_protocols(void)
275+{
276+ char **list = NULL;
277+ int num = 0;
278+ void *opaque = NULL;
279+ const char *name;
280+ while ((name = avio_enum_protocols(&opaque, 0)))
281+ MP_TARRAY_APPEND(NULL, list, num, talloc_strdup(list, name));
282+ MP_TARRAY_APPEND(NULL, list, num, NULL);
283+ return list;
284+}
285+
274286 int mp_codec_to_av_codec_id(const char *codec)
275287 {
276288 int id = AV_CODEC_ID_NONE;
common/av_common.h+1−0
@@ -42,6 +42,7 @@ void mp_set_avcodec_threads(struct mp_log *l, AVCodecContext *avctx, int threads · 41 unmodified lines
4242 void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type);
4343 void mp_add_lavc_encoders(struct mp_decoder_list *list);
4444 char **mp_get_lavf_demuxers(void);
45+char **mp_get_lavf_protocols(void);
4546 int mp_codec_to_av_codec_id(const char *codec);
4647 const char *mp_codec_from_av_codec_id(int codec_id);
4748 bool mp_codec_is_lossless(const char *codec);
stream/stream.c+29−15
@@ -66,8 +66,6 @@ static const stream_info_t *const stream_list[] = { · 65 unmodified lines
6666 #if HAVE_CDDA
6767 &stream_info_cdda,
6868 #endif
69− &stream_info_ffmpeg,
70− &stream_info_ffmpeg_unsafe,
7169 &stream_info_avdevice,
7270 #if HAVE_DVBIN
7371 &stream_info_dvb,
@@ -92,6 +90,8 @@ static const stream_info_t *const stream_list[] = { · 18 unmodified lines
9290 &stream_info_slice,
9391 &stream_info_fd,
9492 &stream_info_cb,
93+ &stream_info_ffmpeg,
94+ &stream_info_ffmpeg_unsafe,
9595 };
9696
9797 // Because of guarantees documented on STREAM_BUFFER_SIZE.
@@ -325,12 +325,17 @@ static int stream_create_instance(const stream_info_t *sinfo, · 227 unmodified lines
325325 if (!sinfo->local_fs)
326326 return STREAM_NO_MATCH;
327327 } else {
328− for (int n = 0; sinfo->protocols && sinfo->protocols[n]; n++) {
329− path = match_proto(url, sinfo->protocols[n]);
328+ char **get_protocols = sinfo->get_protocols ? sinfo->get_protocols() : NULL;
329+ char **protocols = get_protocols ? get_protocols : (char **)sinfo->protocols;
330+
331+ for (int n = 0; protocols && protocols[n]; n++) {
332+ path = match_proto(url, protocols[n]);
330333 if (path)
331334 break;
332335 }
333336
337+ talloc_free(get_protocols);
338+
334339 if (!path)
335340 return STREAM_NO_MATCH;
336341 }
@@ -864,16 +869,17 @@ char **stream_get_proto_list(void) · 527 unmodified lines
864869 for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {
865870 const stream_info_t *stream_info = stream_list[i];
866871
867− if (!stream_info->protocols)
868− continue;
872+ char **get_protocols = stream_info->get_protocols ? stream_info->get_protocols() : NULL;
873+ char **protocols = get_protocols ? get_protocols : (char **)stream_info->protocols;
869874
870− for (int j = 0; stream_info->protocols[j]; j++) {
871− if (*stream_info->protocols[j] == '\0')
872− continue;
875+ for (int j = 0; protocols && protocols[j]; j++) {
876+ if (*protocols[j] == '\0')
877+ continue;
873878
874− MP_TARRAY_APPEND(NULL, list, num,
875− talloc_strdup(NULL, stream_info->protocols[j]));
879+ MP_TARRAY_APPEND(NULL, list, num, talloc_strdup(list, protocols[j]));
876880 }
881+
882+ talloc_free(get_protocols);
877883 }
878884 MP_TARRAY_APPEND(NULL, list, num, NULL);
879885 return list;
@@ -888,7 +894,6 @@ void stream_print_proto_list(struct mp_log *log) · 8 unmodified lines
888894 for (int i = 0; list[i]; i++) {
889895 mp_info(log, " %s://\n", list[i]);
890896 count++;
891− talloc_free(list[i]);
892897 }
893898 talloc_free(list);
894899 mp_info(log, "\nTotal: %d protocols\n", count);
@@ -899,10 +904,19 @@ bool stream_has_proto(const char *proto) · 4 unmodified lines
899904 for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {
900905 const stream_info_t *stream_info = stream_list[i];
901906
902− for (int j = 0; stream_info->protocols && stream_info->protocols[j]; j++) {
903− if (strcmp(stream_info->protocols[j], proto) == 0)
904− return true;
907+ bool match = false;
908+ char **get_protocols = stream_info->get_protocols ? stream_info->get_protocols() : NULL;
909+ char **protocols = get_protocols ? get_protocols : (char **)stream_info->protocols;
910+
911+ for (int j = 0; protocols && protocols[j]; j++) {
912+ if (strcmp(protocols[j], proto) == 0) {
913+ match = true;
914+ break;
915+ }
905916 }
917+
918+ talloc_free(get_protocols);
919+ return match;
906920 }
907921
908922 return false;
stream/stream.h+2−0
@@ -114,6 +114,8 @@ typedef struct stream_info_st { · 113 unmodified lines
114114 // Alternative to open(). Only either open() or open2() can be set.
115115 int (*open2)(struct stream *st, const struct stream_open_args *args);
116116 const char *const *protocols;
117+ // Alternative to protocols. For stream_lavf.
118+ char **(*get_protocols)(void);
117119 bool can_write; // correctly checks for READ/WRITE modes
118120 bool local_fs; // supports STREAM_LOCAL_FS_ONLY
119121 int stream_origin; // 0 or set of STREAM_ORIGIN_*; if 0, the same origin
stream/stream_lavf.c+92−10
@@ -238,6 +238,96 @@ void mp_setup_av_network_options(AVDictionary **dict, const char *target_fmt, · 237 unmodified lines
238238 talloc_free(temp);
239239 }
240240
241+#define PROTO(...) (const char *[]){__VA_ARGS__, NULL}
242+
243+// List of safe protocols and their aliases
244+static const char **safe_protos[] = {
245+ PROTO("data"),
246+ PROTO("gopher"),
247+ PROTO("gophers"),
248+ PROTO("http", "dav", "webdav"),
249+ PROTO("httpproxy"),
250+ PROTO("https", "davs", "webdavs"),
251+ PROTO("ipfs"),
252+ PROTO("ipns"),
253+ PROTO("mmsh", "mms", "mmshttp"),
254+ PROTO("mmst"),
255+ PROTO("rist"),
256+ PROTO("rtmp"),
257+ PROTO("rtmpe"),
258+ PROTO("rtmps"),
259+ PROTO("rtmpt"),
260+ PROTO("rtmpte"),
261+ PROTO("rtmpts"),
262+ PROTO("rtp"),
263+ PROTO("srt"),
264+ PROTO("srtp"),
265+ NULL,
266+};
267+
268+static char **get_safe_protocols(void)
269+{
270+ int num = 0;
271+ char **protocols = NULL;
272+ char **ffmpeg_demuxers = mp_get_lavf_demuxers();
273+ char **ffmpeg_protos = mp_get_lavf_protocols();
274+
275+ for (int i = 0; ffmpeg_protos[i]; i++) {
276+ for (int j = 0; safe_protos[j]; j++) {
277+ if (strcmp(ffmpeg_protos[i], safe_protos[j][0]) != 0)
278+ continue;
279+ for (int k = 0; safe_protos[j][k]; k++)
280+ MP_TARRAY_APPEND(NULL, protocols, num, talloc_strdup(protocols, safe_protos[j][k]));
281+ break;
282+ }
283+ }
284+
285+ // rtsp is a demuxer not protocol in ffmpeg so it is handled separately
286+ for (int i = 0; ffmpeg_demuxers[i]; i++) {
287+ if (strcmp("rtsp", ffmpeg_demuxers[i]) == 0) {
288+ MP_TARRAY_APPEND(NULL, protocols, num, talloc_strdup(protocols, "rtsp"));
289+ MP_TARRAY_APPEND(NULL, protocols, num, talloc_strdup(protocols, "rtsps"));
290+ break;
291+ }
292+ }
293+
294+ MP_TARRAY_APPEND(NULL, protocols, num, NULL);
295+
296+ talloc_free(ffmpeg_demuxers);
297+ talloc_free(ffmpeg_protos);
298+
299+ return protocols;
300+}
301+
302+static char **get_unsafe_protocols(void)
303+{
304+ int num = 0;
305+ char **protocols = NULL;
306+ char **safe_protocols = get_safe_protocols();
307+ char **ffmpeg_protos = mp_get_lavf_protocols();
308+
309+ for (int i = 0; ffmpeg_protos[i]; i++) {
310+ bool safe_protocol = false;
311+ for (int j = 0; safe_protocols[j]; j++) {
312+ if (strcmp(ffmpeg_protos[i], safe_protocols[j]) == 0) {
313+ safe_protocol = true;
314+ break;
315+ }
316+ }
317+ if (!safe_protocol)
318+ MP_TARRAY_APPEND(NULL, protocols, num, talloc_strdup(protocols, ffmpeg_protos[i]));
319+ }
320+
321+ MP_TARRAY_APPEND(NULL, protocols, num, talloc_strdup(protocols, "ffmpeg"));
322+ MP_TARRAY_APPEND(NULL, protocols, num, talloc_strdup(protocols, "lavf"));
323+
324+ MP_TARRAY_APPEND(NULL, protocols, num, NULL);
325+
326+ talloc_free(ffmpeg_protos);
327+ talloc_free(safe_protocols);
328+ return protocols;
329+}
330+
241331 // Escape http URLs with unescaped, invalid characters in them.
242332 // libavformat's http protocol does not do this, and a patch to add this
243333 // in a 100% safe case (spaces only) was rejected.
@@ -431,12 +521,7 @@ done: · 187 unmodified lines
431521 const stream_info_t stream_info_ffmpeg = {
432522 .name = "ffmpeg",
433523 .open = open_f,
434− .protocols = (const char *const[]){
435− "rtmp", "rtsp", "rtsps", "http", "https", "mms", "mmst", "mmsh", "mmshttp",
436− "rtp", "httpproxy", "rtmpe", "rtmps", "rtmpt", "rtmpte", "rtmpts", "srt",
437− "rist", "srtp", "gopher", "gophers", "data", "ipfs", "ipns", "dav",
438− "davs", "webdav", "webdavs",
439− NULL },
524+ .get_protocols = get_safe_protocols,
440525 .can_write = true,
441526 .stream_origin = STREAM_ORIGIN_NET,
442527 };
@@ -448,10 +533,7 @@ const stream_info_t stream_info_ffmpeg = { · 5 unmodified lines
448533 const stream_info_t stream_info_ffmpeg_unsafe = {
449534 .name = "ffmpeg",
450535 .open = open_f,
451− .protocols = (const char *const[]){
452− "lavf", "ffmpeg", "udp", "ftp", "tcp", "tls", "unix", "sftp", "md5",
453− "concat", "smb",
454− NULL },
536+ .get_protocols = get_unsafe_protocols,
455537 .stream_origin = STREAM_ORIGIN_UNSAFE,
456538 .can_write = true,
457539 };

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t