// Main loop.
while (!producer_thread_should_quit) {
+ // Process any queued commands from other threads.
+ vector<QueuedCommand> commands;
+ {
+ lock_guard<mutex> lock(queue_mu);
+ swap(commands, command_queue);
+ }
+ for (const QueuedCommand &cmd : commands) {
+ if (cmd.command == QueuedCommand::REWIND) {
+ if (av_seek_frame(format_ctx.get(), /*stream_index=*/-1, /*timestamp=*/0, /*flags=*/0) < 0) {
+ fprintf(stderr, "%s: Rewind failed, stopping play.\n", pathname.c_str());
+ }
+ start = steady_clock::now();
+ continue;
+ }
+ }
+
// Read packets until we have a frame or there are none left.
int frame_finished = 0;
AVFrameWithDeleter frame = av_frame_alloc_unique();
#include <functional>
#include <map>
#include <memory>
+#include <mutex>
#include <set>
#include <string>
#include <thread>
return card_index;
}
+ void rewind()
+ {
+ std::lock_guard<std::mutex> lock(queue_mu);
+ command_queue.push_back(QueuedCommand { QueuedCommand::REWIND });
+ }
+
// CaptureInterface.
void set_video_frame_allocator(bmusb::FrameAllocator *allocator) override
{
std::atomic<bool> producer_thread_should_quit{false};
std::thread producer_thread;
+
+ std::mutex queue_mu;
+ struct QueuedCommand {
+ enum Command { REWIND } command;
+ };
+ std::vector<QueuedCommand> command_queue; // Protected by <queue_mu>.
};
#endif // !defined(_FFMPEG_CAPTURE_H)
return ret;
}
+int VideoInput_rewind(lua_State* L)
+{
+ assert(lua_gettop(L) == 1);
+ FFmpegCapture **video_input = (FFmpegCapture **)luaL_checkudata(L, 1, "VideoInput");
+ (*video_input)->rewind();
+ return 0;
+}
+
int WhiteBalanceEffect_new(lua_State* L)
{
assert(lua_gettop(L) == 0);
const luaL_Reg VideoInput_funcs[] = {
{ "new", VideoInput_new },
+ { "rewind", VideoInput_rewind },
{ NULL, NULL }
};