<ClInclude Include="consumer\oal\oal_consumer.h" />\r
<ClInclude Include="consumer\ogl\ogl_consumer.h" />\r
<ClInclude Include="mixer\audio\audio_mixer.h" />\r
+ <ClInclude Include="mixer\audio\audio_transform.h" />\r
<ClInclude Include="mixer\frame\draw_frame.h" />\r
<ClInclude Include="mixer\frame\pixel_format.h" />\r
<ClInclude Include="mixer\frame\read_frame.h" />\r
<ClInclude Include="mixer\gpu\ogl_device.h" />\r
<ClInclude Include="mixer\image\image_kernel.h" />\r
<ClInclude Include="mixer\image\image_mixer.h" />\r
+ <ClInclude Include="mixer\image\image_transform.h" />\r
<ClInclude Include="producer\color\color_producer.h" />\r
<ClInclude Include="producer\decklink\decklink_producer.h" />\r
<ClInclude Include="producer\ffmpeg\audio\audio_decoder.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="mixer\audio\audio_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="mixer\frame\draw_frame.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="mixer\image\image_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="mixer\frame_factory.h">\r
<Filter>Source\mixer</Filter>\r
</ClInclude>\r
+ <ClInclude Include="mixer\image\image_transform.h">\r
+ <Filter>Source\mixer\image</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="mixer\audio\audio_transform.h">\r
+ <Filter>Source\mixer\audio</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="consumer\decklink\DeckLinkAPI_i.c">\r
<ClCompile Include="producer\layer.cpp">\r
<Filter>Source\producer</Filter>\r
</ClCompile>\r
+ <ClCompile Include="mixer\image\image_transform.cpp">\r
+ <Filter>Source\mixer\image</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="mixer\audio\audio_transform.cpp">\r
+ <Filter>Source\mixer\audio</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<Midl Include="producer\flash\Flash9e.IDL">\r
#include "../../stdafx.h"\r
\r
#include "audio_mixer.h"\r
+#include "audio_transform.h"\r
\r
namespace caspar { namespace core {\r
\r
-audio_transform::audio_transform()\r
- : gain_(1.0){}\r
-\r
-void audio_transform::set_gain(double value)\r
-{\r
- tbb::spin_mutex::scoped_lock lock(mutex_);\r
- gain_ = value;\r
-}\r
-\r
-double audio_transform::get_gain() const\r
-{\r
- tbb::spin_mutex::scoped_lock lock(mutex_);\r
- return gain_;\r
-}\r
-\r
-audio_transform& audio_transform::operator*=(const audio_transform &other) \r
-{\r
- tbb::spin_mutex::scoped_lock lock(mutex_);\r
- gain_ *= other.gain_;\r
- return *this;\r
-}\r
-\r
-const audio_transform audio_transform::operator*(const audio_transform &other) const \r
-{\r
- return audio_transform(*this) *= other;\r
-}\r
-\r
struct audio_mixer::implementation\r
{\r
std::vector<short> audio_data_;\r
\r
namespace caspar { namespace core {\r
\r
-class audio_transform\r
-{\r
-public:\r
- audio_transform();\r
-\r
- void set_gain(double value);\r
- double get_gain() const;\r
-\r
- audio_transform& operator*=(const audio_transform &other);\r
- const audio_transform operator*(const audio_transform &other) const;\r
-private:\r
- double gain_;\r
- mutable tbb::spin_mutex mutex_;\r
-};\r
+class audio_transform;\r
\r
class audio_mixer\r
{\r
\r
#include "draw_frame.h"\r
\r
+#include "../image/image_transform.h"\r
#include "../image/image_mixer.h"\r
#include "../audio/audio_mixer.h"\r
+#include "../audio/audio_transform.h"\r
#include "pixel_format.h"\r
#include "../../video_format.h"\r
\r
#include "frame_mixer_device.h"\r
\r
#include "audio/audio_mixer.h"\r
+#include "audio/audio_transform.h"\r
#include "image/image_mixer.h"\r
+#include "image/image_transform.h"\r
\r
#include "frame/write_frame.h"\r
#include "frame/read_frame.h"\r
{\r
return make_safe<write_frame>(desc, image_mixer_.create_buffers(desc));\r
}\r
+ \r
+ image_transform get_image_transform(int index)\r
+ {\r
+ return executor_.invoke([&]{return image_transforms_[index];});\r
+ }\r
\r
- image_transform& image(int index) \r
+ audio_transform get_audio_transform(int index)\r
{\r
- return image_transforms_[index];\r
+ return executor_.invoke([&]{return audio_transforms_[index];});\r
}\r
\r
- audio_transform& audio(int index) \r
+ void set_image_transform(int index, image_transform&& transform)\r
{\r
- return audio_transforms_[index];\r
+ return executor_.invoke([&]{image_transforms_[index] = std::move(transform);});\r
+ }\r
+\r
+ void set_audio_transform(int index, audio_transform&& transform)\r
+ {\r
+ return executor_.invoke([&]{audio_transforms_[index] = std::move(transform);});\r
}\r
};\r
\r
desc.planes.push_back(pixel_format_desc::plane(get_video_format_desc().width, get_video_format_desc().height, 4));\r
return create_frame(desc);\r
}\r
-\r
-image_transform& frame_mixer_device::image(int index) { return impl_->image(index);}\r
-audio_transform& frame_mixer_device::audio(int index) { return impl_->audio(index);}\r
+image_transform frame_mixer_device::get_image_transform(int index){return impl_->get_image_transform(index);}\r
+audio_transform frame_mixer_device::get_audio_transform(int index){return impl_->get_audio_transform(index);}\r
+void frame_mixer_device::set_image_transform(int index, image_transform&& transform){impl_->set_image_transform(index, std::move(transform));}\r
+void frame_mixer_device::set_audio_transform(int index, audio_transform&& transform){impl_->set_audio_transform(index, std::move(transform));}\r
\r
}}
\ No newline at end of file
\r
const video_format_desc& get_video_format_desc() const; // nothrow\r
\r
- image_transform& image(int index);\r
- audio_transform& audio(int index);\r
+ image_transform get_image_transform(int index);\r
+ audio_transform get_audio_transform(int index);\r
+\r
+ void set_image_transform(int index, image_transform&& transform);\r
+ void set_audio_transform(int index, audio_transform&& transform);\r
\r
private:\r
struct implementation;\r
\r
#include "image_kernel.h"\r
\r
-#include "image_mixer.h"\r
+#include "image_transform.h"\r
\r
#include <common/exception/exceptions.h>\r
#include <common/gl/gl_check.h>\r
\r
#include "image_mixer.h"\r
#include "image_kernel.h"\r
+#include "image_transform.h"\r
\r
#include "../gpu/ogl_device.h"\r
#include "../gpu/host_buffer.h"\r
\r
namespace caspar { namespace core {\r
\r
-image_transform::image_transform() \r
- : opacity_(1.0)\r
- , gain_(1.0)\r
- , mode_(video_mode::invalid)\r
-{\r
- std::fill(pos_.begin(), pos_.end(), 0.0);\r
- std::fill(size_.begin(), size_.end(), 1.0);\r
- std::fill(uv_.begin(), uv_.end(), 0.0);\r
-}\r
-\r
-void image_transform::set_opacity(double value)\r
-{\r
- tbb::spin_mutex::scoped_lock(mutex_); \r
- opacity_ = value;\r
-}\r
-\r
-double image_transform::get_opacity() const\r
-{\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- return opacity_;\r
-}\r
-\r
-void image_transform::set_gain(double value)\r
-{\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- gain_ = value;\r
-}\r
-\r
-double image_transform::get_gain() const\r
-{\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- return gain_;\r
-}\r
-\r
-void image_transform::set_position(double x, double y)\r
-{\r
- std::array<double, 2> value = {x, y};\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- pos_ = value;\r
-}\r
-\r
-std::array<double, 2> image_transform::get_position() const\r
-{\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- return pos_;\r
-}\r
-\r
-void image_transform::set_size(double x, double y)\r
-{\r
- std::array<double, 2> value = {x, y};\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- size_ = value;\r
-}\r
-\r
-std::array<double, 2> image_transform::get_size() const\r
-{\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- return size_;\r
-}\r
-\r
-void image_transform::set_uv(double left, double top, double right, double bottom)\r
-{\r
- std::array<double, 4> value = {left, top, right, bottom};\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- uv_ = value;\r
-}\r
-\r
-std::array<double, 4> image_transform::get_uv() const\r
-{\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- return uv_;\r
-}\r
-\r
-void image_transform::set_mode(video_mode::type mode)\r
-{\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- mode_ = mode;\r
-}\r
-\r
-video_mode::type image_transform::get_mode() const\r
-{\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- return mode_;\r
-}\r
-\r
-\r
-image_transform& image_transform::operator*=(const image_transform &other)\r
-{\r
- tbb::spin_mutex::scoped_lock(mutex_);\r
- opacity_ *= other.opacity_;\r
- mode_ = other.mode_;\r
- gain_ *= other.gain_;\r
- uv_[0] += other.uv_[0];\r
- uv_[1] += other.uv_[1];\r
- uv_[2] += other.uv_[2];\r
- uv_[3] += other.uv_[3];\r
- pos_[0] += other.pos_[0];\r
- pos_[1] += other.pos_[1];\r
- size_[0] *= other.size_[0];\r
- size_[1] *= other.size_[1];\r
- return *this;\r
-}\r
-\r
-const image_transform image_transform::operator*(const image_transform &other) const\r
-{\r
- return image_transform(*this) *= other;\r
-}\r
-\r
struct image_mixer::implementation : boost::noncopyable\r
{ \r
const video_format_desc format_desc_;\r
{\r
transform_stack_.push(image_transform());\r
transform_stack_.top().set_mode(video_mode::progressive);\r
- transform_stack_.top().set_uv(0.0, 1.0, 1.0, 0.0);\r
\r
GL(glEnable(GL_TEXTURE_2D));\r
+ GL(glEnable(GL_STENCIL_TEST));\r
+ GL(glEnable(GL_SCISSOR_TEST));\r
GL(glDisable(GL_DEPTH_TEST)); \r
\r
render_targets_[0] = context_->create_device_buffer(format_desc.width, format_desc.height, 4);\r
device_buffers[n]->bind();\r
}\r
\r
- auto& p = transform.get_position();\r
- auto& s = transform.get_size();\r
- auto& uv = transform.get_uv();\r
+ auto m_p = transform.get_mask_translation();\r
+ auto m_s = transform.get_mask_scale();\r
+ double w = static_cast<double>(format_desc_.width);\r
+ double h = static_cast<double>(format_desc_.height);\r
\r
+ GL(glScissor(static_cast<size_t>(m_p[0]*w), static_cast<size_t>(m_p[1]*h), static_cast<size_t>(m_s[0]*w), static_cast<size_t>(m_s[1]*h)));\r
+ \r
+ auto f_p = transform.get_image_translation();\r
+ auto f_s = transform.get_image_scale();\r
+ \r
glBegin(GL_QUADS);\r
- glTexCoord2d(uv[0], uv[3]); glVertex2d( p[0]*2.0-1.0, p[1]*2.0-1.0);\r
- glTexCoord2d(uv[2], uv[3]); glVertex2d((p[0]+s[0])*2.0-1.0, p[1]*2.0-1.0);\r
- glTexCoord2d(uv[2], uv[1]); glVertex2d((p[0]+s[0])*2.0-1.0, (p[1]+s[1])*2.0-1.0);\r
- glTexCoord2d(uv[0], uv[1]); glVertex2d( p[0]*2.0-1.0, (p[1]+s[1])*2.0-1.0);\r
+ glTexCoord2d(0.0, 0.0); glVertex2d( f_p[0] *2.0-1.0, f_p[1] *2.0-1.0);\r
+ glTexCoord2d(1.0, 0.0); glVertex2d((f_p[0]+f_s[0])*2.0-1.0, f_p[1] *2.0-1.0);\r
+ glTexCoord2d(1.0, 1.0); glVertex2d((f_p[0]+f_s[0])*2.0-1.0, (f_p[1]+f_s[1])*2.0-1.0);\r
+ glTexCoord2d(0.0, 1.0); glVertex2d( f_p[0] *2.0-1.0, (f_p[1]+f_s[1])*2.0-1.0);\r
glEnd();\r
+\r
+ GL(glScissor(0, 0, format_desc_.width, format_desc_.height));\r
});\r
}\r
\r
\r
namespace caspar { namespace core {\r
\r
-struct pixel_format_desc;\r
- \r
-class image_transform \r
-{\r
-public:\r
- image_transform();\r
-\r
- void set_opacity(double value);\r
- double get_opacity() const;\r
-\r
- void set_gain(double value);\r
- double get_gain() const;\r
-\r
- void set_position(double x, double y);\r
- std::array<double, 2> get_position() const;\r
-\r
- void set_size(double x, double ys);\r
- std::array<double, 2> get_size() const; \r
-\r
- void set_uv(double left, double top, double right, double bottom);\r
- std::array<double, 4> get_uv() const;\r
-\r
- void set_mode(video_mode::type mode);\r
- video_mode::type get_mode() const;\r
-\r
- image_transform& operator*=(const image_transform &other);\r
- const image_transform operator*(const image_transform &other) const;\r
-private:\r
- double opacity_;\r
- double gain_;\r
- std::array<double, 2> pos_;\r
- std::array<double, 2> size_;\r
- std::array<double, 4> uv_;\r
- video_mode::type mode_;\r
-};\r
+struct pixel_format_desc; \r
+class image_transform;\r
\r
class image_mixer : boost::noncopyable\r
{\r
\r
#include "../../video_format.h"\r
#include "../../mixer/frame/draw_frame.h"\r
-#include "../../mixer/audio/audio_mixer.h"\r
+#include "../../mixer/audio/audio_transform.h"\r
\r
#include <common/env.h>\r
\r
\r
#include "../../../video_format.h"\r
#include "../../../mixer/frame/draw_frame.h"\r
-#include "../../../mixer/frame_mixer_device.h"\r
-#include "../../../mixer/image/image_mixer.h"\r
+#include "../../../mixer/image/image_transform.h"\r
\r
#include <common/memory/safe_ptr.h>\r
\r
});\r
\r
if(codec_context_->codec_id == CODEC_ID_DVVIDEO) // Move up one field frame_factory_->get_video_format_desc().mode == video_mode::upper && \r
- write->get_image_transform().set_position(0.0f, 1.0/static_cast<double>(height_));\r
+ write->get_image_transform().set_mask_translation(0.0f, 1.0/static_cast<double>(height_));\r
\r
return write;\r
}\r
#include "../../video_format.h"\r
#include "../../mixer/frame/draw_frame.h"\r
#include "../../mixer/frame_mixer_device.h"\r
-#include "../../mixer/image/image_mixer.h"\r
+#include "../../mixer/image/image_transform.h"\r
#include "../../mixer/audio/audio_mixer.h"\r
+#include "../../mixer/audio/audio_transform.h"\r
\r
#include <boost/range/algorithm/copy.hpp>\r
\r
if(info_.type == transition::mix)\r
my_dest_frame.get_image_transform().set_opacity(alpha); \r
else if(info_.type == transition::slide) \r
- my_dest_frame.get_image_transform().set_position((-1.0+alpha)*dir, 0.0); \r
+ my_dest_frame.get_image_transform().set_image_translation((-1.0+alpha)*dir, 0.0); \r
else if(info_.type == transition::push)\r
{\r
- my_dest_frame.get_image_transform().set_position((-1.0+alpha)*dir, 0.0);\r
- my_src_frame.get_image_transform().set_position((0.0+alpha)*dir, 0.0);\r
- }\r
- else if(info_.type == transition::wipe)\r
- {\r
- my_dest_frame.get_image_transform().set_position((-1.0+alpha)*dir, 0.0); \r
- my_dest_frame.get_image_transform().set_uv((-1.0+alpha)*dir, 0.0, 0.0-(1.0-alpha)*dir, 0.0); \r
+ my_dest_frame.get_image_transform().set_image_translation((-1.0+alpha)*dir, 0.0);\r
+ my_src_frame.get_image_transform().set_image_translation((0.0+alpha)*dir, 0.0); \r
}\r
+ else if(info_.type == transition::wipe) \r
+ my_dest_frame.get_image_transform().set_mask_scale(alpha, 1.0); \r
\r
return draw_frame(std::move(my_src_frame), std::move(my_dest_frame));\r
}\r
#include "AMCPProtocolStrategy.h"\r
#include "../media.h"\r
\r
+#include <core/mixer/image/image_transform.h>\r
+#include <core/mixer/audio/audio_transform.h>\r
+\r
#include <core/producer/frame_producer.h>\r
#include <core/video_format.h>\r
#include <core/producer/flash/flash_producer.h>\r
if(_parameters[1] == L"OPACITY")\r
{\r
double value = boost::lexical_cast<double>(_parameters[2]);\r
- GetChannel()->mixer().image(GetLayerIndex()).set_opacity(value);\r
+ auto transform = GetChannel()->mixer().get_image_transform(GetLayerIndex());\r
+ transform.set_opacity(value);\r
+ GetChannel()->mixer().set_image_transform(GetLayerIndex(), std::move(transform));\r
}\r
else if(_parameters[1] == L"GAIN")\r
{\r
double value = boost::lexical_cast<double>(_parameters[2]);\r
- GetChannel()->mixer().image(GetLayerIndex()).set_gain(value);\r
+ auto transform = GetChannel()->mixer().get_image_transform(GetLayerIndex());\r
+ transform.set_gain(value);\r
+ GetChannel()->mixer().set_image_transform(GetLayerIndex(), std::move(transform));\r
}\r
else if(_parameters[1] == L"FIX_RECT")\r
{\r
double y = boost::lexical_cast<double>(_parameters.at(3));\r
double x_s = boost::lexical_cast<double>(_parameters.at(4));\r
double y_s = boost::lexical_cast<double>(_parameters.at(5));\r
- GetChannel()->mixer().image(GetLayerIndex()).set_position(x, y);\r
- GetChannel()->mixer().image(GetLayerIndex()).set_size(x_s, y_s);\r
- GetChannel()->mixer().image(GetLayerIndex()).set_uv(0.0, 0.0, 0.0, 0.0);\r
+ auto transform = GetChannel()->mixer().get_image_transform(GetLayerIndex());\r
+ transform.set_image_translation(x, y);\r
+ transform.set_image_scale(x_s, y_s);\r
+ GetChannel()->mixer().set_image_transform(GetLayerIndex(), std::move(transform));\r
}\r
else if(_parameters[1] == L"CLIP_RECT")\r
{\r
double y = boost::lexical_cast<double>(_parameters.at(3));\r
double x_s = boost::lexical_cast<double>(_parameters.at(4));\r
double y_s = boost::lexical_cast<double>(_parameters.at(5));\r
- GetChannel()->mixer().image(GetLayerIndex()).set_position(x, y);\r
- GetChannel()->mixer().image(GetLayerIndex()).set_size(x_s, y_s);\r
- GetChannel()->mixer().image(GetLayerIndex()).set_uv(x, -1.0 + y + y_s, -1.0 + x + x_s, y);\r
+ auto transform = GetChannel()->mixer().get_image_transform(GetLayerIndex());\r
+ transform.set_mask_translation(x, y);\r
+ transform.set_mask_scale(x_s, y_s);\r
+ GetChannel()->mixer().set_image_transform(GetLayerIndex(), std::move(transform));\r
}\r
else if(_parameters[1] == L"RESET")\r
{\r
- GetChannel()->mixer().image(GetLayerIndex()) = image_transform();\r
+ GetChannel()->mixer().set_image_transform(GetLayerIndex(), image_transform());\r
}\r
}\r
else if(_parameters[0] == L"AUDIO")\r
if(_parameters[1] == L"GAIN")\r
{\r
double value = boost::lexical_cast<double>(_parameters[2]);\r
- GetChannel()->mixer().audio(GetLayerIndex()).set_gain(value);\r
+ auto transform = GetChannel()->mixer().get_audio_transform(GetLayerIndex());\r
+ transform.set_gain(value);\r
+ GetChannel()->mixer().set_audio_transform(GetLayerIndex(), std::move(transform));\r
}\r
else if(_parameters[1] == L"RESET")\r
{\r
- GetChannel()->mixer().audio(GetLayerIndex()) = audio_transform();\r
+ GetChannel()->mixer().set_audio_transform(GetLayerIndex(), audio_transform());\r
}\r
}\r
else if(_parameters[0] == L"RESET")\r
{\r
- GetChannel()->mixer().image(GetLayerIndex()) = image_transform();\r
- GetChannel()->mixer().audio(GetLayerIndex()) = audio_transform();\r
+ GetChannel()->mixer().set_image_transform(GetLayerIndex(), image_transform());\r
+ GetChannel()->mixer().set_audio_transform(GetLayerIndex(), audio_transform());\r
}\r
\r
SetReplyString(TEXT("202 MIXER OK\r\n"));\r
<stretch>uniform</stretch>\r
<windowed>true</windowed>\r
</ogl>\r
- <!--audio/>\r
- <decklink>\r
+ <audio/>\r
+ <!--decklink>\r
<device>1</device>\r
<embedded-audio>true</embedded-audio>\r
</decklink-->\r