]> git.sesse.net Git - casparcg/commitdiff
Simplified thumbnail creation, making it less intrusive in the frame_producer design.
authorHelge Norberg <helge.norberg@svt.se>
Tue, 1 Mar 2016 16:48:10 +0000 (17:48 +0100)
committerHelge Norberg <helge.norberg@svt.se>
Tue, 1 Mar 2016 16:48:10 +0000 (17:48 +0100)
core/producer/frame_producer.cpp
core/producer/frame_producer.h
core/producer/separated/separated_producer.cpp
core/thumbnail_generator.cpp
modules/ffmpeg/ffmpeg.cpp
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/ffmpeg_producer.h
modules/image/image.cpp
modules/image/producer/image_producer.cpp
modules/image/producer/image_producer.h

index fa458be4450e2408fbfcdf149f1712383ce936fd..2b78c61778998ba10c57bf77552893eb2a830224 100644 (file)
@@ -43,7 +43,7 @@ namespace caspar { namespace core {
 struct frame_producer_registry::impl
 {
        std::vector<producer_factory_t>         producer_factories;
-       std::vector<producer_factory_t>         thumbnail_factories;
+       std::vector<thumbnail_producer_t>       thumbnail_producers;
        spl::shared_ptr<help_repository>        help_repo;
 
        impl(spl::shared_ptr<help_repository> help_repo)
@@ -63,9 +63,9 @@ void frame_producer_registry::register_producer_factory(std::wstring name, const
        impl_->help_repo->register_item({ L"producer" }, std::move(name), describer);
 }
 
-void frame_producer_registry::register_thumbnail_producer_factory(const producer_factory_t& factory)
+void frame_producer_registry::register_thumbnail_producer(const thumbnail_producer_t& thumbnail_producer)
 {
-       impl_->thumbnail_factories.push_back(factory);
+       impl_->thumbnail_producers.push_back(thumbnail_producer);
 }
 
 frame_producer_dependencies::frame_producer_dependencies(
@@ -127,10 +127,6 @@ struct frame_producer_base::impl
        {
                return draw_frame::still(last_frame_);
        }
-       draw_frame create_thumbnail_frame()
-       {
-               return draw_frame::empty();
-       }
 };
 
 frame_producer_base::frame_producer_base() : impl_(new impl(*this))
@@ -151,10 +147,6 @@ draw_frame frame_producer_base::last_frame()
 {
        return impl_->last_frame();
 }
-draw_frame frame_producer_base::create_thumbnail_frame()
-{
-       return impl_->create_thumbnail_frame();
-}
 
 std::future<std::wstring> frame_producer_base::call(const std::vector<std::wstring>&) 
 {
@@ -201,7 +193,6 @@ const spl::shared_ptr<frame_producer>& frame_producer::empty()
                variable& get_variable(const std::wstring& name) override { CASPAR_THROW_EXCEPTION(not_implemented()); }
                const std::vector<std::wstring>& get_variables() const override { static std::vector<std::wstring> empty; return empty; }
                draw_frame last_frame() {return draw_frame::empty();}
-               draw_frame create_thumbnail_frame() {return draw_frame::empty();}
                constraints& pixel_constraints() override { static constraints c; return c; }
        
                boost::property_tree::wptree info() const override
@@ -292,7 +283,6 @@ public:
        void                                                                                            leading_producer(const spl::shared_ptr<frame_producer>& producer) override              {return producer_->leading_producer(producer);}
        uint32_t                                                                                        nb_frames() const override                                                                                                              {return producer_->nb_frames();}
        draw_frame                                                                                      last_frame()                                                                                                                                    {return producer_->last_frame();}
-       draw_frame                                                                                      create_thumbnail_frame()                                                                                                                {return producer_->create_thumbnail_frame();}
        monitor::subject&                                                                       monitor_output() override                                                                                                               {return producer_->monitor_output();}                                                                           
        bool                                                                                            collides(double x, double y) const override                                                                             {return producer_->collides(x, y);}
        void                                                                                            on_interaction(const interaction_event::ptr& event)     override                                        {return producer_->on_interaction(event);}
@@ -339,35 +329,38 @@ spl::shared_ptr<core::frame_producer> do_create_producer(const frame_producer_de
        return producer;
 }
 
-spl::shared_ptr<core::frame_producer> frame_producer_registry::create_thumbnail_producer(const frame_producer_dependencies& dependencies, const std::wstring& media_file) const
+draw_frame do_create_thumbnail_frame(
+               const frame_producer_dependencies& dependencies,
+               const std::wstring& media_file,
+               const std::vector<thumbnail_producer_t>& thumbnail_producers)
+{
+       for (auto& thumbnail_producer : thumbnail_producers)
+       {
+               auto frame = thumbnail_producer(dependencies, media_file);
+
+               if (frame != draw_frame::empty())
+                       return frame;
+       }
+
+       return draw_frame::empty();
+}
+
+draw_frame frame_producer_registry::create_thumbnail(const frame_producer_dependencies& dependencies, const std::wstring& media_file) const
 {
-       auto& thumbnail_factories = impl_->thumbnail_factories;
+       auto& thumbnail_producers = impl_->thumbnail_producers;
        std::vector<std::wstring> params;
        params.push_back(media_file);
 
-       auto producer = do_create_producer(dependencies, params, thumbnail_factories, true);
-       auto key_producer = frame_producer::empty();
-  
-       try // to find a key file.
-       {
-               auto params_copy = params;
-               if (params_copy.size() > 0)
-               {
-                       params_copy[0] += L"_A";
-                       key_producer = do_create_producer(dependencies, params_copy, thumbnail_factories, true);
-                       if (key_producer == frame_producer::empty())
-                       {
-                               params_copy[0] += L"LPHA";
-                               key_producer = do_create_producer(dependencies, params_copy, thumbnail_factories, true);
-                       }
-               }
-       }
-       catch(...){}
+       auto fill_frame = do_create_thumbnail_frame(dependencies, media_file, thumbnail_producers);
+       auto key_frame = do_create_thumbnail_frame(dependencies, media_file + L"_A", thumbnail_producers);
 
-       if (producer != frame_producer::empty() && key_producer != frame_producer::empty())
-               return create_separated_producer(producer, key_producer);
+       if (key_frame == draw_frame::empty())
+               key_frame = do_create_thumbnail_frame(dependencies, media_file + L"_ALPHA", thumbnail_producers);
   
-       return producer;
+       if (fill_frame != draw_frame::empty() && key_frame != draw_frame::empty())
+               return draw_frame::mask(fill_frame, key_frame);
+  
+       return fill_frame;
 }
 
 spl::shared_ptr<core::frame_producer> frame_producer_registry::create_producer(const frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params) const
index fff7186583380e72fbe6fef0088ddf10ab48276e..cf7fb402ac8f6a7e4d42a70b50d9e13a850301c8 100644 (file)
@@ -96,7 +96,6 @@ public:
        virtual uint32_t                                                        nb_frames() const = 0;
        virtual uint32_t                                                        frame_number() const = 0;
        virtual draw_frame                                                      last_frame() = 0;
-       virtual draw_frame                                                      create_thumbnail_frame() = 0;
        virtual constraints&                                            pixel_constraints() = 0;
        virtual void                                                            leading_producer(const spl::shared_ptr<frame_producer>&) {}  
 };
@@ -121,7 +120,6 @@ public:
        uint32_t                                        nb_frames() const override;
        uint32_t                                        frame_number() const override;
        virtual draw_frame                      last_frame() override;
-       virtual draw_frame                      create_thumbnail_frame() override;
 
 private:
        virtual draw_frame                      receive() override;
@@ -149,16 +147,17 @@ struct frame_producer_dependencies
 };
 
 typedef std::function<spl::shared_ptr<core::frame_producer>(const frame_producer_dependencies&, const std::vector<std::wstring>&)> producer_factory_t;
+typedef std::function<draw_frame (const frame_producer_dependencies&, const std::wstring&)> thumbnail_producer_t;
 
 class frame_producer_registry : boost::noncopyable
 {
 public:
        frame_producer_registry(spl::shared_ptr<help_repository> help_repo);
        void register_producer_factory(std::wstring name, const producer_factory_t& factory, const help_item_describer& describer); // Not thread-safe.
-       void register_thumbnail_producer_factory(const producer_factory_t& factory); // Not thread-safe.
+       void register_thumbnail_producer(const thumbnail_producer_t& thumbnail_producer); // Not thread-safe.
        spl::shared_ptr<core::frame_producer> create_producer(const frame_producer_dependencies&, const std::vector<std::wstring>& params) const;
        spl::shared_ptr<core::frame_producer> create_producer(const frame_producer_dependencies&, const std::wstring& params) const;
-       spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const frame_producer_dependencies&, const std::wstring& media_file) const;
+       draw_frame create_thumbnail(const frame_producer_dependencies&, const std::wstring& media_file) const;
 private:
        struct impl;
        spl::shared_ptr<impl> impl_;
index c376eb8e5a48f44e9bba49b67a1b7ca9fcd87c7b..ddcf2293161149d83511585499ef17b27e6fbe75 100644 (file)
@@ -88,20 +88,6 @@ public:
                return draw_frame::mask(fill_producer_->last_frame(), key_producer_->last_frame());
        }
 
-       draw_frame create_thumbnail_frame()
-       {
-               auto fill_frame = fill_producer_->create_thumbnail_frame();
-               auto key_frame = key_producer_->create_thumbnail_frame();
-
-               if (fill_frame == draw_frame::empty() || key_frame == draw_frame::empty())
-                       return draw_frame::empty();
-
-               if (fill_frame == draw_frame::late() || key_frame == draw_frame::late())
-                       return draw_frame::late();
-
-               return draw_frame::mask(fill_frame, key_frame);
-       }
-
        constraints& pixel_constraints() override
        {
                return fill_producer_->pixel_constraints();
index da39a75e1e3b4cb1aeb94b37e37134925cfbb2b1..a80702c8a9dcf62f765b0f1b415a9ae6d32bc3ae 100644 (file)
@@ -246,31 +246,6 @@ public:
                std::promise<void> thumbnail_ready;
 
                {
-                       auto producer = frame_producer::empty();
-
-                       try
-                       {
-                               producer = producer_registry_->create_thumbnail_producer(
-                                               frame_producer_dependencies(image_mixer_, { }, format_desc_, producer_registry_),
-                                               media_file.wstring());
-                       }
-                       catch (const boost::thread_interrupted&)
-                       {
-                               throw;
-                       }
-                       catch (...)
-                       {
-                               CASPAR_LOG_CURRENT_EXCEPTION_AT_LEVEL(trace);
-                               CASPAR_LOG(info) << L"Thumbnail producer failed to initialize for " << media_file_with_extension << L". Turn on log level trace to see more information.";
-                               return;
-                       }
-
-                       if (producer == frame_producer::empty())
-                       {
-                               CASPAR_LOG(debug) << L"No appropriate thumbnail producer found for " << media_file_with_extension;
-                               return;
-                       }
-
                        boost::filesystem::create_directories(png_file.parent_path());
                        output_->on_send = [this, &png_file] (const_frame frame)
                        {
@@ -282,7 +257,7 @@ public:
 
                        try
                        {
-                               raw_frame = producer->create_thumbnail_frame();
+                               raw_frame = producer_registry_->create_thumbnail(frame_producer_dependencies(image_mixer_, {}, format_desc_, producer_registry_), media_file.wstring());
                                media_info_repo_->remove(file.wstring());
                                media_info_repo_->get(file.wstring());
                        }
@@ -300,7 +275,7 @@ public:
                        if (raw_frame == draw_frame::empty()
                                        || raw_frame == draw_frame::late())
                        {
-                               CASPAR_LOG(debug) << L"No thumbnail generated for " << media_file_with_extension;
+                               CASPAR_LOG(debug) << L"No thumbnail producer for " << media_file_with_extension;
                                return;
                        }
 
index ca64f7baf9980cd4b6c255fda58f31a12f06e524..7d8159238c8cc0ed9f386f4c231f41ef64c556ca 100644 (file)
@@ -32,6 +32,7 @@
 #include <common/os/general_protection_fault.h>
 
 #include <core/consumer/frame_consumer.h>
+#include <core/frame/draw_frame.h>
 #include <core/producer/frame_producer.h>
 #include <core/producer/media_info/media_info.h>
 #include <core/producer/media_info/media_info_repository.h>
@@ -298,7 +299,7 @@ void init(core::module_dependencies dependencies)
        dependencies.consumer_registry->register_preconfigured_consumer_factory(L"file", create_preconfigured_consumer);
        dependencies.consumer_registry->register_preconfigured_consumer_factory(L"stream", create_preconfigured_streaming_consumer);
        dependencies.producer_registry->register_producer_factory(L"FFmpeg Producer", boost::bind(&create_producer, _1, _2, info_repo), describe_producer);
-       dependencies.producer_registry->register_thumbnail_producer_factory(boost::bind(&create_thumbnail_producer, _1, _2, info_repo));
+       dependencies.producer_registry->register_thumbnail_producer(boost::bind(&create_thumbnail_frame, _1, _2, info_repo));
 
        info_repo->register_extractor(
                        [](const std::wstring& file, const std::wstring& extension, core::media_info& info) -> bool
index aed7a41dc3d9748ea8bcc16d31e3c4b2c9be3257..fef7848777b3cfd0d07769142293e14113cb8f56 100644 (file)
@@ -237,74 +237,6 @@ public:
                return frame;
        }
 
-       core::draw_frame render_specific_frame(uint32_t file_position)
-       {
-               muxer_->clear();
-               input_.seek(file_position);
-
-               decode_next_frame();
-
-               if (muxer_->empty())
-               {
-                       CASPAR_LOG(trace) << print() << " Giving up finding frame at " << file_position;
-
-                       return core::draw_frame::empty();
-               }
-
-               auto frame = muxer_->front();
-               muxer_->pop();
-
-               return frame;
-       }
-
-       core::draw_frame create_thumbnail_frame() override
-       {
-               auto quiet_logging = temporary_enable_quiet_logging_for_thread(true);
-
-               auto total_frames = nb_frames();
-               auto grid = env::properties().get(L"configuration.thumbnails.video-grid", 2);
-
-               if (grid < 1)
-               {
-                       CASPAR_LOG(error) << L"configuration/thumbnails/video-grid cannot be less than 1";
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("configuration/thumbnails/video-grid cannot be less than 1"));
-               }
-
-               if (grid == 1)
-               {
-                       return render_specific_frame(total_frames / 2);
-               }
-
-               auto num_snapshots = grid * grid;
-
-               std::vector<core::draw_frame> frames;
-
-               for (int i = 0; i < num_snapshots; ++i)
-               {
-                       int x = i % grid;
-                       int y = i / grid;
-                       int desired_frame;
-
-                       if (i == 0)
-                               desired_frame = 0; // first
-                       else if (i == num_snapshots - 1)
-                               desired_frame = total_frames - 1; // last
-                       else
-                               // evenly distributed across the file.
-                               desired_frame = total_frames * i / (num_snapshots - 1);
-
-                       auto frame = render_specific_frame(desired_frame);
-                       frame.transform().image_transform.fill_scale[0] = 1.0 / static_cast<double>(grid);
-                       frame.transform().image_transform.fill_scale[1] = 1.0 / static_cast<double>(grid);
-                       frame.transform().image_transform.fill_translation[0] = 1.0 / static_cast<double>(grid) * x;
-                       frame.transform().image_transform.fill_translation[1] = 1.0 / static_cast<double>(grid) * y;
-
-                       frames.push_back(frame);
-               }
-
-               return core::draw_frame(frames);
-       }
-
        core::draw_frame last_frame() override
        {
                end_seek();
@@ -581,36 +513,80 @@ spl::shared_ptr<core::frame_producer> create_producer(
                        info)));
 }
 
-spl::shared_ptr<core::frame_producer> create_thumbnail_producer(
-               const core::frame_producer_dependencies& dependencies,
-               const std::vector<std::wstring>& params,
-               const spl::shared_ptr<core::media_info_repository>& info_repo)
+core::draw_frame create_thumbnail_frame(
+       const core::frame_producer_dependencies& dependencies,
+       const std::wstring& media_file,
+       const spl::shared_ptr<core::media_info_repository>& info_repo)
 {
        auto quiet_logging = temporary_enable_quiet_logging_for_thread(true);
-       auto filename = probe_stem(env::media_folder() + L"/" + params.at(0), true);
+       auto filename = probe_stem(env::media_folder() + L"/" + media_file, true);
 
-       if(filename.empty())
-               return core::frame_producer::empty();
-       
-       bool loop                       = false;
-       auto start                      = 0;
-       auto length                     = std::numeric_limits<uint32_t>::max();
-       auto filter_str         = L"";
-       auto channel_layout     = L"";
-       bool thumbnail_mode     = true;
-       auto info                       = info_repo->get(filename);
+       if (filename.empty())
+               return core::draw_frame::empty();
 
-       return spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
-                       dependencies.frame_factory,
-                       dependencies.format_desc,
-                       channel_layout,
-                       filename,
-                       filter_str,
-                       loop,
-                       start,
-                       length,
-                       thumbnail_mode,
-                       info));
+       auto render_specific_frame = [&](std::int64_t frame_num)
+       {
+               spl::shared_ptr<core::frame_producer> producer = spl::make_shared<ffmpeg_producer>(
+                               dependencies.frame_factory,
+                               dependencies.format_desc,
+                               L"",
+                               filename,
+                               L"",
+                               false,
+                               static_cast<uint32_t>(frame_num),
+                               std::numeric_limits<uint32_t>::max(),
+                               true,
+                               info_repo->get(filename));
+               return producer->receive();
+       };
+
+       auto info = info_repo->get(filename);
+
+       if (!info)
+               return core::draw_frame::empty();
+
+       auto total_frames = info->duration;
+       auto grid = env::properties().get(L"configuration.thumbnails.video-grid", 2);
+
+       if (grid < 1)
+       {
+               CASPAR_LOG(error) << L"configuration/thumbnails/video-grid cannot be less than 1";
+               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("configuration/thumbnails/video-grid cannot be less than 1"));
+       }
+
+       if (grid == 1)
+       {
+               return render_specific_frame(total_frames / 2);
+       }
+
+       auto num_snapshots = grid * grid;
+
+       std::vector<core::draw_frame> frames;
+
+       for (int i = 0; i < num_snapshots; ++i)
+       {
+               int x = i % grid;
+               int y = i / grid;
+               std::int64_t desired_frame;
+
+               if (i == 0)
+                       desired_frame = 0; // first
+               else if (i == num_snapshots - 1)
+                       desired_frame = total_frames - 30; // last
+               else
+                       // evenly distributed across the file.
+                       desired_frame = total_frames * i / (num_snapshots - 1);
+
+               auto frame = render_specific_frame(desired_frame);
+               frame.transform().image_transform.fill_scale[0] = 1.0 / static_cast<double>(grid);
+               frame.transform().image_transform.fill_scale[1] = 1.0 / static_cast<double>(grid);
+               frame.transform().image_transform.fill_translation[0] = 1.0 / static_cast<double>(grid) * x;
+               frame.transform().image_transform.fill_translation[1] = 1.0 / static_cast<double>(grid) * y;
+
+               frames.push_back(frame);
+       }
+
+       return core::draw_frame(frames);
 }
 
 }}
