From 73ddb883aaf76a76d8c03730e587ac396255c0c9 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Fri, 14 Apr 2017 19:27:07 +0200 Subject: [PATCH] Support changing video files underway, just like images. --- ffmpeg_capture.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ ffmpeg_capture.h | 3 +-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/ffmpeg_capture.cpp b/ffmpeg_capture.cpp index e03382c..464b4cb 100644 --- a/ffmpeg_capture.cpp +++ b/ffmpeg_capture.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include extern "C" { @@ -44,6 +45,19 @@ steady_clock::time_point compute_frame_start(int64_t frame_pts, int64_t pts_orig return origin + duration_cast(pts / rate); } +bool changed_since(const std::string &pathname, const timespec &ts) +{ + if (ts.tv_sec < 0) { + return false; + } + struct stat buf; + if (stat(pathname.c_str(), &buf) != 0) { + fprintf(stderr, "%s: Couldn't check for new version, leaving the old in place.\n", pathname.c_str()); + return false; + } + return (buf.st_mtim.tv_sec != ts.tv_sec || buf.st_mtim.tv_nsec != ts.tv_nsec); +} + } // namespace FFmpegCapture::FFmpegCapture(const string &filename, unsigned width, unsigned height) @@ -142,6 +156,18 @@ void FFmpegCapture::producer_thread_func() bool FFmpegCapture::play_video(const string &pathname) { + // Note: Call before open, not after; otherwise, there's a race. + // (There is now, too, but it tips the correct way. We could use fstat() + // if we had the file descriptor.) + timespec last_modified; + struct stat buf; + if (stat(pathname.c_str(), &buf) != 0) { + // Probably some sort of protocol, so can't stat. + last_modified.tv_sec = -1; + } else { + last_modified = buf.st_mtim; + } + auto format_ctx = avformat_open_input_unique(pathname.c_str(), nullptr, nullptr); if (format_ctx == nullptr) { fprintf(stderr, "%s: Error opening file\n", pathname.c_str()); @@ -209,6 +235,13 @@ bool FFmpegCapture::play_video(const string &pathname) 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()); } + // If the file has changed since last time, return to get it reloaded. + // Note that depending on how you move the file into place, you might + // end up corrupting the one you're already playing, so this path + // might not trigger. + if (changed_since(pathname, last_modified)) { + return true; + } internal_rewind(); break; @@ -260,6 +293,13 @@ bool FFmpegCapture::play_video(const string &pathname) fprintf(stderr, "%s: Rewind failed, not looping.\n", pathname.c_str()); return true; } + // If the file has changed since last time, return to get it reloaded. + // Note that depending on how you move the file into place, you might + // end up corrupting the one you're already playing, so this path + // might not trigger. + if (changed_since(pathname, last_modified)) { + return true; + } internal_rewind(); continue; } diff --git a/ffmpeg_capture.h b/ffmpeg_capture.h index 0950782..3b2f0e4 100644 --- a/ffmpeg_capture.h +++ b/ffmpeg_capture.h @@ -17,8 +17,7 @@ // 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. // -// There is currently no audio support. There is also no support for changing -// the video underway (unlike images), although there really should be. +// There is currently no audio support. #include #include -- 2.39.2