\r
#include "../exception/exceptions.h"\r
#include "../exception/win32_exception.h"\r
+#include "../log/log.h"\r
\r
#include <boost/thread.hpp>\r
\r
#include <tbb/concurrent_queue.h>\r
\r
#include <functional>\r
+#include <array>\r
\r
namespace caspar {\r
\r
return is_running_;\r
}\r
\r
- void stop() // noexcept\r
+ void stop(bool wait = true) // noexcept\r
{\r
is_running_ = false; \r
begin_invoke([]{}); // wake if sleeping\r
- assert(boost::this_thread::get_id() != thread_.get_id());\r
- thread_.join();\r
+ if(wait && boost::this_thread::get_id() != thread_.get_id())\r
+ thread_.join();\r
}\r
\r
void execute() // noexcept\r
\r
return std::move(future); \r
}\r
+\r
+ size_t size() const\r
+ {\r
+ return execution_queue_.size();\r
+ }\r
+\r
+ bool empty() const\r
+ {\r
+ return execution_queue_.empty();\r
+ }\r
\r
template<typename Func>\r
auto invoke(Func&& func, priority p = normal_priority) -> decltype(func())\r
default:\r
BOOST_THROW_EXCEPTION(invalid_argument() << msg_info("Unsupported format.") << arg_name_info("format"));\r
}\r
- if(width < 2 || height < 2)\r
+ if(width < 1 || height < 1)\r
BOOST_THROW_EXCEPTION(invalid_argument() << msg_info("Invalid dimensions.") << arg_name_info("width/height"));\r
}\r
\r
\r
#include "../common/utility/string_convert.h"\r
#include "../common/utility/safe_ptr.h"\r
+//#include "../common/concurrency/executor.h" // Can't include this due to MSVC lambda bug\r
+#include "../common/concurrency/concurrent_queue.h"\r
\r
#include "../common/log/Log.h"\r
#include "../common/exception/exceptions.h"\r
producer_device_->clear();\r
}\r
\r
- void load(int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option = load_option::none)\r
+ void load(int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay)\r
{\r
- producer_device_->load(render_layer, producer, option);\r
+ producer_device_->load(render_layer, producer, autoplay);\r
+ }\r
+\r
+ void preview(int render_layer, const safe_ptr<frame_producer>& producer)\r
+ {\r
+ producer_device_->preview(render_layer, producer);\r
}\r
\r
void pause(int render_layer)\r
channel::channel(channel&& other) : impl_(std::move(other.impl_)){}\r
channel::channel(const safe_ptr<frame_producer_device>& producer_device, const safe_ptr<frame_processor_device>& processor_device, const safe_ptr<frame_consumer_device>& consumer_device)\r
: impl_(new implementation(producer_device, processor_device, consumer_device)){}\r
-void channel::load(int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option){impl_->load(render_layer, producer, option);}\r
+void channel::load(int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay){impl_->load(render_layer, producer, autoplay);}\r
+void channel::preview(int render_layer, const safe_ptr<frame_producer>& producer){impl_->preview(render_layer, producer);}\r
void channel::pause(int render_layer){impl_->pause(render_layer);}\r
void channel::play(int render_layer){impl_->play(render_layer);}\r
void channel::stop(int render_layer){impl_->stop(render_layer);}\r
channel(channel&& other);\r
channel(const safe_ptr<frame_producer_device>& producer_device, const safe_ptr<frame_processor_device>& processor_device, const safe_ptr<frame_consumer_device>& consumer_device);\r
\r
- void load(int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option = load_option::none);\r
+ void load(int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay = false);\r
+ void preview(int render_layer, const safe_ptr<frame_producer>& producer);\r
void pause(int render_layer);\r
void play(int render_layer);\r
void stop(int render_layer);\r
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">debug\</IntDir>\r
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">release\</IntDir>\r
- <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\dependencies\BluefishSDK_V5_8_0_31\Inc\;..\..\..\dependencies\BluefishSDK_V5_8_0_31\Inc\;..\..\dependencies\boost_1_44_0\;..\..\..\dependencies\boost_1_44_0\;..\..\dependencies\ffmpeg 0.6\include\;..\..\..\dependencies\ffmpeg 0.6\include\;..\..\dependencies\FreeImage\Dist\;..\..\..\dependencies\FreeImage\Dist\;..\..\dependencies\GLee5_4\;..\..\..\dependencies\GLee5_4\;..\..\dependencies\SFML-1.6\include\;..\..\..\dependencies\SFML-1.6\include\;..\..\dependencies\tbb30_20100406oss\include\;..\..\..\dependencies\tbb30_20100406oss\include\;$(IncludePath)</IncludePath>\r
- <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\dependencies\BluefishSDK_V5_8_0_31\Inc\;..\..\..\dependencies\BluefishSDK_V5_8_0_31\Inc\;..\..\dependencies\boost_1_44_0\;..\..\..\dependencies\boost_1_44_0\;..\..\dependencies\ffmpeg 0.6\include\;..\..\..\dependencies\ffmpeg 0.6\include\;..\..\dependencies\FreeImage\Dist\;..\..\..\dependencies\FreeImage\Dist\;..\..\dependencies\GLee5_4\;..\..\..\dependencies\GLee5_4\;..\..\dependencies\SFML-1.6\include\;..\..\..\dependencies\SFML-1.6\include\;..\..\dependencies\tbb30_20100406oss\include\;..\..\..\dependencies\tbb30_20100406oss\include\;$(IncludePath)</IncludePath>\r
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\common;..\..\dependencies\BluefishSDK_V5_8_0_31\Inc\;..\..\..\dependencies\BluefishSDK_V5_8_0_31\Inc\;..\..\dependencies\boost_1_44_0\;..\..\..\dependencies\boost_1_44_0\;..\..\dependencies\ffmpeg 0.6\include\;..\..\..\dependencies\ffmpeg 0.6\include\;..\..\dependencies\FreeImage\Dist\;..\..\..\dependencies\FreeImage\Dist\;..\..\dependencies\GLee5_4\;..\..\..\dependencies\GLee5_4\;..\..\dependencies\SFML-1.6\include\;..\..\..\dependencies\SFML-1.6\include\;..\..\dependencies\tbb30_20100406oss\include\;..\..\..\dependencies\tbb30_20100406oss\include\;$(IncludePath)</IncludePath>\r
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\common;..\..\dependencies\BluefishSDK_V5_8_0_31\Inc\;..\..\..\dependencies\BluefishSDK_V5_8_0_31\Inc\;..\..\dependencies\boost_1_44_0\;..\..\..\dependencies\boost_1_44_0\;..\..\dependencies\ffmpeg 0.6\include\;..\..\..\dependencies\ffmpeg 0.6\include\;..\..\dependencies\FreeImage\Dist\;..\..\..\dependencies\FreeImage\Dist\;..\..\dependencies\GLee5_4\;..\..\..\dependencies\GLee5_4\;..\..\dependencies\SFML-1.6\include\;..\..\..\dependencies\SFML-1.6\include\;..\..\dependencies\tbb30_20100406oss\include\;..\..\..\dependencies\tbb30_20100406oss\include\;$(IncludePath)</IncludePath>\r
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\dependencies\BluefishSDK_V5_8_0_31\Lib\;..\..\..\dependencies\BluefishSDK_V5_8_0_31\Lib\;..\..\dependencies\boost_1_44_0\stage\lib\;..\..\..\dependencies\boost_1_44_0\stage\lib\;..\..\dependencies\ffmpeg 0.6\lib\;..\..\..\dependencies\ffmpeg 0.6\lib\;..\..\dependencies\FreeImage\Dist\;..\..\..\dependencies\FreeImage\Dist\;..\..\dependencies\GLee5_4\;..\..\..\dependencies\GLee5_4\;..\..\dependencies\SFML-1.6\lib\;..\..\..\dependencies\SFML-1.6\lib\;..\..\dependencies\tbb30_20100406oss\lib\ia32\vc10\;..\..\..\dependencies\tbb30_20100406oss\lib\ia32\vc10\;$(LibraryPath)</LibraryPath>\r
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\dependencies\BluefishSDK_V5_8_0_31\Lib\;..\..\..\dependencies\BluefishSDK_V5_8_0_31\Lib\;..\..\dependencies\boost_1_44_0\stage\lib\;..\..\..\dependencies\boost_1_44_0\stage\lib\;..\..\dependencies\ffmpeg 0.6\lib\;..\..\..\dependencies\ffmpeg 0.6\lib\;..\..\dependencies\FreeImage\Dist\;..\..\..\dependencies\FreeImage\Dist\;..\..\dependencies\GLee5_4\;..\..\..\dependencies\GLee5_4\;..\..\dependencies\SFML-1.6\lib\;..\..\..\dependencies\SFML-1.6\lib\;..\..\dependencies\tbb30_20100406oss\lib\ia32\vc10\;..\..\..\dependencies\tbb30_20100406oss\lib\ia32\vc10\;$(LibraryPath)</LibraryPath>\r
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)debug\</OutDir>\r
<ClInclude Include="producer\ffmpeg\ffmpeg_producer.h" />\r
<ClInclude Include="producer\ffmpeg\input.h" />\r
<ClInclude Include="producer\ffmpeg\video\video_decoder.h" />\r
- <ClInclude Include="producer\ffmpeg\video\video_transformer.h" />\r
<ClInclude Include="producer\flash\axflash.h" />\r
<ClInclude Include="producer\flash\bitmap.h" />\r
<ClInclude Include="producer\flash\cg_producer.h" />\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
<ClCompile Include="producer\ffmpeg\video\video_decoder.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../../stdafx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../../stdafx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
- <ClCompile Include="producer\ffmpeg\video\video_transformer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../../stdafx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../../stdafx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
<ClInclude Include="producer\ffmpeg\ffmpeg_producer.h">\r
<Filter>Source\channel\producer\ffmpeg</Filter>\r
</ClInclude>\r
- <ClInclude Include="producer\ffmpeg\audio\audio_decoder.h">\r
- <Filter>Source\channel\producer\ffmpeg\audio</Filter>\r
- </ClInclude>\r
- <ClInclude Include="producer\ffmpeg\video\video_decoder.h">\r
- <Filter>Source\channel\producer\ffmpeg\video</Filter>\r
- </ClInclude>\r
<ClInclude Include="producer\image\image_loader.h">\r
<Filter>Source\channel\producer\image</Filter>\r
</ClInclude>\r
<ClInclude Include="producer\frame_producer.h">\r
<Filter>Source\channel\producer</Filter>\r
</ClInclude>\r
- <ClInclude Include="producer\ffmpeg\video\video_transformer.h">\r
- <Filter>Source\channel\producer\ffmpeg\video</Filter>\r
- </ClInclude>\r
<ClInclude Include="producer\flash\cg_producer.h">\r
<Filter>Source\channel\producer\flash</Filter>\r
</ClInclude>\r
<ClInclude Include="processor\read_frame.h">\r
<Filter>Source\channel\processor\frame</Filter>\r
</ClInclude>\r
- <ClInclude Include="producer\ffmpeg\input.h">\r
- <Filter>Source\channel\producer\ffmpeg\io</Filter>\r
- </ClInclude>\r
<ClInclude Include="processor\draw_frame.h">\r
<Filter>Source\channel\processor\frame</Filter>\r
</ClInclude>\r
<ClInclude Include="processor\audio_processor.h">\r
<Filter>Source\channel\processor\audio</Filter>\r
</ClInclude>\r
+ <ClInclude Include="producer\ffmpeg\audio\audio_decoder.h">\r
+ <Filter>Source\channel\producer\ffmpeg\audio</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="producer\ffmpeg\input.h">\r
+ <Filter>Source\channel\producer\ffmpeg\io</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="producer\ffmpeg\video\video_decoder.h">\r
+ <Filter>Source\channel\producer\ffmpeg\video</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="StdAfx.cpp">\r
<ClCompile Include="producer\ffmpeg\ffmpeg_producer.cpp">\r
<Filter>Source\channel\producer\ffmpeg</Filter>\r
</ClCompile>\r
- <ClCompile Include="producer\ffmpeg\audio\audio_decoder.cpp">\r
- <Filter>Source\channel\producer\ffmpeg\audio</Filter>\r
- </ClCompile>\r
- <ClCompile Include="producer\ffmpeg\video\video_decoder.cpp">\r
- <Filter>Source\channel\producer\ffmpeg\video</Filter>\r
- </ClCompile>\r
<ClCompile Include="producer\image\image_loader.cpp">\r
<Filter>Source\channel\producer\image</Filter>\r
</ClCompile>\r
<ClCompile Include="protocol\media.cpp">\r
<Filter>Source\protocol</Filter>\r
</ClCompile>\r
- <ClCompile Include="producer\ffmpeg\video\video_transformer.cpp">\r
- <Filter>Source\channel\producer\ffmpeg\video</Filter>\r
- </ClCompile>\r
<ClCompile Include="producer\flash\cg_producer.cpp">\r
<Filter>Source\channel\producer\flash</Filter>\r
</ClCompile>\r
<ClCompile Include="processor\read_frame.cpp">\r
<Filter>Source\channel\processor\frame</Filter>\r
</ClCompile>\r
- <ClCompile Include="producer\ffmpeg\input.cpp">\r
- <Filter>Source\channel\producer\ffmpeg\io</Filter>\r
- </ClCompile>\r
<ClCompile Include="format\pixel_format.cpp">\r
<Filter>Source\channel\format</Filter>\r
</ClCompile>\r
<ClCompile Include="processor\audio_processor.cpp">\r
<Filter>Source\channel\processor\audio</Filter>\r
</ClCompile>\r
+ <ClCompile Include="producer\ffmpeg\audio\audio_decoder.cpp">\r
+ <Filter>Source\channel\producer\ffmpeg\audio</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="producer\ffmpeg\input.cpp">\r
+ <Filter>Source\channel\producer\ffmpeg\io</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="producer\ffmpeg\video\video_decoder.cpp">\r
+ <Filter>Source\channel\producer\ffmpeg\video</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<Midl Include="consumer\decklink\DeckLinkAPI_v7_3.idl">\r
#pragma once\r
\r
#include <memory>\r
-#include <array>\r
+#include <vector>\r
\r
namespace caspar { namespace core {\r
\r
\r
#include "../format/video_format.h"\r
\r
-#include "../../common/exception/exceptions.h"\r
-#include "../../common/concurrency/executor.h"\r
-#include "../../common/gl/utility.h"\r
-\r
+#include <common/exception/exceptions.h>\r
+#include <common/concurrency/executor.h>\r
+#include <common/gl/utility.h>\r
\r
#include <tbb/concurrent_queue.h>\r
#include <tbb/concurrent_unordered_map.h>\r
\r
#include <boost/range/algorithm.hpp>\r
-#include <boost/thread.hpp>\r
-\r
-#include <functional>\r
\r
namespace caspar { namespace core {\r
\r
safe_ptr<const read_frame> frame_processor_device::receive(){return impl_->receive();}\r
const video_format_desc& frame_processor_device::get_video_format_desc() const { return impl_->fmt_; }\r
safe_ptr<write_frame> frame_processor_device::create_frame(const pixel_format_desc& desc){ return impl_->create_frame(desc); } \r
-safe_ptr<write_frame> frame_processor_device::create_frame(size_t width, size_t height)\r
+safe_ptr<write_frame> frame_processor_device::create_frame(size_t width, size_t height, pixel_format::type pix_fmt)\r
{\r
// Create bgra frame\r
pixel_format_desc desc;\r
- desc.pix_fmt = pixel_format::bgra;\r
+ desc.pix_fmt = pix_fmt;\r
desc.planes.push_back(pixel_format_desc::plane(width, height, 4));\r
return create_frame(desc);\r
}\r
\r
-safe_ptr<write_frame> frame_processor_device::create_frame()\r
+safe_ptr<write_frame> frame_processor_device::create_frame(pixel_format::type pix_fmt)\r
{\r
// Create bgra frame with output resolution\r
pixel_format_desc desc;\r
- desc.pix_fmt = pixel_format::bgra;\r
+ desc.pix_fmt = pix_fmt;\r
desc.planes.push_back(pixel_format_desc::plane(get_video_format_desc().width, get_video_format_desc().height, 4));\r
return create_frame(desc);\r
}\r
*/\r
#pragma once\r
\r
-#include <memory>\r
-#include <vector>\r
-\r
#include "fwd.h"\r
+\r
#include "write_frame.h"\r
\r
#include "../format/video_format.h"\r
\r
-namespace caspar { namespace core {\r
+#include <common/utility/safe_ptr.h>\r
+\r
+#include <memory>\r
\r
+namespace caspar { namespace core {\r
+ \r
class frame_processor_device : boost::noncopyable\r
{\r
public:\r
- frame_processor_device(frame_processor_device&& other);\r
+ frame_processor_device(frame_processor_device&& other); // nothrow\r
frame_processor_device(const video_format_desc& format_desc);\r
\r
- void send(safe_ptr<draw_frame>&& frame);\r
+ void send(safe_ptr<draw_frame>&& frame); // nothrow\r
safe_ptr<const read_frame> receive();\r
- \r
+ \r
safe_ptr<write_frame> create_frame(const pixel_format_desc& desc); \r
- safe_ptr<write_frame> create_frame(size_t width, size_t height); \r
- safe_ptr<write_frame> create_frame();\r
+ safe_ptr<write_frame> create_frame(size_t width, size_t height, pixel_format::type pix_fmt = pixel_format::bgra); \r
+ safe_ptr<write_frame> create_frame(pixel_format::type pix_fmt = pixel_format::bgra);\r
\r
- const video_format_desc& get_video_format_desc() const;\r
+ const video_format_desc& get_video_format_desc() const; // nothrow\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
class read_frame;\r
class write_frame;\r
class draw_frame;\r
-\r
-class draw_frame;\r
-\r
class transform_frame;\r
class composite_frame;\r
\r
class frame_processor;\r
class audio_processor;\r
class frame_processor_device;\r
+\r
}}
\ No newline at end of file
{\r
transform_stack_.pop();\r
set_mode(transform_stack_.top().mode);\r
+ glColor4d(1.0, 1.0, 1.0, transform_stack_.top().alpha);\r
glPopMatrix();\r
}\r
\r
#include "color_producer.h"\r
\r
#include "../../processor/draw_frame.h"\r
-#include "../../format/video_format.h"\r
\r
-#include <intrin.h>\r
-#pragma intrinsic(__movsd, __stosd)\r
+#include <sstream>\r
\r
namespace caspar { namespace core {\r
\r
-unsigned int get_pixel_color_value(const std::wstring& parameter)\r
-{\r
- union Color \r
- {\r
- struct Components \r
- {\r
- unsigned char a;\r
- unsigned char r;\r
- unsigned char g;\r
- unsigned char b;\r
- } comp;\r
-\r
- unsigned int value;\r
- };\r
-\r
- std::wstring color_code;\r
- if(parameter.length() != 9 || parameter[0] != '#')\r
- BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("parameter") << arg_value_info(narrow(parameter)) << msg_info("Invalid color code"));\r
- \r
- color_code = parameter.substr(1);\r
-\r
- Color color;\r
- color.value = _tcstoul(color_code.c_str(), 0, 16);\r
- unsigned char temp = color.comp.a;\r
- color.comp.a = color.comp.b;\r
- color.comp.b = temp;\r
- temp = color.comp.r;\r
- color.comp.r = color.comp.g;\r
- color.comp.g = temp;\r
-\r
- return color.value;\r
-}\r
-\r
class color_producer : public frame_producer\r
{\r
public:\r
- color_producer(color_producer&& other) : frame_(std::move(other.frame_)), color_value_(std::move(other.color_value_)), color_str_(std::move(other.color_str_)){}\r
- explicit color_producer(const std::wstring& color) : color_str_(color), color_value_(get_pixel_color_value(color)), frame_(draw_frame::empty()){}\r
- \r
- safe_ptr<draw_frame> receive()\r
- { \r
- return frame_;\r
+ color_producer(color_producer&& other) : frame_(std::move(other.frame_)), color_str_(std::move(other.color_str_)){}\r
+\r
+ explicit color_producer(const std::wstring& color) : color_str_(color), frame_(draw_frame::empty())\r
+ {\r
+ if(color.length() != 9 || color[0] != '#')\r
+ BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("color") << arg_value_info(narrow(color)) << msg_info("Invalid color code"));\r
}\r
+ \r
+ safe_ptr<draw_frame> receive() { return frame_; }\r
\r
void initialize(const safe_ptr<frame_processor_device>& frame_processor)\r
{\r
- auto frame = std::move(frame_processor->create_frame());\r
- __stosd(reinterpret_cast<unsigned long*>(frame->pixel_data().begin()), color_value_, frame->pixel_data().size() / sizeof(unsigned long));\r
+ auto frame = frame_processor->create_frame(1, 1, pixel_format::bgra);\r
+ auto& value = *reinterpret_cast<unsigned long*>(frame->pixel_data().begin());\r
+ std::wstringstream str(color_str_.substr(1));\r
+ str >> std::hex >> value; \r
frame_ = std::move(frame);\r
}\r
\r
- std::wstring print() const\r
- {\r
- return + L"color[" + color_str_ + L"]";\r
- }\r
+ std::wstring print() const { return + L"color[" + color_str_ + L"]"; }\r
\r
safe_ptr<draw_frame> frame_;\r
- unsigned int color_value_;\r
std::wstring color_str_;\r
};\r
\r
#include "audio_decoder.h"\r
\r
#include <queue>\r
+#include <deque>\r
\r
#include <tbb/cache_aligned_allocator.h>\r
\r
static const int FRAME_AUDIO_SAMPLES = 1920*2;\r
static const int SAMPLE_RATE = 48000;\r
\r
- implementation(AVCodecContext* codec_context) \r
- : current_chunk_(), codec_context_(codec_context), audio_resample_buffer_(4*SAMPLE_RATE*2+FF_INPUT_BUFFER_PADDING_SIZE/2),\r
- audio_buffer_(4*SAMPLE_RATE*2+FF_INPUT_BUFFER_PADDING_SIZE/2)/*, resample_context_(nullptr)*/\r
+ implementation(AVCodecContext* codec_context) : current_chunk_(), codec_context_(codec_context), audio_resample_buffer_(4*SAMPLE_RATE*2+FF_INPUT_BUFFER_PADDING_SIZE/2),\r
+ audio_buffer_(4*SAMPLE_RATE*2+FF_INPUT_BUFFER_PADDING_SIZE/2)//, resample_context_(nullptr)\r
{\r
//if(codec_context_->sample_rate != SAMPLE_RATE)\r
//{\r
buffer audio_buffer_; \r
buffer audio_resample_buffer_;\r
\r
- std::deque<short, tbb::cache_aligned_allocator<short>> current_chunk_;\r
+ std::vector<short, tbb::cache_aligned_allocator<short>> current_chunk_;\r
\r
- std::vector<short, tbb::cache_aligned_allocator<short>> current_resample_chunk_;\r
+ //std::vector<short, tbb::cache_aligned_allocator<short>> current_resample_chunk_;\r
\r
AVCodecContext* codec_context_;\r
};\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
-typedef std::shared_ptr<audio_decoder> audio_decoder_ptr;\r
\r
}}}
\ No newline at end of file
\r
#include "audio/audio_decoder.h"\r
#include "video/video_decoder.h"\r
-#include "video/video_transformer.h"\r
+#include "video/video_decoder.h"\r
\r
#include "../../format/video_format.h"\r
#include "../../processor/transform_frame.h"\r
{\r
public:\r
ffmpeg_producer_impl(const std::wstring& filename, const std::vector<std::wstring>& params) : filename_(filename), last_frame_(transform_frame(draw_frame::empty())), underrun_count_(0),\r
- input_(filename), video_decoder_(input_.get_video_codec_context().get()), video_transformer_(input_.get_video_codec_context().get()), audio_decoder_(input_.get_audio_codec_context().get())\r
+ input_(filename), video_decoder_(input_.get_video_codec_context().get()), audio_decoder_(input_.get_audio_codec_context().get())\r
{ \r
input_.set_loop(std::find(params.begin(), params.end(), L"LOOP") != params.end());\r
\r
void initialize(const safe_ptr<frame_processor_device>& frame_processor)\r
{\r
format_desc_ = frame_processor->get_video_format_desc();\r
- video_transformer_.initialize(frame_processor);\r
+ video_decoder_.initialize(frame_processor);\r
}\r
\r
safe_ptr<draw_frame> receive()\r
{ // Video Decoding and Scaling\r
if(!video_packet.empty())\r
{\r
- auto decoded_frame = video_decoder_.execute(video_packet);\r
- auto frame = video_transformer_.execute(decoded_frame);\r
+ auto frame = video_decoder_.execute(video_packet);\r
video_frame_channel_.push_back(std::move(frame)); \r
}\r
}, \r
input input_; \r
audio_decoder audio_decoder_;\r
video_decoder video_decoder_;\r
- video_transformer video_transformer_;\r
\r
std::deque<safe_ptr<write_frame>> video_frame_channel_; \r
std::deque<std::vector<short>> audio_chunk_channel_;\r
\r
#include "../frame_producer.h"\r
\r
+#include <common/utility/safe_ptr.h>\r
+\r
#include <string>\r
#include <vector>\r
\r
#include "input.h"\r
\r
#include "../../format/video_format.h"\r
-#include "../../../common/utility/scope_exit.h"\r
#include "../../../common/concurrency/concurrent_queue.h"\r
\r
#include <tbb/concurrent_queue.h>\r
#pragma warning (disable : 4244)\r
#endif\r
\r
-#include <boost/thread.hpp>\r
+#include "../../../common/concurrency/executor.h"\r
\r
extern "C" \r
{\r
\r
namespace caspar { namespace core { namespace ffmpeg{\r
\r
-struct input::implementation : public std::enable_shared_from_this<implementation>, boost::noncopyable\r
+struct input::implementation : boost::noncopyable\r
{\r
static const size_t BUFFER_SIZE = 2 << 25;\r
\r
\r
video_codec_context_ = open_stream(CODEC_TYPE_VIDEO, video_s_index_);\r
if(!video_codec_context_)\r
- CASPAR_LOG(warning) << "No video stream found.";\r
+ CASPAR_LOG(warning) << "Could not open any video stream.";\r
\r
audio_codex_context_ = open_stream(CODEC_TYPE_AUDIO, audio_s_index_);\r
if(!audio_codex_context_)\r
- CASPAR_LOG(warning) << "No audio stream found.";\r
+ CASPAR_LOG(warning) << "Could not open any audio stream.";\r
\r
if(!video_codec_context_ && !audio_codex_context_)\r
BOOST_THROW_EXCEPTION(file_read_error() << msg_info("No video or audio codec context found.")); \r
- \r
- is_running_ = true;\r
- io_thread_ = boost::thread([=]{read_file();});\r
+ \r
+ executor_.start();\r
+ executor_.begin_invoke([this]{read_file();});\r
+ CASPAR_LOG(info) << print() << " Started";\r
}\r
\r
- void stop()\r
- { \r
- is_running_ = false;\r
- buffer_size_ = 0;\r
- cond_.notify_one();\r
+ ~implementation()\r
+ {\r
+ CASPAR_LOG(info) << print() << " Ended";\r
}\r
- \r
+ \r
std::shared_ptr<AVCodecContext> open_stream(int codec_type, int& s_index)\r
{ \r
AVStream** streams_end = format_context_->streams+format_context_->nb_streams;\r
return std::shared_ptr<AVCodecContext>((*stream)->codec, avcodec_close);\r
}\r
\r
- void read_file()\r
- { \r
- static tbb::atomic<size_t> instances(boost::initialized_value); // Dangling threads debug info.\r
-\r
- CASPAR_LOG(info) << L"ffmpeg[" << boost::filesystem::wpath(filename_).filename().c_str() << L"] Started file buffer thread. Instances: " << ++instances;\r
- win32_exception::install_handler();\r
- \r
- try\r
+ void read_file() // For every packet taken: read in a number of packets.\r
+ { \r
+ for(size_t n = 0; (n < 3 || video_packet_buffer_.size() < 3 || audio_packet_buffer_.size() < 3) && buffer_size_ < BUFFER_SIZE && executor_.is_running(); ++n)\r
{\r
- auto keep_alive = shared_from_this(); // keep alive this while thread is running.\r
- while(keep_alive->is_running_)\r
+ AVPacket tmp_packet;\r
+ safe_ptr<AVPacket> read_packet(&tmp_packet, av_free_packet); \r
+ tbb::queuing_mutex::scoped_lock lock(seek_mutex_); \r
+\r
+ if (av_read_frame(format_context_.get(), read_packet.get()) >= 0) // NOTE: read_packet is only valid until next call of av_safe_ptr<read_frame> or av_close_input_file\r
{\r
+ auto packet = aligned_buffer(read_packet->data, read_packet->data + read_packet->size);\r
+ if(read_packet->stream_index == video_s_index_) \r
{\r
- AVPacket tmp_packet;\r
- safe_ptr<AVPacket> read_packet(&tmp_packet, av_free_packet); \r
- tbb::queuing_mutex::scoped_lock lock(seek_mutex_); \r
-\r
- if (av_read_frame(format_context_.get(), read_packet.get()) >= 0) // NOTE: read_packet is only valid until next call of av_safe_ptr<read_frame> or av_close_input_file\r
- {\r
- auto packet = aligned_buffer(read_packet->data, read_packet->data + read_packet->size);\r
- if(read_packet->stream_index == video_s_index_) \r
- {\r
- buffer_size_ += packet.size();\r
- video_packet_buffer_.try_push(std::move(packet)); \r
- }\r
- else if(read_packet->stream_index == audio_s_index_) \r
- {\r
- buffer_size_ += packet.size();\r
- audio_packet_buffer_.try_push(std::move(packet));\r
- }\r
- }\r
- else if(!loop_ || av_seek_frame(format_context_.get(), -1, 0, AVSEEK_FLAG_BACKWARD) < 0) // TODO: av_seek_frame does not work for all formats\r
- is_running_ = false;\r
+ buffer_size_ += packet.size();\r
+ video_packet_buffer_.try_push(std::move(packet)); \r
}\r
-\r
- if(!need_packet() && is_running_)\r
- boost::this_thread::sleep(boost::posix_time::milliseconds(10)); // Read packets in max 100 pps\r
-\r
- if(buffer_size_ >= BUFFER_SIZE)\r
+ else if(read_packet->stream_index == audio_s_index_) \r
{\r
- boost::unique_lock<boost::mutex> lock(mut_);\r
- while(buffer_size_ >= BUFFER_SIZE && !need_packet() && is_running_)\r
- cond_.wait(lock);\r
+ buffer_size_ += packet.size();\r
+ audio_packet_buffer_.try_push(std::move(packet));\r
}\r
}\r
+ else if(!loop_ || av_seek_frame(format_context_.get(), -1, 0, AVSEEK_FLAG_BACKWARD) < 0) // TODO: av_seek_frame does not work for all formats\r
+ executor_.stop(false);\r
}\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- }\r
- \r
- is_running_ = false;\r
- \r
- CASPAR_LOG(info) << L"ffmpeg[" << boost::filesystem::wpath(filename_).filename().c_str() << L"] Ended file buffer thread. Instances: " << --instances;\r
- }\r
-\r
- bool need_packet()\r
- {\r
- return video_packet_buffer_.size() < 3 || audio_packet_buffer_.size() < 3;\r
}\r
- \r
+ \r
aligned_buffer get_video_packet()\r
{\r
return get_packet(video_packet_buffer_);\r
if(buffer.try_pop(packet))\r
{\r
buffer_size_ -= packet.size();\r
- cond_.notify_one();\r
+ if(executor_.size() < 4) // Avoid problems when in underrun.\r
+ executor_.begin_invoke([this]{read_file();});\r
}\r
return std::move(packet);\r
}\r
\r
bool is_eof() const\r
{\r
- return !is_running_ && video_packet_buffer_.empty() && audio_packet_buffer_.empty();\r
+ return !executor_.is_running() && video_packet_buffer_.empty() && audio_packet_buffer_.empty();\r
}\r
\r
// TODO: Not properly done.\r
avcodec_flush_buffers(audio_codex_context_.get());\r
return true;\r
}\r
+\r
+ std::wstring print() const\r
+ {\r
+ return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"] Buffering ";\r
+ }\r
\r
std::shared_ptr<AVFormatContext> format_context_; // Destroy this last\r
\r
concurrent_bounded_queue_r<aligned_buffer> video_packet_buffer_;\r
concurrent_bounded_queue_r<aligned_buffer> audio_packet_buffer_;\r
\r
- boost::mutex mut_;\r
- boost::condition_variable cond_;\r
tbb::atomic<size_t> buffer_size_;\r
\r
- boost::thread io_thread_;\r
- tbb::atomic<bool> is_running_;\r
+ executor executor_;\r
};\r
\r
input::input(const std::wstring& filename) : impl_(new implementation(filename)){}\r
-input::~input(){impl_->stop();}\r
void input::set_loop(bool value){impl_->loop_ = value;}\r
const std::shared_ptr<AVCodecContext>& input::get_video_codec_context() const{return impl_->video_codec_context_;}\r
const std::shared_ptr<AVCodecContext>& input::get_audio_codec_context() const{return impl_->audio_codex_context_;}\r
#pragma once\r
\r
-#include <system_error>\r
-\r
#include <tbb/cache_aligned_allocator.h>\r
\r
+#include <memory>\r
+#include <string>\r
+\r
struct AVCodecContext;\r
\r
namespace caspar { namespace core { namespace ffmpeg{ \r
{\r
public:\r
input(const std::wstring& filename);\r
- ~input();\r
const std::shared_ptr<AVCodecContext>& get_video_codec_context() const;\r
const std::shared_ptr<AVCodecContext>& get_audio_codec_context() const;\r
\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
-typedef std::shared_ptr<input> input_ptr;\r
-typedef std::unique_ptr<input> input_uptr;\r
\r
}\r
}}\r
\r
#include "video_decoder.h"\r
\r
-#include "../../../../common/exception/exceptions.h"\r
- \r
+#include "../../../format/video_format.h"\r
+#include "../../../processor/draw_frame.h"\r
+#include "../../../processor/frame_processor_device.h"\r
+\r
+#include <common/utility/safe_ptr.h>\r
+\r
+#include <tbb/parallel_for.h>\r
+\r
+#include <algorithm>\r
+\r
#if defined(_MSC_VER)\r
#pragma warning (push)\r
#pragma warning (disable : 4244)\r
{\r
#define __STDC_CONSTANT_MACROS\r
#define __STDC_LIMIT_MACROS\r
+ #include <libswscale/swscale.h>\r
#include <libavformat/avformat.h>\r
}\r
#if defined(_MSC_VER)\r
#pragma warning (pop)\r
#endif\r
\r
-namespace caspar { namespace core { namespace ffmpeg{\r
+namespace caspar { namespace core { namespace ffmpeg {\r
+ \r
+pixel_format::type get_pixel_format(PixelFormat pix_fmt)\r
+{\r
+ switch(pix_fmt)\r
+ {\r
+ case PIX_FMT_BGRA: return pixel_format::bgra;\r
+ case PIX_FMT_ARGB: return pixel_format::argb;\r
+ case PIX_FMT_RGBA: return pixel_format::rgba;\r
+ case PIX_FMT_ABGR: return pixel_format::abgr;\r
+ case PIX_FMT_YUV444P: return pixel_format::ycbcr;\r
+ case PIX_FMT_YUV422P: return pixel_format::ycbcr;\r
+ case PIX_FMT_YUV420P: return pixel_format::ycbcr;\r
+ case PIX_FMT_YUV411P: return pixel_format::ycbcr;\r
+ case PIX_FMT_YUV410P: return pixel_format::ycbcr;\r
+ case PIX_FMT_YUVA420P: return pixel_format::ycbcra;\r
+ default: return pixel_format::invalid;\r
+ }\r
+}\r
+\r
+pixel_format_desc get_pixel_format_desc(PixelFormat pix_fmt, size_t width, size_t height)\r
+{\r
+ // Get linesizes\r
+ AVPicture dummy_pict; \r
+ avpicture_fill(&dummy_pict, nullptr, pix_fmt, width, height);\r
+\r
+ pixel_format_desc desc;\r
+ desc.pix_fmt = get_pixel_format(pix_fmt);\r
+ \r
+ switch(desc.pix_fmt)\r
+ {\r
+ case pixel_format::bgra:\r
+ case pixel_format::argb:\r
+ case pixel_format::rgba:\r
+ case pixel_format::abgr:\r
+ {\r
+ desc.planes.push_back(pixel_format_desc::plane(dummy_pict.linesize[0]/4, height, 4)); \r
+ return desc;\r
+ }\r
+ case pixel_format::ycbcr:\r
+ case pixel_format::ycbcra:\r
+ { \r
+ // Find chroma height\r
+ size_t size2 = dummy_pict.data[2] - dummy_pict.data[1];\r
+ size_t h2 = size2/dummy_pict.linesize[1]; \r
+\r
+ desc.planes.push_back(pixel_format_desc::plane(dummy_pict.linesize[0], height, 1));\r
+ desc.planes.push_back(pixel_format_desc::plane(dummy_pict.linesize[1], h2, 1));\r
+ desc.planes.push_back(pixel_format_desc::plane(dummy_pict.linesize[2], h2, 1));\r
+\r
+ if(desc.pix_fmt == pixel_format::ycbcra) \r
+ desc.planes.push_back(pixel_format_desc::plane(dummy_pict.linesize[3], height, 1)); \r
+ return desc;\r
+ } \r
+ default: \r
+ desc.pix_fmt = pixel_format::invalid;\r
+ return desc;\r
+ }\r
+}\r
\r
struct video_decoder::implementation : boost::noncopyable\r
{\r
- implementation(AVCodecContext* codec_context) : codec_context_(codec_context){}\r
+ implementation(AVCodecContext* codec_context) : codec_context_(codec_context), width_(codec_context_->width), height_(codec_context_->height), \r
+ pix_fmt_(codec_context_->pix_fmt), desc_(get_pixel_format_desc(pix_fmt_, width_, height_))\r
+ {\r
+ if(desc_.pix_fmt == pixel_format::invalid)\r
+ {\r
+ CASPAR_LOG(warning) << "Hardware accelerated color transform not supported.";\r
\r
- safe_ptr<AVFrame> execute(const aligned_buffer& video_packet)\r
- { \r
+ double param;\r
+ sws_context_.reset(sws_getContext(width_, height_, pix_fmt_, width_, height_, PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, ¶m), sws_freeContext);\r
+ if(!sws_context_)\r
+ BOOST_THROW_EXCEPTION( operation_failed() <<\r
+ msg_info("Could not create software scaling context.") << \r
+ boost::errinfo_api_function("sws_getContext"));\r
+ }\r
+ }\r
+ \r
+ safe_ptr<write_frame> execute(const aligned_buffer& video_packet)\r
+ { \r
safe_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\r
\r
int frame_finished = 0;\r
if(result < 0)\r
BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("avcodec_decode_video failed"));\r
\r
- return decoded_frame; \r
+ if(sws_context_ == nullptr)\r
+ {\r
+ auto write = frame_processor_->create_frame(desc_);\r
+\r
+ tbb::parallel_for(0, static_cast<int>(desc_.planes.size()), 1, [&](int n)\r
+ {\r
+ auto plane = desc_.planes[n];\r
+ auto result = write->pixel_data(n).begin();\r
+ auto decoded = decoded_frame->data[n];\r
+ auto decoded_linesize = decoded_frame->linesize[n];\r
+ \r
+ tbb::parallel_for(0, static_cast<int>(desc_.planes[n].height), 1, [&](int y)\r
+ {\r
+ std::copy_n(decoded + y*decoded_linesize, plane.linesize, result + y*plane.linesize);\r
+ });\r
+ });\r
+\r
+ return std::move(write);\r
+ }\r
+ else\r
+ {\r
+ auto write = frame_processor_->create_frame(width_, height_);\r
+\r
+ AVFrame av_frame; \r
+ avcodec_get_frame_defaults(&av_frame);\r
+ avpicture_fill(reinterpret_cast<AVPicture*>(&av_frame), write->pixel_data().begin(), PIX_FMT_BGRA, width_, height_);\r
+ \r
+ sws_scale(sws_context_.get(), decoded_frame->data, decoded_frame->linesize, 0, height_, av_frame.data, av_frame.linesize); \r
+ \r
+ return std::move(write);\r
+ } \r
+ }\r
+\r
+ void initialize(const safe_ptr<frame_processor_device>& frame_processor)\r
+ {\r
+ frame_processor_ = frame_processor;\r
}\r
\r
+ std::shared_ptr<frame_processor_device> frame_processor_;\r
+ std::shared_ptr<SwsContext> sws_context_;\r
+\r
AVCodecContext* codec_context_;\r
+\r
+ int width_;\r
+ int height_;\r
+ PixelFormat pix_fmt_;\r
+ pixel_format_desc desc_;\r
};\r
\r
video_decoder::video_decoder(AVCodecContext* codec_context) : impl_(new implementation(codec_context)){}\r
-safe_ptr<AVFrame> video_decoder::execute(const aligned_buffer& video_packet){return impl_->execute(video_packet);}\r
+safe_ptr<write_frame> video_decoder::execute(const aligned_buffer& video_packet){return impl_->execute(video_packet);}\r
+void video_decoder::initialize(const safe_ptr<frame_processor_device>& frame_processor){impl_->initialize(frame_processor); }\r
}}}
\ No newline at end of file
#pragma once\r
\r
-#include <tbb/cache_aligned_allocator.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
+#include "../../../processor/frame_processor_device.h"\r
\r
#include <memory>\r
-#include <vector>\r
\r
struct AVCodecContext;\r
-struct AVFrame;\r
\r
-namespace caspar { namespace core { namespace ffmpeg{\r
+namespace caspar { namespace core { namespace ffmpeg {\r
\r
typedef std::vector<unsigned char, tbb::cache_aligned_allocator<unsigned char>> aligned_buffer;\r
\r
{\r
public:\r
video_decoder(AVCodecContext* codec_context);\r
- safe_ptr<AVFrame> execute(const aligned_buffer& video_packet);\r
+ safe_ptr<write_frame> execute(const aligned_buffer& video_packet); \r
+ void initialize(const safe_ptr<frame_processor_device>& frame_processor);\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
-typedef std::shared_ptr<video_decoder> video_decoder_ptr;\r
-typedef std::unique_ptr<video_decoder> video_decoder_uptr;\r
\r
- }\r
-}}
\ No newline at end of file
+}}}
\ No newline at end of file
+++ /dev/null
-#include "../../../stdafx.h"\r
-\r
-#include "video_transformer.h"\r
-\r
-#include "../../../format/video_format.h"\r
-#include "../../../processor/draw_frame.h"\r
-#include "../../../processor/frame_processor_device.h"\r
-\r
-#include <tbb/parallel_for.h>\r
-\r
-#include <algorithm>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
- #define __STDC_CONSTANT_MACROS\r
- #define __STDC_LIMIT_MACROS\r
- #include <libswscale/swscale.h>\r
- #include <libavformat/avformat.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar { namespace core { namespace ffmpeg {\r
- \r
-pixel_format::type get_pixel_format(PixelFormat pix_fmt)\r
-{\r
- switch(pix_fmt)\r
- {\r
- case PIX_FMT_BGRA: return pixel_format::bgra;\r
- case PIX_FMT_ARGB: return pixel_format::argb;\r
- case PIX_FMT_RGBA: return pixel_format::rgba;\r
- case PIX_FMT_ABGR: return pixel_format::abgr;\r
- case PIX_FMT_YUV444P: return pixel_format::ycbcr;\r
- case PIX_FMT_YUV422P: return pixel_format::ycbcr;\r
- case PIX_FMT_YUV420P: return pixel_format::ycbcr;\r
- case PIX_FMT_YUV411P: return pixel_format::ycbcr;\r
- case PIX_FMT_YUV410P: return pixel_format::ycbcr;\r
- case PIX_FMT_YUVA420P: return pixel_format::ycbcra;\r
- default: return pixel_format::invalid;\r
- }\r
-}\r
-\r
-pixel_format_desc get_pixel_format_desc(PixelFormat pix_fmt, size_t width, size_t height)\r
-{\r
- // Get linesizes\r
- AVPicture dummy_pict; \r
- avpicture_fill(&dummy_pict, nullptr, pix_fmt, width, height);\r
-\r
- pixel_format_desc desc;\r
- desc.pix_fmt = get_pixel_format(pix_fmt);\r
- \r
- switch(desc.pix_fmt)\r
- {\r
- case pixel_format::bgra:\r
- case pixel_format::argb:\r
- case pixel_format::rgba:\r
- case pixel_format::abgr:\r
- {\r
- desc.planes.push_back(pixel_format_desc::plane(dummy_pict.linesize[0]/4, height, 4)); \r
- return desc;\r
- }\r
- case pixel_format::ycbcr:\r
- case pixel_format::ycbcra:\r
- { \r
- // Find chroma height\r
- size_t size2 = dummy_pict.data[2] - dummy_pict.data[1];\r
- size_t h2 = size2/dummy_pict.linesize[1]; \r
-\r
- desc.planes.push_back(pixel_format_desc::plane(dummy_pict.linesize[0], height, 1));\r
- desc.planes.push_back(pixel_format_desc::plane(dummy_pict.linesize[1], h2, 1));\r
- desc.planes.push_back(pixel_format_desc::plane(dummy_pict.linesize[2], h2, 1));\r
-\r
- if(desc.pix_fmt == pixel_format::ycbcra) \r
- desc.planes.push_back(pixel_format_desc::plane(dummy_pict.linesize[3], height, 1)); \r
- return desc;\r
- } \r
- default: \r
- desc.pix_fmt = pixel_format::invalid;\r
- return desc;\r
- }\r
-}\r
-\r
-struct video_transformer::implementation : boost::noncopyable\r
-{\r
- implementation(AVCodecContext* codec_context) : codec_context_(codec_context), width_(codec_context_->width), height_(codec_context_->height), \r
- pix_fmt_(codec_context_->pix_fmt), desc_(get_pixel_format_desc(pix_fmt_, width_, height_))\r
- {\r
- if(desc_.pix_fmt == pixel_format::invalid)\r
- {\r
- CASPAR_LOG(warning) << "Hardware accelerated color transform not supported.";\r
-\r
- double param;\r
- sws_context_.reset(sws_getContext(width_, height_, pix_fmt_, width_, height_, PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, ¶m), sws_freeContext);\r
- if(!sws_context_)\r
- BOOST_THROW_EXCEPTION( operation_failed() <<\r
- msg_info("Could not create software scaling context.") << \r
- boost::errinfo_api_function("sws_getContext"));\r
- }\r
- }\r
- \r
- safe_ptr<write_frame> execute(const safe_ptr<AVFrame>& decoded_frame)\r
- { \r
- if(sws_context_ == nullptr)\r
- {\r
- auto write = frame_processor_->create_frame(desc_);\r
-\r
- tbb::parallel_for(0, static_cast<int>(desc_.planes.size()), 1, [&](int n)\r
- {\r
- auto plane = desc_.planes[n];\r
- auto result = write->pixel_data(n).begin();\r
- auto decoded = decoded_frame->data[n];\r
- auto decoded_linesize = decoded_frame->linesize[n];\r
- \r
- tbb::parallel_for(0, static_cast<int>(desc_.planes[n].height), 1, [&](int y)\r
- {\r
- std::copy_n(decoded + y*decoded_linesize, plane.linesize, result + y*plane.linesize);\r
- });\r
- });\r
-\r
- return std::move(write);\r
- }\r
- else\r
- {\r
- auto write = frame_processor_->create_frame(width_, height_);\r
-\r
- AVFrame av_frame; \r
- avcodec_get_frame_defaults(&av_frame);\r
- avpicture_fill(reinterpret_cast<AVPicture*>(&av_frame), write->pixel_data().begin(), PIX_FMT_BGRA, width_, height_);\r
- \r
- sws_scale(sws_context_.get(), decoded_frame->data, decoded_frame->linesize, 0, height_, av_frame.data, av_frame.linesize); \r
- \r
- return std::move(write);\r
- } \r
- }\r
-\r
- void initialize(const safe_ptr<frame_processor_device>& frame_processor)\r
- {\r
- frame_processor_ = frame_processor;\r
- }\r
- \r
- std::shared_ptr<frame_processor_device> frame_processor_;\r
- std::shared_ptr<SwsContext> sws_context_;\r
-\r
- AVCodecContext* codec_context_;\r
-\r
- int width_;\r
- int height_;\r
- PixelFormat pix_fmt_;\r
- pixel_format_desc desc_;\r
-};\r
-\r
-video_transformer::video_transformer(AVCodecContext* codec_context) : impl_(new implementation(codec_context)){}\r
-safe_ptr<write_frame> video_transformer::execute(const safe_ptr<AVFrame>& decoded_frame){return impl_->execute(decoded_frame);}\r
-void video_transformer::initialize(const safe_ptr<frame_processor_device>& frame_processor){impl_->initialize(frame_processor); }\r
-}}}
\ No newline at end of file
+++ /dev/null
-#pragma once\r
-\r
-#include "../../../processor/frame_processor_device.h"\r
-\r
-#include <memory>\r
-\r
-struct AVCodecContext;\r
-struct AVFrame;\r
-\r
-namespace caspar { namespace core { namespace ffmpeg{\r
-\r
-class video_transformer : boost::noncopyable\r
-{\r
-public:\r
- video_transformer(AVCodecContext* codec_context);\r
- safe_ptr<write_frame> execute(const safe_ptr<AVFrame>& video_packet); \r
- void initialize(const safe_ptr<frame_processor_device>& frame_processor);\r
-private:\r
- struct implementation;\r
- std::shared_ptr<implementation> impl_;\r
-};\r
-typedef std::shared_ptr<video_transformer> video_transformer_ptr;\r
-typedef std::unique_ptr<video_transformer> video_transformer_uptr;\r
-\r
-}}}
\ No newline at end of file
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
-typedef std::shared_ptr<bitmap> bitmap_ptr;\r
-typedef std::unique_ptr<bitmap> bitmap_uptr;\r
\r
}}\r
\r
#endif\r
\r
#include "cg_producer.h"\r
+\r
#include "flash_producer.h"\r
\r
#include "../../processor/draw_frame.h"\r
catch(std::bad_cast&)\r
{\r
auto producer = make_safe<cg_producer>(); \r
- channel->load(render_layer, producer, load_option::auto_play); \r
+ channel->load(render_layer, producer, true); \r
return producer;\r
}\r
}\r
\r
#include "../frame_producer.h"\r
\r
+#include <common/utility/safe_ptr.h>\r
+\r
+#include <string>\r
+\r
namespace caspar { namespace core { namespace flash{\r
\r
safe_ptr<frame_producer> create_ct_producer(const std::vector<std::wstring>& params);\r
\r
#include "../../format/video_format.h"\r
#include "../../server.h"\r
-#include "../../../common/concurrency/executor.h"\r
-#include "../../../common/concurrency/concurrent_queue.h"\r
\r
-#include "../../processor/draw_frame.h"\r
#include "../../processor/composite_frame.h"\r
\r
+#include <common/concurrency/executor.h>\r
+#include <common/concurrency/concurrent_queue.h>\r
+\r
#include <boost/filesystem.hpp>\r
#include <boost/thread.hpp>\r
\r
\r
void render()\r
{ \r
- while(frame_buffer_.size() < 3)\r
+ while(frame_buffer_.size() < 3) // Keep pipeline filled.\r
{\r
bool is_progressive = format_desc_.mode == video_mode::progressive || (ax_->GetFPS() - format_desc_.fps/2 == 0);\r
\r
\r
safe_ptr<draw_frame> render_frame()\r
{\r
- ax_->Tick();\r
+ if(!ax_->IsEmpty())\r
+ ax_->Tick();\r
\r
if(ax_->IsReadyToRender() && ax_->InvalidRectangle())\r
{\r
safe_ptr<draw_frame> receive()\r
{\r
auto frame = renderer_ ? renderer_->receive() : draw_frame::empty();\r
- executor_.begin_invoke([this]\r
+ if(executor_.size() < 4) // Avoid problems when in underrun.\r
{\r
- try\r
- {\r
- renderer_->render();\r
- }\r
- catch(...)\r
+ executor_.begin_invoke([this]\r
{\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- renderer_.reset();\r
- }\r
- });\r
+ try\r
+ {\r
+ renderer_->render();\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ renderer_.reset();\r
+ }\r
+ });\r
+ }\r
return frame;\r
}\r
\r
\r
#include "../frame_producer.h"\r
\r
-namespace caspar { namespace core {\r
+#include <memory>\r
\r
-class Monitor;\r
-\r
-namespace flash {\r
-\r
-class FlashAxContainer;\r
+namespace caspar { namespace core { namespace flash {\r
\r
///=================================================================================================\r
/// <summary> Flash Producer. </summary>\r
static std::wstring find_template(const std::wstring& templateName);\r
\r
private: \r
- friend class flash::FlashAxContainer;\r
-\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
\r
\r
#include "../processor/draw_frame.h"\r
#include "../processor/frame_processor_device.h"\r
-#include "../../common/utility/safe_ptr.h"\r
+\r
+#include <common/utility/safe_ptr.h>\r
\r
#include <boost/noncopyable.hpp>\r
\r
-#include <memory>\r
+#include <string>\r
+#include <ostream>\r
\r
namespace caspar { namespace core {\r
- \r
+\r
class frame_producer : boost::noncopyable\r
{\r
public:\r
///\r
/// \return The following producer, or nullptr if there is no following producer. \r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
- virtual safe_ptr<frame_producer> get_following_producer() const {return frame_producer::empty();}\r
+ virtual safe_ptr<frame_producer> get_following_producer() const {return frame_producer::empty();} // nothrow\r
\r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
/// \fn virtual void :::set_leading_producer(const std::shared_ptr<frame_producer>& producer)\r
///\r
/// \param producer The leading producer.\r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
- virtual void set_leading_producer(const safe_ptr<frame_producer>& /*producer*/) {}\r
+ virtual void set_leading_producer(const safe_ptr<frame_producer>& /*producer*/) {} // nothrow\r
\r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
/// \fn virtual void :::initialize(const safe_ptr<frame_processor_device>& frame_processor) = 0;\r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
virtual void initialize(const safe_ptr<frame_processor_device>& frame_processor) = 0;\r
\r
- static safe_ptr<frame_producer> empty()\r
+ static safe_ptr<frame_producer> empty() // nothrow\r
{\r
struct empty_frame_producer : public frame_producer\r
{\r
\r
#include "layer.h"\r
\r
-#include "../format/video_format.h"\r
#include "../processor/composite_frame.h"\r
#include "../processor/draw_frame.h"\r
+#include "../processor/frame_processor_device.h"\r
\r
-#include "../../common/utility/scope_exit.h"\r
-#include "../../common/concurrency/executor.h"\r
+#include <common/concurrency/executor.h>\r
\r
#include <boost/thread.hpp>\r
#include <boost/range/algorithm_ext/erase.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/foreach.hpp>\r
\r
-#include <tbb/concurrent_vector.h>\r
#include <tbb/parallel_for.h>\r
-#include <tbb/mutex.h>\r
\r
namespace caspar { namespace core {\r
\r
executor_.begin_invoke([=]{tick();});\r
}\r
\r
- void load(int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option)\r
+ void load(int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay)\r
{\r
producer->initialize(frame_processor_);\r
executor_.begin_invoke([=]\r
{\r
auto it = layers_.insert(std::make_pair(render_layer, layer(render_layer))).first;\r
- it->second.load(producer, option);\r
+ it->second.load(producer, autoplay);\r
});\r
}\r
\r
+ void preview(int render_layer, const safe_ptr<frame_producer>& producer)\r
+ {\r
+ producer->initialize(frame_processor_);\r
+ executor_.begin_invoke([=]\r
+ {\r
+ auto it = layers_.insert(std::make_pair(render_layer, layer(render_layer))).first;\r
+ it->second.preview(producer);\r
+ });\r
+ }\r
+\r
void pause(int render_layer)\r
{ \r
executor_.begin_invoke([=]\r
{\r
auto it = layers_.find(render_layer);\r
if(it != layers_.end()) \r
+ {\r
it->second.stop(); \r
- if(it->second.empty())\r
- layers_.erase(it);\r
+ if(it->second.empty())\r
+ layers_.erase(it);\r
+ }\r
});\r
}\r
\r
\r
frame_producer_device::frame_producer_device(frame_producer_device&& other) : impl_(std::move(other.impl_)){}\r
frame_producer_device::frame_producer_device(const safe_ptr<frame_processor_device>& frame_processor) : impl_(new implementation(frame_processor)){}\r
-void frame_producer_device::load(int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option){impl_->load(render_layer, producer, option);}\r
+void frame_producer_device::load(int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay){impl_->load(render_layer, producer, autoplay);}\r
+void frame_producer_device::preview(int render_layer, const safe_ptr<frame_producer>& producer){impl_->preview(render_layer, producer);}\r
void frame_producer_device::pause(int render_layer){impl_->pause(render_layer);}\r
void frame_producer_device::play(int render_layer){impl_->play(render_layer);}\r
void frame_producer_device::stop(int render_layer){impl_->stop(render_layer);}\r
#pragma once\r
\r
-#include "../processor/frame_processor_device.h"\r
-#include "../consumer/frame_consumer.h"\r
+#include "frame_producer.h"\r
+\r
#include "../format/video_format.h"\r
\r
-#include "layer.h"\r
+#include <common/utility/safe_ptr.h>\r
\r
-#include <boost/thread.hpp>\r
+#include <boost/thread/future.hpp>\r
\r
-#include <functional>\r
+#include <memory>\r
\r
namespace caspar { namespace core {\r
+\r
+class frame_producer;\r
+class frame_processor_device;\r
+class layer;\r
\r
class frame_producer_device : boost::noncopyable\r
{ \r
public:\r
- frame_producer_device(frame_producer_device&& other);\r
- frame_producer_device(const safe_ptr<frame_processor_device>& frame_processor);\r
+ frame_producer_device(frame_producer_device&& other); // nothrow\r
+ frame_producer_device(const safe_ptr<frame_processor_device>& frame_processor); // nothrow\r
\r
- void load (int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option = load_option::none); \r
- void pause (int render_layer);\r
- void play (int render_layer);\r
- void stop (int render_layer);\r
- void clear (int render_layer);\r
- void clear ();\r
+ void load (int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay = false); // throws if producer->initialize throws\r
+ void preview(int render_layer, const safe_ptr<frame_producer>& producer); // throws if producer->initialize throws\r
+ void pause (int render_layer); // nothrow\r
+ void play (int render_layer); // nothrow\r
+ void stop (int render_layer); // nothrow\r
+ void clear (int render_layer); // nothrow\r
+ void clear (); // nothrow\r
\r
- boost::unique_future<safe_ptr<frame_producer>> foreground(int render_layer) const;\r
- boost::unique_future<safe_ptr<frame_producer>> background(int render_layer) const;\r
+ boost::unique_future<safe_ptr<frame_producer>> foreground(int render_layer) const; // nothrow\r
+ boost::unique_future<safe_ptr<frame_producer>> background(int render_layer) const; // nothrow\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
{ \r
implementation(size_t index) : foreground_(frame_producer::empty()), background_(frame_producer::empty()), last_frame_(draw_frame::empty()), index_(index) {}\r
\r
- void load(const safe_ptr<frame_producer>& frame_producer, load_option::type option)\r
+ void load(const safe_ptr<frame_producer>& frame_producer, bool autoplay)\r
{ \r
background_ = frame_producer;\r
- if(option == load_option::preview) \r
+ if(autoplay)\r
+ play(); \r
+ }\r
+\r
+ void preview(const safe_ptr<frame_producer>& frame_producer)\r
+ {\r
+ background_ = frame_producer;\r
+ foreground_ = frame_producer::empty(); \r
+ try\r
{\r
- foreground_ = frame_producer::empty(); \r
last_frame_ = frame_producer->receive();\r
}\r
- else if(option == load_option::auto_play)\r
- play(); \r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ CASPAR_LOG(warning) << L"layer[" << index_ << L"] Error. Removed " << foreground_->print() << L" from layer.";\r
+ background_ = frame_producer::empty();\r
+ last_frame_ = draw_frame::empty();\r
+ }\r
}\r
\r
void play()\r
}\r
catch(...)\r
{\r
- try\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- CASPAR_LOG(warning) << L"layer[" << index_ << L"] Error. Removed " << foreground_->print() << L" from layer.";\r
- foreground_ = frame_producer::empty();\r
- last_frame_ = draw_frame::empty();\r
- }\r
- catch(...){}\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ CASPAR_LOG(warning) << L"layer[" << index_ << L"] Error. Removed " << foreground_->print() << L" from layer.";\r
+ foreground_ = frame_producer::empty();\r
+ last_frame_ = draw_frame::empty();\r
}\r
\r
return last_frame_;\r
- } \r
- \r
+ }\r
+ \r
tbb::atomic<bool> is_paused_;\r
safe_ptr<draw_frame> last_frame_;\r
safe_ptr<frame_producer> foreground_;\r
other.impl_ = nullptr;\r
return *this;\r
}\r
-void layer::load(const safe_ptr<frame_producer>& frame_producer, load_option::type option){return impl_->load(frame_producer, option);} \r
+void layer::load(const safe_ptr<frame_producer>& frame_producer, bool autoplay){return impl_->load(frame_producer, autoplay);} \r
+void layer::preview(const safe_ptr<frame_producer>& frame_producer){return impl_->preview(frame_producer);} \r
void layer::play(){impl_->play();}\r
void layer::pause(){impl_->pause();}\r
void layer::stop(){impl_->stop();}\r
#pragma once\r
\r
-#include "../producer/frame_producer.h"\r
-\r
#include <boost/noncopyable.hpp>\r
\r
namespace caspar { namespace core {\r
\r
-struct load_option\r
-{\r
- enum type\r
- {\r
- none,\r
- preview,\r
- auto_play\r
- };\r
-};\r
+class frame_producer;\r
+class draw_frame;\r
\r
class layer : boost::noncopyable\r
{\r
public:\r
- layer(size_t index = -1);\r
- layer(layer&& other);\r
- layer& operator=(layer&& other);\r
-\r
- void load(const safe_ptr<frame_producer>& producer, load_option::type option = load_option::none); \r
- void play();\r
- void pause();\r
- void stop();\r
- void clear();\r
-\r
- bool empty() const;\r
+ layer(size_t index = -1); // nothrow\r
+ layer(layer&& other); // nothrow\r
+ layer& operator=(layer&& other); // nothrow\r
+ \r
+ void load(const safe_ptr<frame_producer>& producer, bool autoplay = false); // nothrow\r
+ void preview(const safe_ptr<frame_producer>& producer); // nothrow\r
+ void play(); // nothrow\r
+ void pause(); // nothrow\r
+ void stop(); // nothrow\r
+ void clear(); // nothrow\r
+\r
+ bool empty() const; // nothrow\r
\r
- safe_ptr<frame_producer> foreground() const;\r
- safe_ptr<frame_producer> background() const;\r
+ safe_ptr<frame_producer> foreground() const; // nothrow\r
+ safe_ptr<frame_producer> background() const; // nothrow\r
\r
- safe_ptr<draw_frame> receive();\r
+ safe_ptr<draw_frame> receive(); // nothrow\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
#include "transition_producer.h"\r
\r
#include "../../format/video_format.h"\r
-#include "../../processor/draw_frame.h"\r
#include "../../processor/composite_frame.h"\r
#include "../../processor/transform_frame.h"\r
#include "../../processor/frame_processor_device.h"\r
\r
-#include "../../producer/frame_producer_device.h"\r
-\r
#include <boost/range/algorithm/copy.hpp>\r
\r
namespace caspar { namespace core { \r
#include "../frame_producer.h"\r
\r
#include <string>\r
-#include <vector>\r
+#include <memory>\r
\r
namespace caspar { namespace core {\r
\r
//Perform loading of the clip\r
try\r
{\r
- auto pFP = load_media(_parameters); \r
- bool autoPlay = std::find(_parameters.begin(), _parameters.end(), TEXT("AUTOPLAY")) != _parameters.end(); \r
- GetChannel()->load(GetLayerIndex(), pFP, autoPlay ? load_option::auto_play : load_option::preview);\r
+ auto pFP = load_media(_parameters); \r
+ GetChannel()->preview(GetLayerIndex(), pFP);\r
\r
CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully");\r
\r
\r
pFP = safe_ptr<frame_producer>(transition_producer(pFP, transitionInfo));\r
bool autoPlay = std::find(_parameters.begin(), _parameters.end(), TEXT("AUTOPLAY")) != _parameters.end();\r
- GetChannel()->load(GetLayerIndex(), pFP, autoPlay ? load_option::auto_play : load_option::none); // TODO: LOOP\r
+ GetChannel()->load(GetLayerIndex(), pFP, autoPlay); // TODO: LOOP\r
\r
CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully to background");\r
SetReplyString(TEXT("202 LOADBG OK\r\n"));\r
\r
#include "../../channel.h"\r
\r
-#include "../../../common/io/ProtocolStrategy.h"\r
+#include <common/io/ProtocolStrategy.h>\r
#include "CIICommand.h"\r
\r
#include "../../consumer/frame_consumer.h"\r
#include "../../producer/frame_producer_device.h"\r
\r
-#include "../../../common/concurrency/executor.h"\r
+#include <common/concurrency/executor.h>\r
\r
namespace caspar { namespace core { namespace cii {\r
\r