diff options
author | wm4 <wm4@nowhere> | 2017-11-05 16:36:18 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2017-11-05 18:13:34 +0100 |
commit | 9e1fbffc37779c8f491d3aa8e319ab233e5ab0da (patch) | |
tree | 894c25cc6443805d3453c3a4788ed4ab1ee0bedc /demux/ebml.c | |
parent | 8aa1db3b175d29201f55648849b4f2ddc15f8ea1 (diff) | |
download | mpv-9e1fbffc37779c8f491d3aa8e319ab233e5ab0da.tar.bz2 mpv-9e1fbffc37779c8f491d3aa8e319ab233e5ab0da.tar.xz |
demux_mkv: rewrite packet reading to avoid 1 memcpy()
This directly reads individual mkv sub-packets (block laces) into a
dedicated AVBufferRefs, which can be directly used for creating packets
without a additional copy of the packet data. This also means we switch
parsing of block header fields and lacing metadata to read directly from
the stream, instead of a memory buffer.
This could have been much easier if libavcodec didn't require padding
the packet data with zero bytes. We could just have each packet
reference a slice of the block data. But as it is, the only way to get
padding without a copy is to read the laces into individually allocated
(and padded) memory block, which required a larger rewrite.
This probably makes recovering from broken mkv files slightly worse if
the transport is unseekable. We just read, and then check if we've
overread. But I think that shouldn't be a real concern.
No actual measureable performance change. Potential for some
regressions, as this is quite intrusive, and touches weird obscure shit
like mkv lacing. Still keeping it because I like how it removes some
redundant EBML parsing functions.
Diffstat (limited to 'demux/ebml.c')
-rw-r--r-- | demux/ebml.c | 63 |
1 files changed, 16 insertions, 47 deletions
diff --git a/demux/ebml.c b/demux/ebml.c index e05f7245b0..d2a8629136 100644 --- a/demux/ebml.c +++ b/demux/ebml.c @@ -74,83 +74,52 @@ uint32_t ebml_read_id(stream_t *s) } /* - * Read a variable length unsigned int. + * Read: element content length. */ -uint64_t ebml_read_vlen_uint(bstr *buffer) +uint64_t ebml_read_length(stream_t *s) { int i, j, num_ffs = 0, len_mask = 0x80; - uint64_t num; - - if (buffer->len == 0) - return EBML_UINT_INVALID; + uint64_t len; - for (i = 0, num = buffer->start[0]; i < 8 && !(num & len_mask); i++) + for (i = 0, len = stream_read_char(s); i < 8 && !(len & len_mask); i++) len_mask >>= 1; if (i >= 8) return EBML_UINT_INVALID; j = i + 1; - if ((int) (num &= (len_mask - 1)) == len_mask - 1) + if ((int) (len &= (len_mask - 1)) == len_mask - 1) num_ffs++; - if (j > buffer->len) - return EBML_UINT_INVALID; - for (int n = 0; n < i; n++) { - num = (num << 8) | buffer->start[n + 1]; - if ((num & 0xFF) == 0xFF) + while (i--) { + len = (len << 8) | stream_read_char(s); + if ((len & 0xFF) == 0xFF) num_ffs++; } if (j == num_ffs) return EBML_UINT_INVALID; - buffer->start += j; - buffer->len -= j; - return num; + if (len >= 1ULL<<63) // Can happen if stream_read_char returns EOF + return EBML_UINT_INVALID; + return len; } + /* * Read a variable length signed int. */ -int64_t ebml_read_vlen_int(bstr *buffer) +int64_t ebml_read_signed_length(stream_t *s) { uint64_t unum; int l; /* read as unsigned number first */ - size_t len = buffer->len; - unum = ebml_read_vlen_uint(buffer); + uint64_t offset = stream_tell(s); + unum = ebml_read_length(s); if (unum == EBML_UINT_INVALID) return EBML_INT_INVALID; - l = len - buffer->len; + l = stream_tell(s) - offset; return unum - ((1LL << ((7 * l) - 1)) - 1); } /* - * Read: element content length. - */ -uint64_t ebml_read_length(stream_t *s) -{ - int i, j, num_ffs = 0, len_mask = 0x80; - uint64_t len; - - for (i = 0, len = stream_read_char(s); i < 8 && !(len & len_mask); i++) - len_mask >>= 1; - if (i >= 8) - return EBML_UINT_INVALID; - j = i + 1; - if ((int) (len &= (len_mask - 1)) == len_mask - 1) - num_ffs++; - while (i--) { - len = (len << 8) | stream_read_char(s); - if ((len & 0xFF) == 0xFF) - num_ffs++; - } - if (j == num_ffs) - return EBML_UINT_INVALID; - if (len >= 1ULL<<63) // Can happen if stream_read_char returns EOF - return EBML_UINT_INVALID; - return len; -} - -/* * Read the next element as an unsigned int. */ uint64_t ebml_read_uint(stream_t *s) |