Skip to content

Expose piece bitfield API for streaming video players#574

Open
cemalturkcan wants to merge 4 commits into
ikatson:mainfrom
cemalturkcan:main
Open

Expose piece bitfield API for streaming video players#574
cemalturkcan wants to merge 4 commits into
ikatson:mainfrom
cemalturkcan:main

Conversation

@cemalturkcan
Copy link
Copy Markdown

No description provided.

cemalturkcan and others added 4 commits February 22, 2026 11:30
- Add update_streaming_window() to ChunkTracker for dynamic queue management
- Only queue pieces within a configurable window around stream position
- Add StreamingWindowUpdate struct for tracking changes
- Expose API through ManagedTorrent::update_streaming_window()
- Add unit tests for basic, seek forward, and have-respecting scenarios

This enables video players to download only from playback position forward,
instead of downloading the entire file.

Amp-Thread-ID: https://ampcode.com/threads/T-019c8482-1cce-72be-8f9b-ee739084eb49
Co-authored-by: Amp <amp@ampcode.com>
@michakfromparis
Copy link
Copy Markdown

I was about to submit a similar PR. I second this one

@ikatson
Copy link
Copy Markdown
Owner

ikatson commented Mar 15, 2026

There's an API with bit field exposed that is used by the new Web UI. It's /api/v1/haves, but you need to set accept: application/octet-stream. Please check, but please check and let me know if that's enough

@cemalturkcan
Copy link
Copy Markdown
Author

Thanks, but I’m not using the web server. I’m working directly with the core, so I can’t use /api/v1/haves.

@ikatson
Copy link
Copy Markdown
Owner

ikatson commented Mar 19, 2026

@cemalturkcan can't you use whatever it is using? I.e. api.rs

@michakfromparis
Copy link
Copy Markdown

Hey @ikatson,

like you suggested, I looked into the /api/v1/haves endpoint (backed by api_dump_haves) and it only covers the read side -- querying which pieces are downloaded. That part is indeed equivalent to get_piece_bitfield() from this PR.

However, the critical feature of this PR is update_streaming_window(), which modifies the piece picker queue to restrict downloads to a window around the current playback position. This is what makes streaming video playable -- without it, rqbit downloads in default order (rarest-first), meaning the player has to wait for pieces it may not need yet while the pieces it needs right now aren't prioritized.

Concretely, update_streaming_window on ChunkTracker:

Removes pieces outside the [position - backward_bytes, position + forward_bytes] window from the download queue

Adds pieces inside the window back to the queue (if selected and not already downloaded)

Returns metadata about what changed (pieces_added, pieces_removed, window_start_piece, window_end_piece)

To my knowledge, there is no equivalent to this in the upstream api.rs or anywhere reachable from ManagedTorrentHandle. The existing with_chunk_tracker callback gives read-only access, and there is no with_chunk_tracker_mut in upstream.

I'm using this fork in our plugin and it works well. We call update_streaming_window at the start of playback (position 0, forward ~30MB) to buffer leading pieces, and then periodically as playback advances. Combined with get_piece_bitfield, this gives us a fully working streaming experience with ~3s initial buffer time.

TL;DR: api_dump_haves replaces get_piece_bitfield but not update_streaming_window. The streaming window control is the main value of this PR.

Thanks @cemalturkcan for this. @ikatson is there a reason you're reluctant to merge this ? Anything you'd like to be done differently ? Maybe make this PR use the api_dump_haves ?

@cemalturkcan
Copy link
Copy Markdown
Author

@michakfromparis thanks for the detailed explanation! actually I first added get_piece_bitfield to visualize the buffer, then added update_streaming_window for my own video streaming use case. since it's been a month, looking at the title I totally forgot I had done that 😅

@ikatson
Copy link
Copy Markdown
Owner

ikatson commented May 26, 2026

This is what makes streaming video playable -- without it, rqbit downloads in default order (rarest-first), meaning the player has to wait for pieces it may not need yet while the pieces it needs right now aren't prioritized.

This used to work, maybe it broke in 8c84f54 (that commit was vibe coded), not sure, but streaming pieces should be prioritized:

priority_pieces: self.state.streams.iter_next_pieces(&self.state.lengths),

is there a reason you're reluctant to merge this ?

It's big and complex, and I still don't understand why does it need to exist provided the above question

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants