Thank you for your interest in CasparCG. The included software\r
is provided as-is by Sveriges Televison AB.\r
\r
-\r
LICENSING\r
================================================\r
CasparCG is distributed under the GNU General Public \r
\r
static void* fast_memclr(void* dest, size_t count)\r
{\r
- assert(count % (16*4) == 0);\r
+ assert(count % 128 == 0);\r
assert(dest != nullptr);\r
assert(source != nullptr);\r
\r
\r
static void* fast_memcpy(void* dest, const void* source, size_t count)\r
{\r
- assert(count % (16*8) == 0);\r
+ assert(count % 128 == 0);\r
assert(dest != nullptr);\r
assert(source != nullptr);\r
\r
\r
static void* fast_memcpy(void* dest, const void* source, size_t num)\r
{ \r
- tbb::affinity_partitioner partitioner;\r
+ tbb::affinity_partitioner ap;\r
tbb::parallel_for(tbb::blocked_range<size_t>(0, num/128), [&](const tbb::blocked_range<size_t>& r)\r
{ \r
internal::fast_memcpy(reinterpret_cast<char*>(dest) + r.begin()*128, reinterpret_cast<const char*>(source) + r.begin()*128, r.size()*128); \r
- }, partitioner); \r
+ }, ap); \r
return dest;\r
}\r
\r
class read_frame\r
{\r
public:\r
- virtual const boost::iterator_range<const unsigned char*> image_data() const {return boost::iterator_range<const unsigned char*>();}\r
- virtual const boost::iterator_range<const short*> audio_data() const {return boost::iterator_range<const short*>();}\r
+ virtual const boost::iterator_range<const unsigned char*> image_data() const = 0;\r
+ virtual const boost::iterator_range<const short*> audio_data() const = 0;\r
\r
static safe_ptr<const read_frame> empty()\r
{\r
- return safe_ptr<const read_frame>();\r
+ struct empty : public read_frame\r
+ { \r
+ virtual const boost::iterator_range<const unsigned char*> image_data() const {return boost::iterator_range<const unsigned char*>();}\r
+ virtual const boost::iterator_range<const short*> audio_data() const {return boost::iterator_range<const short*>();}\r
+ };\r
+ static safe_ptr<const empty> frame;\r
+ return frame;\r
}\r
};\r
\r
\r
#include <common/memory/safe_ptr.h>\r
\r
-#include <tbb/spin_rw_mutex.h>\r
-\r
namespace caspar { namespace core {\r
\r
-std::vector<const consumer_factory_t> c_factories;\r
-tbb::spin_rw_mutex c_factories_mutex;\r
+std::vector<const consumer_factory_t> g_factories;\r
\r
void register_consumer_factory(const consumer_factory_t& factory)\r
{\r
- tbb::spin_rw_mutex::scoped_lock(c_factories_mutex, true);\r
- c_factories.push_back(factory);\r
+ g_factories.push_back(factory);\r
}\r
\r
safe_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)\r
if(params.empty())\r
BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));\r
\r
- tbb::spin_rw_mutex::scoped_lock(c_factories_mutex, false);\r
auto consumer = frame_consumer::empty();\r
- std::any_of(c_factories.begin(), c_factories.end(), [&](const consumer_factory_t& factory) -> bool\r
+ std::any_of(g_factories.begin(), g_factories.end(), [&](const consumer_factory_t& factory) -> bool\r
{\r
try\r
{\r
\r
#include <common/memory/safe_ptr.h>\r
\r
-#include <vector>\r
-\r
#include <boost/noncopyable.hpp>\r
\r
namespace caspar { namespace core {\r
BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("color") << arg_value_info(narrow(color)) << msg_info("Invalid color code"));\r
\r
auto frame = frame_factory->create_frame(this, 1, 1, pixel_format::bgra);\r
+ \r
+ // Read color from hex-string and write to frame pixel.\r
auto& value = *reinterpret_cast<unsigned long*>(frame->image_data().begin());\r
std::wstringstream str(color_str_.substr(1));\r
str >> std::hex >> value;\r
+\r
frame_ = std::move(frame);\r
}\r
+\r
+ // frame_producer\r
\r
- virtual safe_ptr<basic_frame> receive() { return frame_; }\r
- \r
+ virtual safe_ptr<basic_frame> receive() { return frame_; } \r
virtual std::wstring print() const { return L"color[" + color_str_ + L"]"; }\r
};\r
\r
\r
namespace caspar { namespace core {\r
\r
- safe_ptr<frame_producer> create_color_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params);\r
+safe_ptr<frame_producer> create_color_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params);\r
\r
}}\r
\r
audio_transform::audio_transform()\r
: gain_(1.0)\r
- , audio_(true){}\r
+ , has_audio_(true){}\r
\r
void audio_transform::set_gain(double value)\r
{\r
\r
void audio_transform::set_has_audio(bool value)\r
{\r
- audio_ = value;\r
+ has_audio_ = value;\r
}\r
\r
bool audio_transform::get_has_audio() const\r
{\r
- return audio_;\r
+ return has_audio_;\r
}\r
\r
audio_transform& audio_transform::operator*=(const audio_transform &other) \r
{\r
gain_ *= other.gain_;\r
- audio_ &= other.audio_;\r
+ has_audio_ &= other.has_audio_;\r
return *this;\r
}\r
\r
const audio_transform operator*(const audio_transform &other) const;\r
private:\r
double gain_;\r
- bool audio_;\r
+ bool has_audio_;\r
};\r
\r
audio_transform tween(double time, const audio_transform& source, const audio_transform& dest, double duration, const tweener_t& tweener);\r
\r
+inline bool operator==(const audio_transform& lhs, const audio_transform& rhs)\r
+{\r
+ return memcmp(&lhs, &rhs, sizeof(audio_transform)) == 0;\r
+}\r
+\r
+inline bool operator!=(const audio_transform& lhs, const audio_transform& rhs)\r
+{\r
+ return !(lhs == rhs);\r
+}\r
+\r
}}
\ No newline at end of file
#include <boost/noncopyable.hpp>\r
#include <boost/range/iterator_range.hpp>\r
\r
-#include <memory>\r
#include <array>\r
+#include <memory>\r
#include <vector>\r
\r
namespace caspar { namespace core {\r
\r
static const safe_ptr<basic_frame>& eof()\r
{\r
- struct eof_frame : public basic_frame{};\r
- static safe_ptr<basic_frame> frame = make_safe<eof_frame>();\r
+ static safe_ptr<basic_frame> frame = make_safe<basic_frame>();\r
return frame;\r
}\r
\r
static const safe_ptr<basic_frame>& empty()\r
{\r
- struct empty_frame : public basic_frame{};\r
- static safe_ptr<basic_frame> frame = make_safe<empty_frame>();\r
+ static safe_ptr<basic_frame> frame = make_safe<basic_frame>();\r
return frame;\r
}\r
\r
#include <core/video_format.h>\r
\r
#include <array>\r
+#include <type_traits>\r
\r
namespace caspar { namespace core {\r
\r
\r
#include <common/memory/safe_ptr.h>\r
\r
-#include <tbb/spin_rw_mutex.h>\r
-\r
namespace caspar { namespace core {\r
\r
-std::vector<const producer_factory_t> p_factories;\r
-tbb::spin_rw_mutex p_factories_mutex;\r
+std::vector<const producer_factory_t> g_factories;\r
\r
safe_ptr<basic_frame> receive_and_follow(safe_ptr<frame_producer>& producer)\r
{ \r
return frame;\r
}\r
\r
-std::wostream& operator<<(std::wostream& out, const frame_producer& producer)\r
-{\r
- out << producer.print().c_str();\r
- return out;\r
-}\r
-\r
-std::wostream& operator<<(std::wostream& out, const safe_ptr<const frame_producer>& producer)\r
-{\r
- out << producer->print().c_str();\r
- return out;\r
-}\r
-\r
void register_producer_factory(const producer_factory_t& factory)\r
{\r
- tbb::spin_rw_mutex::scoped_lock(p_factories_mutex, true);\r
- p_factories.push_back(factory);\r
+ g_factories.push_back(factory);\r
}\r
\r
safe_ptr<core::frame_producer> create_producer(const safe_ptr<frame_factory>& my_frame_factory, const std::vector<std::wstring>& params)\r
if(params.empty())\r
BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));\r
\r
- tbb::spin_rw_mutex::scoped_lock(p_factories_mutex, false);\r
auto producer = frame_producer::empty();\r
- std::any_of(p_factories.begin(), p_factories.end(), [&](const producer_factory_t& factory) -> bool\r
+ std::any_of(g_factories.begin(), g_factories.end(), [&](const producer_factory_t& factory) -> bool\r
{\r
try\r
{\r
#include <boost/noncopyable.hpp>\r
\r
#include <functional>\r
-#include <ostream>\r
#include <string>\r
\r
namespace caspar { namespace core {\r
\r
safe_ptr<basic_frame> receive_and_follow(safe_ptr<frame_producer>& producer);\r
\r
-std::wostream& operator<<(std::wostream& out, const frame_producer& producer);\r
-std::wostream& operator<<(std::wostream& out, const safe_ptr<const frame_producer>& producer);\r
-\r
typedef std::function<safe_ptr<core::frame_producer>(const safe_ptr<frame_factory>&, const std::vector<std::wstring>&)> producer_factory_t;\r
-\r
-void register_producer_factory(const producer_factory_t& factory);\r
+void register_producer_factory(const producer_factory_t& factory); // Not thread-safe.\r
safe_ptr<core::frame_producer> create_producer(const safe_ptr<frame_factory>&, const std::vector<std::wstring>& params);\r
\r
\r
{ \r
background_ = producer;\r
\r
- if(preview)\r
+ if(preview) \r
{\r
+ // Play the first frame and pause.\r
play();\r
receive();\r
pause();\r
layer::layer(const layer& other) : impl_(new implementation(*other.impl_)){}\r
layer& layer::operator=(const layer& other)\r
{\r
- layer tmp(other);\r
- tmp.swap(*this);\r
+ layer temp(other);\r
+ temp.swap(*this);\r
return *this;\r
}\r
void layer::swap(layer& other)\r
safe_ptr<frame_producer> dest_producer_;\r
safe_ptr<frame_producer> source_producer_;\r
\r
- transition_producer(const video_format_desc& format_desc, const safe_ptr<frame_producer>& dest, const transition_info& info) \r
+ explicit transition_producer(const video_format_desc& format_desc, const safe_ptr<frame_producer>& dest, const transition_info& info) \r
: format_desc_(format_desc)\r
, current_frame_(0)\r
, info_(info)\r
, dest_producer_(dest)\r
, source_producer_(frame_producer::empty()){}\r
- \r
- safe_ptr<frame_producer> get_following_producer() const\r
+ \r
+ // frame_producer\r
+\r
+ virtual safe_ptr<frame_producer> get_following_producer() const\r
{\r
return dest_producer_;\r
}\r
\r
- void set_leading_producer(const safe_ptr<frame_producer>& producer)\r
+ virtual void set_leading_producer(const safe_ptr<frame_producer>& producer)\r
{\r
source_producer_ = producer;\r
}\r
\r
- safe_ptr<basic_frame> receive()\r
+ virtual safe_ptr<basic_frame> receive()\r
{\r
if(current_frame_++ >= info_.duration)\r
return basic_frame::eof();\r
\r
return compose(dest, source);\r
}\r
+\r
+ virtual std::wstring print() const\r
+ {\r
+ return L"transition";\r
+ }\r
+\r
+ // transition_producer\r
\r
safe_ptr<basic_frame> compose(const safe_ptr<basic_frame>& dest_frame, const safe_ptr<basic_frame>& src_frame) \r
{ \r
\r
return basic_frame(s_frame, d_frame);\r
}\r
-\r
- std::wstring print() const\r
- {\r
- return L"transition";\r
- }\r
};\r
\r
safe_ptr<frame_producer> create_transition_producer(const video_format_desc& format_desc, const safe_ptr<frame_producer>& destination, const transition_info& info)\r
unsigned long frames_scheduled_;\r
unsigned long audio_scheduled_;\r
\r
- tbb::concurrent_bounded_queue<safe_ptr<const core::read_frame>> video_frame_buffer_;\r
- tbb::concurrent_bounded_queue<safe_ptr<const core::read_frame>> audio_frame_buffer_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<const core::read_frame>> video_frame_buffer_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<const core::read_frame>> audio_frame_buffer_;\r
\r
public:\r
decklink_output(const core::video_format_desc& format_desc,size_t device_index, bool embed_audio, bool internalKey) \r
audio_frame_buffer_.set_capacity(buffer_size);\r
for(size_t n = 0; n < std::max<size_t>(2, buffer_size-2); ++n)\r
{\r
- video_frame_buffer_.try_push(safe_ptr<const core::read_frame>());\r
+ video_frame_buffer_.try_push(core::read_frame::empty());\r
if(embed_audio_)\r
- audio_frame_buffer_.try_push(safe_ptr<const core::read_frame>());\r
+ audio_frame_buffer_.try_push(core::read_frame::empty());\r
}\r
\r
if(FAILED(output_->StartScheduledPlayback(0, frame_time_scale_, 1.0))) \r
if(!is_running_)\r
return S_OK;\r
\r
- safe_ptr<const core::read_frame> frame; \r
+ std::shared_ptr<const core::read_frame> frame; \r
video_frame_buffer_.pop(frame); \r
- schedule_next_video(frame);\r
+ schedule_next_video(safe_ptr<const core::read_frame>(frame));\r
\r
return S_OK;\r
}\r
if(!is_running_)\r
return S_OK;\r
\r
- safe_ptr<const core::read_frame> frame;\r
+ std::shared_ptr<const core::read_frame> frame;\r
audio_frame_buffer_.pop(frame);\r
- schedule_next_audio(frame);\r
+ schedule_next_audio(safe_ptr<const core::read_frame>(frame));\r
\r
return S_OK;\r
}\r
\r
int main(int argc, wchar_t* argv[])\r
{ \r
+ static_assert(sizeof(void*) == 4, "64-bit code generation is not supported.");\r
+ \r
// Install unstructured exception handler.\r
caspar::win32_exception::install_handler();\r
\r
async_servers_.push_back(asyncbootstrapper);\r
}\r
else\r
- BOOST_THROW_EXCEPTION(invalid_bootstrapper() << arg_name_info(name) << msg_info("Invalid controller."));\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << arg_name_info(name) << msg_info("Invalid controller."));\r
}\r
catch(...)\r
{\r
else if(name == "CLOCK")\r
return make_safe<CLK::CLKProtocolStrategy>(channels_);\r
\r
- BOOST_THROW_EXCEPTION(invalid_bootstrapper() << arg_name_info("name") << arg_value_info(name) << msg_info("Invalid protocol"));\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << arg_name_info("name") << arg_value_info(name) << msg_info("Invalid protocol"));\r
}\r
};\r
\r
#include <vector>\r
\r
namespace caspar {\r
-\r
-std::vector<safe_ptr<core::channel>> initialize_channels();\r
- \r
-struct invalid_bootstrapper : virtual boost::exception, virtual std::exception {};\r
-\r
+ \r
class server : boost::noncopyable\r
{\r
public:\r