/* Просмотр одной live-трансляции: запас остаётся в RS-кольце, worker готовит ближайшие FFmpeg/Opus кадры. * GUI владеет output device и окном; audio callback публикует часы физического воспроизведения. * Закрытие останавливает worker и снимает reader. Публикация и общий транспорт не закрываются. */ #pragma once #include #include #include #include #include "audio_device.h" class VideoRenderWidget; class QLabel; class QCloseEvent; class QKeyEvent; class StreamPlayerWindow : public QWidget { Q_OBJECT public: explicit StreamPlayerWindow(uint64_t group, uint64_t source, uint64_t epoch, const QString& name, QWidget* parent = nullptr); ~StreamPlayerWindow() override; void stop(); signals: void statusChanged(const QString& status); void framePresented(); protected: void closeEvent(QCloseEvent* event) override; void keyPressEvent(QKeyEvent* event) override; private: struct Playback; std::unique_ptr m_playback; AudioDevice m_audio; QTimer m_timer; VideoRenderWidget* m_render = nullptr; QLabel* m_status = nullptr; void openAudio(); void tick(); void decode(); };