]> git.sesse.net Git - nageru/blobdiff - image_input.cpp
Add some asserts that will trigger if a driver gives very bogus fps values.
[nageru] / image_input.cpp
index 27c088d59c5b76f5ae8567fec58988bbba8882a1..9a63c1eda09ae93f96cc059328375411b1a3c1ec 100644 (file)
@@ -152,7 +152,7 @@ shared_ptr<const ImageInput::Image> ImageInput::load_image_raw(const string &fil
        unique_ptr<AVCodecContext, decltype(avcodec_close)*> codec_ctx_cleanup(
                codec_ctx, avcodec_close);
 
-       // Read packets until we have a frame.
+       // Read packets until we have a frame or there are none left.
        int frame_finished = 0;
        auto frame = av_frame_alloc_unique();
        do {
@@ -163,8 +163,7 @@ shared_ptr<const ImageInput::Image> ImageInput::load_image_raw(const string &fil
                pkt.data = nullptr;
                pkt.size = 0;
                if (av_read_frame(format_ctx.get(), &pkt) < 0) {
-                       fprintf(stderr, "%s: Cannot read frame\n", filename.c_str());
-                       return nullptr;
+                       break;
                }
                if (pkt.stream_index != stream_index) {
                        continue;
@@ -176,6 +175,21 @@ shared_ptr<const ImageInput::Image> ImageInput::load_image_raw(const string &fil
                }
        } while (!frame_finished);
 
+       // See if there's a cached frame for us.
+       if (!frame_finished) {
+               AVPacket pkt;
+               pkt.data = nullptr;
+               pkt.size = 0;
+               if (avcodec_decode_video2(codec_ctx, frame.get(), &frame_finished, &pkt) < 0) {
+                       fprintf(stderr, "%s: Cannot decode frame\n", filename.c_str());
+                       return nullptr;
+               }
+       }
+       if (!frame_finished) {
+               fprintf(stderr, "%s: Decoder did not output frame.\n", filename.c_str());
+               return nullptr;
+       }
+
        // TODO: Scale down if needed!
        uint8_t *pic_data[4] = {nullptr};
        unique_ptr<uint8_t *, decltype(av_freep)*> pic_data_cleanup(
@@ -206,7 +220,6 @@ shared_ptr<const ImageInput::Image> ImageInput::load_image_raw(const string &fil
 
 // Fire up a thread to update the image every second.
 // We could do inotify, but this is good enough for now.
-// TODO: These don't really quit, ever. Should they?
 void ImageInput::update_thread_func(const std::string &filename, const timespec &first_modified)
 {
        timespec last_modified = first_modified;
@@ -214,6 +227,10 @@ void ImageInput::update_thread_func(const std::string &filename, const timespec
        for ( ;; ) {
                sleep(1);
 
+               if (threads_should_quit) {
+                       return;
+               }
+
                if (stat(filename.c_str(), &buf) != 0) {
                        fprintf(stderr, "%s: Couldn't check for new version, leaving the old in place.\n", filename.c_str());
                        continue;
@@ -235,6 +252,17 @@ void ImageInput::update_thread_func(const std::string &filename, const timespec
        }
 }
 
+void ImageInput::shutdown_updaters()
+{
+       // TODO: Kick these out of the sleep before one second?
+       threads_should_quit = true;
+
+       for (auto &it : update_threads) {
+               it.second.join();
+       }
+}
+
 mutex ImageInput::all_images_lock;
 map<string, shared_ptr<const ImageInput::Image>> ImageInput::all_images;
 map<string, thread> ImageInput::update_threads;
+volatile bool ImageInput::threads_should_quit = false;