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
271 return list;271 return list;
272}272}
273 273
274char **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
274int mp_codec_to_av_codec_id(const char *codec)286int mp_codec_to_av_codec_id(const char *codec)
275{287{
276 int id = AV_CODEC_ID_NONE;288 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
42void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type);42void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type);
43void mp_add_lavc_encoders(struct mp_decoder_list *list);43void mp_add_lavc_encoders(struct mp_decoder_list *list);
44char **mp_get_lavf_demuxers(void);44char **mp_get_lavf_demuxers(void);
45char **mp_get_lavf_protocols(void);
45int mp_codec_to_av_codec_id(const char *codec);46int mp_codec_to_av_codec_id(const char *codec);
46const char *mp_codec_from_av_codec_id(int codec_id);47const char *mp_codec_from_av_codec_id(int codec_id);
47bool mp_codec_is_lossless(const char *codec);48bool 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
66#if HAVE_CDDA66#if HAVE_CDDA
67 &stream_info_cdda,67 &stream_info_cdda,
68#endif68#endif
69 &stream_info_ffmpeg,
70 &stream_info_ffmpeg_unsafe,
71 &stream_info_avdevice,69 &stream_info_avdevice,
72#if HAVE_DVBIN70#if HAVE_DVBIN
73 &stream_info_dvb,71 &stream_info_dvb,
@@ -92,6 +90,8 @@ static const stream_info_t *const stream_list[] = { · 18 unmodified lines
92 &stream_info_slice,90 &stream_info_slice,
93 &stream_info_fd,91 &stream_info_fd,
94 &stream_info_cb,92 &stream_info_cb,
93 &stream_info_ffmpeg,
94 &stream_info_ffmpeg_unsafe,
95};95};
96 96
97// Because of guarantees documented on STREAM_BUFFER_SIZE.97// 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
325 if (!sinfo->local_fs)325 if (!sinfo->local_fs)
326 return STREAM_NO_MATCH;326 return STREAM_NO_MATCH;
327 } else {327 } else {
328 for (int n = 0; sinfo->protocols && sinfo->protocols[n]; n++) {328 char **get_protocols = sinfo->get_protocols ? sinfo->get_protocols() : NULL;
329 path = match_proto(url, sinfo->protocols[n]);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]);
330 if (path)333 if (path)
331 break;334 break;
332 }335 }
333 336
337 talloc_free(get_protocols);
338
334 if (!path)339 if (!path)
335 return STREAM_NO_MATCH;340 return STREAM_NO_MATCH;
336 }341 }
@@ -864,16 +869,17 @@ char **stream_get_proto_list(void) · 527 unmodified lines
864 for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {869 for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {
865 const stream_info_t *stream_info = stream_list[i];870 const stream_info_t *stream_info = stream_list[i];
866 871
867 if (!stream_info->protocols)872 char **get_protocols = stream_info->get_protocols ? stream_info->get_protocols() : NULL;
868 continue;873 char **protocols = get_protocols ? get_protocols : (char **)stream_info->protocols;
869 874
870 for (int j = 0; stream_info->protocols[j]; j++) {875 for (int j = 0; protocols && protocols[j]; j++) {
871 if (*stream_info->protocols[j] == '\0')876 if (*protocols[j] == '\0')
872 continue;877 continue;
873 878
874 MP_TARRAY_APPEND(NULL, list, num,879 MP_TARRAY_APPEND(NULL, list, num, talloc_strdup(list, protocols[j]));
875 talloc_strdup(NULL, stream_info->protocols[j]));
876 }880 }
881
882 talloc_free(get_protocols);
877 }883 }
878 MP_TARRAY_APPEND(NULL, list, num, NULL);884 MP_TARRAY_APPEND(NULL, list, num, NULL);
879 return list;885 return list;
@@ -888,7 +894,6 @@ void stream_print_proto_list(struct mp_log *log) · 8 unmodified lines
888 for (int i = 0; list[i]; i++) {894 for (int i = 0; list[i]; i++) {
889 mp_info(log, " %s://\n", list[i]);895 mp_info(log, " %s://\n", list[i]);
890 count++;896 count++;
891 talloc_free(list[i]);
892 }897 }
893 talloc_free(list);898 talloc_free(list);
894 mp_info(log, "\nTotal: %d protocols\n", count);899 mp_info(log, "\nTotal: %d protocols\n", count);
@@ -899,10 +904,19 @@ bool stream_has_proto(const char *proto) · 4 unmodified lines
899 for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {904 for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {
900 const stream_info_t *stream_info = stream_list[i];905 const stream_info_t *stream_info = stream_list[i];
901 906
902 for (int j = 0; stream_info->protocols && stream_info->protocols[j]; j++) {907 bool match = false;
903 if (strcmp(stream_info->protocols[j], proto) == 0)908 char **get_protocols = stream_info->get_protocols ? stream_info->get_protocols() : NULL;
904 return true;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 }
905 }916 }
917
918 talloc_free(get_protocols);
919 return match;
906 }920 }
907 921
908 return false;922 return false;
stream/stream.h+2−0
@@ -114,6 +114,8 @@ typedef struct stream_info_st { · 113 unmodified lines
114 // Alternative to open(). Only either open() or open2() can be set.114 // Alternative to open(). Only either open() or open2() can be set.
115 int (*open2)(struct stream *st, const struct stream_open_args *args);115 int (*open2)(struct stream *st, const struct stream_open_args *args);
116 const char *const *protocols;116 const char *const *protocols;
117 // Alternative to protocols. For stream_lavf.
118 char **(*get_protocols)(void);
117 bool can_write; // correctly checks for READ/WRITE modes119 bool can_write; // correctly checks for READ/WRITE modes
118 bool local_fs; // supports STREAM_LOCAL_FS_ONLY120 bool local_fs; // supports STREAM_LOCAL_FS_ONLY
119 int stream_origin; // 0 or set of STREAM_ORIGIN_*; if 0, the same origin121 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
238 talloc_free(temp);238 talloc_free(temp);
239}239}
240 240
241#define PROTO(...) (const char *[]){__VA_ARGS__, NULL}
242
243// List of safe protocols and their aliases
244static 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
268static 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
302static 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
241// Escape http URLs with unescaped, invalid characters in them.331// Escape http URLs with unescaped, invalid characters in them.
242// libavformat's http protocol does not do this, and a patch to add this332// libavformat's http protocol does not do this, and a patch to add this
243// in a 100% safe case (spaces only) was rejected.333// in a 100% safe case (spaces only) was rejected.
@@ -431,12 +521,7 @@ done: · 187 unmodified lines
431const stream_info_t stream_info_ffmpeg = {521const stream_info_t stream_info_ffmpeg = {
432 .name = "ffmpeg",522 .name = "ffmpeg",
433 .open = open_f,523 .open = open_f,
434 .protocols = (const char *const[]){524 .get_protocols = get_safe_protocols,
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 },
440 .can_write = true,525 .can_write = true,
441 .stream_origin = STREAM_ORIGIN_NET,526 .stream_origin = STREAM_ORIGIN_NET,
442};527};
@@ -448,10 +533,7 @@ const stream_info_t stream_info_ffmpeg = { · 5 unmodified lines
448const stream_info_t stream_info_ffmpeg_unsafe = {533const stream_info_t stream_info_ffmpeg_unsafe = {
449 .name = "ffmpeg",534 .name = "ffmpeg",
450 .open = open_f,535 .open = open_f,
451 .protocols = (const char *const[]){536 .get_protocols = get_unsafe_protocols,
452 "lavf", "ffmpeg", "udp", "ftp", "tcp", "tls", "unix", "sftp", "md5",
453 "concat", "smb",
454 NULL },
455 .stream_origin = STREAM_ORIGIN_UNSAFE,537 .stream_origin = STREAM_ORIGIN_UNSAFE,
456 .can_write = true,538 .can_write = true,
457};539};

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