<ClInclude Include="exception\exceptions.h" />\r
<ClInclude Include="exception\win32_exception.h" />\r
<ClInclude Include="gl\frame_buffer_object.h" />\r
+ <ClInclude Include="gl\shader_program.h" />\r
<ClInclude Include="gl\utility.h" />\r
<ClInclude Include="gl\pixel_buffer_object.h" />\r
<ClInclude Include="io\AsyncEventServer.h" />\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="gl\shader_program.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="io\AsyncEventServer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<ClCompile Include="gl\pixel_buffer_object.cpp">\r
<Filter>Source\gl</Filter>\r
</ClCompile>\r
+ <ClCompile Include="gl\shader_program.cpp">\r
+ <Filter>Source\gl</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="stdafx.h">\r
<ClInclude Include="compiler\vs\disable_silly_warnings.h">\r
<Filter>Source\compiler\vs</Filter>\r
</ClInclude>\r
+ <ClInclude Include="gl\shader_program.h">\r
+ <Filter>Source\gl</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
--- /dev/null
+#include "../StdAfx.h"\r
+\r
+#include "shader_program.h"\r
+\r
+#include "../exception/exceptions.h"\r
+#include "utility.h"\r
+\r
+#include <Glee.h>\r
+\r
+#include <boost/noncopyable.hpp>\r
+\r
+namespace caspar { namespace common { namespace gl {\r
+\r
+shader_program& shader_program::operator=(shader_program&& other) \r
+{\r
+ program_ = other.program_; \r
+ other.program_ = 0; \r
+ return *this;\r
+}\r
+\r
+shader_program::shader_program(const std::string& vertex_source_str, const std::string& fragment_source_str) : program_(0)\r
+{\r
+ GLint success;\r
+ \r
+ const char* vertex_source = vertex_source_str.c_str();\r
+ \r
+ auto vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);\r
+ \r
+ GL(glShaderSourceARB(vertex_shader, 1, &vertex_source, NULL));\r
+ GL(glCompileShaderARB(vertex_shader));\r
+\r
+ GL(glGetObjectParameterivARB(vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));\r
+ if (success == GL_FALSE)\r
+ {\r
+ char info[2048];\r
+ GL(glGetInfoLogARB(vertex_shader, sizeof(info), 0, info));\r
+ GL(glDeleteObjectARB(vertex_shader));\r
+ std::stringstream str;\r
+ str << "Failed to compile vertex shader:" << std::endl << info << std::endl;\r
+ BOOST_THROW_EXCEPTION(common::gl::gl_error() << msg_info(str.str()));\r
+ }\r
+ \r
+ const char* fragment_source = fragment_source_str.c_str();\r
+ \r
+ auto fragmemt_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);\r
+ \r
+ GL(glShaderSourceARB(fragmemt_shader, 1, &fragment_source, NULL));\r
+ GL(glCompileShaderARB(fragmemt_shader));\r
+\r
+ GL(glGetObjectParameterivARB(fragmemt_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));\r
+ if (success == GL_FALSE)\r
+ {\r
+ char info[2048];\r
+ GL(glGetInfoLogARB(fragmemt_shader, sizeof(info), 0, info));\r
+ GL(glDeleteObjectARB(fragmemt_shader));\r
+ std::stringstream str;\r
+ str << "Failed to compile fragment shader:" << std::endl << info << std::endl;\r
+ BOOST_THROW_EXCEPTION(common::gl::gl_error() << msg_info(str.str()));\r
+ }\r
+ \r
+ program_ = glCreateProgramObjectARB();\r
+ \r
+ GL(glAttachObjectARB(program_, vertex_shader));\r
+ GL(glAttachObjectARB(program_, fragmemt_shader));\r
+\r
+ GL(glLinkProgramARB(program_));\r
+ \r
+ GL(glDeleteObjectARB(vertex_shader));\r
+ GL(glDeleteObjectARB(fragmemt_shader));\r
+\r
+ GL(glGetObjectParameterivARB(program_, GL_OBJECT_LINK_STATUS_ARB, &success));\r
+ if (success == GL_FALSE)\r
+ {\r
+ char info[2048];\r
+ GL(glGetInfoLogARB(program_, sizeof(info), 0, info));\r
+ GL(glDeleteObjectARB(program_));\r
+ std::stringstream str;\r
+ str << "Failed to link shader program:" << std::endl << info << std::endl;\r
+ BOOST_THROW_EXCEPTION(common::gl::gl_error() << msg_info(str.str()));\r
+ }\r
+ GL(glUseProgramObjectARB(program_));\r
+ glUniform1i(glGetUniformLocation(program_, "plane[0]"), 0);\r
+ glUniform1i(glGetUniformLocation(program_, "plane[1]"), 1);\r
+ glUniform1i(glGetUniformLocation(program_, "plane[2]"), 2);\r
+ glUniform1i(glGetUniformLocation(program_, "plane[3]"), 3);\r
+}\r
+\r
+shader_program::~shader_program()\r
+{\r
+ glDeleteProgram(program_);\r
+}\r
+\r
+void shader_program::use()\r
+{ \r
+ GL(glUseProgramObjectARB(program_)); \r
+}\r
+\r
+}}}
\ No newline at end of file
--- /dev/null
+\r
+#include <Glee.h>\r
+\r
+#include <boost/noncopyable.hpp>\r
+\r
+#include <memory>\r
+\r
+namespace caspar { namespace common { namespace gl {\r
+ \r
+class shader_program : boost::noncopyable\r
+{\r
+public:\r
+ shader_program() : program_(0){}\r
+ shader_program(shader_program&& other) : program_(other.program_){}\r
+ shader_program& operator=(shader_program&& other);\r
+\r
+ shader_program(const std::string& vertex_source_str, const std::string& fragment_source_str);\r
+ ~shader_program();\r
+\r
+ void use();\r
+\r
+ GLuint program() { return program_; }\r
+ \r
+private:\r
+ GLuint program_;\r
+};\r
+typedef std::shared_ptr<shader_program> shader_program_ptr;\r
+\r
+}}}
\ No newline at end of file
#include <string>\r
#include <sstream>\r
#include <boost/lexical_cast.hpp>\r
- \r
+ \r
namespace caspar { namespace common {\r
\r
inline std::wstring widen(const std::string& str, const std::locale& locale = std::locale())\r
#pragma warning(push)\r
#pragma warning(disable : 4244)\r
#endif\r
- \r
+ \r
inline std::string narrow(const std::wstring& str, const std::locale& locale = std::locale())\r
{\r
std::stringstream sstr;\r
sstr << ctfacet.narrow(str[i], 0) ;\r
return sstr.str() ;\r
}\r
- \r
+ \r
inline std::string narrow(const std::string& str, const std::locale&)\r
{\r
return str ;\r
#include "exception.h"\r
#include "memory.h"\r
\r
-#include "../../processor/frame.h"\r
+#include "../../processor/write_frame.h"\r
\r
#include <boost/thread.hpp>\r
\r
\r
enable_video_output();\r
\r
- page_locked_buffer::reserve_working_size(MAX_HANC_BUFFER_SIZE * 3); \r
- for(int n = 0; n < 3; ++n)\r
- hanc_buffers_.push_back(std::make_shared<page_locked_buffer>(MAX_HANC_BUFFER_SIZE));\r
+ page_locked_buffer::reserve_working_size(MAX_HANC_BUFFER_SIZE * hanc_buffers_.size()); \r
+ for(size_t n = 0; n < hanc_buffers_.size(); ++n)\r
+ hanc_buffers_[n] = std::make_shared<page_locked_buffer>(MAX_HANC_BUFFER_SIZE);\r
\r
frame_buffer_.set_capacity(1);\r
thread_ = boost::thread([=]{run();});\r
\r
~implementation()\r
{\r
- frame_buffer_.push(nullptr),\r
+ frame_buffer_.push(nullptr);\r
thread_.join();\r
\r
disable_video_output();\r
CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << device_index_ << TEXT(")"); \r
}\r
\r
- void display(const frame_ptr& frame)\r
+ void display(const consumer_frame& frame)\r
{\r
- if(frame == nullptr)\r
- return;\r
-\r
if(exception_ != nullptr)\r
std::rethrow_exception(exception_);\r
\r
- frame_buffer_.push(frame);\r
+ frame_buffer_.push(std::make_shared<consumer_frame>(frame));\r
}\r
\r
- void do_display(const frame_ptr& frame)\r
+ void do_display(consumer_frame_ptr& frame)\r
{\r
try\r
{\r
- auto hanc = hanc_buffers_[current_id_]; \r
- current_id_ = (current_id_+1) % hanc_buffers_.size(); \r
+ auto hanc = hanc_buffers_.front(); \r
+ std::rotate(hanc_buffers_.begin(), hanc_buffers_.begin() + 1, hanc_buffers_.end());\r
\r
static size_t audio_samples = 1920;\r
static size_t audio_nchannels = 2;\r
static std::vector<short> silence(audio_samples*audio_nchannels*2, 0);\r
\r
- auto& frame_audio_data = frame->get_audio_data().empty() ? silence : frame->get_audio_data();\r
\r
unsigned long fieldCount = 0;\r
sdk_->wait_output_video_synch(UPD_FMT_FRAME, fieldCount);\r
\r
if(embed_audio_)\r
{ \r
- encode_hanc(reinterpret_cast<BLUE_UINT32*>(hanc->data()), frame_audio_data.data(), audio_samples, audio_nchannels);\r
+ auto& frame_audio_data = frame->audio_data().empty() ? silence : frame->audio_data();\r
\r
- sdk_->system_buffer_write_async(frame->data().begin(), \r
+ encode_hanc(reinterpret_cast<BLUE_UINT32*>(hanc->data()), const_cast<short*>(frame_audio_data.data()), audio_samples, audio_nchannels);\r
+ \r
+ sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame->data().begin()), \r
frame->data().size(), \r
nullptr, \r
BlueImage_HANC_DMABuffer(current_id_, BLUE_DATA_IMAGE));\r
nullptr, \r
BlueImage_HANC_DMABuffer(current_id_, BLUE_DATA_HANC));\r
\r
- transferring_frame_ = frame;\r
-\r
if(BLUE_FAIL(sdk_->render_buffer_update(BlueBuffer_Image_HANC(current_id_))))\r
CASPAR_LOG(trace) << TEXT("BLUEFISH: render_buffer_update failed");\r
}\r
else\r
{\r
- sdk_->system_buffer_write_async(frame->data().begin(),\r
+ sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame->data().begin()),\r
frame->data().size(), \r
nullptr, \r
BlueImage_DMABuffer(current_id_, BLUE_DATA_IMAGE));\r
if(BLUE_FAIL(sdk_->render_buffer_update(BlueBuffer_Image(current_id_))))\r
CASPAR_LOG(trace) << TEXT("BLUEFISH: render_buffer_update failed");\r
}\r
+\r
+ transferring_frame_ = frame;\r
}\r
catch(...)\r
{\r
{\r
try\r
{\r
- frame_ptr frame;\r
+ consumer_frame_ptr frame;\r
frame_buffer_.pop(frame);\r
- if(frame == nullptr)\r
+\r
+ if(!frame)\r
return;\r
\r
do_display(frame);\r
\r
std::exception_ptr exception_;\r
boost::thread thread_;\r
- tbb::concurrent_bounded_queue<frame_ptr> frame_buffer_;\r
+ tbb::concurrent_bounded_queue<consumer_frame_ptr> frame_buffer_;\r
\r
unsigned long mem_fmt_;\r
unsigned long upd_fmt_;\r
unsigned long res_fmt_; \r
unsigned long engine_mode_;\r
\r
- frame_ptr transferring_frame_;\r
+ consumer_frame_ptr transferring_frame_;\r
\r
- std::vector<page_locked_buffer_ptr> hanc_buffers_;\r
+ std::array<page_locked_buffer_ptr, 3> hanc_buffers_;\r
int current_id_;\r
bool embed_audio_;\r
};\r
\r
consumer::consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio) : impl_(new implementation(format_desc, device_index, embed_audio)){} \r
-void consumer::display(const frame_ptr& frame){impl_->display(frame);}\r
+void consumer::display(const consumer_frame& frame){impl_->display(frame);}\r
\r
}}}\r
\r
public:\r
consumer(const video_format_desc& format_desc, unsigned int deviceIndex, bool embed_audio = false);\r
\r
- virtual void display(const frame_ptr&); \r
+ virtual void display(const consumer_frame&); \r
virtual bool has_sync_clock() const {return true;}\r
private:\r
struct implementation;\r
~Implementation()\r
{\r
input_.push(nullptr);\r
-\r
thread_.join();\r
\r
if(output_) \r
}\r
}\r
\r
- void display(const frame_ptr& frame)\r
+ void display(const consumer_frame& frame)\r
{\r
- if(frame == nullptr)\r
- return; \r
-\r
if(exception_ != nullptr)\r
std::rethrow_exception(exception_);\r
\r
- input_.push(frame);\r
+ input_.push(std::make_shared<consumer_frame>(frame));\r
}\r
\r
- void do_display(const frame_ptr& input_frame)\r
+ void do_display(const consumer_frame& input_frame)\r
{\r
try\r
{\r
auto& output_frame = reserved_frames_[current_index_];\r
current_index_ = (++current_index_) % reserved_frames_.size();\r
\r
- std::copy(input_frame->data().begin(), input_frame->data().end(), static_cast<char*>(output_frame.first));\r
+ std::copy(input_frame.data().begin(), input_frame.data().end(), static_cast<char*>(output_frame.first));\r
\r
if(FAILED(output_->DisplayVideoFrameSync(output_frame.second)))\r
CASPAR_LOG(error) << L"DECKLINK: Failed to display frame.";\r
{\r
try\r
{ \r
- frame_ptr frame;\r
+ consumer_frame_ptr frame;\r
input_.pop(frame);\r
- if(frame == nullptr)\r
+ \r
+ if(!frame)\r
return;\r
\r
- do_display(frame);\r
+ do_display(*frame);\r
}\r
catch(...)\r
{\r
\r
std::exception_ptr exception_;\r
boost::thread thread_;\r
- tbb::concurrent_bounded_queue<frame_ptr> input_;\r
+ tbb::concurrent_bounded_queue<consumer_frame_ptr> input_;\r
};\r
\r
decklink_consumer::decklink_consumer(const video_format_desc& format_desc, bool internalKey) : pImpl_(new Implementation(format_desc, internalKey))\r
{}\r
\r
-void decklink_consumer::display(const frame_ptr& frame)\r
+void decklink_consumer::display(const consumer_frame& frame)\r
{\r
pImpl_->display(frame);\r
}\r
public:\r
explicit decklink_consumer(const video_format_desc& format_desc, bool internalKey = false);\r
\r
- virtual void display(const frame_ptr&);\r
+ virtual void display(const consumer_frame&);\r
virtual bool has_sync_clock() const {return false;}\r
private:\r
struct Implementation;\r
#pragma once\r
\r
#include "../format/video_format.h"\r
-#include "../processor/frame.h"\r
+#include "../processor/read_frame.h"\r
\r
#include <boost/noncopyable.hpp>\r
\r
{\r
virtual ~frame_consumer() {}\r
\r
- virtual void prepare(const frame_ptr&){}\r
- virtual void display(const frame_ptr&){}\r
+ virtual void prepare(const consumer_frame&){}\r
+ virtual void display(const consumer_frame&){}\r
virtual bool has_sync_clock() const {return false;}\r
};\r
typedef std::shared_ptr<frame_consumer> frame_consumer_ptr;\r
#include "frame_consumer_device.h"\r
\r
#include "../format/video_format.h"\r
-#include "../processor/frame.h"\r
+#include "../processor/write_frame.h"\r
#include "../processor/frame_processor_device.h"\r
\r
#include <tbb/concurrent_queue.h>\r
//}\r
\r
needs_clock_ = !std::any_of(consumers.begin(), consumers.end(), std::mem_fn(&frame_consumer::has_sync_clock));\r
- frame_buffer_.set_capacity(3);\r
is_running_ = true;\r
display_thread_ = boost::thread([=]{run();});\r
}\r
{\r
if(needs_clock_)\r
clock.synchronize();\r
- \r
- frame_ptr frame;\r
- while((frame == nullptr || frame == frame::empty()) && is_running_) \r
- frame_processor_->receive(frame);\r
- \r
- display_frame(frame); \r
+ \r
+ display_frame(frame_processor_->receive()); \r
}\r
}\r
\r
- void display_frame(const frame_ptr& frame)\r
+ void display_frame(const consumer_frame& frame)\r
{\r
BOOST_FOREACH(const frame_consumer_ptr& consumer, consumers_)\r
{\r
}\r
}\r
\r
- std::deque<frame_ptr> prepared_frames_;\r
+ std::deque<consumer_frame> prepared_frames_;\r
\r
boost::thread display_thread_;\r
\r
tbb::atomic<bool> is_running_;\r
- tbb::concurrent_bounded_queue<frame_ptr> frame_buffer_;\r
\r
bool needs_clock_;\r
std::vector<frame_consumer_ptr> consumers_;\r
\r
#include "oal_consumer.h"\r
\r
-#include "../../processor/frame.h"\r
+#include "../../processor/write_frame.h"\r
#include "../../format/video_format.h"\r
\r
#include <SFML/Audio.hpp>\r
Stop();\r
}\r
\r
- void push(const frame_ptr& frame)\r
+ void push(const consumer_frame& frame)\r
{\r
// NOTE: tbb::concurrent_queue does not have rvalue support. \r
// Use shared_ptr to emulate move semantics\r
- input_.push(std::make_shared<std::vector<short>>(std::move(frame->get_audio_data()))); \r
+ input_.push(frame.audio_data()); \r
\r
if(GetStatus() != Playing && input_.size() > 2)\r
Play();\r
{\r
static std::vector<short> silence(1920*2, 0);\r
\r
- std::shared_ptr<std::vector<short>> audio_data;\r
+ std::vector<short> audio_data;\r
\r
if(!input_.try_pop(audio_data))\r
{\r
underrun_count_ = 0;\r
}\r
\r
- if(audio_data->empty())\r
+ if(audio_data.empty())\r
{ \r
data.Samples = silence.data();\r
data.NbSamples = silence.size();\r
}\r
else\r
{\r
- container_.push_back(std::move(*audio_data));\r
+ container_.push_back(std::move(audio_data));\r
data.Samples = container_.back().data();\r
data.NbSamples = container_.back().size();\r
}\r
\r
long underrun_count_;\r
boost::circular_buffer<std::vector<short>> container_;\r
- tbb::concurrent_bounded_queue<std::shared_ptr<std::vector<short>>> input_;\r
+ tbb::concurrent_bounded_queue<std::vector<short>> input_;\r
};\r
\r
consumer::consumer(const video_format_desc&) : impl_(new implementation()){}\r
-void consumer::prepare(const frame_ptr& frame){impl_->push(frame);}\r
+void consumer::prepare(const consumer_frame& frame){impl_->push(frame);}\r
}}}\r
public: \r
explicit consumer(const video_format_desc& format_desc);\r
\r
- virtual void prepare(const frame_ptr& frame);\r
+ virtual void prepare(const consumer_frame& frame);\r
virtual bool has_sync_clock() const {return true;}\r
private:\r
struct implementation;\r
#include "ogl_consumer.h"\r
\r
#include "../../format/video_format.h"\r
-#include "../../processor/frame.h"\r
+#include "../../processor/write_frame.h"\r
#include "../../../common/gl/utility.h"\r
#include "../../../common/gl/pixel_buffer_object.h"\r
\r
\r
~implementation()\r
{\r
- frame_buffer_.push(nullptr),\r
+ frame_buffer_.push(nullptr);\r
thread_.join();\r
}\r
\r
return std::make_pair(width, height);\r
}\r
\r
- void render(const frame_ptr& frame)\r
+ void render(const consumer_frame& frame)\r
{ \r
index_ = (index_ + 1) % 2;\r
int next_index = (index_ + 1) % 2;\r
\r
auto ptr = pbos_[index_].end_write();\r
- std::copy_n(frame->data().begin(), frame->data().size(), reinterpret_cast<char*>(ptr));\r
+ std::copy_n(frame.data().begin(), frame.data().size(), reinterpret_cast<char*>(ptr));\r
\r
GL(glClear(GL_COLOR_BUFFER_BIT)); \r
pbos_[next_index].bind_texture(); \r
pbos_[next_index].begin_write();\r
}\r
\r
- void display(const frame_ptr& frame)\r
+ void display(const consumer_frame& frame)\r
{\r
- if(frame == nullptr)\r
- return; \r
-\r
if(exception_ != nullptr)\r
std::rethrow_exception(exception_);\r
\r
- frame_buffer_.push(frame);\r
+ frame_buffer_.push(std::make_shared<consumer_frame>(frame));\r
}\r
\r
void run()\r
{ \r
init();\r
\r
- frame_ptr frame;\r
- do\r
+ while(true)\r
{\r
try\r
{ \r
+ consumer_frame_ptr frame;\r
frame_buffer_.pop(frame);\r
- if(frame != nullptr)\r
- {\r
- sf::Event e;\r
- while(window_.GetEvent(e)){}\r
- window_.SetActive();\r
- render(frame);\r
- window_.Display();\r
- }\r
+\r
+ if(!frame)\r
+ return;\r
+\r
+ sf::Event e;\r
+ while(window_.GetEvent(e)){}\r
+ window_.SetActive();\r
+ render(*frame);\r
+ window_.Display();\r
+ \r
}\r
catch(...)\r
{\r
exception_ = std::current_exception();\r
}\r
} \r
- while(frame != nullptr);\r
} \r
\r
float wratio_;\r
\r
std::exception_ptr exception_;\r
boost::thread thread_;\r
- tbb::concurrent_bounded_queue<frame_ptr> frame_buffer_;\r
+ tbb::concurrent_bounded_queue<consumer_frame_ptr> frame_buffer_;\r
\r
sf::Window window_;\r
};\r
\r
consumer::consumer(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)\r
: impl_(new implementation(format_desc, screen_index, stretch, windowed)){}\r
-void consumer::display(const frame_ptr& frame){impl_->display(frame);}\r
+void consumer::display(const consumer_frame& frame){impl_->display(frame);}\r
}}}\r
public: \r
explicit consumer(const video_format_desc& format_desc, unsigned int screen_index = 0, stretch stretch = stretch::fill, bool windowed = false);\r
\r
- virtual void display(const frame_ptr& frame);\r
+ virtual void display(const consumer_frame& frame);\r
virtual bool has_sync_clock() const {return false;}\r
private:\r
struct implementation;\r
<ClInclude Include="format\pixel_format.h" />\r
<ClInclude Include="format\video_format.h" />\r
<ClInclude Include="processor\composite_frame.h" />\r
- <ClInclude Include="processor\frame.h" />\r
<ClInclude Include="processor\frame_processor_device.h" />\r
<ClInclude Include="processor\frame_renderer.h" />\r
<ClInclude Include="processor\frame_shader.h" />\r
+ <ClInclude Include="processor\fwd.h" />\r
+ <ClInclude Include="processor\gpu_frame.h" />\r
+ <ClInclude Include="processor\read_frame.h" />\r
+ <ClInclude Include="processor\transform_frame.h" />\r
+ <ClInclude Include="processor\write_frame.h" />\r
<ClInclude Include="producer\color\color_producer.h" />\r
<ClInclude Include="producer\ffmpeg\audio\audio_decoder.h" />\r
<ClInclude Include="producer\ffmpeg\ffmpeg_producer.h" />\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="processor\frame.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="processor\frame_processor_device.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\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="processor\read_frame.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="processor\transform_frame.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="processor\write_frame.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\color\color_producer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<Filter Include="Source\channel\format">\r
<UniqueIdentifier>{f19ced4f-4ad2-4c0a-b51f-50e89909d669}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="Source\channel\processor\frame">\r
+ <UniqueIdentifier>{deed18de-67bf-4bb9-9f5e-565af7ab64eb}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="StdAfx.h">\r
<ClInclude Include="processor\frame_processor_device.h">\r
<Filter>Source\channel\processor</Filter>\r
</ClInclude>\r
- <ClInclude Include="processor\frame.h">\r
- <Filter>Source\channel\processor</Filter>\r
- </ClInclude>\r
- <ClInclude Include="processor\composite_frame.h">\r
- <Filter>Source\channel\processor</Filter>\r
- </ClInclude>\r
<ClInclude Include="processor\frame_shader.h">\r
<Filter>Source\channel\processor\renderer</Filter>\r
</ClInclude>\r
<ClInclude Include="consumer\decklink\util.h">\r
<Filter>Source\channel\consumer\decklink</Filter>\r
</ClInclude>\r
+ <ClInclude Include="processor\write_frame.h">\r
+ <Filter>Source\channel\processor\frame</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="processor\read_frame.h">\r
+ <Filter>Source\channel\processor\frame</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="processor\composite_frame.h">\r
+ <Filter>Source\channel\processor\frame</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="processor\transform_frame.h">\r
+ <Filter>Source\channel\processor\frame</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="processor\fwd.h">\r
+ <Filter>Source\channel\processor</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="processor\gpu_frame.h">\r
+ <Filter>Source\channel\processor\frame</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="StdAfx.cpp">\r
<ClCompile Include="processor\frame_processor_device.cpp">\r
<Filter>Source\channel\processor</Filter>\r
</ClCompile>\r
- <ClCompile Include="processor\frame.cpp">\r
- <Filter>Source\channel\processor</Filter>\r
- </ClCompile>\r
- <ClCompile Include="processor\composite_frame.cpp">\r
- <Filter>Source\channel\processor</Filter>\r
- </ClCompile>\r
<ClCompile Include="processor\frame_renderer.cpp">\r
<Filter>Source\channel\processor\renderer</Filter>\r
</ClCompile>\r
<ClCompile Include="consumer\decklink\decklink_consumer.cpp">\r
<Filter>Source\channel\consumer\decklink</Filter>\r
</ClCompile>\r
+ <ClCompile Include="processor\read_frame.cpp">\r
+ <Filter>Source\channel\processor\frame</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="processor\write_frame.cpp">\r
+ <Filter>Source\channel\processor\frame</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="processor\composite_frame.cpp">\r
+ <Filter>Source\channel\processor\frame</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="processor\transform_frame.cpp">\r
+ <Filter>Source\channel\processor\frame</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<Midl Include="consumer\decklink\DeckLinkAPI_v7_3.idl">\r
#include "../StdAfx.h"\r
\r
#include "composite_frame.h"\r
+#include "transform_frame.h"\r
#include "../../common/gl/utility.h"\r
\r
#include <boost/range/algorithm.hpp>\r
\r
struct composite_frame::implementation : boost::noncopyable\r
{ \r
- implementation(composite_frame* self, const std::vector<frame_ptr>& frames) : self_(self)\r
- {\r
- boost::range::transform(frames, std::back_inserter(frames_), std::static_pointer_cast<internal_frame, frame>);\r
- prepare();\r
- }\r
-\r
- implementation(composite_frame* self, const frame_ptr& frame1, const frame_ptr& frame2) : self_(self)\r
- {\r
- frames_.push_back(std::static_pointer_cast<internal_frame>(frame1));\r
- frames_.push_back(std::static_pointer_cast<internal_frame>(frame2));\r
- prepare();\r
- }\r
-\r
- void prepare()\r
+ implementation(const std::vector<gpu_frame_ptr>& frames) : frames_(frames)\r
{\r
boost::range::remove_erase(frames_, nullptr);\r
- boost::range::remove_erase(frames_, frame::empty());\r
- boost::for_each(frames_, [&](const frame_ptr& frame)\r
- {\r
- if(self_->get_audio_data().empty())\r
- self_->get_audio_data() = std::move(frame->get_audio_data());\r
- else\r
- {\r
- tbb::parallel_for\r
- (\r
- tbb::blocked_range<size_t>(0, frame->get_audio_data().size()),\r
- [&](const tbb::blocked_range<size_t>& r)\r
- {\r
- for(size_t n = r.begin(); n < r.end(); ++n)\r
- self_->get_audio_data()[n] = static_cast<short>(static_cast<int>(self_->get_audio_data()[n]) + static_cast<int>(frame->get_audio_data()[n]) & 0xFFFF); \r
- }\r
- );\r
- }\r
- });\r
}\r
-\r
+ \r
void begin_write()\r
{\r
- boost::range::for_each(frames_, std::mem_fn(&internal_frame::begin_write)); \r
+ boost::range::for_each(frames_, std::mem_fn(&gpu_frame::begin_write)); \r
}\r
\r
void end_write()\r
{\r
- boost::range::for_each(frames_, std::mem_fn(&internal_frame::end_write)); \r
+ boost::range::for_each(frames_, std::mem_fn(&gpu_frame::end_write)); \r
}\r
\r
- void begin_read()\r
- { \r
- boost::range::for_each(frames_, std::mem_fn(&internal_frame::begin_read)); \r
- }\r
-\r
- void end_read()\r
+ void draw(frame_shader& shader)\r
{\r
- boost::range::for_each(frames_, std::mem_fn(&internal_frame::end_read)); \r
+ for(size_t n = 0; n < frames_.size(); ++n)\r
+ frames_[n]->draw(shader);\r
}\r
-\r
- void draw(frame_shader& shader)\r
+ \r
+ std::vector<short>& audio_data()\r
{\r
- glPushMatrix();\r
- glTranslated(self_->get_render_transform().pos.get<0>()*2.0, self_->get_render_transform().pos.get<1>()*2.0, 0.0);\r
- boost::range::for_each(frames_, std::bind(&internal_frame::draw, std::placeholders::_1, shader));\r
- glPopMatrix();\r
+ if(!audio_data_.empty() || frames_.empty())\r
+ return audio_data_;\r
+ \r
+ audio_data_.resize(1920*2, 0);\r
+ \r
+ for(size_t n = 0; n < frames_.size(); ++n)\r
+ {\r
+ auto frame = frames_[n];\r
+ tbb::parallel_for\r
+ (\r
+ tbb::blocked_range<size_t>(0, frame->audio_data().size()),\r
+ [&](const tbb::blocked_range<size_t>& r)\r
+ {\r
+ for(size_t n = r.begin(); n < r.end(); ++n) \r
+ audio_data_[n] = static_cast<short>((static_cast<int>(audio_data_[n]) + static_cast<int>(frame->audio_data()[n])) & 0xFFFF); \r
+ }\r
+ );\r
+ }\r
+\r
+ return audio_data_;\r
}\r
\r
- composite_frame* self_;\r
- std::vector<internal_frame_ptr> frames_;\r
+ std::vector<gpu_frame_ptr> frames_;\r
+ std::vector<short> audio_data_;\r
};\r
\r
#if defined(_MSC_VER)\r
#pragma warning (disable : 4355) // 'this' : used in base member initializer list\r
#endif\r
\r
-composite_frame::composite_frame(const std::vector<frame_ptr>& frames) : internal_frame(pixel_format_desc()), impl_(new implementation(this, frames)){}\r
-composite_frame::composite_frame(const frame_ptr& frame1, const frame_ptr& frame2) : internal_frame(pixel_format_desc()), impl_(new implementation(this, frame1, frame2)){}\r
+composite_frame::composite_frame(const std::vector<gpu_frame_ptr>& frames) : impl_(new implementation(frames)){}\r
+composite_frame::composite_frame(const gpu_frame_ptr& frame1, const gpu_frame_ptr& frame2)\r
+{\r
+ std::vector<gpu_frame_ptr> frames;\r
+ frames.push_back(frame1);\r
+ frames.push_back(frame2);\r
+ impl_.reset(new implementation(frames));\r
+}\r
+\r
void composite_frame::begin_write(){impl_->begin_write();}\r
void composite_frame::end_write(){impl_->end_write();} \r
-void composite_frame::begin_read(){impl_->begin_read();}\r
-void composite_frame::end_read(){impl_->end_read();}\r
void composite_frame::draw(frame_shader& shader){impl_->draw(shader);}\r
+std::vector<short>& composite_frame::audio_data(){return impl_->audio_data();}\r
+const std::vector<short>& composite_frame::audio_data() const{return impl_->audio_data();}\r
\r
-frame_ptr composite_frame::interlace(const frame_ptr& frame1, const frame_ptr& frame2, video_mode::type mode)\r
+composite_frame_ptr composite_frame::interlace(const gpu_frame_ptr& frame1, const gpu_frame_ptr& frame2, video_mode::type mode)\r
{ \r
- auto result = std::make_shared<composite_frame>(frame1, frame2);\r
+ auto my_frame1 = std::make_shared<transform_frame>(frame1);\r
+ auto my_frame2 = std::make_shared<transform_frame>(frame2);\r
if(mode == video_mode::upper)\r
{\r
- frame1->get_render_transform().mode = video_mode::upper;\r
- frame2->get_render_transform().mode = video_mode::lower;\r
+ my_frame1->video_mode(video_mode::upper);\r
+ my_frame2->video_mode(video_mode::lower);\r
}\r
else\r
{\r
- frame1->get_render_transform().mode = video_mode::lower;\r
- frame2->get_render_transform().mode = video_mode::upper;\r
+ my_frame1->video_mode(video_mode::lower);\r
+ my_frame2->video_mode(video_mode::upper);\r
}\r
- return result;\r
+ return std::make_shared<composite_frame>(my_frame1, my_frame2);\r
}\r
\r
}}
\ No newline at end of file
#pragma once\r
\r
-#include "frame.h"\r
+#include "gpu_frame.h"\r
+\r
+#include "../format/video_format.h"\r
\r
#include <memory>\r
#include <algorithm>\r
\r
namespace caspar { namespace core {\r
\r
-class composite_frame : public internal_frame\r
+class composite_frame : public gpu_frame\r
{\r
public:\r
- composite_frame(const std::vector<frame_ptr>& container);\r
- composite_frame(const frame_ptr& frame1, const frame_ptr& frame2);\r
+ composite_frame(const std::vector<gpu_frame_ptr>& frames);\r
+ composite_frame(const gpu_frame_ptr& frame1, const gpu_frame_ptr& frame2);\r
\r
- static frame_ptr interlace(const frame_ptr& frame1, const frame_ptr& frame2, video_mode::type mode);\r
+ static std::shared_ptr<composite_frame> interlace(const gpu_frame_ptr& frame1, const gpu_frame_ptr& frame2, video_mode::type mode);\r
\r
-private:\r
+ virtual const std::vector<short>& audio_data() const;\r
+\r
+protected: \r
+ virtual std::vector<short>& audio_data();\r
\r
virtual void begin_write();\r
virtual void end_write();\r
- virtual void begin_read();\r
- virtual void end_read();\r
virtual void draw(frame_shader& shader);\r
\r
+private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
+++ /dev/null
-#include "../StdAfx.h"\r
-\r
-#include "frame.h"\r
-#include "../format/pixel_format.h"\r
-#include "../../common/gl/utility.h"\r
-#include "../../common/gl/pixel_buffer_object.h"\r
-\r
-#include <boost/range/algorithm.hpp>\r
-\r
-namespace caspar { namespace core {\r
- \r
-GLubyte progressive_pattern[] = {\r
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
- 0xff, 0xff, 0xFF, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
- \r
-GLubyte upper_pattern[] = {\r
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00};\r
- \r
-GLubyte lower_pattern[] = {\r
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \r
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \r
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \r
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};\r
- \r
-struct internal_frame::implementation : boost::noncopyable\r
-{\r
- implementation(const pixel_format_desc& desc) : desc_(desc)\r
- { \r
- std::fill(pixel_data_.begin(), pixel_data_.end(), nullptr);\r
-\r
- for(size_t n = 0; n < desc_.planes.size(); ++n)\r
- {\r
- if(desc_.planes[n].size == 0)\r
- break;\r
-\r
- GLuint format = [&]() -> GLuint\r
- {\r
- switch(desc_.planes[n].channels)\r
- {\r
- case 1: return GL_LUMINANCE;\r
- case 2: return GL_LUMINANCE_ALPHA;\r
- case 3: return GL_BGR;\r
- case 4: return GL_BGRA;\r
- default: BOOST_THROW_EXCEPTION(out_of_range() << msg_info("1-4 channels are supported") << arg_name_info("desc.planes.channels")); \r
- }\r
- }();\r
-\r
- pbo_.push_back(std::make_shared<common::gl::pixel_buffer_object>(desc_.planes[n].width, desc_.planes[n].height, format));\r
- pbo_.back()->is_smooth(true);\r
- }\r
- end_write();\r
- }\r
- \r
- void begin_write()\r
- {\r
- std::fill(pixel_data_.begin(), pixel_data_.end(), nullptr);\r
- boost::range::for_each(pbo_, std::mem_fn(&common::gl::pixel_buffer_object::begin_write));\r
- }\r
-\r
- void end_write()\r
- {\r
- boost::range::transform(pbo_, pixel_data_.begin(), std::mem_fn(&common::gl::pixel_buffer_object::end_write));\r
- }\r
- \r
- void begin_read()\r
- { \r
- std::fill(pixel_data_.begin(), pixel_data_.end(), nullptr);\r
- boost::range::for_each(pbo_, std::mem_fn(&common::gl::pixel_buffer_object::begin_read));\r
- }\r
-\r
- void end_read()\r
- {\r
- boost::range::transform(pbo_, pixel_data_.begin(), std::mem_fn(&common::gl::pixel_buffer_object::end_read));\r
- }\r
-\r
- void draw(frame_shader& shader)\r
- {\r
- shader.use(desc_);\r
- glPushMatrix();\r
- glTranslated(transform_.pos.get<0>()*2.0, transform_.pos.get<1>()*2.0, 0.0);\r
- glColor4d(1.0, 1.0, 1.0, transform_.alpha);\r
-\r
- if(transform_.mode == video_mode::progressive)\r
- glPolygonStipple(progressive_pattern);\r
- else if(transform_.mode == video_mode::upper)\r
- glPolygonStipple(upper_pattern);\r
- else if(transform_.mode == video_mode::lower)\r
- glPolygonStipple(lower_pattern);\r
-\r
- for(size_t n = 0; n < pbo_.size(); ++n)\r
- {\r
- glActiveTexture(GL_TEXTURE0+n);\r
- pbo_[n]->bind_texture();\r
- }\r
- glBegin(GL_QUADS);\r
- glTexCoord2d(transform_.uv.get<0>(), transform_.uv.get<3>()); glVertex2d(-1.0, -1.0);\r
- glTexCoord2d(transform_.uv.get<2>(), transform_.uv.get<3>()); glVertex2d( 1.0, -1.0);\r
- glTexCoord2d(transform_.uv.get<2>(), transform_.uv.get<1>()); glVertex2d( 1.0, 1.0);\r
- glTexCoord2d(transform_.uv.get<0>(), transform_.uv.get<1>()); glVertex2d(-1.0, 1.0);\r
- glEnd();\r
- glPopMatrix();\r
- }\r
-\r
- unsigned char* data(size_t index)\r
- {\r
- return static_cast<unsigned char*>(pixel_data_[index]);\r
- }\r
-\r
- void reset()\r
- {\r
- audio_data_.clear();\r
- transform_ = render_transform();\r
- end_write();\r
- }\r
-\r
- std::vector<common::gl::pixel_buffer_object_ptr> pbo_;\r
- std::array<void*, 4> pixel_data_; \r
- std::vector<short> audio_data_;\r
- \r
- const pixel_format_desc desc_;\r
- internal_frame::render_transform transform_;\r
-};\r
- \r
-std::shared_ptr<frame>& frame::empty()\r
-{\r
- static auto empty_frame = std::shared_ptr<frame>(new internal_frame(pixel_format_desc()));\r
- return empty_frame;\r
-}\r
-\r
-internal_frame::internal_frame(const pixel_format_desc& desc) : impl_(new implementation(desc)){}\r
-void internal_frame::draw(frame_shader& shader){impl_->draw(shader);}\r
-void internal_frame::begin_write(){impl_->begin_write();}\r
-void internal_frame::end_write(){impl_->end_write();} \r
-void internal_frame::begin_read(){impl_->begin_read();}\r
-void internal_frame::end_read(){impl_->end_read();}\r
-boost::iterator_range<unsigned char*> internal_frame::data(size_t index)\r
-{\r
- auto ptr = static_cast<unsigned char*>(impl_->pixel_data_[index]);\r
- return boost::iterator_range<unsigned char*>(ptr, ptr+impl_->desc_.planes[index].size);\r
-}\r
-\r
-std::vector<short>& internal_frame::get_audio_data() { return impl_->audio_data_; }\r
-void internal_frame::reset(){impl_->reset();}\r
-internal_frame::render_transform& internal_frame::get_render_transform() { return impl_->transform_;}\r
-}}
\ No newline at end of file
+++ /dev/null
-#pragma once\r
-\r
-#include "frame_shader.h"\r
-\r
-#include "../format/video_format.h"\r
-#include "../format/pixel_format.h"\r
-\r
-#include <memory>\r
-#include <array>\r
-\r
-#include <boost/noncopyable.hpp>\r
-#include <boost/tuple/tuple.hpp>\r
-#include <boost/range/iterator_range.hpp>\r
-\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
- \r
-class frame : boost::noncopyable\r
-{\r
-public:\r
- \r
- struct render_transform\r
- {\r
- render_transform() : alpha(1.0), pos(boost::make_tuple(0.0, 0.0)), uv(boost::make_tuple(0.0, 1.0, 1.0, 0.0)), mode(video_mode::progressive){}\r
- double alpha;\r
- boost::tuple<double, double> pos;\r
- boost::tuple<double, double, double, double> uv;\r
- video_mode::type mode; \r
- };\r
-\r
- virtual ~frame(){}\r
- \r
- virtual boost::iterator_range<unsigned char*> data(size_t index = 0) = 0;\r
- \r
- virtual std::vector<short>& get_audio_data() = 0;\r
- const std::vector<short>& get_audio_data() const { const_cast<frame*>(this)->get_audio_data();}\r
- \r
- virtual render_transform& get_render_transform() = 0;\r
- const render_transform& get_render_transform() const { const_cast<frame*>(this)->get_render_transform();}\r
- \r
- static std::shared_ptr<frame>& empty();\r
-};\r
-typedef std::shared_ptr<frame> frame_ptr;\r
- \r
-class internal_frame : public frame\r
-{\r
-public:\r
- explicit internal_frame(const pixel_format_desc& desc);\r
- \r
- virtual boost::iterator_range<unsigned char*> data(size_t index = 0);\r
-\r
- virtual std::vector<short>& get_audio_data();\r
- virtual core::frame::render_transform& get_render_transform();\r
-\r
- virtual void reset();\r
- \r
- virtual void begin_write();\r
- virtual void end_write();\r
- virtual void begin_read();\r
- virtual void end_read();\r
-\r
- virtual void draw(frame_shader& shader);\r
-\r
-private:\r
- struct implementation;\r
- std::shared_ptr<implementation> impl_;\r
-};\r
-typedef std::shared_ptr<internal_frame> internal_frame_ptr;\r
-\r
-\r
-}}
\ No newline at end of file
#include "frame_processor_device.h"\r
\r
#include "frame_renderer.h"\r
-#include "frame.h"\r
+#include "write_frame.h"\r
+#include "read_frame.h"\r
#include "composite_frame.h"\r
\r
#include "../format/video_format.h"\r
\r
struct frame_processor_device::implementation : boost::noncopyable\r
{ \r
- implementation(frame_processor_device* self, const video_format_desc& format_desc) : fmt_(format_desc), underrun_count_(0)\r
+ implementation(const video_format_desc& format_desc) : fmt_(format_desc), underrun_count_(0)\r
{ \r
output_.set_capacity(3);\r
executor_.start();\r
ogl_context_.reset(new sf::Context());\r
ogl_context_->SetActive(true);\r
\r
- renderer_.reset(new frame_renderer(*self, format_desc));\r
+ renderer_.reset(new frame_renderer(format_desc));\r
});\r
}\r
\r
executor_.stop(); // Wait for executor before destroying anything.\r
}\r
\r
- void clear()\r
- {\r
- output_.clear();\r
- }\r
-\r
- frame_ptr create_frame(const pixel_format_desc& desc)\r
+ write_frame_ptr create_frame(const pixel_format_desc& desc)\r
{\r
auto pool = &frame_pools_[desc];\r
\r
- internal_frame_ptr my_frame;\r
+ write_frame_ptr my_frame;\r
if(!pool->try_pop(my_frame)) \r
- my_frame = executor_.invoke([&]{return std::shared_ptr<internal_frame>(new internal_frame(desc));}); \r
+ my_frame = executor_.invoke([&]{return std::shared_ptr<write_frame>(new write_frame(desc));}); \r
\r
- return internal_frame_ptr(my_frame.get(), [=](frame*)\r
+ return write_frame_ptr(my_frame.get(), [=](write_frame*)\r
{\r
executor_.begin_invoke([=]\r
{\r
});\r
}\r
\r
- void send(const frame_ptr& input_frame)\r
+ void send(const gpu_frame_ptr& input_frame)\r
{ \r
if(input_frame == nullptr)\r
return;\r
\r
- auto future = executor_.begin_invoke([=]{return renderer_->render(std::static_pointer_cast<internal_frame>(input_frame));}); \r
+ auto future = executor_.begin_invoke([=]{return renderer_->render(input_frame);}); \r
output_.push(std::move(future)); // Blocks\r
}\r
\r
- void receive(frame_ptr& output_frame)\r
+ consumer_frame receive()\r
{\r
- boost::shared_future<internal_frame_ptr> future;\r
+ boost::shared_future<consumer_frame> future;\r
\r
if(!output_.try_pop(future))\r
{\r
underrun_count_ = 0;\r
}\r
\r
- output_frame = future.get();\r
+ return future.get();\r
}\r
\r
std::unique_ptr<sf::Context> ogl_context_;\r
+ std::unique_ptr<frame_renderer> renderer_;\r
\r
common::executor executor_; \r
-\r
- std::unique_ptr<frame_renderer> renderer_;\r
\r
- tbb::concurrent_bounded_queue<boost::shared_future<internal_frame_ptr>> output_; \r
- tbb::concurrent_unordered_map<pixel_format_desc, tbb::concurrent_bounded_queue<internal_frame_ptr>, std::hash<pixel_format_desc>> frame_pools_;\r
+ tbb::concurrent_bounded_queue<boost::shared_future<consumer_frame>> output_; \r
+ tbb::concurrent_unordered_map<pixel_format_desc, tbb::concurrent_bounded_queue<write_frame_ptr>, std::hash<pixel_format_desc>> frame_pools_;\r
\r
video_format_desc fmt_;\r
long underrun_count_;\r
};\r
\r
-#if defined(_MSC_VER)\r
-#pragma warning (disable : 4355) // 'this' : used in base member initializer list\r
-#endif\r
+frame_processor_device::frame_processor_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
+void frame_processor_device::send(const gpu_frame_ptr& frame){impl_->send(frame);}\r
+consumer_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
\r
-frame_processor_device::frame_processor_device(const video_format_desc& format_desc) : impl_(new implementation(this, format_desc)){}\r
-frame_ptr frame_processor_device::create_frame(const pixel_format_desc& desc){return impl_->create_frame(desc);}\r
-void frame_processor_device::send(const frame_ptr& frame){impl_->send(frame);}\r
-void frame_processor_device::receive(frame_ptr& frame){impl_->receive(frame);}\r
-const video_format_desc& frame_processor_device::get_video_format_desc() const { return impl_->fmt_;}\r
-\r
-frame_ptr frame_processor_device::create_frame(size_t width, size_t height)\r
+write_frame_ptr frame_processor_device::create_frame(const pixel_format_desc& desc){ return impl_->create_frame(desc); } \r
+write_frame_ptr frame_processor_device::create_frame(size_t width, size_t height)\r
{\r
// Create bgra frame\r
pixel_format_desc desc;\r
return create_frame(desc);\r
}\r
\r
-frame_ptr frame_processor_device::create_frame()\r
+write_frame_ptr frame_processor_device::create_frame()\r
{\r
// Create bgra frame with output resolution\r
pixel_format_desc desc;\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
-void frame_processor_device::clear(){impl_->clear();}\r
+\r
}}
\ No newline at end of file
#include <memory>\r
#include <vector>\r
\r
+#include "fwd.h"\r
+\r
#include "../format/video_format.h"\r
-#include "../processor/frame.h"\r
#include "../consumer/frame_consumer_device.h"\r
\r
namespace caspar { namespace core {\r
public:\r
frame_processor_device(const video_format_desc& format_desc);\r
\r
- void send(const frame_ptr& frame);\r
- void receive(frame_ptr& frame);\r
- void clear();\r
+ void send(const gpu_frame_ptr& frame);\r
+ consumer_frame receive();\r
\r
- frame_ptr create_frame(const pixel_format_desc& desc); \r
- frame_ptr create_frame(size_t width, size_t height); \r
- frame_ptr create_frame();\r
+ write_frame_ptr create_frame(const pixel_format_desc& desc); \r
+ write_frame_ptr create_frame(size_t width, size_t height); \r
+ write_frame_ptr create_frame();\r
\r
const video_format_desc& get_video_format_desc() const;\r
private:\r
\r
#include "frame_renderer.h"\r
\r
-#include "../processor/frame.h"\r
+#include "frame_shader.h"\r
+#include "write_frame.h"\r
+#include "read_frame.h"\r
\r
#include "../format/video_format.h"\r
-#include "../processor/frame_processor_device.h"\r
\r
#include "../../common/exception/exceptions.h"\r
#include "../../common/gl/utility.h"\r
\r
struct frame_renderer::implementation : boost::noncopyable\r
{ \r
- implementation(frame_processor_device& frame_processor, const video_format_desc& format_desc) \r
- : frame_processor_(frame_processor), index_(0), shader_(format_desc), fbo_(format_desc.width, format_desc.height)\r
+ implementation(const video_format_desc& format_desc) : shader_(format_desc), format_desc_(format_desc),\r
+ reading_(new read_frame(0, 0)), writing_(new write_frame(pixel_format_desc())), drawing_(new write_frame(pixel_format_desc())), fbo_(format_desc.width, format_desc.height)\r
{ \r
- auto empty = std::make_shared<internal_frame>(pixel_format_desc());\r
- output_frame_ = empty;\r
- std::fill(writing_.begin(), writing_.end(), empty);\r
GL(glEnable(GL_POLYGON_STIPPLE));\r
GL(glEnable(GL_TEXTURE_2D));\r
GL(glEnable(GL_BLEND));\r
GL(glViewport(0, 0, format_desc.width, format_desc.height));\r
}\r
\r
- internal_frame_ptr render(const internal_frame_ptr& frame)\r
+ consumer_frame render(const gpu_frame_ptr& frame)\r
{\r
if(frame == nullptr)\r
return nullptr;\r
\r
try\r
{\r
- index_ = (index_ + 1) % 2;\r
- int next_index = (index_ + 1) % 2;\r
+ drawing_ = writing_;\r
+ writing_ = frame;\r
\r
- // 1. Write from page-locked system memory to video memory.\r
- frame->begin_write();\r
- writing_[index_] = frame; \r
+ // Write from page-locked system memory to video memory.\r
+ writing_->begin_write();\r
\r
- // 3. Map video memory to page-locked system memory.\r
- output_frame_->end_read();\r
+ // Map video memory to page-locked system memory.\r
+ reading_->end_read(); // Note: This frame has already been sent, it is assumed that there is external buffering of atleast 2 frames.\r
\r
// Clear framebuffer.\r
GL(glClear(GL_COLOR_BUFFER_BIT)); \r
\r
- // 2. Draw to framebuffer\r
- writing_[next_index]->draw(shader_);\r
+ // Draw to framebuffer\r
+ drawing_->draw(shader_);\r
\r
// Create an output frame\r
- output_frame_ = std::static_pointer_cast<internal_frame>(frame_processor_.create_frame());\r
+ reading_ = create_output_frame();\r
\r
// Read from framebuffer into page-locked memory.\r
- output_frame_->begin_read();\r
- output_frame_->get_audio_data() = std::move(writing_[next_index]->get_audio_data());\r
+ reading_->begin_read();\r
+ reading_->audio_data() = std::move(drawing_->audio_data());\r
\r
// Return frames to pool.\r
- //writing_[next_index]->end_write(); // Is done in frame->reset();\r
- writing_[next_index] = nullptr;\r
+ // Note: end_write is done in writing_fram::reset();\r
+ drawing_ = nullptr;\r
}\r
catch(...)\r
{\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
}\r
\r
- return output_frame_;\r
+ return reading_;\r
}\r
\r
- size_t index_;\r
+ read_frame_ptr create_output_frame()\r
+ {\r
+ read_frame_ptr frame;\r
+ if(!frame_pool_.try_pop(frame)) \r
+ frame.reset(new read_frame(format_desc_.width, format_desc_.height)); \r
+ return read_frame_ptr(frame.get(), [=](read_frame*){frame_pool_.push(frame);});\r
+ }\r
\r
- internal_frame_ptr output_frame_; \r
+ tbb::concurrent_bounded_queue<read_frame_ptr> frame_pool_;\r
\r
- frame_processor_device& frame_processor_;\r
+ common::gl::frame_buffer_object fbo_;\r
\r
- std::array<internal_frame_ptr, 2> writing_;\r
+ read_frame_ptr reading_; \r
+ gpu_frame_ptr writing_;\r
+ gpu_frame_ptr drawing_;\r
\r
- common::gl::frame_buffer_object fbo_;\r
frame_shader shader_;\r
+\r
+ video_format_desc format_desc_;\r
};\r
\r
-frame_renderer::frame_renderer(frame_processor_device& frame_processor, const video_format_desc& format_desc) : impl_(new implementation(frame_processor, format_desc)){}\r
-internal_frame_ptr frame_renderer::render(const internal_frame_ptr& frames){ return impl_->render(frames);}\r
+frame_renderer::frame_renderer(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
+consumer_frame frame_renderer::render(const gpu_frame_ptr& frame)\r
+{\r
+ return impl_->render(frame);\r
+}\r
}}
\ No newline at end of file
*/\r
#pragma once\r
\r
-#include "frame_processor_device.h"\r
+#include "fwd.h"\r
\r
#include "../format/video_format.h"\r
\r
class frame_renderer : boost::noncopyable\r
{\r
public:\r
- frame_renderer(frame_processor_device& frame_processor, const video_format_desc& format_desc_);\r
+ frame_renderer(const video_format_desc& format_desc_);\r
\r
- internal_frame_ptr render(const internal_frame_ptr& frames);\r
+ consumer_frame render(const gpu_frame_ptr& frame);\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
\r
#include "../../common/exception/exceptions.h"\r
#include "../../common/gl/utility.h"\r
+#include "../../common/gl/shader_program.h"\r
\r
#include <Glee.h>\r
\r
#include <unordered_map>\r
\r
namespace caspar { namespace core {\r
+ \r
+GLubyte progressive_pattern[] = {\r
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\r
+ 0xff, 0xff, 0xFF, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
\r
-class shader_program : boost::noncopyable\r
-{\r
-public:\r
- shader_program() : program_(0){}\r
- shader_program(shader_program&& other) : program_(other.program_){}\r
- shader_program& operator=(shader_program&& other) \r
- {\r
- program_ = other.program_; \r
- other.program_ = 0; \r
- return *this;\r
- }\r
-\r
- shader_program(const std::string& vertex_source_str, const std::string& fragment_source_str) : program_(0)\r
- {\r
- GLint success;\r
-\r
- try\r
- { \r
- const char* vertex_source = vertex_source_str.c_str();\r
- \r
- auto vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);\r
- \r
- GL(glShaderSourceARB(vertex_shader, 1, &vertex_source, NULL));\r
- GL(glCompileShaderARB(vertex_shader));\r
-\r
- GL(glGetObjectParameterivARB(vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));\r
- if (success == GL_FALSE)\r
- {\r
- char info[2048];\r
- GL(glGetInfoLogARB(vertex_shader, sizeof(info), 0, info));\r
- GL(glDeleteObjectARB(vertex_shader));\r
- std::stringstream str;\r
- str << "Failed to compile vertex shader:" << std::endl << info << std::endl;\r
- BOOST_THROW_EXCEPTION(common::gl::gl_error() << msg_info(str.str()));\r
- }\r
- \r
- const char* fragment_source = fragment_source_str.c_str();\r
- \r
- auto fragmemt_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);\r
- \r
- GL(glShaderSourceARB(fragmemt_shader, 1, &fragment_source, NULL));\r
- GL(glCompileShaderARB(fragmemt_shader));\r
-\r
- GL(glGetObjectParameterivARB(fragmemt_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));\r
- if (success == GL_FALSE)\r
- {\r
- char info[2048];\r
- GL(glGetInfoLogARB(fragmemt_shader, sizeof(info), 0, info));\r
- GL(glDeleteObjectARB(fragmemt_shader));\r
- std::stringstream str;\r
- str << "Failed to compile fragment shader:" << std::endl << info << std::endl;\r
- BOOST_THROW_EXCEPTION(common::gl::gl_error() << msg_info(str.str()));\r
- }\r
- \r
- program_ = glCreateProgramObjectARB();\r
- \r
- GL(glAttachObjectARB(program_, vertex_shader));\r
- GL(glAttachObjectARB(program_, fragmemt_shader));\r
-\r
- GL(glLinkProgramARB(program_));\r
- \r
- GL(glDeleteObjectARB(vertex_shader));\r
- GL(glDeleteObjectARB(fragmemt_shader));\r
-\r
- GL(glGetObjectParameterivARB(program_, GL_OBJECT_LINK_STATUS_ARB, &success));\r
- if (success == GL_FALSE)\r
- {\r
- char info[2048];\r
- GL(glGetInfoLogARB(program_, sizeof(info), 0, info));\r
- GL(glDeleteObjectARB(program_));\r
- std::stringstream str;\r
- str << "Failed to link shader program:" << std::endl << info << std::endl;\r
- BOOST_THROW_EXCEPTION(common::gl::gl_error() << msg_info(str.str()));\r
- }\r
- GL(glUseProgramObjectARB(program_));\r
- glUniform1i(glGetUniformLocation(program_, "plane[0]"), 0);\r
- glUniform1i(glGetUniformLocation(program_, "plane[1]"), 1);\r
- glUniform1i(glGetUniformLocation(program_, "plane[2]"), 2);\r
- glUniform1i(glGetUniformLocation(program_, "plane[3]"), 3);\r
- }\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- throw;\r
- }\r
- }\r
-\r
- ~shader_program()\r
- {\r
- glDeleteProgram(program_);\r
- }\r
-\r
- void use()\r
- { \r
- GL(glUseProgramObjectARB(program_)); \r
- }\r
-\r
- GLuint program() { return program_; }\r
+GLubyte upper_pattern[] = {\r
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\r
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00};\r
+ \r
+GLubyte lower_pattern[] = {\r
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \r
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \r
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, \r
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\r
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};\r
\r
-private:\r
- GLuint program_;\r
-};\r
-typedef std::shared_ptr<shader_program> shader_program_ptr;\r
-\r
struct frame_shader::implementation\r
{\r
- implementation(const video_format_desc& format_desc) \r
- : current_(pixel_format::invalid), format_desc_(format_desc)\r
+ implementation(const video_format_desc& format_desc) : current_(pixel_format::invalid), format_desc_(format_desc), alpha_(1.0)\r
{\r
+ transform_stack_.push(shader_transform());\r
std::string common_vertex = \r
- "uniform sampler2D plane[4]; "\r
- "uniform vec4 plane_size[2]; "\r
- " "\r
"void main() "\r
"{ "\r
- //" vec2 t0 = gl_MultiTexCoord0.xy + plane_size[0].zw*0.5; "\r
- //" vec4 x0 = vec4(-1.0, 0.0, 1.0, 2.0)*plane_size[0].z; "\r
- //" vec4 y0 = vec4(-1.0, 0.0, 1.0, 2.0)*plane_size[0].w; "\r
- //" gl_TexCoord[0] = t0.xyxy + vec4(x0.x, y0.x, x0.y, y0.y); "\r
- //" gl_TexCoord[1] = t0.xyxy + vec4(x0.z, y0.x, x0.w, y0.y); "\r
- //" gl_TexCoord[2] = t0.xyxy + vec4(x0.x, y0.z, x0.y, y0.w); "\r
- //" gl_TexCoord[3] = t0.xyxy + vec4(x0.z, y0.z, x0.w, y0.w); "\r
- //" "\r
- //" vec2 t1 = gl_MultiTexCoord0.xy + plane_size[1].zw*0.5; "\r
- //" vec4 x1 = vec4(-1.0, 0.0, 1.0, 2.0)*plane_size[1].z; "\r
- //" vec4 y1 = vec4(-1.0, 0.0, 1.0, 2.0)*plane_size[1].w; "\r
- //" gl_TexCoord[4] = t1.xyxy + vec4(x1.x, y1.x, x1.y, y1.y); "\r
- //" gl_TexCoord[5] = t1.xyxy + vec4(x1.z, y1.x, x1.w, y1.y); "\r
- //" gl_TexCoord[6] = t1.xyxy + vec4(x1.x, y1.z, x1.y, y1.w); "\r
- //" gl_TexCoord[7] = t1.xyxy + vec4(x1.z, y1.z, x1.w, y1.w); "\r
" gl_TexCoord[0] = gl_MultiTexCoord0; "\r
" gl_FrontColor = gl_Color; "\r
" gl_Position = ftransform(); "\r
" return color; "\r
"} " \r
" ";\r
- //"vec4 texture2DNearest(sampler2D sampler, vec4 uv0, vec4 uv1, vec4 uv2, vec4 uv3, vec4 size)"\r
- //"{ "\r
- //" return texture2D(sampler, uv0.zw); "\r
- //"} "\r
- //" "\r
- //"vec4 texture2DBilinear(sampler2D sampler, vec4 uv0, vec4 uv1, vec4 uv2, vec4 uv3, vec4 size)"\r
- //"{ "\r
- //" vec2 f = fract(uv0*size.xy); "\r
- //" "\r
- //" vec4 t0 = texture2D(sampler, uv0.zw); "\r
- //" vec4 t1 = texture2D(sampler, uv1.xw); "\r
- //" vec4 t2 = texture2D(sampler, uv2.zy); "\r
- //" vec4 t3 = texture2D(sampler, uv3.xy); "\r
- //" "\r
- //" vec4 x0 = mix(t0, t1, f.x); "\r
- //" vec4 x1 = mix(t2, t3, f.x); "\r
- //" return mix(x0, x1, f.y); "\r
- //"} "\r
- //" "\r
- //"vec4 computeWeights(float x) "\r
- //"{ "\r
- //" vec4 x1 = x*vec4(1.0, 1.0, -1.0, -1.0) + vec4(1.0, 0.0, 1.0, 2.0); "\r
- //" vec4 x2 = x1*x1; "\r
- //" vec4 x3 = x2*x1; "\r
- //" "\r
- //" const float A = -0.75; " \r
- //" vec4 w; "\r
- //" w = x3 * vec2( A, A+2.0 ).xyyx; "\r
- //" w += x2 * vec2(-5.0*A, -(A+3.0)).xyyx; "\r
- //" w += x1 * vec2( 8.0*A, 0 ).xyyx; "\r
- //" w += vec2(-4.0*A, 1.0 ).xyyx; "\r
- //" return w; "\r
- //"} "\r
- //" "\r
- //"vec4 cubicFilter(vec4 w, vec4 c0, vec4 c1, vec4 c2, vec4 c3) "\r
- //"{ "\r
- //" return c0*w[0] + c1*w[1] + c2*w[2] + c3*w[3]; "\r
- //"} "\r
- //" "\r
- //"vec4 texture2DBicubic(sampler2D sampler, vec4 uv0, vec4 uv1, vec4 uv2, vec4 uv3, vec4 size)"\r
- //"{ "\r
- //" vec2 f = fract(uv0*size.xy); "\r
- //" "\r
- //" vec4 w = computeWeights(f.x); "\r
- //" vec4 x0 = cubicFilter(w, texture2D(sampler, uv0.xy), "\r
- //" texture2D(sampler, uv0.zy), "\r
- //" texture2D(sampler, uv1.xy), "\r
- //" texture2D(sampler, uv1.zy)); "\r
- //" vec4 x1 = cubicFilter(w, texture2D(sampler, uv0.xw), "\r
- //" texture2D(sampler, uv0.zw), "\r
- //" texture2D(sampler, uv1.xw), "\r
- //" texture2D(sampler, uv1.zw)); "\r
- //" vec4 x2 = cubicFilter(w, texture2D(sampler, uv2.xy), "\r
- //" texture2D(sampler, uv2.zy), "\r
- //" texture2D(sampler, uv3.xy), "\r
- //" texture2D(sampler, uv3.zy)); "\r
- //" vec4 x3 = cubicFilter(w, texture2D(sampler, uv2.xw), "\r
- //" texture2D(sampler, uv2.zw), "\r
- //" texture2D(sampler, uv3.xw), "\r
- //" texture2D(sampler, uv3.zw)); "\r
- //" "\r
- //" w = computeWeights(f.y); "\r
- //" return cubicFilter(w, x0, x1, x2, x3); "\r
- //"} "; \r
\r
- shaders_[pixel_format::abgr] = shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::abgr] = common::gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() "\r
"{ "\r
" gl_FragColor = abgr.argb * gl_Color; "\r
"} ");\r
\r
- shaders_[pixel_format::argb]= shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::argb]= common::gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() " \r
"{ "\r
" gl_FragColor = argb.grab * gl_Color; " \r
"} ");\r
\r
- shaders_[pixel_format::bgra]= shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::bgra]= common::gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() "\r
"{ "\r
" gl_FragColor = bgra.rgba * gl_Color; "\r
"} ");\r
\r
- shaders_[pixel_format::rgba] = shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::rgba] = common::gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() "\r
"{ "\r
" gl_FragColor = rgba.bgra * gl_Color; "\r
"} ");\r
\r
- shaders_[pixel_format::ycbcr] = shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::ycbcr] = common::gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() "\r
"{ "\r
" gl_FragColor = ycbcra_to_bgra(y, cb, cr, a) * gl_Color; "\r
"} ");\r
\r
- shaders_[pixel_format::ycbcra] = shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::ycbcra] = common::gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() "\r
"{ "\r
"} ");\r
}\r
\r
- void use(const pixel_format_desc& desc)\r
+ void begin(const shader_transform& transform)\r
+ {\r
+ transform_stack_.push(transform);\r
+\r
+ glPushMatrix();\r
+ alpha_ *= transform_stack_.top().alpha;\r
+ glColor4d(1.0, 1.0, 1.0, alpha_);\r
+ glTranslated(transform_stack_.top().pos.get<0>()*2.0, transform_stack_.top().pos.get<1>()*2.0, 0.0);\r
+\r
+ if(transform.mode == video_mode::upper)\r
+ glPolygonStipple(upper_pattern);\r
+ else if(transform.mode == video_mode::lower)\r
+ glPolygonStipple(lower_pattern);\r
+ else\r
+ glPolygonStipple(progressive_pattern);\r
+ }\r
+ \r
+ void render(const pixel_format_desc& desc)\r
{\r
set_pixel_format(desc.pix_fmt);\r
- set_planes(desc.planes);\r
+\r
+ auto t = transform_stack_.top();\r
+ glBegin(GL_QUADS);\r
+ glTexCoord2d(0.0, 0.0); glVertex2d(-1.0, -1.0);\r
+ glTexCoord2d(1.0, 0.0); glVertex2d( 1.0, -1.0);\r
+ glTexCoord2d(1.0, 1.0); glVertex2d( 1.0, 1.0);\r
+ glTexCoord2d(0.0, 1.0); glVertex2d(-1.0, 1.0);\r
+ glEnd();\r
+ }\r
+\r
+ void end()\r
+ {\r
+ alpha_ /= transform_stack_.top().alpha;\r
+ glPopMatrix();\r
+ transform_stack_.pop();\r
}\r
\r
void set_pixel_format(pixel_format::type format)\r
current_ = format;\r
shaders_[format].use();\r
}\r
-\r
- void set_planes(const std::vector<pixel_format_desc::plane>& planes)\r
- {\r
- for(size_t n = 0; n < planes.size() && n < 2; ++n)\r
- glUniform4f(glGetUniformLocation(shaders_[current_].program(), std::string("plane_size[" + boost::lexical_cast<std::string>(n) + "]").c_str()), \r
- static_cast<float>(planes[n].width), static_cast<float>(planes[n].height), 1.0f/static_cast<float>(planes[n].width), 1.0f/static_cast<float>(planes[n].height));\r
- }\r
-\r
- //void set_size(pixel_format_desc& desc)\r
- //{\r
- // for(int n = 0; n < 4; ++n)\r
- // {\r
- // std::string name = std::string("plane_size[") + boost::lexical_cast<std::string>(n) + "]";\r
- // GL(glUniform4f(shaders_[current_].get_location(name), \r
- // static_cast<float>(desc.planes[n].width), \r
- // static_cast<float>(desc.planes[n].height),\r
- // 1.0f/static_cast<float>(desc.planes[n].width),\r
- // 1.0f/static_cast<float>(desc.planes[n].height)));\r
- // }\r
- //} \r
+ \r
+ double alpha_;\r
+ std::stack<shader_transform> transform_stack_;\r
\r
video_format_desc format_desc_;\r
pixel_format::type current_;\r
- std::unordered_map<pixel_format::type, shader_program> shaders_;\r
+ std::unordered_map<pixel_format::type, common::gl::shader_program> shaders_;\r
};\r
\r
frame_shader::frame_shader(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
-void frame_shader::use(const pixel_format_desc& desc){impl_->use(desc);}\r
-\r
+void frame_shader::begin(const shader_transform& transform) {impl_->begin(transform);}\r
+void frame_shader::render(const pixel_format_desc& desc){impl_->render(desc);}\r
+void frame_shader::end(){impl_->end();}\r
}}
\ No newline at end of file
#include "../format/video_format.h"\r
#include "../format/pixel_format.h"\r
\r
+#include <boost/tuple/tuple.hpp>\r
+\r
#include <memory>\r
#include <array>\r
\r
namespace caspar { namespace core {\r
\r
+struct shader_transform\r
+{\r
+ shader_transform() : alpha(1.0), pos(boost::make_tuple(0.0, 0.0)), uv(boost::make_tuple(0.0, 1.0, 1.0, 0.0)), mode(video_mode::invalid){}\r
+ double alpha;\r
+ boost::tuple<double, double> pos;\r
+ boost::tuple<double, double, double, double> uv;\r
+ video_mode::type mode; \r
+};\r
+\r
class frame_shader\r
{\r
public:\r
frame_shader(const video_format_desc& format_desc);\r
- void use(const pixel_format_desc& image);\r
\r
+ void begin(const shader_transform& transform);\r
+ void render(const pixel_format_desc& image);\r
+ void end();\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
--- /dev/null
+#pragma once\r
+\r
+#include <memory>\r
+\r
+namespace caspar { namespace core {\r
+ \r
+class gpu_frame;\r
+typedef std::shared_ptr<gpu_frame> gpu_frame_ptr;\r
+\r
+class write_frame;\r
+typedef std::shared_ptr<write_frame> write_frame_ptr;\r
+\r
+class transform_frame;\r
+typedef std::shared_ptr<transform_frame> transform_frame_ptr;\r
+\r
+class composite_frame;\r
+typedef std::shared_ptr<composite_frame> composite_frame_ptr;\r
+\r
+class consumer_frame;\r
+\r
+class frame_shader;\r
+typedef std::shared_ptr<frame_shader> frame_shader_ptr;\r
+\r
+class frame_renderer;\r
+typedef std::shared_ptr<frame_renderer> frame_renderer_ptr;\r
+\r
+class frame_processor_device;\r
+typedef std::shared_ptr<frame_processor_device> frame_processor_device_ptr;\r
+}}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include "fwd.h"\r
+\r
+#include "../../common/exception/exceptions.h"\r
+\r
+#include <boost/noncopyable.hpp>\r
+\r
+#include <memory>\r
+#include <vector>\r
+\r
+namespace caspar { namespace core {\r
+ \r
+class gpu_frame : boost::noncopyable\r
+{ \r
+public:\r
+ virtual const std::vector<short>& audio_data() const = 0;\r
+ virtual std::vector<short>& audio_data() = 0;\r
+ \r
+ virtual void begin_write() = 0;\r
+ virtual void end_write() = 0;\r
+ virtual void draw(frame_shader& shader) = 0;\r
+};\r
+typedef std::shared_ptr<gpu_frame> gpu_frame_ptr;\r
+\r
+\r
+}}
\ No newline at end of file
--- /dev/null
+#include "../StdAfx.h"\r
+\r
+#include "read_frame.h"\r
+#include "../format/pixel_format.h"\r
+#include "../../common/gl/utility.h"\r
+#include "../../common/gl/pixel_buffer_object.h"\r
+\r
+#include <boost/range/algorithm.hpp>\r
+\r
+namespace caspar { namespace core {\r
+ \r
+struct read_frame::implementation : boost::noncopyable\r
+{\r
+ implementation(size_t width, size_t height) : pixel_data_(nullptr)\r
+ {\r
+ if(width > 2 || height > 2)\r
+ pbo_.reset(new common::gl::pixel_buffer_object(width, height, GL_BGRA));\r
+ }\r
+ \r
+ void begin_read()\r
+ { \r
+ if(!pbo_)\r
+ return;\r
+ pixel_data_ = nullptr;\r
+ pbo_->begin_read();\r
+ }\r
+\r
+ void end_read()\r
+ {\r
+ if(!pbo_)\r
+ return;\r
+ pixel_data_ = pbo_->end_read();\r
+ }\r
+ \r
+ std::unique_ptr<common::gl::pixel_buffer_object> pbo_;\r
+ void* pixel_data_; \r
+ std::vector<short> audio_data_;\r
+};\r
+ \r
+read_frame::read_frame(size_t width, size_t height) : impl_(new implementation(width, height)){}\r
+void read_frame::begin_read(){impl_->begin_read();}\r
+void read_frame::end_read(){impl_->end_read();}\r
+const boost::iterator_range<const unsigned char*> read_frame::data() const\r
+{\r
+ auto ptr = static_cast<const unsigned char*>(impl_->pixel_data_);\r
+ return boost::iterator_range<const unsigned char*>(ptr, ptr+impl_->pbo_->size());\r
+}\r
+const std::vector<short>& read_frame::audio_data() const { return impl_->audio_data_; }\r
+std::vector<short>& read_frame::audio_data() { return impl_->audio_data_; }\r
+}}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include "../format/video_format.h"\r
+#include "../format/pixel_format.h"\r
+\r
+#include <boost/noncopyable.hpp>\r
+#include <boost/range/iterator_range.hpp>\r
+\r
+#include <memory>\r
+#include <vector>\r
+\r
+namespace caspar { namespace core {\r
+\r
+class read_frame : boost::noncopyable\r
+{\r
+public: \r
+ explicit read_frame(size_t width, size_t height);\r
+\r
+ const boost::iterator_range<const unsigned char*> data() const;\r
+ const std::vector<short>& audio_data() const;\r
+ std::vector<short>& audio_data();\r
+ \r
+ void begin_read();\r
+ void end_read();\r
+\r
+private:\r
+ struct implementation;\r
+ std::shared_ptr<implementation> impl_;\r
+};\r
+typedef std::shared_ptr<read_frame> read_frame_ptr;\r
+ \r
+class consumer_frame\r
+{\r
+public: \r
+ consumer_frame(const read_frame_ptr& frame) : frame_(frame){}\r
+ const boost::iterator_range<const unsigned char*> data() const {return frame_->data();}\r
+ const std::vector<short>& audio_data() const {return frame_->audio_data();}\r
+ \r
+private:\r
+ read_frame_ptr frame_;\r
+};\r
+typedef std::shared_ptr<consumer_frame> consumer_frame_ptr;\r
+typedef std::unique_ptr<consumer_frame> consumer_frame_uptr;\r
+\r
+}}
\ No newline at end of file
--- /dev/null
+#include "../StdAfx.h"\r
+\r
+#include "transform_frame.h"\r
+\r
+#include "frame_shader.h"\r
+\r
+#include "../format/pixel_format.h"\r
+#include "../../common/gl/utility.h"\r
+#include "../../common/gl/pixel_buffer_object.h"\r
+\r
+#include <boost/range/algorithm.hpp>\r
+\r
+#include <tbb/parallel_for.h>\r
+\r
+namespace caspar { namespace core {\r
+ \r
+struct transform_frame::implementation : boost::noncopyable\r
+{\r
+ implementation(const gpu_frame_ptr& frame) : frame_(frame), audio_volume_(255){}\r
+ \r
+ void draw(frame_shader& shader)\r
+ {\r
+ if(!frame_)\r
+ return;\r
+\r
+ shader.begin(transform_);\r
+ frame_->draw(shader);\r
+ shader.end();\r
+ }\r
+\r
+ std::vector<short>& audio_data()\r
+ {\r
+ if(!audio_data_.empty() || !frame_)\r
+ return audio_data_;\r
+ \r
+ audio_data_ = frame_->audio_data();\r
+ tbb::parallel_for\r
+ (\r
+ tbb::blocked_range<size_t>(0, audio_data_.size()),\r
+ [&](const tbb::blocked_range<size_t>& r)\r
+ {\r
+ for(size_t n = r.begin(); n < r.end(); ++n) \r
+ audio_data_[n] = static_cast<short>((static_cast<int>(audio_data_[n])*audio_volume_)>>8); \r
+ }\r
+ );\r
+ \r
+ return audio_data_;\r
+ }\r
+\r
+ void begin_write()\r
+ {\r
+ if(frame_)\r
+ frame_->begin_write();\r
+ }\r
+\r
+ void end_write()\r
+ {\r
+ if(frame_)\r
+ frame_->end_write();\r
+ }\r
+ \r
+ std::vector<short> audio_data_;\r
+ \r
+ shader_transform transform_;\r
+\r
+ unsigned char audio_volume_;\r
+ gpu_frame_ptr frame_;\r
+};\r
+ \r
+transform_frame::transform_frame(const gpu_frame_ptr& frame) : impl_(new implementation(frame)){}\r
+void transform_frame::begin_write(){impl_->begin_write();}\r
+void transform_frame::end_write(){impl_->end_write();} \r
+void transform_frame::draw(frame_shader& shader){impl_->draw(shader);}\r
+void transform_frame::audio_volume(unsigned char volume){impl_->audio_volume_ = volume;}\r
+void transform_frame::translate(double x, double y){impl_->transform_.pos = boost::make_tuple(x, y);}\r
+void transform_frame::texcoord(double left, double top, double right, double bottom){impl_->transform_.uv = boost::make_tuple(left, top, right, bottom);}\r
+void transform_frame::video_mode(video_mode::type mode){impl_->transform_.mode = mode;}\r
+void transform_frame::alpha(double value){impl_->transform_.alpha = value;}\r
+std::vector<short>& transform_frame::audio_data() { return impl_->audio_data(); }\r
+const std::vector<short>& transform_frame::audio_data() const { return impl_->audio_data(); }\r
+}}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include "gpu_frame.h"\r
+\r
+#include "../format/video_format.h"\r
+#include "../format/pixel_format.h"\r
+\r
+#include <boost/noncopyable.hpp>\r
+#include <boost/range/iterator_range.hpp>\r
+\r
+#include <memory>\r
+#include <array>\r
+#include <vector>\r
+\r
+namespace caspar { namespace core {\r
+ \r
+class transform_frame : public gpu_frame\r
+{\r
+public:\r
+ explicit transform_frame(const gpu_frame_ptr& frame);\r
+ \r
+ virtual std::vector<short>& audio_data();\r
+ virtual const std::vector<short>& audio_data() const;\r
+\r
+ void audio_volume(unsigned char volume);\r
+ void translate(double x, double y);\r
+ void texcoord(double left, double top, double right, double bottom);\r
+ void video_mode(video_mode::type mode);\r
+ void alpha(double value);\r
+\r
+protected: \r
+ virtual void begin_write();\r
+ virtual void end_write();\r
+ virtual void draw(frame_shader& shader);\r
+\r
+private:\r
+ struct implementation;\r
+ std::shared_ptr<implementation> impl_;\r
+};\r
+typedef std::shared_ptr<transform_frame> transform_frame_ptr;\r
+\r
+}}
\ No newline at end of file
--- /dev/null
+#include "../StdAfx.h"\r
+\r
+#include "write_frame.h"\r
+\r
+#include "frame_shader.h"\r
+\r
+#include "../format/pixel_format.h"\r
+#include "../../common/gl/utility.h"\r
+#include "../../common/gl/pixel_buffer_object.h"\r
+\r
+#include <boost/range/algorithm.hpp>\r
+\r
+namespace caspar { namespace core {\r
+ \r
+struct write_frame::implementation : boost::noncopyable\r
+{\r
+ implementation(const pixel_format_desc& desc) : desc_(desc)\r
+ { \r
+ assert(desc_.planes.size() <= 4);\r
+\r
+ std::fill(pixel_data_.begin(), pixel_data_.end(), nullptr);\r
+\r
+ for(size_t n = 0; n < desc_.planes.size(); ++n)\r
+ {\r
+ if(desc_.planes[n].size == 0)\r
+ break;\r
+\r
+ GLuint format = [&]() -> GLuint\r
+ {\r
+ switch(desc_.planes[n].channels)\r
+ {\r
+ case 1: return GL_LUMINANCE;\r
+ case 2: return GL_LUMINANCE_ALPHA;\r
+ case 3: return GL_BGR;\r
+ case 4: return GL_BGRA;\r
+ default: BOOST_THROW_EXCEPTION(out_of_range() << msg_info("1-4 channels are supported") << arg_name_info("desc.planes.channels")); \r
+ }\r
+ }();\r
+\r
+ pbo_.push_back(std::make_shared<common::gl::pixel_buffer_object>(desc_.planes[n].width, desc_.planes[n].height, format));\r
+ pbo_.back()->is_smooth(true);\r
+ }\r
+ end_write();\r
+ }\r
+ \r
+ void begin_write()\r
+ {\r
+ std::fill(pixel_data_.begin(), pixel_data_.end(), nullptr);\r
+ boost::range::for_each(pbo_, std::mem_fn(&common::gl::pixel_buffer_object::begin_write));\r
+ }\r
+\r
+ void end_write()\r
+ {\r
+ boost::range::transform(pbo_, pixel_data_.begin(), std::mem_fn(&common::gl::pixel_buffer_object::end_write));\r
+ }\r
+\r
+ void draw(frame_shader& shader)\r
+ {\r
+ assert(pbo_.size() == desc_.planes.size());\r
+\r
+ for(size_t n = 0; n < pbo_.size(); ++n)\r
+ {\r
+ glActiveTexture(GL_TEXTURE0+n);\r
+ pbo_[n]->bind_texture();\r
+ }\r
+ shader.render(desc_);\r
+ }\r
+\r
+ unsigned char* data(size_t index)\r
+ {\r
+ return static_cast<unsigned char*>(pixel_data_[index]);\r
+ }\r
+\r
+ void reset()\r
+ {\r
+ audio_data_.clear();\r
+ end_write();\r
+ }\r
+ \r
+ std::vector<common::gl::pixel_buffer_object_ptr> pbo_;\r
+ std::array<void*, 4> pixel_data_; \r
+ std::vector<short> audio_data_;\r
+ \r
+ const pixel_format_desc desc_;\r
+};\r
+ \r
+write_frame::write_frame(const pixel_format_desc& desc) : impl_(new implementation(desc)){}\r
+void write_frame::begin_write(){impl_->begin_write();}\r
+void write_frame::end_write(){impl_->end_write();} \r
+void write_frame::draw(frame_shader& shader){impl_->draw(shader);}\r
+boost::iterator_range<unsigned char*> write_frame::data(size_t index)\r
+{\r
+ auto ptr = static_cast<unsigned char*>(impl_->pixel_data_[index]);\r
+ return boost::iterator_range<unsigned char*>(ptr, ptr+impl_->desc_.planes[index].size);\r
+}\r
+const boost::iterator_range<const unsigned char*> write_frame::data(size_t index) const\r
+{\r
+ auto ptr = static_cast<const unsigned char*>(impl_->pixel_data_[index]);\r
+ return boost::iterator_range<const unsigned char*>(ptr, ptr+impl_->desc_.planes[index].size);\r
+}\r
+\r
+std::vector<short>& write_frame::audio_data() { return impl_->audio_data_; }\r
+const std::vector<short>& write_frame::audio_data() const { return impl_->audio_data_; }\r
+void write_frame::reset(){impl_->reset();}\r
+}}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include "fwd.h"\r
+\r
+#include "gpu_frame.h"\r
+\r
+#include "../format/video_format.h"\r
+#include "../format/pixel_format.h"\r
+\r
+#include <boost/noncopyable.hpp>\r
+#include <boost/tuple/tuple.hpp>\r
+#include <boost/range/iterator_range.hpp>\r
+\r
+#include <memory>\r
+#include <array>\r
+#include <vector>\r
+\r
+namespace caspar { namespace core {\r
+ \r
+class write_frame : public gpu_frame\r
+{\r
+ friend class frame_renderer;\r
+ friend class frame_processor_device;\r
+\r
+public: \r
+ boost::iterator_range<unsigned char*> data(size_t index = 0);\r
+ const boost::iterator_range<const unsigned char*> data(size_t index = 0) const;\r
+\r
+ virtual std::vector<short>& audio_data();\r
+ virtual const std::vector<short>& audio_data() const;\r
+ \r
+private:\r
+ explicit write_frame(const pixel_format_desc& desc);\r
+\r
+ virtual void reset();\r
+ \r
+ virtual void begin_write();\r
+ virtual void end_write();\r
+ virtual void draw(frame_shader& shader);\r
+\r
+ struct implementation;\r
+ std::shared_ptr<implementation> impl_;\r
+};\r
+typedef std::shared_ptr<write_frame> write_frame_ptr;\r
+\r
+\r
+}}
\ No newline at end of file
public:\r
explicit color_producer(const std::wstring& color) : color_str_(color), color_value_(get_pixel_color_value(color)){}\r
\r
- frame_ptr render_frame()\r
+ gpu_frame_ptr render_frame()\r
{ \r
return frame_;\r
}\r
return + L"color_producer. color: " + color_str_;\r
}\r
\r
- frame_ptr frame_;\r
+ gpu_frame_ptr frame_;\r
unsigned int color_value_;\r
std::wstring color_str_;\r
};\r
video_transformer_->initialize(frame_processor);\r
}\r
\r
- frame_ptr render_frame()\r
+ gpu_frame_ptr render_frame()\r
{\r
while(ouput_channel_.empty() && !input_->is_eof())\r
{ \r
\r
// Return last frame without audio.\r
if(last_frame_)\r
- last_frame_->get_audio_data().clear();\r
+ last_frame_->audio_data().clear();\r
return last_frame_;\r
}\r
else if(underrun_count_ > 0)\r
{\r
if(has_audio_ && video_frame_channel_.front() != nullptr)\r
{\r
- video_frame_channel_.front()->get_audio_data() = std::move(audio_chunk_channel_.front());\r
+ video_frame_channel_.front()->audio_data() = std::move(audio_chunk_channel_.front());\r
audio_chunk_channel_.pop_front();\r
}\r
\r
- frame_ptr frame = video_frame_channel_.front();\r
+ gpu_frame_ptr frame = video_frame_channel_.front();\r
video_frame_channel_.pop_front();\r
ouput_channel_.push(std::move(frame));\r
} \r
\r
video_decoder_uptr video_decoder_;\r
video_transformer_uptr video_transformer_;\r
- std::deque<frame_ptr> video_frame_channel_;\r
+ std::deque<gpu_frame_ptr> video_frame_channel_;\r
\r
audio_decoder_ptr audio_decoder_;\r
std::deque<std::vector<short>> audio_chunk_channel_;\r
\r
- std::queue<frame_ptr> ouput_channel_;\r
+ std::queue<gpu_frame_ptr> ouput_channel_;\r
\r
std::wstring filename_;\r
\r
long underrun_count_;\r
\r
- frame_ptr last_frame_;\r
+ gpu_frame_ptr last_frame_;\r
};\r
\r
frame_producer_ptr create_ffmpeg_producer(const std::vector<std::wstring>& params)\r
#include "video_transformer.h"\r
\r
#include "../../../format/video_format.h"\r
-#include "../../../processor/frame.h"\r
+#include "../../../processor/write_frame.h"\r
+#include "../../../processor/transform_frame.h"\r
#include "../../../processor/frame_processor_device.h"\r
\r
#include <tbb/parallel_for.h>\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
}\r
}\r
\r
- frame_ptr execute(const std::shared_ptr<AVFrame>& decoded_frame)\r
+ gpu_frame_ptr execute(const std::shared_ptr<AVFrame>& decoded_frame)\r
{ \r
if(decoded_frame == nullptr)\r
return nullptr;\r
\r
- frame_ptr result_frame;\r
+ write_frame_ptr result_frame;\r
if(sws_context_ == nullptr)\r
{\r
result_frame = frame_processor_->create_frame(desc_);\r
\r
// TODO: Make generic for all formats and modes.\r
if(codec_context_->codec_id == CODEC_ID_DVVIDEO) // Move up one field\r
- result_frame->get_render_transform().pos = boost::make_tuple(0.0f, 1.0/static_cast<double>(frame_processor_->get_video_format_desc().height));\r
+ {\r
+ auto transform = std::make_shared<transform_frame>(result_frame);\r
+ transform->translate(0.0f, 1.0/static_cast<double>(frame_processor_->get_video_format_desc().height));\r
+ return transform;\r
+ }\r
\r
return result_frame;\r
}\r
-\r
void initialize(const frame_processor_device_ptr& frame_processor)\r
{\r
frame_processor_ = frame_processor;\r
};\r
\r
video_transformer::video_transformer(AVCodecContext* codec_context) : impl_(new implementation(codec_context)){}\r
-frame_ptr video_transformer::execute(const std::shared_ptr<AVFrame>& decoded_frame){return impl_->execute(decoded_frame);}\r
+gpu_frame_ptr video_transformer::execute(const std::shared_ptr<AVFrame>& decoded_frame){return impl_->execute(decoded_frame);}\r
void video_transformer::initialize(const frame_processor_device_ptr& frame_processor){impl_->initialize(frame_processor); }\r
}}}
\ No newline at end of file
{\r
public:\r
video_transformer(AVCodecContext* codec_context);\r
- frame_ptr execute(const std::shared_ptr<AVFrame>& video_packet); \r
+ gpu_frame_ptr execute(const std::shared_ptr<AVFrame>& video_packet); \r
void initialize(const frame_processor_device_ptr& frame_processor);\r
private:\r
struct implementation;\r
\r
#pragma warning(push)\r
\r
-#include "..\..\processor\frame.h"\r
+#include "..\..\processor\write_frame.h"\r
#include "..\..\format\video_format.h"\r
\r
#include <ocmm.h>\r
#include "cg_producer.h"\r
#include "flash_producer.h"\r
\r
-#include "../../processor/frame.h"\r
+#include "../../processor/write_frame.h"\r
#include "../../Server.h"\r
\r
#include <boost/filesystem.hpp>\r
flash_producer_->param(param.str());\r
}\r
\r
- frame_ptr render_frame()\r
+ gpu_frame_ptr render_frame()\r
{\r
return flash_producer_ ? flash_producer_->render_frame() : nullptr;\r
}\r
}\r
\r
cg_producer::cg_producer() : impl_(new implementation()){}\r
-frame_ptr cg_producer::render_frame(){return impl_->render_frame();}\r
+gpu_frame_ptr cg_producer::render_frame(){return impl_->render_frame();}\r
void cg_producer::clear(){impl_->clear();}\r
void cg_producer::add(int layer, const std::wstring& template_name, bool play_on_load, const std::wstring& startFromLabel, const std::wstring& data){impl_->add(layer, template_name, play_on_load, startFromLabel, data);}\r
void cg_producer::remove(int layer){impl_->remove(layer);}\r
\r
cg_producer();\r
\r
- virtual frame_ptr render_frame();\r
+ virtual gpu_frame_ptr render_frame();\r
virtual void initialize(const frame_processor_device_ptr& frame_processor);\r
\r
void clear();\r
\r
#include "cg_producer.h"\r
\r
-#include "../../processor/frame.h"\r
+#include "../../processor/write_frame.h"\r
#include "../../server.h"\r
\r
#include <boost/assign/list_of.hpp>\r
{\r
ct_producer(const std::wstring& filename) : filename_(filename), initialized_(false){}\r
\r
- frame_ptr render_frame()\r
+ gpu_frame_ptr render_frame()\r
{\r
if(!initialized_)\r
{\r
#include "../../../common/concurrency/executor.h"\r
#include "../../../common/utility/scope_exit.h"\r
\r
-#include "../../processor/frame.h"\r
+#include "../../processor/write_frame.h"\r
#include "../../processor/composite_frame.h"\r
\r
#include <boost/assign.hpp>\r
auto format_desc = frame_processor_->get_video_format_desc();\r
bool is_progressive = format_desc.mode == video_mode::progressive || (flashax_container_->GetFPS() - format_desc.fps/2 == 0);\r
\r
- frame_ptr result;\r
+ gpu_frame_ptr result;\r
\r
if(is_progressive) \r
result = do_render_frame(); \r
else\r
{\r
- frame_ptr frame1 = do_render_frame();\r
- frame_ptr frame2 = do_render_frame();\r
+ gpu_frame_ptr frame1 = do_render_frame();\r
+ gpu_frame_ptr frame2 = do_render_frame();\r
result = composite_frame::interlace(frame1, frame2, format_desc.mode);\r
}\r
\r
}\r
}\r
\r
- frame_ptr do_render_frame()\r
+ gpu_frame_ptr do_render_frame()\r
{\r
auto format_desc = frame_processor_->get_video_format_desc();\r
\r
return frame;\r
}\r
\r
- frame_ptr render_frame()\r
+ gpu_frame_ptr render_frame()\r
{ \r
- return (frame_buffer_.try_pop(last_frame_) || !is_empty_) && last_frame_ ? last_frame_ : frame::empty();\r
+ return (frame_buffer_.try_pop(last_frame_) || !is_empty_) && last_frame_ ? last_frame_ : empty_;\r
}\r
\r
void initialize(const frame_processor_device_ptr& frame_processor)\r
{\r
frame_processor_ = frame_processor;\r
auto format_desc = frame_processor_->get_video_format_desc();\r
+ empty_ = frame_processor_->create_frame(pixel_format_desc());\r
bmp_frame_ = std::make_shared<bitmap>(format_desc.width, format_desc.height);\r
start(false);\r
}\r
\r
CComObject<flash::FlashAxContainer>* flashax_container_;\r
\r
- tbb::concurrent_bounded_queue<frame_ptr> frame_buffer_;\r
+ tbb::concurrent_bounded_queue<gpu_frame_ptr> frame_buffer_;\r
\r
- frame_ptr last_frame_;\r
+ gpu_frame_ptr empty_;\r
+ gpu_frame_ptr last_frame_;\r
\r
bitmap_ptr current_frame_;\r
bitmap_ptr bmp_frame_;\r
};\r
\r
flash_producer::flash_producer(const std::wstring& filename) : impl_(new implementation(this, filename)){}\r
-frame_ptr flash_producer::render_frame(){return impl_->render_frame();}\r
+gpu_frame_ptr flash_producer::render_frame(){return impl_->render_frame();}\r
void flash_producer::param(const std::wstring& param){impl_->param(param);}\r
void flash_producer::initialize(const frame_processor_device_ptr& frame_processor) { impl_->initialize(frame_processor);}\r
std::wstring flash_producer::print() const {return impl_->print();}\r
\r
flash_producer(const std::wstring& filename);\r
\r
- virtual frame_ptr render_frame();\r
+ virtual gpu_frame_ptr render_frame();\r
virtual void initialize(const frame_processor_device_ptr& frame_processor);\r
virtual std::wstring print() const;\r
\r
*/\r
#pragma once\r
\r
-#include "../processor/frame.h"\r
+#include "../processor/write_frame.h"\r
#include "../processor/frame_processor_device.h"\r
\r
#include <boost/noncopyable.hpp>\r
virtual ~frame_producer(){} \r
\r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
- /// \fn virtual frame_ptr :::render_frame() = 0;\r
+ /// \fn virtual gpu_frame_ptr :::render_frame() = 0;\r
///\r
/// \brief Renders a frame.\r
/// \r
///\r
/// \return The frame. \r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
- virtual frame_ptr render_frame() = 0;\r
+ virtual gpu_frame_ptr render_frame() = 0;\r
\r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
/// \fn virtual std::shared_ptr<frame_producer> :::get_following_producer() const\r
\r
namespace caspar { namespace core {\r
\r
-std::vector<frame_ptr> render_frames(std::map<int, layer>& layers)\r
+std::vector<gpu_frame_ptr> render_frames(std::map<int, layer>& layers)\r
{ \r
- std::vector<frame_ptr> frames(layers.size(), nullptr);\r
+ std::vector<gpu_frame_ptr> frames(layers.size(), nullptr);\r
tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size()), \r
[&](const tbb::blocked_range<size_t>& r)\r
{\r
~implementation()\r
{\r
is_running_ = false;\r
- frame_processor_->clear();\r
render_thread_.join();\r
}\r
\r
{\r
try\r
{ \r
- std::vector<frame_ptr> frames;\r
+ std::vector<gpu_frame_ptr> frames;\r
{\r
tbb::mutex::scoped_lock lock(layers_mutex_); \r
frames = render_frames(layers_);\r
\r
#include "../../../common/exception/Exceptions.h"\r
\r
-#include "../../processor/frame.h"\r
+#include "../../processor/write_frame.h"\r
\r
#if defined(_MSC_VER)\r
#pragma warning (disable : 4714) // marked as __forceinline not inlined\r
{\r
image_producer(const std::wstring& filename) : filename_(filename) {}\r
\r
- frame_ptr render_frame(){return frame_;}\r
+ gpu_frame_ptr render_frame(){return frame_;}\r
\r
void initialize(const frame_processor_device_ptr& frame_processor)\r
{\r
\r
frame_processor_device_ptr frame_processor_;\r
std::wstring filename_;\r
- frame_ptr frame_;\r
+ gpu_frame_ptr frame_;\r
};\r
\r
frame_producer_ptr create_image_producer(const std::vector<std::wstring>& params)\r
\r
#include "image_loader.h"\r
\r
-#include "../../processor/frame.h"\r
+#include "../../processor/write_frame.h"\r
#include "../../processor/composite_frame.h"\r
#include "../../format/video_format.h"\r
#include "../../processor/frame_processor_device.h"\r
std::copy_n(&pBits[i* width * 4], width * 4, &image_.get()[i * image_width_ * 4]);\r
}\r
\r
- frame_ptr do_render_frame()\r
+ gpu_frame_ptr do_render_frame()\r
{\r
- frame_ptr frame = frame_processor_->create_frame(format_desc_.width, format_desc_.height);\r
+ auto frame = frame_processor_->create_frame(format_desc_.width, format_desc_.height);\r
std::fill(frame->data().begin(), frame->data().end(), 0);\r
\r
const int delta_x = direction_ == direction::Left ? speed_ : -speed_;\r
return frame;\r
}\r
\r
- frame_ptr render_frame()\r
+ gpu_frame_ptr render_frame()\r
{ \r
if(format_desc_.mode != video_mode::progressive) \r
{\r
- frame_ptr frame1;\r
- frame_ptr frame2;\r
+ gpu_frame_ptr frame1;\r
+ gpu_frame_ptr frame2;\r
tbb::parallel_invoke([&]{ frame1 = do_render_frame(); }, [&]{ frame2 = do_render_frame(); });\r
return composite_frame::interlace(frame1, frame2, format_desc_.mode);\r
} \r
{\r
foreground_ = nullptr; \r
last_frame_ = frame_producer->render_frame();\r
- if(last_frame_ != nullptr)\r
- last_frame_->get_audio_data().clear(); // No audio\r
}\r
else if(option == load_option::auto_play)\r
play(); \r
last_frame_ = nullptr;\r
}\r
\r
- frame_ptr render_frame()\r
+ gpu_frame_ptr render_frame()\r
{ \r
if(!foreground_ || is_paused_)\r
return last_frame_;\r
} \r
\r
tbb::atomic<bool> is_paused_;\r
- frame_ptr last_frame_;\r
+ gpu_frame_ptr last_frame_;\r
frame_producer_ptr foreground_;\r
frame_producer_ptr background_;\r
};\r
void layer::pause(){impl_->pause();}\r
void layer::stop(){impl_->stop();}\r
void layer::clear(){impl_->clear();}\r
-frame_ptr layer::render_frame() {return impl_->render_frame();}\r
+gpu_frame_ptr layer::render_frame() {return impl_->render_frame();}\r
frame_producer_ptr layer::foreground() const { return impl_->foreground_;}\r
frame_producer_ptr layer::background() const { return impl_->background_;}\r
}}
\ No newline at end of file
frame_producer_ptr foreground() const;\r
frame_producer_ptr background() const;\r
\r
- frame_ptr render_frame();\r
+ gpu_frame_ptr render_frame();\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/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
org_source_producer_ = source_producer_ = producer;\r
}\r
\r
- frame_ptr render_frame()\r
+ gpu_frame_ptr render_frame()\r
{\r
if(current_frame_ == 0)\r
CASPAR_LOG(info) << "Transition started.";\r
\r
- frame_ptr result = [&]() -> frame_ptr\r
+ gpu_frame_ptr result = [&]() -> gpu_frame_ptr\r
{\r
if(current_frame_++ >= info_.duration)\r
return nullptr;\r
\r
- frame_ptr source;\r
- frame_ptr dest;\r
+ gpu_frame_ptr source;\r
+ gpu_frame_ptr dest;\r
\r
tbb::parallel_invoke\r
(\r
return compose(dest, source);\r
}();\r
\r
- if(result == nullptr)\r
+ if(!result)\r
CASPAR_LOG(info) << "Transition ended.";\r
\r
return result;\r
}\r
\r
- frame_ptr render_frame(frame_producer_ptr& producer)\r
+ gpu_frame_ptr render_frame(frame_producer_ptr& producer)\r
{\r
- if(producer == nullptr)\r
+ if(!producer)\r
return nullptr;\r
\r
- frame_ptr frame;\r
+ gpu_frame_ptr frame;\r
try\r
{\r
frame = producer->render_frame();\r
\r
if(frame == nullptr)\r
{\r
- if(producer == nullptr || producer->get_following_producer() == nullptr)\r
+ if(!producer || !producer->get_following_producer())\r
return nullptr;\r
\r
try\r
}\r
return frame;\r
}\r
- \r
- void set_volume(const frame_ptr& frame, int volume)\r
- {\r
- assert(volume >= 0 && volume <= 256);\r
- std::for_each(frame->get_audio_data().begin(), frame->get_audio_data().end(), [&](int16_t& sample)\r
- {\r
- sample = static_cast<short>((static_cast<int>(sample)*volume)>>8);\r
- });\r
- }\r
- \r
- frame_ptr compose(frame_ptr dest_frame, frame_ptr src_frame) \r
+ \r
+ gpu_frame_ptr compose(gpu_frame_ptr dest_frame, gpu_frame_ptr src_frame) \r
{ \r
if(!dest_frame && !src_frame)\r
return nullptr;\r
\r
if(info_.type == transition::cut) \r
return src_frame;\r
-\r
- dest_frame = dest_frame ? dest_frame : frame::empty();\r
- src_frame = src_frame ? src_frame : frame::empty();\r
- \r
+ \r
double alpha = static_cast<double>(current_frame_)/static_cast<double>(info_.duration);\r
- int volume = static_cast<int>(alpha*256.0);\r
- \r
- tbb::parallel_invoke\r
- (\r
- [&]{set_volume(dest_frame, volume);},\r
- [&]{set_volume(src_frame, 256-volume);}\r
- );\r
+ unsigned char volume = static_cast<unsigned char>(alpha*256.0);\r
+\r
+ auto my_src_frame = std::make_shared<transform_frame>(src_frame);\r
+ auto my_dest_frame = std::make_shared<transform_frame>(dest_frame);\r
+\r
+ my_src_frame->audio_volume(255-volume);\r
+ my_dest_frame->audio_volume(volume);\r
\r
double dir = info_.direction == transition_direction::from_left ? 1.0 : -1.0; \r
\r
if(info_.type == transition::mix)\r
- dest_frame->get_render_transform().alpha = alpha; \r
+ my_dest_frame->alpha(alpha); \r
else if(info_.type == transition::slide) \r
- dest_frame->get_render_transform().pos = boost::make_tuple((-1.0+alpha)*dir, 0.0); \r
+ my_dest_frame->translate((-1.0+alpha)*dir, 0.0); \r
else if(info_.type == transition::push)\r
{\r
- dest_frame->get_render_transform().pos = boost::make_tuple((-1.0+alpha)*dir, 0.0);\r
- src_frame->get_render_transform().pos = boost::make_tuple((0.0+alpha)*dir, 0.0);\r
+ my_dest_frame->translate((-1.0+alpha)*dir, 0.0);\r
+ my_src_frame->translate((0.0+alpha)*dir, 0.0);\r
}\r
else if(info_.type == transition::wipe)\r
{\r
- dest_frame->get_render_transform().pos = boost::make_tuple((-1.0+alpha)*dir, 0.0); \r
- dest_frame->get_render_transform().uv = boost::make_tuple((-1.0+alpha)*dir, 1.0, 1.0-(1.0-alpha)*dir, 0.0); \r
+ my_dest_frame->translate((-1.0+alpha)*dir, 0.0); \r
+ my_dest_frame->texcoord((-1.0+alpha)*dir, 1.0, 1.0-(1.0-alpha)*dir, 0.0); \r
}\r
\r
- return std::make_shared<composite_frame>(src_frame, dest_frame);\r
+ return std::make_shared<composite_frame>(my_src_frame, my_dest_frame);\r
}\r
\r
void initialize(const frame_processor_device_ptr& frame_processor)\r
};\r
\r
transition_producer::transition_producer(const frame_producer_ptr& dest, const transition_info& info) : impl_(new implementation(dest, info)){}\r
-frame_ptr transition_producer::render_frame(){return impl_->render_frame();}\r
+gpu_frame_ptr transition_producer::render_frame(){return impl_->render_frame();}\r
frame_producer_ptr transition_producer::get_following_producer() const{return impl_->get_following_producer();}\r
void transition_producer::set_leading_producer(const frame_producer_ptr& producer) { impl_->set_leading_producer(producer); }\r
void transition_producer::initialize(const frame_processor_device_ptr& frame_processor) { impl_->initialize(frame_processor);}\r
public:\r
transition_producer(const frame_producer_ptr& destination, const transition_info& info);\r
\r
- frame_ptr render_frame();\r
+ gpu_frame_ptr render_frame();\r
\r
frame_producer_ptr get_following_producer() const;\r
void set_leading_producer(const frame_producer_ptr& producer);\r
</paths>\r
<channels>\r
<channel>\r
- <videomode>PAL</videomode>\r
+ <videomode>1080p2500</videomode>\r
<consumers>\r
<ogl>\r
<device>1</device>\r
</ogl>\r
<audio/>\r
<!--decklink> \r
- </decklink-->\r
- <!--bluefish>\r
+ </decklink>\r
+ <bluefish>\r
<device>1</device> \r
<embedded-audio>true</embedded-audio>\r
</bluefish-->\r