// Since we don't really know much about the video when building the chains,
// there are some limitations. In particular, frames are always assumed to be
// sRGB even if the video container says something else. We could probably
-// try to load the video on startup and pick out the parameters at that point
-// (which would probably also allow us to send Y'CbCr video through without
-// CPU conversion), but it would require some more plumbing, and it would also
-// fail if the file changes parameters midway, which is allowed in some formats.
+// try to load the video on startup and pick out the parameters at that point,
+// but it would require some more plumbing, and it would also fail if the file
+// changes parameters midway, which is allowed in some formats.
//
// There is currently no audio support.
#include <movit/ycbcr.h>
+extern "C" {
+#include <libavutil/pixfmt.h>
+#include <libavutil/rational.h>
+}
+
#include "bmusb/bmusb.h"
+#include "ffmpeg_raii.h"
#include "quittable_sleeper.h"
+struct AVFormatContext;
+struct AVFrame;
+struct AVRational;
+
class FFmpegCapture : public bmusb::CaptureInterface
{
public:
{
std::lock_guard<std::mutex> lock(queue_mu);
command_queue.push_back(QueuedCommand { QueuedCommand::REWIND });
+ producer_thread_should_quit.wakeup();
}
void change_rate(double new_rate)
{
std::lock_guard<std::mutex> lock(queue_mu);
command_queue.push_back(QueuedCommand { QueuedCommand::CHANGE_RATE, new_rate });
+ producer_thread_should_quit.wakeup();
}
// CaptureInterface.
bool play_video(const std::string &pathname);
void internal_rewind();
+ // Returns true if there was an error.
+ bool process_queued_commands(AVFormatContext *format_ctx, const std::string &pathname, timespec last_modified, bool *rewound);
+
+ // Returns nullptr if no frame was decoded (e.g. EOF).
+ AVFrameWithDeleter decode_frame(AVFormatContext *format_ctx, AVCodecContext *codec_ctx, const std::string &pathname, int video_stream_index, bool *error);
+
+ bmusb::VideoFormat construct_video_format(const AVFrame *frame, AVRational video_timebase);
+ bmusb::FrameAllocator::Frame make_video_frame(const AVFrame *frame, const std::string &pathname, bool *error);
+
std::string description, filename;
uint16_t timecode = 0;
unsigned width, height;
movit::YCbCrFormat current_frame_ycbcr_format;
bool running = false;
int card_index = -1;
+ double rate = 1.0;
bool has_dequeue_callbacks = false;
std::function<void()> dequeue_init_callback = nullptr;
std::unique_ptr<bmusb::FrameAllocator> owned_audio_frame_allocator;
bmusb::frame_callback_t frame_callback = nullptr;
+ SwsContextWithDeleter sws_ctx;
+ int sws_last_width = -1, sws_last_height = -1, sws_last_src_format = -1;
+ AVPixelFormat sws_dst_format = AVPixelFormat(-1); // In practice, always initialized.
+ AVRational video_timebase;
+
QuittableSleeper producer_thread_should_quit;
std::thread producer_thread;