]> git.sesse.net Git - nageru/blob - nageru/ffmpeg_capture.h
Fix a Clang 19 warning.
[nageru] / nageru / ffmpeg_capture.h
1 #ifndef _FFMPEG_CAPTURE_H
2 #define _FFMPEG_CAPTURE_H 1
3
4 // FFmpegCapture looks much like a capture card, but the frames it spits out
5 // come from a video in real time, looping. Because it decodes the video using
6 // FFmpeg (thus the name), this means it can handle a very wide array of video
7 // formats, and also things like network streaming and V4L capture, but it is
8 // also significantly less integrated and optimized than the regular capture
9 // cards. In particular, the frames are always scaled and converted to 8-bit
10 // RGBA on the CPU before being sent on to the GPU.
11 //
12 // Since we don't really know much about the video when building the chains,
13 // there are some limitations. In particular, frames are always assumed to be
14 // sRGB even if the video container says something else. We could probably
15 // try to load the video on startup and pick out the parameters at that point,
16 // but it would require some more plumbing, and it would also fail if the file
17 // changes parameters midway, which is allowed in some formats.
18 //
19 // You can get out the audio either as decoded or in raw form (Kaeru uses this).
20 //
21 // If there's a subtitle track, you can also get out the last subtitle at the
22 // point of the frame. Note that once we get a video frame, we don't look for
23 // subtitle, so if subtitles and a frame comes at the same time, you might not
24 // see the subtitle until the next frame.
25
26 #include <assert.h>
27 #include <stddef.h>
28 #include <stdint.h>
29 #include <time.h>
30
31 #include <atomic>
32 #include <chrono>
33 #include <functional>
34 #include <map>
35 #include <memory>
36 #include <mutex>
37 #include <set>
38 #include <string>
39 #include <thread>
40 #include <vector>
41
42 #include <movit/effect.h>
43 #include <movit/ycbcr.h>
44
45 extern "C" {
46 #include <libavutil/frame.h>
47 #include <libswresample/swresample.h>
48 #include <libavutil/channel_layout.h>
49 #include <libavutil/pixfmt.h>
50 #include <libavutil/rational.h>
51 #include <libavutil/samplefmt.h>
52 }
53
54 #include "bmusb/bmusb.h"
55 #include "shared/ffmpeg_raii.h"
56 #include "ref_counted_frame.h"
57 #include "quittable_sleeper.h"
58
59 struct AVFormatContext;
60 struct AVFrame;
61 struct AVRational;
62 struct AVPacket;
63 class QSurface;
64
65 class FFmpegCapture : public bmusb::CaptureInterface
66 {
67 public:
68         FFmpegCapture(const std::string &filename, unsigned width, unsigned height, QSurface *surface);
69 #ifdef HAVE_SRT
70         // Takes ownership of the SRT client socket.
71         FFmpegCapture(int srt_sock, const std::string &stream_id, QSurface *surface);
72 #endif
73         ~FFmpegCapture();
74
75         void set_card_index(int card_index)
76         {
77                 this->card_index = card_index;
78         }
79
80         int get_card_index() const
81         {
82                 return card_index;
83         }
84
85         void rewind()
86         {
87                 std::lock_guard<std::mutex> lock(queue_mu);
88                 command_queue.push_back(QueuedCommand { QueuedCommand::REWIND });
89                 producer_thread_should_quit.wakeup();
90         }
91
92         void change_rate(double new_rate)
93         {
94                 std::lock_guard<std::mutex> lock(queue_mu);
95                 command_queue.push_back(QueuedCommand { QueuedCommand::CHANGE_RATE, new_rate });
96                 producer_thread_should_quit.wakeup();
97         }
98
99         std::string get_filename() const
100         {
101                 std::lock_guard<std::mutex> lock(filename_mu);
102                 return filename;
103         }
104
105         void change_filename(const std::string &new_filename)
106         {
107                 std::lock_guard<std::mutex> lock(filename_mu);
108                 filename = new_filename;
109                 should_interrupt = true;
110         }
111
112         // Will stop the stream even if it's hung on blocking I/O.
113         void disconnect()
114         {
115                 should_interrupt = true;
116         }
117
118         // CaptureInterface.
119         void set_video_frame_allocator(bmusb::FrameAllocator *allocator) override
120         {
121                 video_frame_allocator = allocator;
122                 if (owned_video_frame_allocator.get() != allocator) {
123                         owned_video_frame_allocator.reset();
124                 }
125         }
126
127         bmusb::FrameAllocator *get_video_frame_allocator() override
128         {
129                 return video_frame_allocator;
130         }
131
132         // Does not take ownership.
133         void set_audio_frame_allocator(bmusb::FrameAllocator *allocator) override
134         {
135                 audio_frame_allocator = allocator;
136                 if (owned_audio_frame_allocator.get() != allocator) {
137                         owned_audio_frame_allocator.reset();
138                 }
139         }
140
141         bmusb::FrameAllocator *get_audio_frame_allocator() override
142         {
143                 return audio_frame_allocator;
144         }
145
146         // FFmpegCapture-specific overload of set_frame_callback that also gives
147         // the raw original pts from the video. Negative pts means a dummy frame.
148         typedef std::function<void(int64_t video_pts, AVRational video_timebase, int64_t audio_pts, AVRational audio_timebase,
149                                    uint16_t timecode,
150                                    bmusb::FrameAllocator::Frame video_frame, size_t video_offset, bmusb::VideoFormat video_format,
151                                    bmusb::FrameAllocator::Frame audio_frame, size_t audio_offset, bmusb::AudioFormat audio_format)>
152                 frame_callback_t;
153         void set_frame_callback(frame_callback_t callback)
154         {
155                 frame_callback = callback;
156         }
157
158         void set_frame_callback(bmusb::frame_callback_t callback) override
159         {
160                 frame_callback = std::bind(
161                         callback,
162                         std::placeholders::_5,
163                         std::placeholders::_6,
164                         std::placeholders::_7,
165                         std::placeholders::_8,
166                         std::placeholders::_9,
167                         std::placeholders::_10,
168                         std::placeholders::_11);
169         }
170
171         // FFmpegCapture-specific callback that gives the raw audio/video.
172         typedef std::function<void(const AVPacket *pkt, const AVRational timebase)> packet_callback_t;
173         void set_video_callback(packet_callback_t callback)
174         {
175                 video_callback = callback;
176         }
177         void set_audio_callback(packet_callback_t callback)
178         {
179                 audio_callback = callback;
180         }
181
182         // Used to get precise information about the Y'CbCr format used
183         // for a given frame. Only valid to call during the frame callback,
184         // and only when receiving a frame with pixel format PixelFormat_8BitYCbCrPlanar.
185         movit::YCbCrFormat get_current_frame_ycbcr_format() const
186         {
187                 return current_frame_ycbcr_format;
188         }
189
190         // Only valid to call during the frame callback.
191         std::string get_last_subtitle() const
192         {
193                 return last_subtitle;
194         }
195
196         // Same.
197         bool get_has_last_subtitle() const
198         {
199                 return has_last_subtitle;
200         }
201
202         // Same.
203         movit::RGBTriplet get_last_neutral_color() const
204         {
205                 return last_neutral_color;
206         }
207
208         void set_dequeue_thread_callbacks(std::function<void()> init, std::function<void()> cleanup) override
209         {
210                 dequeue_init_callback = init;
211                 dequeue_cleanup_callback = cleanup;
212                 has_dequeue_callbacks = true;
213         }
214
215         void set_card_disconnected_callback(bmusb::card_disconnected_callback_t callback)
216         {
217                 card_disconnected_callback = callback;
218         }
219
220         std::string get_description() const override
221         {
222                 return description;
223         }
224
225         void configure_card() override;
226         void start_bm_capture() override;
227         void stop_dequeue_thread() override;
228         bool get_disconnected() const override { return disconnected; }  // Only if play_once == true.
229         int get_srt_sock() const { return srt_sock; }
230
231         std::map<uint32_t, bmusb::VideoMode> get_available_video_modes() const override;
232         void set_video_mode(uint32_t video_mode_id) override {}  // Ignore.
233         uint32_t get_current_video_mode() const override { return 0; }
234
235         static constexpr bmusb::PixelFormat PixelFormat_NV12 = static_cast<bmusb::PixelFormat>(100);  // In the private range.
236         std::set<bmusb::PixelFormat> get_available_pixel_formats() const override {
237                 return std::set<bmusb::PixelFormat>{ bmusb::PixelFormat_8BitBGRA, bmusb::PixelFormat_8BitYCbCrPlanar, PixelFormat_NV12 };
238         }
239         void set_pixel_format(bmusb::PixelFormat pixel_format) override {
240                 this->pixel_format = pixel_format;
241         }       
242         bmusb::PixelFormat get_current_pixel_format() const override {
243                 return pixel_format;
244         }
245
246         std::map<uint32_t, std::string> get_available_video_inputs() const override {
247                 return { { 0, "Auto" } }; }
248         void set_video_input(uint32_t video_input_id) override {}  // Ignore.
249         uint32_t get_current_video_input() const override { return 0; }
250
251         std::map<uint32_t, std::string> get_available_audio_inputs() const override {
252                 return { { 0, "Embedded" } };
253         }
254         void set_audio_input(uint32_t audio_input_id) override {}  // Ignore.
255         uint32_t get_current_audio_input() const override { return 0; }
256
257 private:
258         void producer_thread_func();
259         void send_disconnected_frame();
260         bool play_video(const std::string &pathname);
261         void internal_rewind();
262
263         // Returns true if there was an error.
264         bool process_queued_commands(AVFormatContext *format_ctx, const std::string &pathname, timespec last_modified, bool *rewound);
265
266         // Returns nullptr if no frame was decoded (e.g. EOF).
267         AVFrameWithDeleter decode_frame(AVFormatContext *format_ctx, AVCodecContext *video_codec_ctx, AVCodecContext *audio_codec_ctx,
268                                         const std::string &pathname, int video_stream_index, int audio_stream_index, int subtitle_stream_index,
269                                         bmusb::FrameAllocator::Frame *audio_frame, bmusb::AudioFormat *audio_format, int64_t *audio_pts, bool *error);
270         void convert_audio(const AVFrame *audio_avframe, bmusb::FrameAllocator::Frame *audio_frame, bmusb::AudioFormat *audio_format);
271
272         bmusb::VideoFormat construct_video_format(const AVFrame *frame, AVRational video_timebase);
273         UniqueFrame make_video_frame(const AVFrame *frame, const std::string &pathname, bool *error);
274
275         static int interrupt_cb_thunk(void *opaque);
276         int interrupt_cb();
277
278 #ifdef HAVE_SRT
279         static int read_srt_thunk(void *opaque, uint8_t *buf, int buf_size);
280         int read_srt(uint8_t *buf, int buf_size);
281 #endif
282
283         inline unsigned frame_width(const AVFrame *frame) const;
284         inline unsigned frame_height(const AVFrame *frame) const;
285
286         mutable std::mutex filename_mu;
287         std::string description, filename;
288         int srt_sock = -1;
289         uint16_t timecode = 0;
290         unsigned width, height;  // 0 means keep input size.
291         bmusb::PixelFormat pixel_format = bmusb::PixelFormat_8BitBGRA;
292         movit::YCbCrFormat current_frame_ycbcr_format;
293         bool running = false;
294         int card_index = -1;
295         double rate = 1.0;
296         bool play_as_fast_as_possible = false;  // Activated iff rate >= 10.0.
297         std::atomic<bool> should_interrupt{false};
298         bool last_frame_was_connected = true;
299
300         // TODO: Replace with std::optional if we go C++17.
301         bool frame_timeout_valid = false;  // If true, will time out any reads after ten seconds.
302         std::chrono::steady_clock::time_point frame_timeout_started;  // Only relevant if frame_timeout_valid == true.
303
304         bool has_dequeue_callbacks = false;
305         std::function<void()> dequeue_init_callback = nullptr;
306         std::function<void()> dequeue_cleanup_callback = nullptr;
307
308         bmusb::card_disconnected_callback_t card_disconnected_callback = nullptr;
309         bool play_once = false;  // End thread after playing. Only for SRT, since the socket is ephemeral.
310         std::atomic<bool> disconnected{false};
311
312         bmusb::FrameAllocator *video_frame_allocator = nullptr;
313         bmusb::FrameAllocator *audio_frame_allocator = nullptr;
314         std::unique_ptr<bmusb::FrameAllocator> owned_video_frame_allocator;
315         std::unique_ptr<bmusb::FrameAllocator> owned_audio_frame_allocator;
316         frame_callback_t frame_callback = nullptr;
317         packet_callback_t video_callback = nullptr;
318         packet_callback_t audio_callback = nullptr;
319
320         SwsContextWithDeleter sws_ctx;
321         int sws_last_width = -1, sws_last_height = -1, sws_last_src_format = -1;
322         AVPixelFormat sws_dst_format = AVPixelFormat(-1);  // In practice, always initialized.
323         AVRational video_timebase, audio_timebase;
324         bool is_mjpeg = false;
325
326         QuittableSleeper producer_thread_should_quit;
327         std::thread producer_thread;
328
329         int64_t pts_origin, last_pts;
330         std::chrono::steady_clock::time_point start, next_frame_start, last_frame;
331
332         std::mutex queue_mu;
333         struct QueuedCommand {
334                 enum Command { REWIND, CHANGE_RATE } command;
335                 double new_rate;  // For CHANGE_RATE.
336         };
337         std::vector<QueuedCommand> command_queue;  // Protected by <queue_mu>.
338
339         // Audio resampler.
340         SwrContext *resampler = nullptr;
341         AVSampleFormat last_src_format, last_dst_format;
342         AVChannelLayout last_channel_layout;
343         int last_sample_rate;
344
345         // Subtitles (no decoding done, really).
346         bool has_last_subtitle = false;
347         std::string last_subtitle;
348
349         movit::RGBTriplet last_neutral_color{1.0f, 1.0f, 1.0f};
350
351         // Used for suppressing repeated warnings. Reset when a video starts playing.
352         // -1 is strictly speaking outside the range of the enum, but hopefully, it will be alright.
353         AVColorSpace last_colorspace = static_cast<AVColorSpace>(-1);
354         AVChromaLocation last_chroma_location = static_cast<AVChromaLocation>(-1);
355         QSurface *const surface;
356 };
357
358 #endif  // !defined(_FFMPEG_CAPTURE_H)