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.
This commit is contained in:
wm4 2019-06-19 19:38:46 +02:00
parent 43fc314279
commit c4dc600f1f
2 changed files with 23 additions and 32 deletions

View File

@ -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;

View File

@ -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;