Store the response's `Content-Length` (when available) as an "expected
size" on `IncrementallyPopulatedStream`.
This allows `IncrementallyPopulatedStream::size()` to return a
meaningful total length early, instead of blocking until EOF. That's
important for the FFmpeg MP4 demuxer, which queries the stream size
immediately after initialization.
Additionally, use the expected size to pre-reserve the underlying
`ByteBuffer` capacity, avoiding repeated reallocations as chunks are
appended.
`IncrementallyPopulatedStream::Cursor` now tracks whether it's currently
blocked inside a wait for more bytes, allowing higher layers to
distinguish "no frames yet" from "decoder is idle".
Enter buffering when `DisplayingVideoSink` runs out of frames and the
associated `VideoDataProvider` is blocked waiting for data to arrive.
Exit buffering once decoding refills the frame queue.
For now, buffering behaves like paused, but it gives us an explicit
state to hook UI into.
When a seek is requested while a previous seek is still blocked waiting
for not yet available bytes, we want to abandon the old request
immediately and start processing the new one.
...a shared byte stream that can be appended to as network data arrives.
The stream supports creating multiple independent `Cursor`s, each with
its own read position. This matches our demuxing needs, where different
audio/video tracks may read from the same underlying data concurrently.
`Cursor::read_into()` and `Cursor::seek()` block until the requested
range is available (or the stream is closed). This is intentional: the
FFmpeg `avio_alloc_context()` read callback cannot reliably surface
`EAGAIN` without putting the demuxer into an error state that
requires recovery via seeking, so we instead wait until we can satisfy
the read.