1 #ifndef _VIDEO_WIDGET_H
2 #define _VIDEO_WIDGET_H 1
4 #include <QOpenGLWidget>
12 #include <libavutil/pixfmt.h>
13 #include <libavutil/rational.h>
16 #include "ffmpeg_raii.h"
17 #include "quittable_sleeper.h"
19 // Because QVideoWidget sucks, sadly. (Don't use GStreamer, kids.)
21 class VideoWidget : public QOpenGLWidget {
25 VideoWidget(QWidget *parent);
26 ~VideoWidget() { stop(); }
28 void open(const std::string &filename);
30 uint64_t get_position() const { return last_position; } // In milliseconds.
33 void seek(int64_t relative_seek_ms); // Relative seek.
34 void seek_frames(int64_t relative_frames); // Relative seek.
35 void seek_absolute(int64_t position_ms); // Absolute seek.
37 void initializeGL() override;
38 void resizeGL(int w, int h) override;
39 void paintGL() override;
40 void wheelEvent(QWheelEvent *event) override;
43 void position_changed(uint64_t pos);
46 // Should really have been persistent and a PBO, but this is OK for now.
48 unsigned width, height;
49 unsigned chroma_width, chroma_height;
50 std::unique_ptr<uint8_t[]> data; // Y, followed by Cb, followed by Cr.
52 std::shared_ptr<Frame> current_frame;
53 std::deque<AVFrameWithDeleter> queued_frames; // Frames decoded but not displayed. Only used when frame-stepping backwards.
55 GLuint ycbcr_vertex_shader, ycbcr_fragment_shader, ycbcr_program;
56 GLuint bilinear_sampler;
59 GLuint last_width = 0, last_height = 0;
60 GLuint last_chroma_width = 0, last_chroma_height = 0;
61 GLfloat cbcr_offset[2];
62 double display_aspect = 1.0;
63 double zoom_matrix[9] = { // Column-major, to match with OpenGL.
71 std::atomic<uint64_t> last_position{0}; // TODO: sort of redundant wrt. last_pts (but this one can be read from the other thread)
72 std::atomic<bool> running{false};
74 std::chrono::steady_clock::time_point start, next_frame_start, last_frame;
76 SwsContextWithDeleter sws_ctx;
77 int sws_last_width = -1, sws_last_height = -1, sws_last_src_format = -1;
78 AVPixelFormat sws_dst_format = AVPixelFormat(-1); // In practice, always initialized.
79 AVRational video_timebase, audio_timebase;
81 QuittableSleeper producer_thread_should_quit;
82 std::thread producer_thread;
85 struct QueuedCommand {
86 enum Command { PAUSE, RESUME, SEEK, SEEK_ABSOLUTE } command;
87 int64_t relative_seek_ms; // For SEEK.
88 int64_t relative_seek_frames; // For SEEK.
89 int64_t seek_ms; // For SEEK_ABSOLUTE.
91 std::vector<QueuedCommand> command_queue; // Protected by <queue_mu>.
95 void producer_thread_func();
96 bool play_video(const std::string &pathname);
97 void internal_rewind();
98 AVFrameWithDeleter decode_frame(AVFormatContext *format_ctx, AVCodecContext *video_codec_ctx,
99 const std::string &pathname, int video_stream_index,
101 Frame make_video_frame(const AVFrame *frame);
102 bool process_queued_commands(AVFormatContext *format_ctx, AVCodecContext *video_codec_ctx, int video_stream_index, bool *seeked);
103 void store_pts(int64_t pts);
105 void fixup_zoom_matrix();
108 #endif // !defined(_VIDEO_WIDGET_H)