index a197be16b59312ab533ddabac4401d12da6c671c..78a1e75d80b0831ddaa396860c440053bbaf5790 100644 (file)
@@ -35,9 +35,9 @@ spl::shared_ptr<core::frame_producer> create_producer(
                const core::frame_producer_dependencies& dependencies,
                const std::vector<std::wstring>& params,
                const spl::shared_ptr<core::media_info_repository>& info_repo);
-spl::shared_ptr<core::frame_producer> create_thumbnail_producer(
+core::draw_frame create_thumbnail_frame(
                const core::frame_producer_dependencies& dependencies,
-               const std::vector<std::wstring>& params,
+               const std::wstring& media_file,
                const spl::shared_ptr<core::media_info_repository>& info_repo);
 
 }}
\ No newline at end of file
index ea27ca9cec25e2199293155ec29370656636fa3d..a03b01e24a32f952160ddec93e3fe777b238a3a2 100644 (file)
@@ -29,6 +29,7 @@
 #include <core/consumer/frame_consumer.h>
 #include <core/producer/media_info/media_info.h>
 #include <core/producer/media_info/media_info_repository.h>
+#include <core/frame/draw_frame.h>
 #include <core/system_info_provider.h>
 
 #include <common/utf.h>
@@ -49,7 +50,7 @@ void init(core::module_dependencies dependencies)
        FreeImage_Initialise();
        dependencies.producer_registry->register_producer_factory(L"Image Scroll Producer", create_scroll_producer, describe_scroll_producer);
        dependencies.producer_registry->register_producer_factory(L"Image Producer", create_producer, describe_producer);
