summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-06-19 19:38:46 +0200
committerwm4 <wm4@nowhere>2019-09-19 20:37:05 +0200
commitc4dc600f1f2e08f87cf8147098c1559607464824 (patch)
tree1064dd40a619d8cde8984b3c084f124da14b8dc5
parent43fc314279562580c95e558a56a4277f1f7dc5f0 (diff)
downloadmpv-c4dc600f1f2e08f87cf8147098c1559607464824.tar.bz2
mpv-c4dc600f1f2e08f87cf8147098c1559607464824.tar.xz
demux: make webm dash work by using init fragment on all demuxers
Retarded webshit streaming protocols (well, DASH) chop a stream into small fragments, and move unchanging header parts to an "init" fragment to save some bytes (in the case at hand about 300 bytes for each fragment that is 100KB-200KB, sure was worth it, fucking idiots). Since mpv uses an even more retarded hack to inefficiently emulate DASH through EDL, it opens a new demuxer for every fragment. Thus the fragment needs to be virtually concatenated with the init fragment. (To be fair, I'm not sure whether the alternative, reusing the demuxer and letting it see a stream of byte-wise concatenated fragmenmts, would actually be saner.) demux_lavc.c contained a hack for this. Unfortunately, a certain shitty streaming site by an evil company, that will bestow dytopia upon us soon enough, sometimes serves webm based DASH instead of the expected mp4 DASH. And for some reason, libavformat's mkv demuxer can't handle the init fragment or rejects it for some reason. Since I'd rather eat mushrooms grown in Chernobyl than debugging, hacking, or (god no) contributing to FFmpeg, and since Chernobyl is so far away, make it work with our builtin mkv demuxer instead. This is not hard. We just need to copy the hack in demux_lavf.c to demux_mkv.c. Since I'm not _that_ much of a dumbfuck to actually do this, remove the shitty gross demux_lavf.c hack, and replace it by a slightly less bad generic implementation (stream_concat.c from the previous commit), and use it on all demuxers. Although this requires much more code, this frees demux_lavf.c from a hack, and doesn't require adding a duplicated one to demux_mkv.c, so to the naive eye this seems to be a much better outcome. Regarding the code, for some reason stream_memory_open() is never meant to fail, while stream_concat_open() can in extremely obscure situations, and (currently) not in this case, but we handle failure of it anyway. Yep.
-rw-r--r--demux/demux.c20
-rw-r--r--demux/demux_lavf.c35
2 files changed, 23 insertions, 32 deletions
diff --git a/demux/demux.c b/demux/demux.c
index 742619b30a..7025d95161 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -3201,6 +3201,22 @@ done:
return demuxer;
}
+static struct stream *create_webshit_concat_stream(struct mpv_global *global,
+ struct mp_cancel *c,
+ bstr init, struct stream *real)
+{
+ struct stream *mem = stream_memory_open(global, init.start, init.len);
+ assert(mem);
+
+ struct stream *streams[2] = {mem, real};
+ struct stream *concat = stream_concat_open(global, c, streams, 2);
+ if (!concat) {
+ free_stream(mem);
+ free_stream(real);
+ }
+ return concat;
+}
+
// Convenience function: open the stream, enable the cache (according to params
// and global opts.), open the demuxer.
// Also for some reason may close the opened stream if it's not needed.
@@ -3220,6 +3236,10 @@ struct demuxer *demux_open_url(const char *url,
mp_cancel_set_parent(priv_cancel, cancel);
struct stream *s = stream_create(url, STREAM_READ | params->stream_flags,
priv_cancel, global);
+ if (s && params->init_fragment.len) {
+ s = create_webshit_concat_stream(global, priv_cancel,
+ params->init_fragment, s);
+ }
if (!s) {
talloc_free(priv_cancel);
return NULL;
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index bacbfa24de..ad2e6df6ea 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -218,8 +218,6 @@ typedef struct lavf_priv {
AVInputFormat *avif;
int avif_flags;
AVFormatContext *avfc;
- bstr init_fragment;
- int64_t stream_pos;
AVIOContext *pb;
struct stream_info **streams; // NULL for unknown streams
int num_streams;
@@ -281,16 +279,8 @@ static int mp_read(void *opaque, uint8_t *buf, int size)
struct demuxer *demuxer = opaque;
lavf_priv_t *priv = demuxer->priv;
struct stream *stream = priv->stream;
- int ret;
- if (priv->stream_pos < priv->init_fragment.len) {
- ret = MPMIN(size, priv->init_fragment.len - priv->stream_pos);
- memcpy(buf, priv->init_fragment.start + priv->stream_pos, ret);
- priv->stream_pos += ret;
- } else {
- ret = stream_read_partial(stream, buf, size);
- priv->stream_pos = priv->init_fragment.len + stream_tell(stream);
- }
+ int ret = stream_read_partial(stream, buf, size);
MP_TRACE(demuxer, "%d=mp_read(%p, %p, %d), pos: %"PRId64", eof:%d\n",
ret, stream, buf, size, stream_tell(stream), stream->eof);
@@ -311,12 +301,11 @@ static int64_t mp_seek(void *opaque, int64_t pos, int whence)
int64_t end = stream_get_size(stream);
if (end < 0)
return -1;
- end += priv->init_fragment.len;
if (whence == AVSEEK_SIZE)
return end;
pos += end;
} else if (whence == SEEK_CUR) {
- pos += priv->stream_pos;
+ pos += stream_tell(stream);
} else if (whence != SEEK_SET) {
return -1;
}
@@ -324,23 +313,12 @@ static int64_t mp_seek(void *opaque, int64_t pos, int whence)
if (pos < 0)
return -1;
- int64_t stream_target = pos - priv->init_fragment.len;
- bool seek_before = stream_target < 0;
- if (seek_before)
- stream_target = 0; // within init segment - seek real stream to 0
-
int64_t current_pos = stream_tell(stream);
- if (stream_seek(stream, stream_target) == 0) {
+ if (stream_seek(stream, pos) == 0) {
stream_seek(stream, current_pos);
return -1;
}
- if (seek_before) {
- priv->stream_pos = pos;
- } else {
- priv->stream_pos = priv->init_fragment.len + stream_tell(stream);
- }
-
return pos;
}
@@ -478,10 +456,6 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
int nsize = av_clip(avpd.buf_size * 2, INITIAL_PROBE_SIZE,
PROBE_BUF_SIZE);
bstr buf = stream_peek(s, nsize);
- if (demuxer->params && demuxer->params->init_fragment.len) {
- buf = demuxer->params->init_fragment;
- buf.len = MPMIN(buf.len, nsize);
- }
if (buf.len <= avpd.buf_size)
final_probe = true;
memcpy(avpd.buf, buf.start, buf.len);
@@ -933,9 +907,6 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
if (lavf_check_file(demuxer, check) < 0)
return -1;
- if (demuxer->params)
- priv->init_fragment = bstrdup(priv, demuxer->params->init_fragment);
-
avfc = avformat_alloc_context();
if (!avfc)
return -1;