-<?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
<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
\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
\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
\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
\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
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
class basic_frame;\r
class parameters;\r
struct frame_factory;\r
+struct media_info;\r
\r
struct frame_producer : boost::noncopyable\r
{\r
\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
--- /dev/null
+/*
+* 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));
+}
+
+}}
--- /dev/null
+/*
+* 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);
+
+}}
--- /dev/null
+/*
+* 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)
+ {
+ }
+};
+
+}}
--- /dev/null
+/*
+* 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;
+};
+
+}}
#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
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
#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
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
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
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
== 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
\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
\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
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
render_video_mode,\r
ogl,\r
generate_delay_millis,\r
- thumbnail_creator))\r
+ thumbnail_creator,\r
+ media_info_repo))\r
{\r
}\r
\r
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
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
#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
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
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
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
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
#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
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
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
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
#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
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
{\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
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
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
*/\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
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
{\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
#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
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
\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
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
#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
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
, 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
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
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
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
namespace core {\r
class video_channel;\r
class thumbnail_generator;\r
+ struct media_info_repository;\r
}\r
\r
class server : boost::noncopyable\r
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