]> git.sesse.net Git - casparcg/commitdiff
Moved framerate calculation from CLS/CINF to thumbnail generation time for each file...
authorHelge Norberg <helge.norberg@gmail.com>
Wed, 13 Nov 2013 15:51:33 +0000 (16:51 +0100)
committerHelge Norberg <helge.norberg@gmail.com>
Wed, 13 Nov 2013 15:51:33 +0000 (16:51 +0100)
22 files changed:
core/core.vcxproj
core/core.vcxproj.filters
core/producer/frame_producer.cpp
core/producer/frame_producer.h
core/producer/media_info/file_based_media_info_repository.cpp [new file with mode: 0644]
core/producer/media_info/file_based_media_info_repository.h [new file with mode: 0644]
core/producer/media_info/media_info.h [new file with mode: 0644]
core/producer/media_info/media_info_repository.h [new file with mode: 0644]
core/producer/separated/separated_producer.cpp
core/thumbnail_generator.cpp
core/thumbnail_generator.h
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/util/util.cpp
modules/ffmpeg/producer/util/util.h
modules/image/producer/image_producer.cpp
protocol/amcp/AMCPCommand.h
protocol/amcp/AMCPCommandsImpl.cpp
protocol/amcp/AMCPProtocolStrategy.cpp
protocol/amcp/AMCPProtocolStrategy.h
shell/main.cpp
shell/server.cpp
shell/server.h

index 21cf3bf12783378a94f2ceec91d734af68b94d6d..93b8c4f6c5bb7ce7e75b674bd6cc377d079c1e69 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>\r
+<?xml version="1.0" encoding="utf-8"?>\r
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
   <ItemGroup Label="ProjectConfigurations">\r
     <ProjectConfiguration Include="Profile|Win32">\r
     <ClInclude Include="parameters\parameters.h" />\r
     <ClInclude Include="monitor\monitor.h" />\r
     <ClInclude Include="producer\channel\channel_producer.h" />\r
+    <ClInclude Include="producer\media_info\file_based_media_info_repository.h" />\r
+    <ClInclude Include="producer\media_info\media_info.h" />\r
+    <ClInclude Include="producer\media_info\media_info_repository.h" />\r
     <ClInclude Include="thumbnail_generator.h" />\r
     <ClInclude Include="producer\layer\layer_producer.h" />\r
     <ClInclude Include="video_channel.h" />\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
+    <ClCompile Include="producer\media_info\file_based_media_info_repository.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
     <ClCompile Include="thumbnail_generator.cpp" />\r
     <ClCompile Include="producer\layer\layer_producer.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
index 324ed653271263c03ae22639cfae3b5844764902..ef11a28bfb0ac60f8e5a13db0ef01b902ffbb707 100644 (file)
@@ -52,6 +52,9 @@
     <Filter Include="source\parameters">\r
       <UniqueIdentifier>{d04737a6-96b2-40cd-b1e7-e90b69006cd1}</UniqueIdentifier>\r
     </Filter>\r
+    <Filter Include="source\producer\media_info">\r
+      <UniqueIdentifier>{7c832327-1c6a-4538-8ce8-553de2c4b5f0}</UniqueIdentifier>\r
+    </Filter>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="producer\transition\transition_producer.h">\r
     <ClInclude Include="parameters\parameters.h">\r
       <Filter>source\parameters</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="producer\media_info\media_info.h">\r
+      <Filter>source\producer\media_info</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="producer\media_info\media_info_repository.h">\r
+      <Filter>source\producer\media_info</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="producer\media_info\file_based_media_info_repository.h">\r
+      <Filter>source\producer\media_info</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="producer\transition\transition_producer.cpp">\r
     <ClCompile Include="parameters\parameters.cpp">\r
       <Filter>source\parameters</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="producer\media_info\file_based_media_info_repository.cpp">\r
+      <Filter>source\producer\media_info</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 7abaf1401b34e961bd3b3f7c2df5ba7dbdd0e818..06a34a841264efa97b14061cd847d5628880103b 100644 (file)
@@ -29,6 +29,7 @@
 \r
 #include "color/color_producer.h"\r
 #include "separated/separated_producer.h"\r
+#include "media_info/media_info.h"\r
 \r
 #include <common/memory/safe_ptr.h>\r
 #include <common/concurrency/executor.h>\r
@@ -132,7 +133,7 @@ public:
 \r
        virtual safe_ptr<basic_frame>                                                           receive(int hints) override                                                                                             {return (*producer_)->receive(hints);}\r
        virtual safe_ptr<basic_frame>                                                           last_frame() const override                                                                                             {return (*producer_)->last_frame();}\r
-       virtual safe_ptr<basic_frame>                                                           create_thumbnail_frame() override                                                                               {return (*producer_)->create_thumbnail_frame();}\r
+       virtual safe_ptr<basic_frame>                                                           create_thumbnail_frame(media_info& additional_info) override                    {return (*producer_)->create_thumbnail_frame(additional_info);}\r
        virtual std::wstring                                                                            print() const override                                                                                                  {return (*producer_)->print();}\r
        virtual boost::property_tree::wptree                                            info() const override                                                                                                   {return (*producer_)->info();}\r
        virtual boost::unique_future<std::wstring>                                      call(const std::wstring& str) override                                                                  {return (*producer_)->call(str);}\r
