Issue title: DASHStreams allow a manifest string instead of an url
 Issue body: ## Feature Request

- [x] This is a feature request and I have read the contribution guidelines.


### Description

some DASHStreams don't have an URL, they are only provided as a XML String

**Facebook** as an example uses this method

- https://github.com/streamlink/streamlink/issues/2133
- https://github.com/streamlink/streamlink/issues/2168

some example Video URLs can be found in the other issues,
this feature is required to solve the other issues.

---

`parse_manifest` needs an update

https://github.com/streamlink/streamlink/blob/5db462eb993d659e27d9de4babd14ab33eb4ad8d/src/streamlink/stream/dash.py#L165-L180

here is some example, in how it could be done

```diff
diff --git a/src/streamlink/stream/dash.py b/src/streamlink/stream/dash.py
index 7339735c..5859efb5 100644
--- a/src/streamlink/stream/dash.py
+++ b/src/streamlink/stream/dash.py
@@ -5,13 +5,14 @@ import os.path
 
 import requests
 from streamlink import StreamError, PluginError
-from streamlink.compat import urlparse, urlunparse
+from streamlink.compat import urlparse, urlunparse, unquote_plus
 from streamlink.stream.http import valid_args, normalize_key
 from streamlink.stream.stream import Stream
 from streamlink.stream.dash_manifest import MPD, sleeper, sleep_until, utc, freeze_timeline
 from streamlink.stream.ffmpegmux import FFMPEGMuxer
 from streamlink.stream.segmented import SegmentedStreamReader, SegmentedStreamWorker, SegmentedStreamWriter
 from streamlink.utils.l10n import Language
+from streamlink.utils import parse_xml
 
 log = logging.getLogger(__name__)
 
@@ -162,7 +163,7 @@ class DASHStream(Stream):
         return dict(type=type(self).shortname(), url=req.url, headers=headers)
 
     @classmethod
-    def parse_manifest(cls, session, url, **args):
+    def parse_manifest(cls, session, url, manifest=None, **args):
         """
         Attempt to parse a DASH manifest file and return its streams
 
@@ -170,14 +171,26 @@ class DASHStream(Stream):
         :param url: URL of the manifest file
         :return: a dict of name -> DASHStream instances
         """
+
         ret = {}
-        res = session.http.get(url, **args)
-        url = res.url
 
-        urlp = list(urlparse(url))
-        urlp[2], _ = urlp[2].rsplit("/", 1)
+        # XXX: Test manifest
+        url = None
+        manifest = '\x3C?xml version=\"1.0\"?>\n\x3CMPD xmlns=\"urn:mpeg:dash:schema:mpd: ... x3C/AdaptationSet>\x3C/Period>\x3C/MPD>\n'
+
+        if url and not manifest:
+            res = session.http.get(url, **args)
+            url = res.url
+
+            urlp = list(urlparse(url))
+            urlp[2], _ = urlp[2].rsplit("/", 1)
 
-        mpd = MPD(session.http.xml(res, ignore_ns=True), base_url=urlunparse(urlp), url=url)
+            mpd = MPD(session.http.xml(res, ignore_ns=True), base_url=urlunparse(urlp), url=url)
+        elif manifest and not url:
+            mpd = MPD(parse_xml(unquote_plus(manifest).replace("\\", ""), ignore_ns=True))
+            # mpd = MPD(manifest, ignore_ns=True)
+        else:
+            raise StreamError("...")
 
         video, audio = [], []
```

### Expected / Actual behavior

Use a XML String instead of an URL for DASHStreams.


 Comments: 
 Comment 0: Could make it a file like (eg. `StringIO`) then it would work for other cases too, dunno which other cases - but it sounds like a good idea. 
{'source': 'GithubIssues', 'repo_name_with_owner': 'streamlink/streamlink', 'issue_id': 384123631, 'repo_stars': 8271.0}