</ItemDefinitionGroup>\r
<ItemGroup>\r
<ClInclude Include="concurrency\executor.h" />\r
- <ClInclude Include="concurrency\function_task.h" />\r
<ClInclude Include="concurrency\Thread.h" />\r
<ClInclude Include="config.h" />\r
<ClInclude Include="exception\exceptions.h" />\r
<ClInclude Include="concurrency\executor.h">\r
<Filter>Source\concurrency</Filter>\r
</ClInclude>\r
- <ClInclude Include="concurrency\function_task.h">\r
- <Filter>Source\concurrency</Filter>\r
- </ClInclude>\r
<ClInclude Include="config.h">\r
<Filter>Source</Filter>\r
</ClInclude>\r
+++ /dev/null
-#pragma once\r
-\r
-#include <tbb/task.h>\r
-#include <tbb/concurrent_queue.h>\r
-#include <boost/thread/future.hpp>\r
-\r
-namespace caspar { namespace common { namespace function_task {\r
- \r
-namespace detail {\r
- \r
- template<typename Func>\r
- class packaged_task : public tbb::task\r
- {\r
- public:\r
- packaged_task(boost::packaged_task<Func>&& task) : task_(std::forward<boost::packaged_task<Func>>(task)) {}\r
- \r
- private:\r
- tbb::task* execute() \r
- {\r
- task_();\r
- return nullptr;\r
- }\r
-\r
- boost::packaged_task<Func> task_;\r
- };\r
-\r
- template<typename Func>\r
- class internal_function_task : public tbb::task\r
- {\r
- public:\r
- internal_function_task(Func&& func) : func_(std::forward<Func>(func)) {}\r
- private:\r
- tbb::task* execute() \r
- {\r
- func_();\r
- return nullptr;\r
- }\r
-\r
- Func func_;\r
- };\r
-}\r
- \r
-template <typename Func>\r
-void enqueue(Func&& func)\r
-{\r
- tbb::task::enqueue(*new(tbb::task::allocate_root()) detail::internal_function_task<Func>(std::forward<Func>(func)));\r
-}\r
-\r
-template<typename Func>\r
-auto begin_invoke(Func&& func) -> boost::unique_future<decltype(func())>\r
-{ \r
- auto task = boost::packaged_task<decltype(func())>(std::forward<Func>(func));\r
- auto future = task.get_future();\r
- tbb::task::enqueue(*new(tbb::task::allocate_root()) detail::packaged_task<decltype(func())>(boost::move(task))); \r
- return std::move(future); \r
-}\r
-\r
-template<typename Func>\r
-auto invoke(Func&& func) -> decltype(func())\r
-{ \r
- return function_task::begin_invoke(std::forward<Func>(func)).get(); \r
-}\r
-\r
-};\r
-\r
-}}
\ No newline at end of file
\r
struct pixel_buffer_object::implementation : boost::noncopyable\r
{\r
- implementation(size_t width, size_t height) \r
- : width_(width), height_(height), size_(width*height*4), pbo_(0),\r
- texture_(0), writing_(false), reading_(false), mapped_(false){}\r
+ implementation(size_t width, size_t height, GLenum format) \r
+ : width_(width), height_(height), pbo_(0), format_(format),\r
+ texture_(0), writing_(false), reading_(false), mapped_(false)\r
+ {\r
+ switch(format)\r
+ {\r
+ case GL_RGBA:\r
+ case GL_BGRA:\r
+ internal_ = GL_RGBA8;\r
+ size_ = width*height*4;\r
+ break;\r
+ case GL_BGR:\r
+ internal_ = GL_RGB8;\r
+ size_ = width*height*3;\r
+ break;\r
+ case GL_LUMINANCE_ALPHA:\r
+ internal_ = GL_LUMINANCE_ALPHA;\r
+ size_ = width*height*2;\r
+ break;\r
+ case GL_LUMINANCE:\r
+ case GL_ALPHA:\r
+ internal_ = GL_LUMINANCE;\r
+ size_ = width*height*1;\r
+ break;\r
+ default:\r
+ BOOST_THROW_EXCEPTION(invalid_argument() << msg_info("format"));\r
+ }\r
+ }\r
\r
~implementation()\r
{\r
GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));\r
GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));\r
\r
- GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width_, height_, 0, GL_BGRA, \r
+ GL(glTexImage2D(GL_TEXTURE_2D, 0, internal_, width_, height_, 0, format_, \r
GL_UNSIGNED_BYTE, NULL));\r
}\r
GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
GL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));\r
mapped_ = false;\r
bind_texture();\r
- GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, \r
+ GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, format_, \r
GL_UNSIGNED_BYTE, NULL));\r
unbind_pbo(GL_PIXEL_UNPACK_BUFFER);\r
writing_ = true;\r
bool mapped_;\r
bool writing_;\r
bool reading_;\r
+\r
+ GLint internal_;\r
+ GLenum format_;\r
};\r
\r
pixel_buffer_object::pixel_buffer_object(){}\r
-pixel_buffer_object::pixel_buffer_object(size_t width, size_t height) \r
- : impl_(new implementation(width, height)){}\r
-void pixel_buffer_object::create(size_t width, size_t height)\r
+pixel_buffer_object::pixel_buffer_object(size_t width, size_t height, GLenum format) \r
+ : impl_(new implementation(width, height, format)){}\r
+void pixel_buffer_object::create(size_t width, size_t height, GLenum format)\r
{\r
- impl_.reset(new implementation(width, height));\r
+ impl_.reset(new implementation(width, height, format));\r
}\r
void pixel_buffer_object::begin_write() { impl_->begin_write();}\r
void* pixel_buffer_object::end_write() {return impl_->end_write();} \r
void* pixel_buffer_object::end_read(){return impl_->end_read();}\r
void pixel_buffer_object::bind_texture() {impl_->bind_texture();}\r
size_t pixel_buffer_object::width() const {return impl_->width_;}\r
-size_t pixel_buffer_object::heigth() const {return impl_->height_;}\r
+size_t pixel_buffer_object::height() const {return impl_->height_;}\r
size_t pixel_buffer_object::size() const {return impl_->size_;}\r
bool pixel_buffer_object::is_reading() const { return impl_->reading_;}\r
bool pixel_buffer_object::is_writing() const { return impl_->writing_;}\r
{\r
public:\r
pixel_buffer_object();\r
- pixel_buffer_object(size_t width, size_t height);\r
- void create(size_t width, size_t height);\r
+ pixel_buffer_object(size_t width, size_t height, GLenum format = GL_BGRA);\r
+ void create(size_t width, size_t height, GLenum format = GL_BGRA);\r
~pixel_buffer_object(){}\r
\r
void begin_write();\r
void bind_texture();\r
\r
size_t width() const;\r
- size_t heigth() const;\r
+ size_t height() const;\r
size_t size() const;\r
\r
bool is_reading() const;\r
\r
namespace caspar { namespace common {\r
\r
-void* memcpy_SSE2(void* dest, const void* source, size_t num)\r
+void* aligned_memcpy(void* dest, const void* source, size_t num)\r
{ \r
__asm\r
{\r
return dest;\r
}\r
\r
-void* aligned_memcpy(void* dest, const void* source, size_t num)\r
+void* aligned_parallel_memcpy(void* dest, const void* source, size_t num)\r
{ \r
if(num < 128)\r
return memcpy(dest, source, num);\r
\r
tbb::parallel_for(tbb::blocked_range<size_t>(0, num/128), [&](const tbb::blocked_range<size_t>& r)\r
{\r
- memcpy_SSE2(reinterpret_cast<char*>(dest) + r.begin()*128, reinterpret_cast<const char*>(source) + r.begin()*128, r.size()*128);\r
+ aligned_memcpy(reinterpret_cast<char*>(dest) + r.begin()*128, reinterpret_cast<const char*>(source) + r.begin()*128, r.size()*128);\r
}, tbb::affinity_partitioner());\r
\r
return dest;\r
namespace caspar { namespace common {\r
\r
void* aligned_memcpy(void* dest, const void* source, size_t size);\r
+void* aligned_parallel_memcpy(void* dest, const void* source, size_t size);\r
void* clear(void* dest, size_t size);\r
\r
}}
\ No newline at end of file
std::shared_ptr<DecklinkVideoFrame> pTempFrame = GetReservedFrame();\r
if(pTempFrame && frame->size() == pTempFrame->size())\r
{\r
- common::aligned_memcpy(pTempFrame->data(), frame->data(), pTempFrame->size());\r
+ common::aligned_parallel_memcpy(pTempFrame->data(), frame->data(), pTempFrame->size());\r
DoRender(pTempFrame);\r
}\r
else\r
int next_index = (index_ + 1) % 2;\r
\r
auto ptr = pbos_[index_].end_write();\r
- common::aligned_memcpy(ptr, frame->data(), frame->size());\r
+ common::aligned_parallel_memcpy(ptr, frame->data(), frame->size());\r
\r
GL(glClear(GL_COLOR_BUFFER_BIT)); \r
pbos_[next_index].bind_texture(); \r
<ClInclude Include="frame\frame_fwd.h" />\r
<ClInclude Include="frame\gpu_frame.h" />\r
<ClInclude Include="frame\gpu_frame_processor.h" />\r
+ <ClInclude Include="frame\gpu_frame_transform.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="frame\gpu_frame_transform.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
<ClInclude Include="consumer\decklink\DeckLinkAPI_h.h">\r
<Filter>Source\consumer\decklink\interop</Filter>\r
</ClInclude>\r
- <ClInclude Include="consumer\frame_consumer.h">\r
- <Filter>Source\consumer</Filter>\r
- </ClInclude>\r
<ClInclude Include="producer\color\color_producer.h">\r
<Filter>Source\producer\color</Filter>\r
</ClInclude>\r
<ClInclude Include="config.h">\r
<Filter>Source</Filter>\r
</ClInclude>\r
+ <ClInclude Include="frame\gpu_frame_transform.h">\r
+ <Filter>Source\frame\gpu</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="consumer\frame_consumer.h">\r
+ <Filter>Source\consumer</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="StdAfx.cpp">\r
<ClCompile Include="renderer\display_device.cpp">\r
<Filter>Source\renderer</Filter>\r
</ClCompile>\r
+ <ClCompile Include="frame\gpu_frame_transform.cpp">\r
+ <Filter>Source\frame\gpu</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<Midl Include="consumer\decklink\DeckLinkAPI_v7_3.idl">\r
#include "frame_format.h"\r
\r
#include <memory>\r
+#include <array>\r
\r
namespace caspar { namespace core { \r
-\r
+ \r
struct frame_factory\r
{\r
virtual ~frame_factory(){}\r
- virtual gpu_frame_ptr create_frame(size_t width, size_t height) = 0;\r
- gpu_frame_ptr create_frame(const frame_format_desc format_desc)\r
+ virtual void release_frames(void* tag) = 0;\r
+ virtual gpu_frame_ptr create_frame(size_t width, size_t height, void* tag) = 0;\r
+ virtual gpu_frame_ptr create_frame(const planar_frame_dimension& data_size, void* tag) = 0;\r
+ gpu_frame_ptr create_frame(const frame_format_desc format_desc, void* tag)\r
{\r
- return create_frame(format_desc.width, format_desc.height);\r
+ return create_frame(format_desc.width, format_desc.height, tag);\r
}\r
};\r
\r
boost::range::for_each(frames_, std::mem_fn(&gpu_frame::end_read)); \r
}\r
\r
- void draw()\r
+ void draw(const gpu_frame_transform_ptr& transform)\r
{\r
glPushMatrix();\r
glTranslated(self_->x()*2.0, self_->y()*2.0, 0.0);\r
- boost::range::for_each(frames_, std::mem_fn(&gpu_frame::draw));\r
+ boost::range::for_each(frames_, std::bind(&gpu_frame::draw, std::placeholders::_1, transform));\r
glPopMatrix();\r
}\r
\r
}\r
}\r
\r
- unsigned char* data()\r
+ unsigned char* data(size_t index)\r
{\r
BOOST_THROW_EXCEPTION(invalid_operation());\r
}\r
void gpu_composite_frame::end_write(){impl_->end_write();} \r
void gpu_composite_frame::begin_read(){impl_->begin_read();}\r
void gpu_composite_frame::end_read(){impl_->end_read();}\r
-void gpu_composite_frame::draw(){impl_->draw();}\r
-unsigned char* gpu_composite_frame::data(){return impl_->data();}\r
+void gpu_composite_frame::draw(const gpu_frame_transform_ptr& transform){impl_->draw(transform);}\r
+unsigned char* gpu_composite_frame::data(size_t index){return impl_->data(index);}\r
void gpu_composite_frame::add(const gpu_frame_ptr& frame){impl_->add(frame);}\r
\r
gpu_frame_ptr gpu_composite_frame::interlace(const gpu_frame_ptr& frame1,\r
const gpu_frame_ptr& frame2, video_mode mode);\r
\r
private:\r
- virtual unsigned char* data();\r
+ virtual unsigned char* data(size_t index);\r
virtual void begin_write();\r
virtual void end_write();\r
virtual void begin_read();\r
virtual void end_read();\r
- virtual void draw();\r
+ virtual void draw(const gpu_frame_transform_ptr& transform);\r
\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
\r
struct gpu_frame::implementation : boost::noncopyable\r
{\r
- implementation(size_t width, size_t height) \r
- : pbo_(width, height), data_(nullptr), width_(width), height_(height), \r
- size_(width*height*4), reading_(false), alpha_(1.0f), \r
- x_(0.0f), y_(0.0f), mode_(video_mode::progressive), \r
- texcoords_(0.0, 1.0, 1.0, 0.0), writing_(false), mapped_(false)\r
- { \r
+ implementation(size_t width, size_t height)\r
+ : reading_(false), alpha_(1.0f), x_(0.0f), y_(0.0f), mode_(video_mode::progressive), \r
+ texcoords_(0.0, 1.0, 1.0, 0.0), writing_(false), mapped_(false), pix_format_(pixel_format::bgra)\r
+ { \r
+ data_.resize(1, 0);\r
+ pbo_.push_back(std::make_shared<common::gl::pixel_buffer_object>(width, height, GL_BGRA));\r
if(width > 0 && height > 0)\r
end_write();\r
}\r
+\r
+ implementation(const planar_frame_dimension& data_size)\r
+ : reading_(false), alpha_(1.0f), x_(0.0f), y_(0.0f), mode_(video_mode::progressive), \r
+ texcoords_(0.0, 1.0, 1.0, 0.0), writing_(false), mapped_(false), pix_format_(pixel_format::bgra)\r
+ { \r
+ data_.resize(data_size.size(), 0);\r
+ for(size_t n = 0; n < data_size.size() && data_size[n].first > 0 && data_size[n].second > 0; ++n)\r
+ pbo_.push_back(std::make_shared<common::gl::pixel_buffer_object>(data_size[n].first, data_size[n].second, GL_LUMINANCE));\r
+ end_write();\r
+ }\r
\r
void begin_write()\r
{\r
- data_ = nullptr;\r
- pbo_.begin_write(); \r
+ data_ = std::vector<unsigned char*>(4, 0);\r
+ for(size_t n = 0; n < pbo_.size(); ++n)\r
+ pbo_[n]->begin_write(); \r
}\r
\r
void end_write()\r
{\r
- data_ = static_cast<unsigned char*>(pbo_.end_write());\r
+ for(size_t n = 0; n < pbo_.size(); ++n)\r
+ data_[n] = static_cast<unsigned char*>(pbo_[n]->end_write());\r
}\r
\r
void begin_read()\r
{ \r
- data_ = nullptr;\r
- pbo_.begin_read();\r
+ data_ = std::vector<unsigned char*>(4, 0);\r
+ for(size_t n = 0; n < pbo_.size(); ++n)\r
+ pbo_[n]->begin_read(); \r
}\r
\r
void end_read()\r
{\r
- data_ = static_cast<unsigned char*>(pbo_.end_read());\r
+ for(size_t n = 0; n < pbo_.size(); ++n)\r
+ data_[n] = static_cast<unsigned char*>(pbo_[n]->end_read());\r
}\r
\r
- void draw()\r
+ void draw(const gpu_frame_transform_ptr& transform)\r
{\r
+ transform->set_pixel_format(pix_format_);\r
glPushMatrix();\r
glTranslated(x_*2.0, y_*2.0, 0.0);\r
glColor4d(1.0, 1.0, 1.0, alpha_);\r
else if(mode_ == video_mode::lower)\r
glPolygonStipple(lower_pattern);\r
\r
- pbo_.bind_texture();\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(texcoords_.left, texcoords_.bottom); glVertex2d(-1.0, -1.0);\r
glTexCoord2d(texcoords_.right, texcoords_.bottom); glVertex2d( 1.0, -1.0);\r
glPopMatrix();\r
}\r
\r
- unsigned char* data()\r
+ unsigned char* data(size_t index)\r
{\r
- if(data_ == nullptr)\r
+ if(pbo_.size() < index || data_[index] == nullptr)\r
BOOST_THROW_EXCEPTION(invalid_operation());\r
- return data_;\r
+ return data_[index];\r
}\r
\r
void reset()\r
mode_ = video_mode::progressive;\r
}\r
\r
- common::gl::pixel_buffer_object pbo_;\r
+ std::vector<common::gl::pixel_buffer_object_ptr> pbo_;\r
+ std::vector<unsigned char*> data_;\r
+\r
gpu_frame* self_;\r
- unsigned char* data_;\r
- size_t width_;\r
- size_t height_;\r
- size_t size_;\r
\r
bool reading_;\r
bool writing_;\r
double y_;\r
video_mode mode_;\r
rectangle texcoords_;\r
+ pixel_format pix_format_;\r
};\r
\r
gpu_frame::gpu_frame(size_t width, size_t height) \r
: impl_(new implementation(width, height)){}\r
+gpu_frame::gpu_frame(const planar_frame_dimension& data_size)\r
+ : impl_(new implementation(data_size)){}\r
void gpu_frame::begin_write(){impl_->begin_write();}\r
void gpu_frame::end_write(){impl_->end_write();} \r
void gpu_frame::begin_read(){impl_->begin_read();}\r
void gpu_frame::end_read(){impl_->end_read();}\r
-void gpu_frame::draw(){impl_->draw();}\r
-unsigned char* gpu_frame::data(){return impl_->data();}\r
-size_t gpu_frame::size() const { return impl_->size_; }\r
-size_t gpu_frame::width() const { return impl_->width_;}\r
-size_t gpu_frame::height() const { return impl_->height_;}\r
-const std::vector<short>& gpu_frame::audio_data() const{return impl_->audio_data_;} \r
+void gpu_frame::draw(const gpu_frame_transform_ptr& transform){impl_->draw(transform);}\r
+void gpu_frame::set_pixel_format(pixel_format format) {impl_->pix_format_ = format;}\r
+unsigned char* gpu_frame::data(size_t index){return impl_->data(index);}\r
+size_t gpu_frame::size(size_t index) const { return impl_->pbo_.at(index)->size(); }\r
+size_t gpu_frame::width(size_t index) const { return impl_->pbo_.at(index)->width();}\r
+size_t gpu_frame::height(size_t index) const { return impl_->pbo_.at(index)->height();}\r
std::vector<short>& gpu_frame::audio_data() { return impl_->audio_data_; }\r
void gpu_frame::reset(){impl_->reset();}\r
double gpu_frame::alpha() const{ return impl_->alpha_;}\r
\r
#include "frame_format.h"\r
\r
+#include "gpu_frame_transform.h"\r
+\r
#include <memory>\r
+#include <array>\r
\r
#include <boost/noncopyable.hpp>\r
\r
\r
namespace caspar { namespace core {\r
\r
+typedef std::array<std::pair<size_t, size_t>, 4> planar_frame_dimension;\r
+\r
struct rectangle\r
{\r
rectangle(double left, double top, double right, double bottom)\r
public:\r
virtual ~gpu_frame(){}\r
\r
- virtual unsigned char* data();\r
- virtual size_t size() const;\r
- virtual size_t width() const;\r
- virtual size_t height() const;\r
+ virtual unsigned char* data(size_t index = 0);\r
+ virtual size_t size(size_t index = 0) const;\r
+ virtual size_t width(size_t index = 0) const;\r
+ virtual size_t height(size_t index = 0) const;\r
\r
- virtual const std::vector<short>& audio_data() const; \r
virtual std::vector<short>& audio_data();\r
\r
virtual double alpha() const;\r
virtual void mode(video_mode mode);\r
virtual video_mode mode() const;\r
\r
+ virtual void set_pixel_format(pixel_format format);\r
+\r
static std::shared_ptr<gpu_frame> null()\r
{\r
static auto my_null_frame = std::shared_ptr<gpu_frame>(new gpu_frame(0,0));\r
\r
protected:\r
gpu_frame(size_t width, size_t height);\r
+ gpu_frame(const planar_frame_dimension& data_size);\r
\r
friend class gpu_frame_processor;\r
\r
virtual void end_write();\r
virtual void begin_read();\r
virtual void end_read();\r
- virtual void draw();\r
+ virtual void draw(const gpu_frame_transform_ptr& transform);\r
virtual void reset();\r
\r
private:\r
\r
#include "gpu_frame_processor.h"\r
\r
+#include "gpu_frame_transform.h"\r
#include "gpu_frame.h"\r
#include "gpu_composite_frame.h"\r
#include "frame_format.h"\r
#include <functional>\r
#include <unordered_map>\r
#include <numeric>\r
+#include <math.h>\r
\r
namespace caspar { namespace core {\r
\r
// Fill pipeline\r
for(int n = 0; n < 2; ++n)\r
composite(std::vector<gpu_frame_ptr>());\r
+\r
+ transform_ = std::make_shared<gpu_frame_transform>();\r
});\r
}\r
\r
\r
// 2. Draw to framebuffer and start asynchronous DMA transfer \r
// to page-locked memory.\r
- writing_[next_index]->draw();\r
+ writing_[next_index]->draw(transform_);\r
\r
// Create an output frame\r
auto temp_frame = create_output_frame();\r
});\r
}\r
\r
- gpu_frame_ptr create_frame(size_t width, size_t height)\r
+ gpu_frame_ptr do_create_frame(size_t key, const std::function<gpu_frame*()>& constructor)\r
{\r
- size_t key = width | (height << 16);\r
auto& pool = writing_pools_[key];\r
\r
gpu_frame_ptr frame;\r
{\r
frame = executor_.invoke([&]\r
{\r
- return std::shared_ptr<gpu_frame>(new gpu_frame(width, height));\r
+ return std::shared_ptr<gpu_frame>(constructor());\r
});\r
}\r
\r
executor_.begin_invoke(destructor);\r
});\r
}\r
+\r
+ gpu_frame_ptr create_frame(size_t width, size_t height, void* tag)\r
+ {\r
+ size_t key = reinterpret_cast<size_t>(tag);\r
+ return do_create_frame(key, [&]\r
+ {\r
+ return new gpu_frame(width, height);\r
+ });\r
+ }\r
+ \r
+ gpu_frame_ptr create_frame(const planar_frame_dimension& data_size, void* tag)\r
+ {\r
+ size_t key = reinterpret_cast<size_t>(tag);\r
+ return do_create_frame(key, [&]\r
+ {\r
+ return new gpu_frame(data_size);\r
+ });\r
+ }\r
\r
void pop(gpu_frame_ptr& frame)\r
{\r
output_.pop(frame);\r
}\r
- \r
+\r
+ void release_frames(void* tag)\r
+ {\r
+ writing_pools_[reinterpret_cast<size_t>(tag)].clear();\r
+ }\r
+ \r
typedef tbb::concurrent_bounded_queue<gpu_frame_ptr> gpu_frame_queue;\r
tbb::concurrent_unordered_map<size_t, gpu_frame_queue> writing_pools_;\r
gpu_frame_queue reading_pool_; \r
common::executor executor_;\r
\r
common::gl::frame_buffer_object fbo_;\r
+\r
+ gpu_frame_transform_ptr transform_;\r
};\r
\r
gpu_frame_processor::gpu_frame_processor(const frame_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
void gpu_frame_processor::push(const std::vector<gpu_frame_ptr>& frames){ impl_->composite(frames);}\r
void gpu_frame_processor::pop(gpu_frame_ptr& frame){impl_->pop(frame);}\r
-gpu_frame_ptr gpu_frame_processor::create_frame(size_t width, size_t height){return impl_->create_frame(width, height);}\r
-\r
+gpu_frame_ptr gpu_frame_processor::create_frame(size_t width, size_t height, void* tag){return impl_->create_frame(width, height, tag);}\r
+gpu_frame_ptr gpu_frame_processor::create_frame(const planar_frame_dimension& data_size, void* tag){return impl_->create_frame(data_size, tag);}\r
+void gpu_frame_processor::release_frames(void* tag){impl_->release_frames(tag);}\r
}}
\ No newline at end of file
\r
void push(const std::vector<gpu_frame_ptr>& frames);\r
void pop(gpu_frame_ptr& frame);\r
-\r
- gpu_frame_ptr create_frame(size_t width, size_t height);\r
+ \r
+ void release_frames(void* tag);\r
+ gpu_frame_ptr create_frame(size_t width, size_t height, void* tag);\r
+ gpu_frame_ptr create_frame(const planar_frame_dimension& data_size, void* tag);\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
--- /dev/null
+#include "../StdAfx.h"\r
+\r
+#include "gpu_frame_transform.h"\r
+\r
+#include "../../common/exception/exceptions.h"\r
+#include "../../common/gl/gl_check.h"\r
+\r
+#include <Glee.h>\r
+\r
+#include <fstream>\r
+#include <unordered_map>\r
+\r
+namespace caspar { namespace core {\r
+ \r
+class shader_program\r
+{\r
+public:\r
+ shader_program(const std::string& fragment_source_str)\r
+ {\r
+ try\r
+ { \r
+ const char* fragment_source = fragment_source_str.c_str();\r
+ static const char* vertex_source = \r
+ "void main()"\r
+ "{"\r
+ "gl_TexCoord[0] = gl_MultiTexCoord0;"\r
+ "gl_FrontColor = gl_Color;"\r
+ "gl_Position = ftransform();"\r
+ "}";\r
+\r
+ program_ = glCreateProgramObjectARB();\r
+\r
+ auto vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);\r
+ auto fragmemt_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);\r
+\r
+ GL(glShaderSourceARB(vertex_shader, 1, &vertex_source, NULL));\r
+ GL(glShaderSourceARB(fragmemt_shader, 1, &fragment_source, NULL));\r
+ GL(glCompileShaderARB(vertex_shader));\r
+ GL(glCompileShaderARB(fragmemt_shader));\r
+\r
+ GLint success;\r
+ GL(glGetObjectParameterivARB(vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));\r
+ if (success == GL_FALSE)\r
+ {\r
+ char log[1024];\r
+ GL(glGetInfoLogARB(vertex_shader, sizeof(log), 0, log));\r
+ GL(glDeleteObjectARB(vertex_shader));\r
+ GL(glDeleteObjectARB(fragmemt_shader));\r
+ GL(glDeleteObjectARB(program_));\r
+ std::stringstream str;\r
+ str << "Failed to compile vertex shader:" << std::endl << log << std::endl;\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(str.str()));\r
+ }\r
+ GL(glGetObjectParameterivARB(fragmemt_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));\r
+ if (success == GL_FALSE)\r
+ {\r
+ char log[1024];\r
+ GL(glGetInfoLogARB(fragmemt_shader, sizeof(log), 0, log));\r
+ GL(glDeleteObjectARB(vertex_shader));\r
+ GL(glDeleteObjectARB(fragmemt_shader));\r
+ GL(glDeleteObjectARB(program_));\r
+ std::stringstream str;\r
+ str << "Failed to compile fragment shader:" << std::endl << log << std::endl;\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(str.str()));\r
+ }\r
+\r
+ GL(glAttachObjectARB(program_, vertex_shader));\r
+ GL(glAttachObjectARB(program_, fragmemt_shader));\r
+\r
+ GL(glDeleteObjectARB(vertex_shader));\r
+ GL(glDeleteObjectARB(fragmemt_shader));\r
+\r
+ GL(glLinkProgramARB(program_));\r
+\r
+ GL(glGetObjectParameterivARB(program_, GL_OBJECT_LINK_STATUS_ARB, &success));\r
+ if (success == GL_FALSE)\r
+ {\r
+ char log[1024];\r
+ GL(glGetInfoLogARB(program_, sizeof(log), 0, log));\r
+ CASPAR_LOG(warning) << "Failed to link shader:" << std::endl\r
+ << log << std::endl;\r
+ GL(glDeleteObjectARB(program_));\r
+ BOOST_THROW_EXCEPTION(caspar_exception());\r
+ }\r
+ GL(glUseProgramObjectARB(program_));\r
+ glUniform1i(glGetUniformLocation(program_, "tex0"), 0);\r
+ glUniform1i(glGetUniformLocation(program_, "tex1"), 1);\r
+ glUniform1i(glGetUniformLocation(program_, "tex2"), 2);\r
+ glUniform1i(glGetUniformLocation(program_, "tex3"), 3);\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ throw;\r
+ }\r
+ }\r
+\r
+ void use()\r
+ {\r
+ GL(glUseProgramObjectARB(program_));\r
+ }\r
+\r
+private:\r
+ GLuint program_;\r
+};\r
+typedef std::shared_ptr<shader_program> shader_program_ptr;\r
+\r
+struct gpu_frame_transform::implementation\r
+{\r
+ implementation() : current_(pixel_format::invalid_pixel_format)\r
+ {\r
+ std::string common = \r
+ "uniform sampler2D tex0;"\r
+ "uniform sampler2D tex1;"\r
+ "uniform sampler2D tex2;"\r
+ "uniform sampler2D tex3;"\r
+\r
+ "vec4 yuva_to_bgra(float y, float u, float v, float a)"\r
+ "{"\r
+ "vec4 color;"\r
+ \r
+ "u -= 0.5;"\r
+ "v -= 0.5;"\r
+\r
+ "color.r = clamp(y + 1.370705 * v, 0.0 , 1.0);"\r
+ "color.g = clamp(y - 0.698001 * v - 0.337633 * u, 0.0 , 1.0);"\r
+ "color.b = clamp(y + 1.732446 * u, 0.0 , 1.0);"\r
+ "color.a = a;"\r
+\r
+ " return color;"\r
+ "}";\r
+\r
+ shaders_[pixel_format::abgr] = std::make_shared<shader_program>\r
+ (\r
+ common +\r
+\r
+ "void main()"\r
+ "{"\r
+ "gl_FragColor = texture2D(tex0, gl_TexCoord[0].st).argb * gl_Color;"\r
+ "}"\r
+ );\r
+ shaders_[pixel_format::argb] = std::make_shared<shader_program>\r
+ (\r
+ common +\r
+\r
+ "void main()"\r
+ "{"\r
+ "gl_FragColor = texture2D(tex0, gl_TexCoord[0].st).grab * gl_Color;"\r
+ "}"\r
+ );\r
+ shaders_[pixel_format::bgra] = std::make_shared<shader_program>\r
+ (\r
+ common +\r
+\r
+ "void main()"\r
+ "{"\r
+ "gl_FragColor = texture2D(tex0, gl_TexCoord[0].st).rgba * gl_Color;"\r
+ "}"\r
+ );\r
+ shaders_[pixel_format::rgba] = std::make_shared<shader_program>\r
+ (\r
+ common +\r
+\r
+ "void main()"\r
+ "{"\r
+ "gl_FragColor = texture2D(tex0, gl_TexCoord[0].st).bgra * gl_Color;"\r
+ "}"\r
+ );\r
+ shaders_[pixel_format::yuv] = std::make_shared<shader_program>\r
+ (\r
+ common +\r
+\r
+ "void main()"\r
+ "{"\r
+ "float y = texture2D(tex0, gl_TexCoord[0].st).r;"\r
+ "float u = texture2D(tex1, gl_TexCoord[0].st).r;"\r
+ "float v = texture2D(tex2, gl_TexCoord[0].st).r;"\r
+ "gl_FragColor = yuva_to_bgra(y, u , v, 1.0) * gl_Color;"\r
+ "}"\r
+ );\r
+ shaders_[pixel_format::yuva] = std::make_shared<shader_program>\r
+ (\r
+ common +\r
+\r
+ "void main()"\r
+ "{"\r
+ "float y = texture2D(tex0, gl_TexCoord[0].st).r;"\r
+ "float u = texture2D(tex1, gl_TexCoord[0].st).r;"\r
+ "float v = texture2D(tex2, gl_TexCoord[0].st).r;"\r
+ "float a = texture2D(tex3, gl_TexCoord[0].st).r;"\r
+ "gl_FragColor = yuva_to_bgra(y, u, v, a) * gl_Color;"\r
+ "}"\r
+ );\r
+ }\r
+\r
+ void set_pixel_format(pixel_format format)\r
+ {\r
+ if(current_ == format)\r
+ return;\r
+ current_ = format;\r
+ shaders_[format]->use();\r
+ }\r
+\r
+ pixel_format current_;\r
+ std::map<pixel_format, shader_program_ptr> shaders_;\r
+};\r
+\r
+gpu_frame_transform::gpu_frame_transform() : impl_(new implementation()){}\r
+void gpu_frame_transform::set_pixel_format(pixel_format format){impl_->set_pixel_format(format);}\r
+\r
+}}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include <memory>\r
+\r
+enum pixel_format\r
+{\r
+ bgra = 1,\r
+ rgba,\r
+ argb,\r
+ abgr,\r
+ yuv,\r
+ yuva,\r
+ invalid_pixel_format,\r
+};\r
+\r
+namespace caspar { namespace core {\r
+ \r
+class gpu_frame_transform\r
+{\r
+public:\r
+ gpu_frame_transform();\r
+ void set_pixel_format(pixel_format format);\r
+private:\r
+ struct implementation;\r
+ std::shared_ptr<implementation> impl_;\r
+};\r
+typedef std::shared_ptr<gpu_frame_transform> gpu_frame_transform_ptr;\r
+\r
+}}
\ No newline at end of file
explicit color_producer(unsigned int color_value, const frame_format_desc& format_desc) \r
: color_value_(color_value), format_desc_(format_desc){}\r
\r
+ ~color_producer()\r
+ {\r
+ if(factory_)\r
+ factory_->release_frames(this);\r
+ }\r
+\r
gpu_frame_ptr get_frame()\r
{ \r
return frame_;\r
}\r
+\r
const frame_format_desc& get_frame_format_desc() const { return format_desc_; }\r
\r
void initialize(const frame_factory_ptr& factory)\r
{\r
- frame_ = factory->create_frame(format_desc_);\r
+ factory_ = factory;\r
+ frame_ = factory->create_frame(format_desc_, this);\r
__stosd(reinterpret_cast<unsigned long*>(frame_->data()), color_value_, frame_->size() / sizeof(unsigned long));\r
}\r
\r
+ frame_factory_ptr factory_;\r
frame_format_desc format_desc_;\r
gpu_frame_ptr frame_;\r
unsigned int color_value_;\r
#include <tbb/concurrent_queue.h>\r
#include <tbb/scalable_allocator.h>\r
\r
+#include <unordered_map>\r
+\r
#if defined(_MSC_VER)\r
#pragma warning (push)\r
#pragma warning (disable : 4244)\r
\r
namespace caspar { namespace core { namespace ffmpeg{\r
\r
+pixel_format get_pixel_format(PixelFormat pix_fmt)\r
+{\r
+ switch(pix_fmt)\r
+ {\r
+ case PIX_FMT_BGRA: return pixel_format::bgra;\r
+ case PIX_FMT_ARGB: return pixel_format::argb;\r
+ case PIX_FMT_RGBA: return pixel_format::rgba;\r
+ case PIX_FMT_ABGR: return pixel_format::abgr;\r
+ case PIX_FMT_YUV444P: return pixel_format::yuv;\r
+ case PIX_FMT_YUV422P: return pixel_format::yuv;\r
+ case PIX_FMT_YUV420P: return pixel_format::yuv;\r
+ case PIX_FMT_YUV411P: return pixel_format::yuv;\r
+ case PIX_FMT_YUV410P: return pixel_format::yuv;\r
+ case PIX_FMT_YUVA420P: return pixel_format::yuva;\r
+ default: return pixel_format::invalid_pixel_format;\r
+ }\r
+}\r
+\r
struct video_transformer::implementation : boost::noncopyable\r
{\r
+ ~implementation()\r
+ {\r
+ if(factory_)\r
+ factory_->release_frames(this);\r
+ }\r
+\r
video_packet_ptr execute(const video_packet_ptr video_packet)\r
{ \r
assert(video_packet);\r
- size_t width = video_packet->codec_context->width;\r
- size_t height = video_packet->codec_context->height;\r
+ int width = video_packet->codec_context->width;\r
+ int height = video_packet->codec_context->height;\r
auto pix_fmt = video_packet->codec_context->pix_fmt;\r
+ video_packet->decoded_frame;\r
\r
- if(!sws_context_)\r
+ switch(pix_fmt)\r
{\r
- double param;\r
- sws_context_.reset(sws_getContext(width, height, pix_fmt, width, height, \r
- PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, ¶m), sws_freeContext);\r
- }\r
+ case PIX_FMT_BGRA:\r
+ case PIX_FMT_ARGB:\r
+ case PIX_FMT_RGBA:\r
+ case PIX_FMT_ABGR:\r
+ {\r
+ video_packet->frame = factory_->create_frame(width, height, this);\r
+ tbb::parallel_for(0, height, 1, [&](int y)\r
+ {\r
+ common::aligned_memcpy(\r
+ video_packet->frame->data()+y*width*4, \r
+ video_packet->decoded_frame->data[0] + y*video_packet->decoded_frame->linesize[0], \r
+ width*4); \r
+ });\r
+ video_packet->frame->set_pixel_format(get_pixel_format(pix_fmt));\r
+ \r
+ break;\r
+ }\r
+ case PIX_FMT_YUV444P:\r
+ case PIX_FMT_YUV422P:\r
+ case PIX_FMT_YUV420P:\r
+ case PIX_FMT_YUV411P:\r
+ case PIX_FMT_YUV410P:\r
+ case PIX_FMT_YUVA420P:\r
+ { \r
+ // Get linesizes\r
+ AVPicture dummy_pict; \r
+ avpicture_fill(&dummy_pict, nullptr, pix_fmt, width, height);\r
+ \r
+ // Find chroma height\r
+ size_t size2 = dummy_pict.data[2] - dummy_pict.data[1];\r
+ size_t h2 = size2/dummy_pict.linesize[1];\r
\r
- //size_t pic_size = avpicture_get_size(PIX_FMT_YUV411P, width, height);\r
+ planar_frame_dimension data_size;\r
+ data_size[0] = std::make_pair(dummy_pict.linesize[0], height);\r
+ data_size[1] = std::make_pair(dummy_pict.linesize[1], h2);\r
+ data_size[2] = std::make_pair(dummy_pict.linesize[2], h2);\r
+ data_size[3] = std::make_pair(0, 0);\r
\r
- //size_t pic_size_sqr = static_cast<size_t>(sqrt(static_cast<double>(pic_size)))/4;\r
- //pic_size_sqr += pic_size_sqr % 2;\r
+ if(pix_fmt == PIX_FMT_YUVA420P) \r
+ data_size[3] = std::make_pair(dummy_pict.linesize[3], height);\r
\r
- video_packet->frame = factory_->create_frame(width, height);\r
- AVFrame av_frame; \r
- avcodec_get_frame_defaults(&av_frame);\r
- size_t size = avpicture_fill(reinterpret_cast<AVPicture*>(&av_frame), video_packet->frame->data(), PIX_FMT_BGRA, width, height);\r
+ video_packet->frame = factory_->create_frame(data_size, this);\r
+ video_packet->frame->set_pixel_format(get_pixel_format(pix_fmt));\r
+\r
+ tbb::parallel_for(0, static_cast<int>(data_size.size()), 1, [&](int n)\r
+ {\r
+ tbb::parallel_for(0, static_cast<int>(data_size[n].second), 1, [&](int y)\r
+ {\r
+ memcpy(\r
+ video_packet->frame->data(n)+y*dummy_pict.linesize[n], \r
+ video_packet->decoded_frame->data[n] + y*video_packet->decoded_frame->linesize[n], \r
+ dummy_pict.linesize[n]);\r
+ });\r
+ });\r
+ break;\r
+ } \r
+ default: \r
+ {\r
+ video_packet->frame = factory_->create_frame(width, height, this);\r
+ video_packet->frame->set_pixel_format(pixel_format::bgra);\r
+\r
+ AVFrame av_frame; \r
+ avcodec_get_frame_defaults(&av_frame);\r
+ avpicture_fill(reinterpret_cast<AVPicture*>(&av_frame), video_packet->frame->data(), PIX_FMT_BGRA, width, height);\r
+\r
+ if(!sws_context_)\r
+ {\r
+ double param;\r
+ sws_context_.reset(sws_getContext(width, height, pix_fmt, width, height, PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, ¶m), sws_freeContext);\r
+ } \r
\r
- sws_scale(sws_context_.get(), video_packet->decoded_frame->data, video_packet->decoded_frame->linesize, 0, height, av_frame.data, av_frame.linesize);\r
- \r
+ sws_scale(sws_context_.get(), video_packet->decoded_frame->data, video_packet->decoded_frame->linesize, 0, height, av_frame.data, av_frame.linesize); \r
+ }\r
+ }\r
+\r
if(video_packet->codec->id == CODEC_ID_DVVIDEO) // Move up one field\r
video_packet->frame->translate(0.0f, 1.0/static_cast<double>(video_packet->format_desc.height));\r
\r
- return video_packet; \r
+ return video_packet;\r
+ }\r
+\r
+ void initialize(const frame_factory_ptr& factory)\r
+ {\r
+ factory_ = factory;\r
}\r
\r
frame_factory_ptr factory_;\r
\r
video_transformer::video_transformer() : impl_(new implementation()){}\r
video_packet_ptr video_transformer::execute(const video_packet_ptr& video_packet){return impl_->execute(video_packet);}\r
-void video_transformer::initialize(const frame_factory_ptr& factory){impl_->factory_ = factory; }\r
+void video_transformer::initialize(const frame_factory_ptr& factory){impl_->initialize(factory); }\r
}}}
\ No newline at end of file
#include "../../../common/utility/find_file.h"\r
#include "../../server.h"\r
#include "../../../common/concurrency/executor.h"\r
-#include "../../../common/concurrency/function_task.h"\r
#include "../../../common/utility/memory.h"\r
#include "../../../common/utility/scope_exit.h"\r
\r
~implementation() \r
{\r
stop();\r
+ if(factory_)\r
+ factory_->release_frames(this);\r
}\r
\r
void start(bool force = true)\r
});\r
} \r
\r
- auto frame = factory_->create_frame(format_desc_);\r
- common::aligned_memcpy(frame->data(), current_frame_->data(), current_frame_->size()); \r
+ auto frame = factory_->create_frame(format_desc_, this);\r
+ common::aligned_parallel_memcpy(frame->data(), current_frame_->data(), current_frame_->size()); \r
\r
return frame;\r
}\r
{\r
image_producer(const std::wstring& filename, const frame_format_desc& format_desc) : format_desc_(format_desc), filename_(filename) {}\r
\r
+ ~image_producer()\r
+ {\r
+ if(factory_)\r
+ factory_->release_frames(this);\r
+ }\r
+\r
gpu_frame_ptr get_frame(){return frame_;}\r
\r
void initialize(const frame_factory_ptr& factory)\r
{\r
+ factory_ = factory;\r
auto bitmap = load_image(filename_);\r
if(FreeImage_GetWidth(bitmap.get()) != format_desc_.width || FreeImage_GetHeight(bitmap.get()) == format_desc_.height)\r
{\r
}\r
\r
FreeImage_FlipVertical(bitmap.get());\r
- frame_ = factory->create_frame(format_desc_);\r
- common::aligned_memcpy(frame_->data(), FreeImage_GetBits(bitmap.get()), frame_->size());\r
+ frame_ = factory->create_frame(format_desc_, this);\r
+ common::aligned_parallel_memcpy(frame_->data(), FreeImage_GetBits(bitmap.get()), frame_->size());\r
}\r
\r
const frame_format_desc& get_frame_format_desc() const { return format_desc_; } \r
\r
+ frame_factory_ptr factory_;\r
std::wstring filename_;\r
frame_format_desc format_desc_;\r
gpu_frame_ptr frame_;\r
\r
speed_ = static_cast<int>(abs(static_cast<double>(speed_) / format_desc.fps));\r
}\r
+ \r
+ ~image_scroll_producer()\r
+ {\r
+ if(factory_)\r
+ factory_->release_frames(this);\r
+ }\r
\r
void load_and_pad_image(const std::wstring& filename)\r
{\r
unsigned char* pBits = FreeImage_GetBits(pBitmap.get());\r
\r
for (size_t i = 0; i < height; ++i)\r
- common::aligned_memcpy(&image_.get()[i * image_width_ * 4], &pBits[i* width * 4], width * 4);\r
+ common::aligned_parallel_memcpy(&image_.get()[i * image_width_ * 4], &pBits[i* width * 4], width * 4);\r
}\r
\r
gpu_frame_ptr render_frame()\r
{\r
- gpu_frame_ptr frame = factory_->create_frame(format_desc_);\r
+ gpu_frame_ptr frame = factory_->create_frame(format_desc_, this);\r
common::clear(frame->data(), frame->size());\r
\r
const int delta_x = direction_ == direction::Left ? speed_ : -speed_;\r
\r
struct transition_producer::implementation : boost::noncopyable\r
{\r
- implementation(const frame_producer_ptr& dest, const transition_info& info, \r
- const frame_format_desc& format_desc) \r
+ implementation(const frame_producer_ptr& dest, const transition_info& info, const frame_format_desc& format_desc) \r
: current_frame_(0), info_(info), format_desc_(format_desc), dest_producer_(dest)\r
{\r
if(!dest)\r
CASPAR_LOG(warning) << "Removed renderer from transition.";\r
}\r
\r
- if(frame == nullptr && producer != nullptr && producer->get_following_producer() != nullptr)\r
+ if(frame == nullptr && producer != nullptr && \r
+ producer->get_following_producer() != nullptr)\r
{\r
auto following = producer->get_following_producer();\r
following->initialize(factory_);\r
for(size_t n = 0; n < frame->audio_data().size(); ++n)\r
frame->audio_data()[n] = static_cast<short>((static_cast<int>(frame->audio_data()[n])*volume)>>8);\r
}\r
- \r
-\r
+ \r
gpu_frame_ptr compose(const gpu_frame_ptr& dest_frame, gpu_frame_ptr src_frame) \r
{ \r
if(info_.type == transition_type::cut) \r
[&]{set_volume(dest_frame, volume);},\r
[&]{set_volume(src_frame, 256-volume);}\r
);\r
- \r
- auto composite = std::make_shared<gpu_composite_frame>();\r
- if(src_frame)\r
- composite->add(src_frame);\r
- composite->add(dest_frame);\r
-\r
- switch(info_.type)\r
- {\r
- case transition_type::mix: \r
- dest_frame->alpha(alpha); \r
- break;\r
- case transition_type::slide: \r
+ \r
+ if(info_.type == transition_type::mix)\r
+ dest_frame->alpha(alpha); \r
+ else if(info_.type == transition_type::slide)\r
+ { \r
if(info_.direction == transition_direction::from_left) \r
dest_frame->translate(-1.0+alpha, 0.0); \r
else if(info_.direction == transition_direction::from_right)\r
dest_frame->translate(1.0-alpha, 0.0); \r
- break;\r
- case transition_type::push:\r
+ }\r
+ else if(info_.type == transition_type::push)\r
+ {\r
if(info_.direction == transition_direction::from_left) \r
{\r
dest_frame->translate(-1.0+alpha, 0.0);\r
if(src_frame)\r
src_frame->translate(0.0-alpha, 0.0);\r
}\r
- break;\r
- }\r
-\r
- if(info_.type == transition_type::mix)\r
- dest_frame->alpha(alpha); \r
- else if(info_.type == transition_type::slide)\r
- { \r
- }\r
- else if(info_.type == transition_type::push)\r
- {\r
}\r
else if(info_.type == transition_type::wipe)\r
{\r
dest_frame->texcoords(rectangle(1.0-alpha, 1.0, 2.0-alpha, 0.0));\r
}\r
}\r
-\r
+ \r
+ auto composite = std::make_shared<gpu_composite_frame>();\r
+ if(src_frame)\r
+ composite->add(src_frame);\r
+ composite->add(dest_frame);\r
return composite;\r
}\r
\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<root>\r
+ <rdmgr>\r
+ <buildNumber type="s32_t">114808</buildNumber>\r
+ <hostname>vaxtestcaspar</hostname>\r
+ <os>windows</os>\r
+ <product>Intel® Parallel Amplifier 2011</product>\r
+ <timestamp type="u64_t">1288973781</timestamp>\r
+ <variables>\r
+ <at>hs</at>\r
+ </variables>\r
+ </rdmgr>\r
+</root>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<root>\r
+ <rdmgr>\r
+ <buildNumber type="s32_t">114808</buildNumber>\r
+ <hostname>vaxtestcaspar</hostname>\r
+ <os>windows</os>\r
+ <product>Intel® Parallel Amplifier 2011</product>\r
+ <timestamp type="u64_t">1289002710</timestamp>\r
+ <variables>\r
+ <at>hs</at>\r
+ </variables>\r
+ </rdmgr>\r
+</root>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<root>\r
+ <rdmgr>\r
+ <buildNumber type="s32_t">114808</buildNumber>\r
+ <hostname>vaxtestcaspar</hostname>\r
+ <os>windows</os>\r
+ <product>Intel® Parallel Amplifier 2011</product>\r
+ <timestamp type="u64_t">1289002916</timestamp>\r
+ <variables>\r
+ <at>hs</at>\r
+ </variables>\r
+ </rdmgr>\r
+</root>\r
<None Include="caspar.config">\r
<SubType>Designer</SubType>\r
</None>\r
+ <None Include="My Amplifier Results\r000hs\r000hs.ampl" />\r
+ <None Include="My Amplifier Results\r001hs\r001hs.ampl" />\r
+ <None Include="My Amplifier Results\r002hs\r002hs.ampl" />\r
</ItemGroup>\r
<PropertyGroup Label="Globals">\r
<ProjectGuid>{8C26C94F-8092-4769-8D84-DEA479721C5B}</ProjectGuid>\r
</ItemGroup>\r
<ItemGroup>\r
<None Include="caspar.config" />\r
+ <None Include="My Amplifier Results\r000hs\r000hs.ampl">\r
+ <Filter>My Amplifier Results</Filter>\r
+ </None>\r
+ <None Include="My Amplifier Results\r001hs\r001hs.ampl">\r
+ <Filter>My Amplifier Results</Filter>\r
+ </None>\r
+ <None Include="My Amplifier Results\r002hs\r002hs.ampl">\r
+ <Filter>My Amplifier Results</Filter>\r
+ </None>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <Filter Include="My Amplifier Results">\r
+ <UniqueIdentifier>{4df636fc-0183-410c-8d76-2d0e06c29ca3}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
ASSERT_TRUE(producer.get_frame() == nullptr);\r
}\r
\r
-TEST(transition_producer, initialize) \r
+TEST(transition_producer, initialize)\r
{\r
auto dest = std::make_shared<mock_frame_producer>();\r
\r