@@ -167,7 +168,7 @@ public:
 \r
        virtual safe_ptr<basic_frame>                                                           receive(int hints) override                                                                                             {return (producer_)->receive(hints);}\r
        virtual safe_ptr<basic_frame>                                                           last_frame() const override                                                                                             {return (producer_)->last_frame();}\r
-       virtual safe_ptr<basic_frame>                                                           create_thumbnail_frame() override                                                                               {return (producer_)->create_thumbnail_frame();}\r
+       virtual safe_ptr<basic_frame>                                                           create_thumbnail_frame(media_info& additional_info) override                    {return (producer_)->create_thumbnail_frame(additional_info);}\r
        virtual std::wstring                                                                            print() const override                                                                                                  {return (producer_)->print();}\r
        virtual boost::property_tree::wptree                                            info() const override                                                                                                   {return (producer_)->info();}\r
        virtual boost::unique_future<std::wstring>                                      call(const std::wstring& str) override                                                                  {return (producer_)->call(str);}\r
@@ -197,7 +198,7 @@ public:
        \r
        virtual safe_ptr<basic_frame> receive(int){return frame_;}\r
        virtual safe_ptr<core::basic_frame> last_frame() const{return frame_;}\r
-       virtual safe_ptr<core::basic_frame> create_thumbnail_frame() {return frame_;}\r
+       virtual safe_ptr<core::basic_frame> create_thumbnail_frame(media_info&) {return frame_;}\r
        virtual std::wstring print() const{return L"dummy[" + print_ + L"]";}\r
        virtual uint32_t nb_frames() const {return nb_frames_;} \r
        virtual boost::property_tree::wptree info() const override\r
@@ -241,7 +242,7 @@ const safe_ptr<frame_producer>& frame_producer::empty() // nothrow
        return producer;\r
 }\r
 \r
-safe_ptr<basic_frame> frame_producer::create_thumbnail_frame()\r
+safe_ptr<basic_frame> frame_producer::create_thumbnail_frame(media_info&)\r
 {\r
        return basic_frame::empty();\r
 }\r
