feat: stream YouTube video with coordinated audio and video inputs

Resolve public YouTube URLs through external yt-dlp and play selected streams in the existing native window.

Independent bounded network readers keep one authored timeline. Successful seeks clear FFmpeg's sticky aborted-read AVIO error; manifest seekability uses native format flags rather than a top-level I/O handle.

Verified real YouTube playback, seeking, frame stepping, compact mode, cancellation, and the complete native regression checks.
This commit is contained in:
2026-10-10 22:18:24 +02:00
parent 25d674d84d
commit 8fb08db6f3
10 changed files with 2451 additions and 181 deletions
+16
View File
@@ -17,6 +17,10 @@ typedef struct PlayerState {
double duration;
bool has_audio;
bool has_video;
// False for live/non-seekable inputs; reflects both inputs for separate streams.
bool can_seek;
// Network playback is waiting for media; the authoritative clock remains stalled.
bool buffering;
// True until all accepted seeks/frame steps on this timeline finish.
bool seek_pending;
// Display width / height, including sample aspect ratio; zero without video.
@@ -28,7 +32,19 @@ typedef struct PlayerState {
// Playback commands are asynchronous. False means invalid input or a full command queue.
// Paths are copied before returning. All other calls require a live handle.
Player *player_create(void);
typedef struct PlayerNetworkSource {
// Primary video or combined audio/video HTTP(S) URL; audio_url is optional.
const char *video_url;
const char *audio_url;
// Optional HTTP headers encoded as "Name: value\r\n"; copied with the URLs.
const char *video_headers;
const char *audio_headers;
double duration;
bool is_live;
} PlayerNetworkSource;
bool player_open(Player *player, const char *path);
// Streams directly; never downloads or muxes the entire media file before opening.
bool player_open_network(Player *player, const PlayerNetworkSource *source);
bool player_play(Player *player);
bool player_pause(Player *player);
bool player_seek(Player *player, double seconds);