-       dependencies.producer_registry->register_thumbnail_producer_factory(create_thumbnail_producer);
+       dependencies.producer_registry->register_thumbnail_producer(create_thumbnail);
        dependencies.consumer_registry->register_consumer_factory(L"Image Consumer", create_consumer, describe_consumer);
        dependencies.media_info_repo->register_extractor([](const std::wstring& file, const std::wstring& extension, core::media_info& info)
        {
index 70902fd1ddd3eb5bd78ba2d2c233bc65cc433f64..0da1a981c39e69ec3efdf7093db789262eadf51b 100644 (file)
@@ -126,11 +126,6 @@ struct image_producer : public core::frame_producer_base
                return frame_;
        }
 
-       core::draw_frame create_thumbnail_frame() override
-       {
-               return frame_;
-       }
-
        core::constraints& pixel_constraints() override
        {
                return constraints_;
@@ -277,9 +272,9 @@ spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer
 }
 
 
-spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
+core::draw_frame create_thumbnail(const core::frame_producer_dependencies& dependencies, const std::wstring& media_file)
 {
-       std::wstring filename = env::media_folder() + params.at(0);
+       std::wstring filename = env::media_folder() + media_file;
 
        auto ext = std::find_if(g_extensions.begin(), g_extensions.end(), [&](const std::wstring& ex) -> bool
        {
@@ -289,9 +284,14 @@ spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const core::fram
        });
 
        if (ext == g_extensions.end())
-               return core::frame_producer::empty();
+               return core::draw_frame::empty();
 
-       return spl::make_shared<image_producer>(dependencies.frame_factory, *caspar::find_case_insensitive(filename + *ext), true);
+       spl::shared_ptr<core::frame_producer> producer = spl::make_shared<image_producer>(
+                       dependencies.frame_factory,
+                       *caspar::find_case_insensitive(filename + *ext),
+                       true);
+       
+       return producer->receive();
 }
 
 }}
index d60de6315f59eb616fb0620624ea0105d92892ec..eb5af7d29241fca41fdf7693dc2356eb59d9047b 100644 (file)
@@ -30,6 +30,6 @@ namespace caspar { namespace image {
 
 void describe_producer(core::help_sink& sink, const core::help_repository& repo);
 spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
+core::draw_frame create_thumbnail(const core::frame_producer_dependencies& dependencies, const std::wstring& media_file);
 
 }}
\ No newline at end of file