producer/draw/freehand_producer.cpp
+ producer/media_info/in_memory_media_info_repository.cpp
+
producer/scene/const_producer.cpp
producer/scene/expression_parser.cpp
producer/scene/hotswap_producer.cpp
producer/draw/freehand_producer.h
+ producer/media_info/in_memory_media_info_repository.h
+ producer/media_info/media_info.h
+ producer/media_info/media_info_repository.h
+
producer/scene/const_producer.h
producer/scene/expression_parser.h
producer/scene/hotswap_producer.h
source_group(sources\\interaction interaction/*)
source_group(sources\\mixer mixer/*)
source_group(sources\\producer\\draw producer/draw/*)
+source_group(sources\\producer\\media_info producer/media_info/*)
source_group(sources\\producer\\scene producer/scene/*)
source_group(sources\\producer\\text\\utils producer/text/utils/*)
source_group(sources\\producer\\text producer/text/*)
--- /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 "in_memory_media_info_repository.h"
+
+#include <map>
+#include <vector>
+
+#include <boost/thread/mutex.hpp>
+#include <boost/foreach.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
+
+#include "media_info.h"
+#include "media_info_repository.h"
+
+namespace caspar { namespace core {
+
+class in_memory_media_info_repository : public media_info_repository
+{
+ boost::mutex mutex_;
+ std::map<std::wstring, boost::optional<media_info>> info_by_file_;
+ std::vector<media_info_extractor> extractors_;
+public:
+ virtual void register_extractor(media_info_extractor extractor) override
+ {
+ boost::lock_guard<boost::mutex> lock(mutex_);
+
+ extractors_.push_back(extractor);
+ }
+
+ virtual boost::optional<media_info> get(const std::wstring& file) override
+ {
+ boost::lock_guard<boost::mutex> lock(mutex_);
+
+ auto iter = info_by_file_.find(file);
+
+ if (iter == info_by_file_.end())
+ {
+ media_info info;
+ auto extension = boost::to_upper_copy(boost::filesystem::path(file).extension().wstring());
+ bool success = false;
+
+ BOOST_FOREACH(auto& extractor, extractors_)
+ {
+ success = extractor(file, extension, info);
+
+ if (success)
+ break;
+ }
+
+ boost::optional<media_info> result;
+
+ if (success)
+ result = info;
+
+ info_by_file_.insert(std::make_pair(file, result));
+
+ return result;
+ }
+
+ return iter->second;
+ }
+
+ virtual void remove(const std::wstring& file) override
+ {
+ boost::lock_guard<boost::mutex> lock(mutex_);
+
+ info_by_file_.erase(file);
+ }
+};
+
+spl::shared_ptr<struct media_info_repository> create_in_memory_media_info_repository()
+{
+ return spl::make_shared<in_memory_media_info_repository>();
+}
+
+}}
--- /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.h>
+
+namespace caspar { namespace core {
+
+spl::shared_ptr<struct media_info_repository> create_in_memory_media_info_repository();
+
+}}
--- /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 <string>
+
+#include <boost/rational.hpp>
+
+namespace caspar { namespace core {
+
+struct media_info
+{
+ std::int64_t duration = 0;
+ boost::rational<std::int64_t> time_base;
+ std::wstring clip_type;
+
+ media_info()
+ {
+ }
+};
+
+}}
--- /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 <functional>
+
+#include <boost/optional.hpp>
+
+namespace caspar { namespace core {
+
+struct media_info;
+typedef std::function<bool (
+ const std::wstring& file,
+ const std::wstring& upper_case_extension,
+ media_info& info)
+> media_info_extractor;
+
+struct media_info_repository
+{
+ virtual ~media_info_repository() { }
+ virtual void register_extractor(media_info_extractor extractor) = 0;
+ virtual boost::optional<media_info> get(const std::wstring& file) = 0;
+ virtual void remove(const std::wstring& file) = 0;
+};
+
+}}
#include "frame/frame.h"
#include "frame/draw_frame.h"
#include "frame/frame_transform.h"
+#include "producer/media_info/media_info.h"
+#include "producer/media_info/media_info_repository.h"
namespace caspar { namespace core {
struct thumbnail_generator::impl
{
private:
- boost::filesystem::wpath media_path_;
- boost::filesystem::wpath thumbnails_path_;
- int width_;
- int height_;
- spl::shared_ptr<image_mixer> image_mixer_;
- spl::shared_ptr<diagnostics::graph> graph_;
- video_format_desc format_desc_;
- spl::unique_ptr<thumbnail_output> output_;
- mixer mixer_;
- thumbnail_creator thumbnail_creator_;
- filesystem_monitor::ptr monitor_;
+ boost::filesystem::wpath media_path_;
+ boost::filesystem::wpath thumbnails_path_;
+ int width_;
+ int height_;
+ spl::shared_ptr<image_mixer> image_mixer_;
+ spl::shared_ptr<diagnostics::graph> graph_;
+ video_format_desc format_desc_;
+ spl::unique_ptr<thumbnail_output> output_;
+ mixer mixer_;
+ thumbnail_creator thumbnail_creator_;
+ spl::shared_ptr<media_info_repository> media_info_repo_;
+ filesystem_monitor::ptr monitor_;
public:
impl(
filesystem_monitor_factory& monitor_factory,
const video_format_desc& render_video_mode,
std::unique_ptr<image_mixer> image_mixer,
int generate_delay_millis,
- const thumbnail_creator& thumbnail_creator)
+ const thumbnail_creator& thumbnail_creator,
+ spl::shared_ptr<media_info_repository> media_info_repo)
: media_path_(media_path)
, thumbnails_path_(thumbnails_path)
, width_(width)
, output_(spl::make_unique<thumbnail_output>(generate_delay_millis))
, mixer_(graph_, image_mixer_)
, thumbnail_creator_(thumbnail_creator)
+ , media_info_repo_(std::move(media_info_repo))
, monitor_(monitor_factory.create(
media_path,
filesystem_event::ALL,
case filesystem_event::REMOVED:
auto relative_without_extension = get_relative_without_extension(file, media_path_);
boost::filesystem::remove(thumbnails_path_ / (relative_without_extension + L".png"));
+ media_info_repo_->remove(file.wstring());
break;
}
try
{
raw_frame = producer->create_thumbnail_frame();
+ media_info_repo_->remove(file.wstring());
+ media_info_repo_->get(file.wstring());
}
catch (const boost::thread_interrupted&)
{
const video_format_desc& render_video_mode,
std::unique_ptr<image_mixer> image_mixer,
int generate_delay_millis,
- const thumbnail_creator& thumbnail_creator)
+ const thumbnail_creator& thumbnail_creator,
+ spl::shared_ptr<media_info_repository> media_info_repo)
: impl_(new impl(
monitor_factory,
media_path,
render_video_mode,
std::move(image_mixer),
generate_delay_millis,
- thumbnail_creator))
+ thumbnail_creator,
+ media_info_repo))
{
}
#include <boost/noncopyable.hpp>
-#include "memory.h"
+#include <common/memory.h>
#include <common/filesystem_monitor.h>
namespace caspar { namespace core {
class ogl_device;
class read_frame;
struct video_format_desc;
+struct media_info_repository;
typedef std::function<void (
const class const_frame& frame,
const video_format_desc& render_video_mode,
std::unique_ptr<class image_mixer> image_mixer,
int generate_delay_millis,
- const thumbnail_creator& thumbnail_creator);
+ const thumbnail_creator& thumbnail_creator,
+ spl::shared_ptr<media_info_repository> media_info_repo);
~thumbnail_generator();
void generate(const std::wstring& media_file);
void generate_all();
#include "consumer/ffmpeg_consumer.h"
#include "producer/ffmpeg_producer.h"
+#include "producer/util/util.h"
#include <common/log.h>
#include <core/consumer/frame_consumer.h>
#include <core/producer/frame_producer.h>
+#include <core/producer/media_info/media_info.h>
+#include <core/producer/media_info/media_info_repository.h>
#include <tbb/recursive_mutex.h>
//}
//#pragma warning (pop)
-void init()
+void init(const spl::shared_ptr<core::media_info_repository>& media_info_repo)
{
av_lockmgr_register(ffmpeg_lock_callback);
av_log_set_callback(log_callback);
core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
core::register_producer_factory(create_producer);
+
+ media_info_repo->register_extractor(
+ [](const std::wstring& file, const std::wstring& extension, core::media_info& info) -> bool
+ {
+ // TODO: merge thumbnail generation from 2.0
+ //auto disable_logging = temporary_disable_logging_for_thread(true);
+ if (extension == L".WAV" || extension == L".MP3")
+ {
+ info.clip_type = L"AUDIO";
+ return true;
+ }
+
+ if (!is_valid_file(file))
+ return false;
+
+ info.clip_type = L"MOVIE";
+
+ return try_get_duration(file, info.duration, info.time_base);
+ });
+
}
void uninit()
#include <string>
-namespace caspar { namespace ffmpeg {
+#include <common/memory.h>
-void init();
+namespace caspar {
+namespace core {
+
+struct media_info_repository;
+
+}
+
+namespace ffmpeg {
+
+void init(const spl::shared_ptr<core::media_info_repository>& media_info_repo);
void uninit();
std::wstring avcodec_version();
#include <common/assert.h>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/rational.hpp>
#include <fstream>
return av_probe_input_format2(&pb, true, &score) != nullptr;
}
+bool try_get_duration(const std::wstring filename, std::int64_t& duration, boost::rational<std::int64_t>& time_base)
+{
+ AVFormatContext* weak_context = nullptr;
+ if (avformat_open_input(&weak_context, u8(filename).c_str(), nullptr, nullptr) < 0)
+ return false;
+
+ std::shared_ptr<AVFormatContext> context(weak_context, av_close_input_file);
+
+ context->probesize = context->probesize / 10;
+ context->max_analyze_duration = context->probesize / 10;
+
+ if (avformat_find_stream_info(context.get(), nullptr) < 0)
+ return false;
+
+ const auto fps = read_fps(*context, 1.0);
+
+ const auto rational_fps = boost::rational<std::int64_t>(static_cast<int>(fps * AV_TIME_BASE), AV_TIME_BASE);
+
+ duration = boost::rational_cast<std::int64_t>(context->duration * rational_fps / AV_TIME_BASE);
+
+ if (rational_fps == 0)
+ return false;
+
+ time_base = 1 / rational_fps;
+
+ return true;
+}
+
std::wstring probe_stem(const std::wstring& stem)
{
auto stem2 = boost::filesystem::path(stem);
#include <core/frame/pixel_format.h>
#include <core/mixer/audio/audio_mixer.h>
+#include <boost/rational.hpp>
+
#include <array>
#if defined(_MSC_VER)
std::wstring probe_stem(const std::wstring& stem);
bool is_valid_file(const std::wstring& filename);
+bool try_get_duration(const std::wstring filename, std::int64_t& duration, boost::rational<std::int64_t>& time_base);
}}
#include "producer/flash_producer.h"
#include <common/env.h>
+#include <common/os/windows/windows.h>
-#ifdef WIN32
-#include <Windows.h>
-#endif
+#include <core/producer/media_info/media_info.h>
+#include <core/producer/media_info/media_info_repository.h>
+
+#include <string>
namespace caspar { namespace flash {
-void init()
+void init(const spl::shared_ptr<core::media_info_repository>& media_info_repo)
{
core::register_producer_factory(create_ct_producer);
core::register_producer_factory(create_swf_producer);
+ media_info_repo->register_extractor([](const std::wstring& file, const std::wstring& extension, core::media_info& info)
+ {
+ if (extension != L".CT" && extension != L".SWF")
+ return false;
+
+ info.clip_type = L"MOVIE";
+
+ return true;
+ });
}
std::wstring cg_version()
#include <string>
-namespace caspar { namespace flash {
+#include <common/memory.h>
-void init();
+namespace caspar {
+
+namespace core {
+
+struct media_info_repository;
+
+}
+
+namespace flash {
+
+void init(const spl::shared_ptr<core::media_info_repository>& media_info_repo);
std::wstring cg_version();
std::wstring version();
#include <core/producer/frame_producer.h>
#include <core/consumer/frame_consumer.h>
+#include <core/producer/media_info/media_info.h>
+#include <core/producer/media_info/media_info_repository.h>
#include <common/utf.h>
namespace caspar { namespace image {
-void init()
+void init(const spl::shared_ptr<core::media_info_repository>& repo)
{
FreeImage_Initialise();
core::register_producer_factory(create_scroll_producer);
core::register_producer_factory(create_producer);
core::register_thumbnail_producer_factory(create_thumbnail_producer);
core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+ repo->register_extractor([](const std::wstring& file, const std::wstring& extension, core::media_info& info)
+ {
+ if (extension == L".TGA"
+ || extension == L".COL"
+ || extension == L".PNG"
+ || extension == L".JPEG"
+ || extension == L".JPG"
+ || extension == L".GIF"
+ || extension == L".BMP")
+ {
+ info.clip_type = L"STILL";
+
+ return true;
+ }
+
+ return false;
+ });
}
void uninit()
{
FreeImage_DeInitialise();
-// core::register_producer_factory(create_scroll_producer);
-// core::register_producer_factory(create_producer);
-// core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
}
#include <string>
-namespace caspar { namespace image {
+#include <common/memory.h>
-void init();
+namespace caspar {
+
+namespace core {
+
+struct media_info_repository;
+
+}
+
+namespace image {
+
+void init(const spl::shared_ptr<core::media_info_repository>& repo);
void uninit();
std::wstring version();
#include <core/mixer/mixer.h>
#include <core/consumer/output.h>
#include <core/thumbnail_generator.h>
+#include <core/producer/media_info/media_info.h>
+#include <core/producer/media_info/media_info_repository.h>
#include <core/diagnostics/call_context.h>
#include <core/diagnostics/osd_graph.h>
#include <modules/flash/producer/cg_proxy.h>
#include <modules/ffmpeg/producer/util/util.h>
#include <modules/screen/screen.h>
-#include <modules/reroute/producer/reroute_producer.h>
#include <algorithm>
#include <locale>
#include <fstream>
#include <memory>
#include <cctype>
-//#include <io.h>
#include <future>
#include <boost/date_time/posix_time/posix_time.hpp>
return read_latin1_file(file);
}
-std::wstring MediaInfo(const boost::filesystem::path& path)
+std::wstring MediaInfo(const boost::filesystem::path& path, const spl::shared_ptr<media_info_repository>& media_info_repo)
{
- if(boost::filesystem::is_regular_file(path))
- {
- std::wstring clipttype = L"N/A";
- std::wstring extension = boost::to_upper_copy(path.extension().wstring());
- if(extension == L".TGA" || extension == L".COL" || extension == L".PNG" || extension == L".JPEG" || extension == L".JPG" ||
- extension == L"GIF" || extension == L"BMP")
- clipttype = L"STILL";
- else if(extension == L".WAV" || extension == L".MP3")
- clipttype = L"AUDIO";
- else if(extension == L"SWF" || extension == L"CT" || extension == L"DV" || extension == L"MOV" || extension == L"MPG" || extension == L"AVI" || caspar::ffmpeg::is_valid_file(path.wstring()))
- clipttype = L"MOVIE";
-
- if(clipttype != L"N/A")
- {
- auto is_not_digit = [](char c){ return std::isdigit(c) == 0; };
+ if (!boost::filesystem::is_regular_file(path))
+ return L"";
- auto relativePath = boost::filesystem::path(path.wstring().substr(env::media_folder().size()-1, path.wstring().size()));
+ auto media_info = media_info_repo->get(path.wstring());
- auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(path)));
- writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), is_not_digit), writeTimeStr.end());
- auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());
+ if (!media_info)
+ return L"";
- auto sizeStr = boost::lexical_cast<std::wstring>(boost::filesystem::file_size(path));
- sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), is_not_digit), sizeStr.end());
- auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());
-
- auto str = relativePath.replace_extension(L"").generic_wstring();
- while(str.size() > 0 && (str[0] == L'\\' || str[0] == L'/'))
- str = std::wstring(str.begin() + 1, str.end());
+ auto is_not_digit = [](char c){ return std::isdigit(c) == 0; };
- return std::wstring() + L"\"" + str +
- + L"\" " + clipttype +
- + L" " + sizeStr +
- + L" " + writeTimeWStr +
- + L"\r\n";
- }
- }
- return L"";
+ auto relativePath = boost::filesystem::wpath(path.wstring().substr(env::media_folder().size() - 1, path.wstring().size()));
+
+ auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(path)));
+ writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), is_not_digit), writeTimeStr.end());
+ auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());
+
+ auto sizeStr = boost::lexical_cast<std::wstring>(boost::filesystem::file_size(path));
+ sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), is_not_digit), sizeStr.end());
+ auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());
+
+ auto str = relativePath.replace_extension(L"").generic_wstring();
+ if (str[0] == '\\' || str[0] == '/')
+ str = std::wstring(str.begin() + 1, str.end());
+
+ return std::wstring()
+ + L"\"" + str +
+ + L"\" " + media_info->clip_type +
+ + L" " + sizeStr +
+ + L" " + writeTimeWStr +
+ + L" " + boost::lexical_cast<std::wstring>(media_info->duration) +
+ + L" " + boost::lexical_cast<std::wstring>(media_info->time_base.numerator()) + L"/" + boost::lexical_cast<std::wstring>(media_info->time_base.denominator())
+ + L"\r\n";
}
-std::wstring ListMedia()
+std::wstring ListMedia(const spl::shared_ptr<media_info_repository>& media_info_repo)
{
std::wstringstream replyString;
- for (boost::filesystem::recursive_directory_iterator itr(env::media_folder()), end; itr != end; ++itr)
- replyString << MediaInfo(itr->path());
+ for (boost::filesystem::recursive_directory_iterator itr(env::media_folder()), end; itr != end; ++itr)
+ replyString << MediaInfo(itr->path(), media_info_repo);
return boost::to_upper_copy(replyString.str());
}
auto path = itr->path();
auto file = path.replace_extension(L"").filename();
if(boost::iequals(file.wstring(), parameters().at(0)))
- info += MediaInfo(itr->path()) + L"\r\n";
+ info += MediaInfo(itr->path(), repo_) + L"\r\n";
}
if(info.empty())
{
std::wstringstream replyString;
replyString << L"200 CLS OK\r\n";
- replyString << ListMedia();
+ replyString << ListMedia(repo_);
replyString << L"\r\n";
SetReplyString(boost::to_upper_copy(replyString.str()));
}
* Author: Nicklas P Andersson
*/
-
-#ifndef __AMCPCOMMANDSIMPL_H__
-#define __AMCPCOMMANDSIMPL_H__
+#pragma once
#include "AMCPCommand.h"
#include <core/thumbnail_generator.h>
+#include <core/producer/media_info/media_info_repository.h>
#include <future>
-namespace caspar { namespace protocol {
-
-std::wstring ListMedia();
-std::wstring ListTemplates();
-
-namespace amcp {
+namespace caspar { namespace protocol { namespace amcp {
class ChannelGridCommand : public AMCPCommandBase<0>, AMCPChannelsAwareCommand
{
class ClsCommand : public AMCPCommandBase<0>
{
public:
- explicit ClsCommand(IO::ClientInfoPtr client) : AMCPCommandBase(client) {}
+ explicit ClsCommand(IO::ClientInfoPtr client, const spl::shared_ptr<core::media_info_repository>& repo)
+ : AMCPCommandBase(client)
+ , repo_(repo)
+ {}
std::wstring print() const { return L"ClsCommand";}
bool DoExecute();
+private:
+ spl::shared_ptr<core::media_info_repository> repo_;
};
class TlsCommand : public AMCPCommandBase<0>
class CinfCommand : public AMCPCommandBase<1>
{
public:
- explicit CinfCommand(IO::ClientInfoPtr client) : AMCPCommandBase(client) {}
+ explicit CinfCommand(IO::ClientInfoPtr client, const spl::shared_ptr<core::media_info_repository>& repo)
+ : AMCPCommandBase(client)
+ , repo_(repo)
+ {}
std::wstring print() const { return L"CinfCommand";}
bool DoExecute();
+private:
+ spl::shared_ptr<core::media_info_repository> repo_;
};
class InfoCommand : public AMCPCommandBase<0>, AMCPChannelsAwareCommand
} //namespace amcp
}} //namespace caspar
-
-#endif //__AMCPCOMMANDSIMPL_H__
\ No newline at end of file
struct AMCPProtocolStrategy::impl
{
private:
- std::vector<channel_context> channels_;
- std::vector<AMCPCommandQueue::ptr_type> commandQueues_;
- std::shared_ptr<core::thumbnail_generator> thumb_gen_;
- std::promise<bool>& shutdown_server_now_;
+ std::vector<channel_context> channels_;
+ std::vector<AMCPCommandQueue::ptr_type> commandQueues_;
+ std::shared_ptr<core::thumbnail_generator> thumb_gen_;
+ spl::shared_ptr<core::media_info_repository> media_info_repo_;
+ std::promise<bool>& shutdown_server_now_;
public:
- impl(const std::vector<spl::shared_ptr<core::video_channel>>& channels, const std::shared_ptr<core::thumbnail_generator>& thumb_gen, std::promise<bool>& shutdown_server_now) : thumb_gen_(thumb_gen), shutdown_server_now_(shutdown_server_now)
+ impl(
+ const std::vector<spl::shared_ptr<core::video_channel>>& channels,
+ const std::shared_ptr<core::thumbnail_generator>& thumb_gen,
+ const spl::shared_ptr<core::media_info_repository>& media_info_repo,
+ std::promise<bool>& shutdown_server_now)
+ : thumb_gen_(thumb_gen)
+ , media_info_repo_(media_info_repo)
+ , shutdown_server_now_(shutdown_server_now)
{
commandQueues_.push_back(std::make_shared<AMCPCommandQueue>());
if(s == L"DIAG") return std::make_shared<DiagnosticsCommand>(client);
else if(s == L"CHANNEL_GRID") return std::make_shared<ChannelGridCommand>(client, channels_);
else if(s == L"DATA") return std::make_shared<DataCommand>(client);
- else if(s == L"CINF") return std::make_shared<CinfCommand>(client);
+ else if(s == L"CINF") return std::make_shared<CinfCommand>(client, media_info_repo_);
else if(s == L"INFO") return std::make_shared<InfoCommand>(client, channels_);
- else if(s == L"CLS") return std::make_shared<ClsCommand>(client);
+ else if(s == L"CLS") return std::make_shared<ClsCommand>(client, media_info_repo_);
else if(s == L"TLS") return std::make_shared<TlsCommand>(client);
else if(s == L"VERSION") return std::make_shared<VersionCommand>(client);
else if(s == L"BYE") return std::make_shared<ByeCommand>(client);
};
-AMCPProtocolStrategy::AMCPProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels, const std::shared_ptr<core::thumbnail_generator>& thumb_gen, std::promise<bool>& shutdown_server_now) : impl_(spl::make_unique<impl>(channels, thumb_gen, shutdown_server_now)) {}
+AMCPProtocolStrategy::AMCPProtocolStrategy(
+ const std::vector<spl::shared_ptr<core::video_channel>>& channels,
+ const std::shared_ptr<core::thumbnail_generator>& thumb_gen,
+ const spl::shared_ptr<core::media_info_repository>& media_info_repo,
+ std::promise<bool>& shutdown_server_now)
+ : impl_(spl::make_unique<impl>(channels, thumb_gen, media_info_repo, shutdown_server_now))
+{
+}
AMCPProtocolStrategy::~AMCPProtocolStrategy() {}
void AMCPProtocolStrategy::Parse(const std::wstring& msg, IO::ClientInfoPtr pClientInfo) { impl_->Parse(msg, pClientInfo); }
#include <core/video_channel.h>
#include <core/thumbnail_generator.h>
+#include <core/producer/media_info/media_info_repository.h>
#include <common/memory.h>
AMCPProtocolStrategy(
const std::vector<spl::shared_ptr<core::video_channel>>& channels,
const std::shared_ptr<core::thumbnail_generator>& thumb_gen,
+ const spl::shared_ptr<core::media_info_repository>& media_info_repo,
std::promise<bool>& shutdown_server_now);
virtual ~AMCPProtocolStrategy();
// Create a amcp parser for console commands.
//protocol::amcp::AMCPProtocolStrategy amcp(caspar_server.channels());
- auto amcp = spl::make_shared<caspar::IO::delimiter_based_chunking_strategy_factory<wchar_t>>(L"\r\n", spl::make_shared<caspar::IO::legacy_strategy_adapter_factory>(spl::make_shared<protocol::amcp::AMCPProtocolStrategy>(caspar_server.channels(), caspar_server.get_thumbnail_generator(), shutdown_server_now)))->create(console_client);
+ auto amcp = spl::make_shared<caspar::IO::delimiter_based_chunking_strategy_factory<wchar_t>>(
+ L"\r\n",
+ spl::make_shared<caspar::IO::legacy_strategy_adapter_factory>(
+ spl::make_shared<protocol::amcp::AMCPProtocolStrategy>(
+ caspar_server.channels(),
+ caspar_server.get_thumbnail_generator(),
+ caspar_server.get_media_info_repo(),
+ shutdown_server_now)))->create(console_client);
std::wstring wcmd;
while(true)
#include <core/producer/text/text_producer.h>
#include <core/consumer/output.h>
#include <core/thumbnail_generator.h>
+#include <core/producer/media_info/media_info.h>
+#include <core/producer/media_info/media_info_repository.h>
+#include <core/producer/media_info/in_memory_media_info_repository.h>
#include <core/diagnostics/subject_diagnostics.h>
#include <core/diagnostics/call_context.h>
#include <core/diagnostics/osd_graph.h>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
+#include <tbb/atomic.h>
+
#include <future>
namespace caspar {
osc::client osc_client_;
std::vector<std::shared_ptr<void>> predefined_osc_subscriptions_;
std::vector<spl::shared_ptr<video_channel>> channels_;
+ spl::shared_ptr<media_info_repository> media_info_repo_;
+ boost::thread initial_media_info_thread_;
+ tbb::atomic<bool> running_;
std::shared_ptr<thumbnail_generator> thumbnail_generator_;
std::promise<bool>& shutdown_server_now_;
explicit impl(std::promise<bool>& shutdown_server_now)
: accelerator_(env::properties().get(L"configuration.accelerator", L"auto"))
, osc_client_(io_service_manager_.service())
+ , media_info_repo_(create_in_memory_media_info_repository())
, shutdown_server_now_(shutdown_server_now)
{
+ running_ = true;
core::diagnostics::osd::register_sink();
diag_subject_->attach_parent(monitor_subject_);
- ffmpeg::init();
+ ffmpeg::init(media_info_repo_);
CASPAR_LOG(info) << L"Initialized ffmpeg module.";
bluefish::init();
screen::init();
CASPAR_LOG(info) << L"Initialized ogl module.";
- image::init();
+ image::init(media_info_repo_);
CASPAR_LOG(info) << L"Initialized image module.";
- flash::init();
+ flash::init(media_info_repo_);
CASPAR_LOG(info) << L"Initialized flash module.";
psd::init();
setup_osc(env::properties());
CASPAR_LOG(info) << L"Initialized osc.";
+
+ start_initial_media_info_scan();
+ CASPAR_LOG(info) << L"Started initial media information retrieval.";
}
~impl()
{
+ running_ = false;
+ initial_media_info_thread_.join();
thumbnail_generator_.reset();
primary_amcp_server_.reset();
async_servers_.clear();
core::video_format_desc(pt.get(L"configuration.thumbnails.video-mode", L"720p2500")),
accelerator_.create_image_mixer(),
pt.get(L"configuration.thumbnails.generate-delay-millis", 2000),
- &image::write_cropped_png));
+ &image::write_cropped_png,
+ media_info_repo_));
CASPAR_LOG(info) << L"Initialized thumbnail generator.";
}
using namespace IO;
if(boost::iequals(name, L"AMCP"))
- return wrap_legacy_protocol("\r\n", spl::make_shared<amcp::AMCPProtocolStrategy>(channels_, thumbnail_generator_, shutdown_server_now_));
+ return wrap_legacy_protocol("\r\n", spl::make_shared<amcp::AMCPProtocolStrategy>(channels_, thumbnail_generator_, media_info_repo_, shutdown_server_now_));
else if(boost::iequals(name, L"CII"))
return wrap_legacy_protocol("\r\n", spl::make_shared<cii::CIIProtocolStrategy>(channels_));
else if(boost::iequals(name, L"CLOCK"))
CASPAR_THROW_EXCEPTION(caspar_exception() << arg_name_info(L"name") << arg_value_info(name) << msg_info(L"Invalid protocol"));
}
+ void start_initial_media_info_scan()
+ {
+ initial_media_info_thread_ = boost::thread([this]
+ {
+ for (boost::filesystem::wrecursive_directory_iterator iter(env::media_folder()), end; iter != end; ++iter)
+ {
+ if (running_)
+ {
+ if (boost::filesystem::is_regular_file(iter->path()))
+ media_info_repo_->get(iter->path().wstring());
+ }
+ else
+ {
+ CASPAR_LOG(info) << L"Initial media information retrieval aborted.";
+ return;
+ }
+ }
+
+ CASPAR_LOG(info) << L"Initial media information retrieval finished.";
+ });
+ }
};
server::server(std::promise<bool>& shutdown_server_now) : impl_(new impl(shutdown_server_now)){}
return impl_->channels_;
}
std::shared_ptr<core::thumbnail_generator> server::get_thumbnail_generator() const {return impl_->thumbnail_generator_; }
+spl::shared_ptr<media_info_repository> server::get_media_info_repo() const { return impl_->media_info_repo_; }
core::monitor::subject& server::monitor_output() { return *impl_->monitor_subject_; }
}
namespace core {
class video_channel;
class thumbnail_generator;
+ struct media_info_repository;
}
class server final : public boost::noncopyable
explicit server(std::promise<bool>& shutdown_server_now);
const std::vector<spl::shared_ptr<core::video_channel>> channels() const;
std::shared_ptr<core::thumbnail_generator> get_thumbnail_generator() const;
+ spl::shared_ptr<core::media_info_repository> get_media_info_repo() const;
core::monitor::subject& monitor_output();
private: