\r
}\r
\r
-enum priority\r
+enum task_priority\r
{\r
high_priority,\r
normal_priority,\r
priority_count\r
};\r
\r
-enum priority_class\r
+enum thread_priority\r
{\r
high_priority_class,\r
above_normal_priority_class,\r
execution_queue_[normal_priority].set_capacity(capacity);\r
}\r
\r
- void set_priority_class(priority_class p)\r
+ void set_priority_class(thread_priority p)\r
{\r
begin_invoke([=]\r
{\r
}\r
\r
template<typename Func>\r
- auto begin_invoke(Func&& func, priority priority = normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
+ auto begin_invoke(Func&& func, task_priority priority = normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
{ \r
// Create a move on copy adaptor to avoid copying the functor into the queue, tbb::concurrent_queue does not support move semantics.\r
auto task_adaptor = internal::make_move_on_copy(create_task(func));\r
}\r
\r
template<typename Func>\r
- auto try_begin_invoke(Func&& func, priority priority = normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
+ auto try_begin_invoke(Func&& func, task_priority priority = normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
{\r
// Create a move on copy adaptor to avoid copying the functor into the queue, tbb::concurrent_queue does not support move semantics.\r
auto task_adaptor = internal::make_move_on_copy(create_task(func));\r
}\r
\r
template<typename Func>\r
- auto invoke(Func&& func, priority prioriy = normal_priority) -> decltype(func()) // noexcept\r
+ auto invoke(Func&& func, task_priority prioriy = normal_priority) -> decltype(func()) // noexcept\r
{\r
if(boost::this_thread::get_id() == thread_.get_id()) // Avoids potential deadlock.\r
return func();\r
}\r
\r
template<typename Func>\r
- auto try_invoke(Func&& func, priority prioriy = normal_priority) -> decltype(func()) // noexcept\r
+ auto try_invoke(Func&& func, task_priority prioriy = normal_priority) -> decltype(func()) // noexcept\r
{\r
if(boost::this_thread::get_id() == thread_.get_id()) // Avoids potential deadlock.\r
return func();\r
#include <string>\r
#include <vector>\r
\r
+static const size_t CONSUMER_BUFFER_DEPTH = 7;\r
+\r
namespace caspar { namespace core {\r
\r
class read_frame;\r
\r
video_channel_context& channel_;\r
\r
- boost::circular_buffer<fill_and_key> buffer_;\r
-\r
std::map<int, safe_ptr<frame_consumer>> consumers_;\r
typedef std::map<int, safe_ptr<frame_consumer>>::value_type layer_t;\r
\r
this->remove(index);\r
consumers_.insert(std::make_pair(index, consumer));\r
\r
- auto depth = buffer_depth();\r
- auto diff = depth.second-depth.first+1;\r
- \r
- if(diff != buffer_.capacity())\r
- {\r
- buffer_.set_capacity(diff);\r
- CASPAR_LOG(info) << print() << L" Depth-diff: " << diff-1;\r
- }\r
-\r
CASPAR_LOG(info) << print() << L" " << consumer->print() << L" Added.";\r
});\r
}\r
});\r
}\r
\r
- void operator()(const safe_ptr<read_frame>& frame)\r
+ void execute(const safe_ptr<read_frame>& frame)\r
{ \r
if(!has_synchronization_clock())\r
timer_.tick(1.0/channel_.get_format_desc().fps);\r
\r
frame_timer_.restart();\r
- \r
- buffer_.push_back(std::make_pair(frame, get_key_frame(frame)));\r
- if(!buffer_.full())\r
- return;\r
- \r
+ \r
+ auto fill = frame;\r
+ auto key = get_key_frame(frame);\r
+\r
for_each_consumer([&](safe_ptr<frame_consumer>& consumer)\r
{\r
if(consumer->get_video_format_desc() != channel_.get_format_desc())\r
consumer->initialize(channel_.get_format_desc());\r
\r
- auto pair = buffer_[consumer->buffer_depth()-buffer_depth().first];\r
- auto frame = consumer->key_only() ? pair.second : pair.first;\r
+ auto frame = consumer->key_only() ? key : fill;\r
\r
if(static_cast<size_t>(frame->image_data().size()) == consumer->get_video_format_desc().size)\r
consumer->send(frame);\r
: impl_(new implementation(video_channel)){}\r
void frame_consumer_device::add(int index, safe_ptr<frame_consumer>&& consumer){impl_->add(index, std::move(consumer));}\r
void frame_consumer_device::remove(int index){impl_->remove(index);}\r
-void frame_consumer_device::operator()(const safe_ptr<read_frame>& frame) { (*impl_)(frame); }\r
+void frame_consumer_device::execute(const safe_ptr<read_frame>& frame) {impl_->execute(frame); }\r
}}
\ No newline at end of file
void add(int index, safe_ptr<frame_consumer>&& consumer);\r
void remove(int index);\r
\r
- void operator()(const safe_ptr<read_frame>& frame); // nothrow\r
+ void execute(const safe_ptr<read_frame>& frame); // nothrow\r
private:\r
struct implementation;\r
safe_ptr<implementation> impl_;\r
CASPAR_LOG(info) << print() << L" Successfully initialized."; \r
}\r
\r
- safe_ptr<read_frame> operator()(const std::map<int, safe_ptr<core::basic_frame>>& frames)\r
+ safe_ptr<read_frame> execute(const std::map<int, safe_ptr<core::basic_frame>>& frames)\r
{ \r
frame_timer_.restart();\r
\r
};\r
\r
frame_mixer_device::frame_mixer_device(video_channel_context& video_channel) : impl_(new implementation(video_channel)){}\r
-safe_ptr<core::read_frame> frame_mixer_device::operator()(const std::map<int, safe_ptr<core::basic_frame>>& frames){ return (*impl_)(frames);}\r
+safe_ptr<core::read_frame> frame_mixer_device::execute(const std::map<int, safe_ptr<core::basic_frame>>& frames){ return impl_->execute(frames);}\r
core::video_format_desc frame_mixer_device::get_video_format_desc() const { return impl_->channel_.get_format_desc(); }\r
safe_ptr<core::write_frame> frame_mixer_device::create_frame(void* tag, const core::pixel_format_desc& desc){ return impl_->create_frame(tag, desc); } \r
safe_ptr<core::write_frame> frame_mixer_device::create_frame(void* tag, size_t width, size_t height, core::pixel_format::type pix_fmt)\r
public: \r
explicit frame_mixer_device(video_channel_context& video_channel);\r
\r
- safe_ptr<core::read_frame> operator()(const std::map<int, safe_ptr<core::basic_frame>>& frames); // nothrow\r
+ safe_ptr<core::read_frame> execute(const std::map<int, safe_ptr<core::basic_frame>>& frames); // nothrow\r
\r
safe_ptr<core::write_frame> create_frame(void* tag, const core::pixel_format_desc& desc); \r
safe_ptr<core::write_frame> create_frame(void* tag, size_t width, size_t height, core::pixel_format::type pix_fmt = core::pixel_format::bgra); \r
~ogl_device();\r
\r
template<typename Func>\r
- auto begin_invoke(Func&& func, priority priority = normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
+ auto begin_invoke(Func&& func, task_priority priority = normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
{ \r
return executor_.begin_invoke(std::forward<Func>(func), priority);\r
}\r
\r
template<typename Func>\r
- auto invoke(Func&& func, priority priority = normal_priority) -> decltype(func())\r
+ auto invoke(Func&& func, task_priority priority = normal_priority) -> decltype(func())\r
{\r
return executor_.invoke(std::forward<Func>(func), priority);\r
}\r
const boost::iterator_range<const uint8_t*> read_frame::image_data() const{return impl_->image_data();}\r
const boost::iterator_range<const int16_t*> read_frame::audio_data() const{return impl_->audio_data();}\r
\r
+safe_ptr<const read_frame> read_frame::empty()\r
+{\r
+ struct empty : public read_frame\r
+ { \r
+ virtual const boost::iterator_range<const uint8_t*> image_data() const {return boost::iterator_range<const uint8_t*>();}\r
+ virtual const boost::iterator_range<const int16_t*> audio_data() const {return boost::iterator_range<const int16_t*>();}\r
+ virtual int number() const{return -1;}\r
+ };\r
+ static safe_ptr<const empty> frame;\r
+ return frame;\r
+}\r
+\r
}}
\ No newline at end of file
virtual const boost::iterator_range<const uint8_t*> image_data() const;\r
virtual const boost::iterator_range<const int16_t*> audio_data() const;\r
\r
- static safe_ptr<const read_frame> empty()\r
- {\r
- struct empty : public read_frame\r
- { \r
- virtual const boost::iterator_range<const uint8_t*> image_data() const {return boost::iterator_range<const uint8_t*>();}\r
- virtual const boost::iterator_range<const int16_t*> audio_data() const {return boost::iterator_range<const int16_t*>();}\r
- virtual int number() const{return -1;}\r
- };\r
- static safe_ptr<const empty> frame;\r
- return frame;\r
- }\r
+ static safe_ptr<const read_frame> empty();\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
diag_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f)); \r
}\r
\r
- std::map<int, safe_ptr<basic_frame>> operator()()\r
+ std::map<int, safe_ptr<basic_frame>> execute()\r
{ \r
frame_timer_.restart();\r
\r
void frame_producer_device::swap_layer(int index, size_t other_index, frame_producer_device& other){impl_->swap_layer(index, other_index, other);}\r
boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::foreground(size_t index) {return impl_->foreground(index);}\r
boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::background(size_t index) {return impl_->background(index);}\r
-std::map<int, safe_ptr<basic_frame>> frame_producer_device::operator()(){return (*impl_)();}\r
+std::map<int, safe_ptr<basic_frame>> frame_producer_device::execute(){return impl_->execute();}\r
}}
\ No newline at end of file
\r
void swap(frame_producer_device& other);\r
\r
- std::map<int, safe_ptr<basic_frame>> operator()();\r
+ std::map<int, safe_ptr<basic_frame>> execute();\r
\r
void load(int index, const safe_ptr<frame_producer>& producer, bool preview = false);\r
void pause(int index);\r
\r
struct video_channel::implementation : boost::noncopyable\r
{\r
- video_channel_context context_;\r
+ video_channel_context context_;\r
\r
safe_ptr<frame_consumer_device> consumer_;\r
safe_ptr<frame_mixer_device> mixer_;\r
\r
void tick()\r
{\r
- auto simple_frames = (*producer_)();\r
- auto finished_frame = (*mixer_)(simple_frames);\r
- (*consumer_)(finished_frame);\r
+ auto simple_frames = producer_->execute();\r
+ auto finished_frame = mixer_->execute(simple_frames);\r
+ consumer_->execute(finished_frame);\r
\r
context_.execution().begin_invoke([this]{tick();});\r
}\r
ogl_device& ogl_;\r
\r
public:\r
- video_channel_context(int index, ogl_device& ogl, const video_format_desc& format_desc) \r
+ video_channel_context(int index, ogl_device& ogl, const video_format_desc& format_desc) \r
: index_(index)\r
, format_desc_(format_desc)\r
, execution_(print() + L"/execution")\r
\r
executor executor_;\r
public:\r
- bluefish_consumer(const core::video_format_desc& format_desc, unsigned int device_index, bool embedded_audio, size_t buffer_depth) \r
+ bluefish_consumer(const core::video_format_desc& format_desc, unsigned int device_index, bool embedded_audio) \r
: blue_(create_blue(device_index))\r
, device_index_(device_index)\r
, format_desc_(format_desc) \r
, embedded_audio_(embedded_audio)\r
, executor_(print())\r
{\r
- executor_.set_capacity(buffer_depth);\r
+ executor_.set_capacity(CONSUMER_BUFFER_DEPTH);\r
\r
graph_ = diagnostics::create_graph(narrow(print()));\r
graph_->add_guide("tick-time", 0.5);\r
\r
~bluefish_consumer()\r
{\r
- executor_.clear();\r
executor_.invoke([&]\r
{\r
disable_video_output();\r
const size_t device_index_;\r
const bool embedded_audio_;\r
bool key_only_;\r
- size_t buffer_depth_;\r
public:\r
\r
- bluefish_consumer_proxy(size_t device_index, bool embedded_audio, bool key_only, size_t buffer_depth)\r
+ bluefish_consumer_proxy(size_t device_index, bool embedded_audio, bool key_only)\r
: device_index_(device_index)\r
, embedded_audio_(embedded_audio)\r
- , key_only_(key_only)\r
- , buffer_depth_(buffer_depth){}\r
+ , key_only_(key_only){}\r
\r
virtual void initialize(const core::video_format_desc& format_desc)\r
{\r
- consumer_.reset(new bluefish_consumer(format_desc, device_index_, embedded_audio_, buffer_depth_));\r
+ consumer_.reset(new bluefish_consumer(format_desc, device_index_, embedded_audio_));\r
}\r
\r
virtual void send(const safe_ptr<const core::read_frame>& frame)\r
{\r
return key_only_;\r
}\r
-\r
- virtual size_t buffer_depth() const\r
- {\r
- return consumer_->executor_.capacity();\r
- }\r
}; \r
\r
std::wstring get_bluefish_version()\r
bool embedded_audio = std::find(params.begin(), params.end(), L"EMBEDDED_AUDIO") != params.end();\r
bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();\r
\r
- return make_safe<bluefish_consumer_proxy>(device_index, embedded_audio, key_only, 3);\r
+ return make_safe<bluefish_consumer_proxy>(device_index, embedded_audio, key_only);\r
}\r
\r
safe_ptr<core::frame_consumer> create_bluefish_consumer(const boost::property_tree::ptree& ptree) \r
auto device_index = ptree.get("device", 1);\r
auto embedded_audio = ptree.get("embedded-audio", false);\r
bool key_only = ptree.get("key-only", false);\r
- size_t buffer_depth = ptree.get("buffer-depth", 3);\r
\r
- return make_safe<bluefish_consumer_proxy>(device_index, embedded_audio, key_only, buffer_depth);\r
+ return make_safe<bluefish_consumer_proxy>(device_index, embedded_audio, key_only);\r
}\r
\r
}
\ No newline at end of file
, external_key(false)\r
, low_latency(false)\r
, key_only(false)\r
- , buffer_depth(5){}\r
+ , buffer_depth(CONSUMER_BUFFER_DEPTH){}\r
};\r
\r
class decklink_frame_adapter : public IDeckLinkVideoFrame\r
config.key_only = ptree.get("key-only", config.key_only);\r
config.device_index = ptree.get("device", config.device_index);\r
config.embedded_audio = ptree.get("embedded-audio", config.embedded_audio);\r
- config.buffer_depth = ptree.get("buffer-depth", config.buffer_depth);\r
\r
return make_safe<decklink_consumer_proxy>(config);\r
}\r
\r
namespace caspar { \r
\r
-safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const std::vector<std::wstring>& params);\r
-safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const boost::property_tree::ptree& ptree);\r
+//safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const std::vector<std::wstring>& params);\r
+//safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const boost::property_tree::ptree& ptree);\r
\r
}
\ No newline at end of file
av_register_all();\r
avcodec_init();\r
\r
- core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_ffmpeg_consumer(params);});\r
+ //core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_ffmpeg_consumer(params);});\r
core::register_producer_factory(create_ffmpeg_producer);\r
}\r
\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
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">true</ExcludedFromBuild>\r
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">true</ExcludedFromBuild>\r
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="ffmpeg.cpp" />\r
<ClCompile Include="producer\audio\audio_decoder.cpp">\r
tbb::atomic<bool> is_running_;\r
\r
core::video_format_desc format_desc_;\r
+ int preroll_count_;\r
public:\r
implementation(const core::video_format_desc& format_desc) \r
: graph_(diagnostics::create_graph(narrow(print())))\r
, container_(5)\r
, format_desc_(format_desc)\r
+ , preroll_count_(0)\r
{\r
graph_->add_guide("tick-time", 0.5);\r
graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
is_running_ = true;\r
- input_.set_capacity(4);\r
-\r
- // Fill input buffer with silence.\r
- for(size_t n = 0; n < buffer_depth(); ++n)\r
- input_.push(std::vector<short>(static_cast<size_t>(48000.0f/format_desc_.fps)*2, 0)); \r
-\r
+ input_.set_capacity(CONSUMER_BUFFER_DEPTH-2);\r
+ \r
sf::SoundStream::Initialize(2, 48000);\r
Play(); \r
CASPAR_LOG(info) << print() << " Sucessfully initialized.";\r
}\r
\r
void send(const safe_ptr<const core::read_frame>& frame)\r
- { \r
+ { \r
+ if(preroll_count_ < input_.capacity())\r
+ {\r
+ while(input_.try_push(std::vector<short>(static_cast<size_t>(48000.0f/format_desc_.fps)*2, 0)))\r
+ ++preroll_count_;\r
+ }\r
+\r
if(!frame->audio_data().empty())\r
input_.push(std::vector<short>(frame->audio_data().begin(), frame->audio_data().end())); \r
else\r
channels_.back()->consumer()->add(index++, create_bluefish_consumer(xml_consumer.second)); \r
else if(name == "decklink") \r
channels_.back()->consumer()->add(index++, create_decklink_consumer(xml_consumer.second)); \r
- else if(name == "file") \r
- channels_.back()->consumer()->add(index++, create_ffmpeg_consumer(xml_consumer.second)); \r
+ //else if(name == "file") \r
+ // channels_.back()->consumer()->add(index++, create_ffmpeg_consumer(xml_consumer.second)); \r
else if(name == "audio")\r
channels_.back()->consumer()->add(index++, make_safe<oal_consumer>()); \r
else if(name != "<xmlcomment>")\r