index c7d62b35be5fd8489259777f4121db0cab2c9818..c13e30fdc481f1df32f8377142c264a4ae000484 100644 (file)
@@ -47,6 +47,7 @@ namespace core {
 class basic_frame;\r
 class parameters;\r
 struct frame_factory;\r
+struct media_info;\r
 \r
 struct frame_producer : boost::noncopyable\r
 {\r
@@ -75,7 +76,7 @@ public:
        \r
        virtual safe_ptr<basic_frame> receive(int hints) = 0;\r
        virtual safe_ptr<core::basic_frame> last_frame() const = 0;\r
-       virtual safe_ptr<basic_frame> create_thumbnail_frame();\r
+       virtual safe_ptr<basic_frame> create_thumbnail_frame(media_info& additional_info);\r
 \r
        static const safe_ptr<frame_producer>& empty(); // nothrow\r
 \r
diff --git a/core/producer/media_info/file_based_media_info_repository.cpp b/core/producer/media_info/file_based_media_info_repository.cpp
new file mode 100644 (file)
index 0000000..69b0e1d
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#include "../../StdAfx.h"
+
+#include "file_based_media_info_repository.h"
+
+#include <fstream>
+#include <vector>
+
+#include <boost/thread/mutex.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+#include <boost/filesystem.hpp>
+
+#include "media_info.h"
+#include "media_info_repository.h"
+
+namespace {
+
+static const std::wstring delimeter = L",";
+
+std::map<std::wstring, caspar::core::media_info> load(
+               const std::wstring& csv_file)
+{
+       std::map<std::wstring, caspar::core::media_info> result;
+       std::wifstream stream(csv_file);
+
+       if (!stream)
+               return result;
+
+       wchar_t line[1024];
+
+       while (stream.getline(line, 1024))
+       {
+               std::vector<std::wstring> cells;
+               boost::split(
+                               cells,
+                               line,
+                               boost::is_any_of(delimeter),
+                               boost::token_compress_on);
+
+               if (cells.size() != 4)
+                       continue;
+
+               auto filename = cells.at(0);
+               caspar::core::media_info info;
+
+               try
+               {
+                       info.duration = boost::lexical_cast<int64_t>(cells.at(1));
+                       info.time_base = boost::rational<int64_t>(
+                                       boost::lexical_cast<int64_t>(cells.at(2)),
+                                       boost::lexical_cast<int64_t>(cells.at(3)));
+               }
+               catch (const boost::bad_lexical_cast&)
+               {
+                       continue;
+               }
+
+               result.insert(std::make_pair(std::move(filename), std::move(info)));
+       }
+
+       return result;
+}
+
+void save(
+               const std::map<std::wstring, caspar::core::media_info>& infos,
+               const std::wstring& csv_file)
+{
+       std::wstring tmp_file = csv_file + L".tmp";
+       std::wofstream stream(tmp_file, std::ios::trunc);
+
+       if (!stream)
+               throw std::exception();
+
+       BOOST_FOREACH(const auto& info, infos)
+       {
+               stream
+                       << info.first << delimeter
+                       << info.second.duration << delimeter
+                       << info.second.time_base.numerator() << delimeter
+                       << info.second.time_base.denominator() << L"\n";
+       }
+
+       stream << std::flush;
+       stream.close();
+       
+       // The remove is unfortunately needed by the current version of boost.
+       boost::filesystem::remove(csv_file);
+       boost::filesystem::rename(tmp_file, csv_file);
+}
+
+}
+
+namespace caspar { namespace core {
+
+class file_based_media_info_repository : public media_info_repository
+{
+       mutable boost::mutex mutex_;
+       std::wstring csv_file_;
+       std::map<std::wstring, media_info> info_by_media_file_;
+public:
+       file_based_media_info_repository(std::wstring csv_file)
+               : csv_file_(std::move(csv_file))
+               , info_by_media_file_(load(csv_file_))
+       {
+       }
+       
+       virtual void store(std::wstring media_file, media_info info) override
+       {
+               boost::mutex::scoped_lock lock(mutex_);
+
+               info_by_media_file_[std::move(media_file)] = info;
+
+               save(info_by_media_file_, csv_file_);
+       }
+       
+       virtual bool try_load(
+                       const std::wstring& media_file, media_info& info) const override
+       {
+               boost::mutex::scoped_lock lock(mutex_);
+
+               auto iter = info_by_media_file_.find(media_file);
+
+               if (iter == info_by_media_file_.end())
+                       return false;
+
+               info = iter->second;
+
+               return true;
+       }
+
+       virtual void remove(const std::wstring& media_file) override
+       {
+               boost::mutex::scoped_lock lock(mutex_);
+
+               info_by_media_file_.erase(media_file);
+
+               save(info_by_media_file_, csv_file_);
+       }
+};
+
+safe_ptr<struct media_info_repository> create_file_based_media_info_repository(
+               std::wstring csv_file)
+{
+       return make_safe<file_based_media_info_repository>(std::move(csv_file));
+}
+
+}}
diff --git a/core/producer/media_info/file_based_media_info_repository.h b/core/producer/media_info/file_based_media_info_repository.h
new file mode 100644 (file)
index 0000000..8b8297c
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#pragma once
+
+#include <string>
+
+#include <common/memory/safe_ptr.h>
+
+namespace caspar { namespace core {
+
+safe_ptr<struct media_info_repository> create_file_based_media_info_repository(
+               std::wstring csv_file);
+
+}}
diff --git a/core/producer/media_info/media_info.h b/core/producer/media_info/media_info.h
new file mode 100644 (file)
index 0000000..0c110ef
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#pragma once
+
+#include <cstdint>
+
+#include <boost/rational.hpp>
+
+namespace caspar { namespace core {
+
+struct media_info
+{
+       std::int64_t duration;
+       boost::rational<std::int64_t> time_base;
+
+       media_info()
+               : duration(0)
+       {
+       }
+};
+
+}}
diff --git a/core/producer/media_info/media_info_repository.h b/core/producer/media_info/media_info_repository.h
new file mode 100644 (file)
index 0000000..c9b93df
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#pragma once
+
+#include <string>
+
+namespace caspar { namespace core {
+
+struct media_info;
+
+struct media_info_repository
+{
+       virtual ~media_info_repository() { }
+       virtual void store(std::wstring media_file, media_info info) = 0;
+       virtual bool try_load(
+                       const std::wstring& media_file, media_info& info) const = 0;
+       virtual void remove(const std::wstring& media_file) = 0;
+};
+
+}}
index f6fba18ae2957038eebe907442af9b9b3982bb2e..816ae8abe3feb80c1ce58e60d29a4c46172bead3 100644 (file)
@@ -26,6 +26,7 @@
 #include "separated_producer.h"\r
 \r
 #include <core/producer/frame/basic_frame.h>\r
+#include <core/producer/media_info/media_info.h>\r
 \r
 #include <tbb/parallel_invoke.h>\r
 \r
@@ -91,10 +92,11 @@ struct separated_producer : public frame_producer
                return disable_audio(last_frame_);\r
        }\r
 \r
-       virtual safe_ptr<basic_frame> create_thumbnail_frame() override\r
+       virtual safe_ptr<basic_frame> create_thumbnail_frame(media_info& additional_info) override\r
        {\r
-               auto fill_frame = fill_producer_->create_thumbnail_frame();\r
-               auto key_frame = key_producer_->create_thumbnail_frame();\r
+               auto fill_frame = fill_producer_->create_thumbnail_frame(additional_info);\r
+               media_info dummy;\r
+               auto key_frame = key_producer_->create_thumbnail_frame(dummy);\r
 \r
                if (fill_frame == basic_frame::empty() || key_frame == basic_frame::empty())\r
                        return basic_frame::empty();\r
index ba832de9758b28eaf90ed04d2ca0dca1a39cf583..cea2593e95a4bfd5d9156183255db68cd20408b8 100644 (file)
@@ -40,6 +40,8 @@
 #include "video_format.h"\r
 #include "producer/frame/basic_frame.h"\r
 #include "producer/frame/frame_transform.h"\r
+#include "producer/media_info/media_info.h"\r
+#include "producer/media_info/media_info_repository.h"\r
 \r
 namespace caspar { namespace core {\r
 \r
@@ -102,6 +104,7 @@ private:
        safe_ptr<thumbnail_output> output_;\r
        safe_ptr<mixer> mixer_;\r
        thumbnail_creator thumbnail_creator_;\r
+       safe_ptr<media_info_repository> media_info_repo_;\r
        filesystem_monitor::ptr monitor_;\r
 public:\r
        implementation(\r
@@ -113,7 +116,8 @@ public:
                        const video_format_desc& render_video_mode,\r
                        const safe_ptr<ogl_device>& ogl,\r
                        int generate_delay_millis,\r
-                       const thumbnail_creator& thumbnail_creator)\r
+                       const thumbnail_creator& thumbnail_creator,\r
+                       safe_ptr<media_info_repository> media_info_repo)\r
                : media_path_(media_path)\r
                , thumbnails_path_(thumbnails_path)\r
                , width_(width)\r
@@ -128,6 +132,7 @@ public:
                                ogl,\r
                                channel_layout::stereo()))\r
                , thumbnail_creator_(thumbnail_creator)\r
+               , media_info_repo_(std::move(media_info_repo))\r
                , monitor_(monitor_factory.create(\r
                                media_path,\r
                                ALL,\r
@@ -172,7 +177,7 @@ public:
                                        == relative_without_extensions.end();\r
 \r
                        if (no_corresponding_media_file)\r
-                               remove(thumbnails_path_ / (relative_without_extension + L".png"));\r
+                               remove_thumbnail(relative_without_extension);\r
                }\r
        }\r
 \r
@@ -210,13 +215,18 @@ public:
 \r
                        break;\r
                case REMOVED:\r
-                       auto relative_without_extension = get_relative_without_extension(file, media_path_);\r
-                       boost::filesystem::remove(thumbnails_path_ / (relative_without_extension + L".png"));\r
+                       remove_thumbnail(get_relative_without_extension(file, media_path_));\r
 \r
                        break;\r
                }\r
        }\r
 \r
+       void remove_thumbnail(const std::wstring& relative_without_extension)\r
+       {\r
+               boost::filesystem::remove(thumbnails_path_ / (relative_without_extension + L".png"));\r
+               media_info_repo_->remove(relative_without_extension);\r
+       }\r
+\r
        bool needs_to_be_generated(const boost::filesystem::wpath& file)\r
        {\r
                using namespace boost::filesystem;\r
@@ -286,10 +296,12 @@ public:
 \r
                        std::map<int, safe_ptr<basic_frame>> frames;\r
                        auto raw_frame = basic_frame::empty();\r
+                       media_info additional_info;\r
 \r
                        try\r
                        {\r
-                               raw_frame = producer->create_thumbnail_frame();\r
+                               raw_frame = producer->create_thumbnail_frame(additional_info);\r
+                               media_info_repo_->store(media_file, additional_info);\r
                        }\r
                        catch (const boost::thread_interrupted&)\r
                        {\r
@@ -352,7 +364,8 @@ thumbnail_generator::thumbnail_generator(
                const video_format_desc& render_video_mode,\r
                const safe_ptr<ogl_device>& ogl,\r
                int generate_delay_millis,\r
-               const thumbnail_creator& thumbnail_creator)\r
+               const thumbnail_creator& thumbnail_creator,\r
+               safe_ptr<media_info_repository> media_info_repo)\r
                : impl_(new implementation(\r
                                monitor_factory,\r
                                media_path,\r
@@ -361,7 +374,8 @@ thumbnail_generator::thumbnail_generator(
                                render_video_mode,\r
                                ogl,\r
                                generate_delay_millis,\r
-                               thumbnail_creator))\r
+                               thumbnail_creator,\r
+                               media_info_repo))\r
 {\r
 }\r
 \r
index 80d954e2d724bedf833325c9af22d966d827ac86..27e1c8c828716277139d618dfbf3c8795451c2fe 100644 (file)
@@ -31,6 +31,7 @@ namespace caspar { namespace core {
 class ogl_device;\r
 class read_frame;\r
 struct video_format_desc;\r
+struct media_info_repository;\r
 \r
 typedef std::function<void (\r
                const safe_ptr<read_frame>& frame,\r
@@ -51,7 +52,8 @@ public:
                        const video_format_desc& render_video_mode,\r
                        const safe_ptr<ogl_device>& ogl,\r
                        int generate_delay_millis,\r
-                       const thumbnail_creator& thumbnail_creator);\r
+                       const thumbnail_creator& thumbnail_creator,\r
+                       safe_ptr<media_info_repository> media_info_repo);\r
        ~thumbnail_generator();\r
        void generate(const std::wstring& media_file);\r
        void generate_all();\r
index ebee33313a0f7045eac3f8428f52d071f1eecd51..6e24d80345cab997421d6f081ddf699a370a8fe5 100644 (file)
@@ -44,6 +44,7 @@
 #include <core/producer/frame/frame_factory.h>\r
 #include <core/producer/frame/basic_frame.h>\r
 #include <core/producer/frame/frame_transform.h>\r
+#include <core/producer/media_info/media_info.h>\r
 \r
 #include <boost/algorithm/string.hpp>\r
 #include <boost/assign.hpp>\r
@@ -301,12 +302,15 @@ public:
                return core::basic_frame::empty();\r
        }\r
 \r
-       virtual safe_ptr<core::basic_frame> create_thumbnail_frame() override\r
+       virtual safe_ptr<core::basic_frame> create_thumbnail_frame(core::media_info& additional_info) override\r
        {\r
                auto disable_logging = temporary_disable_logging_for_thread(thumbnail_mode_);\r
+\r
                auto total_frames = nb_frames();\r
                auto grid = env::properties().get(L"configuration.thumbnails.video-grid", 2);\r
 \r
+               try_get_duration(*input_.context(), additional_info.duration, additional_info.time_base);\r
+\r
                if (grid < 1)\r
                {\r
                        CASPAR_LOG(error) << L"configuration/thumbnails/video-grid cannot be less than 1";\r
index 92fd8c7f0e29ed4e5aac086782acf16d9e5dea14..4ebdba65572c3dd584208c7af336dfbe0addb49e 100644 (file)
@@ -473,6 +473,21 @@ bool is_valid_file(const std::wstring filename)
        return is_valid_file(filename, invalid_exts);\r
 }\r
 \r
+bool try_get_duration(AVFormatContext& context, std::int64_t& duration, boost::rational<std::int64_t>& time_base)\r
+{              \r
+       const auto fps = read_fps(context, 1.0);\r
+       const auto rational_fps = boost::rational<std::int64_t>(static_cast<int>(fps * AV_TIME_BASE), AV_TIME_BASE);\r
+       \r
+       duration = boost::rational_cast<std::int64_t>(context.duration * rational_fps / AV_TIME_BASE);\r
+\r
+       if (rational_fps == 0)\r
+               return false;\r
+\r
+       time_base = 1/rational_fps;\r
+\r
+       return true;\r
+}\r
+\r
 bool try_get_duration(const std::wstring filename, std::int64_t& duration, boost::rational<std::int64_t>& time_base)\r
 {              \r
        AVFormatContext* weak_context = nullptr;\r
@@ -480,25 +495,14 @@ bool try_get_duration(const std::wstring filename, std::int64_t& duration, boost
                return false;\r
 \r
        std::shared_ptr<AVFormatContext> context(weak_context, av_close_input_file);\r
-       \r
+\r
        context->probesize = context->probesize / 10;\r
        context->max_analyze_duration = context->probesize / 10;\r
 \r
        if(avformat_find_stream_info(context.get(), nullptr) < 0)\r
                return false;\r
-\r
-       const auto fps = read_fps(*context, 1.0);\r
-               \r
-       const auto rational_fps = boost::rational<std::int64_t>(static_cast<int>(fps * AV_TIME_BASE), AV_TIME_BASE);\r
        \r
-       duration = boost::rational_cast<std::int64_t>(context->duration * rational_fps / AV_TIME_BASE);\r
-\r
-       if (rational_fps == 0)\r
-               return false;\r
-\r
-       time_base = 1/rational_fps;\r
-\r
-       return true;\r
+       return try_get_duration(*context, duration, time_base);\r
 }\r
 \r
 std::wstring probe_stem(const std::wstring stem, const std::vector<std::wstring>& invalid_exts)\r
index 2e0f4c0384ba49e38bcdd700496051af1083e813..27b98d792284e07924d884b060c61056fef1020f 100644 (file)
@@ -82,6 +82,7 @@ std::wstring probe_stem(const std::wstring stem, const std::vector<std::wstring>
 std::wstring probe_stem(const std::wstring stem);\r
 bool is_valid_file(const std::wstring filename, const std::vector<std::wstring>& invalid_exts);\r
 bool is_valid_file(const std::wstring filename);\r
+bool try_get_duration(AVFormatContext& context, std::int64_t& duration, boost::rational<std::int64_t>& time_base);\r
 bool try_get_duration(const std::wstring filename, std::int64_t& duration, boost::rational<std::int64_t>& time_base);\r
 \r
 core::channel_layout get_audio_channel_layout(const AVCodecContext& context, const std::wstring& custom_channel_order);\r
index a7ac767628ef5bfddb15e9cbb27bd5c324996be6..2ccb765b0d3f2cc2af1bc4166ee2bc29942f8717 100644 (file)
@@ -29,6 +29,7 @@
 #include <core/monitor/monitor.h>\r
 #include <core/producer/frame/basic_frame.h>\r
 #include <core/producer/frame/frame_factory.h>\r
+#include <core/producer/media_info/media_info.h>\r
 #include <core/mixer/write_frame.h>\r
 \r
 #include <common/env.h>\r
@@ -96,7 +97,7 @@ struct image_producer : public core::frame_producer
                return frame_;\r
        }\r
 \r
-       virtual safe_ptr<core::basic_frame> create_thumbnail_frame() override\r
+       virtual safe_ptr<core::basic_frame> create_thumbnail_frame(core::media_info& additional_info) override\r
        {\r
                return frame_;\r
        }\r
index 8c50a8cef3c3fc10dd992f7918c7fc0d8f74fc20..eb6aba1000d2e13a45c4874507bb693f89fde4ba 100644 (file)
@@ -72,6 +72,9 @@ namespace caspar { namespace protocol { namespace amcp {
                void SetThumbGenerator(const std::shared_ptr<core::thumbnail_generator>& thumb_gen) {thumb_gen_ = thumb_gen;}\r
                std::shared_ptr<core::thumbnail_generator> GetThumbGenerator() { return thumb_gen_; }\r
 \r
+               void SetMediaInfoRepo(const safe_ptr<core::media_info_repository>& media_info_repo) {media_info_repo_ = media_info_repo;}\r
+               std::shared_ptr<core::media_info_repository> GetMediaInfoRepo() { return media_info_repo_; }\r
+\r
                void SetShutdownServerNow(boost::promise<bool>& shutdown_server_now) {shutdown_server_now_ = &shutdown_server_now;}\r
                boost::promise<bool>& GetShutdownServerNow() { return *shutdown_server_now_; }\r
 \r
@@ -103,6 +106,7 @@ namespace caspar { namespace protocol { namespace amcp {
                std::shared_ptr<core::video_channel> pChannel_;\r
                std::vector<safe_ptr<core::video_channel>> channels_;\r
                std::shared_ptr<core::thumbnail_generator> thumb_gen_;\r
+               std::shared_ptr<core::media_info_repository> media_info_repo_;\r
                boost::promise<bool>* shutdown_server_now_;\r
                AMCPCommandScheduling scheduling_;\r
                std::wstring replyString_;\r
index 193c69f073869d3eac0bb227023df6e8a697f0af..ce95138bb6356399a854f6f889814b6d45d90099 100644 (file)
@@ -46,6 +46,8 @@
 #include <core/producer/frame/frame_transform.h>\r
 #include <core/producer/stage.h>\r
 #include <core/producer/layer.h>\r
+#include <core/producer/media_info/media_info.h>\r
+#include <core/producer/media_info/media_info_repository.h>\r
 #include <core/mixer/mixer.h>\r
 #include <core/mixer/gpu/ogl_device.h>\r
 #include <core/consumer/output.h>\r
@@ -197,13 +199,10 @@ std::wstring read_file(const boost::filesystem::wpath& file)
        return read_latin1_file(file);\r
 }\r
 \r
-std::wstring MediaInfo(const boost::filesystem::wpath& path)\r
+std::wstring MediaInfo(const boost::filesystem::wpath& path, const std::shared_ptr<core::media_info_repository>& media_info_repo)\r
 {\r
        if(boost::filesystem::is_regular_file(path))\r
        {\r
-               std::int64_t duration = 0;\r
-               boost::rational<std::int64_t> time_base;\r
-                               \r
                std::wstring clipttype = TEXT(" N/A ");\r
                std::wstring extension = boost::to_upper_copy(path.extension());\r
                if(extension == TEXT(".TGA") || extension == TEXT(".COL") || extension == L".PNG" || extension == L".JPEG" || extension == L".JPG" ||\r
@@ -215,16 +214,12 @@ std::wstring MediaInfo(const boost::filesystem::wpath& path)
                {\r
                        clipttype = TEXT(" AUDIO ");\r
                }\r
-               else if(extension == TEXT(".SWF") || extension == TEXT(".CT"))\r
-               {\r
-                       clipttype = TEXT(" MOVIE ");\r
-               }\r
-               else if(extension == TEXT(".DV") || extension == TEXT(".MOV") || \r
+               else if(extension == TEXT(".SWF") || extension == TEXT(".CT") ||\r
+                               extension == TEXT(".DV") || extension == TEXT(".MOV") || \r
                                extension == TEXT(".MPG") || extension == TEXT(".AVI") || \r
                                extension == TEXT(".MP4") || extension == TEXT(".FLV") || \r
                                caspar::ffmpeg::is_valid_file(path.file_string()))\r
                {\r
-                       ffmpeg::try_get_duration(path.file_string(), duration, time_base);\r
                        clipttype = TEXT(" MOVIE ");\r
                }\r
 \r
@@ -245,25 +240,27 @@ std::wstring MediaInfo(const boost::filesystem::wpath& path)
                        auto str = relativePath.replace_extension(TEXT("")).external_file_string();\r
                        if(str[0] == '\\' || str[0] == '/')\r
                                str = std::wstring(str.begin() + 1, str.end());\r
+                       core::media_info media_info;\r
+                       media_info_repo->try_load(boost::replace_all_copy(str, "\\", "/"), media_info);\r
                        \r
                        return std::wstring() \r
                                        + L"\""         + str +\r
                                        + L"\" "        + clipttype +\r
                                        + L" "          + sizeStr +\r
                                        + L" "          + writeTimeWStr +\r
-                                       + L" "          + boost::lexical_cast<std::wstring>(duration) +\r
-                                       + L" "          + boost::lexical_cast<std::wstring>(time_base.numerator()) + L"/" + boost::lexical_cast<std::wstring>(time_base.denominator())\r
+                                       + L" "          + boost::lexical_cast<std::wstring>(media_info.duration) +\r
+                                       + L" "          + boost::lexical_cast<std::wstring>(media_info.time_base.numerator()) + L"/" + boost::lexical_cast<std::wstring>(media_info.time_base.denominator())\r
                                        + L"\r\n";      \r
                }       \r
        }\r
        return L"";\r
 }\r
 \r
-std::wstring ListMedia()\r
+std::wstring ListMedia(const std::shared_ptr<core::media_info_repository>& media_info_repo)\r
 {              \r
        std::wstringstream replyString;\r
        for (boost::filesystem::wrecursive_directory_iterator itr(env::media_folder()), end; itr != end; ++itr) \r
-               replyString << MediaInfo(itr->path());\r
+               replyString << MediaInfo(itr->path(), media_info_repo);\r
        \r
        return boost::to_upper_copy(replyString.str());\r
 }\r
@@ -1839,7 +1836,7 @@ bool CinfCommand::DoExecute()
                        auto path = itr->path();\r
                        auto file = path.replace_extension(L"").filename();\r
                        if(boost::iequals(file, _parameters.at(0)))\r
-                               info += MediaInfo(itr->path()) + L"\r\n";\r
+                               info += MediaInfo(itr->path(), GetMediaInfoRepo()) + L"\r\n";\r
                }\r
 \r
                if(info.empty())\r
@@ -2041,7 +2038,7 @@ bool ClsCommand::DoExecute()
        */\r
        std::wstringstream replyString;\r
        replyString << TEXT("200 CLS OK\r\n");\r
-       replyString << ListMedia();\r
+       replyString << ListMedia(GetMediaInfoRepo());\r
        replyString << TEXT("\r\n");\r
        SetReplyString(boost::to_upper_copy(replyString.str()));\r
        return true;\r
index ff8270a5e6b5dcf6d5d5fca155d25f3bfc9e6ba2..d3bda841abeaeeed548a0ad42b16d8d9e11e6bc0 100644 (file)
@@ -56,9 +56,11 @@ inline std::shared_ptr<core::video_channel> GetChannelSafe(unsigned int index, c
 AMCPProtocolStrategy::AMCPProtocolStrategy(\r
                const std::vector<safe_ptr<core::video_channel>>& channels,\r
                const std::shared_ptr<core::thumbnail_generator>& thumb_gen,\r
+               const safe_ptr<core::media_info_repository>& media_info_repo,\r
                boost::promise<bool>& shutdown_server_now)\r
        : channels_(channels)\r
        , thumb_gen_(thumb_gen)\r
+       , media_info_repo_(media_info_repo)\r
        , shutdown_server_now_(shutdown_server_now)\r
 {\r
        AMCPCommandQueuePtr pGeneralCommandQueue(new AMCPCommandQueue());\r
@@ -200,6 +202,7 @@ AMCPCommandPtr AMCPProtocolStrategy::InterpretCommandString(const std::wstring&
                        {\r
                                pCommand->SetChannels(channels_);\r
                                pCommand->SetThumbGenerator(thumb_gen_);\r
+                               pCommand->SetMediaInfoRepo(media_info_repo_);\r
                                pCommand->SetShutdownServerNow(shutdown_server_now_);\r
                                //Set scheduling\r
                                if(commandSwitch.size() > 0) {\r
index 90b597974080ae8c8f478bbd758d5bc9dbdfb065..a4e392e648d60e2b48824417b3bc1b4791d0fd81 100644 (file)
@@ -24,6 +24,7 @@
 #include "../util/protocolstrategy.h"\r
 #include <core/video_channel.h>\r
 #include <core/thumbnail_generator.h>\r
+#include <core/producer/media_info/media_info_repository.h>\r
 \r
 #include "AMCPCommand.h"\r
 #include "AMCPCommandQueue.h"\r
@@ -51,6 +52,7 @@ public:
        AMCPProtocolStrategy(\r
                        const std::vector<safe_ptr<core::video_channel>>& channels,\r
                        const std::shared_ptr<core::thumbnail_generator>& thumb_gen,\r
+                       const safe_ptr<core::media_info_repository>& media_info_repo,\r
                        boost::promise<bool>& shutdown_server_now);\r
        virtual ~AMCPProtocolStrategy();\r
 \r
@@ -72,6 +74,7 @@ private:
 \r
        std::vector<safe_ptr<core::video_channel>> channels_;\r
        std::shared_ptr<core::thumbnail_generator> thumb_gen_;\r
+       safe_ptr<core::media_info_repository> media_info_repo_;\r
        boost::promise<bool>& shutdown_server_now_;\r
        std::vector<AMCPCommandQueuePtr> commandQueues_;\r
        static const std::wstring MessageDelimiter;\r
index 320d678b56bf6017c6e983b4782df70a8db28f85..f7cd96ca9df6c907191e3811196b08bffc59288f 100644 (file)
@@ -281,6 +281,7 @@ int main(int argc, wchar_t* argv[])
                                caspar::protocol::amcp::AMCPProtocolStrategy amcp(\r
                                                caspar_server.get_channels(),\r
                                                caspar_server.get_thumbnail_generator(),\r
+                                               caspar_server.get_media_info_repo(),\r
                                                shutdown_server_now);\r
 \r
                                // Create a dummy client which prints amcp responses to console.\r
index e43c4c710fa1cebc77205bff0ca7f393eb750315..09c5594fdc8dfb972569e4d3f66ebc5133e851df 100644 (file)
@@ -37,6 +37,8 @@
 #include <core/consumer/output.h>\r
 #include <core/consumer/synchronizing/synchronizing_consumer.h>\r
 #include <core/thumbnail_generator.h>\r
+#include <core/producer/media_info/media_info_repository.h>\r
+#include <core/producer/media_info/file_based_media_info_repository.h>\r
 \r
 #include <modules/bluefish/bluefish.h>\r
 #include <modules/decklink/decklink.h>\r
@@ -110,6 +112,7 @@ struct server::implementation : boost::noncopyable
        osc::client                                                                     osc_client_;\r
        std::vector<std::shared_ptr<void>>                      predefined_osc_subscriptions_;\r
        std::vector<safe_ptr<video_channel>>            channels_;\r
+       safe_ptr<media_info_repository>                         media_info_repo_;\r
        std::shared_ptr<thumbnail_generator>            thumbnail_generator_;\r
 \r
        implementation(boost::promise<bool>& shutdown_server_now)\r
@@ -117,6 +120,8 @@ struct server::implementation : boost::noncopyable
                , shutdown_server_now_(shutdown_server_now)\r
                , ogl_(ogl_device::create())\r
                , osc_client_(io_service_)\r
+               , media_info_repo_(create_file_based_media_info_repository(\r
+                               env::thumbnails_folder() + L"media_info.csv"))\r
        {\r
                setup_audio(env::properties());\r
 \r
@@ -355,7 +360,8 @@ struct server::implementation : boost::noncopyable
                                core::video_format_desc::get(pt.get(L"configuration.thumbnails.video-mode", L"720p2500")),\r
                                ogl_,\r
                                pt.get(L"configuration.thumbnails.generate-delay-millis", 2000),\r
-                               &image::write_cropped_png));\r
+                               &image::write_cropped_png,\r
+                               media_info_repo_));\r
 \r
                CASPAR_LOG(info) << L"Initialized thumbnail generator.";\r
        }\r
@@ -363,7 +369,7 @@ struct server::implementation : boost::noncopyable
        safe_ptr<IO::IProtocolStrategy> create_protocol(const std::wstring& name) const\r
        {\r
                if(boost::iequals(name, L"AMCP"))\r
-                       return make_safe<amcp::AMCPProtocolStrategy>(channels_, thumbnail_generator_, shutdown_server_now_);\r
+                       return make_safe<amcp::AMCPProtocolStrategy>(channels_, thumbnail_generator_, media_info_repo_, shutdown_server_now_);\r
                else if(boost::iequals(name, L"CII"))\r
                        return make_safe<cii::CIIProtocolStrategy>(channels_);\r
                else if(boost::iequals(name, L"CLOCK"))\r
@@ -389,6 +395,11 @@ std::shared_ptr<thumbnail_generator> server::get_thumbnail_generator() const
        return impl_->thumbnail_generator_;\r
 }\r
 \r
+safe_ptr<media_info_repository> server::get_media_info_repo() const\r
+{\r
+       return impl_->media_info_repo_;\r
+}\r
+\r
 core::monitor::subject& server::monitor_output()\r
 {\r
        return *impl_->monitor_subject_;\r
index d4d6cd69fb1934441346852685a0ea6ff56c9486..d547505b12ab97ad0ef018d32116814f15dccd6f 100644 (file)
@@ -36,6 +36,7 @@ namespace caspar {
 namespace core {\r
        class video_channel;\r
        class thumbnail_generator;\r
+       struct media_info_repository;\r
 }\r
 \r
 class server : boost::noncopyable\r
@@ -44,6 +45,7 @@ public:
        server(boost::promise<bool>& shutdown_server_now);\r
        const std::vector<safe_ptr<core::video_channel>> get_channels() const;\r
        std::shared_ptr<core::thumbnail_generator> get_thumbnail_generator() const;\r
+       safe_ptr<core::media_info_repository> get_media_info_repo() const;\r
 \r
        core::monitor::subject& monitor_output();\r
 \r