]> git.sesse.net Git - casparcg/commitdiff
set svn:eol-style native on .h and .cpp files
authorhellgore <hellgore@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 6 Sep 2012 14:19:42 +0000 (14:19 +0000)
committerhellgore <hellgore@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 6 Sep 2012 14:19:42 +0000 (14:19 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.1.0@3247 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

234 files changed:
accelerator/StdAfx.cpp
accelerator/StdAfx.h
accelerator/accelerator.cpp
accelerator/accelerator.h
accelerator/cpu/image/deinterlacer.cpp
accelerator/cpu/image/deinterlacer.h
accelerator/cpu/image/image_mixer.cpp
accelerator/cpu/image/image_mixer.h
accelerator/cpu/util/xmm.h
accelerator/ogl/image/blending_glsl.h
accelerator/ogl/image/image_kernel.cpp
accelerator/ogl/image/image_kernel.h
accelerator/ogl/image/image_mixer.cpp
accelerator/ogl/image/image_mixer.h
accelerator/ogl/image/image_shader.cpp
accelerator/ogl/image/image_shader.h
accelerator/ogl/util/buffer.cpp
accelerator/ogl/util/buffer.h
accelerator/ogl/util/device.cpp
accelerator/ogl/util/device.h
accelerator/ogl/util/shader.cpp
accelerator/ogl/util/shader.h
accelerator/ogl/util/texture.cpp
accelerator/ogl/util/texture.h
common/array.h
common/assert.h
common/compiler/vs/disable_silly_warnings.h
common/compiler/vs/stack_walker.cpp
common/compiler/vs/stack_walker.h
common/diagnostics/graph.cpp
common/diagnostics/graph.h
common/enum_class.h
common/env.cpp
common/env.h
common/except.cpp
common/except.h
common/executor.h
common/forward.h
common/future.h
common/future_fwd.h
common/gl/gl_check.cpp
common/gl/gl_check.h
common/lock.h
common/log.cpp
common/log.h
common/memory.h
common/memshfl.h
common/os/windows/current_version.h
common/os/windows/system_info.h
common/os/windows/windows.h
common/page_locked_allocator.cpp
common/page_locked_allocator.h
common/param.h
common/prec_timer.cpp
common/prec_timer.h
common/reactive.h
common/stdafx.cpp
common/stdafx.h
common/tweener.cpp
common/tweener.h
common/utf.cpp
common/utf.h
core/StdAfx.cpp
core/StdAfx.h
core/consumer/frame/read_frame.h
core/consumer/frame_consumer.cpp
core/consumer/frame_consumer.h
core/consumer/output.cpp
core/consumer/output.h
core/consumer/port.cpp
core/consumer/port.h
core/frame.h
core/frame/draw_frame.cpp
core/frame/draw_frame.h
core/frame/frame.cpp
core/frame/frame.h
core/frame/frame_factory.h
core/frame/frame_transform.cpp
core/frame/frame_transform.h
core/frame/frame_visitor.h
core/frame/pixel_format.h
core/mixer/audio/audio_mixer.cpp
core/mixer/audio/audio_mixer.h
core/mixer/audio/audio_util.h
core/mixer/image/blend_modes.cpp
core/mixer/image/blend_modes.h
core/mixer/image/image_mixer.h
core/mixer/mixer.cpp
core/mixer/mixer.h
core/monitor/monitor.cpp
core/monitor/monitor.h
core/producer/color/color_producer.cpp
core/producer/color/color_producer.h
core/producer/frame_producer.cpp
core/producer/frame_producer.h
core/producer/layer.cpp
core/producer/layer.h
core/producer/separated/separated_producer.cpp
core/producer/separated/separated_producer.h
core/producer/stage.cpp
core/producer/stage.h
core/producer/transition/transition_producer.cpp
core/producer/transition/transition_producer.h
core/video_channel.cpp
core/video_channel.h
core/video_format.cpp
core/video_format.h
modules/bluefish/StdAfx.cpp
modules/bluefish/StdAfx.h
modules/bluefish/bluefish.cpp
modules/bluefish/bluefish.h
modules/bluefish/consumer/bluefish_consumer.cpp
modules/bluefish/consumer/bluefish_consumer.h
modules/bluefish/util/blue_velvet.cpp
modules/bluefish/util/blue_velvet.h
modules/bluefish/util/memory.h
modules/decklink/StdAfx.cpp
modules/decklink/StdAfx.h
modules/decklink/consumer/decklink_consumer.cpp
modules/decklink/consumer/decklink_consumer.h
modules/decklink/decklink.cpp
modules/decklink/decklink.h
modules/decklink/producer/decklink_producer.cpp
modules/decklink/producer/decklink_producer.h
modules/decklink/util/util.h
modules/ffmpeg/StdAfx.cpp
modules/ffmpeg/StdAfx.h
modules/ffmpeg/consumer/ffmpeg_consumer.cpp
modules/ffmpeg/consumer/ffmpeg_consumer.h
modules/ffmpeg/ffmpeg.cpp
modules/ffmpeg/ffmpeg.h
modules/ffmpeg/ffmpeg_error.cpp
modules/ffmpeg/ffmpeg_error.h
modules/ffmpeg/producer/audio/audio_decoder.cpp
modules/ffmpeg/producer/audio/audio_decoder.h
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/ffmpeg_producer.h
modules/ffmpeg/producer/filter/filter.cpp
modules/ffmpeg/producer/filter/filter.h
modules/ffmpeg/producer/filter/parallel_yadif.cpp
modules/ffmpeg/producer/filter/parallel_yadif.h
modules/ffmpeg/producer/filter/scalable_yadif/scalable_yadif.cpp
modules/ffmpeg/producer/filter/scalable_yadif/scalable_yadif.h
modules/ffmpeg/producer/input/input.cpp
modules/ffmpeg/producer/input/input.h
modules/ffmpeg/producer/muxer/display_mode.h
modules/ffmpeg/producer/muxer/frame_muxer.cpp
modules/ffmpeg/producer/muxer/frame_muxer.h
modules/ffmpeg/producer/tbb_avcodec.cpp
modules/ffmpeg/producer/tbb_avcodec.h
modules/ffmpeg/producer/util/flv.cpp
modules/ffmpeg/producer/util/flv.h
modules/ffmpeg/producer/util/util.cpp
modules/ffmpeg/producer/util/util.h
modules/ffmpeg/producer/video/video_decoder.cpp
modules/ffmpeg/producer/video/video_decoder.h
modules/flash/StdAfx.cpp
modules/flash/StdAfx.h
modules/flash/flash.cpp
modules/flash/flash.h
modules/flash/interop/TimerHelper.h
modules/flash/interop/axflash.h
modules/flash/producer/FlashAxContainer.cpp
modules/flash/producer/FlashAxContainer.h
modules/flash/producer/cg_proxy.cpp
modules/flash/producer/cg_proxy.h
modules/flash/producer/flash_producer.cpp
modules/flash/producer/flash_producer.h
modules/flash/util/swf.cpp
modules/flash/util/swf.h
modules/image/consumer/image_consumer.cpp
modules/image/consumer/image_consumer.h
modules/image/image.cpp
modules/image/image.h
modules/image/producer/image_producer.cpp
modules/image/producer/image_producer.h
modules/image/producer/image_scroll_producer.cpp
modules/image/producer/image_scroll_producer.h
modules/image/util/image_algorithms.h
modules/image/util/image_loader.cpp
modules/image/util/image_loader.h
modules/image/util/image_view.h
modules/oal/consumer/oal_consumer.cpp
modules/oal/consumer/oal_consumer.h
modules/oal/oal.cpp
modules/oal/oal.h
modules/reroute/producer/reroute_producer.cpp
modules/reroute/producer/reroute_producer.h
modules/reroute/stdafx.cpp
modules/reroute/stdafx.h
modules/screen/consumer/screen_consumer.cpp
modules/screen/consumer/screen_consumer.h
modules/screen/screen.cpp
modules/screen/screen.h
protocol/StdAfx.cpp
protocol/StdAfx.h
protocol/amcp/AMCPCommand.h
protocol/amcp/AMCPCommandQueue.cpp
protocol/amcp/AMCPCommandQueue.h
protocol/amcp/AMCPCommandsImpl.cpp
protocol/amcp/AMCPCommandsImpl.h
protocol/amcp/AMCPProtocolStrategy.cpp
protocol/amcp/AMCPProtocolStrategy.h
protocol/cii/CIICommand.h
protocol/cii/CIICommandsImpl.cpp
protocol/cii/CIICommandsImpl.h
protocol/cii/CIIProtocolStrategy.cpp
protocol/cii/CIIProtocolStrategy.h
protocol/clk/CLKCommand.cpp
protocol/clk/CLKCommand.h
protocol/clk/CLKProtocolStrategy.cpp
protocol/clk/CLKProtocolStrategy.h
protocol/osc/oscpack/MessageMappingOscPacketListener.h
protocol/osc/oscpack/OscException.h
protocol/osc/oscpack/OscHostEndianness.h
protocol/osc/oscpack/OscOutboundPacketStream.cpp
protocol/osc/oscpack/OscOutboundPacketStream.h
protocol/osc/oscpack/OscPacketListener.h
protocol/osc/oscpack/OscPrintReceivedElements.cpp
protocol/osc/oscpack/OscPrintReceivedElements.h
protocol/osc/oscpack/OscReceivedElements.cpp
protocol/osc/oscpack/OscReceivedElements.h
protocol/osc/oscpack/OscTypes.cpp
protocol/osc/oscpack/OscTypes.h
protocol/osc/server.cpp
protocol/osc/server.h
protocol/util/AsyncEventServer.cpp
protocol/util/AsyncEventServer.h
protocol/util/ClientInfo.h
protocol/util/ProtocolStrategy.h
shell/main.cpp
shell/server.cpp
shell/server.h
shell/stdafx.h

index f2b946afaae3a37fd2191bec9f0ffa048cfadf85..218fe591a7ddb4d67eced93069b6420d8f13e368 100644 (file)
@@ -1,22 +1,22 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
 #include "stdafx.h"
\ No newline at end of file
index ff33505b0b99c5d3d2d50199b6259984d254bcbd..31ea7b85850a7217a9f1c3d1038f4aa4287e0563 100644 (file)
@@ -1,65 +1,65 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#ifdef _DEBUG\r
-#include <crtdbg.h>\r
-#endif\r
-\r
-#define NOMINMAX\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
-#include <GL/glew.h>\r
-\r
-#include <algorithm>\r
-#include <array>\r
-#include <functional>\r
-#include <deque>\r
-#include <map>\r
-#include <memory>\r
-#include <queue>\r
-#include <string>\r
-#include <vector>\r
-\r
-#include <tbb/atomic.h>\r
-#include <tbb/concurrent_queue.h>\r
-#include <tbb/concurrent_unordered_map.h>\r
-\r
-#include <boost/assign.hpp>\r
-#include <boost/circular_buffer.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/range.hpp>\r
-#include <boost/range/adaptors.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/thread.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/property_tree/xml_parser.hpp>\r
-\r
-#include <common/assert.h>\r
-#include <common/utf.h>\r
-#include <common/memory.h>\r
-//#include "../common/executor.h" // Can't include this due to MSVC lambda bug\r
-\r
-#include <common/log.h>\r
-#include <common/except.h>\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+
+#include <GL/glew.h>
+
+#include <algorithm>
+#include <array>
+#include <functional>
+#include <deque>
+#include <map>
+#include <memory>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include <tbb/atomic.h>
+#include <tbb/concurrent_queue.h>
+#include <tbb/concurrent_unordered_map.h>
+
+#include <boost/assign.hpp>
+#include <boost/circular_buffer.hpp>
+#include <boost/timer.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/range.hpp>
+#include <boost/range/adaptors.hpp>
+#include <boost/range/algorithm.hpp>
+#include <boost/thread.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+
+#include <common/assert.h>
+#include <common/utf.h>
+#include <common/memory.h>
+//#include "../common/executor.h" // Can't include this due to MSVC lambda bug
+
+#include <common/log.h>
+#include <common/except.h>
index ef5aaba36e6230bae9951e1815a122bd8e7b2300..b080a3479875359a2705de5098d360e97fb176f9 100644 (file)
@@ -1,63 +1,63 @@
-#include "stdafx.h"\r
-\r
-#include "accelerator.h"\r
-\r
-#include "cpu/image/image_mixer.h"\r
-#include "ogl/image/image_mixer.h"\r
-\r
-#include "ogl/util/device.h"\r
-\r
-#include <tbb/mutex.h>\r
-\r
-namespace caspar { namespace accelerator {\r
-       \r
-struct accelerator::impl\r
-{\r
-       const std::wstring                              path_;\r
-       tbb::mutex                                              mutex_;\r
-       std::shared_ptr<ogl::device>    ogl_device_;\r
-\r
-       impl(const std::wstring& path)\r
-               : path_(path)\r
-       {\r
-       }\r
-\r
-       std::unique_ptr<core::image_mixer> create_image_mixer()\r
-       {\r
-               try\r
-               {\r
-                       if(path_ == L"gpu" || path_ == L"ogl" || path_ == L"auto" || path_ == L"default")\r
-                       {\r
-                               tbb::mutex::scoped_lock lock(mutex_);\r
-\r
-                               if(!ogl_device_)\r
-                                       ogl_device_.reset(new ogl::device());\r
-\r
-                               return std::unique_ptr<core::image_mixer>(new ogl::image_mixer(spl::make_shared_ptr(ogl_device_)));\r
-                       }\r
-               }\r
-               catch(...)\r
-               {\r
-                       if(path_ == L"gpu" || path_ == L"ogl")\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-\r
-               return std::unique_ptr<core::image_mixer>(new cpu::image_mixer());\r
-       }\r
-};\r
-\r
-accelerator::accelerator(const std::wstring& path)\r
-       : impl_(new impl(path))\r
-{\r
-}\r
-\r
-accelerator::~accelerator()\r
-{\r
-}\r
-\r
-std::unique_ptr<core::image_mixer> accelerator::create_image_mixer()\r
-{\r
-       return impl_->create_image_mixer();\r
-}\r
-\r
+#include "stdafx.h"
+
+#include "accelerator.h"
+
+#include "cpu/image/image_mixer.h"
+#include "ogl/image/image_mixer.h"
+
+#include "ogl/util/device.h"
+
+#include <tbb/mutex.h>
+
+namespace caspar { namespace accelerator {
+       
+struct accelerator::impl
+{
+       const std::wstring                              path_;
+       tbb::mutex                                              mutex_;
+       std::shared_ptr<ogl::device>    ogl_device_;
+
+       impl(const std::wstring& path)
+               : path_(path)
+       {
+       }
+
+       std::unique_ptr<core::image_mixer> create_image_mixer()
+       {
+               try
+               {
+                       if(path_ == L"gpu" || path_ == L"ogl" || path_ == L"auto" || path_ == L"default")
+                       {
+                               tbb::mutex::scoped_lock lock(mutex_);
+
+                               if(!ogl_device_)
+                                       ogl_device_.reset(new ogl::device());
+
+                               return std::unique_ptr<core::image_mixer>(new ogl::image_mixer(spl::make_shared_ptr(ogl_device_)));
+                       }
+               }
+               catch(...)
+               {
+                       if(path_ == L"gpu" || path_ == L"ogl")
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+
+               return std::unique_ptr<core::image_mixer>(new cpu::image_mixer());
+       }
+};
+
+accelerator::accelerator(const std::wstring& path)
+       : impl_(new impl(path))
+{
+}
+
+accelerator::~accelerator()
+{
+}
+
+std::unique_ptr<core::image_mixer> accelerator::create_image_mixer()
+{
+       return impl_->create_image_mixer();
+}
+
 }}
\ No newline at end of file
index a54595cd62c7774882f329e2561421f456def0a7..ae767676a56de33267a14c46c345efe954a5452b 100644 (file)
@@ -1,24 +1,24 @@
-#pragma once\r
-\r
-#include <common/forward.h>\r
-#include <common/memory.h>\r
-\r
-#include <core/mixer/image/image_mixer.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-namespace caspar { namespace accelerator {\r
-       \r
-class accelerator : boost::noncopyable\r
-{\r
-public:\r
-       accelerator(const std::wstring& path);\r
-       ~accelerator();\r
-\r
-       std::unique_ptr<core::image_mixer> create_image_mixer();\r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-\r
+#pragma once
+
+#include <common/forward.h>
+#include <common/memory.h>
+
+#include <core/mixer/image/image_mixer.h>
+
+#include <boost/noncopyable.hpp>
+
+namespace caspar { namespace accelerator {
+       
+class accelerator : boost::noncopyable
+{
+public:
+       accelerator(const std::wstring& path);
+       ~accelerator();
+
+       std::unique_ptr<core::image_mixer> create_image_mixer();
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index fdb25d51c6e388c6ac6655b2b7f3fd085912a776..781726afdba7b42664a14fce571069daa9cc57f7 100644 (file)
@@ -1,52 +1,52 @@
-#include "../../StdAfx.h"\r
-\r
-#include "deinterlacer.h"\r
-\r
-#include <core/frame/frame_factory.h>\r
-\r
-#include <modules/ffmpeg/producer/filter/filter.h>\r
-#include <modules/ffmpeg/producer/util/util.h>\r
-\r
-#include <tbb/concurrent_hash_map.h>\r
-\r
-#include <tuple>\r
-\r
-namespace caspar { namespace accelerator { namespace cpu {\r
-\r
-struct deinterlacer::impl\r
-{\r
-       ffmpeg::filter filter_; \r
-\r
-public:\r
-\r
-       impl() \r
-               : filter_(L"YADIF=1:-1")\r
-       {\r
-       }\r
-\r
-       std::vector<core::const_frame> operator()(const core::const_frame& frame, core::frame_factory& frame_factory)\r
-       {               \r
-               std::array<uint8_t*, 4> data = {};\r
-               for(int n = 0; n < frame.pixel_format_desc().planes.size(); ++n)\r
-                       data[n] = const_cast<uint8_t*>(frame.image_data(n).begin());\r
-\r
-               auto av_frame = ffmpeg::make_av_frame(data, frame.pixel_format_desc());\r
-\r
-               filter_.push(av_frame);\r
-\r
-               auto av_frames = filter_.poll_all();\r
-\r
-               std::vector<core::const_frame> frames;\r
-\r
-               BOOST_FOREACH(auto av_frame, av_frames)\r
-                       frames.push_back(ffmpeg::make_frame(frame.stream_tag(), av_frame, frame.frame_rate(), frame_factory));\r
-               \r
-               return frames;\r
-       }               \r
-};\r
-\r
-deinterlacer::deinterlacer() : impl_(new impl()){}\r
-deinterlacer::~deinterlacer(){}\r
-std::vector<core::const_frame> deinterlacer::operator()(const core::const_frame& frame, core::frame_factory& frame_factory){return (*impl_)(frame, frame_factory);}\r
-\r
+#include "../../StdAfx.h"
+
+#include "deinterlacer.h"
+
+#include <core/frame/frame_factory.h>
+
+#include <modules/ffmpeg/producer/filter/filter.h>
+#include <modules/ffmpeg/producer/util/util.h>
+
+#include <tbb/concurrent_hash_map.h>
+
+#include <tuple>
+
+namespace caspar { namespace accelerator { namespace cpu {
+
+struct deinterlacer::impl
+{
+       ffmpeg::filter filter_; 
+
+public:
+
+       impl() 
+               : filter_(L"YADIF=1:-1")
+       {
+       }
+
+       std::vector<core::const_frame> operator()(const core::const_frame& frame, core::frame_factory& frame_factory)
+       {               
+               std::array<uint8_t*, 4> data = {};
+               for(int n = 0; n < frame.pixel_format_desc().planes.size(); ++n)
+                       data[n] = const_cast<uint8_t*>(frame.image_data(n).begin());
+
+               auto av_frame = ffmpeg::make_av_frame(data, frame.pixel_format_desc());
+
+               filter_.push(av_frame);
+
+               auto av_frames = filter_.poll_all();
+
+               std::vector<core::const_frame> frames;
+
+               BOOST_FOREACH(auto av_frame, av_frames)
+                       frames.push_back(ffmpeg::make_frame(frame.stream_tag(), av_frame, frame.frame_rate(), frame_factory));
+               
+               return frames;
+       }               
+};
+
+deinterlacer::deinterlacer() : impl_(new impl()){}
+deinterlacer::~deinterlacer(){}
+std::vector<core::const_frame> deinterlacer::operator()(const core::const_frame& frame, core::frame_factory& frame_factory){return (*impl_)(frame, frame_factory);}
+
 }}}
\ No newline at end of file
index 7e9339b207259f3d9a86f7dd62c13865ac422884..94374fd46ba7b1aafc06bc4feb98018933cd6786 100644 (file)
@@ -1,33 +1,33 @@
-#pragma once\r
-\r
-#include <common/forward.h>\r
-\r
-#include <core/frame/frame.h>\r
-\r
-FORWARD2(caspar, core, class frame_factory);\r
-\r
-namespace caspar { namespace accelerator { namespace cpu {\r
-       \r
-class deinterlacer sealed \r
-{\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       deinterlacer();\r
-       ~deinterlacer();\r
-\r
-       // Methods      \r
-                       \r
-       std::vector<core::const_frame> operator()(const core::const_frame& frame, core::frame_factory& frame_factory);\r
-               \r
-       // Properties\r
-\r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-\r
+#pragma once
+
+#include <common/forward.h>
+
+#include <core/frame/frame.h>
+
+FORWARD2(caspar, core, class frame_factory);
+
+namespace caspar { namespace accelerator { namespace cpu {
+       
+class deinterlacer sealed 
+{
+public:
+
+       // Static Members
+
+       // Constructors
+
+       deinterlacer();
+       ~deinterlacer();
+
+       // Methods      
+                       
+       std::vector<core::const_frame> operator()(const core::const_frame& frame, core::frame_factory& frame_factory);
+               
+       // Properties
+
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+
 }}}
\ No newline at end of file
index cb27abff13d512a8deef3661fabe99c6a6256cca..ec31d4e29f1ab8e477dc7252b5bcd474f98970d3 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "image_mixer.h"\r
-\r
-#include "../util/xmm.h"\r
-\r
-#include <common/assert.h>\r
-#include <common/gl/gl_check.h>\r
-#include <common/future.h>\r
-#include <common/array.h>\r
-\r
-#include <core/frame/frame.h>\r
-#include <core/frame/frame_transform.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/video_format.h>\r
-\r
-#include <modules/ffmpeg/producer/util/util.h>\r
-\r
-#include <asmlib.h>\r
-\r
-#include <gl/glew.h>\r
-\r
-#include <tbb/cache_aligned_allocator.h>\r
-#include <tbb/parallel_for.h>\r
-#include <tbb/parallel_for_each.h>\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <boost/assign.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/range.hpp>\r
-#include <boost/range/algorithm_ext/erase.hpp>\r
-#include <boost/thread/future.hpp>\r
-\r
-#include <algorithm>\r
-#include <cstdint>\r
-#include <vector>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #include <libswscale/swscale.h>\r
-       #include <libavcodec/avcodec.h>\r
-       #include <libavformat/avformat.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar { namespace accelerator { namespace cpu {\r
-               \r
-struct item\r
-{\r
-       core::pixel_format_desc                 pix_desc;\r
-       std::array<const uint8_t*, 4>   data;\r
-       core::image_transform                   transform;\r
-\r
-       item()\r
-               : pix_desc(core::pixel_format::invalid)\r
-       {\r
-               data.fill(0);\r
-       }\r
-};\r
-\r
-bool operator==(const item& lhs, const item& rhs)\r
-{\r
-       return lhs.data == rhs.data && lhs.transform == rhs.transform;\r
-}\r
-\r
-bool operator!=(const item& lhs, const item& rhs)\r
-{\r
-       return !(lhs == rhs);\r
-}\r
-       \r
-// 100% accurate blending with correct rounding.\r
-inline xmm::s8_x blend(xmm::s8_x d, xmm::s8_x s)\r
-{      \r
-       using namespace xmm;\r
-               \r
-       // C(S, D) = S + D - (((T >> 8) + T) >> 8);\r
-       // T(S, D) = S * D[A] + 0x80\r
-\r
-       auto aaaa   = s8_x::shuffle(d, s8_x(15, 15, 15, 15, 11, 11, 11, 11, 7, 7, 7, 7, 3, 3, 3, 3));\r
-       d                       = s8_x(u8_x::min(u8_x(d), u8_x(aaaa))); // Overflow guard. Some source files have color values which incorrectly exceed pre-multiplied alpha values, e.g. red(255) > alpha(254).\r
-\r
-       auto xaxa       = s16_x(aaaa) >> 8;             \r
-                             \r
-       auto t1         = s16_x::multiply_low(s16_x(s) & 0x00FF, xaxa) + 0x80;    \r
-       auto t2         = s16_x::multiply_low(s16_x(s) >> 8    , xaxa) + 0x80;\r
-               \r
-       auto xyxy       = s8_x(((t1 >> 8) + t1) >> 8);      \r
-       auto yxyx       = s8_x((t2 >> 8) + t2);    \r
-       auto argb   = s8_x::blend(xyxy, yxyx, s8_x(-1, 0, -1, 0));\r
-\r
-       return s8_x(s) + (d - argb);\r
-}\r
-       \r
-template<typename temporal, typename alignment>\r
-static void kernel(uint8_t* dest, const uint8_t* source, size_t count)\r
-{                      \r
-       using namespace xmm;\r
-\r
-       for(auto n = 0; n < count; n += 32)    \r
-       {\r
-               auto s0 = s8_x::load<temporal_tag, alignment>(dest+n+0);\r
-               auto s1 = s8_x::load<temporal_tag, alignment>(dest+n+16);\r
-\r
-               auto d0 = s8_x::load<temporal_tag, alignment>(source+n+0);\r
-               auto d1 = s8_x::load<temporal_tag, alignment>(source+n+16);\r
-               \r
-               auto argb0 = blend(d0, s0);\r
-               auto argb1 = blend(d1, s1);\r
-\r
-               s8_x::store<temporal, alignment>(argb0, dest+n+0 );\r
-               s8_x::store<temporal, alignment>(argb1, dest+n+16);\r
-       } \r
-}\r
-\r
-template<typename temporal>\r
-static void kernel(uint8_t* dest, const uint8_t* source, size_t count)\r
-{                      \r
-       using namespace xmm;\r
-\r
-       if(reinterpret_cast<int>(dest) % 16 != 0 || reinterpret_cast<int>(source) % 16 != 0)\r
-               kernel<temporal_tag, unaligned_tag>(dest, source, count);\r
-       else\r
-               kernel<temporal_tag, aligned_tag>(dest, source, count);\r
-}\r
-\r
-class image_renderer\r
-{\r
-       tbb::concurrent_unordered_map<int64_t, tbb::concurrent_bounded_queue<std::shared_ptr<SwsContext>>>      sws_devices_;\r
-       tbb::concurrent_bounded_queue<spl::shared_ptr<buffer>>                                                                                          temp_buffers_;\r
-public:        \r
-       boost::unique_future<array<const std::uint8_t>> operator()(std::vector<item> items, const core::video_format_desc& format_desc)\r
-       {       \r
-               convert(items, format_desc.width, format_desc.height);          \r
-                               \r
-               // Remove first field stills.\r
-               boost::range::remove_erase_if(items, [&](const item& item)\r
-               {\r
-                       return item.transform.is_still && item.transform.field_mode == format_desc.field_mode; // only us last field for stills.\r
-               });\r
-               \r
-               // Stills are progressive\r
-               BOOST_FOREACH(auto item, items)\r
-               {\r
-                       if(item.transform.is_still)\r
-                               item.transform.field_mode = core::field_mode::progressive;\r
-               }\r
-\r
-               auto result = spl::make_shared<buffer>(format_desc.size, 0);\r
-               if(format_desc.field_mode != core::field_mode::progressive)\r
-               {                       \r
-                       draw(items, result->data(), format_desc.width, format_desc.height, core::field_mode::upper);\r
-                       draw(items, result->data(), format_desc.width, format_desc.height, core::field_mode::lower);\r
-               }\r
-               else\r
-               {\r
-                       draw(items, result->data(), format_desc.width, format_desc.height,  core::field_mode::progressive);\r
-               }\r
-\r
-               temp_buffers_.clear();\r
-               \r
-               return async(launch::deferred, [=]\r
-               {\r
-                       return array<const std::uint8_t>(result->data(), format_desc.size, true, result);\r
-               });     \r
-       }\r
-\r
-private:\r
-\r
-       void draw(std::vector<item> items, uint8_t* dest, std::size_t width, std::size_t height, core::field_mode field_mode)\r
-       {               \r
-               BOOST_FOREACH(auto& item, items)\r
-                       item.transform.field_mode &= field_mode;\r
-               \r
-               // Remove empty items.\r
-               boost::range::remove_erase_if(items, [&](const item& item)\r
-               {\r
-                       return item.transform.field_mode == core::field_mode::empty;\r
-               });\r
-\r
-               if(items.empty())\r
-                       return;\r
-               \r
-               auto start = field_mode == core::field_mode::lower ? 1 : 0;\r
-               auto step  = field_mode == core::field_mode::progressive ? 1 : 2;\r
-               \r
-               // TODO: Add support for fill translations.\r
-               // TODO: Add support for mask rect.\r
-               // TODO: Add support for opacity.\r
-               // TODO: Add support for mix transition.\r
-               // TODO: Add support for push transition.\r
-               // TODO: Add support for wipe transition.\r
-               // TODO: Add support for slide transition.\r
-               tbb::parallel_for(tbb::blocked_range<std::size_t>(0, height/step), [&](const tbb::blocked_range<std::size_t>& r)\r
-               {\r
-                       for(auto i = r.begin(); i != r.end(); ++i)\r
-                       {\r
-                               auto y = i*step+start;\r
-\r
-                               for(std::size_t n = 0; n < items.size()-1; ++n)\r
-                                       kernel<xmm::temporal_tag>(dest + y*width*4, items[n].data.at(0) + y*width*4, width*4);\r
-                               \r
-                               std::size_t n = items.size()-1;                         \r
-                               kernel<xmm::nontemporal_tag>(dest + y*width*4, items[n].data.at(0) + y*width*4, width*4);\r
-                       }\r
-\r
-                       _mm_mfence();\r
-               });\r
-       }\r
-               \r
-       void convert(std::vector<item>& source_items, int width, int height)\r
-       {\r
-               std::set<std::array<const uint8_t*, 4>> buffers;\r
-\r
-               BOOST_FOREACH(auto& item, source_items)\r
-                       buffers.insert(item.data);\r
-               \r
-               auto dest_items = source_items;\r
-\r
-               tbb::parallel_for_each(buffers.begin(), buffers.end(), [&](const std::array<const uint8_t*, 4>& data)\r
-               {                       \r
-                       auto pix_desc = std::find_if(source_items.begin(), source_items.end(), [&](const item& item){return item.data == data;})->pix_desc;\r
-\r
-                       if(pix_desc.format == core::pixel_format::bgra && \r
-                               pix_desc.planes.at(0).width == width &&\r
-                               pix_desc.planes.at(0).height == height)\r
-                               return;\r
-\r
-                       std::array<uint8_t*, 4> data2 = {};\r
-                       for(std::size_t n = 0; n < data.size(); ++n)\r
-                               data2.at(n) = const_cast<uint8_t*>(data[n]);\r
-\r
-                       auto input_av_frame = ffmpeg::make_av_frame(data2, pix_desc);\r
-\r
-               \r
-                       int64_t key = ((static_cast<int64_t>(input_av_frame->width)      << 32) & 0xFFFF00000000) | \r
-                                                 ((static_cast<int64_t>(input_av_frame->height) << 16) & 0xFFFF0000) | \r
-                                                 ((static_cast<int64_t>(input_av_frame->format) <<  8) & 0xFF00);\r
-\r
-                       auto& pool = sws_devices_[key];\r
-\r
-                       std::shared_ptr<SwsContext> sws_device;\r
-                       if(!pool.try_pop(sws_device))\r
-                       {\r
-                               double param;\r
-                               sws_device.reset(sws_getContext(input_av_frame->width, input_av_frame->height, static_cast<PixelFormat>(input_av_frame->format), width, height, PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, &param), sws_freeContext);\r
-                       }\r
-                       \r
-                       if(!sws_device)                         \r
-                               CASPAR_THROW_EXCEPTION(operation_failed() << msg_info("Could not create software scaling device.") << boost::errinfo_api_function("sws_getContext"));                           \r
-               \r
-                       auto dest_frame = spl::make_shared<buffer>(width*height*4);\r
-                       temp_buffers_.push(dest_frame);\r
-\r
-                       {\r
-                               spl::shared_ptr<AVFrame> dest_av_frame(avcodec_alloc_frame(), av_free); \r
-                               avcodec_get_frame_defaults(dest_av_frame.get());                        \r
-                               avpicture_fill(reinterpret_cast<AVPicture*>(dest_av_frame.get()), dest_frame->data(), PIX_FMT_BGRA, width, height);\r
-                               \r
-                               sws_scale(sws_device.get(), input_av_frame->data, input_av_frame->linesize, 0, input_av_frame->height, dest_av_frame->data, dest_av_frame->linesize);                           \r
-                               pool.push(sws_device);\r
-                       }\r
-                                       \r
-                       for(std::size_t n = 0; n < source_items.size(); ++n)\r
-                       {\r
-                               if(source_items[n].data == data)\r
-                               {\r
-                                       dest_items[n].data.assign(0);\r
-                                       dest_items[n].data[0]                   = dest_frame->data();\r
-                                       dest_items[n].pix_desc                  = core::pixel_format_desc(core::pixel_format::bgra);\r
-                                       dest_items[n].pix_desc.planes   = boost::assign::list_of(core::pixel_format_desc::plane(width, height, 4));\r
-                                       dest_items[n].transform                 = source_items[n].transform;\r
-                               }\r
-                       }\r
-               });     \r
-\r
-               source_items = std::move(dest_items);\r
-       }\r
-};\r
-               \r
-struct image_mixer::impl : boost::noncopyable\r
-{      \r
-       image_renderer                                          renderer_;\r
-       std::vector<core::image_transform>      transform_stack_;\r
-       std::vector<item>                                       items_; // layer/stream/items\r
-public:\r
-       impl() \r
-               : transform_stack_(1)   \r
-       {\r
-               CASPAR_LOG(info) << L"Initialized Streaming SIMD Extensions Accelerated CPU Image Mixer";\r
-       }\r
-\r
-       void begin_layer(core::blend_mode blend_mode)\r
-       {\r
-       }\r
-               \r
-       void push(const core::frame_transform& transform)\r
-       {\r
-               transform_stack_.push_back(transform_stack_.back()*transform.image_transform);\r
-       }\r
-               \r
-       void visit(const core::const_frame& frame)\r
-       {                       \r
-               if(frame.pixel_format_desc().format == core::pixel_format::invalid)\r
-                       return;\r
-\r
-               if(frame.pixel_format_desc().planes.empty())\r
-                       return;\r
-               \r
-               if(frame.pixel_format_desc().planes.at(0).size < 16)\r
-                       return;\r
-\r
-               if(transform_stack_.back().field_mode == core::field_mode::empty)\r
-                       return;\r
-\r
-               item item;\r
-               item.pix_desc   = frame.pixel_format_desc();\r
-               item.transform  = transform_stack_.back();\r
-               for(int n = 0; n < item.pix_desc.planes.size(); ++n)\r
-                       item.data.at(n) = frame.image_data(n).begin();          \r
-\r
-               items_.push_back(item);\r
-       }\r
-\r
-       void pop()\r
-       {\r
-               transform_stack_.pop_back();\r
-       }\r
-\r
-       void end_layer()\r
-       {               \r
-       }\r
-       \r
-       boost::unique_future<array<const std::uint8_t>> render(const core::video_format_desc& format_desc)\r
-       {\r
-               return renderer_(std::move(items_), format_desc);\r
-       }\r
-       \r
-       virtual core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc)\r
-       {\r
-               std::vector<array<std::uint8_t>> buffers;\r
-               BOOST_FOREACH(auto& plane, desc.planes)\r
-               {\r
-                       auto buf = spl::make_shared<buffer>(plane.size);\r
-                       buffers.push_back(array<std::uint8_t>(buf->data(), plane.size, true, buf));\r
-               }\r
-               return core::mutable_frame(std::move(buffers), core::audio_buffer(), tag, desc);\r
-       }\r
-};\r
-\r
-image_mixer::image_mixer() : impl_(new impl()){}\r
-image_mixer::~image_mixer(){}\r
-void image_mixer::push(const core::frame_transform& transform){impl_->push(transform);}\r
-void image_mixer::visit(const core::const_frame& frame){impl_->visit(frame);}\r
-void image_mixer::pop(){impl_->pop();}\r
-boost::unique_future<array<const std::uint8_t>> image_mixer::operator()(const core::video_format_desc& format_desc){return impl_->render(format_desc);}\r
-void image_mixer::begin_layer(core::blend_mode blend_mode){impl_->begin_layer(blend_mode);}\r
-void image_mixer::end_layer(){impl_->end_layer();}\r
-core::mutable_frame image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->create_frame(tag, desc);}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "image_mixer.h"
+
+#include "../util/xmm.h"
+
+#include <common/assert.h>
+#include <common/gl/gl_check.h>
+#include <common/future.h>
+#include <common/array.h>
+
+#include <core/frame/frame.h>
+#include <core/frame/frame_transform.h>
+#include <core/frame/pixel_format.h>
+#include <core/video_format.h>
+
+#include <modules/ffmpeg/producer/util/util.h>
+
+#include <asmlib.h>
+
+#include <gl/glew.h>
+
+#include <tbb/cache_aligned_allocator.h>
+#include <tbb/parallel_for.h>
+#include <tbb/parallel_for_each.h>
+#include <tbb/concurrent_queue.h>
+
+#include <boost/assign.hpp>
+#include <boost/foreach.hpp>
+#include <boost/range.hpp>
+#include <boost/range/algorithm_ext/erase.hpp>
+#include <boost/thread/future.hpp>
+
+#include <algorithm>
+#include <cstdint>
+#include <vector>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #include <libswscale/swscale.h>
+       #include <libavcodec/avcodec.h>
+       #include <libavformat/avformat.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+namespace caspar { namespace accelerator { namespace cpu {
+               
+struct item
+{
+       core::pixel_format_desc                 pix_desc;
+       std::array<const uint8_t*, 4>   data;
+       core::image_transform                   transform;
+
+       item()
+               : pix_desc(core::pixel_format::invalid)
+       {
+               data.fill(0);
+       }
+};
+
+bool operator==(const item& lhs, const item& rhs)
+{
+       return lhs.data == rhs.data && lhs.transform == rhs.transform;
+}
+
+bool operator!=(const item& lhs, const item& rhs)
+{
+       return !(lhs == rhs);
+}
+       
+// 100% accurate blending with correct rounding.
+inline xmm::s8_x blend(xmm::s8_x d, xmm::s8_x s)
+{      
+       using namespace xmm;
+               
+       // C(S, D) = S + D - (((T >> 8) + T) >> 8);
+       // T(S, D) = S * D[A] + 0x80
+
+       auto aaaa   = s8_x::shuffle(d, s8_x(15, 15, 15, 15, 11, 11, 11, 11, 7, 7, 7, 7, 3, 3, 3, 3));
+       d                       = s8_x(u8_x::min(u8_x(d), u8_x(aaaa))); // Overflow guard. Some source files have color values which incorrectly exceed pre-multiplied alpha values, e.g. red(255) > alpha(254).
+
+       auto xaxa       = s16_x(aaaa) >> 8;             
+                             
+       auto t1         = s16_x::multiply_low(s16_x(s) & 0x00FF, xaxa) + 0x80;    
+       auto t2         = s16_x::multiply_low(s16_x(s) >> 8    , xaxa) + 0x80;
+               
+       auto xyxy       = s8_x(((t1 >> 8) + t1) >> 8);      
+       auto yxyx       = s8_x((t2 >> 8) + t2);    
+       auto argb   = s8_x::blend(xyxy, yxyx, s8_x(-1, 0, -1, 0));
+
+       return s8_x(s) + (d - argb);
+}
+       
+template<typename temporal, typename alignment>
+static void kernel(uint8_t* dest, const uint8_t* source, size_t count)
+{                      
+       using namespace xmm;
+
+       for(auto n = 0; n < count; n += 32)    
+       {
+               auto s0 = s8_x::load<temporal_tag, alignment>(dest+n+0);
+               auto s1 = s8_x::load<temporal_tag, alignment>(dest+n+16);
+
+               auto d0 = s8_x::load<temporal_tag, alignment>(source+n+0);
+               auto d1 = s8_x::load<temporal_tag, alignment>(source+n+16);
+               
+               auto argb0 = blend(d0, s0);
+               auto argb1 = blend(d1, s1);
+
+               s8_x::store<temporal, alignment>(argb0, dest+n+0 );
+               s8_x::store<temporal, alignment>(argb1, dest+n+16);
+       } 
+}
+
+template<typename temporal>
+static void kernel(uint8_t* dest, const uint8_t* source, size_t count)
+{                      
+       using namespace xmm;
+
+       if(reinterpret_cast<int>(dest) % 16 != 0 || reinterpret_cast<int>(source) % 16 != 0)
+               kernel<temporal_tag, unaligned_tag>(dest, source, count);
+       else
+               kernel<temporal_tag, aligned_tag>(dest, source, count);
+}
+
+class image_renderer
+{
+       tbb::concurrent_unordered_map<int64_t, tbb::concurrent_bounded_queue<std::shared_ptr<SwsContext>>>      sws_devices_;
+       tbb::concurrent_bounded_queue<spl::shared_ptr<buffer>>                                                                                          temp_buffers_;
+public:        
+       boost::unique_future<array<const std::uint8_t>> operator()(std::vector<item> items, const core::video_format_desc& format_desc)
+       {       
+               convert(items, format_desc.width, format_desc.height);          
+                               
+               // Remove first field stills.
+               boost::range::remove_erase_if(items, [&](const item& item)
+               {
+                       return item.transform.is_still && item.transform.field_mode == format_desc.field_mode; // only us last field for stills.
+               });
+               
+               // Stills are progressive
+               BOOST_FOREACH(auto item, items)
+               {
+                       if(item.transform.is_still)
+                               item.transform.field_mode = core::field_mode::progressive;
+               }
+
+               auto result = spl::make_shared<buffer>(format_desc.size, 0);
+               if(format_desc.field_mode != core::field_mode::progressive)
+               {                       
+                       draw(items, result->data(), format_desc.width, format_desc.height, core::field_mode::upper);
+                       draw(items, result->data(), format_desc.width, format_desc.height, core::field_mode::lower);
+               }
+               else
+               {
+                       draw(items, result->data(), format_desc.width, format_desc.height,  core::field_mode::progressive);
+               }
+
+               temp_buffers_.clear();
+               
+               return async(launch::deferred, [=]
+               {
+                       return array<const std::uint8_t>(result->data(), format_desc.size, true, result);
+               });     
+       }
+
+private:
+
+       void draw(std::vector<item> items, uint8_t* dest, std::size_t width, std::size_t height, core::field_mode field_mode)
+       {               
+               BOOST_FOREACH(auto& item, items)
+                       item.transform.field_mode &= field_mode;
+               
+               // Remove empty items.
+               boost::range::remove_erase_if(items, [&](const item& item)
+               {
+                       return item.transform.field_mode == core::field_mode::empty;
+               });
+
+               if(items.empty())
+                       return;
+               
+               auto start = field_mode == core::field_mode::lower ? 1 : 0;
+               auto step  = field_mode == core::field_mode::progressive ? 1 : 2;
+               
+               // TODO: Add support for fill translations.
+               // TODO: Add support for mask rect.
+               // TODO: Add support for opacity.
+               // TODO: Add support for mix transition.
+               // TODO: Add support for push transition.
+               // TODO: Add support for wipe transition.
+               // TODO: Add support for slide transition.
+               tbb::parallel_for(tbb::blocked_range<std::size_t>(0, height/step), [&](const tbb::blocked_range<std::size_t>& r)
+               {
+                       for(auto i = r.begin(); i != r.end(); ++i)
+                       {
+                               auto y = i*step+start;
+
+                               for(std::size_t n = 0; n < items.size()-1; ++n)
+                                       kernel<xmm::temporal_tag>(dest + y*width*4, items[n].data.at(0) + y*width*4, width*4);
+                               
+                               std::size_t n = items.size()-1;                         
+                               kernel<xmm::nontemporal_tag>(dest + y*width*4, items[n].data.at(0) + y*width*4, width*4);
+                       }
+
+                       _mm_mfence();
+               });
+       }
+               
+       void convert(std::vector<item>& source_items, int width, int height)
+       {
+               std::set<std::array<const uint8_t*, 4>> buffers;
+
+               BOOST_FOREACH(auto& item, source_items)
+                       buffers.insert(item.data);
+               
+               auto dest_items = source_items;
+
+               tbb::parallel_for_each(buffers.begin(), buffers.end(), [&](const std::array<const uint8_t*, 4>& data)
+               {                       
+                       auto pix_desc = std::find_if(source_items.begin(), source_items.end(), [&](const item& item){return item.data == data;})->pix_desc;
+
+                       if(pix_desc.format == core::pixel_format::bgra && 
+                               pix_desc.planes.at(0).width == width &&
+                               pix_desc.planes.at(0).height == height)
+                               return;
+
+                       std::array<uint8_t*, 4> data2 = {};
+                       for(std::size_t n = 0; n < data.size(); ++n)
+                               data2.at(n) = const_cast<uint8_t*>(data[n]);
+
+                       auto input_av_frame = ffmpeg::make_av_frame(data2, pix_desc);
+
+               
+                       int64_t key = ((static_cast<int64_t>(input_av_frame->width)      << 32) & 0xFFFF00000000) | 
+                                                 ((static_cast<int64_t>(input_av_frame->height) << 16) & 0xFFFF0000) | 
+                                                 ((static_cast<int64_t>(input_av_frame->format) <<  8) & 0xFF00);
+
+                       auto& pool = sws_devices_[key];
+
+                       std::shared_ptr<SwsContext> sws_device;
+                       if(!pool.try_pop(sws_device))
+                       {
+                               double param;
+                               sws_device.reset(sws_getContext(input_av_frame->width, input_av_frame->height, static_cast<PixelFormat>(input_av_frame->format), width, height, PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, &param), sws_freeContext);
+                       }
+                       
+                       if(!sws_device)                         
+                               CASPAR_THROW_EXCEPTION(operation_failed() << msg_info("Could not create software scaling device.") << boost::errinfo_api_function("sws_getContext"));                           
+               
+                       auto dest_frame = spl::make_shared<buffer>(width*height*4);
+                       temp_buffers_.push(dest_frame);
+
+                       {
+                               spl::shared_ptr<AVFrame> dest_av_frame(avcodec_alloc_frame(), av_free); 
+                               avcodec_get_frame_defaults(dest_av_frame.get());                        
+                               avpicture_fill(reinterpret_cast<AVPicture*>(dest_av_frame.get()), dest_frame->data(), PIX_FMT_BGRA, width, height);
+                               
+                               sws_scale(sws_device.get(), input_av_frame->data, input_av_frame->linesize, 0, input_av_frame->height, dest_av_frame->data, dest_av_frame->linesize);                           
+                               pool.push(sws_device);
+                       }
+                                       
+                       for(std::size_t n = 0; n < source_items.size(); ++n)
+                       {
+                               if(source_items[n].data == data)
+                               {
+                                       dest_items[n].data.assign(0);
+                                       dest_items[n].data[0]                   = dest_frame->data();
+                                       dest_items[n].pix_desc                  = core::pixel_format_desc(core::pixel_format::bgra);
+                                       dest_items[n].pix_desc.planes   = boost::assign::list_of(core::pixel_format_desc::plane(width, height, 4));
+                                       dest_items[n].transform                 = source_items[n].transform;
+                               }
+                       }
+               });     
+
+               source_items = std::move(dest_items);
+       }
+};
+               
+struct image_mixer::impl : boost::noncopyable
+{      
+       image_renderer                                          renderer_;
+       std::vector<core::image_transform>      transform_stack_;
+       std::vector<item>                                       items_; // layer/stream/items
+public:
+       impl() 
+               : transform_stack_(1)   
+       {
+               CASPAR_LOG(info) << L"Initialized Streaming SIMD Extensions Accelerated CPU Image Mixer";
+       }
+
+       void begin_layer(core::blend_mode blend_mode)
+       {
+       }
+               
+       void push(const core::frame_transform& transform)
+       {
+               transform_stack_.push_back(transform_stack_.back()*transform.image_transform);
+       }
+               
+       void visit(const core::const_frame& frame)
+       {                       
+               if(frame.pixel_format_desc().format == core::pixel_format::invalid)
+                       return;
+
+               if(frame.pixel_format_desc().planes.empty())
+                       return;
+               
+               if(frame.pixel_format_desc().planes.at(0).size < 16)
+                       return;
+
+               if(transform_stack_.back().field_mode == core::field_mode::empty)
+                       return;
+
+               item item;
+               item.pix_desc   = frame.pixel_format_desc();
+               item.transform  = transform_stack_.back();
+               for(int n = 0; n < item.pix_desc.planes.size(); ++n)
+                       item.data.at(n) = frame.image_data(n).begin();          
+
+               items_.push_back(item);
+       }
+
+       void pop()
+       {
+               transform_stack_.pop_back();
+       }
+
+       void end_layer()
+       {               
+       }
+       
+       boost::unique_future<array<const std::uint8_t>> render(const core::video_format_desc& format_desc)
+       {
+               return renderer_(std::move(items_), format_desc);
+       }
+       
+       virtual core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc)
+       {
+               std::vector<array<std::uint8_t>> buffers;
+               BOOST_FOREACH(auto& plane, desc.planes)
+               {
+                       auto buf = spl::make_shared<buffer>(plane.size);
+                       buffers.push_back(array<std::uint8_t>(buf->data(), plane.size, true, buf));
+               }
+               return core::mutable_frame(std::move(buffers), core::audio_buffer(), tag, desc);
+       }
+};
+
+image_mixer::image_mixer() : impl_(new impl()){}
+image_mixer::~image_mixer(){}
+void image_mixer::push(const core::frame_transform& transform){impl_->push(transform);}
+void image_mixer::visit(const core::const_frame& frame){impl_->visit(frame);}
+void image_mixer::pop(){impl_->pop();}
+boost::unique_future<array<const std::uint8_t>> image_mixer::operator()(const core::video_format_desc& format_desc){return impl_->render(format_desc);}
+void image_mixer::begin_layer(core::blend_mode blend_mode){impl_->begin_layer(blend_mode);}
+void image_mixer::end_layer(){impl_->end_layer();}
+core::mutable_frame image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->create_frame(tag, desc);}
+
 }}}
\ No newline at end of file
index 516b51ebbdbbac2e8be6470a27573bdcccaa4dd7..22742e3ac7636c952a557a5d5a70146a880d1d62 100644 (file)
@@ -1,56 +1,56 @@
-#pragma once\r
-\r
-#include <common/forward.h>\r
-#include <common/memory.h>\r
-\r
-#include <core/mixer/image/blend_modes.h>\r
-#include <core/mixer/image/image_mixer.h>\r
-\r
-#include <core/frame/frame.h>\r
-#include <core/frame/frame_visitor.h>\r
-#include <core/video_format.h>\r
-\r
-FORWARD1(boost, template<typename> class shared_future);\r
-FORWARD1(boost, template<typename> class iterator_range);\r
-FORWARD2(caspar, core, class frame);\r
-FORWARD2(caspar, core, struct pixel_format_desc);\r
-FORWARD2(caspar, core, struct video_format_desc);\r
-FORWARD2(caspar, core, class mutable_frame);\r
-FORWARD2(caspar, core, struct frame_transform);\r
-\r
-namespace caspar { namespace accelerator { namespace cpu {\r
-       \r
-typedef std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>> buffer;\r
-\r
-class image_mixer sealed : public core::image_mixer\r
-{\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       image_mixer();\r
-       ~image_mixer();\r
-\r
-       // Methods      \r
-\r
-       virtual void begin_layer(core::blend_mode blend_mode);\r
-       virtual void end_layer();\r
-\r
-       virtual void push(const core::frame_transform& frame);\r
-       virtual void visit(const core::const_frame& frame);\r
-       virtual void pop();\r
-               \r
-       boost::unique_future<array<const std::uint8_t>> operator()(const core::video_format_desc& format_desc) override;\r
-               \r
-       core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc) override;\r
-\r
-       // Properties\r
-\r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-\r
+#pragma once
+
+#include <common/forward.h>
+#include <common/memory.h>
+
+#include <core/mixer/image/blend_modes.h>
+#include <core/mixer/image/image_mixer.h>
+
+#include <core/frame/frame.h>
+#include <core/frame/frame_visitor.h>
+#include <core/video_format.h>
+
+FORWARD1(boost, template<typename> class shared_future);
+FORWARD1(boost, template<typename> class iterator_range);
+FORWARD2(caspar, core, class frame);
+FORWARD2(caspar, core, struct pixel_format_desc);
+FORWARD2(caspar, core, struct video_format_desc);
+FORWARD2(caspar, core, class mutable_frame);
+FORWARD2(caspar, core, struct frame_transform);
+
+namespace caspar { namespace accelerator { namespace cpu {
+       
+typedef std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>> buffer;
+
+class image_mixer sealed : public core::image_mixer
+{
+public:
+
+       // Static Members
+
+       // Constructors
+
+       image_mixer();
+       ~image_mixer();
+
+       // Methods      
+
+       virtual void begin_layer(core::blend_mode blend_mode);
+       virtual void end_layer();
+
+       virtual void push(const core::frame_transform& frame);
+       virtual void visit(const core::const_frame& frame);
+       virtual void pop();
+               
+       boost::unique_future<array<const std::uint8_t>> operator()(const core::video_format_desc& format_desc) override;
+               
+       core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc) override;
+
+       // Properties
+
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+
 }}}
\ No newline at end of file
index 764fddb21f04156c5a23bcaf02370eed877d6396..84fb4d8324f6b13e5361eab1bcf7dd2b9de8326a 100644 (file)
-#pragma once\r
-\r
-#include <intrin.h>\r
-#include <type_traits>\r
-\r
-namespace caspar { namespace accelerator { namespace cpu { namespace xmm {\r
-\r
-struct temporal_tag\r
-{\r
-       static const int value = 0x01;\r
-};\r
-struct nontemporal_tag\r
-{\r
-       static const int value = 0x02;\r
-};\r
-struct aligned_tag\r
-{\r
-       static const int value = 0x01;\r
-};\r
-struct unaligned_tag\r
-{\r
-       static const int value = 0x02;\r
-};\r
-\r
-class s32_x;\r
-class s16_x;\r
-class  s8_x;\r
-class  u8_x;\r
-\r
-template<typename T>\r
-class base_x\r
-{\r
-public:\r
-       template<typename temporal, typename alignment>\r
-       static T load(const void* source);\r
-       \r
-       template<typename temporal,typename alignment>\r
-       static void store(const T& source, void* dest);\r
-       \r
-       static T zero();\r
-};\r
-\r
-class s32_x : public base_x<s32_x>\r
-{\r
-       __m128i value_;\r
-       template<typename> friend class base_x;\r
-       friend class s16_x;\r
-       friend class s8_x;\r
-       friend class u8_x;\r
-public:\r
-       typedef s32_x xmm_epi_tag;\r
-\r
-       s32_x();\r
-       explicit s32_x(const s16_x& other);\r
-       explicit s32_x(const s8_x& other);\r
-       explicit s32_x(const u8_x& other);\r
-       s32_x(const __m128i& value);\r
-\r
-       s32_x& operator>>=(int count);\r
-       s32_x& operator<<=(int count);\r
-       s32_x& operator|=(const s32_x& other);\r
-       s32_x& operator&=(const s32_x& other);\r
-       int32_t operator[](int index) const;\r
-       int32_t& operator[](int index);\r
-};\r
-\r
-class s16_x : public base_x<s16_x>\r
-{\r
-       __m128i value_;\r
-\r
-private:\r
-       template<typename> friend class base_x;\r
-       friend class s32_x;\r
-       friend class s8_x;\r
-       friend class u8_x;\r
-public:\r
-       typedef s16_x xmm_epi_tag;\r
-\r
-       s16_x();\r
-       explicit s16_x(const s32_x& other);\r
-       explicit s16_x(const s8_x& other);\r
-       explicit s16_x(const u8_x& other);\r
-       s16_x(const __m128i& value);\r
-       s16_x(short value);\r
-\r
-       s16_x& operator+=(const s16_x& other);  \r
-       s16_x& operator-=(const s16_x& other);\r
-       s16_x& operator>>=(int count);\r
-       s16_x& operator<<=(int count);\r
-       s16_x& operator|=(const s16_x& other);\r
-       s16_x& operator&=(const s16_x& other);  \r
-       int16_t operator[](int index) const;\r
-       int16_t& operator[](int index);\r
-       \r
-       static s16_x unpack_low(const s8_x& lhs, const s8_x& rhs);\r
-       static s16_x unpack_high(const s8_x& lhs, const s8_x& rhs);\r
-       static s32_x horizontal_add(const s16_x& lhs);\r
-       static s16_x multiply_low(const s16_x& lhs, const s16_x& rhs);\r
-       static s16_x multiply_high(const s16_x& lhs, const s16_x& rhs);\r
-       static s16_x umultiply_low(const s16_x& lhs, const s16_x& rhs);\r
-       static s16_x umultiply_high(const s16_x& lhs, const s16_x& rhs);        \r
-       static s16_x unpack_low(const s16_x& lhs, const s16_x& rhs);\r
-       static s16_x unpack_high(const s16_x& lhs, const s16_x& rhs);\r
-       static s16_x and_not(const s16_x& lhs, const s16_x& rhs);       \r
-       static s16_x max(const s16_x& lhs, const s16_x& rhs);\r
-       static s16_x min(const s16_x& lhs, const s16_x& rhs);\r
-};\r
-\r
-template<typename T>\r
-class base8_x : public base_x<s8_x>\r
-{                                                                      \r
-       char operator[](int index) const;\r
-       char& operator[](int index);\r
-};\r
-\r
-class s8_x : public base_x<s8_x>\r
-{\r
-       __m128i value_;\r
-private:\r
-       template<typename> friend class base_x;\r
-       friend class s32_x;\r
-       friend class s16_x;\r
-       friend class u8_x;\r
-public:\r
-       typedef s8_x xmm_epi_tag;\r
-\r
-       s8_x();\r
-       explicit s8_x(const s32_x& other);\r
-       explicit s8_x(const s16_x& other);\r
-       explicit s8_x(const u8_x& other);\r
-       s8_x(const __m128i& value);     \r
-       s8_x(char b);\r
-       s8_x(char b3,  char b2,  char b1,  char b0);\r
-       s8_x(char b15, char b14, char b13, char b12, \r
-                char b11, char b10, char b9,  char b8,  \r
-                char b7,  char b6,  char b5,  char b4,  \r
-                char b3,  char b2,  char b1,  char b0);\r
-\r
-       s8_x& operator+=(const s8_x& other);\r
-       s8_x& operator-=(const s8_x& other);    \r
-       char operator[](int index) const;\r
-       char& operator[](int index);\r
-       \r
-       static s8_x upack(const s16_x& lhs, const s16_x& rhs);\r
-\r
-       static s16_x multiply_add(const u8_x& lhs, const s8_x& rhs);\r
-       static s8_x max(const s8_x& lhs, const s8_x& rhs);\r
-       static s8_x min(const s8_x& lhs, const s8_x& rhs);\r
-\r
-       static s8_x shuffle(const s8_x& lhs, const s8_x& rhs);\r
-       static s8_x blend(const s8_x& lhs, const s8_x& rhs, const s8_x& mask);\r
-};\r
-\r
-class u8_x : public base_x<u8_x>\r
-{\r
-       __m128i value_;\r
-private:\r
-       template<typename> friend class base_x;\r
-       friend class s32_x;\r
-       friend class s16_x;\r
-       friend class s8_x;\r
-public:\r
-       typedef u8_x xmm_epu_tag;\r
-\r
-       u8_x();\r
-       explicit u8_x(const s32_x& other);\r
-       explicit u8_x(const s16_x& other);\r
-       explicit u8_x(const s8_x& other);\r
-       u8_x(const __m128i& value);     \r
-       u8_x(char b);\r
-       u8_x(char b3,  char b2,  char b1,  char b0);\r
-       u8_x(char b15, char b14, char b13, char b12, \r
-                char b11, char b10, char b9,  char b8,  \r
-                char b7,  char b6,  char b5,  char b4,  \r
-                char b3,  char b2,  char b1,  char b0);\r
-                                                                               \r
-       char operator[](int index) const;\r
-       char& operator[](int index);\r
-                       \r
-       static u8_x max(const u8_x& lhs, const u8_x& rhs);\r
-       static u8_x min(const u8_x& lhs, const u8_x& rhs);\r
-               \r
-       static u8_x shuffle(const u8_x& lhs, const u8_x& rhs);\r
-       static u8_x blend(const u8_x& lhs, const u8_x& rhs, const u8_x& mask);\r
-};\r
-\r
-// base_x\r
-\r
-template<typename T>\r
-template<typename temporal, typename alignment>\r
-T base_x<T>::load(const void* source)\r
-{ \r
-       static_assert(temporal::value != nontemporal_tag::value, "streaming loads not supported");\r
-       if(alignment::value == aligned_tag::value)\r
-               return _mm_load_si128(reinterpret_cast<const __m128i*>(source));\r
-       else\r
-               return _mm_loadu_si128(reinterpret_cast<const __m128i*>(source));\r
-}\r
-       \r
-template<typename T>\r
-template<typename temporal, typename alignment>\r
-void base_x<T>::store(const T& source, void* dest)\r
-{\r
-       if(temporal::value == nontemporal_tag::value && alignment::value == aligned_tag::value)\r
-               _mm_stream_si128(reinterpret_cast<__m128i*>(dest), source.value_);\r
-       else if(alignment::value == aligned_tag::value)\r
-               _mm_store_si128(reinterpret_cast<__m128i*>(dest), source.value_);\r
-       else\r
-               _mm_storeu_si128(reinterpret_cast<__m128i*>(dest), source.value_);\r
-}\r
-\r
-template<typename T>\r
-T base_x<T>::zero()\r
-{\r
-       return _mm_setzero_si128();\r
-}\r
-\r
-// s32_x\r
-\r
-s32_x::s32_x()\r
-{\r
-}\r
-\r
-s32_x::s32_x(const s16_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-s32_x::s32_x(const s8_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-s32_x::s32_x(const u8_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-s32_x::s32_x(const __m128i& value)\r
-       : value_(value)\r
-{\r
-}\r
-       \r
-s32_x& s32_x::operator>>=(int count)\r
-{\r
-       value_ = _mm_srli_epi32(value_, count);\r
-       return *this;\r
-}\r
-       \r
-s32_x& s32_x::operator<<=(int count)\r
-{\r
-       value_ = _mm_slli_epi32(value_, count);\r
-       return *this;\r
-}\r
-               \r
-s32_x& s32_x::operator|=(const s32_x& other)\r
-{\r
-       value_ = _mm_or_si128(value_, other.value_);\r
-       return *this;\r
-}      \r
-       \r
-s32_x& s32_x::operator&=(const s32_x& other)\r
-{\r
-       value_ = _mm_and_si128(value_, other.value_);\r
-       return *this;\r
-}      \r
-               \r
-int32_t s32_x::operator[](int index) const\r
-{\r
-       return value_.m128i_i32[index];\r
-}\r
-\r
-int32_t& s32_x::operator[](int index)\r
-{\r
-       return value_.m128i_i32[index];\r
-}\r
-\r
-inline s32_x operator>>(const s32_x& lhs, int count)\r
-{              \r
-       return s32_x(lhs) >>= count;\r
-}\r
-\r
-inline s32_x operator<<(const s32_x& lhs, int count)\r
-{              \r
-       return s32_x(lhs) <<= count;\r
-}\r
-\r
-inline s32_x operator|(const s32_x& lhs, const s32_x& rhs)\r
-{              \r
-       return s32_x(lhs) |= rhs;\r
-}\r
-\r
-inline s32_x operator&(const s32_x& lhs, const s32_x& rhs)\r
-{              \r
-       return s32_x(lhs) &= rhs;\r
-}\r
-\r
-// s16_x\r
-\r
-s16_x::s16_x()\r
-{\r
-}\r
-\r
-s16_x::s16_x(const s32_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-s16_x::s16_x(const s8_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-s16_x::s16_x(const u8_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-s16_x::s16_x(const __m128i& value)\r
-       : value_(value)\r
-{\r
-}\r
-\r
-s16_x::s16_x(short value)\r
-       : value_(_mm_set1_epi16(value))\r
-{\r
-}\r
-\r
-s16_x& s16_x::operator+=(const s16_x& other)\r
-{\r
-       value_ = _mm_add_epi16(value_, other.value_);\r
-       return *this;\r
-}\r
-       \r
-s16_x& s16_x::operator-=(const s16_x& other)\r
-{\r
-       value_ = _mm_sub_epi16(value_, other.value_);\r
-       return *this;\r
-}\r
-\r
-s16_x& s16_x::operator>>=(int count)\r
-{\r
-       value_ = _mm_srli_epi16(value_, count);\r
-       return *this;\r
-}\r
-       \r
-s16_x& s16_x::operator<<=(int count)\r
-{\r
-       value_ = _mm_slli_epi16(value_, count);\r
-       return *this;\r
-}\r
-\r
-s16_x& s16_x::operator|=(const s16_x& other)\r
-{\r
-       value_ = _mm_or_si128(value_, other.value_);\r
-       return *this;\r
-}      \r
-       \r
-s16_x& s16_x::operator&=(const s16_x& other)\r
-{\r
-       value_ = _mm_and_si128(value_, other.value_);\r
-       return *this;\r
-}      \r
-                       \r
-int16_t s16_x::operator[](int index) const\r
-{\r
-       return value_.m128i_i16[index];\r
-}\r
-\r
-int16_t& s16_x::operator[](int index)\r
-{\r
-       return value_.m128i_i16[index];\r
-}\r
-\r
-s16_x s16_x::unpack_low(const s8_x& lhs, const s8_x& rhs)\r
-{\r
-       return _mm_unpacklo_epi8(rhs.value_, lhs.value_);\r
-}\r
-       \r
-s16_x s16_x::unpack_high(const s8_x& lhs, const s8_x& rhs)\r
-{\r
-       return _mm_unpackhi_epi8(rhs.value_, lhs.value_);\r
-}\r
-       \r
-s32_x s16_x::horizontal_add(const s16_x& lhs)\r
-{\r
-       #ifdef SSIM_XOP\r
-                       return _mm_haddd_epi16(value_);\r
-       #else\r
-                       return _mm_madd_epi16(lhs.value_, _mm_set1_epi16(1));\r
-       #endif\r
-}\r
-\r
-s16_x s16_x::multiply_low(const s16_x& lhs, const s16_x& rhs)\r
-{\r
-       return _mm_mullo_epi16(lhs.value_, rhs.value_);\r
-}\r
-\r
-s16_x s16_x::multiply_high(const s16_x& lhs, const s16_x& rhs)\r
-{\r
-       return _mm_mulhi_epi16(lhs.value_, rhs.value_);\r
-}\r
-\r
-s16_x s16_x::unpack_low(const s16_x& lhs, const s16_x& rhs)\r
-{\r
-       return _mm_unpacklo_epi16(lhs.value_, rhs.value_);\r
-}\r
-\r
-s16_x s16_x::unpack_high(const s16_x& lhs, const s16_x& rhs)\r
-{\r
-       return _mm_unpackhi_epi16(lhs.value_, rhs.value_);\r
-}\r
-       \r
-s16_x s16_x::and_not(const s16_x& lhs, const s16_x& rhs)\r
-{\r
-       return _mm_andnot_si128(lhs.value_, rhs.value_);\r
-}\r
-       \r
-s16_x s16_x::max(const s16_x& lhs, const s16_x& rhs)\r
-{\r
-       return _mm_max_epi16(lhs.value_, rhs.value_);\r
-}\r
-       \r
-s16_x s16_x::min(const s16_x& lhs, const s16_x& rhs)\r
-{\r
-       return _mm_min_epi16(lhs.value_, rhs.value_);\r
-}\r
-\r
-inline s16_x operator+(const s16_x& lhs, const s16_x& rhs)\r
-{\r
-       return s16_x(lhs) += rhs;\r
-}\r
-\r
-inline s16_x operator-(const s16_x& lhs, const s16_x& rhs)\r
-{\r
-       return s16_x(lhs) -= rhs;\r
-}\r
-\r
-inline s16_x operator>>(const s16_x& lhs, int count)\r
-{              \r
-       return s16_x(lhs) >>= count;\r
-}\r
-\r
-inline s16_x operator<<(const s16_x& lhs, int count)\r
-{              \r
-       return s16_x(lhs) <<= count;\r
-}\r
-\r
-inline s16_x operator|(const s16_x& lhs, const s16_x& rhs)\r
-{              \r
-       return s16_x(lhs) |= rhs;\r
-}\r
-\r
-inline s16_x operator&(const s16_x& lhs, const s16_x& rhs)\r
-{              \r
-       return s16_x(lhs) &= rhs;\r
-}\r
-\r
-// s8_x\r
-\r
-s8_x::s8_x()\r
-{\r
-}\r
-\r
-s8_x::s8_x(const s32_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-s8_x::s8_x(const s16_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-s8_x::s8_x(const u8_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-s8_x::s8_x(const __m128i& value)\r
-       : value_(value)\r
-{\r
-}      \r
-\r
-s8_x::s8_x(char b)\r
-       : value_(_mm_set1_epi8(b))\r
-{\r
-}\r
-\r
-s8_x::s8_x(char b3,  char b2,  char b1,  char b0)\r
-       : value_(_mm_set_epi8(b3, b2, b1, b0, b3, b2, b1, b0, b3, b2, b1, b0, b3, b2, b1, b0))\r
-{\r
-}\r
-\r
-s8_x::s8_x(char b15, char b14, char b13, char b12, \r
-                  char b11, char b10, char b9,  char b8,  \r
-                  char b7,  char b6,  char b5,  char b4,  \r
-                  char b3,  char b2,  char b1,  char b0)\r
-       : value_(_mm_set_epi8(b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0))\r
-{\r
-}\r
-       \r
-s8_x& s8_x::operator+=(const s8_x& other)\r
-{\r
-       value_ = _mm_add_epi8(value_, other.value_);\r
-       return *this;\r
-}\r
-\r
-s8_x& s8_x::operator-=(const s8_x& other)\r
-{\r
-       value_ = _mm_sub_epi8(value_, other.value_);\r
-       return *this;\r
-}\r
-                                                                       \r
-char s8_x::operator[](int index) const\r
-{\r
-       return value_.m128i_i8[index];\r
-}\r
-\r
-char& s8_x::operator[](int index)\r
-{\r
-       return value_.m128i_i8[index];\r
-}\r
-       \r
-s8_x s8_x::upack(const s16_x& lhs, const s16_x& rhs)\r
-{\r
-       return _mm_packus_epi16(lhs.value_, rhs.value_);\r
-}\r
-\r
-s16_x s8_x::multiply_add(const u8_x& lhs, const s8_x& rhs)\r
-{              \r
-       return _mm_maddubs_epi16(lhs.value_, rhs.value_);\r
-}\r
-       \r
-s8_x s8_x::max(const s8_x& lhs, const s8_x& rhs)\r
-{              \r
-       return _mm_max_epi8(lhs.value_, rhs.value_);\r
-}\r
-       \r
-s8_x s8_x::min(const s8_x& lhs, const s8_x& rhs)\r
-{              \r
-       return _mm_min_epi8(lhs.value_, rhs.value_);\r
-}\r
-\r
-inline s8_x operator+(const s8_x& lhs, const s8_x& rhs)\r
-{\r
-       return s8_x(lhs) += rhs;\r
-}\r
-\r
-inline s8_x operator-(const s8_x& lhs, const s8_x& rhs)\r
-{\r
-       return s8_x(lhs) -= rhs;\r
-}\r
-       \r
-s8_x s8_x::shuffle(const s8_x& lhs, const s8_x& rhs)\r
-{              \r
-       return _mm_shuffle_epi8(lhs.value_, rhs.value_);\r
-}\r
-\r
-s8_x s8_x::blend(const s8_x& lhs, const s8_x& rhs, const s8_x& mask)\r
-{              \r
-       return _mm_blendv_epi8(lhs.value_, rhs.value_, mask.value_);\r
-}\r
-\r
-// u8_x\r
-\r
-u8_x::u8_x()\r
-{\r
-}\r
-\r
-u8_x::u8_x(const s32_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-u8_x::u8_x(const s16_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-u8_x::u8_x(const s8_x& other)\r
-       : value_(other.value_)\r
-{\r
-}\r
-\r
-u8_x::u8_x(const __m128i& value)\r
-       : value_(value)\r
-{\r
-}      \r
-\r
-u8_x::u8_x(char b)\r
-       : value_(_mm_set1_epi8(b))\r
-{\r
-}\r
-\r
-u8_x::u8_x(char b3,  char b2,  char b1,  char b0)\r
-       : value_(_mm_set_epi8(b3, b2, b1, b0, b3, b2, b1, b0, b3, b2, b1, b0, b3, b2, b1, b0))\r
-{\r
-}\r
-\r
-u8_x::u8_x(char b15, char b14, char b13, char b12, \r
-                  char b11, char b10, char b9,  char b8,  \r
-                  char b7,  char b6,  char b5,  char b4,  \r
-                  char b3,  char b2,  char b1,  char b0)\r
-       : value_(_mm_set_epi8(b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0))\r
-{\r
-}\r
-                                                                               \r
-char u8_x::operator[](int index) const\r
-{\r
-       return value_.m128i_i8[index];\r
-}\r
-\r
-char& u8_x::operator[](int index)\r
-{\r
-       return value_.m128i_i8[index];\r
-}\r
-\r
-u8_x u8_x::max(const u8_x& lhs, const u8_x& rhs)\r
-{              \r
-       return _mm_max_epu8(lhs.value_, rhs.value_);\r
-}\r
-       \r
-u8_x u8_x::min(const u8_x& lhs, const u8_x& rhs)\r
-{              \r
-       return _mm_min_epu8(lhs.value_, rhs.value_);\r
-}\r
-\r
-u8_x u8_x::shuffle(const u8_x& lhs, const u8_x& rhs)\r
-{              \r
-       return _mm_shuffle_epi8(lhs.value_, rhs.value_);\r
-}\r
-\r
-u8_x u8_x::blend(const u8_x& lhs, const u8_x& rhs, const u8_x& mask)\r
-{              \r
-       return _mm_blendv_epi8(lhs.value_, rhs.value_, mask.value_);\r
-}\r
-\r
-// xmm_cast\r
-\r
-//template<typename T>\r
-//struct xmm_cast_impl\r
-//{            \r
-//     template<typename U>\r
-//     T operator()(const U& other)\r
-//     {\r
-//             return typename T::xmm_epi_tag(other.value_);\r
-//     }\r
-//};\r
-//\r
-//template<>\r
-//struct xmm_cast_impl<xmm_ps>\r
-//{\r
-//     xmm_ps operator()(const s32_x& other)\r
-//     {\r
-//             return _mm_cvtepi32_ps(other.value_);\r
-//     }\r
-//};\r
-//\r
-//template<typename T, typename U> \r
-//T xmm_cast(const U& other)\r
-//{\r
-//     return xmm_cast_impl<T>()(other);\r
-//}\r
-\r
+#pragma once
+
+#include <intrin.h>
+#include <type_traits>
+
+namespace caspar { namespace accelerator { namespace cpu { namespace xmm {
+
+struct temporal_tag
+{
+       static const int value = 0x01;
+};
+struct nontemporal_tag
+{
+       static const int value = 0x02;
+};
+struct aligned_tag
+{
+       static const int value = 0x01;
+};
+struct unaligned_tag
+{
+       static const int value = 0x02;
+};
+
+class s32_x;
+class s16_x;
+class  s8_x;
+class  u8_x;
+
+template<typename T>
+class base_x
+{
+public:
+       template<typename temporal, typename alignment>
+       static T load(const void* source);
+       
+       template<typename temporal,typename alignment>
+       static void store(const T& source, void* dest);
+       
+       static T zero();
+};
+
+class s32_x : public base_x<s32_x>
+{
+       __m128i value_;
+       template<typename> friend class base_x;
+       friend class s16_x;
+       friend class s8_x;
+       friend class u8_x;
+public:
+       typedef s32_x xmm_epi_tag;
+
+       s32_x();
+       explicit s32_x(const s16_x& other);
+       explicit s32_x(const s8_x& other);
+       explicit s32_x(const u8_x& other);
+       s32_x(const __m128i& value);
+
+       s32_x& operator>>=(int count);
+       s32_x& operator<<=(int count);
+       s32_x& operator|=(const s32_x& other);
+       s32_x& operator&=(const s32_x& other);
+       int32_t operator[](int index) const;
+       int32_t& operator[](int index);
+};
+
+class s16_x : public base_x<s16_x>
+{
+       __m128i value_;
+
+private:
+       template<typename> friend class base_x;
+       friend class s32_x;
+       friend class s8_x;
+       friend class u8_x;
+public:
+       typedef s16_x xmm_epi_tag;
+
+       s16_x();
+       explicit s16_x(const s32_x& other);
+       explicit s16_x(const s8_x& other);
+       explicit s16_x(const u8_x& other);
+       s16_x(const __m128i& value);
+       s16_x(short value);
+
+       s16_x& operator+=(const s16_x& other);  
+       s16_x& operator-=(const s16_x& other);
+       s16_x& operator>>=(int count);
+       s16_x& operator<<=(int count);
+       s16_x& operator|=(const s16_x& other);
+       s16_x& operator&=(const s16_x& other);  
+       int16_t operator[](int index) const;
+       int16_t& operator[](int index);
+       
+       static s16_x unpack_low(const s8_x& lhs, const s8_x& rhs);
+       static s16_x unpack_high(const s8_x& lhs, const s8_x& rhs);
+       static s32_x horizontal_add(const s16_x& lhs);
+       static s16_x multiply_low(const s16_x& lhs, const s16_x& rhs);
+       static s16_x multiply_high(const s16_x& lhs, const s16_x& rhs);
+       static s16_x umultiply_low(const s16_x& lhs, const s16_x& rhs);
+       static s16_x umultiply_high(const s16_x& lhs, const s16_x& rhs);        
+       static s16_x unpack_low(const s16_x& lhs, const s16_x& rhs);
+       static s16_x unpack_high(const s16_x& lhs, const s16_x& rhs);
+       static s16_x and_not(const s16_x& lhs, const s16_x& rhs);       
+       static s16_x max(const s16_x& lhs, const s16_x& rhs);
+       static s16_x min(const s16_x& lhs, const s16_x& rhs);
+};
+
+template<typename T>
+class base8_x : public base_x<s8_x>
+{                                                                      
+       char operator[](int index) const;
+       char& operator[](int index);
+};
+
+class s8_x : public base_x<s8_x>
+{
+       __m128i value_;
+private:
+       template<typename> friend class base_x;
+       friend class s32_x;
+       friend class s16_x;
+       friend class u8_x;
+public:
+       typedef s8_x xmm_epi_tag;
+
+       s8_x();
+       explicit s8_x(const s32_x& other);
+       explicit s8_x(const s16_x& other);
+       explicit s8_x(const u8_x& other);
+       s8_x(const __m128i& value);     
+       s8_x(char b);
+       s8_x(char b3,  char b2,  char b1,  char b0);
+       s8_x(char b15, char b14, char b13, char b12, 
+                char b11, char b10, char b9,  char b8,  
+                char b7,  char b6,  char b5,  char b4,  
+                char b3,  char b2,  char b1,  char b0);
+
+       s8_x& operator+=(const s8_x& other);
+       s8_x& operator-=(const s8_x& other);    
+       char operator[](int index) const;
+       char& operator[](int index);
+       
+       static s8_x upack(const s16_x& lhs, const s16_x& rhs);
+
+       static s16_x multiply_add(const u8_x& lhs, const s8_x& rhs);
+       static s8_x max(const s8_x& lhs, const s8_x& rhs);
+       static s8_x min(const s8_x& lhs, const s8_x& rhs);
+
+       static s8_x shuffle(const s8_x& lhs, const s8_x& rhs);
+       static s8_x blend(const s8_x& lhs, const s8_x& rhs, const s8_x& mask);
+};
+
+class u8_x : public base_x<u8_x>
+{
+       __m128i value_;
+private:
+       template<typename> friend class base_x;
+       friend class s32_x;
+       friend class s16_x;
+       friend class s8_x;
+public:
+       typedef u8_x xmm_epu_tag;
+
+       u8_x();
+       explicit u8_x(const s32_x& other);
+       explicit u8_x(const s16_x& other);
+       explicit u8_x(const s8_x& other);
+       u8_x(const __m128i& value);     
+       u8_x(char b);
+       u8_x(char b3,  char b2,  char b1,  char b0);
+       u8_x(char b15, char b14, char b13, char b12, 
+                char b11, char b10, char b9,  char b8,  
+                char b7,  char b6,  char b5,  char b4,  
+                char b3,  char b2,  char b1,  char b0);
+                                                                               
+       char operator[](int index) const;
+       char& operator[](int index);
+                       
+       static u8_x max(const u8_x& lhs, const u8_x& rhs);
+       static u8_x min(const u8_x& lhs, const u8_x& rhs);
+               
+       static u8_x shuffle(const u8_x& lhs, const u8_x& rhs);
+       static u8_x blend(const u8_x& lhs, const u8_x& rhs, const u8_x& mask);
+};
+
+// base_x
+
+template<typename T>
+template<typename temporal, typename alignment>
+T base_x<T>::load(const void* source)
+{ 
+       static_assert(temporal::value != nontemporal_tag::value, "streaming loads not supported");
+       if(alignment::value == aligned_tag::value)
+               return _mm_load_si128(reinterpret_cast<const __m128i*>(source));
+       else
+               return _mm_loadu_si128(reinterpret_cast<const __m128i*>(source));
+}
+       
+template<typename T>
+template<typename temporal, typename alignment>
+void base_x<T>::store(const T& source, void* dest)
+{
+       if(temporal::value == nontemporal_tag::value && alignment::value == aligned_tag::value)
+               _mm_stream_si128(reinterpret_cast<__m128i*>(dest), source.value_);
+       else if(alignment::value == aligned_tag::value)
+               _mm_store_si128(reinterpret_cast<__m128i*>(dest), source.value_);
+       else
+               _mm_storeu_si128(reinterpret_cast<__m128i*>(dest), source.value_);
+}
+
+template<typename T>
+T base_x<T>::zero()
+{
+       return _mm_setzero_si128();
+}
+
+// s32_x
+
+s32_x::s32_x()
+{
+}
+
+s32_x::s32_x(const s16_x& other)
+       : value_(other.value_)
+{
+}
+
+s32_x::s32_x(const s8_x& other)
+       : value_(other.value_)
+{
+}
+
+s32_x::s32_x(const u8_x& other)
+       : value_(other.value_)
+{
+}
+
+s32_x::s32_x(const __m128i& value)
+       : value_(value)
+{
+}
+       
+s32_x& s32_x::operator>>=(int count)
+{
+       value_ = _mm_srli_epi32(value_, count);
+       return *this;
+}
+       
+s32_x& s32_x::operator<<=(int count)
+{
+       value_ = _mm_slli_epi32(value_, count);
+       return *this;
+}
+               
+s32_x& s32_x::operator|=(const s32_x& other)
+{
+       value_ = _mm_or_si128(value_, other.value_);
+       return *this;
+}      
+       
+s32_x& s32_x::operator&=(const s32_x& other)
+{
+       value_ = _mm_and_si128(value_, other.value_);
+       return *this;
+}      
+               
+int32_t s32_x::operator[](int index) const
+{
+       return value_.m128i_i32[index];
+}
+
+int32_t& s32_x::operator[](int index)
+{
+       return value_.m128i_i32[index];
+}
+
+inline s32_x operator>>(const s32_x& lhs, int count)
+{              
+       return s32_x(lhs) >>= count;
+}
+
+inline s32_x operator<<(const s32_x& lhs, int count)
+{              
+       return s32_x(lhs) <<= count;
+}
+
+inline s32_x operator|(const s32_x& lhs, const s32_x& rhs)
+{              
+       return s32_x(lhs) |= rhs;
+}
+
+inline s32_x operator&(const s32_x& lhs, const s32_x& rhs)
+{              
+       return s32_x(lhs) &= rhs;
+}
+
+// s16_x
+
+s16_x::s16_x()
+{
+}
+
+s16_x::s16_x(const s32_x& other)
+       : value_(other.value_)
+{
+}
+
+s16_x::s16_x(const s8_x& other)
+       : value_(other.value_)
+{
+}
+
+s16_x::s16_x(const u8_x& other)
+       : value_(other.value_)
+{
+}
+
+s16_x::s16_x(const __m128i& value)
+       : value_(value)
+{
+}
+
+s16_x::s16_x(short value)
+       : value_(_mm_set1_epi16(value))
+{
+}
+
+s16_x& s16_x::operator+=(const s16_x& other)
+{
+       value_ = _mm_add_epi16(value_, other.value_);
+       return *this;
+}
+       
+s16_x& s16_x::operator-=(const s16_x& other)
+{
+       value_ = _mm_sub_epi16(value_, other.value_);
+       return *this;
+}
+
+s16_x& s16_x::operator>>=(int count)
+{
+       value_ = _mm_srli_epi16(value_, count);
+       return *this;
+}
+       
+s16_x& s16_x::operator<<=(int count)
+{
+       value_ = _mm_slli_epi16(value_, count);
+       return *this;
+}
+
+s16_x& s16_x::operator|=(const s16_x& other)
+{
+       value_ = _mm_or_si128(value_, other.value_);
+       return *this;
+}      
+       
+s16_x& s16_x::operator&=(const s16_x& other)
+{
+       value_ = _mm_and_si128(value_, other.value_);
+       return *this;
+}      
+                       
+int16_t s16_x::operator[](int index) const
+{
+       return value_.m128i_i16[index];
+}
+
+int16_t& s16_x::operator[](int index)
+{
+       return value_.m128i_i16[index];
+}
+
+s16_x s16_x::unpack_low(const s8_x& lhs, const s8_x& rhs)
+{
+       return _mm_unpacklo_epi8(rhs.value_, lhs.value_);
+}
+       
+s16_x s16_x::unpack_high(const s8_x& lhs, const s8_x& rhs)
+{
+       return _mm_unpackhi_epi8(rhs.value_, lhs.value_);
+}
+       
+s32_x s16_x::horizontal_add(const s16_x& lhs)
+{
+       #ifdef SSIM_XOP
+                       return _mm_haddd_epi16(value_);
+       #else
+                       return _mm_madd_epi16(lhs.value_, _mm_set1_epi16(1));
+       #endif
+}
+
+s16_x s16_x::multiply_low(const s16_x& lhs, const s16_x& rhs)
+{
+       return _mm_mullo_epi16(lhs.value_, rhs.value_);
+}
+
+s16_x s16_x::multiply_high(const s16_x& lhs, const s16_x& rhs)
+{
+       return _mm_mulhi_epi16(lhs.value_, rhs.value_);
+}
+
+s16_x s16_x::unpack_low(const s16_x& lhs, const s16_x& rhs)
+{
+       return _mm_unpacklo_epi16(lhs.value_, rhs.value_);
+}
+
+s16_x s16_x::unpack_high(const s16_x& lhs, const s16_x& rhs)
+{
+       return _mm_unpackhi_epi16(lhs.value_, rhs.value_);
+}
+       
+s16_x s16_x::and_not(const s16_x& lhs, const s16_x& rhs)
+{
+       return _mm_andnot_si128(lhs.value_, rhs.value_);
+}
+       
+s16_x s16_x::max(const s16_x& lhs, const s16_x& rhs)
+{
+       return _mm_max_epi16(lhs.value_, rhs.value_);
+}
+       
+s16_x s16_x::min(const s16_x& lhs, const s16_x& rhs)
+{
+       return _mm_min_epi16(lhs.value_, rhs.value_);
+}
+
+inline s16_x operator+(const s16_x& lhs, const s16_x& rhs)
+{
+       return s16_x(lhs) += rhs;
+}
+
+inline s16_x operator-(const s16_x& lhs, const s16_x& rhs)
+{
+       return s16_x(lhs) -= rhs;
+}
+
+inline s16_x operator>>(const s16_x& lhs, int count)
+{              
+       return s16_x(lhs) >>= count;
+}
+
+inline s16_x operator<<(const s16_x& lhs, int count)
+{              
+       return s16_x(lhs) <<= count;
+}
+
+inline s16_x operator|(const s16_x& lhs, const s16_x& rhs)
+{              
+       return s16_x(lhs) |= rhs;
+}
+
+inline s16_x operator&(const s16_x& lhs, const s16_x& rhs)
+{              
+       return s16_x(lhs) &= rhs;
+}
+
+// s8_x
+
+s8_x::s8_x()
+{
+}
+
+s8_x::s8_x(const s32_x& other)
+       : value_(other.value_)
+{
+}
+
+s8_x::s8_x(const s16_x& other)
+       : value_(other.value_)
+{
+}
+
+s8_x::s8_x(const u8_x& other)
+       : value_(other.value_)
+{
+}
+
+s8_x::s8_x(const __m128i& value)
+       : value_(value)
+{
+}      
+
+s8_x::s8_x(char b)
+       : value_(_mm_set1_epi8(b))
+{
+}
+
+s8_x::s8_x(char b3,  char b2,  char b1,  char b0)
+       : value_(_mm_set_epi8(b3, b2, b1, b0, b3, b2, b1, b0, b3, b2, b1, b0, b3, b2, b1, b0))
+{
+}
+
+s8_x::s8_x(char b15, char b14, char b13, char b12, 
+                  char b11, char b10, char b9,  char b8,  
+                  char b7,  char b6,  char b5,  char b4,  
+                  char b3,  char b2,  char b1,  char b0)
+       : value_(_mm_set_epi8(b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0))
+{
+}
+       
+s8_x& s8_x::operator+=(const s8_x& other)
+{
+       value_ = _mm_add_epi8(value_, other.value_);
+       return *this;
+}
+
+s8_x& s8_x::operator-=(const s8_x& other)
+{
+       value_ = _mm_sub_epi8(value_, other.value_);
+       return *this;
+}
+                                                                       
+char s8_x::operator[](int index) const
+{
+       return value_.m128i_i8[index];
+}
+
+char& s8_x::operator[](int index)
+{
+       return value_.m128i_i8[index];
+}
+       
+s8_x s8_x::upack(const s16_x& lhs, const s16_x& rhs)
+{
+       return _mm_packus_epi16(lhs.value_, rhs.value_);
+}
+
+s16_x s8_x::multiply_add(const u8_x& lhs, const s8_x& rhs)
+{              
+       return _mm_maddubs_epi16(lhs.value_, rhs.value_);
+}
+       
+s8_x s8_x::max(const s8_x& lhs, const s8_x& rhs)
+{              
+       return _mm_max_epi8(lhs.value_, rhs.value_);
+}
+       
+s8_x s8_x::min(const s8_x& lhs, const s8_x& rhs)
+{              
+       return _mm_min_epi8(lhs.value_, rhs.value_);
+}
+
+inline s8_x operator+(const s8_x& lhs, const s8_x& rhs)
+{
+       return s8_x(lhs) += rhs;
+}
+
+inline s8_x operator-(const s8_x& lhs, const s8_x& rhs)
+{
+       return s8_x(lhs) -= rhs;
+}
+       
+s8_x s8_x::shuffle(const s8_x& lhs, const s8_x& rhs)
+{              
+       return _mm_shuffle_epi8(lhs.value_, rhs.value_);
+}
+
+s8_x s8_x::blend(const s8_x& lhs, const s8_x& rhs, const s8_x& mask)
+{              
+       return _mm_blendv_epi8(lhs.value_, rhs.value_, mask.value_);
+}
+
+// u8_x
+
+u8_x::u8_x()
+{
+}
+
+u8_x::u8_x(const s32_x& other)
+       : value_(other.value_)
+{
+}
+
+u8_x::u8_x(const s16_x& other)
+       : value_(other.value_)
+{
+}
+
+u8_x::u8_x(const s8_x& other)
+       : value_(other.value_)
+{
+}
+
+u8_x::u8_x(const __m128i& value)
+       : value_(value)
+{
+}      
+
+u8_x::u8_x(char b)
+       : value_(_mm_set1_epi8(b))
+{
+}
+
+u8_x::u8_x(char b3,  char b2,  char b1,  char b0)
+       : value_(_mm_set_epi8(b3, b2, b1, b0, b3, b2, b1, b0, b3, b2, b1, b0, b3, b2, b1, b0))
+{
+}
+
+u8_x::u8_x(char b15, char b14, char b13, char b12, 
+                  char b11, char b10, char b9,  char b8,  
+                  char b7,  char b6,  char b5,  char b4,  
+                  char b3,  char b2,  char b1,  char b0)
+       : value_(_mm_set_epi8(b15, b14, b13, b12, b11, b10, b9, b8, b7, b6, b5, b4, b3, b2, b1, b0))
+{
+}
+                                                                               
+char u8_x::operator[](int index) const
+{
+       return value_.m128i_i8[index];
+}
+
+char& u8_x::operator[](int index)
+{
+       return value_.m128i_i8[index];
+}
+
+u8_x u8_x::max(const u8_x& lhs, const u8_x& rhs)
+{              
+       return _mm_max_epu8(lhs.value_, rhs.value_);
+}
+       
+u8_x u8_x::min(const u8_x& lhs, const u8_x& rhs)
+{              
+       return _mm_min_epu8(lhs.value_, rhs.value_);
+}
+
+u8_x u8_x::shuffle(const u8_x& lhs, const u8_x& rhs)
+{              
+       return _mm_shuffle_epi8(lhs.value_, rhs.value_);
+}
+
+u8_x u8_x::blend(const u8_x& lhs, const u8_x& rhs, const u8_x& mask)
+{              
+       return _mm_blendv_epi8(lhs.value_, rhs.value_, mask.value_);
+}
+
+// xmm_cast
+
+//template<typename T>
+//struct xmm_cast_impl
+//{            
+//     template<typename U>
+//     T operator()(const U& other)
+//     {
+//             return typename T::xmm_epi_tag(other.value_);
+//     }
+//};
+//
+//template<>
+//struct xmm_cast_impl<xmm_ps>
+//{
+//     xmm_ps operator()(const s32_x& other)
+//     {
+//             return _mm_cvtepi32_ps(other.value_);
+//     }
+//};
+//
+//template<typename T, typename U> 
+//T xmm_cast(const U& other)
+//{
+//     return xmm_cast_impl<T>()(other);
+//}
+
 }}}}
\ No newline at end of file
index aab2ae4faf92bb31f60f44fc98e2d9d62b5dbd74..7ccaf40e81f7b0b8f569323408eb89e1bd08a8b7 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-static std::string get_adjustement_glsl()\r
-{\r
-       return                                                                                                                                                                                                                                                                                                                                                                                                                                          \r
-               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** Contrast, saturation, brightness                                                                                                                                                                                                                                                                                                                                                              "\r
-               "\n     ** Code of this function is from TGM's shader pack                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057                                                                                                                                                                                                                                                                                                 "\r
-               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     vec3 ContrastSaturationBrightness(vec3 color, float brt, float sat, float con)                                                                                                                                                                                                                                                                     "\r
-               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             const float AvgLumR = 0.5;                                                                                                                                                                                                                                                                                                                                                                         "\r
-               "\n             const float AvgLumG = 0.5;                                                                                                                                                                                                                                                                                                                                                                         "\r
-               "\n             const float AvgLumB = 0.5;                                                                                                                                                                                                                                                                                                                                                                         "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n             const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n             vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);                                                                                                                                                                                                                                                                                                                           "\r
-               "\n             vec3 brtColor = color * brt;                                                                                                                                                                                                                                                                                                                                                               "\r
-               "\n             vec3 intensity = vec3(dot(brtColor, LumCoeff));                                                                                                                                                                                                                                                                                                                            "\r
-               "\n             vec3 satColor = mix(intensity, brtColor, sat);                                                                                                                                                                                                                                                                                                                             "\r
-               "\n             vec3 conColor = mix(AvgLumin, satColor, con);                                                                                                                                                                                                                                                                                                                              "\r
-               "\n             return conColor;                                                                                                                                                                                                                                                                                                                                                                                           "\r
-               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                       "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** Gamma correction                                                                                                                                                                                                                                                                                                                                                                                                     "\r
-               "\n     ** Details: http://blog.mouaif.org/2009/01/22/photoshop-gamma-correction-shader/                                                                                                                                                                                                                                                                   "\r
-               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n#define GammaCorrection(color, gamma)                                                                pow(color, vec3(1.0 / gamma))                           \n                                                                                                                                                                                                      "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** Levels control (input (+gamma), output)                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** Details: http://blog.mouaif.org/2009/01/28/levels-control-shader/                                                                                                                                                                                                                                                                                       "\r
-               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n#define LevelsControlInputRange(color, minInput, maxInput)                           min(max(color - vec3(minInput), vec3(0.0)) / (vec3(maxInput) - vec3(minInput)), vec3(1.0))              \n                                                                                 "\r
-               "\n#define LevelsControlInput(color, minInput, gamma, maxInput)                         GammaCorrection(LevelsControlInputRange(color, minInput, maxInput), gamma)                                      \n                                                                                              "       \r
-               "\n#define LevelsControlOutputRange(color, minOutput, maxOutput)                        mix(vec3(minOutput), vec3(maxOutput), color)                                                                                                                    \n                                                                 "\r
-               "\n#define LevelsControl(color, minInput, gamma, maxInput, minOutput, maxOutput)        LevelsControlOutputRange(LevelsControlInput(color, minInput, gamma, maxInput), minOutput, maxOutput)    \n                                                      "\r
-               ;\r
-}\r
-\r
-static std::string get_blend_glsl()\r
-{\r
-       static std::string glsl = \r
-               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** Photoshop & misc math                                                                                                                                                                                                                                                                                                                                                                                   "\r
-               "\n     ** Blending modes, RGB/HSL/Contrast/Desaturate, levels control                                                                                                                                                                                                                                                                                                     "\r
-               "\n     **                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** Romain Dura | Romz                                                                                                                                                                                                                                                                                                                                                                                      "\r
-               "\n     ** Blog: http://blog.mouaif.org                                                                                                                                                                                                                                                                                                                                                            "\r
-               "\n     ** Post: http://blog.mouaif.org/?p=94                                                                                                                                                                                                                                                                                                                                                      "\r
-               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** Desaturation                                                                                                                                                                                                                                                                                                                                                                                            "\r
-               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     vec4 Desaturate(vec3 color, float Desaturation)                                                                                                                                                                                                                                                                                                                            "\r
-               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             vec3 grayXfer = vec3(0.3, 0.59, 0.11);                                                                                                                                                                                                                                                                                                                                             "\r
-               "\n             vec3 gray = vec3(dot(grayXfer, color));                                                                                                                                                                                                                                                                                                                                            "\r
-               "\n             return vec4(mix(color, gray, Desaturation), 1.0);                                                                                                                                                                                                                                                                                                                          "\r
-               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** Hue, saturation, luminance                                                                                                                                                                                                                                                                                                                                                                      "\r
-               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     vec3 RGBToHSL(vec3 color)                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             vec3 hsl;                                                                                                                                                                                                                                                          "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n             float fmin = min(min(color.r, color.g), color.b);                                                                                                                                                                                                                                                                  "\r
-               "\n             float fmax = max(max(color.r, color.g), color.b);                                                                                                                                                                                                                                                                  "\r
-               "\n             float delta = fmax - fmin;                                                                                                                                                                                                                                                                                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n             hsl.z = (fmax + fmin) / 2.0;                                                                                                                                                                                                                                                                                                                       "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n             if (delta == 0.0)                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             {                                                                                                                                                                                                                                                                                                                                                                                                                          "\r
-               "\n                     hsl.x = 0.0;                                                                                                                                                                                                                                                                                                                                                               "\r
-               "\n                     hsl.y = 0.0;                                                                                                                                                                                                                                                                                                                                                       "\r
-               "\n             }                                                                                                                                                                                                                                                                                                                                                                                                                          "\r
-               "\n             else                                                                                                                                                                                                                                                                                                                       "\r
-               "\n             {                                                                                                                                                                                                                                                                                                                                                                                                                          "\r
-               "\n                     if (hsl.z < 0.5)                                                                                                                                                                                                                                                                                                                                                                                   "\r
-               "\n                             hsl.y = delta / (fmax + fmin);                                                                                                                                                                                                                                                                                             "\r
-               "\n                     else                                                                                                                                                                                                                                                                                                                                                                                                       "\r
-               "\n                             hsl.y = delta / (2.0 - fmax - fmin);                                                                                                                                                                                                                                                                                               "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                     float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;                                                                                                                                                                                                                                                                                 "\r
-               "\n                     float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;                                                                                                                                                                                                                                                                                 "\r
-               "\n                     float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;                                                                                                                                                                                                                                                                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                     if (color.r == fmax )                                                                                                                                                                                                                                                                                                                                                                      "\r
-               "\n                             hsl.x = deltaB - deltaG;                                                                                                                                                                                                                                                                                                                                   "\r
-               "\n                     else if (color.g == fmax)                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                             hsl.x = (1.0 / 3.0) + deltaR - deltaB;                                                                                                                                                                                                                                                                                                     "\r
-               "\n                     else if (color.b == fmax)                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                             hsl.x = (2.0 / 3.0) + deltaG - deltaR;                                                                                                                                                                                                                                                                                                     "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                     if (hsl.x < 0.0)                                                                                                                                                                                                                                                                                                                                                                                   "\r
-               "\n                             hsl.x += 1.0;                                                                                                                                                                                                                                                                                                                                                      "\r
-               "\n                     else if (hsl.x > 1.0)                                                                                                                                                                                                                                                                                                                                                                      "\r
-               "\n                             hsl.x -= 1.0;                                                                                                                                                                                                                                                                                                                                                      "\r
-               "\n             }                                                                                                                                                                                                                                                                                                                                                                                                                          "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n             return hsl;                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     float HueToRGB(float f1, float f2, float hue)                                                                                                                                                                                                                                                                                                                                      "\r
-               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             if (hue < 0.0)                                                                                                                                                                                                                                                                                                                                                                                             "\r
-               "\n                     hue += 1.0;                                                                                                                                                                                                                                                                                                                                                                                                "\r
-               "\n             else if (hue > 1.0)                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                     hue -= 1.0;                                                                                                                                                                                                                                                                                                                                                                                                "\r
-               "\n             float res;                                                                                                                                                                                                                                                                                                                                                                                                         "\r
-               "\n             if ((6.0 * hue) < 1.0)                                                                                                                                                                                                                                                                                                                                                                             "\r
-               "\n                     res = f1 + (f2 - f1) * 6.0 * hue;                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             else if ((2.0 * hue) < 1.0)                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                     res = f2;                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             else if ((3.0 * hue) < 2.0)                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                     res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             else                                                                                                                                                                                                                                                                                                                                                                                                               "\r
-               "\n                     res = f1;                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             return res;                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     vec3 HSLToRGB(vec3 hsl)                                                                                                                                                                                                                                                                                                                                                                            "\r
-               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             vec3 rgb;                                                                                                                                                                                                                                                                                                                                                                                                          "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n             if (hsl.y == 0.0)                                                                                                                                                                                                                                                                                                                                                                                          "\r
-               "\n                     rgb = vec3(hsl.z);                                                                                                                                                                                                                                                                                                                                         "\r
-               "\n             else                                                                                                                                                                                                                                                                                                                                                                                                               "\r
-               "\n             {                                                                                                                                                                                                                                                                                                                                                                                                                          "\r
-               "\n                     float f2;                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                     if (hsl.z < 0.5)                                                                                                                                                                                                                                                                                                                                                                                   "\r
-               "\n                             f2 = hsl.z * (1.0 + hsl.y);                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                     else                                                                                                                                                                                                                                                                                                                                                                                                       "\r
-               "\n                             f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);                                                                                                                                                                                                                                                                                                                            "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                     float f1 = 2.0 * hsl.z - f2;                                                                                                                                                                                                                                                                                                                                                       "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                     rgb.r = HueToRGB(f1, f2, hsl.x + (1.0/3.0));                                                                                                                                                                                                                                                                                                                       "\r
-               "\n                     rgb.g = HueToRGB(f1, f2, hsl.x);                                                                                                                                                                                                                                                                                                                                                   "\r
-               "\n                     rgb.b= HueToRGB(f1, f2, hsl.x - (1.0/3.0));                                                                                                                                                                                                                                                                                                                                "\r
-               "\n             }                                                                                                                                                                                                                                                                                                                                                                                                                          "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n             return rgb;                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                                "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** Float blending modes                                                                                                                                                                                                                                                                                                                                                                            "\r
-               "\n     ** Adapted from here: http://www.nathanm.com/photoshop-blending-math/                                                                                                                                                                                                                                                                                      "\r
-               "\n     ** But I modified the HardMix (wrong condition), Overlay, SoftLight, ColorDodge, ColorBurn, VividLight, PinLight (inverted layers) ones to have correct results                                                                                            "\r
-               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                             \n                                         "\r
-               "\n#define BlendLinearDodgef                                    BlendAddf                                                                                                                                                                                                                                                                               \n                                                 "\r
-               "\n#define BlendLinearBurnf                                     BlendSubstractf                                                                                                                                                                                                                                                                 \n                                                 "\r
-               "\n#define BlendAddf(base, blend)                               min(base + blend, 1.0)                                                                                                                                                                                                                                                  \n                                         "\r
-               "\n#define BlendSubstractf(base, blend)                 max(base + blend - 1.0, 0.0)                                                                                                                                                                                                                                    \n                                                 "\r
-               "\n#define BlendLightenf(base, blend)           max(blend, base)                                                                                                                                                                                                                                                                        \n                                 "\r
-               "\n#define BlendDarkenf(base, blend)                    min(blend, base)                                                                                                                                                                                                                                                                \n                                                 "\r
-               "\n#define BlendLinearLightf(base, blend)       (blend < 0.5 ? BlendLinearBurnf(base, (2.0 * blend)) : BlendLinearDodgef(base, (2.0 * (blend - 0.5))))                                                                                          \n                                 "\r
-               "\n#define BlendScreenf(base, blend)                    (1.0 - ((1.0 - base) * (1.0 - blend)))                                                                                                                                                                                                                  \n                                                 "\r
-               "\n#define BlendOverlayf(base, blend)           (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)))                                                                                                                                        \n                                         "\r
-               "\n#define BlendSoftLightf(base, blend)                 ((blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend)))    \n                                                 "\r
-               "\n#define BlendColorDodgef(base, blend)                ((blend == 1.0) ? blend : min(base / (1.0 - blend), 1.0))                                                                                                                                                                               \n                                                 "\r
-               "\n#define BlendColorBurnf(base, blend)                 ((blend == 0.0) ? blend : max((1.0 - ((1.0 - base) / blend)), 0.0))                                                                                                                                                             \n                                                 "\r
-               "\n#define BlendVividLightf(base, blend)                ((blend < 0.5) ? BlendColorBurnf(base, (2.0 * blend)) : BlendColorDodgef(base, (2.0 * (blend - 0.5))))                                                                                  \n                                                 "\r
-               "\n#define BlendPinLightf(base, blend)          ((blend < 0.5) ? BlendDarkenf(base, (2.0 * blend)) : BlendLightenf(base, (2.0 *(blend - 0.5))))                                                                                                         \n                                         "\r
-               "\n#define BlendHardMixf(base, blend)           ((BlendVividLightf(base, blend) < 0.5) ? 0.0 : 1.0)                                                                                                                                                                                                     \n                                         "\r
-               "\n#define BlendReflectf(base, blend)           ((blend == 1.0) ? blend : min(base * base / (1.0 - blend), 1.0))                                                                                                                                                                        \n                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n     ** Vector3 blending modes                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n#define Blend(base, blend, funcf)                    vec3(funcf(base.r, blend.r), funcf(base.g, blend.g), funcf(base.b, blend.b))                            \n                                                                                                                                                         "\r
-               "\n                                                                                                                                                                                                                                                                                     \n                                                                                                                                                 "\r
-               "\n#define BlendNormal(base, blend)                     (blend)                                                                                                                                                                         \n                                                                                                                                                         "\r
-               "\n#define BlendLighten                                         BlendLightenf                                                                                                                                                                   \n                                                                                                                                                         "\r
-               "\n#define BlendDarken                                          BlendDarkenf                                                                                                                                                                    \n                                                                                                                                                         "\r
-               "\n#define BlendMultiply(base, blend)           (base * blend)                                                                                                                                                                  \n                                                                                                                                         "\r
-               "\n#define BlendAverage(base, blend)                    ((base + blend) / 2.0)                                                                                                                                          \n                                                                                                                                                         "\r
-               "\n#define BlendAdd(base, blend)                                min(base + blend, vec3(1.0))                                                                                                                            \n                                                                                                                                                                 "\r
-               "\n#define BlendSubstract(base, blend)          max(base + blend - vec3(1.0), vec3(0.0))                                                                                                                \n                                                                                                                                                 "\r
-               "\n#define BlendDifference(base, blend)                 abs(base - blend)                                                                                                                                                       \n                                                                                                                                                         "\r
-               "\n#define BlendNegation(base, blend)           (vec3(1.0) - abs(vec3(1.0) - base - blend))                                                                                                             \n                                                                                                                                                 "\r
-               "\n#define BlendExclusion(base, blend)          (base + blend - 2.0 * base * blend)                                                                                                                             \n                                                                                                                                                 "\r
-               "\n#define BlendScreen(base, blend)                     Blend(base, blend, BlendScreenf)                                                                                                                        \n                                                                                                                                                         "\r
-               "\n#define BlendOverlay(base, blend)                    Blend(base, blend, BlendOverlayf)                                                                                                                       \n                                                                                                                                                         "\r
-               "\n#define BlendSoftLight(base, blend)          Blend(base, blend, BlendSoftLightf)                                                                                                                             \n                                                                                                                                                 "\r
-               "\n#define BlendHardLight(base, blend)          BlendOverlay(blend, base)                                                                                                                                               \n                                                                                                                                                 "\r
-               "\n#define BlendColorDodge(base, blend)                 Blend(base, blend, BlendColorDodgef)                                                                                                            \n                                                                                                                                                         "\r
-               "\n#define BlendColorBurn(base, blend)          Blend(base, blend, BlendColorBurnf)                                                                                                                             \n                                                                                                                                                 "\r
-               "\n#define BlendLinearDodge                                     BlendAdd                                                                                                                                                                                \n                                                                                                                                                         "\r
-               "\n#define BlendLinearBurn                                      BlendSubstract                                                                                                                                                                  \n                                                                                                                                                         "\r
-               "\n#define BlendLinearLight(base, blend)                Blend(base, blend, BlendLinearLightf)                                                                                                           \n                                                                                                                                                         "\r
-               "\n#define BlendVividLight(base, blend)                 Blend(base, blend, BlendVividLightf)                                                                                                            \n                                                                                                                                                         "\r
-               "\n#define BlendPinLight(base, blend)           Blend(base, blend, BlendPinLightf)                                                                                                                              \n                                                                                                                                         "\r
-               "\n#define BlendHardMix(base, blend)                    Blend(base, blend, BlendHardMixf)                                                                                                                       \n                                                                                                                                                         "\r
-               "\n#define BlendReflect(base, blend)                    Blend(base, blend, BlendReflectf)                                                                                                                       \n                                                                                                                                                         "\r
-               "\n#define BlendGlow(base, blend)                       BlendReflect(blend, base)                                                                                                                                               \n                                                                                                                                                 "\r
-               "\n#define BlendPhoenix(base, blend)                    (min(base, blend) - max(base, blend) + vec3(1.0))                                                                                       \n                                                                                                                                                         "\r
-               "\n#define BlendOpacity(base, blend, F, O)      (F(base, blend) * O + blend * (1.0 - O))                                                                                                                \n                                                                                                                                                         "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     vec3 BlendHue(vec3 base, vec3 blend)                                                                                                                                                                                                                                                                                                                                                       "\r
-               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             vec3 baseHSL = RGBToHSL(base);                                                                                                                                                                                                                                                                                                                                                             "\r
-               "\n             return HSLToRGB(vec3(RGBToHSL(blend).r, baseHSL.g, baseHSL.b));                                                                                                                                                                                                                                                                                            "\r
-               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     vec3 BlendSaturation(vec3 base, vec3 blend)                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             vec3 baseHSL = RGBToHSL(base);                                                                                                                                                                                                                                                                                                                                                             "\r
-               "\n             return HSLToRGB(vec3(baseHSL.r, RGBToHSL(blend).g, baseHSL.b));                                                                                                                                                                                                                                                                                            "\r
-               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     vec3 BlendColor(vec3 base, vec3 blend)                                                                                                                                                                                                                                                                                                                                                     "\r
-               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             vec3 blendHSL = RGBToHSL(blend);                                                                                                                                                                                                                                                                                                                                                           "\r
-               "\n             return HSLToRGB(vec3(blendHSL.r, blendHSL.g, RGBToHSL(base).b));                                                                                                                                                                                                                                                                                           "\r
-               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     vec3 BlendLuminosity(vec3 base, vec3 blend)                                                                                                                                                                                                                                                                                                                                        "\r
-               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n             vec3 baseHSL = RGBToHSL(base);                                                                                                                                                                                                                                                                                                                                                             "\r
-               "\n             return HSLToRGB(vec3(baseHSL.r, baseHSL.g, RGBToHSL(blend).b));                                                                                                                                                                                                                                                                                            "\r
-               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "\r
-               "\n                                                                                                                                                                                                                                                                                                                                                                                                        "\r
-               ;\r
-                                                                                                                                                                                                                                                                                                                                                                                                                                                  \r
-               return glsl;\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+static std::string get_adjustement_glsl()
+{
+       return                                                                                                                                                                                                                                                                                                                                                                                                                                          
+               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** Contrast, saturation, brightness                                                                                                                                                                                                                                                                                                                                                              "
+               "\n     ** Code of this function is from TGM's shader pack                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057                                                                                                                                                                                                                                                                                                 "
+               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     vec3 ContrastSaturationBrightness(vec3 color, float brt, float sat, float con)                                                                                                                                                                                                                                                                     "
+               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             const float AvgLumR = 0.5;                                                                                                                                                                                                                                                                                                                                                                         "
+               "\n             const float AvgLumG = 0.5;                                                                                                                                                                                                                                                                                                                                                                         "
+               "\n             const float AvgLumB = 0.5;                                                                                                                                                                                                                                                                                                                                                                         "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n             const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);                                                                                                                                                                                                                                                                                                                        "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n             vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);                                                                                                                                                                                                                                                                                                                           "
+               "\n             vec3 brtColor = color * brt;                                                                                                                                                                                                                                                                                                                                                               "
+               "\n             vec3 intensity = vec3(dot(brtColor, LumCoeff));                                                                                                                                                                                                                                                                                                                            "
+               "\n             vec3 satColor = mix(intensity, brtColor, sat);                                                                                                                                                                                                                                                                                                                             "
+               "\n             vec3 conColor = mix(AvgLumin, satColor, con);                                                                                                                                                                                                                                                                                                                              "
+               "\n             return conColor;                                                                                                                                                                                                                                                                                                                                                                                           "
+               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                       "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** Gamma correction                                                                                                                                                                                                                                                                                                                                                                                                     "
+               "\n     ** Details: http://blog.mouaif.org/2009/01/22/photoshop-gamma-correction-shader/                                                                                                                                                                                                                                                                   "
+               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n#define GammaCorrection(color, gamma)                                                                pow(color, vec3(1.0 / gamma))                           \n                                                                                                                                                                                                      "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** Levels control (input (+gamma), output)                                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** Details: http://blog.mouaif.org/2009/01/28/levels-control-shader/                                                                                                                                                                                                                                                                                       "
+               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n#define LevelsControlInputRange(color, minInput, maxInput)                           min(max(color - vec3(minInput), vec3(0.0)) / (vec3(maxInput) - vec3(minInput)), vec3(1.0))              \n                                                                                 "
+               "\n#define LevelsControlInput(color, minInput, gamma, maxInput)                         GammaCorrection(LevelsControlInputRange(color, minInput, maxInput), gamma)                                      \n                                                                                              "       
+               "\n#define LevelsControlOutputRange(color, minOutput, maxOutput)                        mix(vec3(minOutput), vec3(maxOutput), color)                                                                                                                    \n                                                                 "
+               "\n#define LevelsControl(color, minInput, gamma, maxInput, minOutput, maxOutput)        LevelsControlOutputRange(LevelsControlInput(color, minInput, gamma, maxInput), minOutput, maxOutput)    \n                                                      "
+               ;
+}
+
+static std::string get_blend_glsl()
+{
+       static std::string glsl = 
+               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** Photoshop & misc math                                                                                                                                                                                                                                                                                                                                                                                   "
+               "\n     ** Blending modes, RGB/HSL/Contrast/Desaturate, levels control                                                                                                                                                                                                                                                                                                     "
+               "\n     **                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** Romain Dura | Romz                                                                                                                                                                                                                                                                                                                                                                                      "
+               "\n     ** Blog: http://blog.mouaif.org                                                                                                                                                                                                                                                                                                                                                            "
+               "\n     ** Post: http://blog.mouaif.org/?p=94                                                                                                                                                                                                                                                                                                                                                      "
+               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** Desaturation                                                                                                                                                                                                                                                                                                                                                                                            "
+               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     vec4 Desaturate(vec3 color, float Desaturation)                                                                                                                                                                                                                                                                                                                            "
+               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             vec3 grayXfer = vec3(0.3, 0.59, 0.11);                                                                                                                                                                                                                                                                                                                                             "
+               "\n             vec3 gray = vec3(dot(grayXfer, color));                                                                                                                                                                                                                                                                                                                                            "
+               "\n             return vec4(mix(color, gray, Desaturation), 1.0);                                                                                                                                                                                                                                                                                                                          "
+               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** Hue, saturation, luminance                                                                                                                                                                                                                                                                                                                                                                      "
+               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     vec3 RGBToHSL(vec3 color)                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             vec3 hsl;                                                                                                                                                                                                                                                          "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n             float fmin = min(min(color.r, color.g), color.b);                                                                                                                                                                                                                                                                  "
+               "\n             float fmax = max(max(color.r, color.g), color.b);                                                                                                                                                                                                                                                                  "
+               "\n             float delta = fmax - fmin;                                                                                                                                                                                                                                                                                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n             hsl.z = (fmax + fmin) / 2.0;                                                                                                                                                                                                                                                                                                                       "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n             if (delta == 0.0)                                                                                                                                                                                                                                                                                                                  "
+               "\n             {                                                                                                                                                                                                                                                                                                                                                                                                                          "
+               "\n                     hsl.x = 0.0;                                                                                                                                                                                                                                                                                                                                                               "
+               "\n                     hsl.y = 0.0;                                                                                                                                                                                                                                                                                                                                                       "
+               "\n             }                                                                                                                                                                                                                                                                                                                                                                                                                          "
+               "\n             else                                                                                                                                                                                                                                                                                                                       "
+               "\n             {                                                                                                                                                                                                                                                                                                                                                                                                                          "
+               "\n                     if (hsl.z < 0.5)                                                                                                                                                                                                                                                                                                                                                                                   "
+               "\n                             hsl.y = delta / (fmax + fmin);                                                                                                                                                                                                                                                                                             "
+               "\n                     else                                                                                                                                                                                                                                                                                                                                                                                                       "
+               "\n                             hsl.y = delta / (2.0 - fmax - fmin);                                                                                                                                                                                                                                                                                               "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                     float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;                                                                                                                                                                                                                                                                                 "
+               "\n                     float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;                                                                                                                                                                                                                                                                                 "
+               "\n                     float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;                                                                                                                                                                                                                                                                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                     if (color.r == fmax )                                                                                                                                                                                                                                                                                                                                                                      "
+               "\n                             hsl.x = deltaB - deltaG;                                                                                                                                                                                                                                                                                                                                   "
+               "\n                     else if (color.g == fmax)                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                             hsl.x = (1.0 / 3.0) + deltaR - deltaB;                                                                                                                                                                                                                                                                                                     "
+               "\n                     else if (color.b == fmax)                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                             hsl.x = (2.0 / 3.0) + deltaG - deltaR;                                                                                                                                                                                                                                                                                                     "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                     if (hsl.x < 0.0)                                                                                                                                                                                                                                                                                                                                                                                   "
+               "\n                             hsl.x += 1.0;                                                                                                                                                                                                                                                                                                                                                      "
+               "\n                     else if (hsl.x > 1.0)                                                                                                                                                                                                                                                                                                                                                                      "
+               "\n                             hsl.x -= 1.0;                                                                                                                                                                                                                                                                                                                                                      "
+               "\n             }                                                                                                                                                                                                                                                                                                                                                                                                                          "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n             return hsl;                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     float HueToRGB(float f1, float f2, float hue)                                                                                                                                                                                                                                                                                                                                      "
+               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             if (hue < 0.0)                                                                                                                                                                                                                                                                                                                                                                                             "
+               "\n                     hue += 1.0;                                                                                                                                                                                                                                                                                                                                                                                                "
+               "\n             else if (hue > 1.0)                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                     hue -= 1.0;                                                                                                                                                                                                                                                                                                                                                                                                "
+               "\n             float res;                                                                                                                                                                                                                                                                                                                                                                                                         "
+               "\n             if ((6.0 * hue) < 1.0)                                                                                                                                                                                                                                                                                                                                                                             "
+               "\n                     res = f1 + (f2 - f1) * 6.0 * hue;                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             else if ((2.0 * hue) < 1.0)                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                     res = f2;                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             else if ((3.0 * hue) < 2.0)                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                     res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;                                                                                                                                                                                                                                                                                                                  "
+               "\n             else                                                                                                                                                                                                                                                                                                                                                                                                               "
+               "\n                     res = f1;                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             return res;                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     vec3 HSLToRGB(vec3 hsl)                                                                                                                                                                                                                                                                                                                                                                            "
+               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             vec3 rgb;                                                                                                                                                                                                                                                                                                                                                                                                          "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n             if (hsl.y == 0.0)                                                                                                                                                                                                                                                                                                                                                                                          "
+               "\n                     rgb = vec3(hsl.z);                                                                                                                                                                                                                                                                                                                                         "
+               "\n             else                                                                                                                                                                                                                                                                                                                                                                                                               "
+               "\n             {                                                                                                                                                                                                                                                                                                                                                                                                                          "
+               "\n                     float f2;                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                     if (hsl.z < 0.5)                                                                                                                                                                                                                                                                                                                                                                                   "
+               "\n                             f2 = hsl.z * (1.0 + hsl.y);                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                     else                                                                                                                                                                                                                                                                                                                                                                                                       "
+               "\n                             f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);                                                                                                                                                                                                                                                                                                                            "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                     float f1 = 2.0 * hsl.z - f2;                                                                                                                                                                                                                                                                                                                                                       "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                     rgb.r = HueToRGB(f1, f2, hsl.x + (1.0/3.0));                                                                                                                                                                                                                                                                                                                       "
+               "\n                     rgb.g = HueToRGB(f1, f2, hsl.x);                                                                                                                                                                                                                                                                                                                                                   "
+               "\n                     rgb.b= HueToRGB(f1, f2, hsl.x - (1.0/3.0));                                                                                                                                                                                                                                                                                                                                "
+               "\n             }                                                                                                                                                                                                                                                                                                                                                                                                                          "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n             return rgb;                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                                "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** Float blending modes                                                                                                                                                                                                                                                                                                                                                                            "
+               "\n     ** Adapted from here: http://www.nathanm.com/photoshop-blending-math/                                                                                                                                                                                                                                                                                      "
+               "\n     ** But I modified the HardMix (wrong condition), Overlay, SoftLight, ColorDodge, ColorBurn, VividLight, PinLight (inverted layers) ones to have correct results                                                                                            "
+               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                             \n                                         "
+               "\n#define BlendLinearDodgef                                    BlendAddf                                                                                                                                                                                                                                                                               \n                                                 "
+               "\n#define BlendLinearBurnf                                     BlendSubstractf                                                                                                                                                                                                                                                                 \n                                                 "
+               "\n#define BlendAddf(base, blend)                               min(base + blend, 1.0)                                                                                                                                                                                                                                                  \n                                         "
+               "\n#define BlendSubstractf(base, blend)                 max(base + blend - 1.0, 0.0)                                                                                                                                                                                                                                    \n                                                 "
+               "\n#define BlendLightenf(base, blend)           max(blend, base)                                                                                                                                                                                                                                                                        \n                                 "
+               "\n#define BlendDarkenf(base, blend)                    min(blend, base)                                                                                                                                                                                                                                                                \n                                                 "
+               "\n#define BlendLinearLightf(base, blend)       (blend < 0.5 ? BlendLinearBurnf(base, (2.0 * blend)) : BlendLinearDodgef(base, (2.0 * (blend - 0.5))))                                                                                          \n                                 "
+               "\n#define BlendScreenf(base, blend)                    (1.0 - ((1.0 - base) * (1.0 - blend)))                                                                                                                                                                                                                  \n                                                 "
+               "\n#define BlendOverlayf(base, blend)           (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)))                                                                                                                                        \n                                         "
+               "\n#define BlendSoftLightf(base, blend)                 ((blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend)))    \n                                                 "
+               "\n#define BlendColorDodgef(base, blend)                ((blend == 1.0) ? blend : min(base / (1.0 - blend), 1.0))                                                                                                                                                                               \n                                                 "
+               "\n#define BlendColorBurnf(base, blend)                 ((blend == 0.0) ? blend : max((1.0 - ((1.0 - base) / blend)), 0.0))                                                                                                                                                             \n                                                 "
+               "\n#define BlendVividLightf(base, blend)                ((blend < 0.5) ? BlendColorBurnf(base, (2.0 * blend)) : BlendColorDodgef(base, (2.0 * (blend - 0.5))))                                                                                  \n                                                 "
+               "\n#define BlendPinLightf(base, blend)          ((blend < 0.5) ? BlendDarkenf(base, (2.0 * blend)) : BlendLightenf(base, (2.0 *(blend - 0.5))))                                                                                                         \n                                         "
+               "\n#define BlendHardMixf(base, blend)           ((BlendVividLightf(base, blend) < 0.5) ? 0.0 : 1.0)                                                                                                                                                                                                     \n                                         "
+               "\n#define BlendReflectf(base, blend)           ((blend == 1.0) ? blend : min(base * base / (1.0 - blend), 1.0))                                                                                                                                                                        \n                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     /*                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n     ** Vector3 blending modes                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n     */                                                                                                                                                                                                                                                                                                                                                                                                                                 "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n#define Blend(base, blend, funcf)                    vec3(funcf(base.r, blend.r), funcf(base.g, blend.g), funcf(base.b, blend.b))                            \n                                                                                                                                                         "
+               "\n                                                                                                                                                                                                                                                                                     \n                                                                                                                                                 "
+               "\n#define BlendNormal(base, blend)                     (blend)                                                                                                                                                                         \n                                                                                                                                                         "
+               "\n#define BlendLighten                                         BlendLightenf                                                                                                                                                                   \n                                                                                                                                                         "
+               "\n#define BlendDarken                                          BlendDarkenf                                                                                                                                                                    \n                                                                                                                                                         "
+               "\n#define BlendMultiply(base, blend)           (base * blend)                                                                                                                                                                  \n                                                                                                                                         "
+               "\n#define BlendAverage(base, blend)                    ((base + blend) / 2.0)                                                                                                                                          \n                                                                                                                                                         "
+               "\n#define BlendAdd(base, blend)                                min(base + blend, vec3(1.0))                                                                                                                            \n                                                                                                                                                                 "
+               "\n#define BlendSubstract(base, blend)          max(base + blend - vec3(1.0), vec3(0.0))                                                                                                                \n                                                                                                                                                 "
+               "\n#define BlendDifference(base, blend)                 abs(base - blend)                                                                                                                                                       \n                                                                                                                                                         "
+               "\n#define BlendNegation(base, blend)           (vec3(1.0) - abs(vec3(1.0) - base - blend))                                                                                                             \n                                                                                                                                                 "
+               "\n#define BlendExclusion(base, blend)          (base + blend - 2.0 * base * blend)                                                                                                                             \n                                                                                                                                                 "
+               "\n#define BlendScreen(base, blend)                     Blend(base, blend, BlendScreenf)                                                                                                                        \n                                                                                                                                                         "
+               "\n#define BlendOverlay(base, blend)                    Blend(base, blend, BlendOverlayf)                                                                                                                       \n                                                                                                                                                         "
+               "\n#define BlendSoftLight(base, blend)          Blend(base, blend, BlendSoftLightf)                                                                                                                             \n                                                                                                                                                 "
+               "\n#define BlendHardLight(base, blend)          BlendOverlay(blend, base)                                                                                                                                               \n                                                                                                                                                 "
+               "\n#define BlendColorDodge(base, blend)                 Blend(base, blend, BlendColorDodgef)                                                                                                            \n                                                                                                                                                         "
+               "\n#define BlendColorBurn(base, blend)          Blend(base, blend, BlendColorBurnf)                                                                                                                             \n                                                                                                                                                 "
+               "\n#define BlendLinearDodge                                     BlendAdd                                                                                                                                                                                \n                                                                                                                                                         "
+               "\n#define BlendLinearBurn                                      BlendSubstract                                                                                                                                                                  \n                                                                                                                                                         "
+               "\n#define BlendLinearLight(base, blend)                Blend(base, blend, BlendLinearLightf)                                                                                                           \n                                                                                                                                                         "
+               "\n#define BlendVividLight(base, blend)                 Blend(base, blend, BlendVividLightf)                                                                                                            \n                                                                                                                                                         "
+               "\n#define BlendPinLight(base, blend)           Blend(base, blend, BlendPinLightf)                                                                                                                              \n                                                                                                                                         "
+               "\n#define BlendHardMix(base, blend)                    Blend(base, blend, BlendHardMixf)                                                                                                                       \n                                                                                                                                                         "
+               "\n#define BlendReflect(base, blend)                    Blend(base, blend, BlendReflectf)                                                                                                                       \n                                                                                                                                                         "
+               "\n#define BlendGlow(base, blend)                       BlendReflect(blend, base)                                                                                                                                               \n                                                                                                                                                 "
+               "\n#define BlendPhoenix(base, blend)                    (min(base, blend) - max(base, blend) + vec3(1.0))                                                                                       \n                                                                                                                                                         "
+               "\n#define BlendOpacity(base, blend, F, O)      (F(base, blend) * O + blend * (1.0 - O))                                                                                                                \n                                                                                                                                                         "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     vec3 BlendHue(vec3 base, vec3 blend)                                                                                                                                                                                                                                                                                                                                                       "
+               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             vec3 baseHSL = RGBToHSL(base);                                                                                                                                                                                                                                                                                                                                                             "
+               "\n             return HSLToRGB(vec3(RGBToHSL(blend).r, baseHSL.g, baseHSL.b));                                                                                                                                                                                                                                                                                            "
+               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     vec3 BlendSaturation(vec3 base, vec3 blend)                                                                                                                                                                                                                                                                                                                                        "
+               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             vec3 baseHSL = RGBToHSL(base);                                                                                                                                                                                                                                                                                                                                                             "
+               "\n             return HSLToRGB(vec3(baseHSL.r, RGBToHSL(blend).g, baseHSL.b));                                                                                                                                                                                                                                                                                            "
+               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     vec3 BlendColor(vec3 base, vec3 blend)                                                                                                                                                                                                                                                                                                                                                     "
+               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             vec3 blendHSL = RGBToHSL(blend);                                                                                                                                                                                                                                                                                                                                                           "
+               "\n             return HSLToRGB(vec3(blendHSL.r, blendHSL.g, RGBToHSL(base).b));                                                                                                                                                                                                                                                                                           "
+               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                                                        "
+               "\n     vec3 BlendLuminosity(vec3 base, vec3 blend)                                                                                                                                                                                                                                                                                                                                        "
+               "\n     {                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n             vec3 baseHSL = RGBToHSL(base);                                                                                                                                                                                                                                                                                                                                                             "
+               "\n             return HSLToRGB(vec3(baseHSL.r, baseHSL.g, RGBToHSL(blend).b));                                                                                                                                                                                                                                                                                            "
+               "\n     }                                                                                                                                                                                                                                                                                                                                                                                                                                  "
+               "\n                                                                                                                                                                                                                                                                                                                                                                                                        "
+               ;
+                                                                                                                                                                                                                                                                                                                                                                                                                                                  
+               return glsl;
 }
\ No newline at end of file
index 831b74223e65153c34d7d92aff9601ef145c0af5..3f77a2d07b83930bbe8f044550088319a6c8777c 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "image_kernel.h"\r
-\r
-#include "image_shader.h"\r
-#include "blending_glsl.h"\r
-\r
-#include "../util/shader.h"\r
-#include "../util/texture.h"\r
-#include "../util/device.h"\r
-\r
-#include <common/except.h>\r
-#include <common/gl/gl_check.h>\r
-#include <common/env.h>\r
-\r
-#include <core/video_format.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/frame/frame_transform.h>\r
-\r
-#include <boost/lexical_cast.hpp>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-       \r
-GLubyte upper_pattern[] = {\r
-       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 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, 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, 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, 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, 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, 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, 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, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};\r
-\r
-struct image_kernel::impl\r
-{      \r
-       spl::shared_ptr<device> ogl_;\r
-       spl::shared_ptr<shader> shader_;\r
-       bool                                    blend_modes_;\r
-                                                       \r
-       impl(const spl::shared_ptr<device>& ogl)\r
-               : ogl_(ogl)\r
-               , shader_(ogl_->invoke([&]{return get_image_shader(blend_modes_);}))\r
-       {\r
-       }\r
-\r
-       void draw(draw_params params)\r
-       {\r
-               static const double epsilon = 0.001;            \r
-               \r
-               CASPAR_ASSERT(params.pix_desc.planes.size() == params.textures.size());\r
-\r
-               if(params.textures.empty() || !params.background)\r
-                       return;\r
-\r
-               if(params.transform.opacity < epsilon)\r
-                       return;\r
-                               \r
-               // Bind textures\r
-\r
-               for(int n = 0; n < params.textures.size(); ++n)\r
-                       params.textures[n]->bind(n);\r
-\r
-               if(params.local_key)\r
-                       params.local_key->bind(texture_id::local_key);\r
-               \r
-               if(params.layer_key)\r
-                       params.layer_key->bind(texture_id::layer_key);\r
-                       \r
-               // Setup shader\r
-                                                               \r
-               shader_->use();\r
-\r
-               shader_->set("plane[0]",                texture_id::plane0);\r
-               shader_->set("plane[1]",                texture_id::plane1);\r
-               shader_->set("plane[2]",                texture_id::plane2);\r
-               shader_->set("plane[3]",                texture_id::plane3);\r
-               for(int n = 0; n < params.textures.size(); ++n)\r
-                       shader_->set("plane_size[" + boost::lexical_cast<std::string>(n) + "]", \r
-                                                static_cast<float>(params.textures[n]->width()), \r
-                                                static_cast<float>(params.textures[n]->height()));\r
-\r
-               shader_->set("local_key",               texture_id::local_key);\r
-               shader_->set("layer_key",               texture_id::layer_key);\r
-               shader_->set("is_hd",                   params.pix_desc.planes.at(0).height > 700 ? 1 : 0);\r
-               shader_->set("has_local_key",   params.local_key);\r
-               shader_->set("has_layer_key",   params.layer_key);\r
-               shader_->set("pixel_format",    params.pix_desc.format.value());        \r
-               shader_->set("opacity",                 params.transform.is_key ? 1.0 : params.transform.opacity);      \r
-                               \r
-\r
-               // Setup blend_func\r
-               \r
-               if(params.transform.is_key)\r
-                       params.blend_mode = core::blend_mode::normal;\r
-\r
-               if(blend_modes_)\r
-               {\r
-                       params.background->bind(texture_id::background);\r
-\r
-                       shader_->set("background",      texture_id::background);\r
-                       shader_->set("blend_mode",      params.blend_mode.value());\r
-                       shader_->set("keyer",           params.keyer.value());\r
-               }\r
-               else\r
-               {\r
-                       GL(glEnable(GL_BLEND));\r
-\r
-                       switch(params.keyer.value())\r
-                       {\r
-                       case keyer::additive:\r
-                               GL(glBlendFunc(GL_ONE, GL_ONE));        \r
-                               break;\r
-                       case keyer::linear:\r
-                       default:                        \r
-                               GL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));\r
-                       }               \r
-               }\r
-\r
-               // Setup image-adjustements\r
-               \r
-               if(params.transform.levels.min_input  > epsilon         ||\r
-                  params.transform.levels.max_input  < 1.0-epsilon     ||\r
-                  params.transform.levels.min_output > epsilon         ||\r
-                  params.transform.levels.max_output < 1.0-epsilon     ||\r
-                  std::abs(params.transform.levels.gamma - 1.0) > epsilon)\r
-               {\r
-                       shader_->set("levels", true);   \r
-                       shader_->set("min_input",       params.transform.levels.min_input);     \r
-                       shader_->set("max_input",       params.transform.levels.max_input);\r
-                       shader_->set("min_output",      params.transform.levels.min_output);\r
-                       shader_->set("max_output",      params.transform.levels.max_output);\r
-                       shader_->set("gamma",           params.transform.levels.gamma);\r
-               }\r
-               else\r
-                       shader_->set("levels", false);  \r
-\r
-               if(std::abs(params.transform.brightness - 1.0) > epsilon ||\r
-                  std::abs(params.transform.saturation - 1.0) > epsilon ||\r
-                  std::abs(params.transform.contrast - 1.0)   > epsilon)\r
-               {\r
-                       shader_->set("csb",     true);  \r
-                       \r
-                       shader_->set("brt", params.transform.brightness);       \r
-                       shader_->set("sat", params.transform.saturation);\r
-                       shader_->set("con", params.transform.contrast);\r
-               }\r
-               else\r
-                       shader_->set("csb",     false); \r
-               \r
-               // Setup interlacing\r
-               \r
-               if(params.transform.field_mode != core::field_mode::progressive)        \r
-               {\r
-                       GL(glEnable(GL_POLYGON_STIPPLE));\r
-\r
-                       if(params.transform.field_mode == core::field_mode::upper)\r
-                               glPolygonStipple(upper_pattern);\r
-                       else if(params.transform.field_mode == core::field_mode::lower)\r
-                               glPolygonStipple(lower_pattern);\r
-               }\r
-\r
-               // Setup drawing area\r
-               \r
-               GL(glViewport(0, 0, params.background->width(), params.background->height()));\r
-                                                                               \r
-               auto m_p = params.transform.clip_translation;\r
-               auto m_s = params.transform.clip_scale;\r
-\r
-               bool scissor = m_p[0] > std::numeric_limits<double>::epsilon()                  || m_p[1] > std::numeric_limits<double>::epsilon() ||\r
-                                          m_s[0] < (1.0 - std::numeric_limits<double>::epsilon())      || m_s[1] < (1.0 - std::numeric_limits<double>::epsilon());\r
-\r
-               if(scissor)\r
-               {\r
-                       double w = static_cast<double>(params.background->width());\r
-                       double h = static_cast<double>(params.background->height());\r
-               \r
-                       GL(glEnable(GL_SCISSOR_TEST));\r
-                       glScissor(static_cast<int>(m_p[0]*w), static_cast<int>(m_p[1]*h), static_cast<int>(m_s[0]*w), static_cast<int>(m_s[1]*h));\r
-               }\r
-\r
-               auto f_p = params.transform.fill_translation;\r
-               auto f_s = params.transform.fill_scale;\r
-               \r
-               // Synchronize and set render target\r
-                                                               \r
-               if(blend_modes_)\r
-               {\r
-                       // http://www.opengl.org/registry/specs/NV/texture_barrier.txt\r
-                       // This allows us to use framebuffer (background) both as source and target while blending.\r
-                       glTextureBarrierNV(); \r
-               }\r
-\r
-               params.background->attach();\r
-               \r
-               // Draw\r
-                               \r
-               glBegin(GL_QUADS);\r
-                       glMultiTexCoord2d(GL_TEXTURE0, 0.0, 0.0); glMultiTexCoord2d(GL_TEXTURE1,  f_p[0]        ,  f_p[1]        );             glVertex2d( f_p[0]        *2.0-1.0,  f_p[1]        *2.0-1.0);\r
-                       glMultiTexCoord2d(GL_TEXTURE0, 1.0, 0.0); glMultiTexCoord2d(GL_TEXTURE1, (f_p[0]+f_s[0]),  f_p[1]        );             glVertex2d((f_p[0]+f_s[0])*2.0-1.0,  f_p[1]        *2.0-1.0);\r
-                       glMultiTexCoord2d(GL_TEXTURE0, 1.0, 1.0); glMultiTexCoord2d(GL_TEXTURE1, (f_p[0]+f_s[0]), (f_p[1]+f_s[1]));             glVertex2d((f_p[0]+f_s[0])*2.0-1.0, (f_p[1]+f_s[1])*2.0-1.0);\r
-                       glMultiTexCoord2d(GL_TEXTURE0, 0.0, 1.0); glMultiTexCoord2d(GL_TEXTURE1,  f_p[0]        , (f_p[1]+f_s[1]));             glVertex2d( f_p[0]        *2.0-1.0, (f_p[1]+f_s[1])*2.0-1.0);\r
-               glEnd();\r
-               \r
-               // Cleanup\r
-               \r
-               GL(glDisable(GL_SCISSOR_TEST));\r
-               GL(glDisable(GL_POLYGON_STIPPLE));\r
-               GL(glDisable(GL_BLEND));\r
-       }\r
-};\r
-\r
-image_kernel::image_kernel(const spl::shared_ptr<device>& ogl) : impl_(new impl(ogl)){}\r
-image_kernel::~image_kernel(){}\r
-void image_kernel::draw(const draw_params& params){impl_->draw(params);}\r
-bool image_kernel::has_blend_modes() const{return impl_->blend_modes_;}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "image_kernel.h"
+
+#include "image_shader.h"
+#include "blending_glsl.h"
+
+#include "../util/shader.h"
+#include "../util/texture.h"
+#include "../util/device.h"
+
+#include <common/except.h>
+#include <common/gl/gl_check.h>
+#include <common/env.h>
+
+#include <core/video_format.h>
+#include <core/frame/pixel_format.h>
+#include <core/frame/frame_transform.h>
+
+#include <boost/lexical_cast.hpp>
+
+namespace caspar { namespace accelerator { namespace ogl {
+       
+GLubyte upper_pattern[] = {
+       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+       0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00};
+               
+GLubyte lower_pattern[] = {
+       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
+       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};
+
+struct image_kernel::impl
+{      
+       spl::shared_ptr<device> ogl_;
+       spl::shared_ptr<shader> shader_;
+       bool                                    blend_modes_;
+                                                       
+       impl(const spl::shared_ptr<device>& ogl)
+               : ogl_(ogl)
+               , shader_(ogl_->invoke([&]{return get_image_shader(blend_modes_);}))
+       {
+       }
+
+       void draw(draw_params params)
+       {
+               static const double epsilon = 0.001;            
+               
+               CASPAR_ASSERT(params.pix_desc.planes.size() == params.textures.size());
+
+               if(params.textures.empty() || !params.background)
+                       return;
+
+               if(params.transform.opacity < epsilon)
+                       return;
+                               
+               // Bind textures
+
+               for(int n = 0; n < params.textures.size(); ++n)
+                       params.textures[n]->bind(n);
+
+               if(params.local_key)
+                       params.local_key->bind(texture_id::local_key);
+               
+               if(params.layer_key)
+                       params.layer_key->bind(texture_id::layer_key);
+                       
+               // Setup shader
+                                                               
+               shader_->use();
+
+               shader_->set("plane[0]",                texture_id::plane0);
+               shader_->set("plane[1]",                texture_id::plane1);
+               shader_->set("plane[2]",                texture_id::plane2);
+               shader_->set("plane[3]",                texture_id::plane3);
+               for(int n = 0; n < params.textures.size(); ++n)
+                       shader_->set("plane_size[" + boost::lexical_cast<std::string>(n) + "]", 
+                                                static_cast<float>(params.textures[n]->width()), 
+                                                static_cast<float>(params.textures[n]->height()));
+
+               shader_->set("local_key",               texture_id::local_key);
+               shader_->set("layer_key",               texture_id::layer_key);
+               shader_->set("is_hd",                   params.pix_desc.planes.at(0).height > 700 ? 1 : 0);
+               shader_->set("has_local_key",   params.local_key);
+               shader_->set("has_layer_key",   params.layer_key);
+               shader_->set("pixel_format",    params.pix_desc.format.value());        
+               shader_->set("opacity",                 params.transform.is_key ? 1.0 : params.transform.opacity);      
+                               
+
+               // Setup blend_func
+               
+               if(params.transform.is_key)
+                       params.blend_mode = core::blend_mode::normal;
+
+               if(blend_modes_)
+               {
+                       params.background->bind(texture_id::background);
+
+                       shader_->set("background",      texture_id::background);
+                       shader_->set("blend_mode",      params.blend_mode.value());
+                       shader_->set("keyer",           params.keyer.value());
+               }
+               else
+               {
+                       GL(glEnable(GL_BLEND));
+
+                       switch(params.keyer.value())
+                       {
+                       case keyer::additive:
+                               GL(glBlendFunc(GL_ONE, GL_ONE));        
+                               break;
+                       case keyer::linear:
+                       default:                        
+                               GL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
+                       }               
+               }
+
+               // Setup image-adjustements
+               
+               if(params.transform.levels.min_input  > epsilon         ||
+                  params.transform.levels.max_input  < 1.0-epsilon     ||
+                  params.transform.levels.min_output > epsilon         ||
+                  params.transform.levels.max_output < 1.0-epsilon     ||
+                  std::abs(params.transform.levels.gamma - 1.0) > epsilon)
+               {
+                       shader_->set("levels", true);   
+                       shader_->set("min_input",       params.transform.levels.min_input);     
+                       shader_->set("max_input",       params.transform.levels.max_input);
+                       shader_->set("min_output",      params.transform.levels.min_output);
+                       shader_->set("max_output",      params.transform.levels.max_output);
+                       shader_->set("gamma",           params.transform.levels.gamma);
+               }
+               else
+                       shader_->set("levels", false);  
+
+               if(std::abs(params.transform.brightness - 1.0) > epsilon ||
+                  std::abs(params.transform.saturation - 1.0) > epsilon ||
+                  std::abs(params.transform.contrast - 1.0)   > epsilon)
+               {
+                       shader_->set("csb",     true);  
+                       
+                       shader_->set("brt", params.transform.brightness);       
+                       shader_->set("sat", params.transform.saturation);
+                       shader_->set("con", params.transform.contrast);
+               }
+               else
+                       shader_->set("csb",     false); 
+               
+               // Setup interlacing
+               
+               if(params.transform.field_mode != core::field_mode::progressive)        
+               {
+                       GL(glEnable(GL_POLYGON_STIPPLE));
+
+                       if(params.transform.field_mode == core::field_mode::upper)
+                               glPolygonStipple(upper_pattern);
+                       else if(params.transform.field_mode == core::field_mode::lower)
+                               glPolygonStipple(lower_pattern);
+               }
+
+               // Setup drawing area
+               
+               GL(glViewport(0, 0, params.background->width(), params.background->height()));
+                                                                               
+               auto m_p = params.transform.clip_translation;
+               auto m_s = params.transform.clip_scale;
+
+               bool scissor = m_p[0] > std::numeric_limits<double>::epsilon()                  || m_p[1] > std::numeric_limits<double>::epsilon() ||
+                                          m_s[0] < (1.0 - std::numeric_limits<double>::epsilon())      || m_s[1] < (1.0 - std::numeric_limits<double>::epsilon());
+
+               if(scissor)
+               {
+                       double w = static_cast<double>(params.background->width());
+                       double h = static_cast<double>(params.background->height());
+               
+                       GL(glEnable(GL_SCISSOR_TEST));
+                       glScissor(static_cast<int>(m_p[0]*w), static_cast<int>(m_p[1]*h), static_cast<int>(m_s[0]*w), static_cast<int>(m_s[1]*h));
+               }
+
+               auto f_p = params.transform.fill_translation;
+               auto f_s = params.transform.fill_scale;
+               
+               // Synchronize and set render target
+                                                               
+               if(blend_modes_)
+               {
+                       // http://www.opengl.org/registry/specs/NV/texture_barrier.txt
+                       // This allows us to use framebuffer (background) both as source and target while blending.
+                       glTextureBarrierNV(); 
+               }
+
+               params.background->attach();
+               
+               // Draw
+                               
+               glBegin(GL_QUADS);
+                       glMultiTexCoord2d(GL_TEXTURE0, 0.0, 0.0); glMultiTexCoord2d(GL_TEXTURE1,  f_p[0]        ,  f_p[1]        );             glVertex2d( f_p[0]        *2.0-1.0,  f_p[1]        *2.0-1.0);
+                       glMultiTexCoord2d(GL_TEXTURE0, 1.0, 0.0); glMultiTexCoord2d(GL_TEXTURE1, (f_p[0]+f_s[0]),  f_p[1]        );             glVertex2d((f_p[0]+f_s[0])*2.0-1.0,  f_p[1]        *2.0-1.0);
+                       glMultiTexCoord2d(GL_TEXTURE0, 1.0, 1.0); glMultiTexCoord2d(GL_TEXTURE1, (f_p[0]+f_s[0]), (f_p[1]+f_s[1]));             glVertex2d((f_p[0]+f_s[0])*2.0-1.0, (f_p[1]+f_s[1])*2.0-1.0);
+                       glMultiTexCoord2d(GL_TEXTURE0, 0.0, 1.0); glMultiTexCoord2d(GL_TEXTURE1,  f_p[0]        , (f_p[1]+f_s[1]));             glVertex2d( f_p[0]        *2.0-1.0, (f_p[1]+f_s[1])*2.0-1.0);
+               glEnd();
+               
+               // Cleanup
+               
+               GL(glDisable(GL_SCISSOR_TEST));
+               GL(glDisable(GL_POLYGON_STIPPLE));
+               GL(glDisable(GL_BLEND));
+       }
+};
+
+image_kernel::image_kernel(const spl::shared_ptr<device>& ogl) : impl_(new impl(ogl)){}
+image_kernel::~image_kernel(){}
+void image_kernel::draw(const draw_params& params){impl_->draw(params);}
+bool image_kernel::has_blend_modes() const{return impl_->blend_modes_;}
+
 }}}
\ No newline at end of file
index 58e20780c853c2d97571efbae4dee72c134fdcd8..fe4dc96e41df19e1d0c1934e37ec5070069c2850 100644 (file)
@@ -1,88 +1,88 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <core/mixer/image/blend_modes.h>\r
-\r
-#include <common/enum_class.h>\r
-#include <common/memory.h>\r
-\r
-#include <core/frame/pixel_format.h>\r
-#include <core/frame/frame_transform.h>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-       \r
-struct keyer_def\r
-{\r
-       enum type\r
-       {\r
-               linear = 0,\r
-               additive,\r
-       };\r
-};\r
-typedef enum_class<keyer_def> keyer;\r
-\r
-struct draw_params sealed\r
-{\r
-       core::pixel_format_desc                                         pix_desc;\r
-       std::vector<spl::shared_ptr<class texture>>     textures;\r
-       core::image_transform                                           transform;\r
-       core::blend_mode                                                        blend_mode;\r
-       keyer                                                                           keyer;\r
-       std::shared_ptr<class texture>                          background;\r
-       std::shared_ptr<class texture>                          local_key;\r
-       std::shared_ptr<class texture>                          layer_key;\r
-\r
-       draw_params() \r
-               : pix_desc(core::pixel_format::invalid)\r
-               , blend_mode(core::blend_mode::normal)\r
-               , keyer(keyer::linear)\r
-       {\r
-       }\r
-};\r
-\r
-class image_kernel sealed\r
-{\r
-       image_kernel(const image_kernel&);\r
-       image_kernel& operator=(const image_kernel&);\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       image_kernel(const spl::shared_ptr<class device>& ogl);\r
-       ~image_kernel();\r
-\r
-       // Methods\r
-\r
-       void draw(const draw_params& params);\r
-       \r
-       // Properties\r
-\r
-       bool has_blend_modes() const;\r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <core/mixer/image/blend_modes.h>
+
+#include <common/enum_class.h>
+#include <common/memory.h>
+
+#include <core/frame/pixel_format.h>
+#include <core/frame/frame_transform.h>
+
+namespace caspar { namespace accelerator { namespace ogl {
+       
+struct keyer_def
+{
+       enum type
+       {
+               linear = 0,
+               additive,
+       };
+};
+typedef enum_class<keyer_def> keyer;
+
+struct draw_params sealed
+{
+       core::pixel_format_desc                                         pix_desc;
+       std::vector<spl::shared_ptr<class texture>>     textures;
+       core::image_transform                                           transform;
+       core::blend_mode                                                        blend_mode;
+       keyer                                                                           keyer;
+       std::shared_ptr<class texture>                          background;
+       std::shared_ptr<class texture>                          local_key;
+       std::shared_ptr<class texture>                          layer_key;
+
+       draw_params() 
+               : pix_desc(core::pixel_format::invalid)
+               , blend_mode(core::blend_mode::normal)
+               , keyer(keyer::linear)
+       {
+       }
+};
+
+class image_kernel sealed
+{
+       image_kernel(const image_kernel&);
+       image_kernel& operator=(const image_kernel&);
+public:
+
+       // Static Members
+
+       // Constructors
+
+       image_kernel(const spl::shared_ptr<class device>& ogl);
+       ~image_kernel();
+
+       // Methods
+
+       void draw(const draw_params& params);
+       
+       // Properties
+
+       bool has_blend_modes() const;
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+
 }}}
\ No newline at end of file
index 18bcd8c5fa8a69b02ee5de07e567f03f7d2c3fad..56dcaa20dc5e3bc09993b2ea9251e120b11b379b 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-#include "../../stdafx.h"\r
-\r
-#include "image_mixer.h"\r
-\r
-#include "image_kernel.h"\r
-\r
-#include "../util/device.h"\r
-#include "../util/buffer.h"\r
-#include "../util/texture.h"\r
-\r
-#include <common/gl/gl_check.h>\r
-#include <common/future.h>\r
-#include <common/array.h>\r
-\r
-#include <core/frame/frame.h>\r
-#include <core/frame/frame_transform.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/video_format.h>\r
-\r
-#include <asmlib.h>\r
-\r
-#include <gl/glew.h>\r
-\r
-#include <boost/foreach.hpp>\r
-#include <boost/range/algorithm_ext/erase.hpp>\r
-#include <boost/thread/future.hpp>\r
-\r
-#include <algorithm>\r
-#include <vector>\r
-\r
-using namespace boost::assign;\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-               \r
-typedef boost::shared_future<spl::shared_ptr<texture>> future_texture;\r
-\r
-struct item\r
-{\r
-       core::pixel_format_desc                                                         pix_desc;\r
-       std::vector<future_texture>                                                     textures;\r
-       core::image_transform                                                           transform;\r
-\r
-       item()\r
-               : pix_desc(core::pixel_format::invalid)\r
-       {\r
-       }\r
-};\r
-\r
-struct layer\r
-{\r
-       std::vector<item>       items;\r
-       core::blend_mode        blend_mode;\r
-\r
-       layer()\r
-               : blend_mode(core::blend_mode::normal)\r
-       {\r
-       }\r
-\r
-       layer(std::vector<item> items, core::blend_mode blend_mode)\r
-               : items(std::move(items))\r
-               , blend_mode(blend_mode)\r
-       {\r
-       }\r
-};\r
-\r
-class image_renderer\r
-{\r
-       spl::shared_ptr<device> ogl_;\r
-       image_kernel                    kernel_;\r
-public:\r
-       image_renderer(const spl::shared_ptr<device>& ogl)\r
-               : ogl_(ogl)\r
-               , kernel_(ogl_)\r
-       {\r
-       }\r
-       \r
-       boost::unique_future<array<const std::uint8_t>> operator()(std::vector<layer> layers, const core::video_format_desc& format_desc)\r
-       {       \r
-               if(layers.empty())\r
-               { // Bypass GPU with empty frame.\r
-                       auto buffer = spl::make_shared<const std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>>>(format_desc.size, 0);\r
-                       return async(launch::deferred, [=]\r
-                       {\r
-                               return array<const std::uint8_t>(buffer->data(), format_desc.size, true, buffer);\r
-                       });\r
-               }               \r
-\r
-               if(format_desc.field_mode != core::field_mode::progressive)\r
-               { // Remove jitter from still.\r
-                       BOOST_FOREACH(auto& layer, layers)\r
-                       {       \r
-                               // Remove first field stills.\r
-                               boost::range::remove_erase_if(layer.items, [&](const item& item)\r
-                               {\r
-                                       return item.transform.is_still && item.transform.field_mode == format_desc.field_mode; // only us last field for stills.\r
-                               });\r
-               \r
-                               // Stills are progressive\r
-                               BOOST_FOREACH(auto& item, layer.items)\r
-                               {\r
-                                       if(item.transform.is_still)\r
-                                               item.transform.field_mode = core::field_mode::progressive;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               return flatten(ogl_->begin_invoke([=]() mutable -> boost::shared_future<array<const std::uint8_t>>\r
-               {\r
-                       auto target_texture = ogl_->create_texture(format_desc.width, format_desc.height, 4);\r
-\r
-                       if(format_desc.field_mode != core::field_mode::progressive)\r
-                       {\r
-                               draw(target_texture, layers,                    format_desc, core::field_mode::upper);\r
-                               draw(target_texture, std::move(layers), format_desc, core::field_mode::lower);\r
-                       }\r
-                       else                    \r
-                               draw(target_texture, std::move(layers), format_desc, core::field_mode::progressive);\r
-                                                               \r
-                       return ogl_->copy_async(target_texture);\r
-               }));\r
-       }\r
-\r
-private:       \r
-       \r
-       void draw(spl::shared_ptr<texture>&                     target_texture, \r
-                         std::vector<layer>                            layers, \r
-                         const core::video_format_desc&        format_desc,\r
-                         core::field_mode                                      field_mode)\r
-       {\r
-               std::shared_ptr<texture> layer_key_texture;\r
-\r
-               BOOST_FOREACH(auto& layer, layers)\r
-                       draw(target_texture, std::move(layer), layer_key_texture, format_desc, field_mode);\r
-       }\r
-\r
-       void draw(spl::shared_ptr<texture>&                     target_texture,\r
-                         layer                                                         layer, \r
-                         std::shared_ptr<texture>&                     layer_key_texture,\r
-                         const core::video_format_desc&        format_desc,\r
-                         core::field_mode                                      field_mode)\r
-       {                       \r
-               // REMOVED: This is done in frame_muxer. \r
-               // Fix frames\r
-               //BOOST_FOREACH(auto& item, layer.items)                \r
-               //{\r
-                       //if(std::abs(item.transform.fill_scale[1]-1.0) > 1.0/target_texture->height() ||\r
-                       //   std::abs(item.transform.fill_translation[1]) > 1.0/target_texture->height())               \r
-                       //      CASPAR_LOG(warning) << L"[image_mixer] Frame should be deinterlaced. Send FILTER DEINTERLACE_BOB when creating producer.";      \r
-\r
-                       //if(item.pix_desc.planes.at(0).height == 480) // NTSC DV\r
-                       //{\r
-                       //      item.transform.fill_translation[1] += 2.0/static_cast<double>(format_desc.height);\r
-                       //      item.transform.fill_scale[1] *= 1.0 - 6.0*1.0/static_cast<double>(format_desc.height);\r
-                       //}\r
-       \r
-                       //// Fix field-order if needed\r
-                       //if(item.field_mode == core::field_mode::lower && format_desc.field_mode == core::field_mode::upper)\r
-                       //      item.transform.fill_translation[1] += 1.0/static_cast<double>(format_desc.height);\r
-                       //else if(item.field_mode == core::field_mode::upper && format_desc.field_mode == core::field_mode::lower)\r
-                       //      item.transform.fill_translation[1] -= 1.0/static_cast<double>(format_desc.height);\r
-               //}\r
-\r
-               // Mask out fields\r
-               BOOST_FOREACH(auto& item, layer.items)                          \r
-                       item.transform.field_mode &= field_mode;\r
-               \r
-               // Remove empty items.\r
-               boost::range::remove_erase_if(layer.items, [&](const item& item)\r
-               {\r
-                       return item.transform.field_mode == core::field_mode::empty;\r
-               });\r
-               \r
-               if(layer.items.empty())\r
-                       return;\r
-\r
-               std::shared_ptr<texture> local_key_texture;\r
-               std::shared_ptr<texture> local_mix_texture;\r
-                               \r
-               if(layer.blend_mode != core::blend_mode::normal)\r
-               {\r
-                       auto layer_texture = ogl_->create_texture(target_texture->width(), target_texture->height(), 4);\r
-\r
-                       BOOST_FOREACH(auto& item, layer.items)\r
-                               draw(layer_texture, std::move(item), layer_key_texture, local_key_texture, local_mix_texture);  \r
-               \r
-                       draw(layer_texture, std::move(local_mix_texture), core::blend_mode::normal);                                                    \r
-                       draw(target_texture, std::move(layer_texture), layer.blend_mode);\r
-               }\r
-               else // fast path\r
-               {\r
-                       BOOST_FOREACH(auto& item, layer.items)          \r
-                               draw(target_texture, std::move(item), layer_key_texture, local_key_texture, local_mix_texture);         \r
-                                       \r
-                       draw(target_texture, std::move(local_mix_texture), core::blend_mode::normal);\r
-               }                                       \r
-\r
-               layer_key_texture = std::move(local_key_texture);\r
-       }\r
-\r
-       void draw(spl::shared_ptr<texture>&     target_texture, \r
-                         item                                          item, \r
-                     std::shared_ptr<texture>& layer_key_texture, \r
-                         std::shared_ptr<texture>&     local_key_texture, \r
-                         std::shared_ptr<texture>&     local_mix_texture)\r
-       {                       \r
-               draw_params draw_params;\r
-               draw_params.pix_desc    = std::move(item.pix_desc);\r
-               draw_params.transform   = std::move(item.transform);\r
-\r
-               BOOST_FOREACH(auto& future_texture, item.textures)\r
-                       draw_params.textures.push_back(future_texture.get());\r
-\r
-               if(item.transform.is_key)\r
-               {\r
-                       local_key_texture = local_key_texture ? local_key_texture : ogl_->create_texture(target_texture->width(), target_texture->height(), 1);\r
-\r
-                       draw_params.background                  = local_key_texture;\r
-                       draw_params.local_key                   = nullptr;\r
-                       draw_params.layer_key                   = nullptr;\r
-\r
-                       kernel_.draw(std::move(draw_params));\r
-               }\r
-               else if(item.transform.is_mix)\r
-               {\r
-                       local_mix_texture = local_mix_texture ? local_mix_texture : ogl_->create_texture(target_texture->width(), target_texture->height(), 4);\r
-\r
-                       draw_params.background                  = local_mix_texture;\r
-                       draw_params.local_key                   = std::move(local_key_texture);\r
-                       draw_params.layer_key                   = layer_key_texture;\r
-\r
-                       draw_params.keyer                               = keyer::additive;\r
-\r
-                       kernel_.draw(std::move(draw_params));\r
-               }\r
-               else\r
-               {\r
-                       draw(target_texture, std::move(local_mix_texture), core::blend_mode::normal);\r
-                       \r
-                       draw_params.background                  = target_texture;\r
-                       draw_params.local_key                   = std::move(local_key_texture);\r
-                       draw_params.layer_key                   = layer_key_texture;\r
-\r
-                       kernel_.draw(std::move(draw_params));\r
-               }       \r
-       }\r
-\r
-       void draw(spl::shared_ptr<texture>&      target_texture, \r
-                         std::shared_ptr<texture>&& source_buffer, \r
-                         core::blend_mode                       blend_mode = core::blend_mode::normal)\r
-       {\r
-               if(!source_buffer)\r
-                       return;\r
-\r
-               draw_params draw_params;\r
-               draw_params.pix_desc.format             = core::pixel_format::bgra;\r
-               draw_params.pix_desc.planes             = list_of(core::pixel_format_desc::plane(source_buffer->width(), source_buffer->height(), 4));\r
-               draw_params.textures                    = list_of(source_buffer);\r
-               draw_params.transform                   = core::image_transform();\r
-               draw_params.blend_mode                  = blend_mode;\r
-               draw_params.background                  = target_texture;\r
-\r
-               kernel_.draw(std::move(draw_params));\r
-       }\r
-};\r
-               \r
-struct image_mixer::impl : public core::frame_factory\r
-{      \r
-       spl::shared_ptr<device>                         ogl_;\r
-       image_renderer                                          renderer_;\r
-       std::vector<core::image_transform>      transform_stack_;\r
-       std::vector<layer>                                      layers_; // layer/stream/items\r
-public:\r
-       impl(const spl::shared_ptr<device>& ogl) \r
-               : ogl_(ogl)\r
-               , renderer_(ogl)\r
-               , transform_stack_(1)   \r
-       {\r
-               CASPAR_LOG(info) << L"Initialized OpenGL Accelerated GPU Image Mixer";\r
-       }\r
-\r
-       void begin_layer(core::blend_mode blend_mode)\r
-       {\r
-               layers_.push_back(layer(std::vector<item>(), blend_mode));\r
-       }\r
-               \r
-       void push(const core::frame_transform& transform)\r
-       {\r
-               transform_stack_.push_back(transform_stack_.back()*transform.image_transform);\r
-       }\r
-               \r
-       void visit(const core::const_frame& frame)\r
-       {                       \r
-               if(frame.pixel_format_desc().format == core::pixel_format::invalid)\r
-                       return;\r
-\r
-               if(frame.pixel_format_desc().planes.empty())\r
-                       return;\r
-\r
-               if(transform_stack_.back().field_mode == core::field_mode::empty)\r
-                       return;\r
-\r
-               item item;\r
-               item.pix_desc   = frame.pixel_format_desc();\r
-               item.transform  = transform_stack_.back();\r
-               \r
-               // NOTE: Once we have copied the arrays they are no longer valid for reading!!! Check for alternative solution e.g. transfer with AMD_pinned_memory.\r
-               for(int n = 0; n < static_cast<int>(item.pix_desc.planes.size()); ++n)\r
-                       item.textures.push_back(ogl_->copy_async(frame.image_data(n), item.pix_desc.planes[n].width, item.pix_desc.planes[n].height, item.pix_desc.planes[n].stride));\r
-               \r
-               layers_.back().items.push_back(item);\r
-       }\r
-\r
-       void pop()\r
-       {\r
-               transform_stack_.pop_back();\r
-       }\r
-\r
-       void end_layer()\r
-       {               \r
-       }\r
-       \r
-       boost::unique_future<array<const std::uint8_t>> render(const core::video_format_desc& format_desc)\r
-       {\r
-               return renderer_(std::move(layers_), format_desc);\r
-       }\r
-       \r
-       core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc) override\r
-       {\r
-               std::vector<array<std::uint8_t>> buffers;\r
-               BOOST_FOREACH(auto& plane, desc.planes)         \r
-                       buffers.push_back(ogl_->create_array(plane.size));              \r
-\r
-               return core::mutable_frame(std::move(buffers), core::audio_buffer(), tag, desc);\r
-       }\r
-};\r
-\r
-image_mixer::image_mixer(const spl::shared_ptr<device>& ogl) : impl_(new impl(ogl)){}\r
-image_mixer::~image_mixer(){}\r
-void image_mixer::push(const core::frame_transform& transform){impl_->push(transform);}\r
-void image_mixer::visit(const core::const_frame& frame){impl_->visit(frame);}\r
-void image_mixer::pop(){impl_->pop();}\r
-boost::unique_future<array<const std::uint8_t>> image_mixer::operator()(const core::video_format_desc& format_desc){return impl_->render(format_desc);}\r
-void image_mixer::begin_layer(core::blend_mode blend_mode){impl_->begin_layer(blend_mode);}\r
-void image_mixer::end_layer(){impl_->end_layer();}\r
-core::mutable_frame image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->create_frame(tag, desc);}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+#include "../../stdafx.h"
+
+#include "image_mixer.h"
+
+#include "image_kernel.h"
+
+#include "../util/device.h"
+#include "../util/buffer.h"
+#include "../util/texture.h"
+
+#include <common/gl/gl_check.h>
+#include <common/future.h>
+#include <common/array.h>
+
+#include <core/frame/frame.h>
+#include <core/frame/frame_transform.h>
+#include <core/frame/pixel_format.h>
+#include <core/video_format.h>
+
+#include <asmlib.h>
+
+#include <gl/glew.h>
+
+#include <boost/foreach.hpp>
+#include <boost/range/algorithm_ext/erase.hpp>
+#include <boost/thread/future.hpp>
+
+#include <algorithm>
+#include <vector>
+
+using namespace boost::assign;
+
+namespace caspar { namespace accelerator { namespace ogl {
+               
+typedef boost::shared_future<spl::shared_ptr<texture>> future_texture;
+
+struct item
+{
+       core::pixel_format_desc                                                         pix_desc;
+       std::vector<future_texture>                                                     textures;
+       core::image_transform                                                           transform;
+
+       item()
+               : pix_desc(core::pixel_format::invalid)
+       {
+       }
+};
+
+struct layer
+{
+       std::vector<item>       items;
+       core::blend_mode        blend_mode;
+
+       layer()
+               : blend_mode(core::blend_mode::normal)
+       {
+       }
+
+       layer(std::vector<item> items, core::blend_mode blend_mode)
+               : items(std::move(items))
+               , blend_mode(blend_mode)
+       {
+       }
+};
+
+class image_renderer
+{
+       spl::shared_ptr<device> ogl_;
+       image_kernel                    kernel_;
+public:
+       image_renderer(const spl::shared_ptr<device>& ogl)
+               : ogl_(ogl)
+               , kernel_(ogl_)
+       {
+       }
+       
+       boost::unique_future<array<const std::uint8_t>> operator()(std::vector<layer> layers, const core::video_format_desc& format_desc)
+       {       
+               if(layers.empty())
+               { // Bypass GPU with empty frame.
+                       auto buffer = spl::make_shared<const std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>>>(format_desc.size, 0);
+                       return async(launch::deferred, [=]
+                       {
+                               return array<const std::uint8_t>(buffer->data(), format_desc.size, true, buffer);
+                       });
+               }               
+
+               if(format_desc.field_mode != core::field_mode::progressive)
+               { // Remove jitter from still.
+                       BOOST_FOREACH(auto& layer, layers)
+                       {       
+                               // Remove first field stills.
+                               boost::range::remove_erase_if(layer.items, [&](const item& item)
+                               {
+                                       return item.transform.is_still && item.transform.field_mode == format_desc.field_mode; // only us last field for stills.
+                               });
+               
+                               // Stills are progressive
+                               BOOST_FOREACH(auto& item, layer.items)
+                               {
+                                       if(item.transform.is_still)
+                                               item.transform.field_mode = core::field_mode::progressive;
+                               }
+                       }
+               }
+
+               return flatten(ogl_->begin_invoke([=]() mutable -> boost::shared_future<array<const std::uint8_t>>
+               {
+                       auto target_texture = ogl_->create_texture(format_desc.width, format_desc.height, 4);
+
+                       if(format_desc.field_mode != core::field_mode::progressive)
+                       {
+                               draw(target_texture, layers,                    format_desc, core::field_mode::upper);
+                               draw(target_texture, std::move(layers), format_desc, core::field_mode::lower);
+                       }
+                       else                    
+                               draw(target_texture, std::move(layers), format_desc, core::field_mode::progressive);
+                                                               
+                       return ogl_->copy_async(target_texture);
+               }));
+       }
+
+private:       
+       
+       void draw(spl::shared_ptr<texture>&                     target_texture, 
+                         std::vector<layer>                            layers, 
+                         const core::video_format_desc&        format_desc,
+                         core::field_mode                                      field_mode)
+       {
+               std::shared_ptr<texture> layer_key_texture;
+
+               BOOST_FOREACH(auto& layer, layers)
+                       draw(target_texture, std::move(layer), layer_key_texture, format_desc, field_mode);
+       }
+
+       void draw(spl::shared_ptr<texture>&                     target_texture,
+                         layer                                                         layer, 
+                         std::shared_ptr<texture>&                     layer_key_texture,
+                         const core::video_format_desc&        format_desc,
+                         core::field_mode                                      field_mode)
+       {                       
+               // REMOVED: This is done in frame_muxer. 
+               // Fix frames
+               //BOOST_FOREACH(auto& item, layer.items)                
+               //{
+                       //if(std::abs(item.transform.fill_scale[1]-1.0) > 1.0/target_texture->height() ||
+                       //   std::abs(item.transform.fill_translation[1]) > 1.0/target_texture->height())               
+                       //      CASPAR_LOG(warning) << L"[image_mixer] Frame should be deinterlaced. Send FILTER DEINTERLACE_BOB when creating producer.";      
+
+                       //if(item.pix_desc.planes.at(0).height == 480) // NTSC DV
+                       //{
+                       //      item.transform.fill_translation[1] += 2.0/static_cast<double>(format_desc.height);
+                       //      item.transform.fill_scale[1] *= 1.0 - 6.0*1.0/static_cast<double>(format_desc.height);
+                       //}
+       
+                       //// Fix field-order if needed
+                       //if(item.field_mode == core::field_mode::lower && format_desc.field_mode == core::field_mode::upper)
+                       //      item.transform.fill_translation[1] += 1.0/static_cast<double>(format_desc.height);
+                       //else if(item.field_mode == core::field_mode::upper && format_desc.field_mode == core::field_mode::lower)
+                       //      item.transform.fill_translation[1] -= 1.0/static_cast<double>(format_desc.height);
+               //}
+
+               // Mask out fields
+               BOOST_FOREACH(auto& item, layer.items)                          
+                       item.transform.field_mode &= field_mode;
+               
+               // Remove empty items.
+               boost::range::remove_erase_if(layer.items, [&](const item& item)
+               {
+                       return item.transform.field_mode == core::field_mode::empty;
+               });
+               
+               if(layer.items.empty())
+                       return;
+
+               std::shared_ptr<texture> local_key_texture;
+               std::shared_ptr<texture> local_mix_texture;
+                               
+               if(layer.blend_mode != core::blend_mode::normal)
+               {
+                       auto layer_texture = ogl_->create_texture(target_texture->width(), target_texture->height(), 4);
+
+                       BOOST_FOREACH(auto& item, layer.items)
+                               draw(layer_texture, std::move(item), layer_key_texture, local_key_texture, local_mix_texture);  
+               
+                       draw(layer_texture, std::move(local_mix_texture), core::blend_mode::normal);                                                    
+                       draw(target_texture, std::move(layer_texture), layer.blend_mode);
+               }
+               else // fast path
+               {
+                       BOOST_FOREACH(auto& item, layer.items)          
+                               draw(target_texture, std::move(item), layer_key_texture, local_key_texture, local_mix_texture);         
+                                       
+                       draw(target_texture, std::move(local_mix_texture), core::blend_mode::normal);
+               }                                       
+
+               layer_key_texture = std::move(local_key_texture);
+       }
+
+       void draw(spl::shared_ptr<texture>&     target_texture, 
+                         item                                          item, 
+                     std::shared_ptr<texture>& layer_key_texture, 
+                         std::shared_ptr<texture>&     local_key_texture, 
+                         std::shared_ptr<texture>&     local_mix_texture)
+       {                       
+               draw_params draw_params;
+               draw_params.pix_desc    = std::move(item.pix_desc);
+               draw_params.transform   = std::move(item.transform);
+
+               BOOST_FOREACH(auto& future_texture, item.textures)
+                       draw_params.textures.push_back(future_texture.get());
+
+               if(item.transform.is_key)
+               {
+                       local_key_texture = local_key_texture ? local_key_texture : ogl_->create_texture(target_texture->width(), target_texture->height(), 1);
+
+                       draw_params.background                  = local_key_texture;
+                       draw_params.local_key                   = nullptr;
+                       draw_params.layer_key                   = nullptr;
+
+                       kernel_.draw(std::move(draw_params));
+               }
+               else if(item.transform.is_mix)
+               {
+                       local_mix_texture = local_mix_texture ? local_mix_texture : ogl_->create_texture(target_texture->width(), target_texture->height(), 4);
+
+                       draw_params.background                  = local_mix_texture;
+                       draw_params.local_key                   = std::move(local_key_texture);
+                       draw_params.layer_key                   = layer_key_texture;
+
+                       draw_params.keyer                               = keyer::additive;
+
+                       kernel_.draw(std::move(draw_params));
+               }
+               else
+               {
+                       draw(target_texture, std::move(local_mix_texture), core::blend_mode::normal);
+                       
+                       draw_params.background                  = target_texture;
+                       draw_params.local_key                   = std::move(local_key_texture);
+                       draw_params.layer_key                   = layer_key_texture;
+
+                       kernel_.draw(std::move(draw_params));
+               }       
+       }
+
+       void draw(spl::shared_ptr<texture>&      target_texture, 
+                         std::shared_ptr<texture>&& source_buffer, 
+                         core::blend_mode                       blend_mode = core::blend_mode::normal)
+       {
+               if(!source_buffer)
+                       return;
+
+               draw_params draw_params;
+               draw_params.pix_desc.format             = core::pixel_format::bgra;
+               draw_params.pix_desc.planes             = list_of(core::pixel_format_desc::plane(source_buffer->width(), source_buffer->height(), 4));
+               draw_params.textures                    = list_of(source_buffer);
+               draw_params.transform                   = core::image_transform();
+               draw_params.blend_mode                  = blend_mode;
+               draw_params.background                  = target_texture;
+
+               kernel_.draw(std::move(draw_params));
+       }
+};
+               
+struct image_mixer::impl : public core::frame_factory
+{      
+       spl::shared_ptr<device>                         ogl_;
+       image_renderer                                          renderer_;
+       std::vector<core::image_transform>      transform_stack_;
+       std::vector<layer>                                      layers_; // layer/stream/items
+public:
+       impl(const spl::shared_ptr<device>& ogl) 
+               : ogl_(ogl)
+               , renderer_(ogl)
+               , transform_stack_(1)   
+       {
+               CASPAR_LOG(info) << L"Initialized OpenGL Accelerated GPU Image Mixer";
+       }
+
+       void begin_layer(core::blend_mode blend_mode)
+       {
+               layers_.push_back(layer(std::vector<item>(), blend_mode));
+       }
+               
+       void push(const core::frame_transform& transform)
+       {
+               transform_stack_.push_back(transform_stack_.back()*transform.image_transform);
+       }
+               
+       void visit(const core::const_frame& frame)
+       {                       
+               if(frame.pixel_format_desc().format == core::pixel_format::invalid)
+                       return;
+
+               if(frame.pixel_format_desc().planes.empty())
+                       return;
+
+               if(transform_stack_.back().field_mode == core::field_mode::empty)
+                       return;
+
+               item item;
+               item.pix_desc   = frame.pixel_format_desc();
+               item.transform  = transform_stack_.back();
+               
+               // NOTE: Once we have copied the arrays they are no longer valid for reading!!! Check for alternative solution e.g. transfer with AMD_pinned_memory.
+               for(int n = 0; n < static_cast<int>(item.pix_desc.planes.size()); ++n)
+                       item.textures.push_back(ogl_->copy_async(frame.image_data(n), item.pix_desc.planes[n].width, item.pix_desc.planes[n].height, item.pix_desc.planes[n].stride));
+               
+               layers_.back().items.push_back(item);
+       }
+
+       void pop()
+       {
+               transform_stack_.pop_back();
+       }
+
+       void end_layer()
+       {               
+       }
+       
+       boost::unique_future<array<const std::uint8_t>> render(const core::video_format_desc& format_desc)
+       {
+               return renderer_(std::move(layers_), format_desc);
+       }
+       
+       core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc) override
+       {
+               std::vector<array<std::uint8_t>> buffers;
+               BOOST_FOREACH(auto& plane, desc.planes)         
+                       buffers.push_back(ogl_->create_array(plane.size));              
+
+               return core::mutable_frame(std::move(buffers), core::audio_buffer(), tag, desc);
+       }
+};
+
+image_mixer::image_mixer(const spl::shared_ptr<device>& ogl) : impl_(new impl(ogl)){}
+image_mixer::~image_mixer(){}
+void image_mixer::push(const core::frame_transform& transform){impl_->push(transform);}
+void image_mixer::visit(const core::const_frame& frame){impl_->visit(frame);}
+void image_mixer::pop(){impl_->pop();}
+boost::unique_future<array<const std::uint8_t>> image_mixer::operator()(const core::video_format_desc& format_desc){return impl_->render(format_desc);}
+void image_mixer::begin_layer(core::blend_mode blend_mode){impl_->begin_layer(blend_mode);}
+void image_mixer::end_layer(){impl_->end_layer();}
+core::mutable_frame image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->create_frame(tag, desc);}
+
 }}}
\ No newline at end of file
index 6411672a96a1bc6c59418610b7d9fc37ed7f5fd8..12b3105bb27cc7a7752da6866f374a936463a22a 100644 (file)
@@ -1,76 +1,76 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/forward.h>\r
-#include <common/memory.h>\r
-#include <common/future_fwd.h>\r
-\r
-#include <core/mixer/image/blend_modes.h>\r
-#include <core/mixer/image/image_mixer.h>\r
-\r
-#include <core/frame/frame_visitor.h>\r
-#include <core/video_format.h>\r
-\r
-FORWARD2(caspar, core, class frame);\r
-FORWARD2(caspar, core, struct pixel_format_desc);\r
-FORWARD2(caspar, core, struct video_format_desc);\r
-FORWARD2(caspar, core, class mutable_frame);\r
-FORWARD2(caspar, core, struct frame_transform);\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-       \r
-class image_mixer sealed : public core::image_mixer\r
-{\r
-       image_mixer(const image_mixer&);\r
-       image_mixer& operator=(const image_mixer&);\r
-public:\r
-\r
-       // Static Members\r
-       \r
-       // Constructors\r
-\r
-       image_mixer(const spl::shared_ptr<class device>& ogl);\r
-       ~image_mixer();\r
-\r
-       // Methods\r
-                       \r
-       boost::unique_future<array<const std::uint8_t>> operator()(const core::video_format_desc& format_desc) override;                \r
-       core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc) override;\r
-\r
-       // core::image_mixer\r
-       \r
-       void begin_layer(core::blend_mode blend_mode) override;\r
-       void end_layer() override;\r
-\r
-       void push(const core::frame_transform& frame) override;\r
-       void visit(const core::const_frame& frame) override;\r
-       void pop() override;\r
-                       \r
-       // Properties\r
-\r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/forward.h>
+#include <common/memory.h>
+#include <common/future_fwd.h>
+
+#include <core/mixer/image/blend_modes.h>
+#include <core/mixer/image/image_mixer.h>
+
+#include <core/frame/frame_visitor.h>
+#include <core/video_format.h>
+
+FORWARD2(caspar, core, class frame);
+FORWARD2(caspar, core, struct pixel_format_desc);
+FORWARD2(caspar, core, struct video_format_desc);
+FORWARD2(caspar, core, class mutable_frame);
+FORWARD2(caspar, core, struct frame_transform);
+
+namespace caspar { namespace accelerator { namespace ogl {
+       
+class image_mixer sealed : public core::image_mixer
+{
+       image_mixer(const image_mixer&);
+       image_mixer& operator=(const image_mixer&);
+public:
+
+       // Static Members
+       
+       // Constructors
+
+       image_mixer(const spl::shared_ptr<class device>& ogl);
+       ~image_mixer();
+
+       // Methods
+                       
+       boost::unique_future<array<const std::uint8_t>> operator()(const core::video_format_desc& format_desc) override;                
+       core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc) override;
+
+       // core::image_mixer
+       
+       void begin_layer(core::blend_mode blend_mode) override;
+       void end_layer() override;
+
+       void push(const core::frame_transform& frame) override;
+       void visit(const core::const_frame& frame) override;
+       void pop() override;
+                       
+       // Properties
+
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+
 }}}
\ No newline at end of file
index 39dce431e505666aec71be903bd0f0b76339485f..047d83edf10d4b45011a1a8bc86c7d519beef8d1 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "image_shader.h"\r
-\r
-#include "../util/shader.h"\r
-#include "../util/device.h"\r
-\r
-#include "blending_glsl.h"\r
-\r
-#include <common/gl/gl_check.h>\r
-#include <common/env.h>\r
-\r
-#include <tbb/mutex.h>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-\r
-std::shared_ptr<shader> g_shader;\r
-tbb::mutex                             g_shader_mutex;\r
-bool                                   g_blend_modes = false;\r
-\r
-std::string get_blend_color_func()\r
-{\r
-       return \r
-                       \r
-       get_adjustement_glsl()\r
-               \r
-       +\r
-\r
-       get_blend_glsl()\r
-               \r
-       +\r
-                       \r
-       "vec3 get_blend_color(vec3 back, vec3 fore)                                                                                     \n"\r
-       "{                                                                                                                                                                      \n"\r
-       "       switch(blend_mode)                                                                                                                              \n"\r
-       "       {                                                                                                                                                               \n"\r
-       "       case  0: return BlendNormal(back, fore);                                                                                \n"\r
-       "       case  1: return BlendLighten(back, fore);                                                                               \n"\r
-       "       case  2: return BlendDarken(back, fore);                                                                                \n"\r
-       "       case  3: return BlendMultiply(back, fore);                                                                              \n"\r
-       "       case  4: return BlendAverage(back, fore);                                                                               \n"\r
-       "       case  5: return BlendAdd(back, fore);                                                                                   \n"\r
-       "       case  6: return BlendSubstract(back, fore);                                                                             \n"\r
-       "       case  7: return BlendDifference(back, fore);                                                                    \n"\r
-       "       case  8: return BlendNegation(back, fore);                                                                              \n"\r
-       "       case  9: return BlendExclusion(back, fore);                                                                             \n"\r
-       "       case 10: return BlendScreen(back, fore);                                                                                \n"\r
-       "       case 11: return BlendOverlay(back, fore);                                                                               \n"\r
-       //"     case 12: return BlendSoftLight(back, fore);                                                                             \n"\r
-       "       case 13: return BlendHardLight(back, fore);                                                                             \n"\r
-       "       case 14: return BlendColorDodge(back, fore);                                                                    \n"\r
-       "       case 15: return BlendColorBurn(back, fore);                                                                             \n"\r
-       "       case 16: return BlendLinearDodge(back, fore);                                                                   \n"\r
-       "       case 17: return BlendLinearBurn(back, fore);                                                                    \n"\r
-       "       case 18: return BlendLinearLight(back, fore);                                                                   \n"\r
-       "       case 19: return BlendVividLight(back, fore);                                                                    \n"\r
-       "       case 20: return BlendPinLight(back, fore);                                                                              \n"\r
-       "       case 21: return BlendHardMix(back, fore);                                                                               \n"\r
-       "       case 22: return BlendReflect(back, fore);                                                                               \n"\r
-       "       case 23: return BlendGlow(back, fore);                                                                                  \n"\r
-       "       case 24: return BlendPhoenix(back, fore);                                                                               \n"\r
-       "       case 25: return BlendHue(back, fore);                                                                                   \n"\r
-       "       case 26: return BlendSaturation(back, fore);                                                                    \n"\r
-       "       case 27: return BlendColor(back, fore);                                                                                 \n"\r
-       "       case 28: return BlendLuminosity(back, fore);                                                                    \n"\r
-       "       }                                                                                                                                                               \n"\r
-       "       return BlendNormal(back, fore);                                                                                                 \n"\r
-       "}                                                                                                                                                                      \n"\r
-       "                                                                                                                                                                       \n"                                                                                                                                                       \r
-       "vec4 blend(vec4 fore)                                                                                                                          \n"\r
-       "{                                                                                                                                                                      \n"\r
-       "   vec4 back = texture2D(background, gl_TexCoord[1].st).bgra;                                          \n"\r
-       "   if(blend_mode != 0)                                                                                                                         \n"\r
-       "               fore.rgb = get_blend_color(back.rgb/(back.a+0.0000001), fore.rgb/(fore.a+0.0000001))*fore.a;\n"\r
-       "       switch(keyer)                                                                                                                                   \n"     \r
-       "       {                                                                                                                                                               \n"     \r
-       "               case 1:  return fore + back; // additive                                                                        \n"\r
-       "               default: return fore + (1.0-fore.a)*back; // linear                                                     \n"\r
-       "       }                                                                                                                                                               \n"\r
-       "}                                                                                                                                                                      \n";                    \r
-}\r
-               \r
-std::string get_simple_blend_color_func()\r
-{\r
-       return  \r
-               \r
-       get_adjustement_glsl()\r
-                       \r
-       +\r
-\r
-       "vec4 blend(vec4 fore)                                                                                                                          \n"\r
-       "{                                                                                                                                                                      \n"\r
-       "       return fore;                                                                                                                                    \n"\r
-       "}                                                                                                                                                                      \n";\r
-}\r
-\r
-std::string get_vertex()\r
-{\r
-       return \r
-\r
-       "void main()                                                                                                                                            \n"\r
-       "{                                                                                                                                                                      \n"\r
-       "       gl_TexCoord[0] = gl_MultiTexCoord0;                                                                                             \n"\r
-       "       gl_TexCoord[1] = gl_MultiTexCoord1;                                                                                             \n"\r
-       "       gl_Position    = ftransform();                                                                                                  \n"\r
-       "}                                                                                                                                                                      \n";\r
-}\r
-\r
-std::string get_fragment(bool blend_modes)\r
-{\r
-       return\r
-\r
-       "#version 130                                                                                                                                           \n"\r
-       "uniform sampler2D      background;                                                                                                             \n"\r
-       "uniform sampler2D      plane[4];                                                                                                               \n"\r
-       "uniform vec2           plane_size[4];                                                                                                  \n"\r
-       "uniform sampler2D      local_key;                                                                                                              \n"\r
-       "uniform sampler2D      layer_key;                                                                                                              \n"\r
-       "                                                                                                                                                                       \n"\r
-       "uniform bool           is_hd;                                                                                                                  \n"\r
-       "uniform bool           has_local_key;                                                                                                  \n"\r
-       "uniform bool           has_layer_key;                                                                                                  \n"\r
-       "uniform int            blend_mode;                                                                                                             \n"\r
-       "uniform int            keyer;                                                                                                                  \n"\r
-       "uniform int            pixel_format;                                                                                                   \n"\r
-       "uniform int            deinterlace;                                                                                                    \n"\r
-       "                                                                                                                                                                       \n"\r
-       "uniform float          opacity;                                                                                                                \n"\r
-       "uniform bool           levels;                                                                                                                 \n"\r
-       "uniform float          min_input;                                                                                                              \n"\r
-       "uniform float          max_input;                                                                                                              \n"\r
-       "uniform float          gamma;                                                                                                                  \n"\r
-       "uniform float          min_output;                                                                                                             \n"\r
-       "uniform float          max_output;                                                                                                             \n"\r
-       "                                                                                                                                                                       \n"\r
-       "uniform bool           csb;                                                                                                                    \n"\r
-       "uniform float          brt;                                                                                                                    \n"\r
-       "uniform float          sat;                                                                                                                    \n"\r
-       "uniform float          con;                                                                                                                    \n"\r
-       "                                                                                                                                                                       \n"     \r
-\r
-       +\r
-               \r
-       (blend_modes ? get_blend_color_func() : get_simple_blend_color_func())\r
-\r
-       +\r
-       \r
-       "                                                                                                                                                                       \n"\r
-       "vec4 ycbcra_to_rgba_sd(float Y, float Cb, float Cr, float A)                                           \n"\r
-       "{                                                                                                                                                                      \n"\r
-       "   vec4 rgba;                                                                                                                                          \n"\r
-       "   rgba.b = (1.164*(Y*255 - 16) + 1.596*(Cr*255 - 128))/255;                                           \n"\r
-       "   rgba.g = (1.164*(Y*255 - 16) - 0.813*(Cr*255 - 128) - 0.391*(Cb*255 - 128))/255;\n"\r
-       "   rgba.r = (1.164*(Y*255 - 16) + 2.018*(Cb*255 - 128))/255;                                           \n"\r
-       "   rgba.a = A;                                                                                                                                         \n"\r
-       "       return rgba;                                                                                                                                    \n"     \r
-       "}                                                                                                                                                                      \n"                     \r
-       "                                                                                                                                                                       \n"\r
-       "vec4 ycbcra_to_rgba_hd(float Y, float Cb, float Cr, float A)                                           \n"\r
-       "{                                                                                                                                                                      \n"\r
-       "   vec4 rgba;                                                                                                                                          \n"\r
-       "   rgba.b = (1.164*(Y*255 - 16) + 1.793*(Cr*255 - 128))/255;                                           \n"\r
-       "   rgba.g = (1.164*(Y*255 - 16) - 0.534*(Cr*255 - 128) - 0.213*(Cb*255 - 128))/255;\n"\r
-       "   rgba.r = (1.164*(Y*255 - 16) + 2.115*(Cb*255 - 128))/255;                                           \n"\r
-       "   rgba.a = A;                                                                                                                                         \n"\r
-       "       return rgba;                                                                                                                                    \n"\r
-       "}                                                                                                                                                                      \n"                                     \r
-       "                                                                                                                                                                       \n"             \r
-       "vec4 ycbcra_to_rgba(float y, float cb, float cr, float a)                                                      \n"\r
-       "{                                                                                                                                                                      \n"\r
-       "       if(is_hd)                                                                                                                                               \n"\r
-       "               return ycbcra_to_rgba_hd(y, cb, cr, a);                                                                         \n"\r
-       "       else                                                                                                                                                    \n"\r
-       "               return ycbcra_to_rgba_sd(y, cb, cr, a);                                                                         \n"\r
-       "}                                                                                                                                                                      \n"\r
-       "                                                                                                                                                                       \n"\r
-       "vec4 get_sample(sampler2D sampler, vec2 coords, vec2 size)                                                     \n"\r
-       "{                                                                                                                                                                      \n"\r
-       "       switch(deinterlace)                                                                                                                             \n"\r
-       "       {                                                                                                                                                               \n"\r
-       "       case 1: // upper                                                                                                                                \n"\r
-       "               return texture2D(sampler, coords);                                                                                      \n"\r
-       "       case 2: // lower                                                                                                                                \n"\r
-       "               return texture2D(sampler, coords);                                                                                      \n"\r
-       "       default:                                                                                                                                                \n"\r
-       "               return texture2D(sampler, coords);                                                                                      \n"\r
-       "       }                                                                                                                                                               \n"\r
-       "}                                                                                                                                                                      \n"\r
-       "                                                                                                                                                                       \n"\r
-       "vec4 get_rgba_color()                                                                                                                          \n"\r
-       "{                                                                                                                                                                      \n"\r
-       "       switch(pixel_format)                                                                                                                    \n"\r
-       "       {                                                                                                                                                               \n"\r
-       "       case 0:         //gray                                                                                                                          \n"\r
-       "               return vec4(get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rrr, 1.0);\n"\r
-       "       case 1:         //bgra,                                                                                                                         \n"\r
-       "               return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).bgra;                     \n"\r
-       "       case 2:         //rgba,                                                                                                                         \n"\r
-       "               return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rgba;                     \n"\r
-       "       case 3:         //argb,                                                                                                                         \n"\r
-       "               return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).argb;                     \n"\r
-       "       case 4:         //abgr,                                                                                                                         \n"\r
-       "               return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).gbar;                     \n"\r
-       "       case 5:         //ycbcr,                                                                                                                        \n"\r
-       "               {                                                                                                                                                       \n"\r
-       "                       float y  = get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).r;    \n"\r
-       "                       float cb = get_sample(plane[1], gl_TexCoord[0].st, plane_size[0]).r;    \n"\r
-       "                       float cr = get_sample(plane[2], gl_TexCoord[0].st, plane_size[0]).r;    \n"\r
-       "                       return ycbcra_to_rgba(y, cb, cr, 1.0);                                                                  \n"\r
-       "               }                                                                                                                                                       \n"\r
-       "       case 6:         //ycbcra                                                                                                                        \n"\r
-       "               {                                                                                                                                                       \n"\r
-       "                       float y  = get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).r;    \n"\r
-       "                       float cb = get_sample(plane[1], gl_TexCoord[0].st, plane_size[0]).r;    \n"\r
-       "                       float cr = get_sample(plane[2], gl_TexCoord[0].st, plane_size[0]).r;    \n"\r
-       "                       float a  = get_sample(plane[3], gl_TexCoord[0].st, plane_size[0]).r;    \n"\r
-       "                       return ycbcra_to_rgba(y, cb, cr, a);                                                                    \n"\r
-       "               }                                                                                                                                                       \n"\r
-       "       case 7:         //luma                                                                                                                          \n"\r
-       "               {                                                                                                                                                       \n"\r
-       "                       vec3 y3 = get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rrr;   \n"\r
-       "                       return vec4((y3-0.065)/0.859, 1.0);                                                                             \n"\r
-       "               }                                                                                                                                                       \n"\r
-       "       case 8:         //bgr,                                                                                                                          \n"\r
-       "               return vec4(get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).bgr, 1.0);\n"\r
-       "       case 9:         //rgb,                                                                                                                          \n"\r
-       "               return vec4(get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rgb, 1.0);\n"\r
-       "       }                                                                                                                                                               \n"\r
-       "       return vec4(0.0, 0.0, 0.0, 0.0);                                                                                                \n"\r
-       "}                                                                                                                                                                      \n"\r
-       "                                                                                                                                                                       \n"\r
-       "void main()                                                                                                                                            \n"\r
-       "{                                                                                                                                                                      \n"\r
-       "       vec4 color = get_rgba_color();                                                                                                  \n"\r
-       "   if(levels)                                                                                                                                          \n"\r
-       "               color.rgb = LevelsControl(color.rgb, min_input, max_input, gamma, min_output, max_output); \n"\r
-       "       if(csb)                                                                                                                                                 \n"\r
-       "               color.rgb = ContrastSaturationBrightness(color.rgb, brt, sat, con);                     \n"\r
-       "       if(has_local_key)                                                                                                                               \n"\r
-       "               color *= texture2D(local_key, gl_TexCoord[1].st).r;                                                     \n"\r
-       "       if(has_layer_key)                                                                                                                               \n"\r
-       "               color *= texture2D(layer_key, gl_TexCoord[1].st).r;                                                     \n"\r
-       "       color *= opacity;                                                                                                                               \n"\r
-       "       color = blend(color);                                                                                                                   \n"\r
-       "       gl_FragColor = color.bgra;                                                                                                              \n"\r
-       "}                                                                                                                                                                      \n";\r
-}\r
-\r
-spl::shared_ptr<shader> get_image_shader(bool& blend_modes)\r
-{\r
-       tbb::mutex::scoped_lock lock(g_shader_mutex);\r
-\r
-       if(g_shader)\r
-       {\r
-               blend_modes = g_blend_modes;\r
-               return spl::make_shared_ptr(g_shader);\r
-       }\r
-               \r
-       try\r
-       {                               \r
-               g_blend_modes  = glTextureBarrierNV ? env::properties().get(L"configuration.blend-modes", true) : false;\r
-               g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)));\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";\r
-                               \r
-               g_blend_modes = false;\r
-               g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)));\r
-       }\r
-                                               \r
-       //if(!g_blend_modes)\r
-       //{\r
-       //      ogl.blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);\r
-       //      CASPAR_LOG(info) << L"[shader] Blend-modes are disabled.";\r
-       //}\r
-\r
-       blend_modes = g_blend_modes;\r
-       return spl::make_shared_ptr(g_shader);\r
-}\r
-\r
-}}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "image_shader.h"
+
+#include "../util/shader.h"
+#include "../util/device.h"
+
+#include "blending_glsl.h"
+
+#include <common/gl/gl_check.h>
+#include <common/env.h>
+
+#include <tbb/mutex.h>
+
+namespace caspar { namespace accelerator { namespace ogl {
+
+std::shared_ptr<shader> g_shader;
+tbb::mutex                             g_shader_mutex;
+bool                                   g_blend_modes = false;
+
+std::string get_blend_color_func()
+{
+       return 
+                       
+       get_adjustement_glsl()
+               
+       +
+
+       get_blend_glsl()
+               
+       +
+                       
+       "vec3 get_blend_color(vec3 back, vec3 fore)                                                                                     \n"
+       "{                                                                                                                                                                      \n"
+       "       switch(blend_mode)                                                                                                                              \n"
+       "       {                                                                                                                                                               \n"
+       "       case  0: return BlendNormal(back, fore);                                                                                \n"
+       "       case  1: return BlendLighten(back, fore);                                                                               \n"
+       "       case  2: return BlendDarken(back, fore);                                                                                \n"
+       "       case  3: return BlendMultiply(back, fore);                                                                              \n"
+       "       case  4: return BlendAverage(back, fore);                                                                               \n"
+       "       case  5: return BlendAdd(back, fore);                                                                                   \n"
+       "       case  6: return BlendSubstract(back, fore);                                                                             \n"
+       "       case  7: return BlendDifference(back, fore);                                                                    \n"
+       "       case  8: return BlendNegation(back, fore);                                                                              \n"
+       "       case  9: return BlendExclusion(back, fore);                                                                             \n"
+       "       case 10: return BlendScreen(back, fore);                                                                                \n"
+       "       case 11: return BlendOverlay(back, fore);                                                                               \n"
+       //"     case 12: return BlendSoftLight(back, fore);                                                                             \n"
+       "       case 13: return BlendHardLight(back, fore);                                                                             \n"
+       "       case 14: return BlendColorDodge(back, fore);                                                                    \n"
+       "       case 15: return BlendColorBurn(back, fore);                                                                             \n"
+       "       case 16: return BlendLinearDodge(back, fore);                                                                   \n"
+       "       case 17: return BlendLinearBurn(back, fore);                                                                    \n"
+       "       case 18: return BlendLinearLight(back, fore);                                                                   \n"
+       "       case 19: return BlendVividLight(back, fore);                                                                    \n"
+       "       case 20: return BlendPinLight(back, fore);                                                                              \n"
+       "       case 21: return BlendHardMix(back, fore);                                                                               \n"
+       "       case 22: return BlendReflect(back, fore);                                                                               \n"
+       "       case 23: return BlendGlow(back, fore);                                                                                  \n"
+       "       case 24: return BlendPhoenix(back, fore);                                                                               \n"
+       "       case 25: return BlendHue(back, fore);                                                                                   \n"
+       "       case 26: return BlendSaturation(back, fore);                                                                    \n"
+       "       case 27: return BlendColor(back, fore);                                                                                 \n"
+       "       case 28: return BlendLuminosity(back, fore);                                                                    \n"
+       "       }                                                                                                                                                               \n"
+       "       return BlendNormal(back, fore);                                                                                                 \n"
+       "}                                                                                                                                                                      \n"
+       "                                                                                                                                                                       \n"                                                                                                                                                       
+       "vec4 blend(vec4 fore)                                                                                                                          \n"
+       "{                                                                                                                                                                      \n"
+       "   vec4 back = texture2D(background, gl_TexCoord[1].st).bgra;                                          \n"
+       "   if(blend_mode != 0)                                                                                                                         \n"
+       "               fore.rgb = get_blend_color(back.rgb/(back.a+0.0000001), fore.rgb/(fore.a+0.0000001))*fore.a;\n"
+       "       switch(keyer)                                                                                                                                   \n"     
+       "       {                                                                                                                                                               \n"     
+       "               case 1:  return fore + back; // additive                                                                        \n"
+       "               default: return fore + (1.0-fore.a)*back; // linear                                                     \n"
+       "       }                                                                                                                                                               \n"
+       "}                                                                                                                                                                      \n";                    
+}
+               
+std::string get_simple_blend_color_func()
+{
+       return  
+               
+       get_adjustement_glsl()
+                       
+       +
+
+       "vec4 blend(vec4 fore)                                                                                                                          \n"
+       "{                                                                                                                                                                      \n"
+       "       return fore;                                                                                                                                    \n"
+       "}                                                                                                                                                                      \n";
+}
+
+std::string get_vertex()
+{
+       return 
+
+       "void main()                                                                                                                                            \n"
+       "{                                                                                                                                                                      \n"
+       "       gl_TexCoord[0] = gl_MultiTexCoord0;                                                                                             \n"
+       "       gl_TexCoord[1] = gl_MultiTexCoord1;                                                                                             \n"
+       "       gl_Position    = ftransform();                                                                                                  \n"
+       "}                                                                                                                                                                      \n";
+}
+
+std::string get_fragment(bool blend_modes)
+{
+       return
+
+       "#version 130                                                                                                                                           \n"
+       "uniform sampler2D      background;                                                                                                             \n"
+       "uniform sampler2D      plane[4];                                                                                                               \n"
+       "uniform vec2           plane_size[4];                                                                                                  \n"
+       "uniform sampler2D      local_key;                                                                                                              \n"
+       "uniform sampler2D      layer_key;                                                                                                              \n"
+       "                                                                                                                                                                       \n"
+       "uniform bool           is_hd;                                                                                                                  \n"
+       "uniform bool           has_local_key;                                                                                                  \n"
+       "uniform bool           has_layer_key;                                                                                                  \n"
+       "uniform int            blend_mode;                                                                                                             \n"
+       "uniform int            keyer;                                                                                                                  \n"
+       "uniform int            pixel_format;                                                                                                   \n"
+       "uniform int            deinterlace;                                                                                                    \n"
+       "                                                                                                                                                                       \n"
+       "uniform float          opacity;                                                                                                                \n"
+       "uniform bool           levels;                                                                                                                 \n"
+       "uniform float          min_input;                                                                                                              \n"
+       "uniform float          max_input;                                                                                                              \n"
+       "uniform float          gamma;                                                                                                                  \n"
+       "uniform float          min_output;                                                                                                             \n"
+       "uniform float          max_output;                                                                                                             \n"
+       "                                                                                                                                                                       \n"
+       "uniform bool           csb;                                                                                                                    \n"
+       "uniform float          brt;                                                                                                                    \n"
+       "uniform float          sat;                                                                                                                    \n"
+       "uniform float          con;                                                                                                                    \n"
+       "                                                                                                                                                                       \n"     
+
+       +
+               
+       (blend_modes ? get_blend_color_func() : get_simple_blend_color_func())
+
+       +
+       
+       "                                                                                                                                                                       \n"
+       "vec4 ycbcra_to_rgba_sd(float Y, float Cb, float Cr, float A)                                           \n"
+       "{                                                                                                                                                                      \n"
+       "   vec4 rgba;                                                                                                                                          \n"
+       "   rgba.b = (1.164*(Y*255 - 16) + 1.596*(Cr*255 - 128))/255;                                           \n"
+       "   rgba.g = (1.164*(Y*255 - 16) - 0.813*(Cr*255 - 128) - 0.391*(Cb*255 - 128))/255;\n"
+       "   rgba.r = (1.164*(Y*255 - 16) + 2.018*(Cb*255 - 128))/255;                                           \n"
+       "   rgba.a = A;                                                                                                                                         \n"
+       "       return rgba;                                                                                                                                    \n"     
+       "}                                                                                                                                                                      \n"                     
+       "                                                                                                                                                                       \n"
+       "vec4 ycbcra_to_rgba_hd(float Y, float Cb, float Cr, float A)                                           \n"
+       "{                                                                                                                                                                      \n"
+       "   vec4 rgba;                                                                                                                                          \n"
+       "   rgba.b = (1.164*(Y*255 - 16) + 1.793*(Cr*255 - 128))/255;                                           \n"
+       "   rgba.g = (1.164*(Y*255 - 16) - 0.534*(Cr*255 - 128) - 0.213*(Cb*255 - 128))/255;\n"
+       "   rgba.r = (1.164*(Y*255 - 16) + 2.115*(Cb*255 - 128))/255;                                           \n"
+       "   rgba.a = A;                                                                                                                                         \n"
+       "       return rgba;                                                                                                                                    \n"
+       "}                                                                                                                                                                      \n"                                     
+       "                                                                                                                                                                       \n"             
+       "vec4 ycbcra_to_rgba(float y, float cb, float cr, float a)                                                      \n"
+       "{                                                                                                                                                                      \n"
+       "       if(is_hd)                                                                                                                                               \n"
+       "               return ycbcra_to_rgba_hd(y, cb, cr, a);                                                                         \n"
+       "       else                                                                                                                                                    \n"
+       "               return ycbcra_to_rgba_sd(y, cb, cr, a);                                                                         \n"
+       "}                                                                                                                                                                      \n"
+       "                                                                                                                                                                       \n"
+       "vec4 get_sample(sampler2D sampler, vec2 coords, vec2 size)                                                     \n"
+       "{                                                                                                                                                                      \n"
+       "       switch(deinterlace)                                                                                                                             \n"
+       "       {                                                                                                                                                               \n"
+       "       case 1: // upper                                                                                                                                \n"
+       "               return texture2D(sampler, coords);                                                                                      \n"
+       "       case 2: // lower                                                                                                                                \n"
+       "               return texture2D(sampler, coords);                                                                                      \n"
+       "       default:                                                                                                                                                \n"
+       "               return texture2D(sampler, coords);                                                                                      \n"
+       "       }                                                                                                                                                               \n"
+       "}                                                                                                                                                                      \n"
+       "                                                                                                                                                                       \n"
+       "vec4 get_rgba_color()                                                                                                                          \n"
+       "{                                                                                                                                                                      \n"
+       "       switch(pixel_format)                                                                                                                    \n"
+       "       {                                                                                                                                                               \n"
+       "       case 0:         //gray                                                                                                                          \n"
+       "               return vec4(get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rrr, 1.0);\n"
+       "       case 1:         //bgra,                                                                                                                         \n"
+       "               return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).bgra;                     \n"
+       "       case 2:         //rgba,                                                                                                                         \n"
+       "               return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rgba;                     \n"
+       "       case 3:         //argb,                                                                                                                         \n"
+       "               return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).argb;                     \n"
+       "       case 4:         //abgr,                                                                                                                         \n"
+       "               return get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).gbar;                     \n"
+       "       case 5:         //ycbcr,                                                                                                                        \n"
+       "               {                                                                                                                                                       \n"
+       "                       float y  = get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).r;    \n"
+       "                       float cb = get_sample(plane[1], gl_TexCoord[0].st, plane_size[0]).r;    \n"
+       "                       float cr = get_sample(plane[2], gl_TexCoord[0].st, plane_size[0]).r;    \n"
+       "                       return ycbcra_to_rgba(y, cb, cr, 1.0);                                                                  \n"
+       "               }                                                                                                                                                       \n"
+       "       case 6:         //ycbcra                                                                                                                        \n"
+       "               {                                                                                                                                                       \n"
+       "                       float y  = get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).r;    \n"
+       "                       float cb = get_sample(plane[1], gl_TexCoord[0].st, plane_size[0]).r;    \n"
+       "                       float cr = get_sample(plane[2], gl_TexCoord[0].st, plane_size[0]).r;    \n"
+       "                       float a  = get_sample(plane[3], gl_TexCoord[0].st, plane_size[0]).r;    \n"
+       "                       return ycbcra_to_rgba(y, cb, cr, a);                                                                    \n"
+       "               }                                                                                                                                                       \n"
+       "       case 7:         //luma                                                                                                                          \n"
+       "               {                                                                                                                                                       \n"
+       "                       vec3 y3 = get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rrr;   \n"
+       "                       return vec4((y3-0.065)/0.859, 1.0);                                                                             \n"
+       "               }                                                                                                                                                       \n"
+       "       case 8:         //bgr,                                                                                                                          \n"
+       "               return vec4(get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).bgr, 1.0);\n"
+       "       case 9:         //rgb,                                                                                                                          \n"
+       "               return vec4(get_sample(plane[0], gl_TexCoord[0].st, plane_size[0]).rgb, 1.0);\n"
+       "       }                                                                                                                                                               \n"
+       "       return vec4(0.0, 0.0, 0.0, 0.0);                                                                                                \n"
+       "}                                                                                                                                                                      \n"
+       "                                                                                                                                                                       \n"
+       "void main()                                                                                                                                            \n"
+       "{                                                                                                                                                                      \n"
+       "       vec4 color = get_rgba_color();                                                                                                  \n"
+       "   if(levels)                                                                                                                                          \n"
+       "               color.rgb = LevelsControl(color.rgb, min_input, max_input, gamma, min_output, max_output); \n"
+       "       if(csb)                                                                                                                                                 \n"
+       "               color.rgb = ContrastSaturationBrightness(color.rgb, brt, sat, con);                     \n"
+       "       if(has_local_key)                                                                                                                               \n"
+       "               color *= texture2D(local_key, gl_TexCoord[1].st).r;                                                     \n"
+       "       if(has_layer_key)                                                                                                                               \n"
+       "               color *= texture2D(layer_key, gl_TexCoord[1].st).r;                                                     \n"
+       "       color *= opacity;                                                                                                                               \n"
+       "       color = blend(color);                                                                                                                   \n"
+       "       gl_FragColor = color.bgra;                                                                                                              \n"
+       "}                                                                                                                                                                      \n";
+}
+
+spl::shared_ptr<shader> get_image_shader(bool& blend_modes)
+{
+       tbb::mutex::scoped_lock lock(g_shader_mutex);
+
+       if(g_shader)
+       {
+               blend_modes = g_blend_modes;
+               return spl::make_shared_ptr(g_shader);
+       }
+               
+       try
+       {                               
+               g_blend_modes  = glTextureBarrierNV ? env::properties().get(L"configuration.blend-modes", true) : false;
+               g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)));
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";
+                               
+               g_blend_modes = false;
+               g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes)));
+       }
+                                               
+       //if(!g_blend_modes)
+       //{
+       //      ogl.blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+       //      CASPAR_LOG(info) << L"[shader] Blend-modes are disabled.";
+       //}
+
+       blend_modes = g_blend_modes;
+       return spl::make_shared_ptr(g_shader);
+}
+
+}}}
index 952f0716805731d453307c6a39c8f64eb5e39dbc..368714bb78cdad1a6549329a9ff699bd683be61c 100644 (file)
@@ -1,48 +1,48 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-\r
-class shader;\r
-class device;\r
-\r
-struct texture_id\r
-{\r
-       enum type\r
-       {\r
-               plane0 = 0,\r
-               plane1,\r
-               plane2,\r
-               plane3,\r
-               local_key,\r
-               layer_key,\r
-               background,\r
-       };\r
-};\r
-\r
-spl::shared_ptr<shader> get_image_shader(bool& blend_modes);\r
-\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+namespace caspar { namespace accelerator { namespace ogl {
+
+class shader;
+class device;
+
+struct texture_id
+{
+       enum type
+       {
+               plane0 = 0,
+               plane1,
+               plane2,
+               plane3,
+               local_key,
+               layer_key,
+               background,
+       };
+};
+
+spl::shared_ptr<shader> get_image_shader(bool& blend_modes);
+
+
 }}}
\ No newline at end of file
index fa4e18005c9ecb99f8ae59931c51530b10f98bac..5700ac13162c9a58f2095a263745f51105e796e4 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "buffer.h"\r
-\r
-#include "texture.h"\r
-#include "device.h"\r
-\r
-#include <common/except.h>\r
-#include <common/gl/gl_check.h>\r
-\r
-#include <gl/glew.h>\r
-\r
-#include <tbb/atomic.h>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-\r
-static tbb::atomic<int> g_w_total_count;\r
-static tbb::atomic<int> g_r_total_count;\r
-                                                                                                                                                                                                                                                                                                                               \r
-struct buffer::impl : boost::noncopyable\r
-{      \r
-       GLuint                                          pbo_;\r
-       const std::size_t                       size_;\r
-       tbb::atomic<uint8_t*>           data_;\r
-       GLenum                                          usage_;\r
-       GLenum                                          target_;\r
-\r
-public:\r
-       impl(std::size_t size, buffer::usage usage) \r
-               : size_(size)\r
-               , target_(usage == buffer::usage::write_only ? GL_PIXEL_UNPACK_BUFFER : GL_PIXEL_PACK_BUFFER)\r
-               , usage_(usage == buffer::usage::write_only ? GL_STREAM_DRAW : GL_STREAM_READ)\r
-       {\r
-               boost::timer timer;\r
-\r
-               data_ = nullptr;\r
-               GL(glGenBuffers(1, &pbo_));\r
-               bind(); \r
-               GL(glBufferData(target_, size_, NULL, usage_));         \r
-               if(usage_ == GL_STREAM_DRAW)    \r
-                       data_ = (uint8_t*)GL2(glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY));  \r
-               unbind();\r
-\r
-               if(!pbo_)\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to allocate buffer."));\r
-               \r
-               if(timer.elapsed() > 0.02)\r
-                       CASPAR_LOG(debug) << L"[buffer] Performance warning. Buffer allocation blocked: " << timer.elapsed();\r
-       \r
-               //CASPAR_LOG(trace) << "[buffer] [" << ++(usage_ == buffer::usage::write_only ? g_w_total_count : g_r_total_count) << L"] allocated size:" << size_ << " usage: " << (usage == buffer::usage::write_only ? "write_only" : "read_only");\r
-       }       \r
-\r
-       ~impl()\r
-       {\r
-               glDeleteBuffers(1, &pbo_);\r
-       }\r
-\r
-       void* map()\r
-       {\r
-               if(data_ != nullptr)\r
-                       return data_;\r
-               \r
-               boost::timer timer;\r
-\r
-               GL(glBindBuffer(target_, pbo_));\r
-               if(usage_ == GL_STREAM_DRAW)                    \r
-                       GL(glBufferData(target_, size_, NULL, usage_)); // Notify OpenGL that we don't care about previous data.\r
-               \r
-               data_ = (uint8_t*)GL2(glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY));  \r
-\r
-               if(timer.elapsed() > 0.02)\r
-                       CASPAR_LOG(debug) << L"[buffer] Performance warning. Buffer mapping blocked: " << timer.elapsed();\r
-\r
-               GL(glBindBuffer(target_, 0));\r
-               if(!data_)\r
-                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to map target OpenGL Pixel Buffer Object."));\r
-\r
-               return data_;\r
-       }\r
-       \r
-       void unmap()\r
-       {\r
-               if(data_ == nullptr)\r
-                       return;\r
-               \r
-               GL(glBindBuffer(target_, pbo_));\r
-               GL(glUnmapBuffer(target_));     \r
-               if(usage_ == GL_STREAM_READ)                    \r
-                       GL(glBufferData(target_, size_, NULL, usage_)); // Notify OpenGL that we don't care about previous data.\r
-               data_ = nullptr;        \r
-               GL(glBindBuffer(target_, 0));\r
-       }\r
-\r
-       void bind()\r
-       {\r
-               GL(glBindBuffer(target_, pbo_));\r
-       }\r
-\r
-       void unbind()\r
-       {\r
-               GL(glBindBuffer(target_, 0));\r
-       }\r
-};\r
-\r
-buffer::buffer(std::size_t size, usage usage) : impl_(new impl(size, usage)){}\r
-buffer::buffer(buffer&& other) : impl_(std::move(other.impl_)){}\r
-buffer::~buffer(){}\r
-buffer& buffer::operator=(buffer&& other){impl_ = std::move(other.impl_); return *this;}\r
-uint8_t* buffer::data(){return impl_->data_;}\r
-void buffer::map(){impl_->map();}\r
-void buffer::unmap(){impl_->unmap();}\r
-void buffer::bind() const{impl_->bind();}\r
-void buffer::unbind() const{impl_->unbind();}\r
-std::size_t buffer::size() const { return impl_->size_; }\r
-int buffer::id() const {return impl_->pbo_;}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "buffer.h"
+
+#include "texture.h"
+#include "device.h"
+
+#include <common/except.h>
+#include <common/gl/gl_check.h>
+
+#include <gl/glew.h>
+
+#include <tbb/atomic.h>
+
+namespace caspar { namespace accelerator { namespace ogl {
+
+static tbb::atomic<int> g_w_total_count;
+static tbb::atomic<int> g_r_total_count;
+                                                                                                                                                                                                                                                                                                                               
+struct buffer::impl : boost::noncopyable
+{      
+       GLuint                                          pbo_;
+       const std::size_t                       size_;
+       tbb::atomic<uint8_t*>           data_;
+       GLenum                                          usage_;
+       GLenum                                          target_;
+
+public:
+       impl(std::size_t size, buffer::usage usage) 
+               : size_(size)
+               , target_(usage == buffer::usage::write_only ? GL_PIXEL_UNPACK_BUFFER : GL_PIXEL_PACK_BUFFER)
+               , usage_(usage == buffer::usage::write_only ? GL_STREAM_DRAW : GL_STREAM_READ)
+       {
+               boost::timer timer;
+
+               data_ = nullptr;
+               GL(glGenBuffers(1, &pbo_));
+               bind(); 
+               GL(glBufferData(target_, size_, NULL, usage_));         
+               if(usage_ == GL_STREAM_DRAW)    
+                       data_ = (uint8_t*)GL2(glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY));  
+               unbind();
+
+               if(!pbo_)
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to allocate buffer."));
+               
+               if(timer.elapsed() > 0.02)
+                       CASPAR_LOG(debug) << L"[buffer] Performance warning. Buffer allocation blocked: " << timer.elapsed();
+       
+               //CASPAR_LOG(trace) << "[buffer] [" << ++(usage_ == buffer::usage::write_only ? g_w_total_count : g_r_total_count) << L"] allocated size:" << size_ << " usage: " << (usage == buffer::usage::write_only ? "write_only" : "read_only");
+       }       
+
+       ~impl()
+       {
+               glDeleteBuffers(1, &pbo_);
+       }
+
+       void* map()
+       {
+               if(data_ != nullptr)
+                       return data_;
+               
+               boost::timer timer;
+
+               GL(glBindBuffer(target_, pbo_));
+               if(usage_ == GL_STREAM_DRAW)                    
+                       GL(glBufferData(target_, size_, NULL, usage_)); // Notify OpenGL that we don't care about previous data.
+               
+               data_ = (uint8_t*)GL2(glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY));  
+
+               if(timer.elapsed() > 0.02)
+                       CASPAR_LOG(debug) << L"[buffer] Performance warning. Buffer mapping blocked: " << timer.elapsed();
+
+               GL(glBindBuffer(target_, 0));
+               if(!data_)
+                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to map target OpenGL Pixel Buffer Object."));
+
+               return data_;
+       }
+       
+       void unmap()
+       {
+               if(data_ == nullptr)
+                       return;
+               
+               GL(glBindBuffer(target_, pbo_));
+               GL(glUnmapBuffer(target_));     
+               if(usage_ == GL_STREAM_READ)                    
+                       GL(glBufferData(target_, size_, NULL, usage_)); // Notify OpenGL that we don't care about previous data.
+               data_ = nullptr;        
+               GL(glBindBuffer(target_, 0));
+       }
+
+       void bind()
+       {
+               GL(glBindBuffer(target_, pbo_));
+       }
+
+       void unbind()
+       {
+               GL(glBindBuffer(target_, 0));
+       }
+};
+
+buffer::buffer(std::size_t size, usage usage) : impl_(new impl(size, usage)){}
+buffer::buffer(buffer&& other) : impl_(std::move(other.impl_)){}
+buffer::~buffer(){}
+buffer& buffer::operator=(buffer&& other){impl_ = std::move(other.impl_); return *this;}
+uint8_t* buffer::data(){return impl_->data_;}
+void buffer::map(){impl_->map();}
+void buffer::unmap(){impl_->unmap();}
+void buffer::bind() const{impl_->bind();}
+void buffer::unbind() const{impl_->unbind();}
+std::size_t buffer::size() const { return impl_->size_; }
+int buffer::id() const {return impl_->pbo_;}
+
 }}}
\ No newline at end of file
index c60a0c0fa935a56c65a97b1421bb2fb86b76969f..2b2c00863bd3d5136d8690142d7081cc24952461 100644 (file)
@@ -1,77 +1,77 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-#include <common/enum_class.h>\r
-\r
-#include <cstdint>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-                       \r
-class buffer sealed\r
-{\r
-       buffer(const buffer&);\r
-       buffer& operator=(const buffer&);\r
-public:\r
-\r
-       // Static Members\r
-\r
-       struct usage_def\r
-       {\r
-               enum type\r
-               {\r
-                       write_only,\r
-                       read_only\r
-               };\r
-       };\r
-       typedef enum_class<usage_def> usage;\r
-       \r
-       // Constructors\r
-\r
-       buffer(std::size_t size, usage usage);\r
-       buffer(buffer&& other);\r
-       ~buffer();\r
-\r
-       // Methods\r
-\r
-       buffer& operator=(buffer&& other);\r
-       \r
-       void map();\r
-       void unmap();\r
-\r
-       void bind() const;\r
-       void unbind() const;\r
-\r
-       // Properties\r
-\r
-       uint8_t* data();\r
-       std::size_t size() const;       \r
-\r
-       int id() const;\r
-\r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+#include <common/enum_class.h>
+
+#include <cstdint>
+
+namespace caspar { namespace accelerator { namespace ogl {
+                       
+class buffer sealed
+{
+       buffer(const buffer&);
+       buffer& operator=(const buffer&);
+public:
+
+       // Static Members
+
+       struct usage_def
+       {
+               enum type
+               {
+                       write_only,
+                       read_only
+               };
+       };
+       typedef enum_class<usage_def> usage;
+       
+       // Constructors
+
+       buffer(std::size_t size, usage usage);
+       buffer(buffer&& other);
+       ~buffer();
+
+       // Methods
+
+       buffer& operator=(buffer&& other);
+       
+       void map();
+       void unmap();
+
+       void bind() const;
+       void unbind() const;
+
+       // Properties
+
+       uint8_t* data();
+       std::size_t size() const;       
+
+       int id() const;
+
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+
 }}}
\ No newline at end of file
index a4a1ffcd547d50663a36739e1390eb90967f2937..4dc5db8b0d79e0cf89f27d09e511a962c93ab0f0 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-// TODO: Smart GC\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "device.h"\r
-\r
-#include "buffer.h"\r
-#include "texture.h"\r
-#include "shader.h"\r
-\r
-#include <common/assert.h>\r
-#include <common/except.h>\r
-#include <common/future.h>\r
-#include <common/array.h>\r
-#include <common/gl/gl_check.h>\r
-#include <common/os/windows/windows.h>\r
-\r
-#include <boost/foreach.hpp>\r
-\r
-#include <gl/glew.h>\r
-\r
-#include <SFML/Window/Context.hpp>\r
-\r
-#include <tbb/concurrent_unordered_map.h>\r
-#include <tbb/concurrent_hash_map.h>\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <boost/utility/declval.hpp>\r
-\r
-#include <array>\r
-#include <unordered_map>\r
-\r
-#include <asmlib.h>\r
-#include <tbb/parallel_for.h>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-               \r
-struct device::impl : public std::enable_shared_from_this<impl>\r
-{      \r
-       static_assert(std::is_same<decltype(boost::declval<device>().impl_), spl::shared_ptr<impl>>::value, "impl_ must be shared_ptr");\r
-\r
-       tbb::concurrent_hash_map<buffer*, std::shared_ptr<texture>> texture_cache_;\r
-\r
-       std::unique_ptr<sf::Context> device_;\r
-       \r
-       std::array<tbb::concurrent_unordered_map<std::size_t, tbb::concurrent_bounded_queue<std::shared_ptr<texture>>>, 4>      device_pools_;\r
-       std::array<tbb::concurrent_unordered_map<std::size_t, tbb::concurrent_bounded_queue<std::shared_ptr<buffer>>>, 2>       host_pools_;\r
-       \r
-       GLuint fbo_;\r
-\r
-       executor& executor_;\r
-                               \r
-       impl(executor& executor) \r
-               : executor_(executor)\r
-       {\r
-               executor_.set_capacity(256);\r
-\r
-               CASPAR_LOG(info) << L"Initializing OpenGL Device.";\r
-               \r
-               executor_.invoke([=]\r
-               {\r
-                       device_.reset(new sf::Context());\r
-                       device_->SetActive(true);               \r
-                                               \r
-                       if (glewInit() != GLEW_OK)\r
-                               CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to initialize GLEW."));\r
-               \r
-                       if(!GLEW_VERSION_3_0)\r
-                               CASPAR_THROW_EXCEPTION(not_supported() << msg_info("Your graphics card does not meet the minimum hardware requirements since it does not support OpenGL 3.0 or higher."));\r
-       \r
-                       glGenFramebuffers(1, &fbo_);                            \r
-                       glBindFramebuffer(GL_FRAMEBUFFER, fbo_);\r
-               });\r
-                               \r
-               CASPAR_LOG(info) << L"Successfully initialized OpenGL " << version();\r
-       }\r
-\r
-       ~impl()\r
-       {\r
-               executor_.invoke([=]\r
-               {\r
-                       BOOST_FOREACH(auto& pool, device_pools_)\r
-                               pool.clear();\r
-                       glDeleteFramebuffers(1, &fbo_);\r
-\r
-                       device_.reset();\r
-               });\r
-       }\r
-               \r
-       std::wstring version()\r
-       {       \r
-               try\r
-               {\r
-                       return executor_.invoke([]\r
-                       {\r
-                               return u16(reinterpret_cast<const char*>(GL2(glGetString(GL_VERSION)))) + L" " + u16(reinterpret_cast<const char*>(GL2(glGetString(GL_VENDOR))));\r
-                       });     \r
-               }\r
-               catch(...)\r
-               {\r
-                       return L"Not found";;\r
-               }\r
-       }\r
-                                                       \r
-       spl::shared_ptr<texture> create_texture(int width, int height, int stride, bool clear = false)\r
-       {\r
-               CASPAR_VERIFY(stride > 0 && stride < 5);\r
-               CASPAR_VERIFY(width > 0 && height > 0);\r
-\r
-               if(!executor_.is_current())\r
-                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Operation only valid in an OpenGL Context."));\r
-                                       \r
-               auto pool = &device_pools_[stride-1][((width << 16) & 0xFFFF0000) | (height & 0x0000FFFF)];\r
-               \r
-               std::shared_ptr<texture> tex;\r
-               if(!pool->try_pop(tex))         \r
-                       tex = spl::make_shared<texture>(width, height, stride);\r
-       \r
-               if(clear)\r
-                       tex->clear();\r
-\r
-               return spl::shared_ptr<texture>(tex.get(), [tex, pool](texture*) mutable\r
-               {               \r
-                       pool->push(tex);        \r
-               });\r
-       }\r
-               \r
-       spl::shared_ptr<buffer> create_buffer(std::size_t size, buffer::usage usage)\r
-       {\r
-               CASPAR_VERIFY(size > 0);\r
-               \r
-               auto pool = &host_pools_[usage.value()][size];\r
-               \r
-               std::shared_ptr<buffer> buf;\r
-               if(!pool->try_pop(buf)) \r
-               {\r
-                       boost::timer timer;\r
-\r
-                       buf = executor_.invoke([&]\r
-                       {\r
-                               return spl::make_shared<buffer>(size, usage);\r
-                       }, task_priority::high_priority);\r
-                       \r
-                       if(timer.elapsed() > 0.02)\r
-                               CASPAR_LOG(debug) << L"[ogl-device] Performance warning. Buffer allocation blocked: " << timer.elapsed();\r
-               }\r
-               \r
-               auto self = shared_from_this(); // buffers can leave the device context, take a hold on life-time.\r
-               return spl::shared_ptr<buffer>(buf.get(), [=](buffer*) mutable\r
-               {       \r
-                       texture_cache_.erase(buf.get());\r
-                       pool->push(buf);\r
-               });\r
-       }\r
-\r
-       array<std::uint8_t> create_array(std::size_t size)\r
-       {               \r
-               auto buf = create_buffer(size, buffer::usage::write_only);\r
-               return array<std::uint8_t>(buf->data(), buf->size(), false, buf);\r
-       }\r
-\r
-       template<typename T>\r
-       std::shared_ptr<buffer> copy_to_buf(const T& source)\r
-       {\r
-               std::shared_ptr<buffer> buf;\r
-\r
-               auto tmp = source.storage<spl::shared_ptr<buffer>>();\r
-               if(tmp)\r
-                       buf = *tmp;\r
-               else\r
-               {                       \r
-                       buf = create_buffer(source.size(), buffer::usage::write_only);\r
-                       tbb::parallel_for(tbb::blocked_range<std::size_t>(0, source.size()), [&](const tbb::blocked_range<std::size_t>& r)\r
-                       {\r
-                               A_memcpy(buf->data() + r.begin(), source.data() + r.begin(), r.size());\r
-                       });\r
-               }\r
-\r
-               return buf;\r
-       }\r
-\r
-       // TODO: Since the returned texture is cached it SHOULD NOT be modified.\r
-       boost::unique_future<spl::shared_ptr<texture>> copy_async(const array<const std::uint8_t>& source, int width, int height, int stride)\r
-       {\r
-               std::shared_ptr<buffer> buf = copy_to_buf(source);\r
-                               \r
-               return executor_.begin_invoke([=]() -> spl::shared_ptr<texture>\r
-               {\r
-                       tbb::concurrent_hash_map<buffer*, std::shared_ptr<texture>>::const_accessor a;\r
-                       if(texture_cache_.find(a, buf.get()))\r
-                               return spl::make_shared_ptr(a->second);\r
-\r
-                       auto texture = create_texture(width, height, stride);\r
-                       texture->copy_from(*buf);       \r
-\r
-                       texture_cache_.insert(std::make_pair(buf.get(), texture));\r
-                       \r
-                       return texture;\r
-               }, task_priority::high_priority);\r
-       }\r
-       \r
-       boost::unique_future<spl::shared_ptr<texture>> copy_async(const array<std::uint8_t>& source, int width, int height, int stride)\r
-       {\r
-               std::shared_ptr<buffer> buf = copy_to_buf(source);\r
-\r
-               return executor_.begin_invoke([=]() -> spl::shared_ptr<texture>\r
-               {\r
-                       auto texture = create_texture(width, height, stride, false);\r
-                       texture->copy_from(*buf);       \r
-                       \r
-                       return texture;\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<array<const std::uint8_t>> copy_async(const spl::shared_ptr<texture>& source)\r
-       {\r
-               if(!executor_.is_current())\r
-                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Operation only valid in an OpenGL Context."));\r
-\r
-               auto buffer = create_buffer(source->size(), buffer::usage::read_only); \r
-               source->copy_to(*buffer);       \r
-\r
-               auto self = shared_from_this();\r
-               return async(launch::deferred, [self, buffer]() mutable -> array<const std::uint8_t>\r
-               {\r
-                       self->executor_.invoke(std::bind(&buffer::map, std::ref(buffer))); // Defer blocking "map" call until data is needed.\r
-                       return array<const std::uint8_t>(buffer->data(), buffer->size(), true, buffer);\r
-               });\r
-       }\r
-};\r
-\r
-device::device() \r
-       : executor_(L"OpenGL Rendering Context")\r
-       , impl_(new impl(executor_)){}\r
-device::~device(){}\r
-spl::shared_ptr<texture>                                                       device::create_texture(int width, int height, int stride){return impl_->create_texture(width, height, stride, true);}\r
-array<std::uint8_t>                                                                    device::create_array(int size){return impl_->create_array(size);}\r
-boost::unique_future<spl::shared_ptr<texture>>         device::copy_async(const array<const std::uint8_t>& source, int width, int height, int stride){return impl_->copy_async(source, width, height, stride);}\r
-boost::unique_future<spl::shared_ptr<texture>>         device::copy_async(const array<std::uint8_t>& source, int width, int height, int stride){return impl_->copy_async(source, width, height, stride);}\r
-boost::unique_future<array<const std::uint8_t>>                device::copy_async(const spl::shared_ptr<texture>& source){return impl_->copy_async(source);}\r
-std::wstring                                                                           device::version() const{return impl_->version();}\r
-\r
-\r
-}}}\r
-\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+// TODO: Smart GC
+
+#include "../../stdafx.h"
+
+#include "device.h"
+
+#include "buffer.h"
+#include "texture.h"
+#include "shader.h"
+
+#include <common/assert.h>
+#include <common/except.h>
+#include <common/future.h>
+#include <common/array.h>
+#include <common/gl/gl_check.h>
+#include <common/os/windows/windows.h>
+
+#include <boost/foreach.hpp>
+
+#include <gl/glew.h>
+
+#include <SFML/Window/Context.hpp>
+
+#include <tbb/concurrent_unordered_map.h>
+#include <tbb/concurrent_hash_map.h>
+#include <tbb/concurrent_queue.h>
+
+#include <boost/utility/declval.hpp>
+
+#include <array>
+#include <unordered_map>
+
+#include <asmlib.h>
+#include <tbb/parallel_for.h>
+
+namespace caspar { namespace accelerator { namespace ogl {
+               
+struct device::impl : public std::enable_shared_from_this<impl>
+{      
+       static_assert(std::is_same<decltype(boost::declval<device>().impl_), spl::shared_ptr<impl>>::value, "impl_ must be shared_ptr");
+
+       tbb::concurrent_hash_map<buffer*, std::shared_ptr<texture>> texture_cache_;
+
+       std::unique_ptr<sf::Context> device_;
+       
+       std::array<tbb::concurrent_unordered_map<std::size_t, tbb::concurrent_bounded_queue<std::shared_ptr<texture>>>, 4>      device_pools_;
+       std::array<tbb::concurrent_unordered_map<std::size_t, tbb::concurrent_bounded_queue<std::shared_ptr<buffer>>>, 2>       host_pools_;
+       
+       GLuint fbo_;
+
+       executor& executor_;
+                               
+       impl(executor& executor) 
+               : executor_(executor)
+       {
+               executor_.set_capacity(256);
+
+               CASPAR_LOG(info) << L"Initializing OpenGL Device.";
+               
+               executor_.invoke([=]
+               {
+                       device_.reset(new sf::Context());
+                       device_->SetActive(true);               
+                                               
+                       if (glewInit() != GLEW_OK)
+                               CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to initialize GLEW."));
+               
+                       if(!GLEW_VERSION_3_0)
+                               CASPAR_THROW_EXCEPTION(not_supported() << msg_info("Your graphics card does not meet the minimum hardware requirements since it does not support OpenGL 3.0 or higher."));
+       
+                       glGenFramebuffers(1, &fbo_);                            
+                       glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
+               });
+                               
+               CASPAR_LOG(info) << L"Successfully initialized OpenGL " << version();
+       }
+
+       ~impl()
+       {
+               executor_.invoke([=]
+               {
+                       BOOST_FOREACH(auto& pool, device_pools_)
+                               pool.clear();
+                       glDeleteFramebuffers(1, &fbo_);
+
+                       device_.reset();
+               });
+       }
+               
+       std::wstring version()
+       {       
+               try
+               {
+                       return executor_.invoke([]
+                       {
+                               return u16(reinterpret_cast<const char*>(GL2(glGetString(GL_VERSION)))) + L" " + u16(reinterpret_cast<const char*>(GL2(glGetString(GL_VENDOR))));
+                       });     
+               }
+               catch(...)
+               {
+                       return L"Not found";;
+               }
+       }
+                                                       
+       spl::shared_ptr<texture> create_texture(int width, int height, int stride, bool clear = false)
+       {
+               CASPAR_VERIFY(stride > 0 && stride < 5);
+               CASPAR_VERIFY(width > 0 && height > 0);
+
+               if(!executor_.is_current())
+                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Operation only valid in an OpenGL Context."));
+                                       
+               auto pool = &device_pools_[stride-1][((width << 16) & 0xFFFF0000) | (height & 0x0000FFFF)];
+               
+               std::shared_ptr<texture> tex;
+               if(!pool->try_pop(tex))         
+                       tex = spl::make_shared<texture>(width, height, stride);
+       
+               if(clear)
+                       tex->clear();
+
+               return spl::shared_ptr<texture>(tex.get(), [tex, pool](texture*) mutable
+               {               
+                       pool->push(tex);        
+               });
+       }
+               
+       spl::shared_ptr<buffer> create_buffer(std::size_t size, buffer::usage usage)
+       {
+               CASPAR_VERIFY(size > 0);
+               
+               auto pool = &host_pools_[usage.value()][size];
+               
+               std::shared_ptr<buffer> buf;
+               if(!pool->try_pop(buf)) 
+               {
+                       boost::timer timer;
+
+                       buf = executor_.invoke([&]
+                       {
+                               return spl::make_shared<buffer>(size, usage);
+                       }, task_priority::high_priority);
+                       
+                       if(timer.elapsed() > 0.02)
+                               CASPAR_LOG(debug) << L"[ogl-device] Performance warning. Buffer allocation blocked: " << timer.elapsed();
+               }
+               
+               auto self = shared_from_this(); // buffers can leave the device context, take a hold on life-time.
+               return spl::shared_ptr<buffer>(buf.get(), [=](buffer*) mutable
+               {       
+                       texture_cache_.erase(buf.get());
+                       pool->push(buf);
+               });
+       }
+
+       array<std::uint8_t> create_array(std::size_t size)
+       {               
+               auto buf = create_buffer(size, buffer::usage::write_only);
+               return array<std::uint8_t>(buf->data(), buf->size(), false, buf);
+       }
+
+       template<typename T>
+       std::shared_ptr<buffer> copy_to_buf(const T& source)
+       {
+               std::shared_ptr<buffer> buf;
+
+               auto tmp = source.storage<spl::shared_ptr<buffer>>();
+               if(tmp)
+                       buf = *tmp;
+               else
+               {                       
+                       buf = create_buffer(source.size(), buffer::usage::write_only);
+                       tbb::parallel_for(tbb::blocked_range<std::size_t>(0, source.size()), [&](const tbb::blocked_range<std::size_t>& r)
+                       {
+                               A_memcpy(buf->data() + r.begin(), source.data() + r.begin(), r.size());
+                       });
+               }
+
+               return buf;
+       }
+
+       // TODO: Since the returned texture is cached it SHOULD NOT be modified.
+       boost::unique_future<spl::shared_ptr<texture>> copy_async(const array<const std::uint8_t>& source, int width, int height, int stride)
+       {
+               std::shared_ptr<buffer> buf = copy_to_buf(source);
+                               
+               return executor_.begin_invoke([=]() -> spl::shared_ptr<texture>
+               {
+                       tbb::concurrent_hash_map<buffer*, std::shared_ptr<texture>>::const_accessor a;
+                       if(texture_cache_.find(a, buf.get()))
+                               return spl::make_shared_ptr(a->second);
+
+                       auto texture = create_texture(width, height, stride);
+                       texture->copy_from(*buf);       
+
+                       texture_cache_.insert(std::make_pair(buf.get(), texture));
+                       
+                       return texture;
+               }, task_priority::high_priority);
+       }
+       
+       boost::unique_future<spl::shared_ptr<texture>> copy_async(const array<std::uint8_t>& source, int width, int height, int stride)
+       {
+               std::shared_ptr<buffer> buf = copy_to_buf(source);
+
+               return executor_.begin_invoke([=]() -> spl::shared_ptr<texture>
+               {
+                       auto texture = create_texture(width, height, stride, false);
+                       texture->copy_from(*buf);       
+                       
+                       return texture;
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<array<const std::uint8_t>> copy_async(const spl::shared_ptr<texture>& source)
+       {
+               if(!executor_.is_current())
+                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Operation only valid in an OpenGL Context."));
+
+               auto buffer = create_buffer(source->size(), buffer::usage::read_only); 
+               source->copy_to(*buffer);       
+
+               auto self = shared_from_this();
+               return async(launch::deferred, [self, buffer]() mutable -> array<const std::uint8_t>
+               {
+                       self->executor_.invoke(std::bind(&buffer::map, std::ref(buffer))); // Defer blocking "map" call until data is needed.
+                       return array<const std::uint8_t>(buffer->data(), buffer->size(), true, buffer);
+               });
+       }
+};
+
+device::device() 
+       : executor_(L"OpenGL Rendering Context")
+       , impl_(new impl(executor_)){}
+device::~device(){}
+spl::shared_ptr<texture>                                                       device::create_texture(int width, int height, int stride){return impl_->create_texture(width, height, stride, true);}
+array<std::uint8_t>                                                                    device::create_array(int size){return impl_->create_array(size);}
+boost::unique_future<spl::shared_ptr<texture>>         device::copy_async(const array<const std::uint8_t>& source, int width, int height, int stride){return impl_->copy_async(source, width, height, stride);}
+boost::unique_future<spl::shared_ptr<texture>>         device::copy_async(const array<std::uint8_t>& source, int width, int height, int stride){return impl_->copy_async(source, width, height, stride);}
+boost::unique_future<array<const std::uint8_t>>                device::copy_async(const spl::shared_ptr<texture>& source){return impl_->copy_async(source);}
+std::wstring                                                                           device::version() const{return impl_->version();}
+
+
+}}}
+
+
index 2e84080366fe7a78c44d3216fedcb26a759f089a..7577285fd4389cc94d71c2c21312b86e484a177c 100644 (file)
@@ -1,80 +1,80 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <core/frame/frame.h>\r
-\r
-#include <common/memory.h>\r
-#include <common/executor.h>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-\r
-class texture;\r
-\r
-class device sealed : public std::enable_shared_from_this<device>\r
-{      \r
-       device(const device&);\r
-       device& operator=(const device&);\r
-\r
-       executor executor_;\r
-public:                \r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       device();\r
-       ~device();\r
-\r
-       // Methods\r
-                       \r
-       spl::shared_ptr<texture> create_texture(int width, int height, int stride);\r
-       array<std::uint8_t>              create_array(int size);\r
-               \r
-       // NOTE: Since the returned texture is cached it SHOULD NOT be modified.\r
-       boost::unique_future<spl::shared_ptr<texture>>  copy_async(const array<const std::uint8_t>& source, int width, int height, int stride);\r
-\r
-       boost::unique_future<spl::shared_ptr<texture>>  copy_async(const array<std::uint8_t>& source, int width, int height, int stride);\r
-       boost::unique_future<array<const std::uint8_t>> copy_async(const spl::shared_ptr<texture>& source);\r
-                       \r
-       template<typename Func>\r
-       auto begin_invoke(Func&& func, task_priority priority = task_priority::normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
-       {                       \r
-               return executor_.begin_invoke(std::forward<Func>(func), priority);\r
-       }\r
-       \r
-       template<typename Func>\r
-       auto invoke(Func&& func, task_priority priority = task_priority::normal_priority) -> decltype(func())\r
-       {\r
-               return executor_.invoke(std::forward<Func>(func), priority);\r
-       }\r
-\r
-       // Properties\r
-       \r
-       std::wstring version() const;\r
-\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <core/frame/frame.h>
+
+#include <common/memory.h>
+#include <common/executor.h>
+
+namespace caspar { namespace accelerator { namespace ogl {
+
+class texture;
+
+class device sealed : public std::enable_shared_from_this<device>
+{      
+       device(const device&);
+       device& operator=(const device&);
+
+       executor executor_;
+public:                
+
+       // Static Members
+
+       // Constructors
+
+       device();
+       ~device();
+
+       // Methods
+                       
+       spl::shared_ptr<texture> create_texture(int width, int height, int stride);
+       array<std::uint8_t>              create_array(int size);
+               
+       // NOTE: Since the returned texture is cached it SHOULD NOT be modified.
+       boost::unique_future<spl::shared_ptr<texture>>  copy_async(const array<const std::uint8_t>& source, int width, int height, int stride);
+
+       boost::unique_future<spl::shared_ptr<texture>>  copy_async(const array<std::uint8_t>& source, int width, int height, int stride);
+       boost::unique_future<array<const std::uint8_t>> copy_async(const spl::shared_ptr<texture>& source);
+                       
+       template<typename Func>
+       auto begin_invoke(Func&& func, task_priority priority = task_priority::normal_priority) -> boost::unique_future<decltype(func())> // noexcept
+       {                       
+               return executor_.begin_invoke(std::forward<Func>(func), priority);
+       }
+       
+       template<typename Func>
+       auto invoke(Func&& func, task_priority priority = task_priority::normal_priority) -> decltype(func())
+       {
+               return executor_.invoke(std::forward<Func>(func), priority);
+       }
+
+       // Properties
+       
+       std::wstring version() const;
+
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}}
\ No newline at end of file
index d64d9abe23a0b3b3056a045ffe522d7f609a9c5c..3d211f78623a8b1cb4b595c227e181bebd84208b 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "shader.h"\r
-\r
-#include <common/gl/gl_check.h>\r
-\r
-#include <gl/glew.h>\r
-\r
-#include <unordered_map>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-\r
-struct shader::impl : boost::noncopyable\r
-{\r
-       GLuint program_;\r
-       std::unordered_map<std::string, GLint> locations_;\r
-public:\r
-\r
-       impl(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
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << 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
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << 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
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(str.str()));\r
-               }\r
-               GL(glUseProgramObjectARB(program_));\r
-       }\r
-       \r
-       ~impl()\r
-       {\r
-               glDeleteProgram(program_);\r
-       }\r
-\r
-       GLint get_location(const char* name)\r
-       {\r
-               auto it = locations_.find(name);\r
-               if(it == locations_.end())\r
-                       it = locations_.insert(std::make_pair(name, glGetUniformLocation(program_, name))).first;\r
-               return it->second;\r
-       }\r
-       \r
-       void set(const std::string& name, bool value)\r
-       {\r
-               set(name, value ? 1 : 0);\r
-       }\r
-\r
-       void set(const std::string& name, int value)\r
-       {\r
-               GL(glUniform1i(get_location(name.c_str()), value));\r
-       }\r
-       \r
-       void set(const std::string& name, float value)\r
-       {\r
-               GL(glUniform1f(get_location(name.c_str()), value));\r
-       }\r
-       \r
-       void set(const std::string& name, float value0, float value1)\r
-       {\r
-               GL(glUniform2f(get_location(name.c_str()), value0, value1));\r
-       }\r
-\r
-       void set(const std::string& name, double value)\r
-       {\r
-               GL(glUniform1f(get_location(name.c_str()), static_cast<float>(value)));\r
-       }\r
-\r
-       void use()\r
-       {               \r
-               GL(glUseProgramObjectARB(program_));    \r
-       }\r
-};\r
-\r
-shader::shader(const std::string& vertex_source_str, const std::string& fragment_source_str) : impl_(new impl(vertex_source_str, fragment_source_str)){}\r
-shader::~shader(){}\r
-void shader::set(const std::string& name, bool value){impl_->set(name, value);}\r
-void shader::set(const std::string& name, int value){impl_->set(name, value);}\r
-void shader::set(const std::string& name, float value){impl_->set(name, value);}\r
-void shader::set(const std::string& name, float value0, float value1){impl_->set(name, value0, value1);}\r
-void shader::set(const std::string& name, double value){impl_->set(name, value);}\r
-int shader::id() const{return impl_->program_;}\r
-void shader::use()const{impl_->use();}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "shader.h"
+
+#include <common/gl/gl_check.h>
+
+#include <gl/glew.h>
+
+#include <unordered_map>
+
+namespace caspar { namespace accelerator { namespace ogl {
+
+struct shader::impl : boost::noncopyable
+{
+       GLuint program_;
+       std::unordered_map<std::string, GLint> locations_;
+public:
+
+       impl(const std::string& vertex_source_str, const std::string& fragment_source_str) : program_(0)
+       {
+               GLint success;
+       
+               const char* vertex_source = vertex_source_str.c_str();
+                                               
+               auto vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+                                       
+               GL(glShaderSourceARB(vertex_shader, 1, &vertex_source, NULL));
+               GL(glCompileShaderARB(vertex_shader));
+
+               GL(glGetObjectParameterivARB(vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));
+               if (success == GL_FALSE)
+               {
+                       char info[2048];
+                       GL(glGetInfoLogARB(vertex_shader, sizeof(info), 0, info));
+                       GL(glDeleteObjectARB(vertex_shader));
+                       std::stringstream str;
+                       str << "Failed to compile vertex shader:" << std::endl << info << std::endl;
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(str.str()));
+               }
+                       
+               const char* fragment_source = fragment_source_str.c_str();
+                                               
+               auto fragmemt_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+                                       
+               GL(glShaderSourceARB(fragmemt_shader, 1, &fragment_source, NULL));
+               GL(glCompileShaderARB(fragmemt_shader));
+
+               GL(glGetObjectParameterivARB(fragmemt_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success));
+               if (success == GL_FALSE)
+               {
+                       char info[2048];
+                       GL(glGetInfoLogARB(fragmemt_shader, sizeof(info), 0, info));
+                       GL(glDeleteObjectARB(fragmemt_shader));
+                       std::stringstream str;
+                       str << "Failed to compile fragment shader:" << std::endl << info << std::endl;
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(str.str()));
+               }
+                       
+               program_ = glCreateProgramObjectARB();
+                       
+               GL(glAttachObjectARB(program_, vertex_shader));
+               GL(glAttachObjectARB(program_, fragmemt_shader));
+
+               GL(glLinkProgramARB(program_));
+                       
+               GL(glDeleteObjectARB(vertex_shader));
+               GL(glDeleteObjectARB(fragmemt_shader));
+
+               GL(glGetObjectParameterivARB(program_, GL_OBJECT_LINK_STATUS_ARB, &success));
+               if (success == GL_FALSE)
+               {
+                       char info[2048];
+                       GL(glGetInfoLogARB(program_, sizeof(info), 0, info));
+                       GL(glDeleteObjectARB(program_));
+                       std::stringstream str;
+                       str << "Failed to link shader program:" << std::endl << info << std::endl;
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(str.str()));
+               }
+               GL(glUseProgramObjectARB(program_));
+       }
+       
+       ~impl()
+       {
+               glDeleteProgram(program_);
+       }
+
+       GLint get_location(const char* name)
+       {
+               auto it = locations_.find(name);
+               if(it == locations_.end())
+                       it = locations_.insert(std::make_pair(name, glGetUniformLocation(program_, name))).first;
+               return it->second;
+       }
+       
+       void set(const std::string& name, bool value)
+       {
+               set(name, value ? 1 : 0);
+       }
+
+       void set(const std::string& name, int value)
+       {
+               GL(glUniform1i(get_location(name.c_str()), value));
+       }
+       
+       void set(const std::string& name, float value)
+       {
+               GL(glUniform1f(get_location(name.c_str()), value));
+       }
+       
+       void set(const std::string& name, float value0, float value1)
+       {
+               GL(glUniform2f(get_location(name.c_str()), value0, value1));
+       }
+
+       void set(const std::string& name, double value)
+       {
+               GL(glUniform1f(get_location(name.c_str()), static_cast<float>(value)));
+       }
+
+       void use()
+       {               
+               GL(glUseProgramObjectARB(program_));    
+       }
+};
+
+shader::shader(const std::string& vertex_source_str, const std::string& fragment_source_str) : impl_(new impl(vertex_source_str, fragment_source_str)){}
+shader::~shader(){}
+void shader::set(const std::string& name, bool value){impl_->set(name, value);}
+void shader::set(const std::string& name, int value){impl_->set(name, value);}
+void shader::set(const std::string& name, float value){impl_->set(name, value);}
+void shader::set(const std::string& name, float value0, float value1){impl_->set(name, value0, value1);}
+void shader::set(const std::string& name, double value){impl_->set(name, value);}
+int shader::id() const{return impl_->program_;}
+void shader::use()const{impl_->use();}
+
 }}}
\ No newline at end of file
index a76593dadcc840caaeb4a9d71b10e46018f1f613..a2ec9ecf8bf3adad067edb8ee9858fc09ea8d39d 100644 (file)
@@ -1,61 +1,61 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-               \r
-class shader sealed\r
-{\r
-       shader(const shader&);\r
-       shader& operator=(const shader&);\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       shader(const std::string& vertex_source_str, const std::string& fragment_source_str);\r
-       ~shader();\r
-\r
-       // Methods\r
-\r
-       void set(const std::string& name, bool value);\r
-       void set(const std::string& name, int value);\r
-       void set(const std::string& name, float value);\r
-       void set(const std::string& name, float value0, float value1);\r
-       void set(const std::string& name, double value);\r
-       void use() const;\r
-\r
-       // Properties\r
-       \r
-       int id() const;\r
-\r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <string>
+
+namespace caspar { namespace accelerator { namespace ogl {
+               
+class shader sealed
+{
+       shader(const shader&);
+       shader& operator=(const shader&);
+public:
+
+       // Static Members
+
+       // Constructors
+
+       shader(const std::string& vertex_source_str, const std::string& fragment_source_str);
+       ~shader();
+
+       // Methods
+
+       void set(const std::string& name, bool value);
+       void set(const std::string& name, int value);
+       void set(const std::string& name, float value);
+       void set(const std::string& name, float value0, float value1);
+       void set(const std::string& name, double value);
+       void use() const;
+
+       // Properties
+       
+       int id() const;
+
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+
 }}}
\ No newline at end of file
index 426cd9a2a2f8ccfa3ea357d75cba884597cf3a6b..ee21c5f45e0c85c3b42d0ef4fa2c79f04146816f 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "texture.h"\r
-\r
-#include "buffer.h"\r
-\r
-#include <common/except.h>\r
-#include <common/gl/gl_check.h>\r
-\r
-#include <gl/glew.h>\r
-\r
-#include <tbb/atomic.h>\r
-\r
-#include <boost/thread/future.hpp>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-       \r
-static GLenum FORMAT[] = {0, GL_RED, GL_RG, GL_BGR, GL_BGRA};\r
-static GLenum INTERNAL_FORMAT[] = {0, GL_R8, GL_RG8, GL_RGB8, GL_RGBA8};       \r
-static GLenum TYPE[] = {0, GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT_8_8_8_8_REV}; \r
-\r
-static tbb::atomic<int> g_total_count;\r
-\r
-struct texture::impl : boost::noncopyable\r
-{\r
-       GLuint  id_;\r
-\r
-       const int width_;\r
-       const int height_;\r
-       const int stride_;\r
-public:\r
-       impl(int width, int height, int stride) \r
-               : width_(width)\r
-               , height_(height)\r
-               , stride_(stride)\r
-       {       \r
-               GL(glGenTextures(1, &id_));\r
-               GL(glBindTexture(GL_TEXTURE_2D, id_));\r
-               GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
-               GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\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
-               GL(glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT[stride_], width_, height_, 0, FORMAT[stride_], TYPE[stride_], NULL));\r
-               GL(glBindTexture(GL_TEXTURE_2D, 0));\r
-               //CASPAR_LOG(trace) << "[texture] [" << ++g_total_count << L"] allocated size:" << width*height*stride; \r
-       }       \r
-\r
-       ~impl()\r
-       {\r
-               glDeleteTextures(1, &id_);\r
-       }\r
-       \r
-       void bind()\r
-       {\r
-               GL(glBindTexture(GL_TEXTURE_2D, id_));\r
-       }\r
-\r
-       void bind(int index)\r
-       {\r
-               GL(glActiveTexture(GL_TEXTURE0+index));\r
-               bind();\r
-       }\r
-\r
-       void unbind()\r
-       {\r
-               GL(glBindTexture(GL_TEXTURE_2D, 0));\r
-       }\r
-\r
-       void attach()\r
-       {               \r
-               GL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, GL_TEXTURE_2D, id_, 0));\r
-       }\r
-\r
-       void clear()\r
-       {\r
-               attach();               \r
-               GL(glClear(GL_COLOR_BUFFER_BIT));\r
-       }\r
-               \r
-       void copy_from(buffer& source)\r
-       {\r
-               source.unmap();\r
-               source.bind();\r
-               GL(glBindTexture(GL_TEXTURE_2D, id_));\r
-               GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, FORMAT[stride_], TYPE[stride_], NULL));\r
-               GL(glBindTexture(GL_TEXTURE_2D, 0));\r
-               source.unbind();\r
-               source.map(); // Just map it back since map will orphan buffer.\r
-       }\r
-\r
-       void copy_to(buffer& dest)\r
-       {\r
-               dest.unmap();\r
-               dest.bind();\r
-               GL(glBindTexture(GL_TEXTURE_2D, id_));\r
-               GL(glReadBuffer(GL_COLOR_ATTACHMENT0));\r
-               GL(glReadPixels(0, 0, width_, height_, FORMAT[stride_], TYPE[stride_], NULL));\r
-               GL(glBindTexture(GL_TEXTURE_2D, 0));\r
-               dest.unbind();\r
-               GL(glFlush());\r
-       }\r
-};\r
-\r
-texture::texture(int width, int height, int stride) : impl_(new impl(width, height, stride)){}\r
-texture::texture(texture&& other) : impl_(std::move(other.impl_)){}\r
-texture::~texture(){}\r
-texture& texture::operator=(texture&& other){impl_ = std::move(other.impl_); return *this;}\r
-void texture::bind(int index){impl_->bind(index);}\r
-void texture::unbind(){impl_->unbind();}\r
-void texture::attach(){impl_->attach();}\r
-void texture::clear(){impl_->clear();}\r
-void texture::copy_from(buffer& source){impl_->copy_from(source);}\r
-void texture::copy_to(buffer& dest){impl_->copy_to(dest);}\r
-int texture::width() const { return impl_->width_; }\r
-int texture::height() const { return impl_->height_; }\r
-int texture::stride() const { return impl_->stride_; }\r
-std::size_t texture::size() const { return static_cast<std::size_t>(impl_->width_*impl_->height_*impl_->stride_); }\r
-int texture::id() const{ return impl_->id_;}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "texture.h"
+
+#include "buffer.h"
+
+#include <common/except.h>
+#include <common/gl/gl_check.h>
+
+#include <gl/glew.h>
+
+#include <tbb/atomic.h>
+
+#include <boost/thread/future.hpp>
+
+namespace caspar { namespace accelerator { namespace ogl {
+       
+static GLenum FORMAT[] = {0, GL_RED, GL_RG, GL_BGR, GL_BGRA};
+static GLenum INTERNAL_FORMAT[] = {0, GL_R8, GL_RG8, GL_RGB8, GL_RGBA8};       
+static GLenum TYPE[] = {0, GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT_8_8_8_8_REV}; 
+
+static tbb::atomic<int> g_total_count;
+
+struct texture::impl : boost::noncopyable
+{
+       GLuint  id_;
+
+       const int width_;
+       const int height_;
+       const int stride_;
+public:
+       impl(int width, int height, int stride) 
+               : width_(width)
+               , height_(height)
+               , stride_(stride)
+       {       
+               GL(glGenTextures(1, &id_));
+               GL(glBindTexture(GL_TEXTURE_2D, id_));
+               GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+               GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+               GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+               GL(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+               GL(glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT[stride_], width_, height_, 0, FORMAT[stride_], TYPE[stride_], NULL));
+               GL(glBindTexture(GL_TEXTURE_2D, 0));
+               //CASPAR_LOG(trace) << "[texture] [" << ++g_total_count << L"] allocated size:" << width*height*stride; 
+       }       
+
+       ~impl()
+       {
+               glDeleteTextures(1, &id_);
+       }
+       
+       void bind()
+       {
+               GL(glBindTexture(GL_TEXTURE_2D, id_));
+       }
+
+       void bind(int index)
+       {
+               GL(glActiveTexture(GL_TEXTURE0+index));
+               bind();
+       }
+
+       void unbind()
+       {
+               GL(glBindTexture(GL_TEXTURE_2D, 0));
+       }
+
+       void attach()
+       {               
+               GL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, GL_TEXTURE_2D, id_, 0));
+       }
+
+       void clear()
+       {
+               attach();               
+               GL(glClear(GL_COLOR_BUFFER_BIT));
+       }
+               
+       void copy_from(buffer& source)
+       {
+               source.unmap();
+               source.bind();
+               GL(glBindTexture(GL_TEXTURE_2D, id_));
+               GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, FORMAT[stride_], TYPE[stride_], NULL));
+               GL(glBindTexture(GL_TEXTURE_2D, 0));
+               source.unbind();
+               source.map(); // Just map it back since map will orphan buffer.
+       }
+
+       void copy_to(buffer& dest)
+       {
+               dest.unmap();
+               dest.bind();
+               GL(glBindTexture(GL_TEXTURE_2D, id_));
+               GL(glReadBuffer(GL_COLOR_ATTACHMENT0));
+               GL(glReadPixels(0, 0, width_, height_, FORMAT[stride_], TYPE[stride_], NULL));
+               GL(glBindTexture(GL_TEXTURE_2D, 0));
+               dest.unbind();
+               GL(glFlush());
+       }
+};
+
+texture::texture(int width, int height, int stride) : impl_(new impl(width, height, stride)){}
+texture::texture(texture&& other) : impl_(std::move(other.impl_)){}
+texture::~texture(){}
+texture& texture::operator=(texture&& other){impl_ = std::move(other.impl_); return *this;}
+void texture::bind(int index){impl_->bind(index);}
+void texture::unbind(){impl_->unbind();}
+void texture::attach(){impl_->attach();}
+void texture::clear(){impl_->clear();}
+void texture::copy_from(buffer& source){impl_->copy_from(source);}
+void texture::copy_to(buffer& dest){impl_->copy_to(dest);}
+int texture::width() const { return impl_->width_; }
+int texture::height() const { return impl_->height_; }
+int texture::stride() const { return impl_->stride_; }
+std::size_t texture::size() const { return static_cast<std::size_t>(impl_->width_*impl_->height_*impl_->stride_); }
+int texture::id() const{ return impl_->id_;}
+
 }}}
\ No newline at end of file
index 78fd008c4623474115a70b92faa1b6a9b5ebdae5..c9d2762d59b6ab5ce75c14fad798dda0ffc744ff 100644 (file)
@@ -1,73 +1,73 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <cstddef>\r
-\r
-namespace caspar { namespace accelerator { namespace ogl {\r
-               \r
-class buffer;\r
-class device;\r
-\r
-class texture sealed\r
-{\r
-       texture(const texture&);\r
-       texture& operator=(const texture&);\r
-public:        \r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       texture(int width, int height, int stride);\r
-       texture(texture&& other);\r
-       ~texture();\r
-       \r
-       // Methods\r
-\r
-       texture& operator=(texture&& other);\r
-               \r
-       void copy_from(buffer& source);\r
-       void copy_to(buffer& dest);\r
-                       \r
-       void attach();\r
-       void clear();\r
-       void bind(int index);\r
-       void unbind();\r
-\r
-       // Properties\r
-\r
-       int width() const;\r
-       int height() const;\r
-       int stride() const;     \r
-       std::size_t size() const;\r
-\r
-       int id() const;\r
-\r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-       \r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <cstddef>
+
+namespace caspar { namespace accelerator { namespace ogl {
+               
+class buffer;
+class device;
+
+class texture sealed
+{
+       texture(const texture&);
+       texture& operator=(const texture&);
+public:        
+
+       // Static Members
+
+       // Constructors
+
+       texture(int width, int height, int stride);
+       texture(texture&& other);
+       ~texture();
+       
+       // Methods
+
+       texture& operator=(texture&& other);
+               
+       void copy_from(buffer& source);
+       void copy_to(buffer& dest);
+                       
+       void attach();
+       void clear();
+       void bind(int index);
+       void unbind();
+
+       // Properties
+
+       int width() const;
+       int height() const;
+       int stride() const;     
+       std::size_t size() const;
+
+       int id() const;
+
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+       
 }}}
\ No newline at end of file
index dc2cc8bbf9f719922594d651435466ff70fd8b9b..8ae95bc000b437ec8d33636eb40b96f387f60a1e 100644 (file)
-#pragma once\r
-\r
-#include "memory.h"\r
-#include "forward.h"\r
-\r
-#include <boost/any.hpp>\r
-\r
-#include <cstddef>\r
-#include <cstdint>\r
-\r
-namespace caspar {\r
-       \r
-template<typename T>\r
-class array sealed\r
-{\r
-       array(const array<std::uint8_t>&);\r
-       array& operator=(const array<std::uint8_t>&);\r
-\r
-       template<typename> friend class array;\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-       \r
-       template<typename T>\r
-       explicit array(std::uint8_t* ptr, std::size_t size, bool cacheable, T&& storage)\r
-               : ptr_(ptr)\r
-               , size_(size)\r
-               , cacheable_(cacheable)\r
-               , storage_(new boost::any(std::forward<T>(storage)))\r
-       {\r
-       }\r
-\r
-       array(array&& other)\r
-               : ptr_(other.ptr_)\r
-               , size_(other.size_)\r
-               , cacheable_(other.cacheable_)\r
-               , storage_(std::move(other.storage_))\r
-       {\r
-               CASPAR_ASSERT(storage_);\r
-       }\r
-\r
-       // Methods\r
-       \r
-       array& operator=(array&& other)\r
-       {\r
-               std::swap(ptr_, other.ptr_);\r
-               std::swap(size_, other.size_);\r
-               std::swap(storage_,     other.storage_);\r
-               std::swap(cacheable_, other.cacheable_);\r
-\r
-               CASPAR_ASSERT(storage_);\r
-\r
-               return *this;\r
-       }\r
-\r
-       // Properties   \r
-                       \r
-       T* begin() const                        {return ptr_;}          \r
-       T* data() const                         {return ptr_;}\r
-       T* end() const                          {return reinterpret_cast<T*>(reinterpret_cast<char*>(ptr_) + size_);}\r
-       std::size_t size() const        {return size_;}\r
-       bool empty() const                      {return size() == 0;}\r
-       bool cacheable() const          {return cacheable_;}\r
-       \r
-       template<typename T>\r
-       T* storage() const\r
-       {\r
-               return boost::any_cast<T>(storage_.get());\r
-       }\r
-private:\r
-       T*                      ptr_;\r
-       std::size_t     size_;\r
-       bool            cacheable_;\r
-       std::unique_ptr<boost::any>     storage_;\r
-};\r
-\r
-template<typename T>\r
-class array<const T> sealed\r
-{\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       template<typename T>\r
-       explicit array(const std::uint8_t* ptr, std::size_t size, bool cacheable, T&& storage)\r
-               : ptr_(ptr)\r
-               , size_(size)\r
-               , cacheable_(cacheable)\r
-               , storage_(new boost::any(std::forward<T>(storage)))\r
-       {\r
-       }\r
-       \r
-       array(const array& other)\r
-               : ptr_(other.ptr_)\r
-               , size_(other.size_)\r
-               , cacheable_(other.cacheable_)\r
-               , storage_(other.storage_)\r
-       {\r
-               CASPAR_ASSERT(storage_);\r
-       }\r
-\r
-       array(array<T>&& other)\r
-               : ptr_(other.ptr_)\r
-               , size_(other.size_)\r
-               , cacheable_(other.cacheable_)\r
-               , storage_(std::move(other.storage_))\r
-       {\r
-               CASPAR_ASSERT(storage_);\r
-       }\r
-\r
-       // Methods\r
-\r
-       array& operator=(array other)\r
-       {\r
-               other.swap(*this);\r
-               return *this;\r
-       }\r
-\r
-       void swap(array& other)\r
-       {\r
-               std::swap(ptr_, other.ptr_);\r
-               std::swap(size_, other.size_);\r
-               std::swap(storage_,     other.storage_);\r
-               std::swap(cacheable_, other.cacheable_);\r
-       }\r
-\r
-       // Properties\r
-                       \r
-       const T* begin() const          {return ptr_;}          \r
-       const T* data() const           {return ptr_;}\r
-       const T* end() const            {return reinterpret_cast<const T*>(reinterpret_cast<const char*>(ptr_) + size_);}\r
-       std::size_t size() const        {return size_;}\r
-       bool empty() const                      {return size() == 0;}\r
-       bool cacheable() const          {return cacheable_;}\r
-       \r
-       template<typename T>\r
-       T* storage() const\r
-       {\r
-               return boost::any_cast<T>(storage_.get());\r
-       }\r
-\r
-private:\r
-       const T*        ptr_;\r
-       std::size_t     size_;\r
-       bool            cacheable_;\r
-       std::shared_ptr<boost::any>     storage_;\r
-};\r
-\r
-}\r
-\r
-namespace std {\r
-       \r
-template<typename T>\r
-void swap(caspar::array<const T>& lhs, caspar::array<const T>& rhs)\r
-{\r
-       lhs.swap(rhs);\r
-}\r
-\r
-}\r
-\r
+#pragma once
+
+#include "memory.h"
+#include "forward.h"
+
+#include <boost/any.hpp>
+
+#include <cstddef>
+#include <cstdint>
+
+namespace caspar {
+       
+template<typename T>
+class array sealed
+{
+       array(const array<std::uint8_t>&);
+       array& operator=(const array<std::uint8_t>&);
+
+       template<typename> friend class array;
+public:
+
+       // Static Members
+
+       // Constructors
+       
+       template<typename T>
+       explicit array(std::uint8_t* ptr, std::size_t size, bool cacheable, T&& storage)
+               : ptr_(ptr)
+               , size_(size)
+               , cacheable_(cacheable)
+               , storage_(new boost::any(std::forward<T>(storage)))
+       {
+       }
+
+       array(array&& other)
+               : ptr_(other.ptr_)
+               , size_(other.size_)
+               , cacheable_(other.cacheable_)
+               , storage_(std::move(other.storage_))
+       {
+               CASPAR_ASSERT(storage_);
+       }
+
+       // Methods
+       
+       array& operator=(array&& other)
+       {
+               std::swap(ptr_, other.ptr_);
+               std::swap(size_, other.size_);
+               std::swap(storage_,     other.storage_);
+               std::swap(cacheable_, other.cacheable_);
+
+               CASPAR_ASSERT(storage_);
+
+               return *this;
+       }
+
+       // Properties   
+                       
+       T* begin() const                        {return ptr_;}          
+       T* data() const                         {return ptr_;}
+       T* end() const                          {return reinterpret_cast<T*>(reinterpret_cast<char*>(ptr_) + size_);}
+       std::size_t size() const        {return size_;}
+       bool empty() const                      {return size() == 0;}
+       bool cacheable() const          {return cacheable_;}
+       
+       template<typename T>
+       T* storage() const
+       {
+               return boost::any_cast<T>(storage_.get());
+       }
+private:
+       T*                      ptr_;
+       std::size_t     size_;
+       bool            cacheable_;
+       std::unique_ptr<boost::any>     storage_;
+};
+
+template<typename T>
+class array<const T> sealed
+{
+public:
+
+       // Static Members
+
+       // Constructors
+
+       template<typename T>
+       explicit array(const std::uint8_t* ptr, std::size_t size, bool cacheable, T&& storage)
+               : ptr_(ptr)
+               , size_(size)
+               , cacheable_(cacheable)
+               , storage_(new boost::any(std::forward<T>(storage)))
+       {
+       }
+       
+       array(const array& other)
+               : ptr_(other.ptr_)
+               , size_(other.size_)
+               , cacheable_(other.cacheable_)
+               , storage_(other.storage_)
+       {
+               CASPAR_ASSERT(storage_);
+       }
+
+       array(array<T>&& other)
+               : ptr_(other.ptr_)
+               , size_(other.size_)
+               , cacheable_(other.cacheable_)
+               , storage_(std::move(other.storage_))
+       {
+               CASPAR_ASSERT(storage_);
+       }
+
+       // Methods
+
+       array& operator=(array other)
+       {
+               other.swap(*this);
+               return *this;
+       }
+
+       void swap(array& other)
+       {
+               std::swap(ptr_, other.ptr_);
+               std::swap(size_, other.size_);
+               std::swap(storage_,     other.storage_);
+               std::swap(cacheable_, other.cacheable_);
+       }
+
+       // Properties
+                       
+       const T* begin() const          {return ptr_;}          
+       const T* data() const           {return ptr_;}
+       const T* end() const            {return reinterpret_cast<const T*>(reinterpret_cast<const char*>(ptr_) + size_);}
+       std::size_t size() const        {return size_;}
+       bool empty() const                      {return size() == 0;}
+       bool cacheable() const          {return cacheable_;}
+       
+       template<typename T>
+       T* storage() const
+       {
+               return boost::any_cast<T>(storage_.get());
+       }
+
+private:
+       const T*        ptr_;
+       std::size_t     size_;
+       bool            cacheable_;
+       std::shared_ptr<boost::any>     storage_;
+};
+
+}
+
+namespace std {
+       
+template<typename T>
+void swap(caspar::array<const T>& lhs, caspar::array<const T>& rhs)
+{
+       lhs.swap(rhs);
+}
+
+}
+
index 5c06a5e03eab1a271d44e8973ddc02b12ab9503a..e077804dbb824e0002e75f120b125354eeb98a60 100644 (file)
@@ -1,45 +1,45 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "log.h"\r
-\r
-#ifdef _MSC_VER\r
-#define _CASPAR_DBG_BREAK _CrtDbgBreak()\r
-#else\r
-#define _CASPAR_DBG_BREAK\r
-#endif\r
-\r
-#define CASPAR_VERIFY_EXPR_STR(str) #str\r
-\r
-#define CASPAR_VERIFY(expr) do{if(!(expr)){ CASPAR_LOG(warning) << "Assertion Failed: " << \\r
-       CASPAR_VERIFY_EXPR_STR(expr) << " " \\r
-       << "file:" << __FILE__ << " " \\r
-       << "line:" << __LINE__ << " "; \\r
-       _CASPAR_DBG_BREAK;\\r
-       }}while(0);\r
-\r
-#ifdef _DEBUG\r
-#define CASPAR_ASSERT(expr) CASPAR_VERIFY(expr)\r
-#else\r
-#define CASPAR_ASSERT(expr)\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "log.h"
+
+#ifdef _MSC_VER
+#define _CASPAR_DBG_BREAK _CrtDbgBreak()
+#else
+#define _CASPAR_DBG_BREAK
+#endif
+
+#define CASPAR_VERIFY_EXPR_STR(str) #str
+
+#define CASPAR_VERIFY(expr) do{if(!(expr)){ CASPAR_LOG(warning) << "Assertion Failed: " << \
+       CASPAR_VERIFY_EXPR_STR(expr) << " " \
+       << "file:" << __FILE__ << " " \
+       << "line:" << __LINE__ << " "; \
+       _CASPAR_DBG_BREAK;\
+       }}while(0);
+
+#ifdef _DEBUG
+#define CASPAR_ASSERT(expr) CASPAR_VERIFY(expr)
+#else
+#define CASPAR_ASSERT(expr)
 #endif
\ No newline at end of file
index 256f932936889a4a07f24c259dee4d5735e53d72..0866ef7a353f4ead2efcf1c3912dbe2cc70af571 100644 (file)
@@ -1,36 +1,36 @@
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-*  This file is part of CasparCG.\r
-*\r
-*    CasparCG is free software: you can redistribute it and/or modify\r
-*    it under the terms of the GNU General Public License as published by\r
-*    the Free Software Foundation, either version 3 of the License, or\r
-*    (at your option) any later version.\r
-*\r
-*    CasparCG is distributed in the hope that it will be useful,\r
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-*    GNU General Public License for more details.\r
-\r
-*    You should have received a copy of the GNU General Public License\r
-*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
-#pragma once\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (disable : 4100) // unreferenced formal parameter\r
-#pragma warning (disable : 4127) // conditional expression is constant\r
-#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored\r
-#pragma warning (disable : 4355) // 'this' : used in base member initializer list\r
-#pragma warning (disable : 4482) // nonstandard extension used: enum 'enum' used in qualified name\r
-#pragma warning (disable : 4503) // decorated name length exceeded, name was truncated\r
-#pragma warning (disable : 4512) // assignment operator could not be generated\r
-#pragma warning (disable : 4702) // unreachable code\r
-#pragma warning (disable : 4714) // marked as __forceinline not inlined\r
-#pragma warning (disable : 4505) // unreferenced local function has been \r
-#pragma warning (disable : 4481) // nonstandard extension used: override specifier 'override'\r
-#pragma warning (disable : 4996) // function call with parameters that may be unsafe\r
-#endif\r
-\r
+/*
+* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
+*
+*  This file is part of CasparCG.
+*
+*    CasparCG is free software: you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation, either version 3 of the License, or
+*    (at your option) any later version.
+*
+*    CasparCG is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+
+*    You should have received a copy of the GNU General Public License
+*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+#pragma once
+
+#if defined(_MSC_VER)
+#pragma warning (disable : 4100) // unreferenced formal parameter
+#pragma warning (disable : 4127) // conditional expression is constant
+#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored
+#pragma warning (disable : 4355) // 'this' : used in base member initializer list
+#pragma warning (disable : 4482) // nonstandard extension used: enum 'enum' used in qualified name
+#pragma warning (disable : 4503) // decorated name length exceeded, name was truncated
+#pragma warning (disable : 4512) // assignment operator could not be generated
+#pragma warning (disable : 4702) // unreachable code
+#pragma warning (disable : 4714) // marked as __forceinline not inlined
+#pragma warning (disable : 4505) // unreferenced local function has been 
+#pragma warning (disable : 4481) // nonstandard extension used: override specifier 'override'
+#pragma warning (disable : 4996) // function call with parameters that may be unsafe
+#endif
+
index d22a4525df53f6efeed3248694172ee831da6861..ad494cb2c599b867c1daa189aa818eb8824f183d 100644 (file)
-/**********************************************************************\r
- * \r
- * stack_walker.cpp\r
- *\r
- *\r
- * History:\r
- *  2005-07-27   v1    - First public release on http://www.codeproject.com/\r
- *                       http://www.codeproject.com/threads/stack_walker.asp\r
- *  2005-07-28   v2    - Changed the params of the constructor and ShowCallstack\r
- *                       (to simplify the usage)\r
- *  2005-08-01   v3    - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL \r
- *                       (should also be enough)\r
- *                     - Changed to compile correctly with the PSDK of VC7.0\r
- *                       (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined:\r
- *                        it uses LPSTR instead of LPCSTR as first paremeter)\r
- *                     - Added declarations to support VC5/6 without using 'dbghelp.h'\r
- *                     - Added a 'pUserData' member to the ShowCallstack function and the \r
- *                       PReadProcessMemoryRoutine declaration (to pass some user-defined data, \r
- *                       which can be used in the readMemoryFunction-callback)\r
- *  2005-08-02   v4    - OnSymInit now also outputs the OS-Version by default\r
- *                     - Added example for doing an exception-callstack-walking in main.cpp\r
- *                       (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268)\r
- *  2005-08-05   v5    - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse!\r
- *\r
- **********************************************************************/\r
-#include <tchar.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-\r
-#pragma warning(push, 1)\r
-\r
-#pragma comment(lib, "version.lib")  // for "VerQueryValue"\r
-\r
-#include "stack_walker.h"\r
-\r
-// If VC7 and later, then use the shipped 'dbghelp.h'-file\r
-#if _MSC_VER >= 1300\r
-#include <dbghelp.h>\r
-#else\r
-// inline the important dbghelp.h-declarations...\r
-typedef enum {\r
-    SymNone = 0,\r
-    SymCoff,\r
-    SymCv,\r
-    SymPdb,\r
-    SymExport,\r
-    SymDeferred,\r
-    SymSym,\r
-    SymDia,\r
-    SymVirtual,\r
-    NumSymTypes\r
-} SYM_TYPE;\r
-typedef struct _IMAGEHLP_LINE64 {\r
-    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_LINE64)\r
-    PVOID                       Key;                    // internal\r
-    DWORD                       LineNumber;             // line number in file\r
-    PCHAR                       FileName;               // full filename\r
-    DWORD64                     Address;                // first instruction of line\r
-} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;\r
-typedef struct _IMAGEHLP_MODULE64 {\r
-    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)\r
-    DWORD64                     BaseOfImage;            // base load address of module\r
-    DWORD                       ImageSize;              // virtual size of the loaded module\r
-    DWORD                       TimeDateStamp;          // date/time stamp from pe header\r
-    DWORD                       CheckSum;               // checksum from the pe header\r
-    DWORD                       NumSyms;                // number of symbols in the symbol table\r
-    SYM_TYPE                    SymType;                // type of symbols loaded\r
-    CHAR                        ModuleName[32];         // module name\r
-    CHAR                        ImageName[256];         // image name\r
-    CHAR                        LoadedImageName[256];   // symbol file name\r
-} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;\r
-typedef struct _IMAGEHLP_SYMBOL64 {\r
-    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_SYMBOL64)\r
-    DWORD64                     Address;                // virtual address including dll base address\r
-    DWORD                       Size;                   // estimated size of symbol, can be zero\r
-    DWORD                       Flags;                  // info about the symbols, see the SYMF defines\r
-    DWORD                       MaxNameLength;          // maximum size of symbol name in 'Name'\r
-    CHAR                        Name[1];                // symbol name (null terminated string)\r
-} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;\r
-typedef enum {\r
-    AddrMode1616,\r
-    AddrMode1632,\r
-    AddrModeReal,\r
-    AddrModeFlat\r
-} ADDRESS_MODE;\r
-typedef struct _tagADDRESS64 {\r
-    DWORD64       Offset;\r
-    WORD          Segment;\r
-    ADDRESS_MODE  Mode;\r
-} ADDRESS64, *LPADDRESS64;\r
-typedef struct _KDHELP64 {\r
-    DWORD64   Thread;\r
-    DWORD   ThCallbackStack;\r
-    DWORD   ThCallbackBStore;\r
-    DWORD   NextCallback;\r
-    DWORD   FramePointer;\r
-    DWORD64   KiCallUserMode;\r
-    DWORD64   KeUserCallbackDispatcher;\r
-    DWORD64   SystemRangeStart;\r
-    DWORD64  Reserved[8];\r
-} KDHELP64, *PKDHELP64;\r
-typedef struct _tagSTACKFRAME64 {\r
-    ADDRESS64   AddrPC;               // program counter\r
-    ADDRESS64   AddrReturn;           // return address\r
-    ADDRESS64   AddrFrame;            // frame pointer\r
-    ADDRESS64   AddrStack;            // stack pointer\r
-    ADDRESS64   AddrBStore;           // backing store pointer\r
-    PVOID       FuncTableEntry;       // pointer to pdata/fpo or NULL\r
-    DWORD64     Params[4];            // possible arguments to the function\r
-    BOOL        Far;                  // WOW far call\r
-    BOOL        Virtual;              // is this a virtual frame?\r
-    DWORD64     Reserved[3];\r
-    KDHELP64    KdHelp;\r
-} STACKFRAME64, *LPSTACKFRAME64;\r
-typedef\r
-BOOL\r
-(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(\r
-    HANDLE      hProcess,\r
-    DWORD64     qwBaseAddress,\r
-    PVOID       lpBuffer,\r
-    DWORD       nSize,\r
-    LPDWORD     lpNumberOfBytesRead\r
-    );\r
-typedef\r
-PVOID\r
-(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(\r
-    HANDLE  hProcess,\r
-    DWORD64 AddrBase\r
-    );\r
-typedef\r
-DWORD64\r
-(__stdcall *PGET_MODULE_BASE_ROUTINE64)(\r
-    HANDLE  hProcess,\r
-    DWORD64 Address\r
-    );\r
-typedef\r
-DWORD64\r
-(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(\r
-    HANDLE    hProcess,\r
-    HANDLE    hThread,\r
-    LPADDRESS64 lpaddr\r
-    );\r
-#define SYMOPT_CASE_INSENSITIVE         0x00000001\r
-#define SYMOPT_UNDNAME                  0x00000002\r
-#define SYMOPT_DEFERRED_LOADS           0x00000004\r
-#define SYMOPT_NO_CPP                   0x00000008\r
-#define SYMOPT_LOAD_LINES               0x00000010\r
-#define SYMOPT_OMAP_FIND_NEAREST        0x00000020\r
-#define SYMOPT_LOAD_ANYTHING            0x00000040\r
-#define SYMOPT_IGNORE_CVREC             0x00000080\r
-#define SYMOPT_NO_UNQUALIFIED_LOADS     0x00000100\r
-#define SYMOPT_FAIL_CRITICAL_ERRORS     0x00000200\r
-#define SYMOPT_EXACT_SYMBOLS            0x00000400\r
-#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS   0x00000800\r
-#define SYMOPT_IGNORE_NT_SYMPATH        0x00001000\r
-#define SYMOPT_INCLUDE_32BIT_MODULES    0x00002000\r
-#define SYMOPT_PUBLICS_ONLY             0x00004000\r
-#define SYMOPT_NO_PUBLICS               0x00008000\r
-#define SYMOPT_AUTO_PUBLICS             0x00010000\r
-#define SYMOPT_NO_IMAGE_SEARCH          0x00020000\r
-#define SYMOPT_SECURE                   0x00040000\r
-#define SYMOPT_DEBUG                    0x80000000\r
-#define UNDNAME_COMPLETE                 (0x0000)  // Enable full undecoration\r
-#define UNDNAME_NAME_ONLY                (0x1000)  // Crack only the name for primary declaration;\r
-#endif  // _MSC_VER < 1300\r
-\r
-// Some missing defines (for VC5/6):\r
-#ifndef INVALID_FILE_ATTRIBUTES\r
-#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)\r
-#endif  \r
-\r
-\r
-// secure-CRT_functions are only available starting with VC8\r
-#if _MSC_VER < 1400\r
-#define strcpy_s strcpy\r
-#define strcat_s(dst, len, src) strcat(dst, src)\r
-#define _snprintf_s _snprintf\r
-#define _tcscat_s _tcscat\r
-#endif\r
-\r
-// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')\r
-#define USED_CONTEXT_FLAGS CONTEXT_FULL\r
-\r
-\r
-class stack_walkerInternal\r
-{\r
-public:\r
-  stack_walkerInternal(stack_walker *parent, HANDLE hProcess)\r
-  {\r
-    m_parent = parent;\r
-    m_hDbhHelp = NULL;\r
-    pSC = NULL;\r
-    m_hProcess = hProcess;\r
-    m_szSymPath = NULL;\r
-    pSFTA = NULL;\r
-    pSGLFA = NULL;\r
-    pSGMB = NULL;\r
-    pSGMI = NULL;\r
-    pSGO = NULL;\r
-    pSGSFA = NULL;\r
-    pSI = NULL;\r
-    pSLM = NULL;\r
-    pSSO = NULL;\r
-    pSW = NULL;\r
-    pUDSN = NULL;\r
-    pSGSP = NULL;\r
-  }\r
-  ~stack_walkerInternal()\r
-  {\r
-    if (pSC != NULL)\r
-      pSC(m_hProcess);  // SymCleanup\r
-    if (m_hDbhHelp != NULL)\r
-      FreeLibrary(m_hDbhHelp);\r
-    m_hDbhHelp = NULL;\r
-    m_parent = NULL;\r
-    if(m_szSymPath != NULL)\r
-      free(m_szSymPath);\r
-    m_szSymPath = NULL;\r
-  }\r
-  BOOL Init(LPCSTR szSymPath)\r
-  {\r
-    if (m_parent == NULL)\r
-      return FALSE;\r
-    // Dynamically load the Entry-Points for dbghelp.dll:\r
-    // First try to load the newsest one from\r
-    TCHAR szTemp[4096];\r
-    // But before wqe do this, we first check if the ".local" file exists\r
-    if (GetModuleFileName(NULL, szTemp, 4096) > 0)\r
-    {\r
-      _tcscat_s(szTemp, _T(".local"));\r
-      if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES)\r
-      {\r
-        // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows"\r
-        if (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)\r
-        {\r
-          _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll"));\r
-          // now check if the file exists:\r
-          if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)\r
-          {\r
-            m_hDbhHelp = LoadLibrary(szTemp);\r
-          }\r
-        }\r
-          // Still not found? Then try to load the 64-Bit version:\r
-        if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )\r
-        {\r
-          _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll"));\r
-          if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)\r
-          {\r
-            m_hDbhHelp = LoadLibrary(szTemp);\r
-          }\r
-        }\r
-      }\r
-    }\r
-    if (m_hDbhHelp == NULL)  // if not already loaded, try to load a default-one\r
-      m_hDbhHelp = LoadLibrary( _T("dbghelp.dll") );\r
-    if (m_hDbhHelp == NULL)\r
-      return FALSE;\r
-    pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" );\r
-    pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" );\r
-\r
-    pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" );\r
-    pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" );\r
-    pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" );\r
-\r
-    pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" );\r
-    pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" );\r
-    pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" );\r
-    pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );\r
-    //pSGMI_V3 = (tSGMI_V3) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );\r
-    pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" );\r
-    pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" );\r
-    pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" );\r
-    pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" );\r
-\r
-    if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||\r
-      pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||\r
-      pSW == NULL || pUDSN == NULL || pSLM == NULL )\r
-    {\r
-      FreeLibrary(m_hDbhHelp);\r
-      m_hDbhHelp = NULL;\r
-      pSC = NULL;\r
-      return FALSE;\r
-    }\r
-\r
-    // SymInitialize\r
-    if (szSymPath != NULL)\r
-      m_szSymPath = _strdup(szSymPath);\r
-    if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)\r
-      this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);\r
-      \r
-    DWORD symOptions = this->pSGO();  // SymGetOptions\r
-    symOptions |= SYMOPT_LOAD_LINES;\r
-    symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;\r
-    //symOptions |= SYMOPT_NO_PROMPTS;\r
-    // SymSetOptions\r
-    symOptions = this->pSSO(symOptions);\r
-\r
-    char buf[stack_walker::STACKWALK_MAX_NAMELEN] = {0};\r
-    if (this->pSGSP != NULL)\r
-    {\r
-      if (this->pSGSP(m_hProcess, buf, stack_walker::STACKWALK_MAX_NAMELEN) == FALSE)\r
-        this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);\r
-    }\r
-    char szUserName[1024] = {0};\r
-    DWORD dwSize = 1024;\r
-    GetUserNameA(szUserName, &dwSize);\r
-    this->m_parent->OnSymInit(buf, symOptions, szUserName);\r
-\r
-    return TRUE;\r
-  }\r
-\r
-  stack_walker *m_parent;\r
-\r
-  HMODULE m_hDbhHelp;\r
-  HANDLE m_hProcess;\r
-  LPSTR m_szSymPath;\r
-\r
-/*typedef struct IMAGEHLP_MODULE64_V3 {\r
-    DWORD    SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)\r
-    DWORD64  BaseOfImage;            // base load address of module\r
-    DWORD    ImageSize;              // virtual size of the loaded module\r
-    DWORD    TimeDateStamp;          // date/time stamp from pe header\r
-    DWORD    CheckSum;               // checksum from the pe header\r
-    DWORD    NumSyms;                // number of symbols in the symbol table\r
-    SYM_TYPE SymType;                // type of symbols loaded\r
-    CHAR     ModuleName[32];         // module name\r
-    CHAR     ImageName[256];         // image name\r
-    // new elements: 07-Jun-2002\r
-    CHAR     LoadedImageName[256];   // symbol file name\r
-    CHAR     LoadedPdbName[256];     // pdb file name\r
-    DWORD    CVSig;                  // Signature of the CV record in the debug directories\r
-    CHAR         CVData[MAX_PATH * 3];   // Contents of the CV record\r
-    DWORD    PdbSig;                 // Signature of PDB\r
-    GUID     PdbSig70;               // Signature of PDB (VC 7 and up)\r
-    DWORD    PdbAge;                 // DBI age of pdb\r
-    BOOL     PdbUnmatched;           // loaded an unmatched pdb\r
-    BOOL     DbgUnmatched;           // loaded an unmatched dbg\r
-    BOOL     LineNumbers;            // we have line number information\r
-    BOOL     GlobalSymbols;          // we have internal symbol information\r
-    BOOL     TypeInfo;               // we have type information\r
-    // new elements: 17-Dec-2003\r
-    BOOL     SourceIndexed;          // pdb supports source server\r
-    BOOL     Publics;                // contains public symbols\r
-};\r
-*/\r
-typedef struct IMAGEHLP_MODULE64_V2 {\r
-    DWORD    SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)\r
-    DWORD64  BaseOfImage;            // base load address of module\r
-    DWORD    ImageSize;              // virtual size of the loaded module\r
-    DWORD    TimeDateStamp;          // date/time stamp from pe header\r
-    DWORD    CheckSum;               // checksum from the pe header\r
-    DWORD    NumSyms;                // number of symbols in the symbol table\r
-    SYM_TYPE SymType;                // type of symbols loaded\r
-    CHAR     ModuleName[32];         // module name\r
-    CHAR     ImageName[256];         // image name\r
-    CHAR     LoadedImageName[256];   // symbol file name\r
-};\r
-\r
-\r
-  // SymCleanup()\r
-  typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess );\r
-  tSC pSC;\r
-\r
-  // SymFunctionTableAccess64()\r
-  typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase );\r
-  tSFTA pSFTA;\r
-\r
-  // SymGetLineFromAddr64()\r
-  typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,\r
-    OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line );\r
-  tSGLFA pSGLFA;\r
-\r
-  // SymGetModuleBase64()\r
-  typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr );\r
-  tSGMB pSGMB;\r
-\r
-  // SymGetModuleInfo64()\r
-  typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V2 *ModuleInfo );\r
-  tSGMI pSGMI;\r
-\r
-//  // SymGetModuleInfo64()\r
-//  typedef BOOL (__stdcall *tSGMI_V3)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo );\r
-//  tSGMI_V3 pSGMI_V3;\r
-\r
-  // SymGetOptions()\r
-  typedef DWORD (__stdcall *tSGO)( VOID );\r
-  tSGO pSGO;\r
-\r
-  // SymGetSymFromAddr64()\r
-  typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,\r
-    OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol );\r
-  tSGSFA pSGSFA;\r
-\r
-  // SymInitialize()\r
-  typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );\r
-  tSI pSI;\r
-\r
-  // SymLoadModule64()\r
-  typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile,\r
-    IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll );\r
-  tSLM pSLM;\r
-\r
-  // SymSetOptions()\r
-  typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions );\r
-  tSSO pSSO;\r
-\r
-  // StackWalk64()\r
-  typedef BOOL (__stdcall *tSW)( \r
-    DWORD MachineType, \r
-    HANDLE hProcess,\r
-    HANDLE hThread, \r
-    LPSTACKFRAME64 StackFrame, \r
-    PVOID ContextRecord,\r
-    PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,\r
-    PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,\r
-    PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,\r
-    PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );\r
-  tSW pSW;\r
-\r
-  // UnDecorateSymbolName()\r
-  typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName,\r
-    DWORD UndecoratedLength, DWORD Flags );\r
-  tUDSN pUDSN;\r
-\r
-  typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);\r
-  tSGSP pSGSP;\r
-\r
-\r
-private:\r
-  // **************************************** ToolHelp32 ************************\r
-  #define MAX_MODULE_NAME32 255\r
-  #define TH32CS_SNAPMODULE   0x00000008\r
-  #pragma pack( push, 8 )\r
-  typedef struct tagMODULEENTRY32\r
-  {\r
-      DWORD   dwSize;\r
-      DWORD   th32ModuleID;       // This module\r
-      DWORD   th32ProcessID;      // owning process\r
-      DWORD   GlblcntUsage;       // Global usage count on the module\r
-      DWORD   ProccntUsage;       // Module usage count in th32ProcessID's context\r
-      BYTE  * modBaseAddr;        // Base address of module in th32ProcessID's context\r
-      DWORD   modBaseSize;        // Size in bytes of module starting at modBaseAddr\r
-      HMODULE hModule;            // The hModule of this module in th32ProcessID's context\r
-      char    szModule[MAX_MODULE_NAME32 + 1];\r
-      char    szExePath[MAX_PATH];\r
-  } MODULEENTRY32;\r
-  typedef MODULEENTRY32 *  PMODULEENTRY32;\r
-  typedef MODULEENTRY32 *  LPMODULEENTRY32;\r
-  #pragma pack( pop )\r
-\r
-  BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid)\r
-  {\r
-    // CreateToolhelp32Snapshot()\r
-    typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID);\r
-    // Module32First()\r
-    typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);\r
-    // Module32Next()\r
-    typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);\r
-\r
-    // try both dlls...\r
-    const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") };\r
-    HINSTANCE hToolhelp = NULL;\r
-    tCT32S pCT32S = NULL;\r
-    tM32F pM32F = NULL;\r
-    tM32N pM32N = NULL;\r
-\r
-    HANDLE hSnap;\r
-    MODULEENTRY32 me;\r
-    me.dwSize = sizeof(me);\r
-    BOOL keepGoing;\r
-    size_t i;\r
-\r
-    for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ )\r
-    {\r
-      hToolhelp = LoadLibrary( dllname[i] );\r
-      if (hToolhelp == NULL)\r
-        continue;\r
-      pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");\r
-      pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First");\r
-      pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next");\r
-      if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) )\r
-        break; // found the functions!\r
-      FreeLibrary(hToolhelp);\r
-      hToolhelp = NULL;\r
-    }\r
-\r
-    if (hToolhelp == NULL)\r
-      return FALSE;\r
-\r
-    hSnap = pCT32S( TH32CS_SNAPMODULE, pid );\r
-    if (hSnap == (HANDLE) -1)\r
-      return FALSE;\r
-\r
-    keepGoing = !!pM32F( hSnap, &me );\r
-    int cnt = 0;\r
-    while (keepGoing)\r
-    {\r
-      this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize);\r
-      cnt++;\r
-      keepGoing = !!pM32N( hSnap, &me );\r
-    }\r
-    CloseHandle(hSnap);\r
-    FreeLibrary(hToolhelp);\r
-    if (cnt <= 0)\r
-      return FALSE;\r
-    return TRUE;\r
-  }  // GetModuleListTH32\r
-\r
-  // **************************************** PSAPI ************************\r
-  typedef struct _MODULEINFO {\r
-      LPVOID lpBaseOfDll;\r
-      DWORD SizeOfImage;\r
-      LPVOID EntryPoint;\r
-  } MODULEINFO, *LPMODULEINFO;\r
-\r
-  BOOL GetModuleListPSAPI(HANDLE hProcess)\r
-  {\r
-    // EnumProcessModules()\r
-    typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );\r
-    // GetModuleFileNameEx()\r
-    typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );\r
-    // GetModuleBaseName()\r
-    typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );\r
-    // GetModuleInformation()\r
-    typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize );\r
-\r
-    HINSTANCE hPsapi;\r
-    tEPM pEPM;\r
-    tGMFNE pGMFNE;\r
-    tGMBN pGMBN;\r
-    tGMI pGMI;\r
-\r
-    DWORD i;\r
-    //ModuleEntry e;\r
-    DWORD cbNeeded;\r
-    MODULEINFO mi;\r
-    HMODULE *hMods = 0;\r
-    char *tt = NULL;\r
-    char *tt2 = NULL;\r
-    const SIZE_T TTBUFLEN = 8096;\r
-    int cnt = 0;\r
-\r
-    hPsapi = LoadLibrary( _T("psapi.dll") );\r
-    if (hPsapi == NULL)\r
-      return FALSE;\r
-\r
-    pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" );\r
-    pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" );\r
-    pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" );\r
-    pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" );\r
-    if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) )\r
-    {\r
-      // we couldn´t find all functions\r
-      FreeLibrary(hPsapi);\r
-      return FALSE;\r
-    }\r
-\r
-    hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE));\r
-    tt = (char*) malloc(sizeof(char) * TTBUFLEN);\r
-    tt2 = (char*) malloc(sizeof(char) * TTBUFLEN);\r
-    if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) )\r
-      goto cleanup;\r
-\r
-    if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) )\r
-    {\r
-      //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );\r
-      goto cleanup;\r
-    }\r
-\r
-    if ( cbNeeded > TTBUFLEN )\r
-    {\r
-      //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );\r
-      goto cleanup;\r
-    }\r
-\r
-    for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ )\r
-    {\r
-      // base address, size\r
-      pGMI(hProcess, hMods[i], &mi, sizeof mi );\r
-      // image file name\r
-      tt[0] = 0;\r
-      pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );\r
-      // module name\r
-      tt2[0] = 0;\r
-      pGMBN(hProcess, hMods[i], tt2, TTBUFLEN );\r
-\r
-      DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage);\r
-      if (dwRes != ERROR_SUCCESS)\r
-        this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0);\r
-      cnt++;\r
-    }\r
-\r
-  cleanup:\r
-    if (hPsapi != NULL) FreeLibrary(hPsapi);\r
-    if (tt2 != NULL) free(tt2);\r
-    if (tt != NULL) free(tt);\r
-    if (hMods != NULL) free(hMods);\r
-\r
-    return cnt != 0;\r
-  }  // GetModuleListPSAPI\r
-\r
-  DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size)\r
-  {\r
-    CHAR *szImg = _strdup(img);\r
-    CHAR *szMod = _strdup(mod);\r
-    DWORD result = ERROR_SUCCESS;\r
-    if ( (szImg == NULL) || (szMod == NULL) )\r
-      result = ERROR_NOT_ENOUGH_MEMORY;\r
-    else\r
-    {\r
-      if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0)\r
-        result = GetLastError();\r
-    }\r
-    ULONGLONG fileVersion = 0;\r
-    if ( (m_parent != NULL) && (szImg != NULL) )\r
-    {\r
-      // try to retrive the file-version:\r
-      if ( (this->m_parent->m_options & stack_walker::RetrieveFileVersion) != 0)\r
-      {\r
-        VS_FIXEDFILEINFO *fInfo = NULL;\r
-        DWORD dwHandle;\r
-        DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle);\r
-        if (dwSize > 0)\r
-        {\r
-          LPVOID vData = malloc(dwSize);\r
-          if (vData != NULL)\r
-          {\r
-            if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0)\r
-            {\r
-              UINT len;\r
-              TCHAR szSubBlock[] = _T("\\");\r
-              if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0)\r
-                fInfo = NULL;\r
-              else\r
-              {\r
-                fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32);\r
-              }\r
-            }\r
-            free(vData);\r
-          }\r
-        }\r
-      }\r
-\r
-      // Retrive some additional-infos about the module\r
-      IMAGEHLP_MODULE64_V2 Module;\r
-      const char *szSymType = "-unknown-";\r
-      if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE)\r
-      {\r
-        switch(Module.SymType)\r
-        {\r
-          case SymNone:\r
-            szSymType = "-nosymbols-";\r
-            break;\r
-          case SymCoff:\r
-            szSymType = "COFF";\r
-            break;\r
-          case SymCv:\r
-            szSymType = "CV";\r
-            break;\r
-          case SymPdb:\r
-            szSymType = "PDB";\r
-            break;\r
-          case SymExport:\r
-            szSymType = "-exported-";\r
-            break;\r
-          case SymDeferred:\r
-            szSymType = "-deferred-";\r
-            break;\r
-          case SymSym:\r
-            szSymType = "SYM";\r
-            break;\r
-          case 8: //SymVirtual:\r
-            szSymType = "Virtual";\r
-            break;\r
-          case 9: // SymDia:\r
-            szSymType = "DIA";\r
-            break;\r
-        }\r
-      }\r
-      this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, Module.LoadedImageName, fileVersion);\r
-    }\r
-    if (szImg != NULL) free(szImg);\r
-    if (szMod != NULL) free(szMod);\r
-    return result;\r
-  }\r
-public:\r
-  BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId)\r
-  {\r
-    // first try toolhelp32\r
-    if (GetModuleListTH32(hProcess, dwProcessId))\r
-      return true;\r
-    // then try psapi\r
-    return GetModuleListPSAPI(hProcess);\r
-  }\r
-\r
-\r
-  BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V2 *pModuleInfo)\r
-  {\r
-    if(this->pSGMI == NULL)\r
-    {\r
-      SetLastError(ERROR_DLL_INIT_FAILED);\r
-      return FALSE;\r
-    }\r
-    // First try to use the larger ModuleInfo-Structure\r
-//    memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));\r
-//    pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);\r
-//    if (this->pSGMI_V3 != NULL)\r
-//    {\r
-//      if (this->pSGMI_V3(hProcess, baseAddr, pModuleInfo) != FALSE)\r
-//        return TRUE;\r
-//      // check if the parameter was wrong (size is bad...)\r
-//      if (GetLastError() != ERROR_INVALID_PARAMETER)\r
-//        return FALSE;\r
-//    }\r
-    // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)...\r
-    pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);\r
-    void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites...\r
-    if (pData == NULL)\r
-    {\r
-      SetLastError(ERROR_NOT_ENOUGH_MEMORY);\r
-      return FALSE;\r
-    }\r
-    memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));\r
-    if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V2*) pData) != FALSE)\r
-    {\r
-      // only copy as much memory as is reserved...\r
-      memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));\r
-      pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);\r
-      free(pData);\r
-      return TRUE;\r
-    }\r
-    free(pData);\r
-    SetLastError(ERROR_DLL_INIT_FAILED);\r
-    return FALSE;\r
-  }\r
-};\r
-\r
-// #############################################################\r
-stack_walker::stack_walker(DWORD dwProcessId, HANDLE hProcess)\r
-{\r
-  this->m_options = OptionsAll;\r
-  this->m_modulesLoaded = FALSE;\r
-  this->m_hProcess = hProcess;\r
-  this->m_sw = new stack_walkerInternal(this, this->m_hProcess);\r
-  this->m_dwProcessId = dwProcessId;\r
-  this->m_szSymPath = NULL;\r
-}\r
-stack_walker::stack_walker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)\r
-{\r
-  this->m_options = options;\r
-  this->m_modulesLoaded = FALSE;\r
-  this->m_hProcess = hProcess;\r
-  this->m_sw = new stack_walkerInternal(this, this->m_hProcess);\r
-  this->m_dwProcessId = dwProcessId;\r
-  if (szSymPath != NULL)\r
-  {\r
-    this->m_szSymPath = _strdup(szSymPath);\r
-    this->m_options |= SymBuildPath;\r
-  }\r
-  else\r
-    this->m_szSymPath = NULL;\r
-}\r
-\r
-stack_walker::~stack_walker()\r
-{\r
-  if (m_szSymPath != NULL)\r
-    free(m_szSymPath);\r
-  m_szSymPath = NULL;\r
-  if (this->m_sw != NULL)\r
-    delete this->m_sw;\r
-  this->m_sw = NULL;\r
-}\r
-\r
-BOOL stack_walker::LoadModules()\r
-{\r
-  if (this->m_sw == NULL)\r
-  {\r
-    SetLastError(ERROR_DLL_INIT_FAILED);\r
-    return FALSE;\r
-  }\r
-  if (m_modulesLoaded != FALSE)\r
-    return TRUE;\r
-\r
-  // Build the sym-path:\r
-  char *szSymPath = NULL;\r
-  if ( (this->m_options & SymBuildPath) != 0)\r
-  {\r
-    const size_t nSymPathLen = 4096;\r
-    szSymPath = (char*) malloc(nSymPathLen);\r
-    if (szSymPath == NULL)\r
-    {\r
-      SetLastError(ERROR_NOT_ENOUGH_MEMORY);\r
-      return FALSE;\r
-    }\r
-    szSymPath[0] = 0;\r
-    // Now first add the (optional) provided sympath:\r
-    if (this->m_szSymPath != NULL)\r
-    {\r
-      strcat_s(szSymPath, nSymPathLen, this->m_szSymPath);\r
-      strcat_s(szSymPath, nSymPathLen, ";");\r
-    }\r
-\r
-    strcat_s(szSymPath, nSymPathLen, ".;");\r
-\r
-    const size_t nTempLen = 1024;\r
-    char szTemp[nTempLen];\r
-    // Now add the current directory:\r
-    if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)\r
-    {\r
-      szTemp[nTempLen-1] = 0;\r
-      strcat_s(szSymPath, nSymPathLen, szTemp);\r
-      strcat_s(szSymPath, nSymPathLen, ";");\r
-    }\r
-\r
-    // Now add the path for the main-module:\r
-    if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0)\r
-    {\r
-      szTemp[nTempLen-1] = 0;\r
-      for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p)\r
-      {\r
-        // locate the rightmost path separator\r
-        if ( (*p == '\\') || (*p == '/') || (*p == ':') )\r
-        {\r
-          *p = 0;\r
-          break;\r
-        }\r
-      }  // for (search for path separator...)\r
-      if (strlen(szTemp) > 0)\r
-      {\r
-        strcat_s(szSymPath, nSymPathLen, szTemp);\r
-        strcat_s(szSymPath, nSymPathLen, ";");\r
-      }\r
-    }\r
-    if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)\r
-    {\r
-      szTemp[nTempLen-1] = 0;\r
-      strcat_s(szSymPath, nSymPathLen, szTemp);\r
-      strcat_s(szSymPath, nSymPathLen, ";");\r
-    }\r
-    if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)\r
-    {\r
-      szTemp[nTempLen-1] = 0;\r
-      strcat_s(szSymPath, nSymPathLen, szTemp);\r
-      strcat_s(szSymPath, nSymPathLen, ";");\r
-    }\r
-    if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)\r
-    {\r
-      szTemp[nTempLen-1] = 0;\r
-      strcat_s(szSymPath, nSymPathLen, szTemp);\r
-      strcat_s(szSymPath, nSymPathLen, ";");\r
-      // also add the "system32"-directory:\r
-      strcat_s(szTemp, nTempLen, "\\system32");\r
-      strcat_s(szSymPath, nSymPathLen, szTemp);\r
-      strcat_s(szSymPath, nSymPathLen, ";");\r
-    }\r
-\r
-    if ( (this->m_options & SymBuildPath) != 0)\r
-    {\r
-      if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0)\r
-      {\r
-        szTemp[nTempLen-1] = 0;\r
-        strcat_s(szSymPath, nSymPathLen, "SRV*");\r
-        strcat_s(szSymPath, nSymPathLen, szTemp);\r
-        strcat_s(szSymPath, nSymPathLen, "\\websymbols");\r
-        strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;");\r
-      }\r
-      else\r
-        strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;");\r
-    }\r
-  }\r
-\r
-  // First Init the whole stuff...\r
-  BOOL bRet = this->m_sw->Init(szSymPath);\r
-  if (szSymPath != NULL) free(szSymPath); szSymPath = NULL;\r
-  if (bRet == FALSE)\r
-  {\r
-    this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);\r
-    SetLastError(ERROR_DLL_INIT_FAILED);\r
-    return FALSE;\r
-  }\r
-\r
-  bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId);\r
-  if (bRet != FALSE)\r
-    m_modulesLoaded = TRUE;\r
-  return bRet;\r
-}\r
-\r
-\r
-// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction\r
-// This has to be done due to a problem with the "hProcess"-parameter in x64...\r
-// Because this class is in no case multi-threading-enabled (because of the limitations \r
-// of dbghelp.dll) it is "safe" to use a static-variable\r
-static stack_walker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL;\r
-static LPVOID s_readMemoryFunction_UserData = NULL;\r
-\r
-BOOL stack_walker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData)\r
-{\r
-  CONTEXT c;;\r
-  CallstackEntry csEntry;\r
-  IMAGEHLP_SYMBOL64 *pSym = NULL;\r
-  stack_walkerInternal::IMAGEHLP_MODULE64_V2 Module;\r
-  IMAGEHLP_LINE64 Line;\r
-  int frameNum;\r
-\r
-  if (m_modulesLoaded == FALSE)\r
-    this->LoadModules();  // ignore the result...\r
-\r
-  if (this->m_sw->m_hDbhHelp == NULL)\r
-  {\r
-    SetLastError(ERROR_DLL_INIT_FAILED);\r
-    return FALSE;\r
-  }\r
-\r
-  s_readMemoryFunction = readMemoryFunction;\r
-  s_readMemoryFunction_UserData = pUserData;\r
-\r
-  if (context == NULL)\r
-  {\r
-    // If no context is provided, capture the context\r
-    if (hThread == GetCurrentThread())\r
-    {\r
-      GET_CURRENT_CONTEXT(c, USED_CONTEXT_FLAGS);\r
-    }\r
-    else\r
-    {\r
-      SuspendThread(hThread);\r
-      memset(&c, 0, sizeof(CONTEXT));\r
-      c.ContextFlags = USED_CONTEXT_FLAGS;\r
-      if (GetThreadContext(hThread, &c) == FALSE)\r
-      {\r
-        ResumeThread(hThread);\r
-        return FALSE;\r
-      }\r
-    }\r
-  }\r
-  else\r
-    c = *context;\r
-\r
-  // init STACKFRAME for first call\r
-  STACKFRAME64 s; // in/out stackframe\r
-  memset(&s, 0, sizeof(s));\r
-  DWORD imageType;\r
-#ifdef _M_IX86\r
-  // normally, call ImageNtHeader() and use machine info from PE header\r
-  imageType = IMAGE_FILE_MACHINE_I386;\r
-  s.AddrPC.Offset = c.Eip;\r
-  s.AddrPC.Mode = AddrModeFlat;\r
-  s.AddrFrame.Offset = c.Ebp;\r
-  s.AddrFrame.Mode = AddrModeFlat;\r
-  s.AddrStack.Offset = c.Esp;\r
-  s.AddrStack.Mode = AddrModeFlat;\r
-#elif _M_X64\r
-  imageType = IMAGE_FILE_MACHINE_AMD64;\r
-  s.AddrPC.Offset = c.Rip;\r
-  s.AddrPC.Mode = AddrModeFlat;\r
-  s.AddrFrame.Offset = c.Rsp;\r
-  s.AddrFrame.Mode = AddrModeFlat;\r
-  s.AddrStack.Offset = c.Rsp;\r
-  s.AddrStack.Mode = AddrModeFlat;\r
-#elif _M_IA64\r
-  imageType = IMAGE_FILE_MACHINE_IA64;\r
-  s.AddrPC.Offset = c.StIIP;\r
-  s.AddrPC.Mode = AddrModeFlat;\r
-  s.AddrFrame.Offset = c.IntSp;\r
-  s.AddrFrame.Mode = AddrModeFlat;\r
-  s.AddrBStore.Offset = c.RsBSP;\r
-  s.AddrBStore.Mode = AddrModeFlat;\r
-  s.AddrStack.Offset = c.IntSp;\r
-  s.AddrStack.Mode = AddrModeFlat;\r
-#else\r
-#error "Platform not supported!"\r
-#endif\r
-\r
-  pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);\r
-  if (!pSym) goto cleanup;  // not enough memory...\r
-  memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);\r
-  pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);\r
-  pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;\r
-\r
-  memset(&Line, 0, sizeof(Line));\r
-  Line.SizeOfStruct = sizeof(Line);\r
-\r
-  memset(&Module, 0, sizeof(Module));\r
-  Module.SizeOfStruct = sizeof(Module);\r
-\r
-  for (frameNum = 0; ; ++frameNum )\r
-  {\r
-    // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())\r
-    // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can\r
-    // assume that either you are done, or that the stack is so hosed that the next\r
-    // deeper frame could not be found.\r
-    // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386!\r
-    if ( ! this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, this->m_sw->pSFTA, this->m_sw->pSGMB, NULL) )\r
-    {\r
-      this->OnDbgHelpErr("StackWalk64", GetLastError(), s.AddrPC.Offset);\r
-      break;\r
-    }\r
-\r
-    csEntry.offset = s.AddrPC.Offset;\r
-    csEntry.name[0] = 0;\r
-    csEntry.undName[0] = 0;\r
-    csEntry.undFullName[0] = 0;\r
-    csEntry.offsetFromSmybol = 0;\r
-    csEntry.offsetFromLine = 0;\r
-    csEntry.lineFileName[0] = 0;\r
-    csEntry.lineNumber = 0;\r
-    csEntry.loadedImageName[0] = 0;\r
-    csEntry.moduleName[0] = 0;\r
-    if (s.AddrPC.Offset == s.AddrReturn.Offset)\r
-    {\r
-      this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);\r
-      break;\r
-    }\r
-    if (s.AddrPC.Offset != 0)\r
-    {\r
-      // we seem to have a valid PC\r
-      // show procedure info (SymGetSymFromAddr64())\r
-      if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE)\r
-      {\r
-        // TODO: Mache dies sicher...!\r
-        strcpy_s(csEntry.name, pSym->Name);\r
-        // UnDecorateSymbolName()\r
-        this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY );\r
-        this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE );\r
-      }\r
-      else\r
-      {\r
-        this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);\r
-      }\r
-\r
-      // show line number info, NT5.0-method (SymGetLineFromAddr64())\r
-      if (this->m_sw->pSGLFA != NULL )\r
-      { // yes, we have SymGetLineFromAddr64()\r
-        if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE)\r
-        {\r
-          csEntry.lineNumber = Line.LineNumber;\r
-          // TODO: Mache dies sicher...!\r
-          strcpy_s(csEntry.lineFileName, Line.FileName);\r
-        }\r
-        else\r
-        {\r
-          this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);\r
-        }\r
-      } // yes, we have SymGetLineFromAddr64()\r
-\r
-      // show module info (SymGetModuleInfo64())\r
-      if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE)\r
-      { // got module info OK\r
-        switch ( Module.SymType )\r
-        {\r
-        case SymNone:\r
-          csEntry.symTypeString = "-nosymbols-";\r
-          break;\r
-        case SymCoff:\r
-          csEntry.symTypeString = "COFF";\r
-          break;\r
-        case SymCv:\r
-          csEntry.symTypeString = "CV";\r
-          break;\r
-        case SymPdb:\r
-          csEntry.symTypeString = "PDB";\r
-          break;\r
-        case SymExport:\r
-          csEntry.symTypeString = "-exported-";\r
-          break;\r
-        case SymDeferred:\r
-          csEntry.symTypeString = "-deferred-";\r
-          break;\r
-        case SymSym:\r
-          csEntry.symTypeString = "SYM";\r
-          break;\r
-#if API_VERSION_NUMBER >= 9\r
-        case SymDia:\r
-          csEntry.symTypeString = "DIA";\r
-          break;\r
-#endif\r
-        case 8: //SymVirtual:\r
-          csEntry.symTypeString = "Virtual";\r
-          break;\r
-        default:\r
-          //_snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType );\r
-          csEntry.symTypeString = NULL;\r
-          break;\r
-        }\r
-\r
-        // TODO: Mache dies sicher...!\r
-        strcpy_s(csEntry.moduleName, Module.ModuleName);\r
-        csEntry.baseOfImage = Module.BaseOfImage;\r
-        strcpy_s(csEntry.loadedImageName, Module.LoadedImageName);\r
-      } // got module info OK\r
-      else\r
-      {\r
-        this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);\r
-      }\r
-    } // we seem to have a valid PC\r
-\r
-    CallstackEntryType et = nextEntry;\r
-    if (frameNum == 0)\r
-      et = firstEntry;\r
-    this->OnCallstackEntry(et, csEntry);\r
-    \r
-    if (s.AddrReturn.Offset == 0)\r
-    {\r
-      this->OnCallstackEntry(lastEntry, csEntry);\r
-      SetLastError(ERROR_SUCCESS);\r
-      break;\r
-    }\r
-  } // for ( frameNum )\r
-\r
-  cleanup:\r
-    if (pSym) free( pSym );\r
-\r
-  if (context == NULL)\r
-    ResumeThread(hThread);\r
-\r
-  return TRUE;\r
-}\r
-\r
-BOOL __stdcall stack_walker::myReadProcMem(\r
-    HANDLE      hProcess,\r
-    DWORD64     qwBaseAddress,\r
-    PVOID       lpBuffer,\r
-    DWORD       nSize,\r
-    LPDWORD     lpNumberOfBytesRead\r
-    )\r
-{\r
-  if (s_readMemoryFunction == NULL)\r
-  {\r
-    SIZE_T st;\r
-    BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st);\r
-    *lpNumberOfBytesRead = (DWORD) st;\r
-    //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);\r
-    return bRet;\r
-  }\r
-  else\r
-  {\r
-    return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData);\r
-  }\r
-}\r
-\r
-void stack_walker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)\r
-{\r
-  CHAR buffer[STACKWALK_MAX_NAMELEN];\r
-  if (fileVersion == 0)\r
-    _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName);\r
-  else\r
-  {\r
-    DWORD v4 = (DWORD) fileVersion & 0xFFFF;\r
-    DWORD v3 = (DWORD) (fileVersion>>16) & 0xFFFF;\r
-    DWORD v2 = (DWORD) (fileVersion>>32) & 0xFFFF;\r
-    DWORD v1 = (DWORD) (fileVersion>>48) & 0xFFFF;\r
-    _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);\r
-  }\r
-  OnOutput(buffer);\r
-}\r
-\r
-void stack_walker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)\r
-{\r
-  CHAR buffer[STACKWALK_MAX_NAMELEN];\r
-  if ( (eType != lastEntry) && (entry.offset != 0) )\r
-  {\r
-    if (entry.name[0] == 0)\r
-      strcpy_s(entry.name, "(function-name not available)");\r
-    if (entry.undName[0] != 0)\r
-      strcpy_s(entry.name, entry.undName);\r
-    if (entry.undFullName[0] != 0)\r
-      strcpy_s(entry.name, entry.undFullName);\r
-    if (entry.lineFileName[0] == 0)\r
-    {\r
-      strcpy_s(entry.lineFileName, "(filename not available)");\r
-      if (entry.moduleName[0] == 0)\r
-        strcpy_s(entry.moduleName, "(module-name not available)");\r
-      _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name);\r
-    }\r
-    else\r
-      _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name);\r
-    OnOutput(buffer);\r
-  }\r
-}\r
-\r
-void stack_walker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)\r
-{\r
-  CHAR buffer[STACKWALK_MAX_NAMELEN];\r
-  _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr);\r
-  OnOutput(buffer);\r
-}\r
-\r
-void stack_walker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)\r
-{\r
-  CHAR buffer[STACKWALK_MAX_NAMELEN];\r
-  _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName);\r
-  OnOutput(buffer);\r
-  // Also display the OS-version\r
-#if _MSC_VER <= 1200\r
-  OSVERSIONINFOA ver;\r
-  ZeroMemory(&ver, sizeof(OSVERSIONINFOA));\r
-  ver.dwOSVersionInfoSize = sizeof(ver);\r
-  if (GetVersionExA(&ver) != FALSE)\r
-  {\r
-    _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", \r
-      ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,\r
-      ver.szCSDVersion);\r
-    OnOutput(buffer);\r
-  }\r
-#else\r
-  OSVERSIONINFOEXA ver;\r
-  ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));\r
-  ver.dwOSVersionInfoSize = sizeof(ver);\r
-  if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE)\r
-  {\r
-    _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", \r
-      ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,\r
-      ver.szCSDVersion, ver.wSuiteMask, ver.wProductType);\r
-    OnOutput(buffer);\r
-  }\r
-#endif\r
-}\r
-\r
-void stack_walker::OnOutput(LPCSTR buffer)\r
-{\r
-  OutputDebugStringA(buffer);\r
-}\r
+/**********************************************************************
+ * 
+ * stack_walker.cpp
+ *
+ *
+ * History:
+ *  2005-07-27   v1    - First public release on http://www.codeproject.com/
+ *                       http://www.codeproject.com/threads/stack_walker.asp
+ *  2005-07-28   v2    - Changed the params of the constructor and ShowCallstack
+ *                       (to simplify the usage)
+ *  2005-08-01   v3    - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL 
+ *                       (should also be enough)
+ *                     - Changed to compile correctly with the PSDK of VC7.0
+ *                       (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined:
+ *                        it uses LPSTR instead of LPCSTR as first paremeter)
+ *                     - Added declarations to support VC5/6 without using 'dbghelp.h'
+ *                     - Added a 'pUserData' member to the ShowCallstack function and the 
+ *                       PReadProcessMemoryRoutine declaration (to pass some user-defined data, 
+ *                       which can be used in the readMemoryFunction-callback)
+ *  2005-08-02   v4    - OnSymInit now also outputs the OS-Version by default
+ *                     - Added example for doing an exception-callstack-walking in main.cpp
+ *                       (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268)
+ *  2005-08-05   v5    - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse!
+ *
+ **********************************************************************/
+#include <tchar.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#pragma warning(push, 1)
+
+#pragma comment(lib, "version.lib")  // for "VerQueryValue"
+
+#include "stack_walker.h"
+
+// If VC7 and later, then use the shipped 'dbghelp.h'-file
+#if _MSC_VER >= 1300
+#include <dbghelp.h>
+#else
+// inline the important dbghelp.h-declarations...
+typedef enum {
+    SymNone = 0,
+    SymCoff,
+    SymCv,
+    SymPdb,
+    SymExport,
+    SymDeferred,
+    SymSym,
+    SymDia,
+    SymVirtual,
+    NumSymTypes
+} SYM_TYPE;
+typedef struct _IMAGEHLP_LINE64 {
+    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_LINE64)
+    PVOID                       Key;                    // internal
+    DWORD                       LineNumber;             // line number in file
+    PCHAR                       FileName;               // full filename
+    DWORD64                     Address;                // first instruction of line
+} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
+typedef struct _IMAGEHLP_MODULE64 {
+    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)
+    DWORD64                     BaseOfImage;            // base load address of module
+    DWORD                       ImageSize;              // virtual size of the loaded module
+    DWORD                       TimeDateStamp;          // date/time stamp from pe header
+    DWORD                       CheckSum;               // checksum from the pe header
+    DWORD                       NumSyms;                // number of symbols in the symbol table
+    SYM_TYPE                    SymType;                // type of symbols loaded
+    CHAR                        ModuleName[32];         // module name
+    CHAR                        ImageName[256];         // image name
+    CHAR                        LoadedImageName[256];   // symbol file name
+} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;
+typedef struct _IMAGEHLP_SYMBOL64 {
+    DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_SYMBOL64)
+    DWORD64                     Address;                // virtual address including dll base address
+    DWORD                       Size;                   // estimated size of symbol, can be zero
+    DWORD                       Flags;                  // info about the symbols, see the SYMF defines
+    DWORD                       MaxNameLength;          // maximum size of symbol name in 'Name'
+    CHAR                        Name[1];                // symbol name (null terminated string)
+} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
+typedef enum {
+    AddrMode1616,
+    AddrMode1632,
+    AddrModeReal,
+    AddrModeFlat
+} ADDRESS_MODE;
+typedef struct _tagADDRESS64 {
+    DWORD64       Offset;
+    WORD          Segment;
+    ADDRESS_MODE  Mode;
+} ADDRESS64, *LPADDRESS64;
+typedef struct _KDHELP64 {
+    DWORD64   Thread;
+    DWORD   ThCallbackStack;
+    DWORD   ThCallbackBStore;
+    DWORD   NextCallback;
+    DWORD   FramePointer;
+    DWORD64   KiCallUserMode;
+    DWORD64   KeUserCallbackDispatcher;
+    DWORD64   SystemRangeStart;
+    DWORD64  Reserved[8];
+} KDHELP64, *PKDHELP64;
+typedef struct _tagSTACKFRAME64 {
+    ADDRESS64   AddrPC;               // program counter
+    ADDRESS64   AddrReturn;           // return address
+    ADDRESS64   AddrFrame;            // frame pointer
+    ADDRESS64   AddrStack;            // stack pointer
+    ADDRESS64   AddrBStore;           // backing store pointer
+    PVOID       FuncTableEntry;       // pointer to pdata/fpo or NULL
+    DWORD64     Params[4];            // possible arguments to the function
+    BOOL        Far;                  // WOW far call
+    BOOL        Virtual;              // is this a virtual frame?
+    DWORD64     Reserved[3];
+    KDHELP64    KdHelp;
+} STACKFRAME64, *LPSTACKFRAME64;
+typedef
+BOOL
+(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(
+    HANDLE      hProcess,
+    DWORD64     qwBaseAddress,
+    PVOID       lpBuffer,
+    DWORD       nSize,
+    LPDWORD     lpNumberOfBytesRead
+    );
+typedef
+PVOID
+(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(
+    HANDLE  hProcess,
+    DWORD64 AddrBase
+    );
+typedef
+DWORD64
+(__stdcall *PGET_MODULE_BASE_ROUTINE64)(
+    HANDLE  hProcess,
+    DWORD64 Address
+    );
+typedef
+DWORD64
+(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(
+    HANDLE    hProcess,
+    HANDLE    hThread,
+    LPADDRESS64 lpaddr
+    );
+#define SYMOPT_CASE_INSENSITIVE         0x00000001
+#define SYMOPT_UNDNAME                  0x00000002
+#define SYMOPT_DEFERRED_LOADS           0x00000004
+#define SYMOPT_NO_CPP                   0x00000008
+#define SYMOPT_LOAD_LINES               0x00000010
+#define SYMOPT_OMAP_FIND_NEAREST        0x00000020
+#define SYMOPT_LOAD_ANYTHING            0x00000040
+#define SYMOPT_IGNORE_CVREC             0x00000080
+#define SYMOPT_NO_UNQUALIFIED_LOADS     0x00000100
+#define SYMOPT_FAIL_CRITICAL_ERRORS     0x00000200
+#define SYMOPT_EXACT_SYMBOLS            0x00000400
+#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS   0x00000800
+#define SYMOPT_IGNORE_NT_SYMPATH        0x00001000
+#define SYMOPT_INCLUDE_32BIT_MODULES    0x00002000
+#define SYMOPT_PUBLICS_ONLY             0x00004000
+#define SYMOPT_NO_PUBLICS               0x00008000
+#define SYMOPT_AUTO_PUBLICS             0x00010000
+#define SYMOPT_NO_IMAGE_SEARCH          0x00020000
+#define SYMOPT_SECURE                   0x00040000
+#define SYMOPT_DEBUG                    0x80000000
+#define UNDNAME_COMPLETE                 (0x0000)  // Enable full undecoration
+#define UNDNAME_NAME_ONLY                (0x1000)  // Crack only the name for primary declaration;
+#endif  // _MSC_VER < 1300
+
+// Some missing defines (for VC5/6):
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif  
+
+
+// secure-CRT_functions are only available starting with VC8
+#if _MSC_VER < 1400
+#define strcpy_s strcpy
+#define strcat_s(dst, len, src) strcat(dst, src)
+#define _snprintf_s _snprintf
+#define _tcscat_s _tcscat
+#endif
+
+// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')
+#define USED_CONTEXT_FLAGS CONTEXT_FULL
+
+
+class stack_walkerInternal
+{
+public:
+  stack_walkerInternal(stack_walker *parent, HANDLE hProcess)
+  {
+    m_parent = parent;
+    m_hDbhHelp = NULL;
+    pSC = NULL;
+    m_hProcess = hProcess;
+    m_szSymPath = NULL;
+    pSFTA = NULL;
+    pSGLFA = NULL;
+    pSGMB = NULL;
+    pSGMI = NULL;
+    pSGO = NULL;
+    pSGSFA = NULL;
+    pSI = NULL;
+    pSLM = NULL;
+    pSSO = NULL;
+    pSW = NULL;
+    pUDSN = NULL;
+    pSGSP = NULL;
+  }
+  ~stack_walkerInternal()
+  {
+    if (pSC != NULL)
+      pSC(m_hProcess);  // SymCleanup
+    if (m_hDbhHelp != NULL)
+      FreeLibrary(m_hDbhHelp);
+    m_hDbhHelp = NULL;
+    m_parent = NULL;
+    if(m_szSymPath != NULL)
+      free(m_szSymPath);
+    m_szSymPath = NULL;
+  }
+  BOOL Init(LPCSTR szSymPath)
+  {
+    if (m_parent == NULL)
+      return FALSE;
+    // Dynamically load the Entry-Points for dbghelp.dll:
+    // First try to load the newsest one from
+    TCHAR szTemp[4096];
+    // But before wqe do this, we first check if the ".local" file exists
+    if (GetModuleFileName(NULL, szTemp, 4096) > 0)
+    {
+      _tcscat_s(szTemp, _T(".local"));
+      if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES)
+      {
+        // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows"
+        if (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)
+        {
+          _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll"));
+          // now check if the file exists:
+          if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
+          {
+            m_hDbhHelp = LoadLibrary(szTemp);
+          }
+        }
+          // Still not found? Then try to load the 64-Bit version:
+        if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
+        {
+          _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll"));
+          if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
+          {
+            m_hDbhHelp = LoadLibrary(szTemp);
+          }
+        }
+      }
+    }
+    if (m_hDbhHelp == NULL)  // if not already loaded, try to load a default-one
+      m_hDbhHelp = LoadLibrary( _T("dbghelp.dll") );
+    if (m_hDbhHelp == NULL)
+      return FALSE;
+    pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" );
+    pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" );
+
+    pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" );
+    pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" );
+    pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" );
+
+    pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" );
+    pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" );
+    pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" );
+    pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );
+    //pSGMI_V3 = (tSGMI_V3) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );
+    pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" );
+    pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" );
+    pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" );
+    pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" );
+
+    if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||
+      pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||
+      pSW == NULL || pUDSN == NULL || pSLM == NULL )
+    {
+      FreeLibrary(m_hDbhHelp);
+      m_hDbhHelp = NULL;
+      pSC = NULL;
+      return FALSE;
+    }
+
+    // SymInitialize
+    if (szSymPath != NULL)
+      m_szSymPath = _strdup(szSymPath);
+    if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)
+      this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);
+      
+    DWORD symOptions = this->pSGO();  // SymGetOptions
+    symOptions |= SYMOPT_LOAD_LINES;
+    symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
+    //symOptions |= SYMOPT_NO_PROMPTS;
+    // SymSetOptions
+    symOptions = this->pSSO(symOptions);
+
+    char buf[stack_walker::STACKWALK_MAX_NAMELEN] = {0};
+    if (this->pSGSP != NULL)
+    {
+      if (this->pSGSP(m_hProcess, buf, stack_walker::STACKWALK_MAX_NAMELEN) == FALSE)
+        this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);
+    }
+    char szUserName[1024] = {0};
+    DWORD dwSize = 1024;
+    GetUserNameA(szUserName, &dwSize);
+    this->m_parent->OnSymInit(buf, symOptions, szUserName);
+
+    return TRUE;
+  }
+
+  stack_walker *m_parent;
+
+  HMODULE m_hDbhHelp;
+  HANDLE m_hProcess;
+  LPSTR m_szSymPath;
+
+/*typedef struct IMAGEHLP_MODULE64_V3 {
+    DWORD    SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)
+    DWORD64  BaseOfImage;            // base load address of module
+    DWORD    ImageSize;              // virtual size of the loaded module
+    DWORD    TimeDateStamp;          // date/time stamp from pe header
+    DWORD    CheckSum;               // checksum from the pe header
+    DWORD    NumSyms;                // number of symbols in the symbol table
+    SYM_TYPE SymType;                // type of symbols loaded
+    CHAR     ModuleName[32];         // module name
+    CHAR     ImageName[256];         // image name
+    // new elements: 07-Jun-2002
+    CHAR     LoadedImageName[256];   // symbol file name
+    CHAR     LoadedPdbName[256];     // pdb file name
+    DWORD    CVSig;                  // Signature of the CV record in the debug directories
+    CHAR         CVData[MAX_PATH * 3];   // Contents of the CV record
+    DWORD    PdbSig;                 // Signature of PDB
+    GUID     PdbSig70;               // Signature of PDB (VC 7 and up)
+    DWORD    PdbAge;                 // DBI age of pdb
+    BOOL     PdbUnmatched;           // loaded an unmatched pdb
+    BOOL     DbgUnmatched;           // loaded an unmatched dbg
+    BOOL     LineNumbers;            // we have line number information
+    BOOL     GlobalSymbols;          // we have internal symbol information
+    BOOL     TypeInfo;               // we have type information
+    // new elements: 17-Dec-2003
+    BOOL     SourceIndexed;          // pdb supports source server
+    BOOL     Publics;                // contains public symbols
+};
+*/
+typedef struct IMAGEHLP_MODULE64_V2 {
+    DWORD    SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)
+    DWORD64  BaseOfImage;            // base load address of module
+    DWORD    ImageSize;              // virtual size of the loaded module
+    DWORD    TimeDateStamp;          // date/time stamp from pe header
+    DWORD    CheckSum;               // checksum from the pe header
+    DWORD    NumSyms;                // number of symbols in the symbol table
+    SYM_TYPE SymType;                // type of symbols loaded
+    CHAR     ModuleName[32];         // module name
+    CHAR     ImageName[256];         // image name
+    CHAR     LoadedImageName[256];   // symbol file name
+};
+
+
+  // SymCleanup()
+  typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess );
+  tSC pSC;
+
+  // SymFunctionTableAccess64()
+  typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase );
+  tSFTA pSFTA;
+
+  // SymGetLineFromAddr64()
+  typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,
+    OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line );
+  tSGLFA pSGLFA;
+
+  // SymGetModuleBase64()
+  typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr );
+  tSGMB pSGMB;
+
+  // SymGetModuleInfo64()
+  typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V2 *ModuleInfo );
+  tSGMI pSGMI;
+
+//  // SymGetModuleInfo64()
+//  typedef BOOL (__stdcall *tSGMI_V3)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo );
+//  tSGMI_V3 pSGMI_V3;
+
+  // SymGetOptions()
+  typedef DWORD (__stdcall *tSGO)( VOID );
+  tSGO pSGO;
+
+  // SymGetSymFromAddr64()
+  typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,
+    OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol );
+  tSGSFA pSGSFA;
+
+  // SymInitialize()
+  typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );
+  tSI pSI;
+
+  // SymLoadModule64()
+  typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile,
+    IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll );
+  tSLM pSLM;
+
+  // SymSetOptions()
+  typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions );
+  tSSO pSSO;
+
+  // StackWalk64()
+  typedef BOOL (__stdcall *tSW)( 
+    DWORD MachineType, 
+    HANDLE hProcess,
+    HANDLE hThread, 
+    LPSTACKFRAME64 StackFrame, 
+    PVOID ContextRecord,
+    PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+    PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+    PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+    PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );
+  tSW pSW;
+
+  // UnDecorateSymbolName()
+  typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName,
+    DWORD UndecoratedLength, DWORD Flags );
+  tUDSN pUDSN;
+
+  typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);
+  tSGSP pSGSP;
+
+
+private:
+  // **************************************** ToolHelp32 ************************
+  #define MAX_MODULE_NAME32 255
+  #define TH32CS_SNAPMODULE   0x00000008
+  #pragma pack( push, 8 )
+  typedef struct tagMODULEENTRY32
+  {
+      DWORD   dwSize;
+      DWORD   th32ModuleID;       // This module
+      DWORD   th32ProcessID;      // owning process
+      DWORD   GlblcntUsage;       // Global usage count on the module
+      DWORD   ProccntUsage;       // Module usage count in th32ProcessID's context
+      BYTE  * modBaseAddr;        // Base address of module in th32ProcessID's context
+      DWORD   modBaseSize;        // Size in bytes of module starting at modBaseAddr
+      HMODULE hModule;            // The hModule of this module in th32ProcessID's context
+      char    szModule[MAX_MODULE_NAME32 + 1];
+      char    szExePath[MAX_PATH];
+  } MODULEENTRY32;
+  typedef MODULEENTRY32 *  PMODULEENTRY32;
+  typedef MODULEENTRY32 *  LPMODULEENTRY32;
+  #pragma pack( pop )
+
+  BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid)
+  {
+    // CreateToolhelp32Snapshot()
+    typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID);
+    // Module32First()
+    typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
+    // Module32Next()
+    typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
+
+    // try both dlls...
+    const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") };
+    HINSTANCE hToolhelp = NULL;
+    tCT32S pCT32S = NULL;
+    tM32F pM32F = NULL;
+    tM32N pM32N = NULL;
+
+    HANDLE hSnap;
+    MODULEENTRY32 me;
+    me.dwSize = sizeof(me);
+    BOOL keepGoing;
+    size_t i;
+
+    for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ )
+    {
+      hToolhelp = LoadLibrary( dllname[i] );
+      if (hToolhelp == NULL)
+        continue;
+      pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
+      pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First");
+      pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next");
+      if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) )
+        break; // found the functions!
+      FreeLibrary(hToolhelp);
+      hToolhelp = NULL;
+    }
+
+    if (hToolhelp == NULL)
+      return FALSE;
+
+    hSnap = pCT32S( TH32CS_SNAPMODULE, pid );
+    if (hSnap == (HANDLE) -1)
+      return FALSE;
+
+    keepGoing = !!pM32F( hSnap, &me );
+    int cnt = 0;
+    while (keepGoing)
+    {
+      this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize);
+      cnt++;
+      keepGoing = !!pM32N( hSnap, &me );
+    }
+    CloseHandle(hSnap);
+    FreeLibrary(hToolhelp);
+    if (cnt <= 0)
+      return FALSE;
+    return TRUE;
+  }  // GetModuleListTH32
+
+  // **************************************** PSAPI ************************
+  typedef struct _MODULEINFO {
+      LPVOID lpBaseOfDll;
+      DWORD SizeOfImage;
+      LPVOID EntryPoint;
+  } MODULEINFO, *LPMODULEINFO;
+
+  BOOL GetModuleListPSAPI(HANDLE hProcess)
+  {
+    // EnumProcessModules()
+    typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
+    // GetModuleFileNameEx()
+    typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
+    // GetModuleBaseName()
+    typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
+    // GetModuleInformation()
+    typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize );
+
+    HINSTANCE hPsapi;
+    tEPM pEPM;
+    tGMFNE pGMFNE;
+    tGMBN pGMBN;
+    tGMI pGMI;
+
+    DWORD i;
+    //ModuleEntry e;
+    DWORD cbNeeded;
+    MODULEINFO mi;
+    HMODULE *hMods = 0;
+    char *tt = NULL;
+    char *tt2 = NULL;
+    const SIZE_T TTBUFLEN = 8096;
+    int cnt = 0;
+
+    hPsapi = LoadLibrary( _T("psapi.dll") );
+    if (hPsapi == NULL)
+      return FALSE;
+
+    pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" );
+    pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" );
+    pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" );
+    pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" );
+    if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) )
+    {
+      // we couldn´t find all functions
+      FreeLibrary(hPsapi);
+      return FALSE;
+    }
+
+    hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE));
+    tt = (char*) malloc(sizeof(char) * TTBUFLEN);
+    tt2 = (char*) malloc(sizeof(char) * TTBUFLEN);
+    if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) )
+      goto cleanup;
+
+    if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) )
+    {
+      //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );
+      goto cleanup;
+    }
+
+    if ( cbNeeded > TTBUFLEN )
+    {
+      //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );
+      goto cleanup;
+    }
+
+    for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ )
+    {
+      // base address, size
+      pGMI(hProcess, hMods[i], &mi, sizeof mi );
+      // image file name
+      tt[0] = 0;
+      pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );
+      // module name
+      tt2[0] = 0;
+      pGMBN(hProcess, hMods[i], tt2, TTBUFLEN );
+
+      DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage);
+      if (dwRes != ERROR_SUCCESS)
+        this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0);
+      cnt++;
+    }
+
+  cleanup:
+    if (hPsapi != NULL) FreeLibrary(hPsapi);
+    if (tt2 != NULL) free(tt2);
+    if (tt != NULL) free(tt);
+    if (hMods != NULL) free(hMods);
+
+    return cnt != 0;
+  }  // GetModuleListPSAPI
+
+  DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size)
+  {
+    CHAR *szImg = _strdup(img);
+    CHAR *szMod = _strdup(mod);
+    DWORD result = ERROR_SUCCESS;
+    if ( (szImg == NULL) || (szMod == NULL) )
+      result = ERROR_NOT_ENOUGH_MEMORY;
+    else
+    {
+      if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0)
+        result = GetLastError();
+    }
+    ULONGLONG fileVersion = 0;
+    if ( (m_parent != NULL) && (szImg != NULL) )
+    {
+      // try to retrive the file-version:
+      if ( (this->m_parent->m_options & stack_walker::RetrieveFileVersion) != 0)
+      {
+        VS_FIXEDFILEINFO *fInfo = NULL;
+        DWORD dwHandle;
+        DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle);
+        if (dwSize > 0)
+        {
+          LPVOID vData = malloc(dwSize);
+          if (vData != NULL)
+          {
+            if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0)
+            {
+              UINT len;
+              TCHAR szSubBlock[] = _T("\\");
+              if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0)
+                fInfo = NULL;
+              else
+              {
+                fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32);
+              }
+            }
+            free(vData);
+          }
+        }
+      }
+
+      // Retrive some additional-infos about the module
+      IMAGEHLP_MODULE64_V2 Module;
+      const char *szSymType = "-unknown-";
+      if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE)
+      {
+        switch(Module.SymType)
+        {
+          case SymNone:
+            szSymType = "-nosymbols-";
+            break;
+          case SymCoff:
+            szSymType = "COFF";
+            break;
+          case SymCv:
+            szSymType = "CV";
+            break;
+          case SymPdb:
+            szSymType = "PDB";
+            break;
+          case SymExport:
+            szSymType = "-exported-";
+            break;
+          case SymDeferred:
+            szSymType = "-deferred-";
+            break;
+          case SymSym:
+            szSymType = "SYM";
+            break;
+          case 8: //SymVirtual:
+            szSymType = "Virtual";
+            break;
+          case 9: // SymDia:
+            szSymType = "DIA";
+            break;
+        }
+      }
+      this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, Module.LoadedImageName, fileVersion);
+    }
+    if (szImg != NULL) free(szImg);
+    if (szMod != NULL) free(szMod);
+    return result;
+  }
+public:
+  BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId)
+  {
+    // first try toolhelp32
+    if (GetModuleListTH32(hProcess, dwProcessId))
+      return true;
+    // then try psapi
+    return GetModuleListPSAPI(hProcess);
+  }
+
+
+  BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V2 *pModuleInfo)
+  {
+    if(this->pSGMI == NULL)
+    {
+      SetLastError(ERROR_DLL_INIT_FAILED);
+      return FALSE;
+    }
+    // First try to use the larger ModuleInfo-Structure
+//    memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));
+//    pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
+//    if (this->pSGMI_V3 != NULL)
+//    {
+//      if (this->pSGMI_V3(hProcess, baseAddr, pModuleInfo) != FALSE)
+//        return TRUE;
+//      // check if the parameter was wrong (size is bad...)
+//      if (GetLastError() != ERROR_INVALID_PARAMETER)
+//        return FALSE;
+//    }
+    // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)...
+    pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
+    void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites...
+    if (pData == NULL)
+    {
+      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+      return FALSE;
+    }
+    memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));
+    if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V2*) pData) != FALSE)
+    {
+      // only copy as much memory as is reserved...
+      memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));
+      pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
+      free(pData);
+      return TRUE;
+    }
+    free(pData);
+    SetLastError(ERROR_DLL_INIT_FAILED);
+    return FALSE;
+  }
+};
+
+// #############################################################
+stack_walker::stack_walker(DWORD dwProcessId, HANDLE hProcess)
+{
+  this->m_options = OptionsAll;
+  this->m_modulesLoaded = FALSE;
+  this->m_hProcess = hProcess;
+  this->m_sw = new stack_walkerInternal(this, this->m_hProcess);
+  this->m_dwProcessId = dwProcessId;
+  this->m_szSymPath = NULL;
+}
+stack_walker::stack_walker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)
+{
+  this->m_options = options;
+  this->m_modulesLoaded = FALSE;
+  this->m_hProcess = hProcess;
+  this->m_sw = new stack_walkerInternal(this, this->m_hProcess);
+  this->m_dwProcessId = dwProcessId;
+  if (szSymPath != NULL)
+  {
+    this->m_szSymPath = _strdup(szSymPath);
+    this->m_options |= SymBuildPath;
+  }
+  else
+    this->m_szSymPath = NULL;
+}
+
+stack_walker::~stack_walker()
+{
+  if (m_szSymPath != NULL)
+    free(m_szSymPath);
+  m_szSymPath = NULL;
+  if (this->m_sw != NULL)
+    delete this->m_sw;
+  this->m_sw = NULL;
+}
+
+BOOL stack_walker::LoadModules()
+{
+  if (this->m_sw == NULL)
+  {
+    SetLastError(ERROR_DLL_INIT_FAILED);
+    return FALSE;
+  }
+  if (m_modulesLoaded != FALSE)
+    return TRUE;
+
+  // Build the sym-path:
+  char *szSymPath = NULL;
+  if ( (this->m_options & SymBuildPath) != 0)
+  {
+    const size_t nSymPathLen = 4096;
+    szSymPath = (char*) malloc(nSymPathLen);
+    if (szSymPath == NULL)
+    {
+      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+      return FALSE;
+    }
+    szSymPath[0] = 0;
+    // Now first add the (optional) provided sympath:
+    if (this->m_szSymPath != NULL)
+    {
+      strcat_s(szSymPath, nSymPathLen, this->m_szSymPath);
+      strcat_s(szSymPath, nSymPathLen, ";");
+    }
+
+    strcat_s(szSymPath, nSymPathLen, ".;");
+
+    const size_t nTempLen = 1024;
+    char szTemp[nTempLen];
+    // Now add the current directory:
+    if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)
+    {
+      szTemp[nTempLen-1] = 0;
+      strcat_s(szSymPath, nSymPathLen, szTemp);
+      strcat_s(szSymPath, nSymPathLen, ";");
+    }
+
+    // Now add the path for the main-module:
+    if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0)
+    {
+      szTemp[nTempLen-1] = 0;
+      for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p)
+      {
+        // locate the rightmost path separator
+        if ( (*p == '\\') || (*p == '/') || (*p == ':') )
+        {
+          *p = 0;
+          break;
+        }
+      }  // for (search for path separator...)
+      if (strlen(szTemp) > 0)
+      {
+        strcat_s(szSymPath, nSymPathLen, szTemp);
+        strcat_s(szSymPath, nSymPathLen, ";");
+      }
+    }
+    if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)
+    {
+      szTemp[nTempLen-1] = 0;
+      strcat_s(szSymPath, nSymPathLen, szTemp);
+      strcat_s(szSymPath, nSymPathLen, ";");
+    }
+    if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)
+    {
+      szTemp[nTempLen-1] = 0;
+      strcat_s(szSymPath, nSymPathLen, szTemp);
+      strcat_s(szSymPath, nSymPathLen, ";");
+    }
+    if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)
+    {
+      szTemp[nTempLen-1] = 0;
+      strcat_s(szSymPath, nSymPathLen, szTemp);
+      strcat_s(szSymPath, nSymPathLen, ";");
+      // also add the "system32"-directory:
+      strcat_s(szTemp, nTempLen, "\\system32");
+      strcat_s(szSymPath, nSymPathLen, szTemp);
+      strcat_s(szSymPath, nSymPathLen, ";");
+    }
+
+    if ( (this->m_options & SymBuildPath) != 0)
+    {
+      if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0)
+      {
+        szTemp[nTempLen-1] = 0;
+        strcat_s(szSymPath, nSymPathLen, "SRV*");
+        strcat_s(szSymPath, nSymPathLen, szTemp);
+        strcat_s(szSymPath, nSymPathLen, "\\websymbols");
+        strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;");
+      }
+      else
+        strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;");
+    }
+  }
+
+  // First Init the whole stuff...
+  BOOL bRet = this->m_sw->Init(szSymPath);
+  if (szSymPath != NULL) free(szSymPath); szSymPath = NULL;
+  if (bRet == FALSE)
+  {
+    this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);
+    SetLastError(ERROR_DLL_INIT_FAILED);
+    return FALSE;
+  }
+
+  bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId);
+  if (bRet != FALSE)
+    m_modulesLoaded = TRUE;
+  return bRet;
+}
+
+
+// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction
+// This has to be done due to a problem with the "hProcess"-parameter in x64...
+// Because this class is in no case multi-threading-enabled (because of the limitations 
+// of dbghelp.dll) it is "safe" to use a static-variable
+static stack_walker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL;
+static LPVOID s_readMemoryFunction_UserData = NULL;
+
+BOOL stack_walker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData)
+{
+  CONTEXT c;;
+  CallstackEntry csEntry;
+  IMAGEHLP_SYMBOL64 *pSym = NULL;
+  stack_walkerInternal::IMAGEHLP_MODULE64_V2 Module;
+  IMAGEHLP_LINE64 Line;
+  int frameNum;
+
+  if (m_modulesLoaded == FALSE)
+    this->LoadModules();  // ignore the result...
+
+  if (this->m_sw->m_hDbhHelp == NULL)
+  {
+    SetLastError(ERROR_DLL_INIT_FAILED);
+    return FALSE;
+  }
+
+  s_readMemoryFunction = readMemoryFunction;
+  s_readMemoryFunction_UserData = pUserData;
+
+  if (context == NULL)
+  {
+    // If no context is provided, capture the context
+    if (hThread == GetCurrentThread())
+    {
+      GET_CURRENT_CONTEXT(c, USED_CONTEXT_FLAGS);
+    }
+    else
+    {
+      SuspendThread(hThread);
+      memset(&c, 0, sizeof(CONTEXT));
+      c.ContextFlags = USED_CONTEXT_FLAGS;
+      if (GetThreadContext(hThread, &c) == FALSE)
+      {
+        ResumeThread(hThread);
+        return FALSE;
+      }
+    }
+  }
+  else
+    c = *context;
+
+  // init STACKFRAME for first call
+  STACKFRAME64 s; // in/out stackframe
+  memset(&s, 0, sizeof(s));
+  DWORD imageType;
+#ifdef _M_IX86
+  // normally, call ImageNtHeader() and use machine info from PE header
+  imageType = IMAGE_FILE_MACHINE_I386;
+  s.AddrPC.Offset = c.Eip;
+  s.AddrPC.Mode = AddrModeFlat;
+  s.AddrFrame.Offset = c.Ebp;
+  s.AddrFrame.Mode = AddrModeFlat;
+  s.AddrStack.Offset = c.Esp;
+  s.AddrStack.Mode = AddrModeFlat;
+#elif _M_X64
+  imageType = IMAGE_FILE_MACHINE_AMD64;
+  s.AddrPC.Offset = c.Rip;
+  s.AddrPC.Mode = AddrModeFlat;
+  s.AddrFrame.Offset = c.Rsp;
+  s.AddrFrame.Mode = AddrModeFlat;
+  s.AddrStack.Offset = c.Rsp;
+  s.AddrStack.Mode = AddrModeFlat;
+#elif _M_IA64
+  imageType = IMAGE_FILE_MACHINE_IA64;
+  s.AddrPC.Offset = c.StIIP;
+  s.AddrPC.Mode = AddrModeFlat;
+  s.AddrFrame.Offset = c.IntSp;
+  s.AddrFrame.Mode = AddrModeFlat;
+  s.AddrBStore.Offset = c.RsBSP;
+  s.AddrBStore.Mode = AddrModeFlat;
+  s.AddrStack.Offset = c.IntSp;
+  s.AddrStack.Mode = AddrModeFlat;
+#else
+#error "Platform not supported!"
+#endif
+
+  pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
+  if (!pSym) goto cleanup;  // not enough memory...
+  memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
+  pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+  pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
+
+  memset(&Line, 0, sizeof(Line));
+  Line.SizeOfStruct = sizeof(Line);
+
+  memset(&Module, 0, sizeof(Module));
+  Module.SizeOfStruct = sizeof(Module);
+
+  for (frameNum = 0; ; ++frameNum )
+  {
+    // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())
+    // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
+    // assume that either you are done, or that the stack is so hosed that the next
+    // deeper frame could not be found.
+    // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386!
+    if ( ! this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, this->m_sw->pSFTA, this->m_sw->pSGMB, NULL) )
+    {
+      this->OnDbgHelpErr("StackWalk64", GetLastError(), s.AddrPC.Offset);
+      break;
+    }
+
+    csEntry.offset = s.AddrPC.Offset;
+    csEntry.name[0] = 0;
+    csEntry.undName[0] = 0;
+    csEntry.undFullName[0] = 0;
+    csEntry.offsetFromSmybol = 0;
+    csEntry.offsetFromLine = 0;
+    csEntry.lineFileName[0] = 0;
+    csEntry.lineNumber = 0;
+    csEntry.loadedImageName[0] = 0;
+    csEntry.moduleName[0] = 0;
+    if (s.AddrPC.Offset == s.AddrReturn.Offset)
+    {
+      this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);
+      break;
+    }
+    if (s.AddrPC.Offset != 0)
+    {
+      // we seem to have a valid PC
+      // show procedure info (SymGetSymFromAddr64())
+      if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE)
+      {
+        // TODO: Mache dies sicher...!
+        strcpy_s(csEntry.name, pSym->Name);
+        // UnDecorateSymbolName()
+        this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY );
+        this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE );
+      }
+      else
+      {
+        this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);
+      }
+
+      // show line number info, NT5.0-method (SymGetLineFromAddr64())
+      if (this->m_sw->pSGLFA != NULL )
+      { // yes, we have SymGetLineFromAddr64()
+        if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE)
+        {
+          csEntry.lineNumber = Line.LineNumber;
+          // TODO: Mache dies sicher...!
+          strcpy_s(csEntry.lineFileName, Line.FileName);
+        }
+        else
+        {
+          this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);
+        }
+      } // yes, we have SymGetLineFromAddr64()
+
+      // show module info (SymGetModuleInfo64())
+      if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE)
+      { // got module info OK
+        switch ( Module.SymType )
+        {
+        case SymNone:
+          csEntry.symTypeString = "-nosymbols-";
+          break;
+        case SymCoff:
+          csEntry.symTypeString = "COFF";
+          break;
+        case SymCv:
+          csEntry.symTypeString = "CV";
+          break;
+        case SymPdb:
+          csEntry.symTypeString = "PDB";
+          break;
+        case SymExport:
+          csEntry.symTypeString = "-exported-";
+          break;
+        case SymDeferred:
+          csEntry.symTypeString = "-deferred-";
+          break;
+        case SymSym:
+          csEntry.symTypeString = "SYM";
+          break;
+#if API_VERSION_NUMBER >= 9
+        case SymDia:
+          csEntry.symTypeString = "DIA";
+          break;
+#endif
+        case 8: //SymVirtual:
+          csEntry.symTypeString = "Virtual";
+          break;
+        default:
+          //_snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType );
+          csEntry.symTypeString = NULL;
+          break;
+        }
+
+        // TODO: Mache dies sicher...!
+        strcpy_s(csEntry.moduleName, Module.ModuleName);
+        csEntry.baseOfImage = Module.BaseOfImage;
+        strcpy_s(csEntry.loadedImageName, Module.LoadedImageName);
+      } // got module info OK
+      else
+      {
+        this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);
+      }
+    } // we seem to have a valid PC
+
+    CallstackEntryType et = nextEntry;
+    if (frameNum == 0)
+      et = firstEntry;
+    this->OnCallstackEntry(et, csEntry);
+    
+    if (s.AddrReturn.Offset == 0)
+    {
+      this->OnCallstackEntry(lastEntry, csEntry);
+      SetLastError(ERROR_SUCCESS);
+      break;
+    }
+  } // for ( frameNum )
+
+  cleanup:
+    if (pSym) free( pSym );
+
+  if (context == NULL)
+    ResumeThread(hThread);
+
+  return TRUE;
+}
+
+BOOL __stdcall stack_walker::myReadProcMem(
+    HANDLE      hProcess,
+    DWORD64     qwBaseAddress,
+    PVOID       lpBuffer,
+    DWORD       nSize,
+    LPDWORD     lpNumberOfBytesRead
+    )
+{
+  if (s_readMemoryFunction == NULL)
+  {
+    SIZE_T st;
+    BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st);
+    *lpNumberOfBytesRead = (DWORD) st;
+    //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);
+    return bRet;
+  }
+  else
+  {
+    return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData);
+  }
+}
+
+void stack_walker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
+{
+  CHAR buffer[STACKWALK_MAX_NAMELEN];
+  if (fileVersion == 0)
+    _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName);
+  else
+  {
+    DWORD v4 = (DWORD) fileVersion & 0xFFFF;
+    DWORD v3 = (DWORD) (fileVersion>>16) & 0xFFFF;
+    DWORD v2 = (DWORD) (fileVersion>>32) & 0xFFFF;
+    DWORD v1 = (DWORD) (fileVersion>>48) & 0xFFFF;
+    _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);
+  }
+  OnOutput(buffer);
+}
+
+void stack_walker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
+{
+  CHAR buffer[STACKWALK_MAX_NAMELEN];
+  if ( (eType != lastEntry) && (entry.offset != 0) )
+  {
+    if (entry.name[0] == 0)
+      strcpy_s(entry.name, "(function-name not available)");
+    if (entry.undName[0] != 0)
+      strcpy_s(entry.name, entry.undName);
+    if (entry.undFullName[0] != 0)
+      strcpy_s(entry.name, entry.undFullName);
+    if (entry.lineFileName[0] == 0)
+    {
+      strcpy_s(entry.lineFileName, "(filename not available)");
+      if (entry.moduleName[0] == 0)
+        strcpy_s(entry.moduleName, "(module-name not available)");
+      _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name);
+    }
+    else
+      _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name);
+    OnOutput(buffer);
+  }
+}
+
+void stack_walker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
+{
+  CHAR buffer[STACKWALK_MAX_NAMELEN];
+  _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr);
+  OnOutput(buffer);
+}
+
+void stack_walker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
+{
+  CHAR buffer[STACKWALK_MAX_NAMELEN];
+  _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName);
+  OnOutput(buffer);
+  // Also display the OS-version
+#if _MSC_VER <= 1200
+  OSVERSIONINFOA ver;
+  ZeroMemory(&ver, sizeof(OSVERSIONINFOA));
+  ver.dwOSVersionInfoSize = sizeof(ver);
+  if (GetVersionExA(&ver) != FALSE)
+  {
+    _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", 
+      ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
+      ver.szCSDVersion);
+    OnOutput(buffer);
+  }
+#else
+  OSVERSIONINFOEXA ver;
+  ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
+  ver.dwOSVersionInfoSize = sizeof(ver);
+  if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE)
+  {
+    _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", 
+      ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
+      ver.szCSDVersion, ver.wSuiteMask, ver.wProductType);
+    OnOutput(buffer);
+  }
+#endif
+}
+
+void stack_walker::OnOutput(LPCSTR buffer)
+{
+  OutputDebugStringA(buffer);
+}
index 0eb3384c79691c20c866b72145a2bc6e9b3e94dc..0e6a7017c5030aa7cdcc842cbe5cc3ed8bab1385 100644 (file)
-/**********************************************************************\r
- * \r
- * stack_walker.h\r
- *\r
- *\r
- * History:\r
- *  2005-07-27   v1    - First public release on http://www.codeproject.com/\r
- *  (for additional changes see History in 'stack_walker.cpp'!\r
- *\r
- **********************************************************************/\r
-// #pragma once is supported starting with _MCS_VER 1000, \r
-// so we need not to check the version (because we only support _MSC_VER >= 1100)!\r
-#pragma once\r
-\r
-#include <windows.h>\r
-\r
-// special defines for VC5/6 (if no actual PSDK is installed):\r
-#if _MSC_VER < 1300\r
-typedef unsigned __int64 DWORD64, *PDWORD64;\r
-#if defined(_WIN64)\r
-typedef unsigned __int64 SIZE_T, *PSIZE_T;\r
-#else\r
-typedef unsigned long SIZE_T, *PSIZE_T;\r
-#endif\r
-#endif  // _MSC_VER < 1300\r
-\r
-class stack_walkerInternal;  // forward\r
-class stack_walker\r
-{\r
-public:\r
-  typedef enum StackWalkOptions\r
-  {\r
-    // No addition info will be retrived \r
-    // (only the address is available)\r
-    RetrieveNone = 0,\r
-    \r
-    // Try to get the symbol-name\r
-    RetrieveSymbol = 1,\r
-    \r
-    // Try to get the line for this symbol\r
-    RetrieveLine = 2,\r
-    \r
-    // Try to retrieve the module-infos\r
-    RetrieveModuleInfo = 4,\r
-    \r
-    // Also retrieve the version for the DLL/EXE\r
-    RetrieveFileVersion = 8,\r
-    \r
-    // Contains all the abouve\r
-    RetrieveVerbose = 0xF,\r
-    \r
-    // Generate a "good" symbol-search-path\r
-    SymBuildPath = 0x10,\r
-    \r
-    // Also use the public Microsoft-Symbol-Server\r
-    SymUseSymSrv = 0x20,\r
-    \r
-    // Contains all the abouve "Sym"-options\r
-    SymAll = 0x30,\r
-    \r
-    // Contains all options (default)\r
-    OptionsAll = 0x3F\r
-  } StackWalkOptions;\r
-\r
-  stack_walker(\r
-    int options = OptionsAll, // 'int' is by design, to combine the enum-flags\r
-    LPCSTR szSymPath = NULL, \r
-    DWORD dwProcessId = GetCurrentProcessId(), \r
-    HANDLE hProcess = GetCurrentProcess()\r
-    );\r
-  stack_walker(DWORD dwProcessId, HANDLE hProcess);\r
-  virtual ~stack_walker();\r
-\r
-  typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(\r
-    HANDLE      hProcess,\r
-    DWORD64     qwBaseAddress,\r
-    PVOID       lpBuffer,\r
-    DWORD       nSize,\r
-    LPDWORD     lpNumberOfBytesRead,\r
-    LPVOID      pUserData  // optional data, which was passed in "ShowCallstack"\r
-    );\r
-\r
-  BOOL LoadModules();\r
-\r
-  BOOL ShowCallstack(\r
-    HANDLE hThread = GetCurrentThread(), \r
-    const CONTEXT *context = NULL, \r
-    PReadProcessMemoryRoutine readMemoryFunction = NULL,\r
-    LPVOID pUserData = NULL  // optional to identify some data in the 'readMemoryFunction'-callback\r
-    );\r
-\r
-#if _MSC_VER >= 1300\r
-// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" \r
-// in older compilers in order to use it... starting with VC7 we can declare it as "protected"\r
-protected:\r
-#endif\r
-       enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols\r
-\r
-protected:\r
-  // Entry for each Callstack-Entry\r
-  typedef struct CallstackEntry\r
-  {\r
-    DWORD64 offset;  // if 0, we have no valid entry\r
-    CHAR name[STACKWALK_MAX_NAMELEN];\r
-    CHAR undName[STACKWALK_MAX_NAMELEN];\r
-    CHAR undFullName[STACKWALK_MAX_NAMELEN];\r
-    DWORD64 offsetFromSmybol;\r
-    DWORD offsetFromLine;\r
-    DWORD lineNumber;\r
-    CHAR lineFileName[STACKWALK_MAX_NAMELEN];\r
-    DWORD symType;\r
-    LPCSTR symTypeString;\r
-    CHAR moduleName[STACKWALK_MAX_NAMELEN];\r
-    DWORD64 baseOfImage;\r
-    CHAR loadedImageName[STACKWALK_MAX_NAMELEN];\r
-  } CallstackEntry;\r
-\r
-  typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};\r
-\r
-  virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);\r
-  virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);\r
-  virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);\r
-  virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);\r
-  virtual void OnOutput(LPCSTR szText);\r
-\r
-  stack_walkerInternal *m_sw;\r
-  HANDLE m_hProcess;\r
-  DWORD m_dwProcessId;\r
-  BOOL m_modulesLoaded;\r
-  LPSTR m_szSymPath;\r
-\r
-  int m_options;\r
-\r
-  static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);\r
-\r
-  friend stack_walkerInternal;\r
-};\r
-\r
-\r
-// The "ugly" assembler-implementation is needed for systems before XP\r
-// If you have a new PSDK and you only compile for XP and later, then you can use \r
-// the "RtlCaptureContext"\r
-// Currently there is no define which determines the PSDK-Version... \r
-// So we just use the compiler-version (and assumes that the PSDK is \r
-// the one which was installed by the VS-IDE)\r
-\r
-// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...\r
-//       But I currently use it in x64/IA64 environments...\r
-//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)\r
-\r
-#if defined(_M_IX86)\r
-#ifdef CURRENT_THREAD_VIA_EXCEPTION\r
-// TODO: The following is not a "good" implementation, \r
-// because the callstack is only valid in the "__except" block...\r
-#define GET_CURRENT_CONTEXT(c, contextFlags) \\r
-  do { \\r
-    memset(&c, 0, sizeof(CONTEXT)); \\r
-    EXCEPTION_POINTERS *pExp = NULL; \\r
-    __try { \\r
-      throw 0; \\r
-    } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \\r
-    if (pExp != NULL) \\r
-      memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \\r
-      c.ContextFlags = contextFlags; \\r
-  } while(0);\r
-#else\r
-// The following should be enough for walking the callstack...\r
-#define GET_CURRENT_CONTEXT(c, contextFlags) \\r
-  do { \\r
-    memset(&c, 0, sizeof(CONTEXT)); \\r
-    c.ContextFlags = contextFlags; \\r
-    __asm    call x \\r
-    __asm x: pop eax \\r
-    __asm    mov c.Eip, eax \\r
-    __asm    mov c.Ebp, ebp \\r
-    __asm    mov c.Esp, esp \\r
-  } while(0);\r
-#endif\r
-\r
-#else\r
-\r
-// The following is defined for x86 (XP and higher), x64 and IA64:\r
-#define GET_CURRENT_CONTEXT(c, contextFlags) \\r
-  do { \\r
-    memset(&c, 0, sizeof(CONTEXT)); \\r
-    c.ContextFlags = contextFlags; \\r
-    RtlCaptureContext(&c); \\r
-} while(0);\r
-#endif\r
+/**********************************************************************
+ * 
+ * stack_walker.h
+ *
+ *
+ * History:
+ *  2005-07-27   v1    - First public release on http://www.codeproject.com/
+ *  (for additional changes see History in 'stack_walker.cpp'!
+ *
+ **********************************************************************/
+// #pragma once is supported starting with _MCS_VER 1000, 
+// so we need not to check the version (because we only support _MSC_VER >= 1100)!
+#pragma once
+
+#include <windows.h>
+
+// special defines for VC5/6 (if no actual PSDK is installed):
+#if _MSC_VER < 1300
+typedef unsigned __int64 DWORD64, *PDWORD64;
+#if defined(_WIN64)
+typedef unsigned __int64 SIZE_T, *PSIZE_T;
+#else
+typedef unsigned long SIZE_T, *PSIZE_T;
+#endif
+#endif  // _MSC_VER < 1300
+
+class stack_walkerInternal;  // forward
+class stack_walker
+{
+public:
+  typedef enum StackWalkOptions
+  {
+    // No addition info will be retrived 
+    // (only the address is available)
+    RetrieveNone = 0,
+    
+    // Try to get the symbol-name
+    RetrieveSymbol = 1,
+    
+    // Try to get the line for this symbol
+    RetrieveLine = 2,
+    
+    // Try to retrieve the module-infos
+    RetrieveModuleInfo = 4,
+    
+    // Also retrieve the version for the DLL/EXE
+    RetrieveFileVersion = 8,
+    
+    // Contains all the abouve
+    RetrieveVerbose = 0xF,
+    
+    // Generate a "good" symbol-search-path
+    SymBuildPath = 0x10,
+    
+    // Also use the public Microsoft-Symbol-Server
+    SymUseSymSrv = 0x20,
+    
+    // Contains all the abouve "Sym"-options
+    SymAll = 0x30,
+    
+    // Contains all options (default)
+    OptionsAll = 0x3F
+  } StackWalkOptions;
+
+  stack_walker(
+    int options = OptionsAll, // 'int' is by design, to combine the enum-flags
+    LPCSTR szSymPath = NULL, 
+    DWORD dwProcessId = GetCurrentProcessId(), 
+    HANDLE hProcess = GetCurrentProcess()
+    );
+  stack_walker(DWORD dwProcessId, HANDLE hProcess);
+  virtual ~stack_walker();
+
+  typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
+    HANDLE      hProcess,
+    DWORD64     qwBaseAddress,
+    PVOID       lpBuffer,
+    DWORD       nSize,
+    LPDWORD     lpNumberOfBytesRead,
+    LPVOID      pUserData  // optional data, which was passed in "ShowCallstack"
+    );
+
+  BOOL LoadModules();
+
+  BOOL ShowCallstack(
+    HANDLE hThread = GetCurrentThread(), 
+    const CONTEXT *context = NULL, 
+    PReadProcessMemoryRoutine readMemoryFunction = NULL,
+    LPVOID pUserData = NULL  // optional to identify some data in the 'readMemoryFunction'-callback
+    );
+
+#if _MSC_VER >= 1300
+// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" 
+// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
+protected:
+#endif
+       enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols
+
+protected:
+  // Entry for each Callstack-Entry
+  typedef struct CallstackEntry
+  {
+    DWORD64 offset;  // if 0, we have no valid entry
+    CHAR name[STACKWALK_MAX_NAMELEN];
+    CHAR undName[STACKWALK_MAX_NAMELEN];
+    CHAR undFullName[STACKWALK_MAX_NAMELEN];
+    DWORD64 offsetFromSmybol;
+    DWORD offsetFromLine;
+    DWORD lineNumber;
+    CHAR lineFileName[STACKWALK_MAX_NAMELEN];
+    DWORD symType;
+    LPCSTR symTypeString;
+    CHAR moduleName[STACKWALK_MAX_NAMELEN];
+    DWORD64 baseOfImage;
+    CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
+  } CallstackEntry;
+
+  typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};
+
+  virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
+  virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
+  virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
+  virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
+  virtual void OnOutput(LPCSTR szText);
+
+  stack_walkerInternal *m_sw;
+  HANDLE m_hProcess;
+  DWORD m_dwProcessId;
+  BOOL m_modulesLoaded;
+  LPSTR m_szSymPath;
+
+  int m_options;
+
+  static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
+
+  friend stack_walkerInternal;
+};
+
+
+// The "ugly" assembler-implementation is needed for systems before XP
+// If you have a new PSDK and you only compile for XP and later, then you can use 
+// the "RtlCaptureContext"
+// Currently there is no define which determines the PSDK-Version... 
+// So we just use the compiler-version (and assumes that the PSDK is 
+// the one which was installed by the VS-IDE)
+
+// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
+//       But I currently use it in x64/IA64 environments...
+//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
+
+#if defined(_M_IX86)
+#ifdef CURRENT_THREAD_VIA_EXCEPTION
+// TODO: The following is not a "good" implementation, 
+// because the callstack is only valid in the "__except" block...
+#define GET_CURRENT_CONTEXT(c, contextFlags) \
+  do { \
+    memset(&c, 0, sizeof(CONTEXT)); \
+    EXCEPTION_POINTERS *pExp = NULL; \
+    __try { \
+      throw 0; \
+    } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
+    if (pExp != NULL) \
+      memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
+      c.ContextFlags = contextFlags; \
+  } while(0);
+#else
+// The following should be enough for walking the callstack...
+#define GET_CURRENT_CONTEXT(c, contextFlags) \
+  do { \
+    memset(&c, 0, sizeof(CONTEXT)); \
+    c.ContextFlags = contextFlags; \
+    __asm    call x \
+    __asm x: pop eax \
+    __asm    mov c.Eip, eax \
+    __asm    mov c.Ebp, ebp \
+    __asm    mov c.Esp, esp \
+  } while(0);
+#endif
+
+#else
+
+// The following is defined for x86 (XP and higher), x64 and IA64:
+#define GET_CURRENT_CONTEXT(c, contextFlags) \
+  do { \
+    memset(&c, 0, sizeof(CONTEXT)); \
+    c.ContextFlags = contextFlags; \
+    RtlCaptureContext(&c); \
+} while(0);
+#endif
index d54a127e6654a883f231c52787d55676e43c406a..e89e26ff037551f205eaa6c35124a01089a85fb9 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "graph.h"\r
-\r
-#pragma warning (disable : 4244)\r
-\r
-#include "../executor.h"\r
-#include "../lock.h"\r
-#include "../env.h"\r
-\r
-#include <SFML/Graphics.hpp>\r
-\r
-#include <boost/foreach.hpp>\r
-#include <boost/optional.hpp>\r
-#include <boost/circular_buffer.hpp>\r
-#include <boost/range/algorithm_ext/erase.hpp>\r
-\r
-#include <tbb/concurrent_unordered_map.h>\r
-#include <tbb/atomic.h>\r
-#include <tbb/spin_mutex.h>\r
-\r
-#include <array>\r
-#include <numeric>\r
-#include <tuple>\r
-\r
-namespace caspar { namespace diagnostics {\r
-               \r
-int color(float r, float g, float b, float a)\r
-{\r
-       int code = 0;\r
-       code |= static_cast<int>(r*255.0f+0.5f) << 24;\r
-       code |= static_cast<int>(g*255.0f+0.5f) << 16;\r
-       code |= static_cast<int>(b*255.0f+0.5f) <<  8;\r
-       code |= static_cast<int>(a*255.0f+0.5f) <<  0;\r
-       return code;\r
-}\r
-\r
-std::tuple<float, float, float, float> color(int code)\r
-{\r
-       float r = static_cast<float>((code >> 24) & 255)/255.0f;\r
-       float g = static_cast<float>((code >> 16) & 255)/255.0f;\r
-       float b = static_cast<float>((code >>  8) & 255)/255.0f;\r
-       float a = static_cast<float>((code >>  0) & 255)/255.0f;\r
-       return std::make_tuple(r, g, b, a);\r
-}\r
-\r
-struct drawable : public sf::Drawable\r
-{\r
-       virtual ~drawable(){}\r
-       virtual void render(sf::RenderTarget& target) = 0;\r
-       virtual void Render(sf::RenderTarget& target) const { const_cast<drawable*>(this)->render(target);}\r
-};\r
-\r
-class context : public drawable\r
-{      \r
-       std::unique_ptr<sf::RenderWindow> window_;\r
-       \r
-       std::list<std::weak_ptr<drawable>> drawables_;\r
-               \r
-       executor executor_;\r
-public:                                        \r
-\r
-       static void register_drawable(const std::shared_ptr<drawable>& drawable)\r
-       {\r
-               if(!drawable)\r
-                       return;\r
-\r
-               get_instance().executor_.begin_invoke([=]\r
-               {\r
-                       get_instance().do_register_drawable(drawable);\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       static void show(bool value)\r
-       {\r
-               get_instance().executor_.begin_invoke([=]\r
-               {       \r
-                       get_instance().do_show(value);\r
-               }, task_priority::high_priority);\r
-       }\r
-                               \r
-private:\r
-       context() : executor_(L"diagnostics")\r
-       {\r
-               executor_.begin_invoke([=]\r
-               {                       \r
-                       SetThreadPriority(GetCurrentThread(), BELOW_NORMAL_PRIORITY_CLASS);\r
-               });\r
-       }\r
-\r
-       void do_show(bool value)\r
-       {\r
-               if(value)\r
-               {\r
-                       if(!window_)\r
-                       {\r
-                               window_.reset(new sf::RenderWindow(sf::VideoMode(750, 750), "CasparCG Diagnostics"));\r
-                               window_->SetPosition(0, 0);\r
-                               window_->SetActive();\r
-                               glEnable(GL_BLEND);\r
-                               glEnable(GL_LINE_SMOOTH);\r
-                               glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);\r
-                               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
-                               tick();\r
-                       }\r
-               }\r
-               else\r
-                       window_.reset();\r
-       }\r
-\r
-       void tick()\r
-       {\r
-               if(!window_)\r
-                       return;\r
-\r
-               sf::Event e;\r
-               while(window_->GetEvent(e))\r
-               {\r
-                       if(e.Type == sf::Event::Closed)\r
-                       {\r
-                               window_.reset();\r
-                               return;\r
-                       }\r
-               }               \r
-               glClear(GL_COLOR_BUFFER_BIT);\r
-               window_->Draw(*this);\r
-               window_->Display();\r
-               boost::this_thread::sleep(boost::posix_time::milliseconds(10));\r
-               executor_.begin_invoke([this]{tick();});\r
-       }\r
-\r
-       void render(sf::RenderTarget& target)\r
-       {\r
-               auto count = std::max<size_t>(8, drawables_.size());\r
-               float target_dy = 1.0f/static_cast<float>(count);\r
-\r
-               float last_y = 0.0f;\r
-               int n = 0;\r
-               for(auto it = drawables_.begin(); it != drawables_.end(); ++n)\r
-               {\r
-                       auto drawable = it->lock();\r
-                       if(drawable)\r
-                       {\r
-                               drawable->SetScale(static_cast<float>(window_->GetWidth()), static_cast<float>(target_dy*window_->GetHeight()));\r
-                               float target_y = std::max(last_y, static_cast<float>(n * window_->GetHeight())*target_dy);\r
-                               drawable->SetPosition(0.0f, target_y);                  \r
-                               target.Draw(*drawable);                         \r
-                               ++it;           \r
-                       }\r
-                       else    \r
-                               it = drawables_.erase(it);                      \r
-               }               \r
-       }       \r
-       \r
-       void do_register_drawable(const std::shared_ptr<drawable>& drawable)\r
-       {\r
-               drawables_.push_back(drawable);\r
-               auto it = drawables_.begin();\r
-               while(it != drawables_.end())\r
-               {\r
-                       if(it->lock())\r
-                               ++it;\r
-                       else    \r
-                               it = drawables_.erase(it);                      \r
-               }\r
-       }\r
-       \r
-       static context& get_instance()\r
-       {\r
-               static context impl;\r
-               return impl;\r
-       }\r
-};\r
-\r
-class line : public drawable\r
-{\r
-       boost::circular_buffer<std::pair<float, bool>> line_data_;\r
-\r
-       tbb::atomic<float>      tick_data_;\r
-       tbb::atomic<bool>       tick_tag_;\r
-       tbb::atomic<int>        color_;\r
-public:\r
-       line(size_t res = 1200)\r
-               : line_data_(res)\r
-       {\r
-               tick_data_      = -1.0f;\r
-               color_          = 0xFFFFFFFF;\r
-               tick_tag_       = false;\r
-\r
-               line_data_.push_back(std::make_pair(-1.0f, false));\r
-       }\r
-       \r
-       void set_value(float value)\r
-       {\r
-               tick_data_ = value;\r
-       }\r
-       \r
-       void set_tag()\r
-       {\r
-               tick_tag_ = true;\r
-       }\r
-               \r
-       void set_color(int color)\r
-       {\r
-               color_ = color;\r
-       }\r
-\r
-       int get_color()\r
-       {\r
-               return color_;\r
-       }\r
-               \r
-       void render(sf::RenderTarget&)\r
-       {\r
-               float dx = 1.0f/static_cast<float>(line_data_.capacity());\r
-               float x = static_cast<float>(line_data_.capacity()-line_data_.size())*dx;\r
-\r
-               line_data_.push_back(std::make_pair(tick_data_, tick_tag_));            \r
-               tick_tag_   = false;\r
-                               \r
-               glBegin(GL_LINE_STRIP);\r
-               auto c = color(color_);\r
-               glColor4f(std::get<0>(c), std::get<1>(c), std::get<2>(c), 0.8f);                \r
-               for(size_t n = 0; n < line_data_.size(); ++n)           \r
-                       if(line_data_[n].first > -0.5)\r
-                               glVertex3d(x+n*dx, std::max(0.05, std::min(0.95, (1.0f-line_data_[n].first)*0.8 + 0.1f)), 0.0);         \r
-               glEnd();\r
-                               \r
-               glEnable(GL_LINE_STIPPLE);\r
-               glLineStipple(3, 0xAAAA);\r
-               for(size_t n = 0; n < line_data_.size(); ++n)   \r
-               {\r
-                       if(line_data_[n].second)\r
-                       {\r
-                               glBegin(GL_LINE_STRIP);                 \r
-                                       glVertex3f(x+n*dx, 0.0f, 0.0f);                         \r
-                                       glVertex3f(x+n*dx, 1.0f, 0.0f);         \r
-                               glEnd();\r
-                       }\r
-               }\r
-               glDisable(GL_LINE_STIPPLE);\r
-       }\r
-};\r
-\r
-struct graph::impl : public drawable\r
-{\r
-       tbb::concurrent_unordered_map<std::string, diagnostics::line> lines_;\r
-\r
-       tbb::spin_mutex mutex_;\r
-       std::wstring text_;\r
-\r
-       impl()\r
-       {\r
-       }\r
-               \r
-       void set_text(const std::wstring& value)\r
-       {\r
-               auto temp = value;\r
-               lock(mutex_, [&]\r
-               {\r
-                       text_ = std::move(temp);\r
-               });\r
-       }\r
-\r
-       void set_value(const std::string& name, double value)\r
-       {\r
-               lines_[name].set_value(value);\r
-       }\r
-\r
-       void set_tag(const std::string& name)\r
-       {\r
-               lines_[name].set_tag();\r
-       }\r
-\r
-       void set_color(const std::string& name, int color)\r
-       {\r
-               lines_[name].set_color(color);\r
-       }\r
-               \r
-private:\r
-       void render(sf::RenderTarget& target)\r
-       {\r
-               const size_t text_size = 15;\r
-               const size_t text_margin = 2;\r
-               const size_t text_offset = (text_size+text_margin*2)*2;\r
-\r
-               std::wstring text_str;\r
-               {\r
-                       tbb::spin_mutex::scoped_lock lock(mutex_);\r
-                       text_str = text_;\r
-               }\r
-\r
-               sf::String text(text_str.c_str(), sf::Font::GetDefaultFont(), text_size);\r
-               text.SetStyle(sf::String::Italic);\r
-               text.Move(text_margin, text_margin);\r
-               \r
-               glPushMatrix();\r
-                       glScaled(1.0f/GetScale().x, 1.0f/GetScale().y, 1.0f);\r
-                       target.Draw(text);\r
-                       float x_offset = text_margin;\r
-                       for(auto it = lines_.begin(); it != lines_.end(); ++it)\r
-                       {                                               \r
-                               sf::String line_text(it->first, sf::Font::GetDefaultFont(), text_size);\r
-                               line_text.SetPosition(x_offset, text_margin+text_offset/2);\r
-                               auto c = it->second.get_color();\r
-                               line_text.SetColor(sf::Color((c >> 24) & 255, (c >> 16) & 255, (c >> 8) & 255, (c >> 0) & 255));\r
-                               target.Draw(line_text);\r
-                               x_offset = line_text.GetRect().Right + text_margin*2;\r
-                       }\r
-\r
-                       glDisable(GL_TEXTURE_2D);\r
-               glPopMatrix();\r
-\r
-               glBegin(GL_QUADS);\r
-                       glColor4f(1.0f, 1.0f, 1.0f, 0.2f);      \r
-                       glVertex2f(1.0f, 0.99f);\r
-                       glVertex2f(0.0f, 0.99f);\r
-                       glVertex2f(0.0f, 0.01f);        \r
-                       glVertex2f(1.0f, 0.01f);        \r
-               glEnd();\r
-\r
-               glPushMatrix();\r
-                       glTranslated(0.0f, text_offset/GetScale().y, 1.0f);\r
-                       glScaled(1.0f, 1.0-text_offset/GetScale().y, 1.0f);\r
-               \r
-                       glEnable(GL_LINE_STIPPLE);\r
-                       glLineStipple(3, 0xAAAA);\r
-                       glColor4f(1.0f, 1.0f, 1.9f, 0.5f);      \r
-                       glBegin(GL_LINE_STRIP);         \r
-                               glVertex3f(0.0f, (1.0f-0.5f) * 0.8f + 0.1f, 0.0f);              \r
-                               glVertex3f(1.0f, (1.0f-0.5f) * 0.8f + 0.1f, 0.0f);      \r
-                       glEnd();\r
-                       glBegin(GL_LINE_STRIP);         \r
-                               glVertex3f(0.0f, (1.0f-0.0f) * 0.8f + 0.1f, 0.0f);              \r
-                               glVertex3f(1.0f, (1.0f-0.0f) * 0.8f + 0.1f, 0.0f);      \r
-                       glEnd();\r
-                       glBegin(GL_LINE_STRIP);         \r
-                               glVertex3f(0.0f, (1.0f-1.0f) * 0.8f + 0.1f, 0.0f);              \r
-                               glVertex3f(1.0f, (1.0f-1.0f) * 0.8f + 0.1f, 0.0f);      \r
-                       glEnd();\r
-                       glDisable(GL_LINE_STIPPLE);\r
-\r
-                       //target.Draw(diagnostics::guide(1.0f, color(1.0f, 1.0f, 1.0f, 0.6f)));\r
-                       //target.Draw(diagnostics::guide(0.0f, color(1.0f, 1.0f, 1.0f, 0.6f)));\r
-\r
-                       for(auto it = lines_.begin(); it != lines_.end(); ++it)         \r
-                               target.Draw(it->second);\r
-               \r
-               glPopMatrix();\r
-       }\r
-\r
-       impl(impl&);\r
-       impl& operator=(impl&);\r
-};\r
-       \r
-graph::graph() : impl_(new impl())\r
-{\r
-}\r
-\r
-void graph::set_text(const std::wstring& value){impl_->set_text(value);}\r
-void graph::set_value(const std::string& name, double value){impl_->set_value(name, value);}\r
-void graph::set_color(const std::string& name, int color){impl_->set_color(name, color);}\r
-void graph::set_tag(const std::string& name){impl_->set_tag(name);}\r
-\r
-void register_graph(const spl::shared_ptr<graph>& graph)\r
-{\r
-       context::register_drawable(graph->impl_);\r
-}\r
-\r
-void show_graphs(bool value)\r
-{\r
-       context::show(value);\r
-}\r
-\r
-//namespace v2\r
-//{    \r
-//     \r
-//struct line::impl\r
-//{\r
-//     std::wstring name_;\r
-//     boost::circular_buffer<data> ticks_;\r
-//\r
-//     impl(const std::wstring& name) \r
-//             : name_(name)\r
-//             , ticks_(1024){}\r
-//     \r
-//     void set_value(float value)\r
-//     {\r
-//             ticks_.push_back();\r
-//             ticks_.back().value = value;\r
-//     }\r
-//\r
-//     void set_value(float value)\r
-//     {\r
-//             ticks_.clear();\r
-//             set_value(value);\r
-//     }\r
-//};\r
-//\r
-//line::line(){}\r
-//line::line(const std::wstring& name) : impl_(new impl(name)){}\r
-//std::wstring line::print() const {return impl_->name_;}\r
-//void line::set_value(float value){impl_->set_value(value);}\r
-//void line::set_value(float value){impl_->set_value(value);}\r
-//boost::circular_buffer<data>& line::ticks() { return impl_->ticks_;}\r
-//\r
-//struct graph::impl\r
-//{\r
-//     std::map<std::wstring, line> lines_;\r
-//     color                                            color_;\r
-//     printer                                          printer_;\r
-//\r
-//     impl(const std::wstring& name) \r
-//             : printer_([=]{return name;}){}\r
-//\r
-//     impl(const printer& parent_printer) \r
-//             : printer_(parent_printer){}\r
-//     \r
-//     void set_value(const std::wstring& name, float value)\r
-//     {\r
-//             auto it = lines_.find(name);\r
-//             if(it == lines_.end())\r
-//                     it = lines_.insert(std::make_pair(name, line(name))).first;\r
-//\r
-//             it->second.set_value(value);\r
-//     }\r
-//\r
-//     void set_value(const std::wstring& name, float value)\r
-//     {\r
-//             auto it = lines_.find(name);\r
-//             if(it == lines_.end())\r
-//                     it = lines_.insert(std::make_pair(name, line(name))).first;\r
-//\r
-//             it->second.set_value(value);\r
-//     }\r
-//     \r
-//     void set_color(const std::wstring& name, color color)\r
-//     {\r
-//             color_ = color;\r
-//     }\r
-//\r
-//     std::map<std::wstring, line>& get_lines()\r
-//     {\r
-//             return lines_;\r
-//     }\r
-//     \r
-//     color get_color() const\r
-//     {\r
-//             return color_;\r
-//     }\r
-//\r
-//     std::wstring print() const\r
-//     {\r
-//             return printer_ ? printer_() : L"graph";\r
-//     }\r
-//};\r
-//     \r
-//graph::graph(const std::wstring& name) : impl_(new impl(name)){}\r
-//graph::graph(const printer& parent_printer) : impl_(new impl(parent_printer)){}\r
-//void graph::set_value(const std::wstring& name, float value){impl_->set_value(name, value);}\r
-//void graph::set_value(const std::wstring& name, float value){impl_->set_value(name, value);}\r
-//void graph::set_color(const std::wstring& name, color c){impl_->set_color(name, c);}\r
-//color graph::get_color() const {return impl_->get_color();}\r
-//std::wstring graph::print() const {return impl_->print();}\r
-//\r
-//spl::shared_ptr<graph> graph::clone() const \r
-//{\r
-//     spl::shared_ptr<graph> clone(new graph(std::wstring(L"")));\r
-//     clone->impl_->printer_ = impl_->printer_;\r
-//     clone->impl_->lines_ = impl_->lines_;\r
-//     clone->impl_->color_ = impl_->color_;   \r
-//}\r
-//\r
-//std::map<std::wstring, line>& graph::get_lines() {impl_->get_lines();}\r
-//\r
-//std::vector<spl::shared_ptr<graph>> g_graphs;\r
-//\r
-//spl::shared_ptr<graph> create_graph(const std::string& name)\r
-//{\r
-//     g_graphs.push_back(spl::make_shared<graph>(name));\r
-//     return g_graphs.back();\r
-//}\r
-//\r
-//spl::shared_ptr<graph> create_graph(const printer& parent_printer)\r
-//{\r
-//     g_graphs.push_back(spl::make_shared<graph>(parent_printer));\r
-//     return g_graphs.back();\r
-//}\r
-//\r
-//static std::vector<spl::shared_ptr<graph>> get_all_graphs()\r
-//{\r
-//     std::vector<spl::shared_ptr<graph>> graphs;\r
-//     BOOST_FOREACH(auto& graph, g_graphs)\r
-//             graphs.push_back(graph->clone());\r
-//\r
-//     return graphs;\r
-//}\r
-//\r
-//}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "graph.h"
+
+#pragma warning (disable : 4244)
+
+#include "../executor.h"
+#include "../lock.h"
+#include "../env.h"
+
+#include <SFML/Graphics.hpp>
+
+#include <boost/foreach.hpp>
+#include <boost/optional.hpp>
+#include <boost/circular_buffer.hpp>
+#include <boost/range/algorithm_ext/erase.hpp>
+
+#include <tbb/concurrent_unordered_map.h>
+#include <tbb/atomic.h>
+#include <tbb/spin_mutex.h>
+
+#include <array>
+#include <numeric>
+#include <tuple>
+
+namespace caspar { namespace diagnostics {
+               
+int color(float r, float g, float b, float a)
+{
+       int code = 0;
+       code |= static_cast<int>(r*255.0f+0.5f) << 24;
+       code |= static_cast<int>(g*255.0f+0.5f) << 16;
+       code |= static_cast<int>(b*255.0f+0.5f) <<  8;
+       code |= static_cast<int>(a*255.0f+0.5f) <<  0;
+       return code;
+}
+
+std::tuple<float, float, float, float> color(int code)
+{
+       float r = static_cast<float>((code >> 24) & 255)/255.0f;
+       float g = static_cast<float>((code >> 16) & 255)/255.0f;
+       float b = static_cast<float>((code >>  8) & 255)/255.0f;
+       float a = static_cast<float>((code >>  0) & 255)/255.0f;
+       return std::make_tuple(r, g, b, a);
+}
+
+struct drawable : public sf::Drawable
+{
+       virtual ~drawable(){}
+       virtual void render(sf::RenderTarget& target) = 0;
+       virtual void Render(sf::RenderTarget& target) const { const_cast<drawable*>(this)->render(target);}
+};
+
+class context : public drawable
+{      
+       std::unique_ptr<sf::RenderWindow> window_;
+       
+       std::list<std::weak_ptr<drawable>> drawables_;
+               
+       executor executor_;
+public:                                        
+
+       static void register_drawable(const std::shared_ptr<drawable>& drawable)
+       {
+               if(!drawable)
+                       return;
+
+               get_instance().executor_.begin_invoke([=]
+               {
+                       get_instance().do_register_drawable(drawable);
+               }, task_priority::high_priority);
+       }
+
+       static void show(bool value)
+       {
+               get_instance().executor_.begin_invoke([=]
+               {       
+                       get_instance().do_show(value);
+               }, task_priority::high_priority);
+       }
+                               
+private:
+       context() : executor_(L"diagnostics")
+       {
+               executor_.begin_invoke([=]
+               {                       
+                       SetThreadPriority(GetCurrentThread(), BELOW_NORMAL_PRIORITY_CLASS);
+               });
+       }
+
+       void do_show(bool value)
+       {
+               if(value)
+               {
+                       if(!window_)
+                       {
+                               window_.reset(new sf::RenderWindow(sf::VideoMode(750, 750), "CasparCG Diagnostics"));
+                               window_->SetPosition(0, 0);
+                               window_->SetActive();
+                               glEnable(GL_BLEND);
+                               glEnable(GL_LINE_SMOOTH);
+                               glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+                               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+                               tick();
+                       }
+               }
+               else
+                       window_.reset();
+       }
+
+       void tick()
+       {
+               if(!window_)
+                       return;
+
+               sf::Event e;
+               while(window_->GetEvent(e))
+               {
+                       if(e.Type == sf::Event::Closed)
+                       {
+                               window_.reset();
+                               return;
+                       }
+               }               
+               glClear(GL_COLOR_BUFFER_BIT);
+               window_->Draw(*this);
+               window_->Display();
+               boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+               executor_.begin_invoke([this]{tick();});
+       }
+
+       void render(sf::RenderTarget& target)
+       {
+               auto count = std::max<size_t>(8, drawables_.size());
+               float target_dy = 1.0f/static_cast<float>(count);
+
+               float last_y = 0.0f;
+               int n = 0;
+               for(auto it = drawables_.begin(); it != drawables_.end(); ++n)
+               {
+                       auto drawable = it->lock();
+                       if(drawable)
+                       {
+                               drawable->SetScale(static_cast<float>(window_->GetWidth()), static_cast<float>(target_dy*window_->GetHeight()));
+                               float target_y = std::max(last_y, static_cast<float>(n * window_->GetHeight())*target_dy);
+                               drawable->SetPosition(0.0f, target_y);                  
+                               target.Draw(*drawable);                         
+                               ++it;           
+                       }
+                       else    
+                               it = drawables_.erase(it);                      
+               }               
+       }       
+       
+       void do_register_drawable(const std::shared_ptr<drawable>& drawable)
+       {
+               drawables_.push_back(drawable);
+               auto it = drawables_.begin();
+               while(it != drawables_.end())
+               {
+                       if(it->lock())
+                               ++it;
+                       else    
+                               it = drawables_.erase(it);                      
+               }
+       }
+       
+       static context& get_instance()
+       {
+               static context impl;
+               return impl;
+       }
+};
+
+class line : public drawable
+{
+       boost::circular_buffer<std::pair<float, bool>> line_data_;
+
+       tbb::atomic<float>      tick_data_;
+       tbb::atomic<bool>       tick_tag_;
+       tbb::atomic<int>        color_;
+public:
+       line(size_t res = 1200)
+               : line_data_(res)
+       {
+               tick_data_      = -1.0f;
+               color_          = 0xFFFFFFFF;
+               tick_tag_       = false;
+
+               line_data_.push_back(std::make_pair(-1.0f, false));
+       }
+       
+       void set_value(float value)
+       {
+               tick_data_ = value;
+       }
+       
+       void set_tag()
+       {
+               tick_tag_ = true;
+       }
+               
+       void set_color(int color)
+       {
+               color_ = color;
+       }
+
+       int get_color()
+       {
+               return color_;
+       }
+               
+       void render(sf::RenderTarget&)
+       {
+               float dx = 1.0f/static_cast<float>(line_data_.capacity());
+               float x = static_cast<float>(line_data_.capacity()-line_data_.size())*dx;
+
+               line_data_.push_back(std::make_pair(tick_data_, tick_tag_));            
+               tick_tag_   = false;
+                               
+               glBegin(GL_LINE_STRIP);
+               auto c = color(color_);
+               glColor4f(std::get<0>(c), std::get<1>(c), std::get<2>(c), 0.8f);                
+               for(size_t n = 0; n < line_data_.size(); ++n)           
+                       if(line_data_[n].first > -0.5)
+                               glVertex3d(x+n*dx, std::max(0.05, std::min(0.95, (1.0f-line_data_[n].first)*0.8 + 0.1f)), 0.0);         
+               glEnd();
+                               
+               glEnable(GL_LINE_STIPPLE);
+               glLineStipple(3, 0xAAAA);
+               for(size_t n = 0; n < line_data_.size(); ++n)   
+               {
+                       if(line_data_[n].second)
+                       {
+                               glBegin(GL_LINE_STRIP);                 
+                                       glVertex3f(x+n*dx, 0.0f, 0.0f);                         
+                                       glVertex3f(x+n*dx, 1.0f, 0.0f);         
+                               glEnd();
+                       }
+               }
+               glDisable(GL_LINE_STIPPLE);
+       }
+};
+
+struct graph::impl : public drawable
+{
+       tbb::concurrent_unordered_map<std::string, diagnostics::line> lines_;
+
+       tbb::spin_mutex mutex_;
+       std::wstring text_;
+
+       impl()
+       {
+       }
+               
+       void set_text(const std::wstring& value)
+       {
+               auto temp = value;
+               lock(mutex_, [&]
+               {
+                       text_ = std::move(temp);
+               });
+       }
+
+       void set_value(const std::string& name, double value)
+       {
+               lines_[name].set_value(value);
+       }
+
+       void set_tag(const std::string& name)
+       {
+               lines_[name].set_tag();
+       }
+
+       void set_color(const std::string& name, int color)
+       {
+               lines_[name].set_color(color);
+       }
+               
+private:
+       void render(sf::RenderTarget& target)
+       {
+               const size_t text_size = 15;
+               const size_t text_margin = 2;
+               const size_t text_offset = (text_size+text_margin*2)*2;
+
+               std::wstring text_str;
+               {
+                       tbb::spin_mutex::scoped_lock lock(mutex_);
+                       text_str = text_;
+               }
+
+               sf::String text(text_str.c_str(), sf::Font::GetDefaultFont(), text_size);
+               text.SetStyle(sf::String::Italic);
+               text.Move(text_margin, text_margin);
+               
+               glPushMatrix();
+                       glScaled(1.0f/GetScale().x, 1.0f/GetScale().y, 1.0f);
+                       target.Draw(text);
+                       float x_offset = text_margin;
+                       for(auto it = lines_.begin(); it != lines_.end(); ++it)
+                       {                                               
+                               sf::String line_text(it->first, sf::Font::GetDefaultFont(), text_size);
+                               line_text.SetPosition(x_offset, text_margin+text_offset/2);
+                               auto c = it->second.get_color();
+                               line_text.SetColor(sf::Color((c >> 24) & 255, (c >> 16) & 255, (c >> 8) & 255, (c >> 0) & 255));
+                               target.Draw(line_text);
+                               x_offset = line_text.GetRect().Right + text_margin*2;
+                       }
+
+                       glDisable(GL_TEXTURE_2D);
+               glPopMatrix();
+
+               glBegin(GL_QUADS);
+                       glColor4f(1.0f, 1.0f, 1.0f, 0.2f);      
+                       glVertex2f(1.0f, 0.99f);
+                       glVertex2f(0.0f, 0.99f);
+                       glVertex2f(0.0f, 0.01f);        
+                       glVertex2f(1.0f, 0.01f);        
+               glEnd();
+
+               glPushMatrix();
+                       glTranslated(0.0f, text_offset/GetScale().y, 1.0f);
+                       glScaled(1.0f, 1.0-text_offset/GetScale().y, 1.0f);
+               
+                       glEnable(GL_LINE_STIPPLE);
+                       glLineStipple(3, 0xAAAA);
+                       glColor4f(1.0f, 1.0f, 1.9f, 0.5f);      
+                       glBegin(GL_LINE_STRIP);         
+                               glVertex3f(0.0f, (1.0f-0.5f) * 0.8f + 0.1f, 0.0f);              
+                               glVertex3f(1.0f, (1.0f-0.5f) * 0.8f + 0.1f, 0.0f);      
+                       glEnd();
+                       glBegin(GL_LINE_STRIP);         
+                               glVertex3f(0.0f, (1.0f-0.0f) * 0.8f + 0.1f, 0.0f);              
+                               glVertex3f(1.0f, (1.0f-0.0f) * 0.8f + 0.1f, 0.0f);      
+                       glEnd();
+                       glBegin(GL_LINE_STRIP);         
+                               glVertex3f(0.0f, (1.0f-1.0f) * 0.8f + 0.1f, 0.0f);              
+                               glVertex3f(1.0f, (1.0f-1.0f) * 0.8f + 0.1f, 0.0f);      
+                       glEnd();
+                       glDisable(GL_LINE_STIPPLE);
+
+                       //target.Draw(diagnostics::guide(1.0f, color(1.0f, 1.0f, 1.0f, 0.6f)));
+                       //target.Draw(diagnostics::guide(0.0f, color(1.0f, 1.0f, 1.0f, 0.6f)));
+
+                       for(auto it = lines_.begin(); it != lines_.end(); ++it)         
+                               target.Draw(it->second);
+               
+               glPopMatrix();
+       }
+
+       impl(impl&);
+       impl& operator=(impl&);
+};
+       
+graph::graph() : impl_(new impl())
+{
+}
+
+void graph::set_text(const std::wstring& value){impl_->set_text(value);}
+void graph::set_value(const std::string& name, double value){impl_->set_value(name, value);}
+void graph::set_color(const std::string& name, int color){impl_->set_color(name, color);}
+void graph::set_tag(const std::string& name){impl_->set_tag(name);}
+
+void register_graph(const spl::shared_ptr<graph>& graph)
+{
+       context::register_drawable(graph->impl_);
+}
+
+void show_graphs(bool value)
+{
+       context::show(value);
+}
+
+//namespace v2
+//{    
+//     
+//struct line::impl
+//{
+//     std::wstring name_;
+//     boost::circular_buffer<data> ticks_;
+//
+//     impl(const std::wstring& name) 
+//             : name_(name)
+//             , ticks_(1024){}
+//     
+//     void set_value(float value)
+//     {
+//             ticks_.push_back();
+//             ticks_.back().value = value;
+//     }
+//
+//     void set_value(float value)
+//     {
+//             ticks_.clear();
+//             set_value(value);
+//     }
+//};
+//
+//line::line(){}
+//line::line(const std::wstring& name) : impl_(new impl(name)){}
+//std::wstring line::print() const {return impl_->name_;}
+//void line::set_value(float value){impl_->set_value(value);}
+//void line::set_value(float value){impl_->set_value(value);}
+//boost::circular_buffer<data>& line::ticks() { return impl_->ticks_;}
+//
+//struct graph::impl
+//{
+//     std::map<std::wstring, line> lines_;
+//     color                                            color_;
+//     printer                                          printer_;
+//
+//     impl(const std::wstring& name) 
+//             : printer_([=]{return name;}){}
+//
+//     impl(const printer& parent_printer) 
+//             : printer_(parent_printer){}
+//     
+//     void set_value(const std::wstring& name, float value)
+//     {
+//             auto it = lines_.find(name);
+//             if(it == lines_.end())
+//                     it = lines_.insert(std::make_pair(name, line(name))).first;
+//
+//             it->second.set_value(value);
+//     }
+//
+//     void set_value(const std::wstring& name, float value)
+//     {
+//             auto it = lines_.find(name);
+//             if(it == lines_.end())
+//                     it = lines_.insert(std::make_pair(name, line(name))).first;
+//
+//             it->second.set_value(value);
+//     }
+//     
+//     void set_color(const std::wstring& name, color color)
+//     {
+//             color_ = color;
+//     }
+//
+//     std::map<std::wstring, line>& get_lines()
+//     {
+//             return lines_;
+//     }
+//     
+//     color get_color() const
+//     {
+//             return color_;
+//     }
+//
+//     std::wstring print() const
+//     {
+//             return printer_ ? printer_() : L"graph";
+//     }
+//};
+//     
+//graph::graph(const std::wstring& name) : impl_(new impl(name)){}
+//graph::graph(const printer& parent_printer) : impl_(new impl(parent_printer)){}
+//void graph::set_value(const std::wstring& name, float value){impl_->set_value(name, value);}
+//void graph::set_value(const std::wstring& name, float value){impl_->set_value(name, value);}
+//void graph::set_color(const std::wstring& name, color c){impl_->set_color(name, c);}
+//color graph::get_color() const {return impl_->get_color();}
+//std::wstring graph::print() const {return impl_->print();}
+//
+//spl::shared_ptr<graph> graph::clone() const 
+//{
+//     spl::shared_ptr<graph> clone(new graph(std::wstring(L"")));
+//     clone->impl_->printer_ = impl_->printer_;
+//     clone->impl_->lines_ = impl_->lines_;
+//     clone->impl_->color_ = impl_->color_;   
+//}
+//
+//std::map<std::wstring, line>& graph::get_lines() {impl_->get_lines();}
+//
+//std::vector<spl::shared_ptr<graph>> g_graphs;
+//
+//spl::shared_ptr<graph> create_graph(const std::string& name)
+//{
+//     g_graphs.push_back(spl::make_shared<graph>(name));
+//     return g_graphs.back();
+//}
+//
+//spl::shared_ptr<graph> create_graph(const printer& parent_printer)
+//{
+//     g_graphs.push_back(spl::make_shared<graph>(parent_printer));
+//     return g_graphs.back();
+//}
+//
+//static std::vector<spl::shared_ptr<graph>> get_all_graphs()
+//{
+//     std::vector<spl::shared_ptr<graph>> graphs;
+//     BOOST_FOREACH(auto& graph, g_graphs)
+//             graphs.push_back(graph->clone());
+//
+//     return graphs;
+//}
+//
+//}
+
 }}
\ No newline at end of file
index f82491222bba63421697f20fe7d9c32810907854..e52a2c9d769091c81a1b9cfe955b4227c568afac 100644 (file)
@@ -1,53 +1,53 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "../memory.h"\r
-\r
-#include <string>\r
-#include <tuple>\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-namespace caspar { namespace diagnostics {\r
-       \r
-int color(float r, float g, float b, float a = 1.0f);\r
-std::tuple<float, float, float, float> color(int code);\r
-\r
-class graph : boost::noncopyable\r
-{\r
-       friend void register_graph(const spl::shared_ptr<graph>& graph);\r
-public:\r
-       graph();\r
-       void set_text(const std::wstring& value);\r
-       void set_value(const std::string& name, double value);\r
-       void set_color(const std::string& name, int color);\r
-       void set_tag(const std::string& name);\r
-private:\r
-       struct impl;\r
-       std::shared_ptr<impl> impl_;\r
-};\r
-\r
-void register_graph(const spl::shared_ptr<graph>& graph);\r
-void show_graphs(bool value);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "../memory.h"
+
+#include <string>
+#include <tuple>
+
+#include <boost/noncopyable.hpp>
+
+namespace caspar { namespace diagnostics {
+       
+int color(float r, float g, float b, float a = 1.0f);
+std::tuple<float, float, float, float> color(int code);
+
+class graph : boost::noncopyable
+{
+       friend void register_graph(const spl::shared_ptr<graph>& graph);
+public:
+       graph();
+       void set_text(const std::wstring& value);
+       void set_value(const std::string& name, double value);
+       void set_color(const std::string& name, int color);
+       void set_tag(const std::string& name);
+private:
+       struct impl;
+       std::shared_ptr<impl> impl_;
+};
+
+void register_graph(const spl::shared_ptr<graph>& graph);
+void show_graphs(bool value);
+
 }}
\ No newline at end of file
index 564525d8eefe3adbec731cdd250baec5f9399085..725075947398cc4cfc0c2bb7831be23602e845d4 100644 (file)
@@ -1,57 +1,57 @@
-#pragma once\r
-\r
-namespace caspar {\r
-\r
-template<typename def, typename inner = typename def::type>\r
-class enum_class : public def\r
-{\r
-       typedef typename def::type type;\r
-       inner val_; \r
-public: \r
-       explicit enum_class(int v) : val_(static_cast<type>(v)) {}\r
-       enum_class(type v) : val_(v) {}\r
-       inner value() const { return val_; }\r
\r
-       bool operator==(const enum_class& s) const      { return val_ == s.val_; }\r
-       bool operator!=(const enum_class& s) const      { return val_ != s.val_; }\r
-       bool operator<(const enum_class& s) const       { return val_ <  s.val_; }\r
-       bool operator<=(const enum_class& s) const      { return val_ <= s.val_; }\r
-       bool operator>(const enum_class& s) const       { return val_ >  s.val_; }\r
-       bool operator>=(const enum_class& s) const      { return val_ >= s.val_; }\r
-               \r
-       bool operator==(const int& val) const   { return val_ == val; }\r
-       bool operator!=(const int& val) const   { return val_ != val; }\r
-       bool operator<(const int& val) const    { return val_ <  val; }\r
-       bool operator<=(const int& val) const   { return val_ <= val; }\r
-       bool operator>(const int& val) const    { return val_ >  val; }\r
-       bool operator>=(const int& val) const   { return val_ >= val; }\r
-\r
-       enum_class operator&(const enum_class& s) const\r
-       {\r
-               return enum_class(static_cast<type>(val_ & s.val_));\r
-       }\r
-\r
-       enum_class& operator&=(const enum_class& s)\r
-       {\r
-               val_ = static_cast<type>(val_ & s.val_);\r
-               return *this;\r
-       }\r
-\r
-       enum_class operator|(const enum_class& s) const\r
-       {\r
-               return enum_class(static_cast<type>(val_ | s.val_));\r
-       }\r
-       \r
-       enum_class& operator|=(const enum_class& s)\r
-       {\r
-               val_ = static_cast<type>(val_ | s.val_);\r
-               return *this;\r
-       }\r
-\r
-       //operator inner()\r
-       //{\r
-       //      return val_;\r
-       //}\r
-};\r
-\r
+#pragma once
+
+namespace caspar {
+
+template<typename def, typename inner = typename def::type>
+class enum_class : public def
+{
+       typedef typename def::type type;
+       inner val_; 
+public: 
+       explicit enum_class(int v) : val_(static_cast<type>(v)) {}
+       enum_class(type v) : val_(v) {}
+       inner value() const { return val_; }
+       bool operator==(const enum_class& s) const      { return val_ == s.val_; }
+       bool operator!=(const enum_class& s) const      { return val_ != s.val_; }
+       bool operator<(const enum_class& s) const       { return val_ <  s.val_; }
+       bool operator<=(const enum_class& s) const      { return val_ <= s.val_; }
+       bool operator>(const enum_class& s) const       { return val_ >  s.val_; }
+       bool operator>=(const enum_class& s) const      { return val_ >= s.val_; }
+               
+       bool operator==(const int& val) const   { return val_ == val; }
+       bool operator!=(const int& val) const   { return val_ != val; }
+       bool operator<(const int& val) const    { return val_ <  val; }
+       bool operator<=(const int& val) const   { return val_ <= val; }
+       bool operator>(const int& val) const    { return val_ >  val; }
+       bool operator>=(const int& val) const   { return val_ >= val; }
+
+       enum_class operator&(const enum_class& s) const
+       {
+               return enum_class(static_cast<type>(val_ & s.val_));
+       }
+
+       enum_class& operator&=(const enum_class& s)
+       {
+               val_ = static_cast<type>(val_ & s.val_);
+               return *this;
+       }
+
+       enum_class operator|(const enum_class& s) const
+       {
+               return enum_class(static_cast<type>(val_ | s.val_));
+       }
+       
+       enum_class& operator|=(const enum_class& s)
+       {
+               val_ = static_cast<type>(val_ | s.val_);
+               return *this;
+       }
+
+       //operator inner()
+       //{
+       //      return val_;
+       //}
+};
+
 }
\ No newline at end of file
index 4e78f5bf8b7964156ac46c64a03d6ddfd839754b..684273d9e71a2c4b07e0a7eea8a2ab3f560bdbac 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "stdafx.h"\r
-\r
-#include "env.h"\r
-\r
-#include "../version.h"\r
-\r
-#include "except.h"\r
-#include "log.h"\r
-#include "string.h"\r
-\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/property_tree/xml_parser.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/thread/once.hpp>\r
-\r
-#include <functional>\r
-#include <iostream>\r
-\r
-namespace caspar { namespace env {\r
-       \r
-std::wstring media;\r
-std::wstring log;\r
-std::wstring ftemplate;\r
-std::wstring data;\r
-boost::property_tree::wptree pt;\r
-\r
-void check_is_configured()\r
-{\r
-       if(pt.empty())\r
-               CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info(L"Enviroment properties has not been configured"));\r
-}\r
-\r
-void configure(const std::wstring& filename)\r
-{\r
-       try\r
-       {\r
-               auto initialPath = boost::filesystem3::initial_path().wstring();\r
-       \r
-               std::wifstream file(initialPath + L"\\" + filename);\r
-               boost::property_tree::read_xml(file, pt, boost::property_tree::xml_parser::trim_whitespace | boost::property_tree::xml_parser::no_comments);\r
-\r
-               auto paths      = pt.get_child(L"configuration.paths");\r
-               media           = paths.get(L"media-path", initialPath + L"\\media\\");\r
-               log                     = paths.get(L"log-path", initialPath + L"\\log\\");\r
-               ftemplate       = boost::filesystem3::complete(paths.get(L"template-path", initialPath + L"\\template\\")).wstring();           \r
-               data            = paths.get(L"data-path", initialPath + L"\\data\\");\r
-\r
-               try\r
-               {\r
-                       for(auto it = boost::filesystem::directory_iterator(initialPath); it != boost::filesystem::directory_iterator(); ++it)\r
-                       {\r
-                               if(it->path().wstring().find(L".fth") != std::wstring::npos)                    \r
-                               {\r
-                                       auto from_path = *it;\r
-                                       auto to_path = boost::filesystem::path(ftemplate + L"/" + it->path().wstring());\r
-                               \r
-                                       if(boost::filesystem::exists(to_path))\r
-                                               boost::filesystem::remove(to_path);\r
-\r
-                                       boost::filesystem::copy_file(from_path, to_path);\r
-                               }       \r
-                       }\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       CASPAR_LOG(error) << L"Failed to copy template-hosts from initial-path to template-path.";\r
-               }\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG(error) << L" ### Invalid configuration file. ###";\r
-               throw;\r
-       }\r
-\r
-       try\r
-       {\r
-               try\r
-               {\r
-                       auto log_path = boost::filesystem::path(log);\r
-                       if(!boost::filesystem::exists(log_path))\r
-                               boost::filesystem::create_directories(log_path);\r
-               }\r
-               catch(...)\r
-               {\r
-                       log = L"./";\r
-               }\r
-\r
-               auto media_path = boost::filesystem::path(media);\r
-               if(!boost::filesystem::exists(media_path))\r
-                       boost::filesystem::create_directories(media_path);\r
-                               \r
-               auto template_path = boost::filesystem::path(ftemplate);\r
-               if(!boost::filesystem::exists(template_path))\r
-                       boost::filesystem::create_directories(template_path);\r
-               \r
-               auto data_path = boost::filesystem::path(data);\r
-               if(!boost::filesystem::exists(data_path))\r
-                       boost::filesystem::create_directories(data_path);\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               CASPAR_LOG(error) << L"Failed to create configured directories.";\r
-       }\r
-}\r
-       \r
-const std::wstring& media_folder()\r
-{\r
-       check_is_configured();\r
-       return media;\r
-}\r
-\r
-const std::wstring& log_folder()\r
-{\r
-       check_is_configured();\r
-       return log;\r
-}\r
-\r
-const std::wstring& template_folder()\r
-{\r
-       check_is_configured();\r
-       return ftemplate;\r
-}\r
-\r
-const std::wstring& data_folder()\r
-{\r
-       check_is_configured();\r
-       return data;\r
-}\r
-\r
-#define QUOTE(str) #str\r
-#define EXPAND_AND_QUOTE(str) QUOTE(str)\r
-\r
-const std::wstring& version()\r
-{\r
-       static std::wstring ver = u16(\r
-                       EXPAND_AND_QUOTE(CASPAR_GEN)    "." \r
-                       EXPAND_AND_QUOTE(CASPAR_MAYOR)  "." \r
-                       EXPAND_AND_QUOTE(CASPAR_MINOR)  "." \r
-                       EXPAND_AND_QUOTE(CASPAR_REV)    " " \r
-                       CASPAR_TAG);\r
-       return ver;\r
-}\r
-\r
-const boost::property_tree::wptree& properties()\r
-{\r
-       check_is_configured();\r
-       return pt;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "stdafx.h"
+
+#include "env.h"
+
+#include "../version.h"
+
+#include "except.h"
+#include "log.h"
+#include "string.h"
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/thread/once.hpp>
+
+#include <functional>
+#include <iostream>
+
+namespace caspar { namespace env {
+       
+std::wstring media;
+std::wstring log;
+std::wstring ftemplate;
+std::wstring data;
+boost::property_tree::wptree pt;
+
+void check_is_configured()
+{
+       if(pt.empty())
+               CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info(L"Enviroment properties has not been configured"));
+}
+
+void configure(const std::wstring& filename)
+{
+       try
+       {
+               auto initialPath = boost::filesystem3::initial_path().wstring();
+       
+               std::wifstream file(initialPath + L"\\" + filename);
+               boost::property_tree::read_xml(file, pt, boost::property_tree::xml_parser::trim_whitespace | boost::property_tree::xml_parser::no_comments);
+
+               auto paths      = pt.get_child(L"configuration.paths");
+               media           = paths.get(L"media-path", initialPath + L"\\media\\");
+               log                     = paths.get(L"log-path", initialPath + L"\\log\\");
+               ftemplate       = boost::filesystem3::complete(paths.get(L"template-path", initialPath + L"\\template\\")).wstring();           
+               data            = paths.get(L"data-path", initialPath + L"\\data\\");
+
+               try
+               {
+                       for(auto it = boost::filesystem::directory_iterator(initialPath); it != boost::filesystem::directory_iterator(); ++it)
+                       {
+                               if(it->path().wstring().find(L".fth") != std::wstring::npos)                    
+                               {
+                                       auto from_path = *it;
+                                       auto to_path = boost::filesystem::path(ftemplate + L"/" + it->path().wstring());
+                               
+                                       if(boost::filesystem::exists(to_path))
+                                               boost::filesystem::remove(to_path);
+
+                                       boost::filesystem::copy_file(from_path, to_path);
+                               }       
+                       }
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+                       CASPAR_LOG(error) << L"Failed to copy template-hosts from initial-path to template-path.";
+               }
+       }
+       catch(...)
+       {
+               CASPAR_LOG(error) << L" ### Invalid configuration file. ###";
+               throw;
+       }
+
+       try
+       {
+               try
+               {
+                       auto log_path = boost::filesystem::path(log);
+                       if(!boost::filesystem::exists(log_path))
+                               boost::filesystem::create_directories(log_path);
+               }
+               catch(...)
+               {
+                       log = L"./";
+               }
+
+               auto media_path = boost::filesystem::path(media);
+               if(!boost::filesystem::exists(media_path))
+                       boost::filesystem::create_directories(media_path);
+                               
+               auto template_path = boost::filesystem::path(ftemplate);
+               if(!boost::filesystem::exists(template_path))
+                       boost::filesystem::create_directories(template_path);
+               
+               auto data_path = boost::filesystem::path(data);
+               if(!boost::filesystem::exists(data_path))
+                       boost::filesystem::create_directories(data_path);
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               CASPAR_LOG(error) << L"Failed to create configured directories.";
+       }
+}
+       
+const std::wstring& media_folder()
+{
+       check_is_configured();
+       return media;
+}
+
+const std::wstring& log_folder()
+{
+       check_is_configured();
+       return log;
+}
+
+const std::wstring& template_folder()
+{
+       check_is_configured();
+       return ftemplate;
+}
+
+const std::wstring& data_folder()
+{
+       check_is_configured();
+       return data;
+}
+
+#define QUOTE(str) #str
+#define EXPAND_AND_QUOTE(str) QUOTE(str)
+
+const std::wstring& version()
+{
+       static std::wstring ver = u16(
+                       EXPAND_AND_QUOTE(CASPAR_GEN)    "." 
+                       EXPAND_AND_QUOTE(CASPAR_MAYOR)  "." 
+                       EXPAND_AND_QUOTE(CASPAR_MINOR)  "." 
+                       EXPAND_AND_QUOTE(CASPAR_REV)    " " 
+                       CASPAR_TAG);
+       return ver;
+}
+
+const boost::property_tree::wptree& properties()
+{
+       check_is_configured();
+       return pt;
+}
+
 }}
\ No newline at end of file
index fc8c5b2f9d52a72bb5b8f2728908e46884f8b3e3..850cc29dd2446f351d6423ddc333adf08a2a01a4 100644 (file)
@@ -1,40 +1,40 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <boost/property_tree/ptree_fwd.hpp>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace env {\r
-\r
-void configure(const std::wstring& filename);\r
-\r
-const std::wstring& media_folder();\r
-const std::wstring& log_folder();\r
-const std::wstring& template_folder();\r
-const std::wstring& data_folder();\r
-const std::wstring& version();\r
-\r
-const boost::property_tree::wptree& properties();\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <boost/property_tree/ptree_fwd.hpp>
+
+#include <string>
+
+namespace caspar { namespace env {
+
+void configure(const std::wstring& filename);
+
+const std::wstring& media_folder();
+const std::wstring& log_folder();
+const std::wstring& template_folder();
+const std::wstring& data_folder();
+const std::wstring& version();
+
+const boost::property_tree::wptree& properties();
+
 } }
\ No newline at end of file
index 82bdf638fba4cc8d0bd7dade5b285ccf45b6e43b..86cb8cb6e3877d3dd6095321ee8f23f8500abdf3 100644 (file)
@@ -1,55 +1,55 @@
-#include "stdafx.h"\r
-\r
-#include "except.h"\r
-\r
-#include "os/windows/windows.h"\r
-\r
-namespace caspar {\r
-       \r
-void win32_exception::install_handler() \r
-{\r
-//#ifndef _DEBUG\r
-       _set_se_translator(win32_exception::Handler);\r
-//#endif\r
-}\r
-\r
-void win32_exception::Handler(unsigned int errorCode, EXCEPTION_POINTERS* pInfo) {\r
-       switch(errorCode)\r
-       {\r
-       case EXCEPTION_ACCESS_VIOLATION:\r
-               throw win32_access_violation(*(pInfo->ExceptionRecord));\r
-               break;\r
-\r
-       default:\r
-               throw win32_exception(*(pInfo->ExceptionRecord));\r
-       }\r
-}\r
-\r
-win32_exception::win32_exception(const EXCEPTION_RECORD& info) : message_("Win32 exception"), location_(info.ExceptionAddress), errorCode_(info.ExceptionCode)\r
-{\r
-       switch(info.ExceptionCode)\r
-       {\r
-       case EXCEPTION_ACCESS_VIOLATION:\r
-               message_ = "Access violation";\r
-               break;\r
-       case EXCEPTION_FLT_DIVIDE_BY_ZERO:\r
-       case EXCEPTION_INT_DIVIDE_BY_ZERO:\r
-               message_ = "Divide by zero";\r
-               break;\r
-       }\r
-}\r
-\r
-win32_access_violation::win32_access_violation(const EXCEPTION_RECORD& info) : win32_exception(info), isWrite_(false), badAddress_(0) \r
-{\r
-       isWrite_ = info.ExceptionInformation[0] == 1;\r
-       badAddress_ = reinterpret_cast<win32_exception::address>(info.ExceptionInformation[1]);\r
-}\r
-\r
-const char* win32_access_violation::what() const\r
-{\r
-       sprintf_s<>(messageBuffer_, "Access violation at %p, trying to %s %p", location(), isWrite_?"write":"read", badAddress_);\r
-\r
-       return messageBuffer_;\r
-}\r
-\r
+#include "stdafx.h"
+
+#include "except.h"
+
+#include "os/windows/windows.h"
+
+namespace caspar {
+       
+void win32_exception::install_handler() 
+{
+//#ifndef _DEBUG
+       _set_se_translator(win32_exception::Handler);
+//#endif
+}
+
+void win32_exception::Handler(unsigned int errorCode, EXCEPTION_POINTERS* pInfo) {
+       switch(errorCode)
+       {
+       case EXCEPTION_ACCESS_VIOLATION:
+               throw win32_access_violation(*(pInfo->ExceptionRecord));
+               break;
+
+       default:
+               throw win32_exception(*(pInfo->ExceptionRecord));
+       }
+}
+
+win32_exception::win32_exception(const EXCEPTION_RECORD& info) : message_("Win32 exception"), location_(info.ExceptionAddress), errorCode_(info.ExceptionCode)
+{
+       switch(info.ExceptionCode)
+       {
+       case EXCEPTION_ACCESS_VIOLATION:
+               message_ = "Access violation";
+               break;
+       case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+       case EXCEPTION_INT_DIVIDE_BY_ZERO:
+               message_ = "Divide by zero";
+               break;
+       }
+}
+
+win32_access_violation::win32_access_violation(const EXCEPTION_RECORD& info) : win32_exception(info), isWrite_(false), badAddress_(0) 
+{
+       isWrite_ = info.ExceptionInformation[0] == 1;
+       badAddress_ = reinterpret_cast<win32_exception::address>(info.ExceptionInformation[1]);
+}
+
+const char* win32_access_violation::what() const
+{
+       sprintf_s<>(messageBuffer_, "Access violation at %p, trying to %s %p", location(), isWrite_?"write":"read", badAddress_);
+
+       return messageBuffer_;
+}
+
 }
\ No newline at end of file
index 2e76fff94e95763f1e1da75159ace6d7f0c56cab..b0ce1c8e125c4196db62970129d0eef339d2fc5a 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "utf.h"\r
-\r
-#include "log.h"\r
-\r
-#include <exception>\r
-#include <boost/exception/all.hpp>\r
-#include <boost/exception/error_info.hpp>\r
-#include <boost/throw_exception.hpp>\r
-\r
-struct _EXCEPTION_RECORD;\r
-struct _EXCEPTION_POINTERS;\r
-\r
-typedef _EXCEPTION_RECORD EXCEPTION_RECORD;\r
-typedef _EXCEPTION_POINTERS EXCEPTION_POINTERS;\r
-\r
-namespace caspar {\r
-\r
-typedef boost::error_info<struct tag_arg_name_info, std::string>       arg_name_info_t;\r
-typedef boost::error_info<struct tag_arg_value_info, std::string>      arg_value_info_t;\r
-typedef boost::error_info<struct tag_msg_info, std::string>                    msg_info_t;\r
-typedef boost::error_info<struct tag_call_stack_info, std::string>     call_stack_info_t;\r
-typedef boost::error_info<struct tag_msg_info, std::string>                    error_info_t;\r
-typedef boost::error_info<struct tag_source_info, std::string>         source_info_t;\r
-typedef boost::error_info<struct tag_file_name_info, std::string>      file_name_info_t;\r
-\r
-template<typename T>\r
-inline arg_name_info_t         arg_name_info(const T& str)             {return arg_name_info_t(u8(str));}\r
-template<typename T>\r
-inline arg_value_info_t                arg_value_info(const T& str)    {return arg_value_info_t(u8(str));}\r
-template<typename T>\r
-inline msg_info_t                      msg_info(const T& str)                  {return msg_info_t(u8(str));}\r
-template<typename T>\r
-inline call_stack_info_t       call_stack_info(const T& str)   {return call_stack_info_t(u8(str));}\r
-template<typename T>\r
-inline error_info_t                    error_info(const T& str)                {return error_info_t(u8(str));}\r
-template<typename T>\r
-inline source_info_t           source_info(const T& str)               {return source_info_t(u8(str));}\r
-template<typename T>\r
-inline file_name_info_t        file_name_info(const T& str)    {return file_name_info_t(u8(str));}\r
-\r
-typedef boost::error_info<struct tag_line_info, size_t>                                                line_info;\r
-typedef boost::error_info<struct tag_nested_exception_, std::exception_ptr> nested_exception;\r
-\r
-struct caspar_exception                        : virtual boost::exception, virtual std::exception \r
-{\r
-       caspar_exception(){}\r
-       explicit caspar_exception(const char* msg) : std::exception(msg) {}\r
-};\r
-\r
-struct io_error                                        : virtual caspar_exception {};\r
-struct directory_not_found             : virtual io_error {};\r
-struct file_not_found                  : virtual io_error {};\r
-struct file_read_error          : virtual io_error {};\r
-struct file_write_error         : virtual io_error {};\r
-\r
-struct invalid_argument                        : virtual caspar_exception {};\r
-struct null_argument                   : virtual invalid_argument {};\r
-struct out_of_range                            : virtual invalid_argument {};\r
-struct bad_alloc                               : virtual caspar_exception {};\r
-\r
-struct invalid_operation               : virtual caspar_exception {};\r
-struct operation_failed                        : virtual caspar_exception {};\r
-struct timed_out                               : virtual caspar_exception {};\r
-\r
-struct not_supported                   : virtual caspar_exception {};\r
-struct not_implemented                 : virtual caspar_exception {};\r
-\r
-class win32_exception : public std::exception\r
-{\r
-public:\r
-       typedef const void* address;\r
-       static void install_handler();\r
-\r
-       address location() const { return location_; }\r
-       unsigned int error_code() const { return errorCode_; }\r
-       virtual const char* what() const { return message_;     }\r
-\r
-protected:\r
-       win32_exception(const EXCEPTION_RECORD& info);\r
-       static void Handler(unsigned int errorCode, EXCEPTION_POINTERS* pInfo);\r
-\r
-private:\r
-       const char* message_;\r
-\r
-       address location_;\r
-       unsigned int errorCode_;\r
-};\r
-\r
-class win32_access_violation : public win32_exception\r
-{\r
-       mutable char messageBuffer_[256];\r
-\r
-public:\r
-       bool is_write() const { return isWrite_; }\r
-       address bad_address() const { return badAddress_;}\r
-       virtual const char* what() const;\r
-\r
-protected:\r
-       win32_access_violation(const EXCEPTION_RECORD& info);\r
-       friend void win32_exception::Handler(unsigned int errorCode, EXCEPTION_POINTERS* pInfo);\r
-\r
-private:\r
-       bool isWrite_;\r
-       address badAddress_;\r
-};\r
-\r
-#define CASPAR_THROW_EXCEPTION(e) BOOST_THROW_EXCEPTION(e << call_stack_info(caspar::log::internal::get_call_stack()))\r
-\r
-}\r
-\r
-namespace std\r
-{\r
-\r
-inline bool operator!=(const std::exception_ptr& lhs, const std::exception_ptr& rhs)\r
-{\r
-       return !(lhs == rhs);\r
-}\r
-\r
-inline bool operator!=(const std::exception_ptr& lhs, std::nullptr_t)\r
-{\r
-       return !(lhs == nullptr);\r
-}\r
-\r
-inline bool operator!=(std::nullptr_t, const std::exception_ptr& rhs)\r
-{\r
-       return !(nullptr == rhs);\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "utf.h"
+
+#include "log.h"
+
+#include <exception>
+#include <boost/exception/all.hpp>
+#include <boost/exception/error_info.hpp>
+#include <boost/throw_exception.hpp>
+
+struct _EXCEPTION_RECORD;
+struct _EXCEPTION_POINTERS;
+
+typedef _EXCEPTION_RECORD EXCEPTION_RECORD;
+typedef _EXCEPTION_POINTERS EXCEPTION_POINTERS;
+
+namespace caspar {
+
+typedef boost::error_info<struct tag_arg_name_info, std::string>       arg_name_info_t;
+typedef boost::error_info<struct tag_arg_value_info, std::string>      arg_value_info_t;
+typedef boost::error_info<struct tag_msg_info, std::string>                    msg_info_t;
+typedef boost::error_info<struct tag_call_stack_info, std::string>     call_stack_info_t;
+typedef boost::error_info<struct tag_msg_info, std::string>                    error_info_t;
+typedef boost::error_info<struct tag_source_info, std::string>         source_info_t;
+typedef boost::error_info<struct tag_file_name_info, std::string>      file_name_info_t;
+
+template<typename T>
+inline arg_name_info_t         arg_name_info(const T& str)             {return arg_name_info_t(u8(str));}
+template<typename T>
+inline arg_value_info_t                arg_value_info(const T& str)    {return arg_value_info_t(u8(str));}
+template<typename T>
+inline msg_info_t                      msg_info(const T& str)                  {return msg_info_t(u8(str));}
+template<typename T>
+inline call_stack_info_t       call_stack_info(const T& str)   {return call_stack_info_t(u8(str));}
+template<typename T>
+inline error_info_t                    error_info(const T& str)                {return error_info_t(u8(str));}
+template<typename T>
+inline source_info_t           source_info(const T& str)               {return source_info_t(u8(str));}
+template<typename T>
+inline file_name_info_t        file_name_info(const T& str)    {return file_name_info_t(u8(str));}
+
+typedef boost::error_info<struct tag_line_info, size_t>                                                line_info;
+typedef boost::error_info<struct tag_nested_exception_, std::exception_ptr> nested_exception;
+
+struct caspar_exception                        : virtual boost::exception, virtual std::exception 
+{
+       caspar_exception(){}
+       explicit caspar_exception(const char* msg) : std::exception(msg) {}
+};
+
+struct io_error                                        : virtual caspar_exception {};
+struct directory_not_found             : virtual io_error {};
+struct file_not_found                  : virtual io_error {};
+struct file_read_error          : virtual io_error {};
+struct file_write_error         : virtual io_error {};
+
+struct invalid_argument                        : virtual caspar_exception {};
+struct null_argument                   : virtual invalid_argument {};
+struct out_of_range                            : virtual invalid_argument {};
+struct bad_alloc                               : virtual caspar_exception {};
+
+struct invalid_operation               : virtual caspar_exception {};
+struct operation_failed                        : virtual caspar_exception {};
+struct timed_out                               : virtual caspar_exception {};
+
+struct not_supported                   : virtual caspar_exception {};
+struct not_implemented                 : virtual caspar_exception {};
+
+class win32_exception : public std::exception
+{
+public:
+       typedef const void* address;
+       static void install_handler();
+
+       address location() const { return location_; }
+       unsigned int error_code() const { return errorCode_; }
+       virtual const char* what() const { return message_;     }
+
+protected:
+       win32_exception(const EXCEPTION_RECORD& info);
+       static void Handler(unsigned int errorCode, EXCEPTION_POINTERS* pInfo);
+
+private:
+       const char* message_;
+
+       address location_;
+       unsigned int errorCode_;
+};
+
+class win32_access_violation : public win32_exception
+{
+       mutable char messageBuffer_[256];
+
+public:
+       bool is_write() const { return isWrite_; }
+       address bad_address() const { return badAddress_;}
+       virtual const char* what() const;
+
+protected:
+       win32_access_violation(const EXCEPTION_RECORD& info);
+       friend void win32_exception::Handler(unsigned int errorCode, EXCEPTION_POINTERS* pInfo);
+
+private:
+       bool isWrite_;
+       address badAddress_;
+};
+
+#define CASPAR_THROW_EXCEPTION(e) BOOST_THROW_EXCEPTION(e << call_stack_info(caspar::log::internal::get_call_stack()))
+
+}
+
+namespace std
+{
+
+inline bool operator!=(const std::exception_ptr& lhs, const std::exception_ptr& rhs)
+{
+       return !(lhs == rhs);
+}
+
+inline bool operator!=(const std::exception_ptr& lhs, std::nullptr_t)
+{
+       return !(lhs == nullptr);
+}
+
+inline bool operator!=(std::nullptr_t, const std::exception_ptr& rhs)
+{
+       return !(nullptr == rhs);
+}
+
 }
\ No newline at end of file
index 4b529edbd09b4ece54bb9544d52940b7698511c5..b58339e1f29b704a28c3568eb9b76b10db514a75 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "except.h"\r
-#include "enum_class.h"\r
-#include "log.h"\r
-\r
-#include <tbb/atomic.h>\r
-#include <tbb/concurrent_priority_queue.h>\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <boost/thread.hpp>\r
-\r
-#include <functional>\r
-\r
-namespace caspar {\r
-               \r
-struct task_priority_def\r
-{\r
-       enum type\r
-       {\r
-               lowest_priority = 0,\r
-               lower_priority,\r
-               low_priority,\r
-               normal_priority,\r
-               high_priority,\r
-               higher_priority\r
-       };\r
-};\r
-typedef enum_class<task_priority_def> task_priority;\r
-\r
-class executor sealed\r
-{      \r
-       struct priority_function\r
-       {\r
-               int                                             priority;\r
-               std::function<void()>   func;\r
-\r
-               priority_function()\r
-               {\r
-               }\r
-\r
-               template<typename F>\r
-               priority_function(int priority, F&& func)\r
-                       : priority(priority)\r
-                       , func(std::forward<F>(func))\r
-               {\r
-               }\r
-\r
-               void operator()()\r
-               {\r
-                       func();\r
-               }\r
-\r
-               bool operator<(const priority_function& other) const\r
-               {\r
-                       return priority < other.priority;\r
-               }\r
-       };\r
-\r
-       executor(const executor&);\r
-       executor& operator=(const executor&);\r
-       \r
-       typedef tbb::concurrent_priority_queue<priority_function>       function_queue_t;\r
-       \r
-       const std::wstring                                                                                      name_;\r
-       tbb::atomic<bool>                                                                                       is_running_;\r
-       boost::thread                                                                                           thread_;        \r
-       function_queue_t                                                                                        execution_queue_;\r
-       tbb::concurrent_bounded_queue<int>                                                      semaphore_;\r
-               \r
-public:                \r
-       executor(const std::wstring& name)\r
-               : name_(name)\r
-       {\r
-               is_running_ = true;\r
-               set_capacity(512);\r
-               thread_ = boost::thread([this]{run();});\r
-       }\r
-       \r
-       ~executor()\r
-       {\r
-               try\r
-               {\r
-                       internal_begin_invoke([=]\r
-                       {\r
-                               is_running_ = false;\r
-                       }).wait();\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-               \r
-               thread_.join();\r
-       }\r
-                                               \r
-       template<typename Func>\r
-       auto begin_invoke(Func&& func, task_priority priority = task_priority::normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
-       {       \r
-               if(!is_running_)\r
-                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("executor not running.") << source_info(name_));\r
-                               \r
-               return internal_begin_invoke(std::forward<Func>(func), priority);       \r
-       }\r
-       \r
-       template<typename Func>\r
-       auto invoke(Func&& func, task_priority prioriy = task_priority::normal_priority) -> decltype(func()) // noexcept\r
-       {\r
-               if(is_current())  // Avoids potential deadlock.\r
-                       return func();\r
-               \r
-               return begin_invoke(std::forward<Func>(func), prioriy).get();\r
-       }\r
-\r
-       void yield()\r
-       {\r
-               if(!is_current())\r
-                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Executor can only yield inside of thread context.")  << source_info(name_));\r
-\r
-               int dummy;\r
-               if(!semaphore_.try_pop(dummy))\r
-                       return;\r
-\r
-               priority_function func;\r
-               if(execution_queue_.try_pop(func))\r
-                       func();\r
-       }\r
-\r
-       void set_capacity(std::size_t capacity)\r
-       {\r
-               semaphore_.set_capacity(capacity);\r
-       }\r
-\r
-       std::size_t capacity() const\r
-       {\r
-               return semaphore_.capacity();\r
-       }\r
-       \r
-       void clear()\r
-       {               \r
-               priority_function func;\r
-               while(execution_queue_.try_pop(func));\r
-       }\r
-                               \r
-       void stop()\r
-       {\r
-               invoke([this]\r
-               {\r
-                       is_running_ = false;\r
-               });\r
-       }\r
-\r
-       void wait()\r
-       {\r
-               invoke([]{}, task_priority::lowest_priority);\r
-       }\r
-               \r
-       function_queue_t::size_type size() const \r
-       {\r
-               return execution_queue_.size(); \r
-       }\r
-               \r
-       bool is_running() const\r
-       {\r
-               return is_running_; \r
-       }       \r
-\r
-       bool is_current() const\r
-       {\r
-               return boost::this_thread::get_id() == thread_.get_id();\r
-       }\r
-               \r
-private:       \r
-\r
-       std::wstring print() const\r
-       {\r
-               return L"executor[" + name_ + L"]";\r
-       }\r
-       \r
-       template<typename Func>\r
-       auto internal_begin_invoke(Func&& func, task_priority priority = task_priority::normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
-       {                                       \r
-               typedef typename std::remove_reference<Func>::type      function_type;\r
-               typedef decltype(func())                                                        result_type;\r
-               typedef boost::packaged_task<result_type>                       task_type;\r
-                                                               \r
-               std::unique_ptr<task_type> task;\r
-\r
-               // Use pointers since the boost thread library doesn't fully support move semantics.\r
-\r
-               auto raw_func2 = new function_type(std::forward<Func>(func));\r
-               try\r
-               {\r
-                       task.reset(new task_type([raw_func2]() -> result_type\r
-                       {\r
-                               std::unique_ptr<function_type> func2(raw_func2);\r
-                               return (*func2)();\r
-                       }));\r
-               }\r
-               catch(...)\r
-               {\r
-                       delete raw_func2;\r
-                       throw;\r
-               }\r
-               \r
-               task->set_wait_callback(std::function<void(task_type&)>([=](task_type& my_task) // The std::function wrapper is required in order to add ::result_type to functor class.\r
-               {\r
-                       try\r
-                       {\r
-                               if(is_current())  // Avoids potential deadlock.\r
-                                       my_task();\r
-                       }\r
-                       catch(boost::task_already_started&){}\r
-               }));\r
-                               \r
-               auto future = task->get_future();\r
-\r
-               auto raw_task = task.release();\r
-               priority_function prio_func(priority.value(), [raw_task]\r
-               {\r
-                       std::unique_ptr<task_type> task(raw_task);\r
-                       try\r
-                       {\r
-                               (*task)();\r
-                       }\r
-                       catch(boost::task_already_started&){}\r
-               });\r
-\r
-               execution_queue_.push(prio_func);\r
-\r
-               if(!semaphore_.try_push(0))\r
-               {\r
-                       CASPAR_LOG(debug) << print() << L" Overflow. Blocking caller.";\r
-                       semaphore_.push(0);\r
-               }                                       \r
-               return std::move(future);               \r
-       }\r
-\r
-       void run() // noexcept\r
-       {\r
-               win32_exception::install_handler();             \r
-               while(is_running_)\r
-               {\r
-                       try\r
-                       {\r
-                               int dummy;\r
-                               semaphore_.pop(dummy);\r
-\r
-                               priority_function func;\r
-                               if(execution_queue_.try_pop(func))\r
-                                       func();\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }\r
-               }\r
-       }       \r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "except.h"
+#include "enum_class.h"
+#include "log.h"
+
+#include <tbb/atomic.h>
+#include <tbb/concurrent_priority_queue.h>
+#include <tbb/concurrent_queue.h>
+
+#include <boost/thread.hpp>
+
+#include <functional>
+
+namespace caspar {
+               
+struct task_priority_def
+{
+       enum type
+       {
+               lowest_priority = 0,
+               lower_priority,
+               low_priority,
+               normal_priority,
+               high_priority,
+               higher_priority
+       };
+};
+typedef enum_class<task_priority_def> task_priority;
+
+class executor sealed
+{      
+       struct priority_function
+       {
+               int                                             priority;
+               std::function<void()>   func;
+
+               priority_function()
+               {
+               }
+
+               template<typename F>
+               priority_function(int priority, F&& func)
+                       : priority(priority)
+                       , func(std::forward<F>(func))
+               {
+               }
+
+               void operator()()
+               {
+                       func();
+               }
+
+               bool operator<(const priority_function& other) const
+               {
+                       return priority < other.priority;
+               }
+       };
+
+       executor(const executor&);
+       executor& operator=(const executor&);
+       
+       typedef tbb::concurrent_priority_queue<priority_function>       function_queue_t;
+       
+       const std::wstring                                                                                      name_;
+       tbb::atomic<bool>                                                                                       is_running_;
+       boost::thread                                                                                           thread_;        
+       function_queue_t                                                                                        execution_queue_;
+       tbb::concurrent_bounded_queue<int>                                                      semaphore_;
+               
+public:                
+       executor(const std::wstring& name)
+               : name_(name)
+       {
+               is_running_ = true;
+               set_capacity(512);
+               thread_ = boost::thread([this]{run();});
+       }
+       
+       ~executor()
+       {
+               try
+               {
+                       internal_begin_invoke([=]
+                       {
+                               is_running_ = false;
+                       }).wait();
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+               
+               thread_.join();
+       }
+                                               
+       template<typename Func>
+       auto begin_invoke(Func&& func, task_priority priority = task_priority::normal_priority) -> boost::unique_future<decltype(func())> // noexcept
+       {       
+               if(!is_running_)
+                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("executor not running.") << source_info(name_));
+                               
+               return internal_begin_invoke(std::forward<Func>(func), priority);       
+       }
+       
+       template<typename Func>
+       auto invoke(Func&& func, task_priority prioriy = task_priority::normal_priority) -> decltype(func()) // noexcept
+       {
+               if(is_current())  // Avoids potential deadlock.
+                       return func();
+               
+               return begin_invoke(std::forward<Func>(func), prioriy).get();
+       }
+
+       void yield()
+       {
+               if(!is_current())
+                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Executor can only yield inside of thread context.")  << source_info(name_));
+
+               int dummy;
+               if(!semaphore_.try_pop(dummy))
+                       return;
+
+               priority_function func;
+               if(execution_queue_.try_pop(func))
+                       func();
+       }
+
+       void set_capacity(std::size_t capacity)
+       {
+               semaphore_.set_capacity(capacity);
+       }
+
+       std::size_t capacity() const
+       {
+               return semaphore_.capacity();
+       }
+       
+       void clear()
+       {               
+               priority_function func;
+               while(execution_queue_.try_pop(func));
+       }
+                               
+       void stop()
+       {
+               invoke([this]
+               {
+                       is_running_ = false;
+               });
+       }
+
+       void wait()
+       {
+               invoke([]{}, task_priority::lowest_priority);
+       }
+               
+       function_queue_t::size_type size() const 
+       {
+               return execution_queue_.size(); 
+       }
+               
+       bool is_running() const
+       {
+               return is_running_; 
+       }       
+
+       bool is_current() const
+       {
+               return boost::this_thread::get_id() == thread_.get_id();
+       }
+               
+private:       
+
+       std::wstring print() const
+       {
+               return L"executor[" + name_ + L"]";
+       }
+       
+       template<typename Func>
+       auto internal_begin_invoke(Func&& func, task_priority priority = task_priority::normal_priority) -> boost::unique_future<decltype(func())> // noexcept
+       {                                       
+               typedef typename std::remove_reference<Func>::type      function_type;
+               typedef decltype(func())                                                        result_type;
+               typedef boost::packaged_task<result_type>                       task_type;
+                                                               
+               std::unique_ptr<task_type> task;
+
+               // Use pointers since the boost thread library doesn't fully support move semantics.
+
+               auto raw_func2 = new function_type(std::forward<Func>(func));
+               try
+               {
+                       task.reset(new task_type([raw_func2]() -> result_type
+                       {
+                               std::unique_ptr<function_type> func2(raw_func2);
+                               return (*func2)();
+                       }));
+               }
+               catch(...)
+               {
+                       delete raw_func2;
+                       throw;
+               }
+               
+               task->set_wait_callback(std::function<void(task_type&)>([=](task_type& my_task) // The std::function wrapper is required in order to add ::result_type to functor class.
+               {
+                       try
+                       {
+                               if(is_current())  // Avoids potential deadlock.
+                                       my_task();
+                       }
+                       catch(boost::task_already_started&){}
+               }));
+                               
+               auto future = task->get_future();
+
+               auto raw_task = task.release();
+               priority_function prio_func(priority.value(), [raw_task]
+               {
+                       std::unique_ptr<task_type> task(raw_task);
+                       try
+                       {
+                               (*task)();
+                       }
+                       catch(boost::task_already_started&){}
+               });
+
+               execution_queue_.push(prio_func);
+
+               if(!semaphore_.try_push(0))
+               {
+                       CASPAR_LOG(debug) << print() << L" Overflow. Blocking caller.";
+                       semaphore_.push(0);
+               }                                       
+               return std::move(future);               
+       }
+
+       void run() // noexcept
+       {
+               win32_exception::install_handler();             
+               while(is_running_)
+               {
+                       try
+                       {
+                               int dummy;
+                               semaphore_.pop(dummy);
+
+                               priority_function func;
+                               if(execution_queue_.try_pop(func))
+                                       func();
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }
+               }
+       }       
+};
+
 }
\ No newline at end of file
index d09bc56dd7a30789aa423f81bab60b97dc5adc51..4a8870e9305bd6714a2a3d9c0112b92a28ee18a4 100644 (file)
@@ -1,6 +1,6 @@
-#pragma once\r
-\r
-#define FORWARD0(expr)                                 expr\r
-#define FORWARD1(a1, expr)                             namespace a1 { expr; }\r
-#define FORWARD2(a1, a2, expr)                 namespace a1 { namespace a2 { expr; }}\r
+#pragma once
+
+#define FORWARD0(expr)                                 expr
+#define FORWARD1(a1, expr)                             namespace a1 { expr; }
+#define FORWARD2(a1, a2, expr)                 namespace a1 { namespace a2 { expr; }}
 #define FORWARD3(a1, a2, a3, expr)             namespace a1 { namespace a2 { namespace a3 { expr; } }}
\ No newline at end of file
index afb3ea2669a890caca3a99b7b58a5d2d59e17f9d..7789ab871a6f388e1cd889b96ee25ff00b9ce3cf 100644 (file)
-#pragma once\r
-\r
-#include "enum_class.h"\r
-\r
-#include <boost/thread/future.hpp>\r
-#include <boost/thread/thread.hpp>\r
-#include <boost/shared_ptr.hpp>\r
-\r
-#include <functional>\r
-\r
-namespace caspar {\r
-       \r
-struct launch_policy_def\r
-{\r
-       enum type\r
-       {\r
-               async = 1,\r
-               deferred = 2\r
-       };\r
-};\r
-typedef caspar::enum_class<launch_policy_def> launch;\r
-\r
-namespace detail {\r
-       \r
-template<typename R>\r
-struct future_object_helper\r
-{      \r
-       template<typename T, typename F>\r
-       static void nonlocking_invoke(T& future_object, F& f)\r
-       {                               \r
-        try\r
-        {\r
-                       future_object.mark_finished_with_result_internal(f());\r
-        }\r
-        catch(...)\r
-        {\r
-                       future_object.mark_exceptional_finish_internal(boost::current_exception());\r
-        }\r
-       }\r
-\r
-       template<typename T, typename F>\r
-       static void locking_invoke(T& future_object, F& f)\r
-       {                               \r
-        try\r
-        {\r
-                       future_object.mark_finished_with_result(f());\r
-        }\r
-        catch(...)\r
-        {\r
-                       future_object.mark_exceptional_finish();\r
-        }\r
-       }\r
-};\r
-\r
-template<>\r
-struct future_object_helper<void>\r
-{      \r
-       template<typename T, typename F>\r
-       static void nonlocking_invoke(T& future_object, F& f)\r
-       {                               \r
-        try\r
-        {\r
-                       f();\r
-                       future_object.mark_finished_with_result_internal();\r
-        }\r
-        catch(...)\r
-        {\r
-                       future_object.mark_exceptional_finish_internal(boost::current_exception());\r
-        }\r
-       }\r
-\r
-       template<typename T, typename F>\r
-       static void locking_invoke(T& future_object, F& f)\r
-       {                               \r
-        try\r
-        {\r
-                       f();\r
-                       future_object.mark_finished_with_result();\r
-        }\r
-        catch(...)\r
-        {\r
-                       future_object.mark_exceptional_finish();\r
-        }\r
-       }\r
-};\r
-\r
-template<typename R, typename F>\r
-struct deferred_future_object : public boost::detail::future_object<R>\r
-{      \r
-       F f;\r
-       bool done;\r
-\r
-       template<typename F2>\r
-       deferred_future_object(F2&& f)\r
-               : f(std::forward<F2>(f))\r
-               , done(false)\r
-       {\r
-               set_wait_callback(std::mem_fn(&detail::deferred_future_object<R, F>::operator()), this);\r
-       }\r
-\r
-       ~deferred_future_object()\r
-       {\r
-       }\r
-               \r
-       void operator()()\r
-       {               \r
-               boost::lock_guard<boost::mutex> lock2(mutex);\r
-\r
-               if(done)\r
-                       return;\r
-\r
-               future_object_helper<R>::nonlocking_invoke(*this, f);\r
-\r
-               done = true;\r
-       }\r
-};\r
-\r
-template<typename R, typename F>\r
-struct async_future_object : public boost::detail::future_object<R>\r
-{      \r
-       F f;\r
-       boost::thread thread;\r
-\r
-       template<typename F2>\r
-       async_future_object(F2&& f)\r
-               : f(std::forward<F2>(f))\r
-               , thread([this]{run();})\r
-       {\r
-       }\r
-\r
-       ~async_future_object()\r
-       {\r
-               thread.join();\r
-       }\r
-\r
-       void run()\r
-       {\r
-               future_object_helper<R>::locking_invoke(*this, f);\r
-       }\r
-};\r
-\r
-}\r
-       \r
-template<typename F>\r
-auto async(launch policy, F&& f) -> boost::unique_future<decltype(f())>\r
-{              \r
-       typedef decltype(f())                                                           result_type;    \r
-       typedef boost::detail::future_object<result_type>       future_object_type;\r
-\r
-       boost::shared_ptr<future_object_type> future_object;\r
-\r
-       // HACK: This solution is a hack to avoid modifying boost code.\r
-\r
-       if((policy & launch::async) != 0)\r
-               future_object.reset(new detail::async_future_object<result_type, F>(std::forward<F>(f)), [](future_object_type* p){delete reinterpret_cast<detail::async_future_object<result_type, F>*>(p);});\r
-       else if((policy & launch::deferred) != 0)\r
-               future_object.reset(new detail::deferred_future_object<result_type, F>(std::forward<F>(f)), [](future_object_type* p){delete reinterpret_cast<detail::deferred_future_object<result_type, F>*>(p);});\r
-       else\r
-               throw std::invalid_argument("policy");\r
-       \r
-       boost::unique_future<result_type> future;\r
-\r
-       static_assert(sizeof(future) == sizeof(future_object), "");\r
-\r
-       reinterpret_cast<boost::shared_ptr<future_object_type>&>(future) = std::move(future_object); // Get around the "private" encapsulation.\r
-       return std::move(future);\r
-}\r
-       \r
-template<typename F>\r
-auto async(F&& f) -> boost::unique_future<decltype(f())>\r
-{      \r
-       return async(launch::async | launch::deferred, std::forward<F>(f));\r
-}\r
-\r
-template<typename T>\r
-auto make_shared(boost::unique_future<T>&& f) -> boost::shared_future<T>\r
-{      \r
-       return boost::shared_future<T>(std::move(f));\r
-}\r
-\r
-template<typename T>\r
-auto flatten(boost::unique_future<T>&& f) -> boost::unique_future<decltype(f.get().get())>\r
-{\r
-       auto shared_f = make_shared(std::move(f));\r
-       return async(launch::deferred, [=]() mutable\r
-       {\r
-               return shared_f.get().get();\r
-       });\r
-}\r
-\r
+#pragma once
+
+#include "enum_class.h"
+
+#include <boost/thread/future.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <functional>
+
+namespace caspar {
+       
+struct launch_policy_def
+{
+       enum type
+       {
+               async = 1,
+               deferred = 2
+       };
+};
+typedef caspar::enum_class<launch_policy_def> launch;
+
+namespace detail {
+       
+template<typename R>
+struct future_object_helper
+{      
+       template<typename T, typename F>
+       static void nonlocking_invoke(T& future_object, F& f)
+       {                               
+        try
+        {
+                       future_object.mark_finished_with_result_internal(f());
+        }
+        catch(...)
+        {
+                       future_object.mark_exceptional_finish_internal(boost::current_exception());
+        }
+       }
+
+       template<typename T, typename F>
+       static void locking_invoke(T& future_object, F& f)
+       {                               
+        try
+        {
+                       future_object.mark_finished_with_result(f());
+        }
+        catch(...)
+        {
+                       future_object.mark_exceptional_finish();
+        }
+       }
+};
+
+template<>
+struct future_object_helper<void>
+{      
+       template<typename T, typename F>
+       static void nonlocking_invoke(T& future_object, F& f)
+       {                               
+        try
+        {
+                       f();
+                       future_object.mark_finished_with_result_internal();
+        }
+        catch(...)
+        {
+                       future_object.mark_exceptional_finish_internal(boost::current_exception());
+        }
+       }
+
+       template<typename T, typename F>
+       static void locking_invoke(T& future_object, F& f)
+       {                               
+        try
+        {
+                       f();
+                       future_object.mark_finished_with_result();
+        }
+        catch(...)
+        {
+                       future_object.mark_exceptional_finish();
+        }
+       }
+};
+
+template<typename R, typename F>
+struct deferred_future_object : public boost::detail::future_object<R>
+{      
+       F f;
+       bool done;
+
+       template<typename F2>
+       deferred_future_object(F2&& f)
+               : f(std::forward<F2>(f))
+               , done(false)
+       {
+               set_wait_callback(std::mem_fn(&detail::deferred_future_object<R, F>::operator()), this);
+       }
+
+       ~deferred_future_object()
+       {
+       }
+               
+       void operator()()
+       {               
+               boost::lock_guard<boost::mutex> lock2(mutex);
+
+               if(done)
+                       return;
+
+               future_object_helper<R>::nonlocking_invoke(*this, f);
+
+               done = true;
+       }
+};
+
+template<typename R, typename F>
+struct async_future_object : public boost::detail::future_object<R>
+{      
+       F f;
+       boost::thread thread;
+
+       template<typename F2>
+       async_future_object(F2&& f)
+               : f(std::forward<F2>(f))
+               , thread([this]{run();})
+       {
+       }
+
+       ~async_future_object()
+       {
+               thread.join();
+       }
+
+       void run()
+       {
+               future_object_helper<R>::locking_invoke(*this, f);
+       }
+};
+
+}
+       
+template<typename F>
+auto async(launch policy, F&& f) -> boost::unique_future<decltype(f())>
+{              
+       typedef decltype(f())                                                           result_type;    
+       typedef boost::detail::future_object<result_type>       future_object_type;
+
+       boost::shared_ptr<future_object_type> future_object;
+
+       // HACK: This solution is a hack to avoid modifying boost code.
+
+       if((policy & launch::async) != 0)
+               future_object.reset(new detail::async_future_object<result_type, F>(std::forward<F>(f)), [](future_object_type* p){delete reinterpret_cast<detail::async_future_object<result_type, F>*>(p);});
+       else if((policy & launch::deferred) != 0)
+               future_object.reset(new detail::deferred_future_object<result_type, F>(std::forward<F>(f)), [](future_object_type* p){delete reinterpret_cast<detail::deferred_future_object<result_type, F>*>(p);});
+       else
+               throw std::invalid_argument("policy");
+       
+       boost::unique_future<result_type> future;
+
+       static_assert(sizeof(future) == sizeof(future_object), "");
+
+       reinterpret_cast<boost::shared_ptr<future_object_type>&>(future) = std::move(future_object); // Get around the "private" encapsulation.
+       return std::move(future);
+}
+       
+template<typename F>
+auto async(F&& f) -> boost::unique_future<decltype(f())>
+{      
+       return async(launch::async | launch::deferred, std::forward<F>(f));
+}
+
+template<typename T>
+auto make_shared(boost::unique_future<T>&& f) -> boost::shared_future<T>
+{      
+       return boost::shared_future<T>(std::move(f));
+}
+
+template<typename T>
+auto flatten(boost::unique_future<T>&& f) -> boost::unique_future<decltype(f.get().get())>
+{
+       auto shared_f = make_shared(std::move(f));
+       return async(launch::deferred, [=]() mutable
+       {
+               return shared_f.get().get();
+       });
+}
+
 }
\ No newline at end of file
index ee836ce05933bd68d3de55bf324db8082de6bd42..487914762e79f45265c4caeef2d737ed5fc88fb9 100644 (file)
@@ -1,6 +1,6 @@
-#pragma once\r
-\r
-#include "forward.h"\r
-\r
-FORWARD1(boost, template<typename> class unique_future);\r
-FORWARD1(boost, template<typename> class shared_future);\r
+#pragma once
+
+#include "forward.h"
+
+FORWARD1(boost, template<typename> class unique_future);
+FORWARD1(boost, template<typename> class shared_future);
index 47e111c4842326bf87bba6ec44e59ad3401b9ca8..cc709280feba4c2e618e7e6019c7370d439d2b3a 100644 (file)
-///////////////////////////\r
-//\r
-// SFML - Simple and Fast Multimedia Library\r
-// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)\r
-//\r
-// This software is provided 'as-is', without any express or implied warranty.\r
-// In no event will the authors be held liable for any damages arising from the use of this software.\r
-//\r
-// Permission is granted to anyone to use this software for any purpose,\r
-// including commercial applications, and to alter it and redistribute it freely,\r
-// subject to the following restrictions:\r
-//\r
-// 1. The origin of this software must not be misrepresented;\r
-//    you must not claim that you wrote the original software.\r
-//    If you use this software in a product, an acknowledgment\r
-//    in the product documentation would be appreciated but is not required.\r
-//\r
-// 2. Altered source versions must be plainly marked as such,\r
-//    and must not be misrepresented as being the original software.\r
-//\r
-// 3. This notice may not be removed or altered from any source distribution.\r
-//\r
-///////////////////////////\r
-\r
-#pragma once\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "gl_check.h"\r
-\r
-#include "../log.h"\r
-\r
-#include <GL/glew.h>\r
-\r
-namespace caspar { namespace gl {      \r
-\r
-void SMFL_GLCheckError(const std::string&, const std::string& file, unsigned int line)\r
-{\r
-       // Get the last error\r
-       GLenum LastErrorCode = GL_NO_ERROR;\r
-\r
-       for(GLenum ErrorCode = glGetError(); ErrorCode != GL_NO_ERROR; ErrorCode = glGetError())\r
-       {\r
-               CASPAR_LOG(error) << "OpenGL Error: " << ErrorCode << L" " << glewGetErrorString(ErrorCode);\r
-               LastErrorCode = ErrorCode;\r
-       }\r
-\r
-       if (LastErrorCode != GL_NO_ERROR)\r
-       {\r
-               // Decode the error code\r
-               switch (LastErrorCode)\r
-               {\r
-                       case GL_INVALID_ENUM :\r
-                               CASPAR_THROW_EXCEPTION(ogl_invalid_enum()\r
-                                       << msg_info("an unacceptable value has been specified for an enumerated argument")\r
-                                       << error_info("GL_INVALID_ENUM")\r
-                                       << line_info(line)\r
-                                       << source_info(file));\r
-\r
-                       case GL_INVALID_VALUE :\r
-                               CASPAR_THROW_EXCEPTION(ogl_invalid_value()\r
-                                       << msg_info("a numeric argument is out of range")\r
-                                       << error_info("GL_INVALID_VALUE")\r
-                                       << line_info(line)\r
-                                       << source_info(file));\r
-\r
-                       case GL_INVALID_OPERATION :\r
-                               CASPAR_THROW_EXCEPTION(ogl_invalid_operation()\r
-                                       << msg_info("the specified operation is not allowed in the current state")\r
-                                       << error_info("GL_INVALID_OPERATION")\r
-                                       << line_info(line)\r
-                                       << source_info(file));\r
-\r
-                       case GL_STACK_OVERFLOW :\r
-                               CASPAR_THROW_EXCEPTION(ogl_stack_overflow()\r
-                                       << msg_info("this command would cause a stack overflow")\r
-                                       << error_info("GL_STACK_OVERFLOW")\r
-                                       << line_info(line)\r
-                                       << source_info(file));\r
-\r
-                       case GL_STACK_UNDERFLOW :\r
-                               CASPAR_THROW_EXCEPTION(ogl_stack_underflow()\r
-                                       << msg_info("this command would cause a stack underflow")\r
-                                       << error_info("GL_STACK_UNDERFLOW")\r
-                                       << line_info(line)\r
-                                       << source_info(file));\r
-\r
-                       case GL_OUT_OF_MEMORY :\r
-                               CASPAR_THROW_EXCEPTION(ogl_out_of_memory()\r
-                                       << msg_info("there is not enough memory left to execute the command")\r
-                                       << error_info("GL_OUT_OF_MEMORY")\r
-                                       << line_info(line)\r
-                                       << source_info(file));\r
-\r
-                       case GL_INVALID_FRAMEBUFFER_OPERATION_EXT :\r
-                               CASPAR_THROW_EXCEPTION(ogl_stack_underflow()\r
-                                       << msg_info("the object bound to FRAMEBUFFER_BINDING_EXT is not \"framebuffer complete\"")\r
-                                       << error_info("GL_INVALID_FRAMEBUFFER_OPERATION_EXT")\r
-                                       << line_info(line)\r
-                                       << source_info(file));\r
-               }\r
-       }\r
-}\r
-\r
+///////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+//    you must not claim that you wrote the original software.
+//    If you use this software in a product, an acknowledgment
+//    in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+//    and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+///////////////////////////
+
+#pragma once
+
+#include "../stdafx.h"
+
+#include "gl_check.h"
+
+#include "../log.h"
+
+#include <GL/glew.h>
+
+namespace caspar { namespace gl {      
+
+void SMFL_GLCheckError(const std::string&, const std::string& file, unsigned int line)
+{
+       // Get the last error
+       GLenum LastErrorCode = GL_NO_ERROR;
+
+       for(GLenum ErrorCode = glGetError(); ErrorCode != GL_NO_ERROR; ErrorCode = glGetError())
+       {
+               CASPAR_LOG(error) << "OpenGL Error: " << ErrorCode << L" " << glewGetErrorString(ErrorCode);
+               LastErrorCode = ErrorCode;
+       }
+
+       if (LastErrorCode != GL_NO_ERROR)
+       {
+               // Decode the error code
+               switch (LastErrorCode)
+               {
+                       case GL_INVALID_ENUM :
+                               CASPAR_THROW_EXCEPTION(ogl_invalid_enum()
+                                       << msg_info("an unacceptable value has been specified for an enumerated argument")
+                                       << error_info("GL_INVALID_ENUM")
+                                       << line_info(line)
+                                       << source_info(file));
+
+                       case GL_INVALID_VALUE :
+                               CASPAR_THROW_EXCEPTION(ogl_invalid_value()
+                                       << msg_info("a numeric argument is out of range")
+                                       << error_info("GL_INVALID_VALUE")
+                                       << line_info(line)
+                                       << source_info(file));
+
+                       case GL_INVALID_OPERATION :
+                               CASPAR_THROW_EXCEPTION(ogl_invalid_operation()
+                                       << msg_info("the specified operation is not allowed in the current state")
+                                       << error_info("GL_INVALID_OPERATION")
+                                       << line_info(line)
+                                       << source_info(file));
+
+                       case GL_STACK_OVERFLOW :
+                               CASPAR_THROW_EXCEPTION(ogl_stack_overflow()
+                                       << msg_info("this command would cause a stack overflow")
+                                       << error_info("GL_STACK_OVERFLOW")
+                                       << line_info(line)
+                                       << source_info(file));
+
+                       case GL_STACK_UNDERFLOW :
+                               CASPAR_THROW_EXCEPTION(ogl_stack_underflow()
+                                       << msg_info("this command would cause a stack underflow")
+                                       << error_info("GL_STACK_UNDERFLOW")
+                                       << line_info(line)
+                                       << source_info(file));
+
+                       case GL_OUT_OF_MEMORY :
+                               CASPAR_THROW_EXCEPTION(ogl_out_of_memory()
+                                       << msg_info("there is not enough memory left to execute the command")
+                                       << error_info("GL_OUT_OF_MEMORY")
+                                       << line_info(line)
+                                       << source_info(file));
+
+                       case GL_INVALID_FRAMEBUFFER_OPERATION_EXT :
+                               CASPAR_THROW_EXCEPTION(ogl_stack_underflow()
+                                       << msg_info("the object bound to FRAMEBUFFER_BINDING_EXT is not \"framebuffer complete\"")
+                                       << error_info("GL_INVALID_FRAMEBUFFER_OPERATION_EXT")
+                                       << line_info(line)
+                                       << source_info(file));
+               }
+       }
+}
+
 }}
\ No newline at end of file
index eff6723483a451134bb404e7f73c847637c1430c..72f3d33d736a16f69b84fd9884ef62388629f1ea 100644 (file)
@@ -1,64 +1,64 @@
-///////////////////////////\r
-//\r
-// SFML - Simple and Fast Multimedia Library\r
-// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)\r
-//\r
-// This software is provided 'as-is', without any express or implied warranty.\r
-// In no event will the authors be held liable for any damages arising from the use of this software.\r
-//\r
-// Permission is granted to anyone to use this software for any purpose,\r
-// including commercial applications, and to alter it and redistribute it freely,\r
-// subject to the following restrictions:\r
-//\r
-// 1. The origin of this software must not be misrepresented;\r
-//    you must not claim that you wrote the original software.\r
-//    If you use this software in a product, an acknowledgment\r
-//    in the product documentation would be appreciated but is not required.\r
-//\r
-// 2. Altered source versions must be plainly marked as such,\r
-//    and must not be misrepresented as being the original software.\r
-//\r
-// 3. This notice may not be removed or altered from any source distribution.\r
-//\r
-///////////////////////////\r
-\r
-#pragma once\r
-\r
-#include "../except.h"\r
-\r
-namespace caspar { namespace gl {\r
-\r
-struct ogl_exception                                                   : virtual caspar_exception{};\r
-struct ogl_invalid_enum                                                        : virtual ogl_exception{};\r
-struct ogl_invalid_value                                               : virtual ogl_exception{};\r
-struct ogl_invalid_operation                                   : virtual ogl_exception{};\r
-struct ogl_stack_overflow                                              : virtual ogl_exception{};\r
-struct ogl_stack_underflow                                             : virtual ogl_exception{};                      \r
-struct ogl_out_of_memory                                               : virtual ogl_exception{};\r
-struct ogl_invalid_framebuffer_operation_ext   : virtual ogl_exception{};\r
-\r
-void SMFL_GLCheckError(const std::string& expr, const std::string& File, unsigned int Line);\r
-\r
-//#ifdef _DEBUG\r
-       \r
-#define CASPAR_GL_EXPR_STR(expr) #expr\r
-\r
-#define GL(expr) \\r
-       if(false){}else \\r
-       { \\r
-               (expr);  \\r
-               caspar::gl::SMFL_GLCheckError(CASPAR_GL_EXPR_STR(expr), __FILE__, __LINE__);\\r
-       }\r
-\r
-#define GL2(expr) \\r
-       [&]() -> decltype(expr)\\r
-       {\\r
-               auto ret = (expr); \\r
-               caspar::gl::SMFL_GLCheckError(CASPAR_GL_EXPR_STR(expr), __FILE__, __LINE__);\\r
-               return ret;\\r
-       }()\r
-//#else\r
-//#define GL(expr) expr\r
-//#endif\r
-\r
+///////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+//    you must not claim that you wrote the original software.
+//    If you use this software in a product, an acknowledgment
+//    in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+//    and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+///////////////////////////
+
+#pragma once
+
+#include "../except.h"
+
+namespace caspar { namespace gl {
+
+struct ogl_exception                                                   : virtual caspar_exception{};
+struct ogl_invalid_enum                                                        : virtual ogl_exception{};
+struct ogl_invalid_value                                               : virtual ogl_exception{};
+struct ogl_invalid_operation                                   : virtual ogl_exception{};
+struct ogl_stack_overflow                                              : virtual ogl_exception{};
+struct ogl_stack_underflow                                             : virtual ogl_exception{};                      
+struct ogl_out_of_memory                                               : virtual ogl_exception{};
+struct ogl_invalid_framebuffer_operation_ext   : virtual ogl_exception{};
+
+void SMFL_GLCheckError(const std::string& expr, const std::string& File, unsigned int Line);
+
+//#ifdef _DEBUG
+       
+#define CASPAR_GL_EXPR_STR(expr) #expr
+
+#define GL(expr) \
+       if(false){}else \
+       { \
+               (expr);  \
+               caspar::gl::SMFL_GLCheckError(CASPAR_GL_EXPR_STR(expr), __FILE__, __LINE__);\
+       }
+
+#define GL2(expr) \
+       [&]() -> decltype(expr)\
+       {\
+               auto ret = (expr); \
+               caspar::gl::SMFL_GLCheckError(CASPAR_GL_EXPR_STR(expr), __FILE__, __LINE__);\
+               return ret;\
+       }()
+//#else
+//#define GL(expr) expr
+//#endif
+
 }}
\ No newline at end of file
index 73316b2d205b234bc36598221876bbaa42ee2ff4..f0ae64b6c338a07f21893e4e850a9550987b714a 100644 (file)
@@ -1,12 +1,12 @@
-#pragma once\r
-\r
-namespace caspar {\r
-\r
-template<typename T, typename F>\r
-auto lock(T& mutex, F&& func) -> decltype(func())\r
-{\r
-       T::scoped_lock lock(mutex);\r
-       return func();\r
-}\r
-\r
+#pragma once
+
+namespace caspar {
+
+template<typename T, typename F>
+auto lock(T& mutex, F&& func) -> decltype(func())
+{
+       T::scoped_lock lock(mutex);
+       return func();
+}
+
 }
\ No newline at end of file
index f47e2a996fa9c997e58f3045ff42dd205bf4d3b9..886c413df16155d520d186d1feaaacb1105a8674 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "stdafx.h"\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (disable : 4100) // 'identifier' : unreferenced formal parameter\r
-#pragma warning (disable : 4512) // 'class' : assignment operator could not be generated\r
-#endif\r
-\r
-#include "log.h"\r
-\r
-#include "except.h"\r
-#include "utf.h"\r
-#include "compiler/vs/stack_walker.h"\r
-\r
-#include <ios>\r
-#include <string>\r
-#include <ostream>\r
-\r
-#include <boost/bind.hpp>\r
-#include <boost/shared_ptr.hpp>\r
-#include <boost/make_shared.hpp>\r
-#include <boost/filesystem/convenience.hpp>\r
-#include <boost/date_time/posix_time/posix_time.hpp>\r
-#include <boost/algorithm/string.hpp>\r
-\r
-#include <boost/log/core/core.hpp>\r
-\r
-#include <boost/log/formatters/stream.hpp>\r
-#include <boost/log/formatters/attr.hpp>\r
-#include <boost/log/formatters/date_time.hpp>\r
-#include <boost/log/formatters/message.hpp>\r
-\r
-#include <boost/log/filters/attr.hpp>\r
-\r
-#include <boost/log/sinks/text_file_backend.hpp>\r
-\r
-#include <boost/log/detail/universal_path.hpp>\r
-\r
-#include <boost/log/sinks/text_file_backend.hpp>\r
-#include <boost/log/sinks/text_ostream_backend.hpp>\r
-#include <boost/log/sinks/sync_frontend.hpp>\r
-#include <boost/log/sinks/async_frontend.hpp>\r
-#include <boost/log/core/record.hpp>\r
-#include <boost/log/utility/attribute_value_extractor.hpp>\r
-\r
-#include <boost/log/utility/init/common_attributes.hpp>\r
-#include <boost/log/utility/empty_deleter.hpp>\r
-#include <boost/lambda/lambda.hpp>\r
-\r
-#include <tbb/enumerable_thread_specific.h>\r
-\r
-namespace caspar { namespace log {\r
-\r
-using namespace boost;\r
-\r
-void my_formatter(bool print_all_characters, std::wostream& strm, boost::log::basic_record<wchar_t> const& rec)\r
-{\r
-    namespace lambda = boost::lambda;\r
-       \r
-       #pragma warning(disable : 4996)\r
-       time_t rawtime;\r
-       struct tm* timeinfo;\r
-       time(&rawtime );\r
-       timeinfo = localtime ( &rawtime );\r
-       char buffer [80];\r
-       strftime (buffer,80, "%c", timeinfo);\r
-       strm << L"[" << buffer << L"] ";\r
-               \r
-    boost::log::attributes::current_thread_id::held_type thread_id;\r
-    if(boost::log::extract<boost::log::attributes::current_thread_id::held_type>(L"ThreadID", rec.attribute_values(), lambda::var(thread_id) = lambda::_1))\r
-        strm << L"[" << thread_id << L"] ";\r
-       \r
-    severity_level severity;\r
-    if(boost::log::extract<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get(), rec.attribute_values(), lambda::var(severity) = lambda::_1))\r
-       {\r
-               std::stringstream ss;\r
-               ss << severity;\r
-        strm << L"[" << severity << L"] ";\r
-               for(int n = 0; n < 7-static_cast<int>(ss.str().size()); ++n)\r
-                       strm << L" ";\r
-       }\r
-\r
-       if (print_all_characters)\r
-       {\r
-               strm << rec.message();\r
-       }\r
-       else\r
-       {\r
-           strm << replace_nonprintable_copy(rec.message(), L'?');\r
-       }\r
-}\r
-\r
-namespace internal{\r
-       \r
-void init()\r
-{      \r
-       boost::log::add_common_attributes<wchar_t>();\r
-       typedef boost::log::aux::add_common_attributes_constants<wchar_t> traits_t;\r
-\r
-       typedef boost::log::sinks::synchronous_sink<boost::log::sinks::wtext_file_backend> file_sink_type;\r
-\r
-       typedef boost::log::sinks::asynchronous_sink<boost::log::sinks::wtext_ostream_backend> stream_sink_type;\r
-\r
-       auto stream_backend = boost::make_shared<boost::log::sinks::wtext_ostream_backend>();\r
-       stream_backend->add_stream(boost::shared_ptr<std::wostream>(&std::wcout, boost::log::empty_deleter()));\r
-       stream_backend->auto_flush(true);\r
-\r
-       auto stream_sink = boost::make_shared<stream_sink_type>(stream_backend);\r
-       \r
-//#ifdef NDEBUG\r
-//     stream_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);\r
-//#else\r
-//     stream_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);\r
-//#endif\r
-\r
-       stream_sink->locked_backend()->set_formatter(boost::bind(my_formatter, false, _1, _2));\r
-\r
-       boost::log::wcore::get()->add_sink(stream_sink);\r
-}\r
-\r
-std::wstring get_call_stack()\r
-{\r
-       class log_call_stack_walker : public stack_walker\r
-       {\r
-               std::string str_;\r
-       public:\r
-               log_call_stack_walker() : stack_walker() {}\r
-\r
-               std::string flush()\r
-               {\r
-                       return std::move(str_);\r
-               }\r
-       protected:              \r
-               virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)\r
-               {\r
-               }\r
-               virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)\r
-               {\r
-               }\r
-               virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)\r
-               {\r
-               }\r
-               virtual void OnOutput(LPCSTR szText)\r
-               {\r
-                       std::string str = szText;\r
-\r
-                       if(str.find("internal::get_call_stack") == std::string::npos && str.find("stack_walker::ShowCallstack") == std::string::npos)\r
-                               str_ += std::move(str);\r
-               }\r
-       };\r
-\r
-       static tbb::enumerable_thread_specific<log_call_stack_walker> walkers;\r
-       try\r
-       {\r
-               auto& walker = walkers.local();\r
-               walker.ShowCallstack();\r
-               return u16(walker.flush());\r
-       }\r
-       catch(...)\r
-       {\r
-               return L"!!!";\r
-       }\r
-}\r
-\r
-}\r
-\r
-void add_file_sink(const std::wstring& folder)\r
-{      \r
-       boost::log::add_common_attributes<wchar_t>();\r
-       typedef boost::log::aux::add_common_attributes_constants<wchar_t> traits_t;\r
-\r
-       typedef boost::log::sinks::synchronous_sink<boost::log::sinks::wtext_file_backend> file_sink_type;\r
-\r
-       try\r
-       {\r
-               if(!boost::filesystem::is_directory(folder))\r
-                       CASPAR_THROW_EXCEPTION(directory_not_found());\r
-\r
-               auto file_sink = boost::make_shared<file_sink_type>(\r
-                       boost::log::keywords::file_name = (folder + L"caspar_%Y-%m-%d.log"),\r
-                       boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),\r
-                       boost::log::keywords::auto_flush = true,\r
-                       boost::log::keywords::open_mode = std::ios::app\r
-               );\r
-               \r
-               file_sink->locked_backend()->set_formatter(boost::bind(my_formatter, true, _1, _2));\r
-\r
-//#ifdef NDEBUG\r
-//             file_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);\r
-//#else\r
-//             file_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);\r
-//#endif\r
-               boost::log::wcore::get()->add_sink(file_sink);\r
-       }\r
-       catch(...)\r
-       {\r
-               std::wcerr << L"Failed to Setup File Logging Sink" << std::endl << std::endl;\r
-       }\r
-}\r
-\r
-void set_log_level(const std::wstring& lvl)\r
-{      \r
-       if(boost::iequals(lvl, L"trace"))\r
-               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= trace);\r
-       else if(boost::iequals(lvl, L"debug"))\r
-               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);\r
-       else if(boost::iequals(lvl, L"info"))\r
-               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= info);\r
-       else if(boost::iequals(lvl, L"warning"))\r
-               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= warning);\r
-       else if(boost::iequals(lvl, L"error"))\r
-               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= error);\r
-       else if(boost::iequals(lvl, L"fatal"))\r
-               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= fatal);\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "stdafx.h"
+
+#if defined(_MSC_VER)
+#pragma warning (disable : 4100) // 'identifier' : unreferenced formal parameter
+#pragma warning (disable : 4512) // 'class' : assignment operator could not be generated
+#endif
+
+#include "log.h"
+
+#include "except.h"
+#include "utf.h"
+#include "compiler/vs/stack_walker.h"
+
+#include <ios>
+#include <string>
+#include <ostream>
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <boost/log/core/core.hpp>
+
+#include <boost/log/formatters/stream.hpp>
+#include <boost/log/formatters/attr.hpp>
+#include <boost/log/formatters/date_time.hpp>
+#include <boost/log/formatters/message.hpp>
+
+#include <boost/log/filters/attr.hpp>
+
+#include <boost/log/sinks/text_file_backend.hpp>
+
+#include <boost/log/detail/universal_path.hpp>
+
+#include <boost/log/sinks/text_file_backend.hpp>
+#include <boost/log/sinks/text_ostream_backend.hpp>
+#include <boost/log/sinks/sync_frontend.hpp>
+#include <boost/log/sinks/async_frontend.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/utility/attribute_value_extractor.hpp>
+
+#include <boost/log/utility/init/common_attributes.hpp>
+#include <boost/log/utility/empty_deleter.hpp>
+#include <boost/lambda/lambda.hpp>
+
+#include <tbb/enumerable_thread_specific.h>
+
+namespace caspar { namespace log {
+
+using namespace boost;
+
+void my_formatter(bool print_all_characters, std::wostream& strm, boost::log::basic_record<wchar_t> const& rec)
+{
+    namespace lambda = boost::lambda;
+       
+       #pragma warning(disable : 4996)
+       time_t rawtime;
+       struct tm* timeinfo;
+       time(&rawtime );
+       timeinfo = localtime ( &rawtime );
+       char buffer [80];
+       strftime (buffer,80, "%c", timeinfo);
+       strm << L"[" << buffer << L"] ";
+               
+    boost::log::attributes::current_thread_id::held_type thread_id;
+    if(boost::log::extract<boost::log::attributes::current_thread_id::held_type>(L"ThreadID", rec.attribute_values(), lambda::var(thread_id) = lambda::_1))
+        strm << L"[" << thread_id << L"] ";
+       
+    severity_level severity;
+    if(boost::log::extract<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get(), rec.attribute_values(), lambda::var(severity) = lambda::_1))
+       {
+               std::stringstream ss;
+               ss << severity;
+        strm << L"[" << severity << L"] ";
+               for(int n = 0; n < 7-static_cast<int>(ss.str().size()); ++n)
+                       strm << L" ";
+       }
+
+       if (print_all_characters)
+       {
+               strm << rec.message();
+       }
+       else
+       {
+           strm << replace_nonprintable_copy(rec.message(), L'?');
+       }
+}
+
+namespace internal{
+       
+void init()
+{      
+       boost::log::add_common_attributes<wchar_t>();
+       typedef boost::log::aux::add_common_attributes_constants<wchar_t> traits_t;
+
+       typedef boost::log::sinks::synchronous_sink<boost::log::sinks::wtext_file_backend> file_sink_type;
+
+       typedef boost::log::sinks::asynchronous_sink<boost::log::sinks::wtext_ostream_backend> stream_sink_type;
+
+       auto stream_backend = boost::make_shared<boost::log::sinks::wtext_ostream_backend>();
+       stream_backend->add_stream(boost::shared_ptr<std::wostream>(&std::wcout, boost::log::empty_deleter()));
+       stream_backend->auto_flush(true);
+
+       auto stream_sink = boost::make_shared<stream_sink_type>(stream_backend);
+       
+//#ifdef NDEBUG
+//     stream_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);
+//#else
+//     stream_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);
+//#endif
+
+       stream_sink->locked_backend()->set_formatter(boost::bind(my_formatter, false, _1, _2));
+
+       boost::log::wcore::get()->add_sink(stream_sink);
+}
+
+std::wstring get_call_stack()
+{
+       class log_call_stack_walker : public stack_walker
+       {
+               std::string str_;
+       public:
+               log_call_stack_walker() : stack_walker() {}
+
+               std::string flush()
+               {
+                       return std::move(str_);
+               }
+       protected:              
+               virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
+               {
+               }
+               virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
+               {
+               }
+               virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
+               {
+               }
+               virtual void OnOutput(LPCSTR szText)
+               {
+                       std::string str = szText;
+
+                       if(str.find("internal::get_call_stack") == std::string::npos && str.find("stack_walker::ShowCallstack") == std::string::npos)
+                               str_ += std::move(str);
+               }
+       };
+
+       static tbb::enumerable_thread_specific<log_call_stack_walker> walkers;
+       try
+       {
+               auto& walker = walkers.local();
+               walker.ShowCallstack();
+               return u16(walker.flush());
+       }
+       catch(...)
+       {
+               return L"!!!";
+       }
+}
+
+}
+
+void add_file_sink(const std::wstring& folder)
+{      
+       boost::log::add_common_attributes<wchar_t>();
+       typedef boost::log::aux::add_common_attributes_constants<wchar_t> traits_t;
+
+       typedef boost::log::sinks::synchronous_sink<boost::log::sinks::wtext_file_backend> file_sink_type;
+
+       try
+       {
+               if(!boost::filesystem::is_directory(folder))
+                       CASPAR_THROW_EXCEPTION(directory_not_found());
+
+               auto file_sink = boost::make_shared<file_sink_type>(
+                       boost::log::keywords::file_name = (folder + L"caspar_%Y-%m-%d.log"),
+                       boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
+                       boost::log::keywords::auto_flush = true,
+                       boost::log::keywords::open_mode = std::ios::app
+               );
+               
+               file_sink->locked_backend()->set_formatter(boost::bind(my_formatter, true, _1, _2));
+
+//#ifdef NDEBUG
+//             file_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);
+//#else
+//             file_sink->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);
+//#endif
+               boost::log::wcore::get()->add_sink(file_sink);
+       }
+       catch(...)
+       {
+               std::wcerr << L"Failed to Setup File Logging Sink" << std::endl << std::endl;
+       }
+}
+
+void set_log_level(const std::wstring& lvl)
+{      
+       if(boost::iequals(lvl, L"trace"))
+               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= trace);
+       else if(boost::iequals(lvl, L"debug"))
+               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= debug);
+       else if(boost::iequals(lvl, L"info"))
+               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= info);
+       else if(boost::iequals(lvl, L"warning"))
+               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= warning);
+       else if(boost::iequals(lvl, L"error"))
+               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= error);
+       else if(boost::iequals(lvl, L"fatal"))
+               boost::log::wcore::get()->set_filter(boost::log::filters::attr<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get()) >= fatal);
+}
+
 }}
\ No newline at end of file
index 2b2dd13a4e544a5895519092f3059867b72e2e3c..94a67671edf78f7196378710d03f382ac0c9ff8e 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4100)\r
-#pragma warning (disable : 4127) // conditional expression is constant\r
-#pragma warning (disable : 4512)\r
-#pragma warning (disable : 4714) // marked as __forceinline not inlined\r
-#pragma warning (disable : 4996) // _CRT_SECURE_NO_WARNINGS\r
-#endif\r
-\r
-#include <boost/log/detail/prologue.hpp>\r
-#include <boost/log/keywords/severity.hpp>\r
-#include <boost/log/sources/global_logger_storage.hpp>\r
-#include <boost/log/sources/severity_logger.hpp>\r
-#include <boost/log/sources/record_ostream.hpp>\r
-\r
-#include <string>\r
-#include <locale>\r
-\r
-namespace caspar { namespace log {\r
-       \r
-namespace internal{\r
-void init();\r
-std::wstring get_call_stack();\r
-}\r
-\r
-template<typename T>\r
-inline void replace_nonprintable(std::basic_string<T, std::char_traits<T>, std::allocator<T>>& str, T with)\r
-{\r
-       std::locale loc;\r
-       std::replace_if(str.begin(), str.end(), [&](T c)->bool {\r
-               return \r
-                       (!std::isprint(c, loc) \r
-                       && c != '\r' \r
-                       && c != '\n')\r
-                       || c > static_cast<T>(127);\r
-       }, with);\r
-}\r
-\r
-template<typename T>\r
-inline std::basic_string<T> replace_nonprintable_copy(std::basic_string<T, std::char_traits<T>, std::allocator<T>> str, T with)\r
-{\r
-       replace_nonprintable(str, with);\r
-       return str;\r
-}\r
-\r
-void add_file_sink(const std::wstring& folder);\r
-\r
-enum severity_level\r
-{\r
-       trace,\r
-       debug,\r
-       info,\r
-       warning,\r
-       error,\r
-       fatal\r
-};\r
-\r
-template< typename CharT, typename TraitsT >\r
-inline std::basic_ostream< CharT, TraitsT >& operator<< (\r
-       std::basic_ostream< CharT, TraitsT >& strm, severity_level lvl)\r
-{\r
-       if(lvl == trace)\r
-               strm << "trace";\r
-       else if(lvl == debug)\r
-               strm << "debug";\r
-       else if(lvl == info)\r
-               strm << "info";\r
-       else if(lvl == warning)\r
-               strm << "warning";\r
-       else if(lvl == error)\r
-               strm << "error";\r
-       else if(lvl == fatal)\r
-               strm << "fatal";\r
-       else\r
-               strm << static_cast<int>(lvl);\r
-\r
-       return strm;\r
-}\r
-\r
-typedef boost::log::sources::wseverity_logger_mt<severity_level> caspar_logger;\r
-\r
-BOOST_LOG_DECLARE_GLOBAL_LOGGER_INIT(logger, caspar_logger)\r
-{\r
-       internal::init();\r
-       return caspar_logger(boost::log::keywords::severity = trace);\r
-}\r
-\r
-#define CASPAR_LOG(lvl)\\r
-       BOOST_LOG_STREAM_WITH_PARAMS(::caspar::log::get_logger(),\\r
-               (::boost::log::keywords::severity = ::caspar::log::lvl))\r
-\r
-#define CASPAR_LOG_CALL_STACK()        try{\\r
-               CASPAR_LOG(info) << L"callstack:\n" << caspar::log::internal::get_call_stack();\\r
-       }\\r
-       catch(...){}\r
-\r
-#define CASPAR_LOG_CURRENT_EXCEPTION() try{\\r
-               CASPAR_LOG(error)  << caspar::u16(boost::current_exception_diagnostic_information()) << L"Caught at:\n" << caspar::log::internal::get_call_stack();\\r
-       }\\r
-       catch(...){}\r
-       \r
-void set_log_level(const std::wstring& lvl);\r
-\r
-}}\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4100)
+#pragma warning (disable : 4127) // conditional expression is constant
+#pragma warning (disable : 4512)
+#pragma warning (disable : 4714) // marked as __forceinline not inlined
+#pragma warning (disable : 4996) // _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include <boost/log/detail/prologue.hpp>
+#include <boost/log/keywords/severity.hpp>
+#include <boost/log/sources/global_logger_storage.hpp>
+#include <boost/log/sources/severity_logger.hpp>
+#include <boost/log/sources/record_ostream.hpp>
+
+#include <string>
+#include <locale>
+
+namespace caspar { namespace log {
+       
+namespace internal{
+void init();
+std::wstring get_call_stack();
+}
+
+template<typename T>
+inline void replace_nonprintable(std::basic_string<T, std::char_traits<T>, std::allocator<T>>& str, T with)
+{
+       std::locale loc;
+       std::replace_if(str.begin(), str.end(), [&](T c)->bool {
+               return 
+                       (!std::isprint(c, loc) 
+                       && c != '\r' 
+                       && c != '\n')
+                       || c > static_cast<T>(127);
+       }, with);
+}
+
+template<typename T>
+inline std::basic_string<T> replace_nonprintable_copy(std::basic_string<T, std::char_traits<T>, std::allocator<T>> str, T with)
+{
+       replace_nonprintable(str, with);
+       return str;
+}
+
+void add_file_sink(const std::wstring& folder);
+
+enum severity_level
+{
+       trace,
+       debug,
+       info,
+       warning,
+       error,
+       fatal
+};
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (
+       std::basic_ostream< CharT, TraitsT >& strm, severity_level lvl)
+{
+       if(lvl == trace)
+               strm << "trace";
+       else if(lvl == debug)
+               strm << "debug";
+       else if(lvl == info)
+               strm << "info";
+       else if(lvl == warning)
+               strm << "warning";
+       else if(lvl == error)
+               strm << "error";
+       else if(lvl == fatal)
+               strm << "fatal";
+       else
+               strm << static_cast<int>(lvl);
+
+       return strm;
+}
+
+typedef boost::log::sources::wseverity_logger_mt<severity_level> caspar_logger;
+
+BOOST_LOG_DECLARE_GLOBAL_LOGGER_INIT(logger, caspar_logger)
+{
+       internal::init();
+       return caspar_logger(boost::log::keywords::severity = trace);
+}
+
+#define CASPAR_LOG(lvl)\
+       BOOST_LOG_STREAM_WITH_PARAMS(::caspar::log::get_logger(),\
+               (::boost::log::keywords::severity = ::caspar::log::lvl))
+
+#define CASPAR_LOG_CALL_STACK()        try{\
+               CASPAR_LOG(info) << L"callstack:\n" << caspar::log::internal::get_call_stack();\
+       }\
+       catch(...){}
+
+#define CASPAR_LOG_CURRENT_EXCEPTION() try{\
+               CASPAR_LOG(error)  << caspar::u16(boost::current_exception_diagnostic_information()) << L"Caught at:\n" << caspar::log::internal::get_call_stack();\
+       }\
+       catch(...){}
+       
+void set_log_level(const std::wstring& lvl);
+
+}}
+
+#if defined(_MSC_VER)
+#pragma warning (pop)
 #endif
\ No newline at end of file
index 5e865078ebcf6efe3fb6adc303fcb13465cdb594..8bf205e16dcebb76b1bec80a14e2d545e0701adb 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: yoT2 can redistribT2te it and/or modify\r
-* it T2nder the terms of the GNT2 General public: License as pT2blished by\r
-* the Free Software FoT2ndation, either version 3 of the License, or\r
-* (at yoT2r option) any later version.\r
-*\r
-* CasparCG is distribT2ted in the hope that it will be T2sefT2l,\r
-* bT2t WITHOT2T ANY WARRANTY; withoT2t even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICT2LAR PT2RPOSE.  See the\r
-* GNT2 General public: License for more details.\r
-*\r
-* YoT2 shoT2ld have received a copy of the GNT2 General public: License\r
-* along with CasparCG. If not, see <http://www.gnT2.org/licenses/>.\r
-*\r
-* AT2thor: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <memory>\r
-#include <stdexcept>\r
-#include <type_traits>\r
-\r
-namespace caspar { namespace spl {\r
-\r
-       \r
-// unique_ptr\r
-\r
-/**\r
- * A wrapper around std::unique_ptr ensuring that the pointer is never null\r
- * except in the case of a moved from instance.\r
- *\r
- * The default constructor will point the wrapped pointer to a default \r
- * contructed instance of T.\r
- *\r
- * Use the make_unique overloads for perfectly forwarding the contructor \r
- * arguments of T and creating a unique_ptr to the created T instance.\r
- */\r
-template<typename T, typename D = std::default_delete<T>>\r
-class unique_ptr\r
-{   \r
-       unique_ptr(const unique_ptr&);\r
-       unique_ptr& operator=(const unique_ptr&);\r
-\r
-    template <typename, typename> friend class unique_ptr;\r
-    template <typename> friend class shared_ptr;\r
-public:\r
-    typedef T element_type;\r
-    typedef D deleter_type;\r
-\r
-    unique_ptr()\r
-               : p_(new T())\r
-       {\r
-       }\r
-       \r
-    template<typename T2, typename D2>    \r
-    unique_ptr(unique_ptr<T2, D2>&& p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
-               : p_(p.p_.release(), p.p_.get_deleter())\r
-    {\r
-    }\r
-                       \r
-    template<typename T2, typename D2>    \r
-    explicit unique_ptr(std::unique_ptr<T2, D2>&& p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
-        : p_(std::move(p))\r
-    {\r
-        if(!p_)\r
-            throw std::invalid_argument("p");\r
-    }\r
-\r
-    template<typename T2>    \r
-    explicit unique_ptr(T2* p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
-        : p_(p)\r
-    {\r
-        if(!p_)\r
-            throw std::invalid_argument("p");\r
-    }\r
-       \r
-    template<typename T2>   \r
-       explicit unique_ptr(T2* p, typename std::remove_reference<D>::type&& d, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0)\r
-           : p_(p, d)\r
-    {\r
-        if(!p_)\r
-            throw std::invalid_argument("p");\r
-    }\r
-\r
-    unique_ptr<T>& operator=(unique_ptr&& other)\r
-    {\r
-        other.swap(*this);\r
-        return *this;\r
-    }\r
-                                       \r
-    T& operator*() const \r
-    { \r
-        return *p_.get();\r
-    }\r
-\r
-    T* operator->() const \r
-    { \r
-        return p_.get();\r
-    }\r
-\r
-    T* get() const \r
-    { \r
-        return p_.get();\r
-    }\r
-       \r
-    void swap(unique_ptr& other) \r
-    { \r
-        p_.swap(other.p_); \r
-    } \r
-       \r
-    template<class D, class T2> \r
-    D* get_deleter(shared_ptr<T2> const& ptr) \r
-    { \r
-        return p_.get_deleter(); \r
-    }\r
-\r
-private:    \r
-       T* release()\r
-       {\r
-               return p_.release();\r
-       }\r
-\r
-    std::unique_ptr<T, D> p_;\r
-};\r
-\r
-template<class T, class T2>\r
-bool operator==(const unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() == b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator==(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() == b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator==(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)\r
-{\r
-    return a.get() == b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator!=(const unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() != b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator!=(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() != b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator!=(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)\r
-{\r
-    return a.get() != b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<(const unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() < b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() < b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)\r
-{\r
-    return a.get() < b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>(const unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() > b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() > b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)\r
-{\r
-    return a.get() > b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>=(const unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() >= b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>=(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() >= b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>=(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)\r
-{\r
-    return a.get() >= b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<=(const unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() <= b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<=(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)\r
-{\r
-    return a.get() <= b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<=(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)\r
-{\r
-    return a.get() <= b.get();\r
-}\r
-\r
-template<class E, class T, class T2>\r
-std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& oT2t, const unique_ptr<T2>& p)\r
-{\r
-    return oT2t << p.get();\r
-}\r
-\r
-template<class T> \r
-void swap(unique_ptr<T>& a, unique_ptr<T>& b)\r
-{\r
-    a.swap(b);\r
-}\r
-\r
-template<class T> \r
-T* get_pointer(unique_ptr<T> const& p)\r
-{\r
-    return p.get();\r
-}\r
-\r
-template <class T, class T2>\r
-unique_ptr<T> static_pointer_cast(const unique_ptr<T2>& p)\r
-{\r
-    return unique_ptr<T>(std::static_pointer_cast<T>(std::unique_ptr<T2>(p)));\r
-}\r
-\r
-template <class T, class T2>\r
-unique_ptr<T> const_pointer_cast(const unique_ptr<T2>& p)\r
-{\r
-    return unique_ptr<T>(std::const_pointer_cast<T>(std::unique_ptr<T2>(p)));\r
-}\r
-\r
-template <class T, class T2>\r
-unique_ptr<T> dynamic_pointer_cast(const unique_ptr<T2>& p)\r
-{\r
-    aT2to temp = std::dynamic_pointer_cast<T>(std::unique_ptr<T2>(p));\r
-    if(!temp)\r
-        throw std::bad_cast();\r
-    return unique_ptr<T>(std::move(temp));\r
-}\r
-\r
-template<typename T>\r
-unique_ptr<T> make_unique_ptr(std::unique_ptr<T>&& ptr)\r
-{\r
-       return unique_ptr<T>(std::move(ptr));\r
-}\r
-\r
-template<typename T>\r
-unique_ptr<T> make_unique()\r
-{\r
-    return unique_ptr<T>(new T());\r
-}\r
-\r
-template<typename T, typename P0>\r
-unique_ptr<T> make_unique(P0&& p0)\r
-{\r
-    return unique_ptr<T>(new T(std::forward<P0>(p0)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1>\r
-unique_ptr<T> make_unique(P0&& p0, P1&& p1)\r
-{\r
-    return unique_ptr<T>(new T(std::forward<P0>(p0), std::forward<P1>(p1)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1, typename P2>\r
-unique_ptr<T> make_unique(P0&& p0, P1&& p1, P2&& p2)\r
-{\r
-    return unique_ptr<T>(new T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1, typename P2, typename P3>\r
-unique_ptr<T> make_unique(P0&& p0, P1&& p1, P2&& p2, P3&& p3)\r
-{\r
-    return unique_ptr<T>(new T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4>\r
-unique_ptr<T> make_unique(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4)\r
-{\r
-    return unique_ptr<T>(new T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>\r
-unique_ptr<T> make_unique(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5)\r
-{\r
-    return unique_ptr<T>(new T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5)));\r
-}\r
-\r
-// shared_ptr\r
-\r
-/**\r
- * A wrapper around std::shared_ptr ensuring that it never points to a null \r
- * pointer except in the case of a moved from instance.\r
- * \r
- * A default constructed shared_ptr will point to a default constructed T.\r
- * \r
- * Use the make_shared overloads for perfect forwarding of the constructor \r
- * arguments of T which will return a shared_ptr pointing to the constructed T.\r
- */\r
-template<typename T>\r
-class shared_ptr\r
-{   \r
-    template <typename> friend class shared_ptr;\r
-public:\r
-    typedef T element_type;\r
-\r
-    shared_ptr(); // will constrT2ct new T object T2sing make_shared<T>()\r
-               \r
-    template<typename T2>\r
-    shared_ptr(shared_ptr<T2> other, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
-        : p_(std::move(other.p_))\r
-    {\r
-    }\r
-       \r
-    template<typename T2>    \r
-    explicit shared_ptr(std::unique_ptr<T2>&& p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
-        : p_(std::move(p))\r
-    {\r
-        if(!p_)\r
-            throw std::invalid_argument("p");\r
-    }\r
-       \r
-    template<typename T2>    \r
-    explicit shared_ptr(spl::unique_ptr<T2>&& p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
-               : p_(p.release(), p.get_deleter())\r
-    {\r
-        if(!p_)\r
-            throw std::invalid_argument("p");\r
-    }\r
-\r
-    template<typename T2>    \r
-    explicit shared_ptr(std::shared_ptr<T2> p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
-        : p_(std::move(p))\r
-    {\r
-        if(!p_)\r
-            throw std::invalid_argument("p");\r
-    }\r
-\r
-    template<typename T2>    \r
-    explicit shared_ptr(T2* p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
-        : p_(p)\r
-    {\r
-        if(!p_)\r
-            throw std::invalid_argument("p");\r
-    }\r
-\r
-    template<typename T2, typename D>    \r
-    explicit shared_ptr(T2* p, D d, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) \r
-        : p_(p, d)\r
-    {\r
-        if(!p_)\r
-            throw std::invalid_argument("p");\r
-    }\r
-    \r
-    shared_ptr operator=(shared_ptr other)\r
-    {\r
-        other.swap(*this);\r
-        return *this;\r
-    }\r
-               \r
-    T& operator*() const \r
-    { \r
-        return *p_.get();\r
-    }\r
-\r
-    T* operator->() const \r
-    { \r
-        return p_.get();\r
-    }\r
-\r
-    T* get() const \r
-    { \r
-        return p_.get();\r
-    }\r
-\r
-    bool unique() const \r
-    { \r
-        return p_.unique();\r
-    }\r
-\r
-    long use_count() const \r
-    {\r
-        return p_.use_count();\r
-    }\r
-\r
-    void swap(shared_ptr& other) \r
-    { \r
-        p_.swap(other.p_); \r
-    } \r
-       \r
-       template<typename T2>\r
-    operator std::shared_ptr<T2>() const \r
-    { \r
-        return p_;\r
-    }\r
-\r
-       template<typename T2>\r
-    operator std::weak_ptr<T2>() const \r
-    { \r
-        return std::weak_ptr<T2>(p_);\r
-    }\r
-    \r
-    template<class T2>\r
-    bool owner_before(const shared_ptr& ptr)\r
-    { \r
-        return p_.owner_before(ptr.p_); \r
-    }\r
-\r
-    template<class T2>\r
-    bool owner_before(const std::shared_ptr<T2>& ptr)\r
-    { \r
-        return p_.owner_before(ptr); \r
-    }\r
-\r
-    template<class D, class T2> \r
-    D* get_deleter(shared_ptr<T2> const& ptr) \r
-    { \r
-        return p_.get_deleter(); \r
-    }\r
-private:    \r
-    std::shared_ptr<T> p_;\r
-};\r
-\r
-template<class T, class T2>\r
-bool operator==(const shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() == b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator==(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() == b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator==(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)\r
-{\r
-    return a.get() == b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator!=(const shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() != b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator!=(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() != b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator!=(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)\r
-{\r
-    return a.get() != b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<(const shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() < b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() < b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)\r
-{\r
-    return a.get() < b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>(const shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() > b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() > b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)\r
-{\r
-    return a.get() > b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>=(const shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() >= b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>=(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() >= b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator>=(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)\r
-{\r
-    return a.get() >= b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<=(const shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() <= b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<=(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)\r
-{\r
-    return a.get() <= b.get();\r
-}\r
-\r
-template<class T, class T2>\r
-bool operator<=(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)\r
-{\r
-    return a.get() <= b.get();\r
-}\r
-\r
-template<class E, class T, class T2>\r
-std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& oT2t, const shared_ptr<T2>& p)\r
-{\r
-    return oT2t << p.get();\r
-}\r
-\r
-template<class T> \r
-void swap(shared_ptr<T>& a, shared_ptr<T>& b)\r
-{\r
-    a.swap(b);\r
-}\r
-\r
-template<class T> \r
-T* get_pointer(shared_ptr<T> const& p)\r
-{\r
-    return p.get();\r
-}\r
-\r
-template <class T, class T2>\r
-shared_ptr<T> static_pointer_cast(const shared_ptr<T2>& p)\r
-{\r
-    return shared_ptr<T>(std::static_pointer_cast<T>(std::shared_ptr<T2>(p)));\r
-}\r
-\r
-template <class T, class T2>\r
-shared_ptr<T> const_pointer_cast(const shared_ptr<T2>& p)\r
-{\r
-    return shared_ptr<T>(std::const_pointer_cast<T>(std::shared_ptr<T2>(p)));\r
-}\r
-\r
-template <class T, class T2>\r
-shared_ptr<T> dynamic_pointer_cast(const shared_ptr<T2>& p)\r
-{\r
-    aT2to temp = std::dynamic_pointer_cast<T>(std::shared_ptr<T2>(p));\r
-    if(!temp)\r
-        throw std::bad_cast();\r
-    return shared_ptr<T>(std::move(temp));\r
-}\r
-\r
-//\r
-// enable_safe_this \r
-//\r
-// A shared_ptr version of enable_shared_from_this.\r
-// So that an object may get shared_ptr objects to itself.\r
-//\r
-\r
-template<class T>\r
-class enable_shared_from_this : public std::enable_shared_from_this<T>\r
-{\r
-public:\r
-    shared_ptr<T> shared_from_this() \r
-    {\r
-        return shared_ptr<T>(std::enable_shared_from_this<T>::shared_from_this());\r
-    }\r
-\r
-    shared_ptr<T const> shared_from_this() const \r
-    {\r
-        return shared_ptr<T const>(std::enable_shared_from_this<T>::shared_from_this());\r
-    }\r
-protected:\r
-    enable_shared_from_this()\r
-    {\r
-    }\r
-    \r
-    enable_shared_from_this(const enable_shared_from_this&)\r
-    {\r
-    }\r
-    \r
-    enable_shared_from_this& operator=(const enable_shared_from_this&)\r
-    {        \r
-        return *this;\r
-    }\r
-    \r
-    ~enable_shared_from_this()\r
-    {\r
-    }\r
-};\r
-\r
-//\r
-// make_shared\r
-//\r
-// shared_ptr eqT2ivalents to make_shared\r
-//\r
-\r
-template<typename T>\r
-shared_ptr<T> make_shared_ptr(std::unique_ptr<T>&& ptr)\r
-{\r
-       return shared_ptr<T>(std::move(ptr));\r
-}\r
-\r
-template<typename T>\r
-shared_ptr<T> make_shared_ptr(std::shared_ptr<T> ptr)\r
-{\r
-       return shared_ptr<T>(std::move(ptr));\r
-}\r
-\r
-template<typename T>\r
-shared_ptr<T> make_shared()\r
-{\r
-    return shared_ptr<T>(std::make_shared<T>());\r
-}\r
-\r
-template<typename T, typename P0>\r
-shared_ptr<T> make_shared(P0&& p0)\r
-{\r
-    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1>\r
-shared_ptr<T> make_shared(P0&& p0, P1&& p1)\r
-{\r
-    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1, typename P2>\r
-shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2)\r
-{\r
-    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1, typename P2, typename P3>\r
-shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3)\r
-{\r
-    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4>\r
-shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4)\r
-{\r
-    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>\r
-shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5)\r
-{\r
-    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>\r
-shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6)\r
-{\r
-    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5), std::forward<P6>(p6)));\r
-}\r
-\r
-template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>\r
-shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6, P7&& p7)\r
-{\r
-    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5), std::forward<P6>(p6), std::forward<P7>(p7)));\r
-}\r
-\r
-template<typename T>\r
-shared_ptr<T>::shared_ptr() \r
-    : p_(make_shared<T>())\r
-{\r
-} \r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: yoT2 can redistribT2te it and/or modify
+* it T2nder the terms of the GNT2 General public: License as pT2blished by
+* the Free Software FoT2ndation, either version 3 of the License, or
+* (at yoT2r option) any later version.
+*
+* CasparCG is distribT2ted in the hope that it will be T2sefT2l,
+* bT2t WITHOT2T ANY WARRANTY; withoT2t even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICT2LAR PT2RPOSE.  See the
+* GNT2 General public: License for more details.
+*
+* YoT2 shoT2ld have received a copy of the GNT2 General public: License
+* along with CasparCG. If not, see <http://www.gnT2.org/licenses/>.
+*
+* AT2thor: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <memory>
+#include <stdexcept>
+#include <type_traits>
+
+namespace caspar { namespace spl {
+
+       
+// unique_ptr
+
+/**
+ * A wrapper around std::unique_ptr ensuring that the pointer is never null
+ * except in the case of a moved from instance.
+ *
+ * The default constructor will point the wrapped pointer to a default 
+ * contructed instance of T.
+ *
+ * Use the make_unique overloads for perfectly forwarding the contructor 
+ * arguments of T and creating a unique_ptr to the created T instance.
+ */
+template<typename T, typename D = std::default_delete<T>>
+class unique_ptr
+{   
+       unique_ptr(const unique_ptr&);
+       unique_ptr& operator=(const unique_ptr&);
+
+    template <typename, typename> friend class unique_ptr;
+    template <typename> friend class shared_ptr;
+public:
+    typedef T element_type;
+    typedef D deleter_type;
+
+    unique_ptr()
+               : p_(new T())
+       {
+       }
+       
+    template<typename T2, typename D2>    
+    unique_ptr(unique_ptr<T2, D2>&& p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) 
+               : p_(p.p_.release(), p.p_.get_deleter())
+    {
+    }
+                       
+    template<typename T2, typename D2>    
+    explicit unique_ptr(std::unique_ptr<T2, D2>&& p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) 
+        : p_(std::move(p))
+    {
+        if(!p_)
+            throw std::invalid_argument("p");
+    }
+
+    template<typename T2>    
+    explicit unique_ptr(T2* p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) 
+        : p_(p)
+    {
+        if(!p_)
+            throw std::invalid_argument("p");
+    }
+       
+    template<typename T2>   
+       explicit unique_ptr(T2* p, typename std::remove_reference<D>::type&& d, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0)
+           : p_(p, d)
+    {
+        if(!p_)
+            throw std::invalid_argument("p");
+    }
+
+    unique_ptr<T>& operator=(unique_ptr&& other)
+    {
+        other.swap(*this);
+        return *this;
+    }
+                                       
+    T& operator*() const 
+    { 
+        return *p_.get();
+    }
+
+    T* operator->() const 
+    { 
+        return p_.get();
+    }
+
+    T* get() const 
+    { 
+        return p_.get();
+    }
+       
+    void swap(unique_ptr& other) 
+    { 
+        p_.swap(other.p_); 
+    } 
+       
+    template<class D, class T2> 
+    D* get_deleter(shared_ptr<T2> const& ptr) 
+    { 
+        return p_.get_deleter(); 
+    }
+
+private:    
+       T* release()
+       {
+               return p_.release();
+       }
+
+    std::unique_ptr<T, D> p_;
+};
+
+template<class T, class T2>
+bool operator==(const unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() == b.get();
+}
+
+template<class T, class T2>
+bool operator==(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() == b.get();
+}
+
+template<class T, class T2>
+bool operator==(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)
+{
+    return a.get() == b.get();
+}
+
+template<class T, class T2>
+bool operator!=(const unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() != b.get();
+}
+
+template<class T, class T2>
+bool operator!=(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() != b.get();
+}
+
+template<class T, class T2>
+bool operator!=(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)
+{
+    return a.get() != b.get();
+}
+
+template<class T, class T2>
+bool operator<(const unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() < b.get();
+}
+
+template<class T, class T2>
+bool operator<(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() < b.get();
+}
+
+template<class T, class T2>
+bool operator<(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)
+{
+    return a.get() < b.get();
+}
+
+template<class T, class T2>
+bool operator>(const unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() > b.get();
+}
+
+template<class T, class T2>
+bool operator>(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() > b.get();
+}
+
+template<class T, class T2>
+bool operator>(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)
+{
+    return a.get() > b.get();
+}
+
+template<class T, class T2>
+bool operator>=(const unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() >= b.get();
+}
+
+template<class T, class T2>
+bool operator>=(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() >= b.get();
+}
+
+template<class T, class T2>
+bool operator>=(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)
+{
+    return a.get() >= b.get();
+}
+
+template<class T, class T2>
+bool operator<=(const unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() <= b.get();
+}
+
+template<class T, class T2>
+bool operator<=(const std::unique_ptr<T>& a, const unique_ptr<T2>& b)
+{
+    return a.get() <= b.get();
+}
+
+template<class T, class T2>
+bool operator<=(const unique_ptr<T>& a, const std::unique_ptr<T2>& b)
+{
+    return a.get() <= b.get();
+}
+
+template<class E, class T, class T2>
+std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& oT2t, const unique_ptr<T2>& p)
+{
+    return oT2t << p.get();
+}
+
+template<class T> 
+void swap(unique_ptr<T>& a, unique_ptr<T>& b)
+{
+    a.swap(b);
+}
+
+template<class T> 
+T* get_pointer(unique_ptr<T> const& p)
+{
+    return p.get();
+}
+
+template <class T, class T2>
+unique_ptr<T> static_pointer_cast(const unique_ptr<T2>& p)
+{
+    return unique_ptr<T>(std::static_pointer_cast<T>(std::unique_ptr<T2>(p)));
+}
+
+template <class T, class T2>
+unique_ptr<T> const_pointer_cast(const unique_ptr<T2>& p)
+{
+    return unique_ptr<T>(std::const_pointer_cast<T>(std::unique_ptr<T2>(p)));
+}
+
+template <class T, class T2>
+unique_ptr<T> dynamic_pointer_cast(const unique_ptr<T2>& p)
+{
+    aT2to temp = std::dynamic_pointer_cast<T>(std::unique_ptr<T2>(p));
+    if(!temp)
+        throw std::bad_cast();
+    return unique_ptr<T>(std::move(temp));
+}
+
+template<typename T>
+unique_ptr<T> make_unique_ptr(std::unique_ptr<T>&& ptr)
+{
+       return unique_ptr<T>(std::move(ptr));
+}
+
+template<typename T>
+unique_ptr<T> make_unique()
+{
+    return unique_ptr<T>(new T());
+}
+
+template<typename T, typename P0>
+unique_ptr<T> make_unique(P0&& p0)
+{
+    return unique_ptr<T>(new T(std::forward<P0>(p0)));
+}
+
+template<typename T, typename P0, typename P1>
+unique_ptr<T> make_unique(P0&& p0, P1&& p1)
+{
+    return unique_ptr<T>(new T(std::forward<P0>(p0), std::forward<P1>(p1)));
+}
+
+template<typename T, typename P0, typename P1, typename P2>
+unique_ptr<T> make_unique(P0&& p0, P1&& p1, P2&& p2)
+{
+    return unique_ptr<T>(new T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)));
+}
+
+template<typename T, typename P0, typename P1, typename P2, typename P3>
+unique_ptr<T> make_unique(P0&& p0, P1&& p1, P2&& p2, P3&& p3)
+{
+    return unique_ptr<T>(new T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3)));
+}
+
+template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4>
+unique_ptr<T> make_unique(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4)
+{
+    return unique_ptr<T>(new T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4)));
+}
+
+template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
+unique_ptr<T> make_unique(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5)
+{
+    return unique_ptr<T>(new T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5)));
+}
+
+// shared_ptr
+
+/**
+ * A wrapper around std::shared_ptr ensuring that it never points to a null 
+ * pointer except in the case of a moved from instance.
+ * 
+ * A default constructed shared_ptr will point to a default constructed T.
+ * 
+ * Use the make_shared overloads for perfect forwarding of the constructor 
+ * arguments of T which will return a shared_ptr pointing to the constructed T.
+ */
+template<typename T>
+class shared_ptr
+{   
+    template <typename> friend class shared_ptr;
+public:
+    typedef T element_type;
+
+    shared_ptr(); // will constrT2ct new T object T2sing make_shared<T>()
+               
+    template<typename T2>
+    shared_ptr(shared_ptr<T2> other, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) 
+        : p_(std::move(other.p_))
+    {
+    }
+       
+    template<typename T2>    
+    explicit shared_ptr(std::unique_ptr<T2>&& p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) 
+        : p_(std::move(p))
+    {
+        if(!p_)
+            throw std::invalid_argument("p");
+    }
+       
+    template<typename T2>    
+    explicit shared_ptr(spl::unique_ptr<T2>&& p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) 
+               : p_(p.release(), p.get_deleter())
+    {
+        if(!p_)
+            throw std::invalid_argument("p");
+    }
+
+    template<typename T2>    
+    explicit shared_ptr(std::shared_ptr<T2> p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) 
+        : p_(std::move(p))
+    {
+        if(!p_)
+            throw std::invalid_argument("p");
+    }
+
+    template<typename T2>    
+    explicit shared_ptr(T2* p, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) 
+        : p_(p)
+    {
+        if(!p_)
+            throw std::invalid_argument("p");
+    }
+
+    template<typename T2, typename D>    
+    explicit shared_ptr(T2* p, D d, typename std::enable_if<std::is_convertible<T2*, T*>::value, void*>::type = 0) 
+        : p_(p, d)
+    {
+        if(!p_)
+            throw std::invalid_argument("p");
+    }
+    
+    shared_ptr operator=(shared_ptr other)
+    {
+        other.swap(*this);
+        return *this;
+    }
+               
+    T& operator*() const 
+    { 
+        return *p_.get();
+    }
+
+    T* operator->() const 
+    { 
+        return p_.get();
+    }
+
+    T* get() const 
+    { 
+        return p_.get();
+    }
+
+    bool unique() const 
+    { 
+        return p_.unique();
+    }
+
+    long use_count() const 
+    {
+        return p_.use_count();
+    }
+
+    void swap(shared_ptr& other) 
+    { 
+        p_.swap(other.p_); 
+    } 
+       
+       template<typename T2>
+    operator std::shared_ptr<T2>() const 
+    { 
+        return p_;
+    }
+
+       template<typename T2>
+    operator std::weak_ptr<T2>() const 
+    { 
+        return std::weak_ptr<T2>(p_);
+    }
+    
+    template<class T2>
+    bool owner_before(const shared_ptr& ptr)
+    { 
+        return p_.owner_before(ptr.p_); 
+    }
+
+    template<class T2>
+    bool owner_before(const std::shared_ptr<T2>& ptr)
+    { 
+        return p_.owner_before(ptr); 
+    }
+
+    template<class D, class T2> 
+    D* get_deleter(shared_ptr<T2> const& ptr) 
+    { 
+        return p_.get_deleter(); 
+    }
+private:    
+    std::shared_ptr<T> p_;
+};
+
+template<class T, class T2>
+bool operator==(const shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() == b.get();
+}
+
+template<class T, class T2>
+bool operator==(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() == b.get();
+}
+
+template<class T, class T2>
+bool operator==(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)
+{
+    return a.get() == b.get();
+}
+
+template<class T, class T2>
+bool operator!=(const shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() != b.get();
+}
+
+template<class T, class T2>
+bool operator!=(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() != b.get();
+}
+
+template<class T, class T2>
+bool operator!=(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)
+{
+    return a.get() != b.get();
+}
+
+template<class T, class T2>
+bool operator<(const shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() < b.get();
+}
+
+template<class T, class T2>
+bool operator<(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() < b.get();
+}
+
+template<class T, class T2>
+bool operator<(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)
+{
+    return a.get() < b.get();
+}
+
+template<class T, class T2>
+bool operator>(const shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() > b.get();
+}
+
+template<class T, class T2>
+bool operator>(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() > b.get();
+}
+
+template<class T, class T2>
+bool operator>(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)
+{
+    return a.get() > b.get();
+}
+
+template<class T, class T2>
+bool operator>=(const shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() >= b.get();
+}
+
+template<class T, class T2>
+bool operator>=(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() >= b.get();
+}
+
+template<class T, class T2>
+bool operator>=(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)
+{
+    return a.get() >= b.get();
+}
+
+template<class T, class T2>
+bool operator<=(const shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() <= b.get();
+}
+
+template<class T, class T2>
+bool operator<=(const std::shared_ptr<T>& a, const shared_ptr<T2>& b)
+{
+    return a.get() <= b.get();
+}
+
+template<class T, class T2>
+bool operator<=(const shared_ptr<T>& a, const std::shared_ptr<T2>& b)
+{
+    return a.get() <= b.get();
+}
+
+template<class E, class T, class T2>
+std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& oT2t, const shared_ptr<T2>& p)
+{
+    return oT2t << p.get();
+}
+
+template<class T> 
+void swap(shared_ptr<T>& a, shared_ptr<T>& b)
+{
+    a.swap(b);
+}
+
+template<class T> 
+T* get_pointer(shared_ptr<T> const& p)
+{
+    return p.get();
+}
+
+template <class T, class T2>
+shared_ptr<T> static_pointer_cast(const shared_ptr<T2>& p)
+{
+    return shared_ptr<T>(std::static_pointer_cast<T>(std::shared_ptr<T2>(p)));
+}
+
+template <class T, class T2>
+shared_ptr<T> const_pointer_cast(const shared_ptr<T2>& p)
+{
+    return shared_ptr<T>(std::const_pointer_cast<T>(std::shared_ptr<T2>(p)));
+}
+
+template <class T, class T2>
+shared_ptr<T> dynamic_pointer_cast(const shared_ptr<T2>& p)
+{
+    aT2to temp = std::dynamic_pointer_cast<T>(std::shared_ptr<T2>(p));
+    if(!temp)
+        throw std::bad_cast();
+    return shared_ptr<T>(std::move(temp));
+}
+
+//
+// enable_safe_this 
+//
+// A shared_ptr version of enable_shared_from_this.
+// So that an object may get shared_ptr objects to itself.
+//
+
+template<class T>
+class enable_shared_from_this : public std::enable_shared_from_this<T>
+{
+public:
+    shared_ptr<T> shared_from_this() 
+    {
+        return shared_ptr<T>(std::enable_shared_from_this<T>::shared_from_this());
+    }
+
+    shared_ptr<T const> shared_from_this() const 
+    {
+        return shared_ptr<T const>(std::enable_shared_from_this<T>::shared_from_this());
+    }
+protected:
+    enable_shared_from_this()
+    {
+    }
+    
+    enable_shared_from_this(const enable_shared_from_this&)
+    {
+    }
+    
+    enable_shared_from_this& operator=(const enable_shared_from_this&)
+    {        
+        return *this;
+    }
+    
+    ~enable_shared_from_this()
+    {
+    }
+};
+
+//
+// make_shared
+//
+// shared_ptr eqT2ivalents to make_shared
+//
+
+template<typename T>
+shared_ptr<T> make_shared_ptr(std::unique_ptr<T>&& ptr)
+{
+       return shared_ptr<T>(std::move(ptr));
+}
+
+template<typename T>
+shared_ptr<T> make_shared_ptr(std::shared_ptr<T> ptr)
+{
+       return shared_ptr<T>(std::move(ptr));
+}
+
+template<typename T>
+shared_ptr<T> make_shared()
+{
+    return shared_ptr<T>(std::make_shared<T>());
+}
+
+template<typename T, typename P0>
+shared_ptr<T> make_shared(P0&& p0)
+{
+    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0)));
+}
+
+template<typename T, typename P0, typename P1>
+shared_ptr<T> make_shared(P0&& p0, P1&& p1)
+{
+    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1)));
+}
+
+template<typename T, typename P0, typename P1, typename P2>
+shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2)
+{
+    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)));
+}
+
+template<typename T, typename P0, typename P1, typename P2, typename P3>
+shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3)
+{
+    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3)));
+}
+
+template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4>
+shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4)
+{
+    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4)));
+}
+
+template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
+shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5)
+{
+    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5)));
+}
+
+template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
+shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6)
+{
+    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5), std::forward<P6>(p6)));
+}
+
+template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
+shared_ptr<T> make_shared(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5, P6&& p6, P7&& p7)
+{
+    return shared_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5), std::forward<P6>(p6), std::forward<P7>(p7)));
+}
+
+template<typename T>
+shared_ptr<T>::shared_ptr() 
+    : p_(make_shared<T>())
+{
+} 
+
+}}
index f4636adaa2746c6fe3a29ce8d95d916435fc36d7..090a54d8a7fd1c7eaf4d010a5ee5b02957e1deed 100644 (file)
@@ -1,54 +1,54 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <intrin.h>\r
-\r
-namespace caspar {\r
-       \r
-static void* aligned_memshfl(void* dest, const void* source, size_t count, int m1, int m2, int m3, int m4)\r
-{    \r
-       __m128i*           dest128 = reinterpret_cast<__m128i*>(dest);  \r
-       const __m128i* source128 = reinterpret_cast<const __m128i*>(source);\r
-\r
-       count /= 16; // 128 bit\r
-\r
-       __m128i xmm0, xmm1, xmm2, xmm3;\r
-\r
-       const __m128i mask128 = _mm_set_epi32(m1, m2, m3, m4);\r
-       for(size_t n = 0; n < count/4; ++n)\r
-       {\r
-               xmm0 = _mm_load_si128(source128++);     \r
-               xmm1 = _mm_load_si128(source128++);     \r
-               xmm2 = _mm_load_si128(source128++);     \r
-               xmm3 = _mm_load_si128(source128++);     \r
-\r
-               _mm_stream_si128(dest128++, _mm_shuffle_epi8(xmm0, mask128));\r
-               _mm_stream_si128(dest128++, _mm_shuffle_epi8(xmm1, mask128));\r
-               _mm_stream_si128(dest128++, _mm_shuffle_epi8(xmm2, mask128));\r
-               _mm_stream_si128(dest128++, _mm_shuffle_epi8(xmm3, mask128));\r
-       }\r
-       return dest;\r
-}\r
-\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <intrin.h>
+
+namespace caspar {
+       
+static void* aligned_memshfl(void* dest, const void* source, size_t count, int m1, int m2, int m3, int m4)
+{    
+       __m128i*           dest128 = reinterpret_cast<__m128i*>(dest);  
+       const __m128i* source128 = reinterpret_cast<const __m128i*>(source);
+
+       count /= 16; // 128 bit
+
+       __m128i xmm0, xmm1, xmm2, xmm3;
+
+       const __m128i mask128 = _mm_set_epi32(m1, m2, m3, m4);
+       for(size_t n = 0; n < count/4; ++n)
+       {
+               xmm0 = _mm_load_si128(source128++);     
+               xmm1 = _mm_load_si128(source128++);     
+               xmm2 = _mm_load_si128(source128++);     
+               xmm3 = _mm_load_si128(source128++);     
+
+               _mm_stream_si128(dest128++, _mm_shuffle_epi8(xmm0, mask128));
+               _mm_stream_si128(dest128++, _mm_shuffle_epi8(xmm1, mask128));
+               _mm_stream_si128(dest128++, _mm_shuffle_epi8(xmm2, mask128));
+               _mm_stream_si128(dest128++, _mm_shuffle_epi8(xmm3, mask128));
+       }
+       return dest;
+}
+
+
 }
\ No newline at end of file
index 94d65ef783890c77e4416b3ec5f730af98779169..14d3d6d1d62594ad6473721141eb924d76ab531f 100644 (file)
@@ -1,73 +1,73 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#define NOMINMAX\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
-#include "windows.h"\r
-\r
-#include <string>\r
-\r
-namespace caspar {\r
-\r
-static std::wstring win_product_name()\r
-{\r
-       std::wstring result = L"Unknown Windows Product Name.";\r
-       HKEY hkey; \r
-       DWORD dwType, dwSize;\r
-       if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)\r
-       {\r
-               wchar_t p_name_str[1024];\r
-\r
-               dwType = REG_SZ;\r
-               dwSize = sizeof(p_name_str);\r
-\r
-               if(RegQueryValueEx(hkey, TEXT("ProductName"), NULL, &dwType, (PBYTE)&p_name_str, &dwSize) == ERROR_SUCCESS)             \r
-                       result = p_name_str;            \r
-                \r
-               RegCloseKey(hkey);\r
-       }\r
-       return result;\r
-}\r
-\r
-static std::wstring win_sp_version()\r
-{\r
-       std::wstring result =  L"";\r
-       HKEY hkey; \r
-       DWORD dwType, dwSize;\r
-       if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)\r
-       {\r
-               wchar_t csd_ver_str[1024];\r
-\r
-               dwType = REG_SZ;\r
-               dwSize = sizeof(csd_ver_str);\r
-\r
-               if(RegQueryValueEx(hkey, TEXT("CSDVersion"), NULL, &dwType, (PBYTE)&csd_ver_str, &dwSize) == ERROR_SUCCESS)             \r
-                       result = csd_ver_str;\r
-                \r
-               RegCloseKey(hkey);\r
-       }\r
-       return result;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+
+#include "windows.h"
+
+#include <string>
+
+namespace caspar {
+
+static std::wstring win_product_name()
+{
+       std::wstring result = L"Unknown Windows Product Name.";
+       HKEY hkey; 
+       DWORD dwType, dwSize;
+       if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
+       {
+               wchar_t p_name_str[1024];
+
+               dwType = REG_SZ;
+               dwSize = sizeof(p_name_str);
+
+               if(RegQueryValueEx(hkey, TEXT("ProductName"), NULL, &dwType, (PBYTE)&p_name_str, &dwSize) == ERROR_SUCCESS)             
+                       result = p_name_str;            
+                
+               RegCloseKey(hkey);
+       }
+       return result;
+}
+
+static std::wstring win_sp_version()
+{
+       std::wstring result =  L"";
+       HKEY hkey; 
+       DWORD dwType, dwSize;
+       if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
+       {
+               wchar_t csd_ver_str[1024];
+
+               dwType = REG_SZ;
+               dwSize = sizeof(csd_ver_str);
+
+               if(RegQueryValueEx(hkey, TEXT("CSDVersion"), NULL, &dwType, (PBYTE)&csd_ver_str, &dwSize) == ERROR_SUCCESS)             
+                       result = csd_ver_str;
+                
+               RegCloseKey(hkey);
+       }
+       return result;
+}
+
 }
\ No newline at end of file
index bea92258990bfe8200b418d78fa48e5635d9a167..54c19c7bfba491f4f798281c43f206bce5d0f80d 100644 (file)
@@ -1,82 +1,82 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "windows.h"\r
-\r
-#include <string>\r
-#include <sstream>\r
-\r
-namespace caspar {\r
-       \r
-static std::wstring cpu_info()\r
-{\r
-       std::wstring cpu_name = L"Unknown CPU";\r
-       HKEY hkey; \r
-       DWORD dwType, dwSize;\r
-       if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)\r
-       {\r
-               wchar_t p_name_str[1024];\r
-\r
-               dwType = REG_SZ;\r
-               dwSize = sizeof(p_name_str);\r
-\r
-               if(RegQueryValueEx(hkey, TEXT("ProcessorNameString"), NULL, &dwType, (PBYTE)&p_name_str, &dwSize) == ERROR_SUCCESS)             \r
-                       cpu_name = p_name_str;          \r
-                \r
-               RegCloseKey(hkey);\r
-       }\r
-\r
-\r
-       SYSTEM_INFO sysinfo;\r
-       GetSystemInfo(&sysinfo);\r
-\r
-       std::wstringstream s;\r
-\r
-       s << cpu_name << L" Physical Threads: " << sysinfo.dwNumberOfProcessors;\r
-\r
-       return s.str();\r
-}\r
-\r
-static std::wstring system_product_name()\r
-{\r
-       std::wstring system_product_name = L"Unknown System";\r
-       HKEY hkey; \r
-       DWORD dwType, dwSize;\r
-       if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\BIOS"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)\r
-       {\r
-               wchar_t p_name_str[1024];\r
-\r
-               dwType = REG_SZ;\r
-               dwSize = sizeof(p_name_str);\r
-\r
-               if(RegQueryValueEx(hkey, TEXT("SystemProductName"), NULL, &dwType, (PBYTE)&p_name_str, &dwSize) == ERROR_SUCCESS)               \r
-                       system_product_name = p_name_str;               \r
-                \r
-               RegCloseKey(hkey);\r
-       }\r
-\r
-       return system_product_name;\r
-}\r
-\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "windows.h"
+
+#include <string>
+#include <sstream>
+
+namespace caspar {
+       
+static std::wstring cpu_info()
+{
+       std::wstring cpu_name = L"Unknown CPU";
+       HKEY hkey; 
+       DWORD dwType, dwSize;
+       if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
+       {
+               wchar_t p_name_str[1024];
+
+               dwType = REG_SZ;
+               dwSize = sizeof(p_name_str);
+
+               if(RegQueryValueEx(hkey, TEXT("ProcessorNameString"), NULL, &dwType, (PBYTE)&p_name_str, &dwSize) == ERROR_SUCCESS)             
+                       cpu_name = p_name_str;          
+                
+               RegCloseKey(hkey);
+       }
+
+
+       SYSTEM_INFO sysinfo;
+       GetSystemInfo(&sysinfo);
+
+       std::wstringstream s;
+
+       s << cpu_name << L" Physical Threads: " << sysinfo.dwNumberOfProcessors;
+
+       return s.str();
+}
+
+static std::wstring system_product_name()
+{
+       std::wstring system_product_name = L"Unknown System";
+       HKEY hkey; 
+       DWORD dwType, dwSize;
+       if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\BIOS"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
+       {
+               wchar_t p_name_str[1024];
+
+               dwType = REG_SZ;
+               dwSize = sizeof(p_name_str);
+
+               if(RegQueryValueEx(hkey, TEXT("SystemProductName"), NULL, &dwType, (PBYTE)&p_name_str, &dwSize) == ERROR_SUCCESS)               
+                       system_product_name = p_name_str;               
+                
+               RegCloseKey(hkey);
+       }
+
+       return system_product_name;
+}
+
+
 }
\ No newline at end of file
index b1afff9eaa66ab7c298bd52766bc382511a01826..40f410f3383260b47435cb685def657441d1309f 100644 (file)
@@ -1,26 +1,26 @@
-#pragma once\r
-\r
-#undef _UNICODE\r
-#define _UNICODE\r
-#undef UNICODE\r
-#define UNICODE\r
-\r
-#undef NOMINMAX\r
-#define NOMINMAX\r
-\r
-#undef NOSERVICE\r
-#define NOSERVICE\r
-#undef NOMCX\r
-#define NOMCX\r
-\r
-#ifdef _MSC_VER\r
-#      include <SDKDDKVer.h>\r
-#endif\r
-#ifndef _WIN32_WINNT\r
-#define _WIN32_WINNT _WIN32_WINNT_WIN7\r
-#endif\r
-\r
-#undef WIN32_LEAN_AND_MEAN\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
+#pragma once
+
+#undef _UNICODE
+#define _UNICODE
+#undef UNICODE
+#define UNICODE
+
+#undef NOMINMAX
+#define NOMINMAX
+
+#undef NOSERVICE
+#define NOSERVICE
+#undef NOMCX
+#define NOMCX
+
+#ifdef _MSC_VER
+#      include <SDKDDKVer.h>
+#endif
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT _WIN32_WINNT_WIN7
+#endif
+
+#undef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+
 #include <windows.h>
\ No newline at end of file
index c8d0cac608cac892350a885889bdeeb0c590b01f..ead2654dfddc3e2c18933eef30bb9e1f45b1345f 100644 (file)
@@ -1,66 +1,66 @@
-#include "stdafx.h"\r
-\r
-#include "os/windows/windows.h"\r
-\r
-#include <unordered_map>\r
-#include <tbb/mutex.h>\r
-#include <tbb/atomic.h>\r
-\r
-namespace caspar { namespace detail {\r
-       \r
-tbb::mutex                                                     g_mutex;\r
-std::unordered_map<void*, size_t>      g_map;\r
-size_t                                                         g_free;\r
-\r
-void allocate_store(size_t size)\r
-{              \r
-       SIZE_T workingSetMinSize = 0, workingSetMaxSize = 0;\r
-       if(::GetProcessWorkingSetSize(::GetCurrentProcess(), &workingSetMinSize, &workingSetMaxSize))\r
-       {                       \r
-               workingSetMinSize += size;\r
-               workingSetMaxSize += size;\r
-\r
-               if(!::SetProcessWorkingSetSize(::GetCurrentProcess(), workingSetMinSize, workingSetMaxSize))            \r
-                       throw std::bad_alloc();         \r
-\r
-               g_free += size;\r
-       }\r
-}\r
-\r
-void* alloc_page_locked(size_t size)\r
-{\r
-       tbb::mutex::scoped_lock lock(g_mutex);\r
-\r
-       if(g_free < size)\r
-               allocate_store(size);\r
-\r
-       auto p = ::VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);\r
-       if(!p)\r
-               throw std::bad_alloc();\r
-\r
-       if(::VirtualLock(p, size) == 0) \r
-       {\r
-               ::VirtualFree(p, 0, MEM_RELEASE);\r
-               throw std::bad_alloc();\r
-       }\r
-               \r
-       g_free   -= size;\r
-       g_map[p]        = size;\r
-       return p;\r
-\r
-}\r
-\r
-void free_page_locked(void* p)\r
-{              \r
-       tbb::mutex::scoped_lock lock(g_mutex);\r
-\r
-       if(g_map.find(p) == g_map.end())\r
-               return;\r
-\r
-       ::VirtualFree(p, 0, MEM_RELEASE);\r
-\r
-       g_free += g_map[p];\r
-       g_map.erase(p);\r
-}\r
-\r
+#include "stdafx.h"
+
+#include "os/windows/windows.h"
+
+#include <unordered_map>
+#include <tbb/mutex.h>
+#include <tbb/atomic.h>
+
+namespace caspar { namespace detail {
+       
+tbb::mutex                                                     g_mutex;
+std::unordered_map<void*, size_t>      g_map;
+size_t                                                         g_free;
+
+void allocate_store(size_t size)
+{              
+       SIZE_T workingSetMinSize = 0, workingSetMaxSize = 0;
+       if(::GetProcessWorkingSetSize(::GetCurrentProcess(), &workingSetMinSize, &workingSetMaxSize))
+       {                       
+               workingSetMinSize += size;
+               workingSetMaxSize += size;
+
+               if(!::SetProcessWorkingSetSize(::GetCurrentProcess(), workingSetMinSize, workingSetMaxSize))            
+                       throw std::bad_alloc();         
+
+               g_free += size;
+       }
+}
+
+void* alloc_page_locked(size_t size)
+{
+       tbb::mutex::scoped_lock lock(g_mutex);
+
+       if(g_free < size)
+               allocate_store(size);
+
+       auto p = ::VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+       if(!p)
+               throw std::bad_alloc();
+
+       if(::VirtualLock(p, size) == 0) 
+       {
+               ::VirtualFree(p, 0, MEM_RELEASE);
+               throw std::bad_alloc();
+       }
+               
+       g_free   -= size;
+       g_map[p]        = size;
+       return p;
+
+}
+
+void free_page_locked(void* p)
+{              
+       tbb::mutex::scoped_lock lock(g_mutex);
+
+       if(g_map.find(p) == g_map.end())
+               return;
+
+       ::VirtualFree(p, 0, MEM_RELEASE);
+
+       g_free += g_map[p];
+       g_map.erase(p);
+}
+
 }}
\ No newline at end of file
index 9cce6e8f87899fac36fdd19087dd349a2aba96fb..9a4d72a3b9193889ba0c48a285fe3a94e6e6bb97 100644 (file)
@@ -1,75 +1,75 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-namespace caspar {\r
-\r
-namespace detail {\r
-\r
-void* alloc_page_locked(size_t size);\r
-void free_page_locked(void* p);\r
-\r
-}\r
-       \r
-template <class T>\r
-class page_locked_allocator\r
-{\r
-public:\r
-       typedef size_t    size_type;\r
-       typedef ptrdiff_t difference_type;\r
-       typedef T*        pointer;\r
-       typedef const T*  const_pointer;\r
-       typedef T&        reference;\r
-       typedef const T&  const_reference;\r
-       typedef T         value_type;\r
-\r
-       page_locked_allocator() {}\r
-       page_locked_allocator(const page_locked_allocator&) {}\r
-  \r
-       pointer allocate(size_type n, const void * = 0) \r
-       {\r
-               return reinterpret_cast<T*>(detail::alloc_page_locked(n));\r
-       }\r
-  \r
-       void deallocate(void* p, size_type) \r
-       {\r
-               detail::free_page_locked(p);            \r
-       }\r
-\r
-       pointer           address(reference x) const { return &x; }\r
-       const_pointer     address(const_reference x) const { return &x; }\r
-       page_locked_allocator<T>&  operator=(const page_locked_allocator&) { return *this; }\r
-       void              construct(pointer p, const T& val) { new ((T*) p) T(val); }\r
-       void              destroy(pointer p) { p->~T(); }\r
-\r
-       size_type         max_size() const { return size_t(-1); }\r
-\r
-       template <class U>\r
-       struct rebind { typedef page_locked_allocator<U> other; };\r
-\r
-       template <class U>\r
-       page_locked_allocator(const page_locked_allocator<U>&) {}\r
-\r
-       template <class U>\r
-       page_locked_allocator& operator=(const page_locked_allocator<U>&) { return *this; }\r
-};\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+namespace caspar {
+
+namespace detail {
+
+void* alloc_page_locked(size_t size);
+void free_page_locked(void* p);
+
+}
+       
+template <class T>
+class page_locked_allocator
+{
+public:
+       typedef size_t    size_type;
+       typedef ptrdiff_t difference_type;
+       typedef T*        pointer;
+       typedef const T*  const_pointer;
+       typedef T&        reference;
+       typedef const T&  const_reference;
+       typedef T         value_type;
+
+       page_locked_allocator() {}
+       page_locked_allocator(const page_locked_allocator&) {}
+  
+       pointer allocate(size_type n, const void * = 0) 
+       {
+               return reinterpret_cast<T*>(detail::alloc_page_locked(n));
+       }
+  
+       void deallocate(void* p, size_type) 
+       {
+               detail::free_page_locked(p);            
+       }
+
+       pointer           address(reference x) const { return &x; }
+       const_pointer     address(const_reference x) const { return &x; }
+       page_locked_allocator<T>&  operator=(const page_locked_allocator&) { return *this; }
+       void              construct(pointer p, const T& val) { new ((T*) p) T(val); }
+       void              destroy(pointer p) { p->~T(); }
+
+       size_type         max_size() const { return size_t(-1); }
+
+       template <class U>
+       struct rebind { typedef page_locked_allocator<U> other; };
+
+       template <class U>
+       page_locked_allocator(const page_locked_allocator<U>&) {}
+
+       template <class U>
+       page_locked_allocator& operator=(const page_locked_allocator<U>&) { return *this; }
+};
 }
\ No newline at end of file
index bf1056a65306a1767cda28169c9a256c2685748e..9429536cf1bf06375d38d4b01f210c775928f40d 100644 (file)
@@ -1,52 +1,52 @@
-#pragma once\r
-\r
-#include "except.h"\r
-\r
-#include <boost/lexical_cast.hpp>\r
-\r
-#include <type_traits>\r
-#include <string>\r
-\r
-namespace caspar {\r
-               \r
-template<typename T, typename C>\r
-typename std::enable_if<!std::is_convertible<T, std::wstring>::value, typename std::decay<T>::type>::type get_param(const std::wstring& name, C&& params, T fail_value = T())\r
-{      \r
-       auto it = std::find(std::begin(params), std::end(params), name);\r
-       if(it == params.end())  \r
-               return fail_value;\r
-       \r
-       try\r
-       {\r
-               if(++it == params.end())\r
-                       throw std::out_of_range("");\r
-\r
-               return boost::lexical_cast<std::decay<T>::type>(*it);\r
-       }\r
-       catch(...)\r
-       {               \r
-               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Failed to parse param.") << arg_name_info(name) << nested_exception(std::current_exception()));\r
-       }\r
-}\r
-\r
-template<typename C>\r
-std::wstring get_param(const std::wstring& name, C&& params, const std::wstring& fail_value = L"")\r
-{      \r
-       auto it = std::find(std::begin(params), std::end(params), name);\r
-       if(it == params.end())  \r
-               return fail_value;\r
-       \r
-       try\r
-       {\r
-               if(++it == params.end())\r
-                       throw std::out_of_range("");\r
-\r
-               return *it;     \r
-       }\r
-       catch(...)\r
-       {               \r
-               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Failed to parse param.") << arg_name_info(name) << nested_exception(std::current_exception()));\r
-       }\r
-}\r
-\r
+#pragma once
+
+#include "except.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include <type_traits>
+#include <string>
+
+namespace caspar {
+               
+template<typename T, typename C>
+typename std::enable_if<!std::is_convertible<T, std::wstring>::value, typename std::decay<T>::type>::type get_param(const std::wstring& name, C&& params, T fail_value = T())
+{      
+       auto it = std::find(std::begin(params), std::end(params), name);
+       if(it == params.end())  
+               return fail_value;
+       
+       try
+       {
+               if(++it == params.end())
+                       throw std::out_of_range("");
+
+               return boost::lexical_cast<std::decay<T>::type>(*it);
+       }
+       catch(...)
+       {               
+               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Failed to parse param.") << arg_name_info(name) << nested_exception(std::current_exception()));
+       }
+}
+
+template<typename C>
+std::wstring get_param(const std::wstring& name, C&& params, const std::wstring& fail_value = L"")
+{      
+       auto it = std::find(std::begin(params), std::end(params), name);
+       if(it == params.end())  
+               return fail_value;
+       
+       try
+       {
+               if(++it == params.end())
+                       throw std::out_of_range("");
+
+               return *it;     
+       }
+       catch(...)
+       {               
+               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Failed to parse param.") << arg_name_info(name) << nested_exception(std::current_exception()));
+       }
+}
+
 }
\ No newline at end of file
index 1e4e8eb86b1c7f784c855221c1752ca03221edf9..94c01730aa7a45418a520dfa374be0840b331a54 100644 (file)
@@ -1,80 +1,80 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "stdafx.h"\r
-\r
-#include "prec_timer.h"\r
-\r
-#include "os/windows/windows.h"\r
-\r
-#include <Mmsystem.h>\r
-\r
-namespace caspar {\r
-       \r
-prec_timer::prec_timer()\r
-       : time_(0)\r
-{\r
-}\r
-\r
-// Author: Ryan M. Geiss\r
-// http://www.geisswerks.com/ryan/FAQS/timing.html\r
-void prec_timer::tick(double interval)\r
-{      \r
-       auto t = ::timeGetTime();\r
-\r
-       if (time_ != 0)\r
-       {\r
-               auto ticks_to_wait = static_cast<DWORD>(interval*1000.0);\r
-               bool done = 0;\r
-               do\r
-               {                               \r
-                       auto ticks_passed = t - time_;\r
-                       auto ticks_left   = ticks_to_wait - ticks_passed;\r
-\r
-                       if (t < time_)    // time wrap\r
-                               done = 1;\r
-                       if (ticks_passed >= ticks_to_wait)\r
-                               done = 1;\r
-                               \r
-                       if (!done)\r
-                       {\r
-                               // if > 0.002s left, do Sleep(1), which will actually sleep some \r
-                               //   steady amount, probably 1-2 ms,\r
-                               //   and do so in a nice way (cpu meter drops; laptop battery spared).\r
-                               // otherwise, do a few Sleep(0)'s, which just give up the timeslice,\r
-                               //   but don't really save cpu or battery, but do pass a tiny\r
-                               //   amount of time.\r
-                               if (ticks_left > 2)\r
-                                       Sleep(1);\r
-                               else                        \r
-                                       for (int i = 0; i < 10; ++i) \r
-                                               Sleep(0);  // causes thread to give up its timeslice\r
-                       }\r
-\r
-                       t = ::timeGetTime();\r
-               }\r
-               while (!done);            \r
-       }\r
-\r
-       time_ = t;\r
-}      \r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "stdafx.h"
+
+#include "prec_timer.h"
+
+#include "os/windows/windows.h"
+
+#include <Mmsystem.h>
+
+namespace caspar {
+       
+prec_timer::prec_timer()
+       : time_(0)
+{
+}
+
+// Author: Ryan M. Geiss
+// http://www.geisswerks.com/ryan/FAQS/timing.html
+void prec_timer::tick(double interval)
+{      
+       auto t = ::timeGetTime();
+
+       if (time_ != 0)
+       {
+               auto ticks_to_wait = static_cast<DWORD>(interval*1000.0);
+               bool done = 0;
+               do
+               {                               
+                       auto ticks_passed = t - time_;
+                       auto ticks_left   = ticks_to_wait - ticks_passed;
+
+                       if (t < time_)    // time wrap
+                               done = 1;
+                       if (ticks_passed >= ticks_to_wait)
+                               done = 1;
+                               
+                       if (!done)
+                       {
+                               // if > 0.002s left, do Sleep(1), which will actually sleep some 
+                               //   steady amount, probably 1-2 ms,
+                               //   and do so in a nice way (cpu meter drops; laptop battery spared).
+                               // otherwise, do a few Sleep(0)'s, which just give up the timeslice,
+                               //   but don't really save cpu or battery, but do pass a tiny
+                               //   amount of time.
+                               if (ticks_left > 2)
+                                       Sleep(1);
+                               else                        
+                                       for (int i = 0; i < 10; ++i) 
+                                               Sleep(0);  // causes thread to give up its timeslice
+                       }
+
+                       t = ::timeGetTime();
+               }
+               while (!done);            
+       }
+
+       time_ = t;
+}      
+
 }
\ No newline at end of file
index c3f7ffe85297d6fed1479ce11b2455caa6581dfa..d0a11e74ac26405d3ca19404cf3431534a710fc9 100644 (file)
@@ -1,40 +1,40 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-namespace caspar {\r
-       \r
-class prec_timer\r
-{\r
-public:\r
-       prec_timer();\r
-\r
-       // Author: Ryan M. Geiss\r
-       // http://www.geisswerks.com/ryan/FAQS/timing.html\r
-       void tick(double interval);\r
-\r
-private:       \r
-       unsigned long time_;\r
-};\r
-\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+namespace caspar {
+       
+class prec_timer
+{
+public:
+       prec_timer();
+
+       // Author: Ryan M. Geiss
+       // http://www.geisswerks.com/ryan/FAQS/timing.html
+       void tick(double interval);
+
+private:       
+       unsigned long time_;
+};
+
+
 }
\ No newline at end of file
index e0e2d4aae1bd49b76c3b3b7bfa12716ec7afaaa7..e56f8968e990976002b5f22c695186545031fddf 100644 (file)
-#pragma once\r
-\r
-#include "memory.h"\r
-#include "lock.h"\r
-\r
-#include <tbb/spin_rw_mutex.h>\r
-#include <tbb/cache_aligned_allocator.h>\r
-\r
-#include <algorithm>\r
-#include <functional>\r
-#include <memory>\r
-#include <vector>\r
-\r
-namespace caspar { namespace reactive {\r
-       \r
-namespace detail {\r
-\r
-// function_traits which works with MSVC2010 lambdas.\r
-       \r
-template<typename FPtr>\r
-struct function_traits_impl;\r
-\r
-template<typename R, typename A1>\r
-struct function_traits_impl<R (*)(A1)>\r
-{\r
-       typedef A1 arg1_type;\r
-};\r
-\r
-template<typename R, typename C, typename A1>\r
-struct function_traits_impl<R (C::*)(A1)>\r
-{\r
-       typedef A1 arg1_type;\r
-};\r
-\r
-template<typename R, typename C, typename A1>\r
-struct function_traits_impl<R (C::*)(A1) const>\r
-{\r
-       typedef A1 arg1_type;\r
-};\r
-\r
-template<typename T>\r
-typename function_traits_impl<T>::arg1_type arg1_type_helper(T);\r
-\r
-template<typename F>\r
-struct function_traits\r
-{\r
-       typedef decltype(detail::arg1_type_helper(&F::operator())) arg1_type;\r
-};\r
-\r
-}\r
-\r
-template<typename T>\r
-class observer\r
-{      \r
-       observer(const observer&);\r
-       observer& operator=(const observer&);\r
-public:\r
-\r
-       // Static Members\r
-\r
-       typedef T value_type;\r
-       \r
-       // Constructors\r
-\r
-       observer()\r
-       {\r
-       }\r
-\r
-       virtual ~observer()\r
-       {\r
-       }\r
-\r
-       // Methods\r
-\r
-       virtual void on_next(const T&) = 0;\r
-\r
-       // Properties\r
-};\r
-\r
-template<typename T>\r
-class observable\r
-{\r
-       observable(const observable&);\r
-       observable& operator=(const observable&);\r
-public:\r
-\r
-       // Static Members\r
-\r
-       typedef T                                               value_type;\r
-       typedef observer<T>                             observer;\r
-       typedef std::weak_ptr<observer> observer_ptr;\r
-       \r
-       // Constructors\r
-\r
-       observable()\r
-       {\r
-       }\r
-\r
-       virtual ~observable()\r
-       {\r
-       }\r
-       \r
-       // Methods\r
-\r
-       virtual void subscribe(const observer_ptr&) = 0;\r
-       virtual void unsubscribe(const observer_ptr&) = 0;\r
-       \r
-       // Properties\r
-};\r
-\r
-template<typename I, typename O = I>\r
-class subject : public observer<I>, public observable<O>\r
-{\r
-public:\r
-       \r
-       // Static Members\r
-\r
-       typedef typename observable<O>::observer                observer;\r
-       typedef typename observable<O>::observer_ptr    observer_ptr;\r
-       \r
-       // Constructors\r
-\r
-       virtual ~subject()\r
-       {\r
-       }\r
-       \r
-       // Methods\r
-\r
-       // Properties\r
-};\r
-\r
-template<typename T, typename C>\r
-class observer_function : public observer<T>\r
-{\r
-public:\r
-       \r
-       // Static Members\r
-       \r
-       // Constructors\r
-\r
-       observer_function()\r
-       {\r
-       }\r
-\r
-       observer_function(C func)\r
-               : func_(std::move(func))\r
-       {\r
-       }\r
-\r
-       observer_function(const observer_function& other)\r
-               : func_(other.func_)\r
-       {\r
-       }\r
-\r
-       observer_function(observer_function&& other)\r
-               : func_(std::move(other.func_))\r
-       {\r
-       }\r
-\r
-       observer_function& operator=(observer_function other)\r
-       {\r
-               other.swap(*this);\r
-       }\r
-               \r
-       // Methods\r
-\r
-       void swap(observer_function& other)\r
-       {\r
-               std::swap(func_, other.func_);\r
-               std::swap(filter_, other.filter_);\r
-       }\r
-               \r
-       void on_next(const T& e) override\r
-       {\r
-               func_(e);\r
-       }\r
-\r
-       // Properties\r
-private:\r
-       C func_;\r
-};\r
-\r
-template<typename I, typename O = I>\r
-class basic_subject_impl sealed : public subject<I, O>\r
-{      \r
-    template <typename, typename> friend class basic_subject_impl;\r
-\r
-       basic_subject_impl(const basic_subject_impl&);\r
-       basic_subject_impl& operator=(const basic_subject_impl&);\r
-public:        \r
-       // Static Members\r
-\r
-       typedef typename subject<I, O>::observer                observer;\r
-       typedef typename subject<I, O>::observer_ptr    observer_ptr;\r
-\r
-       // Constructors\r
-\r
-       basic_subject_impl()\r
-       {\r
-       }\r
-                                       \r
-       basic_subject_impl(basic_subject_impl<I, O>&& other)\r
-               : observers_(std::move(other.observers_))\r
-       {\r
-       }\r
-       \r
-       basic_subject_impl& operator=(basic_subject_impl<I, O>&& other)\r
-       {\r
-               observers_ = std::move(observers_);\r
-               return *this;\r
-       }\r
-\r
-       // Methods\r
-\r
-       void clear()\r
-       {\r
-               tbb::spin_rw_mutex::scoped_lock lock(mutex_, true);\r
-\r
-               observers_.clear();\r
-       }\r
-       \r
-       void subscribe(const observer_ptr& o) override\r
-       {                               \r
-               tbb::spin_rw_mutex::scoped_lock lock(mutex_, false);\r
-\r
-               auto it = std::lower_bound(std::begin(observers_), std::end(observers_), o, comp_);\r
-               if (it == std::end(observers_) || comp_(o, *it))\r
-               {\r
-                       lock.upgrade_to_writer();\r
-                       observers_.insert(it, o);\r
-               }               \r
-       }\r
-\r
-       void unsubscribe(const observer_ptr& o) override\r
-       {\r
-               tbb::spin_rw_mutex::scoped_lock lock(mutex_, false);\r
-               \r
-               auto it = std::lower_bound(std::begin(observers_), std::end(observers_), o, comp_);\r
-               if(it != std::end(observers_) && !comp_(o, *it))\r
-               {\r
-                       lock.upgrade_to_writer();\r
-                       observers_.erase(it);\r
-               }               \r
-       }\r
-       \r
-       void on_next(const I& e) override\r
-       {                               \r
-               std::vector<spl::shared_ptr<observer>> observers;\r
-\r
-               {\r
-                       tbb::spin_rw_mutex::scoped_lock lock(mutex_, false);\r
-               \r
-                       auto expired = std::end(observers_);\r
-\r
-                       for(auto it = std::begin(observers_); it != std::end(observers_); ++it)\r
-                       {\r
-                               auto o = it->lock();\r
-                               if(o)\r
-                                       observers.push_back(spl::make_shared_ptr(std::move(o)));\r
-                               else\r
-                                       expired = it;\r
-                       }\r
-\r
-                       if(expired != std::end(observers_))\r
-                       {               \r
-                               lock.upgrade_to_writer();\r
-                               observers_.erase(expired);\r
-                       }       \r
-               }\r
-               \r
-               for(auto it = std::begin(observers); it != std::end(observers); ++it)\r
-                       (*it)->on_next(e);\r
-       }\r
-\r
-       // Properties\r
-\r
-private:\r
-       typedef tbb::cache_aligned_allocator<std::weak_ptr<observer>>   allocator;\r
-\r
-       std::owner_less<std::weak_ptr<observer>>                comp_;\r
-       std::vector<std::weak_ptr<observer>, allocator> observers_;\r
-       mutable tbb::spin_rw_mutex                                              mutex_;\r
-};\r
-\r
-template<typename I, typename O = I>\r
-class basic_subject sealed : public subject<I, O>\r
-{      \r
-    template <typename, typename> friend class basic_subject;\r
-\r
-       basic_subject(const basic_subject&);\r
-       basic_subject& operator=(const basic_subject&);\r
-\r
-       typedef basic_subject_impl<I, O> impl;\r
-public:        \r
-\r
-       // Static Members\r
-\r
-       typedef typename subject<I, O>::observer                observer;\r
-       typedef typename subject<I, O>::observer_ptr    observer_ptr;\r
-\r
-       // Constructors\r
-\r
-       basic_subject()\r
-               : impl_(std::make_shared<impl>())\r
-\r
-       {\r
-       }\r
-               \r
-       basic_subject(subject&& other)\r
-               : impl_(std::move(other.impl_))\r
-       {\r
-       }\r
-       \r
-       basic_subject& operator=(basic_subject&& other)\r
-       {\r
-               other.swap(*this);\r
-       }\r
-\r
-       // Methods\r
-\r
-       void swap(basic_subject& other)\r
-       {\r
-               impl_.swap(other.impl_);\r
-       }\r
-       \r
-       void subscribe(const observer_ptr& o) override\r
-       {                               \r
-               impl_->subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const observer_ptr& o) override\r
-       {\r
-               impl_->unsubscribe(o);\r
-       }\r
-                               \r
-       void on_next(const I& e) override\r
-       {                               \r
-               impl_->on_next(e);\r
-       }\r
-\r
-       operator std::weak_ptr<observer>()\r
-       {\r
-               return impl_;\r
-       }\r
-\r
-       // Properties\r
-\r
-private:\r
-       std::shared_ptr<impl> impl_;\r
-};\r
-\r
-template<typename F>\r
-spl::shared_ptr<observer_function<typename std::decay<typename detail::function_traits<F>::arg1_type>::type, F>> \r
-make_observer(F func)\r
-{\r
-       return spl::make_shared<observer_function<std::decay<typename detail::function_traits<F>::arg1_type>::type, F>>(std::move(func));\r
-}\r
-\r
-template<typename T>\r
-basic_subject<T>& operator<<(basic_subject<T>& s, const T& val)\r
-{\r
-       s.on_next(val);\r
-       return s;\r
-}\r
-\r
+#pragma once
+
+#include "memory.h"
+#include "lock.h"
+
+#include <tbb/spin_rw_mutex.h>
+#include <tbb/cache_aligned_allocator.h>
+
+#include <algorithm>
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace caspar { namespace reactive {
+       
+namespace detail {
+
+// function_traits which works with MSVC2010 lambdas.
+       
+template<typename FPtr>
+struct function_traits_impl;
+
+template<typename R, typename A1>
+struct function_traits_impl<R (*)(A1)>
+{
+       typedef A1 arg1_type;
+};
+
+template<typename R, typename C, typename A1>
+struct function_traits_impl<R (C::*)(A1)>
+{
+       typedef A1 arg1_type;
+};
+
+template<typename R, typename C, typename A1>
+struct function_traits_impl<R (C::*)(A1) const>
+{
+       typedef A1 arg1_type;
+};
+
+template<typename T>
+typename function_traits_impl<T>::arg1_type arg1_type_helper(T);
+
+template<typename F>
+struct function_traits
+{
+       typedef decltype(detail::arg1_type_helper(&F::operator())) arg1_type;
+};
+
+}
+
+template<typename T>
+class observer
+{      
+       observer(const observer&);
+       observer& operator=(const observer&);
+public:
+
+       // Static Members
+
+       typedef T value_type;
+       
+       // Constructors
+
+       observer()
+       {
+       }
+
+       virtual ~observer()
+       {
+       }
+
+       // Methods
+
+       virtual void on_next(const T&) = 0;
+
+       // Properties
+};
+
+template<typename T>
+class observable
+{
+       observable(const observable&);
+       observable& operator=(const observable&);
+public:
+
+       // Static Members
+
+       typedef T                                               value_type;
+       typedef observer<T>                             observer;
+       typedef std::weak_ptr<observer> observer_ptr;
+       
+       // Constructors
+
+       observable()
+       {
+       }
+
+       virtual ~observable()
+       {
+       }
+       
+       // Methods
+
+       virtual void subscribe(const observer_ptr&) = 0;
+       virtual void unsubscribe(const observer_ptr&) = 0;
+       
+       // Properties
+};
+
+template<typename I, typename O = I>
+class subject : public observer<I>, public observable<O>
+{
+public:
+       
+       // Static Members
+
+       typedef typename observable<O>::observer                observer;
+       typedef typename observable<O>::observer_ptr    observer_ptr;
+       
+       // Constructors
+
+       virtual ~subject()
+       {
+       }
+       
+       // Methods
+
+       // Properties
+};
+
+template<typename T, typename C>
+class observer_function : public observer<T>
+{
+public:
+       
+       // Static Members
+       
+       // Constructors
+
+       observer_function()
+       {
+       }
+
+       observer_function(C func)
+               : func_(std::move(func))
+       {
+       }
+
+       observer_function(const observer_function& other)
+               : func_(other.func_)
+       {
+       }
+
+       observer_function(observer_function&& other)
+               : func_(std::move(other.func_))
+       {
+       }
+
+       observer_function& operator=(observer_function other)
+       {
+               other.swap(*this);
+       }
+               
+       // Methods
+
+       void swap(observer_function& other)
+       {
+               std::swap(func_, other.func_);
+               std::swap(filter_, other.filter_);
+       }
+               
+       void on_next(const T& e) override
+       {
+               func_(e);
+       }
+
+       // Properties
+private:
+       C func_;
+};
+
+template<typename I, typename O = I>
+class basic_subject_impl sealed : public subject<I, O>
+{      
+    template <typename, typename> friend class basic_subject_impl;
+
+       basic_subject_impl(const basic_subject_impl&);
+       basic_subject_impl& operator=(const basic_subject_impl&);
+public:        
+       // Static Members
+
+       typedef typename subject<I, O>::observer                observer;
+       typedef typename subject<I, O>::observer_ptr    observer_ptr;
+
+       // Constructors
+
+       basic_subject_impl()
+       {
+       }
+                                       
+       basic_subject_impl(basic_subject_impl<I, O>&& other)
+               : observers_(std::move(other.observers_))
+       {
+       }
+       
+       basic_subject_impl& operator=(basic_subject_impl<I, O>&& other)
+       {
+               observers_ = std::move(observers_);
+               return *this;
+       }
+
+       // Methods
+
+       void clear()
+       {
+               tbb::spin_rw_mutex::scoped_lock lock(mutex_, true);
+
+               observers_.clear();
+       }
+       
+       void subscribe(const observer_ptr& o) override
+       {                               
+               tbb::spin_rw_mutex::scoped_lock lock(mutex_, false);
+
+               auto it = std::lower_bound(std::begin(observers_), std::end(observers_), o, comp_);
+               if (it == std::end(observers_) || comp_(o, *it))
+               {
+                       lock.upgrade_to_writer();
+                       observers_.insert(it, o);
+               }               
+       }
+
+       void unsubscribe(const observer_ptr& o) override
+       {
+               tbb::spin_rw_mutex::scoped_lock lock(mutex_, false);
+               
+               auto it = std::lower_bound(std::begin(observers_), std::end(observers_), o, comp_);
+               if(it != std::end(observers_) && !comp_(o, *it))
+               {
+                       lock.upgrade_to_writer();
+                       observers_.erase(it);
+               }               
+       }
+       
+       void on_next(const I& e) override
+       {                               
+               std::vector<spl::shared_ptr<observer>> observers;
+
+               {
+                       tbb::spin_rw_mutex::scoped_lock lock(mutex_, false);
+               
+                       auto expired = std::end(observers_);
+
+                       for(auto it = std::begin(observers_); it != std::end(observers_); ++it)
+                       {
+                               auto o = it->lock();
+                               if(o)
+                                       observers.push_back(spl::make_shared_ptr(std::move(o)));
+                               else
+                                       expired = it;
+                       }
+
+                       if(expired != std::end(observers_))
+                       {               
+                               lock.upgrade_to_writer();
+                               observers_.erase(expired);
+                       }       
+               }
+               
+               for(auto it = std::begin(observers); it != std::end(observers); ++it)
+                       (*it)->on_next(e);
+       }
+
+       // Properties
+
+private:
+       typedef tbb::cache_aligned_allocator<std::weak_ptr<observer>>   allocator;
+
+       std::owner_less<std::weak_ptr<observer>>                comp_;
+       std::vector<std::weak_ptr<observer>, allocator> observers_;
+       mutable tbb::spin_rw_mutex                                              mutex_;
+};
+
+template<typename I, typename O = I>
+class basic_subject sealed : public subject<I, O>
+{      
+    template <typename, typename> friend class basic_subject;
+
+       basic_subject(const basic_subject&);
+       basic_subject& operator=(const basic_subject&);
+
+       typedef basic_subject_impl<I, O> impl;
+public:        
+
+       // Static Members
+
+       typedef typename subject<I, O>::observer                observer;
+       typedef typename subject<I, O>::observer_ptr    observer_ptr;
+
+       // Constructors
+
+       basic_subject()
+               : impl_(std::make_shared<impl>())
+
+       {
+       }
+               
+       basic_subject(subject&& other)
+               : impl_(std::move(other.impl_))
+       {
+       }
+       
+       basic_subject& operator=(basic_subject&& other)
+       {
+               other.swap(*this);
+       }
+
+       // Methods
+
+       void swap(basic_subject& other)
+       {
+               impl_.swap(other.impl_);
+       }
+       
+       void subscribe(const observer_ptr& o) override
+       {                               
+               impl_->subscribe(o);
+       }
+
+       void unsubscribe(const observer_ptr& o) override
+       {
+               impl_->unsubscribe(o);
+       }
+                               
+       void on_next(const I& e) override
+       {                               
+               impl_->on_next(e);
+       }
+
+       operator std::weak_ptr<observer>()
+       {
+               return impl_;
+       }
+
+       // Properties
+
+private:
+       std::shared_ptr<impl> impl_;
+};
+
+template<typename F>
+spl::shared_ptr<observer_function<typename std::decay<typename detail::function_traits<F>::arg1_type>::type, F>> 
+make_observer(F func)
+{
+       return spl::make_shared<observer_function<std::decay<typename detail::function_traits<F>::arg1_type>::type, F>>(std::move(func));
+}
+
+template<typename T>
+basic_subject<T>& operator<<(basic_subject<T>& s, const T& val)
+{
+       s.on_next(val);
+       return s;
+}
+
 }}
\ No newline at end of file
index 923b06b9a95b823b42ad4e98f18fb7de1a037830..b2f0eab5690e733a64cd8a6f2476d0518ae84a0c 100644 (file)
@@ -1,22 +1,22 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "stdafx.h"\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "stdafx.h"
index 11a6c3c9f703419e89efa7065846c59e108bb395..8467bf2e718a392b9afb22844c908c28b94fc4ef 100644 (file)
@@ -1,24 +1,24 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
 #include "os/windows/windows.h"
\ No newline at end of file
index 8b8c12dbe939ba2b2a5daca4c2a41c5ad3340f2b..bf9e2b450328a6381b9b748d1a414c59e9ca18bc 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-\r
-// The following code is based on Tweener for actionscript, http://code.google.com/p/tweener/\r
-//\r
-//Disclaimer for Robert Penner's Easing Equations license:\r
-//\r
-//TERMS OF USE - EASING EQUATIONS\r
-//\r
-//Open source under the BSD License.\r
-//\r
-//Copyright Â© 2001 Robert Penner\r
-//All rights reserved.\r
-//\r
-//Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\r
-//\r
-//    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\r
-//    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\r
-//    * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.\r
-//\r
-//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-#include "stdafx.h"\r
-\r
-#include "tweener.h"\r
-\r
-#include "except.h"\r
-\r
-#include <boost/assign/list_of.hpp>\r
-#include <boost/regex.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/range/adaptor/map.hpp>\r
-\r
-#include <unordered_map>\r
-#include <string>\r
-#include <locale>\r
-#include <functional>\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
-\r
-typedef std::function<double(double, double, double, double)> tweener_t;\r
-                       \r
-static const double PI = std::atan(1.0)*4.0;\r
-static const double H_PI = std::atan(1.0)*2.0;\r
-\r
-double ease_none (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return c*t/d + b;\r
-}\r
-\r
-double ease_in_quad (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return c*(t/=d)*t + b;\r
-}\r
-       \r
-double ease_out_quad (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return -c *(t/=d)*(t-2) + b;\r
-}      \r
-\r
-double ease_in_out_quad (double t, double b, double c, double d, const std::vector<double>& params)\r
-{\r
-       if ((t/=d/2) < 1) \r
-               return c/2*t*t + b;\r
-\r
-       return -c/2 * ((--t)*(t-2) - 1) + b;\r
-}      \r
-\r
-double ease_out_in_quad (double t, double b, double c, double d, const std::vector<double>& params)\r
-{\r
-       if (t < d/2) \r
-               return ease_out_quad (t*2, b, c/2, d, params);\r
-\r
-       return ease_in_quad((t*2)-d, b+c/2, c/2, d, params);\r
-}\r
-       \r
-double ease_in_cubic (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return c*(t/=d)*t*t + b;\r
-}      \r
-\r
-double ease_out_cubic (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return c*((t=t/d-1)*t*t + 1) + b;\r
-}\r
-       \r
-double ease_in_out_cubic (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if ((t/=d/2) < 1) \r
-               return c/2*t*t*t + b;\r
-\r
-       return c/2*((t-=2)*t*t + 2) + b;\r
-}\r
-       \r
-double ease_out_in_cubic (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t < d/2) return ease_out_cubic (t*2, b, c/2, d, params);\r
-       return ease_in_cubic((t*2)-d, b+c/2, c/2, d, params);\r
-}\r
-       \r
-double ease_in_quart (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return c*(t/=d)*t*t*t + b;\r
-}\r
-       \r
-double ease_out_quart (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return -c * ((t=t/d-1)*t*t*t - 1) + b;\r
-}      \r
-\r
-double ease_in_out_quart (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if ((t/=d/2) < 1)\r
-               return c/2*t*t*t*t + b;\r
-\r
-       return -c/2 * ((t-=2)*t*t*t - 2) + b;\r
-}      \r
-\r
-double ease_out_in_quart (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t < d/2)\r
-               return ease_out_quart (t*2, b, c/2, d, params);\r
-\r
-       return ease_in_quart((t*2)-d, b+c/2, c/2, d, params);\r
-}      \r
-\r
-double ease_in_quint (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return c*(t/=d)*t*t*t*t + b;\r
-}\r
-       \r
-double ease_out_quint (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return c*((t=t/d-1)*t*t*t*t + 1) + b;\r
-}\r
-       \r
-double ease_in_out_quint (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if ((t/=d/2) < 1) \r
-               return c/2*t*t*t*t*t + b;\r
-\r
-       return c/2*((t-=2)*t*t*t*t + 2) + b;\r
-}\r
-       \r
-double ease_out_in_quint (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t < d/2) \r
-               return ease_out_quint (t*2, b, c/2, d, params);\r
-\r
-       return ease_in_quint((t*2)-d, b+c/2, c/2, d, params);\r
-}      \r
-\r
-double ease_in_sine (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return -c * std::cos(t/d * (PI/2)) + c + b;\r
-}      \r
-\r
-double ease_out_sine (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return c * std::sin(t/d * (PI/2)) + b;\r
-}      \r
-\r
-double ease_in_out_sine (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return -c/2 * (std::cos(PI*t/d) - 1) + b;\r
-}      \r
-\r
-double ease_out_in_sine (double t, double b, double c, double d, const std::vector<double>& params)\r
-{\r
-       if (t < d/2) \r
-               return ease_out_sine (t*2, b, c/2, d, params);\r
-       \r
-       return ease_in_sine((t*2)-d, b+c/2, c/2, d, params);\r
-}      \r
-\r
-double ease_in_expo (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return (t==0) ? b : c * std::pow(2, 10 * (t/d - 1)) + b - c * 0.001;\r
-}      \r
-\r
-double ease_out_expo (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return (t==d) ? b+c : c * 1.001 * (-std::pow(2, -10 * t/d) + 1) + b;\r
-}\r
-       \r
-double ease_in_out_expo (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t==0) \r
-               return b;\r
-       if (t==d) \r
-               return b+c;\r
-       if ((t/=d/2) < 1) \r
-               return c/2 * std::pow(2, 10 * (t - 1)) + b - c * 0.0005;\r
-\r
-       return c/2 * 1.0005 * (-std::pow(2, -10 * --t) + 2) + b;\r
-}\r
-       \r
-double ease_out_in_expo (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t < d/2) \r
-               return ease_out_expo (t*2, b, c/2, d, params);\r
-\r
-       return ease_in_expo((t*2)-d, b+c/2, c/2, d, params);\r
-}\r
-       \r
-double ease_in_circ (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return -c * (std::sqrt(1 - (t/=d)*t) - 1) + b;\r
-}\r
-       \r
-double ease_out_circ (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       return c * std::sqrt(1 - (t=t/d-1)*t) + b;\r
-}\r
-       \r
-double ease_in_out_circ (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if ((t/=d/2) < 1) \r
-               return -c/2 * (std::sqrt(1 - t*t) - 1) + b;\r
-\r
-       return c/2 * (std::sqrt(1 - (t-=2)*t) + 1) + b;\r
-}\r
-       \r
-double ease_out_in_circ (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t < d/2) return ease_out_circ(t*2, b, c/2, d, params);\r
-       return ease_in_circ((t*2)-d, b+c/2, c/2, d, params);\r
-}\r
-       \r
-double ease_in_elastic (double t, double b, double c, double d, const std::vector<double>& params)\r
-{\r
-       if (t==0) return b;\r
-       if ((t/=d)==1) return b+c;\r
-       //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*.3 : p_params.period;\r
-       //var s:Number;\r
-       //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;\r
-       double p = params.size() > 0 ? params[0] : d*0.3;\r
-       double s;\r
-       double a = params.size() > 1 ? params[1] : 0.0;\r
-       if (a == 0.0 || a < std::abs(c)) \r
-       {\r
-               a = c;\r
-               s = p/4;\r
-       } \r
-       else \r
-               s = p/(2*PI) * std::asin (c/a);\r
-       \r
-       return -(a*std::pow(2,10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )) + b;\r
-}\r
-       \r
-double ease_out_elastic (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t==0) \r
-               return b;\r
-       if ((t/=d)==1) \r
-               return b+c;\r
-       //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*.3 : p_params.period;\r
-       //var s:Number;\r
-       //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;\r
-       double p = params.size() > 0 ? params[0] : d*0.3;\r
-       double s;\r
-       double a = params.size() > 1 ? params[1] : 0.0;\r
-       if (a == 0.0 || a < std::abs(c))\r
-       {\r
-               a = c;\r
-               s = p/4;\r
-       } \r
-       else \r
-               s = p/(2*PI) * std::asin (c/a);\r
-       \r
-       return (a*std::pow(2,-10*t) * std::sin( (t*d-s)*(2*PI)/p ) + c + b);\r
-}      \r
-\r
-double ease_in_out_elastic (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t==0)\r
-               return b;\r
-       if ((t/=d/2)==2) \r
-               return b+c;\r
-       //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*(.3*1.5) : p_params.period;\r
-       //var s:Number;\r
-       //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;\r
-       double p = params.size() > 0 ? params[0] : d*0.3*1.5;\r
-       double s;\r
-       double a = params.size() > 1 ? params[1] : 0.0;\r
-       if (a == 0.0 || a < std::abs(c)) \r
-       {\r
-               a = c;\r
-               s = p/4;\r
-       }\r
-       else\r
-               s = p/(2*PI) * std::asin (c/a);\r
-       \r
-       if (t < 1) \r
-               return -.5*(a*std::pow(2,10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )) + b;\r
-\r
-       return a*std::pow(2,-10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )*.5 + c + b;\r
-}\r
-       \r
-double ease_out_in_elastic (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t < d/2) return ease_out_elastic (t*2, b, c/2, d, params);\r
-       return ease_in_elastic((t*2)-d, b+c/2, c/2, d, params);\r
-}\r
-       \r
-double ease_in_back (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;\r
-       double s = params.size() > 0 ? params[0] : 1.70158;\r
-       return c*(t/=d)*t*((s+1)*t - s) + b;\r
-}\r
-       \r
-double ease_out_back (double t, double b, double c, double d, const std::vector<double>& params)\r
-{\r
-       //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;\r
-       double s = params.size() > 0 ? params[0] : 1.70158;\r
-       return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;\r
-}\r
-       \r
-double ease_in_out_back (double t, double b, double c, double d, const std::vector<double>& params)\r
-{\r
-       //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;\r
-       double s = params.size() > 0 ? params[0] : 1.70158;\r
-       if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;\r
-       return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;\r
-}\r
-       \r
-double ease_out_int_back (double t, double b, double c, double d, const std::vector<double>& params)\r
-{\r
-       if (t < d/2) return ease_out_back (t*2, b, c/2, d, params);\r
-       return ease_in_back((t*2)-d, b+c/2, c/2, d, params);\r
-}\r
-       \r
-double ease_out_bounce (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if ((t/=d) < (1/2.75))\r
-               return c*(7.5625*t*t) + b;\r
-       else if (t < (2/2.75))\r
-               return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;\r
-       else if (t < (2.5/2.75))\r
-               return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;\r
-       else \r
-               return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;    \r
-}\r
-       \r
-double ease_in_bounce (double t, double b, double c, double d, const std::vector<double>& params)\r
-{\r
-       return c - ease_out_bounce (d-t, 0, c, d, params) + b;\r
-}\r
-\r
-double ease_in_out_bounce (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t < d/2) return ease_in_bounce (t*2, 0, c, d, params) * .5 + b;\r
-       else return ease_out_bounce (t*2-d, 0, c, d, params) * .5 + c*.5 + b;\r
-}\r
-       \r
-\r
-double ease_out_in_bounce (double t, double b, double c, double d, const std::vector<double>& params) \r
-{\r
-       if (t < d/2) return ease_out_bounce (t*2, b, c/2, d, params);\r
-       return ease_in_bounce((t*2)-d, b+c/2, c/2, d, params);\r
-}\r
-\r
-typedef std::function<double(double, double, double, double, const std::vector<double>&)> tween_t;     \r
-\r
-const std::unordered_map<std::wstring, tween_t>& get_tweens()\r
-{\r
-       static const std::unordered_map<std::wstring, tween_t> tweens = boost::assign::map_list_of      \r
-               (L"",                                   ease_none                  )    \r
-               (L"linear",                             ease_none                  )    \r
-               (L"easenone",                   ease_none                  )\r
-               (L"easeinquad",                 ease_in_quad       )\r
-               (L"easeoutquad",                ease_out_quad      )\r
-               (L"easeinoutquad",              ease_in_out_quad   )\r
-               (L"easeoutinquad",              ease_out_in_quad   )\r
-               (L"easeincubic",                ease_in_cubic      )\r
-               (L"easeoutcubic",               ease_out_cubic     )\r
-               (L"easeinoutcubic",             ease_in_out_cubic  )\r
-               (L"easeoutincubic",             ease_out_in_cubic  )\r
-               (L"easeinquart",                ease_in_quart      )\r
-               (L"easeoutquart",               ease_out_quart     )\r
-               (L"easeinoutquart",             ease_in_out_quart  )\r
-               (L"easeoutinquart",             ease_out_in_quart  )\r
-               (L"easeinquint",                ease_in_quint      )\r
-               (L"easeoutquint",               ease_out_quint     )\r
-               (L"easeinoutquint",             ease_in_out_quint  )\r
-               (L"easeoutinquint",             ease_out_in_quint  )\r
-               (L"easeinsine",                 ease_in_sine       )\r
-               (L"easeoutsine",                ease_out_sine      )\r
-               (L"easeinoutsine",              ease_in_out_sine   )\r
-               (L"easeoutinsine",              ease_out_in_sine   )\r
-               (L"easeinexpo",                 ease_in_expo       )\r
-               (L"easeoutexpo",                ease_out_expo      )\r
-               (L"easeinoutexpo",              ease_in_out_expo   )\r
-               (L"easeoutinexpo",              ease_out_in_expo   )\r
-               (L"easeincirc",                 ease_in_circ       )\r
-               (L"easeoutcirc",                ease_out_circ      )\r
-               (L"easeinoutcirc",              ease_in_out_circ   )\r
-               (L"easeoutincirc",              ease_out_in_circ   )\r
-               (L"easeinelastic",              ease_in_elastic    )\r
-               (L"easeoutelastic",             ease_out_elastic   )\r
-               (L"easeinoutelastic",   ease_in_out_elastic)\r
-               (L"easeoutinelastic",   ease_out_in_elastic)\r
-               (L"easeinback",                 ease_in_back       )\r
-               (L"easeoutback",                ease_out_back      )\r
-               (L"easeinoutback",              ease_in_out_back   )\r
-               (L"easeoutintback",             ease_out_int_back  )\r
-               (L"easeoutbounce",              ease_out_bounce    )\r
-               (L"easeinbounce",               ease_in_bounce     )\r
-               (L"easeinoutbounce",    ease_in_out_bounce )\r
-               (L"easeoutinbounce",    ease_out_in_bounce );\r
-\r
-       return tweens;\r
-}\r
-\r
-tweener_t get_tweener(std::wstring name)\r
-{\r
-       std::transform(name.begin(), name.end(), name.begin(), std::tolower);\r
-\r
-       if(name == L"linear")\r
-               return [](double t, double b, double c, double d){return ease_none(t, b, c, d, std::vector<double>());};\r
-       \r
-       std::vector<double> params;\r
-       \r
-       static const boost::wregex expr(L"(?<NAME>\\w*)(:(?<V0>\\d+\\.?\\d?))?(:(?<V1>\\d+\\.?\\d?))?"); // boost::regex has no repeated captures?\r
-       boost::wsmatch what;\r
-       if(boost::regex_match(name, what, expr))\r
-       {\r
-               name = what["NAME"].str();\r
-               if(what["V0"].matched)\r
-                       params.push_back(boost::lexical_cast<double>(what["V0"].str()));\r
-               if(what["V1"].matched)\r
-                       params.push_back(boost::lexical_cast<double>(what["V1"].str()));\r
-       }\r
-               \r
-       auto tweens = get_tweens();\r
-\r
-       auto it = tweens.find(name);\r
-       if(it == tweens.end())\r
-               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Could not find tween.") << arg_value_info(name));\r
-       \r
-       auto tween = it->second;\r
-       return [=](double t, double b, double c, double d)\r
-       {\r
-               return tween(t, b, c, d, params);\r
-       };\r
-};\r
-\r
-tweener::tweener(const std::wstring& name)\r
-       : func_(get_tweener(name))\r
-{\r
-}\r
-\r
-tweener::tweener(const wchar_t* name)\r
-       : func_(get_tweener(name))\r
-{\r
-}\r
-\r
-double tweener::operator()(double t, double b , double c, double d) const\r
-{\r
-       return func_(t, b, c, d);\r
-}\r
-\r
-const std::vector<std::wstring>& tweener::names()\r
-{\r
-       using namespace boost::adaptors;\r
-\r
-       static const std::vector<std::wstring> names(\r
-               (get_tweens() | map_keys).begin(),\r
-               (get_tweens() | map_keys).end());\r
-\r
-       return names;\r
-}\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+
+// The following code is based on Tweener for actionscript, http://code.google.com/p/tweener/
+//
+//Disclaimer for Robert Penner's Easing Equations license:
+//
+//TERMS OF USE - EASING EQUATIONS
+//
+//Open source under the BSD License.
+//
+//Copyright Â© 2001 Robert Penner
+//All rights reserved.
+//
+//Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+//
+//    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+//    * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+//
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include "stdafx.h"
+
+#include "tweener.h"
+
+#include "except.h"
+
+#include <boost/assign/list_of.hpp>
+#include <boost/regex.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/range/adaptor/map.hpp>
+
+#include <unordered_map>
+#include <string>
+#include <locale>
+#include <functional>
+#include <vector>
+
+namespace caspar { namespace core {
+
+typedef std::function<double(double, double, double, double)> tweener_t;
+                       
+static const double PI = std::atan(1.0)*4.0;
+static const double H_PI = std::atan(1.0)*2.0;
+
+double ease_none (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return c*t/d + b;
+}
+
+double ease_in_quad (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return c*(t/=d)*t + b;
+}
+       
+double ease_out_quad (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return -c *(t/=d)*(t-2) + b;
+}      
+
+double ease_in_out_quad (double t, double b, double c, double d, const std::vector<double>& params)
+{
+       if ((t/=d/2) < 1) 
+               return c/2*t*t + b;
+
+       return -c/2 * ((--t)*(t-2) - 1) + b;
+}      
+
+double ease_out_in_quad (double t, double b, double c, double d, const std::vector<double>& params)
+{
+       if (t < d/2) 
+               return ease_out_quad (t*2, b, c/2, d, params);
+
+       return ease_in_quad((t*2)-d, b+c/2, c/2, d, params);
+}
+       
+double ease_in_cubic (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return c*(t/=d)*t*t + b;
+}      
+
+double ease_out_cubic (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return c*((t=t/d-1)*t*t + 1) + b;
+}
+       
+double ease_in_out_cubic (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if ((t/=d/2) < 1) 
+               return c/2*t*t*t + b;
+
+       return c/2*((t-=2)*t*t + 2) + b;
+}
+       
+double ease_out_in_cubic (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t < d/2) return ease_out_cubic (t*2, b, c/2, d, params);
+       return ease_in_cubic((t*2)-d, b+c/2, c/2, d, params);
+}
+       
+double ease_in_quart (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return c*(t/=d)*t*t*t + b;
+}
+       
+double ease_out_quart (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return -c * ((t=t/d-1)*t*t*t - 1) + b;
+}      
+
+double ease_in_out_quart (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if ((t/=d/2) < 1)
+               return c/2*t*t*t*t + b;
+
+       return -c/2 * ((t-=2)*t*t*t - 2) + b;
+}      
+
+double ease_out_in_quart (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t < d/2)
+               return ease_out_quart (t*2, b, c/2, d, params);
+
+       return ease_in_quart((t*2)-d, b+c/2, c/2, d, params);
+}      
+
+double ease_in_quint (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return c*(t/=d)*t*t*t*t + b;
+}
+       
+double ease_out_quint (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return c*((t=t/d-1)*t*t*t*t + 1) + b;
+}
+       
+double ease_in_out_quint (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if ((t/=d/2) < 1) 
+               return c/2*t*t*t*t*t + b;
+
+       return c/2*((t-=2)*t*t*t*t + 2) + b;
+}
+       
+double ease_out_in_quint (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t < d/2) 
+               return ease_out_quint (t*2, b, c/2, d, params);
+
+       return ease_in_quint((t*2)-d, b+c/2, c/2, d, params);
+}      
+
+double ease_in_sine (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return -c * std::cos(t/d * (PI/2)) + c + b;
+}      
+
+double ease_out_sine (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return c * std::sin(t/d * (PI/2)) + b;
+}      
+
+double ease_in_out_sine (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return -c/2 * (std::cos(PI*t/d) - 1) + b;
+}      
+
+double ease_out_in_sine (double t, double b, double c, double d, const std::vector<double>& params)
+{
+       if (t < d/2) 
+               return ease_out_sine (t*2, b, c/2, d, params);
+       
+       return ease_in_sine((t*2)-d, b+c/2, c/2, d, params);
+}      
+
+double ease_in_expo (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return (t==0) ? b : c * std::pow(2, 10 * (t/d - 1)) + b - c * 0.001;
+}      
+
+double ease_out_expo (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return (t==d) ? b+c : c * 1.001 * (-std::pow(2, -10 * t/d) + 1) + b;
+}
+       
+double ease_in_out_expo (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t==0) 
+               return b;
+       if (t==d) 
+               return b+c;
+       if ((t/=d/2) < 1) 
+               return c/2 * std::pow(2, 10 * (t - 1)) + b - c * 0.0005;
+
+       return c/2 * 1.0005 * (-std::pow(2, -10 * --t) + 2) + b;
+}
+       
+double ease_out_in_expo (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t < d/2) 
+               return ease_out_expo (t*2, b, c/2, d, params);
+
+       return ease_in_expo((t*2)-d, b+c/2, c/2, d, params);
+}
+       
+double ease_in_circ (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return -c * (std::sqrt(1 - (t/=d)*t) - 1) + b;
+}
+       
+double ease_out_circ (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       return c * std::sqrt(1 - (t=t/d-1)*t) + b;
+}
+       
+double ease_in_out_circ (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if ((t/=d/2) < 1) 
+               return -c/2 * (std::sqrt(1 - t*t) - 1) + b;
+
+       return c/2 * (std::sqrt(1 - (t-=2)*t) + 1) + b;
+}
+       
+double ease_out_in_circ (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t < d/2) return ease_out_circ(t*2, b, c/2, d, params);
+       return ease_in_circ((t*2)-d, b+c/2, c/2, d, params);
+}
+       
+double ease_in_elastic (double t, double b, double c, double d, const std::vector<double>& params)
+{
+       if (t==0) return b;
+       if ((t/=d)==1) return b+c;
+       //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*.3 : p_params.period;
+       //var s:Number;
+       //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;
+       double p = params.size() > 0 ? params[0] : d*0.3;
+       double s;
+       double a = params.size() > 1 ? params[1] : 0.0;
+       if (a == 0.0 || a < std::abs(c)) 
+       {
+               a = c;
+               s = p/4;
+       } 
+       else 
+               s = p/(2*PI) * std::asin (c/a);
+       
+       return -(a*std::pow(2,10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )) + b;
+}
+       
+double ease_out_elastic (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t==0) 
+               return b;
+       if ((t/=d)==1) 
+               return b+c;
+       //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*.3 : p_params.period;
+       //var s:Number;
+       //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;
+       double p = params.size() > 0 ? params[0] : d*0.3;
+       double s;
+       double a = params.size() > 1 ? params[1] : 0.0;
+       if (a == 0.0 || a < std::abs(c))
+       {
+               a = c;
+               s = p/4;
+       } 
+       else 
+               s = p/(2*PI) * std::asin (c/a);
+       
+       return (a*std::pow(2,-10*t) * std::sin( (t*d-s)*(2*PI)/p ) + c + b);
+}      
+
+double ease_in_out_elastic (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t==0)
+               return b;
+       if ((t/=d/2)==2) 
+               return b+c;
+       //var p:Number = !Boolean(p_params) || isNaN(p_params.period) ? d*(.3*1.5) : p_params.period;
+       //var s:Number;
+       //var a:Number = !Boolean(p_params) || isNaN(p_params.amplitude) ? 0 : p_params.amplitude;
+       double p = params.size() > 0 ? params[0] : d*0.3*1.5;
+       double s;
+       double a = params.size() > 1 ? params[1] : 0.0;
+       if (a == 0.0 || a < std::abs(c)) 
+       {
+               a = c;
+               s = p/4;
+       }
+       else
+               s = p/(2*PI) * std::asin (c/a);
+       
+       if (t < 1) 
+               return -.5*(a*std::pow(2,10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )) + b;
+
+       return a*std::pow(2,-10*(t-=1)) * std::sin( (t*d-s)*(2*PI)/p )*.5 + c + b;
+}
+       
+double ease_out_in_elastic (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t < d/2) return ease_out_elastic (t*2, b, c/2, d, params);
+       return ease_in_elastic((t*2)-d, b+c/2, c/2, d, params);
+}
+       
+double ease_in_back (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;
+       double s = params.size() > 0 ? params[0] : 1.70158;
+       return c*(t/=d)*t*((s+1)*t - s) + b;
+}
+       
+double ease_out_back (double t, double b, double c, double d, const std::vector<double>& params)
+{
+       //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;
+       double s = params.size() > 0 ? params[0] : 1.70158;
+       return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
+}
+       
+double ease_in_out_back (double t, double b, double c, double d, const std::vector<double>& params)
+{
+       //var s:Number = !Boolean(p_params) || isNaN(p_params.overshoot) ? 1.70158 : p_params.overshoot;
+       double s = params.size() > 0 ? params[0] : 1.70158;
+       if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
+       return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
+}
+       
+double ease_out_int_back (double t, double b, double c, double d, const std::vector<double>& params)
+{
+       if (t < d/2) return ease_out_back (t*2, b, c/2, d, params);
+       return ease_in_back((t*2)-d, b+c/2, c/2, d, params);
+}
+       
+double ease_out_bounce (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if ((t/=d) < (1/2.75))
+               return c*(7.5625*t*t) + b;
+       else if (t < (2/2.75))
+               return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
+       else if (t < (2.5/2.75))
+               return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
+       else 
+               return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;    
+}
+       
+double ease_in_bounce (double t, double b, double c, double d, const std::vector<double>& params)
+{
+       return c - ease_out_bounce (d-t, 0, c, d, params) + b;
+}
+
+double ease_in_out_bounce (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t < d/2) return ease_in_bounce (t*2, 0, c, d, params) * .5 + b;
+       else return ease_out_bounce (t*2-d, 0, c, d, params) * .5 + c*.5 + b;
+}
+       
+
+double ease_out_in_bounce (double t, double b, double c, double d, const std::vector<double>& params) 
+{
+       if (t < d/2) return ease_out_bounce (t*2, b, c/2, d, params);
+       return ease_in_bounce((t*2)-d, b+c/2, c/2, d, params);
+}
+
+typedef std::function<double(double, double, double, double, const std::vector<double>&)> tween_t;     
+
+const std::unordered_map<std::wstring, tween_t>& get_tweens()
+{
+       static const std::unordered_map<std::wstring, tween_t> tweens = boost::assign::map_list_of      
+               (L"",                                   ease_none                  )    
+               (L"linear",                             ease_none                  )    
+               (L"easenone",                   ease_none                  )
+               (L"easeinquad",                 ease_in_quad       )
+               (L"easeoutquad",                ease_out_quad      )
+               (L"easeinoutquad",              ease_in_out_quad   )
+               (L"easeoutinquad",              ease_out_in_quad   )
+               (L"easeincubic",                ease_in_cubic      )
+               (L"easeoutcubic",               ease_out_cubic     )
+               (L"easeinoutcubic",             ease_in_out_cubic  )
+               (L"easeoutincubic",             ease_out_in_cubic  )
+               (L"easeinquart",                ease_in_quart      )
+               (L"easeoutquart",               ease_out_quart     )
+               (L"easeinoutquart",             ease_in_out_quart  )
+               (L"easeoutinquart",             ease_out_in_quart  )
+               (L"easeinquint",                ease_in_quint      )
+               (L"easeoutquint",               ease_out_quint     )
+               (L"easeinoutquint",             ease_in_out_quint  )
+               (L"easeoutinquint",             ease_out_in_quint  )
+               (L"easeinsine",                 ease_in_sine       )
+               (L"easeoutsine",                ease_out_sine      )
+               (L"easeinoutsine",              ease_in_out_sine   )
+               (L"easeoutinsine",              ease_out_in_sine   )
+               (L"easeinexpo",                 ease_in_expo       )
+               (L"easeoutexpo",                ease_out_expo      )
+               (L"easeinoutexpo",              ease_in_out_expo   )
+               (L"easeoutinexpo",              ease_out_in_expo   )
+               (L"easeincirc",                 ease_in_circ       )
+               (L"easeoutcirc",                ease_out_circ      )
+               (L"easeinoutcirc",              ease_in_out_circ   )
+               (L"easeoutincirc",              ease_out_in_circ   )
+               (L"easeinelastic",              ease_in_elastic    )
+               (L"easeoutelastic",             ease_out_elastic   )
+               (L"easeinoutelastic",   ease_in_out_elastic)
+               (L"easeoutinelastic",   ease_out_in_elastic)
+               (L"easeinback",                 ease_in_back       )
+               (L"easeoutback",                ease_out_back      )
+               (L"easeinoutback",              ease_in_out_back   )
+               (L"easeoutintback",             ease_out_int_back  )
+               (L"easeoutbounce",              ease_out_bounce    )
+               (L"easeinbounce",               ease_in_bounce     )
+               (L"easeinoutbounce",    ease_in_out_bounce )
+               (L"easeoutinbounce",    ease_out_in_bounce );
+
+       return tweens;
+}
+
+tweener_t get_tweener(std::wstring name)
+{
+       std::transform(name.begin(), name.end(), name.begin(), std::tolower);
+
+       if(name == L"linear")
+               return [](double t, double b, double c, double d){return ease_none(t, b, c, d, std::vector<double>());};
+       
+       std::vector<double> params;
+       
+       static const boost::wregex expr(L"(?<NAME>\\w*)(:(?<V0>\\d+\\.?\\d?))?(:(?<V1>\\d+\\.?\\d?))?"); // boost::regex has no repeated captures?
+       boost::wsmatch what;
+       if(boost::regex_match(name, what, expr))
+       {
+               name = what["NAME"].str();
+               if(what["V0"].matched)
+                       params.push_back(boost::lexical_cast<double>(what["V0"].str()));
+               if(what["V1"].matched)
+                       params.push_back(boost::lexical_cast<double>(what["V1"].str()));
+       }
+               
+       auto tweens = get_tweens();
+
+       auto it = tweens.find(name);
+       if(it == tweens.end())
+               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Could not find tween.") << arg_value_info(name));
+       
+       auto tween = it->second;
+       return [=](double t, double b, double c, double d)
+       {
+               return tween(t, b, c, d, params);
+       };
+};
+
+tweener::tweener(const std::wstring& name)
+       : func_(get_tweener(name))
+{
+}
+
+tweener::tweener(const wchar_t* name)
+       : func_(get_tweener(name))
+{
+}
+
+double tweener::operator()(double t, double b , double c, double d) const
+{
+       return func_(t, b, c, d);
+}
+
+const std::vector<std::wstring>& tweener::names()
+{
+       using namespace boost::adaptors;
+
+       static const std::vector<std::wstring> names(
+               (get_tweens() | map_keys).begin(),
+               (get_tweens() | map_keys).end());
+
+       return names;
+}
+
+}}
index 25833b5030a6e0631b4e40fe941edc1383a51a17..765163013d3107e9dd8595657e957cc8b66d7bed 100644 (file)
@@ -1,80 +1,80 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <functional>\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
-\r
-/**\r
- * A tweener can be used for creating any kind of (image position, image fade\r
- * in/out, audio volume etc) transition, by invoking it for each temporal\r
- * timepoint when a tweened value is needed.\r
- *\r
- * For video the temporal resolution will usually be each frame or field (for\r
- * interlaced material).\r
- *\r
- * For audio the smoothest transitions will be generated by using the samplerate\r
- * as temporal resolution, but using the video frame/field rate is probably fine\r
- * most of the times and much less time consuming.\r
- */\r
-class tweener\r
-{\r
-public:\r
-       /**\r
-        * Constructor.\r
-        *\r
-        * @param name The name of the tween function to use.\r
-        */\r
-       tweener(const std::wstring& name = L"linear");\r
-       tweener(const wchar_t* name);\r
-\r
-       /**\r
-        * @return The possible tween function names. Some of them may also support\r
-        *                 additional parameters appended to the name.\r
-        */\r
-       static const std::vector<std::wstring>& names();\r
-\r
-       /**\r
-        * Calculate a tweened value given a timepoint within the total duration\r
-        * and the starting value and the destination delta value.\r
-        *\r
-        * Usually b, c and d remains constant during a transition, while t changes\r
-        * for each temporal tweened value.\r
-        * \r
-        * @param t     The timepoint within the total duration (0 <= n <= d).\r
-        * @param b     The starting value.\r
-        * @param c     The destination value delta from the starting value\r
-        *              (absolute destination value - b).\r
-        * @param d The total duration (when t = d, the destination value should\r
-        *              have been reached).\r
-        *\r
-        * @return The tweened value for the given timepoint. Can sometimes be less\r
-        *             than b or greater than b + c for some tweener functions.\r
-        */\r
-       double operator()(double t, double b , double c, double d) const;\r
-private:\r
-       std::function<double(double, double, double, double)> func_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <functional>
+#include <vector>
+
+namespace caspar { namespace core {
+
+/**
+ * A tweener can be used for creating any kind of (image position, image fade
+ * in/out, audio volume etc) transition, by invoking it for each temporal
+ * timepoint when a tweened value is needed.
+ *
+ * For video the temporal resolution will usually be each frame or field (for
+ * interlaced material).
+ *
+ * For audio the smoothest transitions will be generated by using the samplerate
+ * as temporal resolution, but using the video frame/field rate is probably fine
+ * most of the times and much less time consuming.
+ */
+class tweener
+{
+public:
+       /**
+        * Constructor.
+        *
+        * @param name The name of the tween function to use.
+        */
+       tweener(const std::wstring& name = L"linear");
+       tweener(const wchar_t* name);
+
+       /**
+        * @return The possible tween function names. Some of them may also support
+        *                 additional parameters appended to the name.
+        */
+       static const std::vector<std::wstring>& names();
+
+       /**
+        * Calculate a tweened value given a timepoint within the total duration
+        * and the starting value and the destination delta value.
+        *
+        * Usually b, c and d remains constant during a transition, while t changes
+        * for each temporal tweened value.
+        * 
+        * @param t     The timepoint within the total duration (0 <= n <= d).
+        * @param b     The starting value.
+        * @param c     The destination value delta from the starting value
+        *              (absolute destination value - b).
+        * @param d The total duration (when t = d, the destination value should
+        *              have been reached).
+        *
+        * @return The tweened value for the given timepoint. Can sometimes be less
+        *             than b or greater than b + c for some tweener functions.
+        */
+       double operator()(double t, double b , double c, double d) const;
+private:
+       std::function<double(double, double, double, double)> func_;
+};
+
 }}
\ No newline at end of file
index b453a044c440359d217b6626bbe116de5e67d313..4b8c65fd6e8beb2c1e342f83be389458b0afe420 100644 (file)
@@ -1,52 +1,52 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "stdafx.h"\r
-\r
-#include "utf.h"\r
-\r
-#pragma warning(push, 1)\r
-\r
-#include <boost/locale.hpp>\r
-\r
-namespace caspar {\r
-       \r
-std::wstring u16(const std::string& str)\r
-{\r
-       return boost::locale::conv::utf_to_utf<wchar_t>(str);//std::wstring(str.begin(), str.end());\r
-}\r
-\r
-std::wstring u16(const std::wstring& str)\r
-{\r
-       return str;\r
-}\r
-          \r
-std::string u8(const std::wstring& str)\r
-{\r
-       return boost::locale::conv::utf_to_utf<char>(str);//std::string(str.begin(), str.end());\r
-}\r
-          \r
-std::string u8(const std::string& str)\r
-{\r
-       return str ;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "stdafx.h"
+
+#include "utf.h"
+
+#pragma warning(push, 1)
+
+#include <boost/locale.hpp>
+
+namespace caspar {
+       
+std::wstring u16(const std::string& str)
+{
+       return boost::locale::conv::utf_to_utf<wchar_t>(str);//std::wstring(str.begin(), str.end());
+}
+
+std::wstring u16(const std::wstring& str)
+{
+       return str;
+}
+          
+std::string u8(const std::wstring& str)
+{
+       return boost::locale::conv::utf_to_utf<char>(str);//std::string(str.begin(), str.end());
+}
+          
+std::string u8(const std::string& str)
+{
+       return str ;
+}
+
 }
\ No newline at end of file
index 776d495a784de0d79894c34f95cabaf60275309d..942d431ff8c2f7d39ca967dcbed972c2fedd9ce8 100644 (file)
@@ -1,33 +1,33 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <string>\r
-          \r
-namespace caspar {\r
-\r
-std::wstring u16(const std::string& str);\r
-std::wstring u16(const std::wstring& str);\r
-std::string u8(const std::wstring& str);          \r
-std::string u8(const std::string& str);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <string>
+          
+namespace caspar {
+
+std::wstring u16(const std::string& str);
+std::wstring u16(const std::wstring& str);
+std::string u8(const std::wstring& str);          
+std::string u8(const std::string& str);
+
 }
\ No newline at end of file
index f2b946afaae3a37fd2191bec9f0ffa048cfadf85..218fe591a7ddb4d67eced93069b6420d8f13e368 100644 (file)
@@ -1,22 +1,22 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
 #include "stdafx.h"
\ No newline at end of file
index ff33505b0b99c5d3d2d50199b6259984d254bcbd..31ea7b85850a7217a9f1c3d1038f4aa4287e0563 100644 (file)
@@ -1,65 +1,65 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#ifdef _DEBUG\r
-#include <crtdbg.h>\r
-#endif\r
-\r
-#define NOMINMAX\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
-#include <GL/glew.h>\r
-\r
-#include <algorithm>\r
-#include <array>\r
-#include <functional>\r
-#include <deque>\r
-#include <map>\r
-#include <memory>\r
-#include <queue>\r
-#include <string>\r
-#include <vector>\r
-\r
-#include <tbb/atomic.h>\r
-#include <tbb/concurrent_queue.h>\r
-#include <tbb/concurrent_unordered_map.h>\r
-\r
-#include <boost/assign.hpp>\r
-#include <boost/circular_buffer.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/range.hpp>\r
-#include <boost/range/adaptors.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/thread.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/property_tree/xml_parser.hpp>\r
-\r
-#include <common/assert.h>\r
-#include <common/utf.h>\r
-#include <common/memory.h>\r
-//#include "../common/executor.h" // Can't include this due to MSVC lambda bug\r
-\r
-#include <common/log.h>\r
-#include <common/except.h>\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+
+#include <GL/glew.h>
+
+#include <algorithm>
+#include <array>
+#include <functional>
+#include <deque>
+#include <map>
+#include <memory>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include <tbb/atomic.h>
+#include <tbb/concurrent_queue.h>
+#include <tbb/concurrent_unordered_map.h>
+
+#include <boost/assign.hpp>
+#include <boost/circular_buffer.hpp>
+#include <boost/timer.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/range.hpp>
+#include <boost/range/adaptors.hpp>
+#include <boost/range/algorithm.hpp>
+#include <boost/thread.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+
+#include <common/assert.h>
+#include <common/utf.h>
+#include <common/memory.h>
+//#include "../common/executor.h" // Can't include this due to MSVC lambda bug
+
+#include <common/log.h>
+#include <common/except.h>
index 02369f8a75b310ccb2494c7ef7f507f4762f718e..a2593eb2d35c806bfd418d9c70f8e48b2d148819 100644 (file)
@@ -1,47 +1,47 @@
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-*  This file is part of CasparCG.\r
-*\r
-*    CasparCG is free software: you can redistribute it and/or modify\r
-*    it under the terms of the GNU General Public License as published by\r
-*    the Free Software Foundation, either version 3 of the License, or\r
-*    (at your option) any later version.\r
-*\r
-*    CasparCG is distributed in the hope that it will be useful,\r
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-*    GNU General Public License for more details.\r
-\r
-*    You should have received a copy of the GNU General Public License\r
-*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
-#pragma once\r
-\r
-#include <common/memory/safe_ptr.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-#include <boost/range/iterator_range.hpp>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-class read_frame : boost::noncopyable\r
-{\r
-public:\r
-       virtual const boost::iterator_range<const unsigned char*> image_data() const = 0;\r
-       virtual const boost::iterator_range<const short*> audio_data() const = 0;\r
-\r
-       static safe_ptr<const read_frame> empty()\r
-       {\r
-               struct empty : public read_frame\r
-               {                       \r
-                       virtual const boost::iterator_range<const unsigned char*> image_data() const {return boost::iterator_range<const unsigned char*>();}\r
-                       virtual const boost::iterator_range<const short*> audio_data() const {return boost::iterator_range<const short*>();}\r
-               };\r
-               static safe_ptr<const empty> frame;\r
-               return frame;\r
-       }\r
-};\r
-\r
+/*
+* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
+*
+*  This file is part of CasparCG.
+*
+*    CasparCG is free software: you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation, either version 3 of the License, or
+*    (at your option) any later version.
+*
+*    CasparCG is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+
+*    You should have received a copy of the GNU General Public License
+*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+#pragma once
+
+#include <common/memory/safe_ptr.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/range/iterator_range.hpp>
+
+namespace caspar { namespace core {
+       
+class read_frame : boost::noncopyable
+{
+public:
+       virtual const boost::iterator_range<const unsigned char*> image_data() const = 0;
+       virtual const boost::iterator_range<const short*> audio_data() const = 0;
+
+       static safe_ptr<const read_frame> empty()
+       {
+               struct empty : public read_frame
+               {                       
+                       virtual const boost::iterator_range<const unsigned char*> image_data() const {return boost::iterator_range<const unsigned char*>();}
+                       virtual const boost::iterator_range<const short*> audio_data() const {return boost::iterator_range<const short*>();}
+               };
+               static safe_ptr<const empty> frame;
+               return frame;
+       }
+};
+
 }}
\ No newline at end of file
index ec75e99c92ef83c3ea96958a168d2b2997a35802..72aa407303a11cf2d26e4edfd4de17095ad1018b 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../StdAfx.h"\r
-\r
-#include "frame_consumer.h"\r
-\r
-#include <common/except.h>\r
-\r
-#include <core/video_format.h>\r
-#include <core/frame/frame.h>\r
-\r
-#include <boost/thread.hpp>\r
-\r
-namespace caspar { namespace core {\r
-               \r
-std::vector<const consumer_factory_t> g_factories;\r
-\r
-void register_consumer_factory(const consumer_factory_t& factory)\r
-{\r
-       g_factories.push_back(factory);\r
-}\r
-\r
-class destroy_consumer_proxy : public frame_consumer\r
-{      \r
-       std::shared_ptr<frame_consumer> consumer_;\r
-public:\r
-       destroy_consumer_proxy(spl::shared_ptr<frame_consumer>&& consumer) \r
-               : consumer_(std::move(consumer))\r
-       {\r
-       }\r
-\r
-       ~destroy_consumer_proxy()\r
-       {               \r
-               static tbb::atomic<int> counter = tbb::atomic<int>();\r
-                       \r
-               ++counter;\r
-               CASPAR_VERIFY(counter < 8);\r
-               \r
-               auto consumer = new std::shared_ptr<frame_consumer>(std::move(consumer_));\r
-               boost::thread([=]\r
-               {\r
-                       std::unique_ptr<std::shared_ptr<frame_consumer>> pointer_guard(consumer);\r
-\r
-                       auto str = (*consumer)->print();\r
-                       try\r
-                       {\r
-                               if(!consumer->unique())\r
-                                       CASPAR_LOG(trace) << str << L" Not destroyed on asynchronous destruction thread: " << consumer->use_count();\r
-                               else\r
-                                       CASPAR_LOG(trace) << str << L" Destroying on asynchronous destruction thread.";\r
-                       }\r
-                       catch(...){}\r
-\r
-                       pointer_guard.reset();\r
-\r
-                       --counter;\r
-               }).detach(); \r
-       }\r
-       \r
-       bool send(const_frame frame) override                                                                                                                           {return consumer_->send(std::move(frame));}\r
-       virtual void initialize(const struct video_format_desc& format_desc, int channel_index) override        {return consumer_->initialize(format_desc, channel_index);}\r
-       std::wstring print() const override                                                                                                                                     {return consumer_->print();}    \r
-       std::wstring name() const override                                                                                                                                      {return consumer_->name();}\r
-       boost::property_tree::wptree info() const override                                                                                                      {return consumer_->info();}\r
-       bool has_synchronization_clock() const override                                                                                                         {return consumer_->has_synchronization_clock();}\r
-       int buffer_depth() const override                                                                                                                                       {return consumer_->buffer_depth();}\r
-       int index() const override                                                                                                                                                      {return consumer_->index();}\r
-       void subscribe(const monitor::observable::observer_ptr& o) override                                                                     {consumer_->subscribe(o);}\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override                                                           {consumer_->unsubscribe(o);}                    \r
-};\r
-\r
-class print_consumer_proxy : public frame_consumer\r
-{      \r
-       std::shared_ptr<frame_consumer> consumer_;\r
-public:\r
-       print_consumer_proxy(spl::shared_ptr<frame_consumer>&& consumer) \r
-               : consumer_(std::move(consumer))\r
-       {\r
-               CASPAR_LOG(info) << consumer_->print() << L" Initialized.";\r
-       }\r
-\r
-       ~print_consumer_proxy()\r
-       {               \r
-               auto str = consumer_->print();\r
-               CASPAR_LOG(trace) << str << L" Uninitializing.";\r
-               consumer_.reset();\r
-               CASPAR_LOG(info) << str << L" Uninitialized.";\r
-       }\r
-       \r
-       bool send(const_frame frame) override                                                                                                   {return consumer_->send(std::move(frame));}\r
-       virtual void initialize(const struct video_format_desc& format_desc, int channel_index) override        {return consumer_->initialize(format_desc, channel_index);}\r
-       std::wstring print() const override                                                                                                                     {return consumer_->print();}\r
-       std::wstring name() const override                                                                                                                      {return consumer_->name();}\r
-       boost::property_tree::wptree info() const override                                                                                      {return consumer_->info();}\r
-       bool has_synchronization_clock() const override                                                                                         {return consumer_->has_synchronization_clock();}\r
-       int buffer_depth() const override                                                                                                                       {return consumer_->buffer_depth();}\r
-       int index() const override                                                                                                                                      {return consumer_->index();}\r
-       void subscribe(const monitor::observable::observer_ptr& o) override                                                                     {consumer_->subscribe(o);}\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override                                                           {consumer_->unsubscribe(o);}    \r
-};\r
-\r
-class recover_consumer_proxy : public frame_consumer\r
-{      \r
-       std::shared_ptr<frame_consumer> consumer_;\r
-       int                                                             channel_index_;\r
-       video_format_desc                               format_desc_;\r
-public:\r
-       recover_consumer_proxy(spl::shared_ptr<frame_consumer>&& consumer) \r
-               : consumer_(std::move(consumer))\r
-       {\r
-       }\r
-       \r
-       virtual bool send(const_frame frame)                                    \r
-       {\r
-               try\r
-               {\r
-                       return consumer_->send(frame);\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       try\r
-                       {\r
-                               consumer_->initialize(format_desc_, channel_index_);\r
-                               return consumer_->send(frame);\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                               CASPAR_LOG(error) << print() << " Failed to recover consumer.";\r
-                               return false;\r
-                       }\r
-               }\r
-       }\r
-\r
-       virtual void initialize(const struct video_format_desc& format_desc, int channel_index)         \r
-       {\r
-               format_desc_    = format_desc;\r
-               channel_index_  = channel_index;\r
-               return consumer_->initialize(format_desc, channel_index);\r
-       }\r
-\r
-       std::wstring print() const override                                                                             {return consumer_->print();}\r
-       std::wstring name() const override                                                                              {return consumer_->name();}\r
-       boost::property_tree::wptree info() const override                                              {return consumer_->info();}\r
-       bool has_synchronization_clock() const override                                                 {return consumer_->has_synchronization_clock();}\r
-       int buffer_depth() const override                                                                               {return consumer_->buffer_depth();}\r
-       int index() const override                                                                                              {return consumer_->index();}\r
-       void subscribe(const monitor::observable::observer_ptr& o) override             {consumer_->subscribe(o);}\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override   {consumer_->unsubscribe(o);}    \r
-};\r
-\r
-// This class is used to guarantee that audio cadence is correct. This is important for NTSC audio.\r
-class cadence_guard : public frame_consumer\r
-{\r
-       spl::shared_ptr<frame_consumer>         consumer_;\r
-       std::vector<int>                                        audio_cadence_;\r
-       boost::circular_buffer<std::size_t>     sync_buffer_;\r
-public:\r
-       cadence_guard(const spl::shared_ptr<frame_consumer>& consumer)\r
-               : consumer_(consumer)\r
-       {\r
-       }\r
-       \r
-       void initialize(const video_format_desc& format_desc, int channel_index) override\r
-       {\r
-               audio_cadence_  = format_desc.audio_cadence;\r
-               sync_buffer_    = boost::circular_buffer<std::size_t>(format_desc.audio_cadence.size());\r
-               consumer_->initialize(format_desc, channel_index);\r
-       }\r
-\r
-       bool send(const_frame frame) override\r
-       {               \r
-               if(audio_cadence_.size() == 1)\r
-                       return consumer_->send(frame);\r
-\r
-               bool result = true;\r
-               \r
-               if(boost::range::equal(sync_buffer_, audio_cadence_) && audio_cadence_.front() == static_cast<int>(frame.audio_data().size())) \r
-               {       \r
-                       // Audio sent so far is in sync, now we can send the next chunk.\r
-                       result = consumer_->send(frame);\r
-                       boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
-               }\r
-               else\r
-                       CASPAR_LOG(trace) << print() << L" Syncing audio.";\r
-\r
-               sync_buffer_.push_back(static_cast<int>(frame.audio_data().size()));\r
-               \r
-               return result;\r
-       }\r
-       \r
-       std::wstring print() const override                                                                             {return consumer_->print();}\r
-       std::wstring name() const override                                                                              {return consumer_->name();}\r
-       boost::property_tree::wptree info() const override                                              {return consumer_->info();}\r
-       bool has_synchronization_clock() const override                                                 {return consumer_->has_synchronization_clock();}\r
-       int buffer_depth() const override                                                                               {return consumer_->buffer_depth();}\r
-       int index() const override                                                                                              {return consumer_->index();}\r
-       void subscribe(const monitor::observable::observer_ptr& o) override             {consumer_->subscribe(o);}\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override   {consumer_->unsubscribe(o);}    \r
-};\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)\r
-{\r
-       if(params.empty())\r
-               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));\r
-       \r
-       auto consumer = frame_consumer::empty();\r
-       std::any_of(g_factories.begin(), g_factories.end(), [&](const consumer_factory_t& factory) -> bool\r
-               {\r
-                       try\r
-                       {\r
-                               consumer = factory(params);\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }\r
-                       return consumer != frame_consumer::empty();\r
-               });\r
-\r
-       if(consumer == frame_consumer::empty())\r
-               CASPAR_THROW_EXCEPTION(file_not_found() << msg_info("No match found for supplied commands. Check syntax."));\r
-\r
-       return spl::make_shared<destroy_consumer_proxy>(\r
-                       spl::make_shared<print_consumer_proxy>(\r
-                        spl::make_shared<recover_consumer_proxy>(\r
-                         spl::make_shared<cadence_guard>(\r
-                          std::move(consumer)))));\r
-}\r
-\r
-const spl::shared_ptr<frame_consumer>& frame_consumer::empty()\r
-{\r
-       class empty_frame_consumer : public frame_consumer\r
-       {\r
-       public:\r
-               bool send(const_frame) override {return false;}\r
-               void initialize(const video_format_desc&, int) override{}\r
-               std::wstring print() const override {return L"empty";}\r
-               std::wstring name() const override {return L"empty";}\r
-               bool has_synchronization_clock() const override {return false;}\r
-               int buffer_depth() const override {return 0;};\r
-               virtual int index() const{return -1;}\r
-               void subscribe(const monitor::observable::observer_ptr& o) override{}\r
-               void unsubscribe(const monitor::observable::observer_ptr& o) override{}\r
-               boost::property_tree::wptree info() const override\r
-               {\r
-                       boost::property_tree::wptree info;\r
-                       info.add(L"type", L"empty");\r
-                       return info;\r
-               }\r
-       };\r
-       static spl::shared_ptr<frame_consumer> consumer = spl::make_shared<empty_frame_consumer>();\r
-       return consumer;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../StdAfx.h"
+
+#include "frame_consumer.h"
+
+#include <common/except.h>
+
+#include <core/video_format.h>
+#include <core/frame/frame.h>
+
+#include <boost/thread.hpp>
+
+namespace caspar { namespace core {
+               
+std::vector<const consumer_factory_t> g_factories;
+
+void register_consumer_factory(const consumer_factory_t& factory)
+{
+       g_factories.push_back(factory);
+}
+
+class destroy_consumer_proxy : public frame_consumer
+{      
+       std::shared_ptr<frame_consumer> consumer_;
+public:
+       destroy_consumer_proxy(spl::shared_ptr<frame_consumer>&& consumer) 
+               : consumer_(std::move(consumer))
+       {
+       }
+
+       ~destroy_consumer_proxy()
+       {               
+               static tbb::atomic<int> counter = tbb::atomic<int>();
+                       
+               ++counter;
+               CASPAR_VERIFY(counter < 8);
+               
+               auto consumer = new std::shared_ptr<frame_consumer>(std::move(consumer_));
+               boost::thread([=]
+               {
+                       std::unique_ptr<std::shared_ptr<frame_consumer>> pointer_guard(consumer);
+
+                       auto str = (*consumer)->print();
+                       try
+                       {
+                               if(!consumer->unique())
+                                       CASPAR_LOG(trace) << str << L" Not destroyed on asynchronous destruction thread: " << consumer->use_count();
+                               else
+                                       CASPAR_LOG(trace) << str << L" Destroying on asynchronous destruction thread.";
+                       }
+                       catch(...){}
+
+                       pointer_guard.reset();
+
+                       --counter;
+               }).detach(); 
+       }
+       
+       bool send(const_frame frame) override                                                                                                                           {return consumer_->send(std::move(frame));}
+       virtual void initialize(const struct video_format_desc& format_desc, int channel_index) override        {return consumer_->initialize(format_desc, channel_index);}
+       std::wstring print() const override                                                                                                                                     {return consumer_->print();}    
+       std::wstring name() const override                                                                                                                                      {return consumer_->name();}
+       boost::property_tree::wptree info() const override                                                                                                      {return consumer_->info();}
+       bool has_synchronization_clock() const override                                                                                                         {return consumer_->has_synchronization_clock();}
+       int buffer_depth() const override                                                                                                                                       {return consumer_->buffer_depth();}
+       int index() const override                                                                                                                                                      {return consumer_->index();}
+       void subscribe(const monitor::observable::observer_ptr& o) override                                                                     {consumer_->subscribe(o);}
+       void unsubscribe(const monitor::observable::observer_ptr& o) override                                                           {consumer_->unsubscribe(o);}                    
+};
+
+class print_consumer_proxy : public frame_consumer
+{      
+       std::shared_ptr<frame_consumer> consumer_;
+public:
+       print_consumer_proxy(spl::shared_ptr<frame_consumer>&& consumer) 
+               : consumer_(std::move(consumer))
+       {
+               CASPAR_LOG(info) << consumer_->print() << L" Initialized.";
+       }
+
+       ~print_consumer_proxy()
+       {               
+               auto str = consumer_->print();
+               CASPAR_LOG(trace) << str << L" Uninitializing.";
+               consumer_.reset();
+               CASPAR_LOG(info) << str << L" Uninitialized.";
+       }
+       
+       bool send(const_frame frame) override                                                                                                   {return consumer_->send(std::move(frame));}
+       virtual void initialize(const struct video_format_desc& format_desc, int channel_index) override        {return consumer_->initialize(format_desc, channel_index);}
+       std::wstring print() const override                                                                                                                     {return consumer_->print();}
+       std::wstring name() const override                                                                                                                      {return consumer_->name();}
+       boost::property_tree::wptree info() const override                                                                                      {return consumer_->info();}
+       bool has_synchronization_clock() const override                                                                                         {return consumer_->has_synchronization_clock();}
+       int buffer_depth() const override                                                                                                                       {return consumer_->buffer_depth();}
+       int index() const override                                                                                                                                      {return consumer_->index();}
+       void subscribe(const monitor::observable::observer_ptr& o) override                                                                     {consumer_->subscribe(o);}
+       void unsubscribe(const monitor::observable::observer_ptr& o) override                                                           {consumer_->unsubscribe(o);}    
+};
+
+class recover_consumer_proxy : public frame_consumer
+{      
+       std::shared_ptr<frame_consumer> consumer_;
+       int                                                             channel_index_;
+       video_format_desc                               format_desc_;
+public:
+       recover_consumer_proxy(spl::shared_ptr<frame_consumer>&& consumer) 
+               : consumer_(std::move(consumer))
+       {
+       }
+       
+       virtual bool send(const_frame frame)                                    
+       {
+               try
+               {
+                       return consumer_->send(frame);
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+                       try
+                       {
+                               consumer_->initialize(format_desc_, channel_index_);
+                               return consumer_->send(frame);
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                               CASPAR_LOG(error) << print() << " Failed to recover consumer.";
+                               return false;
+                       }
+               }
+       }
+
+       virtual void initialize(const struct video_format_desc& format_desc, int channel_index)         
+       {
+               format_desc_    = format_desc;
+               channel_index_  = channel_index;
+               return consumer_->initialize(format_desc, channel_index);
+       }
+
+       std::wstring print() const override                                                                             {return consumer_->print();}
+       std::wstring name() const override                                                                              {return consumer_->name();}
+       boost::property_tree::wptree info() const override                                              {return consumer_->info();}
+       bool has_synchronization_clock() const override                                                 {return consumer_->has_synchronization_clock();}
+       int buffer_depth() const override                                                                               {return consumer_->buffer_depth();}
+       int index() const override                                                                                              {return consumer_->index();}
+       void subscribe(const monitor::observable::observer_ptr& o) override             {consumer_->subscribe(o);}
+       void unsubscribe(const monitor::observable::observer_ptr& o) override   {consumer_->unsubscribe(o);}    
+};
+
+// This class is used to guarantee that audio cadence is correct. This is important for NTSC audio.
+class cadence_guard : public frame_consumer
+{
+       spl::shared_ptr<frame_consumer>         consumer_;
+       std::vector<int>                                        audio_cadence_;
+       boost::circular_buffer<std::size_t>     sync_buffer_;
+public:
+       cadence_guard(const spl::shared_ptr<frame_consumer>& consumer)
+               : consumer_(consumer)
+       {
+       }
+       
+       void initialize(const video_format_desc& format_desc, int channel_index) override
+       {
+               audio_cadence_  = format_desc.audio_cadence;
+               sync_buffer_    = boost::circular_buffer<std::size_t>(format_desc.audio_cadence.size());
+               consumer_->initialize(format_desc, channel_index);
+       }
+
+       bool send(const_frame frame) override
+       {               
+               if(audio_cadence_.size() == 1)
+                       return consumer_->send(frame);
+
+               bool result = true;
+               
+               if(boost::range::equal(sync_buffer_, audio_cadence_) && audio_cadence_.front() == static_cast<int>(frame.audio_data().size())) 
+               {       
+                       // Audio sent so far is in sync, now we can send the next chunk.
+                       result = consumer_->send(frame);
+                       boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);
+               }
+               else
+                       CASPAR_LOG(trace) << print() << L" Syncing audio.";
+
+               sync_buffer_.push_back(static_cast<int>(frame.audio_data().size()));
+               
+               return result;
+       }
+       
+       std::wstring print() const override                                                                             {return consumer_->print();}
+       std::wstring name() const override                                                                              {return consumer_->name();}
+       boost::property_tree::wptree info() const override                                              {return consumer_->info();}
+       bool has_synchronization_clock() const override                                                 {return consumer_->has_synchronization_clock();}
+       int buffer_depth() const override                                                                               {return consumer_->buffer_depth();}
+       int index() const override                                                                                              {return consumer_->index();}
+       void subscribe(const monitor::observable::observer_ptr& o) override             {consumer_->subscribe(o);}
+       void unsubscribe(const monitor::observable::observer_ptr& o) override   {consumer_->unsubscribe(o);}    
+};
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+{
+       if(params.empty())
+               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));
+       
+       auto consumer = frame_consumer::empty();
+       std::any_of(g_factories.begin(), g_factories.end(), [&](const consumer_factory_t& factory) -> bool
+               {
+                       try
+                       {
+                               consumer = factory(params);
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }
+                       return consumer != frame_consumer::empty();
+               });
+
+       if(consumer == frame_consumer::empty())
+               CASPAR_THROW_EXCEPTION(file_not_found() << msg_info("No match found for supplied commands. Check syntax."));
+
+       return spl::make_shared<destroy_consumer_proxy>(
+                       spl::make_shared<print_consumer_proxy>(
+                        spl::make_shared<recover_consumer_proxy>(
+                         spl::make_shared<cadence_guard>(
+                          std::move(consumer)))));
+}
+
+const spl::shared_ptr<frame_consumer>& frame_consumer::empty()
+{
+       class empty_frame_consumer : public frame_consumer
+       {
+       public:
+               bool send(const_frame) override {return false;}
+               void initialize(const video_format_desc&, int) override{}
+               std::wstring print() const override {return L"empty";}
+               std::wstring name() const override {return L"empty";}
+               bool has_synchronization_clock() const override {return false;}
+               int buffer_depth() const override {return 0;};
+               virtual int index() const{return -1;}
+               void subscribe(const monitor::observable::observer_ptr& o) override{}
+               void unsubscribe(const monitor::observable::observer_ptr& o) override{}
+               boost::property_tree::wptree info() const override
+               {
+                       boost::property_tree::wptree info;
+                       info.add(L"type", L"empty");
+                       return info;
+               }
+       };
+       static spl::shared_ptr<frame_consumer> consumer = spl::make_shared<empty_frame_consumer>();
+       return consumer;
+}
+
 }}
\ No newline at end of file
index 0199fd26442dad3e9e3ece0d20ff85f80f393436..9fe65434339b9a22246c11b7fc5eaed6d48c3063 100644 (file)
@@ -1,77 +1,77 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "../monitor/monitor.h"\r
-\r
-#include <common/memory.h>\r
-\r
-#include <boost/property_tree/ptree_fwd.hpp>\r
-\r
-#include <functional>\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-// Interface\r
-class frame_consumer : public monitor::observable\r
-{\r
-       frame_consumer(const frame_consumer&);\r
-       frame_consumer& operator=(const frame_consumer&);\r
-public:\r
-\r
-       // Static Members\r
-       \r
-       static const spl::shared_ptr<frame_consumer>& empty();\r
-\r
-       // Constructors\r
-\r
-       frame_consumer(){}\r
-       virtual ~frame_consumer() {}\r
-       \r
-       // Methods\r
-\r
-       virtual bool                                                    send(class const_frame frame) = 0;\r
-       virtual void                                                    initialize(const struct video_format_desc& format_desc, int channel_index) = 0;\r
-       \r
-       // monitor::observable\r
-\r
-       virtual void subscribe(const monitor::observable::observer_ptr& o) = 0;\r
-       virtual void unsubscribe(const monitor::observable::observer_ptr& o) = 0;\r
-\r
-       // Properties\r
-\r
-       virtual std::wstring                                    print() const = 0;\r
-       virtual std::wstring                                    name() const = 0;\r
-       virtual boost::property_tree::wptree    info() const = 0;\r
-       virtual bool                                                    has_synchronization_clock() const {return true;}\r
-       virtual int                                                             buffer_depth() const = 0;\r
-       virtual int                                                             index() const = 0;\r
-};\r
-\r
-typedef std::function<spl::shared_ptr<frame_consumer>(const std::vector<std::wstring>&)> consumer_factory_t;\r
-\r
-void register_consumer_factory(const consumer_factory_t& factory);\r
-spl::shared_ptr<frame_consumer> create_consumer(const std::vector<std::wstring>& params);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "../monitor/monitor.h"
+
+#include <common/memory.h>
+
+#include <boost/property_tree/ptree_fwd.hpp>
+
+#include <functional>
+#include <string>
+#include <vector>
+
+namespace caspar { namespace core {
+       
+// Interface
+class frame_consumer : public monitor::observable
+{
+       frame_consumer(const frame_consumer&);
+       frame_consumer& operator=(const frame_consumer&);
+public:
+
+       // Static Members
+       
+       static const spl::shared_ptr<frame_consumer>& empty();
+
+       // Constructors
+
+       frame_consumer(){}
+       virtual ~frame_consumer() {}
+       
+       // Methods
+
+       virtual bool                                                    send(class const_frame frame) = 0;
+       virtual void                                                    initialize(const struct video_format_desc& format_desc, int channel_index) = 0;
+       
+       // monitor::observable
+
+       virtual void subscribe(const monitor::observable::observer_ptr& o) = 0;
+       virtual void unsubscribe(const monitor::observable::observer_ptr& o) = 0;
+
+       // Properties
+
+       virtual std::wstring                                    print() const = 0;
+       virtual std::wstring                                    name() const = 0;
+       virtual boost::property_tree::wptree    info() const = 0;
+       virtual bool                                                    has_synchronization_clock() const {return true;}
+       virtual int                                                             buffer_depth() const = 0;
+       virtual int                                                             index() const = 0;
+};
+
+typedef std::function<spl::shared_ptr<frame_consumer>(const std::vector<std::wstring>&)> consumer_factory_t;
+
+void register_consumer_factory(const consumer_factory_t& factory);
+spl::shared_ptr<frame_consumer> create_consumer(const std::vector<std::wstring>& params);
+
 }}
\ No newline at end of file
index 59f749d969216515bb42c13e9af5786d4dc29baf..43aa68f8f40b038ca3d5ca7c062f69e762d2168c 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../StdAfx.h"\r
-\r
-#ifdef _MSC_VER\r
-#pragma warning (disable : 4244)\r
-#endif\r
-\r
-#include "output.h"\r
-\r
-#include "frame_consumer.h"\r
-#include "port.h"\r
-\r
-#include "../video_format.h"\r
-#include "../frame/frame.h"\r
-\r
-#include <common/assert.h>\r
-#include <common/future.h>\r
-#include <common/executor.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/prec_timer.h>\r
-#include <common/memshfl.h>\r
-#include <common/env.h>\r
-\r
-#include <boost/circular_buffer.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/range/adaptors.hpp>\r
-#include <boost/timer.hpp>\r
-\r
-namespace caspar { namespace core {\r
-\r
-struct output::impl\r
-{              \r
-       spl::shared_ptr<diagnostics::graph>     graph_;\r
-       monitor::basic_subject                          event_subject_;\r
-       const int                                                       channel_index_;\r
-       video_format_desc                                       format_desc_;\r
-       std::map<int, port>                                     ports_; \r
-       prec_timer                                                      sync_timer_;\r
-       boost::circular_buffer<const_frame>     frames_;\r
-       executor                                                        executor_;              \r
-public:\r
-       impl(spl::shared_ptr<diagnostics::graph> graph, const video_format_desc& format_desc, int channel_index) \r
-               : graph_(std::move(graph))\r
-               , event_subject_("output")\r
-               , channel_index_(channel_index)\r
-               , format_desc_(format_desc)\r
-               , executor_(L"output")\r
-       {\r
-               graph_->set_color("consume-time", diagnostics::color(1.0f, 0.4f, 0.0f, 0.8));\r
-       }       \r
-       \r
-       void add(int index, spl::shared_ptr<frame_consumer> consumer)\r
-       {               \r
-               remove(index);\r
-\r
-               consumer->initialize(format_desc_, channel_index_);\r
-               \r
-               executor_.begin_invoke([this, index, consumer]\r
-               {                       \r
-                       port p(index, channel_index_, std::move(consumer));\r
-                       p.subscribe(event_subject_);\r
-                       ports_.insert(std::make_pair(index, std::move(p)));\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       void add(const spl::shared_ptr<frame_consumer>& consumer)\r
-       {\r
-               add(consumer->index(), consumer);\r
-       }\r
-\r
-       void remove(int index)\r
-       {               \r
-               executor_.begin_invoke([=]\r
-               {\r
-                       auto it = ports_.find(index);\r
-                       if(it != ports_.end())\r
-                               ports_.erase(it);                                       \r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       void remove(const spl::shared_ptr<frame_consumer>& consumer)\r
-       {\r
-               remove(consumer->index());\r
-       }\r
-       \r
-       void video_format_desc(const core::video_format_desc& format_desc)\r
-       {\r
-               executor_.invoke([&]\r
-               {\r
-                       if(format_desc_ == format_desc)\r
-                               return;\r
-\r
-                       auto it = ports_.begin();\r
-                       while(it != ports_.end())\r
-                       {                                               \r
-                               try\r
-                               {\r
-                                       it->second.video_format_desc(format_desc);\r
-                                       ++it;\r
-                               }\r
-                               catch(...)\r
-                               {\r
-                                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                                       ports_.erase(it++);\r
-                               }\r
-                       }\r
-                       \r
-                       format_desc_ = format_desc;\r
-                       frames_.clear();\r
-               });\r
-       }\r
-\r
-       std::pair<int, int> minmax_buffer_depth() const\r
-       {               \r
-               if(ports_.empty())\r
-                       return std::make_pair(0, 0);\r
-               \r
-               auto buffer_depths = ports_ | \r
-                                                        boost::adaptors::map_values | // std::function is MSVC workaround\r
-                                                        boost::adaptors::transformed(std::function<int(const port&)>([](const port& p){return p.buffer_depth();})); \r
-               \r
-\r
-               return std::make_pair(*boost::range::min_element(buffer_depths), *boost::range::max_element(buffer_depths));\r
-       }\r
-\r
-       bool has_synchronization_clock() const\r
-       {\r
-               return boost::range::count_if(ports_ | boost::adaptors::map_values,\r
-                                                                         [](const port& p){return p.has_synchronization_clock();}) > 0;\r
-       }\r
-               \r
-       void operator()(const_frame input_frame, const core::video_format_desc& format_desc)\r
-       {\r
-               boost::timer frame_timer;\r
-\r
-               video_format_desc(format_desc);         \r
-\r
-               executor_.invoke([=]\r
-               {                       \r
-\r
-                       if(!has_synchronization_clock())\r
-                               sync_timer_.tick(1.0/format_desc_.fps);\r
-                               \r
-                       if(input_frame.size() != format_desc_.size)\r
-                       {\r
-                               CASPAR_LOG(debug) << print() << L" Invalid input frame dimension.";\r
-                               return;\r
-                       }\r
-\r
-                       auto minmax = minmax_buffer_depth();\r
-\r
-                       frames_.set_capacity(std::max(2, minmax.second - minmax.first) + 1); // std::max(2, x) since we want to guarantee some pipeline depth for asycnhronous mixer read-back.\r
-                       frames_.push_back(input_frame);\r
-\r
-                       if(!frames_.full())\r
-                               return;\r
-\r
-                       for(auto it = ports_.begin(); it != ports_.end();)\r
-                       {\r
-                               auto& port      = it->second;\r
-                               auto& frame     = frames_.at(port.buffer_depth()-minmax.first);\r
-                                       \r
-                               try\r
-                               {\r
-                                       if(port.send(frame))\r
-                                               ++it;\r
-                                       else\r
-                                               ports_.erase(it++);                                     \r
-                               }\r
-                               catch(...)\r
-                               {\r
-                                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                                       ports_.erase(it++);\r
-                               }\r
-                       }\r
-               });\r
-\r
-               graph_->set_value("consume-time", frame_timer.elapsed()*format_desc.fps*0.5);\r
-       }\r
-\r
-       std::wstring print() const\r
-       {\r
-               return L"output[" + boost::lexical_cast<std::wstring>(channel_index_) + L"]";\r
-       }\r
-\r
-       boost::unique_future<boost::property_tree::wptree> info()\r
-       {\r
-               return std::move(executor_.begin_invoke([&]() -> boost::property_tree::wptree\r
-               {                       \r
-                       boost::property_tree::wptree info;\r
-                       BOOST_FOREACH(auto& port, ports_)\r
-                       {\r
-                               info.add_child(L"consumers.consumer", port.second.info())\r
-                                       .add(L"index", port.first); \r
-                       }\r
-                       return info;\r
-               }, task_priority::high_priority));\r
-       }\r
-};\r
-\r
-output::output(spl::shared_ptr<diagnostics::graph> graph, const video_format_desc& format_desc, int channel_index) : impl_(new impl(std::move(graph), format_desc, channel_index)){}\r
-void output::add(int index, const spl::shared_ptr<frame_consumer>& consumer){impl_->add(index, consumer);}\r
-void output::add(const spl::shared_ptr<frame_consumer>& consumer){impl_->add(consumer);}\r
-void output::remove(int index){impl_->remove(index);}\r
-void output::remove(const spl::shared_ptr<frame_consumer>& consumer){impl_->remove(consumer);}\r
-boost::unique_future<boost::property_tree::wptree> output::info() const{return impl_->info();}\r
-void output::operator()(const_frame frame, const video_format_desc& format_desc){(*impl_)(std::move(frame), format_desc);}\r
-void output::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.subscribe(o);}\r
-void output::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../StdAfx.h"
+
+#ifdef _MSC_VER
+#pragma warning (disable : 4244)
+#endif
+
+#include "output.h"
+
+#include "frame_consumer.h"
+#include "port.h"
+
+#include "../video_format.h"
+#include "../frame/frame.h"
+
+#include <common/assert.h>
+#include <common/future.h>
+#include <common/executor.h>
+#include <common/diagnostics/graph.h>
+#include <common/prec_timer.h>
+#include <common/memshfl.h>
+#include <common/env.h>
+
+#include <boost/circular_buffer.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/range/algorithm.hpp>
+#include <boost/range/adaptors.hpp>
+#include <boost/timer.hpp>
+
+namespace caspar { namespace core {
+
+struct output::impl
+{              
+       spl::shared_ptr<diagnostics::graph>     graph_;
+       monitor::basic_subject                          event_subject_;
+       const int                                                       channel_index_;
+       video_format_desc                                       format_desc_;
+       std::map<int, port>                                     ports_; 
+       prec_timer                                                      sync_timer_;
+       boost::circular_buffer<const_frame>     frames_;
+       executor                                                        executor_;              
+public:
+       impl(spl::shared_ptr<diagnostics::graph> graph, const video_format_desc& format_desc, int channel_index) 
+               : graph_(std::move(graph))
+               , event_subject_("output")
+               , channel_index_(channel_index)
+               , format_desc_(format_desc)
+               , executor_(L"output")
+       {
+               graph_->set_color("consume-time", diagnostics::color(1.0f, 0.4f, 0.0f, 0.8));
+       }       
+       
+       void add(int index, spl::shared_ptr<frame_consumer> consumer)
+       {               
+               remove(index);
+
+               consumer->initialize(format_desc_, channel_index_);
+               
+               executor_.begin_invoke([this, index, consumer]
+               {                       
+                       port p(index, channel_index_, std::move(consumer));
+                       p.subscribe(event_subject_);
+                       ports_.insert(std::make_pair(index, std::move(p)));
+               }, task_priority::high_priority);
+       }
+
+       void add(const spl::shared_ptr<frame_consumer>& consumer)
+       {
+               add(consumer->index(), consumer);
+       }
+
+       void remove(int index)
+       {               
+               executor_.begin_invoke([=]
+               {
+                       auto it = ports_.find(index);
+                       if(it != ports_.end())
+                               ports_.erase(it);                                       
+               }, task_priority::high_priority);
+       }
+
+       void remove(const spl::shared_ptr<frame_consumer>& consumer)
+       {
+               remove(consumer->index());
+       }
+       
+       void video_format_desc(const core::video_format_desc& format_desc)
+       {
+               executor_.invoke([&]
+               {
+                       if(format_desc_ == format_desc)
+                               return;
+
+                       auto it = ports_.begin();
+                       while(it != ports_.end())
+                       {                                               
+                               try
+                               {
+                                       it->second.video_format_desc(format_desc);
+                                       ++it;
+                               }
+                               catch(...)
+                               {
+                                       CASPAR_LOG_CURRENT_EXCEPTION();
+                                       ports_.erase(it++);
+                               }
+                       }
+                       
+                       format_desc_ = format_desc;
+                       frames_.clear();
+               });
+       }
+
+       std::pair<int, int> minmax_buffer_depth() const
+       {               
+               if(ports_.empty())
+                       return std::make_pair(0, 0);
+               
+               auto buffer_depths = ports_ | 
+                                                        boost::adaptors::map_values | // std::function is MSVC workaround
+                                                        boost::adaptors::transformed(std::function<int(const port&)>([](const port& p){return p.buffer_depth();})); 
+               
+
+               return std::make_pair(*boost::range::min_element(buffer_depths), *boost::range::max_element(buffer_depths));
+       }
+
+       bool has_synchronization_clock() const
+       {
+               return boost::range::count_if(ports_ | boost::adaptors::map_values,
+                                                                         [](const port& p){return p.has_synchronization_clock();}) > 0;
+       }
+               
+       void operator()(const_frame input_frame, const core::video_format_desc& format_desc)
+       {
+               boost::timer frame_timer;
+
+               video_format_desc(format_desc);         
+
+               executor_.invoke([=]
+               {                       
+
+                       if(!has_synchronization_clock())
+                               sync_timer_.tick(1.0/format_desc_.fps);
+                               
+                       if(input_frame.size() != format_desc_.size)
+                       {
+                               CASPAR_LOG(debug) << print() << L" Invalid input frame dimension.";
+                               return;
+                       }
+
+                       auto minmax = minmax_buffer_depth();
+
+                       frames_.set_capacity(std::max(2, minmax.second - minmax.first) + 1); // std::max(2, x) since we want to guarantee some pipeline depth for asycnhronous mixer read-back.
+                       frames_.push_back(input_frame);
+
+                       if(!frames_.full())
+                               return;
+
+                       for(auto it = ports_.begin(); it != ports_.end();)
+                       {
+                               auto& port      = it->second;
+                               auto& frame     = frames_.at(port.buffer_depth()-minmax.first);
+                                       
+                               try
+                               {
+                                       if(port.send(frame))
+                                               ++it;
+                                       else
+                                               ports_.erase(it++);                                     
+                               }
+                               catch(...)
+                               {
+                                       CASPAR_LOG_CURRENT_EXCEPTION();
+                                       ports_.erase(it++);
+                               }
+                       }
+               });
+
+               graph_->set_value("consume-time", frame_timer.elapsed()*format_desc.fps*0.5);
+       }
+
+       std::wstring print() const
+       {
+               return L"output[" + boost::lexical_cast<std::wstring>(channel_index_) + L"]";
+       }
+
+       boost::unique_future<boost::property_tree::wptree> info()
+       {
+               return std::move(executor_.begin_invoke([&]() -> boost::property_tree::wptree
+               {                       
+                       boost::property_tree::wptree info;
+                       BOOST_FOREACH(auto& port, ports_)
+                       {
+                               info.add_child(L"consumers.consumer", port.second.info())
+                                       .add(L"index", port.first); 
+                       }
+                       return info;
+               }, task_priority::high_priority));
+       }
+};
+
+output::output(spl::shared_ptr<diagnostics::graph> graph, const video_format_desc& format_desc, int channel_index) : impl_(new impl(std::move(graph), format_desc, channel_index)){}
+void output::add(int index, const spl::shared_ptr<frame_consumer>& consumer){impl_->add(index, consumer);}
+void output::add(const spl::shared_ptr<frame_consumer>& consumer){impl_->add(consumer);}
+void output::remove(int index){impl_->remove(index);}
+void output::remove(const spl::shared_ptr<frame_consumer>& consumer){impl_->remove(consumer);}
+boost::unique_future<boost::property_tree::wptree> output::info() const{return impl_->info();}
+void output::operator()(const_frame frame, const video_format_desc& format_desc){(*impl_)(std::move(frame), format_desc);}
+void output::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.subscribe(o);}
+void output::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}
 }}
\ No newline at end of file
index 3d51617794d85dc4923380532fb72536476df3a8..00e69cbc5440cc60009d12e098028bf3adcf6274 100644 (file)
@@ -1,72 +1,72 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "../monitor/monitor.h"\r
-\r
-#include <common/forward.h>\r
-#include <common/future_fwd.h>\r
-#include <common/memory.h>\r
-#include <common/reactive.h>\r
-\r
-#include <boost/property_tree/ptree_fwd.hpp>\r
-\r
-FORWARD2(caspar, diagnostics, class graph);\r
-\r
-namespace caspar { namespace core {\r
-       \r
-class output sealed : public monitor::observable\r
-{\r
-       output(const output&);\r
-       output& operator=(const output&);\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       explicit output(spl::shared_ptr<diagnostics::graph> graph, const struct video_format_desc& format_desc, int channel_index);\r
-       \r
-       // Methods\r
-\r
-       void operator()(class const_frame frame, const struct video_format_desc& format_desc);\r
-       \r
-       void add(const spl::shared_ptr<class frame_consumer>& consumer);\r
-       void add(int index, const spl::shared_ptr<class frame_consumer>& consumer);\r
-       void remove(const spl::shared_ptr<class frame_consumer>& consumer);\r
-       void remove(int index);\r
-       \r
-       // monitor::observable\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override;\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override;\r
-\r
-       // Properties\r
-\r
-       boost::unique_future<boost::property_tree::wptree> info() const;\r
-\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "../monitor/monitor.h"
+
+#include <common/forward.h>
+#include <common/future_fwd.h>
+#include <common/memory.h>
+#include <common/reactive.h>
+
+#include <boost/property_tree/ptree_fwd.hpp>
+
+FORWARD2(caspar, diagnostics, class graph);
+
+namespace caspar { namespace core {
+       
+class output sealed : public monitor::observable
+{
+       output(const output&);
+       output& operator=(const output&);
+public:
+
+       // Static Members
+
+       // Constructors
+
+       explicit output(spl::shared_ptr<diagnostics::graph> graph, const struct video_format_desc& format_desc, int channel_index);
+       
+       // Methods
+
+       void operator()(class const_frame frame, const struct video_format_desc& format_desc);
+       
+       void add(const spl::shared_ptr<class frame_consumer>& consumer);
+       void add(int index, const spl::shared_ptr<class frame_consumer>& consumer);
+       void remove(const spl::shared_ptr<class frame_consumer>& consumer);
+       void remove(int index);
+       
+       // monitor::observable
+
+       void subscribe(const monitor::observable::observer_ptr& o) override;
+       void unsubscribe(const monitor::observable::observer_ptr& o) override;
+
+       // Properties
+
+       boost::unique_future<boost::property_tree::wptree> info() const;
+
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index 39cd2721225244b43e484ae7eaab971631e744ec..ca2b063dd0a90bacd1fad794b82d433ef005459c 100644 (file)
@@ -1,69 +1,69 @@
-#include "../StdAfx.h"\r
-\r
-#include "port.h"\r
-\r
-#include "frame_consumer.h"\r
-#include "../frame/frame.h"\r
-\r
-namespace caspar { namespace core {\r
-\r
-struct port::impl\r
-{\r
-       monitor::basic_subject                          event_subject_;\r
-       std::shared_ptr<frame_consumer>         consumer_;\r
-       int                                                                     index_;\r
-       int                                                                     channel_index_;\r
-public:\r
-       impl(int index, int channel_index, spl::shared_ptr<frame_consumer> consumer)\r
-               : event_subject_(monitor::path("port") % index)\r
-               , consumer_(std::move(consumer))\r
-               , index_(index)\r
-               , channel_index_(channel_index)\r
-       {\r
-               consumer_->subscribe(event_subject_);\r
-       }\r
-       \r
-       void video_format_desc(const struct video_format_desc& format_desc)\r
-       {\r
-               consumer_->initialize(format_desc, channel_index_);\r
-       }\r
-               \r
-       bool send(const_frame frame)\r
-       {\r
-               event_subject_ << monitor::event("type") % consumer_->name();\r
-               return consumer_->send(std::move(frame));\r
-       }\r
-       \r
-       int index() const\r
-       {\r
-               return index_;\r
-       }\r
-\r
-       int buffer_depth() const\r
-       {\r
-               return consumer_->buffer_depth();\r
-       }\r
-\r
-       bool has_synchronization_clock() const\r
-       {\r
-               return consumer_->has_synchronization_clock();\r
-       }\r
-\r
-       boost::property_tree::wptree info() const\r
-       {\r
-               return consumer_->info();\r
-       }\r
-};\r
-\r
-port::port(int index, int channel_index, spl::shared_ptr<frame_consumer> consumer) : impl_(new impl(index, channel_index, std::move(consumer))){}\r
-port::port(port&& other) : impl_(std::move(other.impl_)){}\r
-port::~port(){}\r
-port& port::operator=(port&& other){impl_ = std::move(other.impl_); return *this;}\r
-bool port::send(const_frame frame){return impl_->send(std::move(frame));}      \r
-void port::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.subscribe(o);}\r
-void port::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);}\r
-void port::video_format_desc(const struct video_format_desc& format_desc){impl_->video_format_desc(format_desc);}\r
-int port::buffer_depth() const{return impl_->buffer_depth();}\r
-bool port::has_synchronization_clock() const{return impl_->has_synchronization_clock();}\r
-boost::property_tree::wptree port::info() const{return impl_->info();}\r
+#include "../StdAfx.h"
+
+#include "port.h"
+
+#include "frame_consumer.h"
+#include "../frame/frame.h"
+
+namespace caspar { namespace core {
+
+struct port::impl
+{
+       monitor::basic_subject                          event_subject_;
+       std::shared_ptr<frame_consumer>         consumer_;
+       int                                                                     index_;
+       int                                                                     channel_index_;
+public:
+       impl(int index, int channel_index, spl::shared_ptr<frame_consumer> consumer)
+               : event_subject_(monitor::path("port") % index)
+               , consumer_(std::move(consumer))
+               , index_(index)
+               , channel_index_(channel_index)
+       {
+               consumer_->subscribe(event_subject_);
+       }
+       
+       void video_format_desc(const struct video_format_desc& format_desc)
+       {
+               consumer_->initialize(format_desc, channel_index_);
+       }
+               
+       bool send(const_frame frame)
+       {
+               event_subject_ << monitor::event("type") % consumer_->name();
+               return consumer_->send(std::move(frame));
+       }
+       
+       int index() const
+       {
+               return index_;
+       }
+
+       int buffer_depth() const
+       {
+               return consumer_->buffer_depth();
+       }
+
+       bool has_synchronization_clock() const
+       {
+               return consumer_->has_synchronization_clock();
+       }
+
+       boost::property_tree::wptree info() const
+       {
+               return consumer_->info();
+       }
+};
+
+port::port(int index, int channel_index, spl::shared_ptr<frame_consumer> consumer) : impl_(new impl(index, channel_index, std::move(consumer))){}
+port::port(port&& other) : impl_(std::move(other.impl_)){}
+port::~port(){}
+port& port::operator=(port&& other){impl_ = std::move(other.impl_); return *this;}
+bool port::send(const_frame frame){return impl_->send(std::move(frame));}      
+void port::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.subscribe(o);}
+void port::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);}
+void port::video_format_desc(const struct video_format_desc& format_desc){impl_->video_format_desc(format_desc);}
+int port::buffer_depth() const{return impl_->buffer_depth();}
+bool port::has_synchronization_clock() const{return impl_->has_synchronization_clock();}
+boost::property_tree::wptree port::info() const{return impl_->info();}
 }}
\ No newline at end of file
index 225447e56e20845e83200b710dcf830e92d9c034..76ff625df731a67df5ec8a8f966aec33f9c6741c 100644 (file)
@@ -1,47 +1,47 @@
-#pragma once\r
-\r
-#include "../monitor/monitor.h"\r
-\r
-#include <common/memory.h>\r
-\r
-#include <boost/property_tree/ptree_fwd.hpp>\r
-\r
-namespace caspar { namespace core {\r
-\r
-class port : public monitor::observable\r
-{\r
-       port(const port&);\r
-       port& operator=(const port&);\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       port(int index, int channel_index, spl::shared_ptr<class frame_consumer> consumer);\r
-       port(port&& other);\r
-       ~port();\r
-\r
-       // Member Functions\r
-\r
-       port& operator=(port&& other);\r
-\r
-       bool send(class const_frame frame);     \r
-\r
-       // monitor::observable\r
-       \r
-       void subscribe(const monitor::observable::observer_ptr& o) override;\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override;\r
-\r
-       // Properties\r
-\r
-       void video_format_desc(const struct video_format_desc& format_desc);\r
-       int buffer_depth() const;\r
-       bool has_synchronization_clock() const;\r
-       boost::property_tree::wptree info() const;\r
-private:\r
-       struct impl;\r
-       std::unique_ptr<impl> impl_;\r
-};\r
-\r
+#pragma once
+
+#include "../monitor/monitor.h"
+
+#include <common/memory.h>
+
+#include <boost/property_tree/ptree_fwd.hpp>
+
+namespace caspar { namespace core {
+
+class port : public monitor::observable
+{
+       port(const port&);
+       port& operator=(const port&);
+public:
+
+       // Static Members
+
+       // Constructors
+
+       port(int index, int channel_index, spl::shared_ptr<class frame_consumer> consumer);
+       port(port&& other);
+       ~port();
+
+       // Member Functions
+
+       port& operator=(port&& other);
+
+       bool send(class const_frame frame);     
+
+       // monitor::observable
+       
+       void subscribe(const monitor::observable::observer_ptr& o) override;
+       void unsubscribe(const monitor::observable::observer_ptr& o) override;
+
+       // Properties
+
+       void video_format_desc(const struct video_format_desc& format_desc);
+       int buffer_depth() const;
+       bool has_synchronization_clock() const;
+       boost::property_tree::wptree info() const;
+private:
+       struct impl;
+       std::unique_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index abd52fa4910d37755ec15a82d526c72a5ca1a4aa..45d6bfdea19374942c6035fc630b60984d63adc5 100644 (file)
@@ -1,86 +1,86 @@
-#pragma once\r
-\r
-#include <boost/noncopyable.hpp>\r
-#include <boost/range.hpp>\r
-\r
-#include <stdint.h>\r
-\r
-#include "frame/pixel_format.h"\r
-#include "video_format.h"\r
-\r
-namespace caspar { namespace core {\r
-\r
-struct data_frame : boost::noncopyable\r
-{\r
-       virtual ~frame()\r
-       {\r
-       }\r
-\r
-       virtual const struct  pixel_format_desc& get_pixel_format_desc() const = 0;\r
-\r
-       virtual const boost::iterator_range<const uint8_t*> image_data() const = 0;\r
-       virtual const boost::iterator_range<const int32_t*> audio_data() const = 0;\r
-       \r
-       virtual const boost::iterator_range<uint8_t*> image_data() = 0;\r
-       virtual const boost::iterator_range<int32_t*> audio_data() = 0;\r
-\r
-       virtual double get_frame_rate() const = 0;\r
-       virtual field_mode get_field_mode() const = 0;\r
-\r
-       virtual int width() const = 0;\r
-       virtual int height() const = 0;\r
-\r
-       static safe_ptr<frame> empty()\r
-       {\r
-               struct empty_frame : public frame\r
-               {\r
-                       virtual const struct  video_format_desc& get_video_format_desc() const\r
-                       {\r
-                               static video_format_desc invalid;\r
-                               return invalid;\r
-                       }\r
-                       virtual const struct  pixel_format_desc& get_pixel_format_desc() const \r
-                       {\r
-                               static pixel_format_desc invalid;\r
-                               return invalid;\r
-                       }\r
-                       virtual const boost::iterator_range<const uint8_t*> image_data() const \r
-                       {\r
-                               return boost::iterator_range<const uint8_t*>();\r
-                       }\r
-                       virtual const boost::iterator_range<const int32_t*> audio_data() const \r
-                       {\r
-                               return boost::iterator_range<const int32_t*>();\r
-                       }\r
-                       const boost::iterator_range<uint8_t*> image_data()\r
-                       {\r
-                               return boost::iterator_range<uint8_t*>();\r
-                       }\r
-                       const boost::iterator_range<int32_t*> audio_data()\r
-                       {\r
-                               return boost::iterator_range<int32_t*>();\r
-                       }\r
-                       virtual double get_frame_rate() const\r
-                       {\r
-                               return 0.0;\r
-                       }\r
-                       virtual field_mode get_field_mode() const\r
-                       {\r
-                               return field_mode::empty;\r
-                       }\r
-                       virtual int width() const\r
-                       {\r
-                               return 0;\r
-                       }\r
-                       virtual int height() const\r
-                       {\r
-                               return 0;\r
-                       }\r
-               };\r
-\r
-               static safe_ptr<empty_frame> empty;\r
-               return empty;\r
-       }\r
-};\r
-\r
+#pragma once
+
+#include <boost/noncopyable.hpp>
+#include <boost/range.hpp>
+
+#include <stdint.h>
+
+#include "frame/pixel_format.h"
+#include "video_format.h"
+
+namespace caspar { namespace core {
+
+struct data_frame : boost::noncopyable
+{
+       virtual ~frame()
+       {
+       }
+
+       virtual const struct  pixel_format_desc& get_pixel_format_desc() const = 0;
+
+       virtual const boost::iterator_range<const uint8_t*> image_data() const = 0;
+       virtual const boost::iterator_range<const int32_t*> audio_data() const = 0;
+       
+       virtual const boost::iterator_range<uint8_t*> image_data() = 0;
+       virtual const boost::iterator_range<int32_t*> audio_data() = 0;
+
+       virtual double get_frame_rate() const = 0;
+       virtual field_mode get_field_mode() const = 0;
+
+       virtual int width() const = 0;
+       virtual int height() const = 0;
+
+       static safe_ptr<frame> empty()
+       {
+               struct empty_frame : public frame
+               {
+                       virtual const struct  video_format_desc& get_video_format_desc() const
+                       {
+                               static video_format_desc invalid;
+                               return invalid;
+                       }
+                       virtual const struct  pixel_format_desc& get_pixel_format_desc() const 
+                       {
+                               static pixel_format_desc invalid;
+                               return invalid;
+                       }
+                       virtual const boost::iterator_range<const uint8_t*> image_data() const 
+                       {
+                               return boost::iterator_range<const uint8_t*>();
+                       }
+                       virtual const boost::iterator_range<const int32_t*> audio_data() const 
+                       {
+                               return boost::iterator_range<const int32_t*>();
+                       }
+                       const boost::iterator_range<uint8_t*> image_data()
+                       {
+                               return boost::iterator_range<uint8_t*>();
+                       }
+                       const boost::iterator_range<int32_t*> audio_data()
+                       {
+                               return boost::iterator_range<int32_t*>();
+                       }
+                       virtual double get_frame_rate() const
+                       {
+                               return 0.0;
+                       }
+                       virtual field_mode get_field_mode() const
+                       {
+                               return field_mode::empty;
+                       }
+                       virtual int width() const
+                       {
+                               return 0;
+                       }
+                       virtual int height() const
+                       {
+                               return 0;
+                       }
+               };
+
+               static safe_ptr<empty_frame> empty;
+               return empty;
+       }
+};
+
 }}
\ No newline at end of file
index 63d1251ee6a8cb8c5dd6d056855106d94c3a34c7..180c8906011fecb185d181b4219c7de492d2ac16 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "draw_frame.h"\r
-\r
-#include "frame.h"\r
-\r
-#include "frame_transform.h"\r
-\r
-#include <boost/foreach.hpp>\r
-\r
-namespace caspar { namespace core {\r
-               \r
-enum tags\r
-{\r
-       frame_tag = 0,\r
-       empty_tag,\r
-       eof_tag,\r
-       late_tag\r
-};\r
-\r
-struct draw_frame::impl\r
-{              \r
-       std::shared_ptr<const_frame>    frame_;\r
-       std::vector<draw_frame>                 frames_;\r
-       core::frame_transform                   frame_transform_;               \r
-public:                \r
-\r
-       impl()\r
-       {\r
-       }\r
-\r
-       impl(const_frame&& frame) \r
-               : frame_(new const_frame(std::move(frame)))\r
-       {\r
-       }\r
-       \r
-       impl(mutable_frame&& frame) \r
-               : frame_(new const_frame(std::move(frame)))\r
-       {\r
-       }\r
-\r
-       impl(std::vector<draw_frame> frames)\r
-               : frames_(std::move(frames))\r
-       {\r
-       }\r
-\r
-       impl(const impl& other)\r
-               : frames_(other.frames_)\r
-               , frame_(other.frame_)\r
-               , frame_transform_(other.frame_transform_)\r
-       {\r
-       }\r
-                       \r
-       void accept(frame_visitor& visitor) const\r
-       {\r
-               visitor.push(frame_transform_);\r
-               if(frame_)\r
-               {\r
-                       visitor.visit(*frame_);\r
-               }\r
-               else\r
-               {\r
-                       BOOST_FOREACH(auto frame, frames_)\r
-                               frame.accept(visitor);\r
-               }\r
-               visitor.pop();\r
-       }       \r
-               \r
-       bool operator==(const impl& other)\r
-       {\r
-               return  frames_                         == other.frames_ && \r
-                               frame_                          == other.frame_ &&\r
-                               frame_transform_        == other.frame_transform_;\r
-       }\r
-};\r
-       \r
-draw_frame::draw_frame() : impl_(new impl()){}\r
-draw_frame::draw_frame(const draw_frame& other) : impl_(new impl(*other.impl_)){}\r
-draw_frame::draw_frame(draw_frame&& other) : impl_(std::move(other.impl_)){}\r
-draw_frame::draw_frame(const_frame&& frame)  : impl_(new impl(std::move(frame))){}\r
-draw_frame::draw_frame(mutable_frame&& frame)  : impl_(new impl(std::move(frame))){}\r
-draw_frame::draw_frame(std::vector<draw_frame> frames) : impl_(new impl(frames)){}\r
-draw_frame::~draw_frame(){}\r
-draw_frame& draw_frame::operator=(draw_frame other)\r
-{\r
-       other.swap(*this);\r
-       return *this;\r
-}\r
-void draw_frame::swap(draw_frame& other){impl_.swap(other.impl_);}\r
-\r
-const core::frame_transform& draw_frame::transform() const { return impl_->frame_transform_;}\r
-core::frame_transform& draw_frame::transform() { return impl_->frame_transform_;}\r
-void draw_frame::accept(frame_visitor& visitor) const{impl_->accept(visitor);}\r
-bool draw_frame::operator==(const draw_frame& other)const{return *impl_ == *other.impl_;}\r
-bool draw_frame::operator!=(const draw_frame& other)const{return !(*this == other);}\r
-\r
-draw_frame draw_frame::interlace(draw_frame frame1, draw_frame frame2, core::field_mode mode)\r
-{                              \r
-       if(frame1 == draw_frame::empty() && frame2 == draw_frame::empty())\r
-               return draw_frame::empty();\r
-       \r
-       if(frame1 == frame2 || mode == field_mode::progressive)\r
-               return frame2;\r
-\r
-       if(mode == field_mode::upper)\r
-       {\r
-               frame1.transform().image_transform.field_mode = field_mode::upper;      \r
-               frame2.transform().image_transform.field_mode = field_mode::lower;      \r
-       }                                                                        \r
-       else                                                             \r
-       {                                                                        \r
-               frame1.transform().image_transform.field_mode = field_mode::lower;      \r
-               frame2.transform().image_transform.field_mode = field_mode::upper;      \r
-       }\r
-\r
-       std::vector<draw_frame> frames;\r
-       frames.push_back(std::move(frame1));\r
-       frames.push_back(std::move(frame2));\r
-       return draw_frame(std::move(frames));\r
-}\r
-\r
-draw_frame draw_frame::over(draw_frame frame1, draw_frame frame2)\r
-{              \r
-       if(frame1 == draw_frame::empty() && frame2 == draw_frame::empty())\r
-               return draw_frame::empty();\r
-\r
-       std::vector<draw_frame> frames;\r
-       frames.push_back(std::move(frame1));\r
-       frames.push_back(std::move(frame2));\r
-       return draw_frame(std::move(frames));\r
-}\r
-\r
-draw_frame draw_frame::mask(draw_frame fill, draw_frame key)\r
-{      \r
-       if(fill == draw_frame::empty() || key == draw_frame::empty())\r
-               return draw_frame::empty();\r
-\r
-       std::vector<draw_frame> frames;\r
-       key.transform().image_transform.is_key = true;\r
-       frames.push_back(std::move(key));\r
-       frames.push_back(std::move(fill));\r
-       return draw_frame(std::move(frames));\r
-}\r
-\r
-draw_frame draw_frame::push(draw_frame frame)\r
-{\r
-       std::vector<draw_frame> frames;\r
-       frames.push_back(std::move(frame));\r
-       return draw_frame(std::move(frames));\r
-}\r
-\r
-draw_frame eof_frame(const_frame(0));\r
-draw_frame empty_frame(const_frame(0));\r
-draw_frame late_frame(const_frame(0));\r
-\r
-draw_frame draw_frame::still(draw_frame frame)\r
-{\r
-       frame.transform().image_transform.is_still      = true; \r
-       frame.transform().audio_transform.is_still      = true;         \r
-       return frame;\r
-}\r
-\r
-const draw_frame& draw_frame::empty()\r
-{\r
-       return empty_frame;\r
-}\r
-\r
-const draw_frame& draw_frame::late()\r
-{\r
-       return late_frame;\r
-}\r
-       \r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "draw_frame.h"
+
+#include "frame.h"
+
+#include "frame_transform.h"
+
+#include <boost/foreach.hpp>
+
+namespace caspar { namespace core {
+               
+enum tags
+{
+       frame_tag = 0,
+       empty_tag,
+       eof_tag,
+       late_tag
+};
+
+struct draw_frame::impl
+{              
+       std::shared_ptr<const_frame>    frame_;
+       std::vector<draw_frame>                 frames_;
+       core::frame_transform                   frame_transform_;               
+public:                
+
+       impl()
+       {
+       }
+
+       impl(const_frame&& frame) 
+               : frame_(new const_frame(std::move(frame)))
+       {
+       }
+       
+       impl(mutable_frame&& frame) 
+               : frame_(new const_frame(std::move(frame)))
+       {
+       }
+
+       impl(std::vector<draw_frame> frames)
+               : frames_(std::move(frames))
+       {
+       }
+
+       impl(const impl& other)
+               : frames_(other.frames_)
+               , frame_(other.frame_)
+               , frame_transform_(other.frame_transform_)
+       {
+       }
+                       
+       void accept(frame_visitor& visitor) const
+       {
+               visitor.push(frame_transform_);
+               if(frame_)
+               {
+                       visitor.visit(*frame_);
+               }
+               else
+               {
+                       BOOST_FOREACH(auto frame, frames_)
+                               frame.accept(visitor);
+               }
+               visitor.pop();
+       }       
+               
+       bool operator==(const impl& other)
+       {
+               return  frames_                         == other.frames_ && 
+                               frame_                          == other.frame_ &&
+                               frame_transform_        == other.frame_transform_;
+       }
+};
+       
+draw_frame::draw_frame() : impl_(new impl()){}
+draw_frame::draw_frame(const draw_frame& other) : impl_(new impl(*other.impl_)){}
+draw_frame::draw_frame(draw_frame&& other) : impl_(std::move(other.impl_)){}
+draw_frame::draw_frame(const_frame&& frame)  : impl_(new impl(std::move(frame))){}
+draw_frame::draw_frame(mutable_frame&& frame)  : impl_(new impl(std::move(frame))){}
+draw_frame::draw_frame(std::vector<draw_frame> frames) : impl_(new impl(frames)){}
+draw_frame::~draw_frame(){}
+draw_frame& draw_frame::operator=(draw_frame other)
+{
+       other.swap(*this);
+       return *this;
+}
+void draw_frame::swap(draw_frame& other){impl_.swap(other.impl_);}
+
+const core::frame_transform& draw_frame::transform() const { return impl_->frame_transform_;}
+core::frame_transform& draw_frame::transform() { return impl_->frame_transform_;}
+void draw_frame::accept(frame_visitor& visitor) const{impl_->accept(visitor);}
+bool draw_frame::operator==(const draw_frame& other)const{return *impl_ == *other.impl_;}
+bool draw_frame::operator!=(const draw_frame& other)const{return !(*this == other);}
+
+draw_frame draw_frame::interlace(draw_frame frame1, draw_frame frame2, core::field_mode mode)
+{                              
+       if(frame1 == draw_frame::empty() && frame2 == draw_frame::empty())
+               return draw_frame::empty();
+       
+       if(frame1 == frame2 || mode == field_mode::progressive)
+               return frame2;
+
+       if(mode == field_mode::upper)
+       {
+               frame1.transform().image_transform.field_mode = field_mode::upper;      
+               frame2.transform().image_transform.field_mode = field_mode::lower;      
+       }                                                                        
+       else                                                             
+       {                                                                        
+               frame1.transform().image_transform.field_mode = field_mode::lower;      
+               frame2.transform().image_transform.field_mode = field_mode::upper;      
+       }
+
+       std::vector<draw_frame> frames;
+       frames.push_back(std::move(frame1));
+       frames.push_back(std::move(frame2));
+       return draw_frame(std::move(frames));
+}
+
+draw_frame draw_frame::over(draw_frame frame1, draw_frame frame2)
+{              
+       if(frame1 == draw_frame::empty() && frame2 == draw_frame::empty())
+               return draw_frame::empty();
+
+       std::vector<draw_frame> frames;
+       frames.push_back(std::move(frame1));
+       frames.push_back(std::move(frame2));
+       return draw_frame(std::move(frames));
+}
+
+draw_frame draw_frame::mask(draw_frame fill, draw_frame key)
+{      
+       if(fill == draw_frame::empty() || key == draw_frame::empty())
+               return draw_frame::empty();
+
+       std::vector<draw_frame> frames;
+       key.transform().image_transform.is_key = true;
+       frames.push_back(std::move(key));
+       frames.push_back(std::move(fill));
+       return draw_frame(std::move(frames));
+}
+
+draw_frame draw_frame::push(draw_frame frame)
+{
+       std::vector<draw_frame> frames;
+       frames.push_back(std::move(frame));
+       return draw_frame(std::move(frames));
+}
+
+draw_frame eof_frame(const_frame(0));
+draw_frame empty_frame(const_frame(0));
+draw_frame late_frame(const_frame(0));
+
+draw_frame draw_frame::still(draw_frame frame)
+{
+       frame.transform().image_transform.is_still      = true; 
+       frame.transform().audio_transform.is_still      = true;         
+       return frame;
+}
+
+const draw_frame& draw_frame::empty()
+{
+       return empty_frame;
+}
+
+const draw_frame& draw_frame::late()
+{
+       return late_frame;
+}
+       
+
 }}
\ No newline at end of file
index b353ffe6dfc0cd03d641cf27cb163283981760b6..6f188a858abcd5606ecf895a4f51d11b3bd5b75f 100644 (file)
@@ -1,82 +1,82 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "frame_visitor.h"\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <common/memory.h>\r
-\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-struct frame_transform;\r
-\r
-class draw_frame sealed\r
-{\r
-public:                \r
-       // Static Members\r
-\r
-       static draw_frame interlace(draw_frame frame1, draw_frame frame2, core::field_mode mode);\r
-       static draw_frame over(draw_frame frame1, draw_frame frame2);\r
-       static draw_frame mask(draw_frame fill, draw_frame key);\r
-       static draw_frame still(draw_frame frame);\r
-       static draw_frame push(draw_frame frame);\r
-               \r
-       static const draw_frame& empty();\r
-       static const draw_frame& late();\r
-\r
-       // Constructors\r
-\r
-       draw_frame();\r
-       draw_frame(const draw_frame& other);\r
-       draw_frame(draw_frame&& other); \r
-       explicit draw_frame(class const_frame&& frame);\r
-       explicit draw_frame(class mutable_frame&& frame);\r
-       explicit draw_frame(std::vector<draw_frame> frames);\r
-\r
-       ~draw_frame();\r
-       \r
-       // Methods\r
-\r
-       draw_frame& operator=(draw_frame other);\r
-\r
-       void swap(draw_frame& other);   \r
-       \r
-       void accept(frame_visitor& visitor) const;\r
-\r
-       bool operator==(const draw_frame& other) const;\r
-       bool operator!=(const draw_frame& other) const;\r
-\r
-       // Properties\r
-\r
-       const core::frame_transform&    transform() const;\r
-       core::frame_transform&                  transform();                    \r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-       \r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "frame_visitor.h"
+
+#include <core/video_format.h>
+
+#include <common/memory.h>
+
+#include <vector>
+
+namespace caspar { namespace core {
+       
+struct frame_transform;
+
+class draw_frame sealed
+{
+public:                
+       // Static Members
+
+       static draw_frame interlace(draw_frame frame1, draw_frame frame2, core::field_mode mode);
+       static draw_frame over(draw_frame frame1, draw_frame frame2);
+       static draw_frame mask(draw_frame fill, draw_frame key);
+       static draw_frame still(draw_frame frame);
+       static draw_frame push(draw_frame frame);
+               
+       static const draw_frame& empty();
+       static const draw_frame& late();
+
+       // Constructors
+
+       draw_frame();
+       draw_frame(const draw_frame& other);
+       draw_frame(draw_frame&& other); 
+       explicit draw_frame(class const_frame&& frame);
+       explicit draw_frame(class mutable_frame&& frame);
+       explicit draw_frame(std::vector<draw_frame> frames);
+
+       ~draw_frame();
+       
+       // Methods
+
+       draw_frame& operator=(draw_frame other);
+
+       void swap(draw_frame& other);   
+       
+       void accept(frame_visitor& visitor) const;
+
+       bool operator==(const draw_frame& other) const;
+       bool operator!=(const draw_frame& other) const;
+
+       // Properties
+
+       const core::frame_transform&    transform() const;
+       core::frame_transform&                  transform();                    
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+       
+
 }}
\ No newline at end of file
index 71232f51d115a685b8d604fc6c2a5c59d25e90d8..9587953320660fd964372629689d9de01a5ad039 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "frame.h"\r
-\r
-#include <common/except.h>\r
-#include <common/array.h>\r
-\r
-#include <core/frame/frame_visitor.h>\r
-#include <core/frame/pixel_format.h>\r
-\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/thread/future.hpp>\r
-\r
-namespace caspar { namespace core {\r
-               \r
-struct mutable_frame::impl : boost::noncopyable\r
-{                      \r
-       std::vector<array<std::uint8_t>>                        buffers_;\r
-       core::audio_buffer                                                      audio_data_;\r
-       const core::pixel_format_desc                           desc_;\r
-       const void*                                                                     tag_;\r
-       \r
-       impl(std::vector<array<std::uint8_t>> buffers, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) \r
-               : buffers_(std::move(buffers))\r
-               , audio_data_(std::move(audio_buffer))\r
-               , desc_(desc)\r
-               , tag_(tag)\r
-       {\r
-               BOOST_FOREACH(auto& buffer, buffers_)\r
-                       if(!buffer.data())\r
-                               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("mutable_frame: null argument"));\r
-       }\r
-};\r
-       \r
-mutable_frame::mutable_frame(std::vector<array<std::uint8_t>> image_buffers, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) \r
-       : impl_(new impl(std::move(image_buffers), std::move(audio_buffer), tag, desc)){}\r
-mutable_frame::~mutable_frame(){}\r
-mutable_frame::mutable_frame(mutable_frame&& other) : impl_(std::move(other.impl_)){}\r
-mutable_frame& mutable_frame::operator=(mutable_frame&& other)\r
-{\r
-       impl_ = std::move(other.impl_);\r
-       return *this;\r
-}\r
-void mutable_frame::swap(mutable_frame& other){impl_.swap(other.impl_);}\r
-const core::pixel_format_desc& mutable_frame::pixel_format_desc() const{return impl_->desc_;}\r
-const array<std::uint8_t>& mutable_frame::image_data(std::size_t index) const{return impl_->buffers_.at(index);}\r
-const core::audio_buffer& mutable_frame::audio_data() const{return impl_->audio_data_;}\r
-array<std::uint8_t>& mutable_frame::image_data(std::size_t index){return impl_->buffers_.at(index);}\r
-core::audio_buffer& mutable_frame::audio_data(){return impl_->audio_data_;}\r
-std::size_t mutable_frame::width() const{return impl_->desc_.planes.at(0).width;}\r
-std::size_t mutable_frame::height() const{return impl_->desc_.planes.at(0).height;}                                            \r
-const void* mutable_frame::stream_tag()const{return impl_->tag_;}                              \r
-const void* mutable_frame::data_tag()const{return impl_.get();}        \r
-\r
-const const_frame& const_frame::empty()\r
-{\r
-       static int dummy;\r
-       static const_frame empty(&dummy);\r
-       return empty;\r
-}\r
-\r
-struct const_frame::impl : boost::noncopyable\r
-{                      \r
-       mutable std::vector<boost::shared_future<array<const std::uint8_t>>>    future_buffers_;\r
-       int                                                                                     id_;\r
-       core::audio_buffer                                                      audio_data_;\r
-       const core::pixel_format_desc                           desc_;\r
-       const void*                                                                     tag_;\r
-\r
-       impl(const void* tag)\r
-               : desc_(core::pixel_format::invalid)\r
-               , tag_(tag)     \r
-               , id_(0)\r
-       {\r
-       }\r
-       \r
-       impl(boost::shared_future<array<const std::uint8_t>> image, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) \r
-               : audio_data_(std::move(audio_buffer))\r
-               , desc_(desc)\r
-               , tag_(tag)\r
-               , id_(reinterpret_cast<int>(this))\r
-       {\r
-               if(desc.format != core::pixel_format::bgra)\r
-                       CASPAR_THROW_EXCEPTION(not_implemented());\r
-               \r
-               future_buffers_.push_back(std::move(image));\r
-       }\r
-\r
-       impl(mutable_frame&& other)\r
-               : audio_data_(other.audio_data())\r
-               , desc_(other.pixel_format_desc())\r
-               , tag_(other.stream_tag())\r
-               , id_(reinterpret_cast<int>(this))\r
-       {\r
-               for(std::size_t n = 0; n < desc_.planes.size(); ++n)\r
-               {\r
-                       boost::promise<array<const std::uint8_t>> p;\r
-                       p.set_value(std::move(other.image_data(n)));\r
-                       future_buffers_.push_back(p.get_future());\r
-               }\r
-       }\r
-\r
-       array<const std::uint8_t> image_data(int index) const\r
-       {\r
-               return tag_ != empty().stream_tag() ? future_buffers_.at(index).get() : array<const std::uint8_t>(nullptr, 0, true, 0);\r
-       }\r
-\r
-       std::size_t width() const\r
-       {\r
-               return tag_ != empty().stream_tag() ? desc_.planes.at(0).width : 0;\r
-       }\r
-\r
-       std::size_t height() const\r
-       {\r
-               return tag_ != empty().stream_tag() ? desc_.planes.at(0).height : 0;\r
-       }\r
-\r
-       std::size_t size() const\r
-       {\r
-               return tag_ != empty().stream_tag() ? desc_.planes.at(0).size : 0;\r
-       }\r
-};\r
-       \r
-const_frame::const_frame(const void* tag) : impl_(new impl(tag)){}\r
-const_frame::const_frame(boost::shared_future<array<const std::uint8_t>> image, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) \r
-       : impl_(new impl(std::move(image), std::move(audio_buffer), tag, desc)){}\r
-const_frame::const_frame(mutable_frame&& other) : impl_(new impl(std::move(other))){}\r
-const_frame::~const_frame(){}\r
-const_frame::const_frame(const_frame&& other) : impl_(std::move(other.impl_)){}\r
-const_frame& const_frame::operator=(const_frame&& other)\r
-{\r
-       impl_ = std::move(other.impl_);\r
-       return *this;\r
-}\r
-const_frame::const_frame(const const_frame& other) : impl_(other.impl_){}\r
-const_frame& const_frame::operator=(const const_frame& other)\r
-{\r
-       impl_ = other.impl_;\r
-       return *this;\r
-}\r
-bool const_frame::operator==(const const_frame& other){return impl_ == other.impl_;}\r
-bool const_frame::operator!=(const const_frame& other){return !(*this == other);}\r
-bool const_frame::operator<(const const_frame& other){return impl_< other.impl_;}\r
-bool const_frame::operator>(const const_frame& other){return impl_> other.impl_;}\r
-const core::pixel_format_desc& const_frame::pixel_format_desc()const{return impl_->desc_;}\r
-array<const std::uint8_t> const_frame::image_data(int index)const{return impl_->image_data(index);}\r
-const core::audio_buffer& const_frame::audio_data()const{return impl_->audio_data_;}\r
-std::size_t const_frame::width()const{return impl_->width();}\r
-std::size_t const_frame::height()const{return impl_->height();}        \r
-std::size_t const_frame::size()const{return impl_->size();}                                            \r
-const void* const_frame::stream_tag()const{return impl_->tag_;}                                \r
-const void* const_frame::data_tag()const{return impl_.get();}  \r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "frame.h"
+
+#include <common/except.h>
+#include <common/array.h>
+
+#include <core/frame/frame_visitor.h>
+#include <core/frame/pixel_format.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/thread/future.hpp>
+
+namespace caspar { namespace core {
+               
+struct mutable_frame::impl : boost::noncopyable
+{                      
+       std::vector<array<std::uint8_t>>                        buffers_;
+       core::audio_buffer                                                      audio_data_;
+       const core::pixel_format_desc                           desc_;
+       const void*                                                                     tag_;
+       
+       impl(std::vector<array<std::uint8_t>> buffers, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) 
+               : buffers_(std::move(buffers))
+               , audio_data_(std::move(audio_buffer))
+               , desc_(desc)
+               , tag_(tag)
+       {
+               BOOST_FOREACH(auto& buffer, buffers_)
+                       if(!buffer.data())
+                               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("mutable_frame: null argument"));
+       }
+};
+       
+mutable_frame::mutable_frame(std::vector<array<std::uint8_t>> image_buffers, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) 
+       : impl_(new impl(std::move(image_buffers), std::move(audio_buffer), tag, desc)){}
+mutable_frame::~mutable_frame(){}
+mutable_frame::mutable_frame(mutable_frame&& other) : impl_(std::move(other.impl_)){}
+mutable_frame& mutable_frame::operator=(mutable_frame&& other)
+{
+       impl_ = std::move(other.impl_);
+       return *this;
+}
+void mutable_frame::swap(mutable_frame& other){impl_.swap(other.impl_);}
+const core::pixel_format_desc& mutable_frame::pixel_format_desc() const{return impl_->desc_;}
+const array<std::uint8_t>& mutable_frame::image_data(std::size_t index) const{return impl_->buffers_.at(index);}
+const core::audio_buffer& mutable_frame::audio_data() const{return impl_->audio_data_;}
+array<std::uint8_t>& mutable_frame::image_data(std::size_t index){return impl_->buffers_.at(index);}
+core::audio_buffer& mutable_frame::audio_data(){return impl_->audio_data_;}
+std::size_t mutable_frame::width() const{return impl_->desc_.planes.at(0).width;}
+std::size_t mutable_frame::height() const{return impl_->desc_.planes.at(0).height;}                                            
+const void* mutable_frame::stream_tag()const{return impl_->tag_;}                              
+const void* mutable_frame::data_tag()const{return impl_.get();}        
+
+const const_frame& const_frame::empty()
+{
+       static int dummy;
+       static const_frame empty(&dummy);
+       return empty;
+}
+
+struct const_frame::impl : boost::noncopyable
+{                      
+       mutable std::vector<boost::shared_future<array<const std::uint8_t>>>    future_buffers_;
+       int                                                                                     id_;
+       core::audio_buffer                                                      audio_data_;
+       const core::pixel_format_desc                           desc_;
+       const void*                                                                     tag_;
+
+       impl(const void* tag)
+               : desc_(core::pixel_format::invalid)
+               , tag_(tag)     
+               , id_(0)
+       {
+       }
+       
+       impl(boost::shared_future<array<const std::uint8_t>> image, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) 
+               : audio_data_(std::move(audio_buffer))
+               , desc_(desc)
+               , tag_(tag)
+               , id_(reinterpret_cast<int>(this))
+       {
+               if(desc.format != core::pixel_format::bgra)
+                       CASPAR_THROW_EXCEPTION(not_implemented());
+               
+               future_buffers_.push_back(std::move(image));
+       }
+
+       impl(mutable_frame&& other)
+               : audio_data_(other.audio_data())
+               , desc_(other.pixel_format_desc())
+               , tag_(other.stream_tag())
+               , id_(reinterpret_cast<int>(this))
+       {
+               for(std::size_t n = 0; n < desc_.planes.size(); ++n)
+               {
+                       boost::promise<array<const std::uint8_t>> p;
+                       p.set_value(std::move(other.image_data(n)));
+                       future_buffers_.push_back(p.get_future());
+               }
+       }
+
+       array<const std::uint8_t> image_data(int index) const
+       {
+               return tag_ != empty().stream_tag() ? future_buffers_.at(index).get() : array<const std::uint8_t>(nullptr, 0, true, 0);
+       }
+
+       std::size_t width() const
+       {
+               return tag_ != empty().stream_tag() ? desc_.planes.at(0).width : 0;
+       }
+
+       std::size_t height() const
+       {
+               return tag_ != empty().stream_tag() ? desc_.planes.at(0).height : 0;
+       }
+
+       std::size_t size() const
+       {
+               return tag_ != empty().stream_tag() ? desc_.planes.at(0).size : 0;
+       }
+};
+       
+const_frame::const_frame(const void* tag) : impl_(new impl(tag)){}
+const_frame::const_frame(boost::shared_future<array<const std::uint8_t>> image, audio_buffer audio_buffer, const void* tag, const core::pixel_format_desc& desc) 
+       : impl_(new impl(std::move(image), std::move(audio_buffer), tag, desc)){}
+const_frame::const_frame(mutable_frame&& other) : impl_(new impl(std::move(other))){}
+const_frame::~const_frame(){}
+const_frame::const_frame(const_frame&& other) : impl_(std::move(other.impl_)){}
+const_frame& const_frame::operator=(const_frame&& other)
+{
+       impl_ = std::move(other.impl_);
+       return *this;
+}
+const_frame::const_frame(const const_frame& other) : impl_(other.impl_){}
+const_frame& const_frame::operator=(const const_frame& other)
+{
+       impl_ = other.impl_;
+       return *this;
+}
+bool const_frame::operator==(const const_frame& other){return impl_ == other.impl_;}
+bool const_frame::operator!=(const const_frame& other){return !(*this == other);}
+bool const_frame::operator<(const const_frame& other){return impl_< other.impl_;}
+bool const_frame::operator>(const const_frame& other){return impl_> other.impl_;}
+const core::pixel_format_desc& const_frame::pixel_format_desc()const{return impl_->desc_;}
+array<const std::uint8_t> const_frame::image_data(int index)const{return impl_->image_data(index);}
+const core::audio_buffer& const_frame::audio_data()const{return impl_->audio_data_;}
+std::size_t const_frame::width()const{return impl_->width();}
+std::size_t const_frame::height()const{return impl_->height();}        
+std::size_t const_frame::size()const{return impl_->size();}                                            
+const void* const_frame::stream_tag()const{return impl_->tag_;}                                
+const void* const_frame::data_tag()const{return impl_.get();}  
+
 }}
\ No newline at end of file
index 419d71f8891aad549201370a3d99597f4e265be0..454b6e5c36222ec0a1739145048e2b2c9609bf57 100644 (file)
-#pragma once\r
-\r
-#undef BOOST_PARAMETER_MAX_ARITY\r
-#define BOOST_PARAMETER_MAX_ARITY 7\r
-\r
-#include "../video_format.h"\r
-\r
-#include <common/memory.h>\r
-#include <common/forward.h>\r
-#include <common/array.h>\r
-\r
-#include <boost/range.hpp>\r
-#include <boost/any.hpp>\r
-\r
-#include <tbb/cache_aligned_allocator.h>\r
-\r
-#include <cstddef>\r
-#include <cstdint>\r
-\r
-FORWARD1(boost, template<typename> class shared_future);\r
-\r
-namespace caspar { namespace core {\r
-       \r
-typedef std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>> audio_buffer;\r
-\r
-class mutable_frame sealed\r
-{\r
-       mutable_frame(const mutable_frame&);\r
-       mutable_frame& operator=(const mutable_frame&);\r
-public:        \r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       explicit mutable_frame(std::vector<array<std::uint8_t>> image_buffers, \r
-                                               audio_buffer audio_buffer, \r
-                                               const void* tag, \r
-                                               const struct pixel_format_desc& desc);\r
-       ~mutable_frame();\r
-\r
-       // Methods\r
-\r
-       mutable_frame(mutable_frame&& other);\r
-       mutable_frame& operator=(mutable_frame&& other);\r
-\r
-       void swap(mutable_frame& other);\r
-                       \r
-       // Properties\r
-                       \r
-       const struct pixel_format_desc& pixel_format_desc() const;\r
-\r
-       const array<std::uint8_t>& image_data(std::size_t index = 0) const;\r
-       const core::audio_buffer& audio_data() const;\r
-\r
-       array<std::uint8_t>& image_data(std::size_t index = 0);\r
-       core::audio_buffer& audio_data();\r
-       \r
-       std::size_t width() const;\r
-       std::size_t height() const;\r
-                                                               \r
-       const void* stream_tag() const;\r
-       const void* data_tag() const;\r
-                       \r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-\r
-class const_frame sealed\r
-{\r
-public:        \r
-\r
-       // Static Members\r
-\r
-       static const const_frame& empty();\r
-\r
-       // Constructors\r
-\r
-       explicit const_frame(const void* tag = nullptr);\r
-       explicit const_frame(boost::shared_future<array<const std::uint8_t>> image, \r
-                                               audio_buffer audio_buffer, \r
-                                               const void* tag, \r
-                                               const struct pixel_format_desc& desc);\r
-       const_frame(mutable_frame&& other);\r
-       ~const_frame();\r
-\r
-       // Methods\r
-\r
-       const_frame(const_frame&& other);\r
-       const_frame& operator=(const_frame&& other);\r
-       const_frame(const const_frame&);\r
-       const_frame& operator=(const const_frame& other);\r
-                               \r
-       // Properties\r
-                               \r
-       const struct pixel_format_desc& pixel_format_desc() const;\r
-\r
-       array<const std::uint8_t> image_data(int index = 0) const;\r
-       const core::audio_buffer& audio_data() const;\r
-               \r
-       std::size_t width() const;\r
-       std::size_t height() const;\r
-       std::size_t size() const;\r
-                                                               \r
-       const void* stream_tag() const;\r
-       const void* data_tag() const;\r
-\r
-       bool operator==(const const_frame& other);\r
-       bool operator!=(const const_frame& other);\r
-       bool operator<(const const_frame& other);\r
-       bool operator>(const const_frame& other);\r
-                       \r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+#pragma once
+
+#undef BOOST_PARAMETER_MAX_ARITY
+#define BOOST_PARAMETER_MAX_ARITY 7
+
+#include "../video_format.h"
+
+#include <common/memory.h>
+#include <common/forward.h>
+#include <common/array.h>
+
+#include <boost/range.hpp>
+#include <boost/any.hpp>
+
+#include <tbb/cache_aligned_allocator.h>
+
+#include <cstddef>
+#include <cstdint>
+
+FORWARD1(boost, template<typename> class shared_future);
+
+namespace caspar { namespace core {
+       
+typedef std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>> audio_buffer;
+
+class mutable_frame sealed
+{
+       mutable_frame(const mutable_frame&);
+       mutable_frame& operator=(const mutable_frame&);
+public:        
+
+       // Static Members
+
+       // Constructors
+
+       explicit mutable_frame(std::vector<array<std::uint8_t>> image_buffers, 
+                                               audio_buffer audio_buffer, 
+                                               const void* tag, 
+                                               const struct pixel_format_desc& desc);
+       ~mutable_frame();
+
+       // Methods
+
+       mutable_frame(mutable_frame&& other);
+       mutable_frame& operator=(mutable_frame&& other);
+
+       void swap(mutable_frame& other);
+                       
+       // Properties
+                       
+       const struct pixel_format_desc& pixel_format_desc() const;
+
+       const array<std::uint8_t>& image_data(std::size_t index = 0) const;
+       const core::audio_buffer& audio_data() const;
+
+       array<std::uint8_t>& image_data(std::size_t index = 0);
+       core::audio_buffer& audio_data();
+       
+       std::size_t width() const;
+       std::size_t height() const;
+                                                               
+       const void* stream_tag() const;
+       const void* data_tag() const;
+                       
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+
+class const_frame sealed
+{
+public:        
+
+       // Static Members
+
+       static const const_frame& empty();
+
+       // Constructors
+
+       explicit const_frame(const void* tag = nullptr);
+       explicit const_frame(boost::shared_future<array<const std::uint8_t>> image, 
+                                               audio_buffer audio_buffer, 
+                                               const void* tag, 
+                                               const struct pixel_format_desc& desc);
+       const_frame(mutable_frame&& other);
+       ~const_frame();
+
+       // Methods
+
+       const_frame(const_frame&& other);
+       const_frame& operator=(const_frame&& other);
+       const_frame(const const_frame&);
+       const_frame& operator=(const const_frame& other);
+                               
+       // Properties
+                               
+       const struct pixel_format_desc& pixel_format_desc() const;
+
+       array<const std::uint8_t> image_data(int index = 0) const;
+       const core::audio_buffer& audio_data() const;
+               
+       std::size_t width() const;
+       std::size_t height() const;
+       std::size_t size() const;
+                                                               
+       const void* stream_tag() const;
+       const void* data_tag() const;
+
+       bool operator==(const const_frame& other);
+       bool operator!=(const const_frame& other);
+       bool operator<(const const_frame& other);
+       bool operator>(const const_frame& other);
+                       
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index 75d46e6719c01e76818d2d49ff9bfbfe74a2eb45..4c237d7ba90193332832cc5f79ede6e8d419a16d 100644 (file)
@@ -1,49 +1,49 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "frame.h"\r
-\r
-#include <common/memory.h>\r
-\r
-namespace caspar { namespace core {\r
-                       \r
-class frame_factory : boost::noncopyable\r
-{\r
-       frame_factory(const frame_factory&);\r
-       frame_factory& operator=(const frame_factory&);\r
-public:\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       frame_factory(){}\r
-       virtual ~frame_factory(){}\r
-\r
-       // Methods\r
-\r
-       virtual class mutable_frame     create_frame(const void* video_stream_tag, const struct pixel_format_desc& desc) = 0;   \r
-\r
-       // Properties\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "frame.h"
+
+#include <common/memory.h>
+
+namespace caspar { namespace core {
+                       
+class frame_factory : boost::noncopyable
+{
+       frame_factory(const frame_factory&);
+       frame_factory& operator=(const frame_factory&);
+public:
+       // Static Members
+
+       // Constructors
+
+       frame_factory(){}
+       virtual ~frame_factory(){}
+
+       // Methods
+
+       virtual class mutable_frame     create_frame(const void* video_stream_tag, const struct pixel_format_desc& desc) = 0;   
+
+       // Properties
+};
+
 }}
\ No newline at end of file
index 5ebac4740a878dd1c4c5134a746c53696f831f82..f9c14f3aa3f1fa288d273015d61a7a9492098b07 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "frame_transform.h"\r
-\r
-#include <boost/range/algorithm/equal.hpp>\r
-#include <boost/range/algorithm/fill.hpp>\r
-\r
-namespace caspar { namespace core {\r
-               \r
-// image_transform\r
-\r
-image_transform::image_transform() \r
-       : opacity(1.0)\r
-       , brightness(1.0)\r
-       , contrast(1.0)\r
-       , saturation(1.0)\r
-       , field_mode(field_mode::progressive)\r
-       , is_key(false)\r
-       , is_mix(false)\r
-       , is_still(false)\r
-{\r
-       boost::range::fill(fill_translation, 0.0);\r
-       boost::range::fill(fill_scale, 1.0);\r
-       boost::range::fill(clip_translation, 0.0);\r
-       boost::range::fill(clip_scale, 1.0);\r
-}\r
-\r
-image_transform& image_transform::operator*=(const image_transform &other)\r
-{\r
-       opacity                                 *= other.opacity;       \r
-       brightness                              *= other.brightness;\r
-       contrast                                *= other.contrast;\r
-       saturation                              *= other.saturation;\r
-       fill_translation[0]             += other.fill_translation[0]*fill_scale[0];\r
-       fill_translation[1]             += other.fill_translation[1]*fill_scale[1];\r
-       fill_scale[0]                   *= other.fill_scale[0];\r
-       fill_scale[1]                   *= other.fill_scale[1];\r
-       clip_translation[0]             += other.clip_translation[0]*clip_scale[0];\r
-       clip_translation[1]             += other.clip_translation[1]*clip_scale[1];\r
-       clip_scale[0]                   *= other.clip_scale[0];\r
-       clip_scale[1]                   *= other.clip_scale[1];\r
-       levels.min_input                 = std::max(levels.min_input,  other.levels.min_input);\r
-       levels.max_input                 = std::min(levels.max_input,  other.levels.max_input); \r
-       levels.min_output                = std::max(levels.min_output, other.levels.min_output);\r
-       levels.max_output                = std::min(levels.max_output, other.levels.max_output);\r
-       levels.gamma                    *= other.levels.gamma;\r
-       field_mode                               = static_cast<core::field_mode>(field_mode & other.field_mode);\r
-       is_key                                  |= other.is_key;\r
-       is_mix                                  |= other.is_mix;\r
-       is_still                                |= other.is_still;\r
-       return *this;\r
-}\r
-\r
-image_transform image_transform::operator*(const image_transform &other) const\r
-{\r
-       return image_transform(*this) *= other;\r
-}\r
-\r
-image_transform image_transform::tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener& tween)\r
-{      \r
-       auto do_tween = [](double time, double source, double dest, double duration, const tweener& tween)\r
-       {\r
-               return tween(time, source, dest-source, duration);\r
-       };\r
-       \r
-       image_transform result; \r
-       result.brightness                       = do_tween(time, source.brightness,                             dest.brightness,                        duration, tween);\r
-       result.contrast                         = do_tween(time, source.contrast,                               dest.contrast,                          duration, tween);\r
-       result.saturation                       = do_tween(time, source.saturation,                             dest.saturation,                        duration, tween);\r
-       result.opacity                          = do_tween(time, source.opacity,                                dest.opacity,                           duration, tween);       \r
-       result.fill_translation[0]      = do_tween(time, source.fill_translation[0],    dest.fill_translation[0],       duration, tween), \r
-       result.fill_translation[1]      = do_tween(time, source.fill_translation[1],    dest.fill_translation[1],       duration, tween);               \r
-       result.fill_scale[0]            = do_tween(time, source.fill_scale[0],                  dest.fill_scale[0],                     duration, tween), \r
-       result.fill_scale[1]            = do_tween(time, source.fill_scale[1],                  dest.fill_scale[1],                     duration, tween);       \r
-       result.clip_translation[0]      = do_tween(time, source.clip_translation[0],    dest.clip_translation[0],       duration, tween), \r
-       result.clip_translation[1]      = do_tween(time, source.clip_translation[1],    dest.clip_translation[1],       duration, tween);               \r
-       result.clip_scale[0]            = do_tween(time, source.clip_scale[0],                  dest.clip_scale[0],                     duration, tween), \r
-       result.clip_scale[1]            = do_tween(time, source.clip_scale[1],                  dest.clip_scale[1],                     duration, tween);\r
-       result.levels.max_input         = do_tween(time, source.levels.max_input,               dest.levels.max_input,          duration, tween);\r
-       result.levels.min_input         = do_tween(time, source.levels.min_input,               dest.levels.min_input,          duration, tween);       \r
-       result.levels.max_output        = do_tween(time, source.levels.max_output,              dest.levels.max_output,         duration, tween);\r
-       result.levels.min_output        = do_tween(time, source.levels.min_output,              dest.levels.min_output,         duration, tween);\r
-       result.levels.gamma                     = do_tween(time, source.levels.gamma,                   dest.levels.gamma,                      duration, tween);\r
-       result.field_mode                       = source.field_mode & dest.field_mode;\r
-       result.is_key                           = source.is_key | dest.is_key;\r
-       result.is_mix                           = source.is_mix | dest.is_mix;\r
-       result.is_still                         = source.is_still | dest.is_still;\r
-       \r
-       return result;\r
-}\r
-\r
-bool operator==(const image_transform& lhs, const image_transform& rhs)\r
-{\r
-       auto eq = [](double lhs, double rhs)\r
-       {\r
-               return std::abs(lhs - rhs) < 5e-8;\r
-       };\r
-\r
-       return \r
-               eq(lhs.opacity, rhs.opacity) &&\r
-               eq(lhs.contrast, rhs.contrast) &&\r
-               eq(lhs.brightness, rhs.brightness) &&\r
-               eq(lhs.saturation, rhs.saturation) &&\r
-               boost::range::equal(lhs.fill_translation, rhs.fill_translation, eq) &&\r
-               boost::range::equal(lhs.fill_scale, rhs.fill_scale, eq) &&\r
-               boost::range::equal(lhs.clip_translation, rhs.clip_translation, eq) &&\r
-               boost::range::equal(lhs.clip_scale, rhs.clip_scale, eq) &&\r
-               lhs.field_mode == rhs.field_mode &&\r
-               lhs.is_key == rhs.is_key &&\r
-               lhs.is_mix == rhs.is_mix &&\r
-               lhs.is_still == rhs.is_still;\r
-}\r
-\r
-bool operator!=(const image_transform& lhs, const image_transform& rhs)\r
-{\r
-       return !(lhs == rhs);\r
-}\r
-\r
-// audio_transform\r
-               \r
-audio_transform::audio_transform() \r
-       : volume(1.0)\r
-       , is_still(false)\r
-{\r
-}\r
-\r
-audio_transform& audio_transform::operator*=(const audio_transform &other)\r
-{\r
-       volume   *= other.volume;       \r
-       is_still |= other.is_still;\r
-       return *this;\r
-}\r
-\r
-audio_transform audio_transform::operator*(const audio_transform &other) const\r
-{\r
-       return audio_transform(*this) *= other;\r
-}\r
-\r
-audio_transform audio_transform::tween(double time, const audio_transform& source, const audio_transform& dest, double duration, const tweener& tween)\r
-{      \r
-       auto do_tween = [](double time, double source, double dest, double duration, const tweener& tween)\r
-       {\r
-               return tween(time, source, dest-source, duration);\r
-       };\r
-       \r
-       audio_transform result; \r
-       result.is_still                 = source.is_still | dest.is_still;\r
-       result.volume                   = do_tween(time, source.volume,                         dest.volume,                    duration, tween);\r
-       \r
-       return result;\r
-}\r
-\r
-bool operator==(const audio_transform& lhs, const audio_transform& rhs)\r
-{\r
-       auto eq = [](double lhs, double rhs)\r
-       {\r
-               return std::abs(lhs - rhs) < 5e-8;\r
-       };\r
-\r
-       return eq(lhs.volume, rhs.volume) && lhs.is_still == rhs.is_still;\r
-}\r
-\r
-bool operator!=(const audio_transform& lhs, const audio_transform& rhs)\r
-{\r
-       return !(lhs == rhs);\r
-}\r
-\r
-// frame_transform\r
-frame_transform::frame_transform()\r
-{\r
-}\r
-\r
-frame_transform& frame_transform::operator*=(const frame_transform &other)\r
-{\r
-       image_transform *= other.image_transform;\r
-       audio_transform *= other.audio_transform;\r
-       return *this;\r
-}\r
-\r
-frame_transform frame_transform::operator*(const frame_transform &other) const\r
-{\r
-       return frame_transform(*this) *= other;\r
-}\r
-\r
-frame_transform frame_transform::tween(double time, const frame_transform& source, const frame_transform& dest, double duration, const tweener& tween)\r
-{\r
-       frame_transform result;\r
-       result.image_transform = image_transform::tween(time, source.image_transform, dest.image_transform, duration, tween);\r
-       result.audio_transform = audio_transform::tween(time, source.audio_transform, dest.audio_transform, duration, tween);\r
-       return result;\r
-}\r
-\r
-bool operator==(const frame_transform& lhs, const frame_transform& rhs)\r
-{\r
-       return  lhs.image_transform == rhs.image_transform && \r
-                       lhs.audio_transform == rhs.audio_transform;\r
-}\r
-\r
-bool operator!=(const frame_transform& lhs, const frame_transform& rhs)\r
-{\r
-       return !(lhs == rhs);\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "frame_transform.h"
+
+#include <boost/range/algorithm/equal.hpp>
+#include <boost/range/algorithm/fill.hpp>
+
+namespace caspar { namespace core {
+               
+// image_transform
+
+image_transform::image_transform() 
+       : opacity(1.0)
+       , brightness(1.0)
+       , contrast(1.0)
+       , saturation(1.0)
+       , field_mode(field_mode::progressive)
+       , is_key(false)
+       , is_mix(false)
+       , is_still(false)
+{
+       boost::range::fill(fill_translation, 0.0);
+       boost::range::fill(fill_scale, 1.0);
+       boost::range::fill(clip_translation, 0.0);
+       boost::range::fill(clip_scale, 1.0);
+}
+
+image_transform& image_transform::operator*=(const image_transform &other)
+{
+       opacity                                 *= other.opacity;       
+       brightness                              *= other.brightness;
+       contrast                                *= other.contrast;
+       saturation                              *= other.saturation;
+       fill_translation[0]             += other.fill_translation[0]*fill_scale[0];
+       fill_translation[1]             += other.fill_translation[1]*fill_scale[1];
+       fill_scale[0]                   *= other.fill_scale[0];
+       fill_scale[1]                   *= other.fill_scale[1];
+       clip_translation[0]             += other.clip_translation[0]*clip_scale[0];
+       clip_translation[1]             += other.clip_translation[1]*clip_scale[1];
+       clip_scale[0]                   *= other.clip_scale[0];
+       clip_scale[1]                   *= other.clip_scale[1];
+       levels.min_input                 = std::max(levels.min_input,  other.levels.min_input);
+       levels.max_input                 = std::min(levels.max_input,  other.levels.max_input); 
+       levels.min_output                = std::max(levels.min_output, other.levels.min_output);
+       levels.max_output                = std::min(levels.max_output, other.levels.max_output);
+       levels.gamma                    *= other.levels.gamma;
+       field_mode                               = static_cast<core::field_mode>(field_mode & other.field_mode);
+       is_key                                  |= other.is_key;
+       is_mix                                  |= other.is_mix;
+       is_still                                |= other.is_still;
+       return *this;
+}
+
+image_transform image_transform::operator*(const image_transform &other) const
+{
+       return image_transform(*this) *= other;
+}
+
+image_transform image_transform::tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener& tween)
+{      
+       auto do_tween = [](double time, double source, double dest, double duration, const tweener& tween)
+       {
+               return tween(time, source, dest-source, duration);
+       };
+       
+       image_transform result; 
+       result.brightness                       = do_tween(time, source.brightness,                             dest.brightness,                        duration, tween);
+       result.contrast                         = do_tween(time, source.contrast,                               dest.contrast,                          duration, tween);
+       result.saturation                       = do_tween(time, source.saturation,                             dest.saturation,                        duration, tween);
+       result.opacity                          = do_tween(time, source.opacity,                                dest.opacity,                           duration, tween);       
+       result.fill_translation[0]      = do_tween(time, source.fill_translation[0],    dest.fill_translation[0],       duration, tween), 
+       result.fill_translation[1]      = do_tween(time, source.fill_translation[1],    dest.fill_translation[1],       duration, tween);               
+       result.fill_scale[0]            = do_tween(time, source.fill_scale[0],                  dest.fill_scale[0],                     duration, tween), 
+       result.fill_scale[1]            = do_tween(time, source.fill_scale[1],                  dest.fill_scale[1],                     duration, tween);       
+       result.clip_translation[0]      = do_tween(time, source.clip_translation[0],    dest.clip_translation[0],       duration, tween), 
+       result.clip_translation[1]      = do_tween(time, source.clip_translation[1],    dest.clip_translation[1],       duration, tween);               
+       result.clip_scale[0]            = do_tween(time, source.clip_scale[0],                  dest.clip_scale[0],                     duration, tween), 
+       result.clip_scale[1]            = do_tween(time, source.clip_scale[1],                  dest.clip_scale[1],                     duration, tween);
+       result.levels.max_input         = do_tween(time, source.levels.max_input,               dest.levels.max_input,          duration, tween);
+       result.levels.min_input         = do_tween(time, source.levels.min_input,               dest.levels.min_input,          duration, tween);       
+       result.levels.max_output        = do_tween(time, source.levels.max_output,              dest.levels.max_output,         duration, tween);
+       result.levels.min_output        = do_tween(time, source.levels.min_output,              dest.levels.min_output,         duration, tween);
+       result.levels.gamma                     = do_tween(time, source.levels.gamma,                   dest.levels.gamma,                      duration, tween);
+       result.field_mode                       = source.field_mode & dest.field_mode;
+       result.is_key                           = source.is_key | dest.is_key;
+       result.is_mix                           = source.is_mix | dest.is_mix;
+       result.is_still                         = source.is_still | dest.is_still;
+       
+       return result;
+}
+
+bool operator==(const image_transform& lhs, const image_transform& rhs)
+{
+       auto eq = [](double lhs, double rhs)
+       {
+               return std::abs(lhs - rhs) < 5e-8;
+       };
+
+       return 
+               eq(lhs.opacity, rhs.opacity) &&
+               eq(lhs.contrast, rhs.contrast) &&
+               eq(lhs.brightness, rhs.brightness) &&
+               eq(lhs.saturation, rhs.saturation) &&
+               boost::range::equal(lhs.fill_translation, rhs.fill_translation, eq) &&
+               boost::range::equal(lhs.fill_scale, rhs.fill_scale, eq) &&
+               boost::range::equal(lhs.clip_translation, rhs.clip_translation, eq) &&
+               boost::range::equal(lhs.clip_scale, rhs.clip_scale, eq) &&
+               lhs.field_mode == rhs.field_mode &&
+               lhs.is_key == rhs.is_key &&
+               lhs.is_mix == rhs.is_mix &&
+               lhs.is_still == rhs.is_still;
+}
+
+bool operator!=(const image_transform& lhs, const image_transform& rhs)
+{
+       return !(lhs == rhs);
+}
+
+// audio_transform
+               
+audio_transform::audio_transform() 
+       : volume(1.0)
+       , is_still(false)
+{
+}
+
+audio_transform& audio_transform::operator*=(const audio_transform &other)
+{
+       volume   *= other.volume;       
+       is_still |= other.is_still;
+       return *this;
+}
+
+audio_transform audio_transform::operator*(const audio_transform &other) const
+{
+       return audio_transform(*this) *= other;
+}
+
+audio_transform audio_transform::tween(double time, const audio_transform& source, const audio_transform& dest, double duration, const tweener& tween)
+{      
+       auto do_tween = [](double time, double source, double dest, double duration, const tweener& tween)
+       {
+               return tween(time, source, dest-source, duration);
+       };
+       
+       audio_transform result; 
+       result.is_still                 = source.is_still | dest.is_still;
+       result.volume                   = do_tween(time, source.volume,                         dest.volume,                    duration, tween);
+       
+       return result;
+}
+
+bool operator==(const audio_transform& lhs, const audio_transform& rhs)
+{
+       auto eq = [](double lhs, double rhs)
+       {
+               return std::abs(lhs - rhs) < 5e-8;
+       };
+
+       return eq(lhs.volume, rhs.volume) && lhs.is_still == rhs.is_still;
+}
+
+bool operator!=(const audio_transform& lhs, const audio_transform& rhs)
+{
+       return !(lhs == rhs);
+}
+
+// frame_transform
+frame_transform::frame_transform()
+{
+}
+
+frame_transform& frame_transform::operator*=(const frame_transform &other)
+{
+       image_transform *= other.image_transform;
+       audio_transform *= other.audio_transform;
+       return *this;
+}
+
+frame_transform frame_transform::operator*(const frame_transform &other) const
+{
+       return frame_transform(*this) *= other;
+}
+
+frame_transform frame_transform::tween(double time, const frame_transform& source, const frame_transform& dest, double duration, const tweener& tween)
+{
+       frame_transform result;
+       result.image_transform = image_transform::tween(time, source.image_transform, dest.image_transform, duration, tween);
+       result.audio_transform = audio_transform::tween(time, source.audio_transform, dest.audio_transform, duration, tween);
+       return result;
+}
+
+bool operator==(const frame_transform& lhs, const frame_transform& rhs)
+{
+       return  lhs.image_transform == rhs.image_transform && 
+                       lhs.audio_transform == rhs.audio_transform;
+}
+
+bool operator!=(const frame_transform& lhs, const frame_transform& rhs)
+{
+       return !(lhs == rhs);
+}
+
 }}
\ No newline at end of file
index 4d32e8d729924590714e167c96a694e000e5e03c..8b82f3d8445c134ca93a496c525772e024275529 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/tweener.h>\r
-#include <core/video_format.h>\r
-\r
-#include <boost/array.hpp>\r
-\r
-namespace caspar { namespace core {\r
-                       \r
-struct levels sealed\r
-{\r
-       levels() \r
-               : min_input(0.0)\r
-               , max_input(1.0)\r
-               , gamma(1.0)\r
-               , min_output(0.0)\r
-               , max_output(1.0)\r
-       {               \r
-       }\r
-       double min_input;\r
-       double max_input;\r
-       double gamma;\r
-       double min_output;\r
-       double max_output;\r
-};\r
-\r
-struct image_transform sealed\r
-{\r
-public:\r
-       image_transform();\r
-\r
-       double                                  opacity;\r
-       double                                  contrast;\r
-       double                                  brightness;\r
-       double                                  saturation;\r
-       boost::array<double, 2> fill_translation; \r
-       boost::array<double, 2> fill_scale; \r
-       boost::array<double, 2> clip_translation;  \r
-       boost::array<double, 2> clip_scale;  \r
-       levels                                  levels;\r
-\r
-       field_mode                              field_mode;\r
-       bool                                    is_key;\r
-       bool                                    is_mix;\r
-       bool                                    is_still;\r
-       \r
-       image_transform& operator*=(const image_transform &other);\r
-       image_transform operator*(const image_transform &other) const;\r
-\r
-       static image_transform tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener& tween);\r
-};\r
-\r
-bool operator==(const image_transform& lhs, const image_transform& rhs);\r
-bool operator!=(const image_transform& lhs, const image_transform& rhs);\r
-\r
-struct audio_transform sealed\r
-{\r
-public:\r
-       audio_transform();\r
-\r
-       double  volume;\r
-       bool    is_still;\r
-       \r
-       audio_transform& operator*=(const audio_transform &other);\r
-       audio_transform operator*(const audio_transform &other) const;\r
-\r
-       static audio_transform tween(double time, const audio_transform& source, const audio_transform& dest, double duration, const tweener& tween);\r
-};\r
-\r
-bool operator==(const audio_transform& lhs, const audio_transform& rhs);\r
-bool operator!=(const audio_transform& lhs, const audio_transform& rhs);\r
-\r
-//__declspec(align(16)) \r
-struct frame_transform sealed\r
-{\r
-public:\r
-       frame_transform();\r
-       \r
-       image_transform image_transform;\r
-       audio_transform audio_transform;\r
-\r
-       char padding[3];\r
-       \r
-       frame_transform& operator*=(const frame_transform &other);\r
-       frame_transform operator*(const frame_transform &other) const;\r
-\r
-       static frame_transform tween(double time, const frame_transform& source, const frame_transform& dest, double duration, const tweener& tween);\r
-};\r
-\r
-bool operator==(const frame_transform& lhs, const frame_transform& rhs);\r
-bool operator!=(const frame_transform& lhs, const frame_transform& rhs);\r
-\r
-class tweened_transform\r
-{\r
-       frame_transform source_;\r
-       frame_transform dest_;\r
-       int duration_;\r
-       int time_;\r
-       tweener tweener_;\r
-public:        \r
-       tweened_transform()\r
-               : duration_(0)\r
-               , time_(0)\r
-       {\r
-       }\r
-\r
-       tweened_transform(const frame_transform& source, const frame_transform& dest, int duration, const tweener& tween)\r
-               : source_(source)\r
-               , dest_(dest)\r
-               , duration_(duration)\r
-               , time_(0)\r
-               , tweener_(tween)\r
-       {\r
-       }\r
-       \r
-       frame_transform fetch()\r
-       {\r
-               return time_ == duration_ ? dest_ : frame_transform::tween(static_cast<double>(time_), source_, dest_, static_cast<double>(duration_), tweener_);\r
-       }\r
-\r
-       frame_transform fetch_and_tick(int num)\r
-       {                                               \r
-               time_ = std::min(time_+num, duration_);\r
-               return fetch();\r
-       }\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/tweener.h>
+#include <core/video_format.h>
+
+#include <boost/array.hpp>
+
+namespace caspar { namespace core {
+                       
+struct levels sealed
+{
+       levels() 
+               : min_input(0.0)
+               , max_input(1.0)
+               , gamma(1.0)
+               , min_output(0.0)
+               , max_output(1.0)
+       {               
+       }
+       double min_input;
+       double max_input;
+       double gamma;
+       double min_output;
+       double max_output;
+};
+
+struct image_transform sealed
+{
+public:
+       image_transform();
+
+       double                                  opacity;
+       double                                  contrast;
+       double                                  brightness;
+       double                                  saturation;
+       boost::array<double, 2> fill_translation; 
+       boost::array<double, 2> fill_scale; 
+       boost::array<double, 2> clip_translation;  
+       boost::array<double, 2> clip_scale;  
+       levels                                  levels;
+
+       field_mode                              field_mode;
+       bool                                    is_key;
+       bool                                    is_mix;
+       bool                                    is_still;
+       
+       image_transform& operator*=(const image_transform &other);
+       image_transform operator*(const image_transform &other) const;
+
+       static image_transform tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener& tween);
+};
+
+bool operator==(const image_transform& lhs, const image_transform& rhs);
+bool operator!=(const image_transform& lhs, const image_transform& rhs);
+
+struct audio_transform sealed
+{
+public:
+       audio_transform();
+
+       double  volume;
+       bool    is_still;
+       
+       audio_transform& operator*=(const audio_transform &other);
+       audio_transform operator*(const audio_transform &other) const;
+
+       static audio_transform tween(double time, const audio_transform& source, const audio_transform& dest, double duration, const tweener& tween);
+};
+
+bool operator==(const audio_transform& lhs, const audio_transform& rhs);
+bool operator!=(const audio_transform& lhs, const audio_transform& rhs);
+
+//__declspec(align(16)) 
+struct frame_transform sealed
+{
+public:
+       frame_transform();
+       
+       image_transform image_transform;
+       audio_transform audio_transform;
+
+       char padding[3];
+       
+       frame_transform& operator*=(const frame_transform &other);
+       frame_transform operator*(const frame_transform &other) const;
+
+       static frame_transform tween(double time, const frame_transform& source, const frame_transform& dest, double duration, const tweener& tween);
+};
+
+bool operator==(const frame_transform& lhs, const frame_transform& rhs);
+bool operator!=(const frame_transform& lhs, const frame_transform& rhs);
+
+class tweened_transform
+{
+       frame_transform source_;
+       frame_transform dest_;
+       int duration_;
+       int time_;
+       tweener tweener_;
+public:        
+       tweened_transform()
+               : duration_(0)
+               , time_(0)
+       {
+       }
+
+       tweened_transform(const frame_transform& source, const frame_transform& dest, int duration, const tweener& tween)
+               : source_(source)
+               , dest_(dest)
+               , duration_(duration)
+               , time_(0)
+               , tweener_(tween)
+       {
+       }
+       
+       frame_transform fetch()
+       {
+               return time_ == duration_ ? dest_ : frame_transform::tween(static_cast<double>(time_), source_, dest_, static_cast<double>(duration_), tweener_);
+       }
+
+       frame_transform fetch_and_tick(int num)
+       {                                               
+               time_ = std::min(time_+num, duration_);
+               return fetch();
+       }
+};
+
 }}
\ No newline at end of file
index c952a23870cd70df263298e2e9f169bf599fdfbd..ff11de1535060f9bc4ddc288b2b19a20035c88d1 100644 (file)
@@ -1,47 +1,47 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-namespace caspar { namespace core {\r
-       \r
-class frame_visitor\r
-{\r
-       frame_visitor(const frame_visitor&);\r
-       frame_visitor& operator=(const frame_visitor&);\r
-public:\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       frame_visitor(){}\r
-       virtual ~frame_visitor(){}\r
-\r
-       // Methods\r
-\r
-       virtual void push(const struct frame_transform& transform) = 0;\r
-       virtual void visit(const class const_frame& frame) = 0;\r
-       virtual void pop() = 0;\r
-\r
-       // Properties\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+namespace caspar { namespace core {
+       
+class frame_visitor
+{
+       frame_visitor(const frame_visitor&);
+       frame_visitor& operator=(const frame_visitor&);
+public:
+       // Static Members
+
+       // Constructors
+
+       frame_visitor(){}
+       virtual ~frame_visitor(){}
+
+       // Methods
+
+       virtual void push(const struct frame_transform& transform) = 0;
+       virtual void visit(const class const_frame& frame) = 0;
+       virtual void pop() = 0;
+
+       // Properties
+};
+
 }}
\ No newline at end of file
index 98469ce6a47ccb58f00c86a159c31057049914d9..a41d7228c5bc461b1fa58c2ab4a57d9ee73588d7 100644 (file)
@@ -1,91 +1,91 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "../video_format.h"\r
-\r
-#include <common/enum_class.h>\r
-\r
-#include <cstddef>\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
-               \r
-struct pixel_format_def\r
-{\r
-       enum type\r
-       {\r
-               gray = 0,\r
-               bgra,\r
-               rgba,\r
-               argb,\r
-               abgr,\r
-               ycbcr,\r
-               ycbcra,\r
-               luma,\r
-               bgr,\r
-               rgb,\r
-               count,\r
-               invalid,\r
-       };\r
-};\r
-typedef enum_class<pixel_format_def> pixel_format;\r
-\r
-struct pixel_format_desc sealed\r
-{\r
-       struct plane\r
-       {\r
-               int linesize;\r
-               int width;\r
-               int height;\r
-               int size;\r
-               int stride;\r
-\r
-               plane() \r
-                       : linesize(0)\r
-                       , width(0)\r
-                       , height(0)\r
-                       , size(0)\r
-                       , stride(0)\r
-               {\r
-               }\r
-\r
-               plane(int width, int height, int stride)\r
-                       : linesize(width*stride)\r
-                       , width(width)\r
-                       , height(height)\r
-                       , size(width*height*stride)\r
-                       , stride(stride)\r
-               {\r
-               }\r
-       };\r
-\r
-       pixel_format_desc(pixel_format format = core::pixel_format::invalid) \r
-               : format(format)\r
-       {\r
-       }\r
-       \r
-       pixel_format            format;\r
-       std::vector<plane>      planes;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "../video_format.h"
+
+#include <common/enum_class.h>
+
+#include <cstddef>
+#include <vector>
+
+namespace caspar { namespace core {
+               
+struct pixel_format_def
+{
+       enum type
+       {
+               gray = 0,
+               bgra,
+               rgba,
+               argb,
+               abgr,
+               ycbcr,
+               ycbcra,
+               luma,
+               bgr,
+               rgb,
+               count,
+               invalid,
+       };
+};
+typedef enum_class<pixel_format_def> pixel_format;
+
+struct pixel_format_desc sealed
+{
+       struct plane
+       {
+               int linesize;
+               int width;
+               int height;
+               int size;
+               int stride;
+
+               plane() 
+                       : linesize(0)
+                       , width(0)
+                       , height(0)
+                       , size(0)
+                       , stride(0)
+               {
+               }
+
+               plane(int width, int height, int stride)
+                       : linesize(width*stride)
+                       , width(width)
+                       , height(height)
+                       , size(width*height*stride)
+                       , stride(stride)
+               {
+               }
+       };
+
+       pixel_format_desc(pixel_format format = core::pixel_format::invalid) 
+               : format(format)
+       {
+       }
+       
+       pixel_format            format;
+       std::vector<plane>      planes;
+};
+
 }}
\ No newline at end of file
index 2c7453371a0c7ad34980299cd108e40610600ce3..878b56ac0f3fc8391f9790b503ba8df596f48f1c 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "audio_mixer.h"\r
-\r
-#include <core/frame/frame.h>\r
-#include <core/frame/frame_transform.h>\r
-#include <common/diagnostics/graph.h>\r
-\r
-#include <boost/range/adaptors.hpp>\r
-#include <boost/range/distance.hpp>\r
-\r
-#include <map>\r
-#include <stack>\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
-\r
-struct audio_item\r
-{\r
-       const void*                     tag;\r
-       audio_transform         transform;\r
-       audio_buffer            audio_data;\r
-\r
-       audio_item()\r
-       {\r
-       }\r
-\r
-       audio_item(audio_item&& other)\r
-               : tag(std::move(other.tag))\r
-               , transform(std::move(other.transform))\r
-               , audio_data(std::move(other.audio_data))\r
-       {\r
-       }\r
-};\r
-\r
-typedef std::vector<float, tbb::cache_aligned_allocator<float>> audio_buffer_ps;\r
-       \r
-struct audio_stream\r
-{\r
-       audio_transform         prev_transform;\r
-       audio_buffer_ps         audio_data;\r
-       bool                            is_still;\r
-\r
-       audio_stream() \r
-               : is_still(false)\r
-       {\r
-       }\r
-};\r
-\r
-struct audio_mixer::impl : boost::noncopyable\r
-{\r
-       std::stack<core::audio_transform>       transform_stack_;\r
-       std::map<const void*, audio_stream>     audio_streams_;\r
-       std::vector<audio_item>                         items_;\r
-       std::vector<int>                                        audio_cadence_;\r
-       video_format_desc                                       format_desc_;\r
-       \r
-public:\r
-       impl()\r
-       {\r
-               transform_stack_.push(core::audio_transform());\r
-       }\r
-       \r
-       void push(const frame_transform& transform)\r
-       {\r
-               transform_stack_.push(transform_stack_.top()*transform.audio_transform);\r
-       }\r
-\r
-       void visit(const const_frame& frame)\r
-       {\r
-               if(transform_stack_.top().volume < 0.002 || frame.audio_data().empty())\r
-                       return;\r
-\r
-               audio_item item;\r
-               item.tag                = frame.stream_tag();\r
-               item.transform  = transform_stack_.top();\r
-               item.audio_data = frame.audio_data();\r
-\r
-               if(item.transform.is_still)\r
-                       item.transform.volume = 0.0;\r
-               \r
-               items_.push_back(std::move(item));              \r
-       }\r
-\r
-       void begin(const core::audio_transform& transform)\r
-       {\r
-               transform_stack_.push(transform_stack_.top()*transform);\r
-       }\r
-               \r
-       void pop()\r
-       {\r
-               transform_stack_.pop();\r
-       }\r
-       \r
-       audio_buffer mix(const video_format_desc& format_desc)\r
-       {       \r
-               if(format_desc_ != format_desc)\r
-               {\r
-                       audio_streams_.clear();\r
-                       audio_cadence_ = format_desc.audio_cadence;\r
-                       format_desc_ = format_desc;\r
-               }               \r
-               \r
-               std::map<const void*, audio_stream>     next_audio_streams;\r
-               std::vector<const void*> used_tags;\r
-\r
-               BOOST_FOREACH(auto& item, items_)\r
-               {                       \r
-                       audio_buffer_ps next_audio;\r
-\r
-                       auto next_transform = item.transform;\r
-                       auto prev_transform = next_transform;\r
-\r
-                       auto tag = item.tag;\r
-\r
-                       if(boost::range::find(used_tags, tag) != used_tags.end())\r
-                               continue;\r
-                       \r
-                       used_tags.push_back(tag);\r
-\r
-                       const auto it = audio_streams_.find(tag);\r
-                       if(it != audio_streams_.end())\r
-                       {       \r
-                               prev_transform  = it->second.prev_transform;\r
-                               next_audio              = std::move(it->second.audio_data);\r
-                       }\r
-                       \r
-                       // Skip it if there is no existing audio stream and item has no audio-data.\r
-                       if(it == audio_streams_.end() && item.audio_data.empty()) \r
-                               continue;\r
-                                               \r
-                       const float prev_volume = static_cast<float>(prev_transform.volume);\r
-                       const float next_volume = static_cast<float>(next_transform.volume);\r
-                                               \r
-                       // TODO: Move volume mixing into code below, in order to support audio sample counts not corresponding to frame audio samples.\r
-                       auto alpha = (next_volume-prev_volume)/static_cast<float>(item.audio_data.size()/format_desc.audio_channels);\r
-                       \r
-                       for(size_t n = 0; n < item.audio_data.size(); ++n)\r
-                               next_audio.push_back(item.audio_data[n] * (prev_volume + (n/format_desc_.audio_channels) * alpha));\r
-                                                                               \r
-                       next_audio_streams[tag].prev_transform  = std::move(next_transform); // Store all active tags, inactive tags will be removed at the end.\r
-                       next_audio_streams[tag].audio_data              = std::move(next_audio);        \r
-                       next_audio_streams[tag].is_still                = item.transform.is_still;\r
-               }                               \r
-\r
-               items_.clear();\r
-\r
-               audio_streams_ = std::move(next_audio_streams);\r
-               \r
-               if(audio_streams_.empty())              \r
-                       audio_streams_[nullptr].audio_data = audio_buffer_ps(audio_cadence_.front(), 0.0f);\r
-                               \r
-               std::vector<float> result_ps(audio_cadence_.front(), 0.0f);\r
-               BOOST_FOREACH(auto& stream, audio_streams_ | boost::adaptors::map_values)\r
-               {\r
-                       if(stream.audio_data.size() < result_ps.size())\r
-                               stream.audio_data.resize(result_ps.size(), 0.0f);\r
-\r
-                       auto out = boost::range::transform(result_ps, stream.audio_data, std::begin(result_ps), std::plus<float>());\r
-                       stream.audio_data.erase(std::begin(stream.audio_data), std::begin(stream.audio_data) + std::distance(std::begin(result_ps), out));\r
-               }               \r
-               \r
-               boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
-               \r
-               audio_buffer result;\r
-               result.reserve(result_ps.size());\r
-               boost::range::transform(result_ps, std::back_inserter(result), [](float sample){return static_cast<int32_t>(sample);});         \r
-               \r
-               return result;\r
-       }\r
-};\r
-\r
-audio_mixer::audio_mixer() : impl_(new impl()){}\r
-void audio_mixer::push(const frame_transform& transform){impl_->push(transform);}\r
-void audio_mixer::visit(const const_frame& frame){impl_->visit(frame);}\r
-void audio_mixer::pop(){impl_->pop();}\r
-audio_buffer audio_mixer::operator()(const video_format_desc& format_desc){return impl_->mix(format_desc);}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "audio_mixer.h"
+
+#include <core/frame/frame.h>
+#include <core/frame/frame_transform.h>
+#include <common/diagnostics/graph.h>
+
+#include <boost/range/adaptors.hpp>
+#include <boost/range/distance.hpp>
+
+#include <map>
+#include <stack>
+#include <vector>
+
+namespace caspar { namespace core {
+
+struct audio_item
+{
+       const void*                     tag;
+       audio_transform         transform;
+       audio_buffer            audio_data;
+
+       audio_item()
+       {
+       }
+
+       audio_item(audio_item&& other)
+               : tag(std::move(other.tag))
+               , transform(std::move(other.transform))
+               , audio_data(std::move(other.audio_data))
+       {
+       }
+};
+
+typedef std::vector<float, tbb::cache_aligned_allocator<float>> audio_buffer_ps;
+       
+struct audio_stream
+{
+       audio_transform         prev_transform;
+       audio_buffer_ps         audio_data;
+       bool                            is_still;
+
+       audio_stream() 
+               : is_still(false)
+       {
+       }
+};
+
+struct audio_mixer::impl : boost::noncopyable
+{
+       std::stack<core::audio_transform>       transform_stack_;
+       std::map<const void*, audio_stream>     audio_streams_;
+       std::vector<audio_item>                         items_;
+       std::vector<int>                                        audio_cadence_;
+       video_format_desc                                       format_desc_;
+       
+public:
+       impl()
+       {
+               transform_stack_.push(core::audio_transform());
+       }
+       
+       void push(const frame_transform& transform)
+       {
+               transform_stack_.push(transform_stack_.top()*transform.audio_transform);
+       }
+
+       void visit(const const_frame& frame)
+       {
+               if(transform_stack_.top().volume < 0.002 || frame.audio_data().empty())
+                       return;
+
+               audio_item item;
+               item.tag                = frame.stream_tag();
+               item.transform  = transform_stack_.top();
+               item.audio_data = frame.audio_data();
+
+               if(item.transform.is_still)
+                       item.transform.volume = 0.0;
+               
+               items_.push_back(std::move(item));              
+       }
+
+       void begin(const core::audio_transform& transform)
+       {
+               transform_stack_.push(transform_stack_.top()*transform);
+       }
+               
+       void pop()
+       {
+               transform_stack_.pop();
+       }
+       
+       audio_buffer mix(const video_format_desc& format_desc)
+       {       
+               if(format_desc_ != format_desc)
+               {
+                       audio_streams_.clear();
+                       audio_cadence_ = format_desc.audio_cadence;
+                       format_desc_ = format_desc;
+               }               
+               
+               std::map<const void*, audio_stream>     next_audio_streams;
+               std::vector<const void*> used_tags;
+
+               BOOST_FOREACH(auto& item, items_)
+               {                       
+                       audio_buffer_ps next_audio;
+
+                       auto next_transform = item.transform;
+                       auto prev_transform = next_transform;
+
+                       auto tag = item.tag;
+
+                       if(boost::range::find(used_tags, tag) != used_tags.end())
+                               continue;
+                       
+                       used_tags.push_back(tag);
+
+                       const auto it = audio_streams_.find(tag);
+                       if(it != audio_streams_.end())
+                       {       
+                               prev_transform  = it->second.prev_transform;
+                               next_audio              = std::move(it->second.audio_data);
+                       }
+                       
+                       // Skip it if there is no existing audio stream and item has no audio-data.
+                       if(it == audio_streams_.end() && item.audio_data.empty()) 
+                               continue;
+                                               
+                       const float prev_volume = static_cast<float>(prev_transform.volume);
+                       const float next_volume = static_cast<float>(next_transform.volume);
+                                               
+                       // TODO: Move volume mixing into code below, in order to support audio sample counts not corresponding to frame audio samples.
+                       auto alpha = (next_volume-prev_volume)/static_cast<float>(item.audio_data.size()/format_desc.audio_channels);
+                       
+                       for(size_t n = 0; n < item.audio_data.size(); ++n)
+                               next_audio.push_back(item.audio_data[n] * (prev_volume + (n/format_desc_.audio_channels) * alpha));
+                                                                               
+                       next_audio_streams[tag].prev_transform  = std::move(next_transform); // Store all active tags, inactive tags will be removed at the end.
+                       next_audio_streams[tag].audio_data              = std::move(next_audio);        
+                       next_audio_streams[tag].is_still                = item.transform.is_still;
+               }                               
+
+               items_.clear();
+
+               audio_streams_ = std::move(next_audio_streams);
+               
+               if(audio_streams_.empty())              
+                       audio_streams_[nullptr].audio_data = audio_buffer_ps(audio_cadence_.front(), 0.0f);
+                               
+               std::vector<float> result_ps(audio_cadence_.front(), 0.0f);
+               BOOST_FOREACH(auto& stream, audio_streams_ | boost::adaptors::map_values)
+               {
+                       if(stream.audio_data.size() < result_ps.size())
+                               stream.audio_data.resize(result_ps.size(), 0.0f);
+
+                       auto out = boost::range::transform(result_ps, stream.audio_data, std::begin(result_ps), std::plus<float>());
+                       stream.audio_data.erase(std::begin(stream.audio_data), std::begin(stream.audio_data) + std::distance(std::begin(result_ps), out));
+               }               
+               
+               boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);
+               
+               audio_buffer result;
+               result.reserve(result_ps.size());
+               boost::range::transform(result_ps, std::back_inserter(result), [](float sample){return static_cast<int32_t>(sample);});         
+               
+               return result;
+       }
+};
+
+audio_mixer::audio_mixer() : impl_(new impl()){}
+void audio_mixer::push(const frame_transform& transform){impl_->push(transform);}
+void audio_mixer::visit(const const_frame& frame){impl_->visit(frame);}
+void audio_mixer::pop(){impl_->pop();}
+audio_buffer audio_mixer::operator()(const video_format_desc& format_desc){return impl_->mix(format_desc);}
+
 }}
\ No newline at end of file
index dd7764b3444b353cd3f2770deabf8a731af09a5f..77a5e2fad72e8925937c4ed0eebeca9614f69798 100644 (file)
@@ -1,68 +1,68 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/forward.h>\r
-#include <common/memory.h>\r
-\r
-#include <core/frame/frame_visitor.h>\r
-\r
-#include <tbb/cache_aligned_allocator.h>\r
-\r
-#include <vector>\r
-\r
-FORWARD2(caspar, diagnostics, class graph);\r
-\r
-namespace caspar { namespace core {\r
-               \r
-typedef std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>> audio_buffer;\r
-\r
-class audio_mixer sealed : public frame_visitor\r
-{\r
-       audio_mixer(const audio_mixer&);\r
-       audio_mixer& operator=(const audio_mixer&);\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       audio_mixer();\r
-\r
-       // Methods\r
-       \r
-       audio_buffer operator()(const struct video_format_desc& format_desc);\r
-\r
-       // frame_visitor\r
-\r
-       virtual void push(const struct frame_transform& transform);\r
-       virtual void visit(const class const_frame& frame);\r
-       virtual void pop();\r
-       \r
-       // Properties\r
-\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/forward.h>
+#include <common/memory.h>
+
+#include <core/frame/frame_visitor.h>
+
+#include <tbb/cache_aligned_allocator.h>
+
+#include <vector>
+
+FORWARD2(caspar, diagnostics, class graph);
+
+namespace caspar { namespace core {
+               
+typedef std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>> audio_buffer;
+
+class audio_mixer sealed : public frame_visitor
+{
+       audio_mixer(const audio_mixer&);
+       audio_mixer& operator=(const audio_mixer&);
+public:
+
+       // Static Members
+
+       // Constructors
+
+       audio_mixer();
+
+       // Methods
+       
+       audio_buffer operator()(const struct video_format_desc& format_desc);
+
+       // frame_visitor
+
+       virtual void push(const struct frame_transform& transform);
+       virtual void visit(const class const_frame& frame);
+       virtual void pop();
+       
+       // Properties
+
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index 2d4edbdc2614a81c07a45e15febe9b2484cdbce8..833da7e3ad1e0c0d0a9fce309869ad93b0f7e6ba 100644 (file)
@@ -1,64 +1,64 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <algorithm>\r
-#include <vector>\r
-#include <cstdint>\r
-\r
-#include <tbb/cache_aligned_allocator.h>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-template<typename T>\r
-std::vector<int8_t, tbb::cache_aligned_allocator<int8_t>> audio_32_to_24(const T& audio_data)\r
-{      \r
-       auto size                = std::distance(std::begin(audio_data), std::end(audio_data));\r
-       auto input8              = reinterpret_cast<const int8_t*>(&(*std::begin(audio_data)));\r
-       auto output8     = std::vector<int8_t, tbb::cache_aligned_allocator<int8_t>>();\r
-                       \r
-       output8.reserve(size*3);\r
-       for(int n = 0; n < size; ++n)\r
-       {\r
-               output8.push_back(input8[n*4+1]);\r
-               output8.push_back(input8[n*4+2]);\r
-               output8.push_back(input8[n*4+3]);\r
-       }\r
-\r
-       return output8;\r
-}\r
-\r
-template<typename T>\r
-std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>> audio_32_to_16(const T& audio_data)\r
-{      \r
-       auto size                = std::distance(std::begin(audio_data), std::end(audio_data));\r
-       auto input32     = &(*std::begin(audio_data));\r
-       auto output16    = std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>();\r
-                       \r
-       output16.reserve(size);\r
-       for(int n = 0; n < size; ++n)\r
-               output16.push_back((input32[n] >> 16) & 0xFFFF);\r
-\r
-       return output16;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <algorithm>
+#include <vector>
+#include <cstdint>
+
+#include <tbb/cache_aligned_allocator.h>
+
+namespace caspar { namespace core {
+       
+template<typename T>
+std::vector<int8_t, tbb::cache_aligned_allocator<int8_t>> audio_32_to_24(const T& audio_data)
+{      
+       auto size                = std::distance(std::begin(audio_data), std::end(audio_data));
+       auto input8              = reinterpret_cast<const int8_t*>(&(*std::begin(audio_data)));
+       auto output8     = std::vector<int8_t, tbb::cache_aligned_allocator<int8_t>>();
+                       
+       output8.reserve(size*3);
+       for(int n = 0; n < size; ++n)
+       {
+               output8.push_back(input8[n*4+1]);
+               output8.push_back(input8[n*4+2]);
+               output8.push_back(input8[n*4+3]);
+       }
+
+       return output8;
+}
+
+template<typename T>
+std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>> audio_32_to_16(const T& audio_data)
+{      
+       auto size                = std::distance(std::begin(audio_data), std::end(audio_data));
+       auto input32     = &(*std::begin(audio_data));
+       auto output16    = std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>();
+                       
+       output16.reserve(size);
+       for(int n = 0; n < size; ++n)
+               output16.push_back((input32[n] >> 16) & 0xFFFF);
+
+       return output16;
+}
+
 }}
\ No newline at end of file
index 04a51b5041384ec5e80def03d752a846dedcab38..5e9a774b37c7cef7f30ec4c0d9266cc6aada5089 100644 (file)
@@ -1,94 +1,94 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../StdAfx.h"\r
-\r
-#include "blend_modes.h"\r
-\r
-#include <boost/algorithm/string.hpp>\r
-\r
-namespace caspar { namespace core {\r
-               \r
-blend_mode get_blend_mode(const std::wstring& str)\r
-{\r
-       if(boost::iequals(str, L"normal"))\r
-               return blend_mode::normal;\r
-       else if(boost::iequals(str, L"lighten"))\r
-               return blend_mode::lighten;\r
-       else if(boost::iequals(str, L"darken"))\r
-               return blend_mode::darken;\r
-       else if(boost::iequals(str, L"multiply"))\r
-               return blend_mode::multiply;\r
-       else if(boost::iequals(str, L"average"))\r
-               return blend_mode::average;\r
-       else if(boost::iequals(str, L"add"))\r
-               return blend_mode::add;\r
-       else if(boost::iequals(str, L"subtract"))\r
-               return blend_mode::subtract;\r
-       else if(boost::iequals(str, L"difference"))\r
-               return blend_mode::difference;\r
-       else if(boost::iequals(str, L"negation"))\r
-               return blend_mode::negation;\r
-       else if(boost::iequals(str, L"exclusion"))\r
-               return blend_mode::exclusion;\r
-       else if(boost::iequals(str, L"screen"))\r
-               return blend_mode::screen;\r
-       else if(boost::iequals(str, L"overlay"))\r
-               return blend_mode::overlay;\r
-       else if(boost::iequals(str, L"soft_light"))\r
-               return blend_mode::soft_light;\r
-       else if(boost::iequals(str, L"hard_light"))\r
-               return blend_mode::hard_light;\r
-       else if(boost::iequals(str, L"color_dodge"))\r
-               return blend_mode::color_dodge;\r
-       else if(boost::iequals(str, L"color_burn"))\r
-               return blend_mode::color_burn;\r
-       else if(boost::iequals(str, L"linear_dodge"))\r
-               return blend_mode::linear_dodge;\r
-       else if(boost::iequals(str, L"linear_burn"))\r
-               return blend_mode::linear_burn;\r
-       else if(boost::iequals(str, L"linear_light"))\r
-               return blend_mode::linear_light;\r
-       else if(boost::iequals(str, L"vivid_light"))\r
-               return blend_mode::vivid_light;\r
-       else if(boost::iequals(str, L"pin_light"))\r
-               return blend_mode::pin_light;\r
-       else if(boost::iequals(str, L"hard_mix"))\r
-               return blend_mode::hard_mix;\r
-       else if(boost::iequals(str, L"reflect"))\r
-               return blend_mode::reflect;\r
-       else if(boost::iequals(str, L"glow"))\r
-               return blend_mode::glow;\r
-       else if(boost::iequals(str, L"phoenix"))\r
-               return blend_mode::phoenix;\r
-       else if(boost::iequals(str, L"contrast"))\r
-               return blend_mode::contrast;\r
-       else if(boost::iequals(str, L"saturation"))\r
-               return blend_mode::saturation;\r
-       else if(boost::iequals(str, L"color"))\r
-               return blend_mode::color;\r
-       else if(boost::iequals(str, L"luminosity"))\r
-               return blend_mode::luminosity;\r
-               \r
-       return blend_mode::normal;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../StdAfx.h"
+
+#include "blend_modes.h"
+
+#include <boost/algorithm/string.hpp>
+
+namespace caspar { namespace core {
+               
+blend_mode get_blend_mode(const std::wstring& str)
+{
+       if(boost::iequals(str, L"normal"))
+               return blend_mode::normal;
+       else if(boost::iequals(str, L"lighten"))
+               return blend_mode::lighten;
+       else if(boost::iequals(str, L"darken"))
+               return blend_mode::darken;
+       else if(boost::iequals(str, L"multiply"))
+               return blend_mode::multiply;
+       else if(boost::iequals(str, L"average"))
+               return blend_mode::average;
+       else if(boost::iequals(str, L"add"))
+               return blend_mode::add;
+       else if(boost::iequals(str, L"subtract"))
+               return blend_mode::subtract;
+       else if(boost::iequals(str, L"difference"))
+               return blend_mode::difference;
+       else if(boost::iequals(str, L"negation"))
+               return blend_mode::negation;
+       else if(boost::iequals(str, L"exclusion"))
+               return blend_mode::exclusion;
+       else if(boost::iequals(str, L"screen"))
+               return blend_mode::screen;
+       else if(boost::iequals(str, L"overlay"))
+               return blend_mode::overlay;
+       else if(boost::iequals(str, L"soft_light"))
+               return blend_mode::soft_light;
+       else if(boost::iequals(str, L"hard_light"))
+               return blend_mode::hard_light;
+       else if(boost::iequals(str, L"color_dodge"))
+               return blend_mode::color_dodge;
+       else if(boost::iequals(str, L"color_burn"))
+               return blend_mode::color_burn;
+       else if(boost::iequals(str, L"linear_dodge"))
+               return blend_mode::linear_dodge;
+       else if(boost::iequals(str, L"linear_burn"))
+               return blend_mode::linear_burn;
+       else if(boost::iequals(str, L"linear_light"))
+               return blend_mode::linear_light;
+       else if(boost::iequals(str, L"vivid_light"))
+               return blend_mode::vivid_light;
+       else if(boost::iequals(str, L"pin_light"))
+               return blend_mode::pin_light;
+       else if(boost::iequals(str, L"hard_mix"))
+               return blend_mode::hard_mix;
+       else if(boost::iequals(str, L"reflect"))
+               return blend_mode::reflect;
+       else if(boost::iequals(str, L"glow"))
+               return blend_mode::glow;
+       else if(boost::iequals(str, L"phoenix"))
+               return blend_mode::phoenix;
+       else if(boost::iequals(str, L"contrast"))
+               return blend_mode::contrast;
+       else if(boost::iequals(str, L"saturation"))
+               return blend_mode::saturation;
+       else if(boost::iequals(str, L"color"))
+               return blend_mode::color;
+       else if(boost::iequals(str, L"luminosity"))
+               return blend_mode::luminosity;
+               
+       return blend_mode::normal;
+}
+
 }}
\ No newline at end of file
index cdf044f33b9c41e70aef62157c9dd68d54fa9305..8d57fa9208ce6104c71b5983a7545c1826a10f56 100644 (file)
@@ -1,69 +1,69 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/enum_class.h>\r
-\r
-namespace caspar { namespace core {\r
-               \r
-struct blend_mode_def\r
-{\r
-       enum type\r
-       {\r
-               normal = 0,\r
-               lighten,\r
-               darken,\r
-               multiply,\r
-               average,\r
-               add,\r
-               subtract,\r
-               difference,\r
-               negation,\r
-               exclusion,\r
-               screen,\r
-               overlay,\r
-               soft_light,\r
-               hard_light,\r
-               color_dodge,\r
-               color_burn,\r
-               linear_dodge,\r
-               linear_burn,\r
-               linear_light,\r
-               vivid_light,\r
-               pin_light,\r
-               hard_mix,\r
-               reflect,\r
-               glow,\r
-               phoenix,\r
-               contrast,\r
-               saturation,\r
-               color,\r
-               luminosity,\r
-               mix,\r
-               blend_mode_count \r
-       };\r
-};\r
-typedef enum_class<blend_mode_def> blend_mode;\r
-\r
-blend_mode get_blend_mode(const std::wstring& str);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/enum_class.h>
+
+namespace caspar { namespace core {
+               
+struct blend_mode_def
+{
+       enum type
+       {
+               normal = 0,
+               lighten,
+               darken,
+               multiply,
+               average,
+               add,
+               subtract,
+               difference,
+               negation,
+               exclusion,
+               screen,
+               overlay,
+               soft_light,
+               hard_light,
+               color_dodge,
+               color_burn,
+               linear_dodge,
+               linear_burn,
+               linear_light,
+               vivid_light,
+               pin_light,
+               hard_mix,
+               reflect,
+               glow,
+               phoenix,
+               contrast,
+               saturation,
+               color,
+               luminosity,
+               mix,
+               blend_mode_count 
+       };
+};
+typedef enum_class<blend_mode_def> blend_mode;
+
+blend_mode get_blend_mode(const std::wstring& str);
+
 }}
\ No newline at end of file
index aed2c8c46f711beed8ae8c686347d944a6c690a2..a3abd429e1c00073021bc7a92b410388e83667f6 100644 (file)
@@ -1,74 +1,74 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "blend_modes.h"\r
-\r
-#include <common/forward.h>\r
-#include <common/future_fwd.h>\r
-#include <common/memory.h>\r
-\r
-#include <core/video_format.h>\r
-#include <core/frame/frame_visitor.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/frame.h>\r
-\r
-#include <boost/range.hpp>\r
-\r
-#include <cstdint>\r
-\r
-FORWARD2(caspar, core, struct pixel_format_desc);\r
-\r
-namespace caspar { namespace core {\r
-       \r
-// Interface\r
-class image_mixer : public frame_visitor\r
-                                 , public frame_factory\r
-{\r
-       image_mixer(const image_mixer&);\r
-       image_mixer& operator=(const image_mixer&);\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       image_mixer(){}\r
-       virtual ~image_mixer(){}\r
-       \r
-       // Methods\r
-\r
-       virtual void push(const struct frame_transform& frame) = 0;\r
-       virtual void visit(const class const_frame& frame) = 0;\r
-       virtual void pop() = 0;\r
-\r
-       virtual void begin_layer(blend_mode blend_mode) = 0;\r
-       virtual void end_layer() = 0;\r
-               \r
-       virtual boost::unique_future<array<const std::uint8_t>> operator()(const struct video_format_desc& format_desc) = 0;\r
-\r
-       virtual class mutable_frame create_frame(const void* tag, const struct pixel_format_desc& desc) = 0;\r
-\r
-       // Properties\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "blend_modes.h"
+
+#include <common/forward.h>
+#include <common/future_fwd.h>
+#include <common/memory.h>
+
+#include <core/video_format.h>
+#include <core/frame/frame_visitor.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/frame.h>
+
+#include <boost/range.hpp>
+
+#include <cstdint>
+
+FORWARD2(caspar, core, struct pixel_format_desc);
+
+namespace caspar { namespace core {
+       
+// Interface
+class image_mixer : public frame_visitor
+                                 , public frame_factory
+{
+       image_mixer(const image_mixer&);
+       image_mixer& operator=(const image_mixer&);
+public:
+
+       // Static Members
+
+       // Constructors
+
+       image_mixer(){}
+       virtual ~image_mixer(){}
+       
+       // Methods
+
+       virtual void push(const struct frame_transform& frame) = 0;
+       virtual void visit(const class const_frame& frame) = 0;
+       virtual void pop() = 0;
+
+       virtual void begin_layer(blend_mode blend_mode) = 0;
+       virtual void end_layer() = 0;
+               
+       virtual boost::unique_future<array<const std::uint8_t>> operator()(const struct video_format_desc& format_desc) = 0;
+
+       virtual class mutable_frame create_frame(const void* tag, const struct pixel_format_desc& desc) = 0;
+
+       // Properties
+};
+
 }}
\ No newline at end of file
index 0a423fb20dc799e519ac68b91f49e9c6900632d4..c518255da3b7d2fc739404d4837d72cfb03411df 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../StdAfx.h"\r
-\r
-#include "mixer.h"\r
-\r
-#include "../frame/frame.h"\r
-\r
-#include "audio/audio_mixer.h"\r
-#include "image/image_mixer.h"\r
-\r
-#include <common/env.h>\r
-#include <common/executor.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/except.h>\r
-#include <common/gl/gl_check.h>\r
-\r
-#include <core/frame/draw_frame.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/frame_transform.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/video_format.h>\r
-\r
-#include <boost/foreach.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/range/algorithm_ext.hpp>\r
-\r
-#include <tbb/concurrent_queue.h>\r
-#include <tbb/spin_mutex.h>\r
-\r
-#include <unordered_map>\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
-\r
-struct mixer::impl : boost::noncopyable\r
-{                              \r
-       spl::shared_ptr<diagnostics::graph> graph_;\r
-       audio_mixer                                                     audio_mixer_;\r
-       spl::shared_ptr<image_mixer>            image_mixer_;\r
-       \r
-       std::unordered_map<int, blend_mode>     blend_modes_;\r
-                       \r
-       executor executor_;\r
-\r
-public:\r
-       impl(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer) \r
-               : graph_(std::move(graph))\r
-               , audio_mixer_()\r
-               , image_mixer_(std::move(image_mixer))\r
-               , executor_(L"mixer")\r
-       {                       \r
-               graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8));\r
-       }       \r
-       \r
-       const_frame operator()(std::map<int, draw_frame> frames, const video_format_desc& format_desc)\r
-       {               \r
-               boost::timer frame_timer;\r
-\r
-               auto frame = executor_.invoke([=]() mutable -> const_frame\r
-               {               \r
-                       try\r
-                       {       \r
-                               BOOST_FOREACH(auto& frame, frames)\r
-                               {\r
-                                       auto blend_it = blend_modes_.find(frame.first);\r
-                                       image_mixer_->begin_layer(blend_it != blend_modes_.end() ? blend_it->second : blend_mode::normal);\r
-                                                                                                       \r
-                                       frame.second.accept(audio_mixer_);                                      \r
-                                       frame.second.accept(*image_mixer_);\r
-\r
-                                       image_mixer_->end_layer();\r
-                               }\r
-                               \r
-                               auto image = (*image_mixer_)(format_desc);\r
-                               auto audio = audio_mixer_(format_desc);\r
-\r
-                               auto desc = core::pixel_format_desc(core::pixel_format::bgra);\r
-                               desc.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));\r
-                               return const_frame(std::move(image), std::move(audio), this, desc);     \r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                               return const_frame::empty();\r
-                       }       \r
-               });             \r
-                               \r
-               graph_->set_value("mix-time", frame_timer.elapsed()*format_desc.fps*0.5);\r
-\r
-               return frame;\r
-       }\r
-                                       \r
-       void set_blend_mode(int index, blend_mode value)\r
-       {\r
-               executor_.begin_invoke([=]\r
-               {\r
-                       auto it = blend_modes_.find(index);\r
-                       if(it == blend_modes_.end())\r
-                               blend_modes_.insert(std::make_pair(index, value));\r
-                       else\r
-                               it->second = value;\r
-               }, task_priority::high_priority);\r
-       }\r
-       \r
-       boost::unique_future<boost::property_tree::wptree> info() const\r
-       {\r
-               boost::promise<boost::property_tree::wptree> info;\r
-               info.set_value(boost::property_tree::wptree());\r
-               return info.get_future();\r
-       }\r
-};\r
-       \r
-mixer::mixer(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer) \r
-       : impl_(new impl(std::move(graph), std::move(image_mixer))){}\r
-void mixer::set_blend_mode(int index, blend_mode value){impl_->set_blend_mode(index, value);}\r
-boost::unique_future<boost::property_tree::wptree> mixer::info() const{return impl_->info();}\r
-const_frame mixer::operator()(std::map<int, draw_frame> frames, const struct video_format_desc& format_desc){return (*impl_)(std::move(frames), format_desc);}\r
-mutable_frame mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->image_mixer_->create_frame(tag, desc);}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../StdAfx.h"
+
+#include "mixer.h"
+
+#include "../frame/frame.h"
+
+#include "audio/audio_mixer.h"
+#include "image/image_mixer.h"
+
+#include <common/env.h>
+#include <common/executor.h>
+#include <common/diagnostics/graph.h>
+#include <common/except.h>
+#include <common/gl/gl_check.h>
+
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/frame_transform.h>
+#include <core/frame/pixel_format.h>
+#include <core/video_format.h>
+
+#include <boost/foreach.hpp>
+#include <boost/timer.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/range/algorithm_ext.hpp>
+
+#include <tbb/concurrent_queue.h>
+#include <tbb/spin_mutex.h>
+
+#include <unordered_map>
+#include <vector>
+
+namespace caspar { namespace core {
+
+struct mixer::impl : boost::noncopyable
+{                              
+       spl::shared_ptr<diagnostics::graph> graph_;
+       audio_mixer                                                     audio_mixer_;
+       spl::shared_ptr<image_mixer>            image_mixer_;
+       
+       std::unordered_map<int, blend_mode>     blend_modes_;
+                       
+       executor executor_;
+
+public:
+       impl(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer) 
+               : graph_(std::move(graph))
+               , audio_mixer_()
+               , image_mixer_(std::move(image_mixer))
+               , executor_(L"mixer")
+       {                       
+               graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8));
+       }       
+       
+       const_frame operator()(std::map<int, draw_frame> frames, const video_format_desc& format_desc)
+       {               
+               boost::timer frame_timer;
+
+               auto frame = executor_.invoke([=]() mutable -> const_frame
+               {               
+                       try
+                       {       
+                               BOOST_FOREACH(auto& frame, frames)
+                               {
+                                       auto blend_it = blend_modes_.find(frame.first);
+                                       image_mixer_->begin_layer(blend_it != blend_modes_.end() ? blend_it->second : blend_mode::normal);
+                                                                                                       
+                                       frame.second.accept(audio_mixer_);                                      
+                                       frame.second.accept(*image_mixer_);
+
+                                       image_mixer_->end_layer();
+                               }
+                               
+                               auto image = (*image_mixer_)(format_desc);
+                               auto audio = audio_mixer_(format_desc);
+
+                               auto desc = core::pixel_format_desc(core::pixel_format::bgra);
+                               desc.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));
+                               return const_frame(std::move(image), std::move(audio), this, desc);     
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                               return const_frame::empty();
+                       }       
+               });             
+                               
+               graph_->set_value("mix-time", frame_timer.elapsed()*format_desc.fps*0.5);
+
+               return frame;
+       }
+                                       
+       void set_blend_mode(int index, blend_mode value)
+       {
+               executor_.begin_invoke([=]
+               {
+                       auto it = blend_modes_.find(index);
+                       if(it == blend_modes_.end())
+                               blend_modes_.insert(std::make_pair(index, value));
+                       else
+                               it->second = value;
+               }, task_priority::high_priority);
+       }
+       
+       boost::unique_future<boost::property_tree::wptree> info() const
+       {
+               boost::promise<boost::property_tree::wptree> info;
+               info.set_value(boost::property_tree::wptree());
+               return info.get_future();
+       }
+};
+       
+mixer::mixer(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer) 
+       : impl_(new impl(std::move(graph), std::move(image_mixer))){}
+void mixer::set_blend_mode(int index, blend_mode value){impl_->set_blend_mode(index, value);}
+boost::unique_future<boost::property_tree::wptree> mixer::info() const{return impl_->info();}
+const_frame mixer::operator()(std::map<int, draw_frame> frames, const struct video_format_desc& format_desc){return (*impl_)(std::move(frames), format_desc);}
+mutable_frame mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->image_mixer_->create_frame(tag, desc);}
 }}
\ No newline at end of file
index 328b852387743b7300f86138ec9787cba859fac0..d4cceaa3f7fd3ae4218ebb3a5deb8c3c57ebd288 100644 (file)
@@ -1,70 +1,70 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "image/blend_modes.h"\r
-\r
-#include <common/forward.h>\r
-#include <common/future_fwd.h>\r
-#include <common/memory.h>\r
-#include <common/reactive.h>\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <boost/property_tree/ptree_fwd.hpp>\r
-\r
-#include <map>\r
-\r
-FORWARD2(caspar, diagnostics, class graph);\r
-\r
-namespace caspar { namespace core {\r
-       \r
-class mixer sealed\r
-{\r
-       mixer(const mixer&);\r
-       mixer& operator=(const mixer&);\r
-public:\r
-       \r
-       // Static Members\r
-                                       \r
-       // Constructors\r
-       \r
-       explicit mixer(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<class image_mixer> image_mixer);\r
-\r
-       // Methods\r
-               \r
-       class const_frame operator()(std::map<int, class draw_frame> frames, const struct video_format_desc& format_desc);\r
-       \r
-       void set_blend_mode(int index, blend_mode value);\r
-\r
-       class mutable_frame create_frame(const void* tag, const struct pixel_format_desc& desc);\r
-\r
-       // Properties\r
-\r
-       boost::unique_future<boost::property_tree::wptree> info() const;\r
-\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "image/blend_modes.h"
+
+#include <common/forward.h>
+#include <common/future_fwd.h>
+#include <common/memory.h>
+#include <common/reactive.h>
+
+#include <core/video_format.h>
+
+#include <boost/property_tree/ptree_fwd.hpp>
+
+#include <map>
+
+FORWARD2(caspar, diagnostics, class graph);
+
+namespace caspar { namespace core {
+       
+class mixer sealed
+{
+       mixer(const mixer&);
+       mixer& operator=(const mixer&);
+public:
+       
+       // Static Members
+                                       
+       // Constructors
+       
+       explicit mixer(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<class image_mixer> image_mixer);
+
+       // Methods
+               
+       class const_frame operator()(std::map<int, class draw_frame> frames, const struct video_format_desc& format_desc);
+       
+       void set_blend_mode(int index, blend_mode value);
+
+       class mutable_frame create_frame(const void* tag, const struct pixel_format_desc& desc);
+
+       // Properties
+
+       boost::unique_future<boost::property_tree::wptree> info() const;
+
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index 1b5d5cee01bccfade8b49d176ca066a5e027b5f2..8d48970492819f8b210d89d32fb945871e2a7346 100644 (file)
-#include "../StdAfx.h"\r
-\r
-#include "monitor.h"\r
-\r
-#include <utility>\r
-\r
-namespace caspar { namespace monitor {\r
-       \r
-// param\r
-       \r
-namespace detail {\r
-\r
-struct param_visitor : public boost::static_visitor<void>\r
-{\r
-       std::ostream& o;\r
-\r
-       param_visitor(std::ostream& o)\r
-               : o(o)\r
-       {\r
-       }\r
-\r
-       void operator()(const std::vector<int8_t>& bytes)\r
-       {               \r
-               o << std::string(std::begin(bytes), std::end(bytes));\r
-       }\r
-\r
-       void operator()(const duration& duration)\r
-       {               \r
-               o << duration.count();\r
-       }\r
-\r
-       template<typename T>\r
-       void operator()(const T& value)\r
-       {\r
-               o << value;\r
-       }\r
-};\r
-\r
-}\r
-\r
-std::ostream& operator<<(std::ostream& o, const param& p)\r
-{\r
-       detail::param_visitor v(o);\r
-       boost::apply_visitor(v, p);\r
-       return o;\r
-}\r
-\r
-// path\r
-\r
-path::path()\r
-{\r
-}\r
-\r
-path::path(const char* path)\r
-       : str_(path)\r
-{\r
-}\r
-\r
-path::path(std::string path)\r
-       : str_(path)\r
-{\r
-}\r
-\r
-path::path(const path& other)\r
-       : str_(other.str_)\r
-{              \r
-}\r
-       \r
-path::path(path&& other)\r
-       : str_(std::move(other.str_))\r
-{              \r
-}\r
-\r
-path& path::operator=(path other)\r
-{\r
-       std::swap(*this, other);\r
-       return *this;\r
-}\r
-\r
-path& path::operator%=(path other)\r
-{\r
-       return *this %= other.str_;\r
-}\r
-\r
-void path::swap(path& other)\r
-{\r
-       std::swap(str_, other.str_);\r
-}\r
-       \r
-const std::string& path::str() const\r
-{\r
-       return str_;\r
-}\r
-\r
-bool path::empty() const\r
-{\r
-       return str_.empty();\r
-}\r
-\r
-std::ostream& operator<<(std::ostream& o, const path& p)\r
-{\r
-       o << p.str();\r
-       return o;\r
-}\r
-\r
-// event\r
-\r
-event::event(monitor::path path)\r
-       : path_(std::move(path))\r
-{\r
-}\r
-       \r
-event::event(monitor::path path, params_t params)\r
-       : path_(std::move(path))\r
-       , params_(std::move(params))\r
-{\r
-}\r
-\r
-event::event(const event& other)\r
-       : path_(other.path_)\r
-       , params_(other.params_)\r
-{\r
-}\r
-\r
-event::event(event&& other)\r
-       : path_(std::move(other.path_))\r
-       , params_(std::move(other.params_))\r
-{\r
-}\r
-\r
-event& event::operator=(event other)\r
-{\r
-       other.swap(*this);\r
-       return *this;\r
-}\r
-\r
-void event::swap(event& other)\r
-{\r
-       std::swap(path_, other.path_);\r
-       std::swap(params_, other.params_);\r
-}\r
-               \r
-const path&    event::path() const             \r
-{\r
-       return path_;\r
-}\r
-\r
-const event::params_t& event::params() const   \r
-{\r
-       return params_;\r
-}\r
-\r
-event event::propagate(monitor::path path) const\r
-{\r
-       return event(std::move(path) % path_, params_);\r
-}\r
-\r
-std::ostream& operator<<(std::ostream& o, const event& e)\r
-{\r
-       o << e.path();\r
-       for(auto it = e.params().begin(); it != e.params().end(); ++it)\r
-               o << " " << *it;\r
-       return o;\r
-}\r
-\r
+#include "../StdAfx.h"
+
+#include "monitor.h"
+
+#include <utility>
+
+namespace caspar { namespace monitor {
+       
+// param
+       
+namespace detail {
+
+struct param_visitor : public boost::static_visitor<void>
+{
+       std::ostream& o;
+
+       param_visitor(std::ostream& o)
+               : o(o)
+       {
+       }
+
+       void operator()(const std::vector<int8_t>& bytes)
+       {               
+               o << std::string(std::begin(bytes), std::end(bytes));
+       }
+
+       void operator()(const duration& duration)
+       {               
+               o << duration.count();
+       }
+
+       template<typename T>
+       void operator()(const T& value)
+       {
+               o << value;
+       }
+};
+
+}
+
+std::ostream& operator<<(std::ostream& o, const param& p)
+{
+       detail::param_visitor v(o);
+       boost::apply_visitor(v, p);
+       return o;
+}
+
+// path
+
+path::path()
+{
+}
+
+path::path(const char* path)
+       : str_(path)
+{
+}
+
+path::path(std::string path)
+       : str_(path)
+{
+}
+
+path::path(const path& other)
+       : str_(other.str_)
+{              
+}
+       
+path::path(path&& other)
+       : str_(std::move(other.str_))
+{              
+}
+
+path& path::operator=(path other)
+{
+       std::swap(*this, other);
+       return *this;
+}
+
+path& path::operator%=(path other)
+{
+       return *this %= other.str_;
+}
+
+void path::swap(path& other)
+{
+       std::swap(str_, other.str_);
+}
+       
+const std::string& path::str() const
+{
+       return str_;
+}
+
+bool path::empty() const
+{
+       return str_.empty();
+}
+
+std::ostream& operator<<(std::ostream& o, const path& p)
+{
+       o << p.str();
+       return o;
+}
+
+// event
+
+event::event(monitor::path path)
+       : path_(std::move(path))
+{
+}
+       
+event::event(monitor::path path, params_t params)
+       : path_(std::move(path))
+       , params_(std::move(params))
+{
+}
+
+event::event(const event& other)
+       : path_(other.path_)
+       , params_(other.params_)
+{
+}
+
+event::event(event&& other)
+       : path_(std::move(other.path_))
+       , params_(std::move(other.params_))
+{
+}
+
+event& event::operator=(event other)
+{
+       other.swap(*this);
+       return *this;
+}
+
+void event::swap(event& other)
+{
+       std::swap(path_, other.path_);
+       std::swap(params_, other.params_);
+}
+               
+const path&    event::path() const             
+{
+       return path_;
+}
+
+const event::params_t& event::params() const   
+{
+       return params_;
+}
+
+event event::propagate(monitor::path path) const
+{
+       return event(std::move(path) % path_, params_);
+}
+
+std::ostream& operator<<(std::ostream& o, const event& e)
+{
+       o << e.path();
+       for(auto it = e.params().begin(); it != e.params().end(); ++it)
+               o << " " << *it;
+       return o;
+}
+
 }}
\ No newline at end of file
index 6c9f54b197f9d5ac2d9868f34f7c7626ca819665..ba6d7af282b703fe494c5db07c12cdfd388c8a19 100644 (file)
-#pragma once\r
-\r
-#include <common/reactive.h>\r
-\r
-#include <functional>\r
-#include <memory>\r
-#include <ostream>\r
-#include <string>\r
-#include <type_traits>\r
-#include <vector>\r
-\r
-#include <boost/variant.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/chrono.hpp>\r
-\r
-#include <tbb/cache_aligned_allocator.h>\r
-\r
-namespace boost {\r
-namespace detail { namespace variant {\r
-\r
-template <>\r
-struct has_nothrow_move<std::string>\r
-: mpl::true_\r
-{\r
-};\r
-  \r
-template <>\r
-struct has_nothrow_move<std::vector<int8_t>>\r
-: mpl::true_\r
-{\r
-};\r
-\r
-template <>\r
-struct has_nothrow_move<boost::chrono::duration<double, boost::ratio<1, 1>>>\r
-: mpl::true_\r
-{\r
-};\r
-\r
-}}}\r
-\r
-namespace caspar { namespace monitor {\r
-       \r
-// path\r
-\r
-class path sealed\r
-{\r
-public:        \r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       path();         \r
-       path(const char* path);\r
-       path(std::string path);\r
-\r
-       path(const path& other);        \r
-       path(path&& other);\r
-               \r
-       // Methods\r
-\r
-       path& operator=(path other);\r
-       path& operator%=(path other);\r
-\r
-       template<typename T>\r
-       typename std::enable_if<!std::is_same<typename std::decay<T>::type, path>::value, path&>::type operator%=(T&& value)\r
-       {\r
-               auto str = boost::lexical_cast<std::string>(std::forward<T>(value));\r
-\r
-               if(!str.empty())\r
-                       str_ += (str.front() != '/' ? "/" : "") + std::move(str);\r
-\r
-               return *this;\r
-       }\r
-       \r
-       path& operator%=(const char* value)\r
-       {\r
-               return *this %= std::string(value);\r
-       }\r
-\r
-       void swap(path& other);\r
-\r
-       // Properties\r
-\r
-       const std::string& str() const; \r
-       bool empty() const;\r
-private:\r
-       std::string str_;\r
-};\r
-\r
-template<typename T>\r
-path operator%(path path, T&& value)\r
-{      \r
-       return std::move(path %= std::forward<T>(value));\r
-}\r
-\r
-std::ostream& operator<<(std::ostream& o, const path& p);\r
-\r
-// param\r
-\r
-typedef boost::chrono::duration<double, boost::ratio<1, 1>> duration;\r
-\r
-typedef boost::variant<bool, int32_t, int64_t, float, double, std::string, std::wstring, std::vector<int8_t>, duration> param;\r
-\r
-std::ostream& operator<<(std::ostream& o, const param& p);\r
-\r
-// event\r
-\r
-class event sealed\r
-{      \r
-public:        \r
-       \r
-       // Static Members\r
-\r
-       typedef std::vector<param, tbb::cache_aligned_allocator<param>> params_t;\r
-\r
-       // Constructors\r
-\r
-       event(path path);       \r
-       event(path path, params_t params);                                      \r
-       event(const event& other);\r
-       event(event&& other);\r
-\r
-       // Methods\r
-\r
-       event& operator=(event other);\r
-\r
-       void swap(event& other);\r
-               \r
-       template<typename T>\r
-       event& operator%(T&& value)\r
-       {\r
-               params_.push_back(std::forward<T>(value));\r
-               return *this;\r
-       }\r
-       \r
-       event propagate(path path) const;\r
-\r
-       // Properties\r
-\r
-       const path&             path() const;\r
-       const params_t& params() const;\r
-private:\r
-       monitor::path   path_;\r
-       params_t                params_;\r
-};\r
-\r
-std::ostream& operator<<(std::ostream& o, const event& e);\r
-\r
-// reactive\r
-\r
-typedef reactive::observable<monitor::event>   observable;\r
-typedef reactive::observer<monitor::event>             observer;\r
-typedef reactive::subject<monitor::event>              subject;\r
-       \r
-class basic_subject sealed : public reactive::subject<monitor::event>\r
-{          \r
-       basic_subject(const basic_subject&);\r
-       basic_subject& operator=(const basic_subject&);\r
-       \r
-       class impl : public observer\r
-       {\r
-       public:\r
-               impl(monitor::path path = monitor::path())\r
-                       : impl_()\r
-                       , path_(std::move(path))\r
-               {\r
-               }\r
-\r
-               impl(impl&& other)\r
-                       : impl_(std::move(other.impl_))\r
-                       , path_(std::move(other.path_))\r
-               {               \r
-               }\r
-\r
-               impl& operator=(impl&& other)\r
-               {\r
-                       impl_ = std::move(other.impl_);         \r
-                       path_ = std::move(other.path_);\r
-               }\r
-                                                       \r
-               void on_next(const monitor::event& e) override\r
-               {                               \r
-                       impl_.on_next(path_.empty() ? e : e.propagate(path_));\r
-               }\r
-\r
-               void subscribe(const observer_ptr& o)\r
-               {                               \r
-                       impl_.subscribe(o);\r
-               }\r
-\r
-               void unsubscribe(const observer_ptr& o)\r
-               {\r
-                       impl_.unsubscribe(o);\r
-               }\r
-                               \r
-       private:\r
-               reactive::basic_subject_impl<monitor::event>    impl_;          \r
-               monitor::path                                                                   path_;\r
-       };\r
-\r
-public:                \r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       basic_subject(monitor::path path = monitor::path())\r
-               : impl_(std::make_shared<impl>(std::move(path)))\r
-\r
-       {\r
-       }\r
-               \r
-       basic_subject(basic_subject&& other)\r
-               : impl_(std::move(other.impl_))\r
-       {\r
-       }\r
-       \r
-       // Methods\r
-\r
-       basic_subject& operator=(basic_subject&& other)\r
-       {\r
-               impl_ = std::move(other.impl_);\r
-       }\r
-\r
-       operator std::weak_ptr<observer>()\r
-       {\r
-               return impl_;\r
-       }\r
-\r
-       // observable\r
-       \r
-       void subscribe(const observer_ptr& o) override\r
-       {                               \r
-               impl_->subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const observer_ptr& o) override\r
-       {\r
-               impl_->unsubscribe(o);\r
-       }\r
-\r
-       // observer\r
-                               \r
-       void on_next(const monitor::event& e) override\r
-       {                               \r
-               impl_->on_next(e);\r
-       }\r
-\r
-       // Properties\r
-\r
-private:\r
-       std::shared_ptr<impl> impl_;\r
-};\r
-\r
-inline subject& operator<<(subject& s, const event& e)\r
-{\r
-       s.on_next(e);\r
-       return s;\r
-}\r
-\r
+#pragma once
+
+#include <common/reactive.h>
+
+#include <functional>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <boost/variant.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/chrono.hpp>
+
+#include <tbb/cache_aligned_allocator.h>
+
+namespace boost {
+namespace detail { namespace variant {
+
+template <>
+struct has_nothrow_move<std::string>
+: mpl::true_
+{
+};
+  
+template <>
+struct has_nothrow_move<std::vector<int8_t>>
+: mpl::true_
+{
+};
+
+template <>
+struct has_nothrow_move<boost::chrono::duration<double, boost::ratio<1, 1>>>
+: mpl::true_
+{
+};
+
+}}}
+
+namespace caspar { namespace monitor {
+       
+// path
+
+class path sealed
+{
+public:        
+
+       // Static Members
+
+       // Constructors
+
+       path();         
+       path(const char* path);
+       path(std::string path);
+
+       path(const path& other);        
+       path(path&& other);
+               
+       // Methods
+
+       path& operator=(path other);
+       path& operator%=(path other);
+
+       template<typename T>
+       typename std::enable_if<!std::is_same<typename std::decay<T>::type, path>::value, path&>::type operator%=(T&& value)
+       {
+               auto str = boost::lexical_cast<std::string>(std::forward<T>(value));
+
+               if(!str.empty())
+                       str_ += (str.front() != '/' ? "/" : "") + std::move(str);
+
+               return *this;
+       }
+       
+       path& operator%=(const char* value)
+       {
+               return *this %= std::string(value);
+       }
+
+       void swap(path& other);
+
+       // Properties
+
+       const std::string& str() const; 
+       bool empty() const;
+private:
+       std::string str_;
+};
+
+template<typename T>
+path operator%(path path, T&& value)
+{      
+       return std::move(path %= std::forward<T>(value));
+}
+
+std::ostream& operator<<(std::ostream& o, const path& p);
+
+// param
+
+typedef boost::chrono::duration<double, boost::ratio<1, 1>> duration;
+
+typedef boost::variant<bool, int32_t, int64_t, float, double, std::string, std::wstring, std::vector<int8_t>, duration> param;
+
+std::ostream& operator<<(std::ostream& o, const param& p);
+
+// event
+
+class event sealed
+{      
+public:        
+       
+       // Static Members
+
+       typedef std::vector<param, tbb::cache_aligned_allocator<param>> params_t;
+
+       // Constructors
+
+       event(path path);       
+       event(path path, params_t params);                                      
+       event(const event& other);
+       event(event&& other);
+
+       // Methods
+
+       event& operator=(event other);
+
+       void swap(event& other);
+               
+       template<typename T>
+       event& operator%(T&& value)
+       {
+               params_.push_back(std::forward<T>(value));
+               return *this;
+       }
+       
+       event propagate(path path) const;
+
+       // Properties
+
+       const path&             path() const;
+       const params_t& params() const;
+private:
+       monitor::path   path_;
+       params_t                params_;
+};
+
+std::ostream& operator<<(std::ostream& o, const event& e);
+
+// reactive
+
+typedef reactive::observable<monitor::event>   observable;
+typedef reactive::observer<monitor::event>             observer;
+typedef reactive::subject<monitor::event>              subject;
+       
+class basic_subject sealed : public reactive::subject<monitor::event>
+{          
+       basic_subject(const basic_subject&);
+       basic_subject& operator=(const basic_subject&);
+       
+       class impl : public observer
+       {
+       public:
+               impl(monitor::path path = monitor::path())
+                       : impl_()
+                       , path_(std::move(path))
+               {
+               }
+
+               impl(impl&& other)
+                       : impl_(std::move(other.impl_))
+                       , path_(std::move(other.path_))
+               {               
+               }
+
+               impl& operator=(impl&& other)
+               {
+                       impl_ = std::move(other.impl_);         
+                       path_ = std::move(other.path_);
+               }
+                                                       
+               void on_next(const monitor::event& e) override
+               {                               
+                       impl_.on_next(path_.empty() ? e : e.propagate(path_));
+               }
+
+               void subscribe(const observer_ptr& o)
+               {                               
+                       impl_.subscribe(o);
+               }
+
+               void unsubscribe(const observer_ptr& o)
+               {
+                       impl_.unsubscribe(o);
+               }
+                               
+       private:
+               reactive::basic_subject_impl<monitor::event>    impl_;          
+               monitor::path                                                                   path_;
+       };
+
+public:                
+
+       // Static Members
+
+       // Constructors
+
+       basic_subject(monitor::path path = monitor::path())
+               : impl_(std::make_shared<impl>(std::move(path)))
+
+       {
+       }
+               
+       basic_subject(basic_subject&& other)
+               : impl_(std::move(other.impl_))
+       {
+       }
+       
+       // Methods
+
+       basic_subject& operator=(basic_subject&& other)
+       {
+               impl_ = std::move(other.impl_);
+       }
+
+       operator std::weak_ptr<observer>()
+       {
+               return impl_;
+       }
+
+       // observable
+       
+       void subscribe(const observer_ptr& o) override
+       {                               
+               impl_->subscribe(o);
+       }
+
+       void unsubscribe(const observer_ptr& o) override
+       {
+               impl_->unsubscribe(o);
+       }
+
+       // observer
+                               
+       void on_next(const monitor::event& e) override
+       {                               
+               impl_->on_next(e);
+       }
+
+       // Properties
+
+private:
+       std::shared_ptr<impl> impl_;
+};
+
+inline subject& operator<<(subject& s, const event& e)
+{
+       s.on_next(e);
+       return s;
+}
+
 }}
\ No newline at end of file
index 7e7fe3a3cf13c8ca25f3c944c04ac8d6f9826a6e..ed932b446ee94c086e9f51c90dacbcbd1fa8faf5 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "color_producer.h"\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/frame/frame.h>\r
-#include <core/frame/draw_frame.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/monitor/monitor.h>\r
-\r
-#include <common/except.h>\r
-#include <common/array.h>\r
-\r
-#include <boost/algorithm/string.hpp>\r
-\r
-#include <sstream>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-class color_producer : public frame_producer_base\r
-{\r
-       monitor::basic_subject  event_subject_;\r
-\r
-       draw_frame                              frame_;\r
-       const std::wstring              color_str_;\r
-\r
-public:\r
-       explicit color_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const std::wstring& color) \r
-               : color_str_(color)\r
-               , frame_(create_color_frame(this, frame_factory, color))\r
-       {\r
-               CASPAR_LOG(info) << print() << L" Initialized";\r
-       }\r
-\r
-       // frame_producer\r
-                       \r
-       draw_frame receive_impl() override\r
-       {\r
-               event_subject_ << monitor::event("color") % color_str_;\r
-\r
-               return frame_;\r
-       }       \r
-       \r
-       std::wstring print() const override\r
-       {\r
-               return L"color[" + color_str_ + L"]";\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"color";\r
-       }\r
-       \r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"color");\r
-               info.add(L"color", color_str_);\r
-               return info;\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override                                                                                                                     \r
-       {\r
-               return event_subject_.subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override           \r
-       {\r
-               return event_subject_.unsubscribe(o);\r
-       }\r
-};\r
-\r
-std::wstring get_hex_color(const std::wstring& str)\r
-{\r
-       if(str.at(0) == '#')\r
-               return str.length() == 7 ? L"#FF" + str.substr(1) : str;\r
-       \r
-       if(boost::iequals(str, L"EMPTY"))\r
-               return L"#00000000";\r
-\r
-       if(boost::iequals(str, L"BLACK"))\r
-               return L"#FF000000";\r
-       \r
-       if(boost::iequals(str, L"WHITE"))\r
-               return L"#FFFFFFFF";\r
-       \r
-       if(boost::iequals(str, L"RED"))\r
-               return L"#FFFF0000";\r
-       \r
-       if(boost::iequals(str, L"GREEN"))\r
-               return L"#FF00FF00";\r
-       \r
-       if(boost::iequals(str, L"BLUE"))\r
-               return L"#FF0000FF";    \r
-       \r
-       if(boost::iequals(str, L"ORANGE"))\r
-               return L"#FFFFA500";    \r
-       \r
-       if(boost::iequals(str, L"YELLOW"))\r
-               return L"#FFFFFF00";\r
-       \r
-       if(boost::iequals(str, L"BROWN"))\r
-               return L"#FFA52A2A";\r
-       \r
-       if(boost::iequals(str, L"GRAY"))\r
-               return L"#FF808080";\r
-       \r
-       if(boost::iequals(str, L"TEAL"))\r
-               return L"#FF008080";\r
-       \r
-       return str;\r
-}\r
-\r
-spl::shared_ptr<frame_producer> create_color_producer(const spl::shared_ptr<frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
-{\r
-       if(params.size() < 0)\r
-               return core::frame_producer::empty();\r
-\r
-       auto color2 = get_hex_color(params[0]);\r
-       if(color2.length() != 9 || color2[0] != '#')\r
-               return core::frame_producer::empty();\r
-\r
-       return spl::make_shared<color_producer>(frame_factory, color2);\r
-}\r
-\r
-draw_frame create_color_frame(void* tag, const spl::shared_ptr<frame_factory>& frame_factory, const std::wstring& color)\r
-{\r
-       auto color2 = get_hex_color(color);\r
-       if(color2.length() != 9 || color2[0] != '#')\r
-               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("color") << arg_value_info(color2) << msg_info("Invalid color."));\r
-       \r
-       core::pixel_format_desc desc(pixel_format::bgra);\r
-       desc.planes.push_back(core::pixel_format_desc::plane(1, 1, 4));\r
-       auto frame = frame_factory->create_frame(tag, desc);\r
-               \r
-       // Read color from hex-string and write to frame pixel.\r
-\r
-       auto& value = *reinterpret_cast<uint32_t*>(frame.image_data(0).begin());\r
-       std::wstringstream str(color2.substr(1));\r
-       if(!(str >> std::hex >> value) || !str.eof())\r
-               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("color") << arg_value_info(color2) << msg_info("Invalid color."));\r
-                       \r
-       return core::draw_frame(std::move(frame));\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "color_producer.h"
+
+#include <core/producer/frame_producer.h>
+#include <core/frame/frame.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/pixel_format.h>
+#include <core/monitor/monitor.h>
+
+#include <common/except.h>
+#include <common/array.h>
+
+#include <boost/algorithm/string.hpp>
+
+#include <sstream>
+
+namespace caspar { namespace core {
+       
+class color_producer : public frame_producer_base
+{
+       monitor::basic_subject  event_subject_;
+
+       draw_frame                              frame_;
+       const std::wstring              color_str_;
+
+public:
+       explicit color_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const std::wstring& color) 
+               : color_str_(color)
+               , frame_(create_color_frame(this, frame_factory, color))
+       {
+               CASPAR_LOG(info) << print() << L" Initialized";
+       }
+
+       // frame_producer
+                       
+       draw_frame receive_impl() override
+       {
+               event_subject_ << monitor::event("color") % color_str_;
+
+               return frame_;
+       }       
+       
+       std::wstring print() const override
+       {
+               return L"color[" + color_str_ + L"]";
+       }
+
+       std::wstring name() const override
+       {
+               return L"color";
+       }
+       
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"color");
+               info.add(L"color", color_str_);
+               return info;
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override                                                                                                                     
+       {
+               return event_subject_.subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override           
+       {
+               return event_subject_.unsubscribe(o);
+       }
+};
+
+std::wstring get_hex_color(const std::wstring& str)
+{
+       if(str.at(0) == '#')
+               return str.length() == 7 ? L"#FF" + str.substr(1) : str;
+       
+       if(boost::iequals(str, L"EMPTY"))
+               return L"#00000000";
+
+       if(boost::iequals(str, L"BLACK"))
+               return L"#FF000000";
+       
+       if(boost::iequals(str, L"WHITE"))
+               return L"#FFFFFFFF";
+       
+       if(boost::iequals(str, L"RED"))
+               return L"#FFFF0000";
+       
+       if(boost::iequals(str, L"GREEN"))
+               return L"#FF00FF00";
+       
+       if(boost::iequals(str, L"BLUE"))
+               return L"#FF0000FF";    
+       
+       if(boost::iequals(str, L"ORANGE"))
+               return L"#FFFFA500";    
+       
+       if(boost::iequals(str, L"YELLOW"))
+               return L"#FFFFFF00";
+       
+       if(boost::iequals(str, L"BROWN"))
+               return L"#FFA52A2A";
+       
+       if(boost::iequals(str, L"GRAY"))
+               return L"#FF808080";
+       
+       if(boost::iequals(str, L"TEAL"))
+               return L"#FF008080";
+       
+       return str;
+}
+
+spl::shared_ptr<frame_producer> create_color_producer(const spl::shared_ptr<frame_factory>& frame_factory, const std::vector<std::wstring>& params)
+{
+       if(params.size() < 0)
+               return core::frame_producer::empty();
+
+       auto color2 = get_hex_color(params[0]);
+       if(color2.length() != 9 || color2[0] != '#')
+               return core::frame_producer::empty();
+
+       return spl::make_shared<color_producer>(frame_factory, color2);
+}
+
+draw_frame create_color_frame(void* tag, const spl::shared_ptr<frame_factory>& frame_factory, const std::wstring& color)
+{
+       auto color2 = get_hex_color(color);
+       if(color2.length() != 9 || color2[0] != '#')
+               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("color") << arg_value_info(color2) << msg_info("Invalid color."));
+       
+       core::pixel_format_desc desc(pixel_format::bgra);
+       desc.planes.push_back(core::pixel_format_desc::plane(1, 1, 4));
+       auto frame = frame_factory->create_frame(tag, desc);
+               
+       // Read color from hex-string and write to frame pixel.
+
+       auto& value = *reinterpret_cast<uint32_t*>(frame.image_data(0).begin());
+       std::wstringstream str(color2.substr(1));
+       if(!(str >> std::hex >> value) || !str.eof())
+               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("color") << arg_value_info(color2) << msg_info("Invalid color."));
+                       
+       return core::draw_frame(std::move(frame));
+}
+
 }}
\ No newline at end of file
index 6cb7a8d66a7ed43f99130f5d0a2e6357c7c34e0d..153745da71559166d5e72b65ad2d002ad913ed5f 100644 (file)
@@ -1,34 +1,34 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-spl::shared_ptr<class frame_producer> create_color_producer(const spl::shared_ptr<class frame_factory>& frame_factory, const std::vector<std::wstring>& params);\r
-class draw_frame create_color_frame(void* tag, const spl::shared_ptr<class frame_factory>& frame_factory, const std::wstring& color);\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <string>
+#include <vector>
+
+namespace caspar { namespace core {
+       
+spl::shared_ptr<class frame_producer> create_color_producer(const spl::shared_ptr<class frame_factory>& frame_factory, const std::vector<std::wstring>& params);
+class draw_frame create_color_frame(void* tag, const spl::shared_ptr<class frame_factory>& frame_factory, const std::wstring& color);
+
+}}
index cdfea6ffbee8ebf86cbdf753b2e7af344360bfe2..7837b1fddee0c6efaf5bce1cdf0aa578ba36176a 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../StdAfx.h"\r
-\r
-#include "frame_producer.h"\r
-\r
-#include "../frame/draw_frame.h"\r
-#include "../frame/frame_transform.h"\r
-\r
-#include "color/color_producer.h"\r
-#include "separated/separated_producer.h"\r
-\r
-#include <common/assert.h>\r
-#include <common/except.h>\r
-#include <common/executor.h>\r
-#include <common/future.h>\r
-#include <common/memory.h>\r
-\r
-#include <boost/thread.hpp>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-std::vector<const producer_factory_t> g_factories;\r
-\r
-void register_producer_factory(const producer_factory_t& factory)\r
-{\r
-       g_factories.push_back(factory);\r
-}\r
-\r
-struct frame_producer_base::impl\r
-{\r
-       tbb::atomic<uint32_t>   frame_number_;\r
-       tbb::atomic<bool>               paused_;\r
-       frame_producer_base&    self_;\r
-       draw_frame                              last_frame_;\r
-\r
-       impl(frame_producer_base& self)\r
-               : self_(self)\r
-               , last_frame_(draw_frame::empty())\r
-       {\r
-               frame_number_ = 0;\r
-               paused_ = false;\r
-       }\r
-       \r
-       draw_frame receive()\r
-       {\r
-               if(paused_)\r
-                       return self_.last_frame();\r
-\r
-               auto frame = self_.receive_impl();\r
-               if(frame == draw_frame::late())\r
-                       return self_.last_frame();\r
-\r
-               ++frame_number_;\r
-\r
-               return last_frame_ = draw_frame::push(frame);\r
-       }\r
-\r
-       void paused(bool value)\r
-       {\r
-               paused_ = value;\r
-       }\r
-\r
-       draw_frame last_frame()\r
-       {\r
-               return draw_frame::still(last_frame_);\r
-       }\r
-};\r
-\r
-frame_producer_base::frame_producer_base() : impl_(new impl(*this))\r
-{\r
-}\r
-\r
-draw_frame frame_producer_base::receive()\r
-{\r
-       return impl_->receive();\r
-}\r
-\r
-void frame_producer_base::paused(bool value)\r
-{\r
-       impl_->paused(value);\r
-}\r
-\r
-draw_frame frame_producer_base::last_frame()\r
-{\r
-       return impl_->last_frame();\r
-}\r
-\r
-boost::unique_future<std::wstring> frame_producer_base::call(const std::wstring&) \r
-{\r
-       CASPAR_THROW_EXCEPTION(not_supported());\r
-}\r
-\r
-uint32_t frame_producer_base::nb_frames() const\r
-{\r
-       return std::numeric_limits<uint32_t>::max();\r
-}\r
-\r
-uint32_t frame_producer_base::frame_number() const\r
-{\r
-       return impl_->frame_number_;\r
-}\r
-\r
-const spl::shared_ptr<frame_producer>& frame_producer::empty() \r
-{\r
-       class empty_frame_producer : public frame_producer\r
-       {\r
-       public:\r
-               empty_frame_producer(){}\r
-               draw_frame receive() override{return draw_frame::empty();}\r
-               void paused(bool value) override{}\r
-               uint32_t nb_frames() const override {return 0;}\r
-               std::wstring print() const override { return L"empty";}\r
-               void subscribe(const monitor::observable::observer_ptr& o) override{}\r
-               void unsubscribe(const monitor::observable::observer_ptr& o) override{} \r
-               std::wstring name() const override {return L"empty";}\r
-               uint32_t frame_number() const override {return 0;}\r
-               boost::unique_future<std::wstring> call(const std::wstring& params) override{CASPAR_THROW_EXCEPTION(not_supported());}\r
-               draw_frame last_frame() {return draw_frame::empty();}\r
-       \r
-               boost::property_tree::wptree info() const override\r
-               {\r
-                       boost::property_tree::wptree info;\r
-                       info.add(L"type", L"empty-producer");\r
-                       return info;\r
-               }\r
-       };\r
-\r
-       static spl::shared_ptr<frame_producer> producer = spl::make_shared<empty_frame_producer>();\r
-       return producer;\r
-}      \r
-\r
-class destroy_producer_proxy : public frame_producer\r
-{      \r
-       std::shared_ptr<frame_producer> producer_;\r
-public:\r
-       destroy_producer_proxy(spl::shared_ptr<frame_producer>&& producer) \r
-               : producer_(std::move(producer))\r
-       {\r
-       }\r
-\r
-       virtual ~destroy_producer_proxy()\r
-       {               \r
-               static tbb::atomic<int> counter = tbb::atomic<int>();\r
-               \r
-               if(producer_ == core::frame_producer::empty())\r
-                       return;\r
-\r
-               ++counter;\r
-               CASPAR_VERIFY(counter < 8);\r
-               \r
-               auto producer = new spl::shared_ptr<frame_producer>(std::move(producer_));\r
-               boost::thread([=]\r
-               {\r
-                       std::unique_ptr<spl::shared_ptr<frame_producer>> pointer_guard(producer);\r
-                       auto str = (*producer)->print();\r
-                       try\r
-                       {\r
-                               if(!producer->unique())\r
-                                       CASPAR_LOG(trace) << str << L" Not destroyed on asynchronous destruction thread: " << producer->use_count();\r
-                               else\r
-                                       CASPAR_LOG(trace) << str << L" Destroying on asynchronous destruction thread.";\r
-                       }\r
-                       catch(...){}\r
-                       \r
-                       try\r
-                       {\r
-                               pointer_guard.reset();\r
-                               CASPAR_LOG(info) << str << L" Destroyed.";\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }\r
-\r
-                       --counter;\r
-               }).detach(); \r
-       }\r
-       \r
-       draw_frame      receive() override                                                                                                                                                                                                              {return producer_->receive();}\r
-       std::wstring                                                                            print() const override                                                                                                                  {return producer_->print();}\r
-       void                                                                                            paused(bool value) override                                                                                                             {producer_->paused(value);}\r
-       std::wstring                                                                            name() const override                                                                                                                   {return producer_->name();}\r
-       uint32_t                                                                                        frame_number() const override                                                                                                   {return producer_->frame_number();}\r
-       boost::property_tree::wptree                                            info() const override                                                                                                                   {return producer_->info();}\r
-       boost::unique_future<std::wstring>                                      call(const std::wstring& str) override                                                                                  {return producer_->call(str);}\r
-       void                                                                                            leading_producer(const spl::shared_ptr<frame_producer>& producer) override              {return producer_->leading_producer(producer);}\r
-       uint32_t                                                                                        nb_frames() const override                                                                                                              {return producer_->nb_frames();}\r
-       class draw_frame                                                                        last_frame()                                                                                                                            {return producer_->last_frame();}\r
-       void                                                                                            subscribe(const monitor::observable::observer_ptr& o)                                                   {return producer_->subscribe(o);}\r
-       void                                                                                            unsubscribe(const monitor::observable::observer_ptr& o)                                                 {return producer_->unsubscribe(o);}\r
-};\r
-\r
-spl::shared_ptr<core::frame_producer> create_destroy_proxy(spl::shared_ptr<core::frame_producer> producer)\r
-{\r
-       return spl::make_shared<destroy_producer_proxy>(std::move(producer));\r
-}\r
-\r
-spl::shared_ptr<core::frame_producer> do_create_producer(const spl::shared_ptr<frame_factory>& my_frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params)\r
-{\r
-       if(params.empty())\r
-               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));\r
-       \r
-       auto producer = frame_producer::empty();\r
-       std::any_of(g_factories.begin(), g_factories.end(), [&](const producer_factory_t& factory) -> bool\r
-               {\r
-                       try\r
-                       {\r
-                               producer = factory(my_frame_factory, format_desc, params);\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }\r
-                       return producer != frame_producer::empty();\r
-               });\r
-\r
-       if(producer == frame_producer::empty())\r
-               producer = create_color_producer(my_frame_factory, params);\r
-\r
-       if(producer == frame_producer::empty())\r
-               return producer;\r
-               \r
-       return producer;\r
-}\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>& my_frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params)\r
-{      \r
-       auto producer = do_create_producer(my_frame_factory, format_desc, params);\r
-       auto key_producer = frame_producer::empty();\r
-       \r
-       try // to find a key file.\r
-       {\r
-               auto params_copy = params;\r
-               if(params_copy.size() > 0)\r
-               {\r
-                       params_copy[0] += L"_A";\r
-                       key_producer = do_create_producer(my_frame_factory, format_desc, params_copy);                  \r
-                       if(key_producer == frame_producer::empty())\r
-                       {\r
-                               params_copy[0] += L"LPHA";\r
-                               key_producer = do_create_producer(my_frame_factory, format_desc, params_copy);  \r
-                       }\r
-               }\r
-       }\r
-       catch(...){}\r
-\r
-       if(producer != frame_producer::empty() && key_producer != frame_producer::empty())\r
-               return create_separated_producer(producer, key_producer);\r
-       \r
-       if(producer == frame_producer::empty())\r
-       {\r
-               std::wstring str;\r
-               BOOST_FOREACH(auto& param, params)\r
-                       str += param + L" ";\r
-               CASPAR_THROW_EXCEPTION(file_not_found() << msg_info("No match found for supplied commands. Check syntax.") << arg_value_info(u8(str)));\r
-       }\r
-\r
-       return producer;\r
-}\r
-\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>& factory, const video_format_desc& format_desc, const std::wstring& params)\r
-{\r
-       std::wstringstream iss(params);\r
-       std::vector<std::wstring> tokens;\r
-       typedef std::istream_iterator<std::wstring, wchar_t, std::char_traits<wchar_t> > iterator;\r
-       std::copy(iterator(iss),  iterator(), std::back_inserter(tokens));\r
-       return create_producer(factory, format_desc, tokens);\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../StdAfx.h"
+
+#include "frame_producer.h"
+
+#include "../frame/draw_frame.h"
+#include "../frame/frame_transform.h"
+
+#include "color/color_producer.h"
+#include "separated/separated_producer.h"
+
+#include <common/assert.h>
+#include <common/except.h>
+#include <common/executor.h>
+#include <common/future.h>
+#include <common/memory.h>
+
+#include <boost/thread.hpp>
+
+namespace caspar { namespace core {
+       
+std::vector<const producer_factory_t> g_factories;
+
+void register_producer_factory(const producer_factory_t& factory)
+{
+       g_factories.push_back(factory);
+}
+
+struct frame_producer_base::impl
+{
+       tbb::atomic<uint32_t>   frame_number_;
+       tbb::atomic<bool>               paused_;
+       frame_producer_base&    self_;
+       draw_frame                              last_frame_;
+
+       impl(frame_producer_base& self)
+               : self_(self)
+               , last_frame_(draw_frame::empty())
+       {
+               frame_number_ = 0;
+               paused_ = false;
+       }
+       
+       draw_frame receive()
+       {
+               if(paused_)
+                       return self_.last_frame();
+
+               auto frame = self_.receive_impl();
+               if(frame == draw_frame::late())
+                       return self_.last_frame();
+
+               ++frame_number_;
+
+               return last_frame_ = draw_frame::push(frame);
+       }
+
+       void paused(bool value)
+       {
+               paused_ = value;
+       }
+
+       draw_frame last_frame()
+       {
+               return draw_frame::still(last_frame_);
+       }
+};
+
+frame_producer_base::frame_producer_base() : impl_(new impl(*this))
+{
+}
+
+draw_frame frame_producer_base::receive()
+{
+       return impl_->receive();
+}
+
+void frame_producer_base::paused(bool value)
+{
+       impl_->paused(value);
+}
+
+draw_frame frame_producer_base::last_frame()
+{
+       return impl_->last_frame();
+}
+
+boost::unique_future<std::wstring> frame_producer_base::call(const std::wstring&) 
+{
+       CASPAR_THROW_EXCEPTION(not_supported());
+}
+
+uint32_t frame_producer_base::nb_frames() const
+{
+       return std::numeric_limits<uint32_t>::max();
+}
+
+uint32_t frame_producer_base::frame_number() const
+{
+       return impl_->frame_number_;
+}
+
+const spl::shared_ptr<frame_producer>& frame_producer::empty() 
+{
+       class empty_frame_producer : public frame_producer
+       {
+       public:
+               empty_frame_producer(){}
+               draw_frame receive() override{return draw_frame::empty();}
+               void paused(bool value) override{}
+               uint32_t nb_frames() const override {return 0;}
+               std::wstring print() const override { return L"empty";}
+               void subscribe(const monitor::observable::observer_ptr& o) override{}
+               void unsubscribe(const monitor::observable::observer_ptr& o) override{} 
+               std::wstring name() const override {return L"empty";}
+               uint32_t frame_number() const override {return 0;}
+               boost::unique_future<std::wstring> call(const std::wstring& params) override{CASPAR_THROW_EXCEPTION(not_supported());}
+               draw_frame last_frame() {return draw_frame::empty();}
+       
+               boost::property_tree::wptree info() const override
+               {
+                       boost::property_tree::wptree info;
+                       info.add(L"type", L"empty-producer");
+                       return info;
+               }
+       };
+
+       static spl::shared_ptr<frame_producer> producer = spl::make_shared<empty_frame_producer>();
+       return producer;
+}      
+
+class destroy_producer_proxy : public frame_producer
+{      
+       std::shared_ptr<frame_producer> producer_;
+public:
+       destroy_producer_proxy(spl::shared_ptr<frame_producer>&& producer) 
+               : producer_(std::move(producer))
+       {
+       }
+
+       virtual ~destroy_producer_proxy()
+       {               
+               static tbb::atomic<int> counter = tbb::atomic<int>();
+               
+               if(producer_ == core::frame_producer::empty())
+                       return;
+
+               ++counter;
+               CASPAR_VERIFY(counter < 8);
+               
+               auto producer = new spl::shared_ptr<frame_producer>(std::move(producer_));
+               boost::thread([=]
+               {
+                       std::unique_ptr<spl::shared_ptr<frame_producer>> pointer_guard(producer);
+                       auto str = (*producer)->print();
+                       try
+                       {
+                               if(!producer->unique())
+                                       CASPAR_LOG(trace) << str << L" Not destroyed on asynchronous destruction thread: " << producer->use_count();
+                               else
+                                       CASPAR_LOG(trace) << str << L" Destroying on asynchronous destruction thread.";
+                       }
+                       catch(...){}
+                       
+                       try
+                       {
+                               pointer_guard.reset();
+                               CASPAR_LOG(info) << str << L" Destroyed.";
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }
+
+                       --counter;
+               }).detach(); 
+       }
+       
+       draw_frame      receive() override                                                                                                                                                                                                              {return producer_->receive();}
+       std::wstring                                                                            print() const override                                                                                                                  {return producer_->print();}
+       void                                                                                            paused(bool value) override                                                                                                             {producer_->paused(value);}
+       std::wstring                                                                            name() const override                                                                                                                   {return producer_->name();}
+       uint32_t                                                                                        frame_number() const override                                                                                                   {return producer_->frame_number();}
+       boost::property_tree::wptree                                            info() const override                                                                                                                   {return producer_->info();}
+       boost::unique_future<std::wstring>                                      call(const std::wstring& str) override                                                                                  {return producer_->call(str);}
+       void                                                                                            leading_producer(const spl::shared_ptr<frame_producer>& producer) override              {return producer_->leading_producer(producer);}
+       uint32_t                                                                                        nb_frames() const override                                                                                                              {return producer_->nb_frames();}
+       class draw_frame                                                                        last_frame()                                                                                                                            {return producer_->last_frame();}
+       void                                                                                            subscribe(const monitor::observable::observer_ptr& o)                                                   {return producer_->subscribe(o);}
+       void                                                                                            unsubscribe(const monitor::observable::observer_ptr& o)                                                 {return producer_->unsubscribe(o);}
+};
+
+spl::shared_ptr<core::frame_producer> create_destroy_proxy(spl::shared_ptr<core::frame_producer> producer)
+{
+       return spl::make_shared<destroy_producer_proxy>(std::move(producer));
+}
+
+spl::shared_ptr<core::frame_producer> do_create_producer(const spl::shared_ptr<frame_factory>& my_frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params)
+{
+       if(params.empty())
+               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));
+       
+       auto producer = frame_producer::empty();
+       std::any_of(g_factories.begin(), g_factories.end(), [&](const producer_factory_t& factory) -> bool
+               {
+                       try
+                       {
+                               producer = factory(my_frame_factory, format_desc, params);
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }
+                       return producer != frame_producer::empty();
+               });
+
+       if(producer == frame_producer::empty())
+               producer = create_color_producer(my_frame_factory, params);
+
+       if(producer == frame_producer::empty())
+               return producer;
+               
+       return producer;
+}
+
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>& my_frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params)
+{      
+       auto producer = do_create_producer(my_frame_factory, format_desc, params);
+       auto key_producer = frame_producer::empty();
+       
+       try // to find a key file.
+       {
+               auto params_copy = params;
+               if(params_copy.size() > 0)
+               {
+                       params_copy[0] += L"_A";
+                       key_producer = do_create_producer(my_frame_factory, format_desc, params_copy);                  
+                       if(key_producer == frame_producer::empty())
+                       {
+                               params_copy[0] += L"LPHA";
+                               key_producer = do_create_producer(my_frame_factory, format_desc, params_copy);  
+                       }
+               }
+       }
+       catch(...){}
+
+       if(producer != frame_producer::empty() && key_producer != frame_producer::empty())
+               return create_separated_producer(producer, key_producer);
+       
+       if(producer == frame_producer::empty())
+       {
+               std::wstring str;
+               BOOST_FOREACH(auto& param, params)
+                       str += param + L" ";
+               CASPAR_THROW_EXCEPTION(file_not_found() << msg_info("No match found for supplied commands. Check syntax.") << arg_value_info(u8(str)));
+       }
+
+       return producer;
+}
+
+
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>& factory, const video_format_desc& format_desc, const std::wstring& params)
+{
+       std::wstringstream iss(params);
+       std::vector<std::wstring> tokens;
+       typedef std::istream_iterator<std::wstring, wchar_t, std::char_traits<wchar_t> > iterator;
+       std::copy(iterator(iss),  iterator(), std::back_inserter(tokens));
+       return create_producer(factory, format_desc, tokens);
+}
+
 }}
\ No newline at end of file
index dbef6605665e6c76bd87edec4b275bfc9c70044d..44368b2a91d57ea1c5312f79ce3a4d2ffcc1e1e1 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "../monitor/monitor.h"\r
-#include "../video_format.h"\r
-\r
-#include <common/forward.h>\r
-#include <common/future_fwd.h>\r
-#include <common/memory.h>\r
-#include <common/enum_class.h>\r
-\r
-#include <cstdint>\r
-#include <limits>\r
-#include <functional>\r
-#include <string>\r
-#include <type_traits>\r
-#include <vector>\r
-\r
-#include <boost/property_tree/ptree_fwd.hpp>\r
-\r
-FORWARD1(caspar, class executor);\r
-\r
-namespace caspar { namespace core {\r
-       \r
-// Interface\r
-class frame_producer : public monitor::observable\r
-{\r
-       frame_producer(const frame_producer&);\r
-       frame_producer& operator=(const frame_producer&);\r
-public:\r
-\r
-       // Static Members\r
-       \r
-       static const spl::shared_ptr<frame_producer>& empty();\r
-\r
-       // Constructors\r
-\r
-       frame_producer(){}\r
-       virtual ~frame_producer(){}     \r
-\r
-       // Methods      \r
-\r
-       virtual class draw_frame                                        receive() = 0;\r
-       virtual boost::unique_future<std::wstring>      call(const std::wstring& params) = 0;\r
-       \r
-       // monitor::observable\r
-\r
-       virtual void subscribe(const monitor::observable::observer_ptr& o) = 0;\r
-       virtual void unsubscribe(const monitor::observable::observer_ptr& o) = 0;\r
-\r
-       // Properties\r
-       \r
-\r
-       virtual void                                                            paused(bool value) = 0;\r
-       virtual std::wstring                                            print() const = 0;\r
-       virtual std::wstring                                            name() const = 0;\r
-       virtual boost::property_tree::wptree            info() const = 0;\r
-       virtual uint32_t                                                        nb_frames() const = 0;\r
-       virtual uint32_t                                                        frame_number() const = 0;\r
-       virtual class draw_frame                                        last_frame() = 0;\r
-       virtual void                                                            leading_producer(const spl::shared_ptr<frame_producer>&) {}  \r
-};\r
-\r
-class frame_producer_base : public frame_producer\r
-{\r
-public:\r
-       frame_producer_base();\r
-       virtual ~frame_producer_base(){}        \r
-\r
-       // Methods      \r
-\r
-       virtual boost::unique_future<std::wstring>      call(const std::wstring& params);\r
-       \r
-       // monitor::observable\r
-       \r
-       // Properties\r
-       \r
-       void                                            paused(bool value) override;    \r
-       uint32_t                                        nb_frames() const override;\r
-       uint32_t                                        frame_number() const override;\r
-       virtual class draw_frame        last_frame() override;\r
-\r
-private:\r
-       virtual class draw_frame        receive() override;\r
-       virtual class draw_frame        receive_impl() = 0;\r
-\r
-       struct impl;\r
-       friend struct impl;\r
-       std::shared_ptr<impl> impl_;\r
-};\r
-\r
-typedef std::function<spl::shared_ptr<core::frame_producer>(const spl::shared_ptr<class frame_factory>&, const video_format_desc& format_desc, const std::vector<std::wstring>&)> producer_factory_t;\r
-void register_producer_factory(const producer_factory_t& factory); // Not thread-safe.\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>&, const video_format_desc& format_desc, const std::vector<std::wstring>& params);\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>&, const video_format_desc& format_desc, const std::wstring& params);\r
-\r
-spl::shared_ptr<core::frame_producer> create_destroy_proxy(spl::shared_ptr<core::frame_producer> producer);\r
-               \r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "../monitor/monitor.h"
+#include "../video_format.h"
+
+#include <common/forward.h>
+#include <common/future_fwd.h>
+#include <common/memory.h>
+#include <common/enum_class.h>
+
+#include <cstdint>
+#include <limits>
+#include <functional>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <boost/property_tree/ptree_fwd.hpp>
+
+FORWARD1(caspar, class executor);
+
+namespace caspar { namespace core {
+       
+// Interface
+class frame_producer : public monitor::observable
+{
+       frame_producer(const frame_producer&);
+       frame_producer& operator=(const frame_producer&);
+public:
+
+       // Static Members
+       
+       static const spl::shared_ptr<frame_producer>& empty();
+
+       // Constructors
+
+       frame_producer(){}
+       virtual ~frame_producer(){}     
+
+       // Methods      
+
+       virtual class draw_frame                                        receive() = 0;
+       virtual boost::unique_future<std::wstring>      call(const std::wstring& params) = 0;
+       
+       // monitor::observable
+
+       virtual void subscribe(const monitor::observable::observer_ptr& o) = 0;
+       virtual void unsubscribe(const monitor::observable::observer_ptr& o) = 0;
+
+       // Properties
+       
+
+       virtual void                                                            paused(bool value) = 0;
+       virtual std::wstring                                            print() const = 0;
+       virtual std::wstring                                            name() const = 0;
+       virtual boost::property_tree::wptree            info() const = 0;
+       virtual uint32_t                                                        nb_frames() const = 0;
+       virtual uint32_t                                                        frame_number() const = 0;
+       virtual class draw_frame                                        last_frame() = 0;
+       virtual void                                                            leading_producer(const spl::shared_ptr<frame_producer>&) {}  
+};
+
+class frame_producer_base : public frame_producer
+{
+public:
+       frame_producer_base();
+       virtual ~frame_producer_base(){}        
+
+       // Methods      
+
+       virtual boost::unique_future<std::wstring>      call(const std::wstring& params);
+       
+       // monitor::observable
+       
+       // Properties
+       
+       void                                            paused(bool value) override;    
+       uint32_t                                        nb_frames() const override;
+       uint32_t                                        frame_number() const override;
+       virtual class draw_frame        last_frame() override;
+
+private:
+       virtual class draw_frame        receive() override;
+       virtual class draw_frame        receive_impl() = 0;
+
+       struct impl;
+       friend struct impl;
+       std::shared_ptr<impl> impl_;
+};
+
+typedef std::function<spl::shared_ptr<core::frame_producer>(const spl::shared_ptr<class frame_factory>&, const video_format_desc& format_desc, const std::vector<std::wstring>&)> producer_factory_t;
+void register_producer_factory(const producer_factory_t& factory); // Not thread-safe.
+
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>&, const video_format_desc& format_desc, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>&, const video_format_desc& format_desc, const std::wstring& params);
+
+spl::shared_ptr<core::frame_producer> create_destroy_proxy(spl::shared_ptr<core::frame_producer> producer);
+               
+}}
index 205aad1da009fb0f887ccfaa40c955dd0c1b82f4..c53e16900a4b98b01c0a474ff049f48e3f685a43 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "layer.h"\r
-\r
-#include "frame_producer.h"\r
-\r
-#include "../video_format.h"\r
-#include "../frame/draw_frame.h"\r
-#include "../frame/frame_transform.h"\r
-\r
-#include <boost/optional.hpp>\r
-#include <boost/thread/future.hpp>\r
-\r
-namespace caspar { namespace core {\r
-\r
-struct layer::impl\r
-{                              \r
-       monitor::basic_subject                          event_subject_;\r
-       monitor::basic_subject                          foreground_event_subject_;\r
-       monitor::basic_subject                          background_event_subject_;\r
-       spl::shared_ptr<frame_producer>         foreground_;\r
-       spl::shared_ptr<frame_producer>         background_;\r
-       boost::optional<int32_t>                        auto_play_delta_;\r
-\r
-public:\r
-       impl(int index) \r
-               : event_subject_(monitor::path("layer") % index)\r
-               , foreground_event_subject_("")\r
-               , background_event_subject_("background")\r
-               , foreground_(frame_producer::empty())\r
-               , background_(frame_producer::empty())\r
-       {\r
-               foreground_event_subject_.subscribe(event_subject_);\r
-               background_event_subject_.subscribe(event_subject_);\r
-       }\r
-\r
-       void pause()\r
-       {\r
-               foreground_->paused(true);\r
-       }\r
-       \r
-       void load(spl::shared_ptr<frame_producer> producer, bool preview, const boost::optional<int32_t>& auto_play_delta)\r
-       {               \r
-               background_->unsubscribe(background_event_subject_);\r
-               background_ = std::move(producer);\r
-               background_->subscribe(background_event_subject_);\r
-\r
-               auto_play_delta_ = auto_play_delta;\r
-\r
-               if(preview)\r
-               {\r
-                       play();\r
-                       foreground_->paused(true);\r
-               }\r
-\r
-               if(auto_play_delta_ && foreground_ == frame_producer::empty())\r
-                       play();\r
-       }\r
-       \r
-       void play()\r
-       {                       \r
-               if(background_ != frame_producer::empty())\r
-               {\r
-                       background_->leading_producer(foreground_);\r
-\r
-                       background_->unsubscribe(background_event_subject_);\r
-                       foreground_->unsubscribe(foreground_event_subject_);\r
-\r
-                       foreground_ = std::move(background_);\r
-                       background_ = std::move(frame_producer::empty());\r
-                       \r
-                       foreground_->subscribe(foreground_event_subject_);\r
-\r
-                       auto_play_delta_.reset();\r
-               }\r
-\r
-               foreground_->paused(false);\r
-       }\r
-       \r
-       void stop()\r
-       {\r
-               foreground_->unsubscribe(foreground_event_subject_);\r
-\r
-               foreground_ = std::move(frame_producer::empty());\r
-\r
-               auto_play_delta_.reset();\r
-       }\r
-               \r
-       draw_frame receive(const video_format_desc& format_desc)\r
-       {               \r
-               try\r
-               {               \r
-                       auto frame = foreground_->receive();\r
-                       \r
-                       if(frame == core::draw_frame::late())\r
-                               return foreground_->last_frame();\r
-                                               \r
-                       if(auto_play_delta_)\r
-                       {\r
-                               auto frames_left = static_cast<int64_t>(foreground_->nb_frames()) - foreground_->frame_number() - static_cast<int64_t>(*auto_play_delta_);\r
-                               if(frames_left < 1)\r
-                               {\r
-                                       play();\r
-                                       return receive(format_desc);\r
-                               }\r
-                       }\r
-\r
-                       event_subject_  << monitor::event("time")       % monitor::duration(foreground_->frame_number()/format_desc.fps)\r
-                                                                                                               % monitor::duration(static_cast<int64_t>(foreground_->nb_frames()) - static_cast<int64_t>(auto_play_delta_ ? *auto_play_delta_ : 0)/format_desc.fps)\r
-                                                       << monitor::event("frame")      % static_cast<int64_t>(foreground_->frame_number())\r
-                                                                                                               % static_cast<int64_t>((static_cast<int64_t>(foreground_->nb_frames()) - static_cast<int64_t>(auto_play_delta_ ? *auto_play_delta_ : 0)));\r
-\r
-                       foreground_event_subject_ << monitor::event("type") % foreground_->name();\r
-                       background_event_subject_ << monitor::event("type") % background_->name();\r
-                               \r
-                       return frame;\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       stop();\r
-                       return core::draw_frame::empty();\r
-               }\r
-       }\r
-       \r
-       boost::property_tree::wptree info() const\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"auto_delta", (auto_play_delta_ ? boost::lexical_cast<std::wstring>(*auto_play_delta_) : L"null"));\r
-               info.add(L"frame-number", foreground_->frame_number());\r
-\r
-               auto nb_frames = foreground_->nb_frames();\r
-\r
-               info.add(L"nb_frames",   nb_frames == std::numeric_limits<int64_t>::max() ? -1 : nb_frames);\r
-               info.add(L"frames-left", nb_frames == std::numeric_limits<int64_t>::max() ? -1 : (foreground_->nb_frames() - foreground_->frame_number() - (auto_play_delta_ ? *auto_play_delta_ : 0)));\r
-               info.add_child(L"producer", foreground_->info());\r
-               info.add_child(L"background.producer", background_->info());\r
-               return info;\r
-       }\r
-};\r
-\r
-layer::layer(int index) : impl_(new impl(index)){}\r
-layer::layer(layer&& other) : impl_(std::move(other.impl_)){}\r
-layer& layer::operator=(layer&& other)\r
-{\r
-       other.swap(*this);\r
-       return *this;\r
-}\r
-void layer::swap(layer& other)\r
-{      \r
-       impl_.swap(other.impl_);\r
-}\r
-void layer::load(spl::shared_ptr<frame_producer> frame_producer, bool preview, const boost::optional<int32_t>& auto_play_delta){return impl_->load(std::move(frame_producer), preview, auto_play_delta);}      \r
-void layer::play(){impl_->play();}\r
-void layer::pause(){impl_->pause();}\r
-void layer::stop(){impl_->stop();}\r
-draw_frame layer::receive(const video_format_desc& format_desc) {return impl_->receive(format_desc);}\r
-spl::shared_ptr<frame_producer> layer::foreground() const { return impl_->foreground_;}\r
-spl::shared_ptr<frame_producer> layer::background() const { return impl_->background_;}\r
-boost::property_tree::wptree layer::info() const{return impl_->info();}\r
-void layer::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.subscribe(o);}\r
-void layer::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "layer.h"
+
+#include "frame_producer.h"
+
+#include "../video_format.h"
+#include "../frame/draw_frame.h"
+#include "../frame/frame_transform.h"
+
+#include <boost/optional.hpp>
+#include <boost/thread/future.hpp>
+
+namespace caspar { namespace core {
+
+struct layer::impl
+{                              
+       monitor::basic_subject                          event_subject_;
+       monitor::basic_subject                          foreground_event_subject_;
+       monitor::basic_subject                          background_event_subject_;
+       spl::shared_ptr<frame_producer>         foreground_;
+       spl::shared_ptr<frame_producer>         background_;
+       boost::optional<int32_t>                        auto_play_delta_;
+
+public:
+       impl(int index) 
+               : event_subject_(monitor::path("layer") % index)
+               , foreground_event_subject_("")
+               , background_event_subject_("background")
+               , foreground_(frame_producer::empty())
+               , background_(frame_producer::empty())
+       {
+               foreground_event_subject_.subscribe(event_subject_);
+               background_event_subject_.subscribe(event_subject_);
+       }
+
+       void pause()
+       {
+               foreground_->paused(true);
+       }
+       
+       void load(spl::shared_ptr<frame_producer> producer, bool preview, const boost::optional<int32_t>& auto_play_delta)
+       {               
+               background_->unsubscribe(background_event_subject_);
+               background_ = std::move(producer);
+               background_->subscribe(background_event_subject_);
+
+               auto_play_delta_ = auto_play_delta;
+
+               if(preview)
+               {
+                       play();
+                       foreground_->paused(true);
+               }
+
+               if(auto_play_delta_ && foreground_ == frame_producer::empty())
+                       play();
+       }
+       
+       void play()
+       {                       
+               if(background_ != frame_producer::empty())
+               {
+                       background_->leading_producer(foreground_);
+
+                       background_->unsubscribe(background_event_subject_);
+                       foreground_->unsubscribe(foreground_event_subject_);
+
+                       foreground_ = std::move(background_);
+                       background_ = std::move(frame_producer::empty());
+                       
+                       foreground_->subscribe(foreground_event_subject_);
+
+                       auto_play_delta_.reset();
+               }
+
+               foreground_->paused(false);
+       }
+       
+       void stop()
+       {
+               foreground_->unsubscribe(foreground_event_subject_);
+
+               foreground_ = std::move(frame_producer::empty());
+
+               auto_play_delta_.reset();
+       }
+               
+       draw_frame receive(const video_format_desc& format_desc)
+       {               
+               try
+               {               
+                       auto frame = foreground_->receive();
+                       
+                       if(frame == core::draw_frame::late())
+                               return foreground_->last_frame();
+                                               
+                       if(auto_play_delta_)
+                       {
+                               auto frames_left = static_cast<int64_t>(foreground_->nb_frames()) - foreground_->frame_number() - static_cast<int64_t>(*auto_play_delta_);
+                               if(frames_left < 1)
+                               {
+                                       play();
+                                       return receive(format_desc);
+                               }
+                       }
+
+                       event_subject_  << monitor::event("time")       % monitor::duration(foreground_->frame_number()/format_desc.fps)
+                                                                                                               % monitor::duration(static_cast<int64_t>(foreground_->nb_frames()) - static_cast<int64_t>(auto_play_delta_ ? *auto_play_delta_ : 0)/format_desc.fps)
+                                                       << monitor::event("frame")      % static_cast<int64_t>(foreground_->frame_number())
+                                                                                                               % static_cast<int64_t>((static_cast<int64_t>(foreground_->nb_frames()) - static_cast<int64_t>(auto_play_delta_ ? *auto_play_delta_ : 0)));
+
+                       foreground_event_subject_ << monitor::event("type") % foreground_->name();
+                       background_event_subject_ << monitor::event("type") % background_->name();
+                               
+                       return frame;
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+                       stop();
+                       return core::draw_frame::empty();
+               }
+       }
+       
+       boost::property_tree::wptree info() const
+       {
+               boost::property_tree::wptree info;
+               info.add(L"auto_delta", (auto_play_delta_ ? boost::lexical_cast<std::wstring>(*auto_play_delta_) : L"null"));
+               info.add(L"frame-number", foreground_->frame_number());
+
+               auto nb_frames = foreground_->nb_frames();
+
+               info.add(L"nb_frames",   nb_frames == std::numeric_limits<int64_t>::max() ? -1 : nb_frames);
+               info.add(L"frames-left", nb_frames == std::numeric_limits<int64_t>::max() ? -1 : (foreground_->nb_frames() - foreground_->frame_number() - (auto_play_delta_ ? *auto_play_delta_ : 0)));
+               info.add_child(L"producer", foreground_->info());
+               info.add_child(L"background.producer", background_->info());
+               return info;
+       }
+};
+
+layer::layer(int index) : impl_(new impl(index)){}
+layer::layer(layer&& other) : impl_(std::move(other.impl_)){}
+layer& layer::operator=(layer&& other)
+{
+       other.swap(*this);
+       return *this;
+}
+void layer::swap(layer& other)
+{      
+       impl_.swap(other.impl_);
+}
+void layer::load(spl::shared_ptr<frame_producer> frame_producer, bool preview, const boost::optional<int32_t>& auto_play_delta){return impl_->load(std::move(frame_producer), preview, auto_play_delta);}      
+void layer::play(){impl_->play();}
+void layer::pause(){impl_->pause();}
+void layer::stop(){impl_->stop();}
+draw_frame layer::receive(const video_format_desc& format_desc) {return impl_->receive(format_desc);}
+spl::shared_ptr<frame_producer> layer::foreground() const { return impl_->foreground_;}
+spl::shared_ptr<frame_producer> layer::background() const { return impl_->background_;}
+boost::property_tree::wptree layer::info() const{return impl_->info();}
+void layer::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.subscribe(o);}
+void layer::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}
 }}
\ No newline at end of file
index d8adad7f93bb8c9f2659042f41caff5b8202116c..aa7cf5d4ff7eb6f858f4504ec4198ac95ba436a3 100644 (file)
@@ -1,82 +1,82 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "frame_producer.h"\r
-\r
-#include "../monitor/monitor.h"\r
-\r
-#include <common/forward.h>\r
-#include <common/future_fwd.h>\r
-#include <common/memory.h>\r
-\r
-#include <boost/property_tree/ptree_fwd.hpp>\r
-\r
-#include <string>\r
-\r
-FORWARD1(boost, template<typename T> class optional);\r
-\r
-namespace caspar { namespace core {\r
-       \r
-class layer sealed : public monitor::observable\r
-{\r
-       layer(const layer&);\r
-       layer& operator=(const layer&);\r
-public:\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       explicit layer(int index = -1); \r
-       layer(layer&& other); \r
-\r
-       // Methods\r
-\r
-       layer& operator=(layer&& other); \r
-\r
-       void swap(layer& other);  \r
-               \r
-       void load(spl::shared_ptr<class frame_producer> producer, bool preview, const boost::optional<int32_t>& auto_play_delta = nullptr); \r
-       void play(); \r
-       void pause(); \r
-       void stop(); \r
-       \r
-       class draw_frame receive(const struct video_format_desc& format_desc); \r
-       \r
-       // monitor::observable\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override;\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override;\r
-\r
-       // Properties\r
-               \r
-       spl::shared_ptr<class frame_producer>   foreground() const; \r
-       spl::shared_ptr<class frame_producer>   background() const; \r
-\r
-       boost::property_tree::wptree                    info() const;\r
-\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "frame_producer.h"
+
+#include "../monitor/monitor.h"
+
+#include <common/forward.h>
+#include <common/future_fwd.h>
+#include <common/memory.h>
+
+#include <boost/property_tree/ptree_fwd.hpp>
+
+#include <string>
+
+FORWARD1(boost, template<typename T> class optional);
+
+namespace caspar { namespace core {
+       
+class layer sealed : public monitor::observable
+{
+       layer(const layer&);
+       layer& operator=(const layer&);
+public:
+       // Static Members
+
+       // Constructors
+
+       explicit layer(int index = -1); 
+       layer(layer&& other); 
+
+       // Methods
+
+       layer& operator=(layer&& other); 
+
+       void swap(layer& other);  
+               
+       void load(spl::shared_ptr<class frame_producer> producer, bool preview, const boost::optional<int32_t>& auto_play_delta = nullptr); 
+       void play(); 
+       void pause(); 
+       void stop(); 
+       
+       class draw_frame receive(const struct video_format_desc& format_desc); 
+       
+       // monitor::observable
+
+       void subscribe(const monitor::observable::observer_ptr& o) override;
+       void unsubscribe(const monitor::observable::observer_ptr& o) override;
+
+       // Properties
+               
+       spl::shared_ptr<class frame_producer>   foreground() const; 
+       spl::shared_ptr<class frame_producer>   background() const; 
+
+       boost::property_tree::wptree                    info() const;
+
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index b18e8a7065705cfda5cfc109efae809ef98118ce..d624b340424e06dbbfbee8271b9a6ec957394ce0 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "separated_producer.h"\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/frame/draw_frame.h>\r
-#include <core/monitor/monitor.h>\r
-\r
-#include <tbb/parallel_invoke.h>\r
-\r
-namespace caspar { namespace core {    \r
-\r
-class separated_producer : public frame_producer_base\r
-{              \r
-       monitor::basic_subject                  event_subject_;\r
-       monitor::basic_subject                  key_event_subject_;\r
-\r
-       spl::shared_ptr<frame_producer> fill_producer_;\r
-       spl::shared_ptr<frame_producer> key_producer_;\r
-       draw_frame                                              fill_;\r
-       draw_frame                                              key_;\r
-                       \r
-public:\r
-       explicit separated_producer(const spl::shared_ptr<frame_producer>& fill, const spl::shared_ptr<frame_producer>& key) \r
-               : key_event_subject_("keyer")           \r
-               , fill_producer_(fill)\r
-               , key_producer_(key)\r
-               , fill_(core::draw_frame::late())\r
-               , key_(core::draw_frame::late())\r
-       {\r
-               CASPAR_LOG(info) << print() << L" Initialized";\r
-\r
-               key_event_subject_.subscribe(event_subject_);\r
-\r
-               key_producer_->subscribe(key_event_subject_);\r
-               fill_producer_->subscribe(event_subject_);\r
-       }\r
-\r
-       // frame_producer\r
-       \r
-       draw_frame receive_impl() override\r
-       {\r
-               tbb::parallel_invoke(\r
-               [&]\r
-               {\r
-                       if(fill_ == core::draw_frame::late())\r
-                               fill_ = fill_producer_->receive();\r
-               },\r
-               [&]\r
-               {\r
-                       if(key_ == core::draw_frame::late())\r
-                               key_ = key_producer_->receive();\r
-               });\r
-               \r
-               if(fill_ == core::draw_frame::late() || key_ == core::draw_frame::late()) // One of the producers is lagging, keep them in sync.\r
-                       return core::draw_frame::late();\r
-               \r
-               auto frame = draw_frame::mask(fill_, key_);\r
-\r
-               fill_ = draw_frame::late();\r
-               key_  = draw_frame::late();\r
-               \r
-               return frame;\r
-       }\r
-\r
-       draw_frame last_frame()\r
-       {\r
-               return draw_frame::mask(fill_producer_->last_frame(), key_producer_->last_frame());\r
-       }\r
-                               \r
-       uint32_t nb_frames() const override\r
-       {\r
-               return std::min(fill_producer_->nb_frames(), key_producer_->nb_frames());\r
-       }\r
-\r
-       std::wstring print() const override\r
-       {\r
-               return L"separated[fill:" + fill_producer_->print() + L"|key[" + key_producer_->print() + L"]]";\r
-       }       \r
-\r
-       boost::unique_future<std::wstring> call(const std::wstring& str) override\r
-       {\r
-               key_producer_->call(str);\r
-               return fill_producer_->call(str);\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"separated";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               return fill_producer_->info();;\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override                                                                                                                     \r
-       {\r
-               return event_subject_.subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override           \r
-       {\r
-               return event_subject_.unsubscribe(o);\r
-       }\r
-};\r
-\r
-spl::shared_ptr<frame_producer> create_separated_producer(const spl::shared_ptr<frame_producer>& fill, const spl::shared_ptr<frame_producer>& key)\r
-{\r
-       return spl::make_shared<separated_producer>(fill, key);\r
-}\r
-\r
-}}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "separated_producer.h"
+
+#include <core/producer/frame_producer.h>
+#include <core/frame/draw_frame.h>
+#include <core/monitor/monitor.h>
+
+#include <tbb/parallel_invoke.h>
+
+namespace caspar { namespace core {    
+
+class separated_producer : public frame_producer_base
+{              
+       monitor::basic_subject                  event_subject_;
+       monitor::basic_subject                  key_event_subject_;
+
+       spl::shared_ptr<frame_producer> fill_producer_;
+       spl::shared_ptr<frame_producer> key_producer_;
+       draw_frame                                              fill_;
+       draw_frame                                              key_;
+                       
+public:
+       explicit separated_producer(const spl::shared_ptr<frame_producer>& fill, const spl::shared_ptr<frame_producer>& key) 
+               : key_event_subject_("keyer")           
+               , fill_producer_(fill)
+               , key_producer_(key)
+               , fill_(core::draw_frame::late())
+               , key_(core::draw_frame::late())
+       {
+               CASPAR_LOG(info) << print() << L" Initialized";
+
+               key_event_subject_.subscribe(event_subject_);
+
+               key_producer_->subscribe(key_event_subject_);
+               fill_producer_->subscribe(event_subject_);
+       }
+
+       // frame_producer
+       
+       draw_frame receive_impl() override
+       {
+               tbb::parallel_invoke(
+               [&]
+               {
+                       if(fill_ == core::draw_frame::late())
+                               fill_ = fill_producer_->receive();
+               },
+               [&]
+               {
+                       if(key_ == core::draw_frame::late())
+                               key_ = key_producer_->receive();
+               });
+               
+               if(fill_ == core::draw_frame::late() || key_ == core::draw_frame::late()) // One of the producers is lagging, keep them in sync.
+                       return core::draw_frame::late();
+               
+               auto frame = draw_frame::mask(fill_, key_);
+
+               fill_ = draw_frame::late();
+               key_  = draw_frame::late();
+               
+               return frame;
+       }
+
+       draw_frame last_frame()
+       {
+               return draw_frame::mask(fill_producer_->last_frame(), key_producer_->last_frame());
+       }
+                               
+       uint32_t nb_frames() const override
+       {
+               return std::min(fill_producer_->nb_frames(), key_producer_->nb_frames());
+       }
+
+       std::wstring print() const override
+       {
+               return L"separated[fill:" + fill_producer_->print() + L"|key[" + key_producer_->print() + L"]]";
+       }       
+
+       boost::unique_future<std::wstring> call(const std::wstring& str) override
+       {
+               key_producer_->call(str);
+               return fill_producer_->call(str);
+       }
+
+       std::wstring name() const override
+       {
+               return L"separated";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               return fill_producer_->info();;
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override                                                                                                                     
+       {
+               return event_subject_.subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override           
+       {
+               return event_subject_.unsubscribe(o);
+       }
+};
+
+spl::shared_ptr<frame_producer> create_separated_producer(const spl::shared_ptr<frame_producer>& fill, const spl::shared_ptr<frame_producer>& key)
+{
+       return spl::make_shared<separated_producer>(fill, key);
+}
+
+}}
+
index fb6658aa83fe32cfb63aded3282491c6ef127db2..5f7fec7ac7f8b9d5f7d3e569013964364e78ff55 100644 (file)
@@ -1,32 +1,32 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-spl::shared_ptr<class frame_producer> create_separated_producer(const spl::shared_ptr<class frame_producer>& fill, const spl::shared_ptr<class frame_producer>& key);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <string>
+
+namespace caspar { namespace core {
+       
+spl::shared_ptr<class frame_producer> create_separated_producer(const spl::shared_ptr<class frame_producer>& fill, const spl::shared_ptr<class frame_producer>& key);
+
 }}
\ No newline at end of file
index bfc83750b7a6be137b43441e0a6dd07af33ec6ec..694ac0cb8f80f9258c97114382c4837355e3589e 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../StdAfx.h"\r
-\r
-#include "stage.h"\r
-\r
-#include "layer.h"\r
-\r
-#include "../frame/draw_frame.h"\r
-#include "../frame/frame_factory.h"\r
-\r
-#include <common/executor.h>\r
-#include <common/future.h>\r
-#include <common/diagnostics/graph.h>\r
-\r
-#include <core/frame/frame_transform.h>\r
-\r
-#include <boost/foreach.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/range/algorithm_ext.hpp>\r
-\r
-#include <tbb/parallel_for_each.h>\r
-\r
-#include <functional>\r
-#include <map>\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-struct stage::impl : public std::enable_shared_from_this<impl>\r
-{                              \r
-       spl::shared_ptr<diagnostics::graph>                                                     graph_;\r
-       monitor::basic_subject                                                                          event_subject_;\r
-       reactive::basic_subject<std::map<int, class draw_frame>>        frames_subject_;\r
-       std::map<int, layer>                                                                            layers_;        \r
-       std::map<int, tweened_transform>                                                        tweens_;        \r
-       executor                                                                                                        executor_;\r
-public:\r
-       impl(spl::shared_ptr<diagnostics::graph> graph) \r
-               : graph_(std::move(graph))\r
-               , event_subject_("stage")\r
-               , executor_(L"stage")\r
-       {\r
-               graph_->set_color("produce-time", diagnostics::color(0.0f, 1.0f, 0.0f));\r
-       }\r
-               \r
-       std::map<int, draw_frame> operator()(const struct video_format_desc& format_desc)\r
-       {               \r
-               boost::timer frame_timer;\r
-\r
-               auto frames = executor_.invoke([=]() -> std::map<int, draw_frame>\r
-               {\r
-\r
-                       std::map<int, class draw_frame> frames;\r
-                       \r
-                       try\r
-                       {                       \r
-                               std::vector<int> indices;\r
-\r
-                               BOOST_FOREACH(auto& layer, layers_)     \r
-                               {\r
-                                       frames[layer.first] = draw_frame::empty();      \r
-                                       indices.push_back(layer.first);\r
-                               }                               \r
-\r
-                               // WORKAROUND: Compiler doesn't seem to like lambda.\r
-                               tbb::parallel_for_each(indices.begin(), indices.end(), std::bind(&stage::impl::draw, this, std::placeholders::_1, std::ref(format_desc), std::ref(frames)));\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               layers_.clear();\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }       \r
-                       \r
-\r
-                       return frames;\r
-               });\r
-               \r
-               frames_subject_ << frames;\r
-               \r
-               graph_->set_value("produce-time", frame_timer.elapsed()*format_desc.fps*0.5);\r
-               event_subject_ << monitor::event("profiler/time") % frame_timer.elapsed() % (1.0/format_desc.fps);\r
-\r
-               return frames;\r
-       }\r
-\r
-       void draw(int index, const video_format_desc& format_desc, std::map<int, draw_frame>& frames)\r
-       {\r
-               auto& layer             = layers_[index];\r
-               auto& tween             = tweens_[index];\r
-                               \r
-               auto frame  = layer.receive(format_desc);                                       \r
-               auto frame1 = frame;\r
-               frame1.transform() *= tween.fetch_and_tick(1);\r
-\r
-               if(format_desc.field_mode != core::field_mode::progressive)\r
-               {                               \r
-                       auto frame2 = frame;\r
-                       frame2.transform() *= tween.fetch_and_tick(1);\r
-                       frame1 = core::draw_frame::interlace(frame1, frame2, format_desc.field_mode);\r
-               }\r
-\r
-               frames[index] = frame1;\r
-       }\r
-\r
-       layer& get_layer(int index)\r
-       {\r
-               auto it = layers_.find(index);\r
-               if(it == std::end(layers_))\r
-               {\r
-                       it = layers_.insert(std::make_pair(index, layer(index))).first;\r
-                       it->second.subscribe(event_subject_);\r
-               }\r
-               return it->second;\r
-       }\r
-               \r
-       boost::unique_future<void> apply_transforms(const std::vector<std::tuple<int, stage::transform_func_t, unsigned int, tweener>>& transforms)\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       BOOST_FOREACH(auto& transform, transforms)\r
-                       {\r
-                               auto src = tweens_[std::get<0>(transform)].fetch();\r
-                               auto dst = std::get<1>(transform)(src);\r
-                               tweens_[std::get<0>(transform)] = tweened_transform(src, dst, std::get<2>(transform), std::get<3>(transform));\r
-                       }\r
-               }, task_priority::high_priority);\r
-       }\r
-                                               \r
-       boost::unique_future<void> apply_transform(int index, const stage::transform_func_t& transform, unsigned int mix_duration, const tweener& tween)\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       auto src = tweens_[index].fetch();\r
-                       auto dst = transform(src);\r
-                       tweens_[index] = tweened_transform(src, dst, mix_duration, tween);\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<void> clear_transforms(int index)\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       tweens_.erase(index);\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<void> clear_transforms()\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       tweens_.clear();\r
-               }, task_priority::high_priority);\r
-       }\r
-               \r
-       boost::unique_future<void> load(int index, const spl::shared_ptr<frame_producer>& producer, bool preview, const boost::optional<int32_t>& auto_play_delta)\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       get_layer(index).load(producer, preview, auto_play_delta);                      \r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<void> pause(int index)\r
-       {               \r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       layers_[index].pause();\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<void> play(int index)\r
-       {               \r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       layers_[index].play();\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<void> stop(int index)\r
-       {               \r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       layers_[index].stop();\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<void> clear(int index)\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       layers_.erase(index);\r
-               }, task_priority::high_priority);\r
-       }\r
-               \r
-       boost::unique_future<void> clear()\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       layers_.clear();\r
-               }, task_priority::high_priority);\r
-       }       \r
-               \r
-       boost::unique_future<void> swap_layers(stage& other)\r
-       {\r
-               auto other_impl = other.impl_;\r
-\r
-               if(other_impl.get() == this)\r
-                       return async(launch::deferred, []{});\r
-               \r
-               auto func = [=]\r
-               {\r
-                       auto layers                     = layers_ | boost::adaptors::map_values;\r
-                       auto other_layers       = other_impl->layers_ | boost::adaptors::map_values;\r
-\r
-                       BOOST_FOREACH(auto& layer, layers)\r
-                               layer.unsubscribe(event_subject_);\r
-                       \r
-                       BOOST_FOREACH(auto& layer, other_layers)\r
-                               layer.unsubscribe(event_subject_);\r
-                       \r
-                       std::swap(layers_, other_impl->layers_);\r
-                                               \r
-                       BOOST_FOREACH(auto& layer, layers)\r
-                               layer.subscribe(event_subject_);\r
-                       \r
-                       BOOST_FOREACH(auto& layer, other_layers)\r
-                               layer.subscribe(event_subject_);\r
-               };              \r
-\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       other_impl->executor_.invoke(func, task_priority::high_priority);\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<void> swap_layer(int index, int other_index)\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       std::swap(layers_[index], layers_[other_index]);\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<void> swap_layer(int index, int other_index, stage& other)\r
-       {\r
-               auto other_impl = other.impl_;\r
-\r
-               if(other_impl.get() == this)\r
-                       return swap_layer(index, other_index);\r
-               else\r
-               {\r
-                       auto func = [=]\r
-                       {\r
-                               auto& my_layer          = get_layer(index);\r
-                               auto& other_layer       = other_impl->get_layer(other_index);\r
-\r
-                               my_layer.unsubscribe(event_subject_);\r
-                               other_layer.unsubscribe(other_impl->event_subject_);\r
-\r
-                               std::swap(my_layer, other_layer);\r
-\r
-                               my_layer.subscribe(event_subject_);\r
-                               other_layer.subscribe(other_impl->event_subject_);\r
-                       };              \r
-\r
-                       return executor_.begin_invoke([=]\r
-                       {\r
-                               other_impl->executor_.invoke(func, task_priority::high_priority);\r
-                       }, task_priority::high_priority);\r
-               }\r
-       }\r
-               \r
-       boost::unique_future<spl::shared_ptr<frame_producer>> foreground(int index)\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       return layers_[index].foreground();\r
-               }, task_priority::high_priority);\r
-       }\r
-       \r
-       boost::unique_future<spl::shared_ptr<frame_producer>> background(int index)\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       return layers_[index].background();\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<boost::property_tree::wptree> info()\r
-       {\r
-               return executor_.begin_invoke([this]() -> boost::property_tree::wptree\r
-               {\r
-                       boost::property_tree::wptree info;\r
-                       BOOST_FOREACH(auto& layer, layers_)                     \r
-                               info.add_child(L"layers.layer", layer.second.info())\r
-                                       .add(L"index", layer.first);    \r
-                       return info;\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       boost::unique_future<boost::property_tree::wptree> info(int index)\r
-       {\r
-               return executor_.begin_invoke([=]\r
-               {\r
-                       return layers_[index].info();\r
-               }, task_priority::high_priority);\r
-       }               \r
-       \r
-       boost::unique_future<std::wstring> call(int index, const std::wstring& params)\r
-       {\r
-               return flatten(executor_.begin_invoke([=]\r
-               {\r
-                       return make_shared(layers_[index].foreground()->call(params));\r
-               }, task_priority::high_priority));\r
-       }\r
-};\r
-\r
-stage::stage(spl::shared_ptr<diagnostics::graph> graph) : impl_(new impl(std::move(graph))){}\r
-boost::unique_future<std::wstring> stage::call(int index, const std::wstring& params){return impl_->call(index, params);}\r
-boost::unique_future<void> stage::apply_transforms(const std::vector<stage::transform_tuple_t>& transforms){return impl_->apply_transforms(transforms);}\r
-boost::unique_future<void> stage::apply_transform(int index, const std::function<core::frame_transform(core::frame_transform)>& transform, unsigned int mix_duration, const tweener& tween){return impl_->apply_transform(index, transform, mix_duration, tween);}\r
-boost::unique_future<void> stage::clear_transforms(int index){return impl_->clear_transforms(index);}\r
-boost::unique_future<void> stage::clear_transforms(){return impl_->clear_transforms();}\r
-boost::unique_future<void> stage::load(int index, const spl::shared_ptr<frame_producer>& producer, bool preview, const boost::optional<int32_t>& auto_play_delta){return impl_->load(index, producer, preview, auto_play_delta);}\r
-boost::unique_future<void> stage::pause(int index){return impl_->pause(index);}\r
-boost::unique_future<void> stage::play(int index){return impl_->play(index);}\r
-boost::unique_future<void> stage::stop(int index){return impl_->stop(index);}\r
-boost::unique_future<void> stage::clear(int index){return impl_->clear(index);}\r
-boost::unique_future<void> stage::clear(){return impl_->clear();}\r
-boost::unique_future<void> stage::swap_layers(stage& other){return impl_->swap_layers(other);}\r
-boost::unique_future<void> stage::swap_layer(int index, int other_index){return impl_->swap_layer(index, other_index);}\r
-boost::unique_future<void> stage::swap_layer(int index, int other_index, stage& other){return impl_->swap_layer(index, other_index, other);}\r
-boost::unique_future<spl::shared_ptr<frame_producer>> stage::foreground(int index) {return impl_->foreground(index);}\r
-boost::unique_future<spl::shared_ptr<frame_producer>> stage::background(int index) {return impl_->background(index);}\r
-boost::unique_future<boost::property_tree::wptree> stage::info() const{return impl_->info();}\r
-boost::unique_future<boost::property_tree::wptree> stage::info(int index) const{return impl_->info(index);}\r
-std::map<int, class draw_frame> stage::operator()(const video_format_desc& format_desc){return (*impl_)(format_desc);}\r
-void stage::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.subscribe(o);}\r
-void stage::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}\r
-void stage::subscribe(const frame_observable::observer_ptr& o) {impl_->frames_subject_.subscribe(o);}\r
-void stage::unsubscribe(const frame_observable::observer_ptr& o) {impl_->frames_subject_.unsubscribe(o);}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../StdAfx.h"
+
+#include "stage.h"
+
+#include "layer.h"
+
+#include "../frame/draw_frame.h"
+#include "../frame/frame_factory.h"
+
+#include <common/executor.h>
+#include <common/future.h>
+#include <common/diagnostics/graph.h>
+
+#include <core/frame/frame_transform.h>
+
+#include <boost/foreach.hpp>
+#include <boost/timer.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/range/algorithm_ext.hpp>
+
+#include <tbb/parallel_for_each.h>
+
+#include <functional>
+#include <map>
+#include <vector>
+
+namespace caspar { namespace core {
+       
+struct stage::impl : public std::enable_shared_from_this<impl>
+{                              
+       spl::shared_ptr<diagnostics::graph>                                                     graph_;
+       monitor::basic_subject                                                                          event_subject_;
+       reactive::basic_subject<std::map<int, class draw_frame>>        frames_subject_;
+       std::map<int, layer>                                                                            layers_;        
+       std::map<int, tweened_transform>                                                        tweens_;        
+       executor                                                                                                        executor_;
+public:
+       impl(spl::shared_ptr<diagnostics::graph> graph) 
+               : graph_(std::move(graph))
+               , event_subject_("stage")
+               , executor_(L"stage")
+       {
+               graph_->set_color("produce-time", diagnostics::color(0.0f, 1.0f, 0.0f));
+       }
+               
+       std::map<int, draw_frame> operator()(const struct video_format_desc& format_desc)
+       {               
+               boost::timer frame_timer;
+
+               auto frames = executor_.invoke([=]() -> std::map<int, draw_frame>
+               {
+
+                       std::map<int, class draw_frame> frames;
+                       
+                       try
+                       {                       
+                               std::vector<int> indices;
+
+                               BOOST_FOREACH(auto& layer, layers_)     
+                               {
+                                       frames[layer.first] = draw_frame::empty();      
+                                       indices.push_back(layer.first);
+                               }                               
+
+                               // WORKAROUND: Compiler doesn't seem to like lambda.
+                               tbb::parallel_for_each(indices.begin(), indices.end(), std::bind(&stage::impl::draw, this, std::placeholders::_1, std::ref(format_desc), std::ref(frames)));
+                       }
+                       catch(...)
+                       {
+                               layers_.clear();
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }       
+                       
+
+                       return frames;
+               });
+               
+               frames_subject_ << frames;
+               
+               graph_->set_value("produce-time", frame_timer.elapsed()*format_desc.fps*0.5);
+               event_subject_ << monitor::event("profiler/time") % frame_timer.elapsed() % (1.0/format_desc.fps);
+
+               return frames;
+       }
+
+       void draw(int index, const video_format_desc& format_desc, std::map<int, draw_frame>& frames)
+       {
+               auto& layer             = layers_[index];
+               auto& tween             = tweens_[index];
+                               
+               auto frame  = layer.receive(format_desc);                                       
+               auto frame1 = frame;
+               frame1.transform() *= tween.fetch_and_tick(1);
+
+               if(format_desc.field_mode != core::field_mode::progressive)
+               {                               
+                       auto frame2 = frame;
+                       frame2.transform() *= tween.fetch_and_tick(1);
+                       frame1 = core::draw_frame::interlace(frame1, frame2, format_desc.field_mode);
+               }
+
+               frames[index] = frame1;
+       }
+
+       layer& get_layer(int index)
+       {
+               auto it = layers_.find(index);
+               if(it == std::end(layers_))
+               {
+                       it = layers_.insert(std::make_pair(index, layer(index))).first;
+                       it->second.subscribe(event_subject_);
+               }
+               return it->second;
+       }
+               
+       boost::unique_future<void> apply_transforms(const std::vector<std::tuple<int, stage::transform_func_t, unsigned int, tweener>>& transforms)
+       {
+               return executor_.begin_invoke([=]
+               {
+                       BOOST_FOREACH(auto& transform, transforms)
+                       {
+                               auto src = tweens_[std::get<0>(transform)].fetch();
+                               auto dst = std::get<1>(transform)(src);
+                               tweens_[std::get<0>(transform)] = tweened_transform(src, dst, std::get<2>(transform), std::get<3>(transform));
+                       }
+               }, task_priority::high_priority);
+       }
+                                               
+       boost::unique_future<void> apply_transform(int index, const stage::transform_func_t& transform, unsigned int mix_duration, const tweener& tween)
+       {
+               return executor_.begin_invoke([=]
+               {
+                       auto src = tweens_[index].fetch();
+                       auto dst = transform(src);
+                       tweens_[index] = tweened_transform(src, dst, mix_duration, tween);
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<void> clear_transforms(int index)
+       {
+               return executor_.begin_invoke([=]
+               {
+                       tweens_.erase(index);
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<void> clear_transforms()
+       {
+               return executor_.begin_invoke([=]
+               {
+                       tweens_.clear();
+               }, task_priority::high_priority);
+       }
+               
+       boost::unique_future<void> load(int index, const spl::shared_ptr<frame_producer>& producer, bool preview, const boost::optional<int32_t>& auto_play_delta)
+       {
+               return executor_.begin_invoke([=]
+               {
+                       get_layer(index).load(producer, preview, auto_play_delta);                      
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<void> pause(int index)
+       {               
+               return executor_.begin_invoke([=]
+               {
+                       layers_[index].pause();
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<void> play(int index)
+       {               
+               return executor_.begin_invoke([=]
+               {
+                       layers_[index].play();
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<void> stop(int index)
+       {               
+               return executor_.begin_invoke([=]
+               {
+                       layers_[index].stop();
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<void> clear(int index)
+       {
+               return executor_.begin_invoke([=]
+               {
+                       layers_.erase(index);
+               }, task_priority::high_priority);
+       }
+               
+       boost::unique_future<void> clear()
+       {
+               return executor_.begin_invoke([=]
+               {
+                       layers_.clear();
+               }, task_priority::high_priority);
+       }       
+               
+       boost::unique_future<void> swap_layers(stage& other)
+       {
+               auto other_impl = other.impl_;
+
+               if(other_impl.get() == this)
+                       return async(launch::deferred, []{});
+               
+               auto func = [=]
+               {
+                       auto layers                     = layers_ | boost::adaptors::map_values;
+                       auto other_layers       = other_impl->layers_ | boost::adaptors::map_values;
+
+                       BOOST_FOREACH(auto& layer, layers)
+                               layer.unsubscribe(event_subject_);
+                       
+                       BOOST_FOREACH(auto& layer, other_layers)
+                               layer.unsubscribe(event_subject_);
+                       
+                       std::swap(layers_, other_impl->layers_);
+                                               
+                       BOOST_FOREACH(auto& layer, layers)
+                               layer.subscribe(event_subject_);
+                       
+                       BOOST_FOREACH(auto& layer, other_layers)
+                               layer.subscribe(event_subject_);
+               };              
+
+               return executor_.begin_invoke([=]
+               {
+                       other_impl->executor_.invoke(func, task_priority::high_priority);
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<void> swap_layer(int index, int other_index)
+       {
+               return executor_.begin_invoke([=]
+               {
+                       std::swap(layers_[index], layers_[other_index]);
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<void> swap_layer(int index, int other_index, stage& other)
+       {
+               auto other_impl = other.impl_;
+
+               if(other_impl.get() == this)
+                       return swap_layer(index, other_index);
+               else
+               {
+                       auto func = [=]
+                       {
+                               auto& my_layer          = get_layer(index);
+                               auto& other_layer       = other_impl->get_layer(other_index);
+
+                               my_layer.unsubscribe(event_subject_);
+                               other_layer.unsubscribe(other_impl->event_subject_);
+
+                               std::swap(my_layer, other_layer);
+
+                               my_layer.subscribe(event_subject_);
+                               other_layer.subscribe(other_impl->event_subject_);
+                       };              
+
+                       return executor_.begin_invoke([=]
+                       {
+                               other_impl->executor_.invoke(func, task_priority::high_priority);
+                       }, task_priority::high_priority);
+               }
+       }
+               
+       boost::unique_future<spl::shared_ptr<frame_producer>> foreground(int index)
+       {
+               return executor_.begin_invoke([=]
+               {
+                       return layers_[index].foreground();
+               }, task_priority::high_priority);
+       }
+       
+       boost::unique_future<spl::shared_ptr<frame_producer>> background(int index)
+       {
+               return executor_.begin_invoke([=]
+               {
+                       return layers_[index].background();
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<boost::property_tree::wptree> info()
+       {
+               return executor_.begin_invoke([this]() -> boost::property_tree::wptree
+               {
+                       boost::property_tree::wptree info;
+                       BOOST_FOREACH(auto& layer, layers_)                     
+                               info.add_child(L"layers.layer", layer.second.info())
+                                       .add(L"index", layer.first);    
+                       return info;
+               }, task_priority::high_priority);
+       }
+
+       boost::unique_future<boost::property_tree::wptree> info(int index)
+       {
+               return executor_.begin_invoke([=]
+               {
+                       return layers_[index].info();
+               }, task_priority::high_priority);
+       }               
+       
+       boost::unique_future<std::wstring> call(int index, const std::wstring& params)
+       {
+               return flatten(executor_.begin_invoke([=]
+               {
+                       return make_shared(layers_[index].foreground()->call(params));
+               }, task_priority::high_priority));
+       }
+};
+
+stage::stage(spl::shared_ptr<diagnostics::graph> graph) : impl_(new impl(std::move(graph))){}
+boost::unique_future<std::wstring> stage::call(int index, const std::wstring& params){return impl_->call(index, params);}
+boost::unique_future<void> stage::apply_transforms(const std::vector<stage::transform_tuple_t>& transforms){return impl_->apply_transforms(transforms);}
+boost::unique_future<void> stage::apply_transform(int index, const std::function<core::frame_transform(core::frame_transform)>& transform, unsigned int mix_duration, const tweener& tween){return impl_->apply_transform(index, transform, mix_duration, tween);}
+boost::unique_future<void> stage::clear_transforms(int index){return impl_->clear_transforms(index);}
+boost::unique_future<void> stage::clear_transforms(){return impl_->clear_transforms();}
+boost::unique_future<void> stage::load(int index, const spl::shared_ptr<frame_producer>& producer, bool preview, const boost::optional<int32_t>& auto_play_delta){return impl_->load(index, producer, preview, auto_play_delta);}
+boost::unique_future<void> stage::pause(int index){return impl_->pause(index);}
+boost::unique_future<void> stage::play(int index){return impl_->play(index);}
+boost::unique_future<void> stage::stop(int index){return impl_->stop(index);}
+boost::unique_future<void> stage::clear(int index){return impl_->clear(index);}
+boost::unique_future<void> stage::clear(){return impl_->clear();}
+boost::unique_future<void> stage::swap_layers(stage& other){return impl_->swap_layers(other);}
+boost::unique_future<void> stage::swap_layer(int index, int other_index){return impl_->swap_layer(index, other_index);}
+boost::unique_future<void> stage::swap_layer(int index, int other_index, stage& other){return impl_->swap_layer(index, other_index, other);}
+boost::unique_future<spl::shared_ptr<frame_producer>> stage::foreground(int index) {return impl_->foreground(index);}
+boost::unique_future<spl::shared_ptr<frame_producer>> stage::background(int index) {return impl_->background(index);}
+boost::unique_future<boost::property_tree::wptree> stage::info() const{return impl_->info();}
+boost::unique_future<boost::property_tree::wptree> stage::info(int index) const{return impl_->info(index);}
+std::map<int, class draw_frame> stage::operator()(const video_format_desc& format_desc){return (*impl_)(format_desc);}
+void stage::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.subscribe(o);}
+void stage::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}
+void stage::subscribe(const frame_observable::observer_ptr& o) {impl_->frames_subject_.subscribe(o);}
+void stage::unsubscribe(const frame_observable::observer_ptr& o) {impl_->frames_subject_.unsubscribe(o);}
 }}
\ No newline at end of file
index 9a60b192cc1dee7e15f7da959a864bd67a0ed759..fb1f140ff9e92ca7e96f8028fa57441e6bd724a0 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "frame_producer.h"\r
-\r
-#include "../monitor/monitor.h"\r
-\r
-#include <common/forward.h>\r
-#include <common/future_fwd.h>\r
-#include <common/memory.h>\r
-#include <common/tweener.h>\r
-\r
-#include <boost/optional.hpp>\r
-#include <boost/property_tree/ptree_fwd.hpp>\r
-\r
-#include <functional>\r
-#include <map>\r
-#include <tuple>\r
-#include <vector>\r
-\r
-FORWARD2(caspar, diagnostics, class graph);\r
-\r
-namespace caspar { namespace core {\r
-\r
-typedef reactive::observable<std::map<int, class draw_frame>> frame_observable;\r
-       \r
-class stage sealed : public monitor::observable, public frame_observable\r
-{\r
-       stage(const stage&);\r
-       stage& operator=(const stage&);\r
-public:        \r
-\r
-       // Static Members\r
-       \r
-       typedef std::function<struct frame_transform(struct frame_transform)> transform_func_t;\r
-       typedef std::tuple<int, transform_func_t, unsigned int, tweener> transform_tuple_t;\r
-\r
-       // Constructors\r
-\r
-       explicit stage(spl::shared_ptr<diagnostics::graph> graph);\r
-       \r
-       // Methods\r
-\r
-       std::map<int, class draw_frame> operator()(const struct video_format_desc& format_desc);\r
-\r
-       boost::unique_future<void>                      apply_transforms(const std::vector<transform_tuple_t>& transforms);\r
-       boost::unique_future<void>                      apply_transform(int index, const transform_func_t& transform, unsigned int mix_duration = 0, const tweener& tween = L"linear");\r
-       boost::unique_future<void>                      clear_transforms(int index);\r
-       boost::unique_future<void>                      clear_transforms();                             \r
-       boost::unique_future<void>                      load(int index, const spl::shared_ptr<class frame_producer>& producer, bool preview = false, const boost::optional<int32_t>& auto_play_delta = nullptr);\r
-       boost::unique_future<void>                      pause(int index);\r
-       boost::unique_future<void>                      play(int index);\r
-       boost::unique_future<void>                      stop(int index);\r
-       boost::unique_future<std::wstring>      call(int index, const std::wstring& params);\r
-       boost::unique_future<void>                      clear(int index);\r
-       boost::unique_future<void>                      clear();        \r
-       boost::unique_future<void>                      swap_layers(stage& other);\r
-       boost::unique_future<void>                      swap_layer(int index, int other_index);\r
-       boost::unique_future<void>                      swap_layer(int index, int other_index, stage& other);   \r
-\r
-       // monitor::observable\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override;\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override;\r
-       \r
-       // frame_observable\r
-\r
-       void subscribe(const frame_observable::observer_ptr& o) override;\r
-       void unsubscribe(const frame_observable::observer_ptr& o) override;\r
-\r
-       // Properties\r
-\r
-       boost::unique_future<spl::shared_ptr<class frame_producer>>     foreground(int index);\r
-       boost::unique_future<spl::shared_ptr<class frame_producer>>     background(int index);\r
-\r
-       boost::unique_future<boost::property_tree::wptree>                      info() const;\r
-       boost::unique_future<boost::property_tree::wptree>                      info(int index) const;\r
-\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "frame_producer.h"
+
+#include "../monitor/monitor.h"
+
+#include <common/forward.h>
+#include <common/future_fwd.h>
+#include <common/memory.h>
+#include <common/tweener.h>
+
+#include <boost/optional.hpp>
+#include <boost/property_tree/ptree_fwd.hpp>
+
+#include <functional>
+#include <map>
+#include <tuple>
+#include <vector>
+
+FORWARD2(caspar, diagnostics, class graph);
+
+namespace caspar { namespace core {
+
+typedef reactive::observable<std::map<int, class draw_frame>> frame_observable;
+       
+class stage sealed : public monitor::observable, public frame_observable
+{
+       stage(const stage&);
+       stage& operator=(const stage&);
+public:        
+
+       // Static Members
+       
+       typedef std::function<struct frame_transform(struct frame_transform)> transform_func_t;
+       typedef std::tuple<int, transform_func_t, unsigned int, tweener> transform_tuple_t;
+
+       // Constructors
+
+       explicit stage(spl::shared_ptr<diagnostics::graph> graph);
+       
+       // Methods
+
+       std::map<int, class draw_frame> operator()(const struct video_format_desc& format_desc);
+
+       boost::unique_future<void>                      apply_transforms(const std::vector<transform_tuple_t>& transforms);
+       boost::unique_future<void>                      apply_transform(int index, const transform_func_t& transform, unsigned int mix_duration = 0, const tweener& tween = L"linear");
+       boost::unique_future<void>                      clear_transforms(int index);
+       boost::unique_future<void>                      clear_transforms();                             
+       boost::unique_future<void>                      load(int index, const spl::shared_ptr<class frame_producer>& producer, bool preview = false, const boost::optional<int32_t>& auto_play_delta = nullptr);
+       boost::unique_future<void>                      pause(int index);
+       boost::unique_future<void>                      play(int index);
+       boost::unique_future<void>                      stop(int index);
+       boost::unique_future<std::wstring>      call(int index, const std::wstring& params);
+       boost::unique_future<void>                      clear(int index);
+       boost::unique_future<void>                      clear();        
+       boost::unique_future<void>                      swap_layers(stage& other);
+       boost::unique_future<void>                      swap_layer(int index, int other_index);
+       boost::unique_future<void>                      swap_layer(int index, int other_index, stage& other);   
+
+       // monitor::observable
+
+       void subscribe(const monitor::observable::observer_ptr& o) override;
+       void unsubscribe(const monitor::observable::observer_ptr& o) override;
+       
+       // frame_observable
+
+       void subscribe(const frame_observable::observer_ptr& o) override;
+       void unsubscribe(const frame_observable::observer_ptr& o) override;
+
+       // Properties
+
+       boost::unique_future<spl::shared_ptr<class frame_producer>>     foreground(int index);
+       boost::unique_future<spl::shared_ptr<class frame_producer>>     background(int index);
+
+       boost::unique_future<boost::property_tree::wptree>                      info() const;
+       boost::unique_future<boost::property_tree::wptree>                      info(int index) const;
+
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index a32210e29babc1d41f3529f9c6d57ff7adf65934..aed74fd4ce52869c2e00ad87b842ee000a5cd664 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "transition_producer.h"\r
-\r
-#include "../frame_producer.h"\r
-#include "../../frame/draw_frame.h"\r
-#include "../../frame/frame_transform.h"\r
-#include "../../monitor/monitor.h"\r
-\r
-#include <tbb/parallel_invoke.h>\r
-\r
-namespace caspar { namespace core {    \r
-\r
-class transition_producer : public frame_producer_base\r
-{      \r
-       monitor::basic_subject                          event_subject_;\r
-       const field_mode                                        mode_;\r
-       int                                                                     current_frame_;\r
-       \r
-       const transition_info                           info_;\r
-               \r
-       spl::shared_ptr<frame_producer>         dest_producer_;\r
-       spl::shared_ptr<frame_producer>         source_producer_;\r
-\r
-       bool                                                            paused_;\r
-               \r
-public:\r
-       explicit transition_producer(const field_mode& mode, const spl::shared_ptr<frame_producer>& dest, const transition_info& info) \r
-               : mode_(mode)\r
-               , current_frame_(0)\r
-               , info_(info)\r
-               , dest_producer_(dest)\r
-               , source_producer_(frame_producer::empty())\r
-               , paused_(false)\r
-       {\r
-               dest->subscribe(event_subject_);\r
-\r
-               CASPAR_LOG(info) << print() << L" Initialized";\r
-       }\r
-       \r
-       // frame_producer\r
-               \r
-       void leading_producer(const spl::shared_ptr<frame_producer>& producer) override\r
-       {\r
-               source_producer_ = producer;\r
-       }\r
-\r
-       draw_frame receive_impl() override\r
-       {\r
-               if(current_frame_ >= info_.duration)\r
-               {\r
-                       source_producer_ = core::frame_producer::empty();\r
-                       return dest_producer_->receive();               \r
-               }\r
-\r
-               current_frame_ += 1;\r
-\r
-               auto dest = draw_frame::empty();\r
-               auto source = draw_frame::empty();\r
-\r
-               tbb::parallel_invoke(\r
-               [&]\r
-               {\r
-                       dest = dest_producer_->receive();\r
-                       if(dest == core::draw_frame::late())\r
-                               dest = dest_producer_->last_frame();\r
-               },\r
-               [&]\r
-               {\r
-                       source = source_producer_->receive();\r
-                       if(source == core::draw_frame::late())\r
-                               source = source_producer_->last_frame();\r
-               });                     \r
-                                               \r
-               event_subject_  << monitor::event("transition/frame") % current_frame_ % info_.duration\r
-                                               << monitor::event("transition/type") % [&]() -> std::string\r
-                                                                                                                               {\r
-                                                                                                                                       switch(info_.type.value())\r
-                                                                                                                                       {\r
-                                                                                                                                       case transition_type::mix:              return "mix";\r
-                                                                                                                                       case transition_type::wipe:             return "wipe";\r
-                                                                                                                                       case transition_type::slide:    return "slide";\r
-                                                                                                                                       case transition_type::push:             return "push";\r
-                                                                                                                                       case transition_type::cut:              return "cut";\r
-                                                                                                                                       default:                                                return "n/a";\r
-                                                                                                                                       }\r
-                                                                                                                               }();\r
-\r
-               return compose(dest, source);\r
-       }\r
-\r
-       draw_frame last_frame() override\r
-       {\r
-               if(current_frame_ >= info_.duration)\r
-                       return dest_producer_->last_frame();\r
-\r
-               return frame_producer_base::last_frame();\r
-       }\r
-                       \r
-       uint32_t nb_frames() const override\r
-       {\r
-               return dest_producer_->nb_frames();\r
-       }\r
-\r
-       std::wstring print() const override\r
-       {\r
-               return L"transition[" + source_producer_->print() + L"=>" + dest_producer_->print() + L"]";\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"transition";\r
-       }\r
-       \r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               return dest_producer_->info();\r
-       }\r
-       \r
-       boost::unique_future<std::wstring> call(const std::wstring& str) override\r
-       {\r
-               return dest_producer_->call(str);\r
-       }\r
-\r
-       // transition_producer\r
-                                               \r
-       draw_frame compose(draw_frame dest_frame, draw_frame src_frame) const\r
-       {       \r
-               if(info_.type == transition_type::cut)          \r
-                       return src_frame;\r
-                                                                               \r
-               const double delta1 = info_.tweener(current_frame_*2-1, 0.0, 1.0, static_cast<double>(info_.duration*2));\r
-               const double delta2 = info_.tweener(current_frame_*2,   0.0, 1.0, static_cast<double>(info_.duration*2));  \r
-\r
-               const double dir = info_.direction == transition_direction::from_left ? 1.0 : -1.0;             \r
-               \r
-               // For interlaced transitions. Seperate fields into seperate frames which are transitioned accordingly.\r
-               \r
-               src_frame.transform().audio_transform.volume = 1.0-delta2;\r
-               auto s_frame1 = src_frame;\r
-               auto s_frame2 = src_frame;\r
-               \r
-               dest_frame.transform().audio_transform.volume = delta2;\r
-               auto d_frame1 = dest_frame;\r
-               auto d_frame2 = dest_frame;\r
-               \r
-               if(info_.type == transition_type::mix)\r
-               {\r
-                       d_frame1.transform().image_transform.opacity = delta1;  \r
-                       d_frame1.transform().image_transform.is_mix = true;\r
-                       d_frame2.transform().image_transform.opacity = delta2;\r
-                       d_frame2.transform().image_transform.is_mix = true;\r
-\r
-                       s_frame1.transform().image_transform.opacity = 1.0-delta1;      \r
-                       s_frame1.transform().image_transform.is_mix = true;\r
-                       s_frame2.transform().image_transform.opacity = 1.0-delta2;      \r
-                       s_frame2.transform().image_transform.is_mix = true;\r
-               }\r
-               if(info_.type == transition_type::slide)\r
-               {\r
-                       d_frame1.transform().image_transform.fill_translation[0] = (-1.0+delta1)*dir;   \r
-                       d_frame2.transform().image_transform.fill_translation[0] = (-1.0+delta2)*dir;           \r
-               }\r
-               else if(info_.type == transition_type::push)\r
-               {\r
-                       d_frame1.transform().image_transform.fill_translation[0] = (-1.0+delta1)*dir;\r
-                       d_frame2.transform().image_transform.fill_translation[0] = (-1.0+delta2)*dir;\r
-\r
-                       s_frame1.transform().image_transform.fill_translation[0] = (0.0+delta1)*dir;    \r
-                       s_frame2.transform().image_transform.fill_translation[0] = (0.0+delta2)*dir;            \r
-               }\r
-               else if(info_.type == transition_type::wipe)            \r
-               {\r
-                       d_frame1.transform().image_transform.clip_scale[0] = delta1;    \r
-                       d_frame2.transform().image_transform.clip_scale[0] = delta2;                    \r
-               }\r
-                               \r
-               const auto s_frame = s_frame1.transform() == s_frame2.transform() ? s_frame2 : draw_frame::interlace(s_frame1, s_frame2, mode_);\r
-               const auto d_frame = d_frame1.transform() == d_frame2.transform() ? d_frame2 : draw_frame::interlace(d_frame1, d_frame2, mode_);\r
-               \r
-               return draw_frame::over(s_frame, d_frame);\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override                                                                                                                     \r
-       {\r
-               event_subject_.subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override           \r
-       {\r
-               event_subject_.unsubscribe(o);\r
-       }\r
-};\r
-\r
-spl::shared_ptr<frame_producer> create_transition_producer(const field_mode& mode, const spl::shared_ptr<frame_producer>& destination, const transition_info& info)\r
-{\r
-       return spl::make_shared<transition_producer>(mode, destination, info);\r
-}\r
-\r
-}}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "transition_producer.h"
+
+#include "../frame_producer.h"
+#include "../../frame/draw_frame.h"
+#include "../../frame/frame_transform.h"
+#include "../../monitor/monitor.h"
+
+#include <tbb/parallel_invoke.h>
+
+namespace caspar { namespace core {    
+
+class transition_producer : public frame_producer_base
+{      
+       monitor::basic_subject                          event_subject_;
+       const field_mode                                        mode_;
+       int                                                                     current_frame_;
+       
+       const transition_info                           info_;
+               
+       spl::shared_ptr<frame_producer>         dest_producer_;
+       spl::shared_ptr<frame_producer>         source_producer_;
+
+       bool                                                            paused_;
+               
+public:
+       explicit transition_producer(const field_mode& mode, const spl::shared_ptr<frame_producer>& dest, const transition_info& info) 
+               : mode_(mode)
+               , current_frame_(0)
+               , info_(info)
+               , dest_producer_(dest)
+               , source_producer_(frame_producer::empty())
+               , paused_(false)
+       {
+               dest->subscribe(event_subject_);
+
+               CASPAR_LOG(info) << print() << L" Initialized";
+       }
+       
+       // frame_producer
+               
+       void leading_producer(const spl::shared_ptr<frame_producer>& producer) override
+       {
+               source_producer_ = producer;
+       }
+
+       draw_frame receive_impl() override
+       {
+               if(current_frame_ >= info_.duration)
+               {
+                       source_producer_ = core::frame_producer::empty();
+                       return dest_producer_->receive();               
+               }
+
+               current_frame_ += 1;
+
+               auto dest = draw_frame::empty();
+               auto source = draw_frame::empty();
+
+               tbb::parallel_invoke(
+               [&]
+               {
+                       dest = dest_producer_->receive();
+                       if(dest == core::draw_frame::late())
+                               dest = dest_producer_->last_frame();
+               },
+               [&]
+               {
+                       source = source_producer_->receive();
+                       if(source == core::draw_frame::late())
+                               source = source_producer_->last_frame();
+               });                     
+                                               
+               event_subject_  << monitor::event("transition/frame") % current_frame_ % info_.duration
+                                               << monitor::event("transition/type") % [&]() -> std::string
+                                                                                                                               {
+                                                                                                                                       switch(info_.type.value())
+                                                                                                                                       {
+                                                                                                                                       case transition_type::mix:              return "mix";
+                                                                                                                                       case transition_type::wipe:             return "wipe";
+                                                                                                                                       case transition_type::slide:    return "slide";
+                                                                                                                                       case transition_type::push:             return "push";
+                                                                                                                                       case transition_type::cut:              return "cut";
+                                                                                                                                       default:                                                return "n/a";
+                                                                                                                                       }
+                                                                                                                               }();
+
+               return compose(dest, source);
+       }
+
+       draw_frame last_frame() override
+       {
+               if(current_frame_ >= info_.duration)
+                       return dest_producer_->last_frame();
+
+               return frame_producer_base::last_frame();
+       }
+                       
+       uint32_t nb_frames() const override
+       {
+               return dest_producer_->nb_frames();
+       }
+
+       std::wstring print() const override
+       {
+               return L"transition[" + source_producer_->print() + L"=>" + dest_producer_->print() + L"]";
+       }
+
+       std::wstring name() const override
+       {
+               return L"transition";
+       }
+       
+       boost::property_tree::wptree info() const override
+       {
+               return dest_producer_->info();
+       }
+       
+       boost::unique_future<std::wstring> call(const std::wstring& str) override
+       {
+               return dest_producer_->call(str);
+       }
+
+       // transition_producer
+                                               
+       draw_frame compose(draw_frame dest_frame, draw_frame src_frame) const
+       {       
+               if(info_.type == transition_type::cut)          
+                       return src_frame;
+                                                                               
+               const double delta1 = info_.tweener(current_frame_*2-1, 0.0, 1.0, static_cast<double>(info_.duration*2));
+               const double delta2 = info_.tweener(current_frame_*2,   0.0, 1.0, static_cast<double>(info_.duration*2));  
+
+               const double dir = info_.direction == transition_direction::from_left ? 1.0 : -1.0;             
+               
+               // For interlaced transitions. Seperate fields into seperate frames which are transitioned accordingly.
+               
+               src_frame.transform().audio_transform.volume = 1.0-delta2;
+               auto s_frame1 = src_frame;
+               auto s_frame2 = src_frame;
+               
+               dest_frame.transform().audio_transform.volume = delta2;
+               auto d_frame1 = dest_frame;
+               auto d_frame2 = dest_frame;
+               
+               if(info_.type == transition_type::mix)
+               {
+                       d_frame1.transform().image_transform.opacity = delta1;  
+                       d_frame1.transform().image_transform.is_mix = true;
+                       d_frame2.transform().image_transform.opacity = delta2;
+                       d_frame2.transform().image_transform.is_mix = true;
+
+                       s_frame1.transform().image_transform.opacity = 1.0-delta1;      
+                       s_frame1.transform().image_transform.is_mix = true;
+                       s_frame2.transform().image_transform.opacity = 1.0-delta2;      
+                       s_frame2.transform().image_transform.is_mix = true;
+               }
+               if(info_.type == transition_type::slide)
+               {
+                       d_frame1.transform().image_transform.fill_translation[0] = (-1.0+delta1)*dir;   
+                       d_frame2.transform().image_transform.fill_translation[0] = (-1.0+delta2)*dir;           
+               }
+               else if(info_.type == transition_type::push)
+               {
+                       d_frame1.transform().image_transform.fill_translation[0] = (-1.0+delta1)*dir;
+                       d_frame2.transform().image_transform.fill_translation[0] = (-1.0+delta2)*dir;
+
+                       s_frame1.transform().image_transform.fill_translation[0] = (0.0+delta1)*dir;    
+                       s_frame2.transform().image_transform.fill_translation[0] = (0.0+delta2)*dir;            
+               }
+               else if(info_.type == transition_type::wipe)            
+               {
+                       d_frame1.transform().image_transform.clip_scale[0] = delta1;    
+                       d_frame2.transform().image_transform.clip_scale[0] = delta2;                    
+               }
+                               
+               const auto s_frame = s_frame1.transform() == s_frame2.transform() ? s_frame2 : draw_frame::interlace(s_frame1, s_frame2, mode_);
+               const auto d_frame = d_frame1.transform() == d_frame2.transform() ? d_frame2 : draw_frame::interlace(d_frame1, d_frame2, mode_);
+               
+               return draw_frame::over(s_frame, d_frame);
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override                                                                                                                     
+       {
+               event_subject_.subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override           
+       {
+               event_subject_.unsubscribe(o);
+       }
+};
+
+spl::shared_ptr<frame_producer> create_transition_producer(const field_mode& mode, const spl::shared_ptr<frame_producer>& destination, const transition_info& info)
+{
+       return spl::make_shared<transition_producer>(mode, destination, info);
+}
+
+}}
+
index c4e47affcae039e0b938be57a8c58348403fccf8..2992131a22ac9551370f3a646f2817e874ac1a20 100644 (file)
@@ -1,75 +1,75 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "../../video_format.h"\r
-\r
-#include <common/enum_class.h>\r
-#include <common/memory.h>\r
-#include <common/tweener.h>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-struct transition_type_def\r
-{\r
-       enum type\r
-       {\r
-               cut,    \r
-               mix,    \r
-               push,    \r
-               slide,  \r
-               wipe,\r
-               count\r
-       };\r
-};\r
-typedef enum_class<transition_type_def> transition_type;\r
-       \r
-struct transition_direction_def\r
-{\r
-       enum type\r
-       {\r
-               from_left,\r
-               from_right,\r
-               count\r
-       };\r
-};\r
-typedef enum_class<transition_direction_def> transition_direction;\r
-\r
-struct transition_info\r
-{\r
-       transition_info() \r
-               : type(transition_type::cut)\r
-               , duration(0)\r
-               , direction(transition_direction::from_left)\r
-               , tweener(L"linear"){}\r
-               \r
-       int                                             duration;\r
-       transition_direction    direction;\r
-       transition_type                 type;\r
-       tweener                                 tweener;\r
-};\r
-\r
-spl::shared_ptr<class frame_producer> create_transition_producer(const field_mode& mode, const spl::shared_ptr<class frame_producer>& destination, const transition_info& info);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "../../video_format.h"
+
+#include <common/enum_class.h>
+#include <common/memory.h>
+#include <common/tweener.h>
+
+#include <string>
+
+namespace caspar { namespace core {
+       
+struct transition_type_def
+{
+       enum type
+       {
+               cut,    
+               mix,    
+               push,    
+               slide,  
+               wipe,
+               count
+       };
+};
+typedef enum_class<transition_type_def> transition_type;
+       
+struct transition_direction_def
+{
+       enum type
+       {
+               from_left,
+               from_right,
+               count
+       };
+};
+typedef enum_class<transition_direction_def> transition_direction;
+
+struct transition_info
+{
+       transition_info() 
+               : type(transition_type::cut)
+               , duration(0)
+               , direction(transition_direction::from_left)
+               , tweener(L"linear"){}
+               
+       int                                             duration;
+       transition_direction    direction;
+       transition_type                 type;
+       tweener                                 tweener;
+};
+
+spl::shared_ptr<class frame_producer> create_transition_producer(const field_mode& mode, const spl::shared_ptr<class frame_producer>& destination, const transition_info& info);
+
 }}
\ No newline at end of file
index febf5da57f46e398ff893133fef5120c37d7d640..6614f48567d43cf327ac472fd5456ddd048134b9 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "StdAfx.h"\r
-\r
-#include "video_channel.h"\r
-\r
-#include "video_format.h"\r
-\r
-#include "producer/stage.h"\r
-#include "mixer/mixer.h"\r
-#include "consumer/output.h"\r
-#include "frame/frame.h"\r
-#include "frame/draw_frame.h"\r
-#include "frame/frame_factory.h"\r
-\r
-#include <common/diagnostics/graph.h>\r
-#include <common/env.h>\r
-#include <common/lock.h>\r
-#include <common/executor.h>\r
-\r
-#include <core/mixer/image/image_mixer.h>\r
-\r
-#include <tbb/spin_mutex.h>\r
-\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace core {\r
-\r
-struct video_channel::impl sealed\r
-{\r
-       monitor::basic_subject                                                  event_subject_;\r
-\r
-       const int                                                                               index_;\r
-\r
-       mutable tbb::spin_mutex                                                 format_desc_mutex_;\r
-       core::video_format_desc                                                 format_desc_;\r
-       \r
-       const spl::shared_ptr<diagnostics::graph>               graph_;\r
-\r
-       caspar::core::output                                                    output_;\r
-       spl::shared_ptr<image_mixer>                                    image_mixer_;\r
-       caspar::core::mixer                                                             mixer_;\r
-       caspar::core::stage                                                             stage_; \r
-\r
-       executor                                                                                executor_;\r
-public:\r
-       impl(int index, const core::video_format_desc& format_desc, std::unique_ptr<image_mixer> image_mixer)  \r
-               : event_subject_(monitor::path() % "channel" % index)\r
-               , index_(index)\r
-               , format_desc_(format_desc)\r
-               , output_(graph_, format_desc, index)\r
-               , image_mixer_(std::move(image_mixer))\r
-               , mixer_(graph_, image_mixer_)\r
-               , stage_(graph_)\r
-               , executor_(L"video_channel")\r
-       {\r
-               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   \r
-               graph_->set_text(print());\r
-               diagnostics::register_graph(graph_);\r
-               \r
-               output_.subscribe(event_subject_);\r
-               stage_.subscribe(event_subject_);\r
-\r
-               executor_.begin_invoke([=]{tick();});\r
-\r
-               CASPAR_LOG(info) << print() << " Successfully Initialized.";\r
-       }\r
-                                                       \r
-       core::video_format_desc video_format_desc() const\r
-       {\r
-               return lock(format_desc_mutex_, [&]\r
-               {\r
-                       return format_desc_;\r
-               });\r
-       }\r
-               \r
-       void video_format_desc(const core::video_format_desc& format_desc)\r
-       {\r
-               lock(format_desc_mutex_, [&]\r
-               {\r
-                       format_desc_ = format_desc;\r
-                       stage_.clear();\r
-               });\r
-       }\r
-\r
-       void tick()\r
-       {\r
-               try\r
-               {\r
-\r
-                       auto format_desc = video_format_desc();\r
-                       \r
-                       boost::timer frame_timer;\r
-\r
-                       // Produce\r
-                       \r
-                       auto stage_frames = stage_(format_desc);\r
-                       \r
-                       // Mix\r
-                       \r
-                       auto mixed_frame  = mixer_(std::move(stage_frames), format_desc);\r
-                       \r
-                       // Consume\r
-                                               \r
-                       output_(std::move(mixed_frame), format_desc);\r
-               \r
-                       graph_->set_value("tick-time", frame_timer.elapsed()*format_desc.fps*0.5);\r
-\r
-                       event_subject_  << monitor::event("profiler/time")      % frame_timer.elapsed() % (1.0/format_desc_.fps)\r
-                                                       << monitor::event("format")                     % format_desc.name;\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-\r
-               executor_.begin_invoke([=]{tick();});\r
-       }\r
-                       \r
-       std::wstring print() const\r
-       {\r
-               return L"video_channel[" + boost::lexical_cast<std::wstring>(index_) + L"|" +  video_format_desc().name + L"]";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const\r
-       {\r
-               boost::property_tree::wptree info;\r
-\r
-               auto stage_info  = stage_.info();\r
-               auto mixer_info  = mixer_.info();\r
-               auto output_info = output_.info();\r
-\r
-               info.add(L"video-mode", format_desc_.name);\r
-               info.add_child(L"stage", stage_info.get());\r
-               info.add_child(L"mixer", mixer_info.get());\r
-               info.add_child(L"output", output_info.get());\r
-   \r
-               return info;                       \r
-       }\r
-};\r
-\r
-video_channel::video_channel(int index, const core::video_format_desc& format_desc, std::unique_ptr<image_mixer> image_mixer) : impl_(new impl(index, format_desc, std::move(image_mixer))){}\r
-video_channel::~video_channel(){}\r
-const stage& video_channel::stage() const { return impl_->stage_;} \r
-stage& video_channel::stage() { return impl_->stage_;} \r
-const mixer& video_channel::mixer() const{ return impl_->mixer_;} \r
-mixer& video_channel::mixer() { return impl_->mixer_;} \r
-const output& video_channel::output() const { return impl_->output_;} \r
-output& video_channel::output() { return impl_->output_;} \r
-spl::shared_ptr<frame_factory> video_channel::frame_factory() { return impl_->image_mixer_;} \r
-core::video_format_desc video_channel::video_format_desc() const{return impl_->video_format_desc();}\r
-void core::video_channel::video_format_desc(const core::video_format_desc& format_desc){impl_->video_format_desc(format_desc);}\r
-boost::property_tree::wptree video_channel::info() const{return impl_->info();}                \r
-void video_channel::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.subscribe(o);}\r
-void video_channel::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "StdAfx.h"
+
+#include "video_channel.h"
+
+#include "video_format.h"
+
+#include "producer/stage.h"
+#include "mixer/mixer.h"
+#include "consumer/output.h"
+#include "frame/frame.h"
+#include "frame/draw_frame.h"
+#include "frame/frame_factory.h"
+
+#include <common/diagnostics/graph.h>
+#include <common/env.h>
+#include <common/lock.h>
+#include <common/executor.h>
+
+#include <core/mixer/image/image_mixer.h>
+
+#include <tbb/spin_mutex.h>
+
+#include <boost/property_tree/ptree.hpp>
+
+#include <string>
+
+namespace caspar { namespace core {
+
+struct video_channel::impl sealed
+{
+       monitor::basic_subject                                                  event_subject_;
+
+       const int                                                                               index_;
+
+       mutable tbb::spin_mutex                                                 format_desc_mutex_;
+       core::video_format_desc                                                 format_desc_;
+       
+       const spl::shared_ptr<diagnostics::graph>               graph_;
+
+       caspar::core::output                                                    output_;
+       spl::shared_ptr<image_mixer>                                    image_mixer_;
+       caspar::core::mixer                                                             mixer_;
+       caspar::core::stage                                                             stage_; 
+
+       executor                                                                                executor_;
+public:
+       impl(int index, const core::video_format_desc& format_desc, std::unique_ptr<image_mixer> image_mixer)  
+               : event_subject_(monitor::path() % "channel" % index)
+               , index_(index)
+               , format_desc_(format_desc)
+               , output_(graph_, format_desc, index)
+               , image_mixer_(std::move(image_mixer))
+               , mixer_(graph_, image_mixer_)
+               , stage_(graph_)
+               , executor_(L"video_channel")
+       {
+               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   
+               graph_->set_text(print());
+               diagnostics::register_graph(graph_);
+               
+               output_.subscribe(event_subject_);
+               stage_.subscribe(event_subject_);
+
+               executor_.begin_invoke([=]{tick();});
+
+               CASPAR_LOG(info) << print() << " Successfully Initialized.";
+       }
+                                                       
+       core::video_format_desc video_format_desc() const
+       {
+               return lock(format_desc_mutex_, [&]
+               {
+                       return format_desc_;
+               });
+       }
+               
+       void video_format_desc(const core::video_format_desc& format_desc)
+       {
+               lock(format_desc_mutex_, [&]
+               {
+                       format_desc_ = format_desc;
+                       stage_.clear();
+               });
+       }
+
+       void tick()
+       {
+               try
+               {
+
+                       auto format_desc = video_format_desc();
+                       
+                       boost::timer frame_timer;
+
+                       // Produce
+                       
+                       auto stage_frames = stage_(format_desc);
+                       
+                       // Mix
+                       
+                       auto mixed_frame  = mixer_(std::move(stage_frames), format_desc);
+                       
+                       // Consume
+                                               
+                       output_(std::move(mixed_frame), format_desc);
+               
+                       graph_->set_value("tick-time", frame_timer.elapsed()*format_desc.fps*0.5);
+
+                       event_subject_  << monitor::event("profiler/time")      % frame_timer.elapsed() % (1.0/format_desc_.fps)
+                                                       << monitor::event("format")                     % format_desc.name;
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+
+               executor_.begin_invoke([=]{tick();});
+       }
+                       
+       std::wstring print() const
+       {
+               return L"video_channel[" + boost::lexical_cast<std::wstring>(index_) + L"|" +  video_format_desc().name + L"]";
+       }
+
+       boost::property_tree::wptree info() const
+       {
+               boost::property_tree::wptree info;
+
+               auto stage_info  = stage_.info();
+               auto mixer_info  = mixer_.info();
+               auto output_info = output_.info();
+
+               info.add(L"video-mode", format_desc_.name);
+               info.add_child(L"stage", stage_info.get());
+               info.add_child(L"mixer", mixer_info.get());
+               info.add_child(L"output", output_info.get());
+   
+               return info;                       
+       }
+};
+
+video_channel::video_channel(int index, const core::video_format_desc& format_desc, std::unique_ptr<image_mixer> image_mixer) : impl_(new impl(index, format_desc, std::move(image_mixer))){}
+video_channel::~video_channel(){}
+const stage& video_channel::stage() const { return impl_->stage_;} 
+stage& video_channel::stage() { return impl_->stage_;} 
+const mixer& video_channel::mixer() const{ return impl_->mixer_;} 
+mixer& video_channel::mixer() { return impl_->mixer_;} 
+const output& video_channel::output() const { return impl_->output_;} 
+output& video_channel::output() { return impl_->output_;} 
+spl::shared_ptr<frame_factory> video_channel::frame_factory() { return impl_->image_mixer_;} 
+core::video_format_desc video_channel::video_format_desc() const{return impl_->video_format_desc();}
+void core::video_channel::video_format_desc(const core::video_format_desc& format_desc){impl_->video_format_desc(format_desc);}
+boost::property_tree::wptree video_channel::info() const{return impl_->info();}                
+void video_channel::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.subscribe(o);}
+void video_channel::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_.unsubscribe(o);}
+
 }}
\ No newline at end of file
index 32048a7f07ead999885e9f50e7e31b1f985c70e3..2390819a9b26ea3205134177fcfdf38b3c04a2f8 100644 (file)
@@ -1,82 +1,82 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-#include <common/reactive.h>\r
-#include <common/forward.h>\r
-\r
-#include "monitor/monitor.h"\r
-\r
-#include <boost/property_tree/ptree_fwd.hpp>\r
-\r
-FORWARD3(caspar, core, ogl, class accelerator);\r
-FORWARD2(caspar, core, class stage);\r
-FORWARD2(caspar, core, class mixer);\r
-FORWARD2(caspar, core, class output);\r
-FORWARD2(caspar, core, class image_mixer);\r
-FORWARD2(caspar, core, struct video_format_desc);\r
-FORWARD2(caspar, core, class frame_factory);\r
-\r
-namespace caspar { namespace core {\r
-       \r
-class video_channel sealed : public monitor::observable\r
-{\r
-       video_channel(const video_channel&);\r
-       video_channel& operator=(const video_channel&);\r
-public:\r
-\r
-       // Static Members\r
-\r
-       // Constructors\r
-\r
-       explicit video_channel(int index, const video_format_desc& format_desc, std::unique_ptr<image_mixer> image_mixer);\r
-       ~video_channel();\r
-\r
-       // Methods\r
-                       \r
-       // monitor::observable\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override;\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override;\r
-\r
-       // Properties\r
-\r
-       const core::stage&                                       stage() const;\r
-       core::stage&                                             stage();\r
-       const core::mixer&                                       mixer() const;\r
-       core::mixer&                                             mixer();\r
-       const core::output&                                      output() const;\r
-       core::output&                                            output();\r
-                                                                                \r
-       core::video_format_desc                          video_format_desc() const;\r
-       void                                                             video_format_desc(const core::video_format_desc& format_desc);\r
-       \r
-       spl::shared_ptr<core::frame_factory> frame_factory();\r
-\r
-       boost::property_tree::wptree             info() const;\r
-private:\r
-       struct impl;\r
-       spl::unique_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+#include <common/reactive.h>
+#include <common/forward.h>
+
+#include "monitor/monitor.h"
+
+#include <boost/property_tree/ptree_fwd.hpp>
+
+FORWARD3(caspar, core, ogl, class accelerator);
+FORWARD2(caspar, core, class stage);
+FORWARD2(caspar, core, class mixer);
+FORWARD2(caspar, core, class output);
+FORWARD2(caspar, core, class image_mixer);
+FORWARD2(caspar, core, struct video_format_desc);
+FORWARD2(caspar, core, class frame_factory);
+
+namespace caspar { namespace core {
+       
+class video_channel sealed : public monitor::observable
+{
+       video_channel(const video_channel&);
+       video_channel& operator=(const video_channel&);
+public:
+
+       // Static Members
+
+       // Constructors
+
+       explicit video_channel(int index, const video_format_desc& format_desc, std::unique_ptr<image_mixer> image_mixer);
+       ~video_channel();
+
+       // Methods
+                       
+       // monitor::observable
+
+       void subscribe(const monitor::observable::observer_ptr& o) override;
+       void unsubscribe(const monitor::observable::observer_ptr& o) override;
+
+       // Properties
+
+       const core::stage&                                       stage() const;
+       core::stage&                                             stage();
+       const core::mixer&                                       mixer() const;
+       core::mixer&                                             mixer();
+       const core::output&                                      output() const;
+       core::output&                                            output();
+                                                                                
+       core::video_format_desc                          video_format_desc() const;
+       void                                                             video_format_desc(const core::video_format_desc& format_desc);
+       
+       spl::shared_ptr<core::frame_factory> frame_factory();
+
+       boost::property_tree::wptree             info() const;
+private:
+       struct impl;
+       spl::unique_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index ec0c5a099092e5465a49e9ec64a79801af2b4662..146a574c2968a529a46344319c16ffa11bb2fb26 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "StdAfx.h"\r
-\r
-#include "video_format.h"\r
-\r
-#include <boost/algorithm/string.hpp>\r
-#include <boost/assign.hpp>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-const std::vector<video_format_desc> format_descs = boost::assign::list_of\r
-       (video_format_desc(video_format::pal,                    720,  576, 1024, 576,  field_mode::upper,                         25,     1, L"PAL",           boost::assign::list_of<int>(3840)))\r
-       (video_format_desc(video_format::ntsc,                   720,  486,  720, 540,  field_mode::lower,                      30000,  1001, L"NTSC",          boost::assign::list_of<int>(3204)(3202)(3204)(3202)(3204)))\r
-       (video_format_desc(video_format::x576p2500,              720,  576,  720, 576,  field_mode::progressive,           25,     1, L"576p2500",      boost::assign::list_of<int>(3840)                                               ))\r
-       (video_format_desc(video_format::x720p2500,             1280,  720, 1280, 720,  field_mode::progressive,           25,     1, L"720p2500",      boost::assign::list_of<int>(3840)                                               )) \r
-       (video_format_desc(video_format::x720p5000,             1280,  720, 1280, 720,  field_mode::progressive,           50,     1, L"720p5000",      boost::assign::list_of<int>(1920)                                               )) \r
-       (video_format_desc(video_format::x720p5994,             1280,  720, 1280, 720,  field_mode::progressive,        60000,  1001, L"720p5994",      boost::assign::list_of<int>(1602)(1601)(1602)(1601)(1602)))\r
-       (video_format_desc(video_format::x720p6000,             1280,  720, 1280, 720,  field_mode::progressive,           60,     1, L"720p6000",      boost::assign::list_of<int>(1600)                                               ))\r
-       (video_format_desc(video_format::x1080p2397,    1920, 1080, 1920, 1080, field_mode::progressive,        24000,  1001, L"1080p2398",     boost::assign::list_of<int>(4004)                                               ))\r
-       (video_format_desc(video_format::x1080p2400,    1920, 1080, 1920, 1080, field_mode::progressive,           24,     1, L"1080p2400",     boost::assign::list_of<int>(4000)                                               ))\r
-       (video_format_desc(video_format::x1080i5000,    1920, 1080, 1920, 1080, field_mode::upper,                         25,     1, L"1080i5000",     boost::assign::list_of<int>(3840)                                               ))\r
-       (video_format_desc(video_format::x1080i5994,    1920, 1080, 1920, 1080, field_mode::upper,                      30000,  1001, L"1080i5994",     boost::assign::list_of<int>(3204)(3202)(3204)(3202)(3204)))\r
-       (video_format_desc(video_format::x1080i6000,    1920, 1080, 1920, 1080, field_mode::upper,                         30,     1, L"1080i6000",     boost::assign::list_of<int>(3200)                                               ))\r
-       (video_format_desc(video_format::x1080p2500,    1920, 1080, 1920, 1080, field_mode::progressive,           25,     1, L"1080p2500",     boost::assign::list_of<int>(3840)                                               ))\r
-       (video_format_desc(video_format::x1080p2997,    1920, 1080, 1920, 1080, field_mode::progressive,        30000,  1001, L"1080p2997",     boost::assign::list_of<int>(3204)(3202)(3204)(3202)(3204)))\r
-       (video_format_desc(video_format::x1080p3000,    1920, 1080, 1920, 1080, field_mode::progressive,           30,     1, L"1080p3000",     boost::assign::list_of<int>(3200)                                               ))\r
-       (video_format_desc(video_format::x1080p5000,    1920, 1080, 1920, 1080, field_mode::progressive,           50,     1, L"1080p5000",     boost::assign::list_of<int>(1920)                                               ))\r
-       (video_format_desc(video_format::invalid,                  0,    0,    0,        0, field_mode::progressive,        1,     1, L"invalid",       boost::assign::list_of<int>(1)                                                  ));\r
-\r
-video_format_desc::video_format_desc(video_format format,\r
-                                       int width,\r
-                                       int height,\r
-                                       int square_width,\r
-                                       int square_height,\r
-                                       core::field_mode field_mode,\r
-                                       int time_scale,\r
-                                       int duration,\r
-                                       const std::wstring& name,\r
-                                       const std::vector<int>& audio_cadence)\r
-       : format(format)\r
-       , width(width)\r
-       , height(height)\r
-       , square_width(square_width)\r
-       , square_height(square_height)\r
-       , field_mode(field_mode)\r
-       , fps((double)time_scale/(double)duration)\r
-       , time_scale(time_scale)\r
-       , duration(duration)\r
-       , field_count(field_mode == field_mode::progressive ? 1 : 2)\r
-       , size(width*height*4)\r
-       , name(name)\r
-       , audio_sample_rate(48000)\r
-       , audio_channels(2)\r
-       , audio_cadence(audio_cadence)\r
-{\r
-}\r
-\r
-video_format_desc::video_format_desc(video_format format)\r
-       : format(video_format::invalid)\r
-       , field_mode(field_mode::empty)\r
-{\r
-       *this = format_descs.at(format.value());\r
-}\r
-\r
-video_format_desc::video_format_desc(const std::wstring& name)\r
-       : format(video_format::invalid)\r
-       , field_mode(field_mode::empty)\r
-{      \r
-       *this = video_format_desc(video_format::invalid);\r
-       for(auto it = std::begin(format_descs); it != std::end(format_descs)-1; ++it)\r
-       {\r
-               if(boost::iequals(it->name, name))\r
-               {\r
-                       *this = *it;\r
-                       break;\r
-               }\r
-       }\r
-}\r
-\r
-bool operator==(const video_format_desc& lhs, const video_format_desc& rhs)\r
-{                                                                                      \r
-       return lhs.format == rhs.format;\r
-}\r
-\r
-bool operator!=(const video_format_desc& lhs, const video_format_desc& rhs)\r
-{\r
-       return !(lhs == rhs);\r
-}\r
-\r
-std::wostream& operator<<(std::wostream& out, const video_format_desc& format_desc)\r
-{\r
-       out << format_desc.name.c_str();\r
-       return out;\r
-}\r
-\r
-\r
-}}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "StdAfx.h"
+
+#include "video_format.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/assign.hpp>
+
+namespace caspar { namespace core {
+       
+const std::vector<video_format_desc> format_descs = boost::assign::list_of
+       (video_format_desc(video_format::pal,                    720,  576, 1024, 576,  field_mode::upper,                         25,     1, L"PAL",           boost::assign::list_of<int>(3840)))
+       (video_format_desc(video_format::ntsc,                   720,  486,  720, 540,  field_mode::lower,                      30000,  1001, L"NTSC",          boost::assign::list_of<int>(3204)(3202)(3204)(3202)(3204)))
+       (video_format_desc(video_format::x576p2500,              720,  576,  720, 576,  field_mode::progressive,           25,     1, L"576p2500",      boost::assign::list_of<int>(3840)                                               ))
+       (video_format_desc(video_format::x720p2500,             1280,  720, 1280, 720,  field_mode::progressive,           25,     1, L"720p2500",      boost::assign::list_of<int>(3840)                                               )) 
+       (video_format_desc(video_format::x720p5000,             1280,  720, 1280, 720,  field_mode::progressive,           50,     1, L"720p5000",      boost::assign::list_of<int>(1920)                                               )) 
+       (video_format_desc(video_format::x720p5994,             1280,  720, 1280, 720,  field_mode::progressive,        60000,  1001, L"720p5994",      boost::assign::list_of<int>(1602)(1601)(1602)(1601)(1602)))
+       (video_format_desc(video_format::x720p6000,             1280,  720, 1280, 720,  field_mode::progressive,           60,     1, L"720p6000",      boost::assign::list_of<int>(1600)                                               ))
+       (video_format_desc(video_format::x1080p2397,    1920, 1080, 1920, 1080, field_mode::progressive,        24000,  1001, L"1080p2398",     boost::assign::list_of<int>(4004)                                               ))
+       (video_format_desc(video_format::x1080p2400,    1920, 1080, 1920, 1080, field_mode::progressive,           24,     1, L"1080p2400",     boost::assign::list_of<int>(4000)                                               ))
+       (video_format_desc(video_format::x1080i5000,    1920, 1080, 1920, 1080, field_mode::upper,                         25,     1, L"1080i5000",     boost::assign::list_of<int>(3840)                                               ))
+       (video_format_desc(video_format::x1080i5994,    1920, 1080, 1920, 1080, field_mode::upper,                      30000,  1001, L"1080i5994",     boost::assign::list_of<int>(3204)(3202)(3204)(3202)(3204)))
+       (video_format_desc(video_format::x1080i6000,    1920, 1080, 1920, 1080, field_mode::upper,                         30,     1, L"1080i6000",     boost::assign::list_of<int>(3200)                                               ))
+       (video_format_desc(video_format::x1080p2500,    1920, 1080, 1920, 1080, field_mode::progressive,           25,     1, L"1080p2500",     boost::assign::list_of<int>(3840)                                               ))
+       (video_format_desc(video_format::x1080p2997,    1920, 1080, 1920, 1080, field_mode::progressive,        30000,  1001, L"1080p2997",     boost::assign::list_of<int>(3204)(3202)(3204)(3202)(3204)))
+       (video_format_desc(video_format::x1080p3000,    1920, 1080, 1920, 1080, field_mode::progressive,           30,     1, L"1080p3000",     boost::assign::list_of<int>(3200)                                               ))
+       (video_format_desc(video_format::x1080p5000,    1920, 1080, 1920, 1080, field_mode::progressive,           50,     1, L"1080p5000",     boost::assign::list_of<int>(1920)                                               ))
+       (video_format_desc(video_format::invalid,                  0,    0,    0,        0, field_mode::progressive,        1,     1, L"invalid",       boost::assign::list_of<int>(1)                                                  ));
+
+video_format_desc::video_format_desc(video_format format,
+                                       int width,
+                                       int height,
+                                       int square_width,
+                                       int square_height,
+                                       core::field_mode field_mode,
+                                       int time_scale,
+                                       int duration,
+                                       const std::wstring& name,
+                                       const std::vector<int>& audio_cadence)
+       : format(format)
+       , width(width)
+       , height(height)
+       , square_width(square_width)
+       , square_height(square_height)
+       , field_mode(field_mode)
+       , fps((double)time_scale/(double)duration)
+       , time_scale(time_scale)
+       , duration(duration)
+       , field_count(field_mode == field_mode::progressive ? 1 : 2)
+       , size(width*height*4)
+       , name(name)
+       , audio_sample_rate(48000)
+       , audio_channels(2)
+       , audio_cadence(audio_cadence)
+{
+}
+
+video_format_desc::video_format_desc(video_format format)
+       : format(video_format::invalid)
+       , field_mode(field_mode::empty)
+{
+       *this = format_descs.at(format.value());
+}
+
+video_format_desc::video_format_desc(const std::wstring& name)
+       : format(video_format::invalid)
+       , field_mode(field_mode::empty)
+{      
+       *this = video_format_desc(video_format::invalid);
+       for(auto it = std::begin(format_descs); it != std::end(format_descs)-1; ++it)
+       {
+               if(boost::iequals(it->name, name))
+               {
+                       *this = *it;
+                       break;
+               }
+       }
+}
+
+bool operator==(const video_format_desc& lhs, const video_format_desc& rhs)
+{                                                                                      
+       return lhs.format == rhs.format;
+}
+
+bool operator!=(const video_format_desc& lhs, const video_format_desc& rhs)
+{
+       return !(lhs == rhs);
+}
+
+std::wostream& operator<<(std::wostream& out, const video_format_desc& format_desc)
+{
+       out << format_desc.name.c_str();
+       return out;
+}
+
+
+}}
+
index 6fa6f2025e220b35b72ecf3d5c4342723979774b..713ae6cc39a7058ebe54d95ad3481ddd32f46f36 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/enum_class.h>\r
-\r
-#include <vector>\r
-#include <string>\r
-#include <cstddef>\r
-\r
-namespace caspar { namespace core {\r
-       \r
-struct video_format_def \r
-{ \r
-       enum type \r
-       {\r
-               pal,            \r
-               ntsc,           \r
-               x576p2500,      \r
-               x720p2500,      \r
-               x720p5000,      \r
-               x720p5994,      \r
-               x720p6000,      \r
-               x1080p2397,     \r
-               x1080p2400,     \r
-               x1080i5000,     \r
-               x1080i5994,     \r
-               x1080i6000,     \r
-               x1080p2500,     \r
-               x1080p2997,     \r
-               x1080p3000,     \r
-               x1080p5000,     \r
-               invalid,\r
-               count\r
-       };\r
-};\r
-typedef enum_class<video_format_def> video_format;\r
-\r
-struct field_mode_def\r
-{\r
-       enum type \r
-       {\r
-               empty           = 0,\r
-               lower           = 1,\r
-               upper           = 2,\r
-               progressive = 3, // NOTE: progressive == lower | upper;\r
-       };\r
-       static_assert((lower | upper) == progressive, "");\r
-};\r
-typedef enum_class<field_mode_def> field_mode;\r
-\r
-struct video_format_desc sealed\r
-{\r
-       video_format            format;         \r
-\r
-       int                                     width;          \r
-       int                                     height;         \r
-       int                                     square_width;\r
-       int                                     square_height;\r
-       field_mode                      field_mode;     // progressive, interlaced upper field first, interlaced lower field first\r
-       double                          fps;            // actual framerate = duration/time_scale, e.g. i50 = 25 fps, p50 = 50 fps\r
-       int                                     time_scale;\r
-       int                                     duration;\r
-       int                                     field_count;\r
-       std::size_t                     size;           // frame size in bytes \r
-       std::wstring            name;           // name of output format\r
-\r
-       int                                     audio_sample_rate;\r
-       int                                     audio_channels;\r
-       std::vector<int>        audio_cadence;\r
-\r
-       video_format_desc(video_format format,\r
-                                         int width,\r
-                                         int height,\r
-                                         int square_width,\r
-                                         int square_height,\r
-                                         core::field_mode field_mode,\r
-                                         int time_scale,\r
-                                         int duration,\r
-                                         const std::wstring& name,\r
-                                         const std::vector<int>& audio_cadence);\r
-               \r
-       video_format_desc(video_format format = video_format::invalid);\r
-       video_format_desc(const std::wstring& name);\r
-};\r
-\r
-bool operator==(const video_format_desc& rhs, const video_format_desc& lhs);\r
-bool operator!=(const video_format_desc& rhs, const video_format_desc& lhs);\r
-\r
-std::wostream& operator<<(std::wostream& out, const video_format_desc& format_desc);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/enum_class.h>
+
+#include <vector>
+#include <string>
+#include <cstddef>
+
+namespace caspar { namespace core {
+       
+struct video_format_def 
+{ 
+       enum type 
+       {
+               pal,            
+               ntsc,           
+               x576p2500,      
+               x720p2500,      
+               x720p5000,      
+               x720p5994,      
+               x720p6000,      
+               x1080p2397,     
+               x1080p2400,     
+               x1080i5000,     
+               x1080i5994,     
+               x1080i6000,     
+               x1080p2500,     
+               x1080p2997,     
+               x1080p3000,     
+               x1080p5000,     
+               invalid,
+               count
+       };
+};
+typedef enum_class<video_format_def> video_format;
+
+struct field_mode_def
+{
+       enum type 
+       {
+               empty           = 0,
+               lower           = 1,
+               upper           = 2,
+               progressive = 3, // NOTE: progressive == lower | upper;
+       };
+       static_assert((lower | upper) == progressive, "");
+};
+typedef enum_class<field_mode_def> field_mode;
+
+struct video_format_desc sealed
+{
+       video_format            format;         
+
+       int                                     width;          
+       int                                     height;         
+       int                                     square_width;
+       int                                     square_height;
+       field_mode                      field_mode;     // progressive, interlaced upper field first, interlaced lower field first
+       double                          fps;            // actual framerate = duration/time_scale, e.g. i50 = 25 fps, p50 = 50 fps
+       int                                     time_scale;
+       int                                     duration;
+       int                                     field_count;
+       std::size_t                     size;           // frame size in bytes 
+       std::wstring            name;           // name of output format
+
+       int                                     audio_sample_rate;
+       int                                     audio_channels;
+       std::vector<int>        audio_cadence;
+
+       video_format_desc(video_format format,
+                                         int width,
+                                         int height,
+                                         int square_width,
+                                         int square_height,
+                                         core::field_mode field_mode,
+                                         int time_scale,
+                                         int duration,
+                                         const std::wstring& name,
+                                         const std::vector<int>& audio_cadence);
+               
+       video_format_desc(video_format format = video_format::invalid);
+       video_format_desc(const std::wstring& name);
+};
+
+bool operator==(const video_format_desc& rhs, const video_format_desc& lhs);
+bool operator!=(const video_format_desc& rhs, const video_format_desc& lhs);
+
+std::wostream& operator<<(std::wostream& out, const video_format_desc& format_desc);
+
 }}
\ No newline at end of file
index da91e016118ef6f52e1f362bf8271cd75cbaea9e..b06ae69c205c2ce0e27e2d37b1d85ea0fd4086e5 100644 (file)
@@ -1,29 +1,29 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
\r
-// stdafx.cpp : source file that includes just the standard includes\r
-//     dma.pch will be the pre-compiled header\r
-//     stdafx.obj will contain the pre-compiled type information\r
-\r
-#include "stdafx.h"\r
-\r
-// TODO: reference any additional headers you need in STDAFX.H\r
-// and not in this file\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+// stdafx.cpp : source file that includes just the standard includes
+//     dma.pch will be the pre-compiled header
+//     stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
index a75d470b4c0ea72bd61eee02477c1782c459d31c..90c47c4d4b6b72c0f1f32150ea8c9b7d2146b567 100644 (file)
@@ -1,49 +1,49 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#ifdef _DEBUG\r
-#include <crtdbg.h>\r
-#endif\r
-\r
-#define NOMINMAX\r
-\r
-#include <Windows.h>\r
-\r
-#include <memory>\r
-#include <array>\r
-#include <functional>\r
-#include <algorithm>\r
-#include <vector>\r
-#include <deque>\r
-#include <queue>\r
-#include <string>\r
-#include <math.h>\r
-\r
-#include <common/utf.h>\r
-#include <common/memory.h>\r
-//#include "../common/executor.h" // Can't include this due to MSVC lambda bug\r
-\r
-#include <common/log.h>\r
-#include <common/except.h>\r
-\r
-#include <assert.h>\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+#define NOMINMAX
+
+#include <Windows.h>
+
+#include <memory>
+#include <array>
+#include <functional>
+#include <algorithm>
+#include <vector>
+#include <deque>
+#include <queue>
+#include <string>
+#include <math.h>
+
+#include <common/utf.h>
+#include <common/memory.h>
+//#include "../common/executor.h" // Can't include this due to MSVC lambda bug
+
+#include <common/log.h>
+#include <common/except.h>
+
+#include <assert.h>
index 2b41c05656cba0bd4eac7fcf7233e2c600f98ce1..b01e51f46f015f5e307d74bf4df999856d34bb1c 100644 (file)
@@ -1,90 +1,90 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "StdAfx.h"\r
-\r
-#include "bluefish.h"\r
-\r
-#include "consumer/bluefish_consumer.h"\r
-\r
-#include "util/blue_velvet.h"\r
-\r
-#include <common/log.h>\r
-#include <common/utf.h>\r
-\r
-#include <core/consumer/frame_consumer.h>\r
-\r
-#include <boost/lexical_cast.hpp>\r
-\r
-namespace caspar { namespace bluefish {\r
-\r
-void init()\r
-{\r
-       try\r
-       {\r
-               blue_initialize();\r
-               core::register_consumer_factory([](const std::vector<std::wstring>& params)\r
-               {\r
-                       return create_consumer(params);\r
-               });\r
-       }\r
-       catch(...){}\r
-}\r
-\r
-std::wstring version()\r
-{\r
-       try\r
-       {\r
-               blue_initialize();\r
-       }\r
-       catch(...)\r
-       {\r
-               return L"Not found";\r
-       }\r
-\r
-       if(!BlueVelvetVersion)\r
-               return L"Unknown";\r
-\r
-       return u16(BlueVelvetVersion());\r
-}\r
-\r
-std::vector<std::wstring> device_list()\r
-{\r
-       std::vector<std::wstring> devices;\r
-\r
-       try\r
-       {               \r
-               blue_initialize();\r
-               \r
-               auto blue = create_blue();\r
-\r
-               for(int n = 1; BLUE_PASS(blue->device_attach(n, FALSE)); ++n)\r
-               {                               \r
-                       devices.push_back(std::wstring(get_card_desc(*blue)) + L" [" + boost::lexical_cast<std::wstring>(n) + L"]");\r
-                       blue->device_detach();          \r
-               }\r
-       }\r
-       catch(...){}\r
-\r
-       return devices;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "StdAfx.h"
+
+#include "bluefish.h"
+
+#include "consumer/bluefish_consumer.h"
+
+#include "util/blue_velvet.h"
+
+#include <common/log.h>
+#include <common/utf.h>
+
+#include <core/consumer/frame_consumer.h>
+
+#include <boost/lexical_cast.hpp>
+
+namespace caspar { namespace bluefish {
+
+void init()
+{
+       try
+       {
+               blue_initialize();
+               core::register_consumer_factory([](const std::vector<std::wstring>& params)
+               {
+                       return create_consumer(params);
+               });
+       }
+       catch(...){}
+}
+
+std::wstring version()
+{
+       try
+       {
+               blue_initialize();
+       }
+       catch(...)
+       {
+               return L"Not found";
+       }
+
+       if(!BlueVelvetVersion)
+               return L"Unknown";
+
+       return u16(BlueVelvetVersion());
+}
+
+std::vector<std::wstring> device_list()
+{
+       std::vector<std::wstring> devices;
+
+       try
+       {               
+               blue_initialize();
+               
+               auto blue = create_blue();
+
+               for(int n = 1; BLUE_PASS(blue->device_attach(n, FALSE)); ++n)
+               {                               
+                       devices.push_back(std::wstring(get_card_desc(*blue)) + L" [" + boost::lexical_cast<std::wstring>(n) + L"]");
+                       blue->device_detach();          
+               }
+       }
+       catch(...){}
+
+       return devices;
+}
+
 }}
\ No newline at end of file
index 18e651520674fc0d4b65c2f98f3ac03e2bf0982b..716193059a5cd21b4b66b403014f2033e7cb0073 100644 (file)
@@ -1,34 +1,34 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar { namespace bluefish {\r
-\r
-void init();\r
-\r
-std::wstring version();\r
-std::vector<std::wstring> device_list();\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+namespace caspar { namespace bluefish {
+
+void init();
+
+std::wstring version();
+std::vector<std::wstring> device_list();
+
 }}
\ No newline at end of file
index 8e150197bbb517bdab6426bddaba8106d691cbdc..9a2c5588582cb086ac51c33688b927334a399d86 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
\r
-#include "../StdAfx.h"\r
-\r
-#include "bluefish_consumer.h"\r
-#include "../util/blue_velvet.h"\r
-#include "../util/memory.h"\r
-\r
-#include <core/video_format.h>\r
-#include <core/frame/frame.h>\r
-\r
-#include <common/executor.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/array.h>\r
-#include <common/memshfl.h>\r
-\r
-#include <core/consumer/frame_consumer.h>\r
-#include <core/mixer/audio/audio_util.h>\r
-\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <common/assert.h>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-#include <asmlib.h>\r
-\r
-#include <memory>\r
-#include <array>\r
-\r
-namespace caspar { namespace bluefish { \r
-                       \r
-struct bluefish_consumer : boost::noncopyable\r
-{\r
-       spl::shared_ptr<CBlueVelvet4>                           blue_;\r
-       const unsigned int                                      device_index_;\r
-       const core::video_format_desc           format_desc_;\r
-       const int                                                       channel_index_;\r
-\r
-       const std::wstring                                      model_name_;\r
-\r
-       spl::shared_ptr<diagnostics::graph>             graph_;\r
-       boost::timer                                            frame_timer_;\r
-       boost::timer                                            tick_timer_;\r
-       boost::timer                                            sync_timer_;    \r
-                       \r
-       unsigned int                                            vid_fmt_;\r
-\r
-       std::array<blue_dma_buffer_ptr, 4>      reserved_frames_;       \r
-       tbb::concurrent_bounded_queue<core::const_frame> frame_buffer_;\r
-       \r
-       const bool                                                      embedded_audio_;\r
-       const bool                                                      key_only_;\r
-               \r
-       executor                                                        executor_;\r
-public:\r
-       bluefish_consumer(const core::video_format_desc& format_desc, int device_index, bool embedded_audio, bool key_only, int channel_index) \r
-               : blue_(create_blue(device_index))\r
-               , device_index_(device_index)\r
-               , format_desc_(format_desc) \r
-               , channel_index_(channel_index)\r
-               , model_name_(get_card_desc(*blue_))\r
-               , vid_fmt_(get_video_mode(*blue_, format_desc))\r
-               , embedded_audio_(embedded_audio)\r
-               , key_only_(key_only)\r
-               , executor_(print())\r
-       {\r
-               executor_.set_capacity(1);\r
-\r
-               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   \r
-               graph_->set_color("sync-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
-               graph_->set_color("frame-time", diagnostics::color(0.5f, 1.0f, 0.2f));\r
-               graph_->set_text(print());\r
-               diagnostics::register_graph(graph_);\r
-                       \r
-               //Setting output Video mode\r
-               if(BLUE_FAIL(set_card_property(blue_, VIDEO_MODE, vid_fmt_))) \r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set videomode."));\r
-\r
-               //Select Update Mode for output\r
-               if(BLUE_FAIL(set_card_property(blue_, VIDEO_UPDATE_TYPE, UPD_FMT_FRAME))) \r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set update type."));\r
-       \r
-               disable_video_output();\r
-\r
-               //Enable dual link output\r
-               if(BLUE_FAIL(set_card_property(blue_, VIDEO_DUAL_LINK_OUTPUT, 1)))\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to enable dual link."));\r
-\r
-               if(BLUE_FAIL(set_card_property(blue_, VIDEO_DUAL_LINK_OUTPUT_SIGNAL_FORMAT_TYPE, Signal_FormatType_4224)))\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set dual link format type to 4:2:2:4."));\r
-                       \r
-               //Select output memory format\r
-               if(BLUE_FAIL(set_card_property(blue_, VIDEO_MEMORY_FORMAT, MEM_FMT_ARGB_PC))) \r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set memory format."));\r
-               \r
-               //Select image orientation\r
-               if(BLUE_FAIL(set_card_property(blue_, VIDEO_IMAGE_ORIENTATION, ImageOrientation_Normal)))\r
-                       CASPAR_LOG(warning) << print() << L" Failed to set image orientation to normal.";       \r
-\r
-               // Select data range\r
-               if(BLUE_FAIL(set_card_property(blue_, VIDEO_RGB_DATA_RANGE, CGR_RANGE))) \r
-                       CASPAR_LOG(warning) << print() << L" Failed to set RGB data range to CGR.";     \r
-               \r
-               if(BLUE_FAIL(set_card_property(blue_, VIDEO_PREDEFINED_COLOR_MATRIX, vid_fmt_ == VID_FMT_PAL ? MATRIX_601_CGR : MATRIX_709_CGR)))\r
-                       CASPAR_LOG(warning) << print() << L" Failed to set colormatrix to " << (vid_fmt_ == VID_FMT_PAL ? L"601 CGR" : L"709 CGR") << L".";\r
-\r
-               if(!embedded_audio_)\r
-               {\r
-                       if(BLUE_FAIL(set_card_property(blue_, EMBEDEDDED_AUDIO_OUTPUT, 0))) \r
-                               CASPAR_LOG(warning) << TEXT("BLUECARD ERROR: Failed to disable embedded audio.");                       \r
-                       CASPAR_LOG(info) << print() << TEXT(" Disabled embedded-audio.");\r
-               }\r
-               else\r
-               {\r
-                       if(BLUE_FAIL(set_card_property(blue_, EMBEDEDDED_AUDIO_OUTPUT, blue_emb_audio_enable | blue_emb_audio_group1_enable))) \r
-                               CASPAR_LOG(warning) << print() << TEXT(" Failed to enable embedded audio.");                    \r
-                       CASPAR_LOG(info) << print() << TEXT(" Enabled embedded-audio.");\r
-               }\r
-               \r
-               if (blue_->has_output_key()) \r
-               {\r
-                       int dummy = TRUE; int v4444 = FALSE; int invert = FALSE; int white = FALSE;\r
-                       blue_->set_output_key(dummy, v4444, invert, white);\r
-               }\r
-\r
-               if(blue_->GetHDCardType(device_index_) != CRD_HD_INVALID) \r
-                       blue_->Set_DownConverterSignalType(vid_fmt_ == VID_FMT_PAL ? SD_SDI : HD_SDI);  \r
-       \r
-               if(BLUE_FAIL(set_card_property(blue_, VIDEO_OUTPUT_ENGINE, VIDEO_ENGINE_FRAMESTORE))) \r
-                       CASPAR_LOG(warning) << print() << TEXT(" Failed to set video engine."); \r
-               \r
-               enable_video_output();\r
-                                               \r
-               int n = 0;\r
-               boost::range::generate(reserved_frames_, [&]{return std::make_shared<blue_dma_buffer>(static_cast<int>(format_desc_.size), n++);});\r
-       }\r
-\r
-       ~bluefish_consumer()\r
-       {\r
-               try\r
-               {\r
-                       executor_.invoke([&]\r
-                       {\r
-                               disable_video_output();\r
-                               blue_->device_detach();         \r
-                       });\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-       }\r
-       \r
-       void enable_video_output()\r
-       {\r
-               if(!BLUE_PASS(set_card_property(blue_, VIDEO_BLACKGENERATOR, 0)))\r
-                       CASPAR_LOG(error) << print() << TEXT(" Failed to disable video output.");       \r
-       }\r
-\r
-       void disable_video_output()\r
-       {\r
-               blue_->video_playback_stop(0,0);\r
-               if(!BLUE_PASS(set_card_property(blue_, VIDEO_BLACKGENERATOR, 1)))\r
-                       CASPAR_LOG(error)<< print() << TEXT(" Failed to disable video output.");                \r
-       }\r
-       \r
-       void send(core::const_frame& frame)\r
-       {                                       \r
-               executor_.begin_invoke([=]\r
-               {\r
-                       try\r
-                       {       \r
-                               display_frame(frame);                           \r
-                               graph_->set_value("tick-time", static_cast<float>(tick_timer_.elapsed()*format_desc_.fps*0.5));\r
-                               tick_timer_.restart();\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }\r
-               });\r
-       }\r
-\r
-       void display_frame(core::const_frame frame)\r
-       {\r
-               // Sync\r
-\r
-               sync_timer_.restart();\r
-               unsigned long n_field = 0;\r
-               blue_->wait_output_video_synch(UPD_FMT_FRAME, n_field);\r
-               graph_->set_value("sync-time", sync_timer_.elapsed()*format_desc_.fps*0.5);\r
-               \r
-               frame_timer_.restart();         \r
-\r
-               // Copy to local buffers\r
-               \r
-               if(!frame.image_data().empty())\r
-               {\r
-                       if(key_only_)                                           \r
-                               aligned_memshfl(reserved_frames_.front()->image_data(), frame.image_data().begin(), frame.image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
-                       else\r
-                               A_memcpy(reserved_frames_.front()->image_data(), frame.image_data().begin(), frame.image_data().size());\r
-               }\r
-               else\r
-                       A_memset(reserved_frames_.front()->image_data(), 0, reserved_frames_.front()->image_size());\r
-                                                               \r
-\r
-               // Send and display\r
-\r
-               if(embedded_audio_)\r
-               {               \r
-                       auto frame_audio = core::audio_32_to_24(frame.audio_data());                    \r
-                       encode_hanc(reinterpret_cast<BLUE_UINT32*>(reserved_frames_.front()->hanc_data()), \r
-                                               frame_audio.data(), \r
-                                               static_cast<int>(frame.audio_data().size()/format_desc_.audio_channels), \r
-                                               static_cast<int>(format_desc_.audio_channels));\r
-                                                               \r
-                       blue_->system_buffer_write_async(const_cast<uint8_t*>(reserved_frames_.front()->image_data()), \r
-                                                                                       static_cast<unsigned long>(reserved_frames_.front()->image_size()), \r
-                                                                                       nullptr, \r
-                                                                                       BlueImage_HANC_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_IMAGE));\r
-\r
-                       blue_->system_buffer_write_async(reserved_frames_.front()->hanc_data(),\r
-                                                                                       static_cast<unsigned long>(reserved_frames_.front()->hanc_size()), \r
-                                                                                       nullptr,                 \r
-                                                                                       BlueImage_HANC_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_HANC));\r
-\r
-                       if(BLUE_FAIL(blue_->render_buffer_update(BlueBuffer_Image_HANC(reserved_frames_.front()->id()))))\r
-                               CASPAR_LOG(warning) << print() << TEXT(" render_buffer_update failed.");\r
-               }\r
-               else\r
-               {\r
-                       blue_->system_buffer_write_async(const_cast<uint8_t*>(reserved_frames_.front()->image_data()),\r
-                                                                                       static_cast<unsigned long>(reserved_frames_.front()->image_size()), \r
-                                                                                       nullptr,                 \r
-                                                                                       BlueImage_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_IMAGE));\r
-                       \r
-                       if(BLUE_FAIL(blue_->render_buffer_update(BlueBuffer_Image(reserved_frames_.front()->id()))))\r
-                               CASPAR_LOG(warning) << print() << TEXT(" render_buffer_update failed.");\r
-               }\r
-\r
-               boost::range::rotate(reserved_frames_, std::begin(reserved_frames_)+1);\r
-               \r
-               graph_->set_value("frame-time", static_cast<float>(frame_timer_.elapsed()*format_desc_.fps*0.5));\r
-       }\r
-\r
-       void encode_hanc(BLUE_UINT32* hanc_data, void* audio_data, int audio_samples, int audio_nchannels)\r
-       {       \r
-               const auto sample_type = AUDIO_CHANNEL_24BIT | AUDIO_CHANNEL_LITTLEENDIAN;\r
-               const auto emb_audio_flag = blue_emb_audio_enable | blue_emb_audio_group1_enable;\r
-               \r
-               hanc_stream_info_struct hanc_stream_info;\r
-               memset(&hanc_stream_info, 0, sizeof(hanc_stream_info));\r
-               \r
-               hanc_stream_info.AudioDBNArray[0] = -1;\r
-               hanc_stream_info.AudioDBNArray[1] = -1;\r
-               hanc_stream_info.AudioDBNArray[2] = -1;\r
-               hanc_stream_info.AudioDBNArray[3] = -1;\r
-               hanc_stream_info.hanc_data_ptr    = hanc_data;\r
-               hanc_stream_info.video_mode               = vid_fmt_;           \r
-               \r
-               if (!is_epoch_card(*blue_))\r
-                       encode_hanc_frame(&hanc_stream_info, audio_data, audio_nchannels, audio_samples, sample_type, emb_audio_flag);  \r
-               else\r
-                       encode_hanc_frame_ex(blue_->has_video_cardtype(), &hanc_stream_info, audio_data, audio_nchannels, audio_samples, sample_type, emb_audio_flag);\r
-       }\r
-       \r
-       std::wstring print() const\r
-       {\r
-               return model_name_ + L" [" + boost::lexical_cast<std::wstring>(channel_index_) + L"-" + \r
-                       boost::lexical_cast<std::wstring>(device_index_) + L"|" +  format_desc_.name + L"]";\r
-       }\r
-};\r
-\r
-struct bluefish_consumer_proxy : public core::frame_consumer\r
-{\r
-       std::unique_ptr<bluefish_consumer>      consumer_;\r
-       const int                                                       device_index_;\r
-       const bool                                                      embedded_audio_;\r
-       const bool                                                      key_only_;\r
-public:\r
-\r
-       bluefish_consumer_proxy(int device_index, bool embedded_audio, bool key_only)\r
-               : device_index_(device_index)\r
-               , embedded_audio_(embedded_audio)\r
-               , key_only_(key_only)\r
-       {\r
-       }\r
-       \r
-       // frame_consumer\r
-       \r
-       void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
-       {\r
-               consumer_.reset();\r
-               consumer_.reset(new bluefish_consumer(format_desc, device_index_, embedded_audio_, key_only_, channel_index));\r
-       }\r
-       \r
-       bool send(core::const_frame frame) override\r
-       {\r
-               consumer_->send(frame);\r
-               return true;\r
-       }\r
-               \r
-       std::wstring print() const override\r
-       {\r
-               return consumer_ ? consumer_->print() : L"[bluefish_consumer]";\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"bluefish";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"bluefish");\r
-               info.add(L"key-only", key_only_);\r
-               info.add(L"device", device_index_);\r
-               info.add(L"embedded-audio", embedded_audio_);\r
-               return info;\r
-       }\r
-\r
-       int buffer_depth() const override\r
-       {\r
-               return 1;\r
-       }\r
-       \r
-       int index() const override\r
-       {\r
-               return 400 + device_index_;\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }       \r
-};     \r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)\r
-{\r
-       if(params.size() < 1 || params[0] != L"BLUEFISH")\r
-               return core::frame_consumer::empty();\r
-\r
-       const auto device_index = params.size() > 1 ? boost::lexical_cast<int>(params[1]) : 1;\r
-\r
-       const auto embedded_audio = std::find(params.begin(), params.end(), L"EMBEDDED_AUDIO") != params.end();\r
-       const auto key_only               = std::find(params.begin(), params.end(), L"KEY_ONLY")           != params.end();\r
-\r
-       return spl::make_shared<bluefish_consumer_proxy>(device_index, embedded_audio, key_only);\r
-}\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree) \r
-{      \r
-       const auto device_index         = ptree.get(L"device",                  1);\r
-       const auto embedded_audio       = ptree.get(L"embedded-audio",  false);\r
-       const auto key_only                     = ptree.get(L"key-only",                false);\r
-\r
-       return spl::make_shared<bluefish_consumer_proxy>(device_index, embedded_audio, key_only);\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+#include "../StdAfx.h"
+
+#include "bluefish_consumer.h"
+#include "../util/blue_velvet.h"
+#include "../util/memory.h"
+
+#include <core/video_format.h>
+#include <core/frame/frame.h>
+
+#include <common/executor.h>
+#include <common/diagnostics/graph.h>
+#include <common/array.h>
+#include <common/memshfl.h>
+
+#include <core/consumer/frame_consumer.h>
+#include <core/mixer/audio/audio_util.h>
+
+#include <tbb/concurrent_queue.h>
+
+#include <common/assert.h>
+#include <boost/lexical_cast.hpp>
+#include <boost/timer.hpp>
+#include <boost/range/algorithm.hpp>
+#include <boost/property_tree/ptree.hpp>
+
+#include <asmlib.h>
+
+#include <memory>
+#include <array>
+
+namespace caspar { namespace bluefish { 
+                       
+struct bluefish_consumer : boost::noncopyable
+{
+       spl::shared_ptr<CBlueVelvet4>                           blue_;
+       const unsigned int                                      device_index_;
+       const core::video_format_desc           format_desc_;
+       const int                                                       channel_index_;
+
+       const std::wstring                                      model_name_;
+
+       spl::shared_ptr<diagnostics::graph>             graph_;
+       boost::timer                                            frame_timer_;
+       boost::timer                                            tick_timer_;
+       boost::timer                                            sync_timer_;    
+                       
+       unsigned int                                            vid_fmt_;
+
+       std::array<blue_dma_buffer_ptr, 4>      reserved_frames_;       
+       tbb::concurrent_bounded_queue<core::const_frame> frame_buffer_;
+       
+       const bool                                                      embedded_audio_;
+       const bool                                                      key_only_;
+               
+       executor                                                        executor_;
+public:
+       bluefish_consumer(const core::video_format_desc& format_desc, int device_index, bool embedded_audio, bool key_only, int channel_index) 
+               : blue_(create_blue(device_index))
+               , device_index_(device_index)
+               , format_desc_(format_desc) 
+               , channel_index_(channel_index)
+               , model_name_(get_card_desc(*blue_))
+               , vid_fmt_(get_video_mode(*blue_, format_desc))
+               , embedded_audio_(embedded_audio)
+               , key_only_(key_only)
+               , executor_(print())
+       {
+               executor_.set_capacity(1);
+
+               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   
+               graph_->set_color("sync-time", diagnostics::color(1.0f, 0.0f, 0.0f));
+               graph_->set_color("frame-time", diagnostics::color(0.5f, 1.0f, 0.2f));
+               graph_->set_text(print());
+               diagnostics::register_graph(graph_);
+                       
+               //Setting output Video mode
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_MODE, vid_fmt_))) 
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set videomode."));
+
+               //Select Update Mode for output
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_UPDATE_TYPE, UPD_FMT_FRAME))) 
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set update type."));
+       
+               disable_video_output();
+
+               //Enable dual link output
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_DUAL_LINK_OUTPUT, 1)))
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to enable dual link."));
+
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_DUAL_LINK_OUTPUT_SIGNAL_FORMAT_TYPE, Signal_FormatType_4224)))
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set dual link format type to 4:2:2:4."));
+                       
+               //Select output memory format
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_MEMORY_FORMAT, MEM_FMT_ARGB_PC))) 
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to set memory format."));
+               
+               //Select image orientation
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_IMAGE_ORIENTATION, ImageOrientation_Normal)))
+                       CASPAR_LOG(warning) << print() << L" Failed to set image orientation to normal.";       
+
+               // Select data range
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_RGB_DATA_RANGE, CGR_RANGE))) 
+                       CASPAR_LOG(warning) << print() << L" Failed to set RGB data range to CGR.";     
+               
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_PREDEFINED_COLOR_MATRIX, vid_fmt_ == VID_FMT_PAL ? MATRIX_601_CGR : MATRIX_709_CGR)))
+                       CASPAR_LOG(warning) << print() << L" Failed to set colormatrix to " << (vid_fmt_ == VID_FMT_PAL ? L"601 CGR" : L"709 CGR") << L".";
+
+               if(!embedded_audio_)
+               {
+                       if(BLUE_FAIL(set_card_property(blue_, EMBEDEDDED_AUDIO_OUTPUT, 0))) 
+                               CASPAR_LOG(warning) << TEXT("BLUECARD ERROR: Failed to disable embedded audio.");                       
+                       CASPAR_LOG(info) << print() << TEXT(" Disabled embedded-audio.");
+               }
+               else
+               {
+                       if(BLUE_FAIL(set_card_property(blue_, EMBEDEDDED_AUDIO_OUTPUT, blue_emb_audio_enable | blue_emb_audio_group1_enable))) 
+                               CASPAR_LOG(warning) << print() << TEXT(" Failed to enable embedded audio.");                    
+                       CASPAR_LOG(info) << print() << TEXT(" Enabled embedded-audio.");
+               }
+               
+               if (blue_->has_output_key()) 
+               {
+                       int dummy = TRUE; int v4444 = FALSE; int invert = FALSE; int white = FALSE;
+                       blue_->set_output_key(dummy, v4444, invert, white);
+               }
+
+               if(blue_->GetHDCardType(device_index_) != CRD_HD_INVALID) 
+                       blue_->Set_DownConverterSignalType(vid_fmt_ == VID_FMT_PAL ? SD_SDI : HD_SDI);  
+       
+               if(BLUE_FAIL(set_card_property(blue_, VIDEO_OUTPUT_ENGINE, VIDEO_ENGINE_FRAMESTORE))) 
+                       CASPAR_LOG(warning) << print() << TEXT(" Failed to set video engine."); 
+               
+               enable_video_output();
+                                               
+               int n = 0;
+               boost::range::generate(reserved_frames_, [&]{return std::make_shared<blue_dma_buffer>(static_cast<int>(format_desc_.size), n++);});
+       }
+
+       ~bluefish_consumer()
+       {
+               try
+               {
+                       executor_.invoke([&]
+                       {
+                               disable_video_output();
+                               blue_->device_detach();         
+                       });
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+       }
+       
+       void enable_video_output()
+       {
+               if(!BLUE_PASS(set_card_property(blue_, VIDEO_BLACKGENERATOR, 0)))
+                       CASPAR_LOG(error) << print() << TEXT(" Failed to disable video output.");       
+       }
+
+       void disable_video_output()
+       {
+               blue_->video_playback_stop(0,0);
+               if(!BLUE_PASS(set_card_property(blue_, VIDEO_BLACKGENERATOR, 1)))
+                       CASPAR_LOG(error)<< print() << TEXT(" Failed to disable video output.");                
+       }
+       
+       void send(core::const_frame& frame)
+       {                                       
+               executor_.begin_invoke([=]
+               {
+                       try
+                       {       
+                               display_frame(frame);                           
+                               graph_->set_value("tick-time", static_cast<float>(tick_timer_.elapsed()*format_desc_.fps*0.5));
+                               tick_timer_.restart();
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }
+               });
+       }
+
+       void display_frame(core::const_frame frame)
+       {
+               // Sync
+
+               sync_timer_.restart();
+               unsigned long n_field = 0;
+               blue_->wait_output_video_synch(UPD_FMT_FRAME, n_field);
+               graph_->set_value("sync-time", sync_timer_.elapsed()*format_desc_.fps*0.5);
+               
+               frame_timer_.restart();         
+
+               // Copy to local buffers
+               
+               if(!frame.image_data().empty())
+               {
+                       if(key_only_)                                           
+                               aligned_memshfl(reserved_frames_.front()->image_data(), frame.image_data().begin(), frame.image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);
+                       else
+                               A_memcpy(reserved_frames_.front()->image_data(), frame.image_data().begin(), frame.image_data().size());
+               }
+               else
+                       A_memset(reserved_frames_.front()->image_data(), 0, reserved_frames_.front()->image_size());
+                                                               
+
+               // Send and display
+
+               if(embedded_audio_)
+               {               
+                       auto frame_audio = core::audio_32_to_24(frame.audio_data());                    
+                       encode_hanc(reinterpret_cast<BLUE_UINT32*>(reserved_frames_.front()->hanc_data()), 
+                                               frame_audio.data(), 
+                                               static_cast<int>(frame.audio_data().size()/format_desc_.audio_channels), 
+                                               static_cast<int>(format_desc_.audio_channels));
+                                                               
+                       blue_->system_buffer_write_async(const_cast<uint8_t*>(reserved_frames_.front()->image_data()), 
+                                                                                       static_cast<unsigned long>(reserved_frames_.front()->image_size()), 
+                                                                                       nullptr, 
+                                                                                       BlueImage_HANC_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_IMAGE));
+
+                       blue_->system_buffer_write_async(reserved_frames_.front()->hanc_data(),
+                                                                                       static_cast<unsigned long>(reserved_frames_.front()->hanc_size()), 
+                                                                                       nullptr,                 
+                                                                                       BlueImage_HANC_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_HANC));
+
+                       if(BLUE_FAIL(blue_->render_buffer_update(BlueBuffer_Image_HANC(reserved_frames_.front()->id()))))
+                               CASPAR_LOG(warning) << print() << TEXT(" render_buffer_update failed.");
+               }
+               else
+               {
+                       blue_->system_buffer_write_async(const_cast<uint8_t*>(reserved_frames_.front()->image_data()),
+                                                                                       static_cast<unsigned long>(reserved_frames_.front()->image_size()), 
+                                                                                       nullptr,                 
+                                                                                       BlueImage_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_IMAGE));
+                       
+                       if(BLUE_FAIL(blue_->render_buffer_update(BlueBuffer_Image(reserved_frames_.front()->id()))))
+                               CASPAR_LOG(warning) << print() << TEXT(" render_buffer_update failed.");
+               }
+
+               boost::range::rotate(reserved_frames_, std::begin(reserved_frames_)+1);
+               
+               graph_->set_value("frame-time", static_cast<float>(frame_timer_.elapsed()*format_desc_.fps*0.5));
+       }
+
+       void encode_hanc(BLUE_UINT32* hanc_data, void* audio_data, int audio_samples, int audio_nchannels)
+       {       
+               const auto sample_type = AUDIO_CHANNEL_24BIT | AUDIO_CHANNEL_LITTLEENDIAN;
+               const auto emb_audio_flag = blue_emb_audio_enable | blue_emb_audio_group1_enable;
+               
+               hanc_stream_info_struct hanc_stream_info;
+               memset(&hanc_stream_info, 0, sizeof(hanc_stream_info));
+               
+               hanc_stream_info.AudioDBNArray[0] = -1;
+               hanc_stream_info.AudioDBNArray[1] = -1;
+               hanc_stream_info.AudioDBNArray[2] = -1;
+               hanc_stream_info.AudioDBNArray[3] = -1;
+               hanc_stream_info.hanc_data_ptr    = hanc_data;
+               hanc_stream_info.video_mode               = vid_fmt_;           
+               
+               if (!is_epoch_card(*blue_))
+                       encode_hanc_frame(&hanc_stream_info, audio_data, audio_nchannels, audio_samples, sample_type, emb_audio_flag);  
+               else
+                       encode_hanc_frame_ex(blue_->has_video_cardtype(), &hanc_stream_info, audio_data, audio_nchannels, audio_samples, sample_type, emb_audio_flag);
+       }
+       
+       std::wstring print() const
+       {
+               return model_name_ + L" [" + boost::lexical_cast<std::wstring>(channel_index_) + L"-" + 
+                       boost::lexical_cast<std::wstring>(device_index_) + L"|" +  format_desc_.name + L"]";
+       }
+};
+
+struct bluefish_consumer_proxy : public core::frame_consumer
+{
+       std::unique_ptr<bluefish_consumer>      consumer_;
+       const int                                                       device_index_;
+       const bool                                                      embedded_audio_;
+       const bool                                                      key_only_;
+public:
+
+       bluefish_consumer_proxy(int device_index, bool embedded_audio, bool key_only)
+               : device_index_(device_index)
+               , embedded_audio_(embedded_audio)
+               , key_only_(key_only)
+       {
+       }
+       
+       // frame_consumer
+       
+       void initialize(const core::video_format_desc& format_desc, int channel_index) override
+       {
+               consumer_.reset();
+               consumer_.reset(new bluefish_consumer(format_desc, device_index_, embedded_audio_, key_only_, channel_index));
+       }
+       
+       bool send(core::const_frame frame) override
+       {
+               consumer_->send(frame);
+               return true;
+       }
+               
+       std::wstring print() const override
+       {
+               return consumer_ ? consumer_->print() : L"[bluefish_consumer]";
+       }
+
+       std::wstring name() const override
+       {
+               return L"bluefish";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"bluefish");
+               info.add(L"key-only", key_only_);
+               info.add(L"device", device_index_);
+               info.add(L"embedded-audio", embedded_audio_);
+               return info;
+       }
+
+       int buffer_depth() const override
+       {
+               return 1;
+       }
+       
+       int index() const override
+       {
+               return 400 + device_index_;
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }       
+};     
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+{
+       if(params.size() < 1 || params[0] != L"BLUEFISH")
+               return core::frame_consumer::empty();
+
+       const auto device_index = params.size() > 1 ? boost::lexical_cast<int>(params[1]) : 1;
+
+       const auto embedded_audio = std::find(params.begin(), params.end(), L"EMBEDDED_AUDIO") != params.end();
+       const auto key_only               = std::find(params.begin(), params.end(), L"KEY_ONLY")           != params.end();
+
+       return spl::make_shared<bluefish_consumer_proxy>(device_index, embedded_audio, key_only);
+}
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree) 
+{      
+       const auto device_index         = ptree.get(L"device",                  1);
+       const auto embedded_audio       = ptree.get(L"embedded-audio",  false);
+       const auto key_only                     = ptree.get(L"key-only",                false);
+
+       return spl::make_shared<bluefish_consumer_proxy>(device_index, embedded_audio, key_only);
+}
+
 }}
\ No newline at end of file
index 66b3787b6929cb81c489c2bb30cc22e40f43d1bd..91fbeb1d0968cd930145ddb3f3268fbe31801e2d 100644 (file)
@@ -1,41 +1,41 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-#include <string>\r
-\r
-namespace caspar { \r
-\r
-namespace core {\r
-       class frame_consumer;\r
-}\r
-        \r
-namespace bluefish {\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <boost/property_tree/ptree.hpp>
+
+#include <string>
+
+namespace caspar { 
+
+namespace core {
+       class frame_consumer;
+}
+        
+namespace bluefish {
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);
+
 }}
\ No newline at end of file
index 8575c0426fc6d611e34108ca1cc08d2c0db71432..b5f45d5118de75959d509d96300b9185ebdeddcb 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../StdAfx.h"\r
-\r
-#include "blue_velvet.h"\r
-\r
-#include <common/utf.h>\r
-\r
-#include <core/video_format.h>\r
-\r
-namespace caspar { namespace bluefish {\r
-       \r
-CBlueVelvet4* (*BlueVelvetFactory4)() = nullptr;\r
-void (*BlueVelvetDestroy)(CBlueVelvet4* pObj) = nullptr;\r
-const char*    (*BlueVelvetVersion)() = nullptr;\r
-BLUE_UINT32 (*encode_hanc_frame)(struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr,BLUE_UINT32 no_audio_ch,BLUE_UINT32 no_audio_samples,BLUE_UINT32 nTypeOfSample,BLUE_UINT32 emb_audio_flag) = nullptr;\r
-BLUE_UINT32 (*encode_hanc_frame_ex)(BLUE_UINT32 card_type, struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr, BLUE_UINT32 no_audio_ch,    BLUE_UINT32 no_audio_samples, BLUE_UINT32 nTypeOfSample, BLUE_UINT32 emb_audio_flag) = nullptr;\r
-\r
-void blue_velvet_initialize()\r
-{\r
-#ifdef _DEBUG\r
-       std::string module_str = "BlueVelvet64_d.dll";\r
-#else\r
-       std::string module_str = "BlueVelvet64.dll";\r
-#endif\r
-\r
-       auto module = LoadLibrary(u16(module_str).c_str());\r
-       if(!module)\r
-               LoadLibrary(u16(std::string(getenv("SystemDrive")) + "\\Program Files\\Bluefish444\\Driver\\" + module_str).c_str());\r
-       if(!module)\r
-               LoadLibrary(u16(std::string(getenv("SystemDrive")) + "\\Program Files (x86)\\BlueFish444\\Driver\\" + module_str).c_str());\r
-       if(!module)\r
-               CASPAR_THROW_EXCEPTION(file_not_found() << msg_info("Could not find BlueVelvet3.dll. Required drivers are not installed."));\r
-       static std::shared_ptr<void> lib(module, FreeLibrary);\r
-       BlueVelvetFactory4 = reinterpret_cast<decltype(BlueVelvetFactory4)>(GetProcAddress(module, "BlueVelvetFactory4"));\r
-       BlueVelvetDestroy  = reinterpret_cast<decltype(BlueVelvetDestroy)>(GetProcAddress(module, "BlueVelvetDestroy"));\r
-       BlueVelvetVersion  = reinterpret_cast<decltype(BlueVelvetVersion)>(GetProcAddress(module, "BlueVelvetVersion"));\r
-}\r
-\r
-void blue_hanc_initialize()\r
-{\r
-#ifdef _DEBUG\r
-       std::string module_str = "BlueHancUtils64_d.dll";\r
-#else\r
-       std::string module_str = "BlueHancUtils64.dll";\r
-#endif\r
-       \r
-       auto module = LoadLibrary(u16(module_str).c_str());\r
-       if(!module)\r
-               LoadLibrary(u16(std::string(getenv("SystemDrive")) + "\\Program Files\\Bluefish444\\Driver\\" + module_str).c_str());\r
-       if(!module)\r
-               LoadLibrary(u16(std::string(getenv("SystemDrive")) + "\\Program Files (x86)\\BlueFish444\\Driver\\" + module_str).c_str());\r
-       if(!module)\r
-               CASPAR_THROW_EXCEPTION(file_not_found() << msg_info("Could not find BlueHancUtils.dll. Required drivers are not installed."));\r
-       static std::shared_ptr<void> lib(module, FreeLibrary);\r
-       encode_hanc_frame        = reinterpret_cast<decltype(encode_hanc_frame)>(GetProcAddress(module, "encode_hanc_frame"));\r
-       encode_hanc_frame_ex = reinterpret_cast<decltype(encode_hanc_frame_ex)>(GetProcAddress(module, "encode_hanc_frame_ex"));\r
-}\r
-\r
-void blue_initialize()\r
-{\r
-       blue_hanc_initialize();\r
-       blue_velvet_initialize();\r
-}\r
-\r
-EVideoMode vid_fmt_from_video_format(const core::video_format& fmt) \r
-{\r
-       switch(fmt.value())\r
-       {\r
-       case core::video_format::pal:                   return VID_FMT_PAL;\r
-       case core::video_format::ntsc:                  return VID_FMT_NTSC;\r
-       case core::video_format::x576p2500:             return VID_FMT_INVALID; //not supported\r
-       case core::video_format::x720p2500:             return VID_FMT_720P_2500;\r
-       case core::video_format::x720p5000:             return VID_FMT_720P_5000;\r
-       case core::video_format::x720p5994:             return VID_FMT_720P_5994;\r
-       case core::video_format::x720p6000:             return VID_FMT_720P_6000;\r
-       case core::video_format::x1080p2397:    return VID_FMT_1080P_2397;\r
-       case core::video_format::x1080p2400:    return VID_FMT_1080P_2400;\r
-       case core::video_format::x1080i5000:    return VID_FMT_1080I_5000;\r
-       case core::video_format::x1080i5994:    return VID_FMT_1080I_5994;\r
-       case core::video_format::x1080i6000:    return VID_FMT_1080I_6000;\r
-       case core::video_format::x1080p2500:    return VID_FMT_1080P_2500;\r
-       case core::video_format::x1080p2997:    return VID_FMT_1080P_2997;\r
-       case core::video_format::x1080p3000:    return VID_FMT_1080P_3000;\r
-       case core::video_format::x1080p5000:    return VID_FMT_1080P_5000;\r
-       default:                                                                return VID_FMT_INVALID;\r
-       }\r
-}\r
-\r
-bool is_epoch_card(CBlueVelvet4& blue)\r
-{\r
-       switch(blue.has_video_cardtype())\r
-       {\r
-       case CRD_BLUE_EPOCH_HORIZON:\r
-       case CRD_BLUE_EPOCH_CORE:\r
-       case CRD_BLUE_EPOCH_ULTRA:\r
-       case CRD_BLUE_EPOCH_2K_HORIZON:\r
-       case CRD_BLUE_EPOCH_2K_CORE:\r
-       case CRD_BLUE_EPOCH_2K_ULTRA:\r
-       case CRD_BLUE_CREATE_HD:\r
-       case CRD_BLUE_CREATE_2K:\r
-       case CRD_BLUE_CREATE_2K_ULTRA:\r
-       case CRD_BLUE_SUPER_NOVA:\r
-               return true;\r
-       default:\r
-               return false;\r
-       }\r
-}\r
-\r
-std::wstring get_card_desc(CBlueVelvet4& blue)\r
-{\r
-       switch(blue.has_video_cardtype()) \r
-       {\r
-       case CRD_BLUEDEEP_LT:                           return L"Deepblue LT";// D64 Lite\r
-       case CRD_BLUEDEEP_SD:                           return L"Iridium SD";// Iridium SD\r
-       case CRD_BLUEDEEP_AV:                           return L"Iridium AV";// Iridium AV\r
-       case CRD_BLUEDEEP_IO:                           return L"Deepblue IO";// D64 Full\r
-       case CRD_BLUEWILD_AV:                           return L"Wildblue AV";// D64 AV\r
-       case CRD_IRIDIUM_HD:                            return L"Iridium HD";// * Iridium HD\r
-       case CRD_BLUEWILD_RT:                           return L"Wildblue RT";// D64 RT\r
-       case CRD_BLUEWILD_HD:                           return L"Wildblue HD";// * BadAss G2\r
-       case CRD_REDDEVIL:                                      return L"Iridium Full";// Iridium Full\r
-       case CRD_BLUEDEEP_HD:   \r
-       case CRD_BLUEDEEP_HDS:                          return L"Reserved for \"BasAss G2";// * BadAss G2 variant, proposed, reserved\r
-       case CRD_BLUE_ENVY:                                     return L"Blue Envy"; // Mini Din \r
-       case CRD_BLUE_PRIDE:                            return L"Blue Pride";//Mini Din Output \r
-       case CRD_BLUE_GREED:                            return L"Blue Greed";\r
-       case CRD_BLUE_INGEST:                           return L"Blue Ingest";\r
-       case CRD_BLUE_SD_DUALLINK:                      return L"Blue SD Duallink";\r
-       case CRD_BLUE_CATALYST:                         return L"Blue Catalyst";\r
-       case CRD_BLUE_SD_DUALLINK_PRO:          return L"Blue SD Duallink Pro";\r
-       case CRD_BLUE_SD_INGEST_PRO:            return L"Blue SD Ingest pro";\r
-       case CRD_BLUE_SD_DEEPBLUE_LITE_PRO:     return L"Blue SD Deepblue lite Pro";\r
-       case CRD_BLUE_SD_SINGLELINK_PRO:        return L"Blue SD Singlelink Pro";\r
-       case CRD_BLUE_SD_IRIDIUM_AV_PRO:        return L"Blue SD Iridium AV Pro";\r
-       case CRD_BLUE_SD_FIDELITY:                      return L"Blue SD Fidelity";\r
-       case CRD_BLUE_SD_FOCUS:                         return L"Blue SD Focus";\r
-       case CRD_BLUE_SD_PRIME:                         return L"Blue SD Prime";\r
-       case CRD_BLUE_EPOCH_2K_CORE:            return L"Blue Epoch 2K Core";\r
-       case CRD_BLUE_EPOCH_2K_ULTRA:           return L"Blue Epoch 2K Ultra";\r
-       case CRD_BLUE_EPOCH_HORIZON:            return L"Blue Epoch Horizon";\r
-       case CRD_BLUE_EPOCH_CORE:                       return L"Blue Epoch Core";\r
-       case CRD_BLUE_EPOCH_ULTRA:                      return L"Blue Epoch Ultra";\r
-       case CRD_BLUE_CREATE_HD:                        return L"Blue Create HD";\r
-       case CRD_BLUE_CREATE_2K:                        return L"Blue Create 2K";\r
-       case CRD_BLUE_CREATE_2K_ULTRA:          return L"Blue Create 2K Ultra";\r
-       default:                                                        return L"Unknown";\r
-       }\r
-}\r
-\r
-EVideoMode get_video_mode(CBlueVelvet4& blue, const core::video_format_desc& format_desc)\r
-{\r
-       EVideoMode vid_fmt = VID_FMT_INVALID;\r
-       auto desiredVideoFormat = vid_fmt_from_video_format(format_desc.format);\r
-       int videoModeCount = blue.count_video_mode();\r
-       for(int videoModeIndex = 1; videoModeIndex <= videoModeCount; ++videoModeIndex) \r
-       {\r
-               EVideoMode videoMode = blue.enum_video_mode(videoModeIndex);\r
-               if(videoMode == desiredVideoFormat) \r
-                       vid_fmt = videoMode;                    \r
-       }\r
-       if(vid_fmt == VID_FMT_INVALID)\r
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("video-mode not supported.") << arg_value_info(format_desc.name));\r
-\r
-       return vid_fmt;\r
-}\r
-\r
-spl::shared_ptr<CBlueVelvet4> create_blue()\r
-{\r
-       if(!BlueVelvetFactory4 || !encode_hanc_frame || !encode_hanc_frame)\r
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Bluefish drivers not found."));\r
-\r
-       return spl::shared_ptr<CBlueVelvet4>(BlueVelvetFactory4(), BlueVelvetDestroy);\r
-}\r
-\r
-spl::shared_ptr<CBlueVelvet4> create_blue(int device_index)\r
-{\r
-       auto blue = create_blue();\r
-       \r
-       if(BLUE_FAIL(blue->device_attach(device_index, FALSE))) \r
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to attach device."));\r
-\r
-       return blue;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../StdAfx.h"
+
+#include "blue_velvet.h"
+
+#include <common/utf.h>
+
+#include <core/video_format.h>
+
+namespace caspar { namespace bluefish {
+       
+CBlueVelvet4* (*BlueVelvetFactory4)() = nullptr;
+void (*BlueVelvetDestroy)(CBlueVelvet4* pObj) = nullptr;
+const char*    (*BlueVelvetVersion)() = nullptr;
+BLUE_UINT32 (*encode_hanc_frame)(struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr,BLUE_UINT32 no_audio_ch,BLUE_UINT32 no_audio_samples,BLUE_UINT32 nTypeOfSample,BLUE_UINT32 emb_audio_flag) = nullptr;
+BLUE_UINT32 (*encode_hanc_frame_ex)(BLUE_UINT32 card_type, struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr, BLUE_UINT32 no_audio_ch,    BLUE_UINT32 no_audio_samples, BLUE_UINT32 nTypeOfSample, BLUE_UINT32 emb_audio_flag) = nullptr;
+
+void blue_velvet_initialize()
+{
+#ifdef _DEBUG
+       std::string module_str = "BlueVelvet64_d.dll";
+#else
+       std::string module_str = "BlueVelvet64.dll";
+#endif
+
+       auto module = LoadLibrary(u16(module_str).c_str());
+       if(!module)
+               LoadLibrary(u16(std::string(getenv("SystemDrive")) + "\\Program Files\\Bluefish444\\Driver\\" + module_str).c_str());
+       if(!module)
+               LoadLibrary(u16(std::string(getenv("SystemDrive")) + "\\Program Files (x86)\\BlueFish444\\Driver\\" + module_str).c_str());
+       if(!module)
+               CASPAR_THROW_EXCEPTION(file_not_found() << msg_info("Could not find BlueVelvet3.dll. Required drivers are not installed."));
+       static std::shared_ptr<void> lib(module, FreeLibrary);
+       BlueVelvetFactory4 = reinterpret_cast<decltype(BlueVelvetFactory4)>(GetProcAddress(module, "BlueVelvetFactory4"));
+       BlueVelvetDestroy  = reinterpret_cast<decltype(BlueVelvetDestroy)>(GetProcAddress(module, "BlueVelvetDestroy"));
+       BlueVelvetVersion  = reinterpret_cast<decltype(BlueVelvetVersion)>(GetProcAddress(module, "BlueVelvetVersion"));
+}
+
+void blue_hanc_initialize()
+{
+#ifdef _DEBUG
+       std::string module_str = "BlueHancUtils64_d.dll";
+#else
+       std::string module_str = "BlueHancUtils64.dll";
+#endif
+       
+       auto module = LoadLibrary(u16(module_str).c_str());
+       if(!module)
+               LoadLibrary(u16(std::string(getenv("SystemDrive")) + "\\Program Files\\Bluefish444\\Driver\\" + module_str).c_str());
+       if(!module)
+               LoadLibrary(u16(std::string(getenv("SystemDrive")) + "\\Program Files (x86)\\BlueFish444\\Driver\\" + module_str).c_str());
+       if(!module)
+               CASPAR_THROW_EXCEPTION(file_not_found() << msg_info("Could not find BlueHancUtils.dll. Required drivers are not installed."));
+       static std::shared_ptr<void> lib(module, FreeLibrary);
+       encode_hanc_frame        = reinterpret_cast<decltype(encode_hanc_frame)>(GetProcAddress(module, "encode_hanc_frame"));
+       encode_hanc_frame_ex = reinterpret_cast<decltype(encode_hanc_frame_ex)>(GetProcAddress(module, "encode_hanc_frame_ex"));
+}
+
+void blue_initialize()
+{
+       blue_hanc_initialize();
+       blue_velvet_initialize();
+}
+
+EVideoMode vid_fmt_from_video_format(const core::video_format& fmt) 
+{
+       switch(fmt.value())
+       {
+       case core::video_format::pal:                   return VID_FMT_PAL;
+       case core::video_format::ntsc:                  return VID_FMT_NTSC;
+       case core::video_format::x576p2500:             return VID_FMT_INVALID; //not supported
+       case core::video_format::x720p2500:             return VID_FMT_720P_2500;
+       case core::video_format::x720p5000:             return VID_FMT_720P_5000;
+       case core::video_format::x720p5994:             return VID_FMT_720P_5994;
+       case core::video_format::x720p6000:             return VID_FMT_720P_6000;
+       case core::video_format::x1080p2397:    return VID_FMT_1080P_2397;
+       case core::video_format::x1080p2400:    return VID_FMT_1080P_2400;
+       case core::video_format::x1080i5000:    return VID_FMT_1080I_5000;
+       case core::video_format::x1080i5994:    return VID_FMT_1080I_5994;
+       case core::video_format::x1080i6000:    return VID_FMT_1080I_6000;
+       case core::video_format::x1080p2500:    return VID_FMT_1080P_2500;
+       case core::video_format::x1080p2997:    return VID_FMT_1080P_2997;
+       case core::video_format::x1080p3000:    return VID_FMT_1080P_3000;
+       case core::video_format::x1080p5000:    return VID_FMT_1080P_5000;
+       default:                                                                return VID_FMT_INVALID;
+       }
+}
+
+bool is_epoch_card(CBlueVelvet4& blue)
+{
+       switch(blue.has_video_cardtype())
+       {
+       case CRD_BLUE_EPOCH_HORIZON:
+       case CRD_BLUE_EPOCH_CORE:
+       case CRD_BLUE_EPOCH_ULTRA:
+       case CRD_BLUE_EPOCH_2K_HORIZON:
+       case CRD_BLUE_EPOCH_2K_CORE:
+       case CRD_BLUE_EPOCH_2K_ULTRA:
+       case CRD_BLUE_CREATE_HD:
+       case CRD_BLUE_CREATE_2K:
+       case CRD_BLUE_CREATE_2K_ULTRA:
+       case CRD_BLUE_SUPER_NOVA:
+               return true;
+       default:
+               return false;
+       }
+}
+
+std::wstring get_card_desc(CBlueVelvet4& blue)
+{
+       switch(blue.has_video_cardtype()) 
+       {
+       case CRD_BLUEDEEP_LT:                           return L"Deepblue LT";// D64 Lite
+       case CRD_BLUEDEEP_SD:                           return L"Iridium SD";// Iridium SD
+       case CRD_BLUEDEEP_AV:                           return L"Iridium AV";// Iridium AV
+       case CRD_BLUEDEEP_IO:                           return L"Deepblue IO";// D64 Full
+       case CRD_BLUEWILD_AV:                           return L"Wildblue AV";// D64 AV
+       case CRD_IRIDIUM_HD:                            return L"Iridium HD";// * Iridium HD
+       case CRD_BLUEWILD_RT:                           return L"Wildblue RT";// D64 RT
+       case CRD_BLUEWILD_HD:                           return L"Wildblue HD";// * BadAss G2
+       case CRD_REDDEVIL:                                      return L"Iridium Full";// Iridium Full
+       case CRD_BLUEDEEP_HD:   
+       case CRD_BLUEDEEP_HDS:                          return L"Reserved for \"BasAss G2";// * BadAss G2 variant, proposed, reserved
+       case CRD_BLUE_ENVY:                                     return L"Blue Envy"; // Mini Din 
+       case CRD_BLUE_PRIDE:                            return L"Blue Pride";//Mini Din Output 
+       case CRD_BLUE_GREED:                            return L"Blue Greed";
+       case CRD_BLUE_INGEST:                           return L"Blue Ingest";
+       case CRD_BLUE_SD_DUALLINK:                      return L"Blue SD Duallink";
+       case CRD_BLUE_CATALYST:                         return L"Blue Catalyst";
+       case CRD_BLUE_SD_DUALLINK_PRO:          return L"Blue SD Duallink Pro";
+       case CRD_BLUE_SD_INGEST_PRO:            return L"Blue SD Ingest pro";
+       case CRD_BLUE_SD_DEEPBLUE_LITE_PRO:     return L"Blue SD Deepblue lite Pro";
+       case CRD_BLUE_SD_SINGLELINK_PRO:        return L"Blue SD Singlelink Pro";
+       case CRD_BLUE_SD_IRIDIUM_AV_PRO:        return L"Blue SD Iridium AV Pro";
+       case CRD_BLUE_SD_FIDELITY:                      return L"Blue SD Fidelity";
+       case CRD_BLUE_SD_FOCUS:                         return L"Blue SD Focus";
+       case CRD_BLUE_SD_PRIME:                         return L"Blue SD Prime";
+       case CRD_BLUE_EPOCH_2K_CORE:            return L"Blue Epoch 2K Core";
+       case CRD_BLUE_EPOCH_2K_ULTRA:           return L"Blue Epoch 2K Ultra";
+       case CRD_BLUE_EPOCH_HORIZON:            return L"Blue Epoch Horizon";
+       case CRD_BLUE_EPOCH_CORE:                       return L"Blue Epoch Core";
+       case CRD_BLUE_EPOCH_ULTRA:                      return L"Blue Epoch Ultra";
+       case CRD_BLUE_CREATE_HD:                        return L"Blue Create HD";
+       case CRD_BLUE_CREATE_2K:                        return L"Blue Create 2K";
+       case CRD_BLUE_CREATE_2K_ULTRA:          return L"Blue Create 2K Ultra";
+       default:                                                        return L"Unknown";
+       }
+}
+
+EVideoMode get_video_mode(CBlueVelvet4& blue, const core::video_format_desc& format_desc)
+{
+       EVideoMode vid_fmt = VID_FMT_INVALID;
+       auto desiredVideoFormat = vid_fmt_from_video_format(format_desc.format);
+       int videoModeCount = blue.count_video_mode();
+       for(int videoModeIndex = 1; videoModeIndex <= videoModeCount; ++videoModeIndex) 
+       {
+               EVideoMode videoMode = blue.enum_video_mode(videoModeIndex);
+               if(videoMode == desiredVideoFormat) 
+                       vid_fmt = videoMode;                    
+       }
+       if(vid_fmt == VID_FMT_INVALID)
+               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("video-mode not supported.") << arg_value_info(format_desc.name));
+
+       return vid_fmt;
+}
+
+spl::shared_ptr<CBlueVelvet4> create_blue()
+{
+       if(!BlueVelvetFactory4 || !encode_hanc_frame || !encode_hanc_frame)
+               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Bluefish drivers not found."));
+
+       return spl::shared_ptr<CBlueVelvet4>(BlueVelvetFactory4(), BlueVelvetDestroy);
+}
+
+spl::shared_ptr<CBlueVelvet4> create_blue(int device_index)
+{
+       auto blue = create_blue();
+       
+       if(BLUE_FAIL(blue->device_attach(device_index, FALSE))) 
+               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to attach device."));
+
+       return blue;
+}
+
 }}
\ No newline at end of file
index 08273f62eddbcfcba86feb8134471e7a1d72a048..e18cfbc45595ff3b85b8c1a98d62264f80cf007a 100644 (file)
@@ -1,63 +1,63 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <Windows.h>\r
-\r
-#include <BlueVelvet4.h>\r
-#include <BlueHancUtils.h>\r
-\r
-#include <common/memory.h>\r
-#include <common/except.h>\r
-\r
-namespace caspar { \r
-\r
-namespace core {\r
-\r
-struct video_format_desc;\r
-\r
-}\r
-\r
-namespace bluefish {\r
-\r
-extern const char* (*BlueVelvetVersion)();\r
-extern BLUE_UINT32 (*encode_hanc_frame)(struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr,BLUE_UINT32 no_audio_ch,BLUE_UINT32 no_audio_samples,BLUE_UINT32 nTypeOfSample,BLUE_UINT32 emb_audio_flag);\r
-extern BLUE_UINT32 (*encode_hanc_frame_ex)(BLUE_UINT32 card_type, struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr, BLUE_UINT32 no_audio_ch,     BLUE_UINT32 no_audio_samples, BLUE_UINT32 nTypeOfSample, BLUE_UINT32 emb_audio_flag);\r
-\r
-void blue_initialize();\r
-\r
-spl::shared_ptr<CBlueVelvet4> create_blue();\r
-spl::shared_ptr<CBlueVelvet4> create_blue(int device_index);\r
-bool is_epoch_card(CBlueVelvet4& blue);\r
-std::wstring get_card_desc(CBlueVelvet4& blue);\r
-EVideoMode get_video_mode(CBlueVelvet4& blue, const core::video_format_desc& format_desc);\r
-\r
-template<typename T>\r
-int set_card_property(T& pSdk, ULONG prop, ULONG value)\r
-{\r
-       VARIANT variantValue;\r
-       variantValue.vt  = VT_UI4;\r
-       variantValue.ulVal = value;\r
-       return (pSdk->SetCardProperty(prop,variantValue));\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <Windows.h>
+
+#include <BlueVelvet4.h>
+#include <BlueHancUtils.h>
+
+#include <common/memory.h>
+#include <common/except.h>
+
+namespace caspar { 
+
+namespace core {
+
+struct video_format_desc;
+
+}
+
+namespace bluefish {
+
+extern const char* (*BlueVelvetVersion)();
+extern BLUE_UINT32 (*encode_hanc_frame)(struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr,BLUE_UINT32 no_audio_ch,BLUE_UINT32 no_audio_samples,BLUE_UINT32 nTypeOfSample,BLUE_UINT32 emb_audio_flag);
+extern BLUE_UINT32 (*encode_hanc_frame_ex)(BLUE_UINT32 card_type, struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr, BLUE_UINT32 no_audio_ch,     BLUE_UINT32 no_audio_samples, BLUE_UINT32 nTypeOfSample, BLUE_UINT32 emb_audio_flag);
+
+void blue_initialize();
+
+spl::shared_ptr<CBlueVelvet4> create_blue();
+spl::shared_ptr<CBlueVelvet4> create_blue(int device_index);
+bool is_epoch_card(CBlueVelvet4& blue);
+std::wstring get_card_desc(CBlueVelvet4& blue);
+EVideoMode get_video_mode(CBlueVelvet4& blue, const core::video_format_desc& format_desc);
+
+template<typename T>
+int set_card_property(T& pSdk, ULONG prop, ULONG value)
+{
+       VARIANT variantValue;
+       variantValue.vt  = VT_UI4;
+       variantValue.ulVal = value;
+       return (pSdk->SetCardProperty(prop,variantValue));
+}
+
 }}
\ No newline at end of file
index 9299fdb1f8f5690847f555e8b4224b8e940c53eb..3de2922800fe2929f4a0db0bfe48117d98716d61 100644 (file)
@@ -1,64 +1,64 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <Windows.h>\r
-\r
-#include <BlueVelvet4.h>\r
-\r
-#include <common/page_locked_allocator.h>\r
-\r
-#include <vector>\r
-\r
-namespace caspar { namespace bluefish {\r
-       \r
-static const size_t MAX_HANC_BUFFER_SIZE = 256*1024;\r
-static const size_t MAX_VBI_BUFFER_SIZE = 36*1920*4;\r
-\r
-struct blue_dma_buffer\r
-{\r
-public:\r
-       blue_dma_buffer(int image_size, int id) \r
-               : id_(id)\r
-               , image_size_(image_size)\r
-               , hanc_size_(MAX_HANC_BUFFER_SIZE)\r
-               , image_buffer_(image_size_)\r
-               , hanc_buffer_(hanc_size_){}\r
-                       \r
-       int id() const {return id_;}\r
-\r
-       PBYTE image_data() { return image_buffer_.data(); }\r
-       PBYTE hanc_data() { return hanc_buffer_.data(); }\r
-\r
-       size_t image_size() const { return image_size_; }\r
-       size_t hanc_size() const { return hanc_size_; }\r
-\r
-private:       \r
-       int id_;\r
-       size_t image_size_;\r
-       size_t hanc_size_;\r
-       std::vector<BYTE, page_locked_allocator<BYTE>> image_buffer_;   \r
-       std::vector<BYTE, page_locked_allocator<BYTE>> hanc_buffer_;\r
-};\r
-typedef std::shared_ptr<blue_dma_buffer> blue_dma_buffer_ptr;\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <Windows.h>
+
+#include <BlueVelvet4.h>
+
+#include <common/page_locked_allocator.h>
+
+#include <vector>
+
+namespace caspar { namespace bluefish {
+       
+static const size_t MAX_HANC_BUFFER_SIZE = 256*1024;
+static const size_t MAX_VBI_BUFFER_SIZE = 36*1920*4;
+
+struct blue_dma_buffer
+{
+public:
+       blue_dma_buffer(int image_size, int id) 
+               : id_(id)
+               , image_size_(image_size)
+               , hanc_size_(MAX_HANC_BUFFER_SIZE)
+               , image_buffer_(image_size_)
+               , hanc_buffer_(hanc_size_){}
+                       
+       int id() const {return id_;}
+
+       PBYTE image_data() { return image_buffer_.data(); }
+       PBYTE hanc_data() { return hanc_buffer_.data(); }
+
+       size_t image_size() const { return image_size_; }
+       size_t hanc_size() const { return hanc_size_; }
+
+private:       
+       int id_;
+       size_t image_size_;
+       size_t hanc_size_;
+       std::vector<BYTE, page_locked_allocator<BYTE>> image_buffer_;   
+       std::vector<BYTE, page_locked_allocator<BYTE>> hanc_buffer_;
+};
+typedef std::shared_ptr<blue_dma_buffer> blue_dma_buffer_ptr;
+
 }}
\ No newline at end of file
index 61ffa6908b87254ce5fead0b23bb30d825b1dd24..23371bf627c5eb1324da37b67e08fa2359e6f3a9 100644 (file)
@@ -1,25 +1,25 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "stdafx.h"\r
-\r
-// TODO: reference any additional headers you need in STDAFX.H\r
-// and not in this file\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
index fabfdbff07b7cdadd8e3ab64045f19ecb09417a3..4bbb43219ced951be84a6584fe6f026b1d4b55a7 100644 (file)
@@ -1,86 +1,86 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#ifdef _DEBUG\r
-#include <crtdbg.h>\r
-#endif\r
-\r
-#define NOMINMAX\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
-#include <Windows.h>\r
-\r
-#include <algorithm>\r
-#include <array>\r
-#include <assert.h>\r
-#include <deque>\r
-#include <functional>\r
-#include <math.h>\r
-#include <memory>\r
-#include <queue>\r
-#include <string>\r
-#include <vector>\r
-#include <tbb/atomic.h>\r
-#include <tbb/concurrent_queue.h>\r
-#include <tbb/cache_aligned_allocator.h>\r
-#include <boost/assign.hpp>\r
-#include <boost/circular_buffer.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/range.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/algorithm/string.hpp>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
-       #define __STDC_LIMIT_MACROS\r
-       #include <libavcodec/avcodec.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-#pragma warning(push)\r
-#pragma warning(disable : 4996)\r
-\r
-       #include <atlbase.h>\r
-\r
-       #include <atlcom.h>\r
-       #include <atlhost.h>\r
-\r
-#pragma warning(push)\r
-\r
-#include <functional>\r
-\r
-\r
-#include "../common/memory.h"\r
-#include "../common/utf.h"\r
-#include "../common/except.h"\r
-#include "../common/log.h"\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+
+#include <Windows.h>
+
+#include <algorithm>
+#include <array>
+#include <assert.h>
+#include <deque>
+#include <functional>
+#include <math.h>
+#include <memory>
+#include <queue>
+#include <string>
+#include <vector>
+#include <tbb/atomic.h>
+#include <tbb/concurrent_queue.h>
+#include <tbb/cache_aligned_allocator.h>
+#include <boost/assign.hpp>
+#include <boost/circular_buffer.hpp>
+#include <boost/timer.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/range.hpp>
+#include <boost/range/algorithm.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/algorithm/string.hpp>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #define __STDC_CONSTANT_MACROS
+       #define __STDC_LIMIT_MACROS
+       #include <libavcodec/avcodec.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+#pragma warning(push)
+#pragma warning(disable : 4996)
+
+       #include <atlbase.h>
+
+       #include <atlcom.h>
+       #include <atlhost.h>
+
+#pragma warning(push)
+
+#include <functional>
+
+
+#include "../common/memory.h"
+#include "../common/utf.h"
+#include "../common/except.h"
+#include "../common/log.h"
index 185207e13a3ce604588b7bff0d4832ebdfa83ab1..73a39432aa5e3b358e8aaf22b3a26ea567f728c9 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../StdAfx.h"\r
\r
-#include "decklink_consumer.h"\r
-\r
-#include "../util/util.h"\r
-\r
-#include "../interop/DeckLinkAPI_h.h"\r
-\r
-#include <core/frame/frame.h>\r
-#include <core/mixer/audio/audio_mixer.h>\r
-\r
-#include <common/executor.h>\r
-#include <common/lock.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/except.h>\r
-#include <common/memshfl.h>\r
-#include <common/array.h>\r
-\r
-#include <core/consumer/frame_consumer.h>\r
-\r
-#include <tbb/concurrent_queue.h>\r
-#include <tbb/cache_aligned_allocator.h>\r
-\r
-#include <common/assert.h>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/circular_buffer.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-namespace caspar { namespace decklink { \r
-       \r
-struct configuration\r
-{\r
-       enum keyer_t\r
-       {\r
-               internal_keyer,\r
-               external_keyer,\r
-               default_keyer\r
-       };\r
-\r
-       enum latency_t\r
-       {\r
-               low_latency,\r
-               normal_latency,\r
-               default_latency\r
-       };\r
-\r
-       int                     device_index;\r
-       bool            embedded_audio;\r
-       keyer_t         keyer;\r
-       latency_t       latency;\r
-       bool            key_only;\r
-       int                     base_buffer_depth;\r
-       \r
-       configuration()\r
-               : device_index(1)\r
-               , embedded_audio(true)\r
-               , keyer(default_keyer)\r
-               , latency(default_latency)\r
-               , key_only(false)\r
-               , base_buffer_depth(3)\r
-       {\r
-       }\r
-       \r
-       int buffer_depth() const\r
-       {\r
-               return base_buffer_depth + (latency == low_latency ? 0 : 1) + (embedded_audio ? 1 : 0);\r
-       }\r
-};\r
-\r
-class decklink_frame : public IDeckLinkVideoFrame\r
-{\r
-       tbb::atomic<int>                                                                                        ref_count_;\r
-       core::const_frame                                                                                       frame_;\r
-       const core::video_format_desc                                                           format_desc_;\r
-\r
-       const bool                                                                                                      key_only_;\r
-       std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>> data_;\r
-public:\r
-       decklink_frame(core::const_frame frame, const core::video_format_desc& format_desc, bool key_only)\r
-               : frame_(frame)\r
-               , format_desc_(format_desc)\r
-               , key_only_(key_only)\r
-       {\r
-               ref_count_ = 0;\r
-       }\r
-       \r
-       // IUnknown\r
-\r
-       STDMETHOD (QueryInterface(REFIID, LPVOID*))             \r
-       {\r
-               return E_NOINTERFACE;\r
-       }\r
-       \r
-       STDMETHOD_(ULONG,                       AddRef())                       \r
-       {\r
-               return ++ref_count_;\r
-       }\r
-\r
-       STDMETHOD_(ULONG,                       Release())                      \r
-       {\r
-               if(--ref_count_ == 0)\r
-                       delete this;\r
-               return ref_count_;\r
-       }\r
-\r
-       // IDecklinkVideoFrame\r
-\r
-       STDMETHOD_(long,                        GetWidth())                     {return static_cast<long>(format_desc_.width);}        \r
-    STDMETHOD_(long,                   GetHeight())            {return static_cast<long>(format_desc_.height);}        \r
-    STDMETHOD_(long,                   GetRowBytes())          {return static_cast<long>(format_desc_.width*4);}        \r
-       STDMETHOD_(BMDPixelFormat,      GetPixelFormat())       {return bmdFormat8BitBGRA;}        \r
-    STDMETHOD_(BMDFrameFlags,  GetFlags())                     {return bmdFrameFlagDefault;}\r
-        \r
-    STDMETHOD(GetBytes(void** buffer))\r
-       {\r
-               try\r
-               {\r
-                       if(static_cast<int>(frame_.image_data().size()) != format_desc_.size)\r
-                       {\r
-                               data_.resize(format_desc_.size, 0);\r
-                               *buffer = data_.data();\r
-                       }\r
-                       else if(key_only_)\r
-                       {\r
-                               if(data_.empty())\r
-                               {\r
-                                       data_.resize(frame_.image_data().size());\r
-                                       aligned_memshfl(data_.data(), frame_.image_data().begin(), frame_.image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
-                               }\r
-                               *buffer = data_.data();\r
-                       }\r
-                       else\r
-                               *buffer = const_cast<uint8_t*>(frame_.image_data().begin());\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       return E_FAIL;\r
-               }\r
-\r
-               return S_OK;\r
-       }\r
-        \r
-    STDMETHOD(GetTimecode(BMDTimecodeFormat format, IDeckLinkTimecode** timecode)){return S_FALSE;}        \r
-    STDMETHOD(GetAncillaryData(IDeckLinkVideoFrameAncillary** ancillary))                {return S_FALSE;}\r
-\r
-       // decklink_frame       \r
-\r
-       const core::audio_buffer& audio_data()\r
-       {\r
-               return frame_.audio_data();\r
-       }\r
-};\r
-\r
-struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable\r
-{              \r
-       const int                                                       channel_index_;\r
-       const configuration                                     config_;\r
-\r
-       CComPtr<IDeckLink>                                      decklink_;\r
-       CComQIPtr<IDeckLinkOutput>                      output_;\r
-       CComQIPtr<IDeckLinkConfiguration>       configuration_;\r
-       CComQIPtr<IDeckLinkKeyer>                       keyer_;\r
-       CComQIPtr<IDeckLinkAttributes>          attributes_;\r
-\r
-       tbb::spin_mutex                                         exception_mutex_;\r
-       std::exception_ptr                                      exception_;\r
-\r
-       tbb::atomic<bool>                                       is_running_;\r
-               \r
-       const std::wstring                                      model_name_;\r
-       const core::video_format_desc           format_desc_;\r
-       const int                                                       buffer_size_;\r
-\r
-       long long                                                       video_scheduled_;\r
-       long long                                                       audio_scheduled_;\r
-\r
-       int                                                                     preroll_count_;\r
-               \r
-       boost::circular_buffer<std::vector<int32_t>>    audio_container_;\r
-\r
-       tbb::concurrent_bounded_queue<core::const_frame> video_frame_buffer_;\r
-       tbb::concurrent_bounded_queue<core::const_frame> audio_frame_buffer_;\r
-       \r
-       spl::shared_ptr<diagnostics::graph> graph_;\r
-       boost::timer tick_timer_;\r
-\r
-public:\r
-       decklink_consumer(const configuration& config, const core::video_format_desc& format_desc, int channel_index) \r
-               : channel_index_(channel_index)\r
-               , config_(config)\r
-               , decklink_(get_device(config.device_index))\r
-               , output_(decklink_)\r
-               , configuration_(decklink_)\r
-               , keyer_(decklink_)\r
-               , attributes_(decklink_)\r
-               , model_name_(get_model_name(decklink_))\r
-               , format_desc_(format_desc)\r
-               , buffer_size_(config.buffer_depth()) // Minimum buffer-size 3.\r
-               , video_scheduled_(0)\r
-               , audio_scheduled_(0)\r
-               , preroll_count_(0)\r
-               , audio_container_(buffer_size_+1)\r
-       {\r
-               is_running_ = true;\r
-                               \r
-               video_frame_buffer_.set_capacity(1);\r
-               audio_frame_buffer_.set_capacity(1);\r
-\r
-               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   \r
-               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));\r
-               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));\r
-               graph_->set_color("flushed-frame", diagnostics::color(0.4f, 0.3f, 0.8f));\r
-               graph_->set_color("buffered-audio", diagnostics::color(0.9f, 0.9f, 0.5f));\r
-               graph_->set_color("buffered-video", diagnostics::color(0.2f, 0.9f, 0.9f));\r
-               graph_->set_text(print());\r
-               diagnostics::register_graph(graph_);\r
-               \r
-               enable_video(get_display_mode(output_, format_desc_.format, bmdFormat8BitBGRA, bmdVideoOutputFlagDefault));\r
-                               \r
-               if(config.embedded_audio)\r
-                       enable_audio();\r
-               \r
-               set_latency(config.latency);                            \r
-               set_keyer(config.keyer);\r
-                               \r
-               if(config.embedded_audio)               \r
-                       output_->BeginAudioPreroll();           \r
-               \r
-               for(int n = 0; n < buffer_size_; ++n)\r
-                       schedule_next_video(core::const_frame::empty());\r
-\r
-               if(!config.embedded_audio)\r
-                       start_playback();\r
-       }\r
-\r
-       ~decklink_consumer()\r
-       {               \r
-               is_running_ = false;\r
-               video_frame_buffer_.try_push(core::const_frame::empty());\r
-               audio_frame_buffer_.try_push(core::const_frame::empty());\r
-\r
-               if(output_ != nullptr) \r
-               {\r
-                       output_->StopScheduledPlayback(0, nullptr, 0);\r
-                       if(config_.embedded_audio)\r
-                               output_->DisableAudioOutput();\r
-                       output_->DisableVideoOutput();\r
-               }\r
-       }\r
-                       \r
-       void set_latency(configuration::latency_t latency)\r
-       {               \r
-               if(latency == configuration::low_latency)\r
-               {\r
-                       configuration_->SetFlag(bmdDeckLinkConfigLowLatencyVideoOutput, true);\r
-                       CASPAR_LOG(info) << print() << L" Enabled low-latency mode.";\r
-               }\r
-               else if(latency == configuration::normal_latency)\r
-               {                       \r
-                       configuration_->SetFlag(bmdDeckLinkConfigLowLatencyVideoOutput, false);\r
-                       CASPAR_LOG(info) << print() << L" Disabled low-latency mode.";\r
-               }\r
-       }\r
-\r
-       void set_keyer(configuration::keyer_t keyer)\r
-       {\r
-               if(keyer == configuration::internal_keyer) \r
-               {\r
-                       BOOL value = true;\r
-                       if(SUCCEEDED(attributes_->GetFlag(BMDDeckLinkSupportsInternalKeying, &value)) && !value)\r
-                               CASPAR_LOG(error) << print() << L" Failed to enable internal keyer.";   \r
-                       else if(FAILED(keyer_->Enable(FALSE)))                  \r
-                               CASPAR_LOG(error) << print() << L" Failed to enable internal keyer.";                   \r
-                       else if(FAILED(keyer_->SetLevel(255)))                  \r
-                               CASPAR_LOG(error) << print() << L" Failed to set key-level to max.";\r
-                       else\r
-                               CASPAR_LOG(info) << print() << L" Enabled internal keyer.";             \r
-               }\r
-               else if(keyer == configuration::external_keyer)\r
-               {\r
-                       BOOL value = true;\r
-                       if(SUCCEEDED(attributes_->GetFlag(BMDDeckLinkSupportsExternalKeying, &value)) && !value)\r
-                               CASPAR_LOG(error) << print() << L" Failed to enable external keyer.";   \r
-                       else if(FAILED(keyer_->Enable(TRUE)))                   \r
-                               CASPAR_LOG(error) << print() << L" Failed to enable external keyer.";   \r
-                       else if(FAILED(keyer_->SetLevel(255)))                  \r
-                               CASPAR_LOG(error) << print() << L" Failed to set key-level to max.";\r
-                       else\r
-                               CASPAR_LOG(info) << print() << L" Enabled external keyer.";                     \r
-               }\r
-       }\r
-       \r
-       void enable_audio()\r
-       {\r
-               if(FAILED(output_->EnableAudioOutput(bmdAudioSampleRate48kHz, bmdAudioSampleType32bitInteger, 2, bmdAudioOutputStreamTimestamped)))\r
-                               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Could not enable audio output."));\r
-                               \r
-               if(FAILED(output_->SetAudioCallback(this)))\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Could not set audio callback."));\r
-\r
-               CASPAR_LOG(info) << print() << L" Enabled embedded-audio.";\r
-       }\r
-\r
-       void enable_video(BMDDisplayMode display_mode)\r
-       {\r
-               if(FAILED(output_->EnableVideoOutput(display_mode, bmdVideoOutputFlagDefault))) \r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Could not enable video output."));\r
-               \r
-               if(FAILED(output_->SetScheduledFrameCompletionCallback(this)))\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() \r
-                                                                       << msg_info(u8(print()) + " Failed to set playback completion callback.")\r
-                                                                       << boost::errinfo_api_function("SetScheduledFrameCompletionCallback"));\r
-       }\r
-\r
-       void start_playback()\r
-       {\r
-               if(FAILED(output_->StartScheduledPlayback(0, format_desc_.time_scale, 1.0))) \r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Failed to schedule playback."));\r
-       }\r
-       \r
-       STDMETHOD (QueryInterface(REFIID, LPVOID*))     {return E_NOINTERFACE;}\r
-       STDMETHOD_(ULONG, AddRef())                                     {return 1;}\r
-       STDMETHOD_(ULONG, Release())                            {return 1;}\r
-       \r
-       STDMETHOD(ScheduledPlaybackHasStopped())\r
-       {\r
-               is_running_ = false;\r
-               CASPAR_LOG(info) << print() << L" Scheduled playback has stopped.";\r
-               return S_OK;\r
-       }\r
-\r
-       STDMETHOD(ScheduledFrameCompleted(IDeckLinkVideoFrame* completed_frame, BMDOutputFrameCompletionResult result))\r
-       {\r
-               if(!is_running_)\r
-                       return E_FAIL;\r
-               \r
-               try\r
-               {\r
-                       if(result == bmdOutputFrameDisplayedLate)\r
-                       {\r
-                               graph_->set_tag("late-frame");\r
-                               video_scheduled_ += format_desc_.duration;\r
-                               audio_scheduled_ += reinterpret_cast<decklink_frame*>(completed_frame)->audio_data().size()/format_desc_.audio_channels;\r
-                               //++video_scheduled_;\r
-                               //audio_scheduled_ += format_desc_.audio_cadence[0];\r
-                               //++audio_scheduled_;\r
-                       }\r
-                       else if(result == bmdOutputFrameDropped)\r
-                               graph_->set_tag("dropped-frame");\r
-                       else if(result == bmdOutputFrameFlushed)\r
-                               graph_->set_tag("flushed-frame");\r
-\r
-                       auto frame = core::const_frame::empty();        \r
-                       video_frame_buffer_.pop(frame);                                 \r
-                       schedule_next_video(frame);     \r
-                       \r
-                       unsigned long buffered;\r
-                       output_->GetBufferedVideoFrameCount(&buffered);\r
-                       graph_->set_value("buffered-video", static_cast<double>(buffered)/format_desc_.fps);\r
-               }\r
-               catch(...)\r
-               {\r
-                       lock(exception_mutex_, [&]\r
-                       {\r
-                               exception_ = std::current_exception();\r
-                       });\r
-                       return E_FAIL;\r
-               }\r
-\r
-               return S_OK;\r
-       }\r
-               \r
-       STDMETHOD(RenderAudioSamples(BOOL preroll))\r
-       {\r
-               if(!is_running_)\r
-                       return E_FAIL;\r
-               \r
-               try\r
-               {       \r
-                       if(preroll)\r
-                       {\r
-                               if(++preroll_count_ >= buffer_size_)\r
-                               {\r
-                                       output_->EndAudioPreroll();\r
-                                       start_playback();                               \r
-                               }\r
-                               else\r
-                                       schedule_next_audio(core::audio_buffer(format_desc_.audio_cadence[preroll % format_desc_.audio_cadence.size()], 0));    \r
-                       }\r
-                       else\r
-                       {\r
-                               auto frame = core::const_frame::empty();\r
-                               audio_frame_buffer_.pop(frame);\r
-                               schedule_next_audio(frame.audio_data());\r
-                       }\r
-\r
-                       unsigned long buffered;\r
-                       output_->GetBufferedAudioSampleFrameCount(&buffered);\r
-                       graph_->set_value("buffered-audio", static_cast<double>(buffered)/(format_desc_.audio_cadence[0]*2));\r
-               }\r
-               catch(...)\r
-               {\r
-                       tbb::spin_mutex::scoped_lock lock(exception_mutex_);\r
-                       exception_ = std::current_exception();\r
-                       return E_FAIL;\r
-               }\r
-\r
-               return S_OK;\r
-       }\r
-\r
-       template<typename T>\r
-       void schedule_next_audio(const T& audio_data)\r
-       {\r
-               auto sample_frame_count = static_cast<int>(audio_data.size()/format_desc_.audio_channels);\r
-\r
-               audio_container_.push_back(std::vector<int32_t>(audio_data.begin(), audio_data.end()));\r
-\r
-               if(FAILED(output_->ScheduleAudioSamples(audio_container_.back().data(), sample_frame_count, audio_scheduled_, format_desc_.audio_sample_rate, nullptr)))\r
-                       CASPAR_LOG(error) << print() << L" Failed to schedule audio.";\r
-\r
-               audio_scheduled_ += sample_frame_count;\r
-       }\r
-                       \r
-       void schedule_next_video(core::const_frame frame)\r
-       {\r
-               CComPtr<IDeckLinkVideoFrame> frame2(new decklink_frame(frame, format_desc_, config_.key_only));\r
-               if(FAILED(output_->ScheduleVideoFrame(frame2, video_scheduled_, format_desc_.duration, format_desc_.time_scale)))\r
-                       CASPAR_LOG(error) << print() << L" Failed to schedule video.";\r
-\r
-               video_scheduled_ += format_desc_.duration;\r
-\r
-               graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5);\r
-               tick_timer_.restart();\r
-       }\r
-\r
-       void send(core::const_frame frame)\r
-       {\r
-               auto exception = lock(exception_mutex_, [&]\r
-               {\r
-                       return exception_;\r
-               });\r
-\r
-               if(exception != nullptr)\r
-                       std::rethrow_exception(exception);              \r
-\r
-               if(!is_running_)\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Is not running."));\r
-               \r
-               if(config_.embedded_audio)\r
-                       audio_frame_buffer_.push(frame);        \r
-               video_frame_buffer_.push(frame);        \r
-       }\r
-       \r
-       std::wstring print() const\r
-       {\r
-               return model_name_ + L" [" + boost::lexical_cast<std::wstring>(channel_index_) + L"-" +\r
-                       boost::lexical_cast<std::wstring>(config_.device_index) + L"|" +  format_desc_.name + L"]";\r
-       }\r
-};\r
-\r
-struct decklink_consumer_proxy : public core::frame_consumer\r
-{\r
-       const configuration                                     config_;\r
-       std::unique_ptr<decklink_consumer>      consumer_;\r
-       executor                                                        executor_;\r
-public:\r
-\r
-       decklink_consumer_proxy(const configuration& config)\r
-               : config_(config)\r
-               , executor_(L"decklink_consumer[" + boost::lexical_cast<std::wstring>(config.device_index) + L"]")\r
-       {\r
-               executor_.begin_invoke([=]\r
-               {\r
-                       ::CoInitialize(nullptr);\r
-               });\r
-       }\r
-\r
-       ~decklink_consumer_proxy()\r
-       {\r
-               executor_.invoke([=]\r
-               {\r
-                       ::CoUninitialize();\r
-               });\r
-       }\r
-\r
-       // frame_consumer\r
-       \r
-       void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
-       {\r
-               executor_.invoke([=]\r
-               {\r
-                       consumer_.reset();\r
-                       consumer_.reset(new decklink_consumer(config_, format_desc, channel_index));                    \r
-               });\r
-       }\r
-       \r
-       bool send(core::const_frame frame) override\r
-       {\r
-               consumer_->send(frame);\r
-               return true;\r
-       }\r
-       \r
-       std::wstring print() const override\r
-       {\r
-               return consumer_ ? consumer_->print() : L"[decklink_consumer]";\r
-       }               \r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"decklink";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"decklink");\r
-               info.add(L"key-only", config_.key_only);\r
-               info.add(L"device", config_.device_index);\r
-               info.add(L"low-latency", config_.low_latency);\r
-               info.add(L"embedded-audio", config_.embedded_audio);\r
-               info.add(L"low-latency", config_.low_latency);\r
-               //info.add(L"internal-key", config_.internal_key);\r
-               return info;\r
-       }\r
-\r
-       int buffer_depth() const override\r
-       {\r
-               return config_.buffer_depth();\r
-       }\r
-\r
-       int index() const override\r
-       {\r
-               return 300 + config_.device_index;\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }       \r
-};     \r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params) \r
-{\r
-       if(params.size() < 1 || params[0] != L"DECKLINK")\r
-               return core::frame_consumer::empty();\r
-       \r
-       configuration config;\r
-               \r
-       if(params.size() > 1)\r
-               config.device_index = boost::lexical_cast<int>(params[1]);\r
-       \r
-       if(std::find(params.begin(), params.end(), L"INTERNAL_KEY")                     != params.end())\r
-               config.keyer = configuration::internal_keyer;\r
-       else if(std::find(params.begin(), params.end(), L"EXTERNAL_KEY")        != params.end())\r
-               config.keyer = configuration::external_keyer;\r
-       else\r
-               config.keyer = configuration::default_keyer;\r
-\r
-       if(std::find(params.begin(), params.end(), L"LOW_LATENCY")       != params.end())\r
-               config.latency = configuration::low_latency;\r
-\r
-       config.embedded_audio   = std::find(params.begin(), params.end(), L"EMBEDDED_AUDIO") != params.end();\r
-       config.key_only                 = std::find(params.begin(), params.end(), L"KEY_ONLY")           != params.end();\r
-\r
-       return spl::make_shared<decklink_consumer_proxy>(config);\r
-}\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree) \r
-{\r
-       configuration config;\r
-\r
-       auto keyer = ptree.get(L"keyer", L"default");\r
-       if(keyer == L"external")\r
-               config.keyer = configuration::external_keyer;\r
-       else if(keyer == L"internal")\r
-               config.keyer = configuration::internal_keyer;\r
-\r
-       auto latency = ptree.get(L"latency", L"normal");\r
-       if(latency == L"low")\r
-               config.latency = configuration::low_latency;\r
-       else if(latency == L"normal")\r
-               config.latency = configuration::normal_latency;\r
-\r
-       config.key_only                         = ptree.get(L"key-only",                config.key_only);\r
-       config.device_index                     = ptree.get(L"device",                  config.device_index);\r
-       config.embedded_audio           = ptree.get(L"embedded-audio",  config.embedded_audio);\r
-       config.base_buffer_depth        = ptree.get(L"buffer-depth",    config.base_buffer_depth);\r
-\r
-       return spl::make_shared<decklink_consumer_proxy>(config);\r
-}\r
-\r
-}}\r
-\r
-/*\r
-##############################################################################\r
-Pre-rolling\r
-\r
-Mail: 2011-05-09\r
-\r
-Yoshan\r
-BMD Developer Support\r
-developer@blackmagic-design.com\r
-\r
------------------------------------------------------------------------------\r
-\r
-Thanks for your inquiry. The minimum number of frames that you can preroll \r
-for scheduled playback is three frames for video and four frames for audio. \r
-As you mentioned if you preroll less frames then playback will not start or\r
-playback will be very sporadic. From our experience with Media Express, we \r
-recommended that at least seven frames are prerolled for smooth playback. \r
-\r
-Regarding the bmdDeckLinkConfigLowLatencyVideoOutput flag:\r
-There can be around 3 frames worth of latency on scheduled output.\r
-When the bmdDeckLinkConfigLowLatencyVideoOutput flag is used this latency is\r
-reduced  or removed for scheduled playback. If the DisplayVideoFrameSync() \r
-method is used, the bmdDeckLinkConfigLowLatencyVideoOutput setting will \r
-guarantee that the provided frame will be output as soon the previous \r
-frame output has been completed.\r
-################################################################################\r
-*/\r
-\r
-/*\r
-##############################################################################\r
-Async DMA Transfer without redundant copying\r
-\r
-Mail: 2011-05-10\r
-\r
-Yoshan\r
-BMD Developer Support\r
-developer@blackmagic-design.com\r
-\r
------------------------------------------------------------------------------\r
-\r
-Thanks for your inquiry. You could try subclassing IDeckLinkMutableVideoFrame \r
-and providing a pointer to your video buffer when GetBytes() is called. \r
-This may help to keep copying to a minimum. Please ensure that the pixel \r
-format is in bmdFormat10BitYUV, otherwise the DeckLink API / driver will \r
-have to colourspace convert which may result in additional copying.\r
-################################################################################\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../StdAfx.h"
+#include "decklink_consumer.h"
+
+#include "../util/util.h"
+
+#include "../interop/DeckLinkAPI_h.h"
+
+#include <core/frame/frame.h>
+#include <core/mixer/audio/audio_mixer.h>
+
+#include <common/executor.h>
+#include <common/lock.h>
+#include <common/diagnostics/graph.h>
+#include <common/except.h>
+#include <common/memshfl.h>
+#include <common/array.h>
+
+#include <core/consumer/frame_consumer.h>
+
+#include <tbb/concurrent_queue.h>
+#include <tbb/cache_aligned_allocator.h>
+
+#include <common/assert.h>
+#include <boost/lexical_cast.hpp>
+#include <boost/circular_buffer.hpp>
+#include <boost/timer.hpp>
+#include <boost/property_tree/ptree.hpp>
+
+namespace caspar { namespace decklink { 
+       
+struct configuration
+{
+       enum keyer_t
+       {
+               internal_keyer,
+               external_keyer,
+               default_keyer
+       };
+
+       enum latency_t
+       {
+               low_latency,
+               normal_latency,
+               default_latency
+       };
+
+       int                     device_index;
+       bool            embedded_audio;
+       keyer_t         keyer;
+       latency_t       latency;
+       bool            key_only;
+       int                     base_buffer_depth;
+       
+       configuration()
+               : device_index(1)
+               , embedded_audio(true)
+               , keyer(default_keyer)
+               , latency(default_latency)
+               , key_only(false)
+               , base_buffer_depth(3)
+       {
+       }
+       
+       int buffer_depth() const
+       {
+               return base_buffer_depth + (latency == low_latency ? 0 : 1) + (embedded_audio ? 1 : 0);
+       }
+};
+
+class decklink_frame : public IDeckLinkVideoFrame
+{
+       tbb::atomic<int>                                                                                        ref_count_;
+       core::const_frame                                                                                       frame_;
+       const core::video_format_desc                                                           format_desc_;
+
+       const bool                                                                                                      key_only_;
+       std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>> data_;
+public:
+       decklink_frame(core::const_frame frame, const core::video_format_desc& format_desc, bool key_only)
+               : frame_(frame)
+               , format_desc_(format_desc)
+               , key_only_(key_only)
+       {
+               ref_count_ = 0;
+       }
+       
+       // IUnknown
+
+       STDMETHOD (QueryInterface(REFIID, LPVOID*))             
+       {
+               return E_NOINTERFACE;
+       }
+       
+       STDMETHOD_(ULONG,                       AddRef())                       
+       {
+               return ++ref_count_;
+       }
+
+       STDMETHOD_(ULONG,                       Release())                      
+       {
+               if(--ref_count_ == 0)
+                       delete this;
+               return ref_count_;
+       }
+
+       // IDecklinkVideoFrame
+
+       STDMETHOD_(long,                        GetWidth())                     {return static_cast<long>(format_desc_.width);}        
+    STDMETHOD_(long,                   GetHeight())            {return static_cast<long>(format_desc_.height);}        
+    STDMETHOD_(long,                   GetRowBytes())          {return static_cast<long>(format_desc_.width*4);}        
+       STDMETHOD_(BMDPixelFormat,      GetPixelFormat())       {return bmdFormat8BitBGRA;}        
+    STDMETHOD_(BMDFrameFlags,  GetFlags())                     {return bmdFrameFlagDefault;}
+        
+    STDMETHOD(GetBytes(void** buffer))
+       {
+               try
+               {
+                       if(static_cast<int>(frame_.image_data().size()) != format_desc_.size)
+                       {
+                               data_.resize(format_desc_.size, 0);
+                               *buffer = data_.data();
+                       }
+                       else if(key_only_)
+                       {
+                               if(data_.empty())
+                               {
+                                       data_.resize(frame_.image_data().size());
+                                       aligned_memshfl(data_.data(), frame_.image_data().begin(), frame_.image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);
+                               }
+                               *buffer = data_.data();
+                       }
+                       else
+                               *buffer = const_cast<uint8_t*>(frame_.image_data().begin());
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+                       return E_FAIL;
+               }
+
+               return S_OK;
+       }
+        
+    STDMETHOD(GetTimecode(BMDTimecodeFormat format, IDeckLinkTimecode** timecode)){return S_FALSE;}        
+    STDMETHOD(GetAncillaryData(IDeckLinkVideoFrameAncillary** ancillary))                {return S_FALSE;}
+
+       // decklink_frame       
+
+       const core::audio_buffer& audio_data()
+       {
+               return frame_.audio_data();
+       }
+};
+
+struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable
+{              
+       const int                                                       channel_index_;
+       const configuration                                     config_;
+
+       CComPtr<IDeckLink>                                      decklink_;
+       CComQIPtr<IDeckLinkOutput>                      output_;
+       CComQIPtr<IDeckLinkConfiguration>       configuration_;
+       CComQIPtr<IDeckLinkKeyer>                       keyer_;
+       CComQIPtr<IDeckLinkAttributes>          attributes_;
+
+       tbb::spin_mutex                                         exception_mutex_;
+       std::exception_ptr                                      exception_;
+
+       tbb::atomic<bool>                                       is_running_;
+               
+       const std::wstring                                      model_name_;
+       const core::video_format_desc           format_desc_;
+       const int                                                       buffer_size_;
+
+       long long                                                       video_scheduled_;
+       long long                                                       audio_scheduled_;
+
+       int                                                                     preroll_count_;
+               
+       boost::circular_buffer<std::vector<int32_t>>    audio_container_;
+
+       tbb::concurrent_bounded_queue<core::const_frame> video_frame_buffer_;
+       tbb::concurrent_bounded_queue<core::const_frame> audio_frame_buffer_;
+       
+       spl::shared_ptr<diagnostics::graph> graph_;
+       boost::timer tick_timer_;
+
+public:
+       decklink_consumer(const configuration& config, const core::video_format_desc& format_desc, int channel_index) 
+               : channel_index_(channel_index)
+               , config_(config)
+               , decklink_(get_device(config.device_index))
+               , output_(decklink_)
+               , configuration_(decklink_)
+               , keyer_(decklink_)
+               , attributes_(decklink_)
+               , model_name_(get_model_name(decklink_))
+               , format_desc_(format_desc)
+               , buffer_size_(config.buffer_depth()) // Minimum buffer-size 3.
+               , video_scheduled_(0)
+               , audio_scheduled_(0)
+               , preroll_count_(0)
+               , audio_container_(buffer_size_+1)
+       {
+               is_running_ = true;
+                               
+               video_frame_buffer_.set_capacity(1);
+               audio_frame_buffer_.set_capacity(1);
+
+               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   
+               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));
+               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));
+               graph_->set_color("flushed-frame", diagnostics::color(0.4f, 0.3f, 0.8f));
+               graph_->set_color("buffered-audio", diagnostics::color(0.9f, 0.9f, 0.5f));
+               graph_->set_color("buffered-video", diagnostics::color(0.2f, 0.9f, 0.9f));
+               graph_->set_text(print());
+               diagnostics::register_graph(graph_);
+               
+               enable_video(get_display_mode(output_, format_desc_.format, bmdFormat8BitBGRA, bmdVideoOutputFlagDefault));
+                               
+               if(config.embedded_audio)
+                       enable_audio();
+               
+               set_latency(config.latency);                            
+               set_keyer(config.keyer);
+                               
+               if(config.embedded_audio)               
+                       output_->BeginAudioPreroll();           
+               
+               for(int n = 0; n < buffer_size_; ++n)
+                       schedule_next_video(core::const_frame::empty());
+
+               if(!config.embedded_audio)
+                       start_playback();
+       }
+
+       ~decklink_consumer()
+       {               
+               is_running_ = false;
+               video_frame_buffer_.try_push(core::const_frame::empty());
+               audio_frame_buffer_.try_push(core::const_frame::empty());
+
+               if(output_ != nullptr) 
+               {
+                       output_->StopScheduledPlayback(0, nullptr, 0);
+                       if(config_.embedded_audio)
+                               output_->DisableAudioOutput();
+                       output_->DisableVideoOutput();
+               }
+       }
+                       
+       void set_latency(configuration::latency_t latency)
+       {               
+               if(latency == configuration::low_latency)
+               {
+                       configuration_->SetFlag(bmdDeckLinkConfigLowLatencyVideoOutput, true);
+                       CASPAR_LOG(info) << print() << L" Enabled low-latency mode.";
+               }
+               else if(latency == configuration::normal_latency)
+               {                       
+                       configuration_->SetFlag(bmdDeckLinkConfigLowLatencyVideoOutput, false);
+                       CASPAR_LOG(info) << print() << L" Disabled low-latency mode.";
+               }
+       }
+
+       void set_keyer(configuration::keyer_t keyer)
+       {
+               if(keyer == configuration::internal_keyer) 
+               {
+                       BOOL value = true;
+                       if(SUCCEEDED(attributes_->GetFlag(BMDDeckLinkSupportsInternalKeying, &value)) && !value)
+                               CASPAR_LOG(error) << print() << L" Failed to enable internal keyer.";   
+                       else if(FAILED(keyer_->Enable(FALSE)))                  
+                               CASPAR_LOG(error) << print() << L" Failed to enable internal keyer.";                   
+                       else if(FAILED(keyer_->SetLevel(255)))                  
+                               CASPAR_LOG(error) << print() << L" Failed to set key-level to max.";
+                       else
+                               CASPAR_LOG(info) << print() << L" Enabled internal keyer.";             
+               }
+               else if(keyer == configuration::external_keyer)
+               {
+                       BOOL value = true;
+                       if(SUCCEEDED(attributes_->GetFlag(BMDDeckLinkSupportsExternalKeying, &value)) && !value)
+                               CASPAR_LOG(error) << print() << L" Failed to enable external keyer.";   
+                       else if(FAILED(keyer_->Enable(TRUE)))                   
+                               CASPAR_LOG(error) << print() << L" Failed to enable external keyer.";   
+                       else if(FAILED(keyer_->SetLevel(255)))                  
+                               CASPAR_LOG(error) << print() << L" Failed to set key-level to max.";
+                       else
+                               CASPAR_LOG(info) << print() << L" Enabled external keyer.";                     
+               }
+       }
+       
+       void enable_audio()
+       {
+               if(FAILED(output_->EnableAudioOutput(bmdAudioSampleRate48kHz, bmdAudioSampleType32bitInteger, 2, bmdAudioOutputStreamTimestamped)))
+                               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Could not enable audio output."));
+                               
+               if(FAILED(output_->SetAudioCallback(this)))
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Could not set audio callback."));
+
+               CASPAR_LOG(info) << print() << L" Enabled embedded-audio.";
+       }
+
+       void enable_video(BMDDisplayMode display_mode)
+       {
+               if(FAILED(output_->EnableVideoOutput(display_mode, bmdVideoOutputFlagDefault))) 
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Could not enable video output."));
+               
+               if(FAILED(output_->SetScheduledFrameCompletionCallback(this)))
+                       CASPAR_THROW_EXCEPTION(caspar_exception() 
+                                                                       << msg_info(u8(print()) + " Failed to set playback completion callback.")
+                                                                       << boost::errinfo_api_function("SetScheduledFrameCompletionCallback"));
+       }
+
+       void start_playback()
+       {
+               if(FAILED(output_->StartScheduledPlayback(0, format_desc_.time_scale, 1.0))) 
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Failed to schedule playback."));
+       }
+       
+       STDMETHOD (QueryInterface(REFIID, LPVOID*))     {return E_NOINTERFACE;}
+       STDMETHOD_(ULONG, AddRef())                                     {return 1;}
+       STDMETHOD_(ULONG, Release())                            {return 1;}
+       
+       STDMETHOD(ScheduledPlaybackHasStopped())
+       {
+               is_running_ = false;
+               CASPAR_LOG(info) << print() << L" Scheduled playback has stopped.";
+               return S_OK;
+       }
+
+       STDMETHOD(ScheduledFrameCompleted(IDeckLinkVideoFrame* completed_frame, BMDOutputFrameCompletionResult result))
+       {
+               if(!is_running_)
+                       return E_FAIL;
+               
+               try
+               {
+                       if(result == bmdOutputFrameDisplayedLate)
+                       {
+                               graph_->set_tag("late-frame");
+                               video_scheduled_ += format_desc_.duration;
+                               audio_scheduled_ += reinterpret_cast<decklink_frame*>(completed_frame)->audio_data().size()/format_desc_.audio_channels;
+                               //++video_scheduled_;
+                               //audio_scheduled_ += format_desc_.audio_cadence[0];
+                               //++audio_scheduled_;
+                       }
+                       else if(result == bmdOutputFrameDropped)
+                               graph_->set_tag("dropped-frame");
+                       else if(result == bmdOutputFrameFlushed)
+                               graph_->set_tag("flushed-frame");
+
+                       auto frame = core::const_frame::empty();        
+                       video_frame_buffer_.pop(frame);                                 
+                       schedule_next_video(frame);     
+                       
+                       unsigned long buffered;
+                       output_->GetBufferedVideoFrameCount(&buffered);
+                       graph_->set_value("buffered-video", static_cast<double>(buffered)/format_desc_.fps);
+               }
+               catch(...)
+               {
+                       lock(exception_mutex_, [&]
+                       {
+                               exception_ = std::current_exception();
+                       });
+                       return E_FAIL;
+               }
+
+               return S_OK;
+       }
+               
+       STDMETHOD(RenderAudioSamples(BOOL preroll))
+       {
+               if(!is_running_)
+                       return E_FAIL;
+               
+               try
+               {       
+                       if(preroll)
+                       {
+                               if(++preroll_count_ >= buffer_size_)
+                               {
+                                       output_->EndAudioPreroll();
+                                       start_playback();                               
+                               }
+                               else
+                                       schedule_next_audio(core::audio_buffer(format_desc_.audio_cadence[preroll % format_desc_.audio_cadence.size()], 0));    
+                       }
+                       else
+                       {
+                               auto frame = core::const_frame::empty();
+                               audio_frame_buffer_.pop(frame);
+                               schedule_next_audio(frame.audio_data());
+                       }
+
+                       unsigned long buffered;
+                       output_->GetBufferedAudioSampleFrameCount(&buffered);
+                       graph_->set_value("buffered-audio", static_cast<double>(buffered)/(format_desc_.audio_cadence[0]*2));
+               }
+               catch(...)
+               {
+                       tbb::spin_mutex::scoped_lock lock(exception_mutex_);
+                       exception_ = std::current_exception();
+                       return E_FAIL;
+               }
+
+               return S_OK;
+       }
+
+       template<typename T>
+       void schedule_next_audio(const T& audio_data)
+       {
+               auto sample_frame_count = static_cast<int>(audio_data.size()/format_desc_.audio_channels);
+
+               audio_container_.push_back(std::vector<int32_t>(audio_data.begin(), audio_data.end()));
+
+               if(FAILED(output_->ScheduleAudioSamples(audio_container_.back().data(), sample_frame_count, audio_scheduled_, format_desc_.audio_sample_rate, nullptr)))
+                       CASPAR_LOG(error) << print() << L" Failed to schedule audio.";
+
+               audio_scheduled_ += sample_frame_count;
+       }
+                       
+       void schedule_next_video(core::const_frame frame)
+       {
+               CComPtr<IDeckLinkVideoFrame> frame2(new decklink_frame(frame, format_desc_, config_.key_only));
+               if(FAILED(output_->ScheduleVideoFrame(frame2, video_scheduled_, format_desc_.duration, format_desc_.time_scale)))
+                       CASPAR_LOG(error) << print() << L" Failed to schedule video.";
+
+               video_scheduled_ += format_desc_.duration;
+
+               graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5);
+               tick_timer_.restart();
+       }
+
+       void send(core::const_frame frame)
+       {
+               auto exception = lock(exception_mutex_, [&]
+               {
+                       return exception_;
+               });
+
+               if(exception != nullptr)
+                       std::rethrow_exception(exception);              
+
+               if(!is_running_)
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Is not running."));
+               
+               if(config_.embedded_audio)
+                       audio_frame_buffer_.push(frame);        
+               video_frame_buffer_.push(frame);        
+       }
+       
+       std::wstring print() const
+       {
+               return model_name_ + L" [" + boost::lexical_cast<std::wstring>(channel_index_) + L"-" +
+                       boost::lexical_cast<std::wstring>(config_.device_index) + L"|" +  format_desc_.name + L"]";
+       }
+};
+
+struct decklink_consumer_proxy : public core::frame_consumer
+{
+       const configuration                                     config_;
+       std::unique_ptr<decklink_consumer>      consumer_;
+       executor                                                        executor_;
+public:
+
+       decklink_consumer_proxy(const configuration& config)
+               : config_(config)
+               , executor_(L"decklink_consumer[" + boost::lexical_cast<std::wstring>(config.device_index) + L"]")
+       {
+               executor_.begin_invoke([=]
+               {
+                       ::CoInitialize(nullptr);
+               });
+       }
+
+       ~decklink_consumer_proxy()
+       {
+               executor_.invoke([=]
+               {
+                       ::CoUninitialize();
+               });
+       }
+
+       // frame_consumer
+       
+       void initialize(const core::video_format_desc& format_desc, int channel_index) override
+       {
+               executor_.invoke([=]
+               {
+                       consumer_.reset();
+                       consumer_.reset(new decklink_consumer(config_, format_desc, channel_index));                    
+               });
+       }
+       
+       bool send(core::const_frame frame) override
+       {
+               consumer_->send(frame);
+               return true;
+       }
+       
+       std::wstring print() const override
+       {
+               return consumer_ ? consumer_->print() : L"[decklink_consumer]";
+       }               
+
+       std::wstring name() const override
+       {
+               return L"decklink";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"decklink");
+               info.add(L"key-only", config_.key_only);
+               info.add(L"device", config_.device_index);
+               info.add(L"low-latency", config_.low_latency);
+               info.add(L"embedded-audio", config_.embedded_audio);
+               info.add(L"low-latency", config_.low_latency);
+               //info.add(L"internal-key", config_.internal_key);
+               return info;
+       }
+
+       int buffer_depth() const override
+       {
+               return config_.buffer_depth();
+       }
+
+       int index() const override
+       {
+               return 300 + config_.device_index;
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }       
+};     
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params) 
+{
+       if(params.size() < 1 || params[0] != L"DECKLINK")
+               return core::frame_consumer::empty();
+       
+       configuration config;
+               
+       if(params.size() > 1)
+               config.device_index = boost::lexical_cast<int>(params[1]);
+       
+       if(std::find(params.begin(), params.end(), L"INTERNAL_KEY")                     != params.end())
+               config.keyer = configuration::internal_keyer;
+       else if(std::find(params.begin(), params.end(), L"EXTERNAL_KEY")        != params.end())
+               config.keyer = configuration::external_keyer;
+       else
+               config.keyer = configuration::default_keyer;
+
+       if(std::find(params.begin(), params.end(), L"LOW_LATENCY")       != params.end())
+               config.latency = configuration::low_latency;
+
+       config.embedded_audio   = std::find(params.begin(), params.end(), L"EMBEDDED_AUDIO") != params.end();
+       config.key_only                 = std::find(params.begin(), params.end(), L"KEY_ONLY")           != params.end();
+
+       return spl::make_shared<decklink_consumer_proxy>(config);
+}
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree) 
+{
+       configuration config;
+
+       auto keyer = ptree.get(L"keyer", L"default");
+       if(keyer == L"external")
+               config.keyer = configuration::external_keyer;
+       else if(keyer == L"internal")
+               config.keyer = configuration::internal_keyer;
+
+       auto latency = ptree.get(L"latency", L"normal");
+       if(latency == L"low")
+               config.latency = configuration::low_latency;
+       else if(latency == L"normal")
+               config.latency = configuration::normal_latency;
+
+       config.key_only                         = ptree.get(L"key-only",                config.key_only);
+       config.device_index                     = ptree.get(L"device",                  config.device_index);
+       config.embedded_audio           = ptree.get(L"embedded-audio",  config.embedded_audio);
+       config.base_buffer_depth        = ptree.get(L"buffer-depth",    config.base_buffer_depth);
+
+       return spl::make_shared<decklink_consumer_proxy>(config);
+}
+
+}}
+
+/*
+##############################################################################
+Pre-rolling
+
+Mail: 2011-05-09
+
+Yoshan
+BMD Developer Support
+developer@blackmagic-design.com
+
+-----------------------------------------------------------------------------
+
+Thanks for your inquiry. The minimum number of frames that you can preroll 
+for scheduled playback is three frames for video and four frames for audio. 
+As you mentioned if you preroll less frames then playback will not start or
+playback will be very sporadic. From our experience with Media Express, we 
+recommended that at least seven frames are prerolled for smooth playback. 
+
+Regarding the bmdDeckLinkConfigLowLatencyVideoOutput flag:
+There can be around 3 frames worth of latency on scheduled output.
+When the bmdDeckLinkConfigLowLatencyVideoOutput flag is used this latency is
+reduced  or removed for scheduled playback. If the DisplayVideoFrameSync() 
+method is used, the bmdDeckLinkConfigLowLatencyVideoOutput setting will 
+guarantee that the provided frame will be output as soon the previous 
+frame output has been completed.
+################################################################################
+*/
+
+/*
+##############################################################################
+Async DMA Transfer without redundant copying
+
+Mail: 2011-05-10
+
+Yoshan
+BMD Developer Support
+developer@blackmagic-design.com
+
+-----------------------------------------------------------------------------
+
+Thanks for your inquiry. You could try subclassing IDeckLinkMutableVideoFrame 
+and providing a pointer to your video buffer when GetBytes() is called. 
+This may help to keep copying to a minimum. Please ensure that the pixel 
+format is in bmdFormat10BitYUV, otherwise the DeckLink API / driver will 
+have to colourspace convert which may result in additional copying.
+################################################################################
 */
\ No newline at end of file
index 863d62c8a64db5ddaa543ed03b1b63103e4cd446..5991a466c1d1ad673acef3bd0a7b7484ad8fe4d8 100644 (file)
@@ -1,44 +1,44 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar {\r
-\r
-namespace core {\r
-       class frame_consumer;\r
-}\r
-\r
-namespace decklink {\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <core/video_format.h>
+
+#include <boost/property_tree/ptree.hpp>
+
+#include <string>
+#include <vector>
+
+namespace caspar {
+
+namespace core {
+       class frame_consumer;
+}
+
+namespace decklink {
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);
+
 }}
\ No newline at end of file
index f78aae134e74c839b435eedcb99a711a7ed5b705..4252e99d28fb08706390270ab9708000158b0aa0 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "stdafx.h"\r
-\r
-#include "decklink.h"\r
-#include "util/util.h"\r
-\r
-#include "consumer/decklink_consumer.h"\r
-#include "producer/decklink_producer.h"\r
-\r
-#include <core/consumer/frame_consumer.h>\r
-#include <core/producer/frame_producer.h>\r
-\r
-#include "interop/DeckLinkAPI_h.h"\r
-\r
-#pragma warning(push)\r
-#pragma warning(disable : 4996)\r
-\r
-       #include <atlbase.h>\r
-\r
-       #include <atlcom.h>\r
-       #include <atlhost.h>\r
-\r
-#pragma warning(push)\r
-\r
-namespace caspar { namespace decklink {\r
-\r
-void init()\r
-{\r
-       struct co_init\r
-       {\r
-               co_init(){::CoInitialize(nullptr);}\r
-               ~co_init(){::CoUninitialize();}\r
-       } init;\r
-       \r
-       CComPtr<IDeckLinkIterator> pDecklinkIterator;\r
-       if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))         \r
-               return;\r
-               \r
-       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});\r
-       core::register_producer_factory(create_producer);\r
-}\r
-\r
-std::wstring version() \r
-{\r
-       std::wstring version = L"Not found";\r
-       \r
-       struct co_init\r
-       {\r
-               co_init(){::CoInitialize(nullptr);}\r
-               ~co_init(){::CoUninitialize();}\r
-       } init;\r
-\r
-       try\r
-       {\r
-               CComPtr<IDeckLinkIterator> pDecklinkIterator;\r
-               if(SUCCEEDED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))              \r
-                       version = decklink::version(pDecklinkIterator);\r
-       }\r
-       catch(...){}\r
-\r
-       return version;\r
-}\r
-\r
-std::vector<std::wstring> device_list()\r
-{\r
-       std::vector<std::wstring> devices;\r
-       \r
-       struct co_init\r
-       {\r
-               co_init(){::CoInitialize(nullptr);}\r
-               ~co_init(){::CoUninitialize();}\r
-       } init;\r
-\r
-       try\r
-       {\r
-               CComPtr<IDeckLinkIterator> pDecklinkIterator;\r
-               if(SUCCEEDED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))\r
-               {               \r
-                       IDeckLink* decklink;\r
-                       for(int n = 1; pDecklinkIterator->Next(&decklink) == S_OK; ++n) \r
-                       {\r
-                               BSTR model_name = L"Unknown";\r
-                               decklink->GetModelName(&model_name);\r
-                               decklink->Release();\r
-                               devices.push_back(std::wstring(model_name) + L" [" + boost::lexical_cast<std::wstring>(n) + L"]");      \r
-                       }\r
-               }\r
-       }\r
-       catch(...){}\r
-\r
-       return devices;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "stdafx.h"
+
+#include "decklink.h"
+#include "util/util.h"
+
+#include "consumer/decklink_consumer.h"
+#include "producer/decklink_producer.h"
+
+#include <core/consumer/frame_consumer.h>
+#include <core/producer/frame_producer.h>
+
+#include "interop/DeckLinkAPI_h.h"
+
+#pragma warning(push)
+#pragma warning(disable : 4996)
+
+       #include <atlbase.h>
+
+       #include <atlcom.h>
+       #include <atlhost.h>
+
+#pragma warning(push)
+
+namespace caspar { namespace decklink {
+
+void init()
+{
+       struct co_init
+       {
+               co_init(){::CoInitialize(nullptr);}
+               ~co_init(){::CoUninitialize();}
+       } init;
+       
+       CComPtr<IDeckLinkIterator> pDecklinkIterator;
+       if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))         
+               return;
+               
+       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+       core::register_producer_factory(create_producer);
+}
+
+std::wstring version() 
+{
+       std::wstring version = L"Not found";
+       
+       struct co_init
+       {
+               co_init(){::CoInitialize(nullptr);}
+               ~co_init(){::CoUninitialize();}
+       } init;
+
+       try
+       {
+               CComPtr<IDeckLinkIterator> pDecklinkIterator;
+               if(SUCCEEDED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))              
+                       version = decklink::version(pDecklinkIterator);
+       }
+       catch(...){}
+
+       return version;
+}
+
+std::vector<std::wstring> device_list()
+{
+       std::vector<std::wstring> devices;
+       
+       struct co_init
+       {
+               co_init(){::CoInitialize(nullptr);}
+               ~co_init(){::CoUninitialize();}
+       } init;
+
+       try
+       {
+               CComPtr<IDeckLinkIterator> pDecklinkIterator;
+               if(SUCCEEDED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))
+               {               
+                       IDeckLink* decklink;
+                       for(int n = 1; pDecklinkIterator->Next(&decklink) == S_OK; ++n) 
+                       {
+                               BSTR model_name = L"Unknown";
+                               decklink->GetModelName(&model_name);
+                               decklink->Release();
+                               devices.push_back(std::wstring(model_name) + L" [" + boost::lexical_cast<std::wstring>(n) + L"]");      
+                       }
+               }
+       }
+       catch(...){}
+
+       return devices;
+}
+
 }}
\ No newline at end of file
index 317eea50ab3a6fe240c0865c0c44c782935303a0..db268b8a87a4875bb00d3b1ef80a1db6c94b2319 100644 (file)
@@ -1,34 +1,34 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar { namespace decklink {\r
-\r
-void init();\r
-\r
-std::wstring version();\r
-std::vector<std::wstring> device_list();\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+namespace caspar { namespace decklink {
+
+void init();
+
+std::wstring version();
+std::vector<std::wstring> device_list();
+
 }}
\ No newline at end of file
index 301d813909549c0f60ba4eb27102eff68f99a9a1..61a4f2abc58c8252fe0315373b892d40f5f27dc6 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "decklink_producer.h"\r
-\r
-#include "../interop/DeckLinkAPI_h.h"\r
-#include "../util/util.h"\r
-\r
-#include "../../ffmpeg/producer/filter/filter.h"\r
-#include "../../ffmpeg/producer/util/util.h"\r
-#include "../../ffmpeg/producer/muxer/frame_muxer.h"\r
-#include "../../ffmpeg/producer/muxer/display_mode.h"\r
-\r
-#include <common/executor.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/except.h>\r
-#include <common/log.h>\r
-#include <common/param.h>\r
-\r
-#include <core/frame/frame.h>\r
-#include <core/frame/draw_frame.h>\r
-#include <core/frame/frame_transform.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/monitor/monitor.h>\r
-#include <core/mixer/audio/audio_mixer.h>\r
-\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <boost/algorithm/string.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/timer.hpp>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
-       #define __STDC_LIMIT_MACROS\r
-       #include <libavcodec/avcodec.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-#pragma warning(push)\r
-#pragma warning(disable : 4996)\r
-\r
-       #include <atlbase.h>\r
-\r
-       #include <atlcom.h>\r
-       #include <atlhost.h>\r
-\r
-#pragma warning(push)\r
-\r
-#include <functional>\r
-\r
-namespace caspar { namespace decklink {\r
-               \r
-class decklink_producer : boost::noncopyable, public IDeckLinkInputCallback\r
-{      \r
-       monitor::basic_subject                                                  event_subject_;\r
-       spl::shared_ptr<diagnostics::graph>                             graph_;\r
-       boost::timer                                                                    tick_timer_;\r
-\r
-       CComPtr<IDeckLink>                                                              decklink_;\r
-       CComQIPtr<IDeckLinkInput>                                               input_;\r
-       CComQIPtr<IDeckLinkAttributes >                                 attributes_;\r
-       \r
-       const std::wstring                                                              model_name_;\r
-       const int                                                                               device_index_;\r
-       const std::wstring                                                              filter_;\r
-       \r
-       std::vector<int>                                                                audio_cadence_;\r
-       boost::circular_buffer<size_t>                                  sync_buffer_;\r
-       ffmpeg::frame_muxer                                                             muxer_;\r
-                       \r
-       spl::shared_ptr<core::frame_factory>                    frame_factory_;\r
-       core::video_format_desc                                                 in_format_desc_;\r
-       core::video_format_desc                                                 out_format_desc_;\r
-\r
-       tbb::concurrent_bounded_queue<core::draw_frame> frame_buffer_;\r
-\r
-       std::exception_ptr                                                              exception_;             \r
-\r
-public:\r
-       decklink_producer(const core::video_format_desc& in_format_desc, \r
-                                         int device_index, \r
-                                         const spl::shared_ptr<core::frame_factory>& frame_factory, \r
-                                         const core::video_format_desc& out_format_desc, \r
-                                         const std::wstring& filter)\r
-               : decklink_(get_device(device_index))\r
-               , input_(decklink_)\r
-               , attributes_(decklink_)\r
-               , model_name_(get_model_name(decklink_))\r
-               , device_index_(device_index)\r
-               , filter_(filter)\r
-               , in_format_desc_(in_format_desc)\r
-               , out_format_desc_(out_format_desc)\r
-               , muxer_(in_format_desc.fps, frame_factory, out_format_desc, filter)\r
-               , audio_cadence_(out_format_desc.audio_cadence)\r
-               , sync_buffer_(out_format_desc.audio_cadence.size())\r
-               , frame_factory_(frame_factory)\r
-       {       \r
-               frame_buffer_.set_capacity(2);\r
-               \r
-               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   \r
-               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));\r
-               graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
-               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));\r
-               graph_->set_color("output-buffer", diagnostics::color(0.0f, 1.0f, 0.0f));\r
-               graph_->set_text(print());\r
-               diagnostics::register_graph(graph_);\r
-               \r
-               auto display_mode = get_display_mode(input_, in_format_desc.format, bmdFormat8BitYUV, bmdVideoInputFlagDefault);\r
-               \r
-               // NOTE: bmdFormat8BitARGB is currently not supported by any decklink card. (2011-05-08)\r
-               if(FAILED(input_->EnableVideoInput(display_mode, bmdFormat8BitYUV, 0))) \r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() \r
-                                                                       << msg_info(print() + L" Could not enable video input.")\r
-                                                                       << boost::errinfo_api_function("EnableVideoInput"));\r
-\r
-               if(FAILED(input_->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType32bitInteger, static_cast<int>(in_format_desc.audio_channels)))) \r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() \r
-                                                                       << msg_info(print() + L" Could not enable audio input.")\r
-                                                                       << boost::errinfo_api_function("EnableAudioInput"));\r
-                       \r
-               if (FAILED(input_->SetCallback(this)) != S_OK)\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() \r
-                                                                       << msg_info(print() + L" Failed to set input callback.")\r
-                                                                       << boost::errinfo_api_function("SetCallback"));\r
-                       \r
-               if(FAILED(input_->StartStreams()))\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() \r
-                                                                       << msg_info(print() + L" Failed to start input stream.")\r
-                                                                       << boost::errinfo_api_function("StartStreams"));\r
-\r
-               CASPAR_LOG(info) << print() << L" Initialized";\r
-       }\r
-\r
-       ~decklink_producer()\r
-       {\r
-               if(input_ != nullptr) \r
-               {\r
-                       input_->StopStreams();\r
-                       input_->DisableVideoInput();\r
-               }\r
-       }\r
-\r
-       virtual HRESULT STDMETHODCALLTYPE       QueryInterface (REFIID, LPVOID*)        {return E_NOINTERFACE;}\r
-       virtual ULONG STDMETHODCALLTYPE         AddRef ()                                                       {return 1;}\r
-       virtual ULONG STDMETHODCALLTYPE         Release ()                                                      {return 1;}\r
-               \r
-       virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents /*notificationEvents*/, IDeckLinkDisplayMode* newDisplayMode, BMDDetectedVideoInputFormatFlags /*detectedSignalFlags*/)\r
-       {\r
-               return S_OK;\r
-       }\r
-\r
-       virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame* video, IDeckLinkAudioInputPacket* audio)\r
-       {       \r
-               if(!video)\r
-                       return S_OK;\r
-\r
-               try\r
-               {\r
-                       graph_->set_value("tick-time", tick_timer_.elapsed()*out_format_desc_.fps*0.5);\r
-                       tick_timer_.restart();\r
-\r
-                       boost::timer frame_timer;       \r
-                       \r
-                       // Video\r
-\r
-                       void* video_bytes = nullptr;\r
-                       if(FAILED(video->GetBytes(&video_bytes)) || !video_bytes)\r
-                               return S_OK;\r
-                       \r
-                       auto video_frame = ffmpeg::create_frame();\r
-                                               \r
-                       video_frame->data[0]                    = reinterpret_cast<uint8_t*>(video_bytes);\r
-                       video_frame->linesize[0]                = video->GetRowBytes();                 \r
-                       video_frame->format                             = PIX_FMT_UYVY422;\r
-                       video_frame->width                              = video->GetWidth();\r
-                       video_frame->height                             = video->GetHeight();\r
-                       video_frame->interlaced_frame   = in_format_desc_.field_mode != core::field_mode::progressive;\r
-                       video_frame->top_field_first    = in_format_desc_.field_mode == core::field_mode::upper ? 1 : 0;\r
-                               \r
-                       event_subject_  << monitor::event("file/name")                          % model_name_\r
-                                                       << monitor::event("file/path")                          % device_index_\r
-                                                       << monitor::event("file/video/width")           % video->GetWidth()\r
-                                                       << monitor::event("file/video/height")          % video->GetHeight()\r
-                                                       << monitor::event("file/video/field")           % u8(!video_frame->interlaced_frame ? "progressive" : (video_frame->top_field_first ? "upper" : "lower"))\r
-                                                       << monitor::event("file/audio/sample-rate")     % 48000\r
-                                                       << monitor::event("file/audio/channels")        % 2\r
-                                                       << monitor::event("file/audio/format")          % u8(av_get_sample_fmt_name(AV_SAMPLE_FMT_S32))\r
-                                                       << monitor::event("file/fps")                           % in_format_desc_.fps;\r
-\r
-                       // Audio\r
-\r
-                       std::shared_ptr<core::audio_buffer> audio_buffer;\r
-                       \r
-                       void* audio_bytes = nullptr;\r
-                       if(FAILED(audio->GetBytes(&audio_bytes)) || !audio_bytes)\r
-                               return S_OK;\r
-                       \r
-                       auto audio_frame = ffmpeg::create_frame();\r
-\r
-                       audio_frame->data[0]            = reinterpret_cast<uint8_t*>(audio_bytes);\r
-                       audio_frame->linesize[0]        = audio->GetSampleFrameCount()*out_format_desc_.audio_channels*sizeof(int32_t);\r
-                       audio_frame->nb_samples         = audio->GetSampleFrameCount();\r
-                       audio_frame->format                     = AV_SAMPLE_FMT_S32;\r
-                                               \r
-                       // Note: Uses 1 step rotated cadence for 1001 modes (1602, 1602, 1601, 1602, 1601)\r
-                       // This cadence fills the audio mixer most optimally.\r
-\r
-                       sync_buffer_.push_back(audio->GetSampleFrameCount()*out_format_desc_.audio_channels);           \r
-                       if(!boost::range::equal(sync_buffer_, audio_cadence_))\r
-                       {\r
-                               CASPAR_LOG(trace) << print() << L" Syncing audio.";\r
-                               return S_OK;\r
-                       }\r
-                       boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
-                       \r
-                       // PUSH\r
-\r
-                       muxer_.push_video(video_frame); \r
-                       muxer_.push_audio(audio_frame);                                                                                 \r
-                       \r
-                       // POLL\r
-\r
-                       auto frame = core::draw_frame::late();\r
-                       if(!muxer_.empty())\r
-                       {\r
-                               frame = std::move(muxer_.front());\r
-                               muxer_.pop();\r
-\r
-                               if(!frame_buffer_.try_push(frame))\r
-                               {\r
-                                       auto dummy = core::draw_frame::empty();\r
-                                       frame_buffer_.try_pop(dummy);\r
-                                       frame_buffer_.try_push(frame);\r
-                                               \r
-                                       graph_->set_tag("dropped-frame");\r
-                               }\r
-                       }\r
-                       \r
-                       graph_->set_value("frame-time", frame_timer.elapsed()*out_format_desc_.fps*0.5);        \r
-                       event_subject_ << monitor::event("profiler/time") % frame_timer.elapsed() % out_format_desc_.fps;\r
-\r
-                       graph_->set_value("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));      \r
-                       event_subject_ << monitor::event("buffer") % frame_buffer_.size() % frame_buffer_.capacity();\r
-               }\r
-               catch(...)\r
-               {\r
-                       exception_ = std::current_exception();\r
-                       return E_FAIL;\r
-               }\r
-\r
-               return S_OK;\r
-       }\r
-       \r
-       core::draw_frame get_frame()\r
-       {\r
-               if(exception_ != nullptr)\r
-                       std::rethrow_exception(exception_);\r
-               \r
-               core::draw_frame frame = core::draw_frame::late();\r
-               if(!frame_buffer_.try_pop(frame))\r
-                       graph_->set_tag("late-frame");\r
-               graph_->set_value("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));      \r
-               return frame;\r
-       }\r
-       \r
-       std::wstring print() const\r
-       {\r
-               return model_name_ + L" [" + boost::lexical_cast<std::wstring>(device_index_) + L"|" + in_format_desc_.name + L"]";\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o)\r
-       {\r
-               event_subject_.subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o)\r
-       {\r
-               event_subject_.unsubscribe(o);\r
-       }\r
-};\r
-       \r
-class decklink_producer_proxy : public core::frame_producer_base\r
-{              \r
-       std::unique_ptr<decklink_producer>      producer_;\r
-       const uint32_t                                          length_;\r
-       executor                                                        executor_;\r
-public:\r
-       explicit decklink_producer_proxy(const core::video_format_desc& in_format_desc,\r
-                                                                        const spl::shared_ptr<core::frame_factory>& frame_factory, \r
-                                                                        const core::video_format_desc& out_format_desc, \r
-                                                                        int device_index,\r
-                                                                        const std::wstring& filter_str, uint32_t length)\r
-               : executor_(L"decklink_producer[" + boost::lexical_cast<std::wstring>(device_index) + L"]")\r
-               , length_(length)\r
-       {\r
-               executor_.invoke([=]\r
-               {\r
-                       CoInitialize(nullptr);\r
-                       producer_.reset(new decklink_producer(in_format_desc, device_index, frame_factory, out_format_desc, filter_str));\r
-               });\r
-       }\r
-\r
-       ~decklink_producer_proxy()\r
-       {               \r
-               executor_.invoke([=]\r
-               {\r
-                       producer_.reset();\r
-                       CoUninitialize();\r
-               });\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-               producer_->subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-               producer_->unsubscribe(o);\r
-       }\r
-       \r
-       // frame_producer\r
-                               \r
-       core::draw_frame receive_impl() override\r
-       {               \r
-               return producer_->get_frame();\r
-       }\r
-                       \r
-       uint32_t nb_frames() const override\r
-       {\r
-               return length_;\r
-       }\r
-       \r
-       std::wstring print() const override\r
-       {\r
-               return producer_->print();\r
-       }\r
-       \r
-       std::wstring name() const override\r
-       {\r
-               return L"decklink";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"decklink");\r
-               return info;\r
-       }\r
-};\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& out_format_desc, const std::vector<std::wstring>& params)\r
-{\r
-       if(params.empty() || !boost::iequals(params[0], "decklink"))\r
-               return core::frame_producer::empty();\r
-\r
-       auto device_index       = get_param(L"DEVICE", params, -1);\r
-       if(device_index == -1)\r
-               device_index = boost::lexical_cast<int>(params.at(1));\r
-       \r
-       auto filter_str         = get_param(L"FILTER", params);         \r
-       auto length                     = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());   \r
-       auto in_format_desc = core::video_format_desc(get_param(L"FORMAT", params, L"INVALID"));\r
-               \r
-       if(in_format_desc.format == core::video_format::invalid)\r
-               in_format_desc = out_format_desc;\r
-                       \r
-       return create_destroy_proxy(spl::make_shared<decklink_producer_proxy>(in_format_desc, frame_factory, out_format_desc, device_index, filter_str, length));\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "decklink_producer.h"
+
+#include "../interop/DeckLinkAPI_h.h"
+#include "../util/util.h"
+
+#include "../../ffmpeg/producer/filter/filter.h"
+#include "../../ffmpeg/producer/util/util.h"
+#include "../../ffmpeg/producer/muxer/frame_muxer.h"
+#include "../../ffmpeg/producer/muxer/display_mode.h"
+
+#include <common/executor.h>
+#include <common/diagnostics/graph.h>
+#include <common/except.h>
+#include <common/log.h>
+#include <common/param.h>
+
+#include <core/frame/frame.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_transform.h>
+#include <core/frame/frame_factory.h>
+#include <core/monitor/monitor.h>
+#include <core/mixer/audio/audio_mixer.h>
+
+#include <tbb/concurrent_queue.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/timer.hpp>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #define __STDC_CONSTANT_MACROS
+       #define __STDC_LIMIT_MACROS
+       #include <libavcodec/avcodec.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+#pragma warning(push)
+#pragma warning(disable : 4996)
+
+       #include <atlbase.h>
+
+       #include <atlcom.h>
+       #include <atlhost.h>
+
+#pragma warning(push)
+
+#include <functional>
+
+namespace caspar { namespace decklink {
+               
+class decklink_producer : boost::noncopyable, public IDeckLinkInputCallback
+{      
+       monitor::basic_subject                                                  event_subject_;
+       spl::shared_ptr<diagnostics::graph>                             graph_;
+       boost::timer                                                                    tick_timer_;
+
+       CComPtr<IDeckLink>                                                              decklink_;
+       CComQIPtr<IDeckLinkInput>                                               input_;
+       CComQIPtr<IDeckLinkAttributes >                                 attributes_;
+       
+       const std::wstring                                                              model_name_;
+       const int                                                                               device_index_;
+       const std::wstring                                                              filter_;
+       
+       std::vector<int>                                                                audio_cadence_;
+       boost::circular_buffer<size_t>                                  sync_buffer_;
+       ffmpeg::frame_muxer                                                             muxer_;
+                       
+       spl::shared_ptr<core::frame_factory>                    frame_factory_;
+       core::video_format_desc                                                 in_format_desc_;
+       core::video_format_desc                                                 out_format_desc_;
+
+       tbb::concurrent_bounded_queue<core::draw_frame> frame_buffer_;
+
+       std::exception_ptr                                                              exception_;             
+
+public:
+       decklink_producer(const core::video_format_desc& in_format_desc, 
+                                         int device_index, 
+                                         const spl::shared_ptr<core::frame_factory>& frame_factory, 
+                                         const core::video_format_desc& out_format_desc, 
+                                         const std::wstring& filter)
+               : decklink_(get_device(device_index))
+               , input_(decklink_)
+               , attributes_(decklink_)
+               , model_name_(get_model_name(decklink_))
+               , device_index_(device_index)
+               , filter_(filter)
+               , in_format_desc_(in_format_desc)
+               , out_format_desc_(out_format_desc)
+               , muxer_(in_format_desc.fps, frame_factory, out_format_desc, filter)
+               , audio_cadence_(out_format_desc.audio_cadence)
+               , sync_buffer_(out_format_desc.audio_cadence.size())
+               , frame_factory_(frame_factory)
+       {       
+               frame_buffer_.set_capacity(2);
+               
+               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   
+               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));
+               graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));
+               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));
+               graph_->set_color("output-buffer", diagnostics::color(0.0f, 1.0f, 0.0f));
+               graph_->set_text(print());
+               diagnostics::register_graph(graph_);
+               
+               auto display_mode = get_display_mode(input_, in_format_desc.format, bmdFormat8BitYUV, bmdVideoInputFlagDefault);
+               
+               // NOTE: bmdFormat8BitARGB is currently not supported by any decklink card. (2011-05-08)
+               if(FAILED(input_->EnableVideoInput(display_mode, bmdFormat8BitYUV, 0))) 
+                       CASPAR_THROW_EXCEPTION(caspar_exception() 
+                                                                       << msg_info(print() + L" Could not enable video input.")
+                                                                       << boost::errinfo_api_function("EnableVideoInput"));
+
+               if(FAILED(input_->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType32bitInteger, static_cast<int>(in_format_desc.audio_channels)))) 
+                       CASPAR_THROW_EXCEPTION(caspar_exception() 
+                                                                       << msg_info(print() + L" Could not enable audio input.")
+                                                                       << boost::errinfo_api_function("EnableAudioInput"));
+                       
+               if (FAILED(input_->SetCallback(this)) != S_OK)
+                       CASPAR_THROW_EXCEPTION(caspar_exception() 
+                                                                       << msg_info(print() + L" Failed to set input callback.")
+                                                                       << boost::errinfo_api_function("SetCallback"));
+                       
+               if(FAILED(input_->StartStreams()))
+                       CASPAR_THROW_EXCEPTION(caspar_exception() 
+                                                                       << msg_info(print() + L" Failed to start input stream.")
+                                                                       << boost::errinfo_api_function("StartStreams"));
+
+               CASPAR_LOG(info) << print() << L" Initialized";
+       }
+
+       ~decklink_producer()
+       {
+               if(input_ != nullptr) 
+               {
+                       input_->StopStreams();
+                       input_->DisableVideoInput();
+               }
+       }
+
+       virtual HRESULT STDMETHODCALLTYPE       QueryInterface (REFIID, LPVOID*)        {return E_NOINTERFACE;}
+       virtual ULONG STDMETHODCALLTYPE         AddRef ()                                                       {return 1;}
+       virtual ULONG STDMETHODCALLTYPE         Release ()                                                      {return 1;}
+               
+       virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents /*notificationEvents*/, IDeckLinkDisplayMode* newDisplayMode, BMDDetectedVideoInputFormatFlags /*detectedSignalFlags*/)
+       {
+               return S_OK;
+       }
+
+       virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame* video, IDeckLinkAudioInputPacket* audio)
+       {       
+               if(!video)
+                       return S_OK;
+
+               try
+               {
+                       graph_->set_value("tick-time", tick_timer_.elapsed()*out_format_desc_.fps*0.5);
+                       tick_timer_.restart();
+
+                       boost::timer frame_timer;       
+                       
+                       // Video
+
+                       void* video_bytes = nullptr;
+                       if(FAILED(video->GetBytes(&video_bytes)) || !video_bytes)
+                               return S_OK;
+                       
+                       auto video_frame = ffmpeg::create_frame();
+                                               
+                       video_frame->data[0]                    = reinterpret_cast<uint8_t*>(video_bytes);
+                       video_frame->linesize[0]                = video->GetRowBytes();                 
+                       video_frame->format                             = PIX_FMT_UYVY422;
+                       video_frame->width                              = video->GetWidth();
+                       video_frame->height                             = video->GetHeight();
+                       video_frame->interlaced_frame   = in_format_desc_.field_mode != core::field_mode::progressive;
+                       video_frame->top_field_first    = in_format_desc_.field_mode == core::field_mode::upper ? 1 : 0;
+                               
+                       event_subject_  << monitor::event("file/name")                          % model_name_
+                                                       << monitor::event("file/path")                          % device_index_
+                                                       << monitor::event("file/video/width")           % video->GetWidth()
+                                                       << monitor::event("file/video/height")          % video->GetHeight()
+                                                       << monitor::event("file/video/field")           % u8(!video_frame->interlaced_frame ? "progressive" : (video_frame->top_field_first ? "upper" : "lower"))
+                                                       << monitor::event("file/audio/sample-rate")     % 48000
+                                                       << monitor::event("file/audio/channels")        % 2
+                                                       << monitor::event("file/audio/format")          % u8(av_get_sample_fmt_name(AV_SAMPLE_FMT_S32))
+                                                       << monitor::event("file/fps")                           % in_format_desc_.fps;
+
+                       // Audio
+
+                       std::shared_ptr<core::audio_buffer> audio_buffer;
+                       
+                       void* audio_bytes = nullptr;
+                       if(FAILED(audio->GetBytes(&audio_bytes)) || !audio_bytes)
+                               return S_OK;
+                       
+                       auto audio_frame = ffmpeg::create_frame();
+
+                       audio_frame->data[0]            = reinterpret_cast<uint8_t*>(audio_bytes);
+                       audio_frame->linesize[0]        = audio->GetSampleFrameCount()*out_format_desc_.audio_channels*sizeof(int32_t);
+                       audio_frame->nb_samples         = audio->GetSampleFrameCount();
+                       audio_frame->format                     = AV_SAMPLE_FMT_S32;
+                                               
+                       // Note: Uses 1 step rotated cadence for 1001 modes (1602, 1602, 1601, 1602, 1601)
+                       // This cadence fills the audio mixer most optimally.
+
+                       sync_buffer_.push_back(audio->GetSampleFrameCount()*out_format_desc_.audio_channels);           
+                       if(!boost::range::equal(sync_buffer_, audio_cadence_))
+                       {
+                               CASPAR_LOG(trace) << print() << L" Syncing audio.";
+                               return S_OK;
+                       }
+                       boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);
+                       
+                       // PUSH
+
+                       muxer_.push_video(video_frame); 
+                       muxer_.push_audio(audio_frame);                                                                                 
+                       
+                       // POLL
+
+                       auto frame = core::draw_frame::late();
+                       if(!muxer_.empty())
+                       {
+                               frame = std::move(muxer_.front());
+                               muxer_.pop();
+
+                               if(!frame_buffer_.try_push(frame))
+                               {
+                                       auto dummy = core::draw_frame::empty();
+                                       frame_buffer_.try_pop(dummy);
+                                       frame_buffer_.try_push(frame);
+                                               
+                                       graph_->set_tag("dropped-frame");
+                               }
+                       }
+                       
+                       graph_->set_value("frame-time", frame_timer.elapsed()*out_format_desc_.fps*0.5);        
+                       event_subject_ << monitor::event("profiler/time") % frame_timer.elapsed() % out_format_desc_.fps;
+
+                       graph_->set_value("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));      
+                       event_subject_ << monitor::event("buffer") % frame_buffer_.size() % frame_buffer_.capacity();
+               }
+               catch(...)
+               {
+                       exception_ = std::current_exception();
+                       return E_FAIL;
+               }
+
+               return S_OK;
+       }
+       
+       core::draw_frame get_frame()
+       {
+               if(exception_ != nullptr)
+                       std::rethrow_exception(exception_);
+               
+               core::draw_frame frame = core::draw_frame::late();
+               if(!frame_buffer_.try_pop(frame))
+                       graph_->set_tag("late-frame");
+               graph_->set_value("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));      
+               return frame;
+       }
+       
+       std::wstring print() const
+       {
+               return model_name_ + L" [" + boost::lexical_cast<std::wstring>(device_index_) + L"|" + in_format_desc_.name + L"]";
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o)
+       {
+               event_subject_.subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o)
+       {
+               event_subject_.unsubscribe(o);
+       }
+};
+       
+class decklink_producer_proxy : public core::frame_producer_base
+{              
+       std::unique_ptr<decklink_producer>      producer_;
+       const uint32_t                                          length_;
+       executor                                                        executor_;
+public:
+       explicit decklink_producer_proxy(const core::video_format_desc& in_format_desc,
+                                                                        const spl::shared_ptr<core::frame_factory>& frame_factory, 
+                                                                        const core::video_format_desc& out_format_desc, 
+                                                                        int device_index,
+                                                                        const std::wstring& filter_str, uint32_t length)
+               : executor_(L"decklink_producer[" + boost::lexical_cast<std::wstring>(device_index) + L"]")
+               , length_(length)
+       {
+               executor_.invoke([=]
+               {
+                       CoInitialize(nullptr);
+                       producer_.reset(new decklink_producer(in_format_desc, device_index, frame_factory, out_format_desc, filter_str));
+               });
+       }
+
+       ~decklink_producer_proxy()
+       {               
+               executor_.invoke([=]
+               {
+                       producer_.reset();
+                       CoUninitialize();
+               });
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override
+       {
+               producer_->subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override
+       {
+               producer_->unsubscribe(o);
+       }
+       
+       // frame_producer
+                               
+       core::draw_frame receive_impl() override
+       {               
+               return producer_->get_frame();
+       }
+                       
+       uint32_t nb_frames() const override
+       {
+               return length_;
+       }
+       
+       std::wstring print() const override
+       {
+               return producer_->print();
+       }
+       
+       std::wstring name() const override
+       {
+               return L"decklink";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"decklink");
+               return info;
+       }
+};
+
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& out_format_desc, const std::vector<std::wstring>& params)
+{
+       if(params.empty() || !boost::iequals(params[0], "decklink"))
+               return core::frame_producer::empty();
+
+       auto device_index       = get_param(L"DEVICE", params, -1);
+       if(device_index == -1)
+               device_index = boost::lexical_cast<int>(params.at(1));
+       
+       auto filter_str         = get_param(L"FILTER", params);         
+       auto length                     = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());   
+       auto in_format_desc = core::video_format_desc(get_param(L"FORMAT", params, L"INVALID"));
+               
+       if(in_format_desc.format == core::video_format::invalid)
+               in_format_desc = out_format_desc;
+                       
+       return create_destroy_proxy(spl::make_shared<decklink_producer_proxy>(in_format_desc, frame_factory, out_format_desc, device_index, filter_str, length));
+}
+
 }}
\ No newline at end of file
index 8aa88fe6595163a0ec0fdcebcd325a835851382a..7b15aa6af6d1bd8e4a7431b1dd0eb288e30b0196 100644 (file)
@@ -1,33 +1,33 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <core/producer/frame_producer.h>\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar { namespace decklink {\r
-       \r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <core/producer/frame_producer.h>
+
+#include <string>
+#include <vector>
+
+namespace caspar { namespace decklink {
+       
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+
+}}
index a7828f52d4b549ee5cccc0fb8132b16eeef5d3af..9e3b5b27ab8a3ac24444e405d32cd5858aa3150d 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/except.h>\r
-#include <common/log.h>\r
-#include <core/video_format.h>\r
-\r
-#include "../interop/DeckLinkAPI_h.h"\r
-\r
-#include <boost/lexical_cast.hpp>\r
-\r
-#include <atlbase.h>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace decklink {\r
-       \r
-static BMDDisplayMode get_decklink_video_format(core::video_format fmt) \r
-{\r
-       switch(fmt.value())\r
-       {\r
-       case core::video_format::pal:                   return bmdModePAL;\r
-       case core::video_format::ntsc:                  return bmdModeNTSC;\r
-       case core::video_format::x576p2500:             return (BMDDisplayMode)ULONG_MAX;\r
-       case core::video_format::x720p2500:             return (BMDDisplayMode)ULONG_MAX;\r
-       case core::video_format::x720p5000:             return bmdModeHD720p50;\r
-       case core::video_format::x720p5994:             return bmdModeHD720p5994;\r
-       case core::video_format::x720p6000:             return bmdModeHD720p60;\r
-       case core::video_format::x1080p2397:    return bmdModeHD1080p2398;\r
-       case core::video_format::x1080p2400:    return bmdModeHD1080p24;\r
-       case core::video_format::x1080i5000:    return bmdModeHD1080i50;\r
-       case core::video_format::x1080i5994:    return bmdModeHD1080i5994;\r
-       case core::video_format::x1080i6000:    return bmdModeHD1080i6000;\r
-       case core::video_format::x1080p2500:    return bmdModeHD1080p25;\r
-       case core::video_format::x1080p2997:    return bmdModeHD1080p2997;\r
-       case core::video_format::x1080p3000:    return bmdModeHD1080p30;\r
-       case core::video_format::x1080p5000:    return bmdModeHD1080p50;\r
-       default:                                                                return (BMDDisplayMode)ULONG_MAX;\r
-       }\r
-}\r
-\r
-static core::video_format get_caspar_video_format(BMDDisplayMode fmt) \r
-{\r
-       switch(fmt)\r
-       {\r
-       case bmdModePAL:                                                return core::video_format::pal;         \r
-       case bmdModeNTSC:                                               return core::video_format::ntsc;                \r
-       case bmdModeHD720p50:                                   return core::video_format::x720p5000;   \r
-       case bmdModeHD720p5994:                                 return core::video_format::x720p5994;   \r
-       case bmdModeHD720p60:                                   return core::video_format::x720p6000;   \r
-       case bmdModeHD1080p2398:                                return core::video_format::x1080p2397;  \r
-       case bmdModeHD1080p24:                                  return core::video_format::x1080p2400;  \r
-       case bmdModeHD1080i50:                                  return core::video_format::x1080i5000;  \r
-       case bmdModeHD1080i5994:                                return core::video_format::x1080i5994;  \r
-       case bmdModeHD1080i6000:                                return core::video_format::x1080i6000;  \r
-       case bmdModeHD1080p25:                                  return core::video_format::x1080p2500;  \r
-       case bmdModeHD1080p2997:                                return core::video_format::x1080p2997;  \r
-       case bmdModeHD1080p30:                                  return core::video_format::x1080p3000;  \r
-       case bmdModeHD1080p50:                                  return core::video_format::x1080p5000;  \r
-       default:                                                                return core::video_format::invalid;     \r
-       }\r
-}\r
-\r
-template<typename T, typename F>\r
-BMDDisplayMode get_display_mode(const T& device, BMDDisplayMode format, BMDPixelFormat pix_fmt, F flag)\r
-{\r
-       CComPtr<IDeckLinkDisplayModeIterator> iterator;\r
-       CComPtr<IDeckLinkDisplayMode>             mode;\r
-       \r
-       if(SUCCEEDED(device->GetDisplayModeIterator(&iterator)))\r
-       {\r
-               while(SUCCEEDED(iterator->Next(&mode)) && \r
-                               mode != nullptr && \r
-                               mode->GetDisplayMode() != format){}\r
-       }\r
-\r
-       if(!mode)\r
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Device could not find requested video-format.") \r
-                                                                                                << arg_value_info(boost::lexical_cast<std::string>(format))\r
-                                                                                                << arg_name_info("format"));\r
-               \r
-       BMDDisplayModeSupport displayModeSupport;\r
-       if(FAILED(device->DoesSupportVideoMode(mode->GetDisplayMode(), pix_fmt, flag, &displayModeSupport, nullptr)) || displayModeSupport == bmdDisplayModeNotSupported)\r
-               CASPAR_LOG(warning) << L"Device does not support video-format: " << mode->GetDisplayMode();\r
-               //CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Device does not support requested video-format.")\r
-               //                                                                               << arg_value_info(boost::lexical_cast<std::string>(format))\r
-               //                                                                               << arg_name_info("format"));\r
-       else if(displayModeSupport == bmdDisplayModeSupportedWithConversion)\r
-               CASPAR_LOG(warning) << L"Device supports video-format with conversion: " << mode->GetDisplayMode();\r
-\r
-       return mode->GetDisplayMode();\r
-}\r
-\r
-template<typename T, typename F>\r
-static BMDDisplayMode get_display_mode(const T& device, core::video_format fmt, BMDPixelFormat pix_fmt, F flag)\r
-{      \r
-       return get_display_mode(device, get_decklink_video_format(fmt), pix_fmt, flag);\r
-}\r
-\r
-template<typename T>\r
-static std::wstring version(T& iterator)\r
-{\r
-       CComQIPtr<IDeckLinkAPIInformation> info = iterator;\r
-       if (!info)\r
-               return L"Unknown";\r
-       \r
-       BSTR ver;               \r
-       info->GetString(BMDDeckLinkAPIVersion, &ver);\r
-               \r
-       return ver;                                     \r
-}\r
-\r
-static CComPtr<IDeckLink> get_device(size_t device_index)\r
-{\r
-       CComPtr<IDeckLinkIterator> pDecklinkIterator;\r
-       if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))\r
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Decklink drivers not found."));\r
-               \r
-       size_t n = 0;\r
-       CComPtr<IDeckLink> decklink;\r
-       while(n < device_index && pDecklinkIterator->Next(&decklink) == S_OK){++n;}     \r
-\r
-       if(n != device_index || !decklink)\r
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Decklink device not found.") << arg_name_info("device_index") << arg_value_info(boost::lexical_cast<std::string>(device_index)));\r
-               \r
-       return decklink;\r
-}\r
-\r
-template <typename T>\r
-static std::wstring get_model_name(const T& device)\r
-{      \r
-       BSTR pModelName;\r
-       device->GetModelName(&pModelName);\r
-       return std::wstring(pModelName);\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/except.h>
+#include <common/log.h>
+#include <core/video_format.h>
+
+#include "../interop/DeckLinkAPI_h.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include <atlbase.h>
+
+#include <string>
+
+namespace caspar { namespace decklink {
+       
+static BMDDisplayMode get_decklink_video_format(core::video_format fmt) 
+{
+       switch(fmt.value())
+       {
+       case core::video_format::pal:                   return bmdModePAL;
+       case core::video_format::ntsc:                  return bmdModeNTSC;
+       case core::video_format::x576p2500:             return (BMDDisplayMode)ULONG_MAX;
+       case core::video_format::x720p2500:             return (BMDDisplayMode)ULONG_MAX;
+       case core::video_format::x720p5000:             return bmdModeHD720p50;
+       case core::video_format::x720p5994:             return bmdModeHD720p5994;
+       case core::video_format::x720p6000:             return bmdModeHD720p60;
+       case core::video_format::x1080p2397:    return bmdModeHD1080p2398;
+       case core::video_format::x1080p2400:    return bmdModeHD1080p24;
+       case core::video_format::x1080i5000:    return bmdModeHD1080i50;
+       case core::video_format::x1080i5994:    return bmdModeHD1080i5994;
+       case core::video_format::x1080i6000:    return bmdModeHD1080i6000;
+       case core::video_format::x1080p2500:    return bmdModeHD1080p25;
+       case core::video_format::x1080p2997:    return bmdModeHD1080p2997;
+       case core::video_format::x1080p3000:    return bmdModeHD1080p30;
+       case core::video_format::x1080p5000:    return bmdModeHD1080p50;
+       default:                                                                return (BMDDisplayMode)ULONG_MAX;
+       }
+}
+
+static core::video_format get_caspar_video_format(BMDDisplayMode fmt) 
+{
+       switch(fmt)
+       {
+       case bmdModePAL:                                                return core::video_format::pal;         
+       case bmdModeNTSC:                                               return core::video_format::ntsc;                
+       case bmdModeHD720p50:                                   return core::video_format::x720p5000;   
+       case bmdModeHD720p5994:                                 return core::video_format::x720p5994;   
+       case bmdModeHD720p60:                                   return core::video_format::x720p6000;   
+       case bmdModeHD1080p2398:                                return core::video_format::x1080p2397;  
+       case bmdModeHD1080p24:                                  return core::video_format::x1080p2400;  
+       case bmdModeHD1080i50:                                  return core::video_format::x1080i5000;  
+       case bmdModeHD1080i5994:                                return core::video_format::x1080i5994;  
+       case bmdModeHD1080i6000:                                return core::video_format::x1080i6000;  
+       case bmdModeHD1080p25:                                  return core::video_format::x1080p2500;  
+       case bmdModeHD1080p2997:                                return core::video_format::x1080p2997;  
+       case bmdModeHD1080p30:                                  return core::video_format::x1080p3000;  
+       case bmdModeHD1080p50:                                  return core::video_format::x1080p5000;  
+       default:                                                                return core::video_format::invalid;     
+       }
+}
+
+template<typename T, typename F>
+BMDDisplayMode get_display_mode(const T& device, BMDDisplayMode format, BMDPixelFormat pix_fmt, F flag)
+{
+       CComPtr<IDeckLinkDisplayModeIterator> iterator;
+       CComPtr<IDeckLinkDisplayMode>             mode;
+       
+       if(SUCCEEDED(device->GetDisplayModeIterator(&iterator)))
+       {
+               while(SUCCEEDED(iterator->Next(&mode)) && 
+                               mode != nullptr && 
+                               mode->GetDisplayMode() != format){}
+       }
+
+       if(!mode)
+               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Device could not find requested video-format.") 
+                                                                                                << arg_value_info(boost::lexical_cast<std::string>(format))
+                                                                                                << arg_name_info("format"));
+               
+       BMDDisplayModeSupport displayModeSupport;
+       if(FAILED(device->DoesSupportVideoMode(mode->GetDisplayMode(), pix_fmt, flag, &displayModeSupport, nullptr)) || displayModeSupport == bmdDisplayModeNotSupported)
+               CASPAR_LOG(warning) << L"Device does not support video-format: " << mode->GetDisplayMode();
+               //CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Device does not support requested video-format.")
+               //                                                                               << arg_value_info(boost::lexical_cast<std::string>(format))
+               //                                                                               << arg_name_info("format"));
+       else if(displayModeSupport == bmdDisplayModeSupportedWithConversion)
+               CASPAR_LOG(warning) << L"Device supports video-format with conversion: " << mode->GetDisplayMode();
+
+       return mode->GetDisplayMode();
+}
+
+template<typename T, typename F>
+static BMDDisplayMode get_display_mode(const T& device, core::video_format fmt, BMDPixelFormat pix_fmt, F flag)
+{      
+       return get_display_mode(device, get_decklink_video_format(fmt), pix_fmt, flag);
+}
+
+template<typename T>
+static std::wstring version(T& iterator)
+{
+       CComQIPtr<IDeckLinkAPIInformation> info = iterator;
+       if (!info)
+               return L"Unknown";
+       
+       BSTR ver;               
+       info->GetString(BMDDeckLinkAPIVersion, &ver);
+               
+       return ver;                                     
+}
+
+static CComPtr<IDeckLink> get_device(size_t device_index)
+{
+       CComPtr<IDeckLinkIterator> pDecklinkIterator;
+       if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))
+               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Decklink drivers not found."));
+               
+       size_t n = 0;
+       CComPtr<IDeckLink> decklink;
+       while(n < device_index && pDecklinkIterator->Next(&decklink) == S_OK){++n;}     
+
+       if(n != device_index || !decklink)
+               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Decklink device not found.") << arg_name_info("device_index") << arg_value_info(boost::lexical_cast<std::string>(device_index)));
+               
+       return decklink;
+}
+
+template <typename T>
+static std::wstring get_model_name(const T& device)
+{      
+       BSTR pModelName;
+       device->GetModelName(&pModelName);
+       return std::wstring(pModelName);
+}
+
 }}
\ No newline at end of file
index 923b06b9a95b823b42ad4e98f18fb7de1a037830..b2f0eab5690e733a64cd8a6f2476d0518ae84a0c 100644 (file)
@@ -1,22 +1,22 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "stdafx.h"\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "stdafx.h"
index 65af252198b506ae543c1c7e4c5a09e1e1ec2646..8e149aee32d8f18e95f4eb23195f163942d70052 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#ifdef _DEBUG\r
-#include <crtdbg.h>\r
-#endif\r
-\r
-#define NOMINMAX\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
-#include <algorithm>\r
-#include <array>\r
-#include <asmlib.h>\r
-#include <assert.h>\r
-#include <boost/algorithm/string.hpp>\r
-#include <boost/algorithm/string/case_conv.hpp>\r
-#include <boost/algorithm/string/predicate.hpp>\r
-#include <boost/assign.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/noncopyable.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/range/adaptors.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/range/algorithm/find.hpp>\r
-#include <boost/range/algorithm/find_if.hpp>\r
-#include <boost/range/algorithm_ext/push_back.hpp>\r
-#include <boost/range/iterator_range.hpp>\r
-#include <boost/regex.hpp>\r
-#include <boost/thread/condition_variable.hpp>\r
-#include <boost/thread/mutex.hpp>\r
-#include <boost/thread/once.hpp>\r
-#include <boost/thread/thread.hpp>\r
-#include <boost/timer.hpp>\r
-#include <crtdbg.h>\r
-#include <cstdint>\r
-#include <cstdio>\r
-#include <deque>\r
-#include <deque>\r
-#include <functional>\r
-#include <iostream>\r
-#include <limits>\r
-#include <math.h>\r
-#include <memory>\r
-#include <queue>\r
-#include <sstream>\r
-#include <string>\r
-#include <tbb/atomic.h>\r
-#include <tbb/cache_aligned_allocator.h>\r
-#include <tbb/concurrent_queue.h>\r
-#include <tbb/concurrent_unordered_map.h>\r
-#include <tbb/parallel_for.h>\r
-#include <tbb/parallel_invoke.h>\r
-#include <tbb/recursive_mutex.h>\r
-#include <tbb/tbb_thread.h>\r
-#include <unordered_map>\r
-#include <vector>\r
-\r
-#pragma warning(push, 1)\r
-\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
-       #define __STDC_LIMIT_MACROS\r
-       #include <libavcodec/avcodec.h>\r
-       #include <libavfilter/avcodec.h>\r
-       #include <libavfilter/avfilter.h>\r
-       #include <libavfilter/avfiltergraph.h>\r
-       #include <libavfilter/buffersink.h>\r
-       #include <libavfilter/vsrc_buffer.h>\r
-       #include <libavformat/avformat.h>\r
-       #include <libavutil/avutil.h>\r
-       #include <libavutil/common.h>\r
-       #include <libavutil/cpu.h>\r
-       #include <libavutil/error.h>\r
-       #include <libavutil/imgutils.h>\r
-       #include <libavutil/opt.h>\r
-       #include <libavutil/pixdesc.h>\r
-       #include <libavutil/samplefmt.h>\r
-       #include <libswscale/swscale.h>\r
-}\r
-\r
-#pragma warning(pop)\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+
+#include <algorithm>
+#include <array>
+#include <asmlib.h>
+#include <assert.h>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/assign.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/range/adaptors.hpp>
+#include <boost/range/algorithm.hpp>
+#include <boost/range/algorithm.hpp>
+#include <boost/range/algorithm/find.hpp>
+#include <boost/range/algorithm/find_if.hpp>
+#include <boost/range/algorithm_ext/push_back.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/regex.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/once.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/timer.hpp>
+#include <crtdbg.h>
+#include <cstdint>
+#include <cstdio>
+#include <deque>
+#include <deque>
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <math.h>
+#include <memory>
+#include <queue>
+#include <sstream>
+#include <string>
+#include <tbb/atomic.h>
+#include <tbb/cache_aligned_allocator.h>
+#include <tbb/concurrent_queue.h>
+#include <tbb/concurrent_unordered_map.h>
+#include <tbb/parallel_for.h>
+#include <tbb/parallel_invoke.h>
+#include <tbb/recursive_mutex.h>
+#include <tbb/tbb_thread.h>
+#include <unordered_map>
+#include <vector>
+
+#pragma warning(push, 1)
+
+extern "C" 
+{
+       #define __STDC_CONSTANT_MACROS
+       #define __STDC_LIMIT_MACROS
+       #include <libavcodec/avcodec.h>
+       #include <libavfilter/avcodec.h>
+       #include <libavfilter/avfilter.h>
+       #include <libavfilter/avfiltergraph.h>
+       #include <libavfilter/buffersink.h>
+       #include <libavfilter/vsrc_buffer.h>
+       #include <libavformat/avformat.h>
+       #include <libavutil/avutil.h>
+       #include <libavutil/common.h>
+       #include <libavutil/cpu.h>
+       #include <libavutil/error.h>
+       #include <libavutil/imgutils.h>
+       #include <libavutil/opt.h>
+       #include <libavutil/pixdesc.h>
+       #include <libavutil/samplefmt.h>
+       #include <libswscale/swscale.h>
+}
+
+#pragma warning(pop)
index 700092719b137187901583b1bb096a802a5ac00b..eff99a64a26057e8bed0d0cdb2e69bddf4a3601c 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
\r
-#include "../StdAfx.h"\r
-\r
-#include "../ffmpeg_error.h"\r
-\r
-#include "ffmpeg_consumer.h"\r
-\r
-#include "../producer/tbb_avcodec.h"\r
-\r
-#include <core/frame/frame.h>\r
-#include <core/mixer/audio/audio_util.h>\r
-#include <core/consumer/frame_consumer.h>\r
-#include <core/video_format.h>\r
-\r
-#include <common/array.h>\r
-#include <common/env.h>\r
-#include <common/except.h>\r
-#include <common/executor.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/lock.h>\r
-#include <common/memory.h>\r
-#include <common/param.h>\r
-#include <common/utf.h>\r
-#include <common/assert.h>\r
-\r
-#include <boost/algorithm/string.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/range/algorithm_ext.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-\r
-#include <tbb/spin_mutex.h>\r
-\r
-#include <numeric>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
-       #define __STDC_LIMIT_MACROS\r
-       #include <libavformat/avformat.h>\r
-       #include <libswscale/swscale.h>\r
-       #include <libavutil/opt.h>\r
-       #include <libavutil/pixdesc.h>\r
-       #include <libavutil/parseutils.h>\r
-       #include <libavutil/samplefmt.h>\r
-       #include <libswresample/swresample.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-int av_opt_set(void *obj, const char *name, const char *val, int search_flags)\r
-{\r
-       AVClass* av_class = *(AVClass**)obj;\r
-\r
-       if((strcmp(name, "pix_fmt") == 0 || strcmp(name, "pixel_format") == 0) && strcmp(av_class->class_name, "AVCodecContext") == 0)\r
-       {\r
-               AVCodecContext* c = (AVCodecContext*)obj;               \r
-               auto pix_fmt = av_get_pix_fmt(val);\r
-               if(pix_fmt == PIX_FMT_NONE)\r
-                       return -1;              \r
-               c->pix_fmt = pix_fmt;\r
-               return 0;\r
-       }\r
-       //if((strcmp(name, "r") == 0 || strcmp(name, "frame_rate") == 0) && strcmp(av_class->class_name, "AVCodecContext") == 0)\r
-       //{\r
-       //      AVCodecContext* c = (AVCodecContext*)obj;       \r
-\r
-       //      if(c->codec_type != AVMEDIA_TYPE_VIDEO)\r
-       //              return -1;\r
-\r
-       //      AVRational rate;\r
-       //      int ret = av_parse_video_rate(&rate, val);\r
-       //      if(ret < 0)\r
-       //              return ret;\r
-\r
-       //      c->time_base.num = rate.den;\r
-       //      c->time_base.den = rate.num;\r
-       //      return 0;\r
-       //}\r
-\r
-       return ::av_opt_set(obj, name, val, search_flags);\r
-}\r
-\r
-struct option\r
-{\r
-       std::string name;\r
-       std::string value;\r
-\r
-       option(std::string name, std::string value)\r
-               : name(std::move(name))\r
-               , value(std::move(value))\r
-       {\r
-       }\r
-};\r
-       \r
-struct output_format\r
-{\r
-       AVOutputFormat* format;\r
-       int                             width;\r
-       int                             height;\r
-       CodecID                 vcodec;\r
-       CodecID                 acodec;\r
-       int                             croptop;\r
-       int                             cropbot;\r
-\r
-       output_format(const core::video_format_desc& format_desc, const std::string& filename, std::vector<option>& options)\r
-               : format(av_guess_format(nullptr, filename.c_str(), nullptr))\r
-               , width(format_desc.width)\r
-               , height(format_desc.height)\r
-               , vcodec(CODEC_ID_NONE)\r
-               , acodec(CODEC_ID_NONE)\r
-               , croptop(0)\r
-               , cropbot(0)\r
-       {\r
-               if(boost::iequals(boost::filesystem::path(filename).extension().string(), ".dv"))\r
-                       set_opt("f", "dv");\r
-\r
-               boost::range::remove_erase_if(options, [&](const option& o)\r
-               {\r
-                       return set_opt(o.name, o.value);\r
-               });\r
-               \r
-               if(vcodec == CODEC_ID_NONE && format)\r
-                       vcodec = format->video_codec;\r
-\r
-               if(acodec == CODEC_ID_NONE && format)\r
-                       acodec = format->audio_codec;\r
-               \r
-               if(vcodec == CODEC_ID_NONE)\r
-                       vcodec = CODEC_ID_H264;\r
-               \r
-               if(acodec == CODEC_ID_NONE)\r
-                       acodec = CODEC_ID_PCM_S16LE;\r
-       }\r
-       \r
-       bool set_opt(const std::string& name, const std::string& value)\r
-       {\r
-               //if(name == "target")\r
-               //{ \r
-               //      enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;\r
-               //      \r
-               //      if(name.find("pal-") != std::string::npos)\r
-               //              norm = PAL;\r
-               //      else if(name.find("ntsc-") != std::string::npos)\r
-               //              norm = NTSC;\r
-\r
-               //      if(norm == UNKNOWN)\r
-               //              CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("target"));\r
-               //      \r
-               //      if (name.find("-dv") != std::string::npos) \r
-               //      {\r
-               //              set_opt("f", "dv");\r
-               //              if(norm == PAL)\r
-               //              {\r
-               //                      set_opt("s", "720x576");\r
-               //              }\r
-               //              else\r
-               //              {\r
-               //                      set_opt("s", "720x480");\r
-               //                      if(height == 486)\r
-               //                      {\r
-               //                              set_opt("croptop", "2");\r
-               //                              set_opt("cropbot", "4");\r
-               //                      }\r
-               //              }\r
-               //              set_opt("s", norm == PAL ? "720x576" : "720x480");\r
-               //      } \r
-\r
-               //      return true;\r
-               //}\r
-               //else \r
-               if(name == "f")\r
-               {\r
-                       format = av_guess_format(value.c_str(), nullptr, nullptr);\r
-\r
-                       if(format == nullptr)\r
-                               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("f"));\r
-\r
-                       return true;\r
-               }\r
-               else if(name == "vcodec" || name == "v:codec")\r
-               {\r
-                       auto c = avcodec_find_encoder_by_name(value.c_str());\r
-                       if(c == nullptr)\r
-                               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("vcodec"));\r
-\r
-                       vcodec = avcodec_find_encoder_by_name(value.c_str())->id;\r
-                       return true;\r
-\r
-               }\r
-               else if(name == "acodec" || name == "a:codec")\r
-               {\r
-                       auto c = avcodec_find_encoder_by_name(value.c_str());\r
-                       if(c == nullptr)\r
-                               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("acodec"));\r
-\r
-                       acodec = avcodec_find_encoder_by_name(value.c_str())->id;\r
-\r
-                       return true;\r
-               }\r
-               else if(name == "s")\r
-               {\r
-                       if(av_parse_video_size(&width, &height, value.c_str()) < 0)\r
-                               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("s"));\r
-                       \r
-                       return true;\r
-               }\r
-               else if(name == "croptop")\r
-               {\r
-                       croptop = boost::lexical_cast<int>(value);\r
-\r
-                       return true;\r
-               }\r
-               else if(name == "cropbot")\r
-               {\r
-                       cropbot = boost::lexical_cast<int>(value);\r
-\r
-                       return true;\r
-               }\r
-               \r
-               return false;\r
-       }\r
-};\r
-\r
-typedef std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>>    byte_vector;\r
-\r
-struct ffmpeg_consumer : boost::noncopyable\r
-{              \r
-       const spl::shared_ptr<diagnostics::graph>       graph_;\r
-       const std::string                                                       filename_;              \r
-       const std::shared_ptr<AVFormatContext>          oc_;\r
-       const core::video_format_desc                           format_desc_;   \r
-\r
-       monitor::basic_subject                                          event_subject_;\r
-       \r
-       tbb::spin_mutex                                                         exception_mutex_;\r
-       std::exception_ptr                                                      exception_;\r
-       \r
-       std::shared_ptr<AVStream>                                       audio_st_;\r
-       std::shared_ptr<AVStream>                                       video_st_;\r
-       \r
-       byte_vector                                                                     picture_buffer_;\r
-       byte_vector                                                                     audio_buffer_;\r
-       std::shared_ptr<SwrContext>                                     swr_;\r
-       std::shared_ptr<SwsContext>                                     sws_;\r
-\r
-       int64_t                                                                         frame_number_;\r
-\r
-       output_format                                                           output_format_;\r
-       \r
-       executor                                                                        executor_;\r
-public:\r
-       ffmpeg_consumer(const std::string& filename, const core::video_format_desc& format_desc, std::vector<option> options)\r
-               : filename_(filename)\r
-               , oc_(avformat_alloc_context(), av_free)\r
-               , format_desc_(format_desc)\r
-               , frame_number_(0)\r
-               , output_format_(format_desc, filename, options)\r
-               , executor_(print())\r
-       {\r
-               check_space();\r
-\r
-               // TODO: Ask stakeholders about case where file already exists.\r
-               boost::filesystem::remove(boost::filesystem::path(env::media_folder() + u16(filename))); // Delete the file if it exists\r
-\r
-               graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));\r
-               graph_->set_text(print());\r
-               diagnostics::register_graph(graph_);\r
-\r
-               executor_.set_capacity(8);\r
-\r
-               oc_->oformat = output_format_.format;\r
-                               \r
-               strcpy_s(oc_->filename, filename_.c_str());\r
-               \r
-               //  Add the audio and video streams using the default format codecs     and initialize the codecs.\r
-               video_st_ = add_video_stream(options);\r
-               audio_st_ = add_audio_stream(options);\r
-                               \r
-               av_dump_format(oc_.get(), 0, filename_.c_str(), 1);\r
-                \r
-               // Open the output ffmpeg, if needed.\r
-               if (!(oc_->oformat->flags & AVFMT_NOFILE)) \r
-                       THROW_ON_ERROR2(avio_open(&oc_->pb, filename.c_str(), AVIO_FLAG_WRITE), "[ffmpeg_consumer]");\r
-                               \r
-               THROW_ON_ERROR2(avformat_write_header(oc_.get(), nullptr), "[ffmpeg_consumer]");\r
-\r
-               if(options.size() > 0)\r
-               {\r
-                       BOOST_FOREACH(auto& option, options)\r
-                               CASPAR_LOG(warning) << L"Invalid option: -" << u16(option.name) << L" " << u16(option.value);\r
-               }\r
-\r
-               CASPAR_LOG(info) << print() << L" Successfully Initialized.";   \r
-       }\r
-\r
-       ~ffmpeg_consumer()\r
-       {    \r
-               try\r
-               {\r
-                       executor_.wait();\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-\r
-               LOG_ON_ERROR2(av_write_trailer(oc_.get()), "[ffmpeg_consumer]");\r
-               \r
-               audio_st_.reset();\r
-               video_st_.reset();\r
-                         \r
-               if (!(oc_->oformat->flags & AVFMT_NOFILE)) \r
-                       LOG_ON_ERROR2(avio_close(oc_->pb), "[ffmpeg_consumer]");\r
-\r
-               CASPAR_LOG(info) << print() << L" Successfully Uninitialized."; \r
-       }\r
-       \r
-       // frame_consumer\r
-\r
-       bool send(core::const_frame& frame)\r
-       {\r
-               auto exception = lock(exception_mutex_, [&]\r
-               {\r
-                       return exception_;\r
-               });\r
-\r
-               if(exception != nullptr)\r
-                       std::rethrow_exception(exception);\r
-                       \r
-               executor_.begin_invoke([=]\r
-               {               \r
-                       encode(frame);\r
-               });\r
-               \r
-               return true;\r
-       }\r
-\r
-       std::wstring print() const\r
-       {\r
-               return L"ffmpeg[" + u16(filename_) + L"]";\r
-       }\r
-       \r
-       void subscribe(const monitor::observable::observer_ptr& o)\r
-       {\r
-               event_subject_.subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o)\r
-       {\r
-               event_subject_.unsubscribe(o);\r
-       }               \r
-\r
-private:\r
-       std::shared_ptr<AVStream> add_video_stream(std::vector<option>& options)\r
-       { \r
-               if(output_format_.vcodec == CODEC_ID_NONE)\r
-                       return nullptr;\r
-\r
-               auto st = av_new_stream(oc_.get(), 0);\r
-               if (!st)                \r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Could not allocate video-stream.") << boost::errinfo_api_function("av_new_stream"));             \r
-\r
-               auto encoder = avcodec_find_encoder(output_format_.vcodec);\r
-               if (!encoder)\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Codec not found."));\r
-\r
-               auto c = st->codec;\r
-\r
-               avcodec_get_context_defaults3(c, encoder);\r
-                               \r
-               c->codec_id                     = output_format_.vcodec;\r
-               c->codec_type           = AVMEDIA_TYPE_VIDEO;\r
-               c->width                        = output_format_.width;\r
-               c->height                       = output_format_.height - output_format_.croptop - output_format_.cropbot;\r
-               c->time_base.den        = format_desc_.time_scale;\r
-               c->time_base.num        = format_desc_.duration;\r
-               c->gop_size                     = 25;\r
-               c->flags                   |= format_desc_.field_mode == core::field_mode::progressive ? 0 : (CODEC_FLAG_INTERLACED_ME | CODEC_FLAG_INTERLACED_DCT);\r
-               c->pix_fmt                      = c->pix_fmt != PIX_FMT_NONE ? c->pix_fmt : PIX_FMT_YUV420P;\r
-\r
-               if(c->codec_id == CODEC_ID_PRORES)\r
-               {                       \r
-                       c->bit_rate     = output_format_.width < 1280 ? 63*1000000 : 220*1000000;\r
-                       c->pix_fmt      = PIX_FMT_YUV422P10;\r
-               }\r
-               else if(c->codec_id == CODEC_ID_DNXHD)\r
-               {\r
-                       if(c->width < 1280 || c->height < 720)\r
-                               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Unsupported video dimensions."));\r
-\r
-                       c->bit_rate     = 220*1000000;\r
-                       c->pix_fmt      = PIX_FMT_YUV422P;\r
-               }\r
-               else if(c->codec_id == CODEC_ID_DVVIDEO)\r
-               {\r
-                       c->width = c->height == 1280 ? 960  : c->width;\r
-                       \r
-                       if(format_desc_.format == core::video_format::ntsc)\r
-                       {\r
-                               c->pix_fmt = PIX_FMT_YUV411P;\r
-                               output_format_.croptop = 2;\r
-                               output_format_.cropbot = 4;\r
-                               c->height                          = output_format_.height - output_format_.croptop - output_format_.cropbot;\r
-                       }\r
-                       else if(format_desc_.format == core::video_format::pal)\r
-                               c->pix_fmt = PIX_FMT_YUV420P;\r
-                       else // dv50\r
-                               c->pix_fmt = PIX_FMT_YUV422P;\r
-                       \r
-                       if(format_desc_.duration == 1001)                       \r
-                               c->width = c->height == 1080 ? 1280 : c->width;                 \r
-                       else\r
-                               c->width = c->height == 1080 ? 1440 : c->width;                 \r
-               }\r
-               else if(c->codec_id == CODEC_ID_H264)\r
-               {                          \r
-                       c->pix_fmt = PIX_FMT_YUV420P;    \r
-                       av_opt_set(c->priv_data, "preset", "ultrafast", 0);\r
-                       av_opt_set(c->priv_data, "tune",   "fastdecode",   0);\r
-                       av_opt_set(c->priv_data, "crf",    "5",     0);\r
-               }\r
-               else if(c->codec_id == CODEC_ID_QTRLE)\r
-               {\r
-                       c->pix_fmt = PIX_FMT_ARGB;\r
-               }\r
-                                                               \r
-               boost::range::remove_erase_if(options, [&](const option& o)\r
-               {\r
-                       return o.name.at(0) != 'a' && ffmpeg::av_opt_set(c, o.name.c_str(), o.value.c_str(), AV_OPT_SEARCH_CHILDREN) > -1;\r
-               });\r
-                               \r
-               if(output_format_.format->flags & AVFMT_GLOBALHEADER)\r
-                       c->flags |= CODEC_FLAG_GLOBAL_HEADER;\r
-               \r
-               THROW_ON_ERROR2(tbb_avcodec_open(c, encoder), "[ffmpeg_consumer]");\r
-\r
-               return std::shared_ptr<AVStream>(st, [](AVStream* st)\r
-               {\r
-                       LOG_ON_ERROR2(tbb_avcodec_close(st->codec), "[ffmpeg_consumer]");\r
-                       av_freep(&st->codec);\r
-                       av_freep(&st);\r
-               });\r
-       }\r
-               \r
-       std::shared_ptr<AVStream> add_audio_stream(std::vector<option>& options)\r
-       {\r
-               if(output_format_.acodec == CODEC_ID_NONE)\r
-                       return nullptr;\r
-\r
-               auto st = av_new_stream(oc_.get(), 1);\r
-               if(!st)\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Could not allocate audio-stream") << boost::errinfo_api_function("av_new_stream"));              \r
-               \r
-               auto encoder = avcodec_find_encoder(output_format_.acodec);\r
-               if (!encoder)\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("codec not found"));\r
-               \r
-               auto c = st->codec;\r
-\r
-               avcodec_get_context_defaults3(c, encoder);\r
-\r
-               c->codec_id                     = output_format_.acodec;\r
-               c->codec_type           = AVMEDIA_TYPE_AUDIO;\r
-               c->sample_rate          = 48000;\r
-               c->channels                     = 2;\r
-               c->sample_fmt           = AV_SAMPLE_FMT_S16;\r
-               c->time_base.num        = 1;\r
-               c->time_base.den        = c->sample_rate;\r
-\r
-               if(output_format_.vcodec == CODEC_ID_FLV1)              \r
-                       c->sample_rate  = 44100;                \r
-\r
-               if(output_format_.format->flags & AVFMT_GLOBALHEADER)\r
-                       c->flags |= CODEC_FLAG_GLOBAL_HEADER;\r
-                               \r
-               boost::range::remove_erase_if(options, [&](const option& o)\r
-               {\r
-                       return ffmpeg::av_opt_set(c, o.name.c_str(), o.value.c_str(), AV_OPT_SEARCH_CHILDREN) > -1;\r
-               });\r
-\r
-               THROW_ON_ERROR2(avcodec_open(c, encoder), "[ffmpeg_consumer]");\r
-\r
-               return std::shared_ptr<AVStream>(st, [](AVStream* st)\r
-               {\r
-                       LOG_ON_ERROR2(avcodec_close(st->codec), "[ffmpeg_consumer]");;\r
-                       av_freep(&st->codec);\r
-                       av_freep(&st);\r
-               });\r
-       }\r
-  \r
-       void encode_video_frame(core::const_frame frame)\r
-       { \r
-               if(!video_st_)\r
-                       return;\r
-               \r
-               auto enc = video_st_->codec;\r
-        \r
-               auto av_frame                           = convert_video(frame, enc);\r
-               av_frame->interlaced_frame      = format_desc_.field_mode != core::field_mode::progressive;\r
-               av_frame->top_field_first       = format_desc_.field_mode == core::field_mode::upper;\r
-               av_frame->pts                           = frame_number_++;\r
-\r
-               event_subject_ << monitor::event("frame")       % static_cast<int64_t>(frame_number_)\r
-                                                                                                       % static_cast<int64_t>(std::numeric_limits<int64_t>::max());\r
-\r
-               AVPacket pkt;\r
-               av_init_packet(&pkt);\r
-               pkt.data = nullptr;\r
-               pkt.size = 0;\r
-\r
-               int got_packet = 0;\r
-               THROW_ON_ERROR2(avcodec_encode_video2(enc, &pkt, av_frame.get(), &got_packet), "[ffmpeg_consumer]");\r
-               std::shared_ptr<AVPacket> guard(&pkt, av_free_packet);\r
-\r
-               if(!got_packet)\r
-                       return;\r
-                \r
-               if (pkt.pts != AV_NOPTS_VALUE)\r
-                       pkt.pts = av_rescale_q(pkt.pts, enc->time_base, video_st_->time_base);\r
-               if (pkt.dts != AV_NOPTS_VALUE)\r
-                       pkt.dts = av_rescale_q(pkt.dts, enc->time_base, video_st_->time_base);\r
-                \r
-               pkt.stream_index = video_st_->index;\r
-                       \r
-               THROW_ON_ERROR2(av_interleaved_write_frame(oc_.get(), &pkt), "[ffmpeg_consumer]");\r
-       }\r
-               \r
-       uint64_t get_channel_layout(AVCodecContext* dec)\r
-       {\r
-               auto layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels);\r
-               return layout;\r
-       }\r
-               \r
-       void encode_audio_frame(core::const_frame frame)\r
-       {               \r
-               if(!audio_st_)\r
-                       return;\r
-               \r
-               auto enc = audio_st_->codec;\r
-\r
-               boost::push_back(audio_buffer_, convert_audio(frame, enc));\r
-                       \r
-               auto frame_size = enc->frame_size != 0 ? enc->frame_size * enc->channels * av_get_bytes_per_sample(enc->sample_fmt) : static_cast<int>(audio_buffer_.size());\r
-                       \r
-               while(audio_buffer_.size() >= frame_size)\r
-               {                       \r
-                       std::shared_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);\r
-                       avcodec_get_frame_defaults(av_frame.get());             \r
-                       av_frame->nb_samples = frame_size / (enc->channels * av_get_bytes_per_sample(enc->sample_fmt));\r
-\r
-                       AVPacket pkt;\r
-                       av_init_packet(&pkt);\r
-                       pkt.data = nullptr;\r
-                       pkt.size = 0;                           \r
-                       \r
-                       THROW_ON_ERROR2(avcodec_fill_audio_frame(av_frame.get(), enc->channels, enc->sample_fmt, audio_buffer_.data(), frame_size, 1), "[ffmpeg_consumer]");\r
-\r
-                       int got_packet = 0;\r
-                       THROW_ON_ERROR2(avcodec_encode_audio2(enc, &pkt, av_frame.get(), &got_packet), "[ffmpeg_consumer]");\r
-                       std::shared_ptr<AVPacket> guard(&pkt, av_free_packet);\r
-                               \r
-                       audio_buffer_.erase(audio_buffer_.begin(), audio_buffer_.begin() + frame_size);\r
-\r
-                       if(!got_packet)\r
-                               return;\r
-               \r
-                       if (pkt.pts != AV_NOPTS_VALUE)\r
-                               pkt.pts      = av_rescale_q(pkt.pts, enc->time_base, audio_st_->time_base);\r
-                       if (pkt.dts != AV_NOPTS_VALUE)\r
-                               pkt.dts      = av_rescale_q(pkt.dts, enc->time_base, audio_st_->time_base);\r
-                       if (pkt.duration > 0)\r
-                               pkt.duration = static_cast<int>(av_rescale_q(pkt.duration, enc->time_base, audio_st_->time_base));\r
-               \r
-                       pkt.stream_index = audio_st_->index;\r
-                                               \r
-                       THROW_ON_ERROR2(av_interleaved_write_frame(oc_.get(), &pkt), "[ffmpeg_consumer]");\r
-               }\r
-       }                \r
-       \r
-       std::shared_ptr<AVFrame> convert_video(core::const_frame frame, AVCodecContext* c)\r
-       {\r
-               if(!sws_) \r
-               {\r
-                       sws_.reset(sws_getContext(format_desc_.width, \r
-                                                                         format_desc_.height - output_format_.croptop  - output_format_.cropbot, \r
-                                                                         PIX_FMT_BGRA,\r
-                                                                         c->width,\r
-                                                                         c->height, \r
-                                                                         c->pix_fmt, \r
-                                                                         SWS_BICUBIC, nullptr, nullptr, nullptr), \r
-                                               sws_freeContext);\r
-                       if (sws_ == nullptr) \r
-                               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Cannot initialize the conversion context"));\r
-               }\r
-\r
-               // #in_frame\r
-\r
-               std::shared_ptr<AVFrame> in_frame(avcodec_alloc_frame(), av_free);\r
-\r
-               avpicture_fill(reinterpret_cast<AVPicture*>(in_frame.get()), \r
-                                          const_cast<uint8_t*>(frame.image_data().begin()),\r
-                                          PIX_FMT_BGRA, \r
-                                          format_desc_.width,\r
-                                          format_desc_.height - output_format_.croptop  - output_format_.cropbot);\r
-               // crop-top\r
-\r
-               for(int n = 0; n < 4; ++n)              \r
-                       in_frame->data[n] += in_frame->linesize[n] * output_format_.croptop;            \r
-               \r
-               // #out_frame\r
-\r
-               std::shared_ptr<AVFrame> out_frame(avcodec_alloc_frame(), av_free);\r
-               \r
-               av_image_fill_linesizes(out_frame->linesize, c->pix_fmt, c->width);\r
-               for(int n = 0; n < 4; ++n)\r
-                       out_frame->linesize[n] += 32 - (out_frame->linesize[n] % 32); // align\r
-\r
-               picture_buffer_.resize(av_image_fill_pointers(out_frame->data, c->pix_fmt, c->height, nullptr, out_frame->linesize));\r
-               av_image_fill_pointers(out_frame->data, c->pix_fmt, c->height, picture_buffer_.data(), out_frame->linesize);\r
-               \r
-               // #scale\r
-\r
-               sws_scale(sws_.get(), \r
-                                 in_frame->data, \r
-                                 in_frame->linesize,\r
-                                 0, \r
-                                 format_desc_.height - output_format_.cropbot - output_format_.croptop, \r
-                                 out_frame->data, \r
-                                 out_frame->linesize);\r
-\r
-               return out_frame;\r
-       }\r
-       \r
-       byte_vector convert_audio(core::const_frame& frame, AVCodecContext* c)\r
-       {\r
-               if(!swr_) \r
-               {\r
-                       swr_ = std::shared_ptr<SwrContext>(swr_alloc_set_opts(nullptr,\r
-                                                                               get_channel_layout(c), c->sample_fmt, c->sample_rate,\r
-                                                                               av_get_default_channel_layout(format_desc_.audio_channels), AV_SAMPLE_FMT_S32, format_desc_.audio_sample_rate,\r
-                                                                               0, nullptr), [](SwrContext* p){swr_free(&p);});\r
-\r
-                       if(!swr_)\r
-                               CASPAR_THROW_EXCEPTION(bad_alloc());\r
-\r
-                       THROW_ON_ERROR2(swr_init(swr_.get()), "[audio_decoder]");\r
-               }\r
-                               \r
-               byte_vector buffer(48000);\r
-\r
-               const uint8_t* in[]  = {reinterpret_cast<const uint8_t*>(frame.audio_data().data())};\r
-               uint8_t*       out[] = {buffer.data()};\r
-\r
-               auto channel_samples = swr_convert(swr_.get(), \r
-                                                                                  out, static_cast<int>(buffer.size()) / c->channels / av_get_bytes_per_sample(c->sample_fmt), \r
-                                                                                  in, static_cast<int>(frame.audio_data().size()/format_desc_.audio_channels));\r
-\r
-               buffer.resize(channel_samples * c->channels * av_get_bytes_per_sample(c->sample_fmt));  \r
-\r
-               return buffer;\r
-       }\r
-\r
-       void check_space()\r
-       {\r
-               auto space = boost::filesystem::space(boost::filesystem::path(filename_).parent_path());\r
-               if(space.available < 512*1000000)\r
-                       BOOST_THROW_EXCEPTION(file_write_error() << msg_info("out of space"));\r
-       }\r
-\r
-       void encode(const core::const_frame& frame)\r
-       {\r
-               try\r
-               {\r
-                       if(frame_number_ % 25 == 0)\r
-                               check_space();\r
-\r
-                       boost::timer frame_timer;\r
-\r
-                       encode_video_frame(frame);\r
-                       encode_audio_frame(frame);\r
-\r
-                       graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);\r
-               }\r
-               catch(...)\r
-               {                       \r
-                       lock(exception_mutex_, [&]\r
-                       {\r
-                               exception_ = std::current_exception();\r
-                       });\r
-               }\r
-       }\r
-};\r
-\r
-struct ffmpeg_consumer_proxy : public core::frame_consumer\r
-{\r
-       const std::wstring                              filename_;\r
-       const std::vector<option>               options_;\r
-\r
-       std::unique_ptr<ffmpeg_consumer> consumer_;\r
-\r
-public:\r
-\r
-       ffmpeg_consumer_proxy(const std::wstring& filename, const std::vector<option>& options)\r
-               : filename_(filename)\r
-               , options_(options)\r
-       {\r
-       }\r
-       \r
-       virtual void initialize(const core::video_format_desc& format_desc, int)\r
-       {\r
-               if(consumer_)\r
-                       BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Cannot reinitialize ffmpeg-consumer."));\r
-\r
-               consumer_.reset(new ffmpeg_consumer(u8(filename_), format_desc, options_));\r
-       }\r
-       \r
-       bool send(core::const_frame frame) override\r
-       {\r
-               return consumer_->send(frame);\r
-       }\r
-       \r
-       std::wstring print() const override\r
-       {\r
-               return consumer_ ? consumer_->print() : L"[ffmpeg_consumer]";\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"file";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"file");\r
-               info.add(L"filename", filename_);\r
-               return info;\r
-       }\r
-               \r
-       bool has_synchronization_clock() const override\r
-       {\r
-               return false;\r
-       }\r
-\r
-       int buffer_depth() const override\r
-       {\r
-               return 1;\r
-       }\r
-\r
-       int index() const override\r
-       {\r
-               return 200;\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-               consumer_->subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-               consumer_->unsubscribe(o);\r
-       }               \r
-};     \r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)\r
-{\r
-       auto str = std::accumulate(params.begin(), params.end(), std::wstring(), [](const std::wstring& lhs, const std::wstring& rhs) {return lhs + L" " + rhs;});\r
-       \r
-       boost::wregex path_exp(L"\\s*FILE(\\s(?<PATH>.+\\.[^\\s]+))?.*", boost::regex::icase);\r
-\r
-       boost::wsmatch path;\r
-       if(!boost::regex_match(str, path, path_exp))\r
-               return core::frame_consumer::empty();\r
-       \r
-       boost::wregex opt_exp(L"-((?<NAME>[^\\s]+)\\s+(?<VALUE>[^\\s]+))");     \r
-       \r
-       std::vector<option> options;\r
-       for(boost::wsregex_iterator it(str.begin(), str.end(), opt_exp); it != boost::wsregex_iterator(); ++it)\r
-       {\r
-               auto name  = u8(boost::trim_copy(boost::to_lower_copy((*it)["NAME"].str())));\r
-               auto value = u8(boost::trim_copy(boost::to_lower_copy((*it)["VALUE"].str())));\r
-               \r
-               if(value == "h264")\r
-                       value = "libx264";\r
-               else if(value == "dvcpro")\r
-                       value = "dvvideo";\r
-\r
-               options.push_back(option(name, value));\r
-       }\r
-                               \r
-       return spl::make_shared<ffmpeg_consumer_proxy>(env::media_folder() + path["PATH"].str(), options);\r
-}\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree)\r
-{\r
-       auto filename   = ptree.get<std::wstring>(L"path");\r
-       auto codec              = ptree.get(L"vcodec", L"libx264");\r
-\r
-       std::vector<option> options;\r
-       options.push_back(option("vcodec", u8(codec)));\r
-       \r
-       return spl::make_shared<ffmpeg_consumer_proxy>(env::media_folder() + filename, options);\r
-}\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+#include "../StdAfx.h"
+
+#include "../ffmpeg_error.h"
+
+#include "ffmpeg_consumer.h"
+
+#include "../producer/tbb_avcodec.h"
+
+#include <core/frame/frame.h>
+#include <core/mixer/audio/audio_util.h>
+#include <core/consumer/frame_consumer.h>
+#include <core/video_format.h>
+
+#include <common/array.h>
+#include <common/env.h>
+#include <common/except.h>
+#include <common/executor.h>
+#include <common/diagnostics/graph.h>
+#include <common/lock.h>
+#include <common/memory.h>
+#include <common/param.h>
+#include <common/utf.h>
+#include <common/assert.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/timer.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/range/algorithm.hpp>
+#include <boost/range/algorithm_ext.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <tbb/spin_mutex.h>
+
+#include <numeric>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #define __STDC_CONSTANT_MACROS
+       #define __STDC_LIMIT_MACROS
+       #include <libavformat/avformat.h>
+       #include <libswscale/swscale.h>
+       #include <libavutil/opt.h>
+       #include <libavutil/pixdesc.h>
+       #include <libavutil/parseutils.h>
+       #include <libavutil/samplefmt.h>
+       #include <libswresample/swresample.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+namespace caspar { namespace ffmpeg {
+       
+int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
+{
+       AVClass* av_class = *(AVClass**)obj;
+
+       if((strcmp(name, "pix_fmt") == 0 || strcmp(name, "pixel_format") == 0) && strcmp(av_class->class_name, "AVCodecContext") == 0)
+       {
+               AVCodecContext* c = (AVCodecContext*)obj;               
+               auto pix_fmt = av_get_pix_fmt(val);
+               if(pix_fmt == PIX_FMT_NONE)
+                       return -1;              
+               c->pix_fmt = pix_fmt;
+               return 0;
+       }
+       //if((strcmp(name, "r") == 0 || strcmp(name, "frame_rate") == 0) && strcmp(av_class->class_name, "AVCodecContext") == 0)
+       //{
+       //      AVCodecContext* c = (AVCodecContext*)obj;       
+
+       //      if(c->codec_type != AVMEDIA_TYPE_VIDEO)
+       //              return -1;
+
+       //      AVRational rate;
+       //      int ret = av_parse_video_rate(&rate, val);
+       //      if(ret < 0)
+       //              return ret;
+
+       //      c->time_base.num = rate.den;
+       //      c->time_base.den = rate.num;
+       //      return 0;
+       //}
+
+       return ::av_opt_set(obj, name, val, search_flags);
+}
+
+struct option
+{
+       std::string name;
+       std::string value;
+
+       option(std::string name, std::string value)
+               : name(std::move(name))
+               , value(std::move(value))
+       {
+       }
+};
+       
+struct output_format
+{
+       AVOutputFormat* format;
+       int                             width;
+       int                             height;
+       CodecID                 vcodec;
+       CodecID                 acodec;
+       int                             croptop;
+       int                             cropbot;
+
+       output_format(const core::video_format_desc& format_desc, const std::string& filename, std::vector<option>& options)
+               : format(av_guess_format(nullptr, filename.c_str(), nullptr))
+               , width(format_desc.width)
+               , height(format_desc.height)
+               , vcodec(CODEC_ID_NONE)
+               , acodec(CODEC_ID_NONE)
+               , croptop(0)
+               , cropbot(0)
+       {
+               if(boost::iequals(boost::filesystem::path(filename).extension().string(), ".dv"))
+                       set_opt("f", "dv");
+
+               boost::range::remove_erase_if(options, [&](const option& o)
+               {
+                       return set_opt(o.name, o.value);
+               });
+               
+               if(vcodec == CODEC_ID_NONE && format)
+                       vcodec = format->video_codec;
+
+               if(acodec == CODEC_ID_NONE && format)
+                       acodec = format->audio_codec;
+               
+               if(vcodec == CODEC_ID_NONE)
+                       vcodec = CODEC_ID_H264;
+               
+               if(acodec == CODEC_ID_NONE)
+                       acodec = CODEC_ID_PCM_S16LE;
+       }
+       
+       bool set_opt(const std::string& name, const std::string& value)
+       {
+               //if(name == "target")
+               //{ 
+               //      enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;
+               //      
+               //      if(name.find("pal-") != std::string::npos)
+               //              norm = PAL;
+               //      else if(name.find("ntsc-") != std::string::npos)
+               //              norm = NTSC;
+
+               //      if(norm == UNKNOWN)
+               //              CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("target"));
+               //      
+               //      if (name.find("-dv") != std::string::npos) 
+               //      {
+               //              set_opt("f", "dv");
+               //              if(norm == PAL)
+               //              {
+               //                      set_opt("s", "720x576");
+               //              }
+               //              else
+               //              {
+               //                      set_opt("s", "720x480");
+               //                      if(height == 486)
+               //                      {
+               //                              set_opt("croptop", "2");
+               //                              set_opt("cropbot", "4");
+               //                      }
+               //              }
+               //              set_opt("s", norm == PAL ? "720x576" : "720x480");
+               //      } 
+
+               //      return true;
+               //}
+               //else 
+               if(name == "f")
+               {
+                       format = av_guess_format(value.c_str(), nullptr, nullptr);
+
+                       if(format == nullptr)
+                               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("f"));
+
+                       return true;
+               }
+               else if(name == "vcodec" || name == "v:codec")
+               {
+                       auto c = avcodec_find_encoder_by_name(value.c_str());
+                       if(c == nullptr)
+                               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("vcodec"));
+
+                       vcodec = avcodec_find_encoder_by_name(value.c_str())->id;
+                       return true;
+
+               }
+               else if(name == "acodec" || name == "a:codec")
+               {
+                       auto c = avcodec_find_encoder_by_name(value.c_str());
+                       if(c == nullptr)
+                               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("acodec"));
+
+                       acodec = avcodec_find_encoder_by_name(value.c_str())->id;
+
+                       return true;
+               }
+               else if(name == "s")
+               {
+                       if(av_parse_video_size(&width, &height, value.c_str()) < 0)
+                               CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("s"));
+                       
+                       return true;
+               }
+               else if(name == "croptop")
+               {
+                       croptop = boost::lexical_cast<int>(value);
+
+                       return true;
+               }
+               else if(name == "cropbot")
+               {
+                       cropbot = boost::lexical_cast<int>(value);
+
+                       return true;
+               }
+               
+               return false;
+       }
+};
+
+typedef std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>>    byte_vector;
+
+struct ffmpeg_consumer : boost::noncopyable
+{              
+       const spl::shared_ptr<diagnostics::graph>       graph_;
+       const std::string                                                       filename_;              
+       const std::shared_ptr<AVFormatContext>          oc_;
+       const core::video_format_desc                           format_desc_;   
+
+       monitor::basic_subject                                          event_subject_;
+       
+       tbb::spin_mutex                                                         exception_mutex_;
+       std::exception_ptr                                                      exception_;
+       
+       std::shared_ptr<AVStream>                                       audio_st_;
+       std::shared_ptr<AVStream>                                       video_st_;
+       
+       byte_vector                                                                     picture_buffer_;
+       byte_vector                                                                     audio_buffer_;
+       std::shared_ptr<SwrContext>                                     swr_;
+       std::shared_ptr<SwsContext>                                     sws_;
+
+       int64_t                                                                         frame_number_;
+
+       output_format                                                           output_format_;
+       
+       executor                                                                        executor_;
+public:
+       ffmpeg_consumer(const std::string& filename, const core::video_format_desc& format_desc, std::vector<option> options)
+               : filename_(filename)
+               , oc_(avformat_alloc_context(), av_free)
+               , format_desc_(format_desc)
+               , frame_number_(0)
+               , output_format_(format_desc, filename, options)
+               , executor_(print())
+       {
+               check_space();
+
+               // TODO: Ask stakeholders about case where file already exists.
+               boost::filesystem::remove(boost::filesystem::path(env::media_folder() + u16(filename))); // Delete the file if it exists
+
+               graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
+               graph_->set_text(print());
+               diagnostics::register_graph(graph_);
+
+               executor_.set_capacity(8);
+
+               oc_->oformat = output_format_.format;
+                               
+               strcpy_s(oc_->filename, filename_.c_str());
+               
+               //  Add the audio and video streams using the default format codecs     and initialize the codecs.
+               video_st_ = add_video_stream(options);
+               audio_st_ = add_audio_stream(options);
+                               
+               av_dump_format(oc_.get(), 0, filename_.c_str(), 1);
+                
+               // Open the output ffmpeg, if needed.
+               if (!(oc_->oformat->flags & AVFMT_NOFILE)) 
+                       THROW_ON_ERROR2(avio_open(&oc_->pb, filename.c_str(), AVIO_FLAG_WRITE), "[ffmpeg_consumer]");
+                               
+               THROW_ON_ERROR2(avformat_write_header(oc_.get(), nullptr), "[ffmpeg_consumer]");
+
+               if(options.size() > 0)
+               {
+                       BOOST_FOREACH(auto& option, options)
+                               CASPAR_LOG(warning) << L"Invalid option: -" << u16(option.name) << L" " << u16(option.value);
+               }
+
+               CASPAR_LOG(info) << print() << L" Successfully Initialized.";   
+       }
+
+       ~ffmpeg_consumer()
+       {    
+               try
+               {
+                       executor_.wait();
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+
+               LOG_ON_ERROR2(av_write_trailer(oc_.get()), "[ffmpeg_consumer]");
+               
+               audio_st_.reset();
+               video_st_.reset();
+                         
+               if (!(oc_->oformat->flags & AVFMT_NOFILE)) 
+                       LOG_ON_ERROR2(avio_close(oc_->pb), "[ffmpeg_consumer]");
+
+               CASPAR_LOG(info) << print() << L" Successfully Uninitialized."; 
+       }
+       
+       // frame_consumer
+
+       bool send(core::const_frame& frame)
+       {
+               auto exception = lock(exception_mutex_, [&]
+               {
+                       return exception_;
+               });
+
+               if(exception != nullptr)
+                       std::rethrow_exception(exception);
+                       
+               executor_.begin_invoke([=]
+               {               
+                       encode(frame);
+               });
+               
+               return true;
+       }
+
+       std::wstring print() const
+       {
+               return L"ffmpeg[" + u16(filename_) + L"]";
+       }
+       
+       void subscribe(const monitor::observable::observer_ptr& o)
+       {
+               event_subject_.subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o)
+       {
+               event_subject_.unsubscribe(o);
+       }               
+
+private:
+       std::shared_ptr<AVStream> add_video_stream(std::vector<option>& options)
+       { 
+               if(output_format_.vcodec == CODEC_ID_NONE)
+                       return nullptr;
+
+               auto st = av_new_stream(oc_.get(), 0);
+               if (!st)                
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Could not allocate video-stream.") << boost::errinfo_api_function("av_new_stream"));             
+
+               auto encoder = avcodec_find_encoder(output_format_.vcodec);
+               if (!encoder)
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Codec not found."));
+
+               auto c = st->codec;
+
+               avcodec_get_context_defaults3(c, encoder);
+                               
+               c->codec_id                     = output_format_.vcodec;
+               c->codec_type           = AVMEDIA_TYPE_VIDEO;
+               c->width                        = output_format_.width;
+               c->height                       = output_format_.height - output_format_.croptop - output_format_.cropbot;
+               c->time_base.den        = format_desc_.time_scale;
+               c->time_base.num        = format_desc_.duration;
+               c->gop_size                     = 25;
+               c->flags                   |= format_desc_.field_mode == core::field_mode::progressive ? 0 : (CODEC_FLAG_INTERLACED_ME | CODEC_FLAG_INTERLACED_DCT);
+               c->pix_fmt                      = c->pix_fmt != PIX_FMT_NONE ? c->pix_fmt : PIX_FMT_YUV420P;
+
+               if(c->codec_id == CODEC_ID_PRORES)
+               {                       
+                       c->bit_rate     = output_format_.width < 1280 ? 63*1000000 : 220*1000000;
+                       c->pix_fmt      = PIX_FMT_YUV422P10;
+               }
+               else if(c->codec_id == CODEC_ID_DNXHD)
+               {
+                       if(c->width < 1280 || c->height < 720)
+                               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Unsupported video dimensions."));
+
+                       c->bit_rate     = 220*1000000;
+                       c->pix_fmt      = PIX_FMT_YUV422P;
+               }
+               else if(c->codec_id == CODEC_ID_DVVIDEO)
+               {
+                       c->width = c->height == 1280 ? 960  : c->width;
+                       
+                       if(format_desc_.format == core::video_format::ntsc)
+                       {
+                               c->pix_fmt = PIX_FMT_YUV411P;
+                               output_format_.croptop = 2;
+                               output_format_.cropbot = 4;
+                               c->height                          = output_format_.height - output_format_.croptop - output_format_.cropbot;
+                       }
+                       else if(format_desc_.format == core::video_format::pal)
+                               c->pix_fmt = PIX_FMT_YUV420P;
+                       else // dv50
+                               c->pix_fmt = PIX_FMT_YUV422P;
+                       
+                       if(format_desc_.duration == 1001)                       
+                               c->width = c->height == 1080 ? 1280 : c->width;                 
+                       else
+                               c->width = c->height == 1080 ? 1440 : c->width;                 
+               }
+               else if(c->codec_id == CODEC_ID_H264)
+               {                          
+                       c->pix_fmt = PIX_FMT_YUV420P;    
+                       av_opt_set(c->priv_data, "preset", "ultrafast", 0);
+                       av_opt_set(c->priv_data, "tune",   "fastdecode",   0);
+                       av_opt_set(c->priv_data, "crf",    "5",     0);
+               }
+               else if(c->codec_id == CODEC_ID_QTRLE)
+               {
+                       c->pix_fmt = PIX_FMT_ARGB;
+               }
+                                                               
+               boost::range::remove_erase_if(options, [&](const option& o)
+               {
+                       return o.name.at(0) != 'a' && ffmpeg::av_opt_set(c, o.name.c_str(), o.value.c_str(), AV_OPT_SEARCH_CHILDREN) > -1;
+               });
+                               
+               if(output_format_.format->flags & AVFMT_GLOBALHEADER)
+                       c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+               
+               THROW_ON_ERROR2(tbb_avcodec_open(c, encoder), "[ffmpeg_consumer]");
+
+               return std::shared_ptr<AVStream>(st, [](AVStream* st)
+               {
+                       LOG_ON_ERROR2(tbb_avcodec_close(st->codec), "[ffmpeg_consumer]");
+                       av_freep(&st->codec);
+                       av_freep(&st);
+               });
+       }
+               
+       std::shared_ptr<AVStream> add_audio_stream(std::vector<option>& options)
+       {
+               if(output_format_.acodec == CODEC_ID_NONE)
+                       return nullptr;
+
+               auto st = av_new_stream(oc_.get(), 1);
+               if(!st)
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Could not allocate audio-stream") << boost::errinfo_api_function("av_new_stream"));              
+               
+               auto encoder = avcodec_find_encoder(output_format_.acodec);
+               if (!encoder)
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("codec not found"));
+               
+               auto c = st->codec;
+
+               avcodec_get_context_defaults3(c, encoder);
+
+               c->codec_id                     = output_format_.acodec;
+               c->codec_type           = AVMEDIA_TYPE_AUDIO;
+               c->sample_rate          = 48000;
+               c->channels                     = 2;
+               c->sample_fmt           = AV_SAMPLE_FMT_S16;
+               c->time_base.num        = 1;
+               c->time_base.den        = c->sample_rate;
+
+               if(output_format_.vcodec == CODEC_ID_FLV1)              
+                       c->sample_rate  = 44100;                
+
+               if(output_format_.format->flags & AVFMT_GLOBALHEADER)
+                       c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+                               
+               boost::range::remove_erase_if(options, [&](const option& o)
+               {
+                       return ffmpeg::av_opt_set(c, o.name.c_str(), o.value.c_str(), AV_OPT_SEARCH_CHILDREN) > -1;
+               });
+
+               THROW_ON_ERROR2(avcodec_open(c, encoder), "[ffmpeg_consumer]");
+
+               return std::shared_ptr<AVStream>(st, [](AVStream* st)
+               {
+                       LOG_ON_ERROR2(avcodec_close(st->codec), "[ffmpeg_consumer]");;
+                       av_freep(&st->codec);
+                       av_freep(&st);
+               });
+       }
+  
+       void encode_video_frame(core::const_frame frame)
+       { 
+               if(!video_st_)
+                       return;
+               
+               auto enc = video_st_->codec;
+        
+               auto av_frame                           = convert_video(frame, enc);
+               av_frame->interlaced_frame      = format_desc_.field_mode != core::field_mode::progressive;
+               av_frame->top_field_first       = format_desc_.field_mode == core::field_mode::upper;
+               av_frame->pts                           = frame_number_++;
+
+               event_subject_ << monitor::event("frame")       % static_cast<int64_t>(frame_number_)
+                                                                                                       % static_cast<int64_t>(std::numeric_limits<int64_t>::max());
+
+               AVPacket pkt;
+               av_init_packet(&pkt);
+               pkt.data = nullptr;
+               pkt.size = 0;
+
+               int got_packet = 0;
+               THROW_ON_ERROR2(avcodec_encode_video2(enc, &pkt, av_frame.get(), &got_packet), "[ffmpeg_consumer]");
+               std::shared_ptr<AVPacket> guard(&pkt, av_free_packet);
+
+               if(!got_packet)
+                       return;
+                
+               if (pkt.pts != AV_NOPTS_VALUE)
+                       pkt.pts = av_rescale_q(pkt.pts, enc->time_base, video_st_->time_base);
+               if (pkt.dts != AV_NOPTS_VALUE)
+                       pkt.dts = av_rescale_q(pkt.dts, enc->time_base, video_st_->time_base);
+                
+               pkt.stream_index = video_st_->index;
+                       
+               THROW_ON_ERROR2(av_interleaved_write_frame(oc_.get(), &pkt), "[ffmpeg_consumer]");
+       }
+               
+       uint64_t get_channel_layout(AVCodecContext* dec)
+       {
+               auto layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels);
+               return layout;
+       }
+               
+       void encode_audio_frame(core::const_frame frame)
+       {               
+               if(!audio_st_)
+                       return;
+               
+               auto enc = audio_st_->codec;
+
+               boost::push_back(audio_buffer_, convert_audio(frame, enc));
+                       
+               auto frame_size = enc->frame_size != 0 ? enc->frame_size * enc->channels * av_get_bytes_per_sample(enc->sample_fmt) : static_cast<int>(audio_buffer_.size());
+                       
+               while(audio_buffer_.size() >= frame_size)
+               {                       
+                       std::shared_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);
+                       avcodec_get_frame_defaults(av_frame.get());             
+                       av_frame->nb_samples = frame_size / (enc->channels * av_get_bytes_per_sample(enc->sample_fmt));
+
+                       AVPacket pkt;
+                       av_init_packet(&pkt);
+                       pkt.data = nullptr;
+                       pkt.size = 0;                           
+                       
+                       THROW_ON_ERROR2(avcodec_fill_audio_frame(av_frame.get(), enc->channels, enc->sample_fmt, audio_buffer_.data(), frame_size, 1), "[ffmpeg_consumer]");
+
+                       int got_packet = 0;
+                       THROW_ON_ERROR2(avcodec_encode_audio2(enc, &pkt, av_frame.get(), &got_packet), "[ffmpeg_consumer]");
+                       std::shared_ptr<AVPacket> guard(&pkt, av_free_packet);
+                               
+                       audio_buffer_.erase(audio_buffer_.begin(), audio_buffer_.begin() + frame_size);
+
+                       if(!got_packet)
+                               return;
+               
+                       if (pkt.pts != AV_NOPTS_VALUE)
+                               pkt.pts      = av_rescale_q(pkt.pts, enc->time_base, audio_st_->time_base);
+                       if (pkt.dts != AV_NOPTS_VALUE)
+                               pkt.dts      = av_rescale_q(pkt.dts, enc->time_base, audio_st_->time_base);
+                       if (pkt.duration > 0)
+                               pkt.duration = static_cast<int>(av_rescale_q(pkt.duration, enc->time_base, audio_st_->time_base));
+               
+                       pkt.stream_index = audio_st_->index;
+                                               
+                       THROW_ON_ERROR2(av_interleaved_write_frame(oc_.get(), &pkt), "[ffmpeg_consumer]");
+               }
+       }                
+       
+       std::shared_ptr<AVFrame> convert_video(core::const_frame frame, AVCodecContext* c)
+       {
+               if(!sws_) 
+               {
+                       sws_.reset(sws_getContext(format_desc_.width, 
+                                                                         format_desc_.height - output_format_.croptop  - output_format_.cropbot, 
+                                                                         PIX_FMT_BGRA,
+                                                                         c->width,
+                                                                         c->height, 
+                                                                         c->pix_fmt, 
+                                                                         SWS_BICUBIC, nullptr, nullptr, nullptr), 
+                                               sws_freeContext);
+                       if (sws_ == nullptr) 
+                               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Cannot initialize the conversion context"));
+               }
+
+               // #in_frame
+
+               std::shared_ptr<AVFrame> in_frame(avcodec_alloc_frame(), av_free);
+
+               avpicture_fill(reinterpret_cast<AVPicture*>(in_frame.get()), 
+                                          const_cast<uint8_t*>(frame.image_data().begin()),
+                                          PIX_FMT_BGRA, 
+                                          format_desc_.width,
+                                          format_desc_.height - output_format_.croptop  - output_format_.cropbot);
+               // crop-top
+
+               for(int n = 0; n < 4; ++n)              
+                       in_frame->data[n] += in_frame->linesize[n] * output_format_.croptop;            
+               
+               // #out_frame
+
+               std::shared_ptr<AVFrame> out_frame(avcodec_alloc_frame(), av_free);
+               
+               av_image_fill_linesizes(out_frame->linesize, c->pix_fmt, c->width);
+               for(int n = 0; n < 4; ++n)
+                       out_frame->linesize[n] += 32 - (out_frame->linesize[n] % 32); // align
+
+               picture_buffer_.resize(av_image_fill_pointers(out_frame->data, c->pix_fmt, c->height, nullptr, out_frame->linesize));
+               av_image_fill_pointers(out_frame->data, c->pix_fmt, c->height, picture_buffer_.data(), out_frame->linesize);
+               
+               // #scale
+
+               sws_scale(sws_.get(), 
+                                 in_frame->data, 
+                                 in_frame->linesize,
+                                 0, 
+                                 format_desc_.height - output_format_.cropbot - output_format_.croptop, 
+                                 out_frame->data, 
+                                 out_frame->linesize);
+
+               return out_frame;
+       }
+       
+       byte_vector convert_audio(core::const_frame& frame, AVCodecContext* c)
+       {
+               if(!swr_) 
+               {
+                       swr_ = std::shared_ptr<SwrContext>(swr_alloc_set_opts(nullptr,
+                                                                               get_channel_layout(c), c->sample_fmt, c->sample_rate,
+                                                                               av_get_default_channel_layout(format_desc_.audio_channels), AV_SAMPLE_FMT_S32, format_desc_.audio_sample_rate,
+                                                                               0, nullptr), [](SwrContext* p){swr_free(&p);});
+
+                       if(!swr_)
+                               CASPAR_THROW_EXCEPTION(bad_alloc());
+
+                       THROW_ON_ERROR2(swr_init(swr_.get()), "[audio_decoder]");
+               }
+                               
+               byte_vector buffer(48000);
+
+               const uint8_t* in[]  = {reinterpret_cast<const uint8_t*>(frame.audio_data().data())};
+               uint8_t*       out[] = {buffer.data()};
+
+               auto channel_samples = swr_convert(swr_.get(), 
+                                                                                  out, static_cast<int>(buffer.size()) / c->channels / av_get_bytes_per_sample(c->sample_fmt), 
+                                                                                  in, static_cast<int>(frame.audio_data().size()/format_desc_.audio_channels));
+
+               buffer.resize(channel_samples * c->channels * av_get_bytes_per_sample(c->sample_fmt));  
+
+               return buffer;
+       }
+
+       void check_space()
+       {
+               auto space = boost::filesystem::space(boost::filesystem::path(filename_).parent_path());
+               if(space.available < 512*1000000)
+                       BOOST_THROW_EXCEPTION(file_write_error() << msg_info("out of space"));
+       }
+
+       void encode(const core::const_frame& frame)
+       {
+               try
+               {
+                       if(frame_number_ % 25 == 0)
+                               check_space();
+
+                       boost::timer frame_timer;
+
+                       encode_video_frame(frame);
+                       encode_audio_frame(frame);
+
+                       graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
+               }
+               catch(...)
+               {                       
+                       lock(exception_mutex_, [&]
+                       {
+                               exception_ = std::current_exception();
+                       });
+               }
+       }
+};
+
+struct ffmpeg_consumer_proxy : public core::frame_consumer
+{
+       const std::wstring                              filename_;
+       const std::vector<option>               options_;
+
+       std::unique_ptr<ffmpeg_consumer> consumer_;
+
+public:
+
+       ffmpeg_consumer_proxy(const std::wstring& filename, const std::vector<option>& options)
+               : filename_(filename)
+               , options_(options)
+       {
+       }
+       
+       virtual void initialize(const core::video_format_desc& format_desc, int)
+       {
+               if(consumer_)
+                       BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Cannot reinitialize ffmpeg-consumer."));
+
+               consumer_.reset(new ffmpeg_consumer(u8(filename_), format_desc, options_));
+       }
+       
+       bool send(core::const_frame frame) override
+       {
+               return consumer_->send(frame);
+       }
+       
+       std::wstring print() const override
+       {
+               return consumer_ ? consumer_->print() : L"[ffmpeg_consumer]";
+       }
+
+       std::wstring name() const override
+       {
+               return L"file";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"file");
+               info.add(L"filename", filename_);
+               return info;
+       }
+               
+       bool has_synchronization_clock() const override
+       {
+               return false;
+       }
+
+       int buffer_depth() const override
+       {
+               return 1;
+       }
+
+       int index() const override
+       {
+               return 200;
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override
+       {
+               consumer_->subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override
+       {
+               consumer_->unsubscribe(o);
+       }               
+};     
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+{
+       auto str = std::accumulate(params.begin(), params.end(), std::wstring(), [](const std::wstring& lhs, const std::wstring& rhs) {return lhs + L" " + rhs;});
+       
+       boost::wregex path_exp(L"\\s*FILE(\\s(?<PATH>.+\\.[^\\s]+))?.*", boost::regex::icase);
+
+       boost::wsmatch path;
+       if(!boost::regex_match(str, path, path_exp))
+               return core::frame_consumer::empty();
+       
+       boost::wregex opt_exp(L"-((?<NAME>[^\\s]+)\\s+(?<VALUE>[^\\s]+))");     
+       
+       std::vector<option> options;
+       for(boost::wsregex_iterator it(str.begin(), str.end(), opt_exp); it != boost::wsregex_iterator(); ++it)
+       {
+               auto name  = u8(boost::trim_copy(boost::to_lower_copy((*it)["NAME"].str())));
+               auto value = u8(boost::trim_copy(boost::to_lower_copy((*it)["VALUE"].str())));
+               
+               if(value == "h264")
+                       value = "libx264";
+               else if(value == "dvcpro")
+                       value = "dvvideo";
+
+               options.push_back(option(name, value));
+       }
+                               
+       return spl::make_shared<ffmpeg_consumer_proxy>(env::media_folder() + path["PATH"].str(), options);
+}
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree)
+{
+       auto filename   = ptree.get<std::wstring>(L"path");
+       auto codec              = ptree.get(L"vcodec", L"libx264");
+
+       std::vector<option> options;
+       options.push_back(option("vcodec", u8(codec)));
+       
+       return spl::make_shared<ffmpeg_consumer_proxy>(env::media_folder() + filename, options);
+}
+
+}}
index 476e675762f36a5a7fd09756fc178f173551eb16..29226f4fdb94f7052381d037afa969be9e32f5da 100644 (file)
@@ -1,43 +1,43 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <boost/property_tree/ptree_fwd.hpp>\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar { \r
-\r
-namespace core {\r
-       class frame_consumer;\r
-}\r
-\r
-namespace ffmpeg {\r
-\r
-       \r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <boost/property_tree/ptree_fwd.hpp>
+
+#include <string>
+#include <vector>
+
+namespace caspar { 
+
+namespace core {
+       class frame_consumer;
+}
+
+namespace ffmpeg {
+
+       
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);
+
 }}
\ No newline at end of file
index 48ee8b20bb76c051db45b1bf6758ed8f9afb1a8a..95599bfcef48a64d0b4a9bc5ee27d5e4589f5b6a 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "StdAfx.h"\r
-\r
-#include "consumer/ffmpeg_consumer.h"\r
-#include "producer/ffmpeg_producer.h"\r
-\r
-#include <common/log.h>\r
-\r
-#include <core/consumer/frame_consumer.h>\r
-#include <core/producer/frame_producer.h>\r
-\r
-#include <tbb/recursive_mutex.h>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (disable : 4244)\r
-#pragma warning (disable : 4603)\r
-#pragma warning (disable : 4996)\r
-#endif\r
-\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
-       #define __STDC_LIMIT_MACROS\r
-       #include <libavformat/avformat.h>\r
-       #include <libswscale/swscale.h>\r
-       #include <libavutil/avutil.h>\r
-       #include <libavfilter/avfilter.h>\r
-}\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-int ffmpeg_lock_callback(void **mutex, enum AVLockOp op) \r
-{ \r
-       if(!mutex)\r
-               return 0;\r
-\r
-       auto my_mutex = reinterpret_cast<tbb::recursive_mutex*>(*mutex);\r
-       \r
-       switch(op) \r
-       { \r
-               case AV_LOCK_CREATE: \r
-               { \r
-                       *mutex = new tbb::recursive_mutex(); \r
-                       break; \r
-               } \r
-               case AV_LOCK_OBTAIN: \r
-               { \r
-                       if(my_mutex)\r
-                               my_mutex->lock(); \r
-                       break; \r
-               } \r
-               case AV_LOCK_RELEASE: \r
-               { \r
-                       if(my_mutex)\r
-                               my_mutex->unlock(); \r
-                       break; \r
-               } \r
-               case AV_LOCK_DESTROY: \r
-               { \r
-                       delete my_mutex;\r
-                       *mutex = nullptr;\r
-                       break; \r
-               } \r
-       } \r
-       return 0; \r
-} \r
-\r
-static void sanitize(uint8_t *line)\r
-{\r
-    while(*line)\r
-       {\r
-        if(*line < 0x08 || (*line > 0x0D && *line < 0x20))\r
-            *line='?';\r
-        line++;\r
-    }\r
-}\r
-\r
-void log_callback(void* ptr, int level, const char* fmt, va_list vl)\r
-{\r
-    static int print_prefix=1;\r
-    static int count;\r
-    static char prev[1024];\r
-    char line[8192];\r
-    static int is_atty;\r
-    AVClass* avc= ptr ? *(AVClass**)ptr : NULL;\r
-    if(level > av_log_get_level())\r
-        return;\r
-    line[0]=0;\r
-       \r
-#undef fprintf\r
-    if(print_prefix && avc) \r
-       {\r
-        if (avc->parent_log_context_offset) \r
-               {\r
-            AVClass** parent= *(AVClass***)(((uint8_t*)ptr) + avc->parent_log_context_offset);\r
-            if(parent && *parent)\r
-                std::sprintf(line, "[%s @ %p] ", (*parent)->item_name(parent), parent);            \r
-        }\r
-        std::sprintf(line + strlen(line), "[%s @ %p] ", avc->item_name(ptr), ptr);\r
-    }\r
-\r
-    std::vsprintf(line + strlen(line), fmt, vl);\r
-\r
-    print_prefix = strlen(line) && line[strlen(line)-1] == '\n';\r
-       \r
-    //if(print_prefix && !strcmp(line, prev)){\r
-    //    count++;\r
-    //    if(is_atty==1)\r
-    //        fprintf(stderr, "    Last message repeated %d times\r", count);\r
-    //    return;\r
-    //}\r
-    //if(count>0){\r
-    //    fprintf(stderr, "    Last message repeated %d times\n", count);\r
-    //    count=0;\r
-    //}\r
-    strcpy(prev, line);\r
-    sanitize((uint8_t*)line);\r
-\r
-       auto len = strlen(line);\r
-       if(len > 0)\r
-               line[len-1] = 0;\r
-       \r
-       if(level == AV_LOG_DEBUG)\r
-               CASPAR_LOG(debug) << L"[ffmpeg] " << line;\r
-       else if(level == AV_LOG_INFO)\r
-               CASPAR_LOG(info) << L"[ffmpeg] " << line;\r
-       else if(level == AV_LOG_WARNING)\r
-               CASPAR_LOG(warning) << L"[ffmpeg] " << line;\r
-       else if(level == AV_LOG_ERROR)\r
-               CASPAR_LOG(error) << L"[ffmpeg] " << line;\r
-       else if(level == AV_LOG_FATAL)\r
-               CASPAR_LOG(fatal) << L"[ffmpeg] " << line;\r
-       else\r
-               CASPAR_LOG(trace) << L"[ffmpeg] " << line;\r
-\r
-    //colored_fputs(av_clip(level>>3, 0, 6), line);\r
-}\r
-\r
-//static int query_yadif_formats(AVFilterContext *ctx)\r
-//{\r
-//    static const int pix_fmts[] = {\r
-//        PIX_FMT_YUV444P,\r
-//        PIX_FMT_YUV422P,\r
-//        PIX_FMT_YUV420P,\r
-//        PIX_FMT_YUV410P,\r
-//        PIX_FMT_YUV411P,\r
-//        PIX_FMT_GRAY8,\r
-//        PIX_FMT_YUVJ444P,\r
-//        PIX_FMT_YUVJ422P,\r
-//        PIX_FMT_YUVJ420P,\r
-//        AV_NE( PIX_FMT_GRAY16BE, PIX_FMT_GRAY16LE ),\r
-//        PIX_FMT_YUV440P,\r
-//        PIX_FMT_YUVJ440P,\r
-//        AV_NE( PIX_FMT_YUV444P16BE, PIX_FMT_YUV444P16LE ),\r
-//        AV_NE( PIX_FMT_YUV422P16BE, PIX_FMT_YUV422P16LE ),\r
-//        AV_NE( PIX_FMT_YUV420P16BE, PIX_FMT_YUV420P16LE ),\r
-//        PIX_FMT_YUVA420P,\r
-//        PIX_FMT_NONE\r
-//    };\r
-//    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));\r
-//\r
-//    return 0;\r
-//}\r
-//\r
-//#pragma warning (push)\r
-//#pragma warning (disable : 4706)\r
-//void fix_yadif_filter_format_query()\r
-//{\r
-//     AVFilter** filter = nullptr;\r
-//    while((filter = av_filter_next(filter)) && *filter)\r
-//     {\r
-//             if(strstr((*filter)->name, "yadif") != 0)\r
-//                     (*filter)->query_formats = query_yadif_formats;\r
-//     }\r
-//}\r
-//#pragma warning (pop)\r
-\r
-void init()\r
-{\r
-       av_lockmgr_register(ffmpeg_lock_callback);\r
-       av_log_set_callback(log_callback);\r
-\r
-    avfilter_register_all();\r
-       //fix_yadif_filter_format_query();\r
-       av_register_all();\r
-    avformat_network_init();\r
-    avcodec_register_all();\r
-       \r
-       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});\r
-       core::register_producer_factory(create_producer);\r
-}\r
-\r
-void uninit()\r
-{\r
-       avfilter_uninit();\r
-    avformat_network_deinit();\r
-       av_lockmgr_register(nullptr);\r
-}\r
-\r
-std::wstring make_version(unsigned int ver)\r
-{\r
-       std::wstringstream str;\r
-       str << ((ver >> 16) & 0xFF) << L"." << ((ver >> 8) & 0xFF) << L"." << ((ver >> 0) & 0xFF);\r
-       return str.str();\r
-}\r
-\r
-std::wstring avcodec_version()\r
-{\r
-       return make_version(::avcodec_version());\r
-}\r
-\r
-std::wstring avformat_version()\r
-{\r
-       return make_version(::avformat_version());\r
-}\r
-\r
-std::wstring avutil_version()\r
-{\r
-       return make_version(::avutil_version());\r
-}\r
-\r
-std::wstring avfilter_version()\r
-{\r
-       return make_version(::avfilter_version());\r
-}\r
-\r
-std::wstring swscale_version()\r
-{\r
-       return make_version(::swscale_version());\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "StdAfx.h"
+
+#include "consumer/ffmpeg_consumer.h"
+#include "producer/ffmpeg_producer.h"
+
+#include <common/log.h>
+
+#include <core/consumer/frame_consumer.h>
+#include <core/producer/frame_producer.h>
+
+#include <tbb/recursive_mutex.h>
+
+#if defined(_MSC_VER)
+#pragma warning (disable : 4244)
+#pragma warning (disable : 4603)
+#pragma warning (disable : 4996)
+#endif
+
+extern "C" 
+{
+       #define __STDC_CONSTANT_MACROS
+       #define __STDC_LIMIT_MACROS
+       #include <libavformat/avformat.h>
+       #include <libswscale/swscale.h>
+       #include <libavutil/avutil.h>
+       #include <libavfilter/avfilter.h>
+}
+
+namespace caspar { namespace ffmpeg {
+       
+int ffmpeg_lock_callback(void **mutex, enum AVLockOp op) 
+{ 
+       if(!mutex)
+               return 0;
+
+       auto my_mutex = reinterpret_cast<tbb::recursive_mutex*>(*mutex);
+       
+       switch(op) 
+       { 
+               case AV_LOCK_CREATE: 
+               { 
+                       *mutex = new tbb::recursive_mutex(); 
+                       break; 
+               } 
+               case AV_LOCK_OBTAIN: 
+               { 
+                       if(my_mutex)
+                               my_mutex->lock(); 
+                       break; 
+               } 
+               case AV_LOCK_RELEASE: 
+               { 
+                       if(my_mutex)
+                               my_mutex->unlock(); 
+                       break; 
+               } 
+               case AV_LOCK_DESTROY: 
+               { 
+                       delete my_mutex;
+                       *mutex = nullptr;
+                       break; 
+               } 
+       } 
+       return 0; 
+} 
+
+static void sanitize(uint8_t *line)
+{
+    while(*line)
+       {
+        if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
+            *line='?';
+        line++;
+    }
+}
+
+void log_callback(void* ptr, int level, const char* fmt, va_list vl)
+{
+    static int print_prefix=1;
+    static int count;
+    static char prev[1024];
+    char line[8192];
+    static int is_atty;
+    AVClass* avc= ptr ? *(AVClass**)ptr : NULL;
+    if(level > av_log_get_level())
+        return;
+    line[0]=0;
+       
+#undef fprintf
+    if(print_prefix && avc) 
+       {
+        if (avc->parent_log_context_offset) 
+               {
+            AVClass** parent= *(AVClass***)(((uint8_t*)ptr) + avc->parent_log_context_offset);
+            if(parent && *parent)
+                std::sprintf(line, "[%s @ %p] ", (*parent)->item_name(parent), parent);            
+        }
+        std::sprintf(line + strlen(line), "[%s @ %p] ", avc->item_name(ptr), ptr);
+    }
+
+    std::vsprintf(line + strlen(line), fmt, vl);
+
+    print_prefix = strlen(line) && line[strlen(line)-1] == '\n';
+       
+    //if(print_prefix && !strcmp(line, prev)){
+    //    count++;
+    //    if(is_atty==1)
+    //        fprintf(stderr, "    Last message repeated %d times\r", count);
+    //    return;
+    //}
+    //if(count>0){
+    //    fprintf(stderr, "    Last message repeated %d times\n", count);
+    //    count=0;
+    //}
+    strcpy(prev, line);
+    sanitize((uint8_t*)line);
+
+       auto len = strlen(line);
+       if(len > 0)
+               line[len-1] = 0;
+       
+       if(level == AV_LOG_DEBUG)
+               CASPAR_LOG(debug) << L"[ffmpeg] " << line;
+       else if(level == AV_LOG_INFO)
+               CASPAR_LOG(info) << L"[ffmpeg] " << line;
+       else if(level == AV_LOG_WARNING)
+               CASPAR_LOG(warning) << L"[ffmpeg] " << line;
+       else if(level == AV_LOG_ERROR)
+               CASPAR_LOG(error) << L"[ffmpeg] " << line;
+       else if(level == AV_LOG_FATAL)
+               CASPAR_LOG(fatal) << L"[ffmpeg] " << line;
+       else
+               CASPAR_LOG(trace) << L"[ffmpeg] " << line;
+
+    //colored_fputs(av_clip(level>>3, 0, 6), line);
+}
+
+//static int query_yadif_formats(AVFilterContext *ctx)
+//{
+//    static const int pix_fmts[] = {
+//        PIX_FMT_YUV444P,
+//        PIX_FMT_YUV422P,
+//        PIX_FMT_YUV420P,
+//        PIX_FMT_YUV410P,
+//        PIX_FMT_YUV411P,
+//        PIX_FMT_GRAY8,
+//        PIX_FMT_YUVJ444P,
+//        PIX_FMT_YUVJ422P,
+//        PIX_FMT_YUVJ420P,
+//        AV_NE( PIX_FMT_GRAY16BE, PIX_FMT_GRAY16LE ),
+//        PIX_FMT_YUV440P,
+//        PIX_FMT_YUVJ440P,
+//        AV_NE( PIX_FMT_YUV444P16BE, PIX_FMT_YUV444P16LE ),
+//        AV_NE( PIX_FMT_YUV422P16BE, PIX_FMT_YUV422P16LE ),
+//        AV_NE( PIX_FMT_YUV420P16BE, PIX_FMT_YUV420P16LE ),
+//        PIX_FMT_YUVA420P,
+//        PIX_FMT_NONE
+//    };
+//    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
+//
+//    return 0;
+//}
+//
+//#pragma warning (push)
+//#pragma warning (disable : 4706)
+//void fix_yadif_filter_format_query()
+//{
+//     AVFilter** filter = nullptr;
+//    while((filter = av_filter_next(filter)) && *filter)
+//     {
+//             if(strstr((*filter)->name, "yadif") != 0)
+//                     (*filter)->query_formats = query_yadif_formats;
+//     }
+//}
+//#pragma warning (pop)
+
+void init()
+{
+       av_lockmgr_register(ffmpeg_lock_callback);
+       av_log_set_callback(log_callback);
+
+    avfilter_register_all();
+       //fix_yadif_filter_format_query();
+       av_register_all();
+    avformat_network_init();
+    avcodec_register_all();
+       
+       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+       core::register_producer_factory(create_producer);
+}
+
+void uninit()
+{
+       avfilter_uninit();
+    avformat_network_deinit();
+       av_lockmgr_register(nullptr);
+}
+
+std::wstring make_version(unsigned int ver)
+{
+       std::wstringstream str;
+       str << ((ver >> 16) & 0xFF) << L"." << ((ver >> 8) & 0xFF) << L"." << ((ver >> 0) & 0xFF);
+       return str.str();
+}
+
+std::wstring avcodec_version()
+{
+       return make_version(::avcodec_version());
+}
+
+std::wstring avformat_version()
+{
+       return make_version(::avformat_version());
+}
+
+std::wstring avutil_version()
+{
+       return make_version(::avutil_version());
+}
+
+std::wstring avfilter_version()
+{
+       return make_version(::avfilter_version());
+}
+
+std::wstring swscale_version()
+{
+       return make_version(::swscale_version());
+}
+
 }}
\ No newline at end of file
index 79117c666922da8e7b5fb46efa93e7f821fb6287..f0eb9006c8ab2b21f73e7740efe143ed043b547a 100644 (file)
@@ -1,37 +1,37 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace ffmpeg {\r
-\r
-void init();\r
-void uninit();\r
-\r
-std::wstring avcodec_version();\r
-std::wstring avformat_version();\r
-std::wstring avutil_version();\r
-std::wstring avfilter_version();\r
-std::wstring swscale_version();\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <string>
+
+namespace caspar { namespace ffmpeg {
+
+void init();
+void uninit();
+
+std::wstring avcodec_version();
+std::wstring avformat_version();
+std::wstring avutil_version();
+std::wstring avfilter_version();
+std::wstring swscale_version();
+
 }}
\ No newline at end of file
index a5b70330a88d95b28c56ef84fd497ace16c2e5e1..de51f14f65a718c3bfe932e1cd24019016459e6f 100644 (file)
-#include "StdAfx.h"\r
-\r
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-#include "ffmpeg_error.h"\r
-\r
-#include <common/utf.h>\r
-\r
-#pragma warning(disable: 4146)\r
-\r
-extern "C" \r
-{\r
-#include <libavutil/error.h>\r
-}\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-std::string av_error_str(int errn)\r
-{\r
-       char buf[256];\r
-       memset(buf, 0, 256);\r
-       if(av_strerror(errn, buf, 256) < 0)\r
-               return "";\r
-       return std::string(buf);\r
-}\r
-\r
-void throw_on_ffmpeg_error(int ret, const char* source, const char* func, const char* local_func, const char* file, int line)\r
-{\r
-       if(ret >= 0)\r
-               return;\r
-\r
-       switch(ret)\r
-       {\r
-       case AVERROR_BSF_NOT_FOUND:\r
-               ::boost::exception_detail::throw_exception_(averror_bsf_not_found()<<                                                                           \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);  \r
-       case AVERROR_DECODER_NOT_FOUND:\r
-               ::boost::exception_detail::throw_exception_(averror_decoder_not_found()<<                                                                               \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       case AVERROR_DEMUXER_NOT_FOUND:\r
-               ::boost::exception_detail::throw_exception_(averror_demuxer_not_found()<<                                                                               \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       case AVERROR_ENCODER_NOT_FOUND:\r
-               ::boost::exception_detail::throw_exception_(averror_encoder_not_found()<<                                                                               \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);  \r
-       case AVERROR_EOF:       \r
-               ::boost::exception_detail::throw_exception_(averror_eof()<<                                                                             \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       case AVERROR_EXIT:                              \r
-               ::boost::exception_detail::throw_exception_(averror_exit()<<                                                                            \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       case AVERROR_FILTER_NOT_FOUND:                          \r
-               ::boost::exception_detail::throw_exception_(averror_filter_not_found()<<                                                                                \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       case AVERROR_MUXER_NOT_FOUND:   \r
-               ::boost::exception_detail::throw_exception_(averror_muxer_not_found()<<                                                                         \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       case AVERROR_OPTION_NOT_FOUND:  \r
-               ::boost::exception_detail::throw_exception_(averror_option_not_found()<<                                                                                \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       case AVERROR_PATCHWELCOME:      \r
-               ::boost::exception_detail::throw_exception_(averror_patchwelcome()<<                                                                            \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       case AVERROR_PROTOCOL_NOT_FOUND:        \r
-               ::boost::exception_detail::throw_exception_(averror_protocol_not_found()<<                                                                              \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       case AVERROR_STREAM_NOT_FOUND:\r
-               ::boost::exception_detail::throw_exception_(averror_stream_not_found()<<                                                                                \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       default:\r
-               ::boost::exception_detail::throw_exception_(ffmpeg_error()<<                                                                            \r
-                       msg_info(av_error_str(ret)) <<                                                  \r
-                       source_info(source) <<                                          \r
-                       boost::errinfo_api_function(func) <<                                    \r
-                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);\r
-       }\r
-}\r
-\r
-void throw_on_ffmpeg_error(int ret, const std::wstring& source, const char* func, const char* local_func, const char* file, int line)\r
-{\r
-       throw_on_ffmpeg_error(ret, u8(source).c_str(), func, local_func, file, line);\r
-}\r
-\r
+#include "StdAfx.h"
+
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+#include "ffmpeg_error.h"
+
+#include <common/utf.h>
+
+#pragma warning(disable: 4146)
+
+extern "C" 
+{
+#include <libavutil/error.h>
+}
+
+namespace caspar { namespace ffmpeg {
+       
+std::string av_error_str(int errn)
+{
+       char buf[256];
+       memset(buf, 0, 256);
+       if(av_strerror(errn, buf, 256) < 0)
+               return "";
+       return std::string(buf);
+}
+
+void throw_on_ffmpeg_error(int ret, const char* source, const char* func, const char* local_func, const char* file, int line)
+{
+       if(ret >= 0)
+               return;
+
+       switch(ret)
+       {
+       case AVERROR_BSF_NOT_FOUND:
+               ::boost::exception_detail::throw_exception_(averror_bsf_not_found()<<                                                                           
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);  
+       case AVERROR_DECODER_NOT_FOUND:
+               ::boost::exception_detail::throw_exception_(averror_decoder_not_found()<<                                                                               
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       case AVERROR_DEMUXER_NOT_FOUND:
+               ::boost::exception_detail::throw_exception_(averror_demuxer_not_found()<<                                                                               
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       case AVERROR_ENCODER_NOT_FOUND:
+               ::boost::exception_detail::throw_exception_(averror_encoder_not_found()<<                                                                               
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);  
+       case AVERROR_EOF:       
+               ::boost::exception_detail::throw_exception_(averror_eof()<<                                                                             
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       case AVERROR_EXIT:                              
+               ::boost::exception_detail::throw_exception_(averror_exit()<<                                                                            
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       case AVERROR_FILTER_NOT_FOUND:                          
+               ::boost::exception_detail::throw_exception_(averror_filter_not_found()<<                                                                                
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       case AVERROR_MUXER_NOT_FOUND:   
+               ::boost::exception_detail::throw_exception_(averror_muxer_not_found()<<                                                                         
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       case AVERROR_OPTION_NOT_FOUND:  
+               ::boost::exception_detail::throw_exception_(averror_option_not_found()<<                                                                                
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       case AVERROR_PATCHWELCOME:      
+               ::boost::exception_detail::throw_exception_(averror_patchwelcome()<<                                                                            
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       case AVERROR_PROTOCOL_NOT_FOUND:        
+               ::boost::exception_detail::throw_exception_(averror_protocol_not_found()<<                                                                              
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       case AVERROR_STREAM_NOT_FOUND:
+               ::boost::exception_detail::throw_exception_(averror_stream_not_found()<<                                                                                
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       default:
+               ::boost::exception_detail::throw_exception_(ffmpeg_error()<<                                                                            
+                       msg_info(av_error_str(ret)) <<                                                  
+                       source_info(source) <<                                          
+                       boost::errinfo_api_function(func) <<                                    
+                       boost::errinfo_errno(AVUNERROR(ret)), local_func, file, line);
+       }
+}
+
+void throw_on_ffmpeg_error(int ret, const std::wstring& source, const char* func, const char* local_func, const char* file, int line)
+{
+       throw_on_ffmpeg_error(ret, u8(source).c_str(), func, local_func, file, line);
+}
+
 }}
\ No newline at end of file
index 59f4e43895ddbfebdfa3b6aff8609f8d2b6fbec5..4b959b53a293fa97c5a71cd6daec992eac7bcc32 100644 (file)
@@ -1,78 +1,78 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/except.h>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace ffmpeg {\r
-\r
-struct ffmpeg_error : virtual caspar_exception{};\r
-struct averror_bsf_not_found : virtual ffmpeg_error{};\r
-struct averror_decoder_not_found : virtual ffmpeg_error{};\r
-struct averror_demuxer_not_found : virtual ffmpeg_error{};\r
-struct averror_encoder_not_found : virtual ffmpeg_error{};\r
-struct averror_eof : virtual ffmpeg_error{};\r
-struct averror_exit : virtual ffmpeg_error{};\r
-struct averror_filter_not_found : virtual ffmpeg_error{};\r
-struct averror_muxer_not_found : virtual ffmpeg_error{};\r
-struct averror_option_not_found : virtual ffmpeg_error{};\r
-struct averror_patchwelcome : virtual ffmpeg_error{};\r
-struct averror_protocol_not_found : virtual ffmpeg_error{};\r
-struct averror_stream_not_found : virtual ffmpeg_error{};\r
-\r
-std::string av_error_str(int errn);\r
-\r
-void throw_on_ffmpeg_error(int ret, const char* source, const char* func, const char* local_func, const char* file, int line);\r
-void throw_on_ffmpeg_error(int ret, const std::wstring& source, const char* func, const char* local_func, const char* file, int line);\r
-\r
-\r
-//#define THROW_ON_ERROR(ret, source, func) throw_on_ffmpeg_error(ret, source, __FUNC__, __FILE__, __LINE__)\r
-\r
-#define THROW_ON_ERROR_STR_(call) #call\r
-#define THROW_ON_ERROR_STR(call) THROW_ON_ERROR_STR_(call)\r
-\r
-#define THROW_ON_ERROR(ret, func, source) \\r
-               throw_on_ffmpeg_error(ret, source, func, __FUNCTION__, __FILE__, __LINE__);             \r
-\r
-#define THROW_ON_ERROR2(call, source)                                                                          \\r
-       [&]() -> int                                                                                                                    \\r
-       {                                                                                                                                               \\r
-               int ret = call;                                                                                                         \\r
-               throw_on_ffmpeg_error(ret, source, THROW_ON_ERROR_STR(call), __FUNCTION__, __FILE__, __LINE__); \\r
-               return ret;                                                                                                                     \\r
-       }()\r
-\r
-#define LOG_ON_ERROR2(call, source)                                                                                    \\r
-       [&]() -> int                                                                                                                    \\r
-       {                                       \\r
-               int ret = -1;\\r
-               try{                                                                                                                            \\r
-                ret = call;                                                                                                                    \\r
-               throw_on_ffmpeg_error(ret, source, THROW_ON_ERROR_STR(call), __FUNCTION__, __FILE__, __LINE__); \\r
-               return ret;                                                                                                                     \\r
-               }catch(...){CASPAR_LOG_CURRENT_EXCEPTION();}                                            \\r
-               return ret;                                                                                                                     \\r
-       }()\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/except.h>
+
+#include <string>
+
+namespace caspar { namespace ffmpeg {
+
+struct ffmpeg_error : virtual caspar_exception{};
+struct averror_bsf_not_found : virtual ffmpeg_error{};
+struct averror_decoder_not_found : virtual ffmpeg_error{};
+struct averror_demuxer_not_found : virtual ffmpeg_error{};
+struct averror_encoder_not_found : virtual ffmpeg_error{};
+struct averror_eof : virtual ffmpeg_error{};
+struct averror_exit : virtual ffmpeg_error{};
+struct averror_filter_not_found : virtual ffmpeg_error{};
+struct averror_muxer_not_found : virtual ffmpeg_error{};
+struct averror_option_not_found : virtual ffmpeg_error{};
+struct averror_patchwelcome : virtual ffmpeg_error{};
+struct averror_protocol_not_found : virtual ffmpeg_error{};
+struct averror_stream_not_found : virtual ffmpeg_error{};
+
+std::string av_error_str(int errn);
+
+void throw_on_ffmpeg_error(int ret, const char* source, const char* func, const char* local_func, const char* file, int line);
+void throw_on_ffmpeg_error(int ret, const std::wstring& source, const char* func, const char* local_func, const char* file, int line);
+
+
+//#define THROW_ON_ERROR(ret, source, func) throw_on_ffmpeg_error(ret, source, __FUNC__, __FILE__, __LINE__)
+
+#define THROW_ON_ERROR_STR_(call) #call
+#define THROW_ON_ERROR_STR(call) THROW_ON_ERROR_STR_(call)
+
+#define THROW_ON_ERROR(ret, func, source) \
+               throw_on_ffmpeg_error(ret, source, func, __FUNCTION__, __FILE__, __LINE__);             
+
+#define THROW_ON_ERROR2(call, source)                                                                          \
+       [&]() -> int                                                                                                                    \
+       {                                                                                                                                               \
+               int ret = call;                                                                                                         \
+               throw_on_ffmpeg_error(ret, source, THROW_ON_ERROR_STR(call), __FUNCTION__, __FILE__, __LINE__); \
+               return ret;                                                                                                                     \
+       }()
+
+#define LOG_ON_ERROR2(call, source)                                                                                    \
+       [&]() -> int                                                                                                                    \
+       {                                       \
+               int ret = -1;\
+               try{                                                                                                                            \
+                ret = call;                                                                                                                    \
+               throw_on_ffmpeg_error(ret, source, THROW_ON_ERROR_STR(call), __FUNCTION__, __FILE__, __LINE__); \
+               return ret;                                                                                                                     \
+               }catch(...){CASPAR_LOG_CURRENT_EXCEPTION();}                                            \
+               return ret;                                                                                                                     \
+       }()
+
+}}
index 20246195bb18ea98acb1d609e66331abf78aa0e1..e6d5431a1f3334daf7868d40783baedfc3e91853 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "audio_decoder.h"\r
-\r
-#include "../util/util.h"\r
-#include "../input/input.h"\r
-#include "../../ffmpeg_error.h"\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <common/log.h>\r
-\r
-#include <tbb/cache_aligned_allocator.h>\r
-\r
-#include <queue>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #include <libavformat/avformat.h>\r
-       #include <libavcodec/avcodec.h>\r
-       #include <libswresample/swresample.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-uint64_t get_channel_layout(AVCodecContext* dec)\r
-{\r
-       auto layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels);\r
-       return layout;\r
-}\r
-\r
-struct audio_decoder::impl : boost::noncopyable\r
-{      \r
-       monitor::basic_subject                                                                          event_subject_;\r
-       input*                                                                                                          input_;\r
-       int                                                                                                                     index_;\r
-       const spl::shared_ptr<AVCodecContext>                                           codec_context_;         \r
-       const core::video_format_desc                                                           format_desc_;\r
-\r
-       std::shared_ptr<SwrContext>                                                                     swr_;\r
-\r
-       std::vector<uint8_t, tbb::cache_aligned_allocator<int8_t>>      buffer_;\r
-\r
-       std::shared_ptr<AVPacket>                                                                       current_packet_;\r
-       \r
-public:\r
-       explicit impl(input& in, const core::video_format_desc& format_desc) \r
-               : input_(&in)\r
-               , format_desc_(format_desc)     \r
-               , codec_context_(open_codec(input_->context(), AVMEDIA_TYPE_AUDIO, index_))\r
-               , swr_(swr_alloc_set_opts(nullptr,\r
-                                                                               av_get_default_channel_layout(format_desc_.audio_channels), AV_SAMPLE_FMT_S32, format_desc_.audio_sample_rate,\r
-                                                                               get_channel_layout(codec_context_.get()), codec_context_->sample_fmt, codec_context_->sample_rate,\r
-                                                                               0, nullptr), [](SwrContext* p){swr_free(&p);})\r
-               , buffer_(AVCODEC_MAX_AUDIO_FRAME_SIZE*4)\r
-       {               \r
-               if(!swr_)\r
-                       CASPAR_THROW_EXCEPTION(bad_alloc());\r
-\r
-               THROW_ON_ERROR2(swr_init(swr_.get()), "[audio_decoder]");\r
-       }\r
-               \r
-       std::shared_ptr<AVFrame> poll()\r
-       {               \r
-               if(!current_packet_ && !input_->try_pop_audio(current_packet_))\r
-                       return nullptr;\r
-               \r
-               std::shared_ptr<AVFrame> audio;\r
-\r
-               if(!current_packet_)    \r
-               {\r
-                       avcodec_flush_buffers(codec_context_.get());    \r
-               }\r
-               else if(!current_packet_->data)\r
-               {\r
-                       if(codec_context_->codec->capabilities & CODEC_CAP_DELAY)                       \r
-                               audio = decode(*current_packet_);\r
-                       \r
-                       if(!audio)\r
-                               current_packet_.reset();\r
-               }\r
-               else\r
-               {\r
-                       audio = decode(*current_packet_);\r
-                       \r
-                       if(current_packet_->size == 0)\r
-                               current_packet_.reset();\r
-               }\r
-       \r
-               return audio ? audio : poll();\r
-       }\r
-\r
-       std::shared_ptr<AVFrame> decode(AVPacket& pkt)\r
-       {               \r
-               auto frame = create_frame();\r
-               \r
-               int got_frame = 0;\r
-               auto len = THROW_ON_ERROR2(avcodec_decode_audio4(codec_context_.get(), frame.get(), &got_frame, &pkt), "[audio_decoder]");\r
-                                       \r
-               if(len == 0)\r
-               {\r
-                       pkt.size = 0;\r
-                       return nullptr;\r
-               }\r
-\r
-        pkt.data += len;\r
-        pkt.size -= len;\r
-\r
-               if(!got_frame)\r
-                       return nullptr;\r
-                                                       \r
-               const uint8_t *in[] = {frame->data[0]};\r
-               uint8_t* out[]          = {buffer_.data()};\r
-\r
-               auto channel_samples = swr_convert(swr_.get(), \r
-                                                                                       out, static_cast<int>(buffer_.size()) / format_desc_.audio_channels / av_get_bytes_per_sample(AV_SAMPLE_FMT_S32), \r
-                                                                                       in, frame->nb_samples); \r
-\r
-               frame->data[0]          = buffer_.data();\r
-               frame->linesize[0]      = channel_samples * format_desc_.audio_channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S32);\r
-               frame->nb_samples       = channel_samples;\r
-               frame->format           = AV_SAMPLE_FMT_S32;\r
-                                                       \r
-               event_subject_  << monitor::event("file/audio/sample-rate")     % codec_context_->sample_rate\r
-                                               << monitor::event("file/audio/channels")        % codec_context_->channels\r
-                                               << monitor::event("file/audio/format")          % u8(av_get_sample_fmt_name(codec_context_->sample_fmt))\r
-                                               << monitor::event("file/audio/codec")           % u8(codec_context_->codec->long_name);                 \r
-\r
-               return frame;\r
-       }\r
-       \r
-       uint32_t nb_frames() const\r
-       {\r
-               return 0;\r
-       }\r
-\r
-       std::wstring print() const\r
-       {               \r
-               return L"[audio-decoder] " + u16(codec_context_->codec->long_name);\r
-       }\r
-};\r
-\r
-audio_decoder::audio_decoder(input& input, const core::video_format_desc& format_desc) : impl_(new impl(input, format_desc)){}\r
-audio_decoder::audio_decoder(audio_decoder&& other) : impl_(std::move(other.impl_)){}\r
-audio_decoder& audio_decoder::operator=(audio_decoder&& other){impl_ = std::move(other.impl_); return *this;}\r
-std::shared_ptr<AVFrame> audio_decoder::operator()(){return impl_->poll();}\r
-uint32_t audio_decoder::nb_frames() const{return impl_->nb_frames();}\r
-std::wstring audio_decoder::print() const{return impl_->print();}\r
-void audio_decoder::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.subscribe(o);}\r
-void audio_decoder::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "audio_decoder.h"
+
+#include "../util/util.h"
+#include "../input/input.h"
+#include "../../ffmpeg_error.h"
+
+#include <core/video_format.h>
+
+#include <common/log.h>
+
+#include <tbb/cache_aligned_allocator.h>
+
+#include <queue>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #include <libavformat/avformat.h>
+       #include <libavcodec/avcodec.h>
+       #include <libswresample/swresample.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+namespace caspar { namespace ffmpeg {
+       
+uint64_t get_channel_layout(AVCodecContext* dec)
+{
+       auto layout = (dec->channel_layout && dec->channels == av_get_channel_layout_nb_channels(dec->channel_layout)) ? dec->channel_layout : av_get_default_channel_layout(dec->channels);
+       return layout;
+}
+
+struct audio_decoder::impl : boost::noncopyable
+{      
+       monitor::basic_subject                                                                          event_subject_;
+       input*                                                                                                          input_;
+       int                                                                                                                     index_;
+       const spl::shared_ptr<AVCodecContext>                                           codec_context_;         
+       const core::video_format_desc                                                           format_desc_;
+
+       std::shared_ptr<SwrContext>                                                                     swr_;
+
+       std::vector<uint8_t, tbb::cache_aligned_allocator<int8_t>>      buffer_;
+
+       std::shared_ptr<AVPacket>                                                                       current_packet_;
+       
+public:
+       explicit impl(input& in, const core::video_format_desc& format_desc) 
+               : input_(&in)
+               , format_desc_(format_desc)     
+               , codec_context_(open_codec(input_->context(), AVMEDIA_TYPE_AUDIO, index_))
+               , swr_(swr_alloc_set_opts(nullptr,
+                                                                               av_get_default_channel_layout(format_desc_.audio_channels), AV_SAMPLE_FMT_S32, format_desc_.audio_sample_rate,
+                                                                               get_channel_layout(codec_context_.get()), codec_context_->sample_fmt, codec_context_->sample_rate,
+                                                                               0, nullptr), [](SwrContext* p){swr_free(&p);})
+               , buffer_(AVCODEC_MAX_AUDIO_FRAME_SIZE*4)
+       {               
+               if(!swr_)
+                       CASPAR_THROW_EXCEPTION(bad_alloc());
+
+               THROW_ON_ERROR2(swr_init(swr_.get()), "[audio_decoder]");
+       }
+               
+       std::shared_ptr<AVFrame> poll()
+       {               
+               if(!current_packet_ && !input_->try_pop_audio(current_packet_))
+                       return nullptr;
+               
+               std::shared_ptr<AVFrame> audio;
+
+               if(!current_packet_)    
+               {
+                       avcodec_flush_buffers(codec_context_.get());    
+               }
+               else if(!current_packet_->data)
+               {
+                       if(codec_context_->codec->capabilities & CODEC_CAP_DELAY)                       
+                               audio = decode(*current_packet_);
+                       
+                       if(!audio)
+                               current_packet_.reset();
+               }
+               else
+               {
+                       audio = decode(*current_packet_);
+                       
+                       if(current_packet_->size == 0)
+                               current_packet_.reset();
+               }
+       
+               return audio ? audio : poll();
+       }
+
+       std::shared_ptr<AVFrame> decode(AVPacket& pkt)
+       {               
+               auto frame = create_frame();
+               
+               int got_frame = 0;
+               auto len = THROW_ON_ERROR2(avcodec_decode_audio4(codec_context_.get(), frame.get(), &got_frame, &pkt), "[audio_decoder]");
+                                       
+               if(len == 0)
+               {
+                       pkt.size = 0;
+                       return nullptr;
+               }
+
+        pkt.data += len;
+        pkt.size -= len;
+
+               if(!got_frame)
+                       return nullptr;
+                                                       
+               const uint8_t *in[] = {frame->data[0]};
+               uint8_t* out[]          = {buffer_.data()};
+
+               auto channel_samples = swr_convert(swr_.get(), 
+                                                                                       out, static_cast<int>(buffer_.size()) / format_desc_.audio_channels / av_get_bytes_per_sample(AV_SAMPLE_FMT_S32), 
+                                                                                       in, frame->nb_samples); 
+
+               frame->data[0]          = buffer_.data();
+               frame->linesize[0]      = channel_samples * format_desc_.audio_channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S32);
+               frame->nb_samples       = channel_samples;
+               frame->format           = AV_SAMPLE_FMT_S32;
+                                                       
+               event_subject_  << monitor::event("file/audio/sample-rate")     % codec_context_->sample_rate
+                                               << monitor::event("file/audio/channels")        % codec_context_->channels
+                                               << monitor::event("file/audio/format")          % u8(av_get_sample_fmt_name(codec_context_->sample_fmt))
+                                               << monitor::event("file/audio/codec")           % u8(codec_context_->codec->long_name);                 
+
+               return frame;
+       }
+       
+       uint32_t nb_frames() const
+       {
+               return 0;
+       }
+
+       std::wstring print() const
+       {               
+               return L"[audio-decoder] " + u16(codec_context_->codec->long_name);
+       }
+};
+
+audio_decoder::audio_decoder(input& input, const core::video_format_desc& format_desc) : impl_(new impl(input, format_desc)){}
+audio_decoder::audio_decoder(audio_decoder&& other) : impl_(std::move(other.impl_)){}
+audio_decoder& audio_decoder::operator=(audio_decoder&& other){impl_ = std::move(other.impl_); return *this;}
+std::shared_ptr<AVFrame> audio_decoder::operator()(){return impl_->poll();}
+uint32_t audio_decoder::nb_frames() const{return impl_->nb_frames();}
+std::wstring audio_decoder::print() const{return impl_->print();}
+void audio_decoder::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.subscribe(o);}
+void audio_decoder::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);}
+
 }}
\ No newline at end of file
index fd221936a919a4c383210d87948681ea88060e98..160f5423716beb32774fbb1e924d2118d898cd18 100644 (file)
@@ -1,69 +1,69 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <core/mixer/audio/audio_mixer.h>\r
-#include <core/monitor/monitor.h>\r
-\r
-#include <common/memory.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-struct AVPacket;\r
-struct AVFormatContext;\r
-\r
-namespace caspar { \r
-                       \r
-namespace core {\r
-\r
-struct video_format_desc;\r
-\r
-}\r
-\r
-namespace ffmpeg {\r
-       \r
-class audio_decoder : public monitor::observable\r
-                                       , boost::noncopyable\r
-{\r
-public:\r
-       explicit audio_decoder(class input& input, const core::video_format_desc& format_desc);\r
-       \r
-       audio_decoder(audio_decoder&& other);\r
-       audio_decoder& operator=(audio_decoder&& other);\r
-\r
-       std::shared_ptr<AVFrame> operator()();\r
-\r
-       uint32_t nb_frames() const;\r
-       \r
-       std::wstring print() const;\r
-       \r
-       // monitor::observable\r
-       \r
-       void subscribe(const monitor::observable::observer_ptr& o) override;\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override;\r
-\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <core/mixer/audio/audio_mixer.h>
+#include <core/monitor/monitor.h>
+
+#include <common/memory.h>
+
+#include <boost/noncopyable.hpp>
+
+struct AVPacket;
+struct AVFormatContext;
+
+namespace caspar { 
+                       
+namespace core {
+
+struct video_format_desc;
+
+}
+
+namespace ffmpeg {
+       
+class audio_decoder : public monitor::observable
+                                       , boost::noncopyable
+{
+public:
+       explicit audio_decoder(class input& input, const core::video_format_desc& format_desc);
+       
+       audio_decoder(audio_decoder&& other);
+       audio_decoder& operator=(audio_decoder&& other);
+
+       std::shared_ptr<AVFrame> operator()();
+
+       uint32_t nb_frames() const;
+       
+       std::wstring print() const;
+       
+       // monitor::observable
+       
+       void subscribe(const monitor::observable::observer_ptr& o) override;
+       void unsubscribe(const monitor::observable::observer_ptr& o) override;
+
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index 24bd48ee851407086c5e13c4d6514e8ef471cb08..3a378a2bb73e3b730062909832b6dd4e80dca5d6 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "ffmpeg_producer.h"\r
-\r
-#include "../ffmpeg_error.h"\r
-\r
-#include "muxer/frame_muxer.h"\r
-#include "input/input.h"\r
-#include "util/util.h"\r
-#include "audio/audio_decoder.h"\r
-#include "video/video_decoder.h"\r
-\r
-#include <common/env.h>\r
-#include <common/log.h>\r
-#include <common/param.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/future.h>\r
-\r
-#include <core/video_format.h>\r
-#include <core/producer/frame_producer.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/draw_frame.h>\r
-#include <core/frame/frame_transform.h>\r
-#include <core/monitor/monitor.h>\r
-\r
-#include <boost/algorithm/string.hpp>\r
-#include <common/assert.h>\r
-#include <boost/assign.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/range/algorithm/find_if.hpp>\r
-#include <boost/range/algorithm/find.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/regex.hpp>\r
-#include <boost/thread/future.hpp>\r
-\r
-#include <tbb/parallel_invoke.h>\r
-\r
-#include <limits>\r
-#include <memory>\r
-#include <queue>\r
-\r
-namespace caspar { namespace ffmpeg {\r
-                               \r
-struct ffmpeg_producer : public core::frame_producer_base\r
-{\r
-       monitor::basic_subject                                                  event_subject_;\r
-       const std::wstring                                                              filename_;\r
-       \r
-       const spl::shared_ptr<diagnostics::graph>               graph_;\r
-                                       \r
-       const spl::shared_ptr<core::frame_factory>              frame_factory_;\r
-       const core::video_format_desc                                   format_desc_;\r
-\r
-       input                                                                                   input_; \r
-\r
-       const double                                                                    fps_;\r
-       const uint32_t                                                                  start_;\r
-               \r
-       std::unique_ptr<video_decoder>                                  video_decoder_;\r
-       std::unique_ptr<audio_decoder>                                  audio_decoder_; \r
-       frame_muxer                                                                             muxer_;\r
-       \r
-       core::draw_frame                                                                last_frame_;\r
-\r
-       boost::optional<uint32_t>                                               seek_target_;\r
-       \r
-public:\r
-       explicit ffmpeg_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, \r
-                                                        const core::video_format_desc& format_desc, \r
-                                                        const std::wstring& filename, \r
-                                                        const std::wstring& filter, \r
-                                                        bool loop, \r
-                                                        uint32_t start, \r
-                                                        uint32_t length) \r
-               : filename_(filename)\r
-               , frame_factory_(frame_factory)         \r
-               , format_desc_(format_desc)\r
-               , input_(graph_, filename_, loop, start, length)\r
-               , fps_(read_fps(input_.context(), format_desc_.fps))\r
-               , muxer_(fps_, frame_factory, format_desc_, filter)\r
-               , start_(start)\r
-               , last_frame_(core::draw_frame::empty())\r
-       {\r
-               graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));\r
-               graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));   \r
-               diagnostics::register_graph(graph_);\r
-               \r
-\r
-               try\r
-               {\r
-                       video_decoder_.reset(new video_decoder(input_));\r
-                       video_decoder_->subscribe(event_subject_);\r
-                       \r
-                       CASPAR_LOG(info) << print() << L" " << video_decoder_->print();\r
-               }\r
-               catch(averror_stream_not_found&)\r
-               {\r
-                       //CASPAR_LOG(warning) << print() << " No video-stream found. Running without video.";   \r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";        \r
-               }\r
-\r
-               try\r
-               {\r
-                       audio_decoder_ .reset(new audio_decoder(input_, format_desc_));\r
-                       audio_decoder_->subscribe(event_subject_);\r
-                       \r
-                       CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();\r
-               }\r
-               catch(averror_stream_not_found&)\r
-               {\r
-                       //CASPAR_LOG(warning) << print() << " No audio-stream found. Running without audio.";   \r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";               \r
-               }       \r
-               \r
-               decode_next_frame();\r
-\r
-               CASPAR_LOG(info) << print() << L" Initialized";\r
-       }\r
-\r
-       // frame_producer\r
-       \r
-       core::draw_frame receive_impl() override\r
-       {                               \r
-               auto frame = core::draw_frame::late();          \r
-               \r
-               boost::timer frame_timer;\r
-               \r
-               end_seek();\r
-                               \r
-               decode_next_frame();\r
-               \r
-               if(!muxer_.empty())\r
-               {\r
-                       last_frame_ = frame = std::move(muxer_.front());\r
-                       muxer_.pop();   \r
-               }\r
-               else                            \r
-                       graph_->set_tag("underflow");\r
-                                                                       \r
-               graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);\r
-               event_subject_  << monitor::event("profiler/time") % frame_timer.elapsed() % (1.0/format_desc_.fps);                    \r
-                                                               \r
-               event_subject_  << monitor::event("file/time")                  % monitor::duration(file_frame_number()/fps_) \r
-                                                                                                                               % monitor::duration(file_nb_frames()/fps_)\r
-                                               << monitor::event("file/frame")                 % static_cast<int32_t>(file_frame_number())\r
-                                                                                                                               % static_cast<int32_t>(file_nb_frames())\r
-                                               << monitor::event("file/fps")                   % fps_\r
-                                               << monitor::event("file/path")                  % filename_\r
-                                               << monitor::event("loop")                               % input_.loop();\r
-                                               \r
-               return frame;\r
-       }\r
-\r
-       core::draw_frame last_frame() override\r
-       {\r
-               end_seek();\r
-               return core::draw_frame::still(last_frame_);\r
-       }\r
-               \r
-       uint32_t nb_frames() const override\r
-       {\r
-               if(input_.loop())\r
-                       return std::numeric_limits<uint32_t>::max();\r
-\r
-               uint32_t nb_frames = file_nb_frames();\r
-\r
-               nb_frames = std::min(input_.length(), nb_frames);\r
-               nb_frames = muxer_.calc_nb_frames(nb_frames);\r
-               \r
-               return nb_frames > start_ ? nb_frames - start_ : 0;\r
-       }\r
-\r
-       uint32_t file_nb_frames() const\r
-       {\r
-               uint32_t file_nb_frames = 0;\r
-               file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);\r
-               file_nb_frames = std::max(file_nb_frames, audio_decoder_ ? audio_decoder_->nb_frames() : 0);\r
-               return file_nb_frames;\r
-       }\r
-\r
-       uint32_t file_frame_number() const\r
-       {\r
-               return video_decoder_ ? video_decoder_->file_frame_number() : 0;\r
-       }\r
-               \r
-       boost::unique_future<std::wstring> call(const std::wstring& param) override\r
-       {\r
-               static const boost::wregex loop_exp(L"LOOP\\s*(?<VALUE>\\d?)?", boost::regex::icase);\r
-               static const boost::wregex seek_exp(L"SEEK\\s+(?<VALUE>\\d+)", boost::regex::icase);\r
-               static const boost::wregex length_exp(L"LENGTH\\s+(?<VALUE>\\d+)?", boost::regex::icase);\r
-               static const boost::wregex start_exp(L"START\\s+(?<VALUE>\\d+)?", boost::regex::icase);\r
-               \r
-               std::wstring result;\r
-                       \r
-               boost::wsmatch what;\r
-               if(boost::regex_match(param, what, loop_exp))\r
-               {\r
-                       auto value = what["VALUE"].str();\r
-                       if(!value.empty())\r
-                               input_.loop(boost::lexical_cast<bool>(value));\r
-                       result = boost::lexical_cast<std::wstring>(loop());\r
-               }\r
-               else if(boost::regex_match(param, what, seek_exp))\r
-               {\r
-                       auto value = what["VALUE"].str();\r
-                       seek(boost::lexical_cast<uint32_t>(value));\r
-               }\r
-               else if(boost::regex_match(param, what, length_exp))\r
-               {\r
-                       auto value = what["VALUE"].str();\r
-                       if(!value.empty())\r
-                               length(boost::lexical_cast<uint32_t>(value));                   \r
-                       result = boost::lexical_cast<std::wstring>(length());\r
-               }\r
-               else if(boost::regex_match(param, what, start_exp))\r
-               {\r
-                       auto value = what["VALUE"].str();\r
-                       if(!value.empty())\r
-                               start(boost::lexical_cast<uint32_t>(value));\r
-                       result = boost::lexical_cast<std::wstring>(start());\r
-               }\r
-               else\r
-                       CASPAR_THROW_EXCEPTION(invalid_argument());\r
-\r
-               return async(launch::deferred, [=]{return result;});\r
-       }\r
-                               \r
-       std::wstring print() const override\r
-       {\r
-               return L"ffmpeg[" + boost::filesystem::path(filename_).filename().wstring() + L"|" \r
-                                                 + print_mode() + L"|" \r
-                                                 + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"ffmpeg";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type",                               L"ffmpeg");\r
-               info.add(L"filename",                   filename_);\r
-               info.add(L"width",                              video_decoder_ ? video_decoder_->width() : 0);\r
-               info.add(L"height",                             video_decoder_ ? video_decoder_->height() : 0);\r
-               info.add(L"progressive",                video_decoder_ ? video_decoder_->is_progressive() : 0);\r
-               info.add(L"fps",                                fps_);\r
-               info.add(L"loop",                               input_.loop());\r
-               info.add(L"frame-number",               frame_number());\r
-               auto nb_frames2 = nb_frames();\r
-               info.add(L"nb-frames",                  nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);\r
-               info.add(L"file-frame-number",  file_frame_number());\r
-               info.add(L"file-nb-frames",             file_nb_frames());\r
-               return info;\r
-       }\r
-       \r
-       void subscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-               event_subject_.subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-               event_subject_.unsubscribe(o);\r
-       }\r
-\r
-       // ffmpeg_producer\r
-       \r
-       void end_seek()\r
-       {\r
-               for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)\r
-               {\r
-                       decode_next_frame();\r
-                       if(!muxer_.empty())\r
-                       {\r
-                               last_frame_ = muxer_.front();\r
-                               seek_target_.reset();\r
-                       }\r
-               }\r
-       }\r
-\r
-       void loop(bool value)\r
-       {\r
-               input_.loop(value);\r
-       }\r
-\r
-       bool loop() const\r
-       {\r
-               return input_.loop();\r
-       }\r
-\r
-       void length(uint32_t value)\r
-       {\r
-               input_.length(value);\r
-       }\r
-\r
-       uint32_t length()\r
-       {\r
-               return input_.length();\r
-       }\r
-       \r
-       void start(uint32_t value)\r
-       {\r
-               input_.start(value);\r
-       }\r
-\r
-       uint32_t start()\r
-       {\r
-               return input_.start();\r
-       }\r
-\r
-       void seek(uint32_t target)\r
-       {               \r
-               seek_target_ = std::min(target, file_nb_frames());\r
-\r
-               input_.seek(*seek_target_);\r
-               muxer_.clear();\r
-       }\r
-\r
-       std::wstring print_mode() const\r
-       {\r
-               return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0, \r
-                       video_decoder_ ? video_decoder_->height() : 0, \r
-                       fps_, \r
-                       video_decoder_ ? !video_decoder_->is_progressive() : false);\r
-       }\r
-                       \r
-       void decode_next_frame()\r
-       {\r
-               for(int n = 0; n < 8 && muxer_.empty(); ++n)\r
-               {                               \r
-                       if(!muxer_.video_ready())\r
-                               muxer_.push_video(video_decoder_ ? (*video_decoder_)() : create_frame());\r
-                       if(!muxer_.audio_ready())\r
-                               muxer_.push_audio(audio_decoder_ ? (*audio_decoder_)() : create_frame());\r
-               }\r
-               graph_->set_text(print());\r
-       }\r
-};\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)\r
-{              \r
-       auto filename = probe_stem(env::media_folder() + L"\\" + params.at(0));\r
-\r
-       if(filename.empty())\r
-               return core::frame_producer::empty();\r
-       \r
-       auto loop               = boost::range::find(params, L"LOOP") != params.end();\r
-       auto start              = get_param(L"START", params, get_param(L"SEEK", params, static_cast<uint32_t>(0)));\r
-       auto length             = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());\r
-       auto filter_str = get_param(L"FILTER", params, L"");    \r
-       \r
-       return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(frame_factory, format_desc, filename, filter_str, loop, start, length)));\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "ffmpeg_producer.h"
+
+#include "../ffmpeg_error.h"
+
+#include "muxer/frame_muxer.h"
+#include "input/input.h"
+#include "util/util.h"
+#include "audio/audio_decoder.h"
+#include "video/video_decoder.h"
+
+#include <common/env.h>
+#include <common/log.h>
+#include <common/param.h>
+#include <common/diagnostics/graph.h>
+#include <common/future.h>
+
+#include <core/video_format.h>
+#include <core/producer/frame_producer.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_transform.h>
+#include <core/monitor/monitor.h>
+
+#include <boost/algorithm/string.hpp>
+#include <common/assert.h>
+#include <boost/assign.hpp>
+#include <boost/timer.hpp>
+#include <boost/foreach.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/range/algorithm/find_if.hpp>
+#include <boost/range/algorithm/find.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/regex.hpp>
+#include <boost/thread/future.hpp>
+
+#include <tbb/parallel_invoke.h>
+
+#include <limits>
+#include <memory>
+#include <queue>
+
+namespace caspar { namespace ffmpeg {
+                               
+struct ffmpeg_producer : public core::frame_producer_base
+{
+       monitor::basic_subject                                                  event_subject_;
+       const std::wstring                                                              filename_;
+       
+       const spl::shared_ptr<diagnostics::graph>               graph_;
+                                       
+       const spl::shared_ptr<core::frame_factory>              frame_factory_;
+       const core::video_format_desc                                   format_desc_;
+
+       input                                                                                   input_; 
+
+       const double                                                                    fps_;
+       const uint32_t                                                                  start_;
+               
+       std::unique_ptr<video_decoder>                                  video_decoder_;
+       std::unique_ptr<audio_decoder>                                  audio_decoder_; 
+       frame_muxer                                                                             muxer_;
+       
+       core::draw_frame                                                                last_frame_;
+
+       boost::optional<uint32_t>                                               seek_target_;
+       
+public:
+       explicit ffmpeg_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, 
+                                                        const core::video_format_desc& format_desc, 
+                                                        const std::wstring& filename, 
+                                                        const std::wstring& filter, 
+                                                        bool loop, 
+                                                        uint32_t start, 
+                                                        uint32_t length) 
+               : filename_(filename)
+               , frame_factory_(frame_factory)         
+               , format_desc_(format_desc)
+               , input_(graph_, filename_, loop, start, length)
+               , fps_(read_fps(input_.context(), format_desc_.fps))
+               , muxer_(fps_, frame_factory, format_desc_, filter)
+               , start_(start)
+               , last_frame_(core::draw_frame::empty())
+       {
+               graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
+               graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));   
+               diagnostics::register_graph(graph_);
+               
+
+               try
+               {
+                       video_decoder_.reset(new video_decoder(input_));
+                       video_decoder_->subscribe(event_subject_);
+                       
+                       CASPAR_LOG(info) << print() << L" " << video_decoder_->print();
+               }
+               catch(averror_stream_not_found&)
+               {
+                       //CASPAR_LOG(warning) << print() << " No video-stream found. Running without video.";   
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+                       CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";        
+               }
+
+               try
+               {
+                       audio_decoder_ .reset(new audio_decoder(input_, format_desc_));
+                       audio_decoder_->subscribe(event_subject_);
+                       
+                       CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();
+               }
+               catch(averror_stream_not_found&)
+               {
+                       //CASPAR_LOG(warning) << print() << " No audio-stream found. Running without audio.";   
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+                       CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";               
+               }       
+               
+               decode_next_frame();
+
+               CASPAR_LOG(info) << print() << L" Initialized";
+       }
+
+       // frame_producer
+       
+       core::draw_frame receive_impl() override
+       {                               
+               auto frame = core::draw_frame::late();          
+               
+               boost::timer frame_timer;
+               
+               end_seek();
+                               
+               decode_next_frame();
+               
+               if(!muxer_.empty())
+               {
+                       last_frame_ = frame = std::move(muxer_.front());
+                       muxer_.pop();   
+               }
+               else                            
+                       graph_->set_tag("underflow");
+                                                                       
+               graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
+               event_subject_  << monitor::event("profiler/time") % frame_timer.elapsed() % (1.0/format_desc_.fps);                    
+                                                               
+               event_subject_  << monitor::event("file/time")                  % monitor::duration(file_frame_number()/fps_) 
+                                                                                                                               % monitor::duration(file_nb_frames()/fps_)
+                                               << monitor::event("file/frame")                 % static_cast<int32_t>(file_frame_number())
+                                                                                                                               % static_cast<int32_t>(file_nb_frames())
+                                               << monitor::event("file/fps")                   % fps_
+                                               << monitor::event("file/path")                  % filename_
+                                               << monitor::event("loop")                               % input_.loop();
+                                               
+               return frame;
+       }
+
+       core::draw_frame last_frame() override
+       {
+               end_seek();
+               return core::draw_frame::still(last_frame_);
+       }
+               
+       uint32_t nb_frames() const override
+       {
+               if(input_.loop())
+                       return std::numeric_limits<uint32_t>::max();
+
+               uint32_t nb_frames = file_nb_frames();
+
+               nb_frames = std::min(input_.length(), nb_frames);
+               nb_frames = muxer_.calc_nb_frames(nb_frames);
+               
+               return nb_frames > start_ ? nb_frames - start_ : 0;
+       }
+
+       uint32_t file_nb_frames() const
+       {
+               uint32_t file_nb_frames = 0;
+               file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);
+               file_nb_frames = std::max(file_nb_frames, audio_decoder_ ? audio_decoder_->nb_frames() : 0);
+               return file_nb_frames;
+       }
+
+       uint32_t file_frame_number() const
+       {
+               return video_decoder_ ? video_decoder_->file_frame_number() : 0;
+       }
+               
+       boost::unique_future<std::wstring> call(const std::wstring& param) override
+       {
+               static const boost::wregex loop_exp(L"LOOP\\s*(?<VALUE>\\d?)?", boost::regex::icase);
+               static const boost::wregex seek_exp(L"SEEK\\s+(?<VALUE>\\d+)", boost::regex::icase);
+               static const boost::wregex length_exp(L"LENGTH\\s+(?<VALUE>\\d+)?", boost::regex::icase);
+               static const boost::wregex start_exp(L"START\\s+(?<VALUE>\\d+)?", boost::regex::icase);
+               
+               std::wstring result;
+                       
+               boost::wsmatch what;
+               if(boost::regex_match(param, what, loop_exp))
+               {
+                       auto value = what["VALUE"].str();
+                       if(!value.empty())
+                               input_.loop(boost::lexical_cast<bool>(value));
+                       result = boost::lexical_cast<std::wstring>(loop());
+               }
+               else if(boost::regex_match(param, what, seek_exp))
+               {
+                       auto value = what["VALUE"].str();
+                       seek(boost::lexical_cast<uint32_t>(value));
+               }
+               else if(boost::regex_match(param, what, length_exp))
+               {
+                       auto value = what["VALUE"].str();
+                       if(!value.empty())
+                               length(boost::lexical_cast<uint32_t>(value));                   
+                       result = boost::lexical_cast<std::wstring>(length());
+               }
+               else if(boost::regex_match(param, what, start_exp))
+               {
+                       auto value = what["VALUE"].str();
+                       if(!value.empty())
+                               start(boost::lexical_cast<uint32_t>(value));
+                       result = boost::lexical_cast<std::wstring>(start());
+               }
+               else
+                       CASPAR_THROW_EXCEPTION(invalid_argument());
+
+               return async(launch::deferred, [=]{return result;});
+       }
+                               
+       std::wstring print() const override
+       {
+               return L"ffmpeg[" + boost::filesystem::path(filename_).filename().wstring() + L"|" 
+                                                 + print_mode() + L"|" 
+                                                 + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";
+       }
+
+       std::wstring name() const override
+       {
+               return L"ffmpeg";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type",                               L"ffmpeg");
+               info.add(L"filename",                   filename_);
+               info.add(L"width",                              video_decoder_ ? video_decoder_->width() : 0);
+               info.add(L"height",                             video_decoder_ ? video_decoder_->height() : 0);
+               info.add(L"progressive",                video_decoder_ ? video_decoder_->is_progressive() : 0);
+               info.add(L"fps",                                fps_);
+               info.add(L"loop",                               input_.loop());
+               info.add(L"frame-number",               frame_number());
+               auto nb_frames2 = nb_frames();
+               info.add(L"nb-frames",                  nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);
+               info.add(L"file-frame-number",  file_frame_number());
+               info.add(L"file-nb-frames",             file_nb_frames());
+               return info;
+       }
+       
+       void subscribe(const monitor::observable::observer_ptr& o) override
+       {
+               event_subject_.subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override
+       {
+               event_subject_.unsubscribe(o);
+       }
+
+       // ffmpeg_producer
+       
+       void end_seek()
+       {
+               for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)
+               {
+                       decode_next_frame();
+                       if(!muxer_.empty())
+                       {
+                               last_frame_ = muxer_.front();
+                               seek_target_.reset();
+                       }
+               }
+       }
+
+       void loop(bool value)
+       {
+               input_.loop(value);
+       }
+
+       bool loop() const
+       {
+               return input_.loop();
+       }
+
+       void length(uint32_t value)
+       {
+               input_.length(value);
+       }
+
+       uint32_t length()
+       {
+               return input_.length();
+       }
+       
+       void start(uint32_t value)
+       {
+               input_.start(value);
+       }
+
+       uint32_t start()
+       {
+               return input_.start();
+       }
+
+       void seek(uint32_t target)
+       {               
+               seek_target_ = std::min(target, file_nb_frames());
+
+               input_.seek(*seek_target_);
+               muxer_.clear();
+       }
+
+       std::wstring print_mode() const
+       {
+               return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0, 
+                       video_decoder_ ? video_decoder_->height() : 0, 
+                       fps_, 
+                       video_decoder_ ? !video_decoder_->is_progressive() : false);
+       }
+                       
+       void decode_next_frame()
+       {
+               for(int n = 0; n < 8 && muxer_.empty(); ++n)
+               {                               
+                       if(!muxer_.video_ready())
+                               muxer_.push_video(video_decoder_ ? (*video_decoder_)() : create_frame());
+                       if(!muxer_.audio_ready())
+                               muxer_.push_audio(audio_decoder_ ? (*audio_decoder_)() : create_frame());
+               }
+               graph_->set_text(print());
+       }
+};
+
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+{              
+       auto filename = probe_stem(env::media_folder() + L"\\" + params.at(0));
+
+       if(filename.empty())
+               return core::frame_producer::empty();
+       
+       auto loop               = boost::range::find(params, L"LOOP") != params.end();
+       auto start              = get_param(L"START", params, get_param(L"SEEK", params, static_cast<uint32_t>(0)));
+       auto length             = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
+       auto filter_str = get_param(L"FILTER", params, L"");    
+       
+       return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(frame_factory, format_desc, filename, filter_str, loop, start, length)));
+}
+
 }}
\ No newline at end of file
index 72853ad82cb8b98e6e3f86919ff54ad5af886f62..512baf58ae240637f9d383b7e114c4c73ea377c0 100644 (file)
@@ -1,45 +1,45 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/video_format.h>\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar {\r
-\r
-namespace core {\r
-\r
-class frame_producer;\r
-class frame_factory;\r
-\r
-}\r
-       \r
-namespace ffmpeg {\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <core/producer/frame_producer.h>
+#include <core/video_format.h>
+
+#include <string>
+#include <vector>
+
+namespace caspar {
+
+namespace core {
+
+class frame_producer;
+class frame_factory;
+
+}
+       
+namespace ffmpeg {
+
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+
 }}
\ No newline at end of file
index b9ed762b74f4c10e61aa383cfcd9304edfa2bc00..9d6b4de0329e8d0f6f211bcaa46e5d95b7b0e59f 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "filter.h"\r
-\r
-#include "parallel_yadif.h"\r
-\r
-#include "../../ffmpeg_error.h"\r
-\r
-#include <common/except.h>\r
-\r
-#include <boost/assign.hpp>\r
-#include <boost/range/iterator_range.hpp>\r
-#include <boost/range/adaptors.hpp>\r
-#include <boost/assign.hpp>\r
-#include <boost/algorithm/string.hpp>\r
-#include <boost/foreach.hpp>\r
-\r
-#include <cstdio>\r
-#include <sstream>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #include <libavutil/avutil.h>\r
-       #include <libavutil/imgutils.h>\r
-       #include <libavfilter/avfilter.h>\r
-       #include <libavfilter/avcodec.h>\r
-       #include <libavfilter/avfiltergraph.h>\r
-       #include <libavfilter/buffersink.h>\r
-       #include <libavfilter/vsrc_buffer.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-\r
-namespace caspar { namespace ffmpeg {\r
-\r
-static int query_formats_444(AVFilterContext *ctx)\r
-{\r
-    static const int pix_fmts[] = {PIX_FMT_YUV444P, PIX_FMT_NONE};\r
-    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));\r
-    return 0;\r
-}\r
-\r
-static int query_formats_422(AVFilterContext *ctx)\r
-{\r
-    static const int pix_fmts[] = {PIX_FMT_YUV422P, PIX_FMT_NONE};\r
-    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));\r
-    return 0;\r
-}\r
-\r
-static int query_formats_420(AVFilterContext *ctx)\r
-{\r
-    static const int pix_fmts[] = {PIX_FMT_YUV420P, PIX_FMT_NONE};\r
-    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));\r
-    return 0;\r
-}\r
-\r
-static int query_formats_420a(AVFilterContext *ctx)\r
-{\r
-    static const int pix_fmts[] = {PIX_FMT_YUVA420P, PIX_FMT_NONE};\r
-    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));\r
-    return 0;\r
-}\r
-\r
-static int query_formats_411(AVFilterContext *ctx)\r
-{\r
-    static const int pix_fmts[] = {PIX_FMT_YUV411P, PIX_FMT_NONE};\r
-    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));\r
-    return 0;\r
-}\r
-\r
-static int query_formats_410(AVFilterContext *ctx)\r
-{\r
-    static const int pix_fmts[] = {PIX_FMT_YUV410P, PIX_FMT_NONE};\r
-    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));\r
-    return 0;\r
-}\r
-\r
-struct filter::impl\r
-{\r
-       std::wstring                                    filters_;\r
-       std::shared_ptr<AVFilterGraph>  graph_; \r
-       AVFilterContext*                                buffersink_ctx_;\r
-       AVFilterContext*                                buffersrc_ctx_;\r
-       std::shared_ptr<void>                   parallel_yadif_ctx_;\r
-       std::vector<PixelFormat>                pix_fmts_;\r
-       std::queue<spl::shared_ptr<AVFrame>>    bypass_;\r
-               \r
-       impl(const std::wstring& filters, const std::vector<PixelFormat>& pix_fmts) \r
-               : filters_(filters)\r
-               , parallel_yadif_ctx_(nullptr)\r
-               , pix_fmts_(pix_fmts)\r
-       {\r
-               if(pix_fmts_.empty())\r
-               {\r
-                       pix_fmts_ = boost::assign::list_of\r
-                               (PIX_FMT_YUVA420P)\r
-                               (PIX_FMT_YUV444P)\r
-                               (PIX_FMT_YUV422P)\r
-                               (PIX_FMT_YUV420P)\r
-                               (PIX_FMT_YUV411P)\r
-                               (PIX_FMT_BGRA)\r
-                               (PIX_FMT_ARGB)\r
-                               (PIX_FMT_RGBA)\r
-                               (PIX_FMT_ABGR)\r
-                               (PIX_FMT_GRAY8);\r
-               }\r
-               \r
-               pix_fmts_.push_back(PIX_FMT_NONE);\r
-       }\r
-       \r
-       void push(const std::shared_ptr<AVFrame>& frame)\r
-       {               \r
-               if(!frame)\r
-                       return;\r
-\r
-               if(frame->data[0] == nullptr || frame->width < 1)\r
-                       CASPAR_THROW_EXCEPTION(invalid_argument());\r
-\r
-               if(filters_.empty())\r
-               {\r
-                       bypass_.push(spl::make_shared_ptr(frame));\r
-                       return;\r
-               }\r
-               \r
-               try\r
-               {\r
-                       if(!graph_)\r
-                       {\r
-                               try\r
-                               {\r
-                                       graph_.reset(avfilter_graph_alloc(), [](AVFilterGraph* p){avfilter_graph_free(&p);});\r
-                                                               \r
-                                       // Input\r
-                                       std::stringstream args;\r
-                                       args << frame->width << ":" << frame->height << ":" << frame->format << ":" << 0 << ":" << 0 << ":" << 0 << ":" << 0; // don't care about pts and aspect_ratio\r
-                                       THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("buffer"), "src", args.str().c_str(), NULL, graph_.get()), "[filter]");\r
-                                       \r
-                               #if FF_API_OLD_VSINK_API\r
-                                       THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, pix_fmts_.data(), graph_.get()), "[filter]");\r
-                               #else\r
-                                       spl::shared_ptr<AVBufferSinkParams> buffersink_params(av_buffersink_params_alloc(), av_free);\r
-                                       buffersink_params->pixel_fmts = pix_fmts_.data();\r
-                                       THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, buffersink_params.get(), graph_.get()), "[filter]");                            \r
-                               #endif\r
-                                       AVFilterInOut* inputs  = avfilter_inout_alloc();\r
-                                       AVFilterInOut* outputs = avfilter_inout_alloc();\r
-                                                               \r
-                                       outputs->name                   = av_strdup("in");\r
-                                       outputs->filter_ctx             = buffersrc_ctx_;\r
-                                       outputs->pad_idx                = 0;\r
-                                       outputs->next                   = nullptr;\r
-\r
-                                       inputs->name                    = av_strdup("out");\r
-                                       inputs->filter_ctx              = buffersink_ctx_;\r
-                                       inputs->pad_idx                 = 0;\r
-                                       inputs->next                    = nullptr;\r
-                       \r
-                                       std::string filters = boost::to_lower_copy(u8(filters_));\r
-                                       THROW_ON_ERROR2(avfilter_graph_parse(graph_.get(), filters.c_str(), &inputs, &outputs, NULL), "[filter]");\r
-                       \r
-                                       auto yadif_filter = boost::adaptors::filtered([&](AVFilterContext* p){return strstr(p->name, "yadif") != 0;});\r
-\r
-                                       BOOST_FOREACH(auto filter_ctx, boost::make_iterator_range(graph_->filters, graph_->filters + graph_->filter_count) | yadif_filter)\r
-                                       {\r
-                                               // Don't trust that libavfilter chooses optimal format.\r
-                                               filter_ctx->filter->query_formats = [&]() -> int (*)(AVFilterContext*)\r
-                                               {\r
-                                                       switch(frame->format)\r
-                                                       {\r
-                                                       case PIX_FMT_YUV444P16: \r
-                                                       case PIX_FMT_YUV444P10: \r
-                                                       case PIX_FMT_YUV444P9:          \r
-                                                       case PIX_FMT_YUV444P:   \r
-                                                       case PIX_FMT_BGR24:             \r
-                                                       case PIX_FMT_RGB24:     \r
-                                                               return query_formats_444;\r
-                                                       case PIX_FMT_YUV422P16: \r
-                                                       case PIX_FMT_YUV422P10: \r
-                                                       case PIX_FMT_YUV422P9:  \r
-                                                       case PIX_FMT_YUV422P:   \r
-                                                       case PIX_FMT_UYVY422:   \r
-                                                       case PIX_FMT_YUYV422:   \r
-                                                               return query_formats_422;\r
-                                                       case PIX_FMT_YUV420P16: \r
-                                                       case PIX_FMT_YUV420P10: \r
-                                                       case PIX_FMT_YUV420P9:  \r
-                                                       case PIX_FMT_YUV420P:   \r
-                                                               return query_formats_420;\r
-                                                       case PIX_FMT_YUVA420P:  \r
-                                                       case PIX_FMT_BGRA:              \r
-                                                       case PIX_FMT_RGBA:              \r
-                                                       case PIX_FMT_ABGR:              \r
-                                                       case PIX_FMT_ARGB:              \r
-                                                               return query_formats_420a;\r
-                                                       case PIX_FMT_UYYVYY411: \r
-                                                       case PIX_FMT_YUV411P:   \r
-                                                               return query_formats_411;\r
-                                                       case PIX_FMT_YUV410P:   \r
-                                                               return query_formats_410;\r
-                                                       default:                                \r
-                                                               return filter_ctx->filter->query_formats;\r
-                                                       }\r
-                                               }();\r
-                                       }\r
-                                       \r
-                                       THROW_ON_ERROR2(avfilter_graph_config(graph_.get(), NULL), "[filter]"); \r
-                                       \r
-                                       BOOST_FOREACH(auto filter_ctx, boost::make_iterator_range(graph_->filters, graph_->filters + graph_->filter_count) | yadif_filter)                                              \r
-                                               parallel_yadif_ctx_ = make_parallel_yadif(filter_ctx);                                          \r
-                               }\r
-                               catch(...)\r
-                               {\r
-                                       graph_ = nullptr;\r
-                                       throw;\r
-                               }\r
-                       }\r
-               \r
-                       THROW_ON_ERROR2(av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0), "[filter]");\r
-               }\r
-               catch(ffmpeg_error&)\r
-               {\r
-                       throw;\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_THROW_EXCEPTION(ffmpeg_error() << boost::errinfo_nested_exception(boost::current_exception()));\r
-               }\r
-       }\r
-\r
-       std::shared_ptr<AVFrame> poll()\r
-       {\r
-               if(filters_.empty())\r
-               {\r
-                       if(bypass_.empty())\r
-                               return nullptr;\r
-                       auto frame = bypass_.front();\r
-                       bypass_.pop();\r
-                       return frame;\r
-               }\r
-\r
-               if(!graph_)\r
-                       return nullptr;\r
-               \r
-               try\r
-               {\r
-                       if(avfilter_poll_frame(buffersink_ctx_->inputs[0])) \r
-                       {\r
-                               AVFilterBufferRef *picref;\r
-                               THROW_ON_ERROR2(av_buffersink_get_buffer_ref(buffersink_ctx_, &picref, 0), "[filter]");\r
-\r
-                               if (!picref) \r
-                                       return nullptr;\r
-                               \r
-                               spl::shared_ptr<AVFrame> frame(avcodec_alloc_frame(), [=](AVFrame* p)\r
-                               {\r
-                                       av_free(p);\r
-                                       avfilter_unref_buffer(picref);\r
-                               });\r
-\r
-                               avcodec_get_frame_defaults(frame.get());        \r
-\r
-                               memcpy(frame->data,     picref->data,     sizeof(frame->data));\r
-                               memcpy(frame->linesize, picref->linesize, sizeof(frame->linesize));\r
-                               frame->format                           = picref->format;\r
-                               frame->width                            = picref->video->w;\r
-                               frame->height                           = picref->video->h;\r
-                               frame->pkt_pos                          = picref->pos;\r
-                               frame->interlaced_frame         = picref->video->interlaced;\r
-                               frame->top_field_first          = picref->video->top_field_first;\r
-                               frame->key_frame                        = picref->video->key_frame;\r
-                               frame->pict_type                        = picref->video->pict_type;\r
-                               frame->sample_aspect_ratio      = picref->video->sample_aspect_ratio;\r
-                                       \r
-                               return frame;                           \r
-                       }\r
-\r
-                       return nullptr;\r
-               }\r
-               catch(ffmpeg_error&)\r
-               {\r
-                       throw;\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_THROW_EXCEPTION(ffmpeg_error() << boost::errinfo_nested_exception(boost::current_exception()));\r
-               }\r
-       }\r
-};\r
-\r
-filter::filter(const std::wstring& filters, const std::vector<PixelFormat>& pix_fmts) : impl_(new impl(filters, pix_fmts)){}\r
-filter::filter(filter&& other) : impl_(std::move(other.impl_)){}\r
-filter& filter::operator=(filter&& other){impl_ = std::move(other.impl_); return *this;}\r
-void filter::push(const std::shared_ptr<AVFrame>& frame){impl_->push(frame);}\r
-std::shared_ptr<AVFrame> filter::poll(){return impl_->poll();}\r
-std::wstring filter::filter_str() const{return impl_->filters_;}\r
-std::vector<spl::shared_ptr<AVFrame>> filter::poll_all()\r
-{      \r
-       std::vector<spl::shared_ptr<AVFrame>> frames;\r
-       for(auto frame = poll(); frame; frame = poll())\r
-               frames.push_back(spl::make_shared_ptr(frame));\r
-       return frames;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "filter.h"
+
+#include "parallel_yadif.h"
+
+#include "../../ffmpeg_error.h"
+
+#include <common/except.h>
+
+#include <boost/assign.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/range/adaptors.hpp>
+#include <boost/assign.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
+
+#include <cstdio>
+#include <sstream>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #include <libavutil/avutil.h>
+       #include <libavutil/imgutils.h>
+       #include <libavfilter/avfilter.h>
+       #include <libavfilter/avcodec.h>
+       #include <libavfilter/avfiltergraph.h>
+       #include <libavfilter/buffersink.h>
+       #include <libavfilter/vsrc_buffer.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+
+namespace caspar { namespace ffmpeg {
+
+static int query_formats_444(AVFilterContext *ctx)
+{
+    static const int pix_fmts[] = {PIX_FMT_YUV444P, PIX_FMT_NONE};
+    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
+    return 0;
+}
+
+static int query_formats_422(AVFilterContext *ctx)
+{
+    static const int pix_fmts[] = {PIX_FMT_YUV422P, PIX_FMT_NONE};
+    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
+    return 0;
+}
+
+static int query_formats_420(AVFilterContext *ctx)
+{
+    static const int pix_fmts[] = {PIX_FMT_YUV420P, PIX_FMT_NONE};
+    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
+    return 0;
+}
+
+static int query_formats_420a(AVFilterContext *ctx)
+{
+    static const int pix_fmts[] = {PIX_FMT_YUVA420P, PIX_FMT_NONE};
+    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
+    return 0;
+}
+
+static int query_formats_411(AVFilterContext *ctx)
+{
+    static const int pix_fmts[] = {PIX_FMT_YUV411P, PIX_FMT_NONE};
+    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
+    return 0;
+}
+
+static int query_formats_410(AVFilterContext *ctx)
+{
+    static const int pix_fmts[] = {PIX_FMT_YUV410P, PIX_FMT_NONE};
+    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
+    return 0;
+}
+
+struct filter::impl
+{
+       std::wstring                                    filters_;
+       std::shared_ptr<AVFilterGraph>  graph_; 
+       AVFilterContext*                                buffersink_ctx_;
+       AVFilterContext*                                buffersrc_ctx_;
+       std::shared_ptr<void>                   parallel_yadif_ctx_;
+       std::vector<PixelFormat>                pix_fmts_;
+       std::queue<spl::shared_ptr<AVFrame>>    bypass_;
+               
+       impl(const std::wstring& filters, const std::vector<PixelFormat>& pix_fmts) 
+               : filters_(filters)
+               , parallel_yadif_ctx_(nullptr)
+               , pix_fmts_(pix_fmts)
+       {
+               if(pix_fmts_.empty())
+               {
+                       pix_fmts_ = boost::assign::list_of
+                               (PIX_FMT_YUVA420P)
+                               (PIX_FMT_YUV444P)
+                               (PIX_FMT_YUV422P)
+                               (PIX_FMT_YUV420P)
+                               (PIX_FMT_YUV411P)
+                               (PIX_FMT_BGRA)
+                               (PIX_FMT_ARGB)
+                               (PIX_FMT_RGBA)
+                               (PIX_FMT_ABGR)
+                               (PIX_FMT_GRAY8);
+               }
+               
+               pix_fmts_.push_back(PIX_FMT_NONE);
+       }
+       
+       void push(const std::shared_ptr<AVFrame>& frame)
+       {               
+               if(!frame)
+                       return;
+
+               if(frame->data[0] == nullptr || frame->width < 1)
+                       CASPAR_THROW_EXCEPTION(invalid_argument());
+
+               if(filters_.empty())
+               {
+                       bypass_.push(spl::make_shared_ptr(frame));
+                       return;
+               }
+               
+               try
+               {
+                       if(!graph_)
+                       {
+                               try
+                               {
+                                       graph_.reset(avfilter_graph_alloc(), [](AVFilterGraph* p){avfilter_graph_free(&p);});
+                                                               
+                                       // Input
+                                       std::stringstream args;
+                                       args << frame->width << ":" << frame->height << ":" << frame->format << ":" << 0 << ":" << 0 << ":" << 0 << ":" << 0; // don't care about pts and aspect_ratio
+                                       THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("buffer"), "src", args.str().c_str(), NULL, graph_.get()), "[filter]");
+                                       
+                               #if FF_API_OLD_VSINK_API
+                                       THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, pix_fmts_.data(), graph_.get()), "[filter]");
+                               #else
+                                       spl::shared_ptr<AVBufferSinkParams> buffersink_params(av_buffersink_params_alloc(), av_free);
+                                       buffersink_params->pixel_fmts = pix_fmts_.data();
+                                       THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, buffersink_params.get(), graph_.get()), "[filter]");                            
+                               #endif
+                                       AVFilterInOut* inputs  = avfilter_inout_alloc();
+                                       AVFilterInOut* outputs = avfilter_inout_alloc();
+                                                               
+                                       outputs->name                   = av_strdup("in");
+                                       outputs->filter_ctx             = buffersrc_ctx_;
+                                       outputs->pad_idx                = 0;
+                                       outputs->next                   = nullptr;
+
+                                       inputs->name                    = av_strdup("out");
+                                       inputs->filter_ctx              = buffersink_ctx_;
+                                       inputs->pad_idx                 = 0;
+                                       inputs->next                    = nullptr;
+                       
+                                       std::string filters = boost::to_lower_copy(u8(filters_));
+                                       THROW_ON_ERROR2(avfilter_graph_parse(graph_.get(), filters.c_str(), &inputs, &outputs, NULL), "[filter]");
+                       
+                                       auto yadif_filter = boost::adaptors::filtered([&](AVFilterContext* p){return strstr(p->name, "yadif") != 0;});
+
+                                       BOOST_FOREACH(auto filter_ctx, boost::make_iterator_range(graph_->filters, graph_->filters + graph_->filter_count) | yadif_filter)
+                                       {
+                                               // Don't trust that libavfilter chooses optimal format.
+                                               filter_ctx->filter->query_formats = [&]() -> int (*)(AVFilterContext*)
+                                               {
+                                                       switch(frame->format)
+                                                       {
+                                                       case PIX_FMT_YUV444P16: 
+                                                       case PIX_FMT_YUV444P10: 
+                                                       case PIX_FMT_YUV444P9:          
+                                                       case PIX_FMT_YUV444P:   
+                                                       case PIX_FMT_BGR24:             
+                                                       case PIX_FMT_RGB24:     
+                                                               return query_formats_444;
+                                                       case PIX_FMT_YUV422P16: 
+                                                       case PIX_FMT_YUV422P10: 
+                                                       case PIX_FMT_YUV422P9:  
+                                                       case PIX_FMT_YUV422P:   
+                                                       case PIX_FMT_UYVY422:   
+                                                       case PIX_FMT_YUYV422:   
+                                                               return query_formats_422;
+                                                       case PIX_FMT_YUV420P16: 
+                                                       case PIX_FMT_YUV420P10: 
+                                                       case PIX_FMT_YUV420P9:  
+                                                       case PIX_FMT_YUV420P:   
+                                                               return query_formats_420;
+                                                       case PIX_FMT_YUVA420P:  
+                                                       case PIX_FMT_BGRA:              
+                                                       case PIX_FMT_RGBA:              
+                                                       case PIX_FMT_ABGR:              
+                                                       case PIX_FMT_ARGB:              
+                                                               return query_formats_420a;
+                                                       case PIX_FMT_UYYVYY411: 
+                                                       case PIX_FMT_YUV411P:   
+                                                               return query_formats_411;
+                                                       case PIX_FMT_YUV410P:   
+                                                               return query_formats_410;
+                                                       default:                                
+                                                               return filter_ctx->filter->query_formats;
+                                                       }
+                                               }();
+                                       }
+                                       
+                                       THROW_ON_ERROR2(avfilter_graph_config(graph_.get(), NULL), "[filter]"); 
+                                       
+                                       BOOST_FOREACH(auto filter_ctx, boost::make_iterator_range(graph_->filters, graph_->filters + graph_->filter_count) | yadif_filter)                                              
+                                               parallel_yadif_ctx_ = make_parallel_yadif(filter_ctx);                                          
+                               }
+                               catch(...)
+                               {
+                                       graph_ = nullptr;
+                                       throw;
+                               }
+                       }
+               
+                       THROW_ON_ERROR2(av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0), "[filter]");
+               }
+               catch(ffmpeg_error&)
+               {
+                       throw;
+               }
+               catch(...)
+               {
+                       CASPAR_THROW_EXCEPTION(ffmpeg_error() << boost::errinfo_nested_exception(boost::current_exception()));
+               }
+       }
+
+       std::shared_ptr<AVFrame> poll()
+       {
+               if(filters_.empty())
+               {
+                       if(bypass_.empty())
+                               return nullptr;
+                       auto frame = bypass_.front();
+                       bypass_.pop();
+                       return frame;
+               }
+
+               if(!graph_)
+                       return nullptr;
+               
+               try
+               {
+                       if(avfilter_poll_frame(buffersink_ctx_->inputs[0])) 
+                       {
+                               AVFilterBufferRef *picref;
+                               THROW_ON_ERROR2(av_buffersink_get_buffer_ref(buffersink_ctx_, &picref, 0), "[filter]");
+
+                               if (!picref) 
+                                       return nullptr;
+                               
+                               spl::shared_ptr<AVFrame> frame(avcodec_alloc_frame(), [=](AVFrame* p)
+                               {
+                                       av_free(p);
+                                       avfilter_unref_buffer(picref);
+                               });
+
+                               avcodec_get_frame_defaults(frame.get());        
+
+                               memcpy(frame->data,     picref->data,     sizeof(frame->data));
+                               memcpy(frame->linesize, picref->linesize, sizeof(frame->linesize));
+                               frame->format                           = picref->format;
+                               frame->width                            = picref->video->w;
+                               frame->height                           = picref->video->h;
+                               frame->pkt_pos                          = picref->pos;
+                               frame->interlaced_frame         = picref->video->interlaced;
+                               frame->top_field_first          = picref->video->top_field_first;
+                               frame->key_frame                        = picref->video->key_frame;
+                               frame->pict_type                        = picref->video->pict_type;
+                               frame->sample_aspect_ratio      = picref->video->sample_aspect_ratio;
+                                       
+                               return frame;                           
+                       }
+
+                       return nullptr;
+               }
+               catch(ffmpeg_error&)
+               {
+                       throw;
+               }
+               catch(...)
+               {
+                       CASPAR_THROW_EXCEPTION(ffmpeg_error() << boost::errinfo_nested_exception(boost::current_exception()));
+               }
+       }
+};
+
+filter::filter(const std::wstring& filters, const std::vector<PixelFormat>& pix_fmts) : impl_(new impl(filters, pix_fmts)){}
+filter::filter(filter&& other) : impl_(std::move(other.impl_)){}
+filter& filter::operator=(filter&& other){impl_ = std::move(other.impl_); return *this;}
+void filter::push(const std::shared_ptr<AVFrame>& frame){impl_->push(frame);}
+std::shared_ptr<AVFrame> filter::poll(){return impl_->poll();}
+std::wstring filter::filter_str() const{return impl_->filters_;}
+std::vector<spl::shared_ptr<AVFrame>> filter::poll_all()
+{      
+       std::vector<spl::shared_ptr<AVFrame>> frames;
+       for(auto frame = poll(); frame; frame = poll())
+               frames.push_back(spl::make_shared_ptr(frame));
+       return frames;
+}
+
 }}
\ No newline at end of file
index da472f0e45a9b64421f38e3b98028843d4c08660..ecac5e7a921d81b2ab7fbb719230504b032455dc 100644 (file)
@@ -1,97 +1,97 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-#include <boost/algorithm/string/case_conv.hpp>\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-struct AVFrame;\r
-enum PixelFormat;\r
-\r
-namespace caspar { namespace ffmpeg {\r
-\r
-static std::wstring append_filter(const std::wstring& filters, const std::wstring& filter)\r
-{\r
-       return filters + (filters.empty() ? L"" : L",") + filter;\r
-}\r
-\r
-class filter : boost::noncopyable\r
-{\r
-public:\r
-       filter(const std::wstring& filters = L"", const std::vector<PixelFormat>& pix_fmts = std::vector<PixelFormat>());\r
-       filter(filter&& other);\r
-       filter& operator=(filter&& other);\r
-\r
-       void push(const std::shared_ptr<AVFrame>& frame);\r
-       std::shared_ptr<AVFrame> poll();\r
-       std::vector<spl::shared_ptr<AVFrame>> poll_all();\r
-\r
-       std::wstring filter_str() const;\r
-                       \r
-       static bool is_double_rate(const std::wstring& filters)\r
-       {\r
-               if(boost::to_upper_copy(filters).find(L"YADIF=1") != std::string::npos)\r
-                       return true;\r
-       \r
-               if(boost::to_upper_copy(filters).find(L"YADIF=3") != std::string::npos)\r
-                       return true;\r
-\r
-               return false;\r
-       }\r
-\r
-       static bool is_deinterlacing(const std::wstring& filters)\r
-       {\r
-               if(boost::to_upper_copy(filters).find(L"YADIF") != std::string::npos)\r
-                       return true;    \r
-               return false;\r
-       }       \r
-       \r
-       static int delay(const std::wstring& filters)\r
-       {\r
-               return is_double_rate(filters) ? 1 : 0;\r
-       }\r
-\r
-       int delay() const\r
-       {\r
-               return delay(filter_str());\r
-       }\r
-\r
-       bool is_double_rate() const\r
-       {\r
-               return is_double_rate(filter_str());\r
-       }\r
-       \r
-       bool is_deinterlacing() const\r
-       {\r
-               return is_deinterlacing(filter_str());\r
-       }\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
+
+#include <string>
+#include <vector>
+
+struct AVFrame;
+enum PixelFormat;
+
+namespace caspar { namespace ffmpeg {
+
+static std::wstring append_filter(const std::wstring& filters, const std::wstring& filter)
+{
+       return filters + (filters.empty() ? L"" : L",") + filter;
+}
+
+class filter : boost::noncopyable
+{
+public:
+       filter(const std::wstring& filters = L"", const std::vector<PixelFormat>& pix_fmts = std::vector<PixelFormat>());
+       filter(filter&& other);
+       filter& operator=(filter&& other);
+
+       void push(const std::shared_ptr<AVFrame>& frame);
+       std::shared_ptr<AVFrame> poll();
+       std::vector<spl::shared_ptr<AVFrame>> poll_all();
+
+       std::wstring filter_str() const;
+                       
+       static bool is_double_rate(const std::wstring& filters)
+       {
+               if(boost::to_upper_copy(filters).find(L"YADIF=1") != std::string::npos)
+                       return true;
+       
+               if(boost::to_upper_copy(filters).find(L"YADIF=3") != std::string::npos)
+                       return true;
+
+               return false;
+       }
+
+       static bool is_deinterlacing(const std::wstring& filters)
+       {
+               if(boost::to_upper_copy(filters).find(L"YADIF") != std::string::npos)
+                       return true;    
+               return false;
+       }       
+       
+       static int delay(const std::wstring& filters)
+       {
+               return is_double_rate(filters) ? 1 : 0;
+       }
+
+       int delay() const
+       {
+               return delay(filter_str());
+       }
+
+       bool is_double_rate() const
+       {
+               return is_double_rate(filter_str());
+       }
+       
+       bool is_deinterlacing() const
+       {
+               return is_deinterlacing(filter_str());
+       }
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index 70bc454863ac9040cac4463457fe12702691fc94..d0b4adbbec9b1f64f96f49a5b46ab2017c36e349 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../StdAfx.h"\r
-\r
-#include "parallel_yadif.h"\r
-\r
-#include <common/log.h>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #include <libavfilter/avfilter.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-#include <tbb/parallel_for.h>\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <boost/thread/once.hpp>\r
-\r
-typedef struct {\r
-    int mode;\r
-    int parity;\r
-    int frame_pending;\r
-    int auto_enable;\r
-    AVFilterBufferRef *cur;\r
-    AVFilterBufferRef *next;\r
-    AVFilterBufferRef *prev;\r
-    AVFilterBufferRef *out;\r
-    void (*filter_line)(uint8_t *dst,\r
-                        uint8_t *prev, uint8_t *cur, uint8_t *next,\r
-                        int w, int prefs, int mrefs, int parity, int mode);\r
-    //const AVPixFmtDescriptor *csp;\r
-} YADIFContext;\r
-\r
-struct parallel_yadif_context\r
-{\r
-       struct arg\r
-       {\r
-               uint8_t *dst;\r
-               uint8_t *prev;\r
-               uint8_t *cur; \r
-               uint8_t *next; \r
-               int w; \r
-               int prefs; \r
-               int mrefs;\r
-               int parity;\r
-               int mode;\r
-       };\r
-\r
-       int                              size;\r
-       std::vector<arg> args;\r
-};\r
-\r
-void (*org_yadif_filter_line)(uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode) = 0;\r
-\r
-void parallel_yadif_filter_line(parallel_yadif_context& ctx, uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode)\r
-{\r
-       parallel_yadif_context::arg arg = {dst, prev, cur, next, w, prefs, mrefs, parity, mode};\r
-       ctx.args.push_back(arg);\r
-       \r
-       if(ctx.args.size() == ctx.size)\r
-       {               \r
-               tbb::parallel_for(tbb::blocked_range<size_t>(0, ctx.args.size()), [=](const tbb::blocked_range<size_t>& r)\r
-               {\r
-                       for(auto n = r.begin(); n != r.end(); ++n)\r
-                               org_yadif_filter_line(ctx.args[n].dst, ctx.args[n].prev, ctx.args[n].cur, ctx.args[n].next, ctx.args[n].w, ctx.args[n].prefs, ctx.args[n].mrefs, ctx.args[n].parity, ctx.args[n].mode);\r
-               });\r
-               ctx.args.clear();\r
-       }\r
-}\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-tbb::concurrent_bounded_queue<decltype(org_yadif_filter_line)> parallel_line_func_pool;\r
-std::array<parallel_yadif_context, 18> ctxs;\r
-\r
-#define RENAME(a) f ## a\r
-\r
-#define ff(x) \\r
-void RENAME(x)(uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode) \\r
-{\\r
-       parallel_yadif_filter_line(ctxs[x], dst, prev, cur, next, w, prefs, mrefs, parity, mode);\\r
-}\r
-\r
-ff(0); ff(1); ff(2); ff(3); ff(4); ff(5); ff(6); ff(7); ff(8); ff(9); ff(10); ff(11); ff(12); ff(13); ff(14); ff(15); ff(16); ff(17);\r
-\r
-void (*fs[])(uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode) = \r
-{f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17};\r
-\r
-\r
-void init_pool()\r
-{\r
-       for(int n = 0; n < sizeof(fs)/sizeof(fs[0]); ++n)\r
-               parallel_line_func_pool.push(fs[n]);\r
-}\r
-\r
-void return_parallel_yadif(void* func)\r
-{\r
-       if(func != nullptr)\r
-               parallel_line_func_pool.push(reinterpret_cast<decltype(fs[0])>(func));\r
-}\r
-\r
-std::shared_ptr<void> make_parallel_yadif(AVFilterContext* ctx)\r
-{\r
-       static boost::once_flag flag = BOOST_ONCE_INIT;\r
-       boost::call_once(&init_pool, flag);\r
-\r
-       YADIFContext* yadif = (YADIFContext*)ctx->priv;\r
-       org_yadif_filter_line = yadif->filter_line; // Data race is not a problem.\r
-       \r
-       decltype(org_yadif_filter_line) func = nullptr;\r
-       if(!parallel_line_func_pool.try_pop(func))      \r
-               CASPAR_LOG(warning) << "Not enough scalable-yadif context instances. Running non-scalable";\r
-       else\r
-       {\r
-               int index = 0;\r
-               while(index < sizeof(fs)/sizeof(fs[0]) && fs[index] != func)\r
-                       ++index;\r
-\r
-               ctxs[index].size = 0;\r
-               for (int y = 0; y < ctx->inputs[0]->h; y++)\r
-               {\r
-            if ((y ^ yadif->parity) & 1)\r
-                               ++ctxs[index].size;\r
-               }\r
-\r
-               yadif->filter_line = func;\r
-       }\r
-\r
-       return std::shared_ptr<void>(func, return_parallel_yadif);\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../StdAfx.h"
+
+#include "parallel_yadif.h"
+
+#include <common/log.h>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #include <libavfilter/avfilter.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+#include <tbb/parallel_for.h>
+#include <tbb/concurrent_queue.h>
+
+#include <boost/thread/once.hpp>
+
+typedef struct {
+    int mode;
+    int parity;
+    int frame_pending;
+    int auto_enable;
+    AVFilterBufferRef *cur;
+    AVFilterBufferRef *next;
+    AVFilterBufferRef *prev;
+    AVFilterBufferRef *out;
+    void (*filter_line)(uint8_t *dst,
+                        uint8_t *prev, uint8_t *cur, uint8_t *next,
+                        int w, int prefs, int mrefs, int parity, int mode);
+    //const AVPixFmtDescriptor *csp;
+} YADIFContext;
+
+struct parallel_yadif_context
+{
+       struct arg
+       {
+               uint8_t *dst;
+               uint8_t *prev;
+               uint8_t *cur; 
+               uint8_t *next; 
+               int w; 
+               int prefs; 
+               int mrefs;
+               int parity;
+               int mode;
+       };
+
+       int                              size;
+       std::vector<arg> args;
+};
+
+void (*org_yadif_filter_line)(uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode) = 0;
+
+void parallel_yadif_filter_line(parallel_yadif_context& ctx, uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode)
+{
+       parallel_yadif_context::arg arg = {dst, prev, cur, next, w, prefs, mrefs, parity, mode};
+       ctx.args.push_back(arg);
+       
+       if(ctx.args.size() == ctx.size)
+       {               
+               tbb::parallel_for(tbb::blocked_range<size_t>(0, ctx.args.size()), [=](const tbb::blocked_range<size_t>& r)
+               {
+                       for(auto n = r.begin(); n != r.end(); ++n)
+                               org_yadif_filter_line(ctx.args[n].dst, ctx.args[n].prev, ctx.args[n].cur, ctx.args[n].next, ctx.args[n].w, ctx.args[n].prefs, ctx.args[n].mrefs, ctx.args[n].parity, ctx.args[n].mode);
+               });
+               ctx.args.clear();
+       }
+}
+
+namespace caspar { namespace ffmpeg {
+       
+tbb::concurrent_bounded_queue<decltype(org_yadif_filter_line)> parallel_line_func_pool;
+std::array<parallel_yadif_context, 18> ctxs;
+
+#define RENAME(a) f ## a
+
+#define ff(x) \
+void RENAME(x)(uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode) \
+{\
+       parallel_yadif_filter_line(ctxs[x], dst, prev, cur, next, w, prefs, mrefs, parity, mode);\
+}
+
+ff(0); ff(1); ff(2); ff(3); ff(4); ff(5); ff(6); ff(7); ff(8); ff(9); ff(10); ff(11); ff(12); ff(13); ff(14); ff(15); ff(16); ff(17);
+
+void (*fs[])(uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode) = 
+{f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17};
+
+
+void init_pool()
+{
+       for(int n = 0; n < sizeof(fs)/sizeof(fs[0]); ++n)
+               parallel_line_func_pool.push(fs[n]);
+}
+
+void return_parallel_yadif(void* func)
+{
+       if(func != nullptr)
+               parallel_line_func_pool.push(reinterpret_cast<decltype(fs[0])>(func));
+}
+
+std::shared_ptr<void> make_parallel_yadif(AVFilterContext* ctx)
+{
+       static boost::once_flag flag = BOOST_ONCE_INIT;
+       boost::call_once(&init_pool, flag);
+
+       YADIFContext* yadif = (YADIFContext*)ctx->priv;
+       org_yadif_filter_line = yadif->filter_line; // Data race is not a problem.
+       
+       decltype(org_yadif_filter_line) func = nullptr;
+       if(!parallel_line_func_pool.try_pop(func))      
+               CASPAR_LOG(warning) << "Not enough scalable-yadif context instances. Running non-scalable";
+       else
+       {
+               int index = 0;
+               while(index < sizeof(fs)/sizeof(fs[0]) && fs[index] != func)
+                       ++index;
+
+               ctxs[index].size = 0;
+               for (int y = 0; y < ctx->inputs[0]->h; y++)
+               {
+            if ((y ^ yadif->parity) & 1)
+                               ++ctxs[index].size;
+               }
+
+               yadif->filter_line = func;
+       }
+
+       return std::shared_ptr<void>(func, return_parallel_yadif);
+}
+
 }}
\ No newline at end of file
index 6c2a3b89bc5dff71d9daf57128aa32b2bb69e144..6e8e9758865728c01c2e7df375d44efbf49a43a0 100644 (file)
@@ -1,32 +1,32 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <memory>\r
-\r
-struct AVFilterContext;\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-std::shared_ptr<void> make_parallel_yadif(AVFilterContext* ctx);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <memory>
+
+struct AVFilterContext;
+
+namespace caspar { namespace ffmpeg {
+       
+std::shared_ptr<void> make_parallel_yadif(AVFilterContext* ctx);
+
 }}
\ No newline at end of file
index aa35e0aa44a2e2044495acb1c6a243e2acfb7259..1b16d273a62707f3ee1f9fd3daf71257352a7981 100644 (file)
@@ -1,8 +1,8 @@
-#include "../../../StdAfx.h"\r
-\r
-#include "scalable_yadif.h"\r
-\r
-\r
+#include "../../../StdAfx.h"
+
+#include "scalable_yadif.h"
+
+
 /*
  * Copyright (C) 2006-2010 Michael Niedermayer <michaelni@gmx.at>
  *               2010      James Darnley <james.darnley@gmail.com>
@@ -21,7 +21,7 @@
  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-\r
+
 #pragma warning(push, 0)
 
 
@@ -372,9 +372,9 @@ int init(AVFilterContext *ctx, const char *args, void *opaque)
 
     if (args) sscanf(args, "%d:%d:%d", &yadif->mode, &yadif->parity, &yadif->auto_enable);
 
-       \r
-       auto module = LoadLibrary(L"avfilter-2.dll");\r
-       static std::shared_ptr<void> lib(module, FreeLibrary);\r
+       
+       auto module = LoadLibrary(L"avfilter-2.dll");
+       static std::shared_ptr<void> lib(module, FreeLibrary);
     yadif->filter_line = (decltype(yadif->filter_line))(GetProcAddress(module, "ff_yadif_filter_line_ssse3"));
 
     //yadif->filter_line = filter_line_c;
index e73405744149e1433975c4d7204ba219fd40c591..781bbf0dbd7d028aa58d94f21cd6b7a87de2f1b0 100644 (file)
@@ -1,23 +1,23 @@
-#pragma once\r
-\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
+#pragma once
+
+extern "C" 
+{
+       #define __STDC_CONSTANT_MACROS
        #define __STDC_LIMIT_MACROS
        #include <libavutil/cpu.h>
        #include <libavutil/common.h>
        #include <libavutil/pixdesc.h>
-       #include <libavfilter/avfilter.h>\r
-}\r
-\r
-int init(AVFilterContext *ctx, const char *args, void *opaque);\r
-void uninit(AVFilterContext *ctx);\r
-int query_formats(AVFilterContext *ctx);\r
-int poll_frame(AVFilterLink *link);\r
-int request_frame(AVFilterLink *link);\r
-void start_frame(AVFilterLink *link, AVFilterBufferRef *picref);\r
-void end_frame(AVFilterLink *link);\r
-void return_frame(AVFilterContext *ctx, int is_second);\r
-AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms, int w, int h);\r
-\r
+       #include <libavfilter/avfilter.h>
+}
+
+int init(AVFilterContext *ctx, const char *args, void *opaque);
+void uninit(AVFilterContext *ctx);
+int query_formats(AVFilterContext *ctx);
+int poll_frame(AVFilterLink *link);
+int request_frame(AVFilterLink *link);
+void start_frame(AVFilterLink *link, AVFilterBufferRef *picref);
+void end_frame(AVFilterLink *link);
+void return_frame(AVFilterContext *ctx, int is_second);
+AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms, int w, int h);
+
 void register_scalable_yadif();
\ No newline at end of file
index a77534b9a02bee69fd19e0c9c15e102dc56f23cd..a6611d37e7934e27e509dbeca597f43e0df953ac 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "input.h"\r
-\r
-#include "../util/util.h"\r
-#include "../../ffmpeg_error.h"\r
-\r
-#include <common/diagnostics/graph.h>\r
-#include <common/executor.h>\r
-#include <common/lock.h>\r
-#include <common/except.h>\r
-#include <common/log.h>\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <tbb/concurrent_queue.h>\r
-#include <tbb/atomic.h>\r
-#include <tbb/recursive_mutex.h>\r
-\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/thread/condition_variable.hpp>\r
-#include <boost/thread/mutex.hpp>\r
-#include <boost/thread/thread.hpp>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
-       #define __STDC_LIMIT_MACROS\r
-       #include <libavformat/avformat.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar { namespace ffmpeg {\r
-\r
-static const int MIN_FRAMES = 25;\r
-\r
-class stream\r
-{\r
-       stream(const stream&);\r
-       stream& operator=(const stream&);\r
-\r
-       typedef tbb::concurrent_bounded_queue<std::shared_ptr<AVPacket>>::size_type size_type;\r
-\r
-       int                                                                                                              index_;\r
-       tbb::concurrent_bounded_queue<std::shared_ptr<AVPacket>> packets_;\r
-public:\r
-\r
-       stream(int index) \r
-               : index_(index)\r
-       {\r
-       }\r
-       \r
-       void push(const std::shared_ptr<AVPacket>& packet)\r
-       {\r
-               if(packet && packet->data && packet->stream_index != index_)\r
-                       return;\r
-\r
-               packets_.push(packet);\r
-       }\r
-\r
-       bool try_pop(std::shared_ptr<AVPacket>& packet)\r
-       {\r
-               return packets_.try_pop(packet);\r
-       }\r
-\r
-       void clear()\r
-       {\r
-               std::shared_ptr<AVPacket> packet;\r
-               while(packets_.try_pop(packet));\r
-       }\r
-               \r
-       size_type size() const\r
-       {\r
-               return index_ != -1 ? packets_.size() : std::numeric_limits<size_type>::max();\r
-       }\r
-};\r
-               \r
-struct input::impl : boost::noncopyable\r
-{              \r
-       const spl::shared_ptr<diagnostics::graph>                                       graph_;\r
-\r
-       const spl::shared_ptr<AVFormatContext>                                          format_context_; // Destroy this last\r
-       const int                                                                                                       default_stream_index_;\r
-                       \r
-       const std::wstring                                                                                      filename_;\r
-       tbb::atomic<uint32_t>                                                                           start_;         \r
-       tbb::atomic<uint32_t>                                                                           length_;\r
-       tbb::atomic<bool>                                                                                       loop_;\r
-       double                                                                                                          fps_;\r
-       uint32_t                                                                                                        frame_number_;\r
-       \r
-       stream                                                                                                          video_stream_;\r
-       stream                                                                                                          audio_stream_;\r
-\r
-       boost::optional<uint32_t>                                                                       seek_target_;\r
-\r
-       tbb::atomic<bool>                                                                                       is_running_;\r
-       boost::mutex                                                                                            mutex_;\r
-       boost::condition_variable                                                                       cond_;\r
-       boost::thread                                                                                           thread_;\r
-       \r
-       impl(const spl::shared_ptr<diagnostics::graph> graph, const std::wstring& filename, const bool loop, const uint32_t start, const uint32_t length) \r
-               : graph_(graph)\r
-               , format_context_(open_input(filename))         \r
-               , default_stream_index_(av_find_default_stream_index(format_context_.get()))\r
-               , filename_(filename)\r
-               , frame_number_(0)\r
-               , fps_(read_fps(*format_context_, 0.0))\r
-               , video_stream_(av_find_best_stream(format_context_.get(), AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0))\r
-               , audio_stream_(av_find_best_stream(format_context_.get(), AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0))\r
-       {               \r
-               start_                  = start;\r
-               length_                 = length;\r
-               loop_                   = loop;\r
-               is_running_             = true;\r
-\r
-               if(start_ != 0)\r
-                       seek_target_ = start_;\r
-                                                                                                               \r
-               graph_->set_color("seek", diagnostics::color(1.0f, 0.5f, 0.0f));        \r
-               graph_->set_color("audio-buffer", diagnostics::color(0.7f, 0.4f, 0.4f));\r
-               graph_->set_color("video-buffer", diagnostics::color(1.0f, 1.0f, 0.0f));        \r
-               \r
-               for(int n = 0; n < 8; ++n)\r
-                       tick();\r
-\r
-               thread_ = boost::thread([this]{run();});\r
-       }\r
-\r
-       ~impl()\r
-       {\r
-               is_running_ = false;\r
-               cond_.notify_one();\r
-               thread_.join();\r
-       }\r
-       \r
-       bool try_pop_video(std::shared_ptr<AVPacket>& packet)\r
-       {                               \r
-               bool result = video_stream_.try_pop(packet);\r
-               if(result)\r
-                       cond_.notify_one();\r
-               \r
-               graph_->set_value("video-buffer", std::min(1.0, static_cast<double>(video_stream_.size()/MIN_FRAMES)));\r
-                               \r
-               return result;\r
-       }\r
-       \r
-       bool try_pop_audio(std::shared_ptr<AVPacket>& packet)\r
-       {                               \r
-               bool result = audio_stream_.try_pop(packet);\r
-               if(result)\r
-                       cond_.notify_one();\r
-                               \r
-               graph_->set_value("audio-buffer", std::min(1.0, static_cast<double>(audio_stream_.size()/MIN_FRAMES)));\r
-\r
-               return result;\r
-       }\r
-\r
-       void seek(uint32_t target)\r
-       {\r
-               {\r
-                       boost::lock_guard<boost::mutex> lock(mutex_);\r
-\r
-                       seek_target_ = target;\r
-                       video_stream_.clear();\r
-                       audio_stream_.clear();\r
-               }\r
-               \r
-               cond_.notify_one();\r
-       }\r
-               \r
-       std::wstring print() const\r
-       {\r
-               return L"ffmpeg_input[" + filename_ + L")]";\r
-       }\r
-\r
-private:\r
-       void internal_seek(uint32_t target)\r
-       {\r
-               graph_->set_tag("seek");        \r
-\r
-               CASPAR_LOG(debug) << print() << " Seeking: " << target;\r
-\r
-               int flags = AVSEEK_FLAG_FRAME;\r
-               if(target == 0)\r
-               {\r
-                       // Fix VP6 seeking\r
-                       int vid_stream_index = av_find_best_stream(format_context_.get(), AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);\r
-                       if(vid_stream_index >= 0)\r
-                       {\r
-                               auto codec_id = format_context_->streams[vid_stream_index]->codec->codec_id;\r
-                               if(codec_id == CODEC_ID_VP6A || codec_id == CODEC_ID_VP6F || codec_id == CODEC_ID_VP6)\r
-                                       flags = AVSEEK_FLAG_BYTE;\r
-                       }\r
-               }\r
-               \r
-               auto stream = format_context_->streams[default_stream_index_];\r
-               auto codec  = stream->codec;\r
-               auto fixed_target = (target*stream->time_base.den*codec->time_base.num)/(stream->time_base.num*codec->time_base.den)*codec->ticks_per_frame;\r
-               \r
-               THROW_ON_ERROR2(avformat_seek_file(format_context_.get(), default_stream_index_, std::numeric_limits<int64_t>::min(), fixed_target, fixed_target, 0), print());         \r
-               \r
-               video_stream_.push(nullptr);\r
-               audio_stream_.push(nullptr);\r
-       }\r
-\r
-       void tick()\r
-       {\r
-               if(seek_target_)                                \r
-               {\r
-                       internal_seek(*seek_target_);\r
-                       seek_target_.reset();\r
-               }\r
-\r
-               auto packet = create_packet();\r
-               \r
-               auto ret = av_read_frame(format_context_.get(), packet.get()); // packet is only valid until next call of av_read_frame. Use av_dup_packet to extend its life.  \r
-               \r
-               if(is_eof(ret))                                                                                                              \r
-               {\r
-                       video_stream_.push(packet);\r
-                       audio_stream_.push(packet);\r
-\r
-                       if(loop_)                       \r
-                               internal_seek(start_);                          \r
-               }\r
-               else\r
-               {               \r
-                       THROW_ON_ERROR(ret, "av_read_frame", print());\r
-                                       \r
-                       THROW_ON_ERROR2(av_dup_packet(packet.get()), print());\r
-                               \r
-                       // Make sure that the packet is correctly deallocated even if size and data is modified during decoding.\r
-                       const auto size = packet->size;\r
-                       const auto data = packet->data;\r
-                       \r
-                       packet = spl::shared_ptr<AVPacket>(packet.get(), [packet, size, data](AVPacket*)\r
-                       {\r
-                               packet->size = size;\r
-                               packet->data = data;                            \r
-                       });\r
-                                       \r
-                       const auto stream_time_base = format_context_->streams[packet->stream_index]->time_base;\r
-                       const auto packet_frame_number = static_cast<uint32_t>((static_cast<double>(packet->pts * stream_time_base.num)/stream_time_base.den)*fps_);\r
-\r
-                       if(packet->stream_index == default_stream_index_)\r
-                               frame_number_ = packet_frame_number;\r
-                                       \r
-                       if(packet_frame_number >= start_ && packet_frame_number < length_)\r
-                       {\r
-                               video_stream_.push(packet);\r
-                               audio_stream_.push(packet);\r
-                       }\r
-               }       \r
-                                               \r
-               graph_->set_value("video-buffer", std::min(1.0, static_cast<double>(video_stream_.size()/MIN_FRAMES)));\r
-               graph_->set_value("audio-buffer", std::min(1.0, static_cast<double>(audio_stream_.size()/MIN_FRAMES)));\r
-       }\r
-                       \r
-       bool full() const\r
-       {\r
-               return video_stream_.size() > MIN_FRAMES && audio_stream_.size() > MIN_FRAMES;\r
-       }\r
-\r
-       void run()\r
-       {\r
-               win32_exception::install_handler();\r
-\r
-               while(is_running_)\r
-               {\r
-                       try\r
-                       {\r
-                               boost::this_thread::sleep(boost::posix_time::milliseconds(1));\r
-                               \r
-                               {\r
-                                       boost::unique_lock<boost::mutex> lock(mutex_);\r
-\r
-                                       while(full() && !seek_target_ && is_running_)\r
-                                               cond_.wait(lock);\r
-                                       \r
-                                       tick();\r
-                               }\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                               is_running_ = false;\r
-                       }\r
-               }\r
-       }\r
-                       \r
-       bool is_eof(int ret)\r
-       {\r
-               #pragma warning (disable : 4146)\r
-               return ret == AVERROR_EOF || ret == AVERROR(EIO) || frame_number_ >= length_; // av_read_frame doesn't always correctly return AVERROR_EOF;\r
-       }\r
-};\r
-\r
-input::input(const spl::shared_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, uint32_t start, uint32_t length) \r
-       : impl_(new impl(graph, filename, loop, start, length)){}\r
-bool input::try_pop_video(std::shared_ptr<AVPacket>& packet){return impl_->try_pop_video(packet);}\r
-bool input::try_pop_audio(std::shared_ptr<AVPacket>& packet){return impl_->try_pop_audio(packet);}\r
-AVFormatContext& input::context(){return *impl_->format_context_;}\r
-void input::loop(bool value){impl_->loop_ = value;}\r
-bool input::loop() const{return impl_->loop_;}\r
-void input::seek(uint32_t target){impl_->seek(target);}\r
-void input::start(uint32_t value){impl_->start_ = value;}\r
-uint32_t input::start() const{return impl_->start_;}\r
-void input::length(uint32_t value){impl_->length_ = value;}\r
-uint32_t input::length() const{return impl_->length_;}\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "input.h"
+
+#include "../util/util.h"
+#include "../../ffmpeg_error.h"
+
+#include <common/diagnostics/graph.h>
+#include <common/executor.h>
+#include <common/lock.h>
+#include <common/except.h>
+#include <common/log.h>
+
+#include <core/video_format.h>
+
+#include <tbb/concurrent_queue.h>
+#include <tbb/atomic.h>
+#include <tbb/recursive_mutex.h>
+
+#include <boost/range/algorithm.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #define __STDC_CONSTANT_MACROS
+       #define __STDC_LIMIT_MACROS
+       #include <libavformat/avformat.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+namespace caspar { namespace ffmpeg {
+
+static const int MIN_FRAMES = 25;
+
+class stream
+{
+       stream(const stream&);
+       stream& operator=(const stream&);
+
+       typedef tbb::concurrent_bounded_queue<std::shared_ptr<AVPacket>>::size_type size_type;
+
+       int                                                                                                              index_;
+       tbb::concurrent_bounded_queue<std::shared_ptr<AVPacket>> packets_;
+public:
+
+       stream(int index) 
+               : index_(index)
+       {
+       }
+       
+       void push(const std::shared_ptr<AVPacket>& packet)
+       {
+               if(packet && packet->data && packet->stream_index != index_)
+                       return;
+
+               packets_.push(packet);
+       }
+
+       bool try_pop(std::shared_ptr<AVPacket>& packet)
+       {
+               return packets_.try_pop(packet);
+       }
+
+       void clear()
+       {
+               std::shared_ptr<AVPacket> packet;
+               while(packets_.try_pop(packet));
+       }
+               
+       size_type size() const
+       {
+               return index_ != -1 ? packets_.size() : std::numeric_limits<size_type>::max();
+       }
+};
+               
+struct input::impl : boost::noncopyable
+{              
+       const spl::shared_ptr<diagnostics::graph>                                       graph_;
+
+       const spl::shared_ptr<AVFormatContext>                                          format_context_; // Destroy this last
+       const int                                                                                                       default_stream_index_;
+                       
+       const std::wstring                                                                                      filename_;
+       tbb::atomic<uint32_t>                                                                           start_;         
+       tbb::atomic<uint32_t>                                                                           length_;
+       tbb::atomic<bool>                                                                                       loop_;
+       double                                                                                                          fps_;
+       uint32_t                                                                                                        frame_number_;
+       
+       stream                                                                                                          video_stream_;
+       stream                                                                                                          audio_stream_;
+
+       boost::optional<uint32_t>                                                                       seek_target_;
+
+       tbb::atomic<bool>                                                                                       is_running_;
+       boost::mutex                                                                                            mutex_;
+       boost::condition_variable                                                                       cond_;
+       boost::thread                                                                                           thread_;
+       
+       impl(const spl::shared_ptr<diagnostics::graph> graph, const std::wstring& filename, const bool loop, const uint32_t start, const uint32_t length) 
+               : graph_(graph)
+               , format_context_(open_input(filename))         
+               , default_stream_index_(av_find_default_stream_index(format_context_.get()))
+               , filename_(filename)
+               , frame_number_(0)
+               , fps_(read_fps(*format_context_, 0.0))
+               , video_stream_(av_find_best_stream(format_context_.get(), AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0))
+               , audio_stream_(av_find_best_stream(format_context_.get(), AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0))
+       {               
+               start_                  = start;
+               length_                 = length;
+               loop_                   = loop;
+               is_running_             = true;
+
+               if(start_ != 0)
+                       seek_target_ = start_;
+                                                                                                               
+               graph_->set_color("seek", diagnostics::color(1.0f, 0.5f, 0.0f));        
+               graph_->set_color("audio-buffer", diagnostics::color(0.7f, 0.4f, 0.4f));
+               graph_->set_color("video-buffer", diagnostics::color(1.0f, 1.0f, 0.0f));        
+               
+               for(int n = 0; n < 8; ++n)
+                       tick();
+
+               thread_ = boost::thread([this]{run();});
+       }
+
+       ~impl()
+       {
+               is_running_ = false;
+               cond_.notify_one();
+               thread_.join();
+       }
+       
+       bool try_pop_video(std::shared_ptr<AVPacket>& packet)
+       {                               
+               bool result = video_stream_.try_pop(packet);
+               if(result)
+                       cond_.notify_one();
+               
+               graph_->set_value("video-buffer", std::min(1.0, static_cast<double>(video_stream_.size()/MIN_FRAMES)));
+                               
+               return result;
+       }
+       
+       bool try_pop_audio(std::shared_ptr<AVPacket>& packet)
+       {                               
+               bool result = audio_stream_.try_pop(packet);
+               if(result)
+                       cond_.notify_one();
+                               
+               graph_->set_value("audio-buffer", std::min(1.0, static_cast<double>(audio_stream_.size()/MIN_FRAMES)));
+
+               return result;
+       }
+
+       void seek(uint32_t target)
+       {
+               {
+                       boost::lock_guard<boost::mutex> lock(mutex_);
+
+                       seek_target_ = target;
+                       video_stream_.clear();
+                       audio_stream_.clear();
+               }
+               
+               cond_.notify_one();
+       }
+               
+       std::wstring print() const
+       {
+               return L"ffmpeg_input[" + filename_ + L")]";
+       }
+
+private:
+       void internal_seek(uint32_t target)
+       {
+               graph_->set_tag("seek");        
+
+               CASPAR_LOG(debug) << print() << " Seeking: " << target;
+
+               int flags = AVSEEK_FLAG_FRAME;
+               if(target == 0)
+               {
+                       // Fix VP6 seeking
+                       int vid_stream_index = av_find_best_stream(format_context_.get(), AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);
+                       if(vid_stream_index >= 0)
+                       {
+                               auto codec_id = format_context_->streams[vid_stream_index]->codec->codec_id;
+                               if(codec_id == CODEC_ID_VP6A || codec_id == CODEC_ID_VP6F || codec_id == CODEC_ID_VP6)
+                                       flags = AVSEEK_FLAG_BYTE;
+                       }
+               }
+               
+               auto stream = format_context_->streams[default_stream_index_];
+               auto codec  = stream->codec;
+               auto fixed_target = (target*stream->time_base.den*codec->time_base.num)/(stream->time_base.num*codec->time_base.den)*codec->ticks_per_frame;
+               
+               THROW_ON_ERROR2(avformat_seek_file(format_context_.get(), default_stream_index_, std::numeric_limits<int64_t>::min(), fixed_target, fixed_target, 0), print());         
+               
+               video_stream_.push(nullptr);
+               audio_stream_.push(nullptr);
+       }
+
+       void tick()
+       {
+               if(seek_target_)                                
+               {
+                       internal_seek(*seek_target_);
+                       seek_target_.reset();
+               }
+
+               auto packet = create_packet();
+               
+               auto ret = av_read_frame(format_context_.get(), packet.get()); // packet is only valid until next call of av_read_frame. Use av_dup_packet to extend its life.  
+               
+               if(is_eof(ret))                                                                                                              
+               {
+                       video_stream_.push(packet);
+                       audio_stream_.push(packet);
+
+                       if(loop_)                       
+                               internal_seek(start_);                          
+               }
+               else
+               {               
+                       THROW_ON_ERROR(ret, "av_read_frame", print());
+                                       
+                       THROW_ON_ERROR2(av_dup_packet(packet.get()), print());
+                               
+                       // Make sure that the packet is correctly deallocated even if size and data is modified during decoding.
+                       const auto size = packet->size;
+                       const auto data = packet->data;
+                       
+                       packet = spl::shared_ptr<AVPacket>(packet.get(), [packet, size, data](AVPacket*)
+                       {
+                               packet->size = size;
+                               packet->data = data;                            
+                       });
+                                       
+                       const auto stream_time_base = format_context_->streams[packet->stream_index]->time_base;
+                       const auto packet_frame_number = static_cast<uint32_t>((static_cast<double>(packet->pts * stream_time_base.num)/stream_time_base.den)*fps_);
+
+                       if(packet->stream_index == default_stream_index_)
+                               frame_number_ = packet_frame_number;
+                                       
+                       if(packet_frame_number >= start_ && packet_frame_number < length_)
+                       {
+                               video_stream_.push(packet);
+                               audio_stream_.push(packet);
+                       }
+               }       
+                                               
+               graph_->set_value("video-buffer", std::min(1.0, static_cast<double>(video_stream_.size()/MIN_FRAMES)));
+               graph_->set_value("audio-buffer", std::min(1.0, static_cast<double>(audio_stream_.size()/MIN_FRAMES)));
+       }
+                       
+       bool full() const
+       {
+               return video_stream_.size() > MIN_FRAMES && audio_stream_.size() > MIN_FRAMES;
+       }
+
+       void run()
+       {
+               win32_exception::install_handler();
+
+               while(is_running_)
+               {
+                       try
+                       {
+                               boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+                               
+                               {
+                                       boost::unique_lock<boost::mutex> lock(mutex_);
+
+                                       while(full() && !seek_target_ && is_running_)
+                                               cond_.wait(lock);
+                                       
+                                       tick();
+                               }
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                               is_running_ = false;
+                       }
+               }
+       }
+                       
+       bool is_eof(int ret)
+       {
+               #pragma warning (disable : 4146)
+               return ret == AVERROR_EOF || ret == AVERROR(EIO) || frame_number_ >= length_; // av_read_frame doesn't always correctly return AVERROR_EOF;
+       }
+};
+
+input::input(const spl::shared_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, uint32_t start, uint32_t length) 
+       : impl_(new impl(graph, filename, loop, start, length)){}
+bool input::try_pop_video(std::shared_ptr<AVPacket>& packet){return impl_->try_pop_video(packet);}
+bool input::try_pop_audio(std::shared_ptr<AVPacket>& packet){return impl_->try_pop_audio(packet);}
+AVFormatContext& input::context(){return *impl_->format_context_;}
+void input::loop(bool value){impl_->loop_ = value;}
+bool input::loop() const{return impl_->loop_;}
+void input::seek(uint32_t target){impl_->seek(target);}
+void input::start(uint32_t value){impl_->start_ = value;}
+uint32_t input::start() const{return impl_->start_;}
+void input::length(uint32_t value){impl_->length_ = value;}
+uint32_t input::length() const{return impl_->length_;}
+}}
index e13ccd28887e51569a2d91f12822e76770e4072e..7bba5aa3af3a4ccb8f02462e7b1398f9308b0c1e 100644 (file)
@@ -1,71 +1,71 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <memory>\r
-#include <string>\r
-#include <cstdint>\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-struct AVFormatContext;\r
-struct AVPacket;\r
-\r
-namespace caspar {\r
-\r
-namespace diagnostics {\r
-\r
-class graph;\r
-\r
-}\r
-        \r
-namespace ffmpeg {\r
-\r
-class input : boost::noncopyable\r
-{\r
-public:\r
-       explicit input(const spl::shared_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, uint32_t start, uint32_t length);\r
-\r
-       bool            try_pop_video(std::shared_ptr<AVPacket>& packet);\r
-       bool            try_pop_audio(std::shared_ptr<AVPacket>& packet);\r
-\r
-       void            loop(bool value);\r
-       bool            loop() const;\r
-\r
-       void            start(uint32_t value);\r
-       uint32_t        start() const;\r
-\r
-       void            length(uint32_t value);\r
-       uint32_t        length() const;\r
-\r
-       void            seek(uint32_t target);\r
-\r
-       AVFormatContext& context();\r
-private:\r
-       struct impl;\r
-       std::shared_ptr<impl> impl_;\r
-};\r
-\r
-       \r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <memory>
+#include <string>
+#include <cstdint>
+
+#include <boost/noncopyable.hpp>
+
+struct AVFormatContext;
+struct AVPacket;
+
+namespace caspar {
+
+namespace diagnostics {
+
+class graph;
+
+}
+        
+namespace ffmpeg {
+
+class input : boost::noncopyable
+{
+public:
+       explicit input(const spl::shared_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, uint32_t start, uint32_t length);
+
+       bool            try_pop_video(std::shared_ptr<AVPacket>& packet);
+       bool            try_pop_audio(std::shared_ptr<AVPacket>& packet);
+
+       void            loop(bool value);
+       bool            loop() const;
+
+       void            start(uint32_t value);
+       uint32_t        start() const;
+
+       void            length(uint32_t value);
+       uint32_t        length() const;
+
+       void            seek(uint32_t target);
+
+       AVFormatContext& context();
+private:
+       struct impl;
+       std::shared_ptr<impl> impl_;
+};
+
+       
+}}
index 99da41372e8286a7ed7e4d3731283b61c93e2516..78d4fd1f7048b774ca6dc4919e7406ff13eda74e 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <ostream>\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-enum display_mode\r
-{\r
-       simple,\r
-       duplicate,\r
-       half,\r
-       interlace,\r
-       deinterlace_bob,\r
-       deinterlace_bob_reinterlace,\r
-       deinterlace,\r
-       count,\r
-       invalid\r
-};\r
-\r
-template< typename CharT, typename TraitsT >\r
-std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream<CharT, TraitsT>& o, display_mode value)\r
-{      \r
-       switch(value)\r
-       {\r
-               case simple:                                            return o << L"simple";\r
-               case duplicate:                                         return o << L"duplicate";\r
-               case half:                                                      return o << L"half";\r
-               case interlace:                                         return o << L"interlace";\r
-               case deinterlace_bob:                           return o << L"deinterlace_bob";\r
-               case deinterlace_bob_reinterlace:       return o << L"deinterlace_bob_reinterlace";\r
-               case deinterlace:                                       return o << L"deinterlace";\r
-               default:                                                        return o << L"invalid";\r
-       }\r
-}\r
-\r
-static display_mode get_display_mode(const core::field_mode in_mode, double in_fps, const core::field_mode out_mode, double out_fps)\r
-{              \r
-       static const auto epsilon = 2.0;\r
-\r
-       if(in_fps < 20.0 || in_fps > 80.0)\r
-       {\r
-               //if(out_mode != core::field_mode::progressive && in_mode == core::field_mode::progressive)\r
-               //      return display_mode::interlace;\r
-               \r
-               if(out_mode == core::field_mode::progressive && in_mode != core::field_mode::progressive)\r
-               {\r
-                       if(in_fps < 35.0)\r
-                               return display_mode::deinterlace;\r
-                       else\r
-                               return display_mode::deinterlace_bob;\r
-               }\r
-       }\r
-\r
-       if(std::abs(in_fps - out_fps) < epsilon)\r
-       {\r
-               if(in_mode != core::field_mode::progressive && out_mode == core::field_mode::progressive)\r
-                       return display_mode::deinterlace;\r
-               //else if(in_mode == core::field_mode::progressive && out_mode != core::field_mode::progressive)\r
-               //      simple(); // interlace_duplicate();\r
-               else\r
-                       return display_mode::simple;\r
-       }\r
-       else if(std::abs(in_fps/2.0 - out_fps) < epsilon)\r
-       {\r
-               if(in_mode != core::field_mode::progressive)\r
-                       return display_mode::invalid;\r
-\r
-               if(out_mode != core::field_mode::progressive)\r
-                       return display_mode::interlace;\r
-               else\r
-                       return display_mode::half;\r
-       }\r
-       else if(std::abs(in_fps - out_fps/2.0) < epsilon)\r
-       {\r
-               if(out_mode != core::field_mode::progressive)\r
-                       return display_mode::invalid;\r
-\r
-               if(in_mode != core::field_mode::progressive)\r
-                       return display_mode::deinterlace_bob;\r
-               else\r
-                       return display_mode::duplicate;\r
-       }\r
-\r
-       return display_mode::invalid;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <core/video_format.h>
+
+#include <ostream>
+
+namespace caspar { namespace ffmpeg {
+       
+enum display_mode
+{
+       simple,
+       duplicate,
+       half,
+       interlace,
+       deinterlace_bob,
+       deinterlace_bob_reinterlace,
+       deinterlace,
+       count,
+       invalid
+};
+
+template< typename CharT, typename TraitsT >
+std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream<CharT, TraitsT>& o, display_mode value)
+{      
+       switch(value)
+       {
+               case simple:                                            return o << L"simple";
+               case duplicate:                                         return o << L"duplicate";
+               case half:                                                      return o << L"half";
+               case interlace:                                         return o << L"interlace";
+               case deinterlace_bob:                           return o << L"deinterlace_bob";
+               case deinterlace_bob_reinterlace:       return o << L"deinterlace_bob_reinterlace";
+               case deinterlace:                                       return o << L"deinterlace";
+               default:                                                        return o << L"invalid";
+       }
+}
+
+static display_mode get_display_mode(const core::field_mode in_mode, double in_fps, const core::field_mode out_mode, double out_fps)
+{              
+       static const auto epsilon = 2.0;
+
+       if(in_fps < 20.0 || in_fps > 80.0)
+       {
+               //if(out_mode != core::field_mode::progressive && in_mode == core::field_mode::progressive)
+               //      return display_mode::interlace;
+               
+               if(out_mode == core::field_mode::progressive && in_mode != core::field_mode::progressive)
+               {
+                       if(in_fps < 35.0)
+                               return display_mode::deinterlace;
+                       else
+                               return display_mode::deinterlace_bob;
+               }
+       }
+
+       if(std::abs(in_fps - out_fps) < epsilon)
+       {
+               if(in_mode != core::field_mode::progressive && out_mode == core::field_mode::progressive)
+                       return display_mode::deinterlace;
+               //else if(in_mode == core::field_mode::progressive && out_mode != core::field_mode::progressive)
+               //      simple(); // interlace_duplicate();
+               else
+                       return display_mode::simple;
+       }
+       else if(std::abs(in_fps/2.0 - out_fps) < epsilon)
+       {
+               if(in_mode != core::field_mode::progressive)
+                       return display_mode::invalid;
+
+               if(out_mode != core::field_mode::progressive)
+                       return display_mode::interlace;
+               else
+                       return display_mode::half;
+       }
+       else if(std::abs(in_fps - out_fps/2.0) < epsilon)
+       {
+               if(out_mode != core::field_mode::progressive)
+                       return display_mode::invalid;
+
+               if(in_mode != core::field_mode::progressive)
+                       return display_mode::deinterlace_bob;
+               else
+                       return display_mode::duplicate;
+       }
+
+       return display_mode::invalid;
+}
+
 }}
\ No newline at end of file
index 463ced26b4a060818e34ddb602c7b591d3bc3aec..36b747a0e788450f8b1f653e8586d5b96d89a767 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../StdAfx.h"\r
-\r
-#include "frame_muxer.h"\r
-\r
-#include "../filter/filter.h"\r
-#include "../util/util.h"\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/frame/draw_frame.h>\r
-#include <core/frame/frame_transform.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/frame.h>\r
-\r
-#include <common/env.h>\r
-#include <common/except.h>\r
-#include <common/log.h>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
-       #define __STDC_LIMIT_MACROS\r
-       #include <libavcodec/avcodec.h>\r
-       #include <libavformat/avformat.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-#include <common/assert.h>\r
-#include <boost/foreach.hpp>\r
-#include <boost/range/algorithm_ext/push_back.hpp>\r
-#include <boost/algorithm/string/predicate.hpp>\r
-\r
-#include <deque>\r
-#include <queue>\r
-#include <vector>\r
-\r
-using namespace caspar::core;\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-struct frame_muxer::impl : boost::noncopyable\r
-{      \r
-       std::queue<core::mutable_frame>                                 video_stream_;\r
-       core::audio_buffer                                                              audio_stream_;\r
-       std::queue<draw_frame>                                                  frame_buffer_;\r
-       display_mode                                                                    display_mode_;\r
-       const double                                                                    in_fps_;\r
-       const video_format_desc                                                 format_desc_;\r
-       \r
-       std::vector<int>                                                                audio_cadence_;\r
-                       \r
-       spl::shared_ptr<core::frame_factory>                    frame_factory_;\r
-       \r
-       filter                                                                                  filter_;\r
-       const std::wstring                                                              filter_str_;\r
-       bool                                                                                    force_deinterlacing_;\r
-               \r
-       impl(double in_fps, const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::wstring& filter_str)\r
-               : display_mode_(display_mode::invalid)\r
-               , in_fps_(in_fps)\r
-               , format_desc_(format_desc)\r
-               , audio_cadence_(format_desc_.audio_cadence)\r
-               , frame_factory_(frame_factory)\r
-               , filter_str_(filter_str)\r
-               , force_deinterlacing_(env::properties().get(L"configuration.force-deinterlace", true))\r
-       {               \r
-               // Note: Uses 1 step rotated cadence for 1001 modes (1602, 1602, 1601, 1602, 1601)\r
-               // This cadence fills the audio mixer most optimally.\r
-               boost::range::rotate(audio_cadence_, std::end(audio_cadence_)-1);\r
-       }\r
-       \r
-       void push_video(const std::shared_ptr<AVFrame>& video)\r
-       {               \r
-               if(!video)\r
-                       return;\r
-\r
-               if(!video->data[0])\r
-               {\r
-                       auto empty_frame = frame_factory_->create_frame(this, core::pixel_format_desc(core::pixel_format::invalid));\r
-                       video_stream_.push(std::move(empty_frame));\r
-                       display_mode_ = display_mode::simple;\r
-               }\r
-               else\r
-               {\r
-                       if(display_mode_ == display_mode::invalid)\r
-                               update_display_mode(video);\r
-                               \r
-                       filter_.push(video);\r
-                       BOOST_FOREACH(auto& av_frame, filter_.poll_all())                       \r
-                               video_stream_.push(make_frame(this, av_frame, format_desc_.fps, *frame_factory_));                      \r
-               }\r
-\r
-               merge();\r
-       }\r
-       \r
-       void push_audio(const std::shared_ptr<AVFrame>& audio)\r
-       {\r
-               if(!audio)\r
-                       return;\r
-\r
-               if(!audio->data[0])             \r
-               {\r
-                       boost::range::push_back(audio_stream_, core::audio_buffer(audio_cadence_.front(), 0));  \r
-               }\r
-               else\r
-               {\r
-                       auto ptr = reinterpret_cast<int32_t*>(audio->data[0]);\r
-                       audio_stream_.insert(audio_stream_.end(), ptr, ptr + audio->linesize[0]/sizeof(int32_t));\r
-               }\r
-\r
-               merge();\r
-       }\r
-       \r
-       bool video_ready() const\r
-       {               \r
-               switch(display_mode_)\r
-               {\r
-               case display_mode::deinterlace_bob_reinterlace:                                 \r
-               case display_mode::interlace:   \r
-               case display_mode::half:\r
-                       return video_stream_.size() >= 2;\r
-               default:                                                                                \r
-                       return video_stream_.size() >= 1;\r
-               }\r
-       }\r
-       \r
-       bool audio_ready() const\r
-       {\r
-               switch(display_mode_)\r
-               {\r
-               case display_mode::duplicate:                                   \r
-                       return audio_stream_.size() >= static_cast<size_t>(audio_cadence_[0] + audio_cadence_[1 % audio_cadence_.size()]);\r
-               default:                                                                                \r
-                       return audio_stream_.size() >= static_cast<size_t>(audio_cadence_.front());\r
-               }\r
-       }\r
-\r
-       bool empty() const\r
-       {\r
-               return frame_buffer_.empty();\r
-       }\r
-\r
-       core::draw_frame front() const\r
-       {\r
-               return frame_buffer_.front();\r
-       }\r
-\r
-       void pop()\r
-       {\r
-               frame_buffer_.pop();\r
-       }\r
-               \r
-       void merge()\r
-       {\r
-               while(video_ready() && audio_ready() && display_mode_ != display_mode::invalid)\r
-               {                               \r
-                       auto frame1                     = pop_video();\r
-                       frame1.audio_data()     = pop_audio();\r
-\r
-                       switch(display_mode_)\r
-                       {\r
-                       case display_mode::simple:                                              \r
-                       case display_mode::deinterlace_bob:                             \r
-                       case display_mode::deinterlace: \r
-                               {\r
-                                       frame_buffer_.push(core::draw_frame(std::move(frame1)));\r
-                                       break;\r
-                               }\r
-                       case display_mode::interlace:                                   \r
-                       case display_mode::deinterlace_bob_reinterlace: \r
-                               {                               \r
-                                       auto frame2 = pop_video();\r
-\r
-                                       frame_buffer_.push(core::draw_frame::interlace(\r
-                                               core::draw_frame(std::move(frame1)),\r
-                                               core::draw_frame(std::move(frame2)),\r
-                                               format_desc_.field_mode));      \r
-                                       break;\r
-                               }\r
-                       case display_mode::duplicate:   \r
-                               {\r
-                                       boost::range::push_back(frame1.audio_data(), pop_audio());\r
-\r
-                                       auto draw_frame = core::draw_frame(std::move(frame1));\r
-                                       frame_buffer_.push(draw_frame);\r
-                                       frame_buffer_.push(draw_frame);\r
-                                       break;\r
-                               }\r
-                       case display_mode::half:        \r
-                               {                               \r
-                                       pop_video(); // Throw away\r
-\r
-                                       frame_buffer_.push(core::draw_frame(std::move(frame1)));\r
-                                       break;\r
-                               }\r
-                       default:\r
-                               CASPAR_THROW_EXCEPTION(invalid_operation());\r
-                       }\r
-               }\r
-       }\r
-       \r
-       core::mutable_frame pop_video()\r
-       {\r
-               auto frame = std::move(video_stream_.front());\r
-               video_stream_.pop();            \r
-               return std::move(frame);\r
-       }\r
-\r
-       core::audio_buffer pop_audio()\r
-       {\r
-               if(audio_stream_.size() < audio_cadence_.front())\r
-                       CASPAR_THROW_EXCEPTION(out_of_range());\r
-\r
-               auto begin = audio_stream_.begin();\r
-               auto end   = begin + audio_cadence_.front();\r
-\r
-               core::audio_buffer samples(begin, end);\r
-               audio_stream_.erase(begin, end);\r
-               \r
-               boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
-\r
-               return samples;\r
-       }\r
-                               \r
-       void update_display_mode(const std::shared_ptr<AVFrame>& frame)\r
-       {\r
-               std::wstring filter_str = filter_str_;\r
-\r
-               display_mode_ = display_mode::simple;\r
-\r
-               auto mode = get_mode(*frame);\r
-               if(mode == core::field_mode::progressive && frame->height < 720 && in_fps_ < 50.0) // SD frames are interlaced. Probably incorrect meta-data. Fix it.\r
-                       mode = core::field_mode::upper;\r
-\r
-               auto fps  = in_fps_;\r
-\r
-               if(filter::is_deinterlacing(filter_str_))\r
-                       mode = core::field_mode::progressive;\r
-\r
-               if(filter::is_double_rate(filter_str_))\r
-                       fps *= 2;\r
-                       \r
-               display_mode_ = get_display_mode(mode, fps, format_desc_.field_mode, format_desc_.fps);\r
-                       \r
-               if((frame->height != 480 || format_desc_.height != 486) && // don't deinterlace for NTSC DV\r
-                               display_mode_ == display_mode::simple && mode != core::field_mode::progressive && format_desc_.field_mode != core::field_mode::progressive && \r
-                               frame->height != format_desc_.height)\r
-               {\r
-                       display_mode_ = display_mode::deinterlace_bob_reinterlace; // The frame will most likely be scaled, we need to deinterlace->reinterlace \r
-               }\r
-\r
-               // ALWAYS de-interlace, until we have GPU de-interlacing.\r
-               if(force_deinterlacing_ && frame->interlaced_frame && display_mode_ != display_mode::deinterlace_bob && display_mode_ != display_mode::deinterlace)\r
-                       display_mode_ = display_mode::deinterlace_bob_reinterlace;\r
-               \r
-               if(display_mode_ == display_mode::deinterlace)\r
-                       filter_str = append_filter(filter_str, L"YADIF=0:-1");\r
-               else if(display_mode_ == display_mode::deinterlace_bob || display_mode_ == display_mode::deinterlace_bob_reinterlace)\r
-                       filter_str = append_filter(filter_str, L"YADIF=1:-1");\r
-\r
-               if(display_mode_ == display_mode::invalid)\r
-               {\r
-                       CASPAR_LOG(warning) << L"[frame_muxer] Auto-transcode: Failed to detect display-mode.";\r
-                       display_mode_ = display_mode::simple;\r
-               }\r
-\r
-               if(frame->height == 480) // NTSC DV\r
-               {\r
-                       auto pad_str = L"PAD=" + boost::lexical_cast<std::wstring>(frame->width) + L":486:0:2:black";\r
-                       filter_str = append_filter(filter_str, pad_str);\r
-               }\r
-\r
-               filter_ = filter(filter_str);\r
-               CASPAR_LOG(info) << L"[frame_muxer] " << display_mode_ << L" " << print_mode(frame->width, frame->height, in_fps_, frame->interlaced_frame > 0);\r
-       }\r
-       \r
-       uint32_t calc_nb_frames(uint32_t nb_frames) const\r
-       {\r
-               uint64_t nb_frames2 = nb_frames;\r
-               \r
-               if(filter_.is_double_rate()) // Take into account transformations in filter.\r
-                       nb_frames2 *= 2;\r
-\r
-               switch(display_mode_) // Take into account transformation in run.\r
-               {\r
-               case display_mode::deinterlace_bob_reinterlace:\r
-               case display_mode::interlace:   \r
-               case display_mode::half:\r
-                       nb_frames2 /= 2;\r
-                       break;\r
-               case display_mode::duplicate:\r
-                       nb_frames2 *= 2;\r
-                       break;\r
-               }\r
-\r
-               return static_cast<uint32_t>(nb_frames2);\r
-       }\r
-\r
-       void clear()\r
-       {\r
-               while(!video_stream_.empty())\r
-                       video_stream_.pop();    \r
-\r
-               audio_stream_.clear();\r
-\r
-               while(!frame_buffer_.empty())\r
-                       frame_buffer_.pop();\r
-\r
-               filter_ = filter(filter_.filter_str());\r
-       }\r
-};\r
-\r
-frame_muxer::frame_muxer(double in_fps, const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::wstring& filter)\r
-       : impl_(new impl(in_fps, frame_factory, format_desc, filter)){}\r
-void frame_muxer::push_video(const std::shared_ptr<AVFrame>& frame){impl_->push_video(frame);}\r
-void frame_muxer::push_audio(const std::shared_ptr<AVFrame>& frame){impl_->push_audio(frame);}\r
-bool frame_muxer::empty() const{return impl_->empty();}\r
-core::draw_frame frame_muxer::front() const{return impl_->front();}\r
-void frame_muxer::pop(){return impl_->pop();}\r
-void frame_muxer::clear(){impl_->clear();}\r
-uint32_t frame_muxer::calc_nb_frames(uint32_t nb_frames) const {return impl_->calc_nb_frames(nb_frames);}\r
-bool frame_muxer::video_ready() const{return impl_->video_ready();}\r
-bool frame_muxer::audio_ready() const{return impl_->audio_ready();}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../StdAfx.h"
+
+#include "frame_muxer.h"
+
+#include "../filter/filter.h"
+#include "../util/util.h"
+
+#include <core/producer/frame_producer.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_transform.h>
+#include <core/frame/pixel_format.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/frame.h>
+
+#include <common/env.h>
+#include <common/except.h>
+#include <common/log.h>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #define __STDC_CONSTANT_MACROS
+       #define __STDC_LIMIT_MACROS
+       #include <libavcodec/avcodec.h>
+       #include <libavformat/avformat.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+#include <common/assert.h>
+#include <boost/foreach.hpp>
+#include <boost/range/algorithm_ext/push_back.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+
+#include <deque>
+#include <queue>
+#include <vector>
+
+using namespace caspar::core;
+
+namespace caspar { namespace ffmpeg {
+       
+struct frame_muxer::impl : boost::noncopyable
+{      
+       std::queue<core::mutable_frame>                                 video_stream_;
+       core::audio_buffer                                                              audio_stream_;
+       std::queue<draw_frame>                                                  frame_buffer_;
+       display_mode                                                                    display_mode_;
+       const double                                                                    in_fps_;
+       const video_format_desc                                                 format_desc_;
+       
+       std::vector<int>                                                                audio_cadence_;
+                       
+       spl::shared_ptr<core::frame_factory>                    frame_factory_;
+       
+       filter                                                                                  filter_;
+       const std::wstring                                                              filter_str_;
+       bool                                                                                    force_deinterlacing_;
+               
+       impl(double in_fps, const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::wstring& filter_str)
+               : display_mode_(display_mode::invalid)
+               , in_fps_(in_fps)
+               , format_desc_(format_desc)
+               , audio_cadence_(format_desc_.audio_cadence)
+               , frame_factory_(frame_factory)
+               , filter_str_(filter_str)
+               , force_deinterlacing_(env::properties().get(L"configuration.force-deinterlace", true))
+       {               
+               // Note: Uses 1 step rotated cadence for 1001 modes (1602, 1602, 1601, 1602, 1601)
+               // This cadence fills the audio mixer most optimally.
+               boost::range::rotate(audio_cadence_, std::end(audio_cadence_)-1);
+       }
+       
+       void push_video(const std::shared_ptr<AVFrame>& video)
+       {               
+               if(!video)
+                       return;
+
+               if(!video->data[0])
+               {
+                       auto empty_frame = frame_factory_->create_frame(this, core::pixel_format_desc(core::pixel_format::invalid));
+                       video_stream_.push(std::move(empty_frame));
+                       display_mode_ = display_mode::simple;
+               }
+               else
+               {
+                       if(display_mode_ == display_mode::invalid)
+                               update_display_mode(video);
+                               
+                       filter_.push(video);
+                       BOOST_FOREACH(auto& av_frame, filter_.poll_all())                       
+                               video_stream_.push(make_frame(this, av_frame, format_desc_.fps, *frame_factory_));                      
+               }
+
+               merge();
+       }
+       
+       void push_audio(const std::shared_ptr<AVFrame>& audio)
+       {
+               if(!audio)
+                       return;
+
+               if(!audio->data[0])             
+               {
+                       boost::range::push_back(audio_stream_, core::audio_buffer(audio_cadence_.front(), 0));  
+               }
+               else
+               {
+                       auto ptr = reinterpret_cast<int32_t*>(audio->data[0]);
+                       audio_stream_.insert(audio_stream_.end(), ptr, ptr + audio->linesize[0]/sizeof(int32_t));
+               }
+
+               merge();
+       }
+       
+       bool video_ready() const
+       {               
+               switch(display_mode_)
+               {
+               case display_mode::deinterlace_bob_reinterlace:                                 
+               case display_mode::interlace:   
+               case display_mode::half:
+                       return video_stream_.size() >= 2;
+               default:                                                                                
+                       return video_stream_.size() >= 1;
+               }
+       }
+       
+       bool audio_ready() const
+       {
+               switch(display_mode_)
+               {
+               case display_mode::duplicate:                                   
+                       return audio_stream_.size() >= static_cast<size_t>(audio_cadence_[0] + audio_cadence_[1 % audio_cadence_.size()]);
+               default:                                                                                
+                       return audio_stream_.size() >= static_cast<size_t>(audio_cadence_.front());
+               }
+       }
+
+       bool empty() const
+       {
+               return frame_buffer_.empty();
+       }
+
+       core::draw_frame front() const
+       {
+               return frame_buffer_.front();
+       }
+
+       void pop()
+       {
+               frame_buffer_.pop();
+       }
+               
+       void merge()
+       {
+               while(video_ready() && audio_ready() && display_mode_ != display_mode::invalid)
+               {                               
+                       auto frame1                     = pop_video();
+                       frame1.audio_data()     = pop_audio();
+
+                       switch(display_mode_)
+                       {
+                       case display_mode::simple:                                              
+                       case display_mode::deinterlace_bob:                             
+                       case display_mode::deinterlace: 
+                               {
+                                       frame_buffer_.push(core::draw_frame(std::move(frame1)));
+                                       break;
+                               }
+                       case display_mode::interlace:                                   
+                       case display_mode::deinterlace_bob_reinterlace: 
+                               {                               
+                                       auto frame2 = pop_video();
+
+                                       frame_buffer_.push(core::draw_frame::interlace(
+                                               core::draw_frame(std::move(frame1)),
+                                               core::draw_frame(std::move(frame2)),
+                                               format_desc_.field_mode));      
+                                       break;
+                               }
+                       case display_mode::duplicate:   
+                               {
+                                       boost::range::push_back(frame1.audio_data(), pop_audio());
+
+                                       auto draw_frame = core::draw_frame(std::move(frame1));
+                                       frame_buffer_.push(draw_frame);
+                                       frame_buffer_.push(draw_frame);
+                                       break;
+                               }
+                       case display_mode::half:        
+                               {                               
+                                       pop_video(); // Throw away
+
+                                       frame_buffer_.push(core::draw_frame(std::move(frame1)));
+                                       break;
+                               }
+                       default:
+                               CASPAR_THROW_EXCEPTION(invalid_operation());
+                       }
+               }
+       }
+       
+       core::mutable_frame pop_video()
+       {
+               auto frame = std::move(video_stream_.front());
+               video_stream_.pop();            
+               return std::move(frame);
+       }
+
+       core::audio_buffer pop_audio()
+       {
+               if(audio_stream_.size() < audio_cadence_.front())
+                       CASPAR_THROW_EXCEPTION(out_of_range());
+
+               auto begin = audio_stream_.begin();
+               auto end   = begin + audio_cadence_.front();
+
+               core::audio_buffer samples(begin, end);
+               audio_stream_.erase(begin, end);
+               
+               boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);
+
+               return samples;
+       }
+                               
+       void update_display_mode(const std::shared_ptr<AVFrame>& frame)
+       {
+               std::wstring filter_str = filter_str_;
+
+               display_mode_ = display_mode::simple;
+
+               auto mode = get_mode(*frame);
+               if(mode == core::field_mode::progressive && frame->height < 720 && in_fps_ < 50.0) // SD frames are interlaced. Probably incorrect meta-data. Fix it.
+                       mode = core::field_mode::upper;
+
+               auto fps  = in_fps_;
+
+               if(filter::is_deinterlacing(filter_str_))
+                       mode = core::field_mode::progressive;
+
+               if(filter::is_double_rate(filter_str_))
+                       fps *= 2;
+                       
+               display_mode_ = get_display_mode(mode, fps, format_desc_.field_mode, format_desc_.fps);
+                       
+               if((frame->height != 480 || format_desc_.height != 486) && // don't deinterlace for NTSC DV
+                               display_mode_ == display_mode::simple && mode != core::field_mode::progressive && format_desc_.field_mode != core::field_mode::progressive && 
+                               frame->height != format_desc_.height)
+               {
+                       display_mode_ = display_mode::deinterlace_bob_reinterlace; // The frame will most likely be scaled, we need to deinterlace->reinterlace 
+               }
+
+               // ALWAYS de-interlace, until we have GPU de-interlacing.
+               if(force_deinterlacing_ && frame->interlaced_frame && display_mode_ != display_mode::deinterlace_bob && display_mode_ != display_mode::deinterlace)
+                       display_mode_ = display_mode::deinterlace_bob_reinterlace;
+               
+               if(display_mode_ == display_mode::deinterlace)
+                       filter_str = append_filter(filter_str, L"YADIF=0:-1");
+               else if(display_mode_ == display_mode::deinterlace_bob || display_mode_ == display_mode::deinterlace_bob_reinterlace)
+                       filter_str = append_filter(filter_str, L"YADIF=1:-1");
+
+               if(display_mode_ == display_mode::invalid)
+               {
+                       CASPAR_LOG(warning) << L"[frame_muxer] Auto-transcode: Failed to detect display-mode.";
+                       display_mode_ = display_mode::simple;
+               }
+
+               if(frame->height == 480) // NTSC DV
+               {
+                       auto pad_str = L"PAD=" + boost::lexical_cast<std::wstring>(frame->width) + L":486:0:2:black";
+                       filter_str = append_filter(filter_str, pad_str);
+               }
+
+               filter_ = filter(filter_str);
+               CASPAR_LOG(info) << L"[frame_muxer] " << display_mode_ << L" " << print_mode(frame->width, frame->height, in_fps_, frame->interlaced_frame > 0);
+       }
+       
+       uint32_t calc_nb_frames(uint32_t nb_frames) const
+       {
+               uint64_t nb_frames2 = nb_frames;
+               
+               if(filter_.is_double_rate()) // Take into account transformations in filter.
+                       nb_frames2 *= 2;
+
+               switch(display_mode_) // Take into account transformation in run.
+               {
+               case display_mode::deinterlace_bob_reinterlace:
+               case display_mode::interlace:   
+               case display_mode::half:
+                       nb_frames2 /= 2;
+                       break;
+               case display_mode::duplicate:
+                       nb_frames2 *= 2;
+                       break;
+               }
+
+               return static_cast<uint32_t>(nb_frames2);
+       }
+
+       void clear()
+       {
+               while(!video_stream_.empty())
+                       video_stream_.pop();    
+
+               audio_stream_.clear();
+
+               while(!frame_buffer_.empty())
+                       frame_buffer_.pop();
+
+               filter_ = filter(filter_.filter_str());
+       }
+};
+
+frame_muxer::frame_muxer(double in_fps, const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::wstring& filter)
+       : impl_(new impl(in_fps, frame_factory, format_desc, filter)){}
+void frame_muxer::push_video(const std::shared_ptr<AVFrame>& frame){impl_->push_video(frame);}
+void frame_muxer::push_audio(const std::shared_ptr<AVFrame>& frame){impl_->push_audio(frame);}
+bool frame_muxer::empty() const{return impl_->empty();}
+core::draw_frame frame_muxer::front() const{return impl_->front();}
+void frame_muxer::pop(){return impl_->pop();}
+void frame_muxer::clear(){impl_->clear();}
+uint32_t frame_muxer::calc_nb_frames(uint32_t nb_frames) const {return impl_->calc_nb_frames(nb_frames);}
+bool frame_muxer::video_ready() const{return impl_->video_ready();}
+bool frame_muxer::audio_ready() const{return impl_->audio_ready();}
+
 }}
\ No newline at end of file
index e91777bf4cc20e4f03e8d1ac755771f4c134899f..1cbda7a48d42145358d31474373350b8196bb735 100644 (file)
@@ -1,68 +1,68 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "display_mode.h"\r
-\r
-#include <common/forward.h>\r
-#include <common/memory.h>\r
-\r
-#include <core/mixer/audio/audio_mixer.h>\r
-#include <core/video_format.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-#include <vector>\r
-\r
-struct AVFrame;\r
-\r
-FORWARD2(caspar, core, struct pixel_format_desc);\r
-FORWARD2(caspar, core, class frame);\r
-FORWARD2(caspar, core, class frame_factory);\r
-FORWARD2(caspar, core, class draw_frame);\r
-\r
-namespace caspar { namespace ffmpeg {\r
-\r
-class frame_muxer : boost::noncopyable\r
-{\r
-public:\r
-       frame_muxer(double in_fps, const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::wstring& filter = L"");\r
-       \r
-       void push_video(const std::shared_ptr<AVFrame>& frame);\r
-       void push_audio(const std::shared_ptr<AVFrame>& frame);\r
-       \r
-       bool video_ready() const;\r
-       bool audio_ready() const;\r
-\r
-       void clear();\r
-\r
-       bool empty() const;\r
-       core::draw_frame front() const;\r
-       void pop();\r
-\r
-       uint32_t calc_nb_frames(uint32_t nb_frames) const;\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include "display_mode.h"
+
+#include <common/forward.h>
+#include <common/memory.h>
+
+#include <core/mixer/audio/audio_mixer.h>
+#include <core/video_format.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <vector>
+
+struct AVFrame;
+
+FORWARD2(caspar, core, struct pixel_format_desc);
+FORWARD2(caspar, core, class frame);
+FORWARD2(caspar, core, class frame_factory);
+FORWARD2(caspar, core, class draw_frame);
+
+namespace caspar { namespace ffmpeg {
+
+class frame_muxer : boost::noncopyable
+{
+public:
+       frame_muxer(double in_fps, const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::wstring& filter = L"");
+       
+       void push_video(const std::shared_ptr<AVFrame>& frame);
+       void push_audio(const std::shared_ptr<AVFrame>& frame);
+       
+       bool video_ready() const;
+       bool audio_ready() const;
+
+       void clear();
+
+       bool empty() const;
+       core::draw_frame front() const;
+       void pop();
+
+       uint32_t calc_nb_frames(uint32_t nb_frames) const;
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index 7f9913dde7d56d81dd03d9f1faf384d1a861ed30..18743ec7db0325f668df5aded3346f64bc072137 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "tbb_avcodec.h"\r
-\r
-#include <common/assert.h>\r
-#include <common/except.h>\r
-#include <common/log.h>\r
-#include <common/env.h>\r
-\r
-#include <tbb/atomic.h>\r
-#include <tbb/parallel_for.h>\r
-#include <tbb/tbb_thread.h>\r
-\r
-#include <boost/foreach.hpp>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
-       #define __STDC_LIMIT_MACROS\r
-       #include <libavformat/avformat.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar {\r
-               \r
-static const int MAX_THREADS = 16; // See mpegvideo.h\r
-\r
-int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)\r
-{\r
-       tbb::parallel_for(0, count, 1, [&](int i)\r
-       {\r
-        int r = func(s, (char*)arg + i*size);\r
-        if(ret) \r
-                       ret[i] = r;\r
-    });\r
-\r
-       return 0;\r
-}\r
-\r
-int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)\r
-{         \r
-       // TODO: Micro-optimize...\r
-\r
-       std::array<std::vector<int>, 16> jobs;\r
-       \r
-       for(int n = 0; n < count; ++n)  \r
-               jobs[(n*MAX_THREADS) / count].push_back(n);     \r
-       \r
-       tbb::parallel_for(0, MAX_THREADS, [&](int n)    \r
-    {   \r
-               BOOST_FOREACH(auto k, jobs[n])\r
-               {\r
-                       int r = func(s, arg, k, n);\r
-                       if(ret) \r
-                               ret[k]= r;\r
-               }\r
-    });   \r
-\r
-       return 0; \r
-}\r
-\r
-void thread_init(AVCodecContext* s)\r
-{\r
-       static int dummy_opaque;\r
-\r
-    s->active_thread_type = FF_THREAD_SLICE;\r
-       s->thread_opaque          = &dummy_opaque; \r
-    s->execute                   = thread_execute;\r
-    s->execute2                          = thread_execute2;\r
-    s->thread_count              = MAX_THREADS; // We are using a task-scheduler, so use as many "threads/tasks" as possible. \r
-}\r
-\r
-void thread_free(AVCodecContext* s)\r
-{\r
-       if(!s->thread_opaque)\r
-               return;\r
-\r
-       s->thread_opaque = nullptr;\r
-}\r
-\r
-int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)\r
-{\r
-       if(codec->capabilities & CODEC_CAP_EXPERIMENTAL)\r
-               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Experimental codecs are not supported."));\r
-\r
-       avctx->thread_count = 1;\r
-\r
-       if(codec->capabilities & CODEC_CAP_SLICE_THREADS)       \r
-               thread_init(avctx);\r
-       \r
-       // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1.\r
-       return avcodec_open(avctx, codec); \r
-}\r
-\r
-int tbb_avcodec_close(AVCodecContext* avctx)\r
-{\r
-       thread_free(avctx);\r
-       // ff_thread_free will not be executed since thread_opaque == nullptr.\r
-       return avcodec_close(avctx); \r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "tbb_avcodec.h"
+
+#include <common/assert.h>
+#include <common/except.h>
+#include <common/log.h>
+#include <common/env.h>
+
+#include <tbb/atomic.h>
+#include <tbb/parallel_for.h>
+#include <tbb/tbb_thread.h>
+
+#include <boost/foreach.hpp>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #define __STDC_CONSTANT_MACROS
+       #define __STDC_LIMIT_MACROS
+       #include <libavformat/avformat.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+namespace caspar {
+               
+static const int MAX_THREADS = 16; // See mpegvideo.h
+
+int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)
+{
+       tbb::parallel_for(0, count, 1, [&](int i)
+       {
+        int r = func(s, (char*)arg + i*size);
+        if(ret) 
+                       ret[i] = r;
+    });
+
+       return 0;
+}
+
+int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)
+{         
+       // TODO: Micro-optimize...
+
+       std::array<std::vector<int>, 16> jobs;
+       
+       for(int n = 0; n < count; ++n)  
+               jobs[(n*MAX_THREADS) / count].push_back(n);     
+       
+       tbb::parallel_for(0, MAX_THREADS, [&](int n)    
+    {   
+               BOOST_FOREACH(auto k, jobs[n])
+               {
+                       int r = func(s, arg, k, n);
+                       if(ret) 
+                               ret[k]= r;
+               }
+    });   
+
+       return 0; 
+}
+
+void thread_init(AVCodecContext* s)
+{
+       static int dummy_opaque;
+
+    s->active_thread_type = FF_THREAD_SLICE;
+       s->thread_opaque          = &dummy_opaque; 
+    s->execute                   = thread_execute;
+    s->execute2                          = thread_execute2;
+    s->thread_count              = MAX_THREADS; // We are using a task-scheduler, so use as many "threads/tasks" as possible. 
+}
+
+void thread_free(AVCodecContext* s)
+{
+       if(!s->thread_opaque)
+               return;
+
+       s->thread_opaque = nullptr;
+}
+
+int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)
+{
+       if(codec->capabilities & CODEC_CAP_EXPERIMENTAL)
+               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Experimental codecs are not supported."));
+
+       avctx->thread_count = 1;
+
+       if(codec->capabilities & CODEC_CAP_SLICE_THREADS)       
+               thread_init(avctx);
+       
+       // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1.
+       return avcodec_open(avctx, codec); 
+}
+
+int tbb_avcodec_close(AVCodecContext* avctx)
+{
+       thread_free(avctx);
+       // ff_thread_free will not be executed since thread_opaque == nullptr.
+       return avcodec_close(avctx); 
+}
+
 }
\ No newline at end of file
index 2756cad8781cbfefe5f668caaafd9a1b1a5bc8b9..de9b6baf5d98f6ad39035784ee1ac724373b4e72 100644 (file)
@@ -1,32 +1,32 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-struct AVCodecContext;\r
-struct AVCodec;\r
-\r
-namespace caspar {\r
-       \r
-int tbb_avcodec_open(AVCodecContext *avctx, AVCodec *codec);\r
-int tbb_avcodec_close(AVCodecContext *avctx);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+struct AVCodecContext;
+struct AVCodec;
+
+namespace caspar {
+       
+int tbb_avcodec_open(AVCodecContext *avctx, AVCodec *codec);
+int tbb_avcodec_close(AVCodecContext *avctx);
+
 }
\ No newline at end of file
index 15a6fa3525da9083f8b0b7f7b9897739b79da0a2..72445136a6a2a63f61d32c5ef4c20cc569396da6 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "flv.h"\r
-\r
-#include <common/except.h>\r
-#include <common/log.h>\r
-\r
-#include <boost/filesystem.hpp>\r
-\r
-#include <iostream>\r
-\r
-#include <unordered_map>\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-std::map<std::string, std::string> read_flv_meta_info(const std::string& filename)\r
-{\r
-       std::map<std::string, std::string>  values;\r
-\r
-       if(boost::filesystem::path(filename).extension().string() != ".flv")\r
-               return values;\r
-       \r
-       try\r
-       {\r
-               if(!boost::filesystem::exists(filename))\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception());\r
-       \r
-               std::fstream fileStream = std::fstream(filename, std::fstream::in);\r
-               \r
-               std::vector<char> bytes2(256);\r
-               fileStream.read(bytes2.data(), bytes2.size());\r
-\r
-               auto ptr = bytes2.data();\r
-               \r
-               ptr += 27;\r
-                                               \r
-               if(std::string(ptr, ptr+10) == "onMetaData")\r
-               {\r
-                       ptr += 16;\r
-\r
-                       for(int n = 0; n < 16; ++n)\r
-                       {\r
-                               char name_size = *ptr++;\r
-\r
-                               if(name_size == 0)\r
-                                       break;\r
-\r
-                               auto name = std::string(ptr, ptr + name_size);\r
-                               ptr += name_size;\r
-\r
-                               char data_type = *ptr++;\r
-                               switch(data_type)\r
-                               {\r
-                               case 0: // double\r
-                                       {\r
-                                               static_assert(sizeof(double) == 8, "");\r
-                                               std::reverse(ptr, ptr+8);\r
-                                               values[name] = boost::lexical_cast<std::string>(*(double*)(ptr));\r
-                                               ptr += 9;\r
-\r
-                                               break;\r
-                                       }\r
-                               case 1: // bool\r
-                                       {\r
-                                               values[name] = boost::lexical_cast<std::string>(*ptr != 0);\r
-                                               ptr += 2;\r
-\r
-                                               break;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-       }\r
-\r
-    return values;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "flv.h"
+
+#include <common/except.h>
+#include <common/log.h>
+
+#include <boost/filesystem.hpp>
+
+#include <iostream>
+
+#include <unordered_map>
+
+namespace caspar { namespace ffmpeg {
+       
+std::map<std::string, std::string> read_flv_meta_info(const std::string& filename)
+{
+       std::map<std::string, std::string>  values;
+
+       if(boost::filesystem::path(filename).extension().string() != ".flv")
+               return values;
+       
+       try
+       {
+               if(!boost::filesystem::exists(filename))
+                       CASPAR_THROW_EXCEPTION(caspar_exception());
+       
+               std::fstream fileStream = std::fstream(filename, std::fstream::in);
+               
+               std::vector<char> bytes2(256);
+               fileStream.read(bytes2.data(), bytes2.size());
+
+               auto ptr = bytes2.data();
+               
+               ptr += 27;
+                                               
+               if(std::string(ptr, ptr+10) == "onMetaData")
+               {
+                       ptr += 16;
+
+                       for(int n = 0; n < 16; ++n)
+                       {
+                               char name_size = *ptr++;
+
+                               if(name_size == 0)
+                                       break;
+
+                               auto name = std::string(ptr, ptr + name_size);
+                               ptr += name_size;
+
+                               char data_type = *ptr++;
+                               switch(data_type)
+                               {
+                               case 0: // double
+                                       {
+                                               static_assert(sizeof(double) == 8, "");
+                                               std::reverse(ptr, ptr+8);
+                                               values[name] = boost::lexical_cast<std::string>(*(double*)(ptr));
+                                               ptr += 9;
+
+                                               break;
+                                       }
+                               case 1: // bool
+                                       {
+                                               values[name] = boost::lexical_cast<std::string>(*ptr != 0);
+                                               ptr += 2;
+
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+       }
+
+    return values;
+}
+
 }}
\ No newline at end of file
index 6de0ba3532e5acc03b2e4ee6d8180c52e65f7ae8..713e489a778b178d6c12352c76e50d09c05d48d2 100644 (file)
@@ -1,28 +1,28 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-std::map<std::string, std::string> read_flv_meta_info(const std::string& filename);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+namespace caspar { namespace ffmpeg {
+       
+std::map<std::string, std::string> read_flv_meta_info(const std::string& filename);
+
 }}
\ No newline at end of file
index 0d526cbd13ea1397be45330721811c8673538915..87755784b6df44033933503223f2cf796a00e598 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "util.h"\r
-\r
-#include "flv.h"\r
-\r
-#include "../tbb_avcodec.h"\r
-#include "../../ffmpeg_error.h"\r
-\r
-#include <tbb/concurrent_unordered_map.h>\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <core/frame/frame_transform.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/frame.h>\r
-#include <core/producer/frame_producer.h>\r
-\r
-#include <common/except.h>\r
-#include <common/array.h>\r
-\r
-#include <tbb/parallel_for.h>\r
-\r
-#include <common/assert.h>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-\r
-#include <asmlib.h>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #include <libswscale/swscale.h>\r
-       #include <libavcodec/avcodec.h>\r
-       #include <libavformat/avformat.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar { namespace ffmpeg {\r
-               \r
-core::field_mode get_mode(const AVFrame& frame)\r
-{\r
-       if(!frame.interlaced_frame)\r
-               return core::field_mode::progressive;\r
-\r
-       return frame.top_field_first ? core::field_mode::upper : core::field_mode::lower;\r
-}\r
-\r
-core::pixel_format get_pixel_format(PixelFormat pix_fmt)\r
-{\r
-       switch(pix_fmt)\r
-       {\r
-       case PIX_FMT_GRAY8:                     return core::pixel_format::gray;\r
-       case PIX_FMT_RGB24:                     return core::pixel_format::rgb;\r
-       case PIX_FMT_BGR24:                     return core::pixel_format::bgr;\r
-       case PIX_FMT_BGRA:                      return core::pixel_format::bgra;\r
-       case PIX_FMT_ARGB:                      return core::pixel_format::argb;\r
-       case PIX_FMT_RGBA:                      return core::pixel_format::rgba;\r
-       case PIX_FMT_ABGR:                      return core::pixel_format::abgr;\r
-       case PIX_FMT_YUV444P:           return core::pixel_format::ycbcr;\r
-       case PIX_FMT_YUV422P:           return core::pixel_format::ycbcr;\r
-       case PIX_FMT_YUV420P:           return core::pixel_format::ycbcr;\r
-       case PIX_FMT_YUV411P:           return core::pixel_format::ycbcr;\r
-       case PIX_FMT_YUV410P:           return core::pixel_format::ycbcr;\r
-       case PIX_FMT_YUVA420P:          return core::pixel_format::ycbcra;\r
-       default:                                        return core::pixel_format::invalid;\r
-       }\r
-}\r
-\r
-core::pixel_format_desc pixel_format_desc(PixelFormat pix_fmt, int width, int height)\r
-{\r
-       // Get linesizes\r
-       AVPicture dummy_pict;   \r
-       avpicture_fill(&dummy_pict, nullptr, pix_fmt, width, height);\r
-\r
-       core::pixel_format_desc desc = get_pixel_format(pix_fmt);\r
-               \r
-       switch(desc.format.value())\r
-       {\r
-       case core::pixel_format::gray:\r
-       case core::pixel_format::luma:\r
-               {\r
-                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0], height, 1));                                               \r
-                       return desc;\r
-               }\r
-       case core::pixel_format::bgr:\r
-       case core::pixel_format::rgb:\r
-               {\r
-                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0]/3, height, 3));                                             \r
-                       return desc;\r
-               }\r
-       case core::pixel_format::bgra:\r
-       case core::pixel_format::argb:\r
-       case core::pixel_format::rgba:\r
-       case core::pixel_format::abgr:\r
-               {\r
-                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0]/4, height, 4));                                             \r
-                       return desc;\r
-               }\r
-       case core::pixel_format::ycbcr:\r
-       case core::pixel_format::ycbcra:\r
-               {               \r
-                       // Find chroma height\r
-                       int size2 = static_cast<int>(dummy_pict.data[2] - dummy_pict.data[1]);\r
-                       int h2 = size2/dummy_pict.linesize[1];                  \r
-\r
-                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0], height, 1));\r
-                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[1], h2, 1));\r
-                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[2], h2, 1));\r
-\r
-                       if(desc.format == core::pixel_format::ycbcra)                                           \r
-                               desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[3], height, 1));       \r
-                       return desc;\r
-               }               \r
-       default:                \r
-               desc.format = core::pixel_format::invalid;\r
-               return desc;\r
-       }\r
-}\r
-\r
-core::mutable_frame make_frame(const void* tag, const spl::shared_ptr<AVFrame>& decoded_frame, double fps, core::frame_factory& frame_factory)\r
-{                      \r
-       static tbb::concurrent_unordered_map<int64_t, tbb::concurrent_queue<std::shared_ptr<SwsContext>>> sws_contvalid_exts_;\r
-       \r
-       if(decoded_frame->width < 1 || decoded_frame->height < 1)\r
-               return frame_factory.create_frame(tag, core::pixel_format_desc(core::pixel_format::invalid));\r
-\r
-       const auto width  = decoded_frame->width;\r
-       const auto height = decoded_frame->height;\r
-       auto desc                 = pixel_format_desc(static_cast<PixelFormat>(decoded_frame->format), width, height);\r
-               \r
-       if(desc.format == core::pixel_format::invalid)\r
-       {\r
-               auto pix_fmt = static_cast<PixelFormat>(decoded_frame->format);\r
-               auto target_pix_fmt = PIX_FMT_BGRA;\r
-\r
-               if(pix_fmt == PIX_FMT_UYVY422)\r
-                       target_pix_fmt = PIX_FMT_YUV422P;\r
-               else if(pix_fmt == PIX_FMT_YUYV422)\r
-                       target_pix_fmt = PIX_FMT_YUV422P;\r
-               else if(pix_fmt == PIX_FMT_UYYVYY411)\r
-                       target_pix_fmt = PIX_FMT_YUV411P;\r
-               else if(pix_fmt == PIX_FMT_YUV420P10)\r
-                       target_pix_fmt = PIX_FMT_YUV420P;\r
-               else if(pix_fmt == PIX_FMT_YUV422P10)\r
-                       target_pix_fmt = PIX_FMT_YUV422P;\r
-               else if(pix_fmt == PIX_FMT_YUV444P10)\r
-                       target_pix_fmt = PIX_FMT_YUV444P;\r
-               \r
-               auto target_desc = pixel_format_desc(target_pix_fmt, width, height);\r
-\r
-               auto write = frame_factory.create_frame(tag, target_desc);\r
-\r
-               std::shared_ptr<SwsContext> sws_context;\r
-\r
-               //CASPAR_LOG(warning) << "Hardware accelerated color transform not supported.";\r
-               \r
-               int64_t key = ((static_cast<int64_t>(width)                      << 32) & 0xFFFF00000000) | \r
-                                         ((static_cast<int64_t>(height)                 << 16) & 0xFFFF0000) | \r
-                                         ((static_cast<int64_t>(pix_fmt)                <<  8) & 0xFF00) | \r
-                                         ((static_cast<int64_t>(target_pix_fmt) <<  0) & 0xFF);\r
-                       \r
-               auto& pool = sws_contvalid_exts_[key];\r
-                                               \r
-               if(!pool.try_pop(sws_context))\r
-               {\r
-                       double param;\r
-                       sws_context.reset(sws_getContext(width, height, pix_fmt, width, height, target_pix_fmt, SWS_BILINEAR, nullptr, nullptr, &param), sws_freeContext);\r
-               }\r
-                       \r
-               if(!sws_context)\r
-               {\r
-                       CASPAR_THROW_EXCEPTION(operation_failed() << msg_info("Could not create software scaling context.") << \r
-                                                                       boost::errinfo_api_function("sws_getContext"));\r
-               }       \r
-               \r
-               spl::shared_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);      \r
-               avcodec_get_frame_defaults(av_frame.get());                     \r
-               if(target_pix_fmt == PIX_FMT_BGRA)\r
-               {\r
-                       auto size = avpicture_fill(reinterpret_cast<AVPicture*>(av_frame.get()), write.image_data(0).begin(), PIX_FMT_BGRA, width, height);\r
-                       CASPAR_VERIFY(size == write.image_data(0).size()); \r
-               }\r
-               else\r
-               {\r
-                       av_frame->width  = width;\r
-                       av_frame->height = height;\r
-                       for(int n = 0; n < target_desc.planes.size(); ++n)\r
-                       {\r
-                               av_frame->data[n]               = write.image_data(n).begin();\r
-                               av_frame->linesize[n]   = target_desc.planes[n].linesize;\r
-                       }\r
-               }\r
-\r
-               sws_scale(sws_context.get(), decoded_frame->data, decoded_frame->linesize, 0, height, av_frame->data, av_frame->linesize);      \r
-               pool.push(sws_context); \r
-\r
-               return std::move(write);\r
-       }\r
-       else\r
-       {\r
-               auto write = frame_factory.create_frame(tag, desc);\r
-               \r
-               for(int n = 0; n < static_cast<int>(desc.planes.size()); ++n)\r
-               {\r
-                       auto plane            = desc.planes[n];\r
-                       auto result           = write.image_data(n).begin();\r
-                       auto decoded          = decoded_frame->data[n];\r
-                       auto decoded_linesize = decoded_frame->linesize[n];\r
-                       \r
-                       CASPAR_ASSERT(decoded);\r
-                       CASPAR_ASSERT(write.image_data(n).begin());\r
-\r
-                       // Copy line by line since ffmpeg sometimes pads each line.\r
-                       tbb::affinity_partitioner ap;\r
-                       tbb::parallel_for(tbb::blocked_range<int>(0, desc.planes[n].height), [&](const tbb::blocked_range<int>& r)\r
-                       {\r
-                               for(int y = r.begin(); y != r.end(); ++y)\r
-                                       A_memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize);\r
-                       }, ap);\r
-               }\r
-       \r
-               return std::move(write);\r
-       }\r
-}\r
-\r
-spl::shared_ptr<AVFrame> make_av_frame(core::mutable_frame& frame)\r
-{\r
-       std::array<uint8_t*, 4> data = {};\r
-       for(int n = 0; n < frame.pixel_format_desc().planes.size(); ++n)\r
-               data[n] = frame.image_data(n).begin();\r
-\r
-       return make_av_frame(data, frame.pixel_format_desc());\r
-}\r
-\r
-spl::shared_ptr<AVFrame> make_av_frame(std::array<uint8_t*, 4> data, const core::pixel_format_desc& pix_desc)\r
-{\r
-       spl::shared_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);      \r
-       avcodec_get_frame_defaults(av_frame.get());\r
-       \r
-       auto planes              = pix_desc.planes;\r
-       auto format              = pix_desc.format.value();\r
-\r
-       av_frame->width  = planes[0].width;\r
-       av_frame->height = planes[0].height;\r
-       for(int n = 0; n < planes.size(); ++n)  \r
-       {\r
-               av_frame->data[n]         = data[n];\r
-               av_frame->linesize[n] = planes[n].linesize;     \r
-       }\r
-\r
-       switch(format)\r
-       {\r
-       case core::pixel_format::rgb:\r
-               av_frame->format = PIX_FMT_RGB24;\r
-               break;\r
-       case core::pixel_format::bgr:\r
-               av_frame->format = PIX_FMT_BGR24;\r
-               break;\r
-       case core::pixel_format::rgba:\r
-               av_frame->format = PIX_FMT_RGBA; \r
-               break;\r
-       case core::pixel_format::argb:\r
-               av_frame->format = PIX_FMT_ARGB; \r
-               break;\r
-       case core::pixel_format::bgra:\r
-               av_frame->format = PIX_FMT_BGRA; \r
-               break;\r
-       case core::pixel_format::abgr:\r
-               av_frame->format = PIX_FMT_ABGR; \r
-               break;\r
-       case core::pixel_format::gray:\r
-               av_frame->format = PIX_FMT_GRAY8; \r
-               break;\r
-       case core::pixel_format::ycbcr:\r
-       {\r
-               int y_w = planes[0].width;\r
-               int y_h = planes[0].height;\r
-               int c_w = planes[1].width;\r
-               int c_h = planes[1].height;\r
-\r
-               if(c_h == y_h && c_w == y_w)\r
-                       av_frame->format = PIX_FMT_YUV444P;\r
-               else if(c_h == y_h && c_w*2 == y_w)\r
-                       av_frame->format = PIX_FMT_YUV422P;\r
-               else if(c_h == y_h && c_w*4 == y_w)\r
-                       av_frame->format = PIX_FMT_YUV411P;\r
-               else if(c_h*2 == y_h && c_w*2 == y_w)\r
-                       av_frame->format = PIX_FMT_YUV420P;\r
-               else if(c_h*2 == y_h && c_w*4 == y_w)\r
-                       av_frame->format = PIX_FMT_YUV410P;\r
-\r
-               break;\r
-       }\r
-       case core::pixel_format::ycbcra:\r
-               av_frame->format = PIX_FMT_YUVA420P;\r
-               break;\r
-       }\r
-       return av_frame;\r
-}\r
-\r
-bool is_sane_fps(AVRational time_base)\r
-{\r
-       double fps = static_cast<double>(time_base.den) / static_cast<double>(time_base.num);\r
-       return fps > 20.0 && fps < 65.0;\r
-}\r
-\r
-AVRational fix_time_base(AVRational time_base)\r
-{\r
-       if(time_base.num == 1)\r
-               time_base.num = static_cast<int>(std::pow(10.0, static_cast<int>(std::log10(static_cast<float>(time_base.den)))-1));    \r
-                       \r
-       if(!is_sane_fps(time_base))\r
-       {\r
-               auto tmp = time_base;\r
-               tmp.den /= 2;\r
-               if(is_sane_fps(tmp))\r
-                       time_base = tmp;\r
-       }\r
-\r
-       return time_base;\r
-}\r
-\r
-double read_fps(AVFormatContext& context, double fail_value)\r
-{                                              \r
-       auto video_index = av_find_best_stream(&context, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);\r
-       auto audio_index = av_find_best_stream(&context, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);\r
-       \r
-       if(video_index > -1)\r
-       {\r
-               const auto video_context = context.streams[video_index]->codec;\r
-               const auto video_stream  = context.streams[video_index];\r
-                                               \r
-               AVRational time_base = video_context->time_base;\r
-\r
-               if(boost::filesystem::path(context.filename).extension().string() == ".flv")\r
-               {\r
-                       try\r
-                       {\r
-                               auto meta = read_flv_meta_info(context.filename);\r
-                               return boost::lexical_cast<double>(meta["framerate"]);\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               return 0.0;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       time_base.num *= video_context->ticks_per_frame;\r
-\r
-                       if(!is_sane_fps(time_base))\r
-                       {                       \r
-                               time_base = fix_time_base(time_base);\r
-\r
-                               if(!is_sane_fps(time_base) && audio_index > -1)\r
-                               {\r
-                                       auto& audio_context = *context.streams[audio_index]->codec;\r
-                                       auto& audio_stream  = *context.streams[audio_index];\r
-\r
-                                       double duration_sec = audio_stream.duration / static_cast<double>(audio_context.sample_rate);\r
-                                                               \r
-                                       time_base.num = static_cast<int>(duration_sec*100000.0);\r
-                                       time_base.den = static_cast<int>(video_stream->nb_frames*100000);\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               double fps = static_cast<double>(time_base.den) / static_cast<double>(time_base.num);\r
-\r
-               double closest_fps = 0.0;\r
-               for(int n = 0; n < core::video_format::count; ++n)\r
-               {\r
-                       auto format = core::video_format_desc(core::video_format(n));\r
-\r
-                       double diff1 = std::abs(format.fps - fps);\r
-                       double diff2 = std::abs(closest_fps - fps);\r
-\r
-                       if(diff1 < diff2)\r
-                               closest_fps = format.fps;\r
-               }\r
-       \r
-               return closest_fps;\r
-       }\r
-\r
-       return fail_value;      \r
-}\r
-\r
-void fix_meta_data(AVFormatContext& context)\r
-{\r
-       auto video_index = av_find_best_stream(&context, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);\r
-\r
-       if(video_index > -1)\r
-       {\r
-               auto video_stream   = context.streams[video_index];\r
-               auto video_context  = context.streams[video_index]->codec;\r
-                                               \r
-               if(boost::filesystem::path(context.filename).extension().string() == ".flv")\r
-               {\r
-                       try\r
-                       {\r
-                               auto meta = read_flv_meta_info(context.filename);\r
-                               double fps = boost::lexical_cast<double>(meta["framerate"]);\r
-                               video_stream->nb_frames = static_cast<int64_t>(boost::lexical_cast<double>(meta["duration"])*fps);\r
-                       }\r
-                       catch(...){}\r
-               }\r
-               else\r
-               {\r
-                       auto stream_time = video_stream->time_base;\r
-                       auto duration    = video_stream->duration;\r
-                       auto codec_time  = video_context->time_base;\r
-                       auto ticks               = video_context->ticks_per_frame;\r
-\r
-                       if(video_stream->nb_frames == 0)\r
-                               video_stream->nb_frames = (duration*stream_time.num*codec_time.den)/(stream_time.den*codec_time.num*ticks);     \r
-               }\r
-       }\r
-}\r
-\r
-spl::shared_ptr<AVPacket> create_packet()\r
-{\r
-       spl::shared_ptr<AVPacket> packet(new AVPacket(), [](AVPacket* p)\r
-       {\r
-               av_free_packet(p);\r
-               delete p;\r
-       });\r
-       \r
-       av_init_packet(packet.get());\r
-       return packet;\r
-}\r
-\r
-spl::shared_ptr<AVFrame> create_frame()\r
-{      \r
-       spl::shared_ptr<AVFrame> frame(avcodec_alloc_frame(), av_free);\r
-       avcodec_get_frame_defaults(frame.get());\r
-       return frame;\r
-}\r
-\r
-spl::shared_ptr<AVCodecContext> open_codec(AVFormatContext& context, enum AVMediaType type, int& index)\r
-{      \r
-       AVCodec* decoder;\r
-       index = THROW_ON_ERROR2(av_find_best_stream(&context, type, -1, -1, &decoder, 0), "");\r
-       //if(strcmp(decoder->name, "prores") == 0 && decoder->next && strcmp(decoder->next->name, "prores_lgpl") == 0)\r
-       //      decoder = decoder->next;\r
-\r
-       THROW_ON_ERROR2(tbb_avcodec_open(context.streams[index]->codec, decoder), "");\r
-       return spl::shared_ptr<AVCodecContext>(context.streams[index]->codec, tbb_avcodec_close);\r
-}\r
-\r
-spl::shared_ptr<AVFormatContext> open_input(const std::wstring& filename)\r
-{\r
-       AVFormatContext* weak_context = nullptr;\r
-       THROW_ON_ERROR2(avformat_open_input(&weak_context, u8(filename).c_str(), nullptr, nullptr), filename);\r
-       spl::shared_ptr<AVFormatContext> context(weak_context, av_close_input_file);                    \r
-       THROW_ON_ERROR2(avformat_find_stream_info(weak_context, nullptr), filename);\r
-       fix_meta_data(*context);\r
-       return context;\r
-}\r
-\r
-std::wstring print_mode(int width, int height, double fps, bool interlaced)\r
-{\r
-       std::wostringstream fps_ss;\r
-       fps_ss << std::fixed << std::setprecision(2) << (!interlaced ? fps : 2.0 * fps);\r
-\r
-       return boost::lexical_cast<std::wstring>(width) + L"x" + boost::lexical_cast<std::wstring>(height) + (!interlaced ? L"p" : L"i") + fps_ss.str();\r
-}\r
-\r
-bool is_valid_file(const std::wstring filename)\r
-{                              \r
-       static const std::vector<std::wstring> invalid_exts = boost::assign::list_of(L".png")(L".tga")(L".bmp")(L".jpg")(L".jpeg")(L".gif")(L".tiff")(L".tif")(L".jp2")(L".jpx")(L".j2k")(L".j2c")(L".swf")(L".ct");\r
-       static std::vector<std::wstring>           valid_exts   = boost::assign::list_of(L".m2t")(L".mov")(L".mp4")(L".dv")(L".flv")(L".mpg")(L".wav")(L".mp3")(L".dnxhd")(L".h264")(L".prores");\r
-\r
-       auto ext = boost::to_lower_copy(boost::filesystem::path(filename).extension().wstring());\r
-               \r
-       if(std::find(valid_exts.begin(), valid_exts.end(), ext) != valid_exts.end())\r
-               return true;    \r
-       \r
-       if(std::find(invalid_exts.begin(), invalid_exts.end(), ext) != invalid_exts.end())\r
-               return false;   \r
-\r
-       auto u8filename = u8(filename);\r
-       \r
-       int score = 0;\r
-       AVProbeData pb = {};\r
-       pb.filename = u8filename.c_str();\r
-\r
-       if(av_probe_input_format2(&pb, false, &score) != nullptr)\r
-               return true;\r
-\r
-       std::ifstream file(filename);\r
-\r
-       std::vector<unsigned char> buf;\r
-       for(auto file_it = std::istreambuf_iterator<char>(file); file_it != std::istreambuf_iterator<char>() && buf.size() < 1024; ++file_it)\r
-               buf.push_back(*file_it);\r
-\r
-       if(buf.empty())\r
-               return nullptr;\r
-\r
-       pb.buf          = buf.data();\r
-       pb.buf_size = static_cast<int>(buf.size());\r
-\r
-       return av_probe_input_format2(&pb, true, &score) != nullptr;\r
-}\r
-\r
-std::wstring probe_stem(const std::wstring stem)\r
-{\r
-       auto stem2 = boost::filesystem::path(stem);\r
-       auto dir = stem2.parent_path();\r
-       for(auto it = boost::filesystem::directory_iterator(dir); it != boost::filesystem::directory_iterator(); ++it)\r
-       {\r
-               if(boost::iequals(it->path().stem().wstring(), stem2.filename().wstring()) && is_valid_file(it->path().wstring()))\r
-                       return it->path().wstring();\r
-       }\r
-       return L"";\r
-}\r
-//\r
-//void av_dup_frame(AVFrame* frame)\r
-//{\r
-//     AVFrame* new_frame = avcodec_alloc_frame();\r
-//\r
-//\r
-//     const uint8_t *src_data[4] = {0};\r
-//     memcpy(const_cast<uint8_t**>(&src_data[0]), frame->data, 4);\r
-//     const int src_linesizes[4] = {0};\r
-//     memcpy(const_cast<int*>(&src_linesizes[0]), frame->linesize, 4);\r
-//\r
-//     av_image_alloc(new_frame->data, new_frame->linesize, new_frame->width, new_frame->height, frame->format, 16);\r
-//\r
-//     av_image_copy(new_frame->data, new_frame->linesize, src_data, src_linesizes, frame->format, new_frame->width, new_frame->height);\r
-//\r
-//     frame =\r
-//}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "util.h"
+
+#include "flv.h"
+
+#include "../tbb_avcodec.h"
+#include "../../ffmpeg_error.h"
+
+#include <tbb/concurrent_unordered_map.h>
+#include <tbb/concurrent_queue.h>
+
+#include <core/frame/frame_transform.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/frame.h>
+#include <core/producer/frame_producer.h>
+
+#include <common/except.h>
+#include <common/array.h>
+
+#include <tbb/parallel_for.h>
+
+#include <common/assert.h>
+#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <asmlib.h>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #include <libswscale/swscale.h>
+       #include <libavcodec/avcodec.h>
+       #include <libavformat/avformat.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+namespace caspar { namespace ffmpeg {
+               
+core::field_mode get_mode(const AVFrame& frame)
+{
+       if(!frame.interlaced_frame)
+               return core::field_mode::progressive;
+
+       return frame.top_field_first ? core::field_mode::upper : core::field_mode::lower;
+}
+
+core::pixel_format get_pixel_format(PixelFormat pix_fmt)
+{
+       switch(pix_fmt)
+       {
+       case PIX_FMT_GRAY8:                     return core::pixel_format::gray;
+       case PIX_FMT_RGB24:                     return core::pixel_format::rgb;
+       case PIX_FMT_BGR24:                     return core::pixel_format::bgr;
+       case PIX_FMT_BGRA:                      return core::pixel_format::bgra;
+       case PIX_FMT_ARGB:                      return core::pixel_format::argb;
+       case PIX_FMT_RGBA:                      return core::pixel_format::rgba;
+       case PIX_FMT_ABGR:                      return core::pixel_format::abgr;
+       case PIX_FMT_YUV444P:           return core::pixel_format::ycbcr;
+       case PIX_FMT_YUV422P:           return core::pixel_format::ycbcr;
+       case PIX_FMT_YUV420P:           return core::pixel_format::ycbcr;
+       case PIX_FMT_YUV411P:           return core::pixel_format::ycbcr;
+       case PIX_FMT_YUV410P:           return core::pixel_format::ycbcr;
+       case PIX_FMT_YUVA420P:          return core::pixel_format::ycbcra;
+       default:                                        return core::pixel_format::invalid;
+       }
+}
+
+core::pixel_format_desc pixel_format_desc(PixelFormat pix_fmt, int width, int height)
+{
+       // Get linesizes
+       AVPicture dummy_pict;   
+       avpicture_fill(&dummy_pict, nullptr, pix_fmt, width, height);
+
+       core::pixel_format_desc desc = get_pixel_format(pix_fmt);
+               
+       switch(desc.format.value())
+       {
+       case core::pixel_format::gray:
+       case core::pixel_format::luma:
+               {
+                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0], height, 1));                                               
+                       return desc;
+               }
+       case core::pixel_format::bgr:
+       case core::pixel_format::rgb:
+               {
+                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0]/3, height, 3));                                             
+                       return desc;
+               }
+       case core::pixel_format::bgra:
+       case core::pixel_format::argb:
+       case core::pixel_format::rgba:
+       case core::pixel_format::abgr:
+               {
+                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0]/4, height, 4));                                             
+                       return desc;
+               }
+       case core::pixel_format::ycbcr:
+       case core::pixel_format::ycbcra:
+               {               
+                       // Find chroma height
+                       int size2 = static_cast<int>(dummy_pict.data[2] - dummy_pict.data[1]);
+                       int h2 = size2/dummy_pict.linesize[1];                  
+
+                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0], height, 1));
+                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[1], h2, 1));
+                       desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[2], h2, 1));
+
+                       if(desc.format == core::pixel_format::ycbcra)                                           
+                               desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[3], height, 1));       
+                       return desc;
+               }               
+       default:                
+               desc.format = core::pixel_format::invalid;
+               return desc;
+       }
+}
+
+core::mutable_frame make_frame(const void* tag, const spl::shared_ptr<AVFrame>& decoded_frame, double fps, core::frame_factory& frame_factory)
+{                      
+       static tbb::concurrent_unordered_map<int64_t, tbb::concurrent_queue<std::shared_ptr<SwsContext>>> sws_contvalid_exts_;
+       
+       if(decoded_frame->width < 1 || decoded_frame->height < 1)
+               return frame_factory.create_frame(tag, core::pixel_format_desc(core::pixel_format::invalid));
+
+       const auto width  = decoded_frame->width;
+       const auto height = decoded_frame->height;
+       auto desc                 = pixel_format_desc(static_cast<PixelFormat>(decoded_frame->format), width, height);
+               
+       if(desc.format == core::pixel_format::invalid)
+       {
+               auto pix_fmt = static_cast<PixelFormat>(decoded_frame->format);
+               auto target_pix_fmt = PIX_FMT_BGRA;
+
+               if(pix_fmt == PIX_FMT_UYVY422)
+                       target_pix_fmt = PIX_FMT_YUV422P;
+               else if(pix_fmt == PIX_FMT_YUYV422)
+                       target_pix_fmt = PIX_FMT_YUV422P;
+               else if(pix_fmt == PIX_FMT_UYYVYY411)
+                       target_pix_fmt = PIX_FMT_YUV411P;
+               else if(pix_fmt == PIX_FMT_YUV420P10)
+                       target_pix_fmt = PIX_FMT_YUV420P;
+               else if(pix_fmt == PIX_FMT_YUV422P10)
+                       target_pix_fmt = PIX_FMT_YUV422P;
+               else if(pix_fmt == PIX_FMT_YUV444P10)
+                       target_pix_fmt = PIX_FMT_YUV444P;
+               
+               auto target_desc = pixel_format_desc(target_pix_fmt, width, height);
+
+               auto write = frame_factory.create_frame(tag, target_desc);
+
+               std::shared_ptr<SwsContext> sws_context;
+
+               //CASPAR_LOG(warning) << "Hardware accelerated color transform not supported.";
+               
+               int64_t key = ((static_cast<int64_t>(width)                      << 32) & 0xFFFF00000000) | 
+                                         ((static_cast<int64_t>(height)                 << 16) & 0xFFFF0000) | 
+                                         ((static_cast<int64_t>(pix_fmt)                <<  8) & 0xFF00) | 
+                                         ((static_cast<int64_t>(target_pix_fmt) <<  0) & 0xFF);
+                       
+               auto& pool = sws_contvalid_exts_[key];
+                                               
+               if(!pool.try_pop(sws_context))
+               {
+                       double param;
+                       sws_context.reset(sws_getContext(width, height, pix_fmt, width, height, target_pix_fmt, SWS_BILINEAR, nullptr, nullptr, &param), sws_freeContext);
+               }
+                       
+               if(!sws_context)
+               {
+                       CASPAR_THROW_EXCEPTION(operation_failed() << msg_info("Could not create software scaling context.") << 
+                                                                       boost::errinfo_api_function("sws_getContext"));
+               }       
+               
+               spl::shared_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);      
+               avcodec_get_frame_defaults(av_frame.get());                     
+               if(target_pix_fmt == PIX_FMT_BGRA)
+               {
+                       auto size = avpicture_fill(reinterpret_cast<AVPicture*>(av_frame.get()), write.image_data(0).begin(), PIX_FMT_BGRA, width, height);
+                       CASPAR_VERIFY(size == write.image_data(0).size()); 
+               }
+               else
+               {
+                       av_frame->width  = width;
+                       av_frame->height = height;
+                       for(int n = 0; n < target_desc.planes.size(); ++n)
+                       {
+                               av_frame->data[n]               = write.image_data(n).begin();
+                               av_frame->linesize[n]   = target_desc.planes[n].linesize;
+                       }
+               }
+
+               sws_scale(sws_context.get(), decoded_frame->data, decoded_frame->linesize, 0, height, av_frame->data, av_frame->linesize);      
+               pool.push(sws_context); 
+
+               return std::move(write);
+       }
+       else
+       {
+               auto write = frame_factory.create_frame(tag, desc);
+               
+               for(int n = 0; n < static_cast<int>(desc.planes.size()); ++n)
+               {
+                       auto plane            = desc.planes[n];
+                       auto result           = write.image_data(n).begin();
+                       auto decoded          = decoded_frame->data[n];
+                       auto decoded_linesize = decoded_frame->linesize[n];
+                       
+                       CASPAR_ASSERT(decoded);
+                       CASPAR_ASSERT(write.image_data(n).begin());
+
+                       // Copy line by line since ffmpeg sometimes pads each line.
+                       tbb::affinity_partitioner ap;
+                       tbb::parallel_for(tbb::blocked_range<int>(0, desc.planes[n].height), [&](const tbb::blocked_range<int>& r)
+                       {
+                               for(int y = r.begin(); y != r.end(); ++y)
+                                       A_memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize);
+                       }, ap);
+               }
+       
+               return std::move(write);
+       }
+}
+
+spl::shared_ptr<AVFrame> make_av_frame(core::mutable_frame& frame)
+{
+       std::array<uint8_t*, 4> data = {};
+       for(int n = 0; n < frame.pixel_format_desc().planes.size(); ++n)
+               data[n] = frame.image_data(n).begin();
+
+       return make_av_frame(data, frame.pixel_format_desc());
+}
+
+spl::shared_ptr<AVFrame> make_av_frame(std::array<uint8_t*, 4> data, const core::pixel_format_desc& pix_desc)
+{
+       spl::shared_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);      
+       avcodec_get_frame_defaults(av_frame.get());
+       
+       auto planes              = pix_desc.planes;
+       auto format              = pix_desc.format.value();
+
+       av_frame->width  = planes[0].width;
+       av_frame->height = planes[0].height;
+       for(int n = 0; n < planes.size(); ++n)  
+       {
+               av_frame->data[n]         = data[n];
+               av_frame->linesize[n] = planes[n].linesize;     
+       }
+
+       switch(format)
+       {
+       case core::pixel_format::rgb:
+               av_frame->format = PIX_FMT_RGB24;
+               break;
+       case core::pixel_format::bgr:
+               av_frame->format = PIX_FMT_BGR24;
+               break;
+       case core::pixel_format::rgba:
+               av_frame->format = PIX_FMT_RGBA; 
+               break;
+       case core::pixel_format::argb:
+               av_frame->format = PIX_FMT_ARGB; 
+               break;
+       case core::pixel_format::bgra:
+               av_frame->format = PIX_FMT_BGRA; 
+               break;
+       case core::pixel_format::abgr:
+               av_frame->format = PIX_FMT_ABGR; 
+               break;
+       case core::pixel_format::gray:
+               av_frame->format = PIX_FMT_GRAY8; 
+               break;
+       case core::pixel_format::ycbcr:
+       {
+               int y_w = planes[0].width;
+               int y_h = planes[0].height;
+               int c_w = planes[1].width;
+               int c_h = planes[1].height;
+
+               if(c_h == y_h && c_w == y_w)
+                       av_frame->format = PIX_FMT_YUV444P;
+               else if(c_h == y_h && c_w*2 == y_w)
+                       av_frame->format = PIX_FMT_YUV422P;
+               else if(c_h == y_h && c_w*4 == y_w)
+                       av_frame->format = PIX_FMT_YUV411P;
+               else if(c_h*2 == y_h && c_w*2 == y_w)
+                       av_frame->format = PIX_FMT_YUV420P;
+               else if(c_h*2 == y_h && c_w*4 == y_w)
+                       av_frame->format = PIX_FMT_YUV410P;
+
+               break;
+       }
+       case core::pixel_format::ycbcra:
+               av_frame->format = PIX_FMT_YUVA420P;
+               break;
+       }
+       return av_frame;
+}
+
+bool is_sane_fps(AVRational time_base)
+{
+       double fps = static_cast<double>(time_base.den) / static_cast<double>(time_base.num);
+       return fps > 20.0 && fps < 65.0;
+}
+
+AVRational fix_time_base(AVRational time_base)
+{
+       if(time_base.num == 1)
+               time_base.num = static_cast<int>(std::pow(10.0, static_cast<int>(std::log10(static_cast<float>(time_base.den)))-1));    
+                       
+       if(!is_sane_fps(time_base))
+       {
+               auto tmp = time_base;
+               tmp.den /= 2;
+               if(is_sane_fps(tmp))
+                       time_base = tmp;
+       }
+
+       return time_base;
+}
+
+double read_fps(AVFormatContext& context, double fail_value)
+{                                              
+       auto video_index = av_find_best_stream(&context, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);
+       auto audio_index = av_find_best_stream(&context, AVMEDIA_TYPE_AUDIO, -1, -1, 0, 0);
+       
+       if(video_index > -1)
+       {
+               const auto video_context = context.streams[video_index]->codec;
+               const auto video_stream  = context.streams[video_index];
+                                               
+               AVRational time_base = video_context->time_base;
+
+               if(boost::filesystem::path(context.filename).extension().string() == ".flv")
+               {
+                       try
+                       {
+                               auto meta = read_flv_meta_info(context.filename);
+                               return boost::lexical_cast<double>(meta["framerate"]);
+                       }
+                       catch(...)
+                       {
+                               return 0.0;
+                       }
+               }
+               else
+               {
+                       time_base.num *= video_context->ticks_per_frame;
+
+                       if(!is_sane_fps(time_base))
+                       {                       
+                               time_base = fix_time_base(time_base);
+
+                               if(!is_sane_fps(time_base) && audio_index > -1)
+                               {
+                                       auto& audio_context = *context.streams[audio_index]->codec;
+                                       auto& audio_stream  = *context.streams[audio_index];
+
+                                       double duration_sec = audio_stream.duration / static_cast<double>(audio_context.sample_rate);
+                                                               
+                                       time_base.num = static_cast<int>(duration_sec*100000.0);
+                                       time_base.den = static_cast<int>(video_stream->nb_frames*100000);
+                               }
+                       }
+               }
+               
+               double fps = static_cast<double>(time_base.den) / static_cast<double>(time_base.num);
+
+               double closest_fps = 0.0;
+               for(int n = 0; n < core::video_format::count; ++n)
+               {
+                       auto format = core::video_format_desc(core::video_format(n));
+
+                       double diff1 = std::abs(format.fps - fps);
+                       double diff2 = std::abs(closest_fps - fps);
+
+                       if(diff1 < diff2)
+                               closest_fps = format.fps;
+               }
+       
+               return closest_fps;
+       }
+
+       return fail_value;      
+}
+
+void fix_meta_data(AVFormatContext& context)
+{
+       auto video_index = av_find_best_stream(&context, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);
+
+       if(video_index > -1)
+       {
+               auto video_stream   = context.streams[video_index];
+               auto video_context  = context.streams[video_index]->codec;
+                                               
+               if(boost::filesystem::path(context.filename).extension().string() == ".flv")
+               {
+                       try
+                       {
+                               auto meta = read_flv_meta_info(context.filename);
+                               double fps = boost::lexical_cast<double>(meta["framerate"]);
+                               video_stream->nb_frames = static_cast<int64_t>(boost::lexical_cast<double>(meta["duration"])*fps);
+                       }
+                       catch(...){}
+               }
+               else
+               {
+                       auto stream_time = video_stream->time_base;
+                       auto duration    = video_stream->duration;
+                       auto codec_time  = video_context->time_base;
+                       auto ticks               = video_context->ticks_per_frame;
+
+                       if(video_stream->nb_frames == 0)
+                               video_stream->nb_frames = (duration*stream_time.num*codec_time.den)/(stream_time.den*codec_time.num*ticks);     
+               }
+       }
+}
+
+spl::shared_ptr<AVPacket> create_packet()
+{
+       spl::shared_ptr<AVPacket> packet(new AVPacket(), [](AVPacket* p)
+       {
+               av_free_packet(p);
+               delete p;
+       });
+       
+       av_init_packet(packet.get());
+       return packet;
+}
+
+spl::shared_ptr<AVFrame> create_frame()
+{      
+       spl::shared_ptr<AVFrame> frame(avcodec_alloc_frame(), av_free);
+       avcodec_get_frame_defaults(frame.get());
+       return frame;
+}
+
+spl::shared_ptr<AVCodecContext> open_codec(AVFormatContext& context, enum AVMediaType type, int& index)
+{      
+       AVCodec* decoder;
+       index = THROW_ON_ERROR2(av_find_best_stream(&context, type, -1, -1, &decoder, 0), "");
+       //if(strcmp(decoder->name, "prores") == 0 && decoder->next && strcmp(decoder->next->name, "prores_lgpl") == 0)
+       //      decoder = decoder->next;
+
+       THROW_ON_ERROR2(tbb_avcodec_open(context.streams[index]->codec, decoder), "");
+       return spl::shared_ptr<AVCodecContext>(context.streams[index]->codec, tbb_avcodec_close);
+}
+
+spl::shared_ptr<AVFormatContext> open_input(const std::wstring& filename)
+{
+       AVFormatContext* weak_context = nullptr;
+       THROW_ON_ERROR2(avformat_open_input(&weak_context, u8(filename).c_str(), nullptr, nullptr), filename);
+       spl::shared_ptr<AVFormatContext> context(weak_context, av_close_input_file);                    
+       THROW_ON_ERROR2(avformat_find_stream_info(weak_context, nullptr), filename);
+       fix_meta_data(*context);
+       return context;
+}
+
+std::wstring print_mode(int width, int height, double fps, bool interlaced)
+{
+       std::wostringstream fps_ss;
+       fps_ss << std::fixed << std::setprecision(2) << (!interlaced ? fps : 2.0 * fps);
+
+       return boost::lexical_cast<std::wstring>(width) + L"x" + boost::lexical_cast<std::wstring>(height) + (!interlaced ? L"p" : L"i") + fps_ss.str();
+}
+
+bool is_valid_file(const std::wstring filename)
+{                              
+       static const std::vector<std::wstring> invalid_exts = boost::assign::list_of(L".png")(L".tga")(L".bmp")(L".jpg")(L".jpeg")(L".gif")(L".tiff")(L".tif")(L".jp2")(L".jpx")(L".j2k")(L".j2c")(L".swf")(L".ct");
+       static std::vector<std::wstring>           valid_exts   = boost::assign::list_of(L".m2t")(L".mov")(L".mp4")(L".dv")(L".flv")(L".mpg")(L".wav")(L".mp3")(L".dnxhd")(L".h264")(L".prores");
+
+       auto ext = boost::to_lower_copy(boost::filesystem::path(filename).extension().wstring());
+               
+       if(std::find(valid_exts.begin(), valid_exts.end(), ext) != valid_exts.end())
+               return true;    
+       
+       if(std::find(invalid_exts.begin(), invalid_exts.end(), ext) != invalid_exts.end())
+               return false;   
+
+       auto u8filename = u8(filename);
+       
+       int score = 0;
+       AVProbeData pb = {};
+       pb.filename = u8filename.c_str();
+
+       if(av_probe_input_format2(&pb, false, &score) != nullptr)
+               return true;
+
+       std::ifstream file(filename);
+
+       std::vector<unsigned char> buf;
+       for(auto file_it = std::istreambuf_iterator<char>(file); file_it != std::istreambuf_iterator<char>() && buf.size() < 1024; ++file_it)
+               buf.push_back(*file_it);
+
+       if(buf.empty())
+               return nullptr;
+
+       pb.buf          = buf.data();
+       pb.buf_size = static_cast<int>(buf.size());
+
+       return av_probe_input_format2(&pb, true, &score) != nullptr;
+}
+
+std::wstring probe_stem(const std::wstring stem)
+{
+       auto stem2 = boost::filesystem::path(stem);
+       auto dir = stem2.parent_path();
+       for(auto it = boost::filesystem::directory_iterator(dir); it != boost::filesystem::directory_iterator(); ++it)
+       {
+               if(boost::iequals(it->path().stem().wstring(), stem2.filename().wstring()) && is_valid_file(it->path().wstring()))
+                       return it->path().wstring();
+       }
+       return L"";
+}
+//
+//void av_dup_frame(AVFrame* frame)
+//{
+//     AVFrame* new_frame = avcodec_alloc_frame();
+//
+//
+//     const uint8_t *src_data[4] = {0};
+//     memcpy(const_cast<uint8_t**>(&src_data[0]), frame->data, 4);
+//     const int src_linesizes[4] = {0};
+//     memcpy(const_cast<int*>(&src_linesizes[0]), frame->linesize, 4);
+//
+//     av_image_alloc(new_frame->data, new_frame->linesize, new_frame->width, new_frame->height, frame->format, 16);
+//
+//     av_image_copy(new_frame->data, new_frame->linesize, src_data, src_linesizes, frame->format, new_frame->width, new_frame->height);
+//
+//     frame =
+//}
+
 }}
\ No newline at end of file
index 9b82765a017fe02bcb3c12fd0658fcef3de9b566..cac1b441e2fb9cace5aa11d87a28efb026bedad2 100644 (file)
@@ -1,72 +1,72 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/forward.h>\r
-#include <common/memory.h>\r
-\r
-#include <core/video_format.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/mixer/audio/audio_mixer.h>\r
-\r
-#include <array>\r
-\r
-enum PixelFormat;\r
-struct AVFrame;\r
-struct AVFormatContext;\r
-struct AVPacket;\r
-struct AVRational;\r
-struct AVCodecContext;\r
-\r
-FORWARD2(caspar, core, struct pixel_format_desc);\r
-FORWARD2(caspar, core, class mutable_frame);\r
-FORWARD2(caspar, core, class frame_factory);\r
-\r
-namespace caspar { namespace ffmpeg {\r
-               \r
-// Utils\r
-\r
-core::field_mode                                       get_mode(const AVFrame& frame);\r
-core::mutable_frame                                    make_frame(const void* tag, const spl::shared_ptr<AVFrame>& decoded_frame, double fps, core::frame_factory& frame_factory);\r
-spl::shared_ptr<AVFrame>                       make_av_frame(core::mutable_frame& frame);\r
-spl::shared_ptr<AVFrame>                       make_av_frame(core::const_frame& frame);\r
-spl::shared_ptr<AVFrame>                       make_av_frame(std::array<uint8_t*, 4> data, const core::pixel_format_desc& pix_desc);\r
-\r
-core::pixel_format_desc                                pixel_format_desc(PixelFormat pix_fmt, int width, int height);\r
-\r
-spl::shared_ptr<AVPacket> create_packet();\r
-spl::shared_ptr<AVFrame>  create_frame();\r
-\r
-spl::shared_ptr<AVCodecContext> open_codec(AVFormatContext& context,  enum AVMediaType type, int& index);\r
-spl::shared_ptr<AVFormatContext> open_input(const std::wstring& filename);\r
-\r
-bool is_sane_fps(AVRational time_base);\r
-AVRational fix_time_base(AVRational time_base);\r
-\r
-double read_fps(AVFormatContext& context, double fail_value);\r
-\r
-std::wstring print_mode(int width, int height, double fps, bool interlaced);\r
-\r
-std::wstring probe_stem(const std::wstring stem);\r
-bool is_valid_file(const std::wstring filename);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/forward.h>
+#include <common/memory.h>
+
+#include <core/video_format.h>
+#include <core/frame/pixel_format.h>
+#include <core/mixer/audio/audio_mixer.h>
+
+#include <array>
+
+enum PixelFormat;
+struct AVFrame;
+struct AVFormatContext;
+struct AVPacket;
+struct AVRational;
+struct AVCodecContext;
+
+FORWARD2(caspar, core, struct pixel_format_desc);
+FORWARD2(caspar, core, class mutable_frame);
+FORWARD2(caspar, core, class frame_factory);
+
+namespace caspar { namespace ffmpeg {
+               
+// Utils
+
+core::field_mode                                       get_mode(const AVFrame& frame);
+core::mutable_frame                                    make_frame(const void* tag, const spl::shared_ptr<AVFrame>& decoded_frame, double fps, core::frame_factory& frame_factory);
+spl::shared_ptr<AVFrame>                       make_av_frame(core::mutable_frame& frame);
+spl::shared_ptr<AVFrame>                       make_av_frame(core::const_frame& frame);
+spl::shared_ptr<AVFrame>                       make_av_frame(std::array<uint8_t*, 4> data, const core::pixel_format_desc& pix_desc);
+
+core::pixel_format_desc                                pixel_format_desc(PixelFormat pix_fmt, int width, int height);
+
+spl::shared_ptr<AVPacket> create_packet();
+spl::shared_ptr<AVFrame>  create_frame();
+
+spl::shared_ptr<AVCodecContext> open_codec(AVFormatContext& context,  enum AVMediaType type, int& index);
+spl::shared_ptr<AVFormatContext> open_input(const std::wstring& filename);
+
+bool is_sane_fps(AVRational time_base);
+AVRational fix_time_base(AVRational time_base);
+
+double read_fps(AVFormatContext& context, double fail_value);
+
+std::wstring print_mode(int width, int height, double fps, bool interlaced);
+
+std::wstring probe_stem(const std::wstring stem);
+bool is_valid_file(const std::wstring filename);
+
 }}
\ No newline at end of file
index 3850e42756a179e884802ba18eb765ed13dccff8..e9a805ac7f81c3cc72543cc79e1135298bdc1b1e 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "video_decoder.h"\r
-\r
-#include "../util/util.h"\r
-#include "../input/input.h"\r
-\r
-#include "../../ffmpeg_error.h"\r
-\r
-#include <common/log.h>\r
-#include <core/frame/frame_transform.h>\r
-#include <core/frame/frame_factory.h>\r
-\r
-#include <boost/range/algorithm_ext/push_back.hpp>\r
-#include <boost/filesystem.hpp>\r
-\r
-#include <queue>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #include <libavcodec/avcodec.h>\r
-       #include <libavformat/avformat.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-struct video_decoder::impl : boost::noncopyable\r
-{\r
-       monitor::basic_subject                                  event_subject_;\r
-       input*                                                                  input_;\r
-       int                                                                             index_;\r
-       const spl::shared_ptr<AVCodecContext>   codec_context_;\r
-\r
-       std::queue<spl::shared_ptr<AVPacket>>   packets_;\r
-       \r
-       const AVStream*                                                 stream_;\r
-       const uint32_t                                                  nb_frames_;\r
-       const int                                                               width_;\r
-       const int                                                               height_;\r
-\r
-       bool                                                                    is_progressive_;\r
-       uint32_t                                                                file_frame_number_;\r
-       double                                                                  fps_;\r
-       \r
-       std::shared_ptr<AVPacket>                               current_packet_;\r
-\r
-public:\r
-       explicit impl(input& in) \r
-               : input_(&in)\r
-               , codec_context_(open_codec(input_->context(), AVMEDIA_TYPE_VIDEO, index_))\r
-               , stream_(input_->context().streams[index_])\r
-               , nb_frames_(static_cast<uint32_t>(stream_->nb_frames))\r
-               , width_(codec_context_->width)\r
-               , height_(codec_context_->height)\r
-               , file_frame_number_(0)\r
-               , fps_(read_fps(input_->context(), 0.0))\r
-       {\r
-       }\r
-       \r
-       std::shared_ptr<AVFrame> poll()\r
-       {                       \r
-               if(!current_packet_ && !input_->try_pop_video(current_packet_))\r
-                       return nullptr;\r
-               \r
-               std::shared_ptr<AVFrame> frame;\r
-\r
-               if(!current_packet_)            \r
-               {\r
-                       avcodec_flush_buffers(codec_context_.get());    \r
-               }\r
-               else if(!current_packet_->data)\r
-               {\r
-                       if(codec_context_->codec->capabilities & CODEC_CAP_DELAY)                       \r
-                               frame = decode(*current_packet_);\r
-                       \r
-                       if(!frame)\r
-                               current_packet_.reset();\r
-               }\r
-               else\r
-               {\r
-                       frame = decode(*current_packet_);\r
-                       \r
-                       if(current_packet_->size == 0)\r
-                               current_packet_.reset();\r
-               }\r
-                       \r
-               return frame ? frame : poll();\r
-       }\r
-\r
-       std::shared_ptr<AVFrame> decode(AVPacket& pkt)\r
-       {\r
-               auto frame = create_frame();\r
-\r
-               int got_frame = 0;\r
-               auto len = THROW_ON_ERROR2(avcodec_decode_video2(codec_context_.get(), frame.get(), &got_frame, &pkt), "[video_decocer]");\r
-                               \r
-               if(len == 0)\r
-               {\r
-                       pkt.size = 0;\r
-                       return nullptr;\r
-               }\r
-\r
-        pkt.data += len;\r
-        pkt.size -= len;\r
-\r
-               if(got_frame == 0)      \r
-                       return nullptr;\r
-               \r
-               auto stream_time_base    = stream_->time_base;\r
-               auto packet_frame_number = static_cast<uint32_t>((static_cast<double>(pkt.pts * stream_time_base.num)/stream_time_base.den)*fps_);\r
-\r
-               file_frame_number_ = packet_frame_number;\r
-\r
-               is_progressive_ = !frame->interlaced_frame;\r
-               \r
-               if(frame->repeat_pict > 0)\r
-                       CASPAR_LOG(warning) << "[video_decoder] repeat_pict not implemented.";\r
-                               \r
-               event_subject_  << monitor::event("file/video/width")   % width_\r
-                                               << monitor::event("file/video/height")  % height_\r
-                                               << monitor::event("file/video/field")   % u8(!frame->interlaced_frame ? "progressive" : (frame->top_field_first ? "upper" : "lower"))\r
-                                               << monitor::event("file/video/codec")   % u8(codec_context_->codec->long_name);\r
-               \r
-               return frame;\r
-       }\r
-       \r
-       uint32_t nb_frames() const\r
-       {\r
-               return std::max(nb_frames_, file_frame_number_);\r
-       }\r
-\r
-       std::wstring print() const\r
-       {               \r
-               return L"[video-decoder] " + u16(codec_context_->codec->long_name);\r
-       }\r
-};\r
-\r
-video_decoder::video_decoder(input& in) : impl_(new impl(in)){}\r
-video_decoder::video_decoder(video_decoder&& other) : impl_(std::move(other.impl_)){}\r
-video_decoder& video_decoder::operator=(video_decoder&& other){impl_ = std::move(other.impl_); return *this;}\r
-std::shared_ptr<AVFrame> video_decoder::operator()(){return impl_->poll();}\r
-int video_decoder::width() const{return impl_->width_;}\r
-int video_decoder::height() const{return impl_->height_;}\r
-uint32_t video_decoder::nb_frames() const{return impl_->nb_frames();}\r
-uint32_t video_decoder::file_frame_number() const{return impl_->file_frame_number_;}\r
-bool video_decoder::is_progressive() const{return impl_->is_progressive_;}\r
-std::wstring video_decoder::print() const{return impl_->print();}\r
-void video_decoder::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.subscribe(o);}\r
-void video_decoder::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../../stdafx.h"
+
+#include "video_decoder.h"
+
+#include "../util/util.h"
+#include "../input/input.h"
+
+#include "../../ffmpeg_error.h"
+
+#include <common/log.h>
+#include <core/frame/frame_transform.h>
+#include <core/frame/frame_factory.h>
+
+#include <boost/range/algorithm_ext/push_back.hpp>
+#include <boost/filesystem.hpp>
+
+#include <queue>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #include <libavcodec/avcodec.h>
+       #include <libavformat/avformat.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+namespace caspar { namespace ffmpeg {
+       
+struct video_decoder::impl : boost::noncopyable
+{
+       monitor::basic_subject                                  event_subject_;
+       input*                                                                  input_;
+       int                                                                             index_;
+       const spl::shared_ptr<AVCodecContext>   codec_context_;
+
+       std::queue<spl::shared_ptr<AVPacket>>   packets_;
+       
+       const AVStream*                                                 stream_;
+       const uint32_t                                                  nb_frames_;
+       const int                                                               width_;
+       const int                                                               height_;
+
+       bool                                                                    is_progressive_;
+       uint32_t                                                                file_frame_number_;
+       double                                                                  fps_;
+       
+       std::shared_ptr<AVPacket>                               current_packet_;
+
+public:
+       explicit impl(input& in) 
+               : input_(&in)
+               , codec_context_(open_codec(input_->context(), AVMEDIA_TYPE_VIDEO, index_))
+               , stream_(input_->context().streams[index_])
+               , nb_frames_(static_cast<uint32_t>(stream_->nb_frames))
+               , width_(codec_context_->width)
+               , height_(codec_context_->height)
+               , file_frame_number_(0)
+               , fps_(read_fps(input_->context(), 0.0))
+       {
+       }
+       
+       std::shared_ptr<AVFrame> poll()
+       {                       
+               if(!current_packet_ && !input_->try_pop_video(current_packet_))
+                       return nullptr;
+               
+               std::shared_ptr<AVFrame> frame;
+
+               if(!current_packet_)            
+               {
+                       avcodec_flush_buffers(codec_context_.get());    
+               }
+               else if(!current_packet_->data)
+               {
+                       if(codec_context_->codec->capabilities & CODEC_CAP_DELAY)                       
+                               frame = decode(*current_packet_);
+                       
+                       if(!frame)
+                               current_packet_.reset();
+               }
+               else
+               {
+                       frame = decode(*current_packet_);
+                       
+                       if(current_packet_->size == 0)
+                               current_packet_.reset();
+               }
+                       
+               return frame ? frame : poll();
+       }
+
+       std::shared_ptr<AVFrame> decode(AVPacket& pkt)
+       {
+               auto frame = create_frame();
+
+               int got_frame = 0;
+               auto len = THROW_ON_ERROR2(avcodec_decode_video2(codec_context_.get(), frame.get(), &got_frame, &pkt), "[video_decocer]");
+                               
+               if(len == 0)
+               {
+                       pkt.size = 0;
+                       return nullptr;
+               }
+
+        pkt.data += len;
+        pkt.size -= len;
+
+               if(got_frame == 0)      
+                       return nullptr;
+               
+               auto stream_time_base    = stream_->time_base;
+               auto packet_frame_number = static_cast<uint32_t>((static_cast<double>(pkt.pts * stream_time_base.num)/stream_time_base.den)*fps_);
+
+               file_frame_number_ = packet_frame_number;
+
+               is_progressive_ = !frame->interlaced_frame;
+               
+               if(frame->repeat_pict > 0)
+                       CASPAR_LOG(warning) << "[video_decoder] repeat_pict not implemented.";
+                               
+               event_subject_  << monitor::event("file/video/width")   % width_
+                                               << monitor::event("file/video/height")  % height_
+                                               << monitor::event("file/video/field")   % u8(!frame->interlaced_frame ? "progressive" : (frame->top_field_first ? "upper" : "lower"))
+                                               << monitor::event("file/video/codec")   % u8(codec_context_->codec->long_name);
+               
+               return frame;
+       }
+       
+       uint32_t nb_frames() const
+       {
+               return std::max(nb_frames_, file_frame_number_);
+       }
+
+       std::wstring print() const
+       {               
+               return L"[video-decoder] " + u16(codec_context_->codec->long_name);
+       }
+};
+
+video_decoder::video_decoder(input& in) : impl_(new impl(in)){}
+video_decoder::video_decoder(video_decoder&& other) : impl_(std::move(other.impl_)){}
+video_decoder& video_decoder::operator=(video_decoder&& other){impl_ = std::move(other.impl_); return *this;}
+std::shared_ptr<AVFrame> video_decoder::operator()(){return impl_->poll();}
+int video_decoder::width() const{return impl_->width_;}
+int video_decoder::height() const{return impl_->height_;}
+uint32_t video_decoder::nb_frames() const{return impl_->nb_frames();}
+uint32_t video_decoder::file_frame_number() const{return impl_->file_frame_number_;}
+bool video_decoder::is_progressive() const{return impl_->is_progressive_;}
+std::wstring video_decoder::print() const{return impl_->print();}
+void video_decoder::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.subscribe(o);}
+void video_decoder::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);}
+
 }}
\ No newline at end of file
index 4c53e9b1c0c2067bf5d167f9b4cd6f20575e96da..e77a16f3f47d2dd3b9a785643629b13797bb4248 100644 (file)
@@ -1,67 +1,67 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-#include <common/forward.h>\r
-\r
-#include <core/monitor/monitor.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-struct AVFormatContext;\r
-struct AVFrame;\r
-struct AVPacket;\r
-\r
-namespace caspar { namespace ffmpeg {\r
-\r
-class video_decoder : public monitor::observable\r
-                                       , boost::noncopyable\r
-{\r
-public:\r
-       explicit video_decoder(class input& input);\r
-       \r
-       video_decoder(video_decoder&& other);\r
-       video_decoder& operator=(video_decoder&& other);\r
-\r
-       std::shared_ptr<AVFrame> operator()();\r
-       \r
-       int      width() const;\r
-       int      height() const;\r
-       bool is_progressive() const;\r
-       uint32_t file_frame_number() const;\r
-\r
-       uint32_t nb_frames() const;\r
-\r
-       std::wstring print() const;\r
-               \r
-       // monitor::observable\r
-       \r
-       void subscribe(const monitor::observable::observer_ptr& o) override;\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override;\r
-\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+#include <common/forward.h>
+
+#include <core/monitor/monitor.h>
+
+#include <boost/noncopyable.hpp>
+
+struct AVFormatContext;
+struct AVFrame;
+struct AVPacket;
+
+namespace caspar { namespace ffmpeg {
+
+class video_decoder : public monitor::observable
+                                       , boost::noncopyable
+{
+public:
+       explicit video_decoder(class input& input);
+       
+       video_decoder(video_decoder&& other);
+       video_decoder& operator=(video_decoder&& other);
+
+       std::shared_ptr<AVFrame> operator()();
+       
+       int      width() const;
+       int      height() const;
+       bool is_progressive() const;
+       uint32_t file_frame_number() const;
+
+       uint32_t nb_frames() const;
+
+       std::wstring print() const;
+               
+       // monitor::observable
+       
+       void subscribe(const monitor::observable::observer_ptr& o) override;
+       void unsubscribe(const monitor::observable::observer_ptr& o) override;
+
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }}
\ No newline at end of file
index f2b946afaae3a37fd2191bec9f0ffa048cfadf85..218fe591a7ddb4d67eced93069b6420d8f13e368 100644 (file)
@@ -1,22 +1,22 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
 #include "stdafx.h"
\ No newline at end of file
index 35988d2ad339648804367543e7da49a3ccf4289d..f913689ec56841ee578942dd91860c0e8b653668 100644 (file)
@@ -1,61 +1,61 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#define NOMINMAX\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
-#include "../common/compiler/vs/disable_silly_warnings.h"\r
-\r
-#ifdef _DEBUG\r
-#include <crtdbg.h>\r
-#endif\r
-\r
-#include <assert.h>\r
-#include <memory>\r
-#include <array>\r
-#include <functional>\r
-#include <algorithm>\r
-#include <vector>\r
-#include <deque>\r
-#include <queue>\r
-#include <string>\r
-#include <math.h>\r
-\r
-#include <tbb/atomic.h>\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <boost/assign.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-#include <boost/format.hpp>\r
-#include <boost/algorithm/string.hpp>\r
-#include <boost/regex.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-#include "../common/utf.h"\r
-#include "../common/memory.h"\r
-//#include "../common/executor.h" // Can't include this due to MSVC lambda bug\r
-\r
-#include "../common/log.h"\r
-#include "../common/except.h"\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+
+#include "../common/compiler/vs/disable_silly_warnings.h"
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+#include <assert.h>
+#include <memory>
+#include <array>
+#include <functional>
+#include <algorithm>
+#include <vector>
+#include <deque>
+#include <queue>
+#include <string>
+#include <math.h>
+
+#include <tbb/atomic.h>
+#include <tbb/concurrent_queue.h>
+
+#include <boost/assign.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/range/algorithm.hpp>
+#include <boost/format.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/regex.hpp>
+#include <boost/property_tree/ptree.hpp>
+
+#include "../common/utf.h"
+#include "../common/memory.h"
+//#include "../common/executor.h" // Can't include this due to MSVC lambda bug
+
+#include "../common/log.h"
+#include "../common/except.h"
index 5517d86090d8e17fd8a9e17a74336082793df81e..b755a6a77e27bdf435274eb96f769e66d415b4e1 100644 (file)
@@ -1,67 +1,67 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "StdAfx.h"\r
-\r
-#include "flash.h"\r
-\r
-#include "producer/cg_proxy.h"\r
-#include "producer/flash_producer.h"\r
-\r
-#include <common/env.h>\r
-\r
-namespace caspar { namespace flash {\r
-\r
-void init()\r
-{\r
-       core::register_producer_factory(create_ct_producer);\r
-       core::register_producer_factory(create_swf_producer);\r
-}\r
-\r
-std::wstring cg_version()\r
-{\r
-       return L"Unknown";\r
-}\r
-\r
-std::wstring version()\r
-{              \r
-       std::wstring version = L"Not found";\r
-#ifdef WIN32\r
-       HKEY   hkey;\r
\r
-       DWORD dwType, dwSize;\r
-       if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Macromedia\\FlashPlayerActiveX"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)\r
-       {\r
-               wchar_t ver_str[1024];\r
-\r
-               dwType = REG_SZ;\r
-               dwSize = sizeof(ver_str);\r
-               RegQueryValueEx(hkey, TEXT("Version"), NULL, &dwType, (PBYTE)&ver_str, &dwSize);\r
\r
-               version = ver_str;\r
-\r
-               RegCloseKey(hkey);\r
-       }\r
-#endif\r
-       return version;\r
-}\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "StdAfx.h"
+
+#include "flash.h"
+
+#include "producer/cg_proxy.h"
+#include "producer/flash_producer.h"
+
+#include <common/env.h>
+
+namespace caspar { namespace flash {
+
+void init()
+{
+       core::register_producer_factory(create_ct_producer);
+       core::register_producer_factory(create_swf_producer);
+}
+
+std::wstring cg_version()
+{
+       return L"Unknown";
+}
+
+std::wstring version()
+{              
+       std::wstring version = L"Not found";
+#ifdef WIN32
+       HKEY   hkey;
+       DWORD dwType, dwSize;
+       if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Macromedia\\FlashPlayerActiveX"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
+       {
+               wchar_t ver_str[1024];
+
+               dwType = REG_SZ;
+               dwSize = sizeof(ver_str);
+               RegQueryValueEx(hkey, TEXT("Version"), NULL, &dwType, (PBYTE)&ver_str, &dwSize);
+               version = ver_str;
+
+               RegCloseKey(hkey);
+       }
+#endif
+       return version;
+}
+
+}}
index dbb248297ce230af9f767867fc08828012fb4b63..0b6562111a0a5ce8d2f6e3240bd61de141629b59 100644 (file)
@@ -1,33 +1,33 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace flash {\r
-\r
-void init();\r
-\r
-std::wstring cg_version();\r
-std::wstring version();\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <string>
+
+namespace caspar { namespace flash {
+
+void init();
+
+std::wstring cg_version();
+std::wstring version();
+
 }}
\ No newline at end of file
index a0de2b19e8bf86bdf0403c02860e15f912684e7e..a848ac011e55bb41e87e4e256d46bdfbc3769c51 100644 (file)
@@ -1,77 +1,77 @@
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-*  This file is part of CasparCG.\r
-*\r
-*    CasparCG is free software: you can redistribute it and/or modify\r
-*    it under the terms of the GNU General Public License as published by\r
-*    the Free Software Foundation, either version 3 of the License, or\r
-*    (at your option) any later version.\r
-*\r
-*    CasparCG is distributed in the hope that it will be useful,\r
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-*    GNU General Public License for more details.\r
-\r
-*    You should have received a copy of the GNU General Public License\r
-*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
\r
-#ifndef _TIMER_HELPER_H__\r
-#define _TIMER_HELPER_H__\r
-\r
-#include "FlashAxContainer.h"\r
-\r
-namespace caspar {\r
-namespace flash {\r
-\r
-       class TimerHelper\r
-       {\r
-               TimerHelper(const TimerHelper&);\r
-               const TimerHelper& operator=(const TimerHelper&);\r
-\r
-       public:\r
-               TimerHelper()\r
-               {}\r
-               TimerHelper(DWORD first, DWORD interv, ITimerSink* pTS) : firstTime(first), interval(interv), currentTime(first), pTimerSink(pTS)\r
-               {\r
-                       ID = first;\r
-               }\r
-               ~TimerHelper()\r
-               {\r
-               }\r
-               void Setup(DWORD first, DWORD interv, ITimerSink* pTS)\r
-               {\r
-                       firstTime = first;\r
-                       interval = interv;\r
-                       currentTime = first;\r
-                       pTimerSink = pTS;\r
-                       ID = first;\r
-               }\r
-\r
-               DWORD Invoke()\r
-               {\r
-                       if(pTimerSink != 0)\r
-                       {\r
-                               VARIANT value;\r
-                               value.vt = VT_UI4;\r
-                               value.ulVal = currentTime;\r
-\r
-                               pTimerSink->OnTimer(value);\r
-                               currentTime += interval;\r
-                       }\r
-                       return currentTime;\r
-               }\r
-\r
-               DWORD firstTime;\r
-               DWORD interval;\r
-               DWORD currentTime;\r
-               ATL::CComPtr<ITimerSink> pTimerSink;\r
-               DWORD ID;\r
-       };\r
-\r
-}      //namespace flash\r
-}      //namespace caspar\r
-\r
+/*
+* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
+*
+*  This file is part of CasparCG.
+*
+*    CasparCG is free software: you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation, either version 3 of the License, or
+*    (at your option) any later version.
+*
+*    CasparCG is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+
+*    You should have received a copy of the GNU General Public License
+*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+#ifndef _TIMER_HELPER_H__
+#define _TIMER_HELPER_H__
+
+#include "FlashAxContainer.h"
+
+namespace caspar {
+namespace flash {
+
+       class TimerHelper
+       {
+               TimerHelper(const TimerHelper&);
+               const TimerHelper& operator=(const TimerHelper&);
+
+       public:
+               TimerHelper()
+               {}
+               TimerHelper(DWORD first, DWORD interv, ITimerSink* pTS) : firstTime(first), interval(interv), currentTime(first), pTimerSink(pTS)
+               {
+                       ID = first;
+               }
+               ~TimerHelper()
+               {
+               }
+               void Setup(DWORD first, DWORD interv, ITimerSink* pTS)
+               {
+                       firstTime = first;
+                       interval = interv;
+                       currentTime = first;
+                       pTimerSink = pTS;
+                       ID = first;
+               }
+
+               DWORD Invoke()
+               {
+                       if(pTimerSink != 0)
+                       {
+                               VARIANT value;
+                               value.vt = VT_UI4;
+                               value.ulVal = currentTime;
+
+                               pTimerSink->OnTimer(value);
+                               currentTime += interval;
+                       }
+                       return currentTime;
+               }
+
+               DWORD firstTime;
+               DWORD interval;
+               DWORD currentTime;
+               ATL::CComPtr<ITimerSink> pTimerSink;
+               DWORD ID;
+       };
+
+}      //namespace flash
+}      //namespace caspar
+
 #endif //_TIMER_HELPER_H__
\ No newline at end of file
index da7aa8b56787dee9e45f0c05420e451470d065e7..18f965487406bed425797a2cc5663590cad0de36 100644 (file)
-\r
-\r
-/* this ALWAYS GENERATED file contains the definitions for the interfaces */\r
-\r
-\r
- /* File created by MIDL compiler version 6.00.0366 */\r
-/* at Tue Mar 18 13:05:00 2008\r
- */\r
-/* Compiler settings for .\flash\Flash9e.IDL:\r
-    Oicf, W4, Zp8, env=Win32 (32b run)\r
-    protocol : dce , ms_ext, c_ext, robust\r
-    error checks: allocation ref bounds_check enum stub_data \r
-    VC __declspec() decoration level: \r
-         __declspec(uuid()), __declspec(selectany), __declspec(novtable)\r
-         DECLSPEC_UUID(), MIDL_INTERFACE()\r
-*/\r
-//@@MIDL_FILE_HEADING(  )\r
-\r
-#pragma warning( disable: 4049 )  /* more than 64k source lines */\r
-\r
-\r
-/* verify that the <rpcndr.h> version is high enough to compile this file*/\r
-#ifndef __REQUIRED_RPCNDR_H_VERSION__\r
-#define __REQUIRED_RPCNDR_H_VERSION__ 475\r
-#endif\r
-\r
-#include "rpc.h"\r
-#include "rpcndr.h"\r
-#include <dispex.h>\r
-\r
-#ifndef __RPCNDR_H_VERSION__\r
-#error this stub requires an updated version of <rpcndr.h>\r
-#endif // __RPCNDR_H_VERSION__\r
-\r
-\r
-#ifndef __axflash_h__\r
-#define __axflash_h__\r
-\r
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)\r
-#pragma once\r
-#endif\r
-\r
-/* Forward Declarations */ \r
-\r
-#ifndef __IShockwaveFlash_FWD_DEFINED__\r
-#define __IShockwaveFlash_FWD_DEFINED__\r
-typedef interface IShockwaveFlash IShockwaveFlash;\r
-#endif         /* __IShockwaveFlash_FWD_DEFINED__ */\r
-\r
-\r
-#ifndef ___IShockwaveFlashEvents_FWD_DEFINED__\r
-#define ___IShockwaveFlashEvents_FWD_DEFINED__\r
-typedef interface _IShockwaveFlashEvents _IShockwaveFlashEvents;\r
-#endif         /* ___IShockwaveFlashEvents_FWD_DEFINED__ */\r
-\r
-\r
-#ifndef __IFlashFactory_FWD_DEFINED__\r
-#define __IFlashFactory_FWD_DEFINED__\r
-typedef interface IFlashFactory IFlashFactory;\r
-#endif         /* __IFlashFactory_FWD_DEFINED__ */\r
-\r
-\r
-#ifndef __IDispatchEx_FWD_DEFINED__\r
-#define __IDispatchEx_FWD_DEFINED__\r
-typedef interface IDispatchEx IDispatchEx;\r
-#endif         /* __IDispatchEx_FWD_DEFINED__ */\r
-\r
-\r
-#ifndef __IFlashObjectInterface_FWD_DEFINED__\r
-#define __IFlashObjectInterface_FWD_DEFINED__\r
-typedef interface IFlashObjectInterface IFlashObjectInterface;\r
-#endif         /* __IFlashObjectInterface_FWD_DEFINED__ */\r
-\r
-\r
-#ifndef __IServiceProvider_FWD_DEFINED__\r
-#define __IServiceProvider_FWD_DEFINED__\r
-typedef interface IServiceProvider IServiceProvider;\r
-#endif         /* __IServiceProvider_FWD_DEFINED__ */\r
-\r
-\r
-#ifndef __ShockwaveFlash_FWD_DEFINED__\r
-#define __ShockwaveFlash_FWD_DEFINED__\r
-\r
-#ifdef __cplusplus\r
-typedef class ShockwaveFlash ShockwaveFlash;\r
-#else\r
-typedef struct ShockwaveFlash ShockwaveFlash;\r
-#endif /* __cplusplus */\r
-\r
-#endif         /* __ShockwaveFlash_FWD_DEFINED__ */\r
-\r
-\r
-#ifndef __FlashObjectInterface_FWD_DEFINED__\r
-#define __FlashObjectInterface_FWD_DEFINED__\r
-\r
-#ifdef __cplusplus\r
-typedef class FlashObjectInterface FlashObjectInterface;\r
-#else\r
-typedef struct FlashObjectInterface FlashObjectInterface;\r
-#endif /* __cplusplus */\r
-\r
-#endif         /* __FlashObjectInterface_FWD_DEFINED__ */\r
-\r
-\r
-#ifdef __cplusplus\r
-extern "C"{\r
-#endif \r
-\r
-void * __RPC_USER MIDL_user_allocate(size_t);\r
-void __RPC_USER MIDL_user_free( void * ); \r
-\r
-\r
-#ifndef __ShockwaveFlashObjects_LIBRARY_DEFINED__\r
-#define __ShockwaveFlashObjects_LIBRARY_DEFINED__\r
-\r
-/* library ShockwaveFlashObjects */\r
-/* [custom][custom][helpstring][version][uuid] */ \r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-EXTERN_C const IID LIBID_ShockwaveFlashObjects;\r
-\r
-#ifndef __IShockwaveFlash_INTERFACE_DEFINED__\r
-#define __IShockwaveFlash_INTERFACE_DEFINED__\r
-\r
-/* interface IShockwaveFlash */\r
-/* [object][oleautomation][dual][helpstring][uuid] */ \r
-\r
-\r
-EXTERN_C const IID IID_IShockwaveFlash;\r
-\r
-#if defined(__cplusplus) && !defined(CINTERFACE)\r
-    \r
-    MIDL_INTERFACE("D27CDB6C-AE6D-11CF-96B8-444553540000")\r
-    IShockwaveFlash : public IDispatch\r
-    {\r
-    public:\r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_ReadyState( \r
-            /* [retval][out] */ long *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_TotalFrames( \r
-            /* [retval][out] */ long *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Playing( \r
-            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Playing( \r
-            /* [in] */ VARIANT_BOOL pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Quality( \r
-            /* [retval][out] */ int *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Quality( \r
-            /* [in] */ int pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_ScaleMode( \r
-            /* [retval][out] */ int *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_ScaleMode( \r
-            /* [in] */ int pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_AlignMode( \r
-            /* [retval][out] */ int *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_AlignMode( \r
-            /* [in] */ int pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_BackgroundColor( \r
-            /* [retval][out] */ long *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_BackgroundColor( \r
-            /* [in] */ long pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Loop( \r
-            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Loop( \r
-            /* [in] */ VARIANT_BOOL pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Movie( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Movie( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE receiveNum( \r
-            /* [retval][out] */ long *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_FrameNum( \r
-            /* [in] */ long pVal) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetZoomRect( \r
-            /* [in] */ long left,\r
-            /* [in] */ long top,\r
-            /* [in] */ long right,\r
-            /* [in] */ long bottom) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Zoom( \r
-            /* [in] */ int factor) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Pan( \r
-            /* [in] */ long x,\r
-            /* [in] */ long y,\r
-            /* [in] */ int mode) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Play( void) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Stop( void) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Back( void) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Forward( void) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Rewind( void) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE StopPlay( void) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GotoFrame( \r
-            /* [in] */ long FrameNum) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE CurrentFrame( \r
-            /* [retval][out] */ long *FrameNum) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IsPlaying( \r
-            /* [retval][out] */ VARIANT_BOOL *Playing) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE PercentLoaded( \r
-            /* [retval][out] */ long *percent) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE FrameLoaded( \r
-            /* [in] */ long FrameNum,\r
-            /* [retval][out] */ VARIANT_BOOL *loaded) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE FlashVersion( \r
-            /* [retval][out] */ long *version) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_WMode( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_WMode( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_SAlign( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_SAlign( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Menu( \r
-            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Menu( \r
-            /* [in] */ VARIANT_BOOL pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Base( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Base( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Scale( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Scale( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_DeviceFont( \r
-            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_DeviceFont( \r
-            /* [in] */ VARIANT_BOOL pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_EmbedMovie( \r
-            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_EmbedMovie( \r
-            /* [in] */ VARIANT_BOOL pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_BGColor( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_BGColor( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Quality2( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Quality2( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE LoadMovie( \r
-            /* [in] */ int layer,\r
-            /* [in] */ BSTR url) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TGotoFrame( \r
-            /* [in] */ BSTR target,\r
-            /* [in] */ long FrameNum) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TGotoLabel( \r
-            /* [in] */ BSTR target,\r
-            /* [in] */ BSTR label) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TCurrentFrame( \r
-            /* [in] */ BSTR target,\r
-            /* [retval][out] */ long *FrameNum) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TCurrentLabel( \r
-            /* [in] */ BSTR target,\r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TPlay( \r
-            /* [in] */ BSTR target) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TStopPlay( \r
-            /* [in] */ BSTR target) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetVariable( \r
-            /* [in] */ BSTR name,\r
-            /* [in] */ BSTR value) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetVariable( \r
-            /* [in] */ BSTR name,\r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TSetProperty( \r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int property,\r
-            /* [in] */ BSTR value) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TGetProperty( \r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int property,\r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TCallFrame( \r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int FrameNum) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TCallLabel( \r
-            /* [in] */ BSTR target,\r
-            /* [in] */ BSTR label) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TSetPropertyNum( \r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int property,\r
-            /* [in] */ double value) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TGetPropertyNum( \r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int property,\r
-            /* [retval][out] */ double *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TGetPropertyAsNumber( \r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int property,\r
-            /* [retval][out] */ double *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_SWRemote( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_SWRemote( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_FlashVars( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_FlashVars( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_AllowScriptAccess( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_AllowScriptAccess( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_MovieData( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_MovieData( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_InlineData( \r
-            /* [retval][out] */ IUnknown **ppIUnknown) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_InlineData( \r
-            /* [in] */ IUnknown *ppIUnknown) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_SeamlessTabbing( \r
-            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_SeamlessTabbing( \r
-            /* [in] */ VARIANT_BOOL pVal) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE EnforceLocalSecurity( void) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Profile( \r
-            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Profile( \r
-            /* [in] */ VARIANT_BOOL pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_ProfileAddress( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_ProfileAddress( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_ProfilePort( \r
-            /* [retval][out] */ long *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_ProfilePort( \r
-            /* [in] */ long pVal) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE CallFunction( \r
-            /* [in] */ BSTR request,\r
-            /* [retval][out] */ BSTR *response) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetReturnValue( \r
-            /* [in] */ BSTR returnValue) = 0;\r
-        \r
-        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE DisableLocalSecurity( void) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_AllowNetworking( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_AllowNetworking( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_AllowFullScreen( \r
-            /* [retval][out] */ BSTR *pVal) = 0;\r
-        \r
-        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_AllowFullScreen( \r
-            /* [in] */ BSTR pVal) = 0;\r
-        \r
-    };\r
-    \r
-#else  /* C style interface */\r
-\r
-    typedef struct IShockwaveFlashVtbl\r
-    {\r
-        BEGIN_INTERFACE\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ REFIID riid,\r
-            /* [iid_is][out] */ void **ppvObject);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *AddRef )( \r
-            IShockwaveFlash * This);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *Release )( \r
-            IShockwaveFlash * This);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( \r
-            IShockwaveFlash * This,\r
-            /* [out] */ UINT *pctinfo);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ UINT iTInfo,\r
-            /* [in] */ LCID lcid,\r
-            /* [out] */ ITypeInfo **ppTInfo);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ REFIID riid,\r
-            /* [size_is][in] */ LPOLESTR *rgszNames,\r
-            /* [in] */ UINT cNames,\r
-            /* [in] */ LCID lcid,\r
-            /* [size_is][out] */ DISPID *rgDispId);\r
-        \r
-        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ DISPID dispIdMember,\r
-            /* [in] */ REFIID riid,\r
-            /* [in] */ LCID lcid,\r
-            /* [in] */ WORD wFlags,\r
-            /* [out][in] */ DISPPARAMS *pDispParams,\r
-            /* [out] */ VARIANT *pVarResult,\r
-            /* [out] */ EXCEPINFO *pExcepInfo,\r
-            /* [out] */ UINT *puArgErr);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_ReadyState )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ long *pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_TotalFrames )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ long *pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Playing )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ VARIANT_BOOL *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Playing )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ VARIANT_BOOL pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Quality )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ int *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Quality )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ int pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_ScaleMode )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ int *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_ScaleMode )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ int pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_AlignMode )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ int *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_AlignMode )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ int pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_BackgroundColor )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ long *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_BackgroundColor )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ long pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Loop )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ VARIANT_BOOL *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Loop )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ VARIANT_BOOL pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Movie )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Movie )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *receiveNum )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ long *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_FrameNum )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ long pVal);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetZoomRect )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ long left,\r
-            /* [in] */ long top,\r
-            /* [in] */ long right,\r
-            /* [in] */ long bottom);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Zoom )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ int factor);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Pan )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ long x,\r
-            /* [in] */ long y,\r
-            /* [in] */ int mode);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Play )( \r
-            IShockwaveFlash * This);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Stop )( \r
-            IShockwaveFlash * This);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Back )( \r
-            IShockwaveFlash * This);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Forward )( \r
-            IShockwaveFlash * This);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Rewind )( \r
-            IShockwaveFlash * This);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *StopPlay )( \r
-            IShockwaveFlash * This);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GotoFrame )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ long FrameNum);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *CurrentFrame )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ long *FrameNum);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *IsPlaying )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ VARIANT_BOOL *Playing);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *PercentLoaded )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ long *percent);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *FrameLoaded )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ long FrameNum,\r
-            /* [retval][out] */ VARIANT_BOOL *loaded);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *FlashVersion )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ long *version);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_WMode )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_WMode )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_SAlign )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_SAlign )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Menu )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ VARIANT_BOOL *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Menu )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ VARIANT_BOOL pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Base )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Base )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Scale )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Scale )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_DeviceFont )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ VARIANT_BOOL *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_DeviceFont )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ VARIANT_BOOL pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_EmbedMovie )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ VARIANT_BOOL *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_EmbedMovie )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ VARIANT_BOOL pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_BGColor )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_BGColor )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Quality2 )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Quality2 )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *LoadMovie )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ int layer,\r
-            /* [in] */ BSTR url);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TGotoFrame )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [in] */ long FrameNum);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TGotoLabel )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [in] */ BSTR label);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TCurrentFrame )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [retval][out] */ long *FrameNum);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TCurrentLabel )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TPlay )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TStopPlay )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetVariable )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR name,\r
-            /* [in] */ BSTR value);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetVariable )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR name,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TSetProperty )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int property,\r
-            /* [in] */ BSTR value);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TGetProperty )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int property,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TCallFrame )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int FrameNum);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TCallLabel )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [in] */ BSTR label);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TSetPropertyNum )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int property,\r
-            /* [in] */ double value);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TGetPropertyNum )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int property,\r
-            /* [retval][out] */ double *pVal);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TGetPropertyAsNumber )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR target,\r
-            /* [in] */ int property,\r
-            /* [retval][out] */ double *pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_SWRemote )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_SWRemote )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_FlashVars )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_FlashVars )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_AllowScriptAccess )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_AllowScriptAccess )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_MovieData )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_MovieData )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_InlineData )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ IUnknown **ppIUnknown);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_InlineData )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ IUnknown *ppIUnknown);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_SeamlessTabbing )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ VARIANT_BOOL *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_SeamlessTabbing )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ VARIANT_BOOL pVal);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *EnforceLocalSecurity )( \r
-            IShockwaveFlash * This);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Profile )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ VARIANT_BOOL *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Profile )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ VARIANT_BOOL pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_ProfileAddress )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_ProfileAddress )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_ProfilePort )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ long *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_ProfilePort )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ long pVal);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *CallFunction )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR request,\r
-            /* [retval][out] */ BSTR *response);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetReturnValue )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR returnValue);\r
-        \r
-        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *DisableLocalSecurity )( \r
-            IShockwaveFlash * This);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_AllowNetworking )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_AllowNetworking )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_AllowFullScreen )( \r
-            IShockwaveFlash * This,\r
-            /* [retval][out] */ BSTR *pVal);\r
-        \r
-        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_AllowFullScreen )( \r
-            IShockwaveFlash * This,\r
-            /* [in] */ BSTR pVal);\r
-        \r
-        END_INTERFACE\r
-    } IShockwaveFlashVtbl;\r
-\r
-    interface IShockwaveFlash\r
-    {\r
-        CONST_VTBL struct IShockwaveFlashVtbl *lpVtbl;\r
-    };\r
-\r
-    \r
-\r
-#ifdef COBJMACROS\r
-\r
-\r
-#define IShockwaveFlash_QueryInterface(This,riid,ppvObject)    \\r
-    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)\r
-\r
-#define IShockwaveFlash_AddRef(This)   \\r
-    (This)->lpVtbl -> AddRef(This)\r
-\r
-#define IShockwaveFlash_Release(This)  \\r
-    (This)->lpVtbl -> Release(This)\r
-\r
-\r
-#define IShockwaveFlash_GetTypeInfoCount(This,pctinfo) \\r
-    (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)\r
-\r
-#define IShockwaveFlash_GetTypeInfo(This,iTInfo,lcid,ppTInfo)  \\r
-    (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)\r
-\r
-#define IShockwaveFlash_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)        \\r
-    (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)\r
-\r
-#define IShockwaveFlash_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)  \\r
-    (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)\r
-\r
-\r
-#define IShockwaveFlash_get_ReadyState(This,pVal)      \\r
-    (This)->lpVtbl -> get_ReadyState(This,pVal)\r
-\r
-#define IShockwaveFlash_get_TotalFrames(This,pVal)     \\r
-    (This)->lpVtbl -> get_TotalFrames(This,pVal)\r
-\r
-#define IShockwaveFlash_get_Playing(This,pVal) \\r
-    (This)->lpVtbl -> get_Playing(This,pVal)\r
-\r
-#define IShockwaveFlash_put_Playing(This,pVal) \\r
-    (This)->lpVtbl -> put_Playing(This,pVal)\r
-\r
-#define IShockwaveFlash_get_Quality(This,pVal) \\r
-    (This)->lpVtbl -> get_Quality(This,pVal)\r
-\r
-#define IShockwaveFlash_put_Quality(This,pVal) \\r
-    (This)->lpVtbl -> put_Quality(This,pVal)\r
-\r
-#define IShockwaveFlash_get_ScaleMode(This,pVal)       \\r
-    (This)->lpVtbl -> get_ScaleMode(This,pVal)\r
-\r
-#define IShockwaveFlash_put_ScaleMode(This,pVal)       \\r
-    (This)->lpVtbl -> put_ScaleMode(This,pVal)\r
-\r
-#define IShockwaveFlash_get_AlignMode(This,pVal)       \\r
-    (This)->lpVtbl -> get_AlignMode(This,pVal)\r
-\r
-#define IShockwaveFlash_put_AlignMode(This,pVal)       \\r
-    (This)->lpVtbl -> put_AlignMode(This,pVal)\r
-\r
-#define IShockwaveFlash_get_BackgroundColor(This,pVal) \\r
-    (This)->lpVtbl -> get_BackgroundColor(This,pVal)\r
-\r
-#define IShockwaveFlash_put_BackgroundColor(This,pVal) \\r
-    (This)->lpVtbl -> put_BackgroundColor(This,pVal)\r
-\r
-#define IShockwaveFlash_get_Loop(This,pVal)    \\r
-    (This)->lpVtbl -> get_Loop(This,pVal)\r
-\r
-#define IShockwaveFlash_put_Loop(This,pVal)    \\r
-    (This)->lpVtbl -> put_Loop(This,pVal)\r
-\r
-#define IShockwaveFlash_get_Movie(This,pVal)   \\r
-    (This)->lpVtbl -> get_Movie(This,pVal)\r
-\r
-#define IShockwaveFlash_put_Movie(This,pVal)   \\r
-    (This)->lpVtbl -> put_Movie(This,pVal)\r
-\r
-#define IShockwaveFlash_receiveNum(This,pVal)  \\r
-    (This)->lpVtbl -> receiveNum(This,pVal)\r
-\r
-#define IShockwaveFlash_put_FrameNum(This,pVal)        \\r
-    (This)->lpVtbl -> put_FrameNum(This,pVal)\r
-\r
-#define IShockwaveFlash_SetZoomRect(This,left,top,right,bottom)        \\r
-    (This)->lpVtbl -> SetZoomRect(This,left,top,right,bottom)\r
-\r
-#define IShockwaveFlash_Zoom(This,factor)      \\r
-    (This)->lpVtbl -> Zoom(This,factor)\r
-\r
-#define IShockwaveFlash_Pan(This,x,y,mode)     \\r
-    (This)->lpVtbl -> Pan(This,x,y,mode)\r
-\r
-#define IShockwaveFlash_Play(This)     \\r
-    (This)->lpVtbl -> Play(This)\r
-\r
-#define IShockwaveFlash_Stop(This)     \\r
-    (This)->lpVtbl -> Stop(This)\r
-\r
-#define IShockwaveFlash_Back(This)     \\r
-    (This)->lpVtbl -> Back(This)\r
-\r
-#define IShockwaveFlash_Forward(This)  \\r
-    (This)->lpVtbl -> Forward(This)\r
-\r
-#define IShockwaveFlash_Rewind(This)   \\r
-    (This)->lpVtbl -> Rewind(This)\r
-\r
-#define IShockwaveFlash_StopPlay(This) \\r
-    (This)->lpVtbl -> StopPlay(This)\r
-\r
-#define IShockwaveFlash_GotoFrame(This,FrameNum)       \\r
-    (This)->lpVtbl -> GotoFrame(This,FrameNum)\r
-\r
-#define IShockwaveFlash_CurrentFrame(This,FrameNum)    \\r
-    (This)->lpVtbl -> CurrentFrame(This,FrameNum)\r
-\r
-#define IShockwaveFlash_IsPlaying(This,Playing)        \\r
-    (This)->lpVtbl -> IsPlaying(This,Playing)\r
-\r
-#define IShockwaveFlash_PercentLoaded(This,percent)    \\r
-    (This)->lpVtbl -> PercentLoaded(This,percent)\r
-\r
-#define IShockwaveFlash_FrameLoaded(This,FrameNum,loaded)      \\r
-    (This)->lpVtbl -> FrameLoaded(This,FrameNum,loaded)\r
-\r
-#define IShockwaveFlash_FlashVersion(This,version)     \\r
-    (This)->lpVtbl -> FlashVersion(This,version)\r
-\r
-#define IShockwaveFlash_get_WMode(This,pVal)   \\r
-    (This)->lpVtbl -> get_WMode(This,pVal)\r
-\r
-#define IShockwaveFlash_put_WMode(This,pVal)   \\r
-    (This)->lpVtbl -> put_WMode(This,pVal)\r
-\r
-#define IShockwaveFlash_get_SAlign(This,pVal)  \\r
-    (This)->lpVtbl -> get_SAlign(This,pVal)\r
-\r
-#define IShockwaveFlash_put_SAlign(This,pVal)  \\r
-    (This)->lpVtbl -> put_SAlign(This,pVal)\r
-\r
-#define IShockwaveFlash_get_Menu(This,pVal)    \\r
-    (This)->lpVtbl -> get_Menu(This,pVal)\r
-\r
-#define IShockwaveFlash_put_Menu(This,pVal)    \\r
-    (This)->lpVtbl -> put_Menu(This,pVal)\r
-\r
-#define IShockwaveFlash_get_Base(This,pVal)    \\r
-    (This)->lpVtbl -> get_Base(This,pVal)\r
-\r
-#define IShockwaveFlash_put_Base(This,pVal)    \\r
-    (This)->lpVtbl -> put_Base(This,pVal)\r
-\r
-#define IShockwaveFlash_get_Scale(This,pVal)   \\r
-    (This)->lpVtbl -> get_Scale(This,pVal)\r
-\r
-#define IShockwaveFlash_put_Scale(This,pVal)   \\r
-    (This)->lpVtbl -> put_Scale(This,pVal)\r
-\r
-#define IShockwaveFlash_get_DeviceFont(This,pVal)      \\r
-    (This)->lpVtbl -> get_DeviceFont(This,pVal)\r
-\r
-#define IShockwaveFlash_put_DeviceFont(This,pVal)      \\r
-    (This)->lpVtbl -> put_DeviceFont(This,pVal)\r
-\r
-#define IShockwaveFlash_get_EmbedMovie(This,pVal)      \\r
-    (This)->lpVtbl -> get_EmbedMovie(This,pVal)\r
-\r
-#define IShockwaveFlash_put_EmbedMovie(This,pVal)      \\r
-    (This)->lpVtbl -> put_EmbedMovie(This,pVal)\r
-\r
-#define IShockwaveFlash_get_BGColor(This,pVal) \\r
-    (This)->lpVtbl -> get_BGColor(This,pVal)\r
-\r
-#define IShockwaveFlash_put_BGColor(This,pVal) \\r
-    (This)->lpVtbl -> put_BGColor(This,pVal)\r
-\r
-#define IShockwaveFlash_get_Quality2(This,pVal)        \\r
-    (This)->lpVtbl -> get_Quality2(This,pVal)\r
-\r
-#define IShockwaveFlash_put_Quality2(This,pVal)        \\r
-    (This)->lpVtbl -> put_Quality2(This,pVal)\r
-\r
-#define IShockwaveFlash_LoadMovie(This,layer,url)      \\r
-    (This)->lpVtbl -> LoadMovie(This,layer,url)\r
-\r
-#define IShockwaveFlash_TGotoFrame(This,target,FrameNum)       \\r
-    (This)->lpVtbl -> TGotoFrame(This,target,FrameNum)\r
-\r
-#define IShockwaveFlash_TGotoLabel(This,target,label)  \\r
-    (This)->lpVtbl -> TGotoLabel(This,target,label)\r
-\r
-#define IShockwaveFlash_TCurrentFrame(This,target,FrameNum)    \\r
-    (This)->lpVtbl -> TCurrentFrame(This,target,FrameNum)\r
-\r
-#define IShockwaveFlash_TCurrentLabel(This,target,pVal)        \\r
-    (This)->lpVtbl -> TCurrentLabel(This,target,pVal)\r
-\r
-#define IShockwaveFlash_TPlay(This,target)     \\r
-    (This)->lpVtbl -> TPlay(This,target)\r
-\r
-#define IShockwaveFlash_TStopPlay(This,target) \\r
-    (This)->lpVtbl -> TStopPlay(This,target)\r
-\r
-#define IShockwaveFlash_SetVariable(This,name,value)   \\r
-    (This)->lpVtbl -> SetVariable(This,name,value)\r
-\r
-#define IShockwaveFlash_GetVariable(This,name,pVal)    \\r
-    (This)->lpVtbl -> GetVariable(This,name,pVal)\r
-\r
-#define IShockwaveFlash_TSetProperty(This,target,property,value)       \\r
-    (This)->lpVtbl -> TSetProperty(This,target,property,value)\r
-\r
-#define IShockwaveFlash_TGetProperty(This,target,property,pVal)        \\r
-    (This)->lpVtbl -> TGetProperty(This,target,property,pVal)\r
-\r
-#define IShockwaveFlash_TCallFrame(This,target,FrameNum)       \\r
-    (This)->lpVtbl -> TCallFrame(This,target,FrameNum)\r
-\r
-#define IShockwaveFlash_TCallLabel(This,target,label)  \\r
-    (This)->lpVtbl -> TCallLabel(This,target,label)\r
-\r
-#define IShockwaveFlash_TSetPropertyNum(This,target,property,value)    \\r
-    (This)->lpVtbl -> TSetPropertyNum(This,target,property,value)\r
-\r
-#define IShockwaveFlash_TGetPropertyNum(This,target,property,pVal)     \\r
-    (This)->lpVtbl -> TGetPropertyNum(This,target,property,pVal)\r
-\r
-#define IShockwaveFlash_TGetPropertyAsNumber(This,target,property,pVal)        \\r
-    (This)->lpVtbl -> TGetPropertyAsNumber(This,target,property,pVal)\r
-\r
-#define IShockwaveFlash_get_SWRemote(This,pVal)        \\r
-    (This)->lpVtbl -> get_SWRemote(This,pVal)\r
-\r
-#define IShockwaveFlash_put_SWRemote(This,pVal)        \\r
-    (This)->lpVtbl -> put_SWRemote(This,pVal)\r
-\r
-#define IShockwaveFlash_get_FlashVars(This,pVal)       \\r
-    (This)->lpVtbl -> get_FlashVars(This,pVal)\r
-\r
-#define IShockwaveFlash_put_FlashVars(This,pVal)       \\r
-    (This)->lpVtbl -> put_FlashVars(This,pVal)\r
-\r
-#define IShockwaveFlash_get_AllowScriptAccess(This,pVal)       \\r
-    (This)->lpVtbl -> get_AllowScriptAccess(This,pVal)\r
-\r
-#define IShockwaveFlash_put_AllowScriptAccess(This,pVal)       \\r
-    (This)->lpVtbl -> put_AllowScriptAccess(This,pVal)\r
-\r
-#define IShockwaveFlash_get_MovieData(This,pVal)       \\r
-    (This)->lpVtbl -> get_MovieData(This,pVal)\r
-\r
-#define IShockwaveFlash_put_MovieData(This,pVal)       \\r
-    (This)->lpVtbl -> put_MovieData(This,pVal)\r
-\r
-#define IShockwaveFlash_get_InlineData(This,ppIUnknown)        \\r
-    (This)->lpVtbl -> get_InlineData(This,ppIUnknown)\r
-\r
-#define IShockwaveFlash_put_InlineData(This,ppIUnknown)        \\r
-    (This)->lpVtbl -> put_InlineData(This,ppIUnknown)\r
-\r
-#define IShockwaveFlash_get_SeamlessTabbing(This,pVal) \\r
-    (This)->lpVtbl -> get_SeamlessTabbing(This,pVal)\r
-\r
-#define IShockwaveFlash_put_SeamlessTabbing(This,pVal) \\r
-    (This)->lpVtbl -> put_SeamlessTabbing(This,pVal)\r
-\r
-#define IShockwaveFlash_EnforceLocalSecurity(This)     \\r
-    (This)->lpVtbl -> EnforceLocalSecurity(This)\r
-\r
-#define IShockwaveFlash_get_Profile(This,pVal) \\r
-    (This)->lpVtbl -> get_Profile(This,pVal)\r
-\r
-#define IShockwaveFlash_put_Profile(This,pVal) \\r
-    (This)->lpVtbl -> put_Profile(This,pVal)\r
-\r
-#define IShockwaveFlash_get_ProfileAddress(This,pVal)  \\r
-    (This)->lpVtbl -> get_ProfileAddress(This,pVal)\r
-\r
-#define IShockwaveFlash_put_ProfileAddress(This,pVal)  \\r
-    (This)->lpVtbl -> put_ProfileAddress(This,pVal)\r
-\r
-#define IShockwaveFlash_get_ProfilePort(This,pVal)     \\r
-    (This)->lpVtbl -> get_ProfilePort(This,pVal)\r
-\r
-#define IShockwaveFlash_put_ProfilePort(This,pVal)     \\r
-    (This)->lpVtbl -> put_ProfilePort(This,pVal)\r
-\r
-#define IShockwaveFlash_CallFunction(This,request,response)    \\r
-    (This)->lpVtbl -> CallFunction(This,request,response)\r
-\r
-#define IShockwaveFlash_SetReturnValue(This,returnValue)       \\r
-    (This)->lpVtbl -> SetReturnValue(This,returnValue)\r
-\r
-#define IShockwaveFlash_DisableLocalSecurity(This)     \\r
-    (This)->lpVtbl -> DisableLocalSecurity(This)\r
-\r
-#define IShockwaveFlash_get_AllowNetworking(This,pVal) \\r
-    (This)->lpVtbl -> get_AllowNetworking(This,pVal)\r
-\r
-#define IShockwaveFlash_put_AllowNetworking(This,pVal) \\r
-    (This)->lpVtbl -> put_AllowNetworking(This,pVal)\r
-\r
-#define IShockwaveFlash_get_AllowFullScreen(This,pVal) \\r
-    (This)->lpVtbl -> get_AllowFullScreen(This,pVal)\r
-\r
-#define IShockwaveFlash_put_AllowFullScreen(This,pVal) \\r
-    (This)->lpVtbl -> put_AllowFullScreen(This,pVal)\r
-\r
-#endif /* COBJMACROS */\r
-\r
-\r
-#endif         /* C style interface */\r
-\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_ReadyState_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ long *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_ReadyState_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_TotalFrames_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ long *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_TotalFrames_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Playing_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ VARIANT_BOOL *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_Playing_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Playing_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ VARIANT_BOOL pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_Playing_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Quality_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ int *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_Quality_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Quality_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ int pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_Quality_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_ScaleMode_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ int *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_ScaleMode_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_ScaleMode_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ int pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_ScaleMode_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_AlignMode_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ int *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_AlignMode_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_AlignMode_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ int pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_AlignMode_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_BackgroundColor_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ long *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_BackgroundColor_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_BackgroundColor_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ long pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_BackgroundColor_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Loop_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ VARIANT_BOOL *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_Loop_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Loop_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ VARIANT_BOOL pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_Loop_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Movie_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_Movie_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Movie_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_Movie_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_receiveNum_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ long *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_receiveNum_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_FrameNum_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ long pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_FrameNum_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_SetZoomRect_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ long left,\r
-    /* [in] */ long top,\r
-    /* [in] */ long right,\r
-    /* [in] */ long bottom);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_SetZoomRect_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Zoom_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ int factor);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_Zoom_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Pan_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ long x,\r
-    /* [in] */ long y,\r
-    /* [in] */ int mode);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_Pan_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Play_Proxy( \r
-    IShockwaveFlash * This);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_Play_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Stop_Proxy( \r
-    IShockwaveFlash * This);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_Stop_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Back_Proxy( \r
-    IShockwaveFlash * This);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_Back_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Forward_Proxy( \r
-    IShockwaveFlash * This);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_Forward_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Rewind_Proxy( \r
-    IShockwaveFlash * This);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_Rewind_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_StopPlay_Proxy( \r
-    IShockwaveFlash * This);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_StopPlay_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_GotoFrame_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ long FrameNum);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_GotoFrame_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_CurrentFrame_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ long *FrameNum);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_CurrentFrame_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_IsPlaying_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ VARIANT_BOOL *Playing);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_IsPlaying_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_PercentLoaded_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ long *percent);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_PercentLoaded_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_FrameLoaded_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ long FrameNum,\r
-    /* [retval][out] */ VARIANT_BOOL *loaded);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_FrameLoaded_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_FlashVersion_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ long *version);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_FlashVersion_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_WMode_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_WMode_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_WMode_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_WMode_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_SAlign_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_SAlign_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_SAlign_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_SAlign_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Menu_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ VARIANT_BOOL *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_Menu_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Menu_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ VARIANT_BOOL pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_Menu_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Base_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_Base_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Base_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_Base_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Scale_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_Scale_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Scale_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_Scale_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_DeviceFont_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ VARIANT_BOOL *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_DeviceFont_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_DeviceFont_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ VARIANT_BOOL pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_DeviceFont_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_EmbedMovie_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ VARIANT_BOOL *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_EmbedMovie_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_EmbedMovie_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ VARIANT_BOOL pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_EmbedMovie_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_BGColor_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_BGColor_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_BGColor_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_BGColor_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Quality2_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_Quality2_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Quality2_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_Quality2_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_LoadMovie_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ int layer,\r
-    /* [in] */ BSTR url);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_LoadMovie_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TGotoFrame_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [in] */ long FrameNum);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TGotoFrame_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TGotoLabel_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [in] */ BSTR label);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TGotoLabel_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TCurrentFrame_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [retval][out] */ long *FrameNum);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TCurrentFrame_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TCurrentLabel_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TCurrentLabel_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TPlay_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TPlay_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TStopPlay_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TStopPlay_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_SetVariable_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR name,\r
-    /* [in] */ BSTR value);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_SetVariable_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_GetVariable_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR name,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_GetVariable_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TSetProperty_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [in] */ int property,\r
-    /* [in] */ BSTR value);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TSetProperty_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TGetProperty_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [in] */ int property,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TGetProperty_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TCallFrame_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [in] */ int FrameNum);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TCallFrame_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TCallLabel_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [in] */ BSTR label);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TCallLabel_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TSetPropertyNum_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [in] */ int property,\r
-    /* [in] */ double value);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TSetPropertyNum_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TGetPropertyNum_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [in] */ int property,\r
-    /* [retval][out] */ double *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TGetPropertyNum_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TGetPropertyAsNumber_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR target,\r
-    /* [in] */ int property,\r
-    /* [retval][out] */ double *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_TGetPropertyAsNumber_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_SWRemote_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_SWRemote_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_SWRemote_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_SWRemote_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_FlashVars_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_FlashVars_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_FlashVars_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_FlashVars_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_AllowScriptAccess_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_AllowScriptAccess_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_AllowScriptAccess_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_AllowScriptAccess_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_MovieData_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_MovieData_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_MovieData_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_MovieData_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_InlineData_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ IUnknown **ppIUnknown);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_InlineData_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_InlineData_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ IUnknown *ppIUnknown);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_InlineData_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_SeamlessTabbing_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ VARIANT_BOOL *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_SeamlessTabbing_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_SeamlessTabbing_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ VARIANT_BOOL pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_SeamlessTabbing_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_EnforceLocalSecurity_Proxy( \r
-    IShockwaveFlash * This);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_EnforceLocalSecurity_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Profile_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ VARIANT_BOOL *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_Profile_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Profile_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ VARIANT_BOOL pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_Profile_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_ProfileAddress_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_ProfileAddress_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_ProfileAddress_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_ProfileAddress_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_ProfilePort_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ long *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_ProfilePort_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_ProfilePort_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ long pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_ProfilePort_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_CallFunction_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR request,\r
-    /* [retval][out] */ BSTR *response);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_CallFunction_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_SetReturnValue_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR returnValue);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_SetReturnValue_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_DisableLocalSecurity_Proxy( \r
-    IShockwaveFlash * This);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_DisableLocalSecurity_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_AllowNetworking_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_AllowNetworking_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_AllowNetworking_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_AllowNetworking_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_AllowFullScreen_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [retval][out] */ BSTR *pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_get_AllowFullScreen_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_AllowFullScreen_Proxy( \r
-    IShockwaveFlash * This,\r
-    /* [in] */ BSTR pVal);\r
-\r
-\r
-void __RPC_STUB IShockwaveFlash_put_AllowFullScreen_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-\r
-#endif         /* __IShockwaveFlash_INTERFACE_DEFINED__ */\r
-\r
-\r
-#ifndef ___IShockwaveFlashEvents_DISPINTERFACE_DEFINED__\r
-#define ___IShockwaveFlashEvents_DISPINTERFACE_DEFINED__\r
-\r
-/* dispinterface _IShockwaveFlashEvents */\r
-/* [hidden][helpstring][uuid] */ \r
-\r
-\r
-EXTERN_C const IID DIID__IShockwaveFlashEvents;\r
-\r
-#if defined(__cplusplus) && !defined(CINTERFACE)\r
-\r
-    MIDL_INTERFACE("D27CDB6D-AE6D-11CF-96B8-444553540000")\r
-    _IShockwaveFlashEvents : public IDispatch\r
-    {\r
-    };\r
-    \r
-#else  /* C style interface */\r
-\r
-    typedef struct _IShockwaveFlashEventsVtbl\r
-    {\r
-        BEGIN_INTERFACE\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( \r
-            _IShockwaveFlashEvents * This,\r
-            /* [in] */ REFIID riid,\r
-            /* [iid_is][out] */ void **ppvObject);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *AddRef )( \r
-            _IShockwaveFlashEvents * This);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *Release )( \r
-            _IShockwaveFlashEvents * This);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( \r
-            _IShockwaveFlashEvents * This,\r
-            /* [out] */ UINT *pctinfo);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( \r
-            _IShockwaveFlashEvents * This,\r
-            /* [in] */ UINT iTInfo,\r
-            /* [in] */ LCID lcid,\r
-            /* [out] */ ITypeInfo **ppTInfo);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( \r
-            _IShockwaveFlashEvents * This,\r
-            /* [in] */ REFIID riid,\r
-            /* [size_is][in] */ LPOLESTR *rgszNames,\r
-            /* [in] */ UINT cNames,\r
-            /* [in] */ LCID lcid,\r
-            /* [size_is][out] */ DISPID *rgDispId);\r
-        \r
-        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( \r
-            _IShockwaveFlashEvents * This,\r
-            /* [in] */ DISPID dispIdMember,\r
-            /* [in] */ REFIID riid,\r
-            /* [in] */ LCID lcid,\r
-            /* [in] */ WORD wFlags,\r
-            /* [out][in] */ DISPPARAMS *pDispParams,\r
-            /* [out] */ VARIANT *pVarResult,\r
-            /* [out] */ EXCEPINFO *pExcepInfo,\r
-            /* [out] */ UINT *puArgErr);\r
-        \r
-        END_INTERFACE\r
-    } _IShockwaveFlashEventsVtbl;\r
-\r
-    interface _IShockwaveFlashEvents\r
-    {\r
-        CONST_VTBL struct _IShockwaveFlashEventsVtbl *lpVtbl;\r
-    };\r
-\r
-    \r
-\r
-#ifdef COBJMACROS\r
-\r
-\r
-#define _IShockwaveFlashEvents_QueryInterface(This,riid,ppvObject)     \\r
-    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)\r
-\r
-#define _IShockwaveFlashEvents_AddRef(This)    \\r
-    (This)->lpVtbl -> AddRef(This)\r
-\r
-#define _IShockwaveFlashEvents_Release(This)   \\r
-    (This)->lpVtbl -> Release(This)\r
-\r
-\r
-#define _IShockwaveFlashEvents_GetTypeInfoCount(This,pctinfo)  \\r
-    (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)\r
-\r
-#define _IShockwaveFlashEvents_GetTypeInfo(This,iTInfo,lcid,ppTInfo)   \\r
-    (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)\r
-\r
-#define _IShockwaveFlashEvents_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \\r
-    (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)\r
-\r
-#define _IShockwaveFlashEvents_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)   \\r
-    (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)\r
-\r
-#endif /* COBJMACROS */\r
-\r
-\r
-#endif         /* C style interface */\r
-\r
-\r
-#endif         /* ___IShockwaveFlashEvents_DISPINTERFACE_DEFINED__ */\r
-\r
-\r
-#ifndef __IFlashFactory_INTERFACE_DEFINED__\r
-#define __IFlashFactory_INTERFACE_DEFINED__\r
-\r
-/* interface IFlashFactory */\r
-/* [object][helpstring][uuid] */ \r
-\r
-\r
-EXTERN_C const IID IID_IFlashFactory;\r
-\r
-#if defined(__cplusplus) && !defined(CINTERFACE)\r
-    \r
-    MIDL_INTERFACE("D27CDB70-AE6D-11CF-96B8-444553540000")\r
-    IFlashFactory : public IUnknown\r
-    {\r
-    public:\r
-    };\r
-    \r
-#else  /* C style interface */\r
-\r
-    typedef struct IFlashFactoryVtbl\r
-    {\r
-        BEGIN_INTERFACE\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( \r
-            IFlashFactory * This,\r
-            /* [in] */ REFIID riid,\r
-            /* [iid_is][out] */ void **ppvObject);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *AddRef )( \r
-            IFlashFactory * This);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *Release )( \r
-            IFlashFactory * This);\r
-        \r
-        END_INTERFACE\r
-    } IFlashFactoryVtbl;\r
-\r
-    interface IFlashFactory\r
-    {\r
-        CONST_VTBL struct IFlashFactoryVtbl *lpVtbl;\r
-    };\r
-\r
-    \r
-\r
-#ifdef COBJMACROS\r
-\r
-\r
-#define IFlashFactory_QueryInterface(This,riid,ppvObject)      \\r
-    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)\r
-\r
-#define IFlashFactory_AddRef(This)     \\r
-    (This)->lpVtbl -> AddRef(This)\r
-\r
-#define IFlashFactory_Release(This)    \\r
-    (This)->lpVtbl -> Release(This)\r
-\r
-\r
-#endif /* COBJMACROS */\r
-\r
-\r
-#endif         /* C style interface */\r
-\r
-\r
-\r
-\r
-#endif         /* __IFlashFactory_INTERFACE_DEFINED__ */\r
-\r
-\r
-#ifndef __IFlashObjectInterface_INTERFACE_DEFINED__\r
-#define __IFlashObjectInterface_INTERFACE_DEFINED__\r
-\r
-/* interface IFlashObjectInterface */\r
-/* [object][helpstring][uuid] */ \r
-\r
-\r
-EXTERN_C const IID IID_IFlashObjectInterface;\r
-\r
-#if defined(__cplusplus) && !defined(CINTERFACE)\r
-    \r
-    MIDL_INTERFACE("D27CDB72-AE6D-11CF-96B8-444553540000")\r
-    IFlashObjectInterface : public IDispatchEx\r
-    {\r
-    public:\r
-    };\r
-    \r
-#else  /* C style interface */\r
-\r
-    typedef struct IFlashObjectInterfaceVtbl\r
-    {\r
-        BEGIN_INTERFACE\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ REFIID riid,\r
-            /* [iid_is][out] */ void **ppvObject);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *AddRef )( \r
-            IFlashObjectInterface * This);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *Release )( \r
-            IFlashObjectInterface * This);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( \r
-            IFlashObjectInterface * This,\r
-            /* [out] */ UINT *pctinfo);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ UINT iTInfo,\r
-            /* [in] */ LCID lcid,\r
-            /* [out] */ ITypeInfo **ppTInfo);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ REFIID riid,\r
-            /* [size_is][in] */ LPOLESTR *rgszNames,\r
-            /* [in] */ UINT cNames,\r
-            /* [in] */ LCID lcid,\r
-            /* [size_is][out] */ DISPID *rgDispId);\r
-        \r
-        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ DISPID dispIdMember,\r
-            /* [in] */ REFIID riid,\r
-            /* [in] */ LCID lcid,\r
-            /* [in] */ WORD wFlags,\r
-            /* [out][in] */ DISPPARAMS *pDispParams,\r
-            /* [out] */ VARIANT *pVarResult,\r
-            /* [out] */ EXCEPINFO *pExcepInfo,\r
-            /* [out] */ UINT *puArgErr);\r
-        \r
-        HRESULT ( __stdcall *GetDispID )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ BSTR bstrName,\r
-            /* [in] */ unsigned long grfdex,\r
-            /* [out] */ long *pid);\r
-        \r
-        HRESULT ( __stdcall *RemoteInvokeEx )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ long id,\r
-            /* [in] */ unsigned long lcid,\r
-            /* [in] */ unsigned long dwFlags,\r
-            /* [in] */ DISPPARAMS *pdp,\r
-            /* [out] */ VARIANT *pvarRes,\r
-            /* [out] */ EXCEPINFO *pei,\r
-            /* [in] */ IServiceProvider *pspCaller,\r
-            /* [in] */ unsigned int cvarRefArg,\r
-            /* [in] */ unsigned int *rgiRefArg,\r
-            /* [out][in] */ VARIANT *rgvarRefArg);\r
-        \r
-        HRESULT ( __stdcall *DeleteMemberByName )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ BSTR bstrName,\r
-            /* [in] */ unsigned long grfdex);\r
-        \r
-        HRESULT ( __stdcall *DeleteMemberByDispID )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ long id);\r
-        \r
-        HRESULT ( __stdcall *GetMemberProperties )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ long id,\r
-            /* [in] */ unsigned long grfdexFetch,\r
-            /* [out] */ unsigned long *pgrfdex);\r
-        \r
-        HRESULT ( __stdcall *GetMemberName )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ long id,\r
-            /* [out] */ BSTR *pbstrName);\r
-        \r
-        HRESULT ( __stdcall *GetNextDispID )( \r
-            IFlashObjectInterface * This,\r
-            /* [in] */ unsigned long grfdex,\r
-            /* [in] */ long id,\r
-            /* [out] */ long *pid);\r
-        \r
-        HRESULT ( __stdcall *GetNameSpaceParent )( \r
-            IFlashObjectInterface * This,\r
-            /* [out] */ IUnknown **ppunk);\r
-        \r
-        END_INTERFACE\r
-    } IFlashObjectInterfaceVtbl;\r
-\r
-    interface IFlashObjectInterface\r
-    {\r
-        CONST_VTBL struct IFlashObjectInterfaceVtbl *lpVtbl;\r
-    };\r
-\r
-    \r
-\r
-#ifdef COBJMACROS\r
-\r
-\r
-#define IFlashObjectInterface_QueryInterface(This,riid,ppvObject)      \\r
-    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)\r
-\r
-#define IFlashObjectInterface_AddRef(This)     \\r
-    (This)->lpVtbl -> AddRef(This)\r
-\r
-#define IFlashObjectInterface_Release(This)    \\r
-    (This)->lpVtbl -> Release(This)\r
-\r
-\r
-#define IFlashObjectInterface_GetTypeInfoCount(This,pctinfo)   \\r
-    (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)\r
-\r
-#define IFlashObjectInterface_GetTypeInfo(This,iTInfo,lcid,ppTInfo)    \\r
-    (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)\r
-\r
-#define IFlashObjectInterface_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)  \\r
-    (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)\r
-\r
-#define IFlashObjectInterface_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)    \\r
-    (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)\r
-\r
-\r
-#define IFlashObjectInterface_GetDispID(This,bstrName,grfdex,pid)      \\r
-    (This)->lpVtbl -> GetDispID(This,bstrName,grfdex,pid)\r
-\r
-#define IFlashObjectInterface_RemoteInvokeEx(This,id,lcid,dwFlags,pdp,pvarRes,pei,pspCaller,cvarRefArg,rgiRefArg,rgvarRefArg)  \\r
-    (This)->lpVtbl -> RemoteInvokeEx(This,id,lcid,dwFlags,pdp,pvarRes,pei,pspCaller,cvarRefArg,rgiRefArg,rgvarRefArg)\r
-\r
-#define IFlashObjectInterface_DeleteMemberByName(This,bstrName,grfdex) \\r
-    (This)->lpVtbl -> DeleteMemberByName(This,bstrName,grfdex)\r
-\r
-#define IFlashObjectInterface_DeleteMemberByDispID(This,id)    \\r
-    (This)->lpVtbl -> DeleteMemberByDispID(This,id)\r
-\r
-#define IFlashObjectInterface_GetMemberProperties(This,id,grfdexFetch,pgrfdex) \\r
-    (This)->lpVtbl -> GetMemberProperties(This,id,grfdexFetch,pgrfdex)\r
-\r
-#define IFlashObjectInterface_GetMemberName(This,id,pbstrName) \\r
-    (This)->lpVtbl -> GetMemberName(This,id,pbstrName)\r
-\r
-#define IFlashObjectInterface_GetNextDispID(This,grfdex,id,pid)        \\r
-    (This)->lpVtbl -> GetNextDispID(This,grfdex,id,pid)\r
-\r
-#define IFlashObjectInterface_GetNameSpaceParent(This,ppunk)   \\r
-    (This)->lpVtbl -> GetNameSpaceParent(This,ppunk)\r
-\r
-\r
-#endif /* COBJMACROS */\r
-\r
-\r
-#endif         /* C style interface */\r
-\r
-\r
-\r
-\r
-#endif         /* __IFlashObjectInterface_INTERFACE_DEFINED__ */\r
-\r
-\r
-#ifndef __IDispatchEx_INTERFACE_DEFINED__\r
-#define __IDispatchEx_INTERFACE_DEFINED__\r
-\r
-/* interface IDispatchEx */\r
-/* [object][uuid] */ \r
-\r
-\r
-EXTERN_C const IID IID_IDispatchEx;\r
-\r
-#if defined(__cplusplus) && !defined(CINTERFACE)\r
-    \r
-    MIDL_INTERFACE("A6EF9860-C720-11D0-9337-00A0C90DCAA9")\r
-    IDispatchEx : public IDispatch\r
-    {\r
-    public:\r
-        virtual HRESULT __stdcall GetDispID( \r
-            /* [in] */ BSTR bstrName,\r
-            /* [in] */ unsigned long grfdex,\r
-            /* [out] */ long *pid) = 0;\r
-        \r
-        virtual HRESULT __stdcall RemoteInvokeEx( \r
-            /* [in] */ long id,\r
-            /* [in] */ unsigned long lcid,\r
-            /* [in] */ unsigned long dwFlags,\r
-            /* [in] */ DISPPARAMS *pdp,\r
-            /* [out] */ VARIANT *pvarRes,\r
-            /* [out] */ EXCEPINFO *pei,\r
-            /* [in] */ IServiceProvider *pspCaller,\r
-            /* [in] */ unsigned int cvarRefArg,\r
-            /* [in] */ unsigned int *rgiRefArg,\r
-            /* [out][in] */ VARIANT *rgvarRefArg) = 0;\r
-        \r
-        virtual HRESULT __stdcall DeleteMemberByName( \r
-            /* [in] */ BSTR bstrName,\r
-            /* [in] */ unsigned long grfdex) = 0;\r
-        \r
-        virtual HRESULT __stdcall DeleteMemberByDispID( \r
-            /* [in] */ long id) = 0;\r
-        \r
-        virtual HRESULT __stdcall GetMemberProperties( \r
-            /* [in] */ long id,\r
-            /* [in] */ unsigned long grfdexFetch,\r
-            /* [out] */ unsigned long *pgrfdex) = 0;\r
-        \r
-        virtual HRESULT __stdcall GetMemberName( \r
-            /* [in] */ long id,\r
-            /* [out] */ BSTR *pbstrName) = 0;\r
-        \r
-        virtual HRESULT __stdcall GetNextDispID( \r
-            /* [in] */ unsigned long grfdex,\r
-            /* [in] */ long id,\r
-            /* [out] */ long *pid) = 0;\r
-        \r
-        virtual HRESULT __stdcall GetNameSpaceParent( \r
-            /* [out] */ IUnknown **ppunk) = 0;\r
-        \r
-    };\r
-    \r
-#else  /* C style interface */\r
-\r
-    typedef struct IDispatchExVtbl\r
-    {\r
-        BEGIN_INTERFACE\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( \r
-            IDispatchEx * This,\r
-            /* [in] */ REFIID riid,\r
-            /* [iid_is][out] */ void **ppvObject);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *AddRef )( \r
-            IDispatchEx * This);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *Release )( \r
-            IDispatchEx * This);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( \r
-            IDispatchEx * This,\r
-            /* [out] */ UINT *pctinfo);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( \r
-            IDispatchEx * This,\r
-            /* [in] */ UINT iTInfo,\r
-            /* [in] */ LCID lcid,\r
-            /* [out] */ ITypeInfo **ppTInfo);\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( \r
-            IDispatchEx * This,\r
-            /* [in] */ REFIID riid,\r
-            /* [size_is][in] */ LPOLESTR *rgszNames,\r
-            /* [in] */ UINT cNames,\r
-            /* [in] */ LCID lcid,\r
-            /* [size_is][out] */ DISPID *rgDispId);\r
-        \r
-        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( \r
-            IDispatchEx * This,\r
-            /* [in] */ DISPID dispIdMember,\r
-            /* [in] */ REFIID riid,\r
-            /* [in] */ LCID lcid,\r
-            /* [in] */ WORD wFlags,\r
-            /* [out][in] */ DISPPARAMS *pDispParams,\r
-            /* [out] */ VARIANT *pVarResult,\r
-            /* [out] */ EXCEPINFO *pExcepInfo,\r
-            /* [out] */ UINT *puArgErr);\r
-        \r
-        HRESULT ( __stdcall *GetDispID )( \r
-            IDispatchEx * This,\r
-            /* [in] */ BSTR bstrName,\r
-            /* [in] */ unsigned long grfdex,\r
-            /* [out] */ long *pid);\r
-        \r
-        HRESULT ( __stdcall *RemoteInvokeEx )( \r
-            IDispatchEx * This,\r
-            /* [in] */ long id,\r
-            /* [in] */ unsigned long lcid,\r
-            /* [in] */ unsigned long dwFlags,\r
-            /* [in] */ DISPPARAMS *pdp,\r
-            /* [out] */ VARIANT *pvarRes,\r
-            /* [out] */ EXCEPINFO *pei,\r
-            /* [in] */ IServiceProvider *pspCaller,\r
-            /* [in] */ unsigned int cvarRefArg,\r
-            /* [in] */ unsigned int *rgiRefArg,\r
-            /* [out][in] */ VARIANT *rgvarRefArg);\r
-        \r
-        HRESULT ( __stdcall *DeleteMemberByName )( \r
-            IDispatchEx * This,\r
-            /* [in] */ BSTR bstrName,\r
-            /* [in] */ unsigned long grfdex);\r
-        \r
-        HRESULT ( __stdcall *DeleteMemberByDispID )( \r
-            IDispatchEx * This,\r
-            /* [in] */ long id);\r
-        \r
-        HRESULT ( __stdcall *GetMemberProperties )( \r
-            IDispatchEx * This,\r
-            /* [in] */ long id,\r
-            /* [in] */ unsigned long grfdexFetch,\r
-            /* [out] */ unsigned long *pgrfdex);\r
-        \r
-        HRESULT ( __stdcall *GetMemberName )( \r
-            IDispatchEx * This,\r
-            /* [in] */ long id,\r
-            /* [out] */ BSTR *pbstrName);\r
-        \r
-        HRESULT ( __stdcall *GetNextDispID )( \r
-            IDispatchEx * This,\r
-            /* [in] */ unsigned long grfdex,\r
-            /* [in] */ long id,\r
-            /* [out] */ long *pid);\r
-        \r
-        HRESULT ( __stdcall *GetNameSpaceParent )( \r
-            IDispatchEx * This,\r
-            /* [out] */ IUnknown **ppunk);\r
-        \r
-        END_INTERFACE\r
-    } IDispatchExVtbl;\r
-\r
-    interface IDispatchEx\r
-    {\r
-        CONST_VTBL struct IDispatchExVtbl *lpVtbl;\r
-    };\r
-\r
-    \r
-\r
-#ifdef COBJMACROS\r
-\r
-\r
-#define IDispatchEx_QueryInterface(This,riid,ppvObject)        \\r
-    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)\r
-\r
-#define IDispatchEx_AddRef(This)       \\r
-    (This)->lpVtbl -> AddRef(This)\r
-\r
-#define IDispatchEx_Release(This)      \\r
-    (This)->lpVtbl -> Release(This)\r
-\r
-\r
-#define IDispatchEx_GetTypeInfoCount(This,pctinfo)     \\r
-    (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)\r
-\r
-#define IDispatchEx_GetTypeInfo(This,iTInfo,lcid,ppTInfo)      \\r
-    (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)\r
-\r
-#define IDispatchEx_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)    \\r
-    (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)\r
-\r
-#define IDispatchEx_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)      \\r
-    (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)\r
-\r
-\r
-#define IDispatchEx_GetDispID(This,bstrName,grfdex,pid)        \\r
-    (This)->lpVtbl -> GetDispID(This,bstrName,grfdex,pid)\r
-\r
-#define IDispatchEx_RemoteInvokeEx(This,id,lcid,dwFlags,pdp,pvarRes,pei,pspCaller,cvarRefArg,rgiRefArg,rgvarRefArg)    \\r
-    (This)->lpVtbl -> RemoteInvokeEx(This,id,lcid,dwFlags,pdp,pvarRes,pei,pspCaller,cvarRefArg,rgiRefArg,rgvarRefArg)\r
-\r
-#define IDispatchEx_DeleteMemberByName(This,bstrName,grfdex)   \\r
-    (This)->lpVtbl -> DeleteMemberByName(This,bstrName,grfdex)\r
-\r
-#define IDispatchEx_DeleteMemberByDispID(This,id)      \\r
-    (This)->lpVtbl -> DeleteMemberByDispID(This,id)\r
-\r
-#define IDispatchEx_GetMemberProperties(This,id,grfdexFetch,pgrfdex)   \\r
-    (This)->lpVtbl -> GetMemberProperties(This,id,grfdexFetch,pgrfdex)\r
-\r
-#define IDispatchEx_GetMemberName(This,id,pbstrName)   \\r
-    (This)->lpVtbl -> GetMemberName(This,id,pbstrName)\r
-\r
-#define IDispatchEx_GetNextDispID(This,grfdex,id,pid)  \\r
-    (This)->lpVtbl -> GetNextDispID(This,grfdex,id,pid)\r
-\r
-#define IDispatchEx_GetNameSpaceParent(This,ppunk)     \\r
-    (This)->lpVtbl -> GetNameSpaceParent(This,ppunk)\r
-\r
-#endif /* COBJMACROS */\r
-\r
-\r
-#endif         /* C style interface */\r
-\r
-\r
-\r
-HRESULT __stdcall IDispatchEx_GetDispID_Proxy( \r
-    IDispatchEx * This,\r
-    /* [in] */ BSTR bstrName,\r
-    /* [in] */ unsigned long grfdex,\r
-    /* [out] */ long *pid);\r
-\r
-\r
-void __RPC_STUB IDispatchEx_GetDispID_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-HRESULT __stdcall IDispatchEx_RemoteInvokeEx_Proxy( \r
-    IDispatchEx * This,\r
-    /* [in] */ long id,\r
-    /* [in] */ unsigned long lcid,\r
-    /* [in] */ unsigned long dwFlags,\r
-    /* [in] */ DISPPARAMS *pdp,\r
-    /* [out] */ VARIANT *pvarRes,\r
-    /* [out] */ EXCEPINFO *pei,\r
-    /* [in] */ IServiceProvider *pspCaller,\r
-    /* [in] */ unsigned int cvarRefArg,\r
-    /* [in] */ unsigned int *rgiRefArg,\r
-    /* [out][in] */ VARIANT *rgvarRefArg);\r
-\r
-\r
-void __RPC_STUB IDispatchEx_RemoteInvokeEx_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-HRESULT __stdcall IDispatchEx_DeleteMemberByName_Proxy( \r
-    IDispatchEx * This,\r
-    /* [in] */ BSTR bstrName,\r
-    /* [in] */ unsigned long grfdex);\r
-\r
-\r
-void __RPC_STUB IDispatchEx_DeleteMemberByName_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-HRESULT __stdcall IDispatchEx_DeleteMemberByDispID_Proxy( \r
-    IDispatchEx * This,\r
-    /* [in] */ long id);\r
-\r
-\r
-void __RPC_STUB IDispatchEx_DeleteMemberByDispID_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-HRESULT __stdcall IDispatchEx_GetMemberProperties_Proxy( \r
-    IDispatchEx * This,\r
-    /* [in] */ long id,\r
-    /* [in] */ unsigned long grfdexFetch,\r
-    /* [out] */ unsigned long *pgrfdex);\r
-\r
-\r
-void __RPC_STUB IDispatchEx_GetMemberProperties_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-HRESULT __stdcall IDispatchEx_GetMemberName_Proxy( \r
-    IDispatchEx * This,\r
-    /* [in] */ long id,\r
-    /* [out] */ BSTR *pbstrName);\r
-\r
-\r
-void __RPC_STUB IDispatchEx_GetMemberName_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-HRESULT __stdcall IDispatchEx_GetNextDispID_Proxy( \r
-    IDispatchEx * This,\r
-    /* [in] */ unsigned long grfdex,\r
-    /* [in] */ long id,\r
-    /* [out] */ long *pid);\r
-\r
-\r
-void __RPC_STUB IDispatchEx_GetNextDispID_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-HRESULT __stdcall IDispatchEx_GetNameSpaceParent_Proxy( \r
-    IDispatchEx * This,\r
-    /* [out] */ IUnknown **ppunk);\r
-\r
-\r
-void __RPC_STUB IDispatchEx_GetNameSpaceParent_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-\r
-#endif         /* __IDispatchEx_INTERFACE_DEFINED__ */\r
-\r
-\r
-#ifndef __IServiceProvider_INTERFACE_DEFINED__\r
-#define __IServiceProvider_INTERFACE_DEFINED__\r
-\r
-/* interface IServiceProvider */\r
-/* [object][uuid] */ \r
-\r
-\r
-EXTERN_C const IID IID_IServiceProvider;\r
-\r
-#if defined(__cplusplus) && !defined(CINTERFACE)\r
-    \r
-    MIDL_INTERFACE("6D5140C1-7436-11CE-8034-00AA006009FA")\r
-    IServiceProvider : public IUnknown\r
-    {\r
-    public:\r
-        virtual HRESULT __stdcall RemoteQueryService( \r
-            /* [in] */ GUID *guidService,\r
-            /* [in] */ GUID *riid,\r
-            /* [out] */ IUnknown **ppvObject) = 0;\r
-        \r
-    };\r
-    \r
-#else  /* C style interface */\r
-\r
-    typedef struct IServiceProviderVtbl\r
-    {\r
-        BEGIN_INTERFACE\r
-        \r
-        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( \r
-            IServiceProvider * This,\r
-            /* [in] */ REFIID riid,\r
-            /* [iid_is][out] */ void **ppvObject);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *AddRef )( \r
-            IServiceProvider * This);\r
-        \r
-        ULONG ( STDMETHODCALLTYPE *Release )( \r
-            IServiceProvider * This);\r
-        \r
-        HRESULT ( __stdcall *RemoteQueryService )( \r
-            IServiceProvider * This,\r
-            /* [in] */ GUID *guidService,\r
-            /* [in] */ GUID *riid,\r
-            /* [out] */ IUnknown **ppvObject);\r
-        \r
-        END_INTERFACE\r
-    } IServiceProviderVtbl;\r
-\r
-    interface IServiceProvider\r
-    {\r
-        CONST_VTBL struct IServiceProviderVtbl *lpVtbl;\r
-    };\r
-\r
-    \r
-\r
-#ifdef COBJMACROS\r
-\r
-\r
-#define IServiceProvider_QueryInterface(This,riid,ppvObject)   \\r
-    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)\r
-\r
-#define IServiceProvider_AddRef(This)  \\r
-    (This)->lpVtbl -> AddRef(This)\r
-\r
-#define IServiceProvider_Release(This) \\r
-    (This)->lpVtbl -> Release(This)\r
-\r
-\r
-#define IServiceProvider_RemoteQueryService(This,guidService,riid,ppvObject)   \\r
-    (This)->lpVtbl -> RemoteQueryService(This,guidService,riid,ppvObject)\r
-\r
-#endif /* COBJMACROS */\r
-\r
-\r
-#endif         /* C style interface */\r
-\r
-\r
-\r
-HRESULT __stdcall IServiceProvider_RemoteQueryService_Proxy( \r
-    IServiceProvider * This,\r
-    /* [in] */ GUID *guidService,\r
-    /* [in] */ GUID *riid,\r
-    /* [out] */ IUnknown **ppvObject);\r
-\r
-\r
-void __RPC_STUB IServiceProvider_RemoteQueryService_Stub(\r
-    IRpcStubBuffer *This,\r
-    IRpcChannelBuffer *_pRpcChannelBuffer,\r
-    PRPC_MESSAGE _pRpcMessage,\r
-    DWORD *_pdwStubPhase);\r
-\r
-\r
-\r
-#endif         /* __IServiceProvider_INTERFACE_DEFINED__ */\r
-\r
-\r
-EXTERN_C const CLSID CLSID_ShockwaveFlash;\r
-\r
-#ifdef __cplusplus\r
-\r
-class DECLSPEC_UUID("D27CDB6E-AE6D-11CF-96B8-444553540000")\r
-ShockwaveFlash;\r
-#endif\r
-\r
-EXTERN_C const CLSID CLSID_FlashObjectInterface;\r
-\r
-#ifdef __cplusplus\r
-\r
-class DECLSPEC_UUID("D27CDB71-AE6D-11CF-96B8-444553540000")\r
-FlashObjectInterface;\r
-#endif\r
-#endif /* __ShockwaveFlashObjects_LIBRARY_DEFINED__ */\r
-\r
-/* Additional Prototypes for ALL interfaces */\r
-\r
-/* end of Additional Prototypes */\r
-\r
-#ifdef __cplusplus\r
-}\r
-#endif\r
-\r
-#endif\r
-\r
-\r
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 6.00.0366 */
+/* at Tue Mar 18 13:05:00 2008
+ */
+/* Compiler settings for .\flash\Flash9e.IDL:
+    Oicf, W4, Zp8, env=Win32 (32b run)
+    protocol : dce , ms_ext, c_ext, robust
+    error checks: allocation ref bounds_check enum stub_data 
+    VC __declspec() decoration level: 
+         __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+         DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+//@@MIDL_FILE_HEADING(  )
+
+#pragma warning( disable: 4049 )  /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+#include <dispex.h>
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+
+#ifndef __axflash_h__
+#define __axflash_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */ 
+
+#ifndef __IShockwaveFlash_FWD_DEFINED__
+#define __IShockwaveFlash_FWD_DEFINED__
+typedef interface IShockwaveFlash IShockwaveFlash;
+#endif         /* __IShockwaveFlash_FWD_DEFINED__ */
+
+
+#ifndef ___IShockwaveFlashEvents_FWD_DEFINED__
+#define ___IShockwaveFlashEvents_FWD_DEFINED__
+typedef interface _IShockwaveFlashEvents _IShockwaveFlashEvents;
+#endif         /* ___IShockwaveFlashEvents_FWD_DEFINED__ */
+
+
+#ifndef __IFlashFactory_FWD_DEFINED__
+#define __IFlashFactory_FWD_DEFINED__
+typedef interface IFlashFactory IFlashFactory;
+#endif         /* __IFlashFactory_FWD_DEFINED__ */
+
+
+#ifndef __IDispatchEx_FWD_DEFINED__
+#define __IDispatchEx_FWD_DEFINED__
+typedef interface IDispatchEx IDispatchEx;
+#endif         /* __IDispatchEx_FWD_DEFINED__ */
+
+
+#ifndef __IFlashObjectInterface_FWD_DEFINED__
+#define __IFlashObjectInterface_FWD_DEFINED__
+typedef interface IFlashObjectInterface IFlashObjectInterface;
+#endif         /* __IFlashObjectInterface_FWD_DEFINED__ */
+
+
+#ifndef __IServiceProvider_FWD_DEFINED__
+#define __IServiceProvider_FWD_DEFINED__
+typedef interface IServiceProvider IServiceProvider;
+#endif         /* __IServiceProvider_FWD_DEFINED__ */
+
+
+#ifndef __ShockwaveFlash_FWD_DEFINED__
+#define __ShockwaveFlash_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class ShockwaveFlash ShockwaveFlash;
+#else
+typedef struct ShockwaveFlash ShockwaveFlash;
+#endif /* __cplusplus */
+
+#endif         /* __ShockwaveFlash_FWD_DEFINED__ */
+
+
+#ifndef __FlashObjectInterface_FWD_DEFINED__
+#define __FlashObjectInterface_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class FlashObjectInterface FlashObjectInterface;
+#else
+typedef struct FlashObjectInterface FlashObjectInterface;
+#endif /* __cplusplus */
+
+#endif         /* __FlashObjectInterface_FWD_DEFINED__ */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif 
+
+void * __RPC_USER MIDL_user_allocate(size_t);
+void __RPC_USER MIDL_user_free( void * ); 
+
+
+#ifndef __ShockwaveFlashObjects_LIBRARY_DEFINED__
+#define __ShockwaveFlashObjects_LIBRARY_DEFINED__
+
+/* library ShockwaveFlashObjects */
+/* [custom][custom][helpstring][version][uuid] */ 
+
+
+
+
+
+
+
+
+EXTERN_C const IID LIBID_ShockwaveFlashObjects;
+
+#ifndef __IShockwaveFlash_INTERFACE_DEFINED__
+#define __IShockwaveFlash_INTERFACE_DEFINED__
+
+/* interface IShockwaveFlash */
+/* [object][oleautomation][dual][helpstring][uuid] */ 
+
+
+EXTERN_C const IID IID_IShockwaveFlash;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+    
+    MIDL_INTERFACE("D27CDB6C-AE6D-11CF-96B8-444553540000")
+    IShockwaveFlash : public IDispatch
+    {
+    public:
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_ReadyState( 
+            /* [retval][out] */ long *pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_TotalFrames( 
+            /* [retval][out] */ long *pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Playing( 
+            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Playing( 
+            /* [in] */ VARIANT_BOOL pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Quality( 
+            /* [retval][out] */ int *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Quality( 
+            /* [in] */ int pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_ScaleMode( 
+            /* [retval][out] */ int *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_ScaleMode( 
+            /* [in] */ int pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_AlignMode( 
+            /* [retval][out] */ int *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_AlignMode( 
+            /* [in] */ int pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_BackgroundColor( 
+            /* [retval][out] */ long *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_BackgroundColor( 
+            /* [in] */ long pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Loop( 
+            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Loop( 
+            /* [in] */ VARIANT_BOOL pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Movie( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Movie( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE receiveNum( 
+            /* [retval][out] */ long *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_FrameNum( 
+            /* [in] */ long pVal) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetZoomRect( 
+            /* [in] */ long left,
+            /* [in] */ long top,
+            /* [in] */ long right,
+            /* [in] */ long bottom) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Zoom( 
+            /* [in] */ int factor) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Pan( 
+            /* [in] */ long x,
+            /* [in] */ long y,
+            /* [in] */ int mode) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Play( void) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Stop( void) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Back( void) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Forward( void) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Rewind( void) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE StopPlay( void) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GotoFrame( 
+            /* [in] */ long FrameNum) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE CurrentFrame( 
+            /* [retval][out] */ long *FrameNum) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IsPlaying( 
+            /* [retval][out] */ VARIANT_BOOL *Playing) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE PercentLoaded( 
+            /* [retval][out] */ long *percent) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE FrameLoaded( 
+            /* [in] */ long FrameNum,
+            /* [retval][out] */ VARIANT_BOOL *loaded) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE FlashVersion( 
+            /* [retval][out] */ long *version) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_WMode( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_WMode( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_SAlign( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_SAlign( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Menu( 
+            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Menu( 
+            /* [in] */ VARIANT_BOOL pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Base( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Base( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Scale( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Scale( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_DeviceFont( 
+            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_DeviceFont( 
+            /* [in] */ VARIANT_BOOL pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_EmbedMovie( 
+            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_EmbedMovie( 
+            /* [in] */ VARIANT_BOOL pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_BGColor( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_BGColor( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Quality2( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Quality2( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE LoadMovie( 
+            /* [in] */ int layer,
+            /* [in] */ BSTR url) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TGotoFrame( 
+            /* [in] */ BSTR target,
+            /* [in] */ long FrameNum) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TGotoLabel( 
+            /* [in] */ BSTR target,
+            /* [in] */ BSTR label) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TCurrentFrame( 
+            /* [in] */ BSTR target,
+            /* [retval][out] */ long *FrameNum) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TCurrentLabel( 
+            /* [in] */ BSTR target,
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TPlay( 
+            /* [in] */ BSTR target) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TStopPlay( 
+            /* [in] */ BSTR target) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetVariable( 
+            /* [in] */ BSTR name,
+            /* [in] */ BSTR value) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetVariable( 
+            /* [in] */ BSTR name,
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TSetProperty( 
+            /* [in] */ BSTR target,
+            /* [in] */ int property,
+            /* [in] */ BSTR value) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TGetProperty( 
+            /* [in] */ BSTR target,
+            /* [in] */ int property,
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TCallFrame( 
+            /* [in] */ BSTR target,
+            /* [in] */ int FrameNum) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TCallLabel( 
+            /* [in] */ BSTR target,
+            /* [in] */ BSTR label) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TSetPropertyNum( 
+            /* [in] */ BSTR target,
+            /* [in] */ int property,
+            /* [in] */ double value) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TGetPropertyNum( 
+            /* [in] */ BSTR target,
+            /* [in] */ int property,
+            /* [retval][out] */ double *pVal) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE TGetPropertyAsNumber( 
+            /* [in] */ BSTR target,
+            /* [in] */ int property,
+            /* [retval][out] */ double *pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_SWRemote( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_SWRemote( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_FlashVars( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_FlashVars( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_AllowScriptAccess( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_AllowScriptAccess( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_MovieData( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_MovieData( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_InlineData( 
+            /* [retval][out] */ IUnknown **ppIUnknown) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_InlineData( 
+            /* [in] */ IUnknown *ppIUnknown) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_SeamlessTabbing( 
+            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_SeamlessTabbing( 
+            /* [in] */ VARIANT_BOOL pVal) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE EnforceLocalSecurity( void) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_Profile( 
+            /* [retval][out] */ VARIANT_BOOL *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_Profile( 
+            /* [in] */ VARIANT_BOOL pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_ProfileAddress( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_ProfileAddress( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_ProfilePort( 
+            /* [retval][out] */ long *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_ProfilePort( 
+            /* [in] */ long pVal) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE CallFunction( 
+            /* [in] */ BSTR request,
+            /* [retval][out] */ BSTR *response) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetReturnValue( 
+            /* [in] */ BSTR returnValue) = 0;
+        
+        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE DisableLocalSecurity( void) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_AllowNetworking( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_AllowNetworking( 
+            /* [in] */ BSTR pVal) = 0;
+        
+        virtual /* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE get_AllowFullScreen( 
+            /* [retval][out] */ BSTR *pVal) = 0;
+        
+        virtual /* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE put_AllowFullScreen( 
+            /* [in] */ BSTR pVal) = 0;
+        
+    };
+    
+#else  /* C style interface */
+
+    typedef struct IShockwaveFlashVtbl
+    {
+        BEGIN_INTERFACE
+        
+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
+            IShockwaveFlash * This,
+            /* [in] */ REFIID riid,
+            /* [iid_is][out] */ void **ppvObject);
+        
+        ULONG ( STDMETHODCALLTYPE *AddRef )( 
+            IShockwaveFlash * This);
+        
+        ULONG ( STDMETHODCALLTYPE *Release )( 
+            IShockwaveFlash * This);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( 
+            IShockwaveFlash * This,
+            /* [out] */ UINT *pctinfo);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( 
+            IShockwaveFlash * This,
+            /* [in] */ UINT iTInfo,
+            /* [in] */ LCID lcid,
+            /* [out] */ ITypeInfo **ppTInfo);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( 
+            IShockwaveFlash * This,
+            /* [in] */ REFIID riid,
+            /* [size_is][in] */ LPOLESTR *rgszNames,
+            /* [in] */ UINT cNames,
+            /* [in] */ LCID lcid,
+            /* [size_is][out] */ DISPID *rgDispId);
+        
+        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( 
+            IShockwaveFlash * This,
+            /* [in] */ DISPID dispIdMember,
+            /* [in] */ REFIID riid,
+            /* [in] */ LCID lcid,
+            /* [in] */ WORD wFlags,
+            /* [out][in] */ DISPPARAMS *pDispParams,
+            /* [out] */ VARIANT *pVarResult,
+            /* [out] */ EXCEPINFO *pExcepInfo,
+            /* [out] */ UINT *puArgErr);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_ReadyState )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ long *pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_TotalFrames )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ long *pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Playing )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ VARIANT_BOOL *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Playing )( 
+            IShockwaveFlash * This,
+            /* [in] */ VARIANT_BOOL pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Quality )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ int *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Quality )( 
+            IShockwaveFlash * This,
+            /* [in] */ int pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_ScaleMode )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ int *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_ScaleMode )( 
+            IShockwaveFlash * This,
+            /* [in] */ int pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_AlignMode )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ int *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_AlignMode )( 
+            IShockwaveFlash * This,
+            /* [in] */ int pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_BackgroundColor )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ long *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_BackgroundColor )( 
+            IShockwaveFlash * This,
+            /* [in] */ long pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Loop )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ VARIANT_BOOL *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Loop )( 
+            IShockwaveFlash * This,
+            /* [in] */ VARIANT_BOOL pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Movie )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Movie )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *receiveNum )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ long *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_FrameNum )( 
+            IShockwaveFlash * This,
+            /* [in] */ long pVal);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetZoomRect )( 
+            IShockwaveFlash * This,
+            /* [in] */ long left,
+            /* [in] */ long top,
+            /* [in] */ long right,
+            /* [in] */ long bottom);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Zoom )( 
+            IShockwaveFlash * This,
+            /* [in] */ int factor);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Pan )( 
+            IShockwaveFlash * This,
+            /* [in] */ long x,
+            /* [in] */ long y,
+            /* [in] */ int mode);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Play )( 
+            IShockwaveFlash * This);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Stop )( 
+            IShockwaveFlash * This);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Back )( 
+            IShockwaveFlash * This);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Forward )( 
+            IShockwaveFlash * This);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Rewind )( 
+            IShockwaveFlash * This);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *StopPlay )( 
+            IShockwaveFlash * This);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GotoFrame )( 
+            IShockwaveFlash * This,
+            /* [in] */ long FrameNum);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *CurrentFrame )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ long *FrameNum);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *IsPlaying )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ VARIANT_BOOL *Playing);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *PercentLoaded )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ long *percent);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *FrameLoaded )( 
+            IShockwaveFlash * This,
+            /* [in] */ long FrameNum,
+            /* [retval][out] */ VARIANT_BOOL *loaded);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *FlashVersion )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ long *version);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_WMode )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_WMode )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_SAlign )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_SAlign )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Menu )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ VARIANT_BOOL *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Menu )( 
+            IShockwaveFlash * This,
+            /* [in] */ VARIANT_BOOL pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Base )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Base )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Scale )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Scale )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_DeviceFont )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ VARIANT_BOOL *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_DeviceFont )( 
+            IShockwaveFlash * This,
+            /* [in] */ VARIANT_BOOL pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_EmbedMovie )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ VARIANT_BOOL *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_EmbedMovie )( 
+            IShockwaveFlash * This,
+            /* [in] */ VARIANT_BOOL pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_BGColor )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_BGColor )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Quality2 )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Quality2 )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *LoadMovie )( 
+            IShockwaveFlash * This,
+            /* [in] */ int layer,
+            /* [in] */ BSTR url);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TGotoFrame )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [in] */ long FrameNum);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TGotoLabel )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [in] */ BSTR label);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TCurrentFrame )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [retval][out] */ long *FrameNum);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TCurrentLabel )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TPlay )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TStopPlay )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetVariable )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR name,
+            /* [in] */ BSTR value);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetVariable )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR name,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TSetProperty )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [in] */ int property,
+            /* [in] */ BSTR value);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TGetProperty )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [in] */ int property,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TCallFrame )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [in] */ int FrameNum);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TCallLabel )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [in] */ BSTR label);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TSetPropertyNum )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [in] */ int property,
+            /* [in] */ double value);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TGetPropertyNum )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [in] */ int property,
+            /* [retval][out] */ double *pVal);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *TGetPropertyAsNumber )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR target,
+            /* [in] */ int property,
+            /* [retval][out] */ double *pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_SWRemote )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_SWRemote )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_FlashVars )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_FlashVars )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_AllowScriptAccess )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_AllowScriptAccess )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_MovieData )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_MovieData )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_InlineData )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ IUnknown **ppIUnknown);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_InlineData )( 
+            IShockwaveFlash * This,
+            /* [in] */ IUnknown *ppIUnknown);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_SeamlessTabbing )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ VARIANT_BOOL *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_SeamlessTabbing )( 
+            IShockwaveFlash * This,
+            /* [in] */ VARIANT_BOOL pVal);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *EnforceLocalSecurity )( 
+            IShockwaveFlash * This);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_Profile )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ VARIANT_BOOL *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_Profile )( 
+            IShockwaveFlash * This,
+            /* [in] */ VARIANT_BOOL pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_ProfileAddress )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_ProfileAddress )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_ProfilePort )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ long *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_ProfilePort )( 
+            IShockwaveFlash * This,
+            /* [in] */ long pVal);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *CallFunction )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR request,
+            /* [retval][out] */ BSTR *response);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetReturnValue )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR returnValue);
+        
+        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *DisableLocalSecurity )( 
+            IShockwaveFlash * This);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_AllowNetworking )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_AllowNetworking )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        /* [helpstring][propget][id] */ HRESULT ( STDMETHODCALLTYPE *get_AllowFullScreen )( 
+            IShockwaveFlash * This,
+            /* [retval][out] */ BSTR *pVal);
+        
+        /* [helpstring][propput][id] */ HRESULT ( STDMETHODCALLTYPE *put_AllowFullScreen )( 
+            IShockwaveFlash * This,
+            /* [in] */ BSTR pVal);
+        
+        END_INTERFACE
+    } IShockwaveFlashVtbl;
+
+    interface IShockwaveFlash
+    {
+        CONST_VTBL struct IShockwaveFlashVtbl *lpVtbl;
+    };
+
+    
+
+#ifdef COBJMACROS
+
+
+#define IShockwaveFlash_QueryInterface(This,riid,ppvObject)    \
+    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IShockwaveFlash_AddRef(This)   \
+    (This)->lpVtbl -> AddRef(This)
+
+#define IShockwaveFlash_Release(This)  \
+    (This)->lpVtbl -> Release(This)
+
+
+#define IShockwaveFlash_GetTypeInfoCount(This,pctinfo) \
+    (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)
+
+#define IShockwaveFlash_GetTypeInfo(This,iTInfo,lcid,ppTInfo)  \
+    (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)
+
+#define IShockwaveFlash_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)        \
+    (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)
+
+#define IShockwaveFlash_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)  \
+    (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)
+
+
+#define IShockwaveFlash_get_ReadyState(This,pVal)      \
+    (This)->lpVtbl -> get_ReadyState(This,pVal)
+
+#define IShockwaveFlash_get_TotalFrames(This,pVal)     \
+    (This)->lpVtbl -> get_TotalFrames(This,pVal)
+
+#define IShockwaveFlash_get_Playing(This,pVal) \
+    (This)->lpVtbl -> get_Playing(This,pVal)
+
+#define IShockwaveFlash_put_Playing(This,pVal) \
+    (This)->lpVtbl -> put_Playing(This,pVal)
+
+#define IShockwaveFlash_get_Quality(This,pVal) \
+    (This)->lpVtbl -> get_Quality(This,pVal)
+
+#define IShockwaveFlash_put_Quality(This,pVal) \
+    (This)->lpVtbl -> put_Quality(This,pVal)
+
+#define IShockwaveFlash_get_ScaleMode(This,pVal)       \
+    (This)->lpVtbl -> get_ScaleMode(This,pVal)
+
+#define IShockwaveFlash_put_ScaleMode(This,pVal)       \
+    (This)->lpVtbl -> put_ScaleMode(This,pVal)
+
+#define IShockwaveFlash_get_AlignMode(This,pVal)       \
+    (This)->lpVtbl -> get_AlignMode(This,pVal)
+
+#define IShockwaveFlash_put_AlignMode(This,pVal)       \
+    (This)->lpVtbl -> put_AlignMode(This,pVal)
+
+#define IShockwaveFlash_get_BackgroundColor(This,pVal) \
+    (This)->lpVtbl -> get_BackgroundColor(This,pVal)
+
+#define IShockwaveFlash_put_BackgroundColor(This,pVal) \
+    (This)->lpVtbl -> put_BackgroundColor(This,pVal)
+
+#define IShockwaveFlash_get_Loop(This,pVal)    \
+    (This)->lpVtbl -> get_Loop(This,pVal)
+
+#define IShockwaveFlash_put_Loop(This,pVal)    \
+    (This)->lpVtbl -> put_Loop(This,pVal)
+
+#define IShockwaveFlash_get_Movie(This,pVal)   \
+    (This)->lpVtbl -> get_Movie(This,pVal)
+
+#define IShockwaveFlash_put_Movie(This,pVal)   \
+    (This)->lpVtbl -> put_Movie(This,pVal)
+
+#define IShockwaveFlash_receiveNum(This,pVal)  \
+    (This)->lpVtbl -> receiveNum(This,pVal)
+
+#define IShockwaveFlash_put_FrameNum(This,pVal)        \
+    (This)->lpVtbl -> put_FrameNum(This,pVal)
+
+#define IShockwaveFlash_SetZoomRect(This,left,top,right,bottom)        \
+    (This)->lpVtbl -> SetZoomRect(This,left,top,right,bottom)
+
+#define IShockwaveFlash_Zoom(This,factor)      \
+    (This)->lpVtbl -> Zoom(This,factor)
+
+#define IShockwaveFlash_Pan(This,x,y,mode)     \
+    (This)->lpVtbl -> Pan(This,x,y,mode)
+
+#define IShockwaveFlash_Play(This)     \
+    (This)->lpVtbl -> Play(This)
+
+#define IShockwaveFlash_Stop(This)     \
+    (This)->lpVtbl -> Stop(This)
+
+#define IShockwaveFlash_Back(This)     \
+    (This)->lpVtbl -> Back(This)
+
+#define IShockwaveFlash_Forward(This)  \
+    (This)->lpVtbl -> Forward(This)
+
+#define IShockwaveFlash_Rewind(This)   \
+    (This)->lpVtbl -> Rewind(This)
+
+#define IShockwaveFlash_StopPlay(This) \
+    (This)->lpVtbl -> StopPlay(This)
+
+#define IShockwaveFlash_GotoFrame(This,FrameNum)       \
+    (This)->lpVtbl -> GotoFrame(This,FrameNum)
+
+#define IShockwaveFlash_CurrentFrame(This,FrameNum)    \
+    (This)->lpVtbl -> CurrentFrame(This,FrameNum)
+
+#define IShockwaveFlash_IsPlaying(This,Playing)        \
+    (This)->lpVtbl -> IsPlaying(This,Playing)
+
+#define IShockwaveFlash_PercentLoaded(This,percent)    \
+    (This)->lpVtbl -> PercentLoaded(This,percent)
+
+#define IShockwaveFlash_FrameLoaded(This,FrameNum,loaded)      \
+    (This)->lpVtbl -> FrameLoaded(This,FrameNum,loaded)
+
+#define IShockwaveFlash_FlashVersion(This,version)     \
+    (This)->lpVtbl -> FlashVersion(This,version)
+
+#define IShockwaveFlash_get_WMode(This,pVal)   \
+    (This)->lpVtbl -> get_WMode(This,pVal)
+
+#define IShockwaveFlash_put_WMode(This,pVal)   \
+    (This)->lpVtbl -> put_WMode(This,pVal)
+
+#define IShockwaveFlash_get_SAlign(This,pVal)  \
+    (This)->lpVtbl -> get_SAlign(This,pVal)
+
+#define IShockwaveFlash_put_SAlign(This,pVal)  \
+    (This)->lpVtbl -> put_SAlign(This,pVal)
+
+#define IShockwaveFlash_get_Menu(This,pVal)    \
+    (This)->lpVtbl -> get_Menu(This,pVal)
+
+#define IShockwaveFlash_put_Menu(This,pVal)    \
+    (This)->lpVtbl -> put_Menu(This,pVal)
+
+#define IShockwaveFlash_get_Base(This,pVal)    \
+    (This)->lpVtbl -> get_Base(This,pVal)
+
+#define IShockwaveFlash_put_Base(This,pVal)    \
+    (This)->lpVtbl -> put_Base(This,pVal)
+
+#define IShockwaveFlash_get_Scale(This,pVal)   \
+    (This)->lpVtbl -> get_Scale(This,pVal)
+
+#define IShockwaveFlash_put_Scale(This,pVal)   \
+    (This)->lpVtbl -> put_Scale(This,pVal)
+
+#define IShockwaveFlash_get_DeviceFont(This,pVal)      \
+    (This)->lpVtbl -> get_DeviceFont(This,pVal)
+
+#define IShockwaveFlash_put_DeviceFont(This,pVal)      \
+    (This)->lpVtbl -> put_DeviceFont(This,pVal)
+
+#define IShockwaveFlash_get_EmbedMovie(This,pVal)      \
+    (This)->lpVtbl -> get_EmbedMovie(This,pVal)
+
+#define IShockwaveFlash_put_EmbedMovie(This,pVal)      \
+    (This)->lpVtbl -> put_EmbedMovie(This,pVal)
+
+#define IShockwaveFlash_get_BGColor(This,pVal) \
+    (This)->lpVtbl -> get_BGColor(This,pVal)
+
+#define IShockwaveFlash_put_BGColor(This,pVal) \
+    (This)->lpVtbl -> put_BGColor(This,pVal)
+
+#define IShockwaveFlash_get_Quality2(This,pVal)        \
+    (This)->lpVtbl -> get_Quality2(This,pVal)
+
+#define IShockwaveFlash_put_Quality2(This,pVal)        \
+    (This)->lpVtbl -> put_Quality2(This,pVal)
+
+#define IShockwaveFlash_LoadMovie(This,layer,url)      \
+    (This)->lpVtbl -> LoadMovie(This,layer,url)
+
+#define IShockwaveFlash_TGotoFrame(This,target,FrameNum)       \
+    (This)->lpVtbl -> TGotoFrame(This,target,FrameNum)
+
+#define IShockwaveFlash_TGotoLabel(This,target,label)  \
+    (This)->lpVtbl -> TGotoLabel(This,target,label)
+
+#define IShockwaveFlash_TCurrentFrame(This,target,FrameNum)    \
+    (This)->lpVtbl -> TCurrentFrame(This,target,FrameNum)
+
+#define IShockwaveFlash_TCurrentLabel(This,target,pVal)        \
+    (This)->lpVtbl -> TCurrentLabel(This,target,pVal)
+
+#define IShockwaveFlash_TPlay(This,target)     \
+    (This)->lpVtbl -> TPlay(This,target)
+
+#define IShockwaveFlash_TStopPlay(This,target) \
+    (This)->lpVtbl -> TStopPlay(This,target)
+
+#define IShockwaveFlash_SetVariable(This,name,value)   \
+    (This)->lpVtbl -> SetVariable(This,name,value)
+
+#define IShockwaveFlash_GetVariable(This,name,pVal)    \
+    (This)->lpVtbl -> GetVariable(This,name,pVal)
+
+#define IShockwaveFlash_TSetProperty(This,target,property,value)       \
+    (This)->lpVtbl -> TSetProperty(This,target,property,value)
+
+#define IShockwaveFlash_TGetProperty(This,target,property,pVal)        \
+    (This)->lpVtbl -> TGetProperty(This,target,property,pVal)
+
+#define IShockwaveFlash_TCallFrame(This,target,FrameNum)       \
+    (This)->lpVtbl -> TCallFrame(This,target,FrameNum)
+
+#define IShockwaveFlash_TCallLabel(This,target,label)  \
+    (This)->lpVtbl -> TCallLabel(This,target,label)
+
+#define IShockwaveFlash_TSetPropertyNum(This,target,property,value)    \
+    (This)->lpVtbl -> TSetPropertyNum(This,target,property,value)
+
+#define IShockwaveFlash_TGetPropertyNum(This,target,property,pVal)     \
+    (This)->lpVtbl -> TGetPropertyNum(This,target,property,pVal)
+
+#define IShockwaveFlash_TGetPropertyAsNumber(This,target,property,pVal)        \
+    (This)->lpVtbl -> TGetPropertyAsNumber(This,target,property,pVal)
+
+#define IShockwaveFlash_get_SWRemote(This,pVal)        \
+    (This)->lpVtbl -> get_SWRemote(This,pVal)
+
+#define IShockwaveFlash_put_SWRemote(This,pVal)        \
+    (This)->lpVtbl -> put_SWRemote(This,pVal)
+
+#define IShockwaveFlash_get_FlashVars(This,pVal)       \
+    (This)->lpVtbl -> get_FlashVars(This,pVal)
+
+#define IShockwaveFlash_put_FlashVars(This,pVal)       \
+    (This)->lpVtbl -> put_FlashVars(This,pVal)
+
+#define IShockwaveFlash_get_AllowScriptAccess(This,pVal)       \
+    (This)->lpVtbl -> get_AllowScriptAccess(This,pVal)
+
+#define IShockwaveFlash_put_AllowScriptAccess(This,pVal)       \
+    (This)->lpVtbl -> put_AllowScriptAccess(This,pVal)
+
+#define IShockwaveFlash_get_MovieData(This,pVal)       \
+    (This)->lpVtbl -> get_MovieData(This,pVal)
+
+#define IShockwaveFlash_put_MovieData(This,pVal)       \
+    (This)->lpVtbl -> put_MovieData(This,pVal)
+
+#define IShockwaveFlash_get_InlineData(This,ppIUnknown)        \
+    (This)->lpVtbl -> get_InlineData(This,ppIUnknown)
+
+#define IShockwaveFlash_put_InlineData(This,ppIUnknown)        \
+    (This)->lpVtbl -> put_InlineData(This,ppIUnknown)
+
+#define IShockwaveFlash_get_SeamlessTabbing(This,pVal) \
+    (This)->lpVtbl -> get_SeamlessTabbing(This,pVal)
+
+#define IShockwaveFlash_put_SeamlessTabbing(This,pVal) \
+    (This)->lpVtbl -> put_SeamlessTabbing(This,pVal)
+
+#define IShockwaveFlash_EnforceLocalSecurity(This)     \
+    (This)->lpVtbl -> EnforceLocalSecurity(This)
+
+#define IShockwaveFlash_get_Profile(This,pVal) \
+    (This)->lpVtbl -> get_Profile(This,pVal)
+
+#define IShockwaveFlash_put_Profile(This,pVal) \
+    (This)->lpVtbl -> put_Profile(This,pVal)
+
+#define IShockwaveFlash_get_ProfileAddress(This,pVal)  \
+    (This)->lpVtbl -> get_ProfileAddress(This,pVal)
+
+#define IShockwaveFlash_put_ProfileAddress(This,pVal)  \
+    (This)->lpVtbl -> put_ProfileAddress(This,pVal)
+
+#define IShockwaveFlash_get_ProfilePort(This,pVal)     \
+    (This)->lpVtbl -> get_ProfilePort(This,pVal)
+
+#define IShockwaveFlash_put_ProfilePort(This,pVal)     \
+    (This)->lpVtbl -> put_ProfilePort(This,pVal)
+
+#define IShockwaveFlash_CallFunction(This,request,response)    \
+    (This)->lpVtbl -> CallFunction(This,request,response)
+
+#define IShockwaveFlash_SetReturnValue(This,returnValue)       \
+    (This)->lpVtbl -> SetReturnValue(This,returnValue)
+
+#define IShockwaveFlash_DisableLocalSecurity(This)     \
+    (This)->lpVtbl -> DisableLocalSecurity(This)
+
+#define IShockwaveFlash_get_AllowNetworking(This,pVal) \
+    (This)->lpVtbl -> get_AllowNetworking(This,pVal)
+
+#define IShockwaveFlash_put_AllowNetworking(This,pVal) \
+    (This)->lpVtbl -> put_AllowNetworking(This,pVal)
+
+#define IShockwaveFlash_get_AllowFullScreen(This,pVal) \
+    (This)->lpVtbl -> get_AllowFullScreen(This,pVal)
+
+#define IShockwaveFlash_put_AllowFullScreen(This,pVal) \
+    (This)->lpVtbl -> put_AllowFullScreen(This,pVal)
+
+#endif /* COBJMACROS */
+
+
+#endif         /* C style interface */
+
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_ReadyState_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ long *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_ReadyState_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_TotalFrames_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ long *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_TotalFrames_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Playing_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ VARIANT_BOOL *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_Playing_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Playing_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ VARIANT_BOOL pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_Playing_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Quality_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ int *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_Quality_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Quality_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ int pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_Quality_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_ScaleMode_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ int *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_ScaleMode_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_ScaleMode_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ int pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_ScaleMode_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_AlignMode_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ int *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_AlignMode_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_AlignMode_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ int pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_AlignMode_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_BackgroundColor_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ long *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_BackgroundColor_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_BackgroundColor_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ long pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_BackgroundColor_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Loop_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ VARIANT_BOOL *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_Loop_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Loop_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ VARIANT_BOOL pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_Loop_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Movie_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_Movie_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Movie_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_Movie_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_receiveNum_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ long *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_receiveNum_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_FrameNum_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ long pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_FrameNum_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_SetZoomRect_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ long left,
+    /* [in] */ long top,
+    /* [in] */ long right,
+    /* [in] */ long bottom);
+
+
+void __RPC_STUB IShockwaveFlash_SetZoomRect_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Zoom_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ int factor);
+
+
+void __RPC_STUB IShockwaveFlash_Zoom_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Pan_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ long x,
+    /* [in] */ long y,
+    /* [in] */ int mode);
+
+
+void __RPC_STUB IShockwaveFlash_Pan_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Play_Proxy( 
+    IShockwaveFlash * This);
+
+
+void __RPC_STUB IShockwaveFlash_Play_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Stop_Proxy( 
+    IShockwaveFlash * This);
+
+
+void __RPC_STUB IShockwaveFlash_Stop_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Back_Proxy( 
+    IShockwaveFlash * This);
+
+
+void __RPC_STUB IShockwaveFlash_Back_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Forward_Proxy( 
+    IShockwaveFlash * This);
+
+
+void __RPC_STUB IShockwaveFlash_Forward_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_Rewind_Proxy( 
+    IShockwaveFlash * This);
+
+
+void __RPC_STUB IShockwaveFlash_Rewind_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_StopPlay_Proxy( 
+    IShockwaveFlash * This);
+
+
+void __RPC_STUB IShockwaveFlash_StopPlay_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_GotoFrame_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ long FrameNum);
+
+
+void __RPC_STUB IShockwaveFlash_GotoFrame_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_CurrentFrame_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ long *FrameNum);
+
+
+void __RPC_STUB IShockwaveFlash_CurrentFrame_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_IsPlaying_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ VARIANT_BOOL *Playing);
+
+
+void __RPC_STUB IShockwaveFlash_IsPlaying_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_PercentLoaded_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ long *percent);
+
+
+void __RPC_STUB IShockwaveFlash_PercentLoaded_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_FrameLoaded_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ long FrameNum,
+    /* [retval][out] */ VARIANT_BOOL *loaded);
+
+
+void __RPC_STUB IShockwaveFlash_FrameLoaded_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_FlashVersion_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ long *version);
+
+
+void __RPC_STUB IShockwaveFlash_FlashVersion_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_WMode_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_WMode_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_WMode_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_WMode_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_SAlign_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_SAlign_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_SAlign_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_SAlign_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Menu_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ VARIANT_BOOL *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_Menu_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Menu_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ VARIANT_BOOL pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_Menu_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Base_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_Base_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Base_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_Base_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Scale_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_Scale_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Scale_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_Scale_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_DeviceFont_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ VARIANT_BOOL *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_DeviceFont_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_DeviceFont_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ VARIANT_BOOL pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_DeviceFont_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_EmbedMovie_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ VARIANT_BOOL *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_EmbedMovie_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_EmbedMovie_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ VARIANT_BOOL pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_EmbedMovie_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_BGColor_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_BGColor_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_BGColor_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_BGColor_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Quality2_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_Quality2_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Quality2_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_Quality2_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_LoadMovie_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ int layer,
+    /* [in] */ BSTR url);
+
+
+void __RPC_STUB IShockwaveFlash_LoadMovie_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TGotoFrame_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [in] */ long FrameNum);
+
+
+void __RPC_STUB IShockwaveFlash_TGotoFrame_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TGotoLabel_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [in] */ BSTR label);
+
+
+void __RPC_STUB IShockwaveFlash_TGotoLabel_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TCurrentFrame_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [retval][out] */ long *FrameNum);
+
+
+void __RPC_STUB IShockwaveFlash_TCurrentFrame_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TCurrentLabel_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_TCurrentLabel_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TPlay_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target);
+
+
+void __RPC_STUB IShockwaveFlash_TPlay_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TStopPlay_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target);
+
+
+void __RPC_STUB IShockwaveFlash_TStopPlay_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_SetVariable_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR name,
+    /* [in] */ BSTR value);
+
+
+void __RPC_STUB IShockwaveFlash_SetVariable_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_GetVariable_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR name,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_GetVariable_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TSetProperty_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [in] */ int property,
+    /* [in] */ BSTR value);
+
+
+void __RPC_STUB IShockwaveFlash_TSetProperty_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TGetProperty_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [in] */ int property,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_TGetProperty_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TCallFrame_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [in] */ int FrameNum);
+
+
+void __RPC_STUB IShockwaveFlash_TCallFrame_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TCallLabel_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [in] */ BSTR label);
+
+
+void __RPC_STUB IShockwaveFlash_TCallLabel_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TSetPropertyNum_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [in] */ int property,
+    /* [in] */ double value);
+
+
+void __RPC_STUB IShockwaveFlash_TSetPropertyNum_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TGetPropertyNum_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [in] */ int property,
+    /* [retval][out] */ double *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_TGetPropertyNum_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_TGetPropertyAsNumber_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR target,
+    /* [in] */ int property,
+    /* [retval][out] */ double *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_TGetPropertyAsNumber_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_SWRemote_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_SWRemote_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_SWRemote_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_SWRemote_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_FlashVars_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_FlashVars_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_FlashVars_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_FlashVars_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_AllowScriptAccess_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_AllowScriptAccess_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_AllowScriptAccess_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_AllowScriptAccess_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_MovieData_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_MovieData_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_MovieData_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_MovieData_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_InlineData_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ IUnknown **ppIUnknown);
+
+
+void __RPC_STUB IShockwaveFlash_get_InlineData_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_InlineData_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ IUnknown *ppIUnknown);
+
+
+void __RPC_STUB IShockwaveFlash_put_InlineData_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_SeamlessTabbing_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ VARIANT_BOOL *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_SeamlessTabbing_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_SeamlessTabbing_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ VARIANT_BOOL pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_SeamlessTabbing_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_EnforceLocalSecurity_Proxy( 
+    IShockwaveFlash * This);
+
+
+void __RPC_STUB IShockwaveFlash_EnforceLocalSecurity_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_Profile_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ VARIANT_BOOL *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_Profile_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_Profile_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ VARIANT_BOOL pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_Profile_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_ProfileAddress_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_ProfileAddress_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_ProfileAddress_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_ProfileAddress_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_ProfilePort_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ long *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_ProfilePort_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_ProfilePort_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ long pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_ProfilePort_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_CallFunction_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR request,
+    /* [retval][out] */ BSTR *response);
+
+
+void __RPC_STUB IShockwaveFlash_CallFunction_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_SetReturnValue_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR returnValue);
+
+
+void __RPC_STUB IShockwaveFlash_SetReturnValue_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_DisableLocalSecurity_Proxy( 
+    IShockwaveFlash * This);
+
+
+void __RPC_STUB IShockwaveFlash_DisableLocalSecurity_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_AllowNetworking_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_AllowNetworking_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_AllowNetworking_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_AllowNetworking_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propget][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_get_AllowFullScreen_Proxy( 
+    IShockwaveFlash * This,
+    /* [retval][out] */ BSTR *pVal);
+
+
+void __RPC_STUB IShockwaveFlash_get_AllowFullScreen_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+/* [helpstring][propput][id] */ HRESULT STDMETHODCALLTYPE IShockwaveFlash_put_AllowFullScreen_Proxy( 
+    IShockwaveFlash * This,
+    /* [in] */ BSTR pVal);
+
+
+void __RPC_STUB IShockwaveFlash_put_AllowFullScreen_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+
+#endif         /* __IShockwaveFlash_INTERFACE_DEFINED__ */
+
+
+#ifndef ___IShockwaveFlashEvents_DISPINTERFACE_DEFINED__
+#define ___IShockwaveFlashEvents_DISPINTERFACE_DEFINED__
+
+/* dispinterface _IShockwaveFlashEvents */
+/* [hidden][helpstring][uuid] */ 
+
+
+EXTERN_C const IID DIID__IShockwaveFlashEvents;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+    MIDL_INTERFACE("D27CDB6D-AE6D-11CF-96B8-444553540000")
+    _IShockwaveFlashEvents : public IDispatch
+    {
+    };
+    
+#else  /* C style interface */
+
+    typedef struct _IShockwaveFlashEventsVtbl
+    {
+        BEGIN_INTERFACE
+        
+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
+            _IShockwaveFlashEvents * This,
+            /* [in] */ REFIID riid,
+            /* [iid_is][out] */ void **ppvObject);
+        
+        ULONG ( STDMETHODCALLTYPE *AddRef )( 
+            _IShockwaveFlashEvents * This);
+        
+        ULONG ( STDMETHODCALLTYPE *Release )( 
+            _IShockwaveFlashEvents * This);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( 
+            _IShockwaveFlashEvents * This,
+            /* [out] */ UINT *pctinfo);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( 
+            _IShockwaveFlashEvents * This,
+            /* [in] */ UINT iTInfo,
+            /* [in] */ LCID lcid,
+            /* [out] */ ITypeInfo **ppTInfo);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( 
+            _IShockwaveFlashEvents * This,
+            /* [in] */ REFIID riid,
+            /* [size_is][in] */ LPOLESTR *rgszNames,
+            /* [in] */ UINT cNames,
+            /* [in] */ LCID lcid,
+            /* [size_is][out] */ DISPID *rgDispId);
+        
+        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( 
+            _IShockwaveFlashEvents * This,
+            /* [in] */ DISPID dispIdMember,
+            /* [in] */ REFIID riid,
+            /* [in] */ LCID lcid,
+            /* [in] */ WORD wFlags,
+            /* [out][in] */ DISPPARAMS *pDispParams,
+            /* [out] */ VARIANT *pVarResult,
+            /* [out] */ EXCEPINFO *pExcepInfo,
+            /* [out] */ UINT *puArgErr);
+        
+        END_INTERFACE
+    } _IShockwaveFlashEventsVtbl;
+
+    interface _IShockwaveFlashEvents
+    {
+        CONST_VTBL struct _IShockwaveFlashEventsVtbl *lpVtbl;
+    };
+
+    
+
+#ifdef COBJMACROS
+
+
+#define _IShockwaveFlashEvents_QueryInterface(This,riid,ppvObject)     \
+    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define _IShockwaveFlashEvents_AddRef(This)    \
+    (This)->lpVtbl -> AddRef(This)
+
+#define _IShockwaveFlashEvents_Release(This)   \
+    (This)->lpVtbl -> Release(This)
+
+
+#define _IShockwaveFlashEvents_GetTypeInfoCount(This,pctinfo)  \
+    (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)
+
+#define _IShockwaveFlashEvents_GetTypeInfo(This,iTInfo,lcid,ppTInfo)   \
+    (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)
+
+#define _IShockwaveFlashEvents_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \
+    (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)
+
+#define _IShockwaveFlashEvents_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)   \
+    (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)
+
+#endif /* COBJMACROS */
+
+
+#endif         /* C style interface */
+
+
+#endif         /* ___IShockwaveFlashEvents_DISPINTERFACE_DEFINED__ */
+
+
+#ifndef __IFlashFactory_INTERFACE_DEFINED__
+#define __IFlashFactory_INTERFACE_DEFINED__
+
+/* interface IFlashFactory */
+/* [object][helpstring][uuid] */ 
+
+
+EXTERN_C const IID IID_IFlashFactory;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+    
+    MIDL_INTERFACE("D27CDB70-AE6D-11CF-96B8-444553540000")
+    IFlashFactory : public IUnknown
+    {
+    public:
+    };
+    
+#else  /* C style interface */
+
+    typedef struct IFlashFactoryVtbl
+    {
+        BEGIN_INTERFACE
+        
+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
+            IFlashFactory * This,
+            /* [in] */ REFIID riid,
+            /* [iid_is][out] */ void **ppvObject);
+        
+        ULONG ( STDMETHODCALLTYPE *AddRef )( 
+            IFlashFactory * This);
+        
+        ULONG ( STDMETHODCALLTYPE *Release )( 
+            IFlashFactory * This);
+        
+        END_INTERFACE
+    } IFlashFactoryVtbl;
+
+    interface IFlashFactory
+    {
+        CONST_VTBL struct IFlashFactoryVtbl *lpVtbl;
+    };
+
+    
+
+#ifdef COBJMACROS
+
+
+#define IFlashFactory_QueryInterface(This,riid,ppvObject)      \
+    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IFlashFactory_AddRef(This)     \
+    (This)->lpVtbl -> AddRef(This)
+
+#define IFlashFactory_Release(This)    \
+    (This)->lpVtbl -> Release(This)
+
+
+#endif /* COBJMACROS */
+
+
+#endif         /* C style interface */
+
+
+
+
+#endif         /* __IFlashFactory_INTERFACE_DEFINED__ */
+
+
+#ifndef __IFlashObjectInterface_INTERFACE_DEFINED__
+#define __IFlashObjectInterface_INTERFACE_DEFINED__
+
+/* interface IFlashObjectInterface */
+/* [object][helpstring][uuid] */ 
+
+
+EXTERN_C const IID IID_IFlashObjectInterface;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+    
+    MIDL_INTERFACE("D27CDB72-AE6D-11CF-96B8-444553540000")
+    IFlashObjectInterface : public IDispatchEx
+    {
+    public:
+    };
+    
+#else  /* C style interface */
+
+    typedef struct IFlashObjectInterfaceVtbl
+    {
+        BEGIN_INTERFACE
+        
+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
+            IFlashObjectInterface * This,
+            /* [in] */ REFIID riid,
+            /* [iid_is][out] */ void **ppvObject);
+        
+        ULONG ( STDMETHODCALLTYPE *AddRef )( 
+            IFlashObjectInterface * This);
+        
+        ULONG ( STDMETHODCALLTYPE *Release )( 
+            IFlashObjectInterface * This);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( 
+            IFlashObjectInterface * This,
+            /* [out] */ UINT *pctinfo);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( 
+            IFlashObjectInterface * This,
+            /* [in] */ UINT iTInfo,
+            /* [in] */ LCID lcid,
+            /* [out] */ ITypeInfo **ppTInfo);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( 
+            IFlashObjectInterface * This,
+            /* [in] */ REFIID riid,
+            /* [size_is][in] */ LPOLESTR *rgszNames,
+            /* [in] */ UINT cNames,
+            /* [in] */ LCID lcid,
+            /* [size_is][out] */ DISPID *rgDispId);
+        
+        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( 
+            IFlashObjectInterface * This,
+            /* [in] */ DISPID dispIdMember,
+            /* [in] */ REFIID riid,
+            /* [in] */ LCID lcid,
+            /* [in] */ WORD wFlags,
+            /* [out][in] */ DISPPARAMS *pDispParams,
+            /* [out] */ VARIANT *pVarResult,
+            /* [out] */ EXCEPINFO *pExcepInfo,
+            /* [out] */ UINT *puArgErr);
+        
+        HRESULT ( __stdcall *GetDispID )( 
+            IFlashObjectInterface * This,
+            /* [in] */ BSTR bstrName,
+            /* [in] */ unsigned long grfdex,
+            /* [out] */ long *pid);
+        
+        HRESULT ( __stdcall *RemoteInvokeEx )( 
+            IFlashObjectInterface * This,
+            /* [in] */ long id,
+            /* [in] */ unsigned long lcid,
+            /* [in] */ unsigned long dwFlags,
+            /* [in] */ DISPPARAMS *pdp,
+            /* [out] */ VARIANT *pvarRes,
+            /* [out] */ EXCEPINFO *pei,
+            /* [in] */ IServiceProvider *pspCaller,
+            /* [in] */ unsigned int cvarRefArg,
+            /* [in] */ unsigned int *rgiRefArg,
+            /* [out][in] */ VARIANT *rgvarRefArg);
+        
+        HRESULT ( __stdcall *DeleteMemberByName )( 
+            IFlashObjectInterface * This,
+            /* [in] */ BSTR bstrName,
+            /* [in] */ unsigned long grfdex);
+        
+        HRESULT ( __stdcall *DeleteMemberByDispID )( 
+            IFlashObjectInterface * This,
+            /* [in] */ long id);
+        
+        HRESULT ( __stdcall *GetMemberProperties )( 
+            IFlashObjectInterface * This,
+            /* [in] */ long id,
+            /* [in] */ unsigned long grfdexFetch,
+            /* [out] */ unsigned long *pgrfdex);
+        
+        HRESULT ( __stdcall *GetMemberName )( 
+            IFlashObjectInterface * This,
+            /* [in] */ long id,
+            /* [out] */ BSTR *pbstrName);
+        
+        HRESULT ( __stdcall *GetNextDispID )( 
+            IFlashObjectInterface * This,
+            /* [in] */ unsigned long grfdex,
+            /* [in] */ long id,
+            /* [out] */ long *pid);
+        
+        HRESULT ( __stdcall *GetNameSpaceParent )( 
+            IFlashObjectInterface * This,
+            /* [out] */ IUnknown **ppunk);
+        
+        END_INTERFACE
+    } IFlashObjectInterfaceVtbl;
+
+    interface IFlashObjectInterface
+    {
+        CONST_VTBL struct IFlashObjectInterfaceVtbl *lpVtbl;
+    };
+
+    
+
+#ifdef COBJMACROS
+
+
+#define IFlashObjectInterface_QueryInterface(This,riid,ppvObject)      \
+    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IFlashObjectInterface_AddRef(This)     \
+    (This)->lpVtbl -> AddRef(This)
+
+#define IFlashObjectInterface_Release(This)    \
+    (This)->lpVtbl -> Release(This)
+
+
+#define IFlashObjectInterface_GetTypeInfoCount(This,pctinfo)   \
+    (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)
+
+#define IFlashObjectInterface_GetTypeInfo(This,iTInfo,lcid,ppTInfo)    \
+    (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)
+
+#define IFlashObjectInterface_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)  \
+    (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)
+
+#define IFlashObjectInterface_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)    \
+    (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)
+
+
+#define IFlashObjectInterface_GetDispID(This,bstrName,grfdex,pid)      \
+    (This)->lpVtbl -> GetDispID(This,bstrName,grfdex,pid)
+
+#define IFlashObjectInterface_RemoteInvokeEx(This,id,lcid,dwFlags,pdp,pvarRes,pei,pspCaller,cvarRefArg,rgiRefArg,rgvarRefArg)  \
+    (This)->lpVtbl -> RemoteInvokeEx(This,id,lcid,dwFlags,pdp,pvarRes,pei,pspCaller,cvarRefArg,rgiRefArg,rgvarRefArg)
+
+#define IFlashObjectInterface_DeleteMemberByName(This,bstrName,grfdex) \
+    (This)->lpVtbl -> DeleteMemberByName(This,bstrName,grfdex)
+
+#define IFlashObjectInterface_DeleteMemberByDispID(This,id)    \
+    (This)->lpVtbl -> DeleteMemberByDispID(This,id)
+
+#define IFlashObjectInterface_GetMemberProperties(This,id,grfdexFetch,pgrfdex) \
+    (This)->lpVtbl -> GetMemberProperties(This,id,grfdexFetch,pgrfdex)
+
+#define IFlashObjectInterface_GetMemberName(This,id,pbstrName) \
+    (This)->lpVtbl -> GetMemberName(This,id,pbstrName)
+
+#define IFlashObjectInterface_GetNextDispID(This,grfdex,id,pid)        \
+    (This)->lpVtbl -> GetNextDispID(This,grfdex,id,pid)
+
+#define IFlashObjectInterface_GetNameSpaceParent(This,ppunk)   \
+    (This)->lpVtbl -> GetNameSpaceParent(This,ppunk)
+
+
+#endif /* COBJMACROS */
+
+
+#endif         /* C style interface */
+
+
+
+
+#endif         /* __IFlashObjectInterface_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDispatchEx_INTERFACE_DEFINED__
+#define __IDispatchEx_INTERFACE_DEFINED__
+
+/* interface IDispatchEx */
+/* [object][uuid] */ 
+
+
+EXTERN_C const IID IID_IDispatchEx;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+    
+    MIDL_INTERFACE("A6EF9860-C720-11D0-9337-00A0C90DCAA9")
+    IDispatchEx : public IDispatch
+    {
+    public:
+        virtual HRESULT __stdcall GetDispID( 
+            /* [in] */ BSTR bstrName,
+            /* [in] */ unsigned long grfdex,
+            /* [out] */ long *pid) = 0;
+        
+        virtual HRESULT __stdcall RemoteInvokeEx( 
+            /* [in] */ long id,
+            /* [in] */ unsigned long lcid,
+            /* [in] */ unsigned long dwFlags,
+            /* [in] */ DISPPARAMS *pdp,
+            /* [out] */ VARIANT *pvarRes,
+            /* [out] */ EXCEPINFO *pei,
+            /* [in] */ IServiceProvider *pspCaller,
+            /* [in] */ unsigned int cvarRefArg,
+            /* [in] */ unsigned int *rgiRefArg,
+            /* [out][in] */ VARIANT *rgvarRefArg) = 0;
+        
+        virtual HRESULT __stdcall DeleteMemberByName( 
+            /* [in] */ BSTR bstrName,
+            /* [in] */ unsigned long grfdex) = 0;
+        
+        virtual HRESULT __stdcall DeleteMemberByDispID( 
+            /* [in] */ long id) = 0;
+        
+        virtual HRESULT __stdcall GetMemberProperties( 
+            /* [in] */ long id,
+            /* [in] */ unsigned long grfdexFetch,
+            /* [out] */ unsigned long *pgrfdex) = 0;
+        
+        virtual HRESULT __stdcall GetMemberName( 
+            /* [in] */ long id,
+            /* [out] */ BSTR *pbstrName) = 0;
+        
+        virtual HRESULT __stdcall GetNextDispID( 
+            /* [in] */ unsigned long grfdex,
+            /* [in] */ long id,
+            /* [out] */ long *pid) = 0;
+        
+        virtual HRESULT __stdcall GetNameSpaceParent( 
+            /* [out] */ IUnknown **ppunk) = 0;
+        
+    };
+    
+#else  /* C style interface */
+
+    typedef struct IDispatchExVtbl
+    {
+        BEGIN_INTERFACE
+        
+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
+            IDispatchEx * This,
+            /* [in] */ REFIID riid,
+            /* [iid_is][out] */ void **ppvObject);
+        
+        ULONG ( STDMETHODCALLTYPE *AddRef )( 
+            IDispatchEx * This);
+        
+        ULONG ( STDMETHODCALLTYPE *Release )( 
+            IDispatchEx * This);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( 
+            IDispatchEx * This,
+            /* [out] */ UINT *pctinfo);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( 
+            IDispatchEx * This,
+            /* [in] */ UINT iTInfo,
+            /* [in] */ LCID lcid,
+            /* [out] */ ITypeInfo **ppTInfo);
+        
+        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( 
+            IDispatchEx * This,
+            /* [in] */ REFIID riid,
+            /* [size_is][in] */ LPOLESTR *rgszNames,
+            /* [in] */ UINT cNames,
+            /* [in] */ LCID lcid,
+            /* [size_is][out] */ DISPID *rgDispId);
+        
+        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( 
+            IDispatchEx * This,
+            /* [in] */ DISPID dispIdMember,
+            /* [in] */ REFIID riid,
+            /* [in] */ LCID lcid,
+            /* [in] */ WORD wFlags,
+            /* [out][in] */ DISPPARAMS *pDispParams,
+            /* [out] */ VARIANT *pVarResult,
+            /* [out] */ EXCEPINFO *pExcepInfo,
+            /* [out] */ UINT *puArgErr);
+        
+        HRESULT ( __stdcall *GetDispID )( 
+            IDispatchEx * This,
+            /* [in] */ BSTR bstrName,
+            /* [in] */ unsigned long grfdex,
+            /* [out] */ long *pid);
+        
+        HRESULT ( __stdcall *RemoteInvokeEx )( 
+            IDispatchEx * This,
+            /* [in] */ long id,
+            /* [in] */ unsigned long lcid,
+            /* [in] */ unsigned long dwFlags,
+            /* [in] */ DISPPARAMS *pdp,
+            /* [out] */ VARIANT *pvarRes,
+            /* [out] */ EXCEPINFO *pei,
+            /* [in] */ IServiceProvider *pspCaller,
+            /* [in] */ unsigned int cvarRefArg,
+            /* [in] */ unsigned int *rgiRefArg,
+            /* [out][in] */ VARIANT *rgvarRefArg);
+        
+        HRESULT ( __stdcall *DeleteMemberByName )( 
+            IDispatchEx * This,
+            /* [in] */ BSTR bstrName,
+            /* [in] */ unsigned long grfdex);
+        
+        HRESULT ( __stdcall *DeleteMemberByDispID )( 
+            IDispatchEx * This,
+            /* [in] */ long id);
+        
+        HRESULT ( __stdcall *GetMemberProperties )( 
+            IDispatchEx * This,
+            /* [in] */ long id,
+            /* [in] */ unsigned long grfdexFetch,
+            /* [out] */ unsigned long *pgrfdex);
+        
+        HRESULT ( __stdcall *GetMemberName )( 
+            IDispatchEx * This,
+            /* [in] */ long id,
+            /* [out] */ BSTR *pbstrName);
+        
+        HRESULT ( __stdcall *GetNextDispID )( 
+            IDispatchEx * This,
+            /* [in] */ unsigned long grfdex,
+            /* [in] */ long id,
+            /* [out] */ long *pid);
+        
+        HRESULT ( __stdcall *GetNameSpaceParent )( 
+            IDispatchEx * This,
+            /* [out] */ IUnknown **ppunk);
+        
+        END_INTERFACE
+    } IDispatchExVtbl;
+
+    interface IDispatchEx
+    {
+        CONST_VTBL struct IDispatchExVtbl *lpVtbl;
+    };
+
+    
+
+#ifdef COBJMACROS
+
+
+#define IDispatchEx_QueryInterface(This,riid,ppvObject)        \
+    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IDispatchEx_AddRef(This)       \
+    (This)->lpVtbl -> AddRef(This)
+
+#define IDispatchEx_Release(This)      \
+    (This)->lpVtbl -> Release(This)
+
+
+#define IDispatchEx_GetTypeInfoCount(This,pctinfo)     \
+    (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)
+
+#define IDispatchEx_GetTypeInfo(This,iTInfo,lcid,ppTInfo)      \
+    (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)
+
+#define IDispatchEx_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)    \
+    (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)
+
+#define IDispatchEx_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)      \
+    (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)
+
+
+#define IDispatchEx_GetDispID(This,bstrName,grfdex,pid)        \
+    (This)->lpVtbl -> GetDispID(This,bstrName,grfdex,pid)
+
+#define IDispatchEx_RemoteInvokeEx(This,id,lcid,dwFlags,pdp,pvarRes,pei,pspCaller,cvarRefArg,rgiRefArg,rgvarRefArg)    \
+    (This)->lpVtbl -> RemoteInvokeEx(This,id,lcid,dwFlags,pdp,pvarRes,pei,pspCaller,cvarRefArg,rgiRefArg,rgvarRefArg)
+
+#define IDispatchEx_DeleteMemberByName(This,bstrName,grfdex)   \
+    (This)->lpVtbl -> DeleteMemberByName(This,bstrName,grfdex)
+
+#define IDispatchEx_DeleteMemberByDispID(This,id)      \
+    (This)->lpVtbl -> DeleteMemberByDispID(This,id)
+
+#define IDispatchEx_GetMemberProperties(This,id,grfdexFetch,pgrfdex)   \
+    (This)->lpVtbl -> GetMemberProperties(This,id,grfdexFetch,pgrfdex)
+
+#define IDispatchEx_GetMemberName(This,id,pbstrName)   \
+    (This)->lpVtbl -> GetMemberName(This,id,pbstrName)
+
+#define IDispatchEx_GetNextDispID(This,grfdex,id,pid)  \
+    (This)->lpVtbl -> GetNextDispID(This,grfdex,id,pid)
+
+#define IDispatchEx_GetNameSpaceParent(This,ppunk)     \
+    (This)->lpVtbl -> GetNameSpaceParent(This,ppunk)
+
+#endif /* COBJMACROS */
+
+
+#endif         /* C style interface */
+
+
+
+HRESULT __stdcall IDispatchEx_GetDispID_Proxy( 
+    IDispatchEx * This,
+    /* [in] */ BSTR bstrName,
+    /* [in] */ unsigned long grfdex,
+    /* [out] */ long *pid);
+
+
+void __RPC_STUB IDispatchEx_GetDispID_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+HRESULT __stdcall IDispatchEx_RemoteInvokeEx_Proxy( 
+    IDispatchEx * This,
+    /* [in] */ long id,
+    /* [in] */ unsigned long lcid,
+    /* [in] */ unsigned long dwFlags,
+    /* [in] */ DISPPARAMS *pdp,
+    /* [out] */ VARIANT *pvarRes,
+    /* [out] */ EXCEPINFO *pei,
+    /* [in] */ IServiceProvider *pspCaller,
+    /* [in] */ unsigned int cvarRefArg,
+    /* [in] */ unsigned int *rgiRefArg,
+    /* [out][in] */ VARIANT *rgvarRefArg);
+
+
+void __RPC_STUB IDispatchEx_RemoteInvokeEx_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+HRESULT __stdcall IDispatchEx_DeleteMemberByName_Proxy( 
+    IDispatchEx * This,
+    /* [in] */ BSTR bstrName,
+    /* [in] */ unsigned long grfdex);
+
+
+void __RPC_STUB IDispatchEx_DeleteMemberByName_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+HRESULT __stdcall IDispatchEx_DeleteMemberByDispID_Proxy( 
+    IDispatchEx * This,
+    /* [in] */ long id);
+
+
+void __RPC_STUB IDispatchEx_DeleteMemberByDispID_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+HRESULT __stdcall IDispatchEx_GetMemberProperties_Proxy( 
+    IDispatchEx * This,
+    /* [in] */ long id,
+    /* [in] */ unsigned long grfdexFetch,
+    /* [out] */ unsigned long *pgrfdex);
+
+
+void __RPC_STUB IDispatchEx_GetMemberProperties_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+HRESULT __stdcall IDispatchEx_GetMemberName_Proxy( 
+    IDispatchEx * This,
+    /* [in] */ long id,
+    /* [out] */ BSTR *pbstrName);
+
+
+void __RPC_STUB IDispatchEx_GetMemberName_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+HRESULT __stdcall IDispatchEx_GetNextDispID_Proxy( 
+    IDispatchEx * This,
+    /* [in] */ unsigned long grfdex,
+    /* [in] */ long id,
+    /* [out] */ long *pid);
+
+
+void __RPC_STUB IDispatchEx_GetNextDispID_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+HRESULT __stdcall IDispatchEx_GetNameSpaceParent_Proxy( 
+    IDispatchEx * This,
+    /* [out] */ IUnknown **ppunk);
+
+
+void __RPC_STUB IDispatchEx_GetNameSpaceParent_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+
+#endif         /* __IDispatchEx_INTERFACE_DEFINED__ */
+
+
+#ifndef __IServiceProvider_INTERFACE_DEFINED__
+#define __IServiceProvider_INTERFACE_DEFINED__
+
+/* interface IServiceProvider */
+/* [object][uuid] */ 
+
+
+EXTERN_C const IID IID_IServiceProvider;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+    
+    MIDL_INTERFACE("6D5140C1-7436-11CE-8034-00AA006009FA")
+    IServiceProvider : public IUnknown
+    {
+    public:
+        virtual HRESULT __stdcall RemoteQueryService( 
+            /* [in] */ GUID *guidService,
+            /* [in] */ GUID *riid,
+            /* [out] */ IUnknown **ppvObject) = 0;
+        
+    };
+    
+#else  /* C style interface */
+
+    typedef struct IServiceProviderVtbl
+    {
+        BEGIN_INTERFACE
+        
+        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
+            IServiceProvider * This,
+            /* [in] */ REFIID riid,
+            /* [iid_is][out] */ void **ppvObject);
+        
+        ULONG ( STDMETHODCALLTYPE *AddRef )( 
+            IServiceProvider * This);
+        
+        ULONG ( STDMETHODCALLTYPE *Release )( 
+            IServiceProvider * This);
+        
+        HRESULT ( __stdcall *RemoteQueryService )( 
+            IServiceProvider * This,
+            /* [in] */ GUID *guidService,
+            /* [in] */ GUID *riid,
+            /* [out] */ IUnknown **ppvObject);
+        
+        END_INTERFACE
+    } IServiceProviderVtbl;
+
+    interface IServiceProvider
+    {
+        CONST_VTBL struct IServiceProviderVtbl *lpVtbl;
+    };
+
+    
+
+#ifdef COBJMACROS
+
+
+#define IServiceProvider_QueryInterface(This,riid,ppvObject)   \
+    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IServiceProvider_AddRef(This)  \
+    (This)->lpVtbl -> AddRef(This)
+
+#define IServiceProvider_Release(This) \
+    (This)->lpVtbl -> Release(This)
+
+
+#define IServiceProvider_RemoteQueryService(This,guidService,riid,ppvObject)   \
+    (This)->lpVtbl -> RemoteQueryService(This,guidService,riid,ppvObject)
+
+#endif /* COBJMACROS */
+
+
+#endif         /* C style interface */
+
+
+
+HRESULT __stdcall IServiceProvider_RemoteQueryService_Proxy( 
+    IServiceProvider * This,
+    /* [in] */ GUID *guidService,
+    /* [in] */ GUID *riid,
+    /* [out] */ IUnknown **ppvObject);
+
+
+void __RPC_STUB IServiceProvider_RemoteQueryService_Stub(
+    IRpcStubBuffer *This,
+    IRpcChannelBuffer *_pRpcChannelBuffer,
+    PRPC_MESSAGE _pRpcMessage,
+    DWORD *_pdwStubPhase);
+
+
+
+#endif         /* __IServiceProvider_INTERFACE_DEFINED__ */
+
+
+EXTERN_C const CLSID CLSID_ShockwaveFlash;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("D27CDB6E-AE6D-11CF-96B8-444553540000")
+ShockwaveFlash;
+#endif
+
+EXTERN_C const CLSID CLSID_FlashObjectInterface;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("D27CDB71-AE6D-11CF-96B8-444553540000")
+FlashObjectInterface;
+#endif
+#endif /* __ShockwaveFlashObjects_LIBRARY_DEFINED__ */
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
index bfdcfa91a93bc7148ed8f16dac1dd606b1250440..9949be7393b5360ea206a6c0866d8094024c8955 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "FlashAxContainer.h"\r
-#include "../interop/TimerHelper.h"\r
-\r
-#include <common/log.h>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push, 2) // TODO\r
-#endif\r
-\r
-using namespace ATL;\r
-\r
-namespace caspar { namespace flash {\r
-\r
-CComBSTR FlashAxContainer::flashGUID_(_T("{D27CDB6E-AE6D-11CF-96B8-444553540000}"));\r
-\r
-_ATL_FUNC_INFO fnInfoFlashCallEvent = { CC_STDCALL, VT_EMPTY, 1, { VT_BSTR } };\r
-_ATL_FUNC_INFO fnInfoReadyStateChangeEvent = { CC_STDCALL, VT_EMPTY, 1, { VT_I4 } };\r
-\r
-FlashAxContainer::FlashAxContainer() : bInPlaceActive_(FALSE), pTimerHelper(0), bInvalidRect_(false), bReadyToRender_(false), bHasNewTiming_(false), m_lpDD4(0), timerCount_(0), bIsEmpty_(true)\r
-{\r
-}\r
-FlashAxContainer::~FlashAxContainer()\r
-{      \r
-       if(m_lpDD4)\r
-       {\r
-               m_lpDD4->Release();\r
-               m_lpDD4 = nullptr;\r
-       }\r
-\r
-       if(pTimerHelper != 0)\r
-               delete pTimerHelper;\r
-}\r
-\r
-\r
-/////////\r
-// IObjectWithSite\r
-/////////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::SetSite(IUnknown* pUnkSite)\r
-{\r
-       ATLTRACE(_T("IObjectWithSite::SetSite\n"));\r
-       HRESULT hr = IObjectWithSiteImpl<FlashAxContainer>::SetSite(pUnkSite);\r
-\r
-       if (SUCCEEDED(hr) && m_spUnkSite)\r
-       {\r
-               // Look for "outer" IServiceProvider\r
-               hr = m_spUnkSite->QueryInterface(__uuidof(IServiceProvider), (void**)&m_spServices);\r
-               ATLASSERT( !hr && _T("No ServiceProvider!") );\r
-       }\r
-\r
-       if (pUnkSite == NULL)\r
-               m_spServices.Release();\r
-\r
-       return hr;\r
-}\r
-\r
-/////////\r
-// IOleClientSite\r
-/////////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::SaveObject()\r
-{\r
-       ATLTRACENOTIMPL(_T("IOleClientSite::SaveObject"));\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk)\r
-{\r
-/*     if(*ppmk != NULL) {\r
-               if(m_spMyMoniker == NULL) {\r
-                       ATL::CComObject<MyMoniker>* pMoniker = NULL;\r
-                       HRESULT hr = ATL::CComObject<MyMoniker>::CreateInstance(&pMoniker);\r
-                       if(SUCCEEDED(hr))\r
-                               m_spMyMoniker = pMoniker;\r
-               }\r
-\r
-               if(m_spMyMoniker != NULL) {\r
-                       *ppmk = m_spMyMoniker;\r
-                       (*ppmk)->AddRef();\r
-                       return S_OK;\r
-               }\r
-       }\r
-*/     if(ppmk != NULL)\r
-               *ppmk = NULL;\r
-       return E_FAIL;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetContainer(IOleContainer** ppContainer)\r
-{\r
-       ATLTRACE(_T("IOleClientSite::GetContainer\n"));\r
-       (*ppContainer) = NULL;\r
-       return E_NOINTERFACE;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::ShowObject()\r
-{\r
-       ATLTRACE(_T("IOleClientSite::ShowObject\n"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnShowWindow(BOOL fShow)\r
-{\r
-       ATLTRACE(_T("IOleClientSite::OnShowWindow"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::RequestNewObjectLayout()\r
-{\r
-       ATLTRACE(_T("IOleClientSite::RequestNewObjectLayout"));\r
-       return S_OK;\r
-}\r
-\r
-/////////\r
-// IOleInPlaceSite\r
-/////////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetWindow(HWND* pHwnd)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::GetWindow\n"));\r
-       (*pHwnd) = NULL;//GetApplication()->GetMainWindow()->getHwnd();\r
-       return E_FAIL;\r
-}\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::ContextSensitiveHelp(BOOL fEnterMode)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::ContextSensitiveHelp"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::CanInPlaceActivate()\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::CanInPlaceActivate\n"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceActivate()\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::OnInPlaceActivate"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnUIActivate()\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::OnUIActivate\n"));\r
-       bUIActive_ = TRUE;\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetWindowContext(IOleInPlaceFrame** ppFrame, IOleInPlaceUIWindow** ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO pFrameInfo)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::GetWindowContext\n"));\r
-       if (ppFrame != NULL)\r
-               *ppFrame = NULL;\r
-       if (ppDoc != NULL)\r
-               *ppDoc = NULL;\r
-\r
-       if (ppFrame == NULL || ppDoc == NULL || lprcPosRect == NULL || lprcClipRect == NULL)\r
-               return E_POINTER;\r
-\r
-       pFrameInfo->fMDIApp = FALSE;\r
-       pFrameInfo->haccel = NULL;\r
-       pFrameInfo->cAccelEntries = 0;\r
-       pFrameInfo->hwndFrame = NULL;\r
-\r
-       lprcPosRect->top = m_rcPos.top;\r
-       lprcPosRect->left = m_rcPos.left;\r
-       lprcPosRect->right = m_rcPos.right;\r
-       lprcPosRect->bottom = m_rcPos.bottom;\r
-\r
-       lprcClipRect->top = m_rcPos.top;\r
-       lprcClipRect->left = m_rcPos.left;\r
-       lprcClipRect->right = m_rcPos.right;\r
-       lprcClipRect->bottom = m_rcPos.bottom;\r
-\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::Scroll(SIZE scrollExtant)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::Scroll"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnUIDeactivate(BOOL fUndoable)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::OnUIDeactivate\n"));\r
-       bUIActive_ = FALSE;\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceDeactivate()\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::OnInPlaceDeactivate\n"));\r
-       bInPlaceActive_ = FALSE;\r
-       m_spInPlaceObjectWindowless.Release();\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::DiscardUndoState()\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::DiscardUndoState"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::DeactivateAndUndo()\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::DeactivateAndUndo"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnPosRectChange(LPCRECT lprcPosRect)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSite::OnPosRectChange"));\r
-       return S_OK;\r
-}\r
-\r
-\r
-//////////\r
-// IOleInPlaceSiteEx\r
-//////////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceActivateEx(BOOL* pfNoRedraw, DWORD dwFlags)\r
-{\r
-       // should only be called once the first time control is inplace-activated\r
-       ATLTRACE(_T("IOleInPlaceSiteEx::OnInPlaceActivateEx\n"));\r
-       ATLASSERT(bInPlaceActive_ == FALSE);\r
-       ATLASSERT(m_spInPlaceObjectWindowless == NULL);\r
-\r
-       bInPlaceActive_ = TRUE;\r
-       OleLockRunning(m_spOleObject, TRUE, FALSE);\r
-       HRESULT hr = E_FAIL;\r
-       if (dwFlags & ACTIVATE_WINDOWLESS)\r
-       {\r
-               hr = m_spOleObject->QueryInterface(__uuidof(IOleInPlaceObjectWindowless), (void**) &m_spInPlaceObjectWindowless);\r
-\r
-               if (m_spInPlaceObjectWindowless != NULL)\r
-                       m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &m_rcPos);\r
-       }\r
-\r
-       return (m_spInPlaceObjectWindowless != NULL) ? S_OK : E_FAIL;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceDeactivateEx(BOOL fNoRedraw)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteEx::OnInPlaceDeactivateEx\n"));\r
-       bInPlaceActive_ = FALSE;\r
-       m_spInPlaceObjectWindowless.Release();\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::RequestUIActivate()\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteEx::RequestUIActivate\n"));\r
-       return S_OK;\r
-}\r
-\r
-\r
-//////////////\r
-// IOleInPlaceSiteWindowless\r
-//////////////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::CanWindowlessActivate()\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::CanWindowlessActivate\n"));\r
-       return S_OK;\r
-//     return S_FALSE;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetCapture()\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::GetCapture\n"));\r
-       return bCapture_ ? S_OK : S_FALSE;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::SetCapture(BOOL fCapture)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::SetCapture\n"));\r
-       bCapture_ = fCapture;\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetFocus()\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::GetFocus\n"));\r
-       return bHaveFocus_ ? S_OK : S_FALSE;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::SetFocus(BOOL fGotFocus)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::SetFocus\n"));\r
-       bHaveFocus_ = fGotFocus;\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetDC(LPCRECT pRect, DWORD grfFlags, HDC* phDC)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::GetDC"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::ReleaseDC(HDC hDC)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::ReleaseDC"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::InvalidateRect(LPCRECT pRect, BOOL fErase)\r
-{\r
-//     ATLTRACE(_T("IOleInPlaceSiteWindowless::InvalidateRect\n"));\r
-       \r
-       bInvalidRect_ = true;\r
-\r
-/*     //Keep a list of dirty rectangles in order to be able to redraw only them\r
-       if(pRect != NULL) {\r
-               bDirtyRects_.push_back(DirtyRect(*pRect, fErase != 0));\r
-       }\r
-       else {\r
-               bDirtyRects_.push_back(DirtyRect(true));\r
-       }\r
-*/     return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::InvalidateRgn(HRGN hRGN, BOOL fErase)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::InvalidateRng\n"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::ScrollRect(INT dx, INT dy, LPCRECT pRectScroll, LPCRECT pRectClip)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::ScrollRect"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::AdjustRect(LPRECT prc)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::AdjustRect"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnDefWindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* plResult)\r
-{\r
-       ATLTRACE(_T("IOleInPlaceSiteWindowless::OnDefWindowMessage"));\r
-       return S_OK;\r
-}\r
-\r
-/////////\r
-// IOleControlSite\r
-/////////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnControlInfoChanged()\r
-{\r
-       ATLTRACE(_T("IOleControlSite::OnControlInfoChanged"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::LockInPlaceActive(BOOL fLock)\r
-{\r
-       ATLTRACE(_T("IOleControlSite::LockInPlaceActive"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetExtendedControl(IDispatch** ppDisp)\r
-{\r
-       ATLTRACE(_T("IOleControlSite::GetExtendedControl"));\r
-\r
-       if (ppDisp == NULL)\r
-               return E_POINTER;\r
-       return m_spOleObject.QueryInterface(ppDisp);\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::TransformCoords(POINTL* pPtlHimetric, POINTF* pPtfContainer, DWORD dwFlags)\r
-{\r
-       ATLTRACE(_T("IOleControlSite::TransformCoords"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::TranslateAccelerator(LPMSG lpMsg, DWORD grfModifiers)\r
-{\r
-       ATLTRACE(_T("IOleControlSite::TranslateAccelerator"));\r
-       return S_FALSE;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::OnFocus(BOOL fGotFocus)\r
-{\r
-       bHaveFocus_ = fGotFocus;\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::ShowPropertyFrame()\r
-{\r
-       ATLTRACE(_T("IOleControlSite::ShowPropertyFrame"));\r
-       return S_OK;\r
-}\r
-\r
-\r
-/////////\r
-// IAdviseSink\r
-/////////\r
-void STDMETHODCALLTYPE FlashAxContainer::OnDataChange(FORMATETC* pFormatetc, STGMEDIUM* pStgmed)\r
-{\r
-       ATLTRACE(_T("IAdviseSink::OnDataChange\n"));\r
-}\r
-\r
-void STDMETHODCALLTYPE FlashAxContainer::OnViewChange(DWORD dwAspect, LONG lindex)\r
-{\r
-       ATLTRACE(_T("IAdviseSink::OnViewChange\n"));\r
-}\r
-\r
-void STDMETHODCALLTYPE FlashAxContainer::OnRename(IMoniker* pmk)\r
-{\r
-       ATLTRACE(_T("IAdviseSink::OnRename\n"));\r
-}\r
-\r
-void STDMETHODCALLTYPE FlashAxContainer::OnSave()\r
-{\r
-       ATLTRACE(_T("IAdviseSink::OnSave\n"));\r
-}\r
-\r
-void STDMETHODCALLTYPE FlashAxContainer::OnClose()\r
-{\r
-       ATLTRACE(_T("IAdviseSink::OnClose\n"));\r
-}\r
-\r
-\r
-//DirectDraw GUIDS\r
-\r
-DEFINE_GUID2(CLSID_DirectDraw,0xD7B70EE0,0x4340,0x11CF,0xB0,0x63,0x00,0x20,0xAF,0xC2,0xCD,0x35);\r
-DEFINE_GUID2(CLSID_DirectDraw7,0x3c305196,0x50db,0x11d3,0x9c,0xfe,0x00,0xc0,0x4f,0xd9,0x30,0xc5);\r
-\r
-DEFINE_GUID2(IID_IDirectDraw,0x6C14DB80,0xA733,0x11CE,0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60);\r
-DEFINE_GUID2(IID_IDirectDraw3,0x618f8ad4,0x8b7a,0x11d0,0x8f,0xcc,0x0,0xc0,0x4f,0xd9,0x18,0x9d);\r
-DEFINE_GUID2(IID_IDirectDraw4,0x9c59509a,0x39bd,0x11d1,0x8c,0x4a,0x00,0xc0,0x4f,0xd9,0x30,0xc5);\r
-DEFINE_GUID2(IID_IDirectDraw7,0x15e65ec0,0x3b9c,0x11d2,0xb9,0x2f,0x00,0x60,0x97,0x97,0xea,0x5b);\r
-\r
-/////////\r
-// IServiceProvider\r
-/////////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::QueryService( REFGUID rsid, REFIID riid, void** ppvObj) \r
-{\r
-//     ATLTRACE(_T("IServiceProvider::QueryService\n"));\r
-       //the flashcontrol asks for an interface {618F8AD4-8B7A-11D0-8FCC-00C04FD9189D}, this is IID for a DirectDraw3 object\r
-\r
-       ATLASSERT(ppvObj != NULL);\r
-       if (ppvObj == NULL)\r
-               return E_POINTER;\r
-       *ppvObj = NULL;\r
-       \r
-       HRESULT hr;\r
-       // Author: Makarov Igor\r
-       // Transparent Flash Control in Plain C++ \r
-       // http://www.codeproject.com/KB/COM/flashcontrol.aspx \r
-       if (IsEqualGUID(rsid, IID_IDirectDraw3))\r
-       {\r
-               if (!m_lpDD4)\r
-               {\r
-                       m_lpDD4 = new IDirectDraw4Ptr;\r
-                       hr = m_lpDD4->CreateInstance(CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER); \r
-                       if (FAILED(hr))\r
-                       {\r
-                               delete m_lpDD4;\r
-                               m_lpDD4 = NULL;\r
-                               CASPAR_LOG(info) << print_() << " DirectDraw not installed. Running without DirectDraw.";\r
-                               return E_NOINTERFACE;\r
-                       }\r
-               }\r
-               if (m_lpDD4 && m_lpDD4->GetInterfacePtr())\r
-               {\r
-                       *ppvObj = m_lpDD4->GetInterfacePtr();\r
-                       m_lpDD4->AddRef();\r
-                       return S_OK;\r
-               }\r
-       }\r
-\r
-       //TODO: The fullscreen-consumer requires that ths does NOT return an ITimerService\r
-       hr = QueryInterface(riid, ppvObj);//E_NOINTERFACE;\r
-\r
-       return hr;\r
-}\r
-\r
-\r
-/////////\r
-// ITimerService\r
-/////////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::CreateTimer(ITimer *pReferenceTimer, ITimer **ppNewTimer)\r
-{\r
-       ATLTRACE(_T("ITimerService::CreateTimer\n"));\r
-       if(pTimerHelper != 0)\r
-       {\r
-               delete pTimerHelper;\r
-               pTimerHelper = 0;\r
-       }\r
-       pTimerHelper = new TimerHelper();\r
-       return QueryInterface(__uuidof(ITimer), (void**) ppNewTimer);\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetNamedTimer(REFGUID rguidName, ITimer **ppTimer)\r
-{\r
-       ATLTRACE(_T("ITimerService::GetNamedTimer"));\r
-       if(ppTimer == NULL)\r
-               return E_POINTER;\r
-       else\r
-               *ppTimer = NULL;\r
-\r
-       return E_FAIL;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::SetNamedTimerReference(REFGUID rguidName, ITimer *pReferenceTimer)\r
-{\r
-       ATLTRACE(_T("ITimerService::SetNamedTimerReference"));\r
-       return S_OK;\r
-}\r
-\r
-//////\r
-// ITimer\r
-//////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::Advise(VARIANT vtimeMin, VARIANT vtimeMax, VARIANT vtimeInterval, DWORD dwFlags, ITimerSink *pTimerSink, DWORD *pdwCookie)\r
-{\r
-       ATLTRACE(_T("Timer::Advise\n"));\r
-\r
-       if(pdwCookie == 0)\r
-               return E_POINTER;\r
-\r
-       if(pTimerHelper != 0)\r
-       {\r
-               pTimerHelper->Setup(vtimeMin.ulVal, vtimeInterval.ulVal, pTimerSink);\r
-               *pdwCookie = pTimerHelper->ID;\r
-               bHasNewTiming_ = true;\r
-\r
-               return S_OK;\r
-       }\r
-       else\r
-               return E_OUTOFMEMORY;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::Unadvise(/* [in] */ DWORD dwCookie)\r
-{\r
-       ATLTRACE(_T("Timer::Unadvice\n"));\r
-       if(pTimerHelper != 0)\r
-       {\r
-               pTimerHelper->pTimerSink = 0;\r
-               return S_OK;\r
-       }\r
-       else\r
-               return E_FAIL;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::Freeze(/* [in] */ BOOL fFreeze)\r
-{\r
-       ATLTRACE(_T("Timer::Freeze\n"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetTime(/* [out] */ VARIANT *pvtime)\r
-{\r
-       ATLTRACE(_T("Timer::GetTime\n"));\r
-       if(pvtime == 0)\r
-               return E_POINTER;\r
-\r
-//     return E_NOTIMPL;\r
-       pvtime->lVal = 0;\r
-       return S_OK;\r
-}\r
-\r
-double FlashAxContainer::GetFPS() {\r
-       if(pTimerHelper != 0 && pTimerHelper->interval > 0)\r
-               return (1000.0 / static_cast<double>(pTimerHelper->interval));\r
-       \r
-       return 0.0;\r
-}\r
-\r
-bool FlashAxContainer::IsReadyToRender() const {\r
-       return bReadyToRender_;\r
-}\r
-\r
-void FlashAxContainer::EnterFullscreen()\r
-{\r
-       if(m_spInPlaceObjectWindowless != 0)\r
-       {\r
-               LRESULT result;\r
-               m_spInPlaceObjectWindowless->OnWindowMessage(WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1), &result);\r
-               m_spInPlaceObjectWindowless->OnWindowMessage(WM_LBUTTONUP, 0, MAKELPARAM(1, 1), &result);\r
-       }\r
-}\r
-\r
-void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request)\r
-{\r
-       std::wstring str(request);\r
-       if(str.find(TEXT("DisplayedTemplate")) != std::wstring::npos)\r
-       {\r
-               ATLTRACE(_T("ShockwaveFlash::DisplayedTemplate\n"));\r
-               bReadyToRender_ = true;\r
-       }\r
-       else if(str.find(TEXT("OnCommand")) != std::wstring::npos) {\r
-               //this is how templatehost 1.8 reports that a command has been received\r
-               CASPAR_LOG(debug)  << print_()  << L" [command]      " << str;\r
-               bCallSuccessful_ = true;\r
-       }\r
-       else if(str.find(TEXT("Activity")) != std::wstring::npos)\r
-       {\r
-               CASPAR_LOG(debug) << print_() << L" [activity]     " << str;\r
-\r
-               //this is how templatehost 1.7 reports that a command has been received\r
-               if(str.find(TEXT("Command recieved")) != std::wstring::npos)\r
-                       bCallSuccessful_ = true;\r
-\r
-               /*if(pFlashProducer_ != 0 && pFlashProducer_->pMonitor_) {\r
-                       std::wstring::size_type pos = str.find(TEXT('@'));\r
-                       if(pos != std::wstring::npos)\r
-                               pFlashProducer_->pMonitor_->Inform(str.substr(pos, str.find(TEXT('<'), pos)-pos));\r
-               }*/\r
-       }\r
-       else if(str.find(TEXT("OnNotify")) != std::wstring::npos)\r
-       {\r
-               CASPAR_LOG(info) << print_() << L" [notification] " << str;\r
-\r
-               //if(pFlashProducer_ != 0 && pFlashProducer_->pMonitor_) {\r
-               //      std::wstring::size_type pos = str.find(TEXT('@'));\r
-               //      if(pos != std::wstring::npos)\r
-               //              pFlashProducer_->pMonitor_->Inform(str.substr(pos, str.find(TEXT('<'), pos)-pos));\r
-               //}\r
-       }\r
-       else if(str.find(TEXT("IsEmpty")) != std::wstring::npos)\r
-       {\r
-               CASPAR_LOG(trace) << print_() << L" Empty.";\r
-               ATLTRACE(_T("ShockwaveFlash::IsEmpty\n"));\r
-               bIsEmpty_ = true;\r
-       }\r
-       else if(str.find(TEXT("OnError")) != std::wstring::npos)\r
-       {\r
-               CASPAR_LOG(error) << print_() << L" [error]        " << str;\r
-       }\r
-       else if(str.find(TEXT("OnDebug")) != std::wstring::npos)\r
-       {\r
-               CASPAR_LOG(debug) << print_() << L" [debug]        " << str;\r
-       }\r
-       //else if(str.find(TEXT("OnTemplateDescription")) != std::wstring::npos)\r
-       //{\r
-       //      CASPAR_LOG(error) << print_() << L" TemplateDescription: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
-       //}\r
-       //else if(str.find(TEXT("OnGetInfo")) != std::wstring::npos)\r
-       //{\r
-       //      CASPAR_LOG(error) << print_() << L" Info: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
-       //}\r
-       //else\r
-       //{\r
-       //      CASPAR_LOG(error) << print_() << L" Unknown: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
-       //}\r
-\r
-       CComPtr<IShockwaveFlash> spFlash;\r
-       HRESULT hr = m_spOleObject->QueryInterface(__uuidof(IShockwaveFlash), (void**) &spFlash);\r
-       if(hr == S_OK && spFlash)\r
-       {\r
-               hr = spFlash->SetReturnValue(TEXT("<null/>"));\r
-       }\r
-}\r
-\r
-void STDMETHODCALLTYPE FlashAxContainer::OnReadyStateChange(long newState)\r
-{\r
-       if(newState == 4)\r
-       {\r
-               bReadyToRender_ = true;\r
-       }\r
-       else\r
-               bReadyToRender_ = false;\r
-}\r
-\r
-void FlashAxContainer::DestroyAxControl()\r
-{\r
-       GetControllingUnknown()->AddRef();\r
-\r
-       if ((!m_spViewObject) == false)\r
-               m_spViewObject->SetAdvise(DVASPECT_CONTENT, 0, NULL);\r
-\r
-       if ((!m_spOleObject) == false)\r
-       {\r
-               DispEventUnadvise(m_spOleObject, &DIID__IShockwaveFlashEvents);\r
-               m_spOleObject->Unadvise(m_dwOleObject);\r
-               m_spOleObject->Close(OLECLOSE_NOSAVE);\r
-               m_spOleObject->SetClientSite(NULL);\r
-       }\r
-\r
-       if ((!m_spUnknown) == false)\r
-       {\r
-               CComPtr<IObjectWithSite> spSite;\r
-               m_spUnknown->QueryInterface(__uuidof(IObjectWithSite), (void**)&spSite);\r
-               if (spSite != NULL)\r
-                       spSite->SetSite(NULL);\r
-       }\r
-\r
-       if ((!m_spViewObject) == false)\r
-               m_spViewObject.Release();\r
-\r
-       if ((!m_spInPlaceObjectWindowless) == false)\r
-               m_spInPlaceObjectWindowless.Release();\r
-\r
-       if ((!m_spOleObject) == false)\r
-               m_spOleObject.Release();\r
-\r
-       if ((!m_spUnknown) == false)\r
-               m_spUnknown.Release();\r
-}\r
-\r
-bool FlashAxContainer::CheckForFlashSupport()\r
-{\r
-       CLSID clsid;\r
-       return SUCCEEDED(CLSIDFromString((LPOLESTR)flashGUID_, &clsid));\r
-}\r
-\r
-HRESULT FlashAxContainer::CreateAxControl()\r
-{\r
-       CLSID clsid;\r
-       HRESULT hr = CLSIDFromString((LPOLESTR)flashGUID_, &clsid); \r
-       if(SUCCEEDED(hr))\r
-               hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, __uuidof(IUnknown), (void**)&m_spUnknown);\r
-\r
-//Start ActivateAx\r
-       if(SUCCEEDED(hr))\r
-       {\r
-               m_spUnknown->QueryInterface(__uuidof(IOleObject), (void**)&m_spOleObject);\r
-               if(m_spOleObject)\r
-               {\r
-                       m_spOleObject->GetMiscStatus(DVASPECT_CONTENT, &m_dwMiscStatus);\r
-                       if (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)\r
-                       {\r
-                               CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());\r
-                               m_spOleObject->SetClientSite(spClientSite);\r
-                       }\r
-\r
-                       //Initialize control\r
-                       CComQIPtr<IPersistStreamInit> spPSI(m_spOleObject);\r
-                       if (spPSI)\r
-                               hr = spPSI->InitNew();\r
-\r
-                       if (FAILED(hr)) // If the initialization of the control failed...\r
-                       {\r
-                               // Clean up and return\r
-                               if (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)\r
-                                       m_spOleObject->SetClientSite(NULL);\r
-\r
-                               m_dwMiscStatus = 0;\r
-                               m_spOleObject.Release();\r
-                               m_spUnknown.Release();\r
-\r
-                               return hr;\r
-                       }\r
-                       //end Initialize object\r
-\r
-                       if (0 == (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))\r
-                       {\r
-                               CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());\r
-                               m_spOleObject->SetClientSite(spClientSite);\r
-                       }\r
-\r
-                       CComPtr<IShockwaveFlash> spFlash;\r
-                       HRESULT hResultQuality;\r
-                       HRESULT hr2 = m_spOleObject->QueryInterface(__uuidof(IShockwaveFlash), (void**) &spFlash);\r
-                       if(hr2 == S_OK && spFlash)\r
-                       {\r
-                               if(FAILED(spFlash->put_WMode(TEXT("Transparent"))))\r
-                                       CASPAR_LOG(warning) << print_() << L" Failed to set flash container to transparent mode.";\r
-                               //spFlash->put_WMode(TEXT("ogl"));\r
-                               hResultQuality = spFlash->put_Quality2(TEXT("Best"));\r
-                       }\r
-                       if(SUCCEEDED(DispEventAdvise(spFlash, &DIID__IShockwaveFlashEvents)))\r
-                       {\r
-                       }\r
-\r
-                       HRESULT hrView = m_spOleObject->QueryInterface(__uuidof(IViewObjectEx), (void**) &m_spViewObject);\r
-\r
-                       CComQIPtr<IAdviseSink> spAdviseSink(GetControllingUnknown());\r
-                       m_spOleObject->Advise(spAdviseSink, &m_dwOleObject);\r
-                       if (m_spViewObject)\r
-                               m_spViewObject->SetAdvise(DVASPECT_CONTENT, 0, spAdviseSink);\r
-\r
-                       if ((m_dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME) == 0)\r
-                       {\r
-                               //Initialize window to some dummy size\r
-                               m_rcPos.top = 0;\r
-                               m_rcPos.left = 0;\r
-                               m_rcPos.right = 720;\r
-                               m_rcPos.bottom = 576;\r
-\r
-                               m_pxSize.cx = m_rcPos.right - m_rcPos.left;\r
-                               m_pxSize.cy = m_rcPos.bottom - m_rcPos.top;\r
-                               AtlPixelToHiMetric(&m_pxSize, &m_hmSize);\r
-                               m_spOleObject->SetExtent(DVASPECT_CONTENT, &m_hmSize);\r
-                               m_spOleObject->GetExtent(DVASPECT_CONTENT, &m_hmSize);\r
-                               AtlHiMetricToPixel(&m_hmSize, &m_pxSize);\r
-                               m_rcPos.right = m_rcPos.left + m_pxSize.cx;\r
-                               m_rcPos.bottom = m_rcPos.top + m_pxSize.cy;\r
-\r
-                               CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());\r
-                               hr = m_spOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, spClientSite, 0, NULL, &m_rcPos);\r
-                       }\r
-               }\r
-               CComPtr<IObjectWithSite> spSite;\r
-               m_spUnknown->QueryInterface(__uuidof(IObjectWithSite), (void**)&spSite);\r
-               if (spSite != NULL)\r
-                       spSite->SetSite(GetControllingUnknown());\r
-       }\r
-//End ActivateAx\r
-\r
-//     hr = E_FAIL;\r
-       if (FAILED(hr) || m_spUnknown == NULL)\r
-       {\r
-               return E_FAIL;\r
-               // We don't have a control or something failed so release\r
-//             ReleaseAll();\r
-       }\r
-\r
-       return S_OK;\r
-}\r
-\r
-void FlashAxContainer::SetSize(size_t width, size_t height) {\r
-       if(m_spInPlaceObjectWindowless != 0)\r
-       {\r
-               m_rcPos.top = 0;\r
-               m_rcPos.left = 0;\r
-               m_rcPos.right = width;\r
-               m_rcPos.bottom = height;\r
-\r
-               m_pxSize.cx = m_rcPos.right - m_rcPos.left;\r
-               m_pxSize.cy = m_rcPos.bottom - m_rcPos.top;\r
-               AtlPixelToHiMetric(&m_pxSize, &m_hmSize);\r
-               m_spOleObject->SetExtent(DVASPECT_CONTENT, &m_hmSize);\r
-               m_spOleObject->GetExtent(DVASPECT_CONTENT, &m_hmSize);\r
-               AtlHiMetricToPixel(&m_hmSize, &m_pxSize);\r
-               m_rcPos.right = m_rcPos.left + m_pxSize.cx;\r
-               m_rcPos.bottom = m_rcPos.top + m_pxSize.cy;\r
-\r
-               m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &m_rcPos);\r
-               bInvalidRect_ = true;\r
-       }\r
-}\r
-\r
-HRESULT FlashAxContainer::QueryControl(REFIID iid, void** ppUnk)\r
-{\r
-       ATLASSERT(ppUnk != NULL);\r
-       if (ppUnk == NULL)\r
-               return E_POINTER;\r
-       HRESULT hr;\r
-       hr = m_spOleObject->QueryInterface(iid, ppUnk);\r
-       return hr;\r
-}\r
-\r
-bool FlashAxContainer::DrawControl(HDC targetDC)\r
-{\r
-//     ATLTRACE(_T("FlashAxContainer::DrawControl\n"));\r
-       DVASPECTINFO aspectInfo = {sizeof(DVASPECTINFO), DVASPECTINFOFLAG_CANOPTIMIZE};\r
-       HRESULT hr = S_OK;\r
-\r
-       hr = m_spViewObject->Draw(DVASPECT_CONTENT, -1, &aspectInfo, NULL, NULL, targetDC, NULL, NULL, NULL, NULL); \r
-       bInvalidRect_ = false;\r
-/*     const video_format_desc& fmtDesc = video_format_desc::FormatDescriptions[format_];\r
-\r
-       //Trying to redraw just the dirty rectangles. Doesn't seem to work when the movie uses "filters", such as glow, dropshadow etc.\r
-       std::vector<flash::DirtyRect>::iterator it = bDirtyRects_.begin();\r
-       std::vector<flash::DirtyRect>::iterator end = bDirtyRects_.end();\r
-       for(; it != end; ++it) {\r
-               flash::DirtyRect& dirtyRect = (*it);\r
-               if(dirtyRect.bWhole || dirtyRect.rect.right >= fmtDesc.width || dirtyRect.rect.bottom >= fmtDesc.height) {\r
-                       m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &m_rcPos);\r
-                       hr = m_spViewObject->Draw(DVASPECT_OPAQUE, -1, NULL, NULL, NULL, targetDC, NULL, NULL, NULL, NULL); \r
-                       break;\r
-               }\r
-               else {\r
-                       m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &(dirtyRect.rect));\r
-                       hr = m_spViewObject->Draw(DVASPECT_OPAQUE, -1, NULL, NULL, NULL, targetDC, NULL, NULL, NULL, NULL); \r
-               }\r
-       }\r
-       bDirtyRects_.clear();\r
-*/\r
-\r
-       return (hr == S_OK);\r
-}\r
-\r
-void FlashAxContainer::Tick()\r
-{\r
-       if(pTimerHelper)\r
-       {\r
-               DWORD time = pTimerHelper->Invoke(); // Tick flash\r
-               if(time - timerCount_ >= 400)\r
-               {\r
-                       timerCount_ = time;\r
-                       LRESULT hr;\r
-                       m_spInPlaceObjectWindowless->OnWindowMessage(WM_TIMER, 3, 0, &hr);\r
-               }\r
-       }\r
-}\r
-\r
-bool FlashAxContainer::FlashCall(const std::wstring& str, std::wstring& result2)\r
-{\r
-       CComBSTR result;\r
-       CComPtr<IShockwaveFlash> spFlash;\r
-       QueryControl(&spFlash);\r
-       CComBSTR request(str.c_str());\r
-       \r
-       bIsEmpty_ = false;\r
-       bCallSuccessful_ = false;\r
-       for(size_t retries = 0; !bCallSuccessful_ && retries < 4; ++retries)\r
-               spFlash->CallFunction(request, &result);\r
-\r
-       if(bCallSuccessful_)\r
-               result2 = result;\r
-\r
-       return bCallSuccessful_;\r
-}\r
-\r
-}      //namespace flash\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#include "../stdafx.h"
+
+#include "FlashAxContainer.h"
+#include "../interop/TimerHelper.h"
+
+#include <common/log.h>
+
+#if defined(_MSC_VER)
+#pragma warning (push, 2) // TODO
+#endif
+
+using namespace ATL;
+
+namespace caspar { namespace flash {
+
+CComBSTR FlashAxContainer::flashGUID_(_T("{D27CDB6E-AE6D-11CF-96B8-444553540000}"));
+
+_ATL_FUNC_INFO fnInfoFlashCallEvent = { CC_STDCALL, VT_EMPTY, 1, { VT_BSTR } };
+_ATL_FUNC_INFO fnInfoReadyStateChangeEvent = { CC_STDCALL, VT_EMPTY, 1, { VT_I4 } };
+
+FlashAxContainer::FlashAxContainer() : bInPlaceActive_(FALSE), pTimerHelper(0), bInvalidRect_(false), bReadyToRender_(false), bHasNewTiming_(false), m_lpDD4(0), timerCount_(0), bIsEmpty_(true)
+{
+}
+FlashAxContainer::~FlashAxContainer()
+{      
+       if(m_lpDD4)
+       {
+               m_lpDD4->Release();
+               m_lpDD4 = nullptr;
+       }
+
+       if(pTimerHelper != 0)
+               delete pTimerHelper;
+}
+
+
+/////////
+// IObjectWithSite
+/////////
+HRESULT STDMETHODCALLTYPE FlashAxContainer::SetSite(IUnknown* pUnkSite)
+{
+       ATLTRACE(_T("IObjectWithSite::SetSite\n"));
+       HRESULT hr = IObjectWithSiteImpl<FlashAxContainer>::SetSite(pUnkSite);
+
+       if (SUCCEEDED(hr) && m_spUnkSite)
+       {
+               // Look for "outer" IServiceProvider
+               hr = m_spUnkSite->QueryInterface(__uuidof(IServiceProvider), (void**)&m_spServices);
+               ATLASSERT( !hr && _T("No ServiceProvider!") );
+       }
+
+       if (pUnkSite == NULL)
+               m_spServices.Release();
+
+       return hr;
+}
+
+/////////
+// IOleClientSite
+/////////
+HRESULT STDMETHODCALLTYPE FlashAxContainer::SaveObject()
+{
+       ATLTRACENOTIMPL(_T("IOleClientSite::SaveObject"));
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk)
+{
+/*     if(*ppmk != NULL) {
+               if(m_spMyMoniker == NULL) {
+                       ATL::CComObject<MyMoniker>* pMoniker = NULL;
+                       HRESULT hr = ATL::CComObject<MyMoniker>::CreateInstance(&pMoniker);
+                       if(SUCCEEDED(hr))
+                               m_spMyMoniker = pMoniker;
+               }
+
+               if(m_spMyMoniker != NULL) {
+                       *ppmk = m_spMyMoniker;
+                       (*ppmk)->AddRef();
+                       return S_OK;
+               }
+       }
+*/     if(ppmk != NULL)
+               *ppmk = NULL;
+       return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::GetContainer(IOleContainer** ppContainer)
+{
+       ATLTRACE(_T("IOleClientSite::GetContainer\n"));
+       (*ppContainer) = NULL;
+       return E_NOINTERFACE;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::ShowObject()
+{
+       ATLTRACE(_T("IOleClientSite::ShowObject\n"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnShowWindow(BOOL fShow)
+{
+       ATLTRACE(_T("IOleClientSite::OnShowWindow"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::RequestNewObjectLayout()
+{
+       ATLTRACE(_T("IOleClientSite::RequestNewObjectLayout"));
+       return S_OK;
+}
+
+/////////
+// IOleInPlaceSite
+/////////
+HRESULT STDMETHODCALLTYPE FlashAxContainer::GetWindow(HWND* pHwnd)
+{
+       ATLTRACE(_T("IOleInPlaceSite::GetWindow\n"));
+       (*pHwnd) = NULL;//GetApplication()->GetMainWindow()->getHwnd();
+       return E_FAIL;
+}
+HRESULT STDMETHODCALLTYPE FlashAxContainer::ContextSensitiveHelp(BOOL fEnterMode)
+{
+       ATLTRACE(_T("IOleInPlaceSite::ContextSensitiveHelp"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::CanInPlaceActivate()
+{
+       ATLTRACE(_T("IOleInPlaceSite::CanInPlaceActivate\n"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceActivate()
+{
+       ATLTRACE(_T("IOleInPlaceSite::OnInPlaceActivate"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnUIActivate()
+{
+       ATLTRACE(_T("IOleInPlaceSite::OnUIActivate\n"));
+       bUIActive_ = TRUE;
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::GetWindowContext(IOleInPlaceFrame** ppFrame, IOleInPlaceUIWindow** ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO pFrameInfo)
+{
+       ATLTRACE(_T("IOleInPlaceSite::GetWindowContext\n"));
+       if (ppFrame != NULL)
+               *ppFrame = NULL;
+       if (ppDoc != NULL)
+               *ppDoc = NULL;
+
+       if (ppFrame == NULL || ppDoc == NULL || lprcPosRect == NULL || lprcClipRect == NULL)
+               return E_POINTER;
+
+       pFrameInfo->fMDIApp = FALSE;
+       pFrameInfo->haccel = NULL;
+       pFrameInfo->cAccelEntries = 0;
+       pFrameInfo->hwndFrame = NULL;
+
+       lprcPosRect->top = m_rcPos.top;
+       lprcPosRect->left = m_rcPos.left;
+       lprcPosRect->right = m_rcPos.right;
+       lprcPosRect->bottom = m_rcPos.bottom;
+
+       lprcClipRect->top = m_rcPos.top;
+       lprcClipRect->left = m_rcPos.left;
+       lprcClipRect->right = m_rcPos.right;
+       lprcClipRect->bottom = m_rcPos.bottom;
+
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::Scroll(SIZE scrollExtant)
+{
+       ATLTRACE(_T("IOleInPlaceSite::Scroll"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnUIDeactivate(BOOL fUndoable)
+{
+       ATLTRACE(_T("IOleInPlaceSite::OnUIDeactivate\n"));
+       bUIActive_ = FALSE;
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceDeactivate()
+{
+       ATLTRACE(_T("IOleInPlaceSite::OnInPlaceDeactivate\n"));
+       bInPlaceActive_ = FALSE;
+       m_spInPlaceObjectWindowless.Release();
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::DiscardUndoState()
+{
+       ATLTRACE(_T("IOleInPlaceSite::DiscardUndoState"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::DeactivateAndUndo()
+{
+       ATLTRACE(_T("IOleInPlaceSite::DeactivateAndUndo"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnPosRectChange(LPCRECT lprcPosRect)
+{
+       ATLTRACE(_T("IOleInPlaceSite::OnPosRectChange"));
+       return S_OK;
+}
+
+
+//////////
+// IOleInPlaceSiteEx
+//////////
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceActivateEx(BOOL* pfNoRedraw, DWORD dwFlags)
+{
+       // should only be called once the first time control is inplace-activated
+       ATLTRACE(_T("IOleInPlaceSiteEx::OnInPlaceActivateEx\n"));
+       ATLASSERT(bInPlaceActive_ == FALSE);
+       ATLASSERT(m_spInPlaceObjectWindowless == NULL);
+
+       bInPlaceActive_ = TRUE;
+       OleLockRunning(m_spOleObject, TRUE, FALSE);
+       HRESULT hr = E_FAIL;
+       if (dwFlags & ACTIVATE_WINDOWLESS)
+       {
+               hr = m_spOleObject->QueryInterface(__uuidof(IOleInPlaceObjectWindowless), (void**) &m_spInPlaceObjectWindowless);
+
+               if (m_spInPlaceObjectWindowless != NULL)
+                       m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &m_rcPos);
+       }
+
+       return (m_spInPlaceObjectWindowless != NULL) ? S_OK : E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceDeactivateEx(BOOL fNoRedraw)
+{
+       ATLTRACE(_T("IOleInPlaceSiteEx::OnInPlaceDeactivateEx\n"));
+       bInPlaceActive_ = FALSE;
+       m_spInPlaceObjectWindowless.Release();
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::RequestUIActivate()
+{
+       ATLTRACE(_T("IOleInPlaceSiteEx::RequestUIActivate\n"));
+       return S_OK;
+}
+
+
+//////////////
+// IOleInPlaceSiteWindowless
+//////////////
+HRESULT STDMETHODCALLTYPE FlashAxContainer::CanWindowlessActivate()
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::CanWindowlessActivate\n"));
+       return S_OK;
+//     return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::GetCapture()
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::GetCapture\n"));
+       return bCapture_ ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::SetCapture(BOOL fCapture)
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::SetCapture\n"));
+       bCapture_ = fCapture;
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::GetFocus()
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::GetFocus\n"));
+       return bHaveFocus_ ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::SetFocus(BOOL fGotFocus)
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::SetFocus\n"));
+       bHaveFocus_ = fGotFocus;
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::GetDC(LPCRECT pRect, DWORD grfFlags, HDC* phDC)
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::GetDC"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::ReleaseDC(HDC hDC)
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::ReleaseDC"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::InvalidateRect(LPCRECT pRect, BOOL fErase)
+{
+//     ATLTRACE(_T("IOleInPlaceSiteWindowless::InvalidateRect\n"));
+       
+       bInvalidRect_ = true;
+
+/*     //Keep a list of dirty rectangles in order to be able to redraw only them
+       if(pRect != NULL) {
+               bDirtyRects_.push_back(DirtyRect(*pRect, fErase != 0));
+       }
+       else {
+               bDirtyRects_.push_back(DirtyRect(true));
+       }
+*/     return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::InvalidateRgn(HRGN hRGN, BOOL fErase)
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::InvalidateRng\n"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::ScrollRect(INT dx, INT dy, LPCRECT pRectScroll, LPCRECT pRectClip)
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::ScrollRect"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::AdjustRect(LPRECT prc)
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::AdjustRect"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnDefWindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* plResult)
+{
+       ATLTRACE(_T("IOleInPlaceSiteWindowless::OnDefWindowMessage"));
+       return S_OK;
+}
+
+/////////
+// IOleControlSite
+/////////
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnControlInfoChanged()
+{
+       ATLTRACE(_T("IOleControlSite::OnControlInfoChanged"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::LockInPlaceActive(BOOL fLock)
+{
+       ATLTRACE(_T("IOleControlSite::LockInPlaceActive"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::GetExtendedControl(IDispatch** ppDisp)
+{
+       ATLTRACE(_T("IOleControlSite::GetExtendedControl"));
+
+       if (ppDisp == NULL)
+               return E_POINTER;
+       return m_spOleObject.QueryInterface(ppDisp);
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::TransformCoords(POINTL* pPtlHimetric, POINTF* pPtfContainer, DWORD dwFlags)
+{
+       ATLTRACE(_T("IOleControlSite::TransformCoords"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::TranslateAccelerator(LPMSG lpMsg, DWORD grfModifiers)
+{
+       ATLTRACE(_T("IOleControlSite::TranslateAccelerator"));
+       return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::OnFocus(BOOL fGotFocus)
+{
+       bHaveFocus_ = fGotFocus;
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::ShowPropertyFrame()
+{
+       ATLTRACE(_T("IOleControlSite::ShowPropertyFrame"));
+       return S_OK;
+}
+
+
+/////////
+// IAdviseSink
+/////////
+void STDMETHODCALLTYPE FlashAxContainer::OnDataChange(FORMATETC* pFormatetc, STGMEDIUM* pStgmed)
+{
+       ATLTRACE(_T("IAdviseSink::OnDataChange\n"));
+}
+
+void STDMETHODCALLTYPE FlashAxContainer::OnViewChange(DWORD dwAspect, LONG lindex)
+{
+       ATLTRACE(_T("IAdviseSink::OnViewChange\n"));
+}
+
+void STDMETHODCALLTYPE FlashAxContainer::OnRename(IMoniker* pmk)
+{
+       ATLTRACE(_T("IAdviseSink::OnRename\n"));
+}
+
+void STDMETHODCALLTYPE FlashAxContainer::OnSave()
+{
+       ATLTRACE(_T("IAdviseSink::OnSave\n"));
+}
+
+void STDMETHODCALLTYPE FlashAxContainer::OnClose()
+{
+       ATLTRACE(_T("IAdviseSink::OnClose\n"));
+}
+
+
+//DirectDraw GUIDS
+
+DEFINE_GUID2(CLSID_DirectDraw,0xD7B70EE0,0x4340,0x11CF,0xB0,0x63,0x00,0x20,0xAF,0xC2,0xCD,0x35);
+DEFINE_GUID2(CLSID_DirectDraw7,0x3c305196,0x50db,0x11d3,0x9c,0xfe,0x00,0xc0,0x4f,0xd9,0x30,0xc5);
+
+DEFINE_GUID2(IID_IDirectDraw,0x6C14DB80,0xA733,0x11CE,0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60);
+DEFINE_GUID2(IID_IDirectDraw3,0x618f8ad4,0x8b7a,0x11d0,0x8f,0xcc,0x0,0xc0,0x4f,0xd9,0x18,0x9d);
+DEFINE_GUID2(IID_IDirectDraw4,0x9c59509a,0x39bd,0x11d1,0x8c,0x4a,0x00,0xc0,0x4f,0xd9,0x30,0xc5);
+DEFINE_GUID2(IID_IDirectDraw7,0x15e65ec0,0x3b9c,0x11d2,0xb9,0x2f,0x00,0x60,0x97,0x97,0xea,0x5b);
+
+/////////
+// IServiceProvider
+/////////
+HRESULT STDMETHODCALLTYPE FlashAxContainer::QueryService( REFGUID rsid, REFIID riid, void** ppvObj) 
+{
+//     ATLTRACE(_T("IServiceProvider::QueryService\n"));
+       //the flashcontrol asks for an interface {618F8AD4-8B7A-11D0-8FCC-00C04FD9189D}, this is IID for a DirectDraw3 object
+
+       ATLASSERT(ppvObj != NULL);
+       if (ppvObj == NULL)
+               return E_POINTER;
+       *ppvObj = NULL;
+       
+       HRESULT hr;
+       // Author: Makarov Igor
+       // Transparent Flash Control in Plain C++ 
+       // http://www.codeproject.com/KB/COM/flashcontrol.aspx 
+       if (IsEqualGUID(rsid, IID_IDirectDraw3))
+       {
+               if (!m_lpDD4)
+               {
+                       m_lpDD4 = new IDirectDraw4Ptr;
+                       hr = m_lpDD4->CreateInstance(CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER); 
+                       if (FAILED(hr))
+                       {
+                               delete m_lpDD4;
+                               m_lpDD4 = NULL;
+                               CASPAR_LOG(info) << print_() << " DirectDraw not installed. Running without DirectDraw.";
+                               return E_NOINTERFACE;
+                       }
+               }
+               if (m_lpDD4 && m_lpDD4->GetInterfacePtr())
+               {
+                       *ppvObj = m_lpDD4->GetInterfacePtr();
+                       m_lpDD4->AddRef();
+                       return S_OK;
+               }
+       }
+
+       //TODO: The fullscreen-consumer requires that ths does NOT return an ITimerService
+       hr = QueryInterface(riid, ppvObj);//E_NOINTERFACE;
+
+       return hr;
+}
+
+
+/////////
+// ITimerService
+/////////
+HRESULT STDMETHODCALLTYPE FlashAxContainer::CreateTimer(ITimer *pReferenceTimer, ITimer **ppNewTimer)
+{
+       ATLTRACE(_T("ITimerService::CreateTimer\n"));
+       if(pTimerHelper != 0)
+       {
+               delete pTimerHelper;
+               pTimerHelper = 0;
+       }
+       pTimerHelper = new TimerHelper();
+       return QueryInterface(__uuidof(ITimer), (void**) ppNewTimer);
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::GetNamedTimer(REFGUID rguidName, ITimer **ppTimer)
+{
+       ATLTRACE(_T("ITimerService::GetNamedTimer"));
+       if(ppTimer == NULL)
+               return E_POINTER;
+       else
+               *ppTimer = NULL;
+
+       return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::SetNamedTimerReference(REFGUID rguidName, ITimer *pReferenceTimer)
+{
+       ATLTRACE(_T("ITimerService::SetNamedTimerReference"));
+       return S_OK;
+}
+
+//////
+// ITimer
+//////
+HRESULT STDMETHODCALLTYPE FlashAxContainer::Advise(VARIANT vtimeMin, VARIANT vtimeMax, VARIANT vtimeInterval, DWORD dwFlags, ITimerSink *pTimerSink, DWORD *pdwCookie)
+{
+       ATLTRACE(_T("Timer::Advise\n"));
+
+       if(pdwCookie == 0)
+               return E_POINTER;
+
+       if(pTimerHelper != 0)
+       {
+               pTimerHelper->Setup(vtimeMin.ulVal, vtimeInterval.ulVal, pTimerSink);
+               *pdwCookie = pTimerHelper->ID;
+               bHasNewTiming_ = true;
+
+               return S_OK;
+       }
+       else
+               return E_OUTOFMEMORY;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::Unadvise(/* [in] */ DWORD dwCookie)
+{
+       ATLTRACE(_T("Timer::Unadvice\n"));
+       if(pTimerHelper != 0)
+       {
+               pTimerHelper->pTimerSink = 0;
+               return S_OK;
+       }
+       else
+               return E_FAIL;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::Freeze(/* [in] */ BOOL fFreeze)
+{
+       ATLTRACE(_T("Timer::Freeze\n"));
+       return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE FlashAxContainer::GetTime(/* [out] */ VARIANT *pvtime)
+{
+       ATLTRACE(_T("Timer::GetTime\n"));
+       if(pvtime == 0)
+               return E_POINTER;
+
+//     return E_NOTIMPL;
+       pvtime->lVal = 0;
+       return S_OK;
+}
+
+double FlashAxContainer::GetFPS() {
+       if(pTimerHelper != 0 && pTimerHelper->interval > 0)
+               return (1000.0 / static_cast<double>(pTimerHelper->interval));
+       
+       return 0.0;
+}
+
+bool FlashAxContainer::IsReadyToRender() const {
+       return bReadyToRender_;
+}
+
+void FlashAxContainer::EnterFullscreen()
+{
+       if(m_spInPlaceObjectWindowless != 0)
+       {
+               LRESULT result;
+               m_spInPlaceObjectWindowless->OnWindowMessage(WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1), &result);
+               m_spInPlaceObjectWindowless->OnWindowMessage(WM_LBUTTONUP, 0, MAKELPARAM(1, 1), &result);
+       }
+}
+
+void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request)
+{
+       std::wstring str(request);
+       if(str.find(TEXT("DisplayedTemplate")) != std::wstring::npos)
+       {
+               ATLTRACE(_T("ShockwaveFlash::DisplayedTemplate\n"));
+               bReadyToRender_ = true;
+       }
+       else if(str.find(TEXT("OnCommand")) != std::wstring::npos) {
+               //this is how templatehost 1.8 reports that a command has been received
+               CASPAR_LOG(debug)  << print_()  << L" [command]      " << str;
+               bCallSuccessful_ = true;
+       }
+       else if(str.find(TEXT("Activity")) != std::wstring::npos)
+       {
+               CASPAR_LOG(debug) << print_() << L" [activity]     " << str;
+
+               //this is how templatehost 1.7 reports that a command has been received
+               if(str.find(TEXT("Command recieved")) != std::wstring::npos)
+                       bCallSuccessful_ = true;
+
+               /*if(pFlashProducer_ != 0 && pFlashProducer_->pMonitor_) {
+                       std::wstring::size_type pos = str.find(TEXT('@'));
+                       if(pos != std::wstring::npos)
+                               pFlashProducer_->pMonitor_->Inform(str.substr(pos, str.find(TEXT('<'), pos)-pos));
+               }*/
+       }
+       else if(str.find(TEXT("OnNotify")) != std::wstring::npos)
+       {
+               CASPAR_LOG(info) << print_() << L" [notification] " << str;
+
+               //if(pFlashProducer_ != 0 && pFlashProducer_->pMonitor_) {
+               //      std::wstring::size_type pos = str.find(TEXT('@'));
+               //      if(pos != std::wstring::npos)
+               //              pFlashProducer_->pMonitor_->Inform(str.substr(pos, str.find(TEXT('<'), pos)-pos));
+               //}
+       }
+       else if(str.find(TEXT("IsEmpty")) != std::wstring::npos)
+       {
+               CASPAR_LOG(trace) << print_() << L" Empty.";
+               ATLTRACE(_T("ShockwaveFlash::IsEmpty\n"));
+               bIsEmpty_ = true;
+       }
+       else if(str.find(TEXT("OnError")) != std::wstring::npos)
+       {
+               CASPAR_LOG(error) << print_() << L" [error]        " << str;
+       }
+       else if(str.find(TEXT("OnDebug")) != std::wstring::npos)
+       {
+               CASPAR_LOG(debug) << print_() << L" [debug]        " << str;
+       }
+       //else if(str.find(TEXT("OnTemplateDescription")) != std::wstring::npos)
+       //{
+       //      CASPAR_LOG(error) << print_() << L" TemplateDescription: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";
+       //}
+       //else if(str.find(TEXT("OnGetInfo")) != std::wstring::npos)
+       //{
+       //      CASPAR_LOG(error) << print_() << L" Info: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";
+       //}
+       //else
+       //{
+       //      CASPAR_LOG(error) << print_() << L" Unknown: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";
+       //}
+
+       CComPtr<IShockwaveFlash> spFlash;
+       HRESULT hr = m_spOleObject->QueryInterface(__uuidof(IShockwaveFlash), (void**) &spFlash);
+       if(hr == S_OK && spFlash)
+       {
+               hr = spFlash->SetReturnValue(TEXT("<null/>"));
+       }
+}
+
+void STDMETHODCALLTYPE FlashAxContainer::OnReadyStateChange(long newState)
+{
+       if(newState == 4)
+       {
+               bReadyToRender_ = true;
+       }
+       else
+               bReadyToRender_ = false;
+}
+
+void FlashAxContainer::DestroyAxControl()
+{
+       GetControllingUnknown()->AddRef();
+
+       if ((!m_spViewObject) == false)
+               m_spViewObject->SetAdvise(DVASPECT_CONTENT, 0, NULL);
+
+       if ((!m_spOleObject) == false)
+       {
+               DispEventUnadvise(m_spOleObject, &DIID__IShockwaveFlashEvents);
+               m_spOleObject->Unadvise(m_dwOleObject);
+               m_spOleObject->Close(OLECLOSE_NOSAVE);
+               m_spOleObject->SetClientSite(NULL);
+       }
+
+       if ((!m_spUnknown) == false)
+       {
+               CComPtr<IObjectWithSite> spSite;
+               m_spUnknown->QueryInterface(__uuidof(IObjectWithSite), (void**)&spSite);
+               if (spSite != NULL)
+                       spSite->SetSite(NULL);
+       }
+
+       if ((!m_spViewObject) == false)
+               m_spViewObject.Release();
+
+       if ((!m_spInPlaceObjectWindowless) == false)
+               m_spInPlaceObjectWindowless.Release();
+
+       if ((!m_spOleObject) == false)
+               m_spOleObject.Release();
+
+       if ((!m_spUnknown) == false)
+               m_spUnknown.Release();
+}
+
+bool FlashAxContainer::CheckForFlashSupport()
+{
+       CLSID clsid;
+       return SUCCEEDED(CLSIDFromString((LPOLESTR)flashGUID_, &clsid));
+}
+
+HRESULT FlashAxContainer::CreateAxControl()
+{
+       CLSID clsid;
+       HRESULT hr = CLSIDFromString((LPOLESTR)flashGUID_, &clsid); 
+       if(SUCCEEDED(hr))
+               hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, __uuidof(IUnknown), (void**)&m_spUnknown);
+
+//Start ActivateAx
+       if(SUCCEEDED(hr))
+       {
+               m_spUnknown->QueryInterface(__uuidof(IOleObject), (void**)&m_spOleObject);
+               if(m_spOleObject)
+               {
+                       m_spOleObject->GetMiscStatus(DVASPECT_CONTENT, &m_dwMiscStatus);
+                       if (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
+                       {
+                               CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());
+                               m_spOleObject->SetClientSite(spClientSite);
+                       }
+
+                       //Initialize control
+                       CComQIPtr<IPersistStreamInit> spPSI(m_spOleObject);
+                       if (spPSI)
+                               hr = spPSI->InitNew();
+
+                       if (FAILED(hr)) // If the initialization of the control failed...
+                       {
+                               // Clean up and return
+                               if (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
+                                       m_spOleObject->SetClientSite(NULL);
+
+                               m_dwMiscStatus = 0;
+                               m_spOleObject.Release();
+                               m_spUnknown.Release();
+
+                               return hr;
+                       }
+                       //end Initialize object
+
+                       if (0 == (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
+                       {
+                               CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());
+                               m_spOleObject->SetClientSite(spClientSite);
+                       }
+
+                       CComPtr<IShockwaveFlash> spFlash;
+                       HRESULT hResultQuality;
+                       HRESULT hr2 = m_spOleObject->QueryInterface(__uuidof(IShockwaveFlash), (void**) &spFlash);
+                       if(hr2 == S_OK && spFlash)
+                       {
+                               if(FAILED(spFlash->put_WMode(TEXT("Transparent"))))
+                                       CASPAR_LOG(warning) << print_() << L" Failed to set flash container to transparent mode.";
+                               //spFlash->put_WMode(TEXT("ogl"));
+                               hResultQuality = spFlash->put_Quality2(TEXT("Best"));
+                       }
+                       if(SUCCEEDED(DispEventAdvise(spFlash, &DIID__IShockwaveFlashEvents)))
+                       {
+                       }
+
+                       HRESULT hrView = m_spOleObject->QueryInterface(__uuidof(IViewObjectEx), (void**) &m_spViewObject);
+
+                       CComQIPtr<IAdviseSink> spAdviseSink(GetControllingUnknown());
+                       m_spOleObject->Advise(spAdviseSink, &m_dwOleObject);
+                       if (m_spViewObject)
+                               m_spViewObject->SetAdvise(DVASPECT_CONTENT, 0, spAdviseSink);
+
+                       if ((m_dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME) == 0)
+                       {
+                               //Initialize window to some dummy size
+                               m_rcPos.top = 0;
+                               m_rcPos.left = 0;
+                               m_rcPos.right = 720;
+                               m_rcPos.bottom = 576;
+
+                               m_pxSize.cx = m_rcPos.right - m_rcPos.left;
+                               m_pxSize.cy = m_rcPos.bottom - m_rcPos.top;
+                               AtlPixelToHiMetric(&m_pxSize, &m_hmSize);
+                               m_spOleObject->SetExtent(DVASPECT_CONTENT, &m_hmSize);
+                               m_spOleObject->GetExtent(DVASPECT_CONTENT, &m_hmSize);
+                               AtlHiMetricToPixel(&m_hmSize, &m_pxSize);
+                               m_rcPos.right = m_rcPos.left + m_pxSize.cx;
+                               m_rcPos.bottom = m_rcPos.top + m_pxSize.cy;
+
+                               CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());
+                               hr = m_spOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, spClientSite, 0, NULL, &m_rcPos);
+                       }
+               }
+               CComPtr<IObjectWithSite> spSite;
+               m_spUnknown->QueryInterface(__uuidof(IObjectWithSite), (void**)&spSite);
+               if (spSite != NULL)
+                       spSite->SetSite(GetControllingUnknown());
+       }
+//End ActivateAx
+
+//     hr = E_FAIL;
+       if (FAILED(hr) || m_spUnknown == NULL)
+       {
+               return E_FAIL;
+               // We don't have a control or something failed so release
+//             ReleaseAll();
+       }
+
+       return S_OK;
+}
+
+void FlashAxContainer::SetSize(size_t width, size_t height) {
+       if(m_spInPlaceObjectWindowless != 0)
+       {
+               m_rcPos.top = 0;
+               m_rcPos.left = 0;
+               m_rcPos.right = width;
+               m_rcPos.bottom = height;
+
+               m_pxSize.cx = m_rcPos.right - m_rcPos.left;
+               m_pxSize.cy = m_rcPos.bottom - m_rcPos.top;
+               AtlPixelToHiMetric(&m_pxSize, &m_hmSize);
+               m_spOleObject->SetExtent(DVASPECT_CONTENT, &m_hmSize);
+               m_spOleObject->GetExtent(DVASPECT_CONTENT, &m_hmSize);
+               AtlHiMetricToPixel(&m_hmSize, &m_pxSize);
+               m_rcPos.right = m_rcPos.left + m_pxSize.cx;
+               m_rcPos.bottom = m_rcPos.top + m_pxSize.cy;
+
+               m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &m_rcPos);
+               bInvalidRect_ = true;
+       }
+}
+
+HRESULT FlashAxContainer::QueryControl(REFIID iid, void** ppUnk)
+{
+       ATLASSERT(ppUnk != NULL);
+       if (ppUnk == NULL)
+               return E_POINTER;
+       HRESULT hr;
+       hr = m_spOleObject->QueryInterface(iid, ppUnk);
+       return hr;
+}
+
+bool FlashAxContainer::DrawControl(HDC targetDC)
+{
+//     ATLTRACE(_T("FlashAxContainer::DrawControl\n"));
+       DVASPECTINFO aspectInfo = {sizeof(DVASPECTINFO), DVASPECTINFOFLAG_CANOPTIMIZE};
+       HRESULT hr = S_OK;
+
+       hr = m_spViewObject->Draw(DVASPECT_CONTENT, -1, &aspectInfo, NULL, NULL, targetDC, NULL, NULL, NULL, NULL); 
+       bInvalidRect_ = false;
+/*     const video_format_desc& fmtDesc = video_format_desc::FormatDescriptions[format_];
+
+       //Trying to redraw just the dirty rectangles. Doesn't seem to work when the movie uses "filters", such as glow, dropshadow etc.
+       std::vector<flash::DirtyRect>::iterator it = bDirtyRects_.begin();
+       std::vector<flash::DirtyRect>::iterator end = bDirtyRects_.end();
+       for(; it != end; ++it) {
+               flash::DirtyRect& dirtyRect = (*it);
+               if(dirtyRect.bWhole || dirtyRect.rect.right >= fmtDesc.width || dirtyRect.rect.bottom >= fmtDesc.height) {
+                       m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &m_rcPos);
+                       hr = m_spViewObject->Draw(DVASPECT_OPAQUE, -1, NULL, NULL, NULL, targetDC, NULL, NULL, NULL, NULL); 
+                       break;
+               }
+               else {
+                       m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &(dirtyRect.rect));
+                       hr = m_spViewObject->Draw(DVASPECT_OPAQUE, -1, NULL, NULL, NULL, targetDC, NULL, NULL, NULL, NULL); 
+               }
+       }
+       bDirtyRects_.clear();
+*/
+
+       return (hr == S_OK);
+}
+
+void FlashAxContainer::Tick()
+{
+       if(pTimerHelper)
+       {
+               DWORD time = pTimerHelper->Invoke(); // Tick flash
+               if(time - timerCount_ >= 400)
+               {
+                       timerCount_ = time;
+                       LRESULT hr;
+                       m_spInPlaceObjectWindowless->OnWindowMessage(WM_TIMER, 3, 0, &hr);
+               }
+       }
+}
+
+bool FlashAxContainer::FlashCall(const std::wstring& str, std::wstring& result2)
+{
+       CComBSTR result;
+       CComPtr<IShockwaveFlash> spFlash;
+       QueryControl(&spFlash);
+       CComBSTR request(str.c_str());
+       
+       bIsEmpty_ = false;
+       bCallSuccessful_ = false;
+       for(size_t retries = 0; !bCallSuccessful_ && retries < 4; ++retries)
+               spFlash->CallFunction(request, &result);
+
+       if(bCallSuccessful_)
+               result2 = result;
+
+       return bCallSuccessful_;
+}
+
+}      //namespace flash
 }      //namespace caspar
\ No newline at end of file
index e5663e0a8fff921170d3fd598cd65f33a16c744f..fabca72ccc4e6e333c95e09114e6b35882c7fba5 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
\r
-#ifndef _FLASHAXCONTAINER_H__\r
-#define _FLASHAXCONTAINER_H__\r
-\r
-#pragma once\r
-\r
-#include <atlbase.h>\r
-#include <atlcom.h>\r
-#include <atlhost.h>\r
-#include <ocmm.h>\r
-\r
-#include <functional>\r
-#include <vector>\r
-\r
-#include <core/video_format.h>\r
-#include "../interop/axflash.h"\r
-//#import "progid:ShockwaveFlash.ShockwaveFlash.9" no_namespace, named_guids\r
-\r
-#include <comdef.h>\r
-\r
-#include "../interop/TimerHelper.h"\r
-\r
-#include <InitGuid.h>\r
-#include <ddraw.h>\r
-\r
-#ifndef DEFINE_GUID2\r
-#define DEFINE_GUID2(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\r
-               const GUID name \\r
-                               = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }\r
-#endif    \r
-\r
-_COM_SMARTPTR_TYPEDEF(IDirectDraw4, IID_IDirectDraw4);\r
-\r
-namespace caspar {\r
-\r
-namespace flash {\r
-\r
-class TimerHelper;\r
-struct DirtyRect {\r
-       DirtyRect(LONG l, LONG t, LONG r, LONG b, bool e) : bErase(e), bWhole(false) { \r
-               rect.left = l;\r
-               rect.top = t;\r
-               rect.right = r;\r
-               rect.bottom = b; \r
-       }\r
-       DirtyRect(const RECT& rc, bool e) : bErase(e), bWhole(false)  {\r
-               rect.left = rc.left;\r
-               rect.top = rc.top;\r
-               rect.right = rc.right;\r
-               rect.bottom = rc.bottom; \r
-       }\r
-       explicit DirtyRect(bool b) : bWhole(b) {}\r
-\r
-       RECT    rect;\r
-       bool    bErase;\r
-       bool    bWhole;\r
-};\r
-\r
-extern _ATL_FUNC_INFO fnInfoFlashCallEvent;\r
-extern _ATL_FUNC_INFO fnInfoReadyStateChangeEvent;\r
-\r
-class ATL_NO_VTABLE FlashAxContainer : \r
-               public ATL::CComCoClass<FlashAxContainer , &CLSID_NULL>,\r
-               public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>,\r
-               public IOleClientSite,\r
-               public IOleContainer,\r
-               public IOleControlSite,\r
-               public IOleInPlaceSiteWindowless,\r
-               public IObjectWithSiteImpl<FlashAxContainer>,\r
-               public IServiceProvider,\r
-               public IAdviseSink,\r
-               public ITimerService,\r
-               public ITimer,\r
-               public IDispatchImpl<IDispatch>,\r
-               public IDispEventSimpleImpl<0, FlashAxContainer, &DIID__IShockwaveFlashEvents>\r
-{\r
-\r
-public:\r
-\r
-       FlashAxContainer();\r
-       virtual ~FlashAxContainer();\r
-\r
-       DECLARE_NO_REGISTRY()\r
-       DECLARE_POLY_AGGREGATABLE(FlashAxContainer)\r
-       DECLARE_GET_CONTROLLING_UNKNOWN()\r
-\r
-       BEGIN_COM_MAP(FlashAxContainer)\r
-               COM_INTERFACE_ENTRY(IDispatch)\r
-               COM_INTERFACE_ENTRY(IOleClientSite)\r
-               COM_INTERFACE_ENTRY(IObjectWithSite)\r
-               COM_INTERFACE_ENTRY(IOleControlSite)\r
-               COM_INTERFACE_ENTRY(IOleContainer)\r
-\r
-               COM_INTERFACE_ENTRY(IOleInPlaceSiteWindowless)\r
-               COM_INTERFACE_ENTRY(IOleInPlaceSiteEx)\r
-               COM_INTERFACE_ENTRY(IOleInPlaceSite)\r
-               COM_INTERFACE_ENTRY(IOleWindow)\r
-\r
-               COM_INTERFACE_ENTRY(IServiceProvider)\r
-\r
-               COM_INTERFACE_ENTRY(IAdviseSink)\r
-\r
-               COM_INTERFACE_ENTRY(ITimerService)\r
-\r
-               COM_INTERFACE_ENTRY(ITimer)\r
-       END_COM_MAP()\r
-\r
-       BEGIN_SINK_MAP(FlashAxContainer)\r
-               SINK_ENTRY_INFO(0, DIID__IShockwaveFlashEvents, 0xc5, OnFlashCall, &fnInfoFlashCallEvent)\r
-               SINK_ENTRY_INFO(0, DIID__IShockwaveFlashEvents, 0xfffffd9f, OnReadyStateChange, &fnInfoReadyStateChangeEvent)\r
-       END_SINK_MAP()\r
-\r
-       void STDMETHODCALLTYPE OnFlashCall(BSTR request);\r
-       void STDMETHODCALLTYPE OnReadyStateChange(long newState);\r
-\r
-// IObjectWithSite\r
-       STDMETHOD(SetSite)(IUnknown* pUnkSite);\r
-\r
-// IOleClientSite\r
-       STDMETHOD(SaveObject)();\r
-       STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk);\r
-       STDMETHOD(GetContainer)(IOleContainer** ppContainer);\r
-       STDMETHOD(ShowObject)();\r
-       STDMETHOD(OnShowWindow)(BOOL fShow);\r
-       STDMETHOD(RequestNewObjectLayout)();\r
-\r
-// IOleInPlaceSite\r
-       STDMETHOD(GetWindow)(HWND* pHwnd);\r
-       STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode);\r
-       STDMETHOD(CanInPlaceActivate)();\r
-       STDMETHOD(OnInPlaceActivate)();\r
-       STDMETHOD(OnInPlaceDeactivate)();\r
-       STDMETHOD(OnUIActivate)();\r
-       STDMETHOD(OnUIDeactivate)(BOOL fUndoable);\r
-       STDMETHOD(GetWindowContext)(IOleInPlaceFrame** ppFrame, IOleInPlaceUIWindow** ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO pFrameInfo);\r
-       STDMETHOD(Scroll)(SIZE scrollExtant);\r
-       STDMETHOD(DiscardUndoState)();\r
-       STDMETHOD(DeactivateAndUndo)();\r
-       STDMETHOD(OnPosRectChange)(LPCRECT lprcPosRect);\r
-\r
-// IOleInPlaceSiteEx\r
-       STDMETHOD(OnInPlaceActivateEx)(BOOL* pfNoRedraw, DWORD dwFlags);\r
-       STDMETHOD(OnInPlaceDeactivateEx)(BOOL fNoRedraw);\r
-       STDMETHOD(RequestUIActivate)();\r
-\r
-// IOleInPlaceSiteWindowless\r
-       STDMETHOD(CanWindowlessActivate)();\r
-       STDMETHOD(GetCapture)();\r
-       STDMETHOD(SetCapture)(BOOL fCapture);\r
-       STDMETHOD(GetFocus)();\r
-       STDMETHOD(SetFocus)(BOOL fGotFocus);\r
-       STDMETHOD(GetDC)(LPCRECT pRect, DWORD grfFlags, HDC* phDC);\r
-       STDMETHOD(ReleaseDC)(HDC hDC);\r
-       STDMETHOD(InvalidateRect)(LPCRECT pRect, BOOL fErase);\r
-       STDMETHOD(InvalidateRgn)(HRGN hRGN, BOOL fErase);\r
-       STDMETHOD(ScrollRect)(INT dx, INT dy, LPCRECT pRectScroll, LPCRECT pRectClip);\r
-       STDMETHOD(AdjustRect)(LPRECT prc);\r
-       STDMETHOD(OnDefWindowMessage)(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* plResult);\r
-\r
-// IOleControlSite\r
-       STDMETHOD(OnControlInfoChanged)();\r
-       STDMETHOD(LockInPlaceActive)(BOOL fLock);\r
-       STDMETHOD(GetExtendedControl)(IDispatch** ppDisp);\r
-       STDMETHOD(TransformCoords)(POINTL* pPtlHimetric, POINTF* pPtfContainer, DWORD dwFlags);\r
-       STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, DWORD grfModifiers);\r
-       STDMETHOD(OnFocus)(BOOL fGotFocus);\r
-       STDMETHOD(ShowPropertyFrame)();\r
-\r
-// IAdviseSink\r
-       STDMETHOD_(void, OnDataChange)(FORMATETC* pFormatetc, STGMEDIUM* pStgmed);\r
-       STDMETHOD_(void, OnViewChange)(DWORD dwAspect, LONG lindex);\r
-       STDMETHOD_(void, OnRename)(IMoniker* pmk);\r
-       STDMETHOD_(void, OnSave)();\r
-       STDMETHOD_(void, OnClose)();\r
-\r
-// IServiceProvider\r
-       STDMETHOD(QueryService)( REFGUID rsid, REFIID riid, void** ppvObj);\r
-\r
-// IOleContainer\r
-       STDMETHOD(ParseDisplayName)(IBindCtx*, LPOLESTR, ULONG*, IMoniker**)\r
-       {\r
-               ATLTRACENOTIMPL(_T("IOleContainer::ParseDisplayName"));\r
-       }\r
-       STDMETHOD(EnumObjects)(DWORD, IEnumUnknown** ppenum)\r
-       {\r
-               if (ppenum == NULL)\r
-                       return E_POINTER;\r
-               *ppenum = NULL;\r
-               typedef CComObject<CComEnum<IEnumUnknown, &__uuidof(IEnumUnknown), IUnknown*, _CopyInterface<IUnknown> > > enumunk;\r
-               enumunk* p = NULL;\r
-               ATLTRY(p = new enumunk);\r
-               if(p == NULL)\r
-                       return E_OUTOFMEMORY;\r
-               IUnknown* pTemp = m_spUnknown;\r
-               // There is always only one object.\r
-               HRESULT hRes = p->Init(reinterpret_cast<IUnknown**>(&pTemp), reinterpret_cast<IUnknown**>(&pTemp + 1), GetControllingUnknown(), AtlFlagCopy);\r
-               if (SUCCEEDED(hRes))\r
-                       hRes = p->QueryInterface(__uuidof(IEnumUnknown), (void**)ppenum);\r
-               if (FAILED(hRes))\r
-                       delete p;\r
-               return hRes;\r
-       }\r
-       STDMETHOD(LockContainer)(BOOL)\r
-       {\r
-               ATLTRACENOTIMPL(_T("IOleContainer::LockContainer"));\r
-       }\r
-\r
-//ITimerService\r
-       STDMETHOD(CreateTimer)(ITimer *pReferenceTimer, ITimer **ppNewTimer);\r
-       STDMETHOD(GetNamedTimer)(REFGUID rguidName, ITimer **ppTimer);\r
-       STDMETHOD(SetNamedTimerReference)(REFGUID rguidName, ITimer *pReferenceTimer);\r
-\r
-//ITimer\r
-       STDMETHOD(Advise)(VARIANT vtimeMin, VARIANT vtimeMax, VARIANT vtimeInterval, DWORD dwFlags, ITimerSink *pTimerSink, DWORD *pdwCookie);\r
-       STDMETHOD(Unadvise)(DWORD dwCookie);\r
-       STDMETHOD(Freeze)(BOOL fFreeze);\r
-       STDMETHOD(GetTime)(VARIANT *pvtime);\r
-       double GetFPS();\r
-\r
-       void set_print(const std::function<std::wstring()>& print) { print_ = print;}\r
-\r
-       HRESULT CreateAxControl();\r
-       void DestroyAxControl();\r
-       HRESULT QueryControl(REFIID iid, void** ppUnk);\r
-\r
-       template <class Q>\r
-       HRESULT QueryControl(Q** ppUnk)\r
-       {\r
-               return QueryControl(__uuidof(Q), (void**)ppUnk);\r
-       }\r
-\r
-//     static ATL::CComObject<FlashAxContainer>* CreateInstance();\r
-\r
-       void Tick();\r
-       bool FlashCall(const std::wstring& str, std::wstring& result);\r
-       bool DrawControl(HDC targetDC);\r
-       bool InvalidRect() const { return bInvalidRect_; } \r
-       bool IsEmpty() const { return bIsEmpty_; }\r
-\r
-       void SetSize(size_t width, size_t height);\r
-       bool IsReadyToRender() const;\r
-       void EnterFullscreen();\r
-\r
-       static bool CheckForFlashSupport();\r
-\r
-       ATL::CComPtr<IOleInPlaceObjectWindowless> m_spInPlaceObjectWindowless;\r
-\r
-private:\r
-       std::function<std::wstring()> print_;\r
-       TimerHelper* pTimerHelper;\r
-       volatile bool bInvalidRect_;\r
-       volatile bool bCallSuccessful_;\r
-       volatile bool bReadyToRender_;\r
-       volatile bool bIsEmpty_;\r
-       volatile bool bHasNewTiming_;\r
-       std::vector<DirtyRect> bDirtyRects_;\r
-\r
-\r
-       IDirectDraw4Ptr *m_lpDD4;\r
-       static CComBSTR flashGUID_;\r
-\r
-       DWORD timerCount_;\r
-\r
-//     state\r
-       bool            bUIActive_;\r
-       bool            bInPlaceActive_;\r
-       unsigned long           bHaveFocus_ : 1;\r
-       unsigned long           bCapture_ : 1;\r
-\r
-       DWORD m_dwOleObject;\r
-       DWORD m_dwMiscStatus;\r
-       SIZEL m_hmSize;\r
-       SIZEL m_pxSize;\r
-       RECT m_rcPos;\r
-\r
-       ATL::CComPtr<IUnknown> m_spUnknown;\r
-       ATL::CComPtr<IOleObject> m_spServices;\r
-       ATL::CComPtr<IOleObject> m_spOleObject;\r
-       ATL::CComPtr<IViewObjectEx> m_spViewObject;\r
-\r
-//     ATL::CComPtr<ATL::CComObject<MyMoniker> > m_spMyMoniker;\r
-};\r
-\r
-}      //namespace flash\r
-}      //namespace caspar\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+#ifndef _FLASHAXCONTAINER_H__
+#define _FLASHAXCONTAINER_H__
+
+#pragma once
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlhost.h>
+#include <ocmm.h>
+
+#include <functional>
+#include <vector>
+
+#include <core/video_format.h>
+#include "../interop/axflash.h"
+//#import "progid:ShockwaveFlash.ShockwaveFlash.9" no_namespace, named_guids
+
+#include <comdef.h>
+
+#include "../interop/TimerHelper.h"
+
+#include <InitGuid.h>
+#include <ddraw.h>
+
+#ifndef DEFINE_GUID2
+#define DEFINE_GUID2(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+               const GUID name \
+                               = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
+#endif    
+
+_COM_SMARTPTR_TYPEDEF(IDirectDraw4, IID_IDirectDraw4);
+
+namespace caspar {
+
+namespace flash {
+
+class TimerHelper;
+struct DirtyRect {
+       DirtyRect(LONG l, LONG t, LONG r, LONG b, bool e) : bErase(e), bWhole(false) { 
+               rect.left = l;
+               rect.top = t;
+               rect.right = r;
+               rect.bottom = b; 
+       }
+       DirtyRect(const RECT& rc, bool e) : bErase(e), bWhole(false)  {
+               rect.left = rc.left;
+               rect.top = rc.top;
+               rect.right = rc.right;
+               rect.bottom = rc.bottom; 
+       }
+       explicit DirtyRect(bool b) : bWhole(b) {}
+
+       RECT    rect;
+       bool    bErase;
+       bool    bWhole;
+};
+
+extern _ATL_FUNC_INFO fnInfoFlashCallEvent;
+extern _ATL_FUNC_INFO fnInfoReadyStateChangeEvent;
+
+class ATL_NO_VTABLE FlashAxContainer : 
+               public ATL::CComCoClass<FlashAxContainer , &CLSID_NULL>,
+               public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>,
+               public IOleClientSite,
+               public IOleContainer,
+               public IOleControlSite,
+               public IOleInPlaceSiteWindowless,
+               public IObjectWithSiteImpl<FlashAxContainer>,
+               public IServiceProvider,
+               public IAdviseSink,
+               public ITimerService,
+               public ITimer,
+               public IDispatchImpl<IDispatch>,
+               public IDispEventSimpleImpl<0, FlashAxContainer, &DIID__IShockwaveFlashEvents>
+{
+
+public:
+
+       FlashAxContainer();
+       virtual ~FlashAxContainer();
+
+       DECLARE_NO_REGISTRY()
+       DECLARE_POLY_AGGREGATABLE(FlashAxContainer)
+       DECLARE_GET_CONTROLLING_UNKNOWN()
+
+       BEGIN_COM_MAP(FlashAxContainer)
+               COM_INTERFACE_ENTRY(IDispatch)
+               COM_INTERFACE_ENTRY(IOleClientSite)
+               COM_INTERFACE_ENTRY(IObjectWithSite)
+               COM_INTERFACE_ENTRY(IOleControlSite)
+               COM_INTERFACE_ENTRY(IOleContainer)
+
+               COM_INTERFACE_ENTRY(IOleInPlaceSiteWindowless)
+               COM_INTERFACE_ENTRY(IOleInPlaceSiteEx)
+               COM_INTERFACE_ENTRY(IOleInPlaceSite)
+               COM_INTERFACE_ENTRY(IOleWindow)
+
+               COM_INTERFACE_ENTRY(IServiceProvider)
+
+               COM_INTERFACE_ENTRY(IAdviseSink)
+
+               COM_INTERFACE_ENTRY(ITimerService)
+
+               COM_INTERFACE_ENTRY(ITimer)
+       END_COM_MAP()
+
+       BEGIN_SINK_MAP(FlashAxContainer)
+               SINK_ENTRY_INFO(0, DIID__IShockwaveFlashEvents, 0xc5, OnFlashCall, &fnInfoFlashCallEvent)
+               SINK_ENTRY_INFO(0, DIID__IShockwaveFlashEvents, 0xfffffd9f, OnReadyStateChange, &fnInfoReadyStateChangeEvent)
+       END_SINK_MAP()
+
+       void STDMETHODCALLTYPE OnFlashCall(BSTR request);
+       void STDMETHODCALLTYPE OnReadyStateChange(long newState);
+
+// IObjectWithSite
+       STDMETHOD(SetSite)(IUnknown* pUnkSite);
+
+// IOleClientSite
+       STDMETHOD(SaveObject)();
+       STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk);
+       STDMETHOD(GetContainer)(IOleContainer** ppContainer);
+       STDMETHOD(ShowObject)();
+       STDMETHOD(OnShowWindow)(BOOL fShow);
+       STDMETHOD(RequestNewObjectLayout)();
+
+// IOleInPlaceSite
+       STDMETHOD(GetWindow)(HWND* pHwnd);
+       STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode);
+       STDMETHOD(CanInPlaceActivate)();
+       STDMETHOD(OnInPlaceActivate)();
+       STDMETHOD(OnInPlaceDeactivate)();
+       STDMETHOD(OnUIActivate)();
+       STDMETHOD(OnUIDeactivate)(BOOL fUndoable);
+       STDMETHOD(GetWindowContext)(IOleInPlaceFrame** ppFrame, IOleInPlaceUIWindow** ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO pFrameInfo);
+       STDMETHOD(Scroll)(SIZE scrollExtant);
+       STDMETHOD(DiscardUndoState)();
+       STDMETHOD(DeactivateAndUndo)();
+       STDMETHOD(OnPosRectChange)(LPCRECT lprcPosRect);
+
+// IOleInPlaceSiteEx
+       STDMETHOD(OnInPlaceActivateEx)(BOOL* pfNoRedraw, DWORD dwFlags);
+       STDMETHOD(OnInPlaceDeactivateEx)(BOOL fNoRedraw);
+       STDMETHOD(RequestUIActivate)();
+
+// IOleInPlaceSiteWindowless
+       STDMETHOD(CanWindowlessActivate)();
+       STDMETHOD(GetCapture)();
+       STDMETHOD(SetCapture)(BOOL fCapture);
+       STDMETHOD(GetFocus)();
+       STDMETHOD(SetFocus)(BOOL fGotFocus);
+       STDMETHOD(GetDC)(LPCRECT pRect, DWORD grfFlags, HDC* phDC);
+       STDMETHOD(ReleaseDC)(HDC hDC);
+       STDMETHOD(InvalidateRect)(LPCRECT pRect, BOOL fErase);
+       STDMETHOD(InvalidateRgn)(HRGN hRGN, BOOL fErase);
+       STDMETHOD(ScrollRect)(INT dx, INT dy, LPCRECT pRectScroll, LPCRECT pRectClip);
+       STDMETHOD(AdjustRect)(LPRECT prc);
+       STDMETHOD(OnDefWindowMessage)(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* plResult);
+
+// IOleControlSite
+       STDMETHOD(OnControlInfoChanged)();
+       STDMETHOD(LockInPlaceActive)(BOOL fLock);
+       STDMETHOD(GetExtendedControl)(IDispatch** ppDisp);
+       STDMETHOD(TransformCoords)(POINTL* pPtlHimetric, POINTF* pPtfContainer, DWORD dwFlags);
+       STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, DWORD grfModifiers);
+       STDMETHOD(OnFocus)(BOOL fGotFocus);
+       STDMETHOD(ShowPropertyFrame)();
+
+// IAdviseSink
+       STDMETHOD_(void, OnDataChange)(FORMATETC* pFormatetc, STGMEDIUM* pStgmed);
+       STDMETHOD_(void, OnViewChange)(DWORD dwAspect, LONG lindex);
+       STDMETHOD_(void, OnRename)(IMoniker* pmk);
+       STDMETHOD_(void, OnSave)();
+       STDMETHOD_(void, OnClose)();
+
+// IServiceProvider
+       STDMETHOD(QueryService)( REFGUID rsid, REFIID riid, void** ppvObj);
+
+// IOleContainer
+       STDMETHOD(ParseDisplayName)(IBindCtx*, LPOLESTR, ULONG*, IMoniker**)
+       {
+               ATLTRACENOTIMPL(_T("IOleContainer::ParseDisplayName"));
+       }
+       STDMETHOD(EnumObjects)(DWORD, IEnumUnknown** ppenum)
+       {
+               if (ppenum == NULL)
+                       return E_POINTER;
+               *ppenum = NULL;
+               typedef CComObject<CComEnum<IEnumUnknown, &__uuidof(IEnumUnknown), IUnknown*, _CopyInterface<IUnknown> > > enumunk;
+               enumunk* p = NULL;
+               ATLTRY(p = new enumunk);
+               if(p == NULL)
+                       return E_OUTOFMEMORY;
+               IUnknown* pTemp = m_spUnknown;
+               // There is always only one object.
+               HRESULT hRes = p->Init(reinterpret_cast<IUnknown**>(&pTemp), reinterpret_cast<IUnknown**>(&pTemp + 1), GetControllingUnknown(), AtlFlagCopy);
+               if (SUCCEEDED(hRes))
+                       hRes = p->QueryInterface(__uuidof(IEnumUnknown), (void**)ppenum);
+               if (FAILED(hRes))
+                       delete p;
+               return hRes;
+       }
+       STDMETHOD(LockContainer)(BOOL)
+       {
+               ATLTRACENOTIMPL(_T("IOleContainer::LockContainer"));
+       }
+
+//ITimerService
+       STDMETHOD(CreateTimer)(ITimer *pReferenceTimer, ITimer **ppNewTimer);
+       STDMETHOD(GetNamedTimer)(REFGUID rguidName, ITimer **ppTimer);
+       STDMETHOD(SetNamedTimerReference)(REFGUID rguidName, ITimer *pReferenceTimer);
+
+//ITimer
+       STDMETHOD(Advise)(VARIANT vtimeMin, VARIANT vtimeMax, VARIANT vtimeInterval, DWORD dwFlags, ITimerSink *pTimerSink, DWORD *pdwCookie);
+       STDMETHOD(Unadvise)(DWORD dwCookie);
+       STDMETHOD(Freeze)(BOOL fFreeze);
+       STDMETHOD(GetTime)(VARIANT *pvtime);
+       double GetFPS();
+
+       void set_print(const std::function<std::wstring()>& print) { print_ = print;}
+
+       HRESULT CreateAxControl();
+       void DestroyAxControl();
+       HRESULT QueryControl(REFIID iid, void** ppUnk);
+
+       template <class Q>
+       HRESULT QueryControl(Q** ppUnk)
+       {
+               return QueryControl(__uuidof(Q), (void**)ppUnk);
+       }
+
+//     static ATL::CComObject<FlashAxContainer>* CreateInstance();
+
+       void Tick();
+       bool FlashCall(const std::wstring& str, std::wstring& result);
+       bool DrawControl(HDC targetDC);
+       bool InvalidRect() const { return bInvalidRect_; } 
+       bool IsEmpty() const { return bIsEmpty_; }
+
+       void SetSize(size_t width, size_t height);
+       bool IsReadyToRender() const;
+       void EnterFullscreen();
+
+       static bool CheckForFlashSupport();
+
+       ATL::CComPtr<IOleInPlaceObjectWindowless> m_spInPlaceObjectWindowless;
+
+private:
+       std::function<std::wstring()> print_;
+       TimerHelper* pTimerHelper;
+       volatile bool bInvalidRect_;
+       volatile bool bCallSuccessful_;
+       volatile bool bReadyToRender_;
+       volatile bool bIsEmpty_;
+       volatile bool bHasNewTiming_;
+       std::vector<DirtyRect> bDirtyRects_;
+
+
+       IDirectDraw4Ptr *m_lpDD4;
+       static CComBSTR flashGUID_;
+
+       DWORD timerCount_;
+
+//     state
+       bool            bUIActive_;
+       bool            bInPlaceActive_;
+       unsigned long           bHaveFocus_ : 1;
+       unsigned long           bCapture_ : 1;
+
+       DWORD m_dwOleObject;
+       DWORD m_dwMiscStatus;
+       SIZEL m_hmSize;
+       SIZEL m_pxSize;
+       RECT m_rcPos;
+
+       ATL::CComPtr<IUnknown> m_spUnknown;
+       ATL::CComPtr<IOleObject> m_spServices;
+       ATL::CComPtr<IOleObject> m_spOleObject;
+       ATL::CComPtr<IViewObjectEx> m_spViewObject;
+
+//     ATL::CComPtr<ATL::CComObject<MyMoniker> > m_spMyMoniker;
+};
+
+}      //namespace flash
+}      //namespace caspar
+
 #endif //_FLASHAXCONTAINER_H__
\ No newline at end of file
index 6867145aa77e7a9e3f260332c78f20bc9aae23b1..77f81d849d902bbf079d9d135b48d665038bb991 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../StdAfx.h"\r
-\r
-#include "cg_proxy.h"\r
-\r
-#include "flash_producer.h"\r
-\r
-#include <common/env.h>\r
-\r
-#include <core/mixer/mixer.h>\r
-\r
-#include <boost/filesystem.hpp>\r
-#include <boost/format.hpp>\r
-#include <boost/algorithm/string.hpp>\r
-#include <boost/regex.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-               \r
-namespace caspar { namespace flash {\r
-       \r
-struct cg_proxy::impl : boost::noncopyable\r
-{\r
-       spl::shared_ptr<core::frame_producer> flash_producer_;\r
-public:\r
-       impl(const spl::shared_ptr<core::frame_producer>& frame_producer) \r
-               : flash_producer_(frame_producer)\r
-       {}\r
-       \r
-       boost::unique_future<std::wstring> add(int layer, std::wstring filename,  bool play_on_load, const std::wstring& label, const std::wstring& data)\r
-       {\r
-               if(filename.size() > 0 && filename[0] == L'/')\r
-                       filename = filename.substr(1, filename.size()-1);\r
-\r
-               if(boost::filesystem::wpath(filename).extension() == L"")\r
-                       filename += L".ft";\r
-               \r
-               auto str = (boost::wformat(L"<invoke name=\"Add\" returntype=\"xml\"><arguments><number>%1%</number><string>%2%</string>%3%<string>%4%</string><string><![CDATA[%5%]]></string></arguments></invoke>") % layer % filename % (play_on_load?L"<true/>":L"<false/>") % label % data).str();\r
-\r
-               CASPAR_LOG(info) << flash_producer_->print() << " Invoking add-command: " << str;\r
-               return flash_producer_->call(str);\r
-       }\r
-\r
-       boost::unique_future<std::wstring> remove(int layer)\r
-       {\r
-               auto str = (boost::wformat(L"<invoke name=\"Delete\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str();\r
-               CASPAR_LOG(info) << flash_producer_->print() << " Invoking remove-command: " << str;\r
-               return flash_producer_->call(str);\r
-       }\r
-\r
-       boost::unique_future<std::wstring> play(int layer)\r
-       {\r
-               auto str = (boost::wformat(L"<invoke name=\"Play\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str();\r
-               CASPAR_LOG(info) << flash_producer_->print() << " Invoking play-command: " << str;\r
-               return flash_producer_->call(str);\r
-       }\r
-\r
-       boost::unique_future<std::wstring> stop(int layer, unsigned int)\r
-       {\r
-               auto str = (boost::wformat(L"<invoke name=\"Stop\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array><number>0</number></arguments></invoke>") % layer).str();\r
-               CASPAR_LOG(info) << flash_producer_->print() << " Invoking stop-command: " << str;\r
-               return flash_producer_->call(str);\r
-       }\r
-\r
-       boost::unique_future<std::wstring> next(int layer)\r
-       {\r
-               auto str = (boost::wformat(L"<invoke name=\"Next\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str();\r
-               CASPAR_LOG(info) << flash_producer_->print() << " Invoking next-command: " << str;\r
-               return flash_producer_->call(str);\r
-       }\r
-\r
-       boost::unique_future<std::wstring> update(int layer, const std::wstring& data)\r
-       {\r
-               auto str = (boost::wformat(L"<invoke name=\"SetData\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array><string><![CDATA[%2%]]></string></arguments></invoke>") % layer % data).str();\r
-               CASPAR_LOG(info) << flash_producer_->print() <<" Invoking update-command: " << str;\r
-               return flash_producer_->call(str);\r
-       }\r
-\r
-       boost::unique_future<std::wstring> invoke(int layer, const std::wstring& label)\r
-       {\r
-               auto str = (boost::wformat(L"<invoke name=\"Invoke\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array><string>%2%</string></arguments></invoke>") % layer % label).str();\r
-               CASPAR_LOG(info) << flash_producer_->print() << " Invoking invoke-command: " << str;\r
-               return flash_producer_->call(str);\r
-       }\r
-\r
-       boost::unique_future<std::wstring> description(int layer)\r
-       {\r
-               auto str = (boost::wformat(L"<invoke name=\"GetDescription\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str();\r
-               CASPAR_LOG(info) << flash_producer_->print() << " Invoking description-command: " << str;\r
-               return flash_producer_->call(str);\r
-       }\r
-\r
-       boost::unique_future<std::wstring> template_host_info()\r
-       {\r
-               auto str = (boost::wformat(L"<invoke name=\"GetInfo\" returntype=\"xml\"><arguments></arguments></invoke>")).str();\r
-               CASPAR_LOG(info) << flash_producer_->print() << " Invoking info-command: " << str;\r
-               return flash_producer_->call(str);\r
-       }\r
-               \r
-       std::wstring timed_invoke(int layer, const std::wstring& label)\r
-       {\r
-               auto result = invoke(layer, label);\r
-               if(result.timed_wait(boost::posix_time::seconds(2)))\r
-                       return result.get();\r
-               return L"";\r
-       }\r
-       std::wstring timed_description(int layer)\r
-       {\r
-               auto result = description(layer);\r
-               if(result.timed_wait(boost::posix_time::seconds(2)))\r
-                       return result.get();\r
-               return L"";\r
-       }\r
-       std::wstring timed_template_host_info()\r
-       {\r
-               auto result = template_host_info();\r
-               if(result.timed_wait(boost::posix_time::seconds(2)))\r
-                       return result.get();\r
-               return L"";\r
-       }\r
-};\r
-       \r
-cg_proxy create_cg_proxy(const spl::shared_ptr<core::video_channel>& video_channel, int render_layer)\r
-{      \r
-       auto flash_producer = video_channel->stage().foreground(render_layer).get();\r
-\r
-       try\r
-       {\r
-               if(flash_producer->name() != L"flash")\r
-               {\r
-                       flash_producer = flash::create_producer(video_channel->frame_factory(), video_channel->video_format_desc(), boost::assign::list_of<std::wstring>());    \r
-                       video_channel->stage().load(render_layer, flash_producer); \r
-                       video_channel->stage().play(render_layer);\r
-               }\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               throw;\r
-       }\r
-\r
-       return cg_proxy(std::move(flash_producer));\r
-}\r
-\r
-spl::shared_ptr<core::frame_producer> create_cg_producer_and_autoplay_file(\r
-               const spl::shared_ptr<core::frame_factory> frame_factory, \r
-               const core::video_format_desc& format_desc, \r
-               const std::vector<std::wstring>& params,\r
-               const std::wstring& filename) \r
-{\r
-       if(!boost::filesystem::exists(filename))\r
-               return core::frame_producer::empty();\r
-               \r
-       boost::filesystem::path path(filename);\r
-       path = boost::filesystem3::complete(path);\r
-       auto filename2 = path.wstring();\r
-\r
-       auto flash_producer = flash::create_producer(frame_factory, format_desc, boost::assign::list_of<std::wstring>());       \r
-       auto producer = flash_producer;\r
-       cg_proxy(producer).add(0, filename2, 1);\r
-\r
-       return producer;\r
-}\r
-\r
-spl::shared_ptr<core::frame_producer> create_ct_producer(const spl::shared_ptr<core::frame_factory> frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params) \r
-{\r
-       return create_cg_producer_and_autoplay_file(\r
-               frame_factory, format_desc, params, env::media_folder() + L"\\" + params[0] + L".ct");\r
-}\r
-\r
-spl::shared_ptr<core::frame_producer> create_swf_producer(const spl::shared_ptr<core::frame_factory> frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params) \r
-{\r
-       return create_cg_producer_and_autoplay_file(\r
-               frame_factory, format_desc, params, env::media_folder() + L"\\" + params[0] + L".swf");\r
-}\r
-\r
-cg_proxy::cg_proxy(const spl::shared_ptr<core::frame_producer>& frame_producer) : impl_(new impl(frame_producer)){}\r
-cg_proxy::cg_proxy(cg_proxy&& other) : impl_(std::move(other.impl_)){}\r
-void cg_proxy::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_proxy::remove(int layer){impl_->remove(layer);}\r
-void cg_proxy::play(int layer){impl_->play(layer);}\r
-void cg_proxy::stop(int layer, unsigned int mix_out_duration){impl_->stop(layer, mix_out_duration);}\r
-void cg_proxy::next(int layer){impl_->next(layer);}\r
-void cg_proxy::update(int layer, const std::wstring& data){impl_->update(layer, data);}\r
-std::wstring cg_proxy::invoke(int layer, const std::wstring& label){return impl_->timed_invoke(layer, label);}\r
-std::wstring cg_proxy::description(int layer){return impl_->timed_description(layer);}\r
-std::wstring cg_proxy::template_host_info(){return impl_->timed_template_host_info();}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../StdAfx.h"
+
+#include "cg_proxy.h"
+
+#include "flash_producer.h"
+
+#include <common/env.h>
+
+#include <core/mixer/mixer.h>
+
+#include <boost/filesystem.hpp>
+#include <boost/format.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/regex.hpp>
+#include <boost/property_tree/ptree.hpp>
+               
+namespace caspar { namespace flash {
+       
+struct cg_proxy::impl : boost::noncopyable
+{
+       spl::shared_ptr<core::frame_producer> flash_producer_;
+public:
+       impl(const spl::shared_ptr<core::frame_producer>& frame_producer) 
+               : flash_producer_(frame_producer)
+       {}
+       
+       boost::unique_future<std::wstring> add(int layer, std::wstring filename,  bool play_on_load, const std::wstring& label, const std::wstring& data)
+       {
+               if(filename.size() > 0 && filename[0] == L'/')
+                       filename = filename.substr(1, filename.size()-1);
+
+               if(boost::filesystem::wpath(filename).extension() == L"")
+                       filename += L".ft";
+               
+               auto str = (boost::wformat(L"<invoke name=\"Add\" returntype=\"xml\"><arguments><number>%1%</number><string>%2%</string>%3%<string>%4%</string><string><![CDATA[%5%]]></string></arguments></invoke>") % layer % filename % (play_on_load?L"<true/>":L"<false/>") % label % data).str();
+
+               CASPAR_LOG(info) << flash_producer_->print() << " Invoking add-command: " << str;
+               return flash_producer_->call(str);
+       }
+
+       boost::unique_future<std::wstring> remove(int layer)
+       {
+               auto str = (boost::wformat(L"<invoke name=\"Delete\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str();
+               CASPAR_LOG(info) << flash_producer_->print() << " Invoking remove-command: " << str;
+               return flash_producer_->call(str);
+       }
+
+       boost::unique_future<std::wstring> play(int layer)
+       {
+               auto str = (boost::wformat(L"<invoke name=\"Play\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str();
+               CASPAR_LOG(info) << flash_producer_->print() << " Invoking play-command: " << str;
+               return flash_producer_->call(str);
+       }
+
+       boost::unique_future<std::wstring> stop(int layer, unsigned int)
+       {
+               auto str = (boost::wformat(L"<invoke name=\"Stop\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array><number>0</number></arguments></invoke>") % layer).str();
+               CASPAR_LOG(info) << flash_producer_->print() << " Invoking stop-command: " << str;
+               return flash_producer_->call(str);
+       }
+
+       boost::unique_future<std::wstring> next(int layer)
+       {
+               auto str = (boost::wformat(L"<invoke name=\"Next\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str();
+               CASPAR_LOG(info) << flash_producer_->print() << " Invoking next-command: " << str;
+               return flash_producer_->call(str);
+       }
+
+       boost::unique_future<std::wstring> update(int layer, const std::wstring& data)
+       {
+               auto str = (boost::wformat(L"<invoke name=\"SetData\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array><string><![CDATA[%2%]]></string></arguments></invoke>") % layer % data).str();
+               CASPAR_LOG(info) << flash_producer_->print() <<" Invoking update-command: " << str;
+               return flash_producer_->call(str);
+       }
+
+       boost::unique_future<std::wstring> invoke(int layer, const std::wstring& label)
+       {
+               auto str = (boost::wformat(L"<invoke name=\"Invoke\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array><string>%2%</string></arguments></invoke>") % layer % label).str();
+               CASPAR_LOG(info) << flash_producer_->print() << " Invoking invoke-command: " << str;
+               return flash_producer_->call(str);
+       }
+
+       boost::unique_future<std::wstring> description(int layer)
+       {
+               auto str = (boost::wformat(L"<invoke name=\"GetDescription\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str();
+               CASPAR_LOG(info) << flash_producer_->print() << " Invoking description-command: " << str;
+               return flash_producer_->call(str);
+       }
+
+       boost::unique_future<std::wstring> template_host_info()
+       {
+               auto str = (boost::wformat(L"<invoke name=\"GetInfo\" returntype=\"xml\"><arguments></arguments></invoke>")).str();
+               CASPAR_LOG(info) << flash_producer_->print() << " Invoking info-command: " << str;
+               return flash_producer_->call(str);
+       }
+               
+       std::wstring timed_invoke(int layer, const std::wstring& label)
+       {
+               auto result = invoke(layer, label);
+               if(result.timed_wait(boost::posix_time::seconds(2)))
+                       return result.get();
+               return L"";
+       }
+       std::wstring timed_description(int layer)
+       {
+               auto result = description(layer);
+               if(result.timed_wait(boost::posix_time::seconds(2)))
+                       return result.get();
+               return L"";
+       }
+       std::wstring timed_template_host_info()
+       {
+               auto result = template_host_info();
+               if(result.timed_wait(boost::posix_time::seconds(2)))
+                       return result.get();
+               return L"";
+       }
+};
+       
+cg_proxy create_cg_proxy(const spl::shared_ptr<core::video_channel>& video_channel, int render_layer)
+{      
+       auto flash_producer = video_channel->stage().foreground(render_layer).get();
+
+       try
+       {
+               if(flash_producer->name() != L"flash")
+               {
+                       flash_producer = flash::create_producer(video_channel->frame_factory(), video_channel->video_format_desc(), boost::assign::list_of<std::wstring>());    
+                       video_channel->stage().load(render_layer, flash_producer); 
+                       video_channel->stage().play(render_layer);
+               }
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               throw;
+       }
+
+       return cg_proxy(std::move(flash_producer));
+}
+
+spl::shared_ptr<core::frame_producer> create_cg_producer_and_autoplay_file(
+               const spl::shared_ptr<core::frame_factory> frame_factory, 
+               const core::video_format_desc& format_desc, 
+               const std::vector<std::wstring>& params,
+               const std::wstring& filename) 
+{
+       if(!boost::filesystem::exists(filename))
+               return core::frame_producer::empty();
+               
+       boost::filesystem::path path(filename);
+       path = boost::filesystem3::complete(path);
+       auto filename2 = path.wstring();
+
+       auto flash_producer = flash::create_producer(frame_factory, format_desc, boost::assign::list_of<std::wstring>());       
+       auto producer = flash_producer;
+       cg_proxy(producer).add(0, filename2, 1);
+
+       return producer;
+}
+
+spl::shared_ptr<core::frame_producer> create_ct_producer(const spl::shared_ptr<core::frame_factory> frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params) 
+{
+       return create_cg_producer_and_autoplay_file(
+               frame_factory, format_desc, params, env::media_folder() + L"\\" + params[0] + L".ct");
+}
+
+spl::shared_ptr<core::frame_producer> create_swf_producer(const spl::shared_ptr<core::frame_factory> frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params) 
+{
+       return create_cg_producer_and_autoplay_file(
+               frame_factory, format_desc, params, env::media_folder() + L"\\" + params[0] + L".swf");
+}
+
+cg_proxy::cg_proxy(const spl::shared_ptr<core::frame_producer>& frame_producer) : impl_(new impl(frame_producer)){}
+cg_proxy::cg_proxy(cg_proxy&& other) : impl_(std::move(other.impl_)){}
+void cg_proxy::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);}
+void cg_proxy::remove(int layer){impl_->remove(layer);}
+void cg_proxy::play(int layer){impl_->play(layer);}
+void cg_proxy::stop(int layer, unsigned int mix_out_duration){impl_->stop(layer, mix_out_duration);}
+void cg_proxy::next(int layer){impl_->next(layer);}
+void cg_proxy::update(int layer, const std::wstring& data){impl_->update(layer, data);}
+std::wstring cg_proxy::invoke(int layer, const std::wstring& label){return impl_->timed_invoke(layer, label);}
+std::wstring cg_proxy::description(int layer){return impl_->timed_description(layer);}
+std::wstring cg_proxy::template_host_info(){return impl_->timed_template_host_info();}
+
 }}
\ No newline at end of file
index 98228cdbfb4bde2a7a2791e96c77769a9964a9f5..0448a20b1e1d541e396db402e8e98e05a5d192df 100644 (file)
@@ -1,64 +1,64 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/producer/stage.h>\r
-#include <core/video_format.h>\r
-#include <core/video_channel.h>\r
-\r
-#include <boost/thread/future.hpp>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace flash {\r
-               \r
-class cg_proxy\r
-{\r
-public:\r
-       static const unsigned int DEFAULT_LAYER = 9999;\r
-\r
-       explicit cg_proxy(const spl::shared_ptr<core::frame_producer>& producer);\r
-       cg_proxy(cg_proxy&& other);\r
-       \r
-       //cg_proxy\r
-\r
-       void add(int layer, const std::wstring& template_name,  bool play_on_load, const std::wstring& start_from_label = L"", const std::wstring& data = L"");\r
-       void remove(int layer);\r
-       void play(int layer);\r
-       void stop(int layer, unsigned int mix_out_duration);\r
-       void next(int layer);\r
-       void update(int layer, const std::wstring& data);\r
-       std::wstring invoke(int layer, const std::wstring& label);\r
-       std::wstring description(int layer);\r
-       std::wstring template_host_info();\r
-\r
-private:\r
-       struct impl;\r
-       std::shared_ptr<impl> impl_;\r
-};\r
-cg_proxy create_cg_proxy(const spl::shared_ptr<core::video_channel>& video_channel, int layer_index = cg_proxy::DEFAULT_LAYER);\r
-\r
-spl::shared_ptr<core::frame_producer> create_ct_producer(const spl::shared_ptr<core::frame_factory> frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);\r
-spl::shared_ptr<core::frame_producer> create_swf_producer(const spl::shared_ptr<core::frame_factory> frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <core/producer/frame_producer.h>
+#include <core/producer/stage.h>
+#include <core/video_format.h>
+#include <core/video_channel.h>
+
+#include <boost/thread/future.hpp>
+
+#include <string>
+
+namespace caspar { namespace flash {
+               
+class cg_proxy
+{
+public:
+       static const unsigned int DEFAULT_LAYER = 9999;
+
+       explicit cg_proxy(const spl::shared_ptr<core::frame_producer>& producer);
+       cg_proxy(cg_proxy&& other);
+       
+       //cg_proxy
+
+       void add(int layer, const std::wstring& template_name,  bool play_on_load, const std::wstring& start_from_label = L"", const std::wstring& data = L"");
+       void remove(int layer);
+       void play(int layer);
+       void stop(int layer, unsigned int mix_out_duration);
+       void next(int layer);
+       void update(int layer, const std::wstring& data);
+       std::wstring invoke(int layer, const std::wstring& label);
+       std::wstring description(int layer);
+       std::wstring template_host_info();
+
+private:
+       struct impl;
+       std::shared_ptr<impl> impl_;
+};
+cg_proxy create_cg_proxy(const spl::shared_ptr<core::video_channel>& video_channel, int layer_index = cg_proxy::DEFAULT_LAYER);
+
+spl::shared_ptr<core::frame_producer> create_ct_producer(const spl::shared_ptr<core::frame_factory> frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_swf_producer(const spl::shared_ptr<core::frame_factory> frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+
+}}
index d6879084837f2e33d4d9b4e912014c37da67caf8..1af0ff3c5a97d6da8af8876b74707dbe84ff8c93 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (disable : 4146)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-\r
-#include "flash_producer.h"\r
-#include "FlashAxContainer.h"\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <core/frame/frame.h>\r
-#include <core/frame/draw_frame.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/monitor/monitor.h>\r
-\r
-#include <common/env.h>\r
-#include <common/executor.h>\r
-#include <common/lock.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/prec_timer.h>\r
-#include <common/array.h>\r
-\r
-#include <boost/filesystem.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/thread.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/algorithm/string.hpp>\r
-\r
-#include <tbb/spin_mutex.h>\r
-\r
-#include <asmlib.h>\r
-\r
-#include <functional>\r
-\r
-namespace caspar { namespace flash {\r
-               \r
-class bitmap\r
-{\r
-public:\r
-       bitmap(int width, int height)\r
-               : bmp_data_(nullptr)\r
-               , hdc_(CreateCompatibleDC(0), DeleteDC)\r
-       {       \r
-               BITMAPINFO info;\r
-               memset(&info, 0, sizeof(BITMAPINFO));\r
-               info.bmiHeader.biBitCount = 32;\r
-               info.bmiHeader.biCompression = BI_RGB;\r
-               info.bmiHeader.biHeight = static_cast<LONG>(-height);\r
-               info.bmiHeader.biPlanes = 1;\r
-               info.bmiHeader.biSize = sizeof(BITMAPINFO);\r
-               info.bmiHeader.biWidth = static_cast<LONG>(width);\r
-\r
-               bmp_.reset(CreateDIBSection(static_cast<HDC>(hdc_.get()), &info, DIB_RGB_COLORS, reinterpret_cast<void**>(&bmp_data_), 0, 0), DeleteObject);\r
-               SelectObject(static_cast<HDC>(hdc_.get()), bmp_.get()); \r
-\r
-               if(!bmp_data_)\r
-                       CASPAR_THROW_EXCEPTION(bad_alloc());\r
-       }\r
-\r
-       operator HDC() {return static_cast<HDC>(hdc_.get());}\r
-\r
-       BYTE* data() { return bmp_data_;}\r
-       const BYTE* data() const { return bmp_data_;}\r
-\r
-private:\r
-       BYTE* bmp_data_;        \r
-       std::shared_ptr<void> hdc_;\r
-       std::shared_ptr<void> bmp_;\r
-};\r
-\r
-struct template_host\r
-{\r
-       std::wstring  video_mode;\r
-       std::wstring  filename;\r
-       int                       width;\r
-       int                       height;\r
-};\r
-\r
-template_host get_template_host(const core::video_format_desc& desc)\r
-{\r
-       try\r
-       {\r
-               std::vector<template_host> template_hosts;\r
-               BOOST_FOREACH(auto& xml_mapping, env::properties().get_child(L"configuration.template-hosts"))\r
-               {\r
-                       try\r
-                       {\r
-                               template_host template_host;\r
-                               template_host.video_mode                = xml_mapping.second.get(L"video-mode", L"");\r
-                               template_host.filename                  = xml_mapping.second.get(L"filename",   L"cg.fth");\r
-                               template_host.width                             = xml_mapping.second.get(L"width",              desc.width);\r
-                               template_host.height                    = xml_mapping.second.get(L"height",             desc.height);\r
-                               template_hosts.push_back(template_host);\r
-                       }\r
-                       catch(...){}\r
-               }\r
-\r
-               auto template_host_it = boost::find_if(template_hosts, [&](template_host template_host){return template_host.video_mode == desc.name;});\r
-               if(template_host_it == template_hosts.end())\r
-                       template_host_it = boost::find_if(template_hosts, [&](template_host template_host){return template_host.video_mode == L"";});\r
-\r
-               if(template_host_it != template_hosts.end())\r
-                       return *template_host_it;\r
-       }\r
-       catch(...){}\r
-               \r
-       template_host template_host;\r
-       template_host.filename = L"cg.fth";\r
-\r
-       for(auto it = boost::filesystem::directory_iterator(env::template_folder()); it != boost::filesystem::directory_iterator(); ++it)\r
-       {\r
-               if(boost::iequals(it->path().extension().wstring(), L"." + desc.name))\r
-               {\r
-                       template_host.filename = it->path().filename().wstring();\r
-                       break;\r
-               }\r
-       }\r
-\r
-       template_host.width =  desc.square_width;\r
-       template_host.height = desc.square_height;\r
-       return template_host;\r
-}\r
-\r
-class flash_renderer\r
-{      \r
-       struct com_init\r
-       {\r
-               HRESULT result_;\r
-\r
-               com_init()\r
-                       : result_(CoInitialize(nullptr))\r
-               {\r
-                       if(FAILED(result_))\r
-                               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to initialize com-context for flash-player"));\r
-               }\r
-\r
-               ~com_init()\r
-               {\r
-                       if(SUCCEEDED(result_))\r
-                               ::CoUninitialize();\r
-               }\r
-       } com_init_;\r
-\r
-       monitor::basic_subject&                                         event_subject_;\r
-\r
-       const std::wstring                                                      filename_;\r
-\r
-       const std::shared_ptr<core::frame_factory>      frame_factory_;\r
-       \r
-       CComObject<caspar::flash::FlashAxContainer>* ax_;\r
-       core::draw_frame                                                        head_;\r
-       bitmap                                                                          bmp_;\r
-       \r
-       spl::shared_ptr<diagnostics::graph>                     graph_;\r
-       \r
-       prec_timer                                                                      timer_;\r
-\r
-       const int                                                                       width_;\r
-       const int                                                                       height_;\r
-       \r
-public:\r
-       flash_renderer(monitor::basic_subject& event_subject, const spl::shared_ptr<diagnostics::graph>& graph, const std::shared_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, int width, int height) \r
-               : event_subject_(event_subject)\r
-               , graph_(graph)\r
-               , filename_(filename)\r
-               , frame_factory_(frame_factory)\r
-               , ax_(nullptr)\r
-               , head_(core::draw_frame::empty())\r
-               , bmp_(width, height)\r
-               , width_(width)\r
-               , height_(height)\r
-       {               \r
-               graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));\r
-               graph_->set_color("param", diagnostics::color(1.0f, 0.5f, 0.0f));       \r
-               graph_->set_color("sync", diagnostics::color(0.8f, 0.3f, 0.2f));                        \r
-               \r
-               if(FAILED(CComObject<caspar::flash::FlashAxContainer>::CreateInstance(&ax_)))\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to create FlashAxContainer"));\r
-               \r
-               ax_->set_print([this]{return print();});\r
-\r
-               if(FAILED(ax_->CreateAxControl()))\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to Create FlashAxControl"));\r
-               \r
-               CComPtr<IShockwaveFlash> spFlash;\r
-               if(FAILED(ax_->QueryControl(&spFlash)))\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to Query FlashAxControl"));\r
-                                                                                               \r
-               if(FAILED(spFlash->put_Playing(true)) )\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to start playing Flash"));\r
-\r
-               if(FAILED(spFlash->put_Movie(CComBSTR(filename.c_str()))))\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to Load Template Host"));\r
-                                                                               \r
-               if(FAILED(spFlash->put_ScaleMode(2)))  //Exact fit. Scale without respect to the aspect ratio.\r
-                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to Set Scale Mode"));\r
-                                               \r
-               ax_->SetSize(width_, height_);          \r
-\r
-               tick(false);\r
-               render();\r
-\r
-               CASPAR_LOG(info) << print() << L" Initialized.";\r
-       }\r
-\r
-       ~flash_renderer()\r
-       {               \r
-               if(ax_)\r
-               {\r
-                       ax_->DestroyAxControl();\r
-                       ax_->Release();\r
-               }\r
-               graph_->set_value("tick-time", 0.0f);\r
-               graph_->set_value("frame-time", 0.0f);\r
-               CASPAR_LOG(info) << print() << L" Uninitialized.";\r
-       }\r
-       \r
-       std::wstring call(const std::wstring& param)\r
-       {               \r
-               std::wstring result;\r
-\r
-               CASPAR_LOG(trace) << print() << " Call: " << param;\r
-\r
-               if(!ax_->FlashCall(param, result))\r
-                       CASPAR_LOG(warning) << print() << L" Flash call failed:" << param;//CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Flash function call failed.") << arg_name_info("param") << arg_value_info(narrow(param)));\r
-               graph_->set_tag("param");\r
-\r
-               return result;\r
-       }\r
-\r
-       void tick(double sync)\r
-       {               \r
-               const float frame_time = 1.0f/ax_->GetFPS();\r
-\r
-               if(sync > 0.00001)                      \r
-                       timer_.tick(frame_time*sync); // This will block the thread.\r
-               else\r
-                       graph_->set_tag("sync");\r
-\r
-               graph_->set_value("sync", sync);\r
-               event_subject_ << monitor::event("sync") % sync;\r
-               \r
-               ax_->Tick();\r
-                                       \r
-               MSG msg;\r
-               while(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) // DO NOT REMOVE THE MESSAGE DISPATCH LOOP. Without this some stuff doesn't work!  \r
-               {\r
-                       if(msg.message == WM_TIMER && msg.wParam == 3 && msg.lParam == 0) // We tick this inside FlashAxContainer\r
-                               continue;\r
-                       \r
-                       TranslateMessage(&msg);\r
-                       DispatchMessage(&msg);                  \r
-               }\r
-       }\r
-       \r
-       core::draw_frame render()\r
-       {                       \r
-               const float frame_time = 1.0f/fps();\r
-\r
-               boost::timer frame_timer;\r
-\r
-               if(ax_->InvalidRect())\r
-               {                       \r
-                       A_memset(bmp_.data(), 0, width_*height_*4);\r
-                       ax_->DrawControl(bmp_);\r
-               \r
-                       core::pixel_format_desc desc = core::pixel_format::bgra;\r
-                       desc.planes.push_back(core::pixel_format_desc::plane(width_, height_, 4));\r
-                       auto frame = frame_factory_->create_frame(this, desc);\r
-\r
-                       A_memcpy(frame.image_data(0).begin(), bmp_.data(), width_*height_*4);\r
-                       head_ = core::draw_frame(std::move(frame));     \r
-               }               \r
-                                                                               \r
-               graph_->set_value("frame-time", static_cast<float>(frame_timer.elapsed()/frame_time)*0.5f);\r
-               event_subject_ << monitor::event("renderer/profiler/time") % frame_timer.elapsed() % frame_time;\r
-               return head_;\r
-       }\r
-       \r
-       bool is_empty() const\r
-       {\r
-               return ax_->IsEmpty();\r
-       }\r
-\r
-       double fps() const\r
-       {\r
-               return ax_->GetFPS();   \r
-       }\r
-       \r
-       std::wstring print()\r
-       {\r
-               return L"flash-player[" + boost::filesystem::wpath(filename_).filename().wstring() \r
-                                 + L"|" + boost::lexical_cast<std::wstring>(width_)\r
-                                 + L"x" + boost::lexical_cast<std::wstring>(height_)\r
-                                 + L"]";               \r
-       }\r
-};\r
-\r
-struct flash_producer : public core::frame_producer_base\r
-{      \r
-       monitor::basic_subject                                                  event_subject_;\r
-       const std::wstring                                                              filename_;      \r
-       const spl::shared_ptr<core::frame_factory>              frame_factory_;\r
-       const core::video_format_desc                                   format_desc_;\r
-       const int                                                                               width_;\r
-       const int                                                                               height_;\r
-       const int                                                                               buffer_size_;\r
-\r
-       tbb::atomic<int>                                                                fps_;\r
-\r
-       spl::shared_ptr<diagnostics::graph>                             graph_;\r
-\r
-       std::queue<core::draw_frame>                                    frame_buffer_;\r
-       tbb::concurrent_bounded_queue<core::draw_frame> output_buffer_;\r
-                               \r
-       boost::timer                                                                    tick_timer_;\r
-       std::unique_ptr<flash_renderer>                                 renderer_;\r
-       \r
-       executor                                                                                executor_;      \r
-public:\r
-       flash_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::wstring& filename, int width, int height) \r
-               : filename_(filename)           \r
-               , frame_factory_(frame_factory)\r
-               , format_desc_(format_desc)\r
-               , width_(width > 0 ? width : format_desc.width)\r
-               , height_(height > 0 ? height : format_desc.height)\r
-               , buffer_size_(env::properties().get(L"configuration.flash.buffer-depth", format_desc.fps > 30.0 ? 4 : 2))\r
-               , executor_(L"flash_producer")\r
-       {       \r
-               fps_ = 0;\r
-        \r
-               graph_->set_color("buffer-size", diagnostics::color(1.0f, 1.0f, 0.0f));\r
-               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));\r
-               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.9f));\r
-               graph_->set_text(print());\r
-               diagnostics::register_graph(graph_);\r
-\r
-               CASPAR_LOG(info) << print() << L" Initialized";\r
-       }\r
-\r
-       ~flash_producer()\r
-       {\r
-               executor_.invoke([this]\r
-               {\r
-                       renderer_.reset();\r
-               }, task_priority::high_priority);\r
-       }\r
-\r
-       // frame_producer\r
-               \r
-       core::draw_frame receive_impl() override\r
-       {                                       \r
-               auto frame = core::draw_frame::late();\r
-               \r
-               if(output_buffer_.try_pop(frame))                       \r
-                       executor_.begin_invoke(std::bind(&flash_producer::next, this));         \r
-               else            \r
-                       graph_->set_tag("late-frame");          \r
-                               \r
-               event_subject_ << monitor::event("host/path")   % filename_\r
-                                          << monitor::event("host/width")      % width_\r
-                                          << monitor::event("host/height") % height_\r
-                                          << monitor::event("host/fps")        % fps_\r
-                                          << monitor::event("buffer")          % output_buffer_.size() % buffer_size_;\r
-\r
-               return frame;\r
-       }\r
-               \r
-       boost::unique_future<std::wstring> call(const std::wstring& param) override\r
-       {       \r
-               return executor_.begin_invoke([this, param]() -> std::wstring\r
-               {                       \r
-                       try\r
-                       {\r
-                               if(!renderer_)\r
-                               {\r
-                                       renderer_.reset(new flash_renderer(event_subject_, graph_, frame_factory_, filename_, width_, height_));\r
-\r
-                                       while(output_buffer_.size() < buffer_size_)\r
-                                               output_buffer_.push(core::draw_frame::empty());\r
-                               }\r
-\r
-                               return renderer_->call(param);  \r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                               renderer_.reset(nullptr);\r
-                       }\r
-\r
-                       return L"";\r
-               });\r
-       }\r
-               \r
-       std::wstring print() const override\r
-       { \r
-               return L"flash[" + boost::filesystem::path(filename_).wstring() + L"|" + boost::lexical_cast<std::wstring>(fps_) + L"]";                \r
-       }       \r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"flash";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"flash");\r
-               return info;\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-               event_subject_.subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-               event_subject_.unsubscribe(o);\r
-       }\r
-\r
-       // flash_producer\r
-       \r
-       void tick()\r
-       {\r
-               double ratio = std::min(1.0, static_cast<double>(output_buffer_.size())/static_cast<double>(std::max(1, buffer_size_ - 1)));\r
-               double sync  = 2*ratio - ratio*ratio;\r
-               renderer_->tick(sync);\r
-       }\r
-       \r
-       void next()\r
-       {       \r
-               if(!renderer_)\r
-                       frame_buffer_.push(core::draw_frame::empty());\r
-\r
-               tick_timer_.restart();                          \r
-\r
-               if(frame_buffer_.empty())\r
-               {                                       \r
-                       tick();\r
-                       auto frame = renderer_->render();\r
-\r
-                       if(abs(renderer_->fps()/2.0 - format_desc_.fps) < 2.0) // flash == 2 * format -> interlace\r
-                       {                                       \r
-                               tick();\r
-                               if(format_desc_.field_mode != core::field_mode::progressive)\r
-                                       frame = core::draw_frame::interlace(frame, renderer_->render(), format_desc_.field_mode);\r
-                               \r
-                               frame_buffer_.push(frame);\r
-                       }\r
-                       else if(abs(renderer_->fps() - format_desc_.fps/2.0) < 2.0) // format == 2 * flash -> duplicate\r
-                       {\r
-                               frame_buffer_.push(frame);\r
-                               frame_buffer_.push(frame);\r
-                       }\r
-                       else //if(abs(renderer_->fps() - format_desc_.fps) < 0.1) // format == flash -> simple\r
-                       {\r
-                               frame_buffer_.push(frame);\r
-                       }\r
-                                               \r
-                       fps_.fetch_and_store(static_cast<int>(renderer_->fps()*100.0));                         \r
-                       graph_->set_text(print());\r
-                       \r
-                       if(renderer_->is_empty())                       \r
-                               renderer_.reset();\r
-               }\r
-\r
-               graph_->set_value("tick-time", static_cast<float>(tick_timer_.elapsed()/fps_)*0.5f);\r
-               event_subject_ << monitor::event("profiler/time") % tick_timer_.elapsed() % fps_;\r
-\r
-               output_buffer_.push(std::move(frame_buffer_.front()));\r
-               frame_buffer_.pop();\r
-       }\r
-};\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)\r
-{\r
-       auto template_host = get_template_host(format_desc);\r
-       \r
-       auto filename = env::template_folder() + L"\\" + template_host.filename;\r
-       \r
-       if(!boost::filesystem::exists(filename))\r
-               CASPAR_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(u8(filename)));     \r
-\r
-       return create_destroy_proxy(spl::make_shared<flash_producer>(frame_factory, format_desc, filename, template_host.width, template_host.height));\r
-}\r
-\r
-std::wstring find_template(const std::wstring& template_name)\r
-{\r
-       if(boost::filesystem::exists(template_name + L".ft")) \r
-               return template_name + L".ft";\r
-       \r
-       if(boost::filesystem::exists(template_name + L".ct"))\r
-               return template_name + L".ct";\r
-       \r
-       if(boost::filesystem::exists(template_name + L".swf"))\r
-               return template_name + L".swf";\r
-\r
-       return L"";\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#if defined(_MSC_VER)
+#pragma warning (disable : 4146)
+#pragma warning (disable : 4244)
+#endif
+
+#include "flash_producer.h"
+#include "FlashAxContainer.h"
+
+#include <core/video_format.h>
+
+#include <core/frame/frame.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/pixel_format.h>
+#include <core/monitor/monitor.h>
+
+#include <common/env.h>
+#include <common/executor.h>
+#include <common/lock.h>
+#include <common/diagnostics/graph.h>
+#include <common/prec_timer.h>
+#include <common/array.h>
+
+#include <boost/filesystem.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/thread.hpp>
+#include <boost/timer.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <tbb/spin_mutex.h>
+
+#include <asmlib.h>
+
+#include <functional>
+
+namespace caspar { namespace flash {
+               
+class bitmap
+{
+public:
+       bitmap(int width, int height)
+               : bmp_data_(nullptr)
+               , hdc_(CreateCompatibleDC(0), DeleteDC)
+       {       
+               BITMAPINFO info;
+               memset(&info, 0, sizeof(BITMAPINFO));
+               info.bmiHeader.biBitCount = 32;
+               info.bmiHeader.biCompression = BI_RGB;
+               info.bmiHeader.biHeight = static_cast<LONG>(-height);
+               info.bmiHeader.biPlanes = 1;
+               info.bmiHeader.biSize = sizeof(BITMAPINFO);
+               info.bmiHeader.biWidth = static_cast<LONG>(width);
+
+               bmp_.reset(CreateDIBSection(static_cast<HDC>(hdc_.get()), &info, DIB_RGB_COLORS, reinterpret_cast<void**>(&bmp_data_), 0, 0), DeleteObject);
+               SelectObject(static_cast<HDC>(hdc_.get()), bmp_.get()); 
+
+               if(!bmp_data_)
+                       CASPAR_THROW_EXCEPTION(bad_alloc());
+       }
+
+       operator HDC() {return static_cast<HDC>(hdc_.get());}
+
+       BYTE* data() { return bmp_data_;}
+       const BYTE* data() const { return bmp_data_;}
+
+private:
+       BYTE* bmp_data_;        
+       std::shared_ptr<void> hdc_;
+       std::shared_ptr<void> bmp_;
+};
+
+struct template_host
+{
+       std::wstring  video_mode;
+       std::wstring  filename;
+       int                       width;
+       int                       height;
+};
+
+template_host get_template_host(const core::video_format_desc& desc)
+{
+       try
+       {
+               std::vector<template_host> template_hosts;
+               BOOST_FOREACH(auto& xml_mapping, env::properties().get_child(L"configuration.template-hosts"))
+               {
+                       try
+                       {
+                               template_host template_host;
+                               template_host.video_mode                = xml_mapping.second.get(L"video-mode", L"");
+                               template_host.filename                  = xml_mapping.second.get(L"filename",   L"cg.fth");
+                               template_host.width                             = xml_mapping.second.get(L"width",              desc.width);
+                               template_host.height                    = xml_mapping.second.get(L"height",             desc.height);
+                               template_hosts.push_back(template_host);
+                       }
+                       catch(...){}
+               }
+
+               auto template_host_it = boost::find_if(template_hosts, [&](template_host template_host){return template_host.video_mode == desc.name;});
+               if(template_host_it == template_hosts.end())
+                       template_host_it = boost::find_if(template_hosts, [&](template_host template_host){return template_host.video_mode == L"";});
+
+               if(template_host_it != template_hosts.end())
+                       return *template_host_it;
+       }
+       catch(...){}
+               
+       template_host template_host;
+       template_host.filename = L"cg.fth";
+
+       for(auto it = boost::filesystem::directory_iterator(env::template_folder()); it != boost::filesystem::directory_iterator(); ++it)
+       {
+               if(boost::iequals(it->path().extension().wstring(), L"." + desc.name))
+               {
+                       template_host.filename = it->path().filename().wstring();
+                       break;
+               }
+       }
+
+       template_host.width =  desc.square_width;
+       template_host.height = desc.square_height;
+       return template_host;
+}
+
+class flash_renderer
+{      
+       struct com_init
+       {
+               HRESULT result_;
+
+               com_init()
+                       : result_(CoInitialize(nullptr))
+               {
+                       if(FAILED(result_))
+                               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to initialize com-context for flash-player"));
+               }
+
+               ~com_init()
+               {
+                       if(SUCCEEDED(result_))
+                               ::CoUninitialize();
+               }
+       } com_init_;
+
+       monitor::basic_subject&                                         event_subject_;
+
+       const std::wstring                                                      filename_;
+
+       const std::shared_ptr<core::frame_factory>      frame_factory_;
+       
+       CComObject<caspar::flash::FlashAxContainer>* ax_;
+       core::draw_frame                                                        head_;
+       bitmap                                                                          bmp_;
+       
+       spl::shared_ptr<diagnostics::graph>                     graph_;
+       
+       prec_timer                                                                      timer_;
+
+       const int                                                                       width_;
+       const int                                                                       height_;
+       
+public:
+       flash_renderer(monitor::basic_subject& event_subject, const spl::shared_ptr<diagnostics::graph>& graph, const std::shared_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, int width, int height) 
+               : event_subject_(event_subject)
+               , graph_(graph)
+               , filename_(filename)
+               , frame_factory_(frame_factory)
+               , ax_(nullptr)
+               , head_(core::draw_frame::empty())
+               , bmp_(width, height)
+               , width_(width)
+               , height_(height)
+       {               
+               graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
+               graph_->set_color("param", diagnostics::color(1.0f, 0.5f, 0.0f));       
+               graph_->set_color("sync", diagnostics::color(0.8f, 0.3f, 0.2f));                        
+               
+               if(FAILED(CComObject<caspar::flash::FlashAxContainer>::CreateInstance(&ax_)))
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to create FlashAxContainer"));
+               
+               ax_->set_print([this]{return print();});
+
+               if(FAILED(ax_->CreateAxControl()))
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to Create FlashAxControl"));
+               
+               CComPtr<IShockwaveFlash> spFlash;
+               if(FAILED(ax_->QueryControl(&spFlash)))
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to Query FlashAxControl"));
+                                                                                               
+               if(FAILED(spFlash->put_Playing(true)) )
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to start playing Flash"));
+
+               if(FAILED(spFlash->put_Movie(CComBSTR(filename.c_str()))))
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to Load Template Host"));
+                                                                               
+               if(FAILED(spFlash->put_ScaleMode(2)))  //Exact fit. Scale without respect to the aspect ratio.
+                       CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to Set Scale Mode"));
+                                               
+               ax_->SetSize(width_, height_);          
+
+               tick(false);
+               render();
+
+               CASPAR_LOG(info) << print() << L" Initialized.";
+       }
+
+       ~flash_renderer()
+       {               
+               if(ax_)
+               {
+                       ax_->DestroyAxControl();
+                       ax_->Release();
+               }
+               graph_->set_value("tick-time", 0.0f);
+               graph_->set_value("frame-time", 0.0f);
+               CASPAR_LOG(info) << print() << L" Uninitialized.";
+       }
+       
+       std::wstring call(const std::wstring& param)
+       {               
+               std::wstring result;
+
+               CASPAR_LOG(trace) << print() << " Call: " << param;
+
+               if(!ax_->FlashCall(param, result))
+                       CASPAR_LOG(warning) << print() << L" Flash call failed:" << param;//CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Flash function call failed.") << arg_name_info("param") << arg_value_info(narrow(param)));
+               graph_->set_tag("param");
+
+               return result;
+       }
+
+       void tick(double sync)
+       {               
+               const float frame_time = 1.0f/ax_->GetFPS();
+
+               if(sync > 0.00001)                      
+                       timer_.tick(frame_time*sync); // This will block the thread.
+               else
+                       graph_->set_tag("sync");
+
+               graph_->set_value("sync", sync);
+               event_subject_ << monitor::event("sync") % sync;
+               
+               ax_->Tick();
+                                       
+               MSG msg;
+               while(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) // DO NOT REMOVE THE MESSAGE DISPATCH LOOP. Without this some stuff doesn't work!  
+               {
+                       if(msg.message == WM_TIMER && msg.wParam == 3 && msg.lParam == 0) // We tick this inside FlashAxContainer
+                               continue;
+                       
+                       TranslateMessage(&msg);
+                       DispatchMessage(&msg);                  
+               }
+       }
+       
+       core::draw_frame render()
+       {                       
+               const float frame_time = 1.0f/fps();
+
+               boost::timer frame_timer;
+
+               if(ax_->InvalidRect())
+               {                       
+                       A_memset(bmp_.data(), 0, width_*height_*4);
+                       ax_->DrawControl(bmp_);
+               
+                       core::pixel_format_desc desc = core::pixel_format::bgra;
+                       desc.planes.push_back(core::pixel_format_desc::plane(width_, height_, 4));
+                       auto frame = frame_factory_->create_frame(this, desc);
+
+                       A_memcpy(frame.image_data(0).begin(), bmp_.data(), width_*height_*4);
+                       head_ = core::draw_frame(std::move(frame));     
+               }               
+                                                                               
+               graph_->set_value("frame-time", static_cast<float>(frame_timer.elapsed()/frame_time)*0.5f);
+               event_subject_ << monitor::event("renderer/profiler/time") % frame_timer.elapsed() % frame_time;
+               return head_;
+       }
+       
+       bool is_empty() const
+       {
+               return ax_->IsEmpty();
+       }
+
+       double fps() const
+       {
+               return ax_->GetFPS();   
+       }
+       
+       std::wstring print()
+       {
+               return L"flash-player[" + boost::filesystem::wpath(filename_).filename().wstring() 
+                                 + L"|" + boost::lexical_cast<std::wstring>(width_)
+                                 + L"x" + boost::lexical_cast<std::wstring>(height_)
+                                 + L"]";               
+       }
+};
+
+struct flash_producer : public core::frame_producer_base
+{      
+       monitor::basic_subject                                                  event_subject_;
+       const std::wstring                                                              filename_;      
+       const spl::shared_ptr<core::frame_factory>              frame_factory_;
+       const core::video_format_desc                                   format_desc_;
+       const int                                                                               width_;
+       const int                                                                               height_;
+       const int                                                                               buffer_size_;
+
+       tbb::atomic<int>                                                                fps_;
+
+       spl::shared_ptr<diagnostics::graph>                             graph_;
+
+       std::queue<core::draw_frame>                                    frame_buffer_;
+       tbb::concurrent_bounded_queue<core::draw_frame> output_buffer_;
+                               
+       boost::timer                                                                    tick_timer_;
+       std::unique_ptr<flash_renderer>                                 renderer_;
+       
+       executor                                                                                executor_;      
+public:
+       flash_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::wstring& filename, int width, int height) 
+               : filename_(filename)           
+               , frame_factory_(frame_factory)
+               , format_desc_(format_desc)
+               , width_(width > 0 ? width : format_desc.width)
+               , height_(height > 0 ? height : format_desc.height)
+               , buffer_size_(env::properties().get(L"configuration.flash.buffer-depth", format_desc.fps > 30.0 ? 4 : 2))
+               , executor_(L"flash_producer")
+       {       
+               fps_ = 0;
+        
+               graph_->set_color("buffer-size", diagnostics::color(1.0f, 1.0f, 0.0f));
+               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));
+               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.9f));
+               graph_->set_text(print());
+               diagnostics::register_graph(graph_);
+
+               CASPAR_LOG(info) << print() << L" Initialized";
+       }
+
+       ~flash_producer()
+       {
+               executor_.invoke([this]
+               {
+                       renderer_.reset();
+               }, task_priority::high_priority);
+       }
+
+       // frame_producer
+               
+       core::draw_frame receive_impl() override
+       {                                       
+               auto frame = core::draw_frame::late();
+               
+               if(output_buffer_.try_pop(frame))                       
+                       executor_.begin_invoke(std::bind(&flash_producer::next, this));         
+               else            
+                       graph_->set_tag("late-frame");          
+                               
+               event_subject_ << monitor::event("host/path")   % filename_
+                                          << monitor::event("host/width")      % width_
+                                          << monitor::event("host/height") % height_
+                                          << monitor::event("host/fps")        % fps_
+                                          << monitor::event("buffer")          % output_buffer_.size() % buffer_size_;
+
+               return frame;
+       }
+               
+       boost::unique_future<std::wstring> call(const std::wstring& param) override
+       {       
+               return executor_.begin_invoke([this, param]() -> std::wstring
+               {                       
+                       try
+                       {
+                               if(!renderer_)
+                               {
+                                       renderer_.reset(new flash_renderer(event_subject_, graph_, frame_factory_, filename_, width_, height_));
+
+                                       while(output_buffer_.size() < buffer_size_)
+                                               output_buffer_.push(core::draw_frame::empty());
+                               }
+
+                               return renderer_->call(param);  
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                               renderer_.reset(nullptr);
+                       }
+
+                       return L"";
+               });
+       }
+               
+       std::wstring print() const override
+       { 
+               return L"flash[" + boost::filesystem::path(filename_).wstring() + L"|" + boost::lexical_cast<std::wstring>(fps_) + L"]";                
+       }       
+
+       std::wstring name() const override
+       {
+               return L"flash";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"flash");
+               return info;
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override
+       {
+               event_subject_.subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override
+       {
+               event_subject_.unsubscribe(o);
+       }
+
+       // flash_producer
+       
+       void tick()
+       {
+               double ratio = std::min(1.0, static_cast<double>(output_buffer_.size())/static_cast<double>(std::max(1, buffer_size_ - 1)));
+               double sync  = 2*ratio - ratio*ratio;
+               renderer_->tick(sync);
+       }
+       
+       void next()
+       {       
+               if(!renderer_)
+                       frame_buffer_.push(core::draw_frame::empty());
+
+               tick_timer_.restart();                          
+
+               if(frame_buffer_.empty())
+               {                                       
+                       tick();
+                       auto frame = renderer_->render();
+
+                       if(abs(renderer_->fps()/2.0 - format_desc_.fps) < 2.0) // flash == 2 * format -> interlace
+                       {                                       
+                               tick();
+                               if(format_desc_.field_mode != core::field_mode::progressive)
+                                       frame = core::draw_frame::interlace(frame, renderer_->render(), format_desc_.field_mode);
+                               
+                               frame_buffer_.push(frame);
+                       }
+                       else if(abs(renderer_->fps() - format_desc_.fps/2.0) < 2.0) // format == 2 * flash -> duplicate
+                       {
+                               frame_buffer_.push(frame);
+                               frame_buffer_.push(frame);
+                       }
+                       else //if(abs(renderer_->fps() - format_desc_.fps) < 0.1) // format == flash -> simple
+                       {
+                               frame_buffer_.push(frame);
+                       }
+                                               
+                       fps_.fetch_and_store(static_cast<int>(renderer_->fps()*100.0));                         
+                       graph_->set_text(print());
+                       
+                       if(renderer_->is_empty())                       
+                               renderer_.reset();
+               }
+
+               graph_->set_value("tick-time", static_cast<float>(tick_timer_.elapsed()/fps_)*0.5f);
+               event_subject_ << monitor::event("profiler/time") % tick_timer_.elapsed() % fps_;
+
+               output_buffer_.push(std::move(frame_buffer_.front()));
+               frame_buffer_.pop();
+       }
+};
+
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+{
+       auto template_host = get_template_host(format_desc);
+       
+       auto filename = env::template_folder() + L"\\" + template_host.filename;
+       
+       if(!boost::filesystem::exists(filename))
+               CASPAR_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(u8(filename)));     
+
+       return create_destroy_proxy(spl::make_shared<flash_producer>(frame_factory, format_desc, filename, template_host.width, template_host.height));
+}
+
+std::wstring find_template(const std::wstring& template_name)
+{
+       if(boost::filesystem::exists(template_name + L".ft")) 
+               return template_name + L".ft";
+       
+       if(boost::filesystem::exists(template_name + L".ct"))
+               return template_name + L".ct";
+       
+       if(boost::filesystem::exists(template_name + L".swf"))
+               return template_name + L".swf";
+
+       return L"";
+}
+
 }}
\ No newline at end of file
index 6abe203baf14acc1e3fb3beea584a09b91f902f2..650909b640b36f5b66d68e16a4f31f5eb1572ab3 100644 (file)
@@ -1,37 +1,37 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <core/producer/frame_producer.h>\r
-\r
-#include <common/memory.h>\r
-\r
-#include <vector>\r
-#include <string>\r
-\r
-namespace caspar { namespace flash {\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);\r
-\r
-std::wstring find_template(const std::wstring& templateName);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <core/producer/frame_producer.h>
+
+#include <common/memory.h>
+
+#include <vector>
+#include <string>
+
+namespace caspar { namespace flash {
+
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+
+std::wstring find_template(const std::wstring& templateName);
+
 }}
\ No newline at end of file
index de325157cace6ae5cec7ae09f3be92a78bc3b8b4..6a52bbbf49afb19b273ff41cbafbbdb2cc695ff0 100644 (file)
@@ -1,95 +1,95 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../StdAfx.h"\r
-\r
-#include <common/except.h>\r
-\r
-#include <zlib.h> // Compiled into FreeImage\r
-\r
-#include <fstream>\r
-#include <streambuf>\r
-\r
-namespace caspar { namespace flash {\r
-       \r
-std::vector<char> decompress_one_file(const std::vector<char>& in_data, uLong buf_size = 5000000)\r
-{\r
-       if(buf_size > 300*1000000)\r
-               CASPAR_THROW_EXCEPTION(file_read_error());\r
-\r
-       std::vector<char> out_data(buf_size, 0);\r
-\r
-       auto ret = uncompress(reinterpret_cast<Bytef*>(out_data.data()), &buf_size, reinterpret_cast<const Bytef*>(in_data.data()), static_cast<uLong>(in_data.size()));\r
-\r
-       if(ret == Z_BUF_ERROR)\r
-               return decompress_one_file(in_data, buf_size*2);\r
-\r
-       if(ret != Z_OK)\r
-               CASPAR_THROW_EXCEPTION(file_read_error());\r
-\r
-       out_data.resize(buf_size);\r
-\r
-       return out_data;\r
-}\r
-\r
-std::string read_template_meta_info(const std::wstring& filename)\r
-{\r
-       auto file = std::fstream(filename, std::ios::in | std::ios::binary);\r
-\r
-       if(!file)\r
-               CASPAR_THROW_EXCEPTION(file_read_error());\r
-       \r
-       char head[4] = {};\r
-       file.read(head, 3);\r
-       \r
-       std::vector<char> data;\r
-       \r
-       file.seekg(0, std::ios::end);   \r
-       data.reserve(static_cast<size_t>(file.tellg()));\r
-       file.seekg(0, std::ios::beg);\r
-\r
-       if(strcmp(head, "CWS") == 0)\r
-       {\r
-               file.seekg(8, std::ios::beg);\r
-               std::copy((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>(), std::back_inserter(data));\r
-               data = decompress_one_file(data);\r
-       }\r
-       else\r
-       {\r
-               file.seekg(0, std::ios::end);   \r
-               data.reserve(static_cast<size_t>(file.tellg()));\r
-               file.seekg(0, std::ios::beg);\r
-\r
-               std::copy((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>(), std::back_inserter(data));\r
-       }\r
-       \r
-       std::string beg_str = "<template version";\r
-       std::string end_str = "</template>";\r
-       auto beg_it = std::find_end(data.begin(), data.end(), beg_str.begin(), beg_str.end());\r
-       auto end_it = std::find_end(beg_it, data.end(), end_str.begin(), end_str.end());\r
-       \r
-       if(beg_it == data.end() || end_it == data.end())\r
-               CASPAR_THROW_EXCEPTION(file_read_error());\r
-                       \r
-       return std::string(beg_it, end_it+end_str.size());\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../StdAfx.h"
+
+#include <common/except.h>
+
+#include <zlib.h> // Compiled into FreeImage
+
+#include <fstream>
+#include <streambuf>
+
+namespace caspar { namespace flash {
+       
+std::vector<char> decompress_one_file(const std::vector<char>& in_data, uLong buf_size = 5000000)
+{
+       if(buf_size > 300*1000000)
+               CASPAR_THROW_EXCEPTION(file_read_error());
+
+       std::vector<char> out_data(buf_size, 0);
+
+       auto ret = uncompress(reinterpret_cast<Bytef*>(out_data.data()), &buf_size, reinterpret_cast<const Bytef*>(in_data.data()), static_cast<uLong>(in_data.size()));
+
+       if(ret == Z_BUF_ERROR)
+               return decompress_one_file(in_data, buf_size*2);
+
+       if(ret != Z_OK)
+               CASPAR_THROW_EXCEPTION(file_read_error());
+
+       out_data.resize(buf_size);
+
+       return out_data;
+}
+
+std::string read_template_meta_info(const std::wstring& filename)
+{
+       auto file = std::fstream(filename, std::ios::in | std::ios::binary);
+
+       if(!file)
+               CASPAR_THROW_EXCEPTION(file_read_error());
+       
+       char head[4] = {};
+       file.read(head, 3);
+       
+       std::vector<char> data;
+       
+       file.seekg(0, std::ios::end);   
+       data.reserve(static_cast<size_t>(file.tellg()));
+       file.seekg(0, std::ios::beg);
+
+       if(strcmp(head, "CWS") == 0)
+       {
+               file.seekg(8, std::ios::beg);
+               std::copy((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>(), std::back_inserter(data));
+               data = decompress_one_file(data);
+       }
+       else
+       {
+               file.seekg(0, std::ios::end);   
+               data.reserve(static_cast<size_t>(file.tellg()));
+               file.seekg(0, std::ios::beg);
+
+               std::copy((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>(), std::back_inserter(data));
+       }
+       
+       std::string beg_str = "<template version";
+       std::string end_str = "</template>";
+       auto beg_it = std::find_end(data.begin(), data.end(), beg_str.begin(), beg_str.end());
+       auto end_it = std::find_end(beg_it, data.end(), end_str.begin(), end_str.end());
+       
+       if(beg_it == data.end() || end_it == data.end())
+               CASPAR_THROW_EXCEPTION(file_read_error());
+                       
+       return std::string(beg_it, end_it+end_str.size());
+}
+
 }}
\ No newline at end of file
index cdd35ee4eada31ae487af03d0e4140a6b42d36ca..f15293950793cc7cd67c2dc9928de11c3367711f 100644 (file)
@@ -1,30 +1,30 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace flash {\r
-\r
-std::string read_template_meta_info(const std::wstring& filename);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <string>
+
+namespace caspar { namespace flash {
+
+std::string read_template_meta_info(const std::wstring& filename);
+
 }}
\ No newline at end of file
index fe06d63d415c6d093ca670ba662e78ea7743a81a..b5b3767df78b804f9a914406cf0656c65aee0ea5 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "image_consumer.h"\r
-\r
-#include <common/except.h>\r
-#include <common/env.h>\r
-#include <common/log.h>\r
-#include <common/utf.h>\r
-#include <common/array.h>\r
-\r
-#include <core/consumer/frame_consumer.h>\r
-#include <core/video_format.h>\r
-#include <core/frame/frame.h>\r
-\r
-#include <boost/date_time/posix_time/posix_time.hpp>\r
-#include <boost/thread.hpp>\r
-\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <asmlib.h>\r
-\r
-#include <FreeImage.h>\r
-\r
-#include <vector>\r
-\r
-namespace caspar { namespace image {\r
-       \r
-struct image_consumer : public core::frame_consumer\r
-{\r
-public:\r
-\r
-       // frame_consumer\r
-\r
-       void initialize(const core::video_format_desc&, int) override\r
-       {\r
-       }\r
-       \r
-       bool send(core::const_frame frame) override\r
-       {                               \r
-               boost::thread async([frame]\r
-               {\r
-                       try\r
-                       {\r
-                               auto filename = u8(env::data_folder()) +  boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time()) + ".png";\r
-\r
-                               auto bitmap = std::shared_ptr<FIBITMAP>(FreeImage_Allocate(static_cast<int>(frame.width()), static_cast<int>(frame.height()), 32), FreeImage_Unload);\r
-                               A_memcpy(FreeImage_GetBits(bitmap.get()), frame.image_data().begin(), frame.image_data().size());\r
-                               FreeImage_FlipVertical(bitmap.get());\r
-                               FreeImage_Save(FIF_PNG, bitmap.get(), filename.c_str(), 0);\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }\r
-               });\r
-               async.detach();\r
-\r
-               return false;\r
-       }\r
-\r
-       std::wstring print() const override\r
-       {\r
-               return L"image[]";\r
-       }\r
-       \r
-       std::wstring name() const override\r
-       {\r
-               return L"image";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"image");\r
-               return info;\r
-       }\r
-\r
-       int buffer_depth() const override\r
-       {\r
-               return 0;\r
-       }\r
-\r
-       int index() const override\r
-       {\r
-               return 100;\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }       \r
-};\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)\r
-{\r
-       if(params.size() < 1 || params[0] != L"IMAGE")\r
-               return core::frame_consumer::empty();\r
-\r
-       return spl::make_shared<image_consumer>();\r
-}\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "image_consumer.h"
+
+#include <common/except.h>
+#include <common/env.h>
+#include <common/log.h>
+#include <common/utf.h>
+#include <common/array.h>
+
+#include <core/consumer/frame_consumer.h>
+#include <core/video_format.h>
+#include <core/frame/frame.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread.hpp>
+
+#include <tbb/concurrent_queue.h>
+
+#include <asmlib.h>
+
+#include <FreeImage.h>
+
+#include <vector>
+
+namespace caspar { namespace image {
+       
+struct image_consumer : public core::frame_consumer
+{
+public:
+
+       // frame_consumer
+
+       void initialize(const core::video_format_desc&, int) override
+       {
+       }
+       
+       bool send(core::const_frame frame) override
+       {                               
+               boost::thread async([frame]
+               {
+                       try
+                       {
+                               auto filename = u8(env::data_folder()) +  boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time()) + ".png";
+
+                               auto bitmap = std::shared_ptr<FIBITMAP>(FreeImage_Allocate(static_cast<int>(frame.width()), static_cast<int>(frame.height()), 32), FreeImage_Unload);
+                               A_memcpy(FreeImage_GetBits(bitmap.get()), frame.image_data().begin(), frame.image_data().size());
+                               FreeImage_FlipVertical(bitmap.get());
+                               FreeImage_Save(FIF_PNG, bitmap.get(), filename.c_str(), 0);
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }
+               });
+               async.detach();
+
+               return false;
+       }
+
+       std::wstring print() const override
+       {
+               return L"image[]";
+       }
+       
+       std::wstring name() const override
+       {
+               return L"image";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"image");
+               return info;
+       }
+
+       int buffer_depth() const override
+       {
+               return 0;
+       }
+
+       int index() const override
+       {
+               return 100;
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }       
+};
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+{
+       if(params.size() < 1 || params[0] != L"IMAGE")
+               return core::frame_consumer::empty();
+
+       return spl::make_shared<image_consumer>();
+}
+
+}}
index 0df10c9fc5e8cd4b7397c9c428d78f8984db20a0..260ed3ede5dbe3bec17eb29d534b3cea3868de49 100644 (file)
@@ -1,43 +1,43 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar { \r
-\r
-namespace core {\r
-       class frame_consumer;\r
-}\r
-\r
-namespace image {\r
-       \r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <core/video_format.h>
+
+#include <boost/property_tree/ptree.hpp>
+
+#include <string>
+#include <vector>
+
+namespace caspar { 
+
+namespace core {
+       class frame_consumer;
+}
+
+namespace image {
+       
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
+
 }}
\ No newline at end of file
index 6faf216191759fc55fb5ac19f93c83a84b9876c0..b738801cef39152954e25425f22684b7fa28e9d2 100644 (file)
@@ -1,59 +1,59 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "image.h"\r
-\r
-#include "producer/image_producer.h"\r
-#include "producer/image_scroll_producer.h"\r
-#include "consumer/image_consumer.h"\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/consumer/frame_consumer.h>\r
-\r
-#include <common/utf.h>\r
-\r
-#include <FreeImage.h>\r
-\r
-namespace caspar { namespace image {\r
-\r
-void init()\r
-{\r
-       FreeImage_Initialise();\r
-       core::register_producer_factory(create_scroll_producer);\r
-       core::register_producer_factory(create_producer);\r
-       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});\r
-}\r
-\r
-void uninit()\r
-{\r
-       FreeImage_DeInitialise();\r
-       core::register_producer_factory(create_scroll_producer);\r
-       core::register_producer_factory(create_producer);\r
-       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});\r
-}\r
-\r
-\r
-std::wstring version()\r
-{\r
-       return u16(FreeImage_GetVersion());\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "image.h"
+
+#include "producer/image_producer.h"
+#include "producer/image_scroll_producer.h"
+#include "consumer/image_consumer.h"
+
+#include <core/producer/frame_producer.h>
+#include <core/consumer/frame_consumer.h>
+
+#include <common/utf.h>
+
+#include <FreeImage.h>
+
+namespace caspar { namespace image {
+
+void init()
+{
+       FreeImage_Initialise();
+       core::register_producer_factory(create_scroll_producer);
+       core::register_producer_factory(create_producer);
+       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+}
+
+void uninit()
+{
+       FreeImage_DeInitialise();
+       core::register_producer_factory(create_scroll_producer);
+       core::register_producer_factory(create_producer);
+       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+}
+
+
+std::wstring version()
+{
+       return u16(FreeImage_GetVersion());
+}
+
 }}
\ No newline at end of file
index 29711b8f6f7c382cbab82fce5bdea2559035dddd..fb9e19fdbf4023110f910887cd433dfc88449c51 100644 (file)
@@ -1,33 +1,33 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace image {\r
-\r
-void init();\r
-void uninit();\r
-\r
-std::wstring version();\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <string>
+
+namespace caspar { namespace image {
+
+void init();
+void uninit();
+
+std::wstring version();
+
 }}
\ No newline at end of file
index 52793e7cc4c2de1f5d3a44526a77253b13788e0f..059decfa8b96f9425172f8dd8c3ec3299d68d666 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "image_producer.h"\r
-\r
-#include "../util/image_loader.h"\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/frame/frame.h>\r
-#include <core/frame/draw_frame.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/monitor/monitor.h>\r
-\r
-#include <common/env.h>\r
-#include <common/log.h>\r
-#include <common/array.h>\r
-\r
-#include <boost/assign.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-#include <algorithm>\r
-\r
-using namespace boost::assign;\r
-\r
-namespace caspar { namespace image {\r
-\r
-struct image_producer : public core::frame_producer_base\r
-{      \r
-       monitor::basic_subject  event_subject_;\r
-       const std::wstring              filename_;\r
-       core::draw_frame                frame_;\r
-       \r
-       explicit image_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const std::wstring& filename) \r
-               : filename_(filename)\r
-               , frame_(core::draw_frame::empty())     \r
-       {\r
-               auto bitmap = load_image(filename_);\r
-               FreeImage_FlipVertical(bitmap.get());\r
-               \r
-               core::pixel_format_desc desc = core::pixel_format::bgra;\r
-               desc.planes.push_back(core::pixel_format_desc::plane(FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()), 4));\r
-               auto frame = frame_factory->create_frame(this, desc);\r
-\r
-               std::copy_n(FreeImage_GetBits(bitmap.get()), frame.image_data(0).size(), frame.image_data(0).begin());\r
-               frame_ = core::draw_frame(std::move(frame));\r
-\r
-               CASPAR_LOG(info) << print() << L" Initialized";\r
-       }\r
-       \r
-       // frame_producer\r
-\r
-       core::draw_frame receive_impl() override\r
-       {\r
-               event_subject_ << monitor::event("file/path") % filename_;\r
-\r
-               return frame_;\r
-       }\r
-                       \r
-       std::wstring print() const override\r
-       {\r
-               return L"image_producer[" + filename_ + L"]";\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"image";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"image");\r
-               info.add(L"filename", filename_);\r
-               return info;\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override                                                                                                                     \r
-       {\r
-               return event_subject_.subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override           \r
-       {\r
-               return event_subject_.unsubscribe(o);\r
-       }\r
-};\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)\r
-{\r
-       static const std::vector<std::wstring> extensions = list_of(L".png")(L".tga")(L".bmp")(L".jpg")(L".jpeg")(L".gif")(L".tiff")(L".tif")(L".jp2")(L".jpx")(L".j2k")(L".j2c");\r
-       std::wstring filename = env::media_folder() + L"\\" + params[0];\r
-       \r
-       auto ext = std::find_if(extensions.begin(), extensions.end(), [&](const std::wstring& ex) -> bool\r
-               {                       \r
-                       return boost::filesystem::is_regular_file(boost::filesystem::path(filename).replace_extension(ex));\r
-               });\r
-\r
-       if(ext == extensions.end())\r
-               return core::frame_producer::empty();\r
-\r
-       return spl::make_shared<image_producer>(frame_factory, filename + *ext);\r
-}\r
-\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "image_producer.h"
+
+#include "../util/image_loader.h"
+
+#include <core/video_format.h>
+
+#include <core/producer/frame_producer.h>
+#include <core/frame/frame.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/pixel_format.h>
+#include <core/monitor/monitor.h>
+
+#include <common/env.h>
+#include <common/log.h>
+#include <common/array.h>
+
+#include <boost/assign.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/property_tree/ptree.hpp>
+
+#include <algorithm>
+
+using namespace boost::assign;
+
+namespace caspar { namespace image {
+
+struct image_producer : public core::frame_producer_base
+{      
+       monitor::basic_subject  event_subject_;
+       const std::wstring              filename_;
+       core::draw_frame                frame_;
+       
+       explicit image_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const std::wstring& filename) 
+               : filename_(filename)
+               , frame_(core::draw_frame::empty())     
+       {
+               auto bitmap = load_image(filename_);
+               FreeImage_FlipVertical(bitmap.get());
+               
+               core::pixel_format_desc desc = core::pixel_format::bgra;
+               desc.planes.push_back(core::pixel_format_desc::plane(FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()), 4));
+               auto frame = frame_factory->create_frame(this, desc);
+
+               std::copy_n(FreeImage_GetBits(bitmap.get()), frame.image_data(0).size(), frame.image_data(0).begin());
+               frame_ = core::draw_frame(std::move(frame));
+
+               CASPAR_LOG(info) << print() << L" Initialized";
+       }
+       
+       // frame_producer
+
+       core::draw_frame receive_impl() override
+       {
+               event_subject_ << monitor::event("file/path") % filename_;
+
+               return frame_;
+       }
+                       
+       std::wstring print() const override
+       {
+               return L"image_producer[" + filename_ + L"]";
+       }
+
+       std::wstring name() const override
+       {
+               return L"image";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"image");
+               info.add(L"filename", filename_);
+               return info;
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override                                                                                                                     
+       {
+               return event_subject_.subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override           
+       {
+               return event_subject_.unsubscribe(o);
+       }
+};
+
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+{
+       static const std::vector<std::wstring> extensions = list_of(L".png")(L".tga")(L".bmp")(L".jpg")(L".jpeg")(L".gif")(L".tiff")(L".tif")(L".jp2")(L".jpx")(L".j2k")(L".j2c");
+       std::wstring filename = env::media_folder() + L"\\" + params[0];
+       
+       auto ext = std::find_if(extensions.begin(), extensions.end(), [&](const std::wstring& ex) -> bool
+               {                       
+                       return boost::filesystem::is_regular_file(boost::filesystem::path(filename).replace_extension(ex));
+               });
+
+       if(ext == extensions.end())
+               return core::frame_producer::empty();
+
+       return spl::make_shared<image_producer>(frame_factory, filename + *ext);
+}
+
+
 }}
\ No newline at end of file
index cd5cede62673836004c621ba8bb13d75506f9038..b994fd46165be870a8a87d6be2bc43180e284e26 100644 (file)
@@ -1,33 +1,33 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <core/producer/frame_producer.h>\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar { namespace image {\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <core/producer/frame_producer.h>
+
+#include <string>
+#include <vector>
+
+namespace caspar { namespace image {
+
+spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+
 }}
\ No newline at end of file
index 0a268bd73cf9c6471820588bb1832570eac6352c..097451d30165a89233f00f249b1b5350bf2116ab 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-* Author: Helge Norberg, helge.norberg@svt.se\r
-*/\r
-\r
-#include "image_scroll_producer.h"\r
-\r
-#include "../util/image_loader.h"\r
-#include "../util/image_view.h"\r
-#include "../util/image_algorithms.h"\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <core/frame/frame.h>\r
-#include <core/frame/draw_frame.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/frame_transform.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/monitor/monitor.h>\r
-\r
-#include <common/env.h>\r
-#include <common/log.h>\r
-#include <common/except.h>\r
-#include <common/array.h>\r
-#include <common/tweener.h>\r
-\r
-#include <boost/assign.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/scoped_array.hpp>\r
-\r
-#include <algorithm>\r
-#include <array>\r
-\r
-using namespace boost::assign;\r
-\r
-namespace caspar { namespace image {\r
-               \r
-struct image_scroll_producer : public core::frame_producer_base\r
-{      \r
-       monitor::basic_subject                  event_subject_;\r
-\r
-       const std::wstring                              filename_;\r
-       std::vector<core::draw_frame>   frames_;\r
-       core::video_format_desc                 format_desc_;\r
-       int                                                             width_;\r
-       int                                                             height_;\r
-\r
-       double                                                  delta_;\r
-       double                                                  speed_;\r
-\r
-       int                                                             start_offset_x_;\r
-       int                                                             start_offset_y_;\r
-       bool                                                    progressive_;\r
-       \r
-       explicit image_scroll_producer(\r
-               const spl::shared_ptr<core::frame_factory>& frame_factory, \r
-               const core::video_format_desc& format_desc, \r
-               const std::wstring& filename, \r
-               double speed,\r
-               double duration,\r
-               int motion_blur_px = 0,\r
-               bool premultiply_with_alpha = false,\r
-               bool progressive = false)\r
-               : filename_(filename)\r
-               , delta_(0)\r
-               , format_desc_(format_desc)\r
-               , speed_(speed)\r
-               , start_offset_x_(0)\r
-               , start_offset_y_(0)\r
-               , progressive_(progressive)\r
-       {\r
-               auto bitmap = load_image(filename_);\r
-               FreeImage_FlipVertical(bitmap.get());\r
-\r
-               width_  = FreeImage_GetWidth(bitmap.get());\r
-               height_ = FreeImage_GetHeight(bitmap.get());\r
-\r
-               bool vertical = width_ == format_desc_.width;\r
-               bool horizontal = height_ == format_desc_.height;\r
-\r
-               if (!vertical && !horizontal)\r
-                       BOOST_THROW_EXCEPTION(\r
-                               caspar::invalid_argument() << msg_info("Neither width nor height matched the video resolution"));\r
-\r
-               if (vertical)\r
-               {\r
-                       if (duration != 0.0)\r
-                       {\r
-                               double total_num_pixels = format_desc_.height * 2 + height_;\r
-\r
-                               speed_ = total_num_pixels / (duration * format_desc_.fps * static_cast<double>(format_desc_.field_count));\r
-\r
-                               if (std::abs(speed_) > 1.0)\r
-                                       speed_ = std::ceil(speed_);\r
-                       }\r
-\r
-                       if (speed_ < 0.0)\r
-                       {\r
-                               start_offset_y_ = height_ + format_desc_.height;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       if (duration != 0.0)\r
-                       {\r
-                               double total_num_pixels = format_desc_.width * 2 + width_;\r
-\r
-                               speed_ = total_num_pixels / (duration * format_desc_.fps * static_cast<double>(format_desc_.field_count));\r
-\r
-                               if (std::abs(speed_) > 1.0)\r
-                                       speed_ = std::ceil(speed_);\r
-                       }\r
-\r
-                       if (speed_ > 0.0)\r
-                               start_offset_x_ = format_desc_.width - (width_ % format_desc_.width);\r
-                       else\r
-                               start_offset_x_ = format_desc_.width - (width_ % format_desc_.width) + width_ + format_desc_.width;\r
-               }\r
-\r
-               auto bytes = FreeImage_GetBits(bitmap.get());\r
-               auto count = width_*height_*4;\r
-               image_view<bgra_pixel> original_view(bytes, width_, height_);\r
-\r
-               if (premultiply_with_alpha)\r
-                       premultiply(original_view);\r
-\r
-               boost::scoped_array<uint8_t> blurred_copy;\r
-\r
-               if (motion_blur_px > 0)\r
-               {\r
-                       double angle = 3.14159265 / 2; // Up\r
-\r
-                       if (horizontal && speed_ < 0)\r
-                               angle *= 2; // Left\r
-                       else if (vertical && speed > 0)\r
-                               angle *= 3; // Down\r
-                       else if (horizontal && speed  > 0)\r
-                               angle = 0.0; // Right\r
-\r
-                       blurred_copy.reset(new uint8_t[count]);\r
-                       image_view<bgra_pixel> blurred_view(blurred_copy.get(), width_, height_);\r
-                       core::tweener blur_tweener(L"easeInQuad");\r
-                       blur(original_view, blurred_view, angle, motion_blur_px, blur_tweener);\r
-                       bytes = blurred_copy.get();\r
-                       bitmap.reset();\r
-               }\r
-\r
-               if (vertical)\r
-               {\r
-                       int n = 1;\r
-\r
-                       while(count > 0)\r
-                       {\r
-                               core::pixel_format_desc desc = core::pixel_format::bgra;\r
-                               desc.planes.push_back(core::pixel_format_desc::plane(width_, format_desc_.height, 4));\r
-                               auto frame = frame_factory->create_frame(reinterpret_cast<void*>(rand()), desc);\r
-\r
-                               if(count >= frame.image_data(0).size())\r
-                               {       \r
-                                       std::copy_n(bytes + count - frame.image_data(0).size(), frame.image_data(0).size(), frame.image_data(0).begin());\r
-                                       count -= static_cast<int>(frame.image_data(0).size());\r
-                               }\r
-                               else\r
-                               {\r
-                                       memset(frame.image_data(0).begin(), 0, frame.image_data(0).size());     \r
-                                       std::copy_n(bytes, count, frame.image_data(0).begin() + format_desc_.size - count);\r
-                                       count = 0;\r
-                               }\r
-\r
-                               core::draw_frame draw_frame(std::move(frame));\r
-\r
-                               // Set the relative position to the other image fragments\r
-                               draw_frame.transform().image_transform.fill_translation[1] = - n++;\r
-\r
-                               frames_.push_back(draw_frame);\r
-                       }\r
-               }\r
-               else if (horizontal)\r
-               {\r
-                       int i = 0;\r
-                       while(count > 0)\r
-                       {\r
-                               core::pixel_format_desc desc = core::pixel_format::bgra;\r
-                               desc.planes.push_back(core::pixel_format_desc::plane(format_desc_.width, height_, 4));\r
-                               auto frame = frame_factory->create_frame(reinterpret_cast<void*>(rand()), desc);\r
-                               if(count >= frame.image_data(0).size())\r
-                               {       \r
-                                       for(int y = 0; y < height_; ++y)\r
-                                               std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, format_desc_.width*4, frame.image_data(0).begin() + y * format_desc_.width*4);\r
-                                       \r
-                                       ++i;\r
-                                       count -= static_cast<int>(frame.image_data(0).size());\r
-                               }\r
-                               else\r
-                               {\r
-                                       memset(frame.image_data(0).begin(), 0, frame.image_data(0).size());     \r
-                                       auto width2 = width_ % format_desc_.width;\r
-                                       for(int y = 0; y < height_; ++y)\r
-                                               std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, width2*4, frame.image_data(0).begin() + y * format_desc_.width*4);\r
-\r
-                                       count = 0;\r
-                               }\r
-                       \r
-                               frames_.push_back(core::draw_frame(std::move(frame)));\r
-                       }\r
-\r
-                       std::reverse(frames_.begin(), frames_.end());\r
-\r
-                       // Set the relative positions of the image fragments.\r
-                       for (size_t n = 0; n < frames_.size(); ++n)\r
-                       {\r
-                               double translation = - (static_cast<double>(n) + 1.0);\r
-                               frames_[n].transform().image_transform.fill_translation[0] = translation;\r
-                       }\r
-               }\r
-\r
-               CASPAR_LOG(info) << print() << L" Initialized";\r
-       }\r
-\r
-       std::vector<core::draw_frame> get_visible()\r
-       {\r
-               std::vector<core::draw_frame> result;\r
-               result.reserve(frames_.size());\r
-\r
-               BOOST_FOREACH(auto& frame, frames_)\r
-               {\r
-                       auto& fill_translation = frame.transform().image_transform.fill_translation;\r
-\r
-                       if (width_ == format_desc_.width)\r
-                       {\r
-                               auto motion_offset_in_screens = (static_cast<double>(start_offset_y_) + delta_) / static_cast<double>(format_desc_.height);\r
-                               auto vertical_offset = fill_translation[1] + motion_offset_in_screens;\r
-\r
-                               if (vertical_offset < -1.0 || vertical_offset > 1.0)\r
-                               {\r
-                                       continue;\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               auto motion_offset_in_screens = (static_cast<double>(start_offset_x_) + delta_) / static_cast<double>(format_desc_.width);\r
-                               auto horizontal_offset = fill_translation[0] + motion_offset_in_screens;\r
-\r
-                               if (horizontal_offset < -1.0 || horizontal_offset > 1.0)\r
-                               {\r
-                                       continue;\r
-                               }\r
-                       }\r
-\r
-                       result.push_back(frame);\r
-               }\r
-\r
-               return std::move(result);\r
-       }\r
-       \r
-       // frame_producer\r
-       core::draw_frame render_frame(bool allow_eof)\r
-       {\r
-               if(frames_.empty())\r
-                       return core::draw_frame::empty();\r
-               \r
-               core::draw_frame result(get_visible());\r
-               auto& fill_translation = result.transform().image_transform.fill_translation;\r
-\r
-               if (width_ == format_desc_.width)\r
-               {\r
-                       if (static_cast<size_t>(std::abs(delta_)) >= height_ + format_desc_.height && allow_eof)\r
-                               return core::draw_frame::empty();\r
-\r
-                       fill_translation[1] = \r
-                               static_cast<double>(start_offset_y_) / static_cast<double>(format_desc_.height)\r
-                               + delta_ / static_cast<double>(format_desc_.height);\r
-               }\r
-               else\r
-               {\r
-                       if (static_cast<size_t>(std::abs(delta_)) >= width_ + format_desc_.width && allow_eof)\r
-                               return core::draw_frame::empty();\r
-\r
-                       fill_translation[0] = \r
-                               static_cast<double>(start_offset_x_) / static_cast<double>(format_desc_.width)\r
-                               + (delta_) / static_cast<double>(format_desc_.width);\r
-               }\r
-\r
-               return result;\r
-       }\r
-\r
-       core::draw_frame render_frame(bool allow_eof, bool advance_delta)\r
-       {\r
-               auto result = render_frame(allow_eof);\r
-\r
-               if (advance_delta)\r
-               {\r
-                       advance();\r
-               }\r
-\r
-               return result;\r
-       }\r
-\r
-       void advance()\r
-       {\r
-               delta_ += speed_;\r
-       }\r
-\r
-       core::draw_frame receive_impl() override\r
-       {\r
-               core::draw_frame result;\r
-\r
-               if (format_desc_.field_mode == core::field_mode::progressive || progressive_)\r
-               {\r
-                       result = render_frame(true, true);\r
-               }\r
-               else\r
-               {\r
-                       auto field1 = render_frame(true, true);\r
-                       auto field2 = render_frame(true, false);\r
-\r
-                       if (field1 != core::draw_frame::empty() && field2 == core::draw_frame::empty())\r
-                       {\r
-                               field2 = render_frame(false, true);\r
-                       }\r
-                       else\r
-                       {\r
-                               advance();\r
-                       }\r
-\r
-                       result = core::draw_frame::interlace(field1, field2, format_desc_.field_mode);\r
-               }\r
-               \r
-               event_subject_ << monitor::event("file/path") % filename_\r
-                                          << monitor::event("delta") % delta_ \r
-                                          << monitor::event("speed") % speed_;\r
-\r
-               return result;\r
-       }\r
-                               \r
-       std::wstring print() const override\r
-       {\r
-               return L"image_scroll_producer[" + filename_ + L"]";\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"image-scroll";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"image-scroll");\r
-               info.add(L"filename", filename_);\r
-               return info;\r
-       }\r
-\r
-       uint32_t nb_frames() const override\r
-       {\r
-               if(width_ == format_desc_.width)\r
-               {\r
-                       auto length = (height_ + format_desc_.height * 2);\r
-                       return static_cast<uint32_t>(length / std::abs(speed_));// + length % std::abs(delta_));\r
-               }\r
-               else\r
-               {\r
-                       auto length = (width_ + format_desc_.width * 2);\r
-                       return static_cast<uint32_t>(length / std::abs(speed_));// + length % std::abs(delta_));\r
-               }\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override                                                                                                                     \r
-       {\r
-               return event_subject_.subscribe(o);\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override           \r
-       {\r
-               return event_subject_.unsubscribe(o);\r
-       }\r
-};\r
-\r
-spl::shared_ptr<core::frame_producer> create_scroll_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)\r
-{\r
-       static const std::vector<std::wstring> extensions = list_of(L".png")(L".tga")(L".bmp")(L".jpg")(L".jpeg")(L".gif")(L".tiff")(L".tif")(L".jp2")(L".jpx")(L".j2k")(L".j2c");\r
-       std::wstring filename = env::media_folder() + L"\\" + params[0];\r
-       \r
-       auto ext = std::find_if(extensions.begin(), extensions.end(), [&](const std::wstring& ex) -> bool\r
-               {                                       \r
-                       return boost::filesystem::is_regular_file(boost::filesystem::path(filename).replace_extension(ex));\r
-               });\r
-\r
-       if(ext == extensions.end())\r
-               return core::frame_producer::empty();\r
-       \r
-       double speed = 0.0;\r
-       double duration = 0.0;\r
-       auto speed_it = std::find(params.begin(), params.end(), L"SPEED");\r
-       if(speed_it != params.end())\r
-       {\r
-               if(++speed_it != params.end())\r
-                       speed = boost::lexical_cast<double>(*speed_it);\r
-       }\r
-\r
-       if (speed == 0)\r
-       {\r
-               auto duration_it = std::find(params.begin(), params.end(), L"DURATION");\r
-\r
-               if (duration_it != params.end() && ++duration_it != params.end())\r
-               {\r
-                       duration = boost::lexical_cast<double>(*duration_it);\r
-               }\r
-       }\r
-\r
-       if(speed == 0 && duration == 0)\r
-               return core::frame_producer::empty();\r
-\r
-       int motion_blur_px = 0;\r
-       auto blur_it = std::find(params.begin(), params.end(), L"BLUR");\r
-       if (blur_it != params.end() && ++blur_it != params.end())\r
-       {\r
-               motion_blur_px = boost::lexical_cast<int>(*blur_it);\r
-       }\r
-\r
-       bool premultiply_with_alpha = std::find(params.begin(), params.end(), L"PREMULTIPLY") != params.end();\r
-       bool progressive = std::find(params.begin(), params.end(), L"PROGRESSIVE") != params.end();\r
-\r
-       return core::create_destroy_proxy(spl::make_shared<image_scroll_producer>(\r
-               frame_factory, \r
-               format_desc, \r
-               filename + *ext, \r
-               -speed, \r
-               -duration, \r
-               motion_blur_px, \r
-               premultiply_with_alpha,\r
-               progressive));\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#include "image_scroll_producer.h"
+
+#include "../util/image_loader.h"
+#include "../util/image_view.h"
+#include "../util/image_algorithms.h"
+
+#include <core/video_format.h>
+
+#include <core/frame/frame.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/frame_transform.h>
+#include <core/frame/pixel_format.h>
+#include <core/monitor/monitor.h>
+
+#include <common/env.h>
+#include <common/log.h>
+#include <common/except.h>
+#include <common/array.h>
+#include <common/tweener.h>
+
+#include <boost/assign.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/scoped_array.hpp>
+
+#include <algorithm>
+#include <array>
+
+using namespace boost::assign;
+
+namespace caspar { namespace image {
+               
+struct image_scroll_producer : public core::frame_producer_base
+{      
+       monitor::basic_subject                  event_subject_;
+
+       const std::wstring                              filename_;
+       std::vector<core::draw_frame>   frames_;
+       core::video_format_desc                 format_desc_;
+       int                                                             width_;
+       int                                                             height_;
+
+       double                                                  delta_;
+       double                                                  speed_;
+
+       int                                                             start_offset_x_;
+       int                                                             start_offset_y_;
+       bool                                                    progressive_;
+       
+       explicit image_scroll_producer(
+               const spl::shared_ptr<core::frame_factory>& frame_factory, 
+               const core::video_format_desc& format_desc, 
+               const std::wstring& filename, 
+               double speed,
+               double duration,
+               int motion_blur_px = 0,
+               bool premultiply_with_alpha = false,
+               bool progressive = false)
+               : filename_(filename)
+               , delta_(0)
+               , format_desc_(format_desc)
+               , speed_(speed)
+               , start_offset_x_(0)
+               , start_offset_y_(0)
+               , progressive_(progressive)
+       {
+               auto bitmap = load_image(filename_);
+               FreeImage_FlipVertical(bitmap.get());
+
+               width_  = FreeImage_GetWidth(bitmap.get());
+               height_ = FreeImage_GetHeight(bitmap.get());
+
+               bool vertical = width_ == format_desc_.width;
+               bool horizontal = height_ == format_desc_.height;
+
+               if (!vertical && !horizontal)
+                       BOOST_THROW_EXCEPTION(
+                               caspar::invalid_argument() << msg_info("Neither width nor height matched the video resolution"));
+
+               if (vertical)
+               {
+                       if (duration != 0.0)
+                       {
+                               double total_num_pixels = format_desc_.height * 2 + height_;
+
+                               speed_ = total_num_pixels / (duration * format_desc_.fps * static_cast<double>(format_desc_.field_count));
+
+                               if (std::abs(speed_) > 1.0)
+                                       speed_ = std::ceil(speed_);
+                       }
+
+                       if (speed_ < 0.0)
+                       {
+                               start_offset_y_ = height_ + format_desc_.height;
+                       }
+               }
+               else
+               {
+                       if (duration != 0.0)
+                       {
+                               double total_num_pixels = format_desc_.width * 2 + width_;
+
+                               speed_ = total_num_pixels / (duration * format_desc_.fps * static_cast<double>(format_desc_.field_count));
+
+                               if (std::abs(speed_) > 1.0)
+                                       speed_ = std::ceil(speed_);
+                       }
+
+                       if (speed_ > 0.0)
+                               start_offset_x_ = format_desc_.width - (width_ % format_desc_.width);
+                       else
+                               start_offset_x_ = format_desc_.width - (width_ % format_desc_.width) + width_ + format_desc_.width;
+               }
+
+               auto bytes = FreeImage_GetBits(bitmap.get());
+               auto count = width_*height_*4;
+               image_view<bgra_pixel> original_view(bytes, width_, height_);
+
+               if (premultiply_with_alpha)
+                       premultiply(original_view);
+
+               boost::scoped_array<uint8_t> blurred_copy;
+
+               if (motion_blur_px > 0)
+               {
+                       double angle = 3.14159265 / 2; // Up
+
+                       if (horizontal && speed_ < 0)
+                               angle *= 2; // Left
+                       else if (vertical && speed > 0)
+                               angle *= 3; // Down
+                       else if (horizontal && speed  > 0)
+                               angle = 0.0; // Right
+
+                       blurred_copy.reset(new uint8_t[count]);
+                       image_view<bgra_pixel> blurred_view(blurred_copy.get(), width_, height_);
+                       core::tweener blur_tweener(L"easeInQuad");
+                       blur(original_view, blurred_view, angle, motion_blur_px, blur_tweener);
+                       bytes = blurred_copy.get();
+                       bitmap.reset();
+               }
+
+               if (vertical)
+               {
+                       int n = 1;
+
+                       while(count > 0)
+                       {
+                               core::pixel_format_desc desc = core::pixel_format::bgra;
+                               desc.planes.push_back(core::pixel_format_desc::plane(width_, format_desc_.height, 4));
+                               auto frame = frame_factory->create_frame(reinterpret_cast<void*>(rand()), desc);
+
+                               if(count >= frame.image_data(0).size())
+                               {       
+                                       std::copy_n(bytes + count - frame.image_data(0).size(), frame.image_data(0).size(), frame.image_data(0).begin());
+                                       count -= static_cast<int>(frame.image_data(0).size());
+                               }
+                               else
+                               {
+                                       memset(frame.image_data(0).begin(), 0, frame.image_data(0).size());     
+                                       std::copy_n(bytes, count, frame.image_data(0).begin() + format_desc_.size - count);
+                                       count = 0;
+                               }
+
+                               core::draw_frame draw_frame(std::move(frame));
+
+                               // Set the relative position to the other image fragments
+                               draw_frame.transform().image_transform.fill_translation[1] = - n++;
+
+                               frames_.push_back(draw_frame);
+                       }
+               }
+               else if (horizontal)
+               {
+                       int i = 0;
+                       while(count > 0)
+                       {
+                               core::pixel_format_desc desc = core::pixel_format::bgra;
+                               desc.planes.push_back(core::pixel_format_desc::plane(format_desc_.width, height_, 4));
+                               auto frame = frame_factory->create_frame(reinterpret_cast<void*>(rand()), desc);
+                               if(count >= frame.image_data(0).size())
+                               {       
+                                       for(int y = 0; y < height_; ++y)
+                                               std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, format_desc_.width*4, frame.image_data(0).begin() + y * format_desc_.width*4);
+                                       
+                                       ++i;
+                                       count -= static_cast<int>(frame.image_data(0).size());
+                               }
+                               else
+                               {
+                                       memset(frame.image_data(0).begin(), 0, frame.image_data(0).size());     
+                                       auto width2 = width_ % format_desc_.width;
+                                       for(int y = 0; y < height_; ++y)
+                                               std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, width2*4, frame.image_data(0).begin() + y * format_desc_.width*4);
+
+                                       count = 0;
+                               }
+                       
+                               frames_.push_back(core::draw_frame(std::move(frame)));
+                       }
+
+                       std::reverse(frames_.begin(), frames_.end());
+
+                       // Set the relative positions of the image fragments.
+                       for (size_t n = 0; n < frames_.size(); ++n)
+                       {
+                               double translation = - (static_cast<double>(n) + 1.0);
+                               frames_[n].transform().image_transform.fill_translation[0] = translation;
+                       }
+               }
+
+               CASPAR_LOG(info) << print() << L" Initialized";
+       }
+
+       std::vector<core::draw_frame> get_visible()
+       {
+               std::vector<core::draw_frame> result;
+               result.reserve(frames_.size());
+
+               BOOST_FOREACH(auto& frame, frames_)
+               {
+                       auto& fill_translation = frame.transform().image_transform.fill_translation;
+
+                       if (width_ == format_desc_.width)
+                       {
+                               auto motion_offset_in_screens = (static_cast<double>(start_offset_y_) + delta_) / static_cast<double>(format_desc_.height);
+                               auto vertical_offset = fill_translation[1] + motion_offset_in_screens;
+
+                               if (vertical_offset < -1.0 || vertical_offset > 1.0)
+                               {
+                                       continue;
+                               }
+                       }
+                       else
+                       {
+                               auto motion_offset_in_screens = (static_cast<double>(start_offset_x_) + delta_) / static_cast<double>(format_desc_.width);
+                               auto horizontal_offset = fill_translation[0] + motion_offset_in_screens;
+
+                               if (horizontal_offset < -1.0 || horizontal_offset > 1.0)
+                               {
+                                       continue;
+                               }
+                       }
+
+                       result.push_back(frame);
+               }
+
+               return std::move(result);
+       }
+       
+       // frame_producer
+       core::draw_frame render_frame(bool allow_eof)
+       {
+               if(frames_.empty())
+                       return core::draw_frame::empty();
+               
+               core::draw_frame result(get_visible());
+               auto& fill_translation = result.transform().image_transform.fill_translation;
+
+               if (width_ == format_desc_.width)
+               {
+                       if (static_cast<size_t>(std::abs(delta_)) >= height_ + format_desc_.height && allow_eof)
+                               return core::draw_frame::empty();
+
+                       fill_translation[1] = 
+                               static_cast<double>(start_offset_y_) / static_cast<double>(format_desc_.height)
+                               + delta_ / static_cast<double>(format_desc_.height);
+               }
+               else
+               {
+                       if (static_cast<size_t>(std::abs(delta_)) >= width_ + format_desc_.width && allow_eof)
+                               return core::draw_frame::empty();
+
+                       fill_translation[0] = 
+                               static_cast<double>(start_offset_x_) / static_cast<double>(format_desc_.width)
+                               + (delta_) / static_cast<double>(format_desc_.width);
+               }
+
+               return result;
+       }
+
+       core::draw_frame render_frame(bool allow_eof, bool advance_delta)
+       {
+               auto result = render_frame(allow_eof);
+
+               if (advance_delta)
+               {
+                       advance();
+               }
+
+               return result;
+       }
+
+       void advance()
+       {
+               delta_ += speed_;
+       }
+
+       core::draw_frame receive_impl() override
+       {
+               core::draw_frame result;
+
+               if (format_desc_.field_mode == core::field_mode::progressive || progressive_)
+               {
+                       result = render_frame(true, true);
+               }
+               else
+               {
+                       auto field1 = render_frame(true, true);
+                       auto field2 = render_frame(true, false);
+
+                       if (field1 != core::draw_frame::empty() && field2 == core::draw_frame::empty())
+                       {
+                               field2 = render_frame(false, true);
+                       }
+                       else
+                       {
+                               advance();
+                       }
+
+                       result = core::draw_frame::interlace(field1, field2, format_desc_.field_mode);
+               }
+               
+               event_subject_ << monitor::event("file/path") % filename_
+                                          << monitor::event("delta") % delta_ 
+                                          << monitor::event("speed") % speed_;
+
+               return result;
+       }
+                               
+       std::wstring print() const override
+       {
+               return L"image_scroll_producer[" + filename_ + L"]";
+       }
+
+       std::wstring name() const override
+       {
+               return L"image-scroll";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"image-scroll");
+               info.add(L"filename", filename_);
+               return info;
+       }
+
+       uint32_t nb_frames() const override
+       {
+               if(width_ == format_desc_.width)
+               {
+                       auto length = (height_ + format_desc_.height * 2);
+                       return static_cast<uint32_t>(length / std::abs(speed_));// + length % std::abs(delta_));
+               }
+               else
+               {
+                       auto length = (width_ + format_desc_.width * 2);
+                       return static_cast<uint32_t>(length / std::abs(speed_));// + length % std::abs(delta_));
+               }
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override                                                                                                                     
+       {
+               return event_subject_.subscribe(o);
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override           
+       {
+               return event_subject_.unsubscribe(o);
+       }
+};
+
+spl::shared_ptr<core::frame_producer> create_scroll_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+{
+       static const std::vector<std::wstring> extensions = list_of(L".png")(L".tga")(L".bmp")(L".jpg")(L".jpeg")(L".gif")(L".tiff")(L".tif")(L".jp2")(L".jpx")(L".j2k")(L".j2c");
+       std::wstring filename = env::media_folder() + L"\\" + params[0];
+       
+       auto ext = std::find_if(extensions.begin(), extensions.end(), [&](const std::wstring& ex) -> bool
+               {                                       
+                       return boost::filesystem::is_regular_file(boost::filesystem::path(filename).replace_extension(ex));
+               });
+
+       if(ext == extensions.end())
+               return core::frame_producer::empty();
+       
+       double speed = 0.0;
+       double duration = 0.0;
+       auto speed_it = std::find(params.begin(), params.end(), L"SPEED");
+       if(speed_it != params.end())
+       {
+               if(++speed_it != params.end())
+                       speed = boost::lexical_cast<double>(*speed_it);
+       }
+
+       if (speed == 0)
+       {
+               auto duration_it = std::find(params.begin(), params.end(), L"DURATION");
+
+               if (duration_it != params.end() && ++duration_it != params.end())
+               {
+                       duration = boost::lexical_cast<double>(*duration_it);
+               }
+       }
+
+       if(speed == 0 && duration == 0)
+               return core::frame_producer::empty();
+
+       int motion_blur_px = 0;
+       auto blur_it = std::find(params.begin(), params.end(), L"BLUR");
+       if (blur_it != params.end() && ++blur_it != params.end())
+       {
+               motion_blur_px = boost::lexical_cast<int>(*blur_it);
+       }
+
+       bool premultiply_with_alpha = std::find(params.begin(), params.end(), L"PREMULTIPLY") != params.end();
+       bool progressive = std::find(params.begin(), params.end(), L"PROGRESSIVE") != params.end();
+
+       return core::create_destroy_proxy(spl::make_shared<image_scroll_producer>(
+               frame_factory, 
+               format_desc, 
+               filename + *ext, 
+               -speed, 
+               -duration, 
+               motion_blur_px, 
+               premultiply_with_alpha,
+               progressive));
+}
+
 }}
\ No newline at end of file
index 7a0978691f26f8dfb830c60e50b996185f1f2785..7cd73de46f97db35f4ac9062fb6cf542bd1a0d14 100644 (file)
@@ -1,33 +1,33 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <core/producer/frame_producer.h>\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar { namespace image {\r
-\r
-spl::shared_ptr<core::frame_producer> create_scroll_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <core/producer/frame_producer.h>
+
+#include <string>
+#include <vector>
+
+namespace caspar { namespace image {
+
+spl::shared_ptr<core::frame_producer> create_scroll_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+
 }}
\ No newline at end of file
index b7b38d285527d939410248643fa8b8629e4aa067..da71b2f25126bcd176cd7147edf499043fcfe212 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Helge Norberg, helge.norberg@svt.se\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/tweener.h>\r
-\r
-#include <cmath>\r
-#include <boost/foreach.hpp>\r
-\r
-namespace caspar { namespace image {\r
-\r
-/**\r
- * Helper for calculating the color of a pixel given any number of of other\r
- * pixels (each with their own weight).\r
- */\r
-class rgba_weighting\r
-{\r
-       int r, g, b, a;\r
-       int total_weight;\r
-public:\r
-       rgba_weighting()\r
-               : r(0), g(0), b(0), a(0), total_weight(0)\r
-       {\r
-       }\r
-\r
-       template<class RGBAPixel>\r
-       inline void add_pixel(const RGBAPixel& pixel, uint8_t weight)\r
-       {\r
-               r += pixel.r() * weight;\r
-               g += pixel.g() * weight;\r
-               b += pixel.b() * weight;\r
-               a += pixel.a() * weight;\r
-\r
-               total_weight += weight;\r
-       }\r
-\r
-       template<class RGBAPixel>\r
-       inline void store_result(RGBAPixel& pixel)\r
-       {\r
-               pixel.r() = static_cast<uint8_t>(r / total_weight);\r
-               pixel.g() = static_cast<uint8_t>(g / total_weight);\r
-               pixel.b() = static_cast<uint8_t>(b / total_weight);\r
-               pixel.a() = static_cast<uint8_t>(a / total_weight);\r
-       }\r
-};\r
-\r
-template<class T>\r
-std::vector<T> get_tweened_values(const core::tweener& tweener, size_t num_values, T from, T to)\r
-{\r
-       std::vector<T> result;\r
-       result.reserve(num_values);\r
-\r
-       double start = static_cast<double>(from);\r
-       double delta = static_cast<double>(to - from);\r
-       double duration = static_cast<double>(num_values);\r
-\r
-       for (double t = 0; t < duration; ++t)\r
-       {\r
-               result.push_back(static_cast<T>(tweener(t, start, delta, duration - 1.0)));\r
-       }\r
-\r
-       return std::move(result);\r
-}\r
-\r
-/**\r
- * Blur a source image and store the blurred result in a destination image.\r
- * <p>\r
- * The blur is done by weighting each relative pixel from a destination pixel\r
- * position using a vector of relative x-y pairs. The further away a related\r
- * pixel is the less weight it gets. A tweener is used to calculate the actual\r
- * weights of each related pixel.\r
- *\r
- * @param src                      The source view. Has to model the ImageView\r
- *                                 concept and have a pixel type modelling the\r
- *                                 RGBAPixel concept.\r
- * @param dst                      The destination view. Has to model the\r
- *                                 ImageView concept and have a pixel type\r
- *                                 modelling the RGBAPixel concept.\r
- * @param motion_trail_coordinates The relative x-y positions to weight in for\r
- *                                 each pixel.\r
- * @param tweener                  The tweener to use for calculating the\r
- *                                 weights of each relative position in the\r
- *                                 motion trail.\r
- */\r
-template<class SrcView, class DstView>\r
-void blur(\r
-       const SrcView& src,\r
-       DstView& dst,\r
-       const std::vector<std::pair<int, int>> motion_trail_coordinates, \r
-       const core::tweener& tweener)\r
-{\r
-       auto blur_px = motion_trail_coordinates.size();\r
-       auto tweened_weights_y = get_tweened_values<uint8_t>(tweener, blur_px + 2, 255, 0);\r
-       tweened_weights_y.pop_back();\r
-       tweened_weights_y.erase(tweened_weights_y.begin());\r
-\r
-       auto src_end = src.end();\r
-       auto dst_iter = dst.begin();\r
-\r
-       for (auto src_iter = src.begin(); src_iter != src_end; ++src_iter, ++dst_iter)\r
-       {\r
-               rgba_weighting w;\r
-\r
-               for (int i = 0; i < blur_px; ++i)\r
-               {\r
-                       auto& coordinate = motion_trail_coordinates[i];\r
-                       auto other_pixel = src.relative(src_iter, coordinate.first, coordinate.second);\r
-\r
-                       if (other_pixel == nullptr)\r
-                               break;\r
-\r
-                       w.add_pixel(*other_pixel, tweened_weights_y[i]);\r
-               }\r
-\r
-               w.add_pixel(*src_iter, 255);\r
-               w.store_result(*dst_iter);\r
-       }\r
-}\r
-\r
-/**\r
- * Calculate relative x-y coordinates of a straight line with a given angle and\r
- * a given number of points.\r
- *\r
- * @param num_pixels    The number of pixels/points to create.\r
- * @param angle_radians The angle of the line in radians.\r
- *\r
- * @return the x-y pairs.\r
- */\r
-std::vector<std::pair<int, int>> get_line_points(int num_pixels, double angle_radians)\r
-{\r
-       std::vector<std::pair<int, int>> line_points;\r
-       line_points.reserve(num_pixels);\r
-\r
-       double delta_x = std::cos(angle_radians);\r
-       double delta_y = -std::sin(angle_radians); // In memory is revered\r
-       double max_delta = std::max(std::abs(delta_x), std::abs(delta_y));\r
-       double amplification = 1.0 / max_delta;\r
-       delta_x *= amplification;\r
-       delta_y *= amplification;\r
-\r
-       for (int i = 1; i <= num_pixels; ++i)\r
-               line_points.push_back(std::make_pair(\r
-                       static_cast<int>(std::floor(delta_x * static_cast<double>(i) + 0.5)), \r
-                       static_cast<int>(std::floor(delta_y * static_cast<double>(i) + 0.5))));\r
-\r
-       return std::move(line_points);\r
-}\r
-\r
-/**\r
- * Directionally blur a source image modelling the ImageView concept and store\r
- * the blurred image to a destination image also modelling the ImageView\r
- * concept.\r
- * <p>\r
- * The pixel type of the views must model the RGBAPixel concept.\r
- *\r
- * @param src           The source image view. Has to model the ImageView\r
- *                      concept and have a pixel type that models RGBAPixel.\r
- * @param dst           The destiation image view. Has to model the ImageView\r
- *                      concept and have a pixel type that models RGBAPixel.\r
- * @param angle_radians The angle in radians to directionally blur the image.\r
- * @param blur_px       The number of pixels of the blur.\r
- * @param tweener       The tweener to use to create a pixel weighting curve\r
- *                      with.\r
- */\r
-template<class SrcView, class DstView>\r
-void blur(\r
-       const SrcView& src,\r
-       DstView& dst,\r
-       double angle_radians,\r
-       int blur_px, \r
-       const core::tweener& tweener)\r
-{\r
-       auto motion_trail = get_line_points(blur_px, angle_radians);\r
-\r
-       blur(src, dst, motion_trail, tweener);\r
-}\r
-\r
-/**\r
- * Premultiply with alpha for each pixel in an ImageView. The modifications is\r
- * done in place. The pixel type of the ImageView must model the RGBAPixel\r
- * concept.\r
- *\r
- * @param view_to_modify The image view to premultiply in place. Has to model\r
- *                       the ImageView concept and have a pixel type that\r
- *                       models RGBAPixel.\r
- */\r
-template<class SrcDstView>\r
-void premultiply(SrcDstView& view_to_modify)\r
-{\r
-       std::for_each(view_to_modify.begin(), view_to_modify.end(), [&](SrcDstView::pixel_type& pixel)\r
-       {\r
-               int alpha = static_cast<int>(pixel.a());\r
-\r
-               if (alpha != 255) // Performance optimization\r
-               {\r
-                       // We don't event try to premultiply 0 since it will be unaffected.\r
-                       if (pixel.r())\r
-                               pixel.r() = static_cast<uint8_t>(static_cast<int>(pixel.r()) * alpha / 255);\r
-\r
-                       if (pixel.g())\r
-                               pixel.g() = static_cast<uint8_t>(static_cast<int>(pixel.g()) * alpha / 255);\r
-\r
-                       if (pixel.b())\r
-                               pixel.b() = static_cast<uint8_t>(static_cast<int>(pixel.b()) * alpha / 255);\r
-               }\r
-       });\r
-}\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#pragma once
+
+#include <common/tweener.h>
+
+#include <cmath>
+#include <boost/foreach.hpp>
+
+namespace caspar { namespace image {
+
+/**
+ * Helper for calculating the color of a pixel given any number of of other
+ * pixels (each with their own weight).
+ */
+class rgba_weighting
+{
+       int r, g, b, a;
+       int total_weight;
+public:
+       rgba_weighting()
+               : r(0), g(0), b(0), a(0), total_weight(0)
+       {
+       }
+
+       template<class RGBAPixel>
+       inline void add_pixel(const RGBAPixel& pixel, uint8_t weight)
+       {
+               r += pixel.r() * weight;
+               g += pixel.g() * weight;
+               b += pixel.b() * weight;
+               a += pixel.a() * weight;
+
+               total_weight += weight;
+       }
+
+       template<class RGBAPixel>
+       inline void store_result(RGBAPixel& pixel)
+       {
+               pixel.r() = static_cast<uint8_t>(r / total_weight);
+               pixel.g() = static_cast<uint8_t>(g / total_weight);
+               pixel.b() = static_cast<uint8_t>(b / total_weight);
+               pixel.a() = static_cast<uint8_t>(a / total_weight);
+       }
+};
+
+template<class T>
+std::vector<T> get_tweened_values(const core::tweener& tweener, size_t num_values, T from, T to)
+{
+       std::vector<T> result;
+       result.reserve(num_values);
+
+       double start = static_cast<double>(from);
+       double delta = static_cast<double>(to - from);
+       double duration = static_cast<double>(num_values);
+
+       for (double t = 0; t < duration; ++t)
+       {
+               result.push_back(static_cast<T>(tweener(t, start, delta, duration - 1.0)));
+       }
+
+       return std::move(result);
+}
+
+/**
+ * Blur a source image and store the blurred result in a destination image.
+ * <p>
+ * The blur is done by weighting each relative pixel from a destination pixel
+ * position using a vector of relative x-y pairs. The further away a related
+ * pixel is the less weight it gets. A tweener is used to calculate the actual
+ * weights of each related pixel.
+ *
+ * @param src                      The source view. Has to model the ImageView
+ *                                 concept and have a pixel type modelling the
+ *                                 RGBAPixel concept.
+ * @param dst                      The destination view. Has to model the
+ *                                 ImageView concept and have a pixel type
+ *                                 modelling the RGBAPixel concept.
+ * @param motion_trail_coordinates The relative x-y positions to weight in for
+ *                                 each pixel.
+ * @param tweener                  The tweener to use for calculating the
+ *                                 weights of each relative position in the
+ *                                 motion trail.
+ */
+template<class SrcView, class DstView>
+void blur(
+       const SrcView& src,
+       DstView& dst,
+       const std::vector<std::pair<int, int>> motion_trail_coordinates, 
+       const core::tweener& tweener)
+{
+       auto blur_px = motion_trail_coordinates.size();
+       auto tweened_weights_y = get_tweened_values<uint8_t>(tweener, blur_px + 2, 255, 0);
+       tweened_weights_y.pop_back();
+       tweened_weights_y.erase(tweened_weights_y.begin());
+
+       auto src_end = src.end();
+       auto dst_iter = dst.begin();
+
+       for (auto src_iter = src.begin(); src_iter != src_end; ++src_iter, ++dst_iter)
+       {
+               rgba_weighting w;
+
+               for (int i = 0; i < blur_px; ++i)
+               {
+                       auto& coordinate = motion_trail_coordinates[i];
+                       auto other_pixel = src.relative(src_iter, coordinate.first, coordinate.second);
+
+                       if (other_pixel == nullptr)
+                               break;
+
+                       w.add_pixel(*other_pixel, tweened_weights_y[i]);
+               }
+
+               w.add_pixel(*src_iter, 255);
+               w.store_result(*dst_iter);
+       }
+}
+
+/**
+ * Calculate relative x-y coordinates of a straight line with a given angle and
+ * a given number of points.
+ *
+ * @param num_pixels    The number of pixels/points to create.
+ * @param angle_radians The angle of the line in radians.
+ *
+ * @return the x-y pairs.
+ */
+std::vector<std::pair<int, int>> get_line_points(int num_pixels, double angle_radians)
+{
+       std::vector<std::pair<int, int>> line_points;
+       line_points.reserve(num_pixels);
+
+       double delta_x = std::cos(angle_radians);
+       double delta_y = -std::sin(angle_radians); // In memory is revered
+       double max_delta = std::max(std::abs(delta_x), std::abs(delta_y));
+       double amplification = 1.0 / max_delta;
+       delta_x *= amplification;
+       delta_y *= amplification;
+
+       for (int i = 1; i <= num_pixels; ++i)
+               line_points.push_back(std::make_pair(
+                       static_cast<int>(std::floor(delta_x * static_cast<double>(i) + 0.5)), 
+                       static_cast<int>(std::floor(delta_y * static_cast<double>(i) + 0.5))));
+
+       return std::move(line_points);
+}
+
+/**
+ * Directionally blur a source image modelling the ImageView concept and store
+ * the blurred image to a destination image also modelling the ImageView
+ * concept.
+ * <p>
+ * The pixel type of the views must model the RGBAPixel concept.
+ *
+ * @param src           The source image view. Has to model the ImageView
+ *                      concept and have a pixel type that models RGBAPixel.
+ * @param dst           The destiation image view. Has to model the ImageView
+ *                      concept and have a pixel type that models RGBAPixel.
+ * @param angle_radians The angle in radians to directionally blur the image.
+ * @param blur_px       The number of pixels of the blur.
+ * @param tweener       The tweener to use to create a pixel weighting curve
+ *                      with.
+ */
+template<class SrcView, class DstView>
+void blur(
+       const SrcView& src,
+       DstView& dst,
+       double angle_radians,
+       int blur_px, 
+       const core::tweener& tweener)
+{
+       auto motion_trail = get_line_points(blur_px, angle_radians);
+
+       blur(src, dst, motion_trail, tweener);
+}
+
+/**
+ * Premultiply with alpha for each pixel in an ImageView. The modifications is
+ * done in place. The pixel type of the ImageView must model the RGBAPixel
+ * concept.
+ *
+ * @param view_to_modify The image view to premultiply in place. Has to model
+ *                       the ImageView concept and have a pixel type that
+ *                       models RGBAPixel.
+ */
+template<class SrcDstView>
+void premultiply(SrcDstView& view_to_modify)
+{
+       std::for_each(view_to_modify.begin(), view_to_modify.end(), [&](SrcDstView::pixel_type& pixel)
+       {
+               int alpha = static_cast<int>(pixel.a());
+
+               if (alpha != 255) // Performance optimization
+               {
+                       // We don't event try to premultiply 0 since it will be unaffected.
+                       if (pixel.r())
+                               pixel.r() = static_cast<uint8_t>(static_cast<int>(pixel.r()) * alpha / 255);
+
+                       if (pixel.g())
+                               pixel.g() = static_cast<uint8_t>(static_cast<int>(pixel.g()) * alpha / 255);
+
+                       if (pixel.b())
+                               pixel.b() = static_cast<uint8_t>(static_cast<int>(pixel.b()) * alpha / 255);
+               }
+       });
+}
+
+}}
index 5f730fd10741891b31146ea819878a546690f997..dd209281349b7eefbb62a5dca7620e1f86ce7090 100644 (file)
@@ -1,56 +1,56 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "image_loader.h"\r
-\r
-#include <common/except.h>\r
-#include <common/utf.h>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (disable : 4714) // marked as __forceinline not inlined\r
-#endif\r
-\r
-#include <boost/exception/errinfo_file_name.hpp>\r
-#include <boost/filesystem.hpp>\r
-\r
-namespace caspar { namespace image {\r
-\r
-std::shared_ptr<FIBITMAP> load_image(const std::wstring& filename)\r
-{\r
-       if(!boost::filesystem::exists(filename))\r
-               CASPAR_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(u8(filename)));\r
-\r
-       FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeU(filename.c_str(), 0);            \r
-       if(fif == FIF_UNKNOWN || !FreeImage_FIFSupportsReading(fif)) \r
-               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Unsupported image format."));\r
-               \r
-       auto bitmap = std::shared_ptr<FIBITMAP>(FreeImage_LoadU(fif, filename.c_str(), 0), FreeImage_Unload);\r
-                 \r
-       if(FreeImage_GetBPP(bitmap.get()) != 32)\r
-       {\r
-               bitmap = std::shared_ptr<FIBITMAP>(FreeImage_ConvertTo32Bits(bitmap.get()), FreeImage_Unload);\r
-               if(!bitmap)\r
-                       CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Unsupported image format."));                    \r
-       }\r
-       \r
-       return bitmap;\r
-}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "image_loader.h"
+
+#include <common/except.h>
+#include <common/utf.h>
+
+#if defined(_MSC_VER)
+#pragma warning (disable : 4714) // marked as __forceinline not inlined
+#endif
+
+#include <boost/exception/errinfo_file_name.hpp>
+#include <boost/filesystem.hpp>
+
+namespace caspar { namespace image {
+
+std::shared_ptr<FIBITMAP> load_image(const std::wstring& filename)
+{
+       if(!boost::filesystem::exists(filename))
+               CASPAR_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(u8(filename)));
+
+       FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeU(filename.c_str(), 0);            
+       if(fif == FIF_UNKNOWN || !FreeImage_FIFSupportsReading(fif)) 
+               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Unsupported image format."));
+               
+       auto bitmap = std::shared_ptr<FIBITMAP>(FreeImage_LoadU(fif, filename.c_str(), 0), FreeImage_Unload);
+                 
+       if(FreeImage_GetBPP(bitmap.get()) != 32)
+       {
+               bitmap = std::shared_ptr<FIBITMAP>(FreeImage_ConvertTo32Bits(bitmap.get()), FreeImage_Unload);
+               if(!bitmap)
+                       CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Unsupported image format."));                    
+       }
+       
+       return bitmap;
+}
 }}
\ No newline at end of file
index 5922058bc1bb4367983c803f1fa235478427d396..7c15be5959e58032046b1faa2e8b5b3f67a71de9 100644 (file)
@@ -1,33 +1,33 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <FreeImage.h>\r
-\r
-#include <memory>\r
-#include <string>\r
-\r
-namespace caspar { namespace image {\r
-\r
-std::shared_ptr<FIBITMAP> load_image(const std::wstring& filename);\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <FreeImage.h>
+
+#include <memory>
+#include <string>
+
+namespace caspar { namespace image {
+
+std::shared_ptr<FIBITMAP> load_image(const std::wstring& filename);
+
+}}
index 422ab3c1ed270069c9a72781bf04eb26ab040808..c9694fdee4301577689d0c6d3946a4bf8556d109 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Helge Norberg, helge.norberg@svt.se\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <boost/iterator/filter_iterator.hpp>\r
-\r
-namespace caspar { namespace image {\r
-\r
-/**\r
- * A POD pixel with a compatible memory layout as a 8bit BGRA pixel (32bits in\r
- * total).\r
- * <p>\r
- * Models the PackedPixel concept used by for example image_view. Also models\r
- * the RGBAPixel concept which does not care about the order between RGBA but\r
- * only requires that all 4 channel has accessors.\r
- */\r
-class bgra_pixel\r
-{\r
-       uint8_t b_;\r
-       uint8_t g_;\r
-       uint8_t r_;\r
-       uint8_t a_;\r
-public:\r
-       bgra_pixel(uint8_t b = 0, uint8_t g = 0, uint8_t r = 0, uint8_t a = 0) : b_(b), g_(g), r_(r), a_(a) {}\r
-       inline const uint8_t& b() const { return b_; }\r
-       inline uint8_t& b() { return b_; }\r
-       inline const uint8_t& g() const { return g_; }\r
-       inline uint8_t& g() { return g_; }\r
-       inline const uint8_t& r() const { return r_; }\r
-       inline uint8_t& r() { return r_; }\r
-       inline const uint8_t& a() const { return a_; }\r
-       inline uint8_t& a() { return a_; }\r
-};\r
-\r
-template<class PackedPixel> class image_sub_view;\r
-\r
-/**\r
- * An image view abstracting raw packed pixel data\r
- * <p>\r
- * This is only a view, it does not own the data.\r
- * <p>\r
- * Models the the ImageView concept.\r
- */\r
-template<class PackedPixel>\r
-class image_view\r
-{\r
-public:\r
-       typedef PackedPixel pixel_type;\r
-\r
-       image_view(void* raw_start, int width, int height)\r
-               : begin_(static_cast<PackedPixel*>(raw_start))\r
-               , end_(begin_ + (width * height))\r
-               , width_(width)\r
-               , height_(height)\r
-       {\r
-       }\r
-\r
-       PackedPixel* begin()\r
-       {\r
-               return begin_;\r
-       }\r
-\r
-       const PackedPixel* begin() const\r
-       {\r
-               return begin_;\r
-       }\r
-\r
-       PackedPixel* end()\r
-       {\r
-               return end_;\r
-       }\r
-\r
-       const PackedPixel* end() const\r
-       {\r
-               return end_;\r
-       }\r
-\r
-       template<class PackedPixelIter>\r
-       inline PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y)\r
-       {\r
-               auto pixel_distance = delta_x + width_ * delta_y;\r
-               PackedPixel* to_address = &(*to);\r
-               auto result = to_address + pixel_distance;\r
-\r
-               if (result < begin_ || result >= end_)\r
-                       return nullptr;\r
-               else\r
-                       return result;\r
-       }\r
-\r
-       template<class PackedPixelIter>\r
-       inline const PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y) const\r
-       {\r
-               //auto x_distance\r
-               auto pixel_distance = delta_x + width_ * delta_y;\r
-               const PackedPixel* to_address = &(*to);\r
-               auto result = to_address + pixel_distance;\r
-\r
-               /*if (delta_x != 0)\r
-               {\r
-                       auto actual_delta_y = result % width_\r
-               }*/\r
-\r
-               if (result < begin_ || result >= end_)\r
-                       return nullptr;\r
-               else\r
-                       return result;\r
-       }\r
-\r
-       int width() const\r
-       {\r
-               return width_;\r
-       }\r
-\r
-       int height() const\r
-       {\r
-               return height_;\r
-       }\r
-\r
-       image_sub_view<PackedPixel> subview(int x, int y, int width, int height)\r
-       {\r
-               return image_sub_view<PackedPixel>(*this, x, y, width, height);\r
-       }\r
-\r
-       const image_sub_view<PackedPixel> subview(int x, int y, int width, int height) const\r
-       {\r
-               return image_sub_view<PackedPixel>(*this, x, y, width, height);\r
-       }\r
-private:\r
-       PackedPixel* begin_;\r
-       PackedPixel* end_;\r
-       int width_;\r
-       int height_;\r
-};\r
-\r
-template<class PackedPixel>\r
-class is_within_view\r
-{\r
-public:\r
-       is_within_view(const PackedPixel* begin, int width, int stride)\r
-               : begin_(begin)\r
-               , width_(width)\r
-               , stride_(stride)\r
-               , no_check_(width == stride)\r
-       {\r
-       }\r
-\r
-       inline bool operator()(const PackedPixel& pixel) const\r
-       {\r
-               if (no_check_)\r
-                       return true;\r
-\r
-               const PackedPixel* position = &pixel;\r
-               int distance_from_row_start = (position - begin_) % stride_;\r
-\r
-               return distance_from_row_start < width_;\r
-       }\r
-private:\r
-       const PackedPixel* begin_;\r
-       int width_;\r
-       int stride_;\r
-       bool no_check_;\r
-};\r
-\r
-template <class PackedPixel>\r
-struct image_stride_iterator : public boost::filter_iterator<is_within_view<PackedPixel>, PackedPixel*>\r
-{\r
-       image_stride_iterator(PackedPixel* begin, PackedPixel* end, int width, int stride)\r
-               : boost::filter_iterator<is_within_view<PackedPixel>, PackedPixel*>::filter_iterator(\r
-                       is_within_view<PackedPixel>(begin, width, stride), begin, end)\r
-       {\r
-       }\r
-};\r
-\r
-/**\r
- * A sub view created from an image_view.\r
- * <p>\r
- * This also models the ImageView concept.\r
- */\r
-template<class PackedPixel>\r
-class image_sub_view\r
-{\r
-public:\r
-       typedef PackedPixel pixel_type;\r
-\r
-       image_sub_view(image_view<PackedPixel>& root_view, int x, int y, int width, int height)\r
-               : root_view_(root_view)\r
-               , relative_to_root_x_(x)\r
-               , relative_to_root_y_(y)\r
-               , width_(width)\r
-               , height_(height)\r
-               , raw_begin_(root_view.relative(root_view.begin(), x, y))\r
-               , raw_end_(root_view.relative(raw_begin_, width - 1, height_ - 1) + 1)\r
-       {\r
-       }\r
-\r
-       image_stride_iterator<PackedPixel> begin()\r
-       {\r
-               return image_stride_iterator<PackedPixel>(raw_begin_, raw_end_, width_, root_view_.width());\r
-       }\r
-\r
-       image_stride_iterator<const PackedPixel> begin() const\r
-       {\r
-               return image_stride_iterator<const PackedPixel>(raw_begin_, raw_end_, width_, root_view_.width());\r
-       }\r
-\r
-       image_stride_iterator<PackedPixel> end()\r
-       {\r
-               return image_stride_iterator<PackedPixel>(raw_end_, raw_end_, width_, root_view_.width());\r
-       }\r
-\r
-       image_stride_iterator<const PackedPixel> end() const\r
-       {\r
-               return image_stride_iterator<const PackedPixel>(raw_end_, raw_end_, width_, root_view_.width());\r
-       }\r
-\r
-       template<class PackedPixelIter>\r
-       PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y)\r
-       {\r
-               return root_view_.relative(to, delta_x, delta_y);\r
-       }\r
-\r
-       template<class PackedPixelIter>\r
-       const PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y) const\r
-       {\r
-               return root_view_.relative(to, delta_x, delta_y);\r
-       }\r
-\r
-       int width() const\r
-       {\r
-               return width_;\r
-       }\r
-\r
-       int height() const\r
-       {\r
-               return height_;\r
-       }\r
-\r
-       image_sub_view<PackedPixel> subview(int x, int y, int width, int height)\r
-       {\r
-               return root_view_.subview(relative_to_root_x_ + x, relative_to_root_y_ + y, width, height);\r
-       }\r
-\r
-       const image_sub_view<PackedPixel> subview(int x, int y, int width, int height) const\r
-       {\r
-               return root_view_.subview(relative_to_root_x_ + x, relative_to_root_y_ + y, width, height);\r
-       }\r
-private:\r
-       image_view<PackedPixel> root_view_;\r
-       int relative_to_root_x_;\r
-       int relative_to_root_y_;\r
-       int width_;\r
-       int height_;\r
-       PackedPixel* raw_begin_;\r
-       PackedPixel* raw_end_;\r
-};\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#pragma once
+
+#include <boost/iterator/filter_iterator.hpp>
+
+namespace caspar { namespace image {
+
+/**
+ * A POD pixel with a compatible memory layout as a 8bit BGRA pixel (32bits in
+ * total).
+ * <p>
+ * Models the PackedPixel concept used by for example image_view. Also models
+ * the RGBAPixel concept which does not care about the order between RGBA but
+ * only requires that all 4 channel has accessors.
+ */
+class bgra_pixel
+{
+       uint8_t b_;
+       uint8_t g_;
+       uint8_t r_;
+       uint8_t a_;
+public:
+       bgra_pixel(uint8_t b = 0, uint8_t g = 0, uint8_t r = 0, uint8_t a = 0) : b_(b), g_(g), r_(r), a_(a) {}
+       inline const uint8_t& b() const { return b_; }
+       inline uint8_t& b() { return b_; }
+       inline const uint8_t& g() const { return g_; }
+       inline uint8_t& g() { return g_; }
+       inline const uint8_t& r() const { return r_; }
+       inline uint8_t& r() { return r_; }
+       inline const uint8_t& a() const { return a_; }
+       inline uint8_t& a() { return a_; }
+};
+
+template<class PackedPixel> class image_sub_view;
+
+/**
+ * An image view abstracting raw packed pixel data
+ * <p>
+ * This is only a view, it does not own the data.
+ * <p>
+ * Models the the ImageView concept.
+ */
+template<class PackedPixel>
+class image_view
+{
+public:
+       typedef PackedPixel pixel_type;
+
+       image_view(void* raw_start, int width, int height)
+               : begin_(static_cast<PackedPixel*>(raw_start))
+               , end_(begin_ + (width * height))
+               , width_(width)
+               , height_(height)
+       {
+       }
+
+       PackedPixel* begin()
+       {
+               return begin_;
+       }
+
+       const PackedPixel* begin() const
+       {
+               return begin_;
+       }
+
+       PackedPixel* end()
+       {
+               return end_;
+       }
+
+       const PackedPixel* end() const
+       {
+               return end_;
+       }
+
+       template<class PackedPixelIter>
+       inline PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y)
+       {
+               auto pixel_distance = delta_x + width_ * delta_y;
+               PackedPixel* to_address = &(*to);
+               auto result = to_address + pixel_distance;
+
+               if (result < begin_ || result >= end_)
+                       return nullptr;
+               else
+                       return result;
+       }
+
+       template<class PackedPixelIter>
+       inline const PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y) const
+       {
+               //auto x_distance
+               auto pixel_distance = delta_x + width_ * delta_y;
+               const PackedPixel* to_address = &(*to);
+               auto result = to_address + pixel_distance;
+
+               /*if (delta_x != 0)
+               {
+                       auto actual_delta_y = result % width_
+               }*/
+
+               if (result < begin_ || result >= end_)
+                       return nullptr;
+               else
+                       return result;
+       }
+
+       int width() const
+       {
+               return width_;
+       }
+
+       int height() const
+       {
+               return height_;
+       }
+
+       image_sub_view<PackedPixel> subview(int x, int y, int width, int height)
+       {
+               return image_sub_view<PackedPixel>(*this, x, y, width, height);
+       }
+
+       const image_sub_view<PackedPixel> subview(int x, int y, int width, int height) const
+       {
+               return image_sub_view<PackedPixel>(*this, x, y, width, height);
+       }
+private:
+       PackedPixel* begin_;
+       PackedPixel* end_;
+       int width_;
+       int height_;
+};
+
+template<class PackedPixel>
+class is_within_view
+{
+public:
+       is_within_view(const PackedPixel* begin, int width, int stride)
+               : begin_(begin)
+               , width_(width)
+               , stride_(stride)
+               , no_check_(width == stride)
+       {
+       }
+
+       inline bool operator()(const PackedPixel& pixel) const
+       {
+               if (no_check_)
+                       return true;
+
+               const PackedPixel* position = &pixel;
+               int distance_from_row_start = (position - begin_) % stride_;
+
+               return distance_from_row_start < width_;
+       }
+private:
+       const PackedPixel* begin_;
+       int width_;
+       int stride_;
+       bool no_check_;
+};
+
+template <class PackedPixel>
+struct image_stride_iterator : public boost::filter_iterator<is_within_view<PackedPixel>, PackedPixel*>
+{
+       image_stride_iterator(PackedPixel* begin, PackedPixel* end, int width, int stride)
+               : boost::filter_iterator<is_within_view<PackedPixel>, PackedPixel*>::filter_iterator(
+                       is_within_view<PackedPixel>(begin, width, stride), begin, end)
+       {
+       }
+};
+
+/**
+ * A sub view created from an image_view.
+ * <p>
+ * This also models the ImageView concept.
+ */
+template<class PackedPixel>
+class image_sub_view
+{
+public:
+       typedef PackedPixel pixel_type;
+
+       image_sub_view(image_view<PackedPixel>& root_view, int x, int y, int width, int height)
+               : root_view_(root_view)
+               , relative_to_root_x_(x)
+               , relative_to_root_y_(y)
+               , width_(width)
+               , height_(height)
+               , raw_begin_(root_view.relative(root_view.begin(), x, y))
+               , raw_end_(root_view.relative(raw_begin_, width - 1, height_ - 1) + 1)
+       {
+       }
+
+       image_stride_iterator<PackedPixel> begin()
+       {
+               return image_stride_iterator<PackedPixel>(raw_begin_, raw_end_, width_, root_view_.width());
+       }
+
+       image_stride_iterator<const PackedPixel> begin() const
+       {
+               return image_stride_iterator<const PackedPixel>(raw_begin_, raw_end_, width_, root_view_.width());
+       }
+
+       image_stride_iterator<PackedPixel> end()
+       {
+               return image_stride_iterator<PackedPixel>(raw_end_, raw_end_, width_, root_view_.width());
+       }
+
+       image_stride_iterator<const PackedPixel> end() const
+       {
+               return image_stride_iterator<const PackedPixel>(raw_end_, raw_end_, width_, root_view_.width());
+       }
+
+       template<class PackedPixelIter>
+       PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y)
+       {
+               return root_view_.relative(to, delta_x, delta_y);
+       }
+
+       template<class PackedPixelIter>
+       const PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y) const
+       {
+               return root_view_.relative(to, delta_x, delta_y);
+       }
+
+       int width() const
+       {
+               return width_;
+       }
+
+       int height() const
+       {
+               return height_;
+       }
+
+       image_sub_view<PackedPixel> subview(int x, int y, int width, int height)
+       {
+               return root_view_.subview(relative_to_root_x_ + x, relative_to_root_y_ + y, width, height);
+       }
+
+       const image_sub_view<PackedPixel> subview(int x, int y, int width, int height) const
+       {
+               return root_view_.subview(relative_to_root_x_ + x, relative_to_root_y_ + y, width, height);
+       }
+private:
+       image_view<PackedPixel> root_view_;
+       int relative_to_root_x_;
+       int relative_to_root_y_;
+       int width_;
+       int height_;
+       PackedPixel* raw_begin_;
+       PackedPixel* raw_end_;
+};
+
+}}
index a756e85f0de10b741ebebd574d4625b2831ff14c..e65ef37ca4fa526128380f41a98f0099e1e01b32 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "oal_consumer.h"\r
-\r
-#include <common/except.h>\r
-#include <common/executor.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/log.h>\r
-#include <common/utf.h>\r
-#include <common/env.h>\r
-\r
-#include <core/consumer/frame_consumer.h>\r
-#include <core/frame/frame.h>\r
-#include <core/mixer/audio/audio_util.h>\r
-#include <core/mixer/audio/audio_mixer.h>\r
-#include <core/video_format.h>\r
-\r
-#include <boost/circular_buffer.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/timer.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/thread/once.hpp>\r
-\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <al/alc.h>\r
-#include <al/al.h>\r
-\r
-#include <array>\r
-\r
-namespace caspar { namespace oal {\r
-\r
-typedef std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>> audio_buffer_16;\r
-\r
-class device\r
-{\r
-       ALCdevice*                                                                                      device_;\r
-       ALCcontext*                                                                                     context_;\r
-\r
-public:\r
-       device()\r
-               : device_(0)\r
-               , context_(0)\r
-       {\r
-               device_ = alcOpenDevice(nullptr);\r
-\r
-               if(!device_)\r
-                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to initialize audio device."));\r
-\r
-               context_ = alcCreateContext(device_, nullptr);\r
-\r
-               if(!context_)\r
-                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to create audio context."));\r
-                       \r
-               if(alcMakeContextCurrent(context_) == ALC_FALSE)\r
-                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to activate audio context."));\r
-       }\r
-\r
-       ~device()\r
-       {\r
-               alcMakeContextCurrent(nullptr);\r
-\r
-               if(context_)\r
-                       alcDestroyContext(context_);\r
-\r
-               if(device_)\r
-                       alcCloseDevice(device_);\r
-       }\r
-\r
-       ALCdevice* get()\r
-       {\r
-               return device_;\r
-       }\r
-};\r
-\r
-void init_device()\r
-{\r
-       static std::unique_ptr<device> instance;\r
-       static boost::once_flag f = BOOST_ONCE_INIT;\r
-       \r
-       boost::call_once(f, []{instance.reset(new device());});\r
-}\r
-\r
-struct oal_consumer : public core::frame_consumer\r
-{\r
-       spl::shared_ptr<diagnostics::graph>                                     graph_;\r
-       boost::timer                                                                            perf_timer_;\r
-       int                                                                                                     channel_index_;\r
-       \r
-       core::video_format_desc                                                         format_desc_;\r
-\r
-       ALuint                                                                                          source_;\r
-       std::array<ALuint, 3>                                                           buffers_;\r
-\r
-       executor                                                                                        executor_;\r
-\r
-public:\r
-       oal_consumer() \r
-               : channel_index_(-1)\r
-               , source_(0)\r
-               , executor_(L"oal_consumer")\r
-       {\r
-               buffers_.assign(0);\r
-\r
-               init_device();\r
-\r
-               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   \r
-               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));\r
-               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));\r
-               diagnostics::register_graph(graph_);\r
-       }\r
-\r
-       ~oal_consumer()\r
-       {\r
-               executor_.begin_invoke([=]\r
-               {               \r
-                       if(source_)\r
-                       {\r
-                               alSourceStop(source_);\r
-                               alDeleteSources(1, &source_);\r
-                       }\r
-\r
-                       BOOST_FOREACH(auto& buffer, buffers_)\r
-                       {\r
-                               if(buffer)\r
-                                       alDeleteBuffers(1, &buffer);\r
-                       };\r
-               });\r
-       }\r
-\r
-       // frame consumer\r
-\r
-       void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
-       {\r
-               format_desc_    = format_desc;          \r
-               channel_index_  = channel_index;\r
-               graph_->set_text(print());\r
-               \r
-               executor_.begin_invoke([=]\r
-               {               \r
-                       alGenBuffers(static_cast<ALsizei>(buffers_.size()), buffers_.data());\r
-                       alGenSources(1, &source_);\r
-\r
-                       for(std::size_t n = 0; n < buffers_.size(); ++n)\r
-                       {\r
-                               std::vector<int16_t> audio(format_desc_.audio_cadence[n % format_desc_.audio_cadence.size()], 0);\r
-                               alBufferData(buffers_[n], AL_FORMAT_STEREO16, audio.data(), static_cast<ALsizei>(audio.size()*sizeof(int16_t)), format_desc_.audio_sample_rate);\r
-                               alSourceQueueBuffers(source_, 1, &buffers_[n]);\r
-                       }\r
-                       \r
-                       alSourcei(source_, AL_LOOPING, AL_FALSE);\r
-\r
-                       alSourcePlay(source_);  \r
-               });\r
-       }\r
-       \r
-       bool send(core::const_frame frame) override\r
-       {                       \r
-               executor_.begin_invoke([=]\r
-               {\r
-                       ALenum state; \r
-                       alGetSourcei(source_, AL_SOURCE_STATE,&state);\r
-                       if(state != AL_PLAYING)\r
-                       {\r
-                               for(int n = 0; n < buffers_.size()-1; ++n)\r
-                               {                                       \r
-                                       ALuint buffer = 0;  \r
-                                       alSourceUnqueueBuffers(source_, 1, &buffer);\r
-                                       if(buffer)\r
-                                       {\r
-                                               std::vector<int16_t> audio(format_desc_.audio_cadence[n % format_desc_.audio_cadence.size()], 0);\r
-                                               alBufferData(buffer, AL_FORMAT_STEREO16, audio.data(), static_cast<ALsizei>(audio.size()*sizeof(int16_t)), format_desc_.audio_sample_rate);\r
-                                               alSourceQueueBuffers(source_, 1, &buffer);\r
-                                       }\r
-                               }\r
-                               alSourcePlay(source_);          \r
-                               graph_->set_tag("late-frame");  \r
-                       }\r
-\r
-                       auto audio = core::audio_32_to_16(frame.audio_data());\r
-                       \r
-                       ALuint buffer = 0;  \r
-                       alSourceUnqueueBuffers(source_, 1, &buffer);\r
-                       if(buffer)\r
-                       {\r
-                               alBufferData(buffer, AL_FORMAT_STEREO16, audio.data(), static_cast<ALsizei>(audio.size()*sizeof(int16_t)), format_desc_.audio_sample_rate);\r
-                               alSourceQueueBuffers(source_, 1, &buffer);\r
-                       }\r
-                       else\r
-                               graph_->set_tag("dropped-frame");\r
-\r
-                       graph_->set_value("tick-time", perf_timer_.elapsed()*format_desc_.fps*0.5);             \r
-                       perf_timer_.restart();\r
-               });\r
-\r
-               return true;\r
-       }\r
-       \r
-       std::wstring print() const override\r
-       {\r
-               return L"oal[" + boost::lexical_cast<std::wstring>(channel_index_) + L"|" + format_desc_.name + L"]";\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"system-audio";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"system-audio");\r
-               return info;\r
-       }\r
-       \r
-       bool has_synchronization_clock() const override\r
-       {\r
-               return false;\r
-       }\r
-       \r
-       int buffer_depth() const override\r
-       {\r
-               return 3;\r
-       }\r
-               \r
-       int index() const override\r
-       {\r
-               return 500;\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }       \r
-};\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)\r
-{\r
-       if(params.size() < 1 || params[0] != L"AUDIO")\r
-               return core::frame_consumer::empty();\r
-\r
-       return spl::make_shared<oal_consumer>();\r
-}\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer()\r
-{\r
-       return spl::make_shared<oal_consumer>();\r
-}\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "oal_consumer.h"
+
+#include <common/except.h>
+#include <common/executor.h>
+#include <common/diagnostics/graph.h>
+#include <common/log.h>
+#include <common/utf.h>
+#include <common/env.h>
+
+#include <core/consumer/frame_consumer.h>
+#include <core/frame/frame.h>
+#include <core/mixer/audio/audio_util.h>
+#include <core/mixer/audio/audio_mixer.h>
+#include <core/video_format.h>
+
+#include <boost/circular_buffer.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/timer.hpp>
+#include <boost/foreach.hpp>
+#include <boost/thread/once.hpp>
+
+#include <tbb/concurrent_queue.h>
+
+#include <al/alc.h>
+#include <al/al.h>
+
+#include <array>
+
+namespace caspar { namespace oal {
+
+typedef std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>> audio_buffer_16;
+
+class device
+{
+       ALCdevice*                                                                                      device_;
+       ALCcontext*                                                                                     context_;
+
+public:
+       device()
+               : device_(0)
+               , context_(0)
+       {
+               device_ = alcOpenDevice(nullptr);
+
+               if(!device_)
+                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to initialize audio device."));
+
+               context_ = alcCreateContext(device_, nullptr);
+
+               if(!context_)
+                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to create audio context."));
+                       
+               if(alcMakeContextCurrent(context_) == ALC_FALSE)
+                       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Failed to activate audio context."));
+       }
+
+       ~device()
+       {
+               alcMakeContextCurrent(nullptr);
+
+               if(context_)
+                       alcDestroyContext(context_);
+
+               if(device_)
+                       alcCloseDevice(device_);
+       }
+
+       ALCdevice* get()
+       {
+               return device_;
+       }
+};
+
+void init_device()
+{
+       static std::unique_ptr<device> instance;
+       static boost::once_flag f = BOOST_ONCE_INIT;
+       
+       boost::call_once(f, []{instance.reset(new device());});
+}
+
+struct oal_consumer : public core::frame_consumer
+{
+       spl::shared_ptr<diagnostics::graph>                                     graph_;
+       boost::timer                                                                            perf_timer_;
+       int                                                                                                     channel_index_;
+       
+       core::video_format_desc                                                         format_desc_;
+
+       ALuint                                                                                          source_;
+       std::array<ALuint, 3>                                                           buffers_;
+
+       executor                                                                                        executor_;
+
+public:
+       oal_consumer() 
+               : channel_index_(-1)
+               , source_(0)
+               , executor_(L"oal_consumer")
+       {
+               buffers_.assign(0);
+
+               init_device();
+
+               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   
+               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));
+               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));
+               diagnostics::register_graph(graph_);
+       }
+
+       ~oal_consumer()
+       {
+               executor_.begin_invoke([=]
+               {               
+                       if(source_)
+                       {
+                               alSourceStop(source_);
+                               alDeleteSources(1, &source_);
+                       }
+
+                       BOOST_FOREACH(auto& buffer, buffers_)
+                       {
+                               if(buffer)
+                                       alDeleteBuffers(1, &buffer);
+                       };
+               });
+       }
+
+       // frame consumer
+
+       void initialize(const core::video_format_desc& format_desc, int channel_index) override
+       {
+               format_desc_    = format_desc;          
+               channel_index_  = channel_index;
+               graph_->set_text(print());
+               
+               executor_.begin_invoke([=]
+               {               
+                       alGenBuffers(static_cast<ALsizei>(buffers_.size()), buffers_.data());
+                       alGenSources(1, &source_);
+
+                       for(std::size_t n = 0; n < buffers_.size(); ++n)
+                       {
+                               std::vector<int16_t> audio(format_desc_.audio_cadence[n % format_desc_.audio_cadence.size()], 0);
+                               alBufferData(buffers_[n], AL_FORMAT_STEREO16, audio.data(), static_cast<ALsizei>(audio.size()*sizeof(int16_t)), format_desc_.audio_sample_rate);
+                               alSourceQueueBuffers(source_, 1, &buffers_[n]);
+                       }
+                       
+                       alSourcei(source_, AL_LOOPING, AL_FALSE);
+
+                       alSourcePlay(source_);  
+               });
+       }
+       
+       bool send(core::const_frame frame) override
+       {                       
+               executor_.begin_invoke([=]
+               {
+                       ALenum state; 
+                       alGetSourcei(source_, AL_SOURCE_STATE,&state);
+                       if(state != AL_PLAYING)
+                       {
+                               for(int n = 0; n < buffers_.size()-1; ++n)
+                               {                                       
+                                       ALuint buffer = 0;  
+                                       alSourceUnqueueBuffers(source_, 1, &buffer);
+                                       if(buffer)
+                                       {
+                                               std::vector<int16_t> audio(format_desc_.audio_cadence[n % format_desc_.audio_cadence.size()], 0);
+                                               alBufferData(buffer, AL_FORMAT_STEREO16, audio.data(), static_cast<ALsizei>(audio.size()*sizeof(int16_t)), format_desc_.audio_sample_rate);
+                                               alSourceQueueBuffers(source_, 1, &buffer);
+                                       }
+                               }
+                               alSourcePlay(source_);          
+                               graph_->set_tag("late-frame");  
+                       }
+
+                       auto audio = core::audio_32_to_16(frame.audio_data());
+                       
+                       ALuint buffer = 0;  
+                       alSourceUnqueueBuffers(source_, 1, &buffer);
+                       if(buffer)
+                       {
+                               alBufferData(buffer, AL_FORMAT_STEREO16, audio.data(), static_cast<ALsizei>(audio.size()*sizeof(int16_t)), format_desc_.audio_sample_rate);
+                               alSourceQueueBuffers(source_, 1, &buffer);
+                       }
+                       else
+                               graph_->set_tag("dropped-frame");
+
+                       graph_->set_value("tick-time", perf_timer_.elapsed()*format_desc_.fps*0.5);             
+                       perf_timer_.restart();
+               });
+
+               return true;
+       }
+       
+       std::wstring print() const override
+       {
+               return L"oal[" + boost::lexical_cast<std::wstring>(channel_index_) + L"|" + format_desc_.name + L"]";
+       }
+
+       std::wstring name() const override
+       {
+               return L"system-audio";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"system-audio");
+               return info;
+       }
+       
+       bool has_synchronization_clock() const override
+       {
+               return false;
+       }
+       
+       int buffer_depth() const override
+       {
+               return 3;
+       }
+               
+       int index() const override
+       {
+               return 500;
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }       
+};
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+{
+       if(params.size() < 1 || params[0] != L"AUDIO")
+               return core::frame_consumer::empty();
+
+       return spl::make_shared<oal_consumer>();
+}
+
+spl::shared_ptr<core::frame_consumer> create_consumer()
+{
+       return spl::make_shared<oal_consumer>();
+}
+
+}}
index cdd32b0dd4623b9524292afb356ce9d92ee98af6..e9f956bc517e0a1f76c9af75bc25bb5cb72adb22 100644 (file)
@@ -1,41 +1,41 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <core/video_format.h>\r
-\r
-#include <vector>\r
-\r
-namespace caspar { \r
-\r
-namespace core {\r
-       class frame_consumer;\r
-}      \r
-\r
-namespace oal {\r
-       \r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);\r
-spl::shared_ptr<core::frame_consumer> create_consumer();\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <core/video_format.h>
+
+#include <vector>
+
+namespace caspar { 
+
+namespace core {
+       class frame_consumer;
+}      
+
+namespace oal {
+       
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_consumer> create_consumer();
+
 }}
\ No newline at end of file
index 696fe3ea2a70d69d80e2f3344f0c5dd8844d996c..a2c191050ac42c774a114a99a0615747105007b2 100644 (file)
@@ -1,35 +1,35 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "oal.h"\r
-\r
-#include "consumer/oal_consumer.h"\r
-\r
-#include <core/consumer/frame_consumer.h>\r
-\r
-namespace caspar { namespace oal {\r
-\r
-void init()\r
-{\r
-       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "oal.h"
+
+#include "consumer/oal_consumer.h"
+
+#include <core/consumer/frame_consumer.h>
+
+namespace caspar { namespace oal {
+
+void init()
+{
+       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+}
+
 }}
\ No newline at end of file
index 5bf91240432d5acfbf6f7120654f862a1c4e7d69..59cd93dab1856b905ddc394e19e3d164b324b769 100644 (file)
@@ -1,28 +1,28 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-namespace caspar { namespace oal {\r
-\r
-void init();\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+namespace caspar { namespace oal {
+
+void init();
+
 }}
\ No newline at end of file
index 127285c74f167a7a31ab6b15ace2643fa2f23c1b..11313a1077dbc48b26c3329eafc940d76e00544f 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "reroute_producer.h"\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/frame/draw_frame.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/frame/frame.h>\r
-#include <core/video_channel.h>\r
-#include <core/producer/stage.h>\r
-\r
-#include <common/except.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/log.h>\r
-#include <common/reactive.h>\r
-\r
-#include <asmlib.h>\r
-\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/optional.hpp>\r
-#include <boost/range/algorithm_ext/push_back.hpp>\r
-#include <boost/range/numeric.hpp>\r
-#include <boost/range/adaptor/map.hpp>\r
-\r
-#include <queue>\r
-\r
-namespace caspar { namespace reroute {\r
-               \r
-class reroute_producer : public reactive::observer<std::map<int, core::draw_frame>>\r
-                                          , public core::frame_producer_base\r
-{\r
-       const spl::shared_ptr<diagnostics::graph>                                               graph_;\r
-       \r
-       tbb::concurrent_bounded_queue<std::map<int, core::draw_frame>>  input_buffer_;\r
-public:\r
-       explicit reroute_producer() \r
-       {\r
-               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));\r
-               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));\r
-               graph_->set_text(print());\r
-               diagnostics::register_graph(graph_);\r
-\r
-               input_buffer_.set_capacity(1);\r
-       }\r
-               \r
-       // observable\r
-\r
-       void on_next(const std::map<int, core::draw_frame>& frames)\r
-       {\r
-               if(!input_buffer_.try_push(frames))\r
-                       graph_->set_tag("dropped-frame");               \r
-       }\r
-\r
-       // frame_producer\r
-                       \r
-       core::draw_frame receive_impl() override\r
-       {               \r
-               std::map<int, core::draw_frame> frames;\r
-               if(!input_buffer_.try_pop(frames))\r
-               {\r
-                       graph_->set_tag("late-frame");\r
-                       return core::draw_frame::late();                \r
-               }\r
-\r
-               return boost::accumulate(frames | boost::adaptors::map_values, core::draw_frame::empty(), core::draw_frame::over);\r
-       }       \r
-               \r
-       std::wstring print() const override\r
-       {\r
-               return L"reroute[]";\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"reroute";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"rerotue-producer");\r
-               return info;\r
-       }\r
-               \r
-       void subscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }\r
-};\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(core::video_channel& channel)\r
-{\r
-       auto producer = spl::make_shared<reroute_producer>();\r
-       \r
-       std::weak_ptr<reactive::observer<std::map<int, core::draw_frame>>> o = producer;\r
-\r
-       channel.stage().subscribe(o);\r
-\r
-       return producer;\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "reroute_producer.h"
+
+#include <core/producer/frame_producer.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_factory.h>
+#include <core/frame/pixel_format.h>
+#include <core/frame/frame.h>
+#include <core/video_channel.h>
+#include <core/producer/stage.h>
+
+#include <common/except.h>
+#include <common/diagnostics/graph.h>
+#include <common/log.h>
+#include <common/reactive.h>
+
+#include <asmlib.h>
+
+#include <tbb/concurrent_queue.h>
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/foreach.hpp>
+#include <boost/optional.hpp>
+#include <boost/range/algorithm_ext/push_back.hpp>
+#include <boost/range/numeric.hpp>
+#include <boost/range/adaptor/map.hpp>
+
+#include <queue>
+
+namespace caspar { namespace reroute {
+               
+class reroute_producer : public reactive::observer<std::map<int, core::draw_frame>>
+                                          , public core::frame_producer_base
+{
+       const spl::shared_ptr<diagnostics::graph>                                               graph_;
+       
+       tbb::concurrent_bounded_queue<std::map<int, core::draw_frame>>  input_buffer_;
+public:
+       explicit reroute_producer() 
+       {
+               graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));
+               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));
+               graph_->set_text(print());
+               diagnostics::register_graph(graph_);
+
+               input_buffer_.set_capacity(1);
+       }
+               
+       // observable
+
+       void on_next(const std::map<int, core::draw_frame>& frames)
+       {
+               if(!input_buffer_.try_push(frames))
+                       graph_->set_tag("dropped-frame");               
+       }
+
+       // frame_producer
+                       
+       core::draw_frame receive_impl() override
+       {               
+               std::map<int, core::draw_frame> frames;
+               if(!input_buffer_.try_pop(frames))
+               {
+                       graph_->set_tag("late-frame");
+                       return core::draw_frame::late();                
+               }
+
+               return boost::accumulate(frames | boost::adaptors::map_values, core::draw_frame::empty(), core::draw_frame::over);
+       }       
+               
+       std::wstring print() const override
+       {
+               return L"reroute[]";
+       }
+
+       std::wstring name() const override
+       {
+               return L"reroute";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"rerotue-producer");
+               return info;
+       }
+               
+       void subscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }
+};
+
+spl::shared_ptr<core::frame_producer> create_producer(core::video_channel& channel)
+{
+       auto producer = spl::make_shared<reroute_producer>();
+       
+       std::weak_ptr<reactive::observer<std::map<int, core::draw_frame>>> o = producer;
+
+       channel.stage().subscribe(o);
+
+       return producer;
+}
+
 }}
\ No newline at end of file
index 3a99bae89dbca7bb11f319a6db311e3b4603fd91..bdbc35722a40b07a946db1497e756b41e2e6617a 100644 (file)
@@ -1,35 +1,35 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-#include <common/forward.h>\r
-#include <common/reactive.h>\r
-\r
-FORWARD2(caspar, core, class video_channel);\r
-FORWARD2(caspar, core, class frame_producer);\r
-\r
-namespace caspar { namespace reroute {\r
-       \r
-spl::shared_ptr<core::frame_producer> create_producer(core::video_channel& channel);\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+#include <common/forward.h>
+#include <common/reactive.h>
+
+FORWARD2(caspar, core, class video_channel);
+FORWARD2(caspar, core, class frame_producer);
+
+namespace caspar { namespace reroute {
+       
+spl::shared_ptr<core::frame_producer> create_producer(core::video_channel& channel);
+
+}}
index a9907817ada2d17aadfcee7e367ca84c9f4cd4c1..00cbe1813c40917d5dc76825734de998dc3c6fce 100644 (file)
@@ -1,8 +1,8 @@
-// stdafx.cpp : source file that includes just the standard includes\r
-// reroute.pch will be the pre-compiled header\r
-// stdafx.obj will contain the pre-compiled type information\r
-\r
-#include "stdafx.h"\r
-\r
-// TODO: reference any additional headers you need in STDAFX.H\r
-// and not in this file\r
+// stdafx.cpp : source file that includes just the standard includes
+// reroute.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
index 50e96676b70271de5381be782b231014f1d79efe..6f70f09beec2219624baeca92e2cd7deaa104fb4 100644 (file)
@@ -1 +1 @@
-#pragma once\r
+#pragma once
index 46b9203a4aa9aae7e49d4508234abbc9519c31b3..45b5b8a30bcf90aba773e7abd093c823dbfd9b6f 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "screen_consumer.h"\r
-\r
-#include <GL/glew.h>\r
-#include <SFML/Window.hpp>\r
-\r
-#include <common/diagnostics/graph.h>\r
-#include <common/gl/gl_check.h>\r
-#include <common/log.h>\r
-#include <common/memory.h>\r
-#include <common/array.h>\r
-#include <common/memshfl.h>\r
-#include <common/utf.h>\r
-#include <common/prec_timer.h>\r
-\r
-#include <ffmpeg/producer/filter/filter.h>\r
-\r
-#include <core/video_format.h>\r
-#include <core/frame/frame.h>\r
-#include <core/consumer/frame_consumer.h>\r
-\r
-#include <boost/timer.hpp>\r
-#include <boost/circular_buffer.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/thread.hpp>\r
-\r
-#include <tbb/atomic.h>\r
-#include <tbb/concurrent_queue.h>\r
-#include <tbb/parallel_for.h>\r
-\r
-#include <boost/assign.hpp>\r
-\r
-#include <asmlib.h>\r
-\r
-#include <algorithm>\r
-#include <vector>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
-       #define __STDC_LIMIT_MACROS\r
-       #include <libavcodec/avcodec.h>\r
-       #include <libavutil/imgutils.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar { namespace screen {\r
-               \r
-enum stretch\r
-{\r
-       none,\r
-       uniform,\r
-       fill,\r
-       uniform_to_fill\r
-};\r
-\r
-struct configuration\r
-{\r
-       enum aspect_ratio\r
-       {\r
-               aspect_4_3 = 0,\r
-               aspect_16_9,\r
-               aspect_invalid,\r
-       };\r
-               \r
-       std::wstring    name;\r
-       int                             screen_index;\r
-       stretch                 stretch;\r
-       bool                    windowed;\r
-       bool                    auto_deinterlace;\r
-       bool                    key_only;\r
-       aspect_ratio    aspect; \r
-       bool                    vsync;\r
-\r
-       configuration()\r
-               : name(L"ogl")\r
-               , screen_index(0)\r
-               , stretch(fill)\r
-               , windowed(true)\r
-               , auto_deinterlace(true)\r
-               , key_only(false)\r
-               , aspect(aspect_invalid)\r
-               , vsync(true)\r
-       {\r
-       }\r
-};\r
-\r
-struct screen_consumer : boost::noncopyable\r
-{              \r
-       const configuration                                     config_;\r
-       core::video_format_desc                         format_desc_;\r
-       int                                                                     channel_index_;\r
-\r
-       GLuint                                                          texture_;\r
-       std::vector<GLuint>                                     pbos_;\r
-                       \r
-       float                                                           width_;\r
-       float                                                           height_;        \r
-       int                                                                     screen_x_;\r
-       int                                                                     screen_y_;\r
-       int                                                                     screen_width_;\r
-       int                                                                     screen_height_;\r
-       int                                                                     square_width_;\r
-       int                                                                     square_height_;                         \r
-       \r
-       sf::Window                                                      window_;\r
-       \r
-       spl::shared_ptr<diagnostics::graph>     graph_;\r
-       boost::timer                                            perf_timer_;\r
-       boost::timer                                            tick_timer_;\r
-\r
-       caspar::prec_timer                                      wait_timer_;\r
-\r
-       tbb::concurrent_bounded_queue<core::const_frame>        frame_buffer_;\r
-\r
-       boost::thread                                           thread_;\r
-       tbb::atomic<bool>                                       is_running_;\r
-       \r
-       ffmpeg::filter                                          filter_;\r
-public:\r
-       screen_consumer(const configuration& config, const core::video_format_desc& format_desc, int channel_index) \r
-               : config_(config)\r
-               , format_desc_(format_desc)\r
-               , channel_index_(channel_index)\r
-               , texture_(0)\r
-               , pbos_(2, 0)   \r
-               , screen_width_(format_desc.width)\r
-               , screen_height_(format_desc.height)\r
-               , square_width_(format_desc.square_width)\r
-               , square_height_(format_desc.square_height)\r
-               , filter_(format_desc.field_mode == core::field_mode::progressive || !config.auto_deinterlace ? L"" : L"YADIF=1:-1", boost::assign::list_of(PIX_FMT_BGRA))\r
-       {               \r
-               if(format_desc_.format == core::video_format::ntsc && config_.aspect == configuration::aspect_4_3)\r
-               {\r
-                       // Use default values which are 4:3.\r
-               }\r
-               else\r
-               {\r
-                       if(config_.aspect == configuration::aspect_16_9)\r
-                               square_width_ = (format_desc.height*16)/9;\r
-                       else if(config_.aspect == configuration::aspect_4_3)\r
-                               square_width_ = (format_desc.height*4)/3;\r
-               }\r
-\r
-               frame_buffer_.set_capacity(2);\r
-               \r
-               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   \r
-               graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));\r
-               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));\r
-               graph_->set_text(print());\r
-               diagnostics::register_graph(graph_);\r
-                                                                       \r
-               DISPLAY_DEVICE d_device = {sizeof(d_device), 0};                        \r
-               std::vector<DISPLAY_DEVICE> displayDevices;\r
-               for(int n = 0; EnumDisplayDevices(NULL, n, &d_device, NULL); ++n)\r
-                       displayDevices.push_back(d_device);\r
-\r
-               if(config_.screen_index >= displayDevices.size())\r
-                       CASPAR_LOG(warning) << print() << L" Invalid screen-index: " << config_.screen_index;\r
-               \r
-               DEVMODE devmode = {};\r
-               if(!EnumDisplaySettings(displayDevices[config_.screen_index].DeviceName, ENUM_CURRENT_SETTINGS, &devmode))\r
-                       CASPAR_LOG(warning) << print() << L" Could not find display settings for screen-index: " << config_.screen_index;\r
-               \r
-               screen_x_               = devmode.dmPosition.x;\r
-               screen_y_               = devmode.dmPosition.y;\r
-               screen_width_   = config_.windowed ? square_width_ : devmode.dmPelsWidth;\r
-               screen_height_  = config_.windowed ? square_height_ : devmode.dmPelsHeight;\r
-               \r
-               is_running_ = true;\r
-               thread_ = boost::thread([this]{run();});\r
-       }\r
-       \r
-       ~screen_consumer()\r
-       {\r
-               is_running_ = false;\r
-               frame_buffer_.try_push(core::const_frame::empty());\r
-               thread_.join();\r
-       }\r
-\r
-       void init()\r
-       {\r
-               window_.Create(sf::VideoMode(screen_width_, screen_height_, 32), u8(print()), config_.windowed ? sf::Style::Resize | sf::Style::Close : sf::Style::Fullscreen);\r
-               window_.ShowMouseCursor(false);\r
-               window_.SetPosition(screen_x_, screen_y_);\r
-               window_.SetSize(screen_width_, screen_height_);\r
-               window_.SetActive();\r
-               \r
-               if(!GLEW_VERSION_2_1 && glewInit() != GLEW_OK)\r
-                       CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to initialize GLEW."));\r
-\r
-               if(!GLEW_VERSION_2_1)\r
-                       CASPAR_THROW_EXCEPTION(not_supported() << msg_info("Missing OpenGL 2.1 support."));\r
-\r
-               GL(glEnable(GL_TEXTURE_2D));\r
-               GL(glDisable(GL_DEPTH_TEST));           \r
-               GL(glClearColor(0.0, 0.0, 0.0, 0.0));\r
-               GL(glViewport(0, 0, format_desc_.width, format_desc_.height));\r
-               GL(glLoadIdentity());\r
-                               \r
-               calculate_aspect();\r
-                       \r
-               GL(glGenTextures(1, &texture_));\r
-               GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
-               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
-               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\r
-               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP));\r
-               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));\r
-               GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, format_desc_.width, format_desc_.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0));\r
-               GL(glBindTexture(GL_TEXTURE_2D, 0));\r
-                                       \r
-               GL(glGenBuffers(2, pbos_.data()));\r
-                       \r
-               glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbos_[0]);\r
-               glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW_ARB);\r
-               glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbos_[1]);\r
-               glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW_ARB);\r
-               glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);\r
-               \r
-               auto wglSwapIntervalEXT = reinterpret_cast<void(APIENTRY*)(int)>(wglGetProcAddress("wglSwapIntervalEXT"));\r
-               if(wglSwapIntervalEXT)\r
-               {\r
-                       if(config_.vsync)\r
-                       {\r
-                               wglSwapIntervalEXT(1);\r
-                               CASPAR_LOG(info) << print() << " Enabled vsync.";\r
-                       }\r
-                       else\r
-                               wglSwapIntervalEXT(0);\r
-               }\r
-\r
-               CASPAR_LOG(info) << print() << " Successfully Initialized.";\r
-       }\r
-\r
-       void uninit()\r
-       {               \r
-               if(texture_)\r
-                       glDeleteTextures(1, &texture_);\r
-\r
-               BOOST_FOREACH(auto& pbo, pbos_)\r
-               {\r
-                       if(pbo)\r
-                               glDeleteBuffers(1, &pbo);\r
-               }\r
-       }\r
-\r
-       void run()\r
-       {\r
-               try\r
-               {\r
-                       init();\r
-\r
-                       while(is_running_)\r
-                       {                       \r
-                               try\r
-                               {\r
-                                       sf::Event e;            \r
-                                       while(window_.GetEvent(e))\r
-                                       {\r
-                                               if(e.Type == sf::Event::Resized)\r
-                                                       calculate_aspect();\r
-                                               else if(e.Type == sf::Event::Closed)\r
-                                                       is_running_ = false;\r
-                                       }\r
-                       \r
-                                       auto frame = core::const_frame::empty();\r
-                                       frame_buffer_.pop(frame);\r
-\r
-                                       render_and_draw_frame(frame);\r
-                                       \r
-                                       /*perf_timer_.restart();\r
-                                       render(frame);\r
-                                       graph_->set_value("frame-time", perf_timer_.elapsed()*format_desc_.fps*0.5);    \r
-\r
-                                       window_.Display();*/\r
-\r
-                                       graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5);     \r
-                                       tick_timer_.restart();\r
-                               }\r
-                               catch(...)\r
-                               {\r
-                                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                                       is_running_ = false;\r
-                               }\r
-                       }\r
-\r
-                       uninit();\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-       }\r
-\r
-       void try_sleep_almost_until_vblank()\r
-       {\r
-               static const double THRESHOLD = 0.003;\r
-               double threshold = config_.vsync ? THRESHOLD : 0.0;\r
-\r
-               auto frame_time = 1.0 / (format_desc_.fps * format_desc_.field_count);\r
-\r
-               wait_timer_.tick(frame_time - threshold);\r
-       }\r
-\r
-       void wait_for_vblank_and_display()\r
-       {\r
-               try_sleep_almost_until_vblank();\r
-               window_.Display();\r
-               // Make sure that the next tick measures the duration from this point in time.\r
-               wait_timer_.tick(0.0);\r
-       }\r
-\r
-       spl::shared_ptr<AVFrame> get_av_frame()\r
-       {               \r
-               spl::shared_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);      \r
-               avcodec_get_frame_defaults(av_frame.get());\r
-                                               \r
-               av_frame->linesize[0]           = format_desc_.width*4;                 \r
-               av_frame->format                        = PIX_FMT_BGRA;\r
-               av_frame->width                         = format_desc_.width;\r
-               av_frame->height                        = format_desc_.height;\r
-               av_frame->interlaced_frame      = format_desc_.field_mode != core::field_mode::progressive;\r
-               av_frame->top_field_first       = format_desc_.field_mode == core::field_mode::upper ? 1 : 0;\r
-\r
-               return av_frame;\r
-       }\r
-\r
-       void render_and_draw_frame(core::const_frame frame)\r
-       {\r
-               if(static_cast<size_t>(frame.image_data().size()) != format_desc_.size)\r
-                       return;\r
-\r
-               if(screen_width_ == 0 && screen_height_ == 0)\r
-                       return;\r
-                                       \r
-               perf_timer_.restart();\r
-               auto av_frame = get_av_frame();\r
-               av_frame->data[0] = const_cast<uint8_t*>(frame.image_data().begin());\r
-\r
-               filter_.push(av_frame);\r
-               auto frames = filter_.poll_all();\r
-\r
-               if (frames.empty())\r
-                       return;\r
-\r
-               if (frames.size() == 1)\r
-               {\r
-                       render(frames[0]);\r
-                       graph_->set_value("frame-time", perf_timer_.elapsed() * format_desc_.fps * 0.5);\r
-\r
-                       wait_for_vblank_and_display(); // progressive frame\r
-               }\r
-               else if (frames.size() == 2)\r
-               {\r
-                       render(frames[0]);\r
-                       double perf_elapsed = perf_timer_.elapsed();\r
-\r
-                       wait_for_vblank_and_display(); // field1\r
-\r
-                       perf_timer_.restart();\r
-                       render(frames[1]);\r
-                       perf_elapsed += perf_timer_.elapsed();\r
-                       graph_->set_value("frame-time", perf_elapsed * format_desc_.fps * 0.5);\r
-\r
-                       wait_for_vblank_and_display(); // field2\r
-               }\r
-       }\r
-\r
-       void render(spl::shared_ptr<AVFrame> av_frame)\r
-       {\r
-               GL(glBindTexture(GL_TEXTURE_2D, texture_));\r
-\r
-               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[0]));\r
-               GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, format_desc_.width, format_desc_.height, GL_BGRA, GL_UNSIGNED_BYTE, 0));\r
-\r
-               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[1]));\r
-               GL(glBufferData(GL_PIXEL_UNPACK_BUFFER, format_desc_.size, 0, GL_STREAM_DRAW));\r
-\r
-               auto ptr = reinterpret_cast<char*>(GL2(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY)));\r
-               if(ptr)\r
-               {\r
-                       if(config_.key_only)\r
-                       {\r
-                               tbb::parallel_for(tbb::blocked_range<int>(0, format_desc_.height), [&](const tbb::blocked_range<int>& r)\r
-                               {\r
-                                       for(int n = r.begin(); n != r.end(); ++n)\r
-                                               aligned_memshfl(ptr+n*format_desc_.width*4, av_frame->data[0]+n*av_frame->linesize[0], format_desc_.width*4, 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
-                               });\r
-                       }\r
-                       else\r
-                       {       \r
-                               tbb::parallel_for(tbb::blocked_range<int>(0, format_desc_.height), [&](const tbb::blocked_range<int>& r)\r
-                               {\r
-                                       for(int n = r.begin(); n != r.end(); ++n)\r
-                                               A_memcpy(ptr+n*format_desc_.width*4, av_frame->data[0]+n*av_frame->linesize[0], format_desc_.width*4);\r
-                               });\r
-                       }\r
-                       \r
-                       GL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER)); // release the mapped buffer\r
-               }\r
-\r
-               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
-                               \r
-               GL(glClear(GL_COLOR_BUFFER_BIT));                       \r
-               glBegin(GL_QUADS);\r
-                               glTexCoord2f(0.0f,        1.0f);        glVertex2f(-width_, -height_);\r
-                               glTexCoord2f(1.0f,        1.0f);        glVertex2f( width_, -height_);\r
-                               glTexCoord2f(1.0f,        0.0f);        glVertex2f( width_,  height_);\r
-                               glTexCoord2f(0.0f,        0.0f);        glVertex2f(-width_,  height_);\r
-               glEnd();\r
-               \r
-               GL(glBindTexture(GL_TEXTURE_2D, 0));\r
-\r
-               std::rotate(pbos_.begin(), pbos_.begin() + 1, pbos_.end());\r
-       }\r
-\r
-\r
-       bool send(core::const_frame frame)\r
-       {\r
-               if(!frame_buffer_.try_push(frame))\r
-                       graph_->set_tag("dropped-frame");\r
-               return is_running_;\r
-       }\r
-               \r
-       std::wstring print() const\r
-       {       \r
-               return config_.name + L"[" + boost::lexical_cast<std::wstring>(channel_index_) + L"|" + format_desc_.name + L"]";\r
-       }\r
-       \r
-       void calculate_aspect()\r
-       {\r
-               if(config_.windowed)\r
-               {\r
-                       screen_height_ = window_.GetHeight();\r
-                       screen_width_ = window_.GetWidth();\r
-               }\r
-               \r
-               GL(glViewport(0, 0, screen_width_, screen_height_));\r
-\r
-               std::pair<float, float> target_ratio = None();\r
-               if(config_.stretch == fill)\r
-                       target_ratio = Fill();\r
-               else if(config_.stretch == uniform)\r
-                       target_ratio = Uniform();\r
-               else if(config_.stretch == uniform_to_fill)\r
-                       target_ratio = UniformToFill();\r
-\r
-               width_ = target_ratio.first;\r
-               height_ = target_ratio.second;\r
-       }\r
-               \r
-       std::pair<float, float> None()\r
-       {\r
-               float width = static_cast<float>(square_width_)/static_cast<float>(screen_width_);\r
-               float height = static_cast<float>(square_height_)/static_cast<float>(screen_height_);\r
-\r
-               return std::make_pair(width, height);\r
-       }\r
-\r
-       std::pair<float, float> Uniform()\r
-       {\r
-               float aspect = static_cast<float>(square_width_)/static_cast<float>(square_height_);\r
-               float width = std::min(1.0f, static_cast<float>(screen_height_)*aspect/static_cast<float>(screen_width_));\r
-               float height = static_cast<float>(screen_width_*width)/static_cast<float>(screen_height_*aspect);\r
-\r
-               return std::make_pair(width, height);\r
-       }\r
-\r
-       std::pair<float, float> Fill()\r
-       {\r
-               return std::make_pair(1.0f, 1.0f);\r
-       }\r
-\r
-       std::pair<float, float> UniformToFill()\r
-       {\r
-               float wr = static_cast<float>(square_width_)/static_cast<float>(screen_width_);\r
-               float hr = static_cast<float>(square_height_)/static_cast<float>(screen_height_);\r
-               float r_inv = 1.0f/std::min(wr, hr);\r
-\r
-               float width = wr*r_inv;\r
-               float height = hr*r_inv;\r
-\r
-               return std::make_pair(width, height);\r
-       }\r
-};\r
-\r
-\r
-struct screen_consumer_proxy : public core::frame_consumer\r
-{\r
-       const configuration config_;\r
-       std::unique_ptr<screen_consumer> consumer_;\r
-\r
-public:\r
-\r
-       screen_consumer_proxy(const configuration& config)\r
-               : config_(config){}\r
-       \r
-       // frame_consumer\r
-\r
-       void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
-       {\r
-               consumer_.reset();\r
-               consumer_.reset(new screen_consumer(config_, format_desc, channel_index));\r
-       }\r
-       \r
-       bool send(core::const_frame frame) override\r
-       {\r
-               return consumer_->send(frame);\r
-       }\r
-       \r
-       std::wstring print() const override\r
-       {\r
-               return consumer_ ? consumer_->print() : L"[screen_consumer]";\r
-       }\r
-\r
-       std::wstring name() const override\r
-       {\r
-               return L"screen";\r
-       }\r
-\r
-       boost::property_tree::wptree info() const override\r
-       {\r
-               boost::property_tree::wptree info;\r
-               info.add(L"type", L"screen");\r
-               info.add(L"key-only", config_.key_only);\r
-               info.add(L"windowed", config_.windowed);\r
-               info.add(L"auto-deinterlace", config_.auto_deinterlace);\r
-               return info;\r
-       }\r
-\r
-       bool has_synchronization_clock() const override\r
-       {\r
-               return false;\r
-       }\r
-       \r
-       int buffer_depth() const override\r
-       {\r
-               return 2;\r
-       }\r
-\r
-       int index() const override\r
-       {\r
-               return 600 + (config_.key_only ? 10 : 0) + config_.screen_index;\r
-       }\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }\r
-\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override\r
-       {\r
-       }       \r
-};     \r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)\r
-{\r
-       if(params.size() < 1 || params[0] != L"SCREEN")\r
-               return core::frame_consumer::empty();\r
-       \r
-       configuration config;\r
-               \r
-       if(params.size() > 1)\r
-               config.screen_index = boost::lexical_cast<int>(params[1]);\r
-               \r
-       config.key_only = std::find(params.begin(), params.end(), L"WINDOWED") != params.end();\r
-       config.key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();\r
-\r
-       auto name_it    = std::find(params.begin(), params.end(), L"NAME");\r
-       if(name_it != params.end() && ++name_it != params.end())\r
-               config.name = *name_it;\r
-\r
-       return spl::make_shared<screen_consumer_proxy>(config);\r
-}\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree) \r
-{\r
-       configuration config;\r
-       config.name                             = ptree.get(L"name",     config.name);\r
-       config.screen_index             = ptree.get(L"device",   config.screen_index+1)-1;\r
-       config.windowed                 = ptree.get(L"windowed", config.windowed);\r
-       config.key_only                 = ptree.get(L"key-only", config.key_only);\r
-       config.auto_deinterlace = ptree.get(L"auto-deinterlace", config.auto_deinterlace);\r
-       config.vsync                    = ptree.get(L"vsync", config.vsync);\r
-       \r
-       auto stretch_str = ptree.get(L"stretch", L"default");\r
-       if(stretch_str == L"uniform")\r
-               config.stretch = stretch::uniform;\r
-       else if(stretch_str == L"uniform_to_fill")\r
-               config.stretch = stretch::uniform_to_fill;\r
-\r
-       auto aspect_str = ptree.get(L"aspect-ratio", L"default");\r
-       if(aspect_str == L"16:9")\r
-               config.aspect = configuration::aspect_16_9;\r
-       else if(aspect_str == L"4:3")\r
-               config.aspect = configuration::aspect_4_3;\r
-       \r
-       return spl::make_shared<screen_consumer_proxy>(config);\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "screen_consumer.h"
+
+#include <GL/glew.h>
+#include <SFML/Window.hpp>
+
+#include <common/diagnostics/graph.h>
+#include <common/gl/gl_check.h>
+#include <common/log.h>
+#include <common/memory.h>
+#include <common/array.h>
+#include <common/memshfl.h>
+#include <common/utf.h>
+#include <common/prec_timer.h>
+
+#include <ffmpeg/producer/filter/filter.h>
+
+#include <core/video_format.h>
+#include <core/frame/frame.h>
+#include <core/consumer/frame_consumer.h>
+
+#include <boost/timer.hpp>
+#include <boost/circular_buffer.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/thread.hpp>
+
+#include <tbb/atomic.h>
+#include <tbb/concurrent_queue.h>
+#include <tbb/parallel_for.h>
+
+#include <boost/assign.hpp>
+
+#include <asmlib.h>
+
+#include <algorithm>
+#include <vector>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C" 
+{
+       #define __STDC_CONSTANT_MACROS
+       #define __STDC_LIMIT_MACROS
+       #include <libavcodec/avcodec.h>
+       #include <libavutil/imgutils.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+namespace caspar { namespace screen {
+               
+enum stretch
+{
+       none,
+       uniform,
+       fill,
+       uniform_to_fill
+};
+
+struct configuration
+{
+       enum aspect_ratio
+       {
+               aspect_4_3 = 0,
+               aspect_16_9,
+               aspect_invalid,
+       };
+               
+       std::wstring    name;
+       int                             screen_index;
+       stretch                 stretch;
+       bool                    windowed;
+       bool                    auto_deinterlace;
+       bool                    key_only;
+       aspect_ratio    aspect; 
+       bool                    vsync;
+
+       configuration()
+               : name(L"ogl")
+               , screen_index(0)
+               , stretch(fill)
+               , windowed(true)
+               , auto_deinterlace(true)
+               , key_only(false)
+               , aspect(aspect_invalid)
+               , vsync(true)
+       {
+       }
+};
+
+struct screen_consumer : boost::noncopyable
+{              
+       const configuration                                     config_;
+       core::video_format_desc                         format_desc_;
+       int                                                                     channel_index_;
+
+       GLuint                                                          texture_;
+       std::vector<GLuint>                                     pbos_;
+                       
+       float                                                           width_;
+       float                                                           height_;        
+       int                                                                     screen_x_;
+       int                                                                     screen_y_;
+       int                                                                     screen_width_;
+       int                                                                     screen_height_;
+       int                                                                     square_width_;
+       int                                                                     square_height_;                         
+       
+       sf::Window                                                      window_;
+       
+       spl::shared_ptr<diagnostics::graph>     graph_;
+       boost::timer                                            perf_timer_;
+       boost::timer                                            tick_timer_;
+
+       caspar::prec_timer                                      wait_timer_;
+
+       tbb::concurrent_bounded_queue<core::const_frame>        frame_buffer_;
+
+       boost::thread                                           thread_;
+       tbb::atomic<bool>                                       is_running_;
+       
+       ffmpeg::filter                                          filter_;
+public:
+       screen_consumer(const configuration& config, const core::video_format_desc& format_desc, int channel_index) 
+               : config_(config)
+               , format_desc_(format_desc)
+               , channel_index_(channel_index)
+               , texture_(0)
+               , pbos_(2, 0)   
+               , screen_width_(format_desc.width)
+               , screen_height_(format_desc.height)
+               , square_width_(format_desc.square_width)
+               , square_height_(format_desc.square_height)
+               , filter_(format_desc.field_mode == core::field_mode::progressive || !config.auto_deinterlace ? L"" : L"YADIF=1:-1", boost::assign::list_of(PIX_FMT_BGRA))
+       {               
+               if(format_desc_.format == core::video_format::ntsc && config_.aspect == configuration::aspect_4_3)
+               {
+                       // Use default values which are 4:3.
+               }
+               else
+               {
+                       if(config_.aspect == configuration::aspect_16_9)
+                               square_width_ = (format_desc.height*16)/9;
+                       else if(config_.aspect == configuration::aspect_4_3)
+                               square_width_ = (format_desc.height*4)/3;
+               }
+
+               frame_buffer_.set_capacity(2);
+               
+               graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   
+               graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
+               graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));
+               graph_->set_text(print());
+               diagnostics::register_graph(graph_);
+                                                                       
+               DISPLAY_DEVICE d_device = {sizeof(d_device), 0};                        
+               std::vector<DISPLAY_DEVICE> displayDevices;
+               for(int n = 0; EnumDisplayDevices(NULL, n, &d_device, NULL); ++n)
+                       displayDevices.push_back(d_device);
+
+               if(config_.screen_index >= displayDevices.size())
+                       CASPAR_LOG(warning) << print() << L" Invalid screen-index: " << config_.screen_index;
+               
+               DEVMODE devmode = {};
+               if(!EnumDisplaySettings(displayDevices[config_.screen_index].DeviceName, ENUM_CURRENT_SETTINGS, &devmode))
+                       CASPAR_LOG(warning) << print() << L" Could not find display settings for screen-index: " << config_.screen_index;
+               
+               screen_x_               = devmode.dmPosition.x;
+               screen_y_               = devmode.dmPosition.y;
+               screen_width_   = config_.windowed ? square_width_ : devmode.dmPelsWidth;
+               screen_height_  = config_.windowed ? square_height_ : devmode.dmPelsHeight;
+               
+               is_running_ = true;
+               thread_ = boost::thread([this]{run();});
+       }
+       
+       ~screen_consumer()
+       {
+               is_running_ = false;
+               frame_buffer_.try_push(core::const_frame::empty());
+               thread_.join();
+       }
+
+       void init()
+       {
+               window_.Create(sf::VideoMode(screen_width_, screen_height_, 32), u8(print()), config_.windowed ? sf::Style::Resize | sf::Style::Close : sf::Style::Fullscreen);
+               window_.ShowMouseCursor(false);
+               window_.SetPosition(screen_x_, screen_y_);
+               window_.SetSize(screen_width_, screen_height_);
+               window_.SetActive();
+               
+               if(!GLEW_VERSION_2_1 && glewInit() != GLEW_OK)
+                       CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to initialize GLEW."));
+
+               if(!GLEW_VERSION_2_1)
+                       CASPAR_THROW_EXCEPTION(not_supported() << msg_info("Missing OpenGL 2.1 support."));
+
+               GL(glEnable(GL_TEXTURE_2D));
+               GL(glDisable(GL_DEPTH_TEST));           
+               GL(glClearColor(0.0, 0.0, 0.0, 0.0));
+               GL(glViewport(0, 0, format_desc_.width, format_desc_.height));
+               GL(glLoadIdentity());
+                               
+               calculate_aspect();
+                       
+               GL(glGenTextures(1, &texture_));
+               GL(glBindTexture(GL_TEXTURE_2D, texture_));
+               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP));
+               GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));
+               GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, format_desc_.width, format_desc_.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0));
+               GL(glBindTexture(GL_TEXTURE_2D, 0));
+                                       
+               GL(glGenBuffers(2, pbos_.data()));
+                       
+               glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbos_[0]);
+               glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW_ARB);
+               glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbos_[1]);
+               glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW_ARB);
+               glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+               
+               auto wglSwapIntervalEXT = reinterpret_cast<void(APIENTRY*)(int)>(wglGetProcAddress("wglSwapIntervalEXT"));
+               if(wglSwapIntervalEXT)
+               {
+                       if(config_.vsync)
+                       {
+                               wglSwapIntervalEXT(1);
+                               CASPAR_LOG(info) << print() << " Enabled vsync.";
+                       }
+                       else
+                               wglSwapIntervalEXT(0);
+               }
+
+               CASPAR_LOG(info) << print() << " Successfully Initialized.";
+       }
+
+       void uninit()
+       {               
+               if(texture_)
+                       glDeleteTextures(1, &texture_);
+
+               BOOST_FOREACH(auto& pbo, pbos_)
+               {
+                       if(pbo)
+                               glDeleteBuffers(1, &pbo);
+               }
+       }
+
+       void run()
+       {
+               try
+               {
+                       init();
+
+                       while(is_running_)
+                       {                       
+                               try
+                               {
+                                       sf::Event e;            
+                                       while(window_.GetEvent(e))
+                                       {
+                                               if(e.Type == sf::Event::Resized)
+                                                       calculate_aspect();
+                                               else if(e.Type == sf::Event::Closed)
+                                                       is_running_ = false;
+                                       }
+                       
+                                       auto frame = core::const_frame::empty();
+                                       frame_buffer_.pop(frame);
+
+                                       render_and_draw_frame(frame);
+                                       
+                                       /*perf_timer_.restart();
+                                       render(frame);
+                                       graph_->set_value("frame-time", perf_timer_.elapsed()*format_desc_.fps*0.5);    
+
+                                       window_.Display();*/
+
+                                       graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5);     
+                                       tick_timer_.restart();
+                               }
+                               catch(...)
+                               {
+                                       CASPAR_LOG_CURRENT_EXCEPTION();
+                                       is_running_ = false;
+                               }
+                       }
+
+                       uninit();
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+       }
+
+       void try_sleep_almost_until_vblank()
+       {
+               static const double THRESHOLD = 0.003;
+               double threshold = config_.vsync ? THRESHOLD : 0.0;
+
+               auto frame_time = 1.0 / (format_desc_.fps * format_desc_.field_count);
+
+               wait_timer_.tick(frame_time - threshold);
+       }
+
+       void wait_for_vblank_and_display()
+       {
+               try_sleep_almost_until_vblank();
+               window_.Display();
+               // Make sure that the next tick measures the duration from this point in time.
+               wait_timer_.tick(0.0);
+       }
+
+       spl::shared_ptr<AVFrame> get_av_frame()
+       {               
+               spl::shared_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);      
+               avcodec_get_frame_defaults(av_frame.get());
+                                               
+               av_frame->linesize[0]           = format_desc_.width*4;                 
+               av_frame->format                        = PIX_FMT_BGRA;
+               av_frame->width                         = format_desc_.width;
+               av_frame->height                        = format_desc_.height;
+               av_frame->interlaced_frame      = format_desc_.field_mode != core::field_mode::progressive;
+               av_frame->top_field_first       = format_desc_.field_mode == core::field_mode::upper ? 1 : 0;
+
+               return av_frame;
+       }
+
+       void render_and_draw_frame(core::const_frame frame)
+       {
+               if(static_cast<size_t>(frame.image_data().size()) != format_desc_.size)
+                       return;
+
+               if(screen_width_ == 0 && screen_height_ == 0)
+                       return;
+                                       
+               perf_timer_.restart();
+               auto av_frame = get_av_frame();
+               av_frame->data[0] = const_cast<uint8_t*>(frame.image_data().begin());
+
+               filter_.push(av_frame);
+               auto frames = filter_.poll_all();
+
+               if (frames.empty())
+                       return;
+
+               if (frames.size() == 1)
+               {
+                       render(frames[0]);
+                       graph_->set_value("frame-time", perf_timer_.elapsed() * format_desc_.fps * 0.5);
+
+                       wait_for_vblank_and_display(); // progressive frame
+               }
+               else if (frames.size() == 2)
+               {
+                       render(frames[0]);
+                       double perf_elapsed = perf_timer_.elapsed();
+
+                       wait_for_vblank_and_display(); // field1
+
+                       perf_timer_.restart();
+                       render(frames[1]);
+                       perf_elapsed += perf_timer_.elapsed();
+                       graph_->set_value("frame-time", perf_elapsed * format_desc_.fps * 0.5);
+
+                       wait_for_vblank_and_display(); // field2
+               }
+       }
+
+       void render(spl::shared_ptr<AVFrame> av_frame)
+       {
+               GL(glBindTexture(GL_TEXTURE_2D, texture_));
+
+               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[0]));
+               GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, format_desc_.width, format_desc_.height, GL_BGRA, GL_UNSIGNED_BYTE, 0));
+
+               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[1]));
+               GL(glBufferData(GL_PIXEL_UNPACK_BUFFER, format_desc_.size, 0, GL_STREAM_DRAW));
+
+               auto ptr = reinterpret_cast<char*>(GL2(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY)));
+               if(ptr)
+               {
+                       if(config_.key_only)
+                       {
+                               tbb::parallel_for(tbb::blocked_range<int>(0, format_desc_.height), [&](const tbb::blocked_range<int>& r)
+                               {
+                                       for(int n = r.begin(); n != r.end(); ++n)
+                                               aligned_memshfl(ptr+n*format_desc_.width*4, av_frame->data[0]+n*av_frame->linesize[0], format_desc_.width*4, 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);
+                               });
+                       }
+                       else
+                       {       
+                               tbb::parallel_for(tbb::blocked_range<int>(0, format_desc_.height), [&](const tbb::blocked_range<int>& r)
+                               {
+                                       for(int n = r.begin(); n != r.end(); ++n)
+                                               A_memcpy(ptr+n*format_desc_.width*4, av_frame->data[0]+n*av_frame->linesize[0], format_desc_.width*4);
+                               });
+                       }
+                       
+                       GL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER)); // release the mapped buffer
+               }
+
+               GL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
+                               
+               GL(glClear(GL_COLOR_BUFFER_BIT));                       
+               glBegin(GL_QUADS);
+                               glTexCoord2f(0.0f,        1.0f);        glVertex2f(-width_, -height_);
+                               glTexCoord2f(1.0f,        1.0f);        glVertex2f( width_, -height_);
+                               glTexCoord2f(1.0f,        0.0f);        glVertex2f( width_,  height_);
+                               glTexCoord2f(0.0f,        0.0f);        glVertex2f(-width_,  height_);
+               glEnd();
+               
+               GL(glBindTexture(GL_TEXTURE_2D, 0));
+
+               std::rotate(pbos_.begin(), pbos_.begin() + 1, pbos_.end());
+       }
+
+
+       bool send(core::const_frame frame)
+       {
+               if(!frame_buffer_.try_push(frame))
+                       graph_->set_tag("dropped-frame");
+               return is_running_;
+       }
+               
+       std::wstring print() const
+       {       
+               return config_.name + L"[" + boost::lexical_cast<std::wstring>(channel_index_) + L"|" + format_desc_.name + L"]";
+       }
+       
+       void calculate_aspect()
+       {
+               if(config_.windowed)
+               {
+                       screen_height_ = window_.GetHeight();
+                       screen_width_ = window_.GetWidth();
+               }
+               
+               GL(glViewport(0, 0, screen_width_, screen_height_));
+
+               std::pair<float, float> target_ratio = None();
+               if(config_.stretch == fill)
+                       target_ratio = Fill();
+               else if(config_.stretch == uniform)
+                       target_ratio = Uniform();
+               else if(config_.stretch == uniform_to_fill)
+                       target_ratio = UniformToFill();
+
+               width_ = target_ratio.first;
+               height_ = target_ratio.second;
+       }
+               
+       std::pair<float, float> None()
+       {
+               float width = static_cast<float>(square_width_)/static_cast<float>(screen_width_);
+               float height = static_cast<float>(square_height_)/static_cast<float>(screen_height_);
+
+               return std::make_pair(width, height);
+       }
+
+       std::pair<float, float> Uniform()
+       {
+               float aspect = static_cast<float>(square_width_)/static_cast<float>(square_height_);
+               float width = std::min(1.0f, static_cast<float>(screen_height_)*aspect/static_cast<float>(screen_width_));
+               float height = static_cast<float>(screen_width_*width)/static_cast<float>(screen_height_*aspect);
+
+               return std::make_pair(width, height);
+       }
+
+       std::pair<float, float> Fill()
+       {
+               return std::make_pair(1.0f, 1.0f);
+       }
+
+       std::pair<float, float> UniformToFill()
+       {
+               float wr = static_cast<float>(square_width_)/static_cast<float>(screen_width_);
+               float hr = static_cast<float>(square_height_)/static_cast<float>(screen_height_);
+               float r_inv = 1.0f/std::min(wr, hr);
+
+               float width = wr*r_inv;
+               float height = hr*r_inv;
+
+               return std::make_pair(width, height);
+       }
+};
+
+
+struct screen_consumer_proxy : public core::frame_consumer
+{
+       const configuration config_;
+       std::unique_ptr<screen_consumer> consumer_;
+
+public:
+
+       screen_consumer_proxy(const configuration& config)
+               : config_(config){}
+       
+       // frame_consumer
+
+       void initialize(const core::video_format_desc& format_desc, int channel_index) override
+       {
+               consumer_.reset();
+               consumer_.reset(new screen_consumer(config_, format_desc, channel_index));
+       }
+       
+       bool send(core::const_frame frame) override
+       {
+               return consumer_->send(frame);
+       }
+       
+       std::wstring print() const override
+       {
+               return consumer_ ? consumer_->print() : L"[screen_consumer]";
+       }
+
+       std::wstring name() const override
+       {
+               return L"screen";
+       }
+
+       boost::property_tree::wptree info() const override
+       {
+               boost::property_tree::wptree info;
+               info.add(L"type", L"screen");
+               info.add(L"key-only", config_.key_only);
+               info.add(L"windowed", config_.windowed);
+               info.add(L"auto-deinterlace", config_.auto_deinterlace);
+               return info;
+       }
+
+       bool has_synchronization_clock() const override
+       {
+               return false;
+       }
+       
+       int buffer_depth() const override
+       {
+               return 2;
+       }
+
+       int index() const override
+       {
+               return 600 + (config_.key_only ? 10 : 0) + config_.screen_index;
+       }
+
+       void subscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }
+
+       void unsubscribe(const monitor::observable::observer_ptr& o) override
+       {
+       }       
+};     
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+{
+       if(params.size() < 1 || params[0] != L"SCREEN")
+               return core::frame_consumer::empty();
+       
+       configuration config;
+               
+       if(params.size() > 1)
+               config.screen_index = boost::lexical_cast<int>(params[1]);
+               
+       config.key_only = std::find(params.begin(), params.end(), L"WINDOWED") != params.end();
+       config.key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();
+
+       auto name_it    = std::find(params.begin(), params.end(), L"NAME");
+       if(name_it != params.end() && ++name_it != params.end())
+               config.name = *name_it;
+
+       return spl::make_shared<screen_consumer_proxy>(config);
+}
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree) 
+{
+       configuration config;
+       config.name                             = ptree.get(L"name",     config.name);
+       config.screen_index             = ptree.get(L"device",   config.screen_index+1)-1;
+       config.windowed                 = ptree.get(L"windowed", config.windowed);
+       config.key_only                 = ptree.get(L"key-only", config.key_only);
+       config.auto_deinterlace = ptree.get(L"auto-deinterlace", config.auto_deinterlace);
+       config.vsync                    = ptree.get(L"vsync", config.vsync);
+       
+       auto stretch_str = ptree.get(L"stretch", L"default");
+       if(stretch_str == L"uniform")
+               config.stretch = stretch::uniform;
+       else if(stretch_str == L"uniform_to_fill")
+               config.stretch = stretch::uniform_to_fill;
+
+       auto aspect_str = ptree.get(L"aspect-ratio", L"default");
+       if(aspect_str == L"16:9")
+               config.aspect = configuration::aspect_16_9;
+       else if(aspect_str == L"4:3")
+               config.aspect = configuration::aspect_4_3;
+       
+       return spl::make_shared<screen_consumer_proxy>(config);
+}
+
 }}
\ No newline at end of file
index 075196774d1d5c0746ed85a149ee9de709cd2fad..666e28f2eb089bad17461b6ed0b41b097d63b074 100644 (file)
@@ -1,41 +1,41 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <vector>\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-namespace caspar { \r
-       \r
-namespace core {\r
-       class frame_consumer;\r
-}\r
-\r
-namespace screen {\r
-\r
-\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);\r
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <vector>
+#include <boost/property_tree/ptree.hpp>
+
+namespace caspar { 
+       
+namespace core {
+       class frame_consumer;
+}
+
+namespace screen {
+
+
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);
+
 }}
\ No newline at end of file
index bec6d52a8eec663a9b4da55f6198c0c6e8d47466..ba0b38e0e6dc3f82c4a82b1eabdc2ee2c62b6762 100644 (file)
@@ -1,35 +1,35 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "screen.h"\r
-\r
-#include "consumer/screen_consumer.h"\r
-\r
-#include <core/consumer/frame_consumer.h>\r
-\r
-namespace caspar { namespace screen {\r
-\r
-void init()\r
-{\r
-       caspar::core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "screen.h"
+
+#include "consumer/screen_consumer.h"
+
+#include <core/consumer/frame_consumer.h>
+
+namespace caspar { namespace screen {
+
+void init()
+{
+       caspar::core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+}
+
 }}
\ No newline at end of file
index d144b75d6310a1cda5b174ff678522423f904ac3..a112b657ee408b8f6428ba8be3af26a334bc6597 100644 (file)
@@ -1,28 +1,28 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-namespace caspar { namespace screen {\r
-\r
-void init();\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+namespace caspar { namespace screen {
+
+void init();
+
 }}
\ No newline at end of file
index 78dab68fd5d01b591d8193f52fbfecde708e6bcb..2af006d7123b6d10f8c2d9f530f8556cd2b1cbda 100644 (file)
@@ -1,22 +1,22 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
 #include "stdafx.h"
\ No newline at end of file
index b49c4ea79f5f58621269b6309a1fb9dc8ffab68f..ac2b26ec8b9defdffdddd28dc925e6e04daf22dd 100644 (file)
@@ -1,65 +1,65 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
-#pragma once\r
-\r
-#define NOMINMAX\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
-#if defined(_MSC_VER)\r
-#      ifndef _SCL_SECURE_NO_WARNINGS\r
-#              define _SCL_SECURE_NO_WARNINGS\r
-#      endif\r
-#      ifndef _CRT_SECURE_NO_WARNINGS\r
-#              define _CRT_SECURE_NO_WARNINGS\r
-#      endif\r
-#endif\r
-\r
-#ifdef _DEBUG\r
-#include <crtdbg.h>\r
-#endif\r
-\r
-#include <cstdint>\r
-#include <winsock2.h>\r
-#include <tchar.h>\r
-#include <sstream>\r
-#include <memory>\r
-#include <functional>\r
-#include <algorithm>\r
-#include <vector>\r
-#include <deque>\r
-#include <queue>\r
-#include <string>\r
-#include <math.h>\r
-\r
-#include <boost/assign.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/range/algorithm.hpp>\r
-\r
-#include "../common/utf.h"\r
-#include "../common/memory.h"\r
-//#include "../common/executor.h" // Can't include this due to MSVC lambda bug\r
-\r
-#include "../common/log.h"\r
-#include "../common/except.h"\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#pragma once
+
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+
+#if defined(_MSC_VER)
+#      ifndef _SCL_SECURE_NO_WARNINGS
+#              define _SCL_SECURE_NO_WARNINGS
+#      endif
+#      ifndef _CRT_SECURE_NO_WARNINGS
+#              define _CRT_SECURE_NO_WARNINGS
+#      endif
+#endif
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+#include <cstdint>
+#include <winsock2.h>
+#include <tchar.h>
+#include <sstream>
+#include <memory>
+#include <functional>
+#include <algorithm>
+#include <vector>
+#include <deque>
+#include <queue>
+#include <string>
+#include <math.h>
+
+#include <boost/assign.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
+#include <boost/range/algorithm.hpp>
+
+#include "../common/utf.h"
+#include "../common/memory.h"
+//#include "../common/executor.h" // Can't include this due to MSVC lambda bug
+
+#include "../common/log.h"
+#include "../common/except.h"
+
 #include <assert.h>
\ No newline at end of file
index d9028b2680d45c13820019adb05edacb8fe89c00..e777154a51a6fa90f4d0849215084449fdaf17fe 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "../util/clientinfo.h"\r
-\r
-#include <core/consumer/frame_consumer.h>\r
-#include <core/video_channel.h>\r
-\r
-#include <boost/algorithm/string.hpp>\r
-\r
-namespace caspar { namespace protocol {\r
-namespace amcp {\r
-       \r
-       class AMCPCommand\r
-       {\r
-               AMCPCommand(const AMCPCommand&);\r
-               AMCPCommand& operator=(const AMCPCommand&);\r
-       public:\r
-               AMCPCommand();\r
-               virtual ~AMCPCommand() {}\r
-               virtual bool Execute() = 0;\r
-\r
-               virtual bool NeedChannel() = 0;\r
-               virtual int GetMinimumParameters() = 0;\r
-\r
-               void SendReply();\r
-\r
-               void AddParameter(const std::wstring& param){_parameters.push_back(param);}\r
-\r
-               void SetClientInfo(IO::ClientInfoPtr& s){pClientInfo_ = s;}\r
-               IO::ClientInfoPtr GetClientInfo(){return pClientInfo_;}\r
-\r
-               void SetChannel(const std::shared_ptr<core::video_channel>& pChannel){pChannel_ = pChannel;}\r
-               std::shared_ptr<core::video_channel> GetChannel(){return pChannel_;}\r
-\r
-               void SetChannels(const std::vector<spl::shared_ptr<core::video_channel>>& channels){channels_ = channels;}\r
-               const std::vector<spl::shared_ptr<core::video_channel>>& GetChannels() { return channels_; }\r
-\r
-               void SetChannelIndex(unsigned int channelIndex){channelIndex_ = channelIndex;}\r
-               unsigned int GetChannelIndex(){return channelIndex_;}\r
-\r
-               void SetLayerIntex(int layerIndex){layerIndex_ = layerIndex;}\r
-               int GetLayerIndex(int defaultValue = 0) const{return layerIndex_ != -1 ? layerIndex_ : defaultValue;}\r
-\r
-               virtual void Clear();\r
-\r
-               virtual std::wstring print() const = 0;\r
-\r
-               void SetReplyString(const std::wstring& str){replyString_ = str;}\r
-\r
-       protected:\r
-               std::vector<std::wstring> _parameters;\r
-               std::vector<std::wstring> _parameters2;\r
-\r
-       private:\r
-               unsigned int channelIndex_;\r
-               int layerIndex_;\r
-               IO::ClientInfoPtr pClientInfo_;\r
-               std::shared_ptr<core::video_channel> pChannel_;\r
-               std::vector<spl::shared_ptr<core::video_channel>> channels_;\r
-               std::wstring replyString_;\r
-       };\r
-\r
-       typedef std::tr1::shared_ptr<AMCPCommand> AMCPCommandPtr;\r
-\r
-       template<bool TNeedChannel,int TMinParameters>\r
-       class AMCPCommandBase : public AMCPCommand\r
-       {\r
-       public:\r
-               virtual bool Execute()\r
-               {\r
-                       _parameters2 = _parameters;\r
-                       for(size_t n = 0; n < _parameters.size(); ++n)\r
-                               _parameters[n] = boost::to_upper_copy(_parameters[n]);\r
-                       return (TNeedChannel && !GetChannel()) || _parameters.size() < TMinParameters ? false : DoExecute();\r
-               }\r
-\r
-               virtual bool NeedChannel(){return TNeedChannel;}                \r
-               virtual int GetMinimumParameters(){return TMinParameters;}\r
-       protected:\r
-               ~AMCPCommandBase(){}\r
-       private:\r
-               virtual bool DoExecute() = 0;\r
-       };      \r
-\r
-}}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#pragma once
+
+#include "../util/clientinfo.h"
+
+#include <core/consumer/frame_consumer.h>
+#include <core/video_channel.h>
+
+#include <boost/algorithm/string.hpp>
+
+namespace caspar { namespace protocol {
+namespace amcp {
+       
+       class AMCPCommand
+       {
+               AMCPCommand(const AMCPCommand&);
+               AMCPCommand& operator=(const AMCPCommand&);
+       public:
+               AMCPCommand();
+               virtual ~AMCPCommand() {}
+               virtual bool Execute() = 0;
+
+               virtual bool NeedChannel() = 0;
+               virtual int GetMinimumParameters() = 0;
+
+               void SendReply();
+
+               void AddParameter(const std::wstring& param){_parameters.push_back(param);}
+
+               void SetClientInfo(IO::ClientInfoPtr& s){pClientInfo_ = s;}
+               IO::ClientInfoPtr GetClientInfo(){return pClientInfo_;}
+
+               void SetChannel(const std::shared_ptr<core::video_channel>& pChannel){pChannel_ = pChannel;}
+               std::shared_ptr<core::video_channel> GetChannel(){return pChannel_;}
+
+               void SetChannels(const std::vector<spl::shared_ptr<core::video_channel>>& channels){channels_ = channels;}
+               const std::vector<spl::shared_ptr<core::video_channel>>& GetChannels() { return channels_; }
+
+               void SetChannelIndex(unsigned int channelIndex){channelIndex_ = channelIndex;}
+               unsigned int GetChannelIndex(){return channelIndex_;}
+
+               void SetLayerIntex(int layerIndex){layerIndex_ = layerIndex;}
+               int GetLayerIndex(int defaultValue = 0) const{return layerIndex_ != -1 ? layerIndex_ : defaultValue;}
+
+               virtual void Clear();
+
+               virtual std::wstring print() const = 0;
+
+               void SetReplyString(const std::wstring& str){replyString_ = str;}
+
+       protected:
+               std::vector<std::wstring> _parameters;
+               std::vector<std::wstring> _parameters2;
+
+       private:
+               unsigned int channelIndex_;
+               int layerIndex_;
+               IO::ClientInfoPtr pClientInfo_;
+               std::shared_ptr<core::video_channel> pChannel_;
+               std::vector<spl::shared_ptr<core::video_channel>> channels_;
+               std::wstring replyString_;
+       };
+
+       typedef std::tr1::shared_ptr<AMCPCommand> AMCPCommandPtr;
+
+       template<bool TNeedChannel,int TMinParameters>
+       class AMCPCommandBase : public AMCPCommand
+       {
+       public:
+               virtual bool Execute()
+               {
+                       _parameters2 = _parameters;
+                       for(size_t n = 0; n < _parameters.size(); ++n)
+                               _parameters[n] = boost::to_upper_copy(_parameters[n]);
+                       return (TNeedChannel && !GetChannel()) || _parameters.size() < TMinParameters ? false : DoExecute();
+               }
+
+               virtual bool NeedChannel(){return TNeedChannel;}                
+               virtual int GetMinimumParameters(){return TMinParameters;}
+       protected:
+               ~AMCPCommandBase(){}
+       private:
+               virtual bool DoExecute() = 0;
+       };      
+
+}}}
index 1a50eae1686e265a158d4a1d795e2712a0987e0a..bb01eb2e4a90e49f550bdad33e90d5b436541901 100644 (file)
@@ -1,89 +1,89 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
-#include "..\stdafx.h"\r
-\r
-#include "AMCPCommandQueue.h"\r
-\r
-#include <boost/timer.hpp>\r
-\r
-namespace caspar { namespace protocol { namespace amcp {\r
-       \r
-AMCPCommandQueue::AMCPCommandQueue() \r
-       : executor_(L"AMCPCommandQueue")\r
-{\r
-}\r
-\r
-AMCPCommandQueue::~AMCPCommandQueue() \r
-{\r
-}\r
-\r
-void AMCPCommandQueue::AddCommand(AMCPCommandPtr pCurrentCommand)\r
-{\r
-       if(!pCurrentCommand)\r
-               return;\r
-       \r
-       if(executor_.size() > 128)\r
-       {\r
-               try\r
-               {\r
-                       CASPAR_LOG(error) << "AMCP Command Queue Overflow.";\r
-                       CASPAR_LOG(error) << "Failed to execute command:" << pCurrentCommand->print();\r
-                       pCurrentCommand->SetReplyString(L"500 FAILED\r\n");\r
-                       pCurrentCommand->SendReply();\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-       }\r
-       \r
-       executor_.begin_invoke([=]\r
-       {\r
-               try\r
-               {\r
-                       try\r
-                       {\r
-                               boost::timer timer;\r
-                               if(pCurrentCommand->Execute()) \r
-                                       CASPAR_LOG(debug) << "Executed command: " << pCurrentCommand->print() << " " << timer.elapsed();\r
-                               else \r
-                                       CASPAR_LOG(warning) << "Failed to execute command: " << pCurrentCommand->print() << " " << timer.elapsed();\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                               CASPAR_LOG(error) << "Failed to execute command:" << pCurrentCommand->print();\r
-                               pCurrentCommand->SetReplyString(L"500 FAILED\r\n");\r
-                       }\r
-                               \r
-                       pCurrentCommand->SendReply();\r
-                       \r
-                       CASPAR_LOG(trace) << "Ready for a new command";\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-       });\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#include "..\stdafx.h"
+
+#include "AMCPCommandQueue.h"
+
+#include <boost/timer.hpp>
+
+namespace caspar { namespace protocol { namespace amcp {
+       
+AMCPCommandQueue::AMCPCommandQueue() 
+       : executor_(L"AMCPCommandQueue")
+{
+}
+
+AMCPCommandQueue::~AMCPCommandQueue() 
+{
+}
+
+void AMCPCommandQueue::AddCommand(AMCPCommandPtr pCurrentCommand)
+{
+       if(!pCurrentCommand)
+               return;
+       
+       if(executor_.size() > 128)
+       {
+               try
+               {
+                       CASPAR_LOG(error) << "AMCP Command Queue Overflow.";
+                       CASPAR_LOG(error) << "Failed to execute command:" << pCurrentCommand->print();
+                       pCurrentCommand->SetReplyString(L"500 FAILED\r\n");
+                       pCurrentCommand->SendReply();
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+       }
+       
+       executor_.begin_invoke([=]
+       {
+               try
+               {
+                       try
+                       {
+                               boost::timer timer;
+                               if(pCurrentCommand->Execute()) 
+                                       CASPAR_LOG(debug) << "Executed command: " << pCurrentCommand->print() << " " << timer.elapsed();
+                               else 
+                                       CASPAR_LOG(warning) << "Failed to execute command: " << pCurrentCommand->print() << " " << timer.elapsed();
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                               CASPAR_LOG(error) << "Failed to execute command:" << pCurrentCommand->print();
+                               pCurrentCommand->SetReplyString(L"500 FAILED\r\n");
+                       }
+                               
+                       pCurrentCommand->SendReply();
+                       
+                       CASPAR_LOG(trace) << "Ready for a new command";
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+       });
+}
+
 }}}
\ No newline at end of file
index dd3e09db504a3d2a3bb9fb4b85ab76437f8695a2..d14b7a6b2a09b55415247acb6875896822e42575 100644 (file)
@@ -1,47 +1,47 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "AMCPCommand.h"\r
-\r
-#include <common/executor.h>\r
-\r
-#include <tbb\mutex.h>\r
-\r
-namespace caspar { namespace protocol { namespace amcp {\r
-\r
-class AMCPCommandQueue\r
-{\r
-       AMCPCommandQueue(const AMCPCommandQueue&);\r
-       AMCPCommandQueue& operator=(const AMCPCommandQueue&);\r
-public:\r
-       AMCPCommandQueue();\r
-       ~AMCPCommandQueue();\r
-\r
-       void AddCommand(AMCPCommandPtr pCommand);\r
-\r
-private:\r
-       executor                        executor_;\r
-};\r
-typedef std::tr1::shared_ptr<AMCPCommandQueue> AMCPCommandQueuePtr;\r
-\r
-}}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#pragma once
+
+#include "AMCPCommand.h"
+
+#include <common/executor.h>
+
+#include <tbb\mutex.h>
+
+namespace caspar { namespace protocol { namespace amcp {
+
+class AMCPCommandQueue
+{
+       AMCPCommandQueue(const AMCPCommandQueue&);
+       AMCPCommandQueue& operator=(const AMCPCommandQueue&);
+public:
+       AMCPCommandQueue();
+       ~AMCPCommandQueue();
+
+       void AddCommand(AMCPCommandPtr pCommand);
+
+private:
+       executor                        executor_;
+};
+typedef std::tr1::shared_ptr<AMCPCommandQueue> AMCPCommandQueuePtr;
+
+}}}
index 38211a84d1717c832bc3e15ea42afc1c9d4c4863..eaa3f35c6f85079f7076609aa3dda7dd341a6f16 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
-#include "../StdAfx.h"\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push, 1) // TODO: Legacy code, just disable warnings\r
-#endif\r
-\r
-#include "AMCPCommandsImpl.h"\r
-#include "AMCPProtocolStrategy.h"\r
-\r
-#include <common/env.h>\r
-\r
-#include <common/log.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/os/windows/current_version.h>\r
-#include <common/os/windows/system_info.h>\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/video_format.h>\r
-#include <core/producer/transition/transition_producer.h>\r
-#include <core/frame/frame_transform.h>\r
-#include <core/producer/stage.h>\r
-#include <core/producer/layer.h>\r
-#include <core/mixer/mixer.h>\r
-#include <core/consumer/output.h>\r
-\r
-#include <modules/reroute/producer/reroute_producer.h>\r
-#include <modules/bluefish/bluefish.h>\r
-#include <modules/decklink/decklink.h>\r
-#include <modules/ffmpeg/ffmpeg.h>\r
-#include <modules/flash/flash.h>\r
-#include <modules/flash/util/swf.h>\r
-#include <modules/flash/producer/flash_producer.h>\r
-#include <modules/flash/producer/cg_proxy.h>\r
-#include <modules/ffmpeg/producer/util/util.h>\r
-#include <modules/image/image.h>\r
-#include <modules/screen/screen.h>\r
-#include <modules/reroute/producer/reroute_producer.h>\r
-\r
-#include <algorithm>\r
-#include <locale>\r
-#include <fstream>\r
-#include <memory>\r
-#include <cctype>\r
-#include <io.h>\r
-\r
-#include <boost/date_time/posix_time/posix_time.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/algorithm/string.hpp>\r
-#include <boost/filesystem.hpp>\r
-#include <boost/filesystem/fstream.hpp>\r
-#include <boost/regex.hpp>\r
-#include <boost/property_tree/xml_parser.hpp>\r
-#include <boost/locale.hpp>\r
-#include <boost/range/adaptor/transformed.hpp>\r
-#include <boost/range/algorithm/copy.hpp>\r
-\r
-#include <tbb/concurrent_unordered_map.h>\r
-\r
-/* Return codes\r
-\r
-100 [action]                   Information om att nÃ¥got har hänt  \r
-101 [action]                   Information om att nÃ¥got har hänt, en rad data skickas  \r
-\r
-202 [kommando] OK              Kommandot har utförts  \r
-201 [kommando] OK              Kommandot har utförts, och en rad data skickas tillbaka  \r
-200 [kommando] OK              Kommandot har utförts, och flera rader data skickas tillbaka. Avslutas med tomrad  \r
-\r
-400 ERROR                              Kommandot kunde inte förstÃ¥s  \r
-401 [kommando] ERROR   Ogiltig kanal  \r
-402 [kommando] ERROR   Parameter saknas  \r
-403 [kommando] ERROR   Ogiltig parameter  \r
-404 [kommando] ERROR   Mediafilen hittades inte  \r
-\r
-500 FAILED                             Internt configurationfel  \r
-501 [kommando] FAILED  Internt configurationfel  \r
-502 [kommando] FAILED  Oläslig mediafil  \r
-\r
-600 [kommando] FAILED  funktion ej implementerad\r
-*/\r
-\r
-namespace caspar { namespace protocol {\r
-\r
-using namespace core;\r
-\r
-std::wstring read_utf8_file(const boost::filesystem::wpath& file)\r
-{\r
-       std::wstringstream result;\r
-       boost::filesystem::wifstream filestream(file);\r
-\r
-       if (filestream) \r
-       {\r
-               // Consume BOM first\r
-               filestream.get();\r
-               // read all data\r
-               result << filestream.rdbuf();\r
-       }\r
-\r
-       return result.str();\r
-}\r
-\r
-std::wstring read_latin1_file(const boost::filesystem::wpath& file)\r
-{\r
-       boost::locale::generator gen;\r
-       gen.locale_cache_enabled(true);\r
-       gen.categories(boost::locale::codepage_facet);\r
-\r
-       std::stringstream result_stream;\r
-       boost::filesystem::ifstream filestream(file);\r
-       filestream.imbue(gen("en_US.ISO8859-1"));\r
-\r
-       if (filestream)\r
-       {\r
-               // read all data\r
-               result_stream << filestream.rdbuf();\r
-       }\r
-\r
-       std::string result = result_stream.str();\r
-       std::wstring widened_result;\r
-\r
-       // The first 255 codepoints in unicode is the same as in latin1\r
-       auto from_signed_to_signed = std::function<unsigned char(char)>(\r
-               [] (char c) { return static_cast<unsigned char>(c); }\r
-       );\r
-       boost::copy(\r
-               result | boost::adaptors::transformed(from_signed_to_signed),\r
-               std::back_inserter(widened_result));\r
-\r
-       return widened_result;\r
-}\r
-\r
-std::wstring read_file(const boost::filesystem::wpath& file)\r
-{\r
-       static const uint8_t BOM[] = {0xef, 0xbb, 0xbf};\r
-\r
-       if (!boost::filesystem::exists(file))\r
-       {\r
-               return L"";\r
-       }\r
-\r
-       if (boost::filesystem::file_size(file) >= 3)\r
-       {\r
-               boost::filesystem::ifstream bom_stream(file);\r
-\r
-               char header[3];\r
-               bom_stream.read(header, 3);\r
-               bom_stream.close();\r
-\r
-               if (std::memcmp(BOM, header, 3) == 0)\r
-                       return read_utf8_file(file);\r
-       }\r
-\r
-       return read_latin1_file(file);\r
-}\r
-\r
-std::wstring MediaInfo(const boost::filesystem::path& path)\r
-{\r
-       if(boost::filesystem::is_regular_file(path))\r
-       {\r
-               std::wstring clipttype = TEXT("N/A");\r
-               std::wstring extension = boost::to_upper_copy(path.extension().wstring());\r
-               if(extension == TEXT(".TGA") || extension == TEXT(".COL") || extension == L".PNG" || extension == L".JPEG" || extension == L".JPG" ||\r
-                       extension == L"GIF" || extension == L"BMP")\r
-                       clipttype = TEXT("STILL");\r
-               else if(extension == TEXT(".WAV") || extension == TEXT(".MP3"))\r
-                       clipttype = TEXT("STILL");\r
-               else if(extension == TEXT("SWF") || extension == TEXT("CT") || extension == TEXT("DV") || extension == TEXT("MOV") || extension == TEXT("MPG") || extension == TEXT("AVI") || caspar::ffmpeg::is_valid_file(path.wstring()))\r
-                       clipttype = TEXT("MOVIE");\r
-\r
-               if(clipttype != TEXT("N/A"))\r
-               {               \r
-                       auto is_not_digit = [](char c){ return std::isdigit(c) == 0; };\r
-\r
-                       auto relativePath = boost::filesystem::path(path.wstring().substr(env::media_folder().size()-1, path.wstring().size()));\r
-\r
-                       auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(path)));\r
-                       writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), is_not_digit), writeTimeStr.end());\r
-                       auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());\r
-\r
-                       auto sizeStr = boost::lexical_cast<std::wstring>(boost::filesystem::file_size(path));\r
-                       sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), is_not_digit), sizeStr.end());\r
-                       auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());\r
-                               \r
-                       auto str = relativePath.replace_extension(TEXT("")).native();\r
-                       while(str.size() > 0 && (str[0] == '\\' || str[0] == '/'))\r
-                               str = std::wstring(str.begin() + 1, str.end());\r
-\r
-                       return std::wstring() + TEXT("\"") + str +\r
-                                       + TEXT("\" ") + clipttype +\r
-                                       + TEXT(" ") + sizeStr +\r
-                                       + TEXT(" ") + writeTimeWStr +\r
-                                       + TEXT("\r\n");         \r
-               }       \r
-       }\r
-       return L"";\r
-}\r
-\r
-std::wstring ListMedia()\r
-{      \r
-       std::wstringstream replyString;\r
-       for (boost::filesystem::recursive_directory_iterator itr(env::media_folder()), end; itr != end; ++itr)  \r
-               replyString << MediaInfo(itr->path());\r
-       \r
-       return boost::to_upper_copy(replyString.str());\r
-}\r
-\r
-std::wstring ListTemplates() \r
-{\r
-       std::wstringstream replyString;\r
-\r
-       for (boost::filesystem::recursive_directory_iterator itr(env::template_folder()), end; itr != end; ++itr)\r
-       {               \r
-               if(boost::filesystem::is_regular_file(itr->path()) && (itr->path().extension() == L".ft" || itr->path().extension() == L".ct"))\r
-               {\r
-                       auto relativePath = boost::filesystem::wpath(itr->path().wstring().substr(env::template_folder().size()-1, itr->path().wstring().size()));\r
-\r
-                       auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(itr->path())));\r
-                       writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), [](char c){ return std::isdigit(c) == 0;}), writeTimeStr.end());\r
-                       auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());\r
-\r
-                       auto sizeStr = boost::lexical_cast<std::string>(boost::filesystem::file_size(itr->path()));\r
-                       sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), [](char c){ return std::isdigit(c) == 0;}), sizeStr.end());\r
-\r
-                       auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());\r
-\r
-                       std::wstring dir = relativePath.parent_path().native();\r
-                       std::wstring file = boost::to_upper_copy(relativePath.filename().wstring());\r
-                       relativePath = boost::filesystem::wpath(dir + L"/" + file);\r
-                                               \r
-                       auto str = relativePath.replace_extension(TEXT("")).native();\r
-                       boost::trim_if(str, boost::is_any_of("\\/"));\r
-\r
-                       replyString << TEXT("\"") << str\r
-                                               << TEXT("\" ") << sizeWStr\r
-                                               << TEXT(" ") << writeTimeWStr\r
-                                               << TEXT("\r\n");                \r
-               }\r
-       }\r
-       return replyString.str();\r
-}\r
-\r
-namespace amcp {\r
-       \r
-AMCPCommand::AMCPCommand() : channelIndex_(0), layerIndex_(-1)\r
-{}\r
-\r
-void AMCPCommand::SendReply()\r
-{\r
-       if(!pClientInfo_) \r
-               return;\r
-\r
-       if(replyString_.empty())\r
-               return;\r
-       pClientInfo_->Send(replyString_);\r
-}\r
-\r
-void AMCPCommand::Clear() \r
-{\r
-       pChannel_->stage().clear();\r
-       pClientInfo_.reset();\r
-       channelIndex_ = 0;\r
-       _parameters.clear();\r
-}\r
-\r
-bool DiagnosticsCommand::DoExecute()\r
-{      \r
-       try\r
-       {\r
-               diagnostics::show_graphs(true);\r
-\r
-               SetReplyString(TEXT("202 DIAG OK\r\n"));\r
-\r
-               return true;\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("502 DIAG FAILED\r\n"));\r
-               return false;\r
-       }\r
-}\r
-\r
-bool ChannelGridCommand::DoExecute()\r
-{\r
-       CASPAR_THROW_EXCEPTION(not_implemented());\r
-\r
-       //int index = 1;\r
-       //auto self = GetChannels().back();\r
-       //\r
-       //std::vector<std::wstring> params;\r
-       //params.push_back(L"SCREEN");\r
-       //params.push_back(L"NAME");\r
-       //params.push_back(L"Channel Grid Window");\r
-       //auto screen = create_consumer(params);\r
-\r
-       //self->output().add(screen);\r
-\r
-       //BOOST_FOREACH(auto channel, GetChannels())\r
-       //{\r
-       //      if(channel != self)\r
-       //      {\r
-       //              auto producer = reroute::create_producer(self->frame_factory(), *channel);              \r
-       //              self->stage().load(index, producer, false);\r
-       //              self->stage().play(index);\r
-       //              index++;\r
-       //      }\r
-       //}\r
-\r
-       //int n = GetChannels().size()-1;\r
-       //double delta = 1.0/static_cast<double>(n);\r
-       //for(int x = 0; x < n; ++x)\r
-       //{\r
-       //      for(int y = 0; y < n; ++y)\r
-       //      {\r
-       //              int index = x+y*n+1;\r
-       //              auto transform = [=](frame_transform transform) -> frame_transform\r
-       //              {               \r
-       //                      transform.image_transform.fill_translation[0]   = x*delta;\r
-       //                      transform.image_transform.fill_translation[1]   = y*delta;\r
-       //                      transform.image_transform.fill_scale[0]                 = delta;\r
-       //                      transform.image_transform.fill_scale[1]                 = delta;\r
-       //                      transform.image_transform.clip_translation[0]   = x*delta;\r
-       //                      transform.image_transform.clip_translation[1]   = y*delta;\r
-       //                      transform.image_transform.clip_scale[0]                 = delta;\r
-       //                      transform.image_transform.clip_scale[1]                 = delta;                        \r
-       //                      return transform;\r
-       //              };\r
-       //              self->stage().apply_transform(index, transform);\r
-       //      }\r
-       //}\r
-\r
-       //return true;\r
-}\r
-\r
-bool CallCommand::DoExecute()\r
-{      \r
-       //Perform loading of the clip\r
-       try\r
-       {\r
-               auto what = _parameters.at(0);\r
-                               \r
-               std::wstring param;\r
-               for(auto it = std::begin(_parameters2); it != std::end(_parameters2); ++it, param += L" ")\r
-                       param += *it;\r
-\r
-               auto result = GetChannel()->stage().call(GetLayerIndex(), boost::trim_copy(param));\r
-               \r
-               if(!result.timed_wait(boost::posix_time::seconds(2)))\r
-                       CASPAR_THROW_EXCEPTION(timed_out());\r
-                               \r
-               std::wstringstream replyString;\r
-               if(result.get().empty())\r
-                       replyString << TEXT("202 CALL OK\r\n");\r
-               else\r
-                       replyString << TEXT("201 CALL OK\r\n") << result.get() << L"\r\n";\r
-               \r
-               SetReplyString(replyString.str());\r
-\r
-               return true;\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("502 CALL FAILED\r\n"));\r
-               return false;\r
-       }\r
-}\r
-\r
-tbb::concurrent_unordered_map<int, std::vector<stage::transform_tuple_t>> deferred_transforms;\r
-\r
-bool MixerCommand::DoExecute()\r
-{      \r
-       //Perform loading of the clip\r
-       try\r
-       {       \r
-               bool defer = _parameters.back() == L"DEFER";\r
-               if(defer)\r
-                       _parameters.pop_back();\r
-\r
-               std::vector<stage::transform_tuple_t> transforms;\r
-\r
-               if(_parameters[0] == L"KEYER" || _parameters[0] == L"IS_KEY")\r
-               {\r
-                       bool value = boost::lexical_cast<int>(_parameters.at(1));\r
-                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform\r
-                       {\r
-                               transform.image_transform.is_key = value;\r
-                               return transform;                                       \r
-                       }, 0, L"linear"));\r
-               }\r
-               else if(_parameters[0] == L"OPACITY")\r
-               {\r
-                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;\r
-                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";\r
-\r
-                       double value = boost::lexical_cast<double>(_parameters.at(1));\r
-                       \r
-                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform\r
-                       {\r
-                               transform.image_transform.opacity = value;\r
-                               return transform;                                       \r
-                       }, duration, tween));\r
-               }\r
-               else if(_parameters[0] == L"FILL" || _parameters[0] == L"FILL_RECT")\r
-               {\r
-                       int duration = _parameters.size() > 5 ? boost::lexical_cast<int>(_parameters[5]) : 0;\r
-                       std::wstring tween = _parameters.size() > 6 ? _parameters[6] : L"linear";\r
-                       double x        = boost::lexical_cast<double>(_parameters.at(1));\r
-                       double y        = boost::lexical_cast<double>(_parameters.at(2));\r
-                       double x_s      = boost::lexical_cast<double>(_parameters.at(3));\r
-                       double y_s      = boost::lexical_cast<double>(_parameters.at(4));\r
-\r
-                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) mutable -> frame_transform\r
-                       {\r
-                               transform.image_transform.fill_translation[0]   = x;\r
-                               transform.image_transform.fill_translation[1]   = y;\r
-                               transform.image_transform.fill_scale[0]                 = x_s;\r
-                               transform.image_transform.fill_scale[1]                 = y_s;\r
-                               transform.image_transform.clip_translation[0]   = x;\r
-                               transform.image_transform.clip_translation[1]   = y;\r
-                               transform.image_transform.clip_scale[0]                 = x_s;\r
-                               transform.image_transform.clip_scale[1]                 = y_s;\r
-                               return transform;\r
-                       }, duration, tween));\r
-               }\r
-               else if(_parameters[0] == L"CLIP" || _parameters[0] == L"CLIP_RECT")\r
-               {\r
-                       int duration = _parameters.size() > 5 ? boost::lexical_cast<int>(_parameters[5]) : 0;\r
-                       std::wstring tween = _parameters.size() > 6 ? _parameters[6] : L"linear";\r
-                       double x        = boost::lexical_cast<double>(_parameters.at(1));\r
-                       double y        = boost::lexical_cast<double>(_parameters.at(2));\r
-                       double x_s      = boost::lexical_cast<double>(_parameters.at(3));\r
-                       double y_s      = boost::lexical_cast<double>(_parameters.at(4));\r
-\r
-                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform\r
-                       {\r
-                               transform.image_transform.clip_translation[0]   = x;\r
-                               transform.image_transform.clip_translation[1]   = y;\r
-                               transform.image_transform.clip_scale[0]                 = x_s;\r
-                               transform.image_transform.clip_scale[1]                 = y_s;\r
-                               return transform;\r
-                       }, duration, tween));\r
-               }\r
-               else if(_parameters[0] == L"GRID")\r
-               {\r
-                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;\r
-                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";\r
-                       int n = boost::lexical_cast<int>(_parameters.at(1));\r
-                       double delta = 1.0/static_cast<double>(n);\r
-                       for(int x = 0; x < n; ++x)\r
-                       {\r
-                               for(int y = 0; y < n; ++y)\r
-                               {\r
-                                       int index = x+y*n+1;\r
-                                       transforms.push_back(stage::transform_tuple_t(index, [=](frame_transform transform) -> frame_transform\r
-                                       {               \r
-                                               transform.image_transform.fill_translation[0]   = x*delta;\r
-                                               transform.image_transform.fill_translation[1]   = y*delta;\r
-                                               transform.image_transform.fill_scale[0]                 = delta;\r
-                                               transform.image_transform.fill_scale[1]                 = delta;\r
-                                               transform.image_transform.clip_translation[0]   = x*delta;\r
-                                               transform.image_transform.clip_translation[1]   = y*delta;\r
-                                               transform.image_transform.clip_scale[0]                 = delta;\r
-                                               transform.image_transform.clip_scale[1]                 = delta;                        \r
-                                               return transform;\r
-                                       }, duration, tween));\r
-                               }\r
-                       }\r
-               }\r
-               else if(_parameters[0] == L"BLEND")\r
-               {\r
-                       auto blend_str = _parameters.at(1);                                                             \r
-                       int layer = GetLayerIndex();\r
-                       GetChannel()->mixer().set_blend_mode(GetLayerIndex(), get_blend_mode(blend_str));       \r
-               }\r
-               else if(_parameters[0] == L"BRIGHTNESS")\r
-               {\r
-                       auto value = boost::lexical_cast<double>(_parameters.at(1));\r
-                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;\r
-                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";\r
-                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform\r
-                       {\r
-                               transform.image_transform.brightness = value;\r
-                               return transform;\r
-                       }, duration, tween));\r
-               }\r
-               else if(_parameters[0] == L"SATURATION")\r
-               {\r
-                       auto value = boost::lexical_cast<double>(_parameters.at(1));\r
-                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;\r
-                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";\r
-                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform\r
-                       {\r
-                               transform.image_transform.saturation = value;\r
-                               return transform;\r
-                       }, duration, tween));   \r
-               }\r
-               else if(_parameters[0] == L"CONTRAST")\r
-               {\r
-                       auto value = boost::lexical_cast<double>(_parameters.at(1));\r
-                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;\r
-                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";\r
-                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform\r
-                       {\r
-                               transform.image_transform.contrast = value;\r
-                               return transform;\r
-                       }, duration, tween));   \r
-               }\r
-               else if(_parameters[0] == L"LEVELS")\r
-               {\r
-                       levels value;\r
-                       value.min_input  = boost::lexical_cast<double>(_parameters.at(1));\r
-                       value.max_input  = boost::lexical_cast<double>(_parameters.at(2));\r
-                       value.gamma              = boost::lexical_cast<double>(_parameters.at(3));\r
-                       value.min_output = boost::lexical_cast<double>(_parameters.at(4));\r
-                       value.max_output = boost::lexical_cast<double>(_parameters.at(5));\r
-                       int duration = _parameters.size() > 6 ? boost::lexical_cast<int>(_parameters[6]) : 0;\r
-                       std::wstring tween = _parameters.size() > 7 ? _parameters[7] : L"linear";\r
-\r
-                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform\r
-                       {\r
-                               transform.image_transform.levels = value;\r
-                               return transform;\r
-                       }, duration, tween));\r
-               }\r
-               else if(_parameters[0] == L"VOLUME")\r
-               {\r
-                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;\r
-                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";\r
-                       double value = boost::lexical_cast<double>(_parameters[1]);\r
-\r
-                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform\r
-                       {\r
-                               transform.audio_transform.volume = value;\r
-                               return transform;\r
-                       }, duration, tween));\r
-               }\r
-               else if(_parameters[0] == L"CLEAR")\r
-               {\r
-                       int layer = GetLayerIndex(std::numeric_limits<int>::max());\r
-                       if(layer ==     std::numeric_limits<int>::max())\r
-                               GetChannel()->stage().clear_transforms();\r
-                       else\r
-                               GetChannel()->stage().clear_transforms(layer);\r
-               }\r
-               else if(_parameters[0] == L"COMMIT")\r
-               {\r
-                       transforms = std::move(deferred_transforms[GetChannelIndex()]);\r
-               }\r
-               else\r
-               {\r
-                       SetReplyString(TEXT("404 MIXER ERROR\r\n"));\r
-                       return false;\r
-               }\r
-\r
-               if(defer)\r
-               {\r
-                       auto& defer_tranforms = deferred_transforms[GetChannelIndex()];\r
-                       defer_tranforms.insert(defer_tranforms.end(), transforms.begin(), transforms.end());\r
-               }\r
-               else\r
-                       GetChannel()->stage().apply_transforms(transforms);\r
-       \r
-               SetReplyString(TEXT("202 MIXER OK\r\n"));\r
-\r
-               return true;\r
-       }\r
-       catch(file_not_found&)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("404 MIXER ERROR\r\n"));\r
-               return false;\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("502 MIXER FAILED\r\n"));\r
-               return false;\r
-       }\r
-}\r
-\r
-bool SwapCommand::DoExecute()\r
-{      \r
-       //Perform loading of the clip\r
-       try\r
-       {\r
-               if(GetLayerIndex(-1) != -1)\r
-               {\r
-                       std::vector<std::string> strs;\r
-                       boost::split(strs, _parameters[0], boost::is_any_of("-"));\r
-                       \r
-                       auto ch1 = GetChannel();\r
-                       auto ch2 = GetChannels().at(boost::lexical_cast<int>(strs.at(0))-1);\r
-\r
-                       int l1 = GetLayerIndex();\r
-                       int l2 = boost::lexical_cast<int>(strs.at(1));\r
-\r
-                       ch1->stage().swap_layer(l1, l2, ch2->stage());\r
-               }\r
-               else\r
-               {\r
-                       auto ch1 = GetChannel();\r
-                       auto ch2 = GetChannels().at(boost::lexical_cast<int>(_parameters[0])-1);\r
-                       ch1->stage().swap_layers(ch2->stage());\r
-               }\r
-               \r
-               SetReplyString(TEXT("202 SWAP OK\r\n"));\r
-\r
-               return true;\r
-       }\r
-       catch(file_not_found&)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("404 SWAP ERROR\r\n"));\r
-               return false;\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("502 SWAP FAILED\r\n"));\r
-               return false;\r
-       }\r
-}\r
-\r
-bool AddCommand::DoExecute()\r
-{      \r
-       //Perform loading of the clip\r
-       try\r
-       {\r
-               auto consumer = create_consumer(_parameters);\r
-               GetChannel()->output().add(GetLayerIndex(consumer->index()), consumer);\r
-       \r
-               SetReplyString(TEXT("202 ADD OK\r\n"));\r
-\r
-               return true;\r
-       }\r
-       catch(file_not_found&)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("404 ADD ERROR\r\n"));\r
-               return false;\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("502 ADD FAILED\r\n"));\r
-               return false;\r
-       }\r
-}\r
-\r
-bool RemoveCommand::DoExecute()\r
-{      \r
-       //Perform loading of the clip\r
-       try\r
-       {\r
-               auto index = GetLayerIndex(std::numeric_limits<int>::min());\r
-               if(index == std::numeric_limits<int>::min())\r
-                       index = create_consumer(_parameters)->index();\r
-\r
-               GetChannel()->output().remove(index);\r
-\r
-               SetReplyString(TEXT("202 REMOVE OK\r\n"));\r
-\r
-               return true;\r
-       }\r
-       catch(file_not_found&)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("404 REMOVE ERROR\r\n"));\r
-               return false;\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("502 REMOVE FAILED\r\n"));\r
-               return false;\r
-       }\r
-}\r
-\r
-bool LoadCommand::DoExecute()\r
-{      \r
-       //Perform loading of the clip\r
-       try\r
-       {\r
-               _parameters[0] = _parameters[0];\r
-               auto pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), _parameters);              \r
-               GetChannel()->stage().load(GetLayerIndex(), pFP, true);\r
-       \r
-               SetReplyString(TEXT("202 LOAD OK\r\n"));\r
-\r
-               return true;\r
-       }\r
-       catch(file_not_found&)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("404 LOAD ERROR\r\n"));\r
-               return false;\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("502 LOAD FAILED\r\n"));\r
-               return false;\r
-       }\r
-}\r
-\r
-\r
-\r
-//std::function<std::wstring()> channel_cg_add_command::parse(const std::wstring& message, const std::vector<renderer::render_device_ptr>& channels)\r
-//{\r
-//     static boost::wregex expr(L"^CG\\s(?<video_channel>\\d+)-?(?<LAYER>\\d+)?\\sADD\\s(?<FLASH_LAYER>\\d+)\\s(?<TEMPLATE>\\S+)\\s?(?<START_LABEL>\\S\\S+)?\\s?(?<PLAY_ON_LOAD>\\d)?\\s?(?<DATA>.*)?");\r
-//\r
-//     boost::wsmatch what;\r
-//     if(!boost::regex_match(message, what, expr))\r
-//             return nullptr;\r
-//\r
-//     auto info = channel_info::parse(what, channels);\r
-//\r
-//     int flash_layer_index = boost::lexical_cast<int>(what["FLASH_LAYER"].str());\r
-//\r
-//     std::wstring templatename = what["TEMPLATE"].str();\r
-//     bool play_on_load = what["PLAY_ON_LOAD"].matched ? what["PLAY_ON_LOAD"].str() != L"0" : 0;\r
-//     std::wstring start_label = what["START_LABEL"].str();   \r
-//     std::wstring data = get_data(what["DATA"].str());\r
-//     \r
-//     boost::replace_all(templatename, "\"", "");\r
-//\r
-//     return [=]() -> std::wstring\r
-//     {       \r
-//             std::wstring fullFilename = flash::flash_producer::find_template(server::template_folder() + templatename);\r
-//             if(fullFilename.empty())\r
-//                     CASPAR_THROW_EXCEPTION(file_not_found());\r
-//     \r
-//             std::wstring extension = boost::filesystem::wpath(fullFilename).extension();\r
-//             std::wstring filename = templatename;\r
-//             filename.append(extension);\r
-//\r
-//             flash::flash::create_cg_proxy(info.video_channel, std::max<int>(DEFAULT_CHANNEL_LAYER+1, info.layer_index))\r
-//                     ->add(flash_layer_index, filename, play_on_load, start_label, data);\r
-//\r
-//             CASPAR_LOG(info) << L"Executed [amcp_channel_cg_add]";\r
-//             return L"";\r
-//     };\r
-\r
-bool LoadbgCommand::DoExecute()\r
-{\r
-       transition_info transitionInfo;\r
-       \r
-       bool bLoop = false;\r
-\r
-       // TRANSITION\r
-\r
-       std::wstring message;\r
-       for(size_t n = 0; n < _parameters.size(); ++n)\r
-               message += _parameters[n] + L" ";\r
-               \r
-       static const boost::wregex expr(L".*(?<TRANSITION>CUT|PUSH|SLIDE|WIPE|MIX)\\s*(?<DURATION>\\d+)\\s*(?<TWEEN>(LINEAR)|(EASE[^\\s]*))?\\s*(?<DIRECTION>FROMLEFT|FROMRIGHT|LEFT|RIGHT)?.*");\r
-       boost::wsmatch what;\r
-       if(boost::regex_match(message, what, expr))\r
-       {\r
-               auto transition = what["TRANSITION"].str();\r
-               transitionInfo.duration = boost::lexical_cast<size_t>(what["DURATION"].str());\r
-               auto direction = what["DIRECTION"].matched ? what["DIRECTION"].str() : L"";\r
-               auto tween = what["TWEEN"].matched ? what["TWEEN"].str() : L"";\r
-               transitionInfo.tweener = tween;         \r
-\r
-               if(transition == TEXT("CUT"))\r
-                       transitionInfo.type = transition_type::cut;\r
-               else if(transition == TEXT("MIX"))\r
-                       transitionInfo.type = transition_type::mix;\r
-               else if(transition == TEXT("PUSH"))\r
-                       transitionInfo.type = transition_type::push;\r
-               else if(transition == TEXT("SLIDE"))\r
-                       transitionInfo.type = transition_type::slide;\r
-               else if(transition == TEXT("WIPE"))\r
-                       transitionInfo.type = transition_type::wipe;\r
-               \r
-               if(direction == TEXT("FROMLEFT"))\r
-                       transitionInfo.direction = transition_direction::from_left;\r
-               else if(direction == TEXT("FROMRIGHT"))\r
-                       transitionInfo.direction = transition_direction::from_right;\r
-               else if(direction == TEXT("LEFT"))\r
-                       transitionInfo.direction = transition_direction::from_right;\r
-               else if(direction == TEXT("RIGHT"))\r
-                       transitionInfo.direction = transition_direction::from_left;\r
-       }\r
-       \r
-       //Perform loading of the clip\r
-       try\r
-       {\r
-               std::shared_ptr<core::frame_producer> pFP;\r
-               \r
-               static boost::wregex expr(L"\\[(?<CHANNEL>\\d+)\\]", boost::regex::icase);\r
-                       \r
-               boost::wsmatch what;\r
-               if(boost::regex_match(_parameters.at(0), what, expr))\r
-               {\r
-                       auto channel_index = boost::lexical_cast<int>(what["CHANNEL"].str());\r
-                       pFP = reroute::create_producer(*GetChannels().at(channel_index-1)); \r
-               }\r
-               else\r
-                       pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), _parameters);\r
-               \r
-               if(pFP == frame_producer::empty())\r
-                       CASPAR_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? _parameters[0] : L""));\r
-\r
-               bool auto_play = std::find(_parameters.begin(), _parameters.end(), L"AUTO") != _parameters.end();\r
-\r
-               auto pFP2 = create_transition_producer(GetChannel()->video_format_desc().field_mode, spl::make_shared_ptr(pFP), transitionInfo);\r
-               if(auto_play)\r
-                       GetChannel()->stage().load(GetLayerIndex(), pFP2, false, transitionInfo.duration); // TODO: LOOP\r
-               else\r
-                       GetChannel()->stage().load(GetLayerIndex(), pFP2, false); // TODO: LOOP\r
-       \r
-               \r
-               SetReplyString(TEXT("202 LOADBG OK\r\n"));\r
-\r
-               return true;\r
-       }\r
-       catch(file_not_found&)\r
-       {               \r
-               std::wstring params2;\r
-               for(auto it = _parameters.begin(); it != _parameters.end(); ++it)\r
-                       params2 += L" " + *it;\r
-               CASPAR_LOG(error) << L"File not found. No match found for parameters. Check syntax:" << params2;\r
-               SetReplyString(TEXT("404 LOADBG ERROR\r\n"));\r
-               return false;\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("502 LOADBG FAILED\r\n"));\r
-               return false;\r
-       }\r
-}\r
-\r
-bool PauseCommand::DoExecute()\r
-{\r
-       try\r
-       {\r
-               GetChannel()->stage().pause(GetLayerIndex());\r
-               SetReplyString(TEXT("202 PAUSE OK\r\n"));\r
-               return true;\r
-       }\r
-       catch(...)\r
-       {\r
-               SetReplyString(TEXT("501 PAUSE FAILED\r\n"));\r
-       }\r
-\r
-       return false;\r
-}\r
-\r
-bool PlayCommand::DoExecute()\r
-{\r
-       try\r
-       {\r
-               if(!_parameters.empty())\r
-               {\r
-                       LoadbgCommand lbg;\r
-                       lbg.SetChannel(GetChannel());\r
-                       lbg.SetChannels(GetChannels());\r
-                       lbg.SetChannelIndex(GetChannelIndex());\r
-                       lbg.SetLayerIntex(GetLayerIndex());\r
-                       lbg.SetClientInfo(GetClientInfo());\r
-                       for(auto it = _parameters.begin(); it != _parameters.end(); ++it)\r
-                               lbg.AddParameter(*it);\r
-                       if(!lbg.Execute())\r
-                               throw std::exception();\r
-               }\r
-\r
-               GetChannel()->stage().play(GetLayerIndex());\r
-               \r
-               SetReplyString(TEXT("202 PLAY OK\r\n"));\r
-               return true;\r
-       }\r
-       catch(...)\r
-       {\r
-               SetReplyString(TEXT("501 PLAY FAILED\r\n"));\r
-       }\r
-\r
-       return false;\r
-}\r
-\r
-bool StopCommand::DoExecute()\r
-{\r
-       try\r
-       {\r
-               GetChannel()->stage().stop(GetLayerIndex());\r
-               SetReplyString(TEXT("202 STOP OK\r\n"));\r
-               return true;\r
-       }\r
-       catch(...)\r
-       {\r
-               SetReplyString(TEXT("501 STOP FAILED\r\n"));\r
-       }\r
-\r
-       return false;\r
-}\r
-\r
-bool ClearCommand::DoExecute()\r
-{\r
-       int index = GetLayerIndex(std::numeric_limits<int>::min());\r
-       if(index != std::numeric_limits<int>::min())\r
-               GetChannel()->stage().clear(index);\r
-       else\r
-               GetChannel()->stage().clear();\r
-               \r
-       SetReplyString(TEXT("202 CLEAR OK\r\n"));\r
-\r
-       return true;\r
-}\r
-\r
-bool PrintCommand::DoExecute()\r
-{\r
-       GetChannel()->output().add(create_consumer(boost::assign::list_of(L"IMAGE")));\r
-               \r
-       SetReplyString(TEXT("202 PRINT OK\r\n"));\r
-\r
-       return true;\r
-}\r
-\r
-bool LogCommand::DoExecute()\r
-{\r
-       if(_parameters.at(0) == L"LEVEL")\r
-               log::set_log_level(_parameters.at(1));\r
-\r
-       SetReplyString(TEXT("202 LOG OK\r\n"));\r
-\r
-       return true;\r
-}\r
-\r
-bool CGCommand::DoExecute()\r
-{\r
-       try\r
-       {\r
-               std::wstring command = _parameters[0];\r
-               if(command == TEXT("ADD"))\r
-                       return DoExecuteAdd();\r
-               else if(command == TEXT("PLAY"))\r
-                       return DoExecutePlay();\r
-               else if(command == TEXT("STOP"))\r
-                       return DoExecuteStop();\r
-               else if(command == TEXT("NEXT"))\r
-                       return DoExecuteNext();\r
-               else if(command == TEXT("REMOVE"))\r
-                       return DoExecuteRemove();\r
-               else if(command == TEXT("CLEAR"))\r
-                       return DoExecuteClear();\r
-               else if(command == TEXT("UPDATE"))\r
-                       return DoExecuteUpdate();\r
-               else if(command == TEXT("INVOKE"))\r
-                       return DoExecuteInvoke();\r
-               else if(command == TEXT("INFO"))\r
-                       return DoExecuteInfo();\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-       }\r
-\r
-       SetReplyString(TEXT("403 CG ERROR\r\n"));\r
-       return false;\r
-}\r
-\r
-bool CGCommand::ValidateLayer(const std::wstring& layerstring) {\r
-       int length = layerstring.length();\r
-       for(int i = 0; i < length; ++i) {\r
-               if(!_istdigit(layerstring[i])) {\r
-                       return false;\r
-               }\r
-       }\r
-\r
-       return true;\r
-}\r
-\r
-bool CGCommand::DoExecuteAdd() {\r
-       //CG 1 ADD 0 "template_folder/templatename" [STARTLABEL] 0/1 [DATA]\r
-\r
-       int layer = 0;                          //_parameters[1]\r
-//     std::wstring templateName;      //_parameters[2]\r
-       std::wstring label;             //_parameters[3]\r
-       bool bDoStart = false;          //_parameters[3] alt. _parameters[4]\r
-//     std::wstring data;                      //_parameters[4] alt. _parameters[5]\r
-\r
-       if(_parameters.size() < 4) \r
-       {\r
-               SetReplyString(TEXT("402 CG ERROR\r\n"));\r
-               return false;\r
-       }\r
-       unsigned int dataIndex = 4;\r
-\r
-       if(!ValidateLayer(_parameters[1])) \r
-       {\r
-               SetReplyString(TEXT("403 CG ERROR\r\n"));\r
-               return false;\r
-       }\r
-\r
-       layer = _ttoi(_parameters[1].c_str());\r
-\r
-       if(_parameters[3].length() > 1) \r
-       {       //read label\r
-               label = _parameters2[3];\r
-               ++dataIndex;\r
-\r
-               if(_parameters.size() > 4 && _parameters[4].length() > 0)       //read play-on-load-flag\r
-                       bDoStart = (_parameters[4][0]==TEXT('1')) ? true : false;\r
-               else \r
-               {\r
-                       SetReplyString(TEXT("402 CG ERROR\r\n"));\r
-                       return false;\r
-               }\r
-       }\r
-       else if(_parameters[3].length() > 0) {  //read play-on-load-flag\r
-               bDoStart = (_parameters[3][0]==TEXT('1')) ? true : false;\r
-       }\r
-       else \r
-       {\r
-               SetReplyString(TEXT("403 CG ERROR\r\n"));\r
-               return false;\r
-       }\r
-\r
-       const TCHAR* pDataString = 0;\r
-       std::wstringstream data;\r
-       std::wstring dataFromFile;\r
-       if(_parameters.size() > dataIndex) \r
-       {       //read data\r
-               const std::wstring& dataString = _parameters2[dataIndex];\r
-\r
-               if(dataString[0] == TEXT('<')) //the data is an XML-string\r
-                       pDataString = dataString.c_str();\r
-               else \r
-               {\r
-                       //The data is not an XML-string, it must be a filename\r
-                       std::wstring filename = env::data_folder();\r
-                       filename.append(dataString);\r
-                       filename.append(TEXT(".ftd"));\r
-\r
-                       dataFromFile = read_file(boost::filesystem::wpath(filename));\r
-                       pDataString = dataFromFile.c_str();\r
-               }\r
-       }\r
-\r
-       std::wstring fullFilename = flash::find_template(env::template_folder() + _parameters[2]);\r
-       if(!fullFilename.empty())\r
-       {\r
-               std::wstring extension = boost::filesystem::path(fullFilename).extension().wstring();\r
-               std::wstring filename = _parameters[2];\r
-               filename.append(extension);\r
-\r
-               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).add(layer, filename, bDoStart, label, (pDataString!=0) ? pDataString : TEXT(""));\r
-               SetReplyString(TEXT("202 CG OK\r\n"));\r
-       }\r
-       else\r
-       {\r
-               CASPAR_LOG(warning) << "Could not find template " << _parameters[2];\r
-               SetReplyString(TEXT("404 CG ERROR\r\n"));\r
-       }\r
-       return true;\r
-}\r
-\r
-bool CGCommand::DoExecutePlay()\r
-{\r
-       if(_parameters.size() > 1)\r
-       {\r
-               if(!ValidateLayer(_parameters[1])) \r
-               {\r
-                       SetReplyString(TEXT("403 CG ERROR\r\n"));\r
-                       return false;\r
-               }\r
-               int layer = _ttoi(_parameters[1].c_str());\r
-               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).play(layer);\r
-       }\r
-       else\r
-       {\r
-               SetReplyString(TEXT("402 CG ERROR\r\n"));\r
-               return true;\r
-       }\r
-\r
-       SetReplyString(TEXT("202 CG OK\r\n"));\r
-       return true;\r
-}\r
-\r
-bool CGCommand::DoExecuteStop() \r
-{\r
-       if(_parameters.size() > 1)\r
-       {\r
-               if(!ValidateLayer(_parameters[1])) \r
-               {\r
-                       SetReplyString(TEXT("403 CG ERROR\r\n"));\r
-                       return false;\r
-               }\r
-               int layer = _ttoi(_parameters[1].c_str());\r
-               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).stop(layer, 0);\r
-       }\r
-       else \r
-       {\r
-               SetReplyString(TEXT("402 CG ERROR\r\n"));\r
-               return true;\r
-       }\r
-\r
-       SetReplyString(TEXT("202 CG OK\r\n"));\r
-       return true;\r
-}\r
-\r
-bool CGCommand::DoExecuteNext()\r
-{\r
-       if(_parameters.size() > 1) \r
-       {\r
-               if(!ValidateLayer(_parameters[1])) \r
-               {\r
-                       SetReplyString(TEXT("403 CG ERROR\r\n"));\r
-                       return false;\r
-               }\r
-\r
-               int layer = _ttoi(_parameters[1].c_str());\r
-               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).next(layer);\r
-       }\r
-       else \r
-       {\r
-               SetReplyString(TEXT("402 CG ERROR\r\n"));\r
-               return true;\r
-       }\r
-\r
-       SetReplyString(TEXT("202 CG OK\r\n"));\r
-       return true;\r
-}\r
-\r
-bool CGCommand::DoExecuteRemove() \r
-{\r
-       if(_parameters.size() > 1) \r
-       {\r
-               if(!ValidateLayer(_parameters[1])) \r
-               {\r
-                       SetReplyString(TEXT("403 CG ERROR\r\n"));\r
-                       return false;\r
-               }\r
-\r
-               int layer = _ttoi(_parameters[1].c_str());\r
-               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).remove(layer);\r
-       }\r
-       else \r
-       {\r
-               SetReplyString(TEXT("402 CG ERROR\r\n"));\r
-               return true;\r
-       }\r
-\r
-       SetReplyString(TEXT("202 CG OK\r\n"));\r
-       return true;\r
-}\r
-\r
-bool CGCommand::DoExecuteClear() \r
-{\r
-       GetChannel()->stage().clear(GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER));\r
-       SetReplyString(TEXT("202 CG OK\r\n"));\r
-       return true;\r
-}\r
-\r
-bool CGCommand::DoExecuteUpdate() \r
-{\r
-       try\r
-       {\r
-               if(!ValidateLayer(_parameters.at(1)))\r
-               {\r
-                       SetReplyString(TEXT("403 CG ERROR\r\n"));\r
-                       return false;\r
-               }\r
-                                               \r
-               std::wstring dataString = _parameters2.at(2);                           \r
-               if(dataString.at(0) != TEXT('<'))\r
-               {\r
-                       //The data is not an XML-string, it must be a filename\r
-                       std::wstring filename = env::data_folder();\r
-                       filename.append(dataString);\r
-                       filename.append(TEXT(".ftd"));\r
-\r
-                       dataString = read_file(boost::filesystem::wpath(filename));\r
-               }               \r
-\r
-               int layer = _ttoi(_parameters.at(1).c_str());\r
-               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).update(layer, dataString);\r
-       }\r
-       catch(...)\r
-       {\r
-               SetReplyString(TEXT("402 CG ERROR\r\n"));\r
-               return true;\r
-       }\r
-\r
-       SetReplyString(TEXT("202 CG OK\r\n"));\r
-       return true;\r
-}\r
-\r
-bool CGCommand::DoExecuteInvoke() \r
-{\r
-       std::wstringstream replyString;\r
-       replyString << TEXT("201 CG OK\r\n");\r
-\r
-       if(_parameters.size() > 2)\r
-       {\r
-               if(!ValidateLayer(_parameters[1]))\r
-               {\r
-                       SetReplyString(TEXT("403 CG ERROR\r\n"));\r
-                       return false;\r
-               }\r
-               int layer = _ttoi(_parameters[1].c_str());\r
-               auto result = flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).invoke(layer, _parameters2[2]);\r
-               replyString << result << TEXT("\r\n"); \r
-       }\r
-       else \r
-       {\r
-               SetReplyString(TEXT("402 CG ERROR\r\n"));\r
-               return true;\r
-       }\r
-       \r
-       SetReplyString(replyString.str());\r
-       return true;\r
-}\r
-\r
-bool CGCommand::DoExecuteInfo() \r
-{\r
-       std::wstringstream replyString;\r
-       replyString << TEXT("201 CG OK\r\n");\r
-\r
-       if(_parameters.size() > 1)\r
-       {\r
-               if(!ValidateLayer(_parameters[1]))\r
-               {\r
-                       SetReplyString(TEXT("403 CG ERROR\r\n"));\r
-                       return false;\r
-               }\r
-\r
-               int layer = _ttoi(_parameters[1].c_str());\r
-               auto desc = flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).description(layer);\r
-               \r
-               replyString << desc << TEXT("\r\n"); \r
-       }\r
-       else \r
-       {\r
-               auto info = flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).template_host_info();\r
-               replyString << info << TEXT("\r\n"); \r
-       }       \r
-\r
-       SetReplyString(replyString.str());\r
-       return true;\r
-}\r
-\r
-bool DataCommand::DoExecute()\r
-{\r
-       std::wstring command = _parameters[0];\r
-       if(command == TEXT("STORE"))\r
-               return DoExecuteStore();\r
-       else if(command == TEXT("RETRIEVE"))\r
-               return DoExecuteRetrieve();\r
-       else if(command == TEXT("LIST"))\r
-               return DoExecuteList();\r
-\r
-       SetReplyString(TEXT("403 DATA ERROR\r\n"));\r
-       return false;\r
-}\r
-\r
-bool DataCommand::DoExecuteStore() \r
-{\r
-       if(_parameters.size() < 3) \r
-       {\r
-               SetReplyString(TEXT("402 DATA STORE ERROR\r\n"));\r
-               return false;\r
-       }\r
-\r
-       std::wstring filename = env::data_folder();\r
-       filename.append(_parameters[1]);\r
-       filename.append(TEXT(".ftd"));\r
-\r
-       std::wofstream datafile(filename.c_str());\r
-       if(!datafile) \r
-       {\r
-               SetReplyString(TEXT("501 DATA STORE FAILED\r\n"));\r
-               return false;\r
-       }\r
-\r
-       datafile << static_cast<wchar_t>(65279); // UTF-8 BOM character\r
-       datafile << _parameters2[2] << std::flush;\r
-       datafile.close();\r
-\r
-       std::wstring replyString = TEXT("202 DATA STORE OK\r\n");\r
-       SetReplyString(replyString);\r
-       return true;\r
-}\r
-\r
-bool DataCommand::DoExecuteRetrieve() \r
-{\r
-       if(_parameters.size() < 2) \r
-       {\r
-               SetReplyString(TEXT("402 DATA RETRIEVE ERROR\r\n"));\r
-               return false;\r
-       }\r
-\r
-       std::wstring filename = env::data_folder();\r
-       filename.append(_parameters[1]);\r
-       filename.append(TEXT(".ftd"));\r
-\r
-       std::wstring file_contents = read_file(boost::filesystem::wpath(filename));\r
-\r
-       if (file_contents.empty()) \r
-       {\r
-               SetReplyString(TEXT("404 DATA RETRIEVE ERROR\r\n"));\r
-               return false;\r
-       }\r
-\r
-       std::wstringstream reply(TEXT("201 DATA RETRIEVE OK\r\n"));\r
-\r
-       reply << file_contents;\r
-       reply << "\r\n";\r
-       SetReplyString(reply.str());\r
-       return true;\r
-}\r
-\r
-bool DataCommand::DoExecuteList() \r
-{\r
-       std::wstringstream replyString;\r
-       replyString << TEXT("200 DATA LIST OK\r\n");\r
-\r
-       for (boost::filesystem::recursive_directory_iterator itr(env::data_folder()), end; itr != end; ++itr)\r
-       {                       \r
-               if(boost::filesystem::is_regular_file(itr->path()))\r
-               {\r
-                       if(!boost::iequals(itr->path().extension().wstring(), L".ftd"))\r
-                               continue;\r
-                       \r
-                       auto relativePath = boost::filesystem::wpath(itr->path().wstring().substr(env::data_folder().size()-1, itr->path().wstring().size()));\r
-                       \r
-                       auto str = relativePath.replace_extension(TEXT("")).native();\r
-                       if(str[0] == '\\' || str[0] == '/')\r
-                               str = std::wstring(str.begin() + 1, str.end());\r
-\r
-                       replyString << str << TEXT("\r\n");     \r
-               }\r
-       }\r
-       \r
-       replyString << TEXT("\r\n");\r
-\r
-       SetReplyString(boost::to_upper_copy(replyString.str()));\r
-       return true;\r
-}\r
-\r
-bool CinfCommand::DoExecute()\r
-{\r
-       std::wstringstream replyString;\r
-       \r
-       try\r
-       {\r
-               std::wstring info;\r
-               for (boost::filesystem::recursive_directory_iterator itr(env::media_folder()), end; itr != end && info.empty(); ++itr)\r
-               {\r
-                       auto path = itr->path();\r
-                       auto file = path.replace_extension(L"").filename();\r
-                       if(boost::iequals(file.wstring(), _parameters.at(0)))\r
-                               info += MediaInfo(itr->path()) + L"\r\n";\r
-               }\r
-\r
-               if(info.empty())\r
-               {\r
-                       SetReplyString(TEXT("404 CINF ERROR\r\n"));\r
-                       return false;\r
-               }\r
-               replyString << TEXT("200 CINF OK\r\n");\r
-               replyString << info << "\r\n";\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("404 CINF ERROR\r\n"));\r
-               return false;\r
-       }\r
-       \r
-       SetReplyString(replyString.str());\r
-       return true;\r
-}\r
-\r
-void GenerateChannelInfo(int index, const spl::shared_ptr<core::video_channel>& pChannel, std::wstringstream& replyString)\r
-{\r
-       replyString << index+1 << TEXT(" ") << pChannel->video_format_desc().name << TEXT(" PLAYING") << TEXT("\r\n");\r
-}\r
-\r
-bool InfoCommand::DoExecute()\r
-{\r
-       std::wstringstream replyString;\r
-       \r
-       boost::property_tree::xml_writer_settings<wchar_t> w(' ', 3);\r
-\r
-       try\r
-       {\r
-               if(_parameters.size() >= 1 && _parameters[0] == L"TEMPLATE")\r
-               {               \r
-                       replyString << L"201 INFO TEMPLATE OK\r\n";\r
-\r
-                       // Needs to be extended for any file, not just flash.\r
-\r
-                       auto filename = flash::find_template(env::template_folder() + _parameters.at(1));\r
-                                               \r
-                       std::wstringstream str;\r
-                       str << u16(flash::read_template_meta_info(filename));\r
-                       boost::property_tree::wptree info;\r
-                       boost::property_tree::xml_parser::read_xml(str, info, boost::property_tree::xml_parser::trim_whitespace | boost::property_tree::xml_parser::no_comments);\r
-\r
-                       boost::property_tree::xml_parser::write_xml(replyString, info, w);\r
-               }\r
-               else if(_parameters.size() >= 1 && _parameters[0] == L"CONFIG")\r
-               {               \r
-                       replyString << L"201 INFO CONFIG OK\r\n";\r
-\r
-                       boost::property_tree::write_xml(replyString, caspar::env::properties(), w);\r
-               }\r
-               else if(_parameters.size() >= 1 && _parameters[0] == L"PATHS")\r
-               {\r
-                       replyString << L"201 INFO PATHS OK\r\n";\r
-\r
-                       boost::property_tree::wptree info;\r
-                       info.add_child(L"paths", caspar::env::properties().get_child(L"configuration.paths"));\r
-                       info.add(L"paths.initial-path", boost::filesystem3::initial_path().wstring() + L"\\");\r
-\r
-                       boost::property_tree::write_xml(replyString, info, w);\r
-               }\r
-               else if(_parameters.size() >= 1 && _parameters[0] == L"SYSTEM")\r
-               {\r
-                       replyString << L"201 INFO SYSTEM OK\r\n";\r
-                       \r
-                       boost::property_tree::wptree info;\r
-                       \r
-                       info.add(L"system.name",                                        caspar::system_product_name());\r
-                       info.add(L"system.windows.name",                        caspar::win_product_name());\r
-                       info.add(L"system.windows.service-pack",        caspar::win_sp_version());\r
-                       info.add(L"system.cpu",                                         caspar::cpu_info());\r
-       \r
-                       BOOST_FOREACH(auto device, caspar::decklink::device_list())\r
-                               info.add(L"system.decklink.device", device);\r
-\r
-                       BOOST_FOREACH(auto device, caspar::bluefish::device_list())\r
-                               info.add(L"system.bluefish.device", device);\r
-                               \r
-                       info.add(L"system.flash",                                       caspar::flash::version());\r
-                       //info.add(L"system.free-image",                                caspar::image::version());\r
-                       info.add(L"system.ffmpeg.avcodec",                      caspar::ffmpeg::avcodec_version());\r
-                       info.add(L"system.ffmpeg.avformat",                     caspar::ffmpeg::avformat_version());\r
-                       info.add(L"system.ffmpeg.avfilter",                     caspar::ffmpeg::avfilter_version());\r
-                       info.add(L"system.ffmpeg.avutil",                       caspar::ffmpeg::avutil_version());\r
-                       info.add(L"system.ffmpeg.swscale",                      caspar::ffmpeg::swscale_version());\r
-                                               \r
-                       boost::property_tree::write_xml(replyString, info, w);\r
-               }\r
-               else if(_parameters.size() >= 1 && _parameters[0] == L"SERVER")\r
-               {\r
-                       replyString << L"201 INFO SERVER OK\r\n";\r
-                       \r
-                       boost::property_tree::wptree info;\r
-\r
-                       int index = 0;\r
-                       BOOST_FOREACH(auto channel, channels_)\r
-                               info.add_child(L"channels.channel", channel->info())\r
-                                       .add(L"index", ++index);\r
-                       \r
-                       boost::property_tree::write_xml(replyString, info, w);\r
-               }\r
-               else // channel\r
-               {                       \r
-                       if(_parameters.size() >= 1)\r
-                       {\r
-                               replyString << TEXT("201 INFO OK\r\n");\r
-                               boost::property_tree::wptree info;\r
-\r
-                               std::vector<std::wstring> split;\r
-                               boost::split(split, _parameters[0], boost::is_any_of("-"));\r
-                                       \r
-                               int layer = std::numeric_limits<int>::min();\r
-                               int channel = boost::lexical_cast<int>(split[0]) - 1;\r
-\r
-                               if(split.size() > 1)\r
-                                       layer = boost::lexical_cast<int>(split[1]);\r
-                               \r
-                               if(layer == std::numeric_limits<int>::min())\r
-                               {       \r
-                                       info.add_child(L"channel", channels_.at(channel)->info())\r
-                                                       .add(L"index", channel);\r
-                               }\r
-                               else\r
-                               {\r
-                                       if(_parameters.size() >= 2)\r
-                                       {\r
-                                               if(_parameters[1] == L"B")\r
-                                                       info.add_child(L"producer", channels_.at(channel)->stage().background(layer).get()->info());\r
-                                               else\r
-                                                       info.add_child(L"producer", channels_.at(channel)->stage().foreground(layer).get()->info());\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               info.add_child(L"layer", channels_.at(channel)->stage().info(layer).get())\r
-                                                       .add(L"index", layer);\r
-                                       }\r
-                               }\r
-                               boost::property_tree::xml_parser::write_xml(replyString, info, w);\r
-                       }\r
-                       else\r
-                       {\r
-                               // This is needed for backwards compatibility with old clients\r
-                               replyString << TEXT("200 INFO OK\r\n");\r
-                               for(size_t n = 0; n < channels_.size(); ++n)\r
-                                       GenerateChannelInfo(n, channels_[n], replyString);\r
-                       }\r
-\r
-               }\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("403 INFO ERROR\r\n"));\r
-               return false;\r
-       }\r
-\r
-       replyString << TEXT("\r\n");\r
-       SetReplyString(replyString.str());\r
-       return true;\r
-}\r
-\r
-bool ClsCommand::DoExecute()\r
-{\r
-/*\r
-               wav = audio\r
-               mp3 = audio\r
-               swf     = movie\r
-               dv  = movie\r
-               tga = still\r
-               col = still\r
-       */\r
-       try\r
-       {\r
-               std::wstringstream replyString;\r
-               replyString << TEXT("200 CLS OK\r\n");\r
-               replyString << ListMedia();\r
-               replyString << TEXT("\r\n");\r
-               SetReplyString(boost::to_upper_copy(replyString.str()));\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("501 CLS FAILED\r\n"));\r
-               return false;\r
-       }\r
-\r
-       return true;\r
-}\r
-\r
-bool TlsCommand::DoExecute()\r
-{\r
-       try\r
-       {\r
-               std::wstringstream replyString;\r
-               replyString << TEXT("200 TLS OK\r\n");\r
-\r
-               replyString << ListTemplates();\r
-               replyString << TEXT("\r\n");\r
-\r
-               SetReplyString(replyString.str());\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("501 TLS FAILED\r\n"));\r
-               return false;\r
-       }\r
-       return true;\r
-}\r
-\r
-bool VersionCommand::DoExecute()\r
-{\r
-       std::wstring replyString = TEXT("201 VERSION OK\r\n") + env::version() + TEXT("\r\n");\r
-\r
-       if(_parameters.size() > 0)\r
-       {\r
-               if(_parameters[0] == L"FLASH")\r
-                       replyString = TEXT("201 VERSION OK\r\n") + flash::version() + TEXT("\r\n");\r
-               else if(_parameters[0] == L"TEMPLATEHOST")\r
-                       replyString = TEXT("201 VERSION OK\r\n") + flash::cg_version() + TEXT("\r\n");\r
-               else if(_parameters[0] != L"SERVER")\r
-                       replyString = TEXT("403 VERSION ERROR\r\n");\r
-       }\r
-\r
-       SetReplyString(replyString);\r
-       return true;\r
-}\r
-\r
-bool ByeCommand::DoExecute()\r
-{\r
-       GetClientInfo()->Disconnect();\r
-       return true;\r
-}\r
-\r
-bool SetCommand::DoExecute()\r
-{\r
-       try\r
-       {\r
-               std::wstring name = _parameters[0];\r
-               std::transform(name.begin(), name.end(), name.begin(), toupper);\r
-\r
-               std::wstring value = _parameters[1];\r
-               std::transform(value.begin(), value.end(), value.begin(), toupper);\r
-\r
-               if(name == TEXT("MODE"))\r
-               {\r
-                       auto format_desc = core::video_format_desc(value);\r
-                       if(format_desc.format != core::video_format::invalid)\r
-                       {\r
-                               GetChannel()->video_format_desc(format_desc);\r
-                               SetReplyString(TEXT("202 SET MODE OK\r\n"));\r
-                       }\r
-                       else\r
-                               SetReplyString(TEXT("501 SET MODE FAILED\r\n"));\r
-               }\r
-               else\r
-               {\r
-                       this->SetReplyString(TEXT("403 SET ERROR\r\n"));\r
-               }\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               SetReplyString(TEXT("501 SET FAILED\r\n"));\r
-               return false;\r
-       }\r
-\r
-       return true;\r
-}\r
-\r
-\r
-}      //namespace amcp\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#include "../StdAfx.h"
+
+#if defined(_MSC_VER)
+#pragma warning (push, 1) // TODO: Legacy code, just disable warnings
+#endif
+
+#include "AMCPCommandsImpl.h"
+#include "AMCPProtocolStrategy.h"
+
+#include <common/env.h>
+
+#include <common/log.h>
+#include <common/diagnostics/graph.h>
+#include <common/os/windows/current_version.h>
+#include <common/os/windows/system_info.h>
+
+#include <core/producer/frame_producer.h>
+#include <core/video_format.h>
+#include <core/producer/transition/transition_producer.h>
+#include <core/frame/frame_transform.h>
+#include <core/producer/stage.h>
+#include <core/producer/layer.h>
+#include <core/mixer/mixer.h>
+#include <core/consumer/output.h>
+
+#include <modules/reroute/producer/reroute_producer.h>
+#include <modules/bluefish/bluefish.h>
+#include <modules/decklink/decklink.h>
+#include <modules/ffmpeg/ffmpeg.h>
+#include <modules/flash/flash.h>
+#include <modules/flash/util/swf.h>
+#include <modules/flash/producer/flash_producer.h>
+#include <modules/flash/producer/cg_proxy.h>
+#include <modules/ffmpeg/producer/util/util.h>
+#include <modules/image/image.h>
+#include <modules/screen/screen.h>
+#include <modules/reroute/producer/reroute_producer.h>
+
+#include <algorithm>
+#include <locale>
+#include <fstream>
+#include <memory>
+#include <cctype>
+#include <io.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/regex.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <boost/locale.hpp>
+#include <boost/range/adaptor/transformed.hpp>
+#include <boost/range/algorithm/copy.hpp>
+
+#include <tbb/concurrent_unordered_map.h>
+
+/* Return codes
+
+100 [action]                   Information om att nÃ¥got har hänt  
+101 [action]                   Information om att nÃ¥got har hänt, en rad data skickas  
+
+202 [kommando] OK              Kommandot har utförts  
+201 [kommando] OK              Kommandot har utförts, och en rad data skickas tillbaka  
+200 [kommando] OK              Kommandot har utförts, och flera rader data skickas tillbaka. Avslutas med tomrad  
+
+400 ERROR                              Kommandot kunde inte förstÃ¥s  
+401 [kommando] ERROR   Ogiltig kanal  
+402 [kommando] ERROR   Parameter saknas  
+403 [kommando] ERROR   Ogiltig parameter  
+404 [kommando] ERROR   Mediafilen hittades inte  
+
+500 FAILED                             Internt configurationfel  
+501 [kommando] FAILED  Internt configurationfel  
+502 [kommando] FAILED  Oläslig mediafil  
+
+600 [kommando] FAILED  funktion ej implementerad
+*/
+
+namespace caspar { namespace protocol {
+
+using namespace core;
+
+std::wstring read_utf8_file(const boost::filesystem::wpath& file)
+{
+       std::wstringstream result;
+       boost::filesystem::wifstream filestream(file);
+
+       if (filestream) 
+       {
+               // Consume BOM first
+               filestream.get();
+               // read all data
+               result << filestream.rdbuf();
+       }
+
+       return result.str();
+}
+
+std::wstring read_latin1_file(const boost::filesystem::wpath& file)
+{
+       boost::locale::generator gen;
+       gen.locale_cache_enabled(true);
+       gen.categories(boost::locale::codepage_facet);
+
+       std::stringstream result_stream;
+       boost::filesystem::ifstream filestream(file);
+       filestream.imbue(gen("en_US.ISO8859-1"));
+
+       if (filestream)
+       {
+               // read all data
+               result_stream << filestream.rdbuf();
+       }
+
+       std::string result = result_stream.str();
+       std::wstring widened_result;
+
+       // The first 255 codepoints in unicode is the same as in latin1
+       auto from_signed_to_signed = std::function<unsigned char(char)>(
+               [] (char c) { return static_cast<unsigned char>(c); }
+       );
+       boost::copy(
+               result | boost::adaptors::transformed(from_signed_to_signed),
+               std::back_inserter(widened_result));
+
+       return widened_result;
+}
+
+std::wstring read_file(const boost::filesystem::wpath& file)
+{
+       static const uint8_t BOM[] = {0xef, 0xbb, 0xbf};
+
+       if (!boost::filesystem::exists(file))
+       {
+               return L"";
+       }
+
+       if (boost::filesystem::file_size(file) >= 3)
+       {
+               boost::filesystem::ifstream bom_stream(file);
+
+               char header[3];
+               bom_stream.read(header, 3);
+               bom_stream.close();
+
+               if (std::memcmp(BOM, header, 3) == 0)
+                       return read_utf8_file(file);
+       }
+
+       return read_latin1_file(file);
+}
+
+std::wstring MediaInfo(const boost::filesystem::path& path)
+{
+       if(boost::filesystem::is_regular_file(path))
+       {
+               std::wstring clipttype = TEXT("N/A");
+               std::wstring extension = boost::to_upper_copy(path.extension().wstring());
+               if(extension == TEXT(".TGA") || extension == TEXT(".COL") || extension == L".PNG" || extension == L".JPEG" || extension == L".JPG" ||
+                       extension == L"GIF" || extension == L"BMP")
+                       clipttype = TEXT("STILL");
+               else if(extension == TEXT(".WAV") || extension == TEXT(".MP3"))
+                       clipttype = TEXT("STILL");
+               else if(extension == TEXT("SWF") || extension == TEXT("CT") || extension == TEXT("DV") || extension == TEXT("MOV") || extension == TEXT("MPG") || extension == TEXT("AVI") || caspar::ffmpeg::is_valid_file(path.wstring()))
+                       clipttype = TEXT("MOVIE");
+
+               if(clipttype != TEXT("N/A"))
+               {               
+                       auto is_not_digit = [](char c){ return std::isdigit(c) == 0; };
+
+                       auto relativePath = boost::filesystem::path(path.wstring().substr(env::media_folder().size()-1, path.wstring().size()));
+
+                       auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(path)));
+                       writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), is_not_digit), writeTimeStr.end());
+                       auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());
+
+                       auto sizeStr = boost::lexical_cast<std::wstring>(boost::filesystem::file_size(path));
+                       sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), is_not_digit), sizeStr.end());
+                       auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());
+                               
+                       auto str = relativePath.replace_extension(TEXT("")).native();
+                       while(str.size() > 0 && (str[0] == '\\' || str[0] == '/'))
+                               str = std::wstring(str.begin() + 1, str.end());
+
+                       return std::wstring() + TEXT("\"") + str +
+                                       + TEXT("\" ") + clipttype +
+                                       + TEXT(" ") + sizeStr +
+                                       + TEXT(" ") + writeTimeWStr +
+                                       + TEXT("\r\n");         
+               }       
+       }
+       return L"";
+}
+
+std::wstring ListMedia()
+{      
+       std::wstringstream replyString;
+       for (boost::filesystem::recursive_directory_iterator itr(env::media_folder()), end; itr != end; ++itr)  
+               replyString << MediaInfo(itr->path());
+       
+       return boost::to_upper_copy(replyString.str());
+}
+
+std::wstring ListTemplates() 
+{
+       std::wstringstream replyString;
+
+       for (boost::filesystem::recursive_directory_iterator itr(env::template_folder()), end; itr != end; ++itr)
+       {               
+               if(boost::filesystem::is_regular_file(itr->path()) && (itr->path().extension() == L".ft" || itr->path().extension() == L".ct"))
+               {
+                       auto relativePath = boost::filesystem::wpath(itr->path().wstring().substr(env::template_folder().size()-1, itr->path().wstring().size()));
+
+                       auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(itr->path())));
+                       writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), [](char c){ return std::isdigit(c) == 0;}), writeTimeStr.end());
+                       auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());
+
+                       auto sizeStr = boost::lexical_cast<std::string>(boost::filesystem::file_size(itr->path()));
+                       sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), [](char c){ return std::isdigit(c) == 0;}), sizeStr.end());
+
+                       auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());
+
+                       std::wstring dir = relativePath.parent_path().native();
+                       std::wstring file = boost::to_upper_copy(relativePath.filename().wstring());
+                       relativePath = boost::filesystem::wpath(dir + L"/" + file);
+                                               
+                       auto str = relativePath.replace_extension(TEXT("")).native();
+                       boost::trim_if(str, boost::is_any_of("\\/"));
+
+                       replyString << TEXT("\"") << str
+                                               << TEXT("\" ") << sizeWStr
+                                               << TEXT(" ") << writeTimeWStr
+                                               << TEXT("\r\n");                
+               }
+       }
+       return replyString.str();
+}
+
+namespace amcp {
+       
+AMCPCommand::AMCPCommand() : channelIndex_(0), layerIndex_(-1)
+{}
+
+void AMCPCommand::SendReply()
+{
+       if(!pClientInfo_) 
+               return;
+
+       if(replyString_.empty())
+               return;
+       pClientInfo_->Send(replyString_);
+}
+
+void AMCPCommand::Clear() 
+{
+       pChannel_->stage().clear();
+       pClientInfo_.reset();
+       channelIndex_ = 0;
+       _parameters.clear();
+}
+
+bool DiagnosticsCommand::DoExecute()
+{      
+       try
+       {
+               diagnostics::show_graphs(true);
+
+               SetReplyString(TEXT("202 DIAG OK\r\n"));
+
+               return true;
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("502 DIAG FAILED\r\n"));
+               return false;
+       }
+}
+
+bool ChannelGridCommand::DoExecute()
+{
+       CASPAR_THROW_EXCEPTION(not_implemented());
+
+       //int index = 1;
+       //auto self = GetChannels().back();
+       //
+       //std::vector<std::wstring> params;
+       //params.push_back(L"SCREEN");
+       //params.push_back(L"NAME");
+       //params.push_back(L"Channel Grid Window");
+       //auto screen = create_consumer(params);
+
+       //self->output().add(screen);
+
+       //BOOST_FOREACH(auto channel, GetChannels())
+       //{
+       //      if(channel != self)
+       //      {
+       //              auto producer = reroute::create_producer(self->frame_factory(), *channel);              
+       //              self->stage().load(index, producer, false);
+       //              self->stage().play(index);
+       //              index++;
+       //      }
+       //}
+
+       //int n = GetChannels().size()-1;
+       //double delta = 1.0/static_cast<double>(n);
+       //for(int x = 0; x < n; ++x)
+       //{
+       //      for(int y = 0; y < n; ++y)
+       //      {
+       //              int index = x+y*n+1;
+       //              auto transform = [=](frame_transform transform) -> frame_transform
+       //              {               
+       //                      transform.image_transform.fill_translation[0]   = x*delta;
+       //                      transform.image_transform.fill_translation[1]   = y*delta;
+       //                      transform.image_transform.fill_scale[0]                 = delta;
+       //                      transform.image_transform.fill_scale[1]                 = delta;
+       //                      transform.image_transform.clip_translation[0]   = x*delta;
+       //                      transform.image_transform.clip_translation[1]   = y*delta;
+       //                      transform.image_transform.clip_scale[0]                 = delta;
+       //                      transform.image_transform.clip_scale[1]                 = delta;                        
+       //                      return transform;
+       //              };
+       //              self->stage().apply_transform(index, transform);
+       //      }
+       //}
+
+       //return true;
+}
+
+bool CallCommand::DoExecute()
+{      
+       //Perform loading of the clip
+       try
+       {
+               auto what = _parameters.at(0);
+                               
+               std::wstring param;
+               for(auto it = std::begin(_parameters2); it != std::end(_parameters2); ++it, param += L" ")
+                       param += *it;
+
+               auto result = GetChannel()->stage().call(GetLayerIndex(), boost::trim_copy(param));
+               
+               if(!result.timed_wait(boost::posix_time::seconds(2)))
+                       CASPAR_THROW_EXCEPTION(timed_out());
+                               
+               std::wstringstream replyString;
+               if(result.get().empty())
+                       replyString << TEXT("202 CALL OK\r\n");
+               else
+                       replyString << TEXT("201 CALL OK\r\n") << result.get() << L"\r\n";
+               
+               SetReplyString(replyString.str());
+
+               return true;
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("502 CALL FAILED\r\n"));
+               return false;
+       }
+}
+
+tbb::concurrent_unordered_map<int, std::vector<stage::transform_tuple_t>> deferred_transforms;
+
+bool MixerCommand::DoExecute()
+{      
+       //Perform loading of the clip
+       try
+       {       
+               bool defer = _parameters.back() == L"DEFER";
+               if(defer)
+                       _parameters.pop_back();
+
+               std::vector<stage::transform_tuple_t> transforms;
+
+               if(_parameters[0] == L"KEYER" || _parameters[0] == L"IS_KEY")
+               {
+                       bool value = boost::lexical_cast<int>(_parameters.at(1));
+                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform
+                       {
+                               transform.image_transform.is_key = value;
+                               return transform;                                       
+                       }, 0, L"linear"));
+               }
+               else if(_parameters[0] == L"OPACITY")
+               {
+                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;
+                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";
+
+                       double value = boost::lexical_cast<double>(_parameters.at(1));
+                       
+                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform
+                       {
+                               transform.image_transform.opacity = value;
+                               return transform;                                       
+                       }, duration, tween));
+               }
+               else if(_parameters[0] == L"FILL" || _parameters[0] == L"FILL_RECT")
+               {
+                       int duration = _parameters.size() > 5 ? boost::lexical_cast<int>(_parameters[5]) : 0;
+                       std::wstring tween = _parameters.size() > 6 ? _parameters[6] : L"linear";
+                       double x        = boost::lexical_cast<double>(_parameters.at(1));
+                       double y        = boost::lexical_cast<double>(_parameters.at(2));
+                       double x_s      = boost::lexical_cast<double>(_parameters.at(3));
+                       double y_s      = boost::lexical_cast<double>(_parameters.at(4));
+
+                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) mutable -> frame_transform
+                       {
+                               transform.image_transform.fill_translation[0]   = x;
+                               transform.image_transform.fill_translation[1]   = y;
+                               transform.image_transform.fill_scale[0]                 = x_s;
+                               transform.image_transform.fill_scale[1]                 = y_s;
+                               transform.image_transform.clip_translation[0]   = x;
+                               transform.image_transform.clip_translation[1]   = y;
+                               transform.image_transform.clip_scale[0]                 = x_s;
+                               transform.image_transform.clip_scale[1]                 = y_s;
+                               return transform;
+                       }, duration, tween));
+               }
+               else if(_parameters[0] == L"CLIP" || _parameters[0] == L"CLIP_RECT")
+               {
+                       int duration = _parameters.size() > 5 ? boost::lexical_cast<int>(_parameters[5]) : 0;
+                       std::wstring tween = _parameters.size() > 6 ? _parameters[6] : L"linear";
+                       double x        = boost::lexical_cast<double>(_parameters.at(1));
+                       double y        = boost::lexical_cast<double>(_parameters.at(2));
+                       double x_s      = boost::lexical_cast<double>(_parameters.at(3));
+                       double y_s      = boost::lexical_cast<double>(_parameters.at(4));
+
+                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform
+                       {
+                               transform.image_transform.clip_translation[0]   = x;
+                               transform.image_transform.clip_translation[1]   = y;
+                               transform.image_transform.clip_scale[0]                 = x_s;
+                               transform.image_transform.clip_scale[1]                 = y_s;
+                               return transform;
+                       }, duration, tween));
+               }
+               else if(_parameters[0] == L"GRID")
+               {
+                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;
+                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";
+                       int n = boost::lexical_cast<int>(_parameters.at(1));
+                       double delta = 1.0/static_cast<double>(n);
+                       for(int x = 0; x < n; ++x)
+                       {
+                               for(int y = 0; y < n; ++y)
+                               {
+                                       int index = x+y*n+1;
+                                       transforms.push_back(stage::transform_tuple_t(index, [=](frame_transform transform) -> frame_transform
+                                       {               
+                                               transform.image_transform.fill_translation[0]   = x*delta;
+                                               transform.image_transform.fill_translation[1]   = y*delta;
+                                               transform.image_transform.fill_scale[0]                 = delta;
+                                               transform.image_transform.fill_scale[1]                 = delta;
+                                               transform.image_transform.clip_translation[0]   = x*delta;
+                                               transform.image_transform.clip_translation[1]   = y*delta;
+                                               transform.image_transform.clip_scale[0]                 = delta;
+                                               transform.image_transform.clip_scale[1]                 = delta;                        
+                                               return transform;
+                                       }, duration, tween));
+                               }
+                       }
+               }
+               else if(_parameters[0] == L"BLEND")
+               {
+                       auto blend_str = _parameters.at(1);                                                             
+                       int layer = GetLayerIndex();
+                       GetChannel()->mixer().set_blend_mode(GetLayerIndex(), get_blend_mode(blend_str));       
+               }
+               else if(_parameters[0] == L"BRIGHTNESS")
+               {
+                       auto value = boost::lexical_cast<double>(_parameters.at(1));
+                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;
+                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";
+                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform
+                       {
+                               transform.image_transform.brightness = value;
+                               return transform;
+                       }, duration, tween));
+               }
+               else if(_parameters[0] == L"SATURATION")
+               {
+                       auto value = boost::lexical_cast<double>(_parameters.at(1));
+                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;
+                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";
+                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform
+                       {
+                               transform.image_transform.saturation = value;
+                               return transform;
+                       }, duration, tween));   
+               }
+               else if(_parameters[0] == L"CONTRAST")
+               {
+                       auto value = boost::lexical_cast<double>(_parameters.at(1));
+                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;
+                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";
+                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform
+                       {
+                               transform.image_transform.contrast = value;
+                               return transform;
+                       }, duration, tween));   
+               }
+               else if(_parameters[0] == L"LEVELS")
+               {
+                       levels value;
+                       value.min_input  = boost::lexical_cast<double>(_parameters.at(1));
+                       value.max_input  = boost::lexical_cast<double>(_parameters.at(2));
+                       value.gamma              = boost::lexical_cast<double>(_parameters.at(3));
+                       value.min_output = boost::lexical_cast<double>(_parameters.at(4));
+                       value.max_output = boost::lexical_cast<double>(_parameters.at(5));
+                       int duration = _parameters.size() > 6 ? boost::lexical_cast<int>(_parameters[6]) : 0;
+                       std::wstring tween = _parameters.size() > 7 ? _parameters[7] : L"linear";
+
+                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform
+                       {
+                               transform.image_transform.levels = value;
+                               return transform;
+                       }, duration, tween));
+               }
+               else if(_parameters[0] == L"VOLUME")
+               {
+                       int duration = _parameters.size() > 2 ? boost::lexical_cast<int>(_parameters[2]) : 0;
+                       std::wstring tween = _parameters.size() > 3 ? _parameters[3] : L"linear";
+                       double value = boost::lexical_cast<double>(_parameters[1]);
+
+                       transforms.push_back(stage::transform_tuple_t(GetLayerIndex(), [=](frame_transform transform) -> frame_transform
+                       {
+                               transform.audio_transform.volume = value;
+                               return transform;
+                       }, duration, tween));
+               }
+               else if(_parameters[0] == L"CLEAR")
+               {
+                       int layer = GetLayerIndex(std::numeric_limits<int>::max());
+                       if(layer ==     std::numeric_limits<int>::max())
+                               GetChannel()->stage().clear_transforms();
+                       else
+                               GetChannel()->stage().clear_transforms(layer);
+               }
+               else if(_parameters[0] == L"COMMIT")
+               {
+                       transforms = std::move(deferred_transforms[GetChannelIndex()]);
+               }
+               else
+               {
+                       SetReplyString(TEXT("404 MIXER ERROR\r\n"));
+                       return false;
+               }
+
+               if(defer)
+               {
+                       auto& defer_tranforms = deferred_transforms[GetChannelIndex()];
+                       defer_tranforms.insert(defer_tranforms.end(), transforms.begin(), transforms.end());
+               }
+               else
+                       GetChannel()->stage().apply_transforms(transforms);
+       
+               SetReplyString(TEXT("202 MIXER OK\r\n"));
+
+               return true;
+       }
+       catch(file_not_found&)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("404 MIXER ERROR\r\n"));
+               return false;
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("502 MIXER FAILED\r\n"));
+               return false;
+       }
+}
+
+bool SwapCommand::DoExecute()
+{      
+       //Perform loading of the clip
+       try
+       {
+               if(GetLayerIndex(-1) != -1)
+               {
+                       std::vector<std::string> strs;
+                       boost::split(strs, _parameters[0], boost::is_any_of("-"));
+                       
+                       auto ch1 = GetChannel();
+                       auto ch2 = GetChannels().at(boost::lexical_cast<int>(strs.at(0))-1);
+
+                       int l1 = GetLayerIndex();
+                       int l2 = boost::lexical_cast<int>(strs.at(1));
+
+                       ch1->stage().swap_layer(l1, l2, ch2->stage());
+               }
+               else
+               {
+                       auto ch1 = GetChannel();
+                       auto ch2 = GetChannels().at(boost::lexical_cast<int>(_parameters[0])-1);
+                       ch1->stage().swap_layers(ch2->stage());
+               }
+               
+               SetReplyString(TEXT("202 SWAP OK\r\n"));
+
+               return true;
+       }
+       catch(file_not_found&)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("404 SWAP ERROR\r\n"));
+               return false;
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("502 SWAP FAILED\r\n"));
+               return false;
+       }
+}
+
+bool AddCommand::DoExecute()
+{      
+       //Perform loading of the clip
+       try
+       {
+               auto consumer = create_consumer(_parameters);
+               GetChannel()->output().add(GetLayerIndex(consumer->index()), consumer);
+       
+               SetReplyString(TEXT("202 ADD OK\r\n"));
+
+               return true;
+       }
+       catch(file_not_found&)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("404 ADD ERROR\r\n"));
+               return false;
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("502 ADD FAILED\r\n"));
+               return false;
+       }
+}
+
+bool RemoveCommand::DoExecute()
+{      
+       //Perform loading of the clip
+       try
+       {
+               auto index = GetLayerIndex(std::numeric_limits<int>::min());
+               if(index == std::numeric_limits<int>::min())
+                       index = create_consumer(_parameters)->index();
+
+               GetChannel()->output().remove(index);
+
+               SetReplyString(TEXT("202 REMOVE OK\r\n"));
+
+               return true;
+       }
+       catch(file_not_found&)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("404 REMOVE ERROR\r\n"));
+               return false;
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("502 REMOVE FAILED\r\n"));
+               return false;
+       }
+}
+
+bool LoadCommand::DoExecute()
+{      
+       //Perform loading of the clip
+       try
+       {
+               _parameters[0] = _parameters[0];
+               auto pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), _parameters);              
+               GetChannel()->stage().load(GetLayerIndex(), pFP, true);
+       
+               SetReplyString(TEXT("202 LOAD OK\r\n"));
+
+               return true;
+       }
+       catch(file_not_found&)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("404 LOAD ERROR\r\n"));
+               return false;
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("502 LOAD FAILED\r\n"));
+               return false;
+       }
+}
+
+
+
+//std::function<std::wstring()> channel_cg_add_command::parse(const std::wstring& message, const std::vector<renderer::render_device_ptr>& channels)
+//{
+//     static boost::wregex expr(L"^CG\\s(?<video_channel>\\d+)-?(?<LAYER>\\d+)?\\sADD\\s(?<FLASH_LAYER>\\d+)\\s(?<TEMPLATE>\\S+)\\s?(?<START_LABEL>\\S\\S+)?\\s?(?<PLAY_ON_LOAD>\\d)?\\s?(?<DATA>.*)?");
+//
+//     boost::wsmatch what;
+//     if(!boost::regex_match(message, what, expr))
+//             return nullptr;
+//
+//     auto info = channel_info::parse(what, channels);
+//
+//     int flash_layer_index = boost::lexical_cast<int>(what["FLASH_LAYER"].str());
+//
+//     std::wstring templatename = what["TEMPLATE"].str();
+//     bool play_on_load = what["PLAY_ON_LOAD"].matched ? what["PLAY_ON_LOAD"].str() != L"0" : 0;
+//     std::wstring start_label = what["START_LABEL"].str();   
+//     std::wstring data = get_data(what["DATA"].str());
+//     
+//     boost::replace_all(templatename, "\"", "");
+//
+//     return [=]() -> std::wstring
+//     {       
+//             std::wstring fullFilename = flash::flash_producer::find_template(server::template_folder() + templatename);
+//             if(fullFilename.empty())
+//                     CASPAR_THROW_EXCEPTION(file_not_found());
+//     
+//             std::wstring extension = boost::filesystem::wpath(fullFilename).extension();
+//             std::wstring filename = templatename;
+//             filename.append(extension);
+//
+//             flash::flash::create_cg_proxy(info.video_channel, std::max<int>(DEFAULT_CHANNEL_LAYER+1, info.layer_index))
+//                     ->add(flash_layer_index, filename, play_on_load, start_label, data);
+//
+//             CASPAR_LOG(info) << L"Executed [amcp_channel_cg_add]";
+//             return L"";
+//     };
+
+bool LoadbgCommand::DoExecute()
+{
+       transition_info transitionInfo;
+       
+       bool bLoop = false;
+
+       // TRANSITION
+
+       std::wstring message;
+       for(size_t n = 0; n < _parameters.size(); ++n)
+               message += _parameters[n] + L" ";
+               
+       static const boost::wregex expr(L".*(?<TRANSITION>CUT|PUSH|SLIDE|WIPE|MIX)\\s*(?<DURATION>\\d+)\\s*(?<TWEEN>(LINEAR)|(EASE[^\\s]*))?\\s*(?<DIRECTION>FROMLEFT|FROMRIGHT|LEFT|RIGHT)?.*");
+       boost::wsmatch what;
+       if(boost::regex_match(message, what, expr))
+       {
+               auto transition = what["TRANSITION"].str();
+               transitionInfo.duration = boost::lexical_cast<size_t>(what["DURATION"].str());
+               auto direction = what["DIRECTION"].matched ? what["DIRECTION"].str() : L"";
+               auto tween = what["TWEEN"].matched ? what["TWEEN"].str() : L"";
+               transitionInfo.tweener = tween;         
+
+               if(transition == TEXT("CUT"))
+                       transitionInfo.type = transition_type::cut;
+               else if(transition == TEXT("MIX"))
+                       transitionInfo.type = transition_type::mix;
+               else if(transition == TEXT("PUSH"))
+                       transitionInfo.type = transition_type::push;
+               else if(transition == TEXT("SLIDE"))
+                       transitionInfo.type = transition_type::slide;
+               else if(transition == TEXT("WIPE"))
+                       transitionInfo.type = transition_type::wipe;
+               
+               if(direction == TEXT("FROMLEFT"))
+                       transitionInfo.direction = transition_direction::from_left;
+               else if(direction == TEXT("FROMRIGHT"))
+                       transitionInfo.direction = transition_direction::from_right;
+               else if(direction == TEXT("LEFT"))
+                       transitionInfo.direction = transition_direction::from_right;
+               else if(direction == TEXT("RIGHT"))
+                       transitionInfo.direction = transition_direction::from_left;
+       }
+       
+       //Perform loading of the clip
+       try
+       {
+               std::shared_ptr<core::frame_producer> pFP;
+               
+               static boost::wregex expr(L"\\[(?<CHANNEL>\\d+)\\]", boost::regex::icase);
+                       
+               boost::wsmatch what;
+               if(boost::regex_match(_parameters.at(0), what, expr))
+               {
+                       auto channel_index = boost::lexical_cast<int>(what["CHANNEL"].str());
+                       pFP = reroute::create_producer(*GetChannels().at(channel_index-1)); 
+               }
+               else
+                       pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), _parameters);
+               
+               if(pFP == frame_producer::empty())
+                       CASPAR_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? _parameters[0] : L""));
+
+               bool auto_play = std::find(_parameters.begin(), _parameters.end(), L"AUTO") != _parameters.end();
+
+               auto pFP2 = create_transition_producer(GetChannel()->video_format_desc().field_mode, spl::make_shared_ptr(pFP), transitionInfo);
+               if(auto_play)
+                       GetChannel()->stage().load(GetLayerIndex(), pFP2, false, transitionInfo.duration); // TODO: LOOP
+               else
+                       GetChannel()->stage().load(GetLayerIndex(), pFP2, false); // TODO: LOOP
+       
+               
+               SetReplyString(TEXT("202 LOADBG OK\r\n"));
+
+               return true;
+       }
+       catch(file_not_found&)
+       {               
+               std::wstring params2;
+               for(auto it = _parameters.begin(); it != _parameters.end(); ++it)
+                       params2 += L" " + *it;
+               CASPAR_LOG(error) << L"File not found. No match found for parameters. Check syntax:" << params2;
+               SetReplyString(TEXT("404 LOADBG ERROR\r\n"));
+               return false;
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("502 LOADBG FAILED\r\n"));
+               return false;
+       }
+}
+
+bool PauseCommand::DoExecute()
+{
+       try
+       {
+               GetChannel()->stage().pause(GetLayerIndex());
+               SetReplyString(TEXT("202 PAUSE OK\r\n"));
+               return true;
+       }
+       catch(...)
+       {
+               SetReplyString(TEXT("501 PAUSE FAILED\r\n"));
+       }
+
+       return false;
+}
+
+bool PlayCommand::DoExecute()
+{
+       try
+       {
+               if(!_parameters.empty())
+               {
+                       LoadbgCommand lbg;
+                       lbg.SetChannel(GetChannel());
+                       lbg.SetChannels(GetChannels());
+                       lbg.SetChannelIndex(GetChannelIndex());
+                       lbg.SetLayerIntex(GetLayerIndex());
+                       lbg.SetClientInfo(GetClientInfo());
+                       for(auto it = _parameters.begin(); it != _parameters.end(); ++it)
+                               lbg.AddParameter(*it);
+                       if(!lbg.Execute())
+                               throw std::exception();
+               }
+
+               GetChannel()->stage().play(GetLayerIndex());
+               
+               SetReplyString(TEXT("202 PLAY OK\r\n"));
+               return true;
+       }
+       catch(...)
+       {
+               SetReplyString(TEXT("501 PLAY FAILED\r\n"));
+       }
+
+       return false;
+}
+
+bool StopCommand::DoExecute()
+{
+       try
+       {
+               GetChannel()->stage().stop(GetLayerIndex());
+               SetReplyString(TEXT("202 STOP OK\r\n"));
+               return true;
+       }
+       catch(...)
+       {
+               SetReplyString(TEXT("501 STOP FAILED\r\n"));
+       }
+
+       return false;
+}
+
+bool ClearCommand::DoExecute()
+{
+       int index = GetLayerIndex(std::numeric_limits<int>::min());
+       if(index != std::numeric_limits<int>::min())
+               GetChannel()->stage().clear(index);
+       else
+               GetChannel()->stage().clear();
+               
+       SetReplyString(TEXT("202 CLEAR OK\r\n"));
+
+       return true;
+}
+
+bool PrintCommand::DoExecute()
+{
+       GetChannel()->output().add(create_consumer(boost::assign::list_of(L"IMAGE")));
+               
+       SetReplyString(TEXT("202 PRINT OK\r\n"));
+
+       return true;
+}
+
+bool LogCommand::DoExecute()
+{
+       if(_parameters.at(0) == L"LEVEL")
+               log::set_log_level(_parameters.at(1));
+
+       SetReplyString(TEXT("202 LOG OK\r\n"));
+
+       return true;
+}
+
+bool CGCommand::DoExecute()
+{
+       try
+       {
+               std::wstring command = _parameters[0];
+               if(command == TEXT("ADD"))
+                       return DoExecuteAdd();
+               else if(command == TEXT("PLAY"))
+                       return DoExecutePlay();
+               else if(command == TEXT("STOP"))
+                       return DoExecuteStop();
+               else if(command == TEXT("NEXT"))
+                       return DoExecuteNext();
+               else if(command == TEXT("REMOVE"))
+                       return DoExecuteRemove();
+               else if(command == TEXT("CLEAR"))
+                       return DoExecuteClear();
+               else if(command == TEXT("UPDATE"))
+                       return DoExecuteUpdate();
+               else if(command == TEXT("INVOKE"))
+                       return DoExecuteInvoke();
+               else if(command == TEXT("INFO"))
+                       return DoExecuteInfo();
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+       }
+
+       SetReplyString(TEXT("403 CG ERROR\r\n"));
+       return false;
+}
+
+bool CGCommand::ValidateLayer(const std::wstring& layerstring) {
+       int length = layerstring.length();
+       for(int i = 0; i < length; ++i) {
+               if(!_istdigit(layerstring[i])) {
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+bool CGCommand::DoExecuteAdd() {
+       //CG 1 ADD 0 "template_folder/templatename" [STARTLABEL] 0/1 [DATA]
+
+       int layer = 0;                          //_parameters[1]
+//     std::wstring templateName;      //_parameters[2]
+       std::wstring label;             //_parameters[3]
+       bool bDoStart = false;          //_parameters[3] alt. _parameters[4]
+//     std::wstring data;                      //_parameters[4] alt. _parameters[5]
+
+       if(_parameters.size() < 4) 
+       {
+               SetReplyString(TEXT("402 CG ERROR\r\n"));
+               return false;
+       }
+       unsigned int dataIndex = 4;
+
+       if(!ValidateLayer(_parameters[1])) 
+       {
+               SetReplyString(TEXT("403 CG ERROR\r\n"));
+               return false;
+       }
+
+       layer = _ttoi(_parameters[1].c_str());
+
+       if(_parameters[3].length() > 1) 
+       {       //read label
+               label = _parameters2[3];
+               ++dataIndex;
+
+               if(_parameters.size() > 4 && _parameters[4].length() > 0)       //read play-on-load-flag
+                       bDoStart = (_parameters[4][0]==TEXT('1')) ? true : false;
+               else 
+               {
+                       SetReplyString(TEXT("402 CG ERROR\r\n"));
+                       return false;
+               }
+       }
+       else if(_parameters[3].length() > 0) {  //read play-on-load-flag
+               bDoStart = (_parameters[3][0]==TEXT('1')) ? true : false;
+       }
+       else 
+       {
+               SetReplyString(TEXT("403 CG ERROR\r\n"));
+               return false;
+       }
+
+       const TCHAR* pDataString = 0;
+       std::wstringstream data;
+       std::wstring dataFromFile;
+       if(_parameters.size() > dataIndex) 
+       {       //read data
+               const std::wstring& dataString = _parameters2[dataIndex];
+
+               if(dataString[0] == TEXT('<')) //the data is an XML-string
+                       pDataString = dataString.c_str();
+               else 
+               {
+                       //The data is not an XML-string, it must be a filename
+                       std::wstring filename = env::data_folder();
+                       filename.append(dataString);
+                       filename.append(TEXT(".ftd"));
+
+                       dataFromFile = read_file(boost::filesystem::wpath(filename));
+                       pDataString = dataFromFile.c_str();
+               }
+       }
+
+       std::wstring fullFilename = flash::find_template(env::template_folder() + _parameters[2]);
+       if(!fullFilename.empty())
+       {
+               std::wstring extension = boost::filesystem::path(fullFilename).extension().wstring();
+               std::wstring filename = _parameters[2];
+               filename.append(extension);
+
+               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).add(layer, filename, bDoStart, label, (pDataString!=0) ? pDataString : TEXT(""));
+               SetReplyString(TEXT("202 CG OK\r\n"));
+       }
+       else
+       {
+               CASPAR_LOG(warning) << "Could not find template " << _parameters[2];
+               SetReplyString(TEXT("404 CG ERROR\r\n"));
+       }
+       return true;
+}
+
+bool CGCommand::DoExecutePlay()
+{
+       if(_parameters.size() > 1)
+       {
+               if(!ValidateLayer(_parameters[1])) 
+               {
+                       SetReplyString(TEXT("403 CG ERROR\r\n"));
+                       return false;
+               }
+               int layer = _ttoi(_parameters[1].c_str());
+               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).play(layer);
+       }
+       else
+       {
+               SetReplyString(TEXT("402 CG ERROR\r\n"));
+               return true;
+       }
+
+       SetReplyString(TEXT("202 CG OK\r\n"));
+       return true;
+}
+
+bool CGCommand::DoExecuteStop() 
+{
+       if(_parameters.size() > 1)
+       {
+               if(!ValidateLayer(_parameters[1])) 
+               {
+                       SetReplyString(TEXT("403 CG ERROR\r\n"));
+                       return false;
+               }
+               int layer = _ttoi(_parameters[1].c_str());
+               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).stop(layer, 0);
+       }
+       else 
+       {
+               SetReplyString(TEXT("402 CG ERROR\r\n"));
+               return true;
+       }
+
+       SetReplyString(TEXT("202 CG OK\r\n"));
+       return true;
+}
+
+bool CGCommand::DoExecuteNext()
+{
+       if(_parameters.size() > 1) 
+       {
+               if(!ValidateLayer(_parameters[1])) 
+               {
+                       SetReplyString(TEXT("403 CG ERROR\r\n"));
+                       return false;
+               }
+
+               int layer = _ttoi(_parameters[1].c_str());
+               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).next(layer);
+       }
+       else 
+       {
+               SetReplyString(TEXT("402 CG ERROR\r\n"));
+               return true;
+       }
+
+       SetReplyString(TEXT("202 CG OK\r\n"));
+       return true;
+}
+
+bool CGCommand::DoExecuteRemove() 
+{
+       if(_parameters.size() > 1) 
+       {
+               if(!ValidateLayer(_parameters[1])) 
+               {
+                       SetReplyString(TEXT("403 CG ERROR\r\n"));
+                       return false;
+               }
+
+               int layer = _ttoi(_parameters[1].c_str());
+               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).remove(layer);
+       }
+       else 
+       {
+               SetReplyString(TEXT("402 CG ERROR\r\n"));
+               return true;
+       }
+
+       SetReplyString(TEXT("202 CG OK\r\n"));
+       return true;
+}
+
+bool CGCommand::DoExecuteClear() 
+{
+       GetChannel()->stage().clear(GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER));
+       SetReplyString(TEXT("202 CG OK\r\n"));
+       return true;
+}
+
+bool CGCommand::DoExecuteUpdate() 
+{
+       try
+       {
+               if(!ValidateLayer(_parameters.at(1)))
+               {
+                       SetReplyString(TEXT("403 CG ERROR\r\n"));
+                       return false;
+               }
+                                               
+               std::wstring dataString = _parameters2.at(2);                           
+               if(dataString.at(0) != TEXT('<'))
+               {
+                       //The data is not an XML-string, it must be a filename
+                       std::wstring filename = env::data_folder();
+                       filename.append(dataString);
+                       filename.append(TEXT(".ftd"));
+
+                       dataString = read_file(boost::filesystem::wpath(filename));
+               }               
+
+               int layer = _ttoi(_parameters.at(1).c_str());
+               flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).update(layer, dataString);
+       }
+       catch(...)
+       {
+               SetReplyString(TEXT("402 CG ERROR\r\n"));
+               return true;
+       }
+
+       SetReplyString(TEXT("202 CG OK\r\n"));
+       return true;
+}
+
+bool CGCommand::DoExecuteInvoke() 
+{
+       std::wstringstream replyString;
+       replyString << TEXT("201 CG OK\r\n");
+
+       if(_parameters.size() > 2)
+       {
+               if(!ValidateLayer(_parameters[1]))
+               {
+                       SetReplyString(TEXT("403 CG ERROR\r\n"));
+                       return false;
+               }
+               int layer = _ttoi(_parameters[1].c_str());
+               auto result = flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).invoke(layer, _parameters2[2]);
+               replyString << result << TEXT("\r\n"); 
+       }
+       else 
+       {
+               SetReplyString(TEXT("402 CG ERROR\r\n"));
+               return true;
+       }
+       
+       SetReplyString(replyString.str());
+       return true;
+}
+
+bool CGCommand::DoExecuteInfo() 
+{
+       std::wstringstream replyString;
+       replyString << TEXT("201 CG OK\r\n");
+
+       if(_parameters.size() > 1)
+       {
+               if(!ValidateLayer(_parameters[1]))
+               {
+                       SetReplyString(TEXT("403 CG ERROR\r\n"));
+                       return false;
+               }
+
+               int layer = _ttoi(_parameters[1].c_str());
+               auto desc = flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).description(layer);
+               
+               replyString << desc << TEXT("\r\n"); 
+       }
+       else 
+       {
+               auto info = flash::create_cg_proxy(spl::shared_ptr<core::video_channel>(GetChannel()), GetLayerIndex(flash::cg_proxy::DEFAULT_LAYER)).template_host_info();
+               replyString << info << TEXT("\r\n"); 
+       }       
+
+       SetReplyString(replyString.str());
+       return true;
+}
+
+bool DataCommand::DoExecute()
+{
+       std::wstring command = _parameters[0];
+       if(command == TEXT("STORE"))
+               return DoExecuteStore();
+       else if(command == TEXT("RETRIEVE"))
+               return DoExecuteRetrieve();
+       else if(command == TEXT("LIST"))
+               return DoExecuteList();
+
+       SetReplyString(TEXT("403 DATA ERROR\r\n"));
+       return false;
+}
+
+bool DataCommand::DoExecuteStore() 
+{
+       if(_parameters.size() < 3) 
+       {
+               SetReplyString(TEXT("402 DATA STORE ERROR\r\n"));
+               return false;
+       }
+
+       std::wstring filename = env::data_folder();
+       filename.append(_parameters[1]);
+       filename.append(TEXT(".ftd"));
+
+       std::wofstream datafile(filename.c_str());
+       if(!datafile) 
+       {
+               SetReplyString(TEXT("501 DATA STORE FAILED\r\n"));
+               return false;
+       }
+
+       datafile << static_cast<wchar_t>(65279); // UTF-8 BOM character
+       datafile << _parameters2[2] << std::flush;
+       datafile.close();
+
+       std::wstring replyString = TEXT("202 DATA STORE OK\r\n");
+       SetReplyString(replyString);
+       return true;
+}
+
+bool DataCommand::DoExecuteRetrieve() 
+{
+       if(_parameters.size() < 2) 
+       {
+               SetReplyString(TEXT("402 DATA RETRIEVE ERROR\r\n"));
+               return false;
+       }
+
+       std::wstring filename = env::data_folder();
+       filename.append(_parameters[1]);
+       filename.append(TEXT(".ftd"));
+
+       std::wstring file_contents = read_file(boost::filesystem::wpath(filename));
+
+       if (file_contents.empty()) 
+       {
+               SetReplyString(TEXT("404 DATA RETRIEVE ERROR\r\n"));
+               return false;
+       }
+
+       std::wstringstream reply(TEXT("201 DATA RETRIEVE OK\r\n"));
+
+       reply << file_contents;
+       reply << "\r\n";
+       SetReplyString(reply.str());
+       return true;
+}
+
+bool DataCommand::DoExecuteList() 
+{
+       std::wstringstream replyString;
+       replyString << TEXT("200 DATA LIST OK\r\n");
+
+       for (boost::filesystem::recursive_directory_iterator itr(env::data_folder()), end; itr != end; ++itr)
+       {                       
+               if(boost::filesystem::is_regular_file(itr->path()))
+               {
+                       if(!boost::iequals(itr->path().extension().wstring(), L".ftd"))
+                               continue;
+                       
+                       auto relativePath = boost::filesystem::wpath(itr->path().wstring().substr(env::data_folder().size()-1, itr->path().wstring().size()));
+                       
+                       auto str = relativePath.replace_extension(TEXT("")).native();
+                       if(str[0] == '\\' || str[0] == '/')
+                               str = std::wstring(str.begin() + 1, str.end());
+
+                       replyString << str << TEXT("\r\n");     
+               }
+       }
+       
+       replyString << TEXT("\r\n");
+
+       SetReplyString(boost::to_upper_copy(replyString.str()));
+       return true;
+}
+
+bool CinfCommand::DoExecute()
+{
+       std::wstringstream replyString;
+       
+       try
+       {
+               std::wstring info;
+               for (boost::filesystem::recursive_directory_iterator itr(env::media_folder()), end; itr != end && info.empty(); ++itr)
+               {
+                       auto path = itr->path();
+                       auto file = path.replace_extension(L"").filename();
+                       if(boost::iequals(file.wstring(), _parameters.at(0)))
+                               info += MediaInfo(itr->path()) + L"\r\n";
+               }
+
+               if(info.empty())
+               {
+                       SetReplyString(TEXT("404 CINF ERROR\r\n"));
+                       return false;
+               }
+               replyString << TEXT("200 CINF OK\r\n");
+               replyString << info << "\r\n";
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("404 CINF ERROR\r\n"));
+               return false;
+       }
+       
+       SetReplyString(replyString.str());
+       return true;
+}
+
+void GenerateChannelInfo(int index, const spl::shared_ptr<core::video_channel>& pChannel, std::wstringstream& replyString)
+{
+       replyString << index+1 << TEXT(" ") << pChannel->video_format_desc().name << TEXT(" PLAYING") << TEXT("\r\n");
+}
+
+bool InfoCommand::DoExecute()
+{
+       std::wstringstream replyString;
+       
+       boost::property_tree::xml_writer_settings<wchar_t> w(' ', 3);
+
+       try
+       {
+               if(_parameters.size() >= 1 && _parameters[0] == L"TEMPLATE")
+               {               
+                       replyString << L"201 INFO TEMPLATE OK\r\n";
+
+                       // Needs to be extended for any file, not just flash.
+
+                       auto filename = flash::find_template(env::template_folder() + _parameters.at(1));
+                                               
+                       std::wstringstream str;
+                       str << u16(flash::read_template_meta_info(filename));
+                       boost::property_tree::wptree info;
+                       boost::property_tree::xml_parser::read_xml(str, info, boost::property_tree::xml_parser::trim_whitespace | boost::property_tree::xml_parser::no_comments);
+
+                       boost::property_tree::xml_parser::write_xml(replyString, info, w);
+               }
+               else if(_parameters.size() >= 1 && _parameters[0] == L"CONFIG")
+               {               
+                       replyString << L"201 INFO CONFIG OK\r\n";
+
+                       boost::property_tree::write_xml(replyString, caspar::env::properties(), w);
+               }
+               else if(_parameters.size() >= 1 && _parameters[0] == L"PATHS")
+               {
+                       replyString << L"201 INFO PATHS OK\r\n";
+
+                       boost::property_tree::wptree info;
+                       info.add_child(L"paths", caspar::env::properties().get_child(L"configuration.paths"));
+                       info.add(L"paths.initial-path", boost::filesystem3::initial_path().wstring() + L"\\");
+
+                       boost::property_tree::write_xml(replyString, info, w);
+               }
+               else if(_parameters.size() >= 1 && _parameters[0] == L"SYSTEM")
+               {
+                       replyString << L"201 INFO SYSTEM OK\r\n";
+                       
+                       boost::property_tree::wptree info;
+                       
+                       info.add(L"system.name",                                        caspar::system_product_name());
+                       info.add(L"system.windows.name",                        caspar::win_product_name());
+                       info.add(L"system.windows.service-pack",        caspar::win_sp_version());
+                       info.add(L"system.cpu",                                         caspar::cpu_info());
+       
+                       BOOST_FOREACH(auto device, caspar::decklink::device_list())
+                               info.add(L"system.decklink.device", device);
+
+                       BOOST_FOREACH(auto device, caspar::bluefish::device_list())
+                               info.add(L"system.bluefish.device", device);
+                               
+                       info.add(L"system.flash",                                       caspar::flash::version());
+                       //info.add(L"system.free-image",                                caspar::image::version());
+                       info.add(L"system.ffmpeg.avcodec",                      caspar::ffmpeg::avcodec_version());
+                       info.add(L"system.ffmpeg.avformat",                     caspar::ffmpeg::avformat_version());
+                       info.add(L"system.ffmpeg.avfilter",                     caspar::ffmpeg::avfilter_version());
+                       info.add(L"system.ffmpeg.avutil",                       caspar::ffmpeg::avutil_version());
+                       info.add(L"system.ffmpeg.swscale",                      caspar::ffmpeg::swscale_version());
+                                               
+                       boost::property_tree::write_xml(replyString, info, w);
+               }
+               else if(_parameters.size() >= 1 && _parameters[0] == L"SERVER")
+               {
+                       replyString << L"201 INFO SERVER OK\r\n";
+                       
+                       boost::property_tree::wptree info;
+
+                       int index = 0;
+                       BOOST_FOREACH(auto channel, channels_)
+                               info.add_child(L"channels.channel", channel->info())
+                                       .add(L"index", ++index);
+                       
+                       boost::property_tree::write_xml(replyString, info, w);
+               }
+               else // channel
+               {                       
+                       if(_parameters.size() >= 1)
+                       {
+                               replyString << TEXT("201 INFO OK\r\n");
+                               boost::property_tree::wptree info;
+
+                               std::vector<std::wstring> split;
+                               boost::split(split, _parameters[0], boost::is_any_of("-"));
+                                       
+                               int layer = std::numeric_limits<int>::min();
+                               int channel = boost::lexical_cast<int>(split[0]) - 1;
+
+                               if(split.size() > 1)
+                                       layer = boost::lexical_cast<int>(split[1]);
+                               
+                               if(layer == std::numeric_limits<int>::min())
+                               {       
+                                       info.add_child(L"channel", channels_.at(channel)->info())
+                                                       .add(L"index", channel);
+                               }
+                               else
+                               {
+                                       if(_parameters.size() >= 2)
+                                       {
+                                               if(_parameters[1] == L"B")
+                                                       info.add_child(L"producer", channels_.at(channel)->stage().background(layer).get()->info());
+                                               else
+                                                       info.add_child(L"producer", channels_.at(channel)->stage().foreground(layer).get()->info());
+                                       }
+                                       else
+                                       {
+                                               info.add_child(L"layer", channels_.at(channel)->stage().info(layer).get())
+                                                       .add(L"index", layer);
+                                       }
+                               }
+                               boost::property_tree::xml_parser::write_xml(replyString, info, w);
+                       }
+                       else
+                       {
+                               // This is needed for backwards compatibility with old clients
+                               replyString << TEXT("200 INFO OK\r\n");
+                               for(size_t n = 0; n < channels_.size(); ++n)
+                                       GenerateChannelInfo(n, channels_[n], replyString);
+                       }
+
+               }
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("403 INFO ERROR\r\n"));
+               return false;
+       }
+
+       replyString << TEXT("\r\n");
+       SetReplyString(replyString.str());
+       return true;
+}
+
+bool ClsCommand::DoExecute()
+{
+/*
+               wav = audio
+               mp3 = audio
+               swf     = movie
+               dv  = movie
+               tga = still
+               col = still
+       */
+       try
+       {
+               std::wstringstream replyString;
+               replyString << TEXT("200 CLS OK\r\n");
+               replyString << ListMedia();
+               replyString << TEXT("\r\n");
+               SetReplyString(boost::to_upper_copy(replyString.str()));
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("501 CLS FAILED\r\n"));
+               return false;
+       }
+
+       return true;
+}
+
+bool TlsCommand::DoExecute()
+{
+       try
+       {
+               std::wstringstream replyString;
+               replyString << TEXT("200 TLS OK\r\n");
+
+               replyString << ListTemplates();
+               replyString << TEXT("\r\n");
+
+               SetReplyString(replyString.str());
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("501 TLS FAILED\r\n"));
+               return false;
+       }
+       return true;
+}
+
+bool VersionCommand::DoExecute()
+{
+       std::wstring replyString = TEXT("201 VERSION OK\r\n") + env::version() + TEXT("\r\n");
+
+       if(_parameters.size() > 0)
+       {
+               if(_parameters[0] == L"FLASH")
+                       replyString = TEXT("201 VERSION OK\r\n") + flash::version() + TEXT("\r\n");
+               else if(_parameters[0] == L"TEMPLATEHOST")
+                       replyString = TEXT("201 VERSION OK\r\n") + flash::cg_version() + TEXT("\r\n");
+               else if(_parameters[0] != L"SERVER")
+                       replyString = TEXT("403 VERSION ERROR\r\n");
+       }
+
+       SetReplyString(replyString);
+       return true;
+}
+
+bool ByeCommand::DoExecute()
+{
+       GetClientInfo()->Disconnect();
+       return true;
+}
+
+bool SetCommand::DoExecute()
+{
+       try
+       {
+               std::wstring name = _parameters[0];
+               std::transform(name.begin(), name.end(), name.begin(), toupper);
+
+               std::wstring value = _parameters[1];
+               std::transform(value.begin(), value.end(), value.begin(), toupper);
+
+               if(name == TEXT("MODE"))
+               {
+                       auto format_desc = core::video_format_desc(value);
+                       if(format_desc.format != core::video_format::invalid)
+                       {
+                               GetChannel()->video_format_desc(format_desc);
+                               SetReplyString(TEXT("202 SET MODE OK\r\n"));
+                       }
+                       else
+                               SetReplyString(TEXT("501 SET MODE FAILED\r\n"));
+               }
+               else
+               {
+                       this->SetReplyString(TEXT("403 SET ERROR\r\n"));
+               }
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               SetReplyString(TEXT("501 SET FAILED\r\n"));
+               return false;
+       }
+
+       return true;
+}
+
+
+}      //namespace amcp
 }}     //namespace caspar
\ No newline at end of file
index 19d801e483b321e1ff4d15aadd7140224e947308..429c7cd821c8c64b694c6801b21e6bbec8090998 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#ifndef __AMCPCOMMANDSIMPL_H__\r
-#define __AMCPCOMMANDSIMPL_H__\r
-\r
-#include "AMCPCommand.h"\r
-\r
-namespace caspar { namespace protocol {\r
-       \r
-std::wstring ListMedia();\r
-std::wstring ListTemplates();\r
-\r
-namespace amcp {\r
-       \r
-class ChannelGridCommand : public AMCPCommandBase<false, 0>\r
-{\r
-       std::wstring print() const { return L"ChannelGridCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class DiagnosticsCommand : public AMCPCommandBase<false, 0>\r
-{\r
-       std::wstring print() const { return L"DiagnosticsCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class CallCommand : public AMCPCommandBase<true, 1>\r
-{\r
-       std::wstring print() const { return L"CallCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class MixerCommand : public AMCPCommandBase<true, 1>\r
-{\r
-       std::wstring print() const { return L"MixerCommand";}\r
-       bool DoExecute();\r
-};\r
-       \r
-class AddCommand : public AMCPCommandBase<true, 1>\r
-{\r
-       std::wstring print() const { return L"AddCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class RemoveCommand : public AMCPCommandBase<true, 0>\r
-{\r
-       std::wstring print() const { return L"RemoveCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class SwapCommand : public AMCPCommandBase<true, 1>\r
-{\r
-       std::wstring print() const { return L"SwapCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class LoadCommand : public AMCPCommandBase<true, 1>\r
-{\r
-       std::wstring print() const { return L"LoadCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class LoadbgCommand : public AMCPCommandBase<true, 1>\r
-{\r
-       std::wstring print() const { return L"LoadbgCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class PlayCommand: public AMCPCommandBase<true, 0>\r
-{\r
-       std::wstring print() const { return L"PlayCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class PauseCommand: public AMCPCommandBase<true, 0>\r
-{\r
-       std::wstring print() const { return L"PauseCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class StopCommand : public AMCPCommandBase<true, 0>\r
-{\r
-       std::wstring print() const { return L"StopCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class ClearCommand : public AMCPCommandBase<true, 0>\r
-{\r
-       std::wstring print() const { return L"ClearCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class PrintCommand : public AMCPCommandBase<true, 0>\r
-{\r
-       std::wstring print() const { return L"PrintCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class LogCommand : public AMCPCommandBase<false, 0>\r
-{\r
-       std::wstring print() const { return L"LogCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class CGCommand : public AMCPCommandBase<true, 1>\r
-{\r
-       std::wstring print() const { return L"CGCommand";}\r
-       bool DoExecute();\r
-       bool ValidateLayer(const std::wstring& layerstring);\r
-\r
-       bool DoExecuteAdd();\r
-       bool DoExecutePlay();\r
-       bool DoExecuteStop();\r
-       bool DoExecuteNext();\r
-       bool DoExecuteRemove();\r
-       bool DoExecuteClear();\r
-       bool DoExecuteUpdate();\r
-       bool DoExecuteInvoke();\r
-       bool DoExecuteInfo();\r
-};\r
-\r
-class DataCommand : public AMCPCommandBase<false, 1>\r
-{\r
-       std::wstring print() const { return L"DataCommand";}\r
-       bool DoExecute();\r
-       bool DoExecuteStore();\r
-       bool DoExecuteRetrieve();\r
-       bool DoExecuteList();\r
-};\r
-\r
-class ClsCommand : public AMCPCommandBase<false, 0>\r
-{\r
-       std::wstring print() const { return L"ClsCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class TlsCommand : public AMCPCommandBase<false, 0>\r
-{\r
-       std::wstring print() const { return L"TlsCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class CinfCommand : public AMCPCommandBase<false, 1>\r
-{\r
-       std::wstring print() const { return L"CinfCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class InfoCommand : public AMCPCommandBase<false, 0>\r
-{\r
-public:\r
-       std::wstring print() const { return L"InfoCommand";}\r
-       InfoCommand(const std::vector<spl::shared_ptr<core::video_channel>>& channels) : channels_(channels){}\r
-       bool DoExecute();\r
-private:\r
-       const std::vector<spl::shared_ptr<core::video_channel>>& channels_;\r
-};\r
-\r
-class VersionCommand : public AMCPCommandBase<false, 0>\r
-{\r
-       std::wstring print() const { return L"VersionCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class ByeCommand : public AMCPCommandBase<false, 0>\r
-{\r
-       std::wstring print() const { return L"ByeCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-class SetCommand : public AMCPCommandBase<true, 2>\r
-{\r
-       std::wstring print() const { return L"SetCommand";}\r
-       bool DoExecute();\r
-};\r
-\r
-//class KillCommand : public AMCPCommand\r
-//{\r
-//public:\r
-//     KillCommand() {}\r
-//     virtual bool DoExecute();\r
-//     virtual AMCPCommandCondition CheckConditions();\r
-//\r
-//     virtual bool NeedChannel() {\r
-//             return false;\r
-//     }\r
-//     virtual AMCPCommandScheduling GetDefaultScheduling() {\r
-//             return AddToQueue;\r
-//     }\r
-//     virtual int GetMinimumParameters() {\r
-//             return 0;\r
-//     }\r
-//};\r
-\r
-}      //namespace amcp\r
-}}     //namespace caspar\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#ifndef __AMCPCOMMANDSIMPL_H__
+#define __AMCPCOMMANDSIMPL_H__
+
+#include "AMCPCommand.h"
+
+namespace caspar { namespace protocol {
+       
+std::wstring ListMedia();
+std::wstring ListTemplates();
+
+namespace amcp {
+       
+class ChannelGridCommand : public AMCPCommandBase<false, 0>
+{
+       std::wstring print() const { return L"ChannelGridCommand";}
+       bool DoExecute();
+};
+
+class DiagnosticsCommand : public AMCPCommandBase<false, 0>
+{
+       std::wstring print() const { return L"DiagnosticsCommand";}
+       bool DoExecute();
+};
+
+class CallCommand : public AMCPCommandBase<true, 1>
+{
+       std::wstring print() const { return L"CallCommand";}
+       bool DoExecute();
+};
+
+class MixerCommand : public AMCPCommandBase<true, 1>
+{
+       std::wstring print() const { return L"MixerCommand";}
+       bool DoExecute();
+};
+       
+class AddCommand : public AMCPCommandBase<true, 1>
+{
+       std::wstring print() const { return L"AddCommand";}
+       bool DoExecute();
+};
+
+class RemoveCommand : public AMCPCommandBase<true, 0>
+{
+       std::wstring print() const { return L"RemoveCommand";}
+       bool DoExecute();
+};
+
+class SwapCommand : public AMCPCommandBase<true, 1>
+{
+       std::wstring print() const { return L"SwapCommand";}
+       bool DoExecute();
+};
+
+class LoadCommand : public AMCPCommandBase<true, 1>
+{
+       std::wstring print() const { return L"LoadCommand";}
+       bool DoExecute();
+};
+
+class LoadbgCommand : public AMCPCommandBase<true, 1>
+{
+       std::wstring print() const { return L"LoadbgCommand";}
+       bool DoExecute();
+};
+
+class PlayCommand: public AMCPCommandBase<true, 0>
+{
+       std::wstring print() const { return L"PlayCommand";}
+       bool DoExecute();
+};
+
+class PauseCommand: public AMCPCommandBase<true, 0>
+{
+       std::wstring print() const { return L"PauseCommand";}
+       bool DoExecute();
+};
+
+class StopCommand : public AMCPCommandBase<true, 0>
+{
+       std::wstring print() const { return L"StopCommand";}
+       bool DoExecute();
+};
+
+class ClearCommand : public AMCPCommandBase<true, 0>
+{
+       std::wstring print() const { return L"ClearCommand";}
+       bool DoExecute();
+};
+
+class PrintCommand : public AMCPCommandBase<true, 0>
+{
+       std::wstring print() const { return L"PrintCommand";}
+       bool DoExecute();
+};
+
+class LogCommand : public AMCPCommandBase<false, 0>
+{
+       std::wstring print() const { return L"LogCommand";}
+       bool DoExecute();
+};
+
+class CGCommand : public AMCPCommandBase<true, 1>
+{
+       std::wstring print() const { return L"CGCommand";}
+       bool DoExecute();
+       bool ValidateLayer(const std::wstring& layerstring);
+
+       bool DoExecuteAdd();
+       bool DoExecutePlay();
+       bool DoExecuteStop();
+       bool DoExecuteNext();
+       bool DoExecuteRemove();
+       bool DoExecuteClear();
+       bool DoExecuteUpdate();
+       bool DoExecuteInvoke();
+       bool DoExecuteInfo();
+};
+
+class DataCommand : public AMCPCommandBase<false, 1>
+{
+       std::wstring print() const { return L"DataCommand";}
+       bool DoExecute();
+       bool DoExecuteStore();
+       bool DoExecuteRetrieve();
+       bool DoExecuteList();
+};
+
+class ClsCommand : public AMCPCommandBase<false, 0>
+{
+       std::wstring print() const { return L"ClsCommand";}
+       bool DoExecute();
+};
+
+class TlsCommand : public AMCPCommandBase<false, 0>
+{
+       std::wstring print() const { return L"TlsCommand";}
+       bool DoExecute();
+};
+
+class CinfCommand : public AMCPCommandBase<false, 1>
+{
+       std::wstring print() const { return L"CinfCommand";}
+       bool DoExecute();
+};
+
+class InfoCommand : public AMCPCommandBase<false, 0>
+{
+public:
+       std::wstring print() const { return L"InfoCommand";}
+       InfoCommand(const std::vector<spl::shared_ptr<core::video_channel>>& channels) : channels_(channels){}
+       bool DoExecute();
+private:
+       const std::vector<spl::shared_ptr<core::video_channel>>& channels_;
+};
+
+class VersionCommand : public AMCPCommandBase<false, 0>
+{
+       std::wstring print() const { return L"VersionCommand";}
+       bool DoExecute();
+};
+
+class ByeCommand : public AMCPCommandBase<false, 0>
+{
+       std::wstring print() const { return L"ByeCommand";}
+       bool DoExecute();
+};
+
+class SetCommand : public AMCPCommandBase<true, 2>
+{
+       std::wstring print() const { return L"SetCommand";}
+       bool DoExecute();
+};
+
+//class KillCommand : public AMCPCommand
+//{
+//public:
+//     KillCommand() {}
+//     virtual bool DoExecute();
+//     virtual AMCPCommandCondition CheckConditions();
+//
+//     virtual bool NeedChannel() {
+//             return false;
+//     }
+//     virtual AMCPCommandScheduling GetDefaultScheduling() {
+//             return AddToQueue;
+//     }
+//     virtual int GetMinimumParameters() {
+//             return 0;
+//     }
+//};
+
+}      //namespace amcp
+}}     //namespace caspar
+
 #endif //__AMCPCOMMANDSIMPL_H__
\ No newline at end of file
index c4d02f7c44a71d992d2cce243642c258691f9fde..2746fbaa758507f2e63c223649726e2bb746dfac 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#include "../StdAfx.h"\r
-\r
-#include "AMCPProtocolStrategy.h"\r
-\r
-#include "../util/AsyncEventServer.h"\r
-#include "AMCPCommandsImpl.h"\r
-\r
-#include <stdio.h>\r
-#include <crtdbg.h>\r
-#include <string.h>\r
-#include <algorithm>\r
-#include <cctype>\r
-\r
-#include <boost/algorithm/string/trim.hpp>\r
-#include <boost/algorithm/string/split.hpp>\r
-#include <boost/algorithm/string/replace.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push, 1) // TODO: Legacy code, just disable warnings\r
-#endif\r
-\r
-namespace caspar { namespace protocol { namespace amcp {\r
-\r
-using IO::ClientInfoPtr;\r
-\r
-const std::wstring AMCPProtocolStrategy::MessageDelimiter = TEXT("\r\n");\r
-\r
-inline std::shared_ptr<core::video_channel> GetChannelSafe(unsigned int index, const std::vector<spl::shared_ptr<core::video_channel>>& channels)\r
-{\r
-       return index < channels.size() ? std::shared_ptr<core::video_channel>(channels[index]) : nullptr;\r
-}\r
-\r
-AMCPProtocolStrategy::AMCPProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels) : channels_(channels) {\r
-       AMCPCommandQueuePtr pGeneralCommandQueue(new AMCPCommandQueue());\r
-       commandQueues_.push_back(pGeneralCommandQueue);\r
-\r
-\r
-       std::shared_ptr<core::video_channel> pChannel;\r
-       unsigned int index = -1;\r
-       //Create a commandpump for each video_channel\r
-       while((pChannel = GetChannelSafe(++index, channels_)) != 0) {\r
-               AMCPCommandQueuePtr pChannelCommandQueue(new AMCPCommandQueue());\r
-               std::wstring title = TEXT("video_channel ");\r
-\r
-               //HACK: Perform real conversion from int to string\r
-               TCHAR num = TEXT('1')+static_cast<TCHAR>(index);\r
-               title += num;\r
-               \r
-               commandQueues_.push_back(pChannelCommandQueue);\r
-       }\r
-}\r
-\r
-AMCPProtocolStrategy::~AMCPProtocolStrategy() {\r
-}\r
-\r
-void AMCPProtocolStrategy::Parse(const TCHAR* pData, int charCount, ClientInfoPtr pClientInfo)\r
-{\r
-       size_t pos;\r
-       std::wstring recvData(pData, charCount);\r
-       std::wstring availibleData = (pClientInfo != nullptr ? pClientInfo->currentMessage_ : L"") + recvData;\r
-\r
-       while(true) {\r
-               pos = availibleData.find(MessageDelimiter);\r
-               if(pos != std::wstring::npos)\r
-               {\r
-                       std::wstring message = availibleData.substr(0,pos);\r
-\r
-                       //This is where a complete message gets taken care of\r
-                       if(message.length() > 0) {\r
-                               ProcessMessage(message, pClientInfo);\r
-                       }\r
-\r
-                       std::size_t nextStartPos = pos + MessageDelimiter.length();\r
-                       if(nextStartPos < availibleData.length())\r
-                               availibleData = availibleData.substr(nextStartPos);\r
-                       else {\r
-                               availibleData.clear();\r
-                               break;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       break;\r
-               }\r
-       }\r
-       if(pClientInfo)\r
-               pClientInfo->currentMessage_ = availibleData;\r
-}\r
-\r
-void AMCPProtocolStrategy::ProcessMessage(const std::wstring& message, ClientInfoPtr& pClientInfo)\r
-{      \r
-       CASPAR_LOG(info) << L"Received message from " << pClientInfo->print() << ": " << message << L"\\r\\n";\r
-       \r
-       bool bError = true;\r
-       MessageParserState state = New;\r
-\r
-       AMCPCommandPtr pCommand;\r
-\r
-       pCommand = InterpretCommandString(message, &state);\r
-\r
-       if(pCommand != 0) {\r
-               pCommand->SetClientInfo(pClientInfo);   \r
-               if(QueueCommand(pCommand))\r
-                       bError = false;\r
-               else\r
-                       state = GetChannel;\r
-       }\r
-\r
-       if(bError == true) {\r
-               std::wstringstream answer;\r
-               switch(state)\r
-               {\r
-               case GetCommand:\r
-                       answer << TEXT("400 ERROR\r\n") + message << "\r\n";\r
-                       break;\r
-               case GetChannel:\r
-                       answer << TEXT("401 ERROR\r\n");\r
-                       break;\r
-               case GetParameters:\r
-                       answer << TEXT("402 ERROR\r\n");\r
-                       break;\r
-               default:\r
-                       answer << TEXT("500 FAILED\r\n");\r
-                       break;\r
-               }\r
-               pClientInfo->Send(answer.str());\r
-       }\r
-}\r
-\r
-AMCPCommandPtr AMCPProtocolStrategy::InterpretCommandString(const std::wstring& message, MessageParserState* pOutState)\r
-{\r
-       std::vector<std::wstring> tokens;\r
-       unsigned int currentToken = 0;\r
-       std::wstring commandSwitch;\r
-\r
-       AMCPCommandPtr pCommand;\r
-       MessageParserState state = New;\r
-\r
-       std::size_t tokensInMessage = TokenizeMessage(message, &tokens);\r
-\r
-       //parse the message one token at the time\r
-       while(currentToken < tokensInMessage)\r
-       {\r
-               switch(state)\r
-               {\r
-               case New:\r
-                       if(tokens[currentToken][0] == TEXT('/'))\r
-                               state = GetSwitch;\r
-                       else\r
-                               state = GetCommand;\r
-                       break;\r
-\r
-               case GetSwitch:\r
-                       commandSwitch = tokens[currentToken];\r
-                       state = GetCommand;\r
-                       ++currentToken;\r
-                       break;\r
-\r
-               case GetCommand:\r
-                       pCommand = CommandFactory(tokens[currentToken]);\r
-                       if(pCommand == 0) {\r
-                               goto ParseFinnished;\r
-                       }\r
-                       else\r
-                       {\r
-                               pCommand->SetChannels(channels_);\r
-                               //Set scheduling\r
-                               if(commandSwitch.size() > 0) {\r
-                                       transform(commandSwitch.begin(), commandSwitch.end(), commandSwitch.begin(), toupper);\r
-\r
-                                       //if(commandSwitch == TEXT("/APP"))\r
-                                       //      pCommand->SetScheduling(AddToQueue);\r
-                                       //else if(commandSwitch  == TEXT("/IMMF"))\r
-                                       //      pCommand->SetScheduling(ImmediatelyAndClear);\r
-                               }\r
-\r
-                               if(pCommand->NeedChannel())\r
-                                       state = GetChannel;\r
-                               else\r
-                                       state = GetParameters;\r
-                       }\r
-                       ++currentToken;\r
-                       break;\r
-\r
-               case GetParameters:\r
-                       {\r
-                               _ASSERTE(pCommand != 0);\r
-                               int parameterCount=0;\r
-                               while(currentToken<tokensInMessage)\r
-                               {\r
-                                       pCommand->AddParameter(tokens[currentToken++]);\r
-                                       ++parameterCount;\r
-                               }\r
-\r
-                               if(parameterCount < pCommand->GetMinimumParameters()) {\r
-                                       goto ParseFinnished;\r
-                               }\r
-\r
-                               state = Done;\r
-                               break;\r
-                       }\r
-\r
-               case GetChannel:\r
-                       {\r
-//                             assert(pCommand != 0);\r
-\r
-                               std::wstring str = boost::trim_copy(tokens[currentToken]);\r
-                               std::vector<std::wstring> split;\r
-                               boost::split(split, str, boost::is_any_of("-"));\r
-                                       \r
-                               int channelIndex = -1;\r
-                               int layerIndex = -1;\r
-                               try\r
-                               {\r
-                                       channelIndex = boost::lexical_cast<int>(split[0]) - 1;\r
-\r
-                                       if(split.size() > 1)\r
-                                               layerIndex = boost::lexical_cast<int>(split[1]);\r
-                               }\r
-                               catch(...)\r
-                               {\r
-                                       goto ParseFinnished;\r
-                               }\r
-\r
-                               std::shared_ptr<core::video_channel> pChannel = GetChannelSafe(channelIndex, channels_);\r
-                               if(pChannel == 0) {\r
-                                       goto ParseFinnished;\r
-                               }\r
-\r
-                               pCommand->SetChannel(pChannel);\r
-                               pCommand->SetChannels(channels_);\r
-                               pCommand->SetChannelIndex(channelIndex);\r
-                               pCommand->SetLayerIntex(layerIndex);\r
-\r
-                               state = GetParameters;\r
-                               ++currentToken;\r
-                               break;\r
-                       }\r
-\r
-               default:        //Done and unexpected\r
-                       goto ParseFinnished;\r
-               }\r
-       }\r
-\r
-ParseFinnished:\r
-       if(state == GetParameters && pCommand->GetMinimumParameters()==0)\r
-               state = Done;\r
-\r
-       if(state != Done) {\r
-               pCommand.reset();\r
-       }\r
-\r
-       if(pOutState != 0) {\r
-               *pOutState = state;\r
-       }\r
-\r
-       return pCommand;\r
-}\r
-\r
-bool AMCPProtocolStrategy::QueueCommand(AMCPCommandPtr pCommand) {\r
-       if(pCommand->NeedChannel()) {\r
-               unsigned int channelIndex = pCommand->GetChannelIndex() + 1;\r
-               if(commandQueues_.size() > channelIndex) {\r
-                       commandQueues_[channelIndex]->AddCommand(pCommand);\r
-               }\r
-               else\r
-                       return false;\r
-       }\r
-       else {\r
-               commandQueues_[0]->AddCommand(pCommand);\r
-       }\r
-       return true;\r
-}\r
-\r
-AMCPCommandPtr AMCPProtocolStrategy::CommandFactory(const std::wstring& str)\r
-{\r
-       std::wstring s = str;\r
-       transform(s.begin(), s.end(), s.begin(), toupper);\r
-       \r
-       if         (s == TEXT("MIXER"))                 return std::make_shared<MixerCommand>();\r
-       else if(s == TEXT("DIAG"))                      return std::make_shared<DiagnosticsCommand>();\r
-       else if(s == TEXT("CHANNEL_GRID"))      return std::make_shared<ChannelGridCommand>();\r
-       else if(s == TEXT("CALL"))                      return std::make_shared<CallCommand>();\r
-       else if(s == TEXT("SWAP"))                      return std::make_shared<SwapCommand>();\r
-       else if(s == TEXT("LOAD"))                      return std::make_shared<LoadCommand>();\r
-       else if(s == TEXT("LOADBG"))            return std::make_shared<LoadbgCommand>();\r
-       else if(s == TEXT("ADD"))                       return std::make_shared<AddCommand>();\r
-       else if(s == TEXT("REMOVE"))            return std::make_shared<RemoveCommand>();\r
-       else if(s == TEXT("PAUSE"))                     return std::make_shared<PauseCommand>();\r
-       else if(s == TEXT("PLAY"))                      return std::make_shared<PlayCommand>();\r
-       else if(s == TEXT("STOP"))                      return std::make_shared<StopCommand>();\r
-       else if(s == TEXT("CLEAR"))                     return std::make_shared<ClearCommand>();\r
-       else if(s == TEXT("PRINT"))                     return std::make_shared<PrintCommand>();\r
-       else if(s == TEXT("LOG"))                       return std::make_shared<LogCommand>();\r
-       else if(s == TEXT("CG"))                        return std::make_shared<CGCommand>();\r
-       else if(s == TEXT("DATA"))                      return std::make_shared<DataCommand>();\r
-       else if(s == TEXT("CINF"))                      return std::make_shared<CinfCommand>();\r
-       else if(s == TEXT("INFO"))                      return std::make_shared<InfoCommand>(channels_);\r
-       else if(s == TEXT("CLS"))                       return std::make_shared<ClsCommand>();\r
-       else if(s == TEXT("TLS"))                       return std::make_shared<TlsCommand>();\r
-       else if(s == TEXT("VERSION"))           return std::make_shared<VersionCommand>();\r
-       else if(s == TEXT("BYE"))                       return std::make_shared<ByeCommand>();\r
-       else if(s == TEXT("SET"))                       return std::make_shared<SetCommand>();\r
-       //else if(s == TEXT("MONITOR"))\r
-       //{\r
-       //      result = AMCPCommandPtr(new MonitorCommand());\r
-       //}\r
-       //else if(s == TEXT("KILL"))\r
-       //{\r
-       //      result = AMCPCommandPtr(new KillCommand());\r
-       //}\r
-       return nullptr;\r
-}\r
-\r
-std::size_t AMCPProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)\r
-{\r
-       //split on whitespace but keep strings within quotationmarks\r
-       //treat \ as the start of an escape-sequence: the following char will indicate what to actually put in the string\r
-\r
-       std::wstring currentToken;\r
-\r
-       char inQuote = 0;\r
-       bool getSpecialCode = false;\r
-\r
-       for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex)\r
-       {\r
-               if(getSpecialCode)\r
-               {\r
-                       //insert code-handling here\r
-                       switch(message[charIndex])\r
-                       {\r
-                       case TEXT('\\'):\r
-                               currentToken += TEXT("\\");\r
-                               break;\r
-                       case TEXT('\"'):\r
-                               currentToken += TEXT("\"");\r
-                               break;\r
-                       case TEXT('n'):\r
-                               currentToken += TEXT("\n");\r
-                               break;\r
-                       default:\r
-                               break;\r
-                       };\r
-                       getSpecialCode = false;\r
-                       continue;\r
-               }\r
-\r
-               if(message[charIndex]==TEXT('\\'))\r
-               {\r
-                       getSpecialCode = true;\r
-                       continue;\r
-               }\r
-\r
-               if(message[charIndex]==' ' && inQuote==false)\r
-               {\r
-                       if(currentToken.size()>0)\r
-                       {\r
-                               pTokenVector->push_back(currentToken);\r
-                               currentToken.clear();\r
-                       }\r
-                       continue;\r
-               }\r
-\r
-               if(message[charIndex]==TEXT('\"'))\r
-               {\r
-                       inQuote ^= 1;\r
-\r
-                       if(currentToken.size()>0)\r
-                       {\r
-                               pTokenVector->push_back(currentToken);\r
-                               currentToken.clear();\r
-                       }\r
-                       continue;\r
-               }\r
-\r
-               currentToken += message[charIndex];\r
-       }\r
-\r
-       if(currentToken.size()>0)\r
-       {\r
-               pTokenVector->push_back(currentToken);\r
-               currentToken.clear();\r
-       }\r
-\r
-       return pTokenVector->size();\r
-}\r
-\r
-}      //namespace amcp\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#include "../StdAfx.h"
+
+#include "AMCPProtocolStrategy.h"
+
+#include "../util/AsyncEventServer.h"
+#include "AMCPCommandsImpl.h"
+
+#include <stdio.h>
+#include <crtdbg.h>
+#include <string.h>
+#include <algorithm>
+#include <cctype>
+
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/lexical_cast.hpp>
+
+#if defined(_MSC_VER)
+#pragma warning (push, 1) // TODO: Legacy code, just disable warnings
+#endif
+
+namespace caspar { namespace protocol { namespace amcp {
+
+using IO::ClientInfoPtr;
+
+const std::wstring AMCPProtocolStrategy::MessageDelimiter = TEXT("\r\n");
+
+inline std::shared_ptr<core::video_channel> GetChannelSafe(unsigned int index, const std::vector<spl::shared_ptr<core::video_channel>>& channels)
+{
+       return index < channels.size() ? std::shared_ptr<core::video_channel>(channels[index]) : nullptr;
+}
+
+AMCPProtocolStrategy::AMCPProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels) : channels_(channels) {
+       AMCPCommandQueuePtr pGeneralCommandQueue(new AMCPCommandQueue());
+       commandQueues_.push_back(pGeneralCommandQueue);
+
+
+       std::shared_ptr<core::video_channel> pChannel;
+       unsigned int index = -1;
+       //Create a commandpump for each video_channel
+       while((pChannel = GetChannelSafe(++index, channels_)) != 0) {
+               AMCPCommandQueuePtr pChannelCommandQueue(new AMCPCommandQueue());
+               std::wstring title = TEXT("video_channel ");
+
+               //HACK: Perform real conversion from int to string
+               TCHAR num = TEXT('1')+static_cast<TCHAR>(index);
+               title += num;
+               
+               commandQueues_.push_back(pChannelCommandQueue);
+       }
+}
+
+AMCPProtocolStrategy::~AMCPProtocolStrategy() {
+}
+
+void AMCPProtocolStrategy::Parse(const TCHAR* pData, int charCount, ClientInfoPtr pClientInfo)
+{
+       size_t pos;
+       std::wstring recvData(pData, charCount);
+       std::wstring availibleData = (pClientInfo != nullptr ? pClientInfo->currentMessage_ : L"") + recvData;
+
+       while(true) {
+               pos = availibleData.find(MessageDelimiter);
+               if(pos != std::wstring::npos)
+               {
+                       std::wstring message = availibleData.substr(0,pos);
+
+                       //This is where a complete message gets taken care of
+                       if(message.length() > 0) {
+                               ProcessMessage(message, pClientInfo);
+                       }
+
+                       std::size_t nextStartPos = pos + MessageDelimiter.length();
+                       if(nextStartPos < availibleData.length())
+                               availibleData = availibleData.substr(nextStartPos);
+                       else {
+                               availibleData.clear();
+                               break;
+                       }
+               }
+               else
+               {
+                       break;
+               }
+       }
+       if(pClientInfo)
+               pClientInfo->currentMessage_ = availibleData;
+}
+
+void AMCPProtocolStrategy::ProcessMessage(const std::wstring& message, ClientInfoPtr& pClientInfo)
+{      
+       CASPAR_LOG(info) << L"Received message from " << pClientInfo->print() << ": " << message << L"\\r\\n";
+       
+       bool bError = true;
+       MessageParserState state = New;
+
+       AMCPCommandPtr pCommand;
+
+       pCommand = InterpretCommandString(message, &state);
+
+       if(pCommand != 0) {
+               pCommand->SetClientInfo(pClientInfo);   
+               if(QueueCommand(pCommand))
+                       bError = false;
+               else
+                       state = GetChannel;
+       }
+
+       if(bError == true) {
+               std::wstringstream answer;
+               switch(state)
+               {
+               case GetCommand:
+                       answer << TEXT("400 ERROR\r\n") + message << "\r\n";
+                       break;
+               case GetChannel:
+                       answer << TEXT("401 ERROR\r\n");
+                       break;
+               case GetParameters:
+                       answer << TEXT("402 ERROR\r\n");
+                       break;
+               default:
+                       answer << TEXT("500 FAILED\r\n");
+                       break;
+               }
+               pClientInfo->Send(answer.str());
+       }
+}
+
+AMCPCommandPtr AMCPProtocolStrategy::InterpretCommandString(const std::wstring& message, MessageParserState* pOutState)
+{
+       std::vector<std::wstring> tokens;
+       unsigned int currentToken = 0;
+       std::wstring commandSwitch;
+
+       AMCPCommandPtr pCommand;
+       MessageParserState state = New;
+
+       std::size_t tokensInMessage = TokenizeMessage(message, &tokens);
+
+       //parse the message one token at the time
+       while(currentToken < tokensInMessage)
+       {
+               switch(state)
+               {
+               case New:
+                       if(tokens[currentToken][0] == TEXT('/'))
+                               state = GetSwitch;
+                       else
+                               state = GetCommand;
+                       break;
+
+               case GetSwitch:
+                       commandSwitch = tokens[currentToken];
+                       state = GetCommand;
+                       ++currentToken;
+                       break;
+
+               case GetCommand:
+                       pCommand = CommandFactory(tokens[currentToken]);
+                       if(pCommand == 0) {
+                               goto ParseFinnished;
+                       }
+                       else
+                       {
+                               pCommand->SetChannels(channels_);
+                               //Set scheduling
+                               if(commandSwitch.size() > 0) {
+                                       transform(commandSwitch.begin(), commandSwitch.end(), commandSwitch.begin(), toupper);
+
+                                       //if(commandSwitch == TEXT("/APP"))
+                                       //      pCommand->SetScheduling(AddToQueue);
+                                       //else if(commandSwitch  == TEXT("/IMMF"))
+                                       //      pCommand->SetScheduling(ImmediatelyAndClear);
+                               }
+
+                               if(pCommand->NeedChannel())
+                                       state = GetChannel;
+                               else
+                                       state = GetParameters;
+                       }
+                       ++currentToken;
+                       break;
+
+               case GetParameters:
+                       {
+                               _ASSERTE(pCommand != 0);
+                               int parameterCount=0;
+                               while(currentToken<tokensInMessage)
+                               {
+                                       pCommand->AddParameter(tokens[currentToken++]);
+                                       ++parameterCount;
+                               }
+
+                               if(parameterCount < pCommand->GetMinimumParameters()) {
+                                       goto ParseFinnished;
+                               }
+
+                               state = Done;
+                               break;
+                       }
+
+               case GetChannel:
+                       {
+//                             assert(pCommand != 0);
+
+                               std::wstring str = boost::trim_copy(tokens[currentToken]);
+                               std::vector<std::wstring> split;
+                               boost::split(split, str, boost::is_any_of("-"));
+                                       
+                               int channelIndex = -1;
+                               int layerIndex = -1;
+                               try
+                               {
+                                       channelIndex = boost::lexical_cast<int>(split[0]) - 1;
+
+                                       if(split.size() > 1)
+                                               layerIndex = boost::lexical_cast<int>(split[1]);
+                               }
+                               catch(...)
+                               {
+                                       goto ParseFinnished;
+                               }
+
+                               std::shared_ptr<core::video_channel> pChannel = GetChannelSafe(channelIndex, channels_);
+                               if(pChannel == 0) {
+                                       goto ParseFinnished;
+                               }
+
+                               pCommand->SetChannel(pChannel);
+                               pCommand->SetChannels(channels_);
+                               pCommand->SetChannelIndex(channelIndex);
+                               pCommand->SetLayerIntex(layerIndex);
+
+                               state = GetParameters;
+                               ++currentToken;
+                               break;
+                       }
+
+               default:        //Done and unexpected
+                       goto ParseFinnished;
+               }
+       }
+
+ParseFinnished:
+       if(state == GetParameters && pCommand->GetMinimumParameters()==0)
+               state = Done;
+
+       if(state != Done) {
+               pCommand.reset();
+       }
+
+       if(pOutState != 0) {
+               *pOutState = state;
+       }
+
+       return pCommand;
+}
+
+bool AMCPProtocolStrategy::QueueCommand(AMCPCommandPtr pCommand) {
+       if(pCommand->NeedChannel()) {
+               unsigned int channelIndex = pCommand->GetChannelIndex() + 1;
+               if(commandQueues_.size() > channelIndex) {
+                       commandQueues_[channelIndex]->AddCommand(pCommand);
+               }
+               else
+                       return false;
+       }
+       else {
+               commandQueues_[0]->AddCommand(pCommand);
+       }
+       return true;
+}
+
+AMCPCommandPtr AMCPProtocolStrategy::CommandFactory(const std::wstring& str)
+{
+       std::wstring s = str;
+       transform(s.begin(), s.end(), s.begin(), toupper);
+       
+       if         (s == TEXT("MIXER"))                 return std::make_shared<MixerCommand>();
+       else if(s == TEXT("DIAG"))                      return std::make_shared<DiagnosticsCommand>();
+       else if(s == TEXT("CHANNEL_GRID"))      return std::make_shared<ChannelGridCommand>();
+       else if(s == TEXT("CALL"))                      return std::make_shared<CallCommand>();
+       else if(s == TEXT("SWAP"))                      return std::make_shared<SwapCommand>();
+       else if(s == TEXT("LOAD"))                      return std::make_shared<LoadCommand>();
+       else if(s == TEXT("LOADBG"))            return std::make_shared<LoadbgCommand>();
+       else if(s == TEXT("ADD"))                       return std::make_shared<AddCommand>();
+       else if(s == TEXT("REMOVE"))            return std::make_shared<RemoveCommand>();
+       else if(s == TEXT("PAUSE"))                     return std::make_shared<PauseCommand>();
+       else if(s == TEXT("PLAY"))                      return std::make_shared<PlayCommand>();
+       else if(s == TEXT("STOP"))                      return std::make_shared<StopCommand>();
+       else if(s == TEXT("CLEAR"))                     return std::make_shared<ClearCommand>();
+       else if(s == TEXT("PRINT"))                     return std::make_shared<PrintCommand>();
+       else if(s == TEXT("LOG"))                       return std::make_shared<LogCommand>();
+       else if(s == TEXT("CG"))                        return std::make_shared<CGCommand>();
+       else if(s == TEXT("DATA"))                      return std::make_shared<DataCommand>();
+       else if(s == TEXT("CINF"))                      return std::make_shared<CinfCommand>();
+       else if(s == TEXT("INFO"))                      return std::make_shared<InfoCommand>(channels_);
+       else if(s == TEXT("CLS"))                       return std::make_shared<ClsCommand>();
+       else if(s == TEXT("TLS"))                       return std::make_shared<TlsCommand>();
+       else if(s == TEXT("VERSION"))           return std::make_shared<VersionCommand>();
+       else if(s == TEXT("BYE"))                       return std::make_shared<ByeCommand>();
+       else if(s == TEXT("SET"))                       return std::make_shared<SetCommand>();
+       //else if(s == TEXT("MONITOR"))
+       //{
+       //      result = AMCPCommandPtr(new MonitorCommand());
+       //}
+       //else if(s == TEXT("KILL"))
+       //{
+       //      result = AMCPCommandPtr(new KillCommand());
+       //}
+       return nullptr;
+}
+
+std::size_t AMCPProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)
+{
+       //split on whitespace but keep strings within quotationmarks
+       //treat \ as the start of an escape-sequence: the following char will indicate what to actually put in the string
+
+       std::wstring currentToken;
+
+       char inQuote = 0;
+       bool getSpecialCode = false;
+
+       for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex)
+       {
+               if(getSpecialCode)
+               {
+                       //insert code-handling here
+                       switch(message[charIndex])
+                       {
+                       case TEXT('\\'):
+                               currentToken += TEXT("\\");
+                               break;
+                       case TEXT('\"'):
+                               currentToken += TEXT("\"");
+                               break;
+                       case TEXT('n'):
+                               currentToken += TEXT("\n");
+                               break;
+                       default:
+                               break;
+                       };
+                       getSpecialCode = false;
+                       continue;
+               }
+
+               if(message[charIndex]==TEXT('\\'))
+               {
+                       getSpecialCode = true;
+                       continue;
+               }
+
+               if(message[charIndex]==' ' && inQuote==false)
+               {
+                       if(currentToken.size()>0)
+                       {
+                               pTokenVector->push_back(currentToken);
+                               currentToken.clear();
+                       }
+                       continue;
+               }
+
+               if(message[charIndex]==TEXT('\"'))
+               {
+                       inQuote ^= 1;
+
+                       if(currentToken.size()>0)
+                       {
+                               pTokenVector->push_back(currentToken);
+                               currentToken.clear();
+                       }
+                       continue;
+               }
+
+               currentToken += message[charIndex];
+       }
+
+       if(currentToken.size()>0)
+       {
+               pTokenVector->push_back(currentToken);
+               currentToken.clear();
+       }
+
+       return pTokenVector->size();
+}
+
+}      //namespace amcp
 }}     //namespace caspar
\ No newline at end of file
index 294fc86f2feaade336f28ea9a92e75e673bd19ab..ac8ee3e7bd49716014216f7b3a9219e7b5ec70c9 100644 (file)
@@ -1,75 +1,75 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "../util/protocolstrategy.h"\r
-#include <core/video_channel.h>\r
-\r
-#include "AMCPCommand.h"\r
-#include "AMCPCommandQueue.h"\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace protocol { namespace amcp {\r
-\r
-class AMCPProtocolStrategy : public IO::IProtocolStrategy, boost::noncopyable\r
-{\r
-       enum MessageParserState {\r
-               New = 0,\r
-               GetSwitch,\r
-               GetCommand,\r
-               GetParameters,\r
-               GetChannel,\r
-               Done\r
-       };\r
-\r
-       AMCPProtocolStrategy(const AMCPProtocolStrategy&);\r
-       AMCPProtocolStrategy& operator=(const AMCPProtocolStrategy&);\r
-\r
-public:\r
-       AMCPProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels);\r
-       virtual ~AMCPProtocolStrategy();\r
-\r
-       virtual void Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo);\r
-       virtual std::string GetCodepage() {\r
-               return "UTF-8";\r
-       }\r
-\r
-       AMCPCommandPtr InterpretCommandString(const std::wstring& str, MessageParserState* pOutState=0);\r
-\r
-private:\r
-       friend class AMCPCommand;\r
-\r
-       void ProcessMessage(const std::wstring& message, IO::ClientInfoPtr& pClientInfo);\r
-       std::size_t TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector);\r
-       AMCPCommandPtr CommandFactory(const std::wstring& str);\r
-\r
-       bool QueueCommand(AMCPCommandPtr);\r
-\r
-       std::vector<spl::shared_ptr<core::video_channel>> channels_;\r
-       std::vector<AMCPCommandQueuePtr> commandQueues_;\r
-       static const std::wstring MessageDelimiter;\r
-};\r
-\r
-}}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#pragma once
+
+#include "../util/protocolstrategy.h"
+#include <core/video_channel.h>
+
+#include "AMCPCommand.h"
+#include "AMCPCommandQueue.h"
+
+#include <boost/noncopyable.hpp>
+
+#include <string>
+
+namespace caspar { namespace protocol { namespace amcp {
+
+class AMCPProtocolStrategy : public IO::IProtocolStrategy, boost::noncopyable
+{
+       enum MessageParserState {
+               New = 0,
+               GetSwitch,
+               GetCommand,
+               GetParameters,
+               GetChannel,
+               Done
+       };
+
+       AMCPProtocolStrategy(const AMCPProtocolStrategy&);
+       AMCPProtocolStrategy& operator=(const AMCPProtocolStrategy&);
+
+public:
+       AMCPProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels);
+       virtual ~AMCPProtocolStrategy();
+
+       virtual void Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo);
+       virtual std::string GetCodepage() {
+               return "UTF-8";
+       }
+
+       AMCPCommandPtr InterpretCommandString(const std::wstring& str, MessageParserState* pOutState=0);
+
+private:
+       friend class AMCPCommand;
+
+       void ProcessMessage(const std::wstring& message, IO::ClientInfoPtr& pClientInfo);
+       std::size_t TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector);
+       AMCPCommandPtr CommandFactory(const std::wstring& str);
+
+       bool QueueCommand(AMCPCommandPtr);
+
+       std::vector<spl::shared_ptr<core::video_channel>> channels_;
+       std::vector<AMCPCommandQueuePtr> commandQueues_;
+       static const std::wstring MessageDelimiter;
+};
+
+}}}
index ea9146f93dfad12a2b0f4ee2c685173b1bfac0d8..5df1e2813c81744ad29f9c863b7f6a46ac61235f 100644 (file)
@@ -1,40 +1,40 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#pragma once\r
-\r
-namespace caspar { namespace protocol {\r
-namespace cii {\r
-\r
-class ICIICommand\r
-{\r
-public:\r
-       virtual ~ICIICommand() {}\r
-       virtual int GetMinimumParameters() = 0;\r
-       virtual void Setup(const std::vector<std::wstring>& parameters) = 0;\r
-\r
-       virtual void Execute() = 0;\r
-};\r
-typedef std::tr1::shared_ptr<ICIICommand> CIICommandPtr;\r
-\r
-}      //namespace cii\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#pragma once
+
+namespace caspar { namespace protocol {
+namespace cii {
+
+class ICIICommand
+{
+public:
+       virtual ~ICIICommand() {}
+       virtual int GetMinimumParameters() = 0;
+       virtual void Setup(const std::vector<std::wstring>& parameters) = 0;
+
+       virtual void Execute() = 0;
+};
+typedef std::tr1::shared_ptr<ICIICommand> CIICommandPtr;
+
+}      //namespace cii
 }}     //namespace caspar
\ No newline at end of file
index 78fad5f79e3975e7a74d1e0ff27b7644a58f03ac..2da5f50d26a46a8980f0eed4ad4930b7fa702c36 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#include "../StdAfx.h"\r
-\r
-#pragma warning (disable: 4244)\r
-\r
-#include "CIIProtocolStrategy.h"\r
-#include "CIICommandsImpl.h"\r
-#include <sstream>\r
-#include <algorithm>\r
-#include <modules/flash/producer/cg_proxy.h>\r
-#include <boost/locale.hpp>\r
-#include <boost/algorithm/string/trim.hpp>\r
-#include <boost/algorithm/string/split.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-\r
-namespace caspar { namespace protocol { namespace cii {\r
-\r
-////////\r
-// MediaCommand\r
-void MediaCommand::Setup(const std::vector<std::wstring>& parameters) \r
-{\r
-       graphicProfile_ = parameters[1].substr(2);\r
-}\r
-\r
-void MediaCommand::Execute() \r
-{\r
-       pCIIStrategy_->SetProfile(graphicProfile_);\r
-}\r
-\r
-\r
-////////\r
-// WriteCommand\r
-void WriteCommand::Setup(const std::vector<std::wstring>& parameters)\r
-{\r
-       try \r
-       {\r
-               if(parameters.size() > 2)\r
-               {\r
-                       targetName_ = parameters[1];\r
-                       templateName_ = parameters[2];\r
-\r
-                       std::wstringstream dataStream;\r
-\r
-                       dataStream << TEXT("<templateData>");\r
-\r
-                       std::vector<std::wstring>::size_type end = parameters.size();\r
-                       for(std::vector<std::wstring>::size_type i = 3; i < end; ++i) \r
-                               dataStream << TEXT("<componentData id=\"field") << i-2 << TEXT("\"><data id=\"text\" value=\"") << parameters[i] << TEXT("\" /></componentData>"); \r
-\r
-                       dataStream << TEXT("</templateData>");\r
-                       xmlData_ = dataStream.str();\r
-               }\r
-       }\r
-       catch(std::exception) {\r
-       }\r
-}\r
-\r
-void WriteCommand::Execute() \r
-{\r
-       pCIIStrategy_->WriteTemplateData(templateName_, targetName_, xmlData_);\r
-}\r
-\r
-\r
-//////////\r
-// ImagestoreCommand\r
-void ImagestoreCommand::Setup(const std::vector<std::wstring>& parameters) \r
-{\r
-       if(parameters[1] == TEXT("7") && parameters.size() > 2) \r
-               titleName_ = parameters[2].substr(0, 4);        \r
-}\r
-\r
-void ImagestoreCommand::Execute()\r
-{\r
-       pCIIStrategy_->DisplayTemplate(titleName_);\r
-}\r
-\r
-\r
-//////////\r
-// MiscellaneousCommand\r
-void MiscellaneousCommand::Setup(const std::vector<std::wstring>& parameters)\r
-{\r
-       //HAWRYS:       V\5\3\1\1\namn.tga\1\r
-       //                      Display still\r
-       if((parameters.size() > 5) && parameters[1] == TEXT("5") && parameters[2] == TEXT("3"))\r
-       {\r
-               filename_ = parameters[5];\r
-               filename_ = filename_.substr(0, filename_.find_last_of(TEXT('.')));\r
-               filename_.append(L".ft");\r
-               state_ = 0;\r
-               return;\r
-       }\r
-       \r
-       //NEPTUNE:      V\5\13\1\X\Template\0\TabField1\TabField2...\r
-       //                      Add Template to layer X in the active templatehost\r
-       if((parameters.size() > 5) && parameters[1] == TEXT("5") && parameters[2] == TEXT("13"))\r
-       {\r
-               layer_ = _ttoi(parameters[4].c_str());\r
-               filename_ = parameters[5];\r
-               if(filename_.find(L"PK/") == std::wstring::npos && filename_.find(L"PK\\") == std::wstring::npos)\r
-                       filename_ = L"PK/" + filename_;\r
-\r
-               state_ = 1;\r
-               if(parameters.size() > 7) {\r
-                       std::wstringstream dataStream;\r
-\r
-                       dataStream << TEXT("<templateData>");\r
-                       std::vector<std::wstring>::size_type end = parameters.size();\r
-                       for(std::vector<std::wstring>::size_type i = 7; i < end; ++i) {\r
-                               dataStream << TEXT("<componentData id=\"f") << i-7 << TEXT("\"><data id=\"text\" value=\"") << parameters[i] << TEXT("\" /></componentData>"); \r
-                       }\r
-                       dataStream << TEXT("</templateData>");\r
-\r
-                       xmlData_ = dataStream.str();\r
-               }\r
-       }\r
-\r
-       // VIDEO MODE V\5\14\MODE\r
-       if((parameters.size() > 3) && parameters[1] == TEXT("5") && parameters[2] == TEXT("14"))\r
-       {\r
-               std::wstring value = parameters[3];\r
-               std::transform(value.begin(), value.end(), value.begin(), toupper);\r
-\r
-               this->pCIIStrategy_->GetChannel()->video_format_desc(core::video_format_desc(value));\r
-       }\r
-}\r
-\r
-void MiscellaneousCommand::Execute() \r
-{\r
-       if(state_ == 0)\r
-               pCIIStrategy_->DisplayMediaFile(filename_);     \r
-\r
-       //TODO: Need to be checked for validity\r
-       else if(state_ == 1)            \r
-       {\r
-               // HACK fix. The data sent is UTF8, however the protocol is implemented for ISO-8859-1. Instead of doing risky changes we simply convert into proper encoding when leaving protocol code.\r
-               auto xmlData2 = boost::locale::conv::utf_to_utf<wchar_t, char>(std::string(xmlData_.begin(), xmlData_.end()));\r
-               flash::create_cg_proxy(pCIIStrategy_->GetChannel()).add(layer_, filename_, false, TEXT(""), xmlData2);\r
-       }\r
-}\r
-\r
-\r
-/////////\r
-// KeydataCommand\r
-void KeydataCommand::Execute() \r
-{\r
-       if(state_ == 0) \r
-               pCIIStrategy_->DisplayTemplate(titleName_);\r
-       \r
-\r
-       //TODO: Need to be checked for validity\r
-       else if(state_ == 1)\r
-               flash::create_cg_proxy(pCIIStrategy_->GetChannel(), casparLayer_).stop(layer_, 0);\r
-       else if(state_ == 2)\r
-               pCIIStrategy_->GetChannel()->stage().clear();\r
-       else if(state_ == 3)\r
-               flash::create_cg_proxy(pCIIStrategy_->GetChannel(), casparLayer_).play(layer_);\r
-}\r
-\r
-void KeydataCommand::Setup(const std::vector<std::wstring>& parameters) {\r
-       //HAWRYS:       Y\<205><247><202><196><192><192><200><248>\r
-       //parameter[1] looks like this: "=g:XXXXh" where XXXX is the name that we want\r
-       if(parameters[1].size() > 6) \r
-       {\r
-               titleName_.resize(4);\r
-               for(int i=0;i<4;++i)\r
-               {\r
-                       if(parameters[1][i+3] < 176) {\r
-                               titleName_ = TEXT("");\r
-                               break;\r
-                       }\r
-                       titleName_[i] = parameters[1][i+3]-144;\r
-               }\r
-               state_ = 0;\r
-       }\r
-\r
-       casparLayer_ = flash::cg_proxy::DEFAULT_LAYER;\r
-       if(parameters.size() > 2)\r
-       {\r
-               //The layer parameter now supports casparlayers.\r
-               //the format is [CasparLayer]-[FlashLayer]\r
-               std::wstring str = boost::trim_copy(parameters[2]);\r
-               std::vector<std::wstring> split;\r
-               boost::split(split, str, boost::is_any_of("-"));\r
-               \r
-               try\r
-               {\r
-                       casparLayer_ = boost::lexical_cast<int>(split[0]);\r
-\r
-                       if(split.size() > 1)\r
-                               layer_ = boost::lexical_cast<int>(split[1]);\r
-               }\r
-               catch(...)\r
-               { \r
-                       casparLayer_ = flash::cg_proxy::DEFAULT_LAYER;\r
-                       layer_ = 0;\r
-               }\r
-       }\r
-\r
-\r
-       if(parameters[1].at(0) == 27)   //NEPTUNE:      Y\<27>\X                        Stop layer X.\r
-               state_ = 1;\r
-       else if(static_cast<unsigned char>(parameters[1].at(1)) == 190) //NEPTUNE:      Y\<254>                 Clear Canvas. \r
-               state_ = 2;\r
-       else if(static_cast<unsigned char>(parameters[1].at(1)) == 149) //NEPTUNE:      Y\<213><243>\X  Play layer X. \r
-               state_ = 3;                                                                                                     //UPDATE 2011-05-09: These char-codes are aparently not valid after converting to wide-chars\r
-                                                                                                                                       //the correct sequence is <195><149><195><179> \r
-               \r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#include "../StdAfx.h"
+
+#pragma warning (disable: 4244)
+
+#include "CIIProtocolStrategy.h"
+#include "CIICommandsImpl.h"
+#include <sstream>
+#include <algorithm>
+#include <modules/flash/producer/cg_proxy.h>
+#include <boost/locale.hpp>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace caspar { namespace protocol { namespace cii {
+
+////////
+// MediaCommand
+void MediaCommand::Setup(const std::vector<std::wstring>& parameters) 
+{
+       graphicProfile_ = parameters[1].substr(2);
+}
+
+void MediaCommand::Execute() 
+{
+       pCIIStrategy_->SetProfile(graphicProfile_);
+}
+
+
+////////
+// WriteCommand
+void WriteCommand::Setup(const std::vector<std::wstring>& parameters)
+{
+       try 
+       {
+               if(parameters.size() > 2)
+               {
+                       targetName_ = parameters[1];
+                       templateName_ = parameters[2];
+
+                       std::wstringstream dataStream;
+
+                       dataStream << TEXT("<templateData>");
+
+                       std::vector<std::wstring>::size_type end = parameters.size();
+                       for(std::vector<std::wstring>::size_type i = 3; i < end; ++i) 
+                               dataStream << TEXT("<componentData id=\"field") << i-2 << TEXT("\"><data id=\"text\" value=\"") << parameters[i] << TEXT("\" /></componentData>"); 
+
+                       dataStream << TEXT("</templateData>");
+                       xmlData_ = dataStream.str();
+               }
+       }
+       catch(std::exception) {
+       }
+}
+
+void WriteCommand::Execute() 
+{
+       pCIIStrategy_->WriteTemplateData(templateName_, targetName_, xmlData_);
+}
+
+
+//////////
+// ImagestoreCommand
+void ImagestoreCommand::Setup(const std::vector<std::wstring>& parameters) 
+{
+       if(parameters[1] == TEXT("7") && parameters.size() > 2) 
+               titleName_ = parameters[2].substr(0, 4);        
+}
+
+void ImagestoreCommand::Execute()
+{
+       pCIIStrategy_->DisplayTemplate(titleName_);
+}
+
+
+//////////
+// MiscellaneousCommand
+void MiscellaneousCommand::Setup(const std::vector<std::wstring>& parameters)
+{
+       //HAWRYS:       V\5\3\1\1\namn.tga\1
+       //                      Display still
+       if((parameters.size() > 5) && parameters[1] == TEXT("5") && parameters[2] == TEXT("3"))
+       {
+               filename_ = parameters[5];
+               filename_ = filename_.substr(0, filename_.find_last_of(TEXT('.')));
+               filename_.append(L".ft");
+               state_ = 0;
+               return;
+       }
+       
+       //NEPTUNE:      V\5\13\1\X\Template\0\TabField1\TabField2...
+       //                      Add Template to layer X in the active templatehost
+       if((parameters.size() > 5) && parameters[1] == TEXT("5") && parameters[2] == TEXT("13"))
+       {
+               layer_ = _ttoi(parameters[4].c_str());
+               filename_ = parameters[5];
+               if(filename_.find(L"PK/") == std::wstring::npos && filename_.find(L"PK\\") == std::wstring::npos)
+                       filename_ = L"PK/" + filename_;
+
+               state_ = 1;
+               if(parameters.size() > 7) {
+                       std::wstringstream dataStream;
+
+                       dataStream << TEXT("<templateData>");
+                       std::vector<std::wstring>::size_type end = parameters.size();
+                       for(std::vector<std::wstring>::size_type i = 7; i < end; ++i) {
+                               dataStream << TEXT("<componentData id=\"f") << i-7 << TEXT("\"><data id=\"text\" value=\"") << parameters[i] << TEXT("\" /></componentData>"); 
+                       }
+                       dataStream << TEXT("</templateData>");
+
+                       xmlData_ = dataStream.str();
+               }
+       }
+
+       // VIDEO MODE V\5\14\MODE
+       if((parameters.size() > 3) && parameters[1] == TEXT("5") && parameters[2] == TEXT("14"))
+       {
+               std::wstring value = parameters[3];
+               std::transform(value.begin(), value.end(), value.begin(), toupper);
+
+               this->pCIIStrategy_->GetChannel()->video_format_desc(core::video_format_desc(value));
+       }
+}
+
+void MiscellaneousCommand::Execute() 
+{
+       if(state_ == 0)
+               pCIIStrategy_->DisplayMediaFile(filename_);     
+
+       //TODO: Need to be checked for validity
+       else if(state_ == 1)            
+       {
+               // HACK fix. The data sent is UTF8, however the protocol is implemented for ISO-8859-1. Instead of doing risky changes we simply convert into proper encoding when leaving protocol code.
+               auto xmlData2 = boost::locale::conv::utf_to_utf<wchar_t, char>(std::string(xmlData_.begin(), xmlData_.end()));
+               flash::create_cg_proxy(pCIIStrategy_->GetChannel()).add(layer_, filename_, false, TEXT(""), xmlData2);
+       }
+}
+
+
+/////////
+// KeydataCommand
+void KeydataCommand::Execute() 
+{
+       if(state_ == 0) 
+               pCIIStrategy_->DisplayTemplate(titleName_);
+       
+
+       //TODO: Need to be checked for validity
+       else if(state_ == 1)
+               flash::create_cg_proxy(pCIIStrategy_->GetChannel(), casparLayer_).stop(layer_, 0);
+       else if(state_ == 2)
+               pCIIStrategy_->GetChannel()->stage().clear();
+       else if(state_ == 3)
+               flash::create_cg_proxy(pCIIStrategy_->GetChannel(), casparLayer_).play(layer_);
+}
+
+void KeydataCommand::Setup(const std::vector<std::wstring>& parameters) {
+       //HAWRYS:       Y\<205><247><202><196><192><192><200><248>
+       //parameter[1] looks like this: "=g:XXXXh" where XXXX is the name that we want
+       if(parameters[1].size() > 6) 
+       {
+               titleName_.resize(4);
+               for(int i=0;i<4;++i)
+               {
+                       if(parameters[1][i+3] < 176) {
+                               titleName_ = TEXT("");
+                               break;
+                       }
+                       titleName_[i] = parameters[1][i+3]-144;
+               }
+               state_ = 0;
+       }
+
+       casparLayer_ = flash::cg_proxy::DEFAULT_LAYER;
+       if(parameters.size() > 2)
+       {
+               //The layer parameter now supports casparlayers.
+               //the format is [CasparLayer]-[FlashLayer]
+               std::wstring str = boost::trim_copy(parameters[2]);
+               std::vector<std::wstring> split;
+               boost::split(split, str, boost::is_any_of("-"));
+               
+               try
+               {
+                       casparLayer_ = boost::lexical_cast<int>(split[0]);
+
+                       if(split.size() > 1)
+                               layer_ = boost::lexical_cast<int>(split[1]);
+               }
+               catch(...)
+               { 
+                       casparLayer_ = flash::cg_proxy::DEFAULT_LAYER;
+                       layer_ = 0;
+               }
+       }
+
+
+       if(parameters[1].at(0) == 27)   //NEPTUNE:      Y\<27>\X                        Stop layer X.
+               state_ = 1;
+       else if(static_cast<unsigned char>(parameters[1].at(1)) == 190) //NEPTUNE:      Y\<254>                 Clear Canvas. 
+               state_ = 2;
+       else if(static_cast<unsigned char>(parameters[1].at(1)) == 149) //NEPTUNE:      Y\<213><243>\X  Play layer X. 
+               state_ = 3;                                                                                                     //UPDATE 2011-05-09: These char-codes are aparently not valid after converting to wide-chars
+                                                                                                                                       //the correct sequence is <195><149><195><179> 
+               
+}
+
 }}}
\ No newline at end of file
index f1fd1e83a3127056ddae1352c71ece36c83d070e..6d51a08e95a983dff4792bf3d4de0f3604472eff 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#pragma once\r
-\r
-#include "ciicommand.h"\r
-\r
-namespace caspar { namespace protocol {\r
-\r
-namespace cii {\r
-\r
-class CIIProtocolStrategy;\r
-\r
-class MediaCommand : public ICIICommand\r
-{\r
-public:\r
-       MediaCommand(CIIProtocolStrategy* pPS) : pCIIStrategy_(pPS)\r
-       {}\r
-\r
-       virtual int GetMinimumParameters() {\r
-               return 1;\r
-       }\r
-\r
-       virtual void Setup(const std::vector<std::wstring>& parameters);\r
-       virtual void Execute();\r
-\r
-private:\r
-       std::wstring graphicProfile_;\r
-\r
-       CIIProtocolStrategy* pCIIStrategy_;\r
-};\r
-\r
-class WriteCommand : public ICIICommand\r
-{\r
-public:\r
-       WriteCommand(CIIProtocolStrategy* pPS) : pCIIStrategy_(pPS)\r
-       {}\r
-\r
-       virtual int GetMinimumParameters() {\r
-               return 2;\r
-       }\r
-\r
-       virtual void Setup(const std::vector<std::wstring>& parameters);\r
-       virtual void Execute();\r
-\r
-private:\r
-       std::wstring targetName_;\r
-       std::wstring templateName_;\r
-       std::wstring xmlData_;\r
-\r
-       CIIProtocolStrategy* pCIIStrategy_;\r
-};\r
-\r
-class MiscellaneousCommand : public ICIICommand\r
-{\r
-public:\r
-       MiscellaneousCommand(CIIProtocolStrategy* pPS) : pCIIStrategy_(pPS), state_(-1), layer_(0)\r
-       {}\r
-\r
-       virtual int GetMinimumParameters() {\r
-               return 5;\r
-       }\r
-\r
-       virtual void Setup(const std::vector<std::wstring>& parameters);\r
-       virtual void Execute();\r
-\r
-private:\r
-       std::wstring filename_;\r
-       std::wstring xmlData_;\r
-       int state_;\r
-       int layer_;\r
-\r
-       CIIProtocolStrategy* pCIIStrategy_;\r
-};\r
-\r
-class ImagestoreCommand : public ICIICommand\r
-{\r
-public:\r
-       ImagestoreCommand(CIIProtocolStrategy* pPS) : pCIIStrategy_(pPS)\r
-       {}\r
-\r
-       virtual int GetMinimumParameters() {\r
-               return 1;\r
-       }\r
-\r
-       virtual void Setup(const std::vector<std::wstring>& parameters);\r
-       virtual void Execute();\r
-\r
-private:\r
-       std::wstring titleName_;\r
-\r
-       CIIProtocolStrategy* pCIIStrategy_;\r
-};\r
-\r
-class KeydataCommand : public ICIICommand\r
-{\r
-public:\r
-       KeydataCommand(CIIProtocolStrategy* pPS) : pCIIStrategy_(pPS), state_(-1), layer_(0), casparLayer_(0)\r
-       {}\r
-\r
-       virtual int GetMinimumParameters() {\r
-               return 1;\r
-       }\r
-\r
-       virtual void Setup(const std::vector<std::wstring>& parameters);\r
-       virtual void Execute();\r
-\r
-private:\r
-       std::wstring titleName_;\r
-       int state_;\r
-       int layer_;\r
-       int casparLayer_;\r
-\r
-       CIIProtocolStrategy* pCIIStrategy_;\r
-};\r
-\r
-}      //namespace cii\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#pragma once
+
+#include "ciicommand.h"
+
+namespace caspar { namespace protocol {
+
+namespace cii {
+
+class CIIProtocolStrategy;
+
+class MediaCommand : public ICIICommand
+{
+public:
+       MediaCommand(CIIProtocolStrategy* pPS) : pCIIStrategy_(pPS)
+       {}
+
+       virtual int GetMinimumParameters() {
+               return 1;
+       }
+
+       virtual void Setup(const std::vector<std::wstring>& parameters);
+       virtual void Execute();
+
+private:
+       std::wstring graphicProfile_;
+
+       CIIProtocolStrategy* pCIIStrategy_;
+};
+
+class WriteCommand : public ICIICommand
+{
+public:
+       WriteCommand(CIIProtocolStrategy* pPS) : pCIIStrategy_(pPS)
+       {}
+
+       virtual int GetMinimumParameters() {
+               return 2;
+       }
+
+       virtual void Setup(const std::vector<std::wstring>& parameters);
+       virtual void Execute();
+
+private:
+       std::wstring targetName_;
+       std::wstring templateName_;
+       std::wstring xmlData_;
+
+       CIIProtocolStrategy* pCIIStrategy_;
+};
+
+class MiscellaneousCommand : public ICIICommand
+{
+public:
+       MiscellaneousCommand(CIIProtocolStrategy* pPS) : pCIIStrategy_(pPS), state_(-1), layer_(0)
+       {}
+
+       virtual int GetMinimumParameters() {
+               return 5;
+       }
+
+       virtual void Setup(const std::vector<std::wstring>& parameters);
+       virtual void Execute();
+
+private:
+       std::wstring filename_;
+       std::wstring xmlData_;
+       int state_;
+       int layer_;
+
+       CIIProtocolStrategy* pCIIStrategy_;
+};
+
+class ImagestoreCommand : public ICIICommand
+{
+public:
+       ImagestoreCommand(CIIProtocolStrategy* pPS) : pCIIStrategy_(pPS)
+       {}
+
+       virtual int GetMinimumParameters() {
+               return 1;
+       }
+
+       virtual void Setup(const std::vector<std::wstring>& parameters);
+       virtual void Execute();
+
+private:
+       std::wstring titleName_;
+
+       CIIProtocolStrategy* pCIIStrategy_;
+};
+
+class KeydataCommand : public ICIICommand
+{
+public:
+       KeydataCommand(CIIProtocolStrategy* pPS) : pCIIStrategy_(pPS), state_(-1), layer_(0), casparLayer_(0)
+       {}
+
+       virtual int GetMinimumParameters() {
+               return 1;
+       }
+
+       virtual void Setup(const std::vector<std::wstring>& parameters);
+       virtual void Execute();
+
+private:
+       std::wstring titleName_;
+       int state_;
+       int layer_;
+       int casparLayer_;
+
+       CIIProtocolStrategy* pCIIStrategy_;
+};
+
+}      //namespace cii
 }}     //namespace caspar
\ No newline at end of file
index 46c8d337e3a5e6ffec678beabc6bfe3c7e640f95..70ca31b98e96a97b365bc18fa838971f09191408 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#include "../StdAfx.h"\r
-\r
-#include <string>\r
-#include <sstream>\r
-#include <algorithm>\r
-#include "CIIProtocolStrategy.h"\r
-#include "CIICommandsimpl.h"\r
-#include <modules/flash/producer/flash_producer.h>\r
-#include <core/producer/transition/transition_producer.h>\r
-#include <core/mixer/mixer.h>\r
-#include <common/env.h>\r
-\r
-#include <boost/algorithm/string/replace.hpp>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push, 1) // TODO: Legacy code, just disable warnings\r
-#endif\r
-\r
-namespace caspar { namespace protocol { namespace cii {\r
-       \r
-using namespace core;\r
-\r
-const std::wstring CIIProtocolStrategy::MessageDelimiter = TEXT("\r\n");\r
-const TCHAR CIIProtocolStrategy::TokenDelimiter = TEXT('\\');\r
-\r
-CIIProtocolStrategy::CIIProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels) : pChannel_(channels.at(0)), executor_(L"CIIProtocolStrategy")\r
-{\r
-}\r
-\r
-void CIIProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo) \r
-{\r
-       std::size_t pos;\r
-       std::wstring msg(pData, charCount);\r
-       std::wstring availibleData = currentMessage_ + msg;\r
-\r
-       while(true)\r
-       {\r
-               pos = availibleData.find(MessageDelimiter);\r
-               if(pos != std::wstring::npos)\r
-               {\r
-                       std::wstring message = availibleData.substr(0,pos);\r
-\r
-                       if(message.length() > 0) {\r
-                               ProcessMessage(message, pClientInfo);\r
-                               if(pClientInfo != 0)\r
-                                       pClientInfo->Send(TEXT("*\r\n"));\r
-                       }\r
-\r
-                       std::size_t nextStartPos = pos + MessageDelimiter.length();\r
-                       if(nextStartPos < availibleData.length())\r
-                               availibleData = availibleData.substr(nextStartPos);\r
-                       else \r
-                       {\r
-                               availibleData.clear();\r
-                               break;\r
-                       }\r
-               }\r
-               else\r
-                       break;\r
-       }\r
-       currentMessage_ = availibleData;\r
-}\r
-\r
-void CIIProtocolStrategy::ProcessMessage(const std::wstring& message, IO::ClientInfoPtr pClientInfo)\r
-{      \r
-       CASPAR_LOG(info) << L"Received message from " << pClientInfo->print() << ": " << message << L"\\r\\n";\r
-\r
-       std::vector<std::wstring> tokens;\r
-       int tokenCount = TokenizeMessage(message, &tokens);\r
-\r
-       CIICommandPtr pCommand = Create(tokens[0]);\r
-       if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters()) \r
-       {\r
-               pCommand->Setup(tokens);\r
-               executor_.begin_invoke([=]{pCommand->Execute();});\r
-       }\r
-       else {} //report error  \r
-}\r
-\r
-int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)\r
-{\r
-       std::wstringstream currentToken;\r
-\r
-       for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex) \r
-       {\r
-               if(message[charIndex] == TokenDelimiter) \r
-               {\r
-                       pTokenVector->push_back(currentToken.str());\r
-                       currentToken.str(TEXT(""));\r
-                       continue;\r
-               }\r
-\r
-               if(message[charIndex] == TEXT('\"')) \r
-                       currentToken << TEXT("&quot;");         \r
-               else if(message[charIndex] == TEXT('<')) \r
-                       currentToken << TEXT("&lt;");           \r
-               else if(message[charIndex] == TEXT('>')) \r
-                       currentToken << TEXT("&gt;");           \r
-               else \r
-                       currentToken << message[charIndex];\r
-       }\r
-\r
-       if(currentToken.str().size() > 0)\r
-               pTokenVector->push_back(currentToken.str());    \r
-\r
-       return (int)pTokenVector->size();\r
-}\r
-\r
-/************\r
-// Examples (<X> = ASCIICHAR X)\r
-\r
-I\25\3\VII\\                                                                   sätter outputtype till 'vii'\r
-I\25\4\1\\                                                                             enablar framebuffer (ignore this)\r
-\r
-M\C/SVTNEWS\\                                                                  pekar ut vilken grafisk profil som skall användas\r
-\r
-W\4009\4067\Jonas Björkman\\                                   Skriver "Jonas Björkman" till första textfältet i template 4067 och sparar den färdiga skylten som 4009\r
-\r
-T\7\4009.VII\A\\                                                               lägger ut skylt 4009\r
-\r
-Y\<205><247><202><196><192><192><200><248>\\   lägger ut skylten 4008 (<205><247><202><196><192><192><200><248> = "=g:4008h" om man drar bort 144 frÃ¥n varje asciivärde)\r
-\r
-V\5\3\1\1\namn.tga\1\\                                                 lägger ut bilden namn.tga\r
-V\0\1\D\C\10\0\0\0\\                                                   gör nÃ¥gon inställning som har med föregÃ¥ende kommando att göra.\r
-\r
-*************/\r
-\r
-/**********************\r
-New Commands to support the Netupe automation system\r
-V\5\13\1\1\Template\0\TabField1\TabField2...\\         Build. Ettan före Template indikerar vilket lager den nya templaten skall laddas in i. OBS. Skall inte visas efter det här steget\r
-Y\<27>\\                                                                                       Stop. Här kommer ett lagerID ocksÃ¥ att skickas med (<27> = ESC)\r
-Y\<254>\\                                                                                      Clear Canvas. Här kommer ett lagerID ocksÃ¥ att skickas med, utan det skall allt tömmas\r
-Y\<213><243>\\                                                                         Play. Här kommer ett lagerID ocksÃ¥ att skickas med\r
-\r
-**********************/\r
-CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)\r
-{\r
-       switch(name[0])\r
-       {\r
-               case TEXT('M'): return std::make_shared<MediaCommand>(this);\r
-               case TEXT('W'): return std::make_shared<WriteCommand>(this);\r
-               case TEXT('T'): return std::make_shared<ImagestoreCommand>(this);\r
-               case TEXT('V'): return std::make_shared<MiscellaneousCommand>(this);\r
-               case TEXT('Y'): return std::make_shared<KeydataCommand>(this);\r
-               default:                return nullptr;\r
-       }\r
-}\r
-\r
-void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData) \r
-{\r
-       std::wstring fullTemplateFilename = env::template_folder();\r
-       if(currentProfile_.size() > 0)\r
-       {\r
-               fullTemplateFilename += currentProfile_;\r
-               fullTemplateFilename += TEXT("\\");\r
-       }\r
-       fullTemplateFilename += templateName;\r
-       fullTemplateFilename = flash::find_template(fullTemplateFilename);\r
-       if(fullTemplateFilename.empty())\r
-       {\r
-               CASPAR_LOG(error) << "Failed to save instance of " << templateName << TEXT(" as ") << titleName << TEXT(", template ") << fullTemplateFilename << " not found";\r
-               return;\r
-       }\r
-       \r
-       auto producer = flash::create_producer(this->GetChannel()->frame_factory(), this->GetChannel()->video_format_desc(), boost::assign::list_of(env::template_folder()+TEXT("CG.fth")));\r
-\r
-       std::wstringstream flashParam;\r
-       flashParam << TEXT("<invoke name=\"Add\" returntype=\"xml\"><arguments><number>1</number><string>") << currentProfile_ << '/' <<  templateName << TEXT("</string><number>0</number><true/><string> </string><string><![CDATA[ ") << xmlData << TEXT(" ]]></string></arguments></invoke>");\r
-       producer->call(flashParam.str());\r
-\r
-       CASPAR_LOG(info) << "Saved an instance of " << templateName << TEXT(" as ") << titleName ;\r
-\r
-       PutPreparedTemplate(titleName, spl::shared_ptr<core::frame_producer>(std::move(producer)));\r
-       \r
-}\r
-\r
-void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)\r
-{\r
-       try\r
-       {\r
-               pChannel_->stage().load(0, GetPreparedTemplate(titleName));\r
-               pChannel_->stage().play(0);\r
-\r
-               CASPAR_LOG(info) << L"Displayed title " << titleName ;\r
-       }\r
-       catch(caspar_exception&)\r
-       {\r
-               CASPAR_LOG(error) << L"Failed to display title " << titleName;\r
-       }\r
-}\r
-\r
-void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename) \r
-{\r
-       transition_info transition;\r
-       transition.type = transition_type::mix;\r
-       transition.duration = 12;\r
-\r
-       auto pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), filename);\r
-       auto pTransition = create_transition_producer(GetChannel()->video_format_desc().field_mode, pFP, transition);\r
-\r
-       try\r
-       {\r
-               pChannel_->stage().load(0, pTransition);\r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               CASPAR_LOG(error) << L"Failed to display " << filename ;\r
-               return;\r
-       }\r
-\r
-       pChannel_->stage().play(0);\r
-\r
-       CASPAR_LOG(info) << L"Displayed " << filename;\r
-}\r
-\r
-spl::shared_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)\r
-{\r
-       spl::shared_ptr<core::frame_producer> result(frame_producer::empty());\r
-\r
-       TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);\r
-       if(it != titles_.end()) {\r
-               CASPAR_LOG(debug) << L"Found title with name " << it->titleName;\r
-               result = (*it).pframe_producer;\r
-       }\r
-       else \r
-               CASPAR_LOG(error) << L"Could not find title with name " << titleName;\r
-\r
-       return result;\r
-}\r
-\r
-void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, spl::shared_ptr<core::frame_producer>& pFP)\r
-{\r
-       CASPAR_LOG(debug) << L"Saved title with name " << titleName;\r
-\r
-       TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);\r
-       if(it != titles_.end()) {\r
-               titles_.remove((*it));\r
-       }\r
-\r
-       titles_.push_front(TitleHolder(titleName, pFP));\r
-\r
-       if(titles_.size() >= 6)\r
-               titles_.resize(5);\r
-}\r
-\r
-bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs) \r
-{\r
-       return lhs.titleName == rhs;\r
-}\r
-\r
-bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)\r
-{\r
-       return lhs == rhs.titleName;\r
-}\r
-\r
-}}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#include "../StdAfx.h"
+
+#include <string>
+#include <sstream>
+#include <algorithm>
+#include "CIIProtocolStrategy.h"
+#include "CIICommandsimpl.h"
+#include <modules/flash/producer/flash_producer.h>
+#include <core/producer/transition/transition_producer.h>
+#include <core/mixer/mixer.h>
+#include <common/env.h>
+
+#include <boost/algorithm/string/replace.hpp>
+
+#if defined(_MSC_VER)
+#pragma warning (push, 1) // TODO: Legacy code, just disable warnings
+#endif
+
+namespace caspar { namespace protocol { namespace cii {
+       
+using namespace core;
+
+const std::wstring CIIProtocolStrategy::MessageDelimiter = TEXT("\r\n");
+const TCHAR CIIProtocolStrategy::TokenDelimiter = TEXT('\\');
+
+CIIProtocolStrategy::CIIProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels) : pChannel_(channels.at(0)), executor_(L"CIIProtocolStrategy")
+{
+}
+
+void CIIProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo) 
+{
+       std::size_t pos;
+       std::wstring msg(pData, charCount);
+       std::wstring availibleData = currentMessage_ + msg;
+
+       while(true)
+       {
+               pos = availibleData.find(MessageDelimiter);
+               if(pos != std::wstring::npos)
+               {
+                       std::wstring message = availibleData.substr(0,pos);
+
+                       if(message.length() > 0) {
+                               ProcessMessage(message, pClientInfo);
+                               if(pClientInfo != 0)
+                                       pClientInfo->Send(TEXT("*\r\n"));
+                       }
+
+                       std::size_t nextStartPos = pos + MessageDelimiter.length();
+                       if(nextStartPos < availibleData.length())
+                               availibleData = availibleData.substr(nextStartPos);
+                       else 
+                       {
+                               availibleData.clear();
+                               break;
+                       }
+               }
+               else
+                       break;
+       }
+       currentMessage_ = availibleData;
+}
+
+void CIIProtocolStrategy::ProcessMessage(const std::wstring& message, IO::ClientInfoPtr pClientInfo)
+{      
+       CASPAR_LOG(info) << L"Received message from " << pClientInfo->print() << ": " << message << L"\\r\\n";
+
+       std::vector<std::wstring> tokens;
+       int tokenCount = TokenizeMessage(message, &tokens);
+
+       CIICommandPtr pCommand = Create(tokens[0]);
+       if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters()) 
+       {
+               pCommand->Setup(tokens);
+               executor_.begin_invoke([=]{pCommand->Execute();});
+       }
+       else {} //report error  
+}
+
+int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)
+{
+       std::wstringstream currentToken;
+
+       for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex) 
+       {
+               if(message[charIndex] == TokenDelimiter) 
+               {
+                       pTokenVector->push_back(currentToken.str());
+                       currentToken.str(TEXT(""));
+                       continue;
+               }
+
+               if(message[charIndex] == TEXT('\"')) 
+                       currentToken << TEXT("&quot;");         
+               else if(message[charIndex] == TEXT('<')) 
+                       currentToken << TEXT("&lt;");           
+               else if(message[charIndex] == TEXT('>')) 
+                       currentToken << TEXT("&gt;");           
+               else 
+                       currentToken << message[charIndex];
+       }
+
+       if(currentToken.str().size() > 0)
+               pTokenVector->push_back(currentToken.str());    
+
+       return (int)pTokenVector->size();
+}
+
+/************
+// Examples (<X> = ASCIICHAR X)
+
+I\25\3\VII\\                                                                   sätter outputtype till 'vii'
+I\25\4\1\\                                                                             enablar framebuffer (ignore this)
+
+M\C/SVTNEWS\\                                                                  pekar ut vilken grafisk profil som skall användas
+
+W\4009\4067\Jonas Björkman\\                                   Skriver "Jonas Björkman" till första textfältet i template 4067 och sparar den färdiga skylten som 4009
+
+T\7\4009.VII\A\\                                                               lägger ut skylt 4009
+
+Y\<205><247><202><196><192><192><200><248>\\   lägger ut skylten 4008 (<205><247><202><196><192><192><200><248> = "=g:4008h" om man drar bort 144 frÃ¥n varje asciivärde)
+
+V\5\3\1\1\namn.tga\1\\                                                 lägger ut bilden namn.tga
+V\0\1\D\C\10\0\0\0\\                                                   gör nÃ¥gon inställning som har med föregÃ¥ende kommando att göra.
+
+*************/
+
+/**********************
+New Commands to support the Netupe automation system
+V\5\13\1\1\Template\0\TabField1\TabField2...\\         Build. Ettan före Template indikerar vilket lager den nya templaten skall laddas in i. OBS. Skall inte visas efter det här steget
+Y\<27>\\                                                                                       Stop. Här kommer ett lagerID ocksÃ¥ att skickas med (<27> = ESC)
+Y\<254>\\                                                                                      Clear Canvas. Här kommer ett lagerID ocksÃ¥ att skickas med, utan det skall allt tömmas
+Y\<213><243>\\                                                                         Play. Här kommer ett lagerID ocksÃ¥ att skickas med
+
+**********************/
+CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)
+{
+       switch(name[0])
+       {
+               case TEXT('M'): return std::make_shared<MediaCommand>(this);
+               case TEXT('W'): return std::make_shared<WriteCommand>(this);
+               case TEXT('T'): return std::make_shared<ImagestoreCommand>(this);
+               case TEXT('V'): return std::make_shared<MiscellaneousCommand>(this);
+               case TEXT('Y'): return std::make_shared<KeydataCommand>(this);
+               default:                return nullptr;
+       }
+}
+
+void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData) 
+{
+       std::wstring fullTemplateFilename = env::template_folder();
+       if(currentProfile_.size() > 0)
+       {
+               fullTemplateFilename += currentProfile_;
+               fullTemplateFilename += TEXT("\\");
+       }
+       fullTemplateFilename += templateName;
+       fullTemplateFilename = flash::find_template(fullTemplateFilename);
+       if(fullTemplateFilename.empty())
+       {
+               CASPAR_LOG(error) << "Failed to save instance of " << templateName << TEXT(" as ") << titleName << TEXT(", template ") << fullTemplateFilename << " not found";
+               return;
+       }
+       
+       auto producer = flash::create_producer(this->GetChannel()->frame_factory(), this->GetChannel()->video_format_desc(), boost::assign::list_of(env::template_folder()+TEXT("CG.fth")));
+
+       std::wstringstream flashParam;
+       flashParam << TEXT("<invoke name=\"Add\" returntype=\"xml\"><arguments><number>1</number><string>") << currentProfile_ << '/' <<  templateName << TEXT("</string><number>0</number><true/><string> </string><string><![CDATA[ ") << xmlData << TEXT(" ]]></string></arguments></invoke>");
+       producer->call(flashParam.str());
+
+       CASPAR_LOG(info) << "Saved an instance of " << templateName << TEXT(" as ") << titleName ;
+
+       PutPreparedTemplate(titleName, spl::shared_ptr<core::frame_producer>(std::move(producer)));
+       
+}
+
+void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)
+{
+       try
+       {
+               pChannel_->stage().load(0, GetPreparedTemplate(titleName));
+               pChannel_->stage().play(0);
+
+               CASPAR_LOG(info) << L"Displayed title " << titleName ;
+       }
+       catch(caspar_exception&)
+       {
+               CASPAR_LOG(error) << L"Failed to display title " << titleName;
+       }
+}
+
+void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename) 
+{
+       transition_info transition;
+       transition.type = transition_type::mix;
+       transition.duration = 12;
+
+       auto pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), filename);
+       auto pTransition = create_transition_producer(GetChannel()->video_format_desc().field_mode, pFP, transition);
+
+       try
+       {
+               pChannel_->stage().load(0, pTransition);
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               CASPAR_LOG(error) << L"Failed to display " << filename ;
+               return;
+       }
+
+       pChannel_->stage().play(0);
+
+       CASPAR_LOG(info) << L"Displayed " << filename;
+}
+
+spl::shared_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)
+{
+       spl::shared_ptr<core::frame_producer> result(frame_producer::empty());
+
+       TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
+       if(it != titles_.end()) {
+               CASPAR_LOG(debug) << L"Found title with name " << it->titleName;
+               result = (*it).pframe_producer;
+       }
+       else 
+               CASPAR_LOG(error) << L"Could not find title with name " << titleName;
+
+       return result;
+}
+
+void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, spl::shared_ptr<core::frame_producer>& pFP)
+{
+       CASPAR_LOG(debug) << L"Saved title with name " << titleName;
+
+       TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
+       if(it != titles_.end()) {
+               titles_.remove((*it));
+       }
+
+       titles_.push_front(TitleHolder(titleName, pFP));
+
+       if(titles_.size() >= 6)
+               titles_.resize(5);
+}
+
+bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs) 
+{
+       return lhs.titleName == rhs;
+}
+
+bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)
+{
+       return lhs == rhs.titleName;
+}
+
+}}}
index 77d9a419a16bfd39df57c949b9fe547a659552e2..032e2add86297e2804987f5d6f5323dfdb5f1829 100644 (file)
@@ -1,95 +1,95 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#pragma once\r
-\r
-#include <core/video_channel.h>\r
-\r
-#include "../util/ProtocolStrategy.h"\r
-#include "CIICommand.h"\r
-\r
-#include <core/producer/stage.h>\r
-\r
-#include <common/executor.h>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace protocol { namespace cii {\r
-\r
-class CIIProtocolStrategy : public IO::IProtocolStrategy\r
-{\r
-public:\r
-       CIIProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels);\r
-\r
-       void Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo);\r
-       std::string GetCodepage() {return "ISO-8859-1";}        //ISO 8859-1\r
-\r
-       void SetProfile(const std::wstring& profile) {currentProfile_ = profile;}\r
-\r
-       spl::shared_ptr<core::video_channel> GetChannel() const{return this->pChannel_;}\r
-\r
-       void DisplayMediaFile(const std::wstring& filename);\r
-       void DisplayTemplate(const std::wstring& titleName);\r
-       void WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData);\r
-\r
-public:\r
-       struct TitleHolder\r
-       {\r
-               TitleHolder() : titleName(TEXT("")), pframe_producer(core::frame_producer::empty())     {}\r
-               TitleHolder(const std::wstring& name, spl::shared_ptr<core::frame_producer> pFP) : titleName(name), pframe_producer(pFP) {}\r
-               TitleHolder(const TitleHolder& th) : titleName(th.titleName), pframe_producer(th.pframe_producer) {}\r
-               const TitleHolder& operator=(const TitleHolder& th) \r
-               {\r
-                       titleName = th.titleName;\r
-                       pframe_producer = th.pframe_producer;\r
-               }\r
-               bool operator==(const TitleHolder& rhs) \r
-               {\r
-                       return pframe_producer == rhs.pframe_producer;\r
-               }\r
-\r
-               std::wstring titleName;\r
-               spl::shared_ptr<core::frame_producer> pframe_producer;\r
-               friend CIIProtocolStrategy;\r
-       };\r
-private:\r
-\r
-       typedef std::list<TitleHolder> TitleList;\r
-       TitleList titles_;\r
-       spl::shared_ptr<core::frame_producer> GetPreparedTemplate(const std::wstring& name);\r
-       void PutPreparedTemplate(const std::wstring& name, spl::shared_ptr<core::frame_producer>& pframe_producer);\r
-\r
-       static const TCHAR TokenDelimiter;\r
-       static const std::wstring MessageDelimiter;\r
-\r
-       void ProcessMessage(const std::wstring& message, IO::ClientInfoPtr pClientInfo);\r
-       int TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector);\r
-       CIICommandPtr Create(const std::wstring& name);\r
-\r
-       executor executor_;\r
-       std::wstring currentMessage_;\r
-\r
-       std::wstring currentProfile_;\r
-       spl::shared_ptr<core::video_channel> pChannel_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#pragma once
+
+#include <core/video_channel.h>
+
+#include "../util/ProtocolStrategy.h"
+#include "CIICommand.h"
+
+#include <core/producer/stage.h>
+
+#include <common/executor.h>
+
+#include <string>
+
+namespace caspar { namespace protocol { namespace cii {
+
+class CIIProtocolStrategy : public IO::IProtocolStrategy
+{
+public:
+       CIIProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels);
+
+       void Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo);
+       std::string GetCodepage() {return "ISO-8859-1";}        //ISO 8859-1
+
+       void SetProfile(const std::wstring& profile) {currentProfile_ = profile;}
+
+       spl::shared_ptr<core::video_channel> GetChannel() const{return this->pChannel_;}
+
+       void DisplayMediaFile(const std::wstring& filename);
+       void DisplayTemplate(const std::wstring& titleName);
+       void WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData);
+
+public:
+       struct TitleHolder
+       {
+               TitleHolder() : titleName(TEXT("")), pframe_producer(core::frame_producer::empty())     {}
+               TitleHolder(const std::wstring& name, spl::shared_ptr<core::frame_producer> pFP) : titleName(name), pframe_producer(pFP) {}
+               TitleHolder(const TitleHolder& th) : titleName(th.titleName), pframe_producer(th.pframe_producer) {}
+               const TitleHolder& operator=(const TitleHolder& th) 
+               {
+                       titleName = th.titleName;
+                       pframe_producer = th.pframe_producer;
+               }
+               bool operator==(const TitleHolder& rhs) 
+               {
+                       return pframe_producer == rhs.pframe_producer;
+               }
+
+               std::wstring titleName;
+               spl::shared_ptr<core::frame_producer> pframe_producer;
+               friend CIIProtocolStrategy;
+       };
+private:
+
+       typedef std::list<TitleHolder> TitleList;
+       TitleList titles_;
+       spl::shared_ptr<core::frame_producer> GetPreparedTemplate(const std::wstring& name);
+       void PutPreparedTemplate(const std::wstring& name, spl::shared_ptr<core::frame_producer>& pframe_producer);
+
+       static const TCHAR TokenDelimiter;
+       static const std::wstring MessageDelimiter;
+
+       void ProcessMessage(const std::wstring& message, IO::ClientInfoPtr pClientInfo);
+       int TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector);
+       CIICommandPtr Create(const std::wstring& name);
+
+       executor executor_;
+       std::wstring currentMessage_;
+
+       std::wstring currentProfile_;
+       spl::shared_ptr<core::video_channel> pChannel_;
+};
+
 }}}
\ No newline at end of file
index b01d4d6720cefee03fd4e58d3d9b34e9cbe4df1e..23813d39bad59f84a5bac5cb2d59abad56f6f918 100644 (file)
@@ -1,96 +1,96 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#include "..\stdafx.h"\r
-#include <algorithm>\r
-#include <locale>\r
-#include "CLKCommand.h"\r
-\r
-namespace caspar { namespace protocol { namespace CLK {\r
-\r
-CLKCommand::CLKCommand() : clockID_(0), command_(CLKInvalidCommand) {}\r
-\r
-CLKCommand::~CLKCommand() {}\r
-\r
-const std::wstring& CLKCommand::GetData() \r
-{\r
-       std::wstringstream dataStream;\r
-\r
-       dataStream << TEXT("<templateData>");   \r
-       dataStream << TEXT("<componentData id=\"command\">");\r
-       dataStream << TEXT("<command id=\"") << commandString_ << TEXT("\" time=\"") << time_ << TEXT("\" clockID=\"") << clockID_ << TEXT("\">");\r
-\r
-       std::vector<std::wstring>::const_iterator it = parameters_.begin();\r
-       std::vector<std::wstring>::const_iterator end = parameters_.end();\r
-       for(; it != end; ++it) {\r
-               dataStream << TEXT("<parameter>") << (*it) << TEXT("</parameter>"); \r
-       }\r
-\r
-       dataStream << TEXT("</command>"); \r
-       dataStream << TEXT("</componentData>"); \r
-       dataStream << TEXT("</templateData>");\r
-\r
-       dataCache_ = dataStream.str();\r
-       return dataCache_;\r
-}\r
-\r
-bool CLKCommand::SetCommand() \r
-{\r
-       bool bResult = true;\r
-       std::transform(commandString_.begin(), commandString_.end(), commandString_.begin(), toupper);\r
-\r
-       if(commandString_ == TEXT("DUR"))\r
-               command_ = CLKDuration;\r
-       else if(commandString_ == TEXT("NEWDUR"))\r
-               command_ = CLKNewDuration;\r
-       else if(commandString_ == TEXT("NEXTEVENT"))\r
-               command_ = CLKNextEvent;\r
-       else if(commandString_ == TEXT("STOP"))\r
-               command_ = CLKStop;\r
-       else if(commandString_ == TEXT("UNTIL"))\r
-               command_ = CLKUntil;\r
-       else if(commandString_ == TEXT("ADD"))\r
-               command_ = CLKAdd;\r
-       else if(commandString_ == TEXT("SUB"))\r
-               command_ = CLKSub;\r
-       else if(commandString_ == TEXT("RESET"))\r
-               command_ = CLKReset;\r
-       else \r
-       {\r
-               command_ = CLKInvalidCommand;\r
-               bResult = false;\r
-       }\r
-\r
-       return bResult;\r
-}\r
-\r
-void CLKCommand::Clear() \r
-{\r
-       dataCache_.clear();\r
-       commandString_.clear();\r
-       time_.clear();\r
-       command_ = CLKDuration;\r
-       clockID_ = 0;\r
-       parameters_.clear();\r
-}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#include "..\stdafx.h"
+#include <algorithm>
+#include <locale>
+#include "CLKCommand.h"
+
+namespace caspar { namespace protocol { namespace CLK {
+
+CLKCommand::CLKCommand() : clockID_(0), command_(CLKInvalidCommand) {}
+
+CLKCommand::~CLKCommand() {}
+
+const std::wstring& CLKCommand::GetData() 
+{
+       std::wstringstream dataStream;
+
+       dataStream << TEXT("<templateData>");   
+       dataStream << TEXT("<componentData id=\"command\">");
+       dataStream << TEXT("<command id=\"") << commandString_ << TEXT("\" time=\"") << time_ << TEXT("\" clockID=\"") << clockID_ << TEXT("\">");
+
+       std::vector<std::wstring>::const_iterator it = parameters_.begin();
+       std::vector<std::wstring>::const_iterator end = parameters_.end();
+       for(; it != end; ++it) {
+               dataStream << TEXT("<parameter>") << (*it) << TEXT("</parameter>"); 
+       }
+
+       dataStream << TEXT("</command>"); 
+       dataStream << TEXT("</componentData>"); 
+       dataStream << TEXT("</templateData>");
+
+       dataCache_ = dataStream.str();
+       return dataCache_;
+}
+
+bool CLKCommand::SetCommand() 
+{
+       bool bResult = true;
+       std::transform(commandString_.begin(), commandString_.end(), commandString_.begin(), toupper);
+
+       if(commandString_ == TEXT("DUR"))
+               command_ = CLKDuration;
+       else if(commandString_ == TEXT("NEWDUR"))
+               command_ = CLKNewDuration;
+       else if(commandString_ == TEXT("NEXTEVENT"))
+               command_ = CLKNextEvent;
+       else if(commandString_ == TEXT("STOP"))
+               command_ = CLKStop;
+       else if(commandString_ == TEXT("UNTIL"))
+               command_ = CLKUntil;
+       else if(commandString_ == TEXT("ADD"))
+               command_ = CLKAdd;
+       else if(commandString_ == TEXT("SUB"))
+               command_ = CLKSub;
+       else if(commandString_ == TEXT("RESET"))
+               command_ = CLKReset;
+       else 
+       {
+               command_ = CLKInvalidCommand;
+               bResult = false;
+       }
+
+       return bResult;
+}
+
+void CLKCommand::Clear() 
+{
+       dataCache_.clear();
+       commandString_.clear();
+       time_.clear();
+       command_ = CLKDuration;
+       clockID_ = 0;
+       parameters_.clear();
+}
+
 }}}
\ No newline at end of file
index e0b95ef5a0fef686f019a27850784548eb6f2997..72e6c92d6bfcf7cbc94bc83a11977ba2eeeff51d 100644 (file)
@@ -1,63 +1,63 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#pragma once\r
-\r
-namespace caspar { namespace protocol { namespace CLK {\r
-\r
-class CLKCommand\r
-{\r
-public:\r
-       enum CLKCommands \r
-       {\r
-               CLKDuration,\r
-               CLKNewDuration,\r
-               CLKNextEvent,\r
-               CLKStop,\r
-               CLKUntil,\r
-               CLKAdd,\r
-               CLKSub,\r
-               CLKReset,\r
-               CLKInvalidCommand\r
-       };\r
-\r
-       CLKCommand();\r
-       virtual ~CLKCommand();\r
-\r
-       bool SetCommand();\r
-       bool NeedsTime() const \r
-       {\r
-               return !(command_ == CLKNextEvent || command_ == CLKStop);\r
-       }\r
-\r
-       void Clear();\r
-       const std::wstring& GetData();\r
-\r
-       std::wstring dataCache_;\r
-       std::wstring commandString_;\r
-       CLKCommands command_;\r
-       int clockID_;\r
-       std::wstring time_;\r
-       std::vector<std::wstring> parameters_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#pragma once
+
+namespace caspar { namespace protocol { namespace CLK {
+
+class CLKCommand
+{
+public:
+       enum CLKCommands 
+       {
+               CLKDuration,
+               CLKNewDuration,
+               CLKNextEvent,
+               CLKStop,
+               CLKUntil,
+               CLKAdd,
+               CLKSub,
+               CLKReset,
+               CLKInvalidCommand
+       };
+
+       CLKCommand();
+       virtual ~CLKCommand();
+
+       bool SetCommand();
+       bool NeedsTime() const 
+       {
+               return !(command_ == CLKNextEvent || command_ == CLKStop);
+       }
+
+       void Clear();
+       const std::wstring& GetData();
+
+       std::wstring dataCache_;
+       std::wstring commandString_;
+       CLKCommands command_;
+       int clockID_;
+       std::wstring time_;
+       std::vector<std::wstring> parameters_;
+};
+
 }}}
\ No newline at end of file
index 7f14171deedd48a324f3f4199fca5b9a4c492ae9..531b75932951f5c44fdf5b1fb17ab87460a4986a 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#include "..\stdafx.h"\r
-\r
-#include "CLKProtocolStrategy.h"\r
-\r
-#include <modules/flash/producer/cg_proxy.h>\r
-\r
-#include <string>\r
-#include <sstream>\r
-#include <algorithm>\r
-\r
-namespace caspar { namespace protocol { namespace CLK {\r
-       \r
-CLKProtocolStrategy::CLKProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels) \r
-       : currentState_(ExpectingNewCommand), bClockLoaded_(false), pChannel_(channels.at(0))\r
-{}\r
-\r
-void CLKProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo) \r
-{\r
-       for(int index = 0; index < charCount; ++index) \r
-       {\r
-               if(currentState_ == ExpectingNewCommand)\r
-                       currentCommandString_.str(TEXT(""));\r
-\r
-               TCHAR currentByte = pData[index];\r
-               if(currentByte < 32)\r
-                       currentCommandString_ << TEXT("<") << (int)currentByte << TEXT(">");\r
-               else\r
-                       currentCommandString_ << currentByte;\r
-\r
-               if(currentByte != 0)\r
-               {\r
-                       switch(currentState_)\r
-                       {\r
-                               case ExpectingNewCommand:\r
-                                       if(currentByte == 1) \r
-                                               currentState_ = ExpectingCommand;                                       \r
-                                       //just throw anything else away\r
-                                       break;\r
-\r
-                               case ExpectingCommand:\r
-                                       if(currentByte == 2) \r
-                                       {\r
-                                               if(!currentCommand_.SetCommand()) \r
-                                               {\r
-                                                       CASPAR_LOG(error) << "CLK: Failed to interpret command";\r
-                                                       currentState_ = ExpectingNewCommand;\r
-                                                       currentCommand_.Clear();\r
-                                               }\r
-                                               else \r
-                                                       currentState_ = ExpectingClockID;                                               \r
-                                       }\r
-                                       else\r
-                                               currentCommand_.commandString_ += currentByte;\r
-                                       break;\r
-\r
-                               case ExpectingClockID:\r
-                                       if(currentByte == 2)\r
-                                               currentState_ = currentCommand_.NeedsTime() ? ExpectingTime : ExpectingParameter;\r
-                                       else\r
-                                               currentCommand_.clockID_ = currentByte - TCHAR('0');\r
-                                       break;\r
-\r
-                               case ExpectingTime:\r
-                                       if(currentByte == 2)\r
-                                               currentState_ = ExpectingParameter;\r
-                                       else\r
-                                               currentCommand_.time_ += currentByte;\r
-                                       break;\r
-\r
-                               case ExpectingParameter:\r
-                                       //allocate new parameter\r
-                                       if(currentCommand_.parameters_.size() == 0 || currentByte == 2)\r
-                                               currentCommand_.parameters_.push_back(std::wstring());\r
-\r
-                                       //add the character to end end of the last parameter\r
-                                       if(currentByte == TEXT('<'))\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&lt;");\r
-                                       else if(currentByte == TEXT('>'))\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&gt;");\r
-                                       else if(currentByte == TEXT('\"'))\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&quot;");\r
-                                       else\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += currentByte;\r
-\r
-                                       break;\r
-                       }\r
-               }\r
-               else \r
-               {\r
-                       if(currentState_ == ExpectingCommand)\r
-                       {\r
-                               if(!currentCommand_.SetCommand())\r
-                                       CASPAR_LOG(error) << "CLK: Failed to interpret command";\r
-                       }\r
-\r
-                       if(currentCommand_.command_ == CLKCommand::CLKReset) \r
-                       {\r
-                               pChannel_->stage().clear(flash::cg_proxy::DEFAULT_LAYER);\r
-                               bClockLoaded_ = false;\r
-                               \r
-                               CASPAR_LOG(info) << L"CLK: Recieved and executed reset-command";\r
-                       }\r
-                       else if(currentCommand_.command_ != CLKCommand::CLKInvalidCommand)\r
-                       {\r
-                               if(!bClockLoaded_) \r
-                               {\r
-                                       flash::create_cg_proxy(pChannel_).add(0, TEXT("hawrysklocka/clock.ft"), true, TEXT(""), currentCommand_.GetData());\r
-                                       bClockLoaded_ = true;\r
-                               }\r
-                               else \r
-                                       flash::create_cg_proxy(pChannel_).update(0, currentCommand_.GetData());\r
-                               \r
-                               CASPAR_LOG(debug) << L"CLK: Clockdata sent: " << currentCommand_.GetData();\r
-                               CASPAR_LOG(debug) << L"CLK: Executed valid command: " << currentCommandString_.str();\r
-                       }\r
-\r
-                       currentState_ = ExpectingNewCommand;\r
-                       currentCommand_.Clear();\r
-               }\r
-       }\r
-}\r
-\r
-}      //namespace CLK\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#include "..\stdafx.h"
+
+#include "CLKProtocolStrategy.h"
+
+#include <modules/flash/producer/cg_proxy.h>
+
+#include <string>
+#include <sstream>
+#include <algorithm>
+
+namespace caspar { namespace protocol { namespace CLK {
+       
+CLKProtocolStrategy::CLKProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels) 
+       : currentState_(ExpectingNewCommand), bClockLoaded_(false), pChannel_(channels.at(0))
+{}
+
+void CLKProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo) 
+{
+       for(int index = 0; index < charCount; ++index) 
+       {
+               if(currentState_ == ExpectingNewCommand)
+                       currentCommandString_.str(TEXT(""));
+
+               TCHAR currentByte = pData[index];
+               if(currentByte < 32)
+                       currentCommandString_ << TEXT("<") << (int)currentByte << TEXT(">");
+               else
+                       currentCommandString_ << currentByte;
+
+               if(currentByte != 0)
+               {
+                       switch(currentState_)
+                       {
+                               case ExpectingNewCommand:
+                                       if(currentByte == 1) 
+                                               currentState_ = ExpectingCommand;                                       
+                                       //just throw anything else away
+                                       break;
+
+                               case ExpectingCommand:
+                                       if(currentByte == 2) 
+                                       {
+                                               if(!currentCommand_.SetCommand()) 
+                                               {
+                                                       CASPAR_LOG(error) << "CLK: Failed to interpret command";
+                                                       currentState_ = ExpectingNewCommand;
+                                                       currentCommand_.Clear();
+                                               }
+                                               else 
+                                                       currentState_ = ExpectingClockID;                                               
+                                       }
+                                       else
+                                               currentCommand_.commandString_ += currentByte;
+                                       break;
+
+                               case ExpectingClockID:
+                                       if(currentByte == 2)
+                                               currentState_ = currentCommand_.NeedsTime() ? ExpectingTime : ExpectingParameter;
+                                       else
+                                               currentCommand_.clockID_ = currentByte - TCHAR('0');
+                                       break;
+
+                               case ExpectingTime:
+                                       if(currentByte == 2)
+                                               currentState_ = ExpectingParameter;
+                                       else
+                                               currentCommand_.time_ += currentByte;
+                                       break;
+
+                               case ExpectingParameter:
+                                       //allocate new parameter
+                                       if(currentCommand_.parameters_.size() == 0 || currentByte == 2)
+                                               currentCommand_.parameters_.push_back(std::wstring());
+
+                                       //add the character to end end of the last parameter
+                                       if(currentByte == TEXT('<'))
+                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&lt;");
+                                       else if(currentByte == TEXT('>'))
+                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&gt;");
+                                       else if(currentByte == TEXT('\"'))
+                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&quot;");
+                                       else
+                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += currentByte;
+
+                                       break;
+                       }
+               }
+               else 
+               {
+                       if(currentState_ == ExpectingCommand)
+                       {
+                               if(!currentCommand_.SetCommand())
+                                       CASPAR_LOG(error) << "CLK: Failed to interpret command";
+                       }
+
+                       if(currentCommand_.command_ == CLKCommand::CLKReset) 
+                       {
+                               pChannel_->stage().clear(flash::cg_proxy::DEFAULT_LAYER);
+                               bClockLoaded_ = false;
+                               
+                               CASPAR_LOG(info) << L"CLK: Recieved and executed reset-command";
+                       }
+                       else if(currentCommand_.command_ != CLKCommand::CLKInvalidCommand)
+                       {
+                               if(!bClockLoaded_) 
+                               {
+                                       flash::create_cg_proxy(pChannel_).add(0, TEXT("hawrysklocka/clock.ft"), true, TEXT(""), currentCommand_.GetData());
+                                       bClockLoaded_ = true;
+                               }
+                               else 
+                                       flash::create_cg_proxy(pChannel_).update(0, currentCommand_.GetData());
+                               
+                               CASPAR_LOG(debug) << L"CLK: Clockdata sent: " << currentCommand_.GetData();
+                               CASPAR_LOG(debug) << L"CLK: Executed valid command: " << currentCommandString_.str();
+                       }
+
+                       currentState_ = ExpectingNewCommand;
+                       currentCommand_.Clear();
+               }
+       }
+}
+
+}      //namespace CLK
 }}     //namespace caspar
\ No newline at end of file
index a9cac13c0823ed25c731eccd7b70da515a23ae6e..b813b540ec92a04e4790c064d0d2b0d068d3ef6a 100644 (file)
@@ -1,60 +1,60 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
\r
-#pragma once\r
-\r
-#include "CLKCommand.h"\r
-#include "../util/ProtocolStrategy.h"\r
-#include <core/video_channel.h>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace protocol { namespace CLK {\r
-\r
-class CLKProtocolStrategy : public IO::IProtocolStrategy\r
-{\r
-public:\r
-       CLKProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels);\r
-\r
-       void Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo);\r
-       std::string GetCodepage() { return "ISO-8859-1"; }      //ISO 8859-1\r
-       \r
-private:\r
-       enum ParserState\r
-       {\r
-               ExpectingNewCommand,\r
-               ExpectingCommand,\r
-               ExpectingClockID,\r
-               ExpectingTime,\r
-               ExpectingParameter\r
-       };\r
-\r
-       ParserState     currentState_;\r
-       CLKCommand currentCommand_;\r
-       std::wstringstream currentCommandString_;\r
-\r
-       spl::shared_ptr<core::video_channel> pChannel_;\r
-\r
-       bool bClockLoaded_;\r
-};\r
-\r
-}}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#pragma once
+
+#include "CLKCommand.h"
+#include "../util/ProtocolStrategy.h"
+#include <core/video_channel.h>
+
+#include <string>
+
+namespace caspar { namespace protocol { namespace CLK {
+
+class CLKProtocolStrategy : public IO::IProtocolStrategy
+{
+public:
+       CLKProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels);
+
+       void Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo);
+       std::string GetCodepage() { return "ISO-8859-1"; }      //ISO 8859-1
+       
+private:
+       enum ParserState
+       {
+               ExpectingNewCommand,
+               ExpectingCommand,
+               ExpectingClockID,
+               ExpectingTime,
+               ExpectingParameter
+       };
+
+       ParserState     currentState_;
+       CLKCommand currentCommand_;
+       std::wstringstream currentCommandString_;
+
+       spl::shared_ptr<core::video_channel> pChannel_;
+
+       bool bClockLoaded_;
+};
+
+}}}
index 017bf05b170382abd79de02583be6e4177b95143..ade00e5b7aefc4cb06993193f180ef67db6b9692 100644 (file)
@@ -1,73 +1,73 @@
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H\r
-#define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H\r
-\r
-#include <string.h>\r
-#include <map>\r
-\r
-#include "OscPacketListener.h"\r
-\r
-\r
-\r
-namespace osc{\r
-\r
-template< class T >\r
-class MessageMappingOscPacketListener : public OscPacketListener{\r
-public:\r
-    typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&);\r
-\r
-protected:\r
-    void RegisterMessageFunction( const char *addressPattern, function_type f )\r
-    {\r
-        functions_.insert( std::make_pair( addressPattern, f ) );\r
-    }\r
-\r
-    virtual void ProcessMessage( const osc::ReceivedMessage& m,\r
-               const IpEndpointName& remoteEndpoint )\r
-    {\r
-        typename function_map_type::iterator i = functions_.find( m.AddressPattern() );\r
-        if( i != functions_.end() )\r
-            (dynamic_cast<T*>(this)->*(i->second))( m, remoteEndpoint );\r
-    }\r
-    \r
-private:\r
-    struct cstr_compare{\r
-        bool operator()( const char *lhs, const char *rhs ) const\r
-            { return strcmp( lhs, rhs ) < 0; }\r
-    };\r
-\r
-    typedef std::map<const char*, function_type, cstr_compare> function_map_type;\r
-    function_map_type functions_;\r
-};\r
-\r
-} // namespace osc\r
-\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
+#define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
+
+#include <string.h>
+#include <map>
+
+#include "OscPacketListener.h"
+
+
+
+namespace osc{
+
+template< class T >
+class MessageMappingOscPacketListener : public OscPacketListener{
+public:
+    typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&);
+
+protected:
+    void RegisterMessageFunction( const char *addressPattern, function_type f )
+    {
+        functions_.insert( std::make_pair( addressPattern, f ) );
+    }
+
+    virtual void ProcessMessage( const osc::ReceivedMessage& m,
+               const IpEndpointName& remoteEndpoint )
+    {
+        typename function_map_type::iterator i = functions_.find( m.AddressPattern() );
+        if( i != functions_.end() )
+            (dynamic_cast<T*>(this)->*(i->second))( m, remoteEndpoint );
+    }
+    
+private:
+    struct cstr_compare{
+        bool operator()( const char *lhs, const char *rhs ) const
+            { return strcmp( lhs, rhs ) < 0; }
+    };
+
+    typedef std::map<const char*, function_type, cstr_compare> function_map_type;
+    function_map_type functions_;
+};
+
+} // namespace osc
+
 #endif /* INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H */
\ No newline at end of file
index cd8d567a091311ccf22f74cf0eed4efd37f9fa9b..8a2d35e318880dbf03ab600f2d741a1a64614161 100644 (file)
@@ -1,54 +1,54 @@
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#ifndef INCLUDED_OSC_EXCEPTION_H\r
-#define INCLUDED_OSC_EXCEPTION_H\r
-\r
-#include <exception>\r
-\r
-namespace osc{\r
-\r
-class Exception : public std::exception {\r
-    const char *what_;\r
-    \r
-public:\r
-    Exception() throw() {}\r
-    Exception( const Exception& src ) throw()\r
-        : what_( src.what_ ) {}\r
-    Exception( const char *w ) throw()\r
-        : what_( w ) {}\r
-    Exception& operator=( const Exception& src ) throw()\r
-        { what_ = src.what_; return *this; }\r
-    virtual ~Exception() throw() {}\r
-    virtual const char* what() const throw() { return what_; }\r
-};\r
-\r
-} // namespace osc\r
-\r
-#endif /* INCLUDED_OSC_EXCEPTION_H */\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSC_EXCEPTION_H
+#define INCLUDED_OSC_EXCEPTION_H
+
+#include <exception>
+
+namespace osc{
+
+class Exception : public std::exception {
+    const char *what_;
+    
+public:
+    Exception() throw() {}
+    Exception( const Exception& src ) throw()
+        : what_( src.what_ ) {}
+    Exception( const char *w ) throw()
+        : what_( w ) {}
+    Exception& operator=( const Exception& src ) throw()
+        { what_ = src.what_; return *this; }
+    virtual ~Exception() throw() {}
+    virtual const char* what() const throw() { return what_; }
+};
+
+} // namespace osc
+
+#endif /* INCLUDED_OSC_EXCEPTION_H */
index d1a248d88cecd15ef627ded3a7f2294506ad6cb6..1ff7bf5899480cbcac571df36a6f61d7fd976b77 100644 (file)
@@ -1,76 +1,76 @@
-/*\r
-        oscpack -- Open Sound Control packet manipulation library\r
-        http://www.audiomulch.com/~rossb/oscpack\r
-\r
-        Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-        Permission is hereby granted, free of charge, to any person obtaining\r
-        a copy of this software and associated documentation files\r
-        (the "Software"), to deal in the Software without restriction,\r
-        including without limitation the rights to use, copy, modify, merge,\r
-        publish, distribute, sublicense, and/or sell copies of the Software,\r
-        and to permit persons to whom the Software is furnished to do so,\r
-        subject to the following conditions:\r
-\r
-        The above copyright notice and this permission notice shall be\r
-        included in all copies or substantial portions of the Software.\r
-\r
-        Any person wishing to distribute modifications to the Software is\r
-        requested to send the modifications to the original developer so that\r
-        they can be incorporated into the canonical version.\r
-\r
-        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-        EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-        MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-        IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-        ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-        CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-        WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#ifndef OSC_HOSTENDIANNESS_H\r
-#define OSC_HOSTENDIANNESS_H\r
-\r
-//#define OSC_HOST_BIG_ENDIAN 1\r
-\r
-//*\r
-//    Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined\r
-//\r
-//    If you know a way to enhance the detection below for Linux and/or MacOSX\r
-//    please let me know! I've tried a few things which don't work.\r
-//*/\r
-//\r
-//#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN)\r
-//\r
-// you can define one of the above symbols from the command line\r
-// then you don't have to edit this file.\r
-//\r
-//#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE)\r
-//\r
-// assume that __WIN32__ is only defined on little endian systems\r
-//\r
-//#define OSC_HOST_LITTLE_ENDIAN 1\r
-//#undef OSC_HOST_BIG_ENDIAN\r
-//\r
-//#elif defined(__APPLE__)\r
-//\r
-//#if defined(__LITTLE_ENDIAN__)\r
-//\r
-//#define OSC_HOST_LITTLE_ENDIAN 1\r
-//#undef OSC_HOST_BIG_ENDIAN\r
-//\r
-//#elif defined(__BIG_ENDIAN__)\r
-//\r
-//#define OSC_HOST_BIG_ENDIAN 1\r
-//#undef OSC_HOST_LITTLE_ENDIAN\r
-//\r
-//#endif\r
-//\r
-//#endif\r
-//\r
-//#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN)\r
-//\r
-//#error please edit OSCHostEndianness.h to configure endianness\r
-//\r
-//#endif\r
-\r
-#endif /* OSC_HOSTENDIANNESS_H */\r
+/*
+        oscpack -- Open Sound Control packet manipulation library
+        http://www.audiomulch.com/~rossb/oscpack
+
+        Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+        Permission is hereby granted, free of charge, to any person obtaining
+        a copy of this software and associated documentation files
+        (the "Software"), to deal in the Software without restriction,
+        including without limitation the rights to use, copy, modify, merge,
+        publish, distribute, sublicense, and/or sell copies of the Software,
+        and to permit persons to whom the Software is furnished to do so,
+        subject to the following conditions:
+
+        The above copyright notice and this permission notice shall be
+        included in all copies or substantial portions of the Software.
+
+        Any person wishing to distribute modifications to the Software is
+        requested to send the modifications to the original developer so that
+        they can be incorporated into the canonical version.
+
+        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+        EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+        MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+        IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+        ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+        CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+        WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef OSC_HOSTENDIANNESS_H
+#define OSC_HOSTENDIANNESS_H
+
+//#define OSC_HOST_BIG_ENDIAN 1
+
+//*
+//    Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined
+//
+//    If you know a way to enhance the detection below for Linux and/or MacOSX
+//    please let me know! I've tried a few things which don't work.
+//*/
+//
+//#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN)
+//
+// you can define one of the above symbols from the command line
+// then you don't have to edit this file.
+//
+//#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE)
+//
+// assume that __WIN32__ is only defined on little endian systems
+//
+//#define OSC_HOST_LITTLE_ENDIAN 1
+//#undef OSC_HOST_BIG_ENDIAN
+//
+//#elif defined(__APPLE__)
+//
+//#if defined(__LITTLE_ENDIAN__)
+//
+//#define OSC_HOST_LITTLE_ENDIAN 1
+//#undef OSC_HOST_BIG_ENDIAN
+//
+//#elif defined(__BIG_ENDIAN__)
+//
+//#define OSC_HOST_BIG_ENDIAN 1
+//#undef OSC_HOST_LITTLE_ENDIAN
+//
+//#endif
+//
+//#endif
+//
+//#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN)
+//
+//#error please edit OSCHostEndianness.h to configure endianness
+//
+//#endif
+
+#endif /* OSC_HOSTENDIANNESS_H */
index 92cc3f3188fad02a5cd0974bcfe7088e86252a0f..20bc386dda010d11a135b4a35286229e3c7a3bc9 100644 (file)
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#undef _CRT_SECURE_NO_WARNINGS\r
-#define _CRT_SECURE_NO_WARNINGS\r
-\r
-#include "OscOutboundPacketStream.h"\r
-\r
-#include <string.h>\r
-#include <stdlib.h>\r
-#include <assert.h>\r
-\r
-#if defined(__WIN32__) || defined(WIN32)\r
-#include <malloc.h> // for alloca\r
-#endif\r
-\r
-#include "OscHostEndianness.h"\r
-\r
-\r
-namespace osc{\r
-\r
-static void FromInt32( char *p, int32 x )\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        osc::int32 i;\r
-        char c[4];\r
-    } u;\r
-\r
-    u.i = x;\r
-\r
-    p[3] = u.c[0];\r
-    p[2] = u.c[1];\r
-    p[1] = u.c[2];\r
-    p[0] = u.c[3];\r
-#else\r
-    *reinterpret_cast<int32*>(p) = x;\r
-#endif\r
-}\r
-\r
-\r
-static void FromUInt32( char *p, uint32 x )\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        osc::uint32 i;\r
-        char c[4];\r
-    } u;\r
-\r
-    u.i = x;\r
-\r
-    p[3] = u.c[0];\r
-    p[2] = u.c[1];\r
-    p[1] = u.c[2];\r
-    p[0] = u.c[3];\r
-#else\r
-    *reinterpret_cast<uint32*>(p) = x;\r
-#endif\r
-}\r
-\r
-\r
-static void FromInt64( char *p, int64 x )\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        osc::int64 i;\r
-        char c[8];\r
-    } u;\r
-\r
-    u.i = x;\r
-\r
-    p[7] = u.c[0];\r
-    p[6] = u.c[1];\r
-    p[5] = u.c[2];\r
-    p[4] = u.c[3];\r
-    p[3] = u.c[4];\r
-    p[2] = u.c[5];\r
-    p[1] = u.c[6];\r
-    p[0] = u.c[7];\r
-#else\r
-    *reinterpret_cast<int64*>(p) = x;\r
-#endif\r
-}\r
-\r
-\r
-static void FromUInt64( char *p, uint64 x )\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        osc::uint64 i;\r
-        char c[8];\r
-    } u;\r
-\r
-    u.i = x;\r
-\r
-    p[7] = u.c[0];\r
-    p[6] = u.c[1];\r
-    p[5] = u.c[2];\r
-    p[4] = u.c[3];\r
-    p[3] = u.c[4];\r
-    p[2] = u.c[5];\r
-    p[1] = u.c[6];\r
-    p[0] = u.c[7];\r
-#else\r
-    *reinterpret_cast<uint64*>(p) = x;\r
-#endif\r
-}\r
-\r
-\r
-static inline long RoundUp4( long x )\r
-{\r
-    return ((x-1) & (~0x03L)) + 4;\r
-}\r
-\r
-\r
-OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity )\r
-    : data_( buffer )\r
-    , end_( data_ + capacity )\r
-    , typeTagsCurrent_( end_ )\r
-    , messageCursor_( data_ )\r
-    , argumentCurrent_( data_ )\r
-    , elementSizePtr_( 0 )\r
-    , messageIsInProgress_( false )\r
-{\r
-\r
-}\r
-\r
-\r
-OutboundPacketStream::~OutboundPacketStream()\r
-{\r
-\r
-}\r
-\r
-\r
-char *OutboundPacketStream::BeginElement( char *beginPtr )\r
-{\r
-    if( elementSizePtr_ == 0 ){\r
-\r
-        elementSizePtr_ = reinterpret_cast<uint32*>(data_);\r
-\r
-        return beginPtr;\r
-\r
-    }else{\r
-        // store an offset to the old element size ptr in the element size slot\r
-        // we store an offset rather than the actual pointer to be 64 bit clean.\r
-        *reinterpret_cast<uint32*>(beginPtr) =\r
-                (uint32)(reinterpret_cast<char*>(elementSizePtr_) - data_);\r
-\r
-        elementSizePtr_ = reinterpret_cast<uint32*>(beginPtr);\r
-\r
-        return beginPtr + 4;\r
-    }\r
-}\r
-\r
-\r
-void OutboundPacketStream::EndElement( char *endPtr )\r
-{\r
-    assert( elementSizePtr_ != 0 );\r
-\r
-    if( elementSizePtr_ == reinterpret_cast<uint32*>(data_) ){\r
-\r
-        elementSizePtr_ = 0;\r
-\r
-    }else{\r
-        // while building an element, an offset to the containing element's\r
-        // size slot is stored in the elements size slot (or a ptr to data_\r
-        // if there is no containing element). We retrieve that here\r
-        uint32 *previousElementSizePtr =\r
-                (uint32*)(data_ + *reinterpret_cast<uint32*>(elementSizePtr_));\r
-\r
-        // then we store the element size in the slot, note that the element\r
-        // size does not include the size slot, hence the - 4 below.\r
-        uint32 elementSize =\r
-                static_cast<uint32>(endPtr - reinterpret_cast<char*>(elementSizePtr_)) - 4;\r
-        FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );\r
-\r
-        // finally, we reset the element size ptr to the containing element\r
-        elementSizePtr_ = previousElementSizePtr;\r
-    }\r
-}\r
-\r
-\r
-bool OutboundPacketStream::ElementSizeSlotRequired() const\r
-{\r
-    return (elementSizePtr_ != 0);\r
-}\r
-\r
-\r
-void OutboundPacketStream::CheckForAvailableBundleSpace()\r
-{\r
-    unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;\r
-\r
-    if( required > Capacity() )\r
-        throw OutOfBufferMemoryException();\r
-}\r
-\r
-\r
-void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern )\r
-{\r
-    // plus 4 for at least four bytes of type tag\r
-     unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0)\r
-            + RoundUp4(static_cast<unsigned long>(strlen(addressPattern)) + 1) + 4;\r
-\r
-    if( required > Capacity() )\r
-        throw OutOfBufferMemoryException();\r
-}\r
-\r
-\r
-void OutboundPacketStream::CheckForAvailableArgumentSpace( long argumentLength )\r
-{\r
-    // plus three for extra type tag, comma and null terminator\r
-     unsigned long required = static_cast<unsigned long>(argumentCurrent_ - data_) + argumentLength\r
-            + RoundUp4( static_cast<unsigned long>(end_ - typeTagsCurrent_) + 3 );\r
-\r
-    if( required > Capacity() )\r
-        throw OutOfBufferMemoryException();\r
-}\r
-\r
-\r
-void OutboundPacketStream::Clear()\r
-{\r
-    typeTagsCurrent_ = end_;\r
-    messageCursor_ = data_;\r
-    argumentCurrent_ = data_;\r
-    elementSizePtr_ = 0;\r
-    messageIsInProgress_ = false;\r
-}\r
-\r
-\r
-unsigned int OutboundPacketStream::Capacity() const\r
-{\r
-    return static_cast<int>(end_ - data_);\r
-}\r
-\r
-\r
-unsigned int OutboundPacketStream::Size() const\r
-{\r
-    unsigned int result = static_cast<unsigned long>(argumentCurrent_ - data_);\r
-    if( IsMessageInProgress() ){\r
-        // account for the length of the type tag string. the total type tag\r
-        // includes an initial comma, plus at least one terminating \0\r
-        result += RoundUp4( static_cast<unsigned long>(end_ - typeTagsCurrent_) + 2 );\r
-    }\r
-\r
-    return result;\r
-}\r
-\r
-\r
-const char *OutboundPacketStream::Data() const\r
-{\r
-    return data_;\r
-}\r
-\r
-\r
-bool OutboundPacketStream::IsReady() const\r
-{\r
-    return (!IsMessageInProgress() && !IsBundleInProgress());\r
-}\r
-\r
-\r
-bool OutboundPacketStream::IsMessageInProgress() const\r
-{\r
-    return messageIsInProgress_;\r
-}\r
-\r
-\r
-bool OutboundPacketStream::IsBundleInProgress() const\r
-{\r
-    return (elementSizePtr_ != 0);\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs )\r
-{\r
-    if( IsMessageInProgress() )\r
-        throw MessageInProgressException();\r
-\r
-    CheckForAvailableBundleSpace();\r
-\r
-    messageCursor_ = BeginElement( messageCursor_ );\r
-\r
-    memcpy( messageCursor_, "#bundle\0", 8 );\r
-    FromUInt64( messageCursor_ + 8, rhs.timeTag );\r
-\r
-    messageCursor_ += 16;\r
-    argumentCurrent_ = messageCursor_;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs )\r
-{\r
-    (void) rhs;\r
-\r
-    if( !IsBundleInProgress() )\r
-        throw BundleNotInProgressException();\r
-    if( IsMessageInProgress() )\r
-        throw MessageInProgressException();\r
-\r
-    EndElement( messageCursor_ );\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs )\r
-{\r
-    if( IsMessageInProgress() )\r
-        throw MessageInProgressException();\r
-\r
-    CheckForAvailableMessageSpace( rhs.addressPattern );\r
-\r
-    messageCursor_ = BeginElement( messageCursor_ );\r
-\r
-    strcpy( messageCursor_, rhs.addressPattern );\r
-    unsigned long rhsLength = static_cast<unsigned long>(strlen(rhs.addressPattern));\r
-    messageCursor_ += rhsLength + 1;\r
-\r
-    // zero pad to 4-byte boundary\r
-    unsigned long i = rhsLength + 1;\r
-    while( i & 0x3 ){\r
-        *messageCursor_++ = '\0';\r
-        ++i;\r
-    }\r
-\r
-    argumentCurrent_ = messageCursor_;\r
-    typeTagsCurrent_ = end_;\r
-\r
-    messageIsInProgress_ = true;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs )\r
-{\r
-    (void) rhs;\r
-\r
-    if( !IsMessageInProgress() )\r
-        throw MessageNotInProgressException();\r
-\r
-    int typeTagsCount = static_cast<int>(end_ - typeTagsCurrent_);\r
-\r
-    if( typeTagsCount ){\r
-\r
-        char *tempTypeTags = (char*)alloca(typeTagsCount);\r
-        memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );\r
-\r
-        // slot size includes comma and null terminator\r
-        int typeTagSlotSize = RoundUp4( typeTagsCount + 2 );\r
-\r
-        uint32 argumentsSize = static_cast<uint32>(argumentCurrent_ - messageCursor_);\r
-\r
-        memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );\r
-\r
-        messageCursor_[0] = ',';\r
-        // copy type tags in reverse (really forward) order\r
-        for( int i=0; i < typeTagsCount; ++i )\r
-            messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];\r
-\r
-        char *p = messageCursor_ + 1 + typeTagsCount;\r
-        for( int i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )\r
-            *p++ = '\0';\r
-\r
-        typeTagsCurrent_ = end_;\r
-\r
-        // advance messageCursor_ for next message\r
-        messageCursor_ += typeTagSlotSize + argumentsSize;\r
-\r
-    }else{\r
-        // send an empty type tags string\r
-        memcpy( messageCursor_, ",\0\0\0", 4 );\r
-\r
-        // advance messageCursor_ for next message\r
-        messageCursor_ += 4;\r
-    }\r
-\r
-    argumentCurrent_ = messageCursor_;\r
-\r
-    EndElement( messageCursor_ );\r
-\r
-    messageIsInProgress_ = false;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs )\r
-{\r
-    CheckForAvailableArgumentSpace(0);\r
-\r
-    *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG);\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs )\r
-{\r
-    (void) rhs;\r
-    CheckForAvailableArgumentSpace(0);\r
-\r
-    *(--typeTagsCurrent_) = NIL_TYPE_TAG;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs )\r
-{\r
-    (void) rhs;\r
-    CheckForAvailableArgumentSpace(0);\r
-\r
-    *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )\r
-{\r
-    CheckForAvailableArgumentSpace(4);\r
-\r
-    *(--typeTagsCurrent_) = INT32_TYPE_TAG;\r
-    FromInt32( argumentCurrent_, rhs );\r
-    argumentCurrent_ += 4;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )\r
-{\r
-    CheckForAvailableArgumentSpace(4);\r
-\r
-    *(--typeTagsCurrent_) = FLOAT_TYPE_TAG;\r
-\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        float f;\r
-        char c[4];\r
-    } u;\r
-\r
-    u.f = rhs;\r
-\r
-    argumentCurrent_[3] = u.c[0];\r
-    argumentCurrent_[2] = u.c[1];\r
-    argumentCurrent_[1] = u.c[2];\r
-    argumentCurrent_[0] = u.c[3];\r
-#else\r
-    *reinterpret_cast<float*>(argumentCurrent_) = rhs;\r
-#endif\r
-\r
-    argumentCurrent_ += 4;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( char rhs )\r
-{\r
-    CheckForAvailableArgumentSpace(4);\r
-\r
-    *(--typeTagsCurrent_) = CHAR_TYPE_TAG;\r
-    FromInt32( argumentCurrent_, rhs );\r
-    argumentCurrent_ += 4;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs )\r
-{\r
-    CheckForAvailableArgumentSpace(4);\r
-\r
-    *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG;\r
-    FromUInt32( argumentCurrent_, rhs );\r
-    argumentCurrent_ += 4;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs )\r
-{\r
-    CheckForAvailableArgumentSpace(4);\r
-\r
-    *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG;\r
-    FromUInt32( argumentCurrent_, rhs );\r
-    argumentCurrent_ += 4;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )\r
-{\r
-    CheckForAvailableArgumentSpace(8);\r
-\r
-    *(--typeTagsCurrent_) = INT64_TYPE_TAG;\r
-    FromInt64( argumentCurrent_, rhs );\r
-    argumentCurrent_ += 8;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs )\r
-{\r
-    CheckForAvailableArgumentSpace(8);\r
-\r
-    *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG;\r
-    FromUInt64( argumentCurrent_, rhs );\r
-    argumentCurrent_ += 8;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )\r
-{\r
-    CheckForAvailableArgumentSpace(8);\r
-\r
-    *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG;\r
-\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        double f;\r
-        char c[8];\r
-    } u;\r
-\r
-    u.f = rhs;\r
-\r
-    argumentCurrent_[7] = u.c[0];\r
-    argumentCurrent_[6] = u.c[1];\r
-    argumentCurrent_[5] = u.c[2];\r
-    argumentCurrent_[4] = u.c[3];\r
-    argumentCurrent_[3] = u.c[4];\r
-    argumentCurrent_[2] = u.c[5];\r
-    argumentCurrent_[1] = u.c[6];\r
-    argumentCurrent_[0] = u.c[7];\r
-#else\r
-    *reinterpret_cast<double*>(argumentCurrent_) = rhs;\r
-#endif\r
-\r
-    argumentCurrent_ += 8;\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )\r
-{\r
-    CheckForAvailableArgumentSpace( RoundUp4(static_cast<long>(strlen(rhs)) + 1) );\r
-\r
-    *(--typeTagsCurrent_) = STRING_TYPE_TAG;\r
-    strcpy( argumentCurrent_, rhs );\r
-    unsigned long rhsLength = static_cast<unsigned long>(strlen(rhs));\r
-    argumentCurrent_ += rhsLength + 1;\r
-\r
-    // zero pad to 4-byte boundary\r
-    unsigned long i = rhsLength + 1;\r
-    while( i & 0x3 ){\r
-        *argumentCurrent_++ = '\0';\r
-        ++i;\r
-    }\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )\r
-{\r
-    CheckForAvailableArgumentSpace( RoundUp4(static_cast<long>(strlen(rhs)) + 1) );\r
-\r
-    *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;\r
-    strcpy( argumentCurrent_, rhs );\r
-    unsigned long rhsLength = static_cast<unsigned long>(strlen(rhs));\r
-    argumentCurrent_ += rhsLength + 1;\r
-\r
-    // zero pad to 4-byte boundary\r
-    unsigned long i = rhsLength + 1;\r
-    while( i & 0x3 ){\r
-        *argumentCurrent_++ = '\0';\r
-        ++i;\r
-    }\r
-\r
-    return *this;\r
-}\r
-\r
-\r
-OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )\r
-{\r
-    CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) );\r
-\r
-    *(--typeTagsCurrent_) = BLOB_TYPE_TAG;\r
-    FromUInt32( argumentCurrent_, rhs.size );\r
-    argumentCurrent_ += 4;\r
-    \r
-    memcpy( argumentCurrent_, rhs.data, rhs.size );\r
-    argumentCurrent_ += rhs.size;\r
-\r
-    // zero pad to 4-byte boundary\r
-    unsigned long i = rhs.size;\r
-    while( i & 0x3 ){\r
-        *argumentCurrent_++ = '\0';\r
-        ++i;\r
-    }\r
-\r
-    return *this;\r
-}\r
-\r
-} // namespace osc\r
-\r
-\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#undef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "OscOutboundPacketStream.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if defined(__WIN32__) || defined(WIN32)
+#include <malloc.h> // for alloca
+#endif
+
+#include "OscHostEndianness.h"
+
+
+namespace osc{
+
+static void FromInt32( char *p, int32 x )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        osc::int32 i;
+        char c[4];
+    } u;
+
+    u.i = x;
+
+    p[3] = u.c[0];
+    p[2] = u.c[1];
+    p[1] = u.c[2];
+    p[0] = u.c[3];
+#else
+    *reinterpret_cast<int32*>(p) = x;
+#endif
+}
+
+
+static void FromUInt32( char *p, uint32 x )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        osc::uint32 i;
+        char c[4];
+    } u;
+
+    u.i = x;
+
+    p[3] = u.c[0];
+    p[2] = u.c[1];
+    p[1] = u.c[2];
+    p[0] = u.c[3];
+#else
+    *reinterpret_cast<uint32*>(p) = x;
+#endif
+}
+
+
+static void FromInt64( char *p, int64 x )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        osc::int64 i;
+        char c[8];
+    } u;
+
+    u.i = x;
+
+    p[7] = u.c[0];
+    p[6] = u.c[1];
+    p[5] = u.c[2];
+    p[4] = u.c[3];
+    p[3] = u.c[4];
+    p[2] = u.c[5];
+    p[1] = u.c[6];
+    p[0] = u.c[7];
+#else
+    *reinterpret_cast<int64*>(p) = x;
+#endif
+}
+
+
+static void FromUInt64( char *p, uint64 x )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        osc::uint64 i;
+        char c[8];
+    } u;
+
+    u.i = x;
+
+    p[7] = u.c[0];
+    p[6] = u.c[1];
+    p[5] = u.c[2];
+    p[4] = u.c[3];
+    p[3] = u.c[4];
+    p[2] = u.c[5];
+    p[1] = u.c[6];
+    p[0] = u.c[7];
+#else
+    *reinterpret_cast<uint64*>(p) = x;
+#endif
+}
+
+
+static inline long RoundUp4( long x )
+{
+    return ((x-1) & (~0x03L)) + 4;
+}
+
+
+OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity )
+    : data_( buffer )
+    , end_( data_ + capacity )
+    , typeTagsCurrent_( end_ )
+    , messageCursor_( data_ )
+    , argumentCurrent_( data_ )
+    , elementSizePtr_( 0 )
+    , messageIsInProgress_( false )
+{
+
+}
+
+
+OutboundPacketStream::~OutboundPacketStream()
+{
+
+}
+
+
+char *OutboundPacketStream::BeginElement( char *beginPtr )
+{
+    if( elementSizePtr_ == 0 ){
+
+        elementSizePtr_ = reinterpret_cast<uint32*>(data_);
+
+        return beginPtr;
+
+    }else{
+        // store an offset to the old element size ptr in the element size slot
+        // we store an offset rather than the actual pointer to be 64 bit clean.
+        *reinterpret_cast<uint32*>(beginPtr) =
+                (uint32)(reinterpret_cast<char*>(elementSizePtr_) - data_);
+
+        elementSizePtr_ = reinterpret_cast<uint32*>(beginPtr);
+
+        return beginPtr + 4;
+    }
+}
+
+
+void OutboundPacketStream::EndElement( char *endPtr )
+{
+    assert( elementSizePtr_ != 0 );
+
+    if( elementSizePtr_ == reinterpret_cast<uint32*>(data_) ){
+
+        elementSizePtr_ = 0;
+
+    }else{
+        // while building an element, an offset to the containing element's
+        // size slot is stored in the elements size slot (or a ptr to data_
+        // if there is no containing element). We retrieve that here
+        uint32 *previousElementSizePtr =
+                (uint32*)(data_ + *reinterpret_cast<uint32*>(elementSizePtr_));
+
+        // then we store the element size in the slot, note that the element
+        // size does not include the size slot, hence the - 4 below.
+        uint32 elementSize =
+                static_cast<uint32>(endPtr - reinterpret_cast<char*>(elementSizePtr_)) - 4;
+        FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
+
+        // finally, we reset the element size ptr to the containing element
+        elementSizePtr_ = previousElementSizePtr;
+    }
+}
+
+
+bool OutboundPacketStream::ElementSizeSlotRequired() const
+{
+    return (elementSizePtr_ != 0);
+}
+
+
+void OutboundPacketStream::CheckForAvailableBundleSpace()
+{
+    unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
+
+    if( required > Capacity() )
+        throw OutOfBufferMemoryException();
+}
+
+
+void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern )
+{
+    // plus 4 for at least four bytes of type tag
+     unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0)
+            + RoundUp4(static_cast<unsigned long>(strlen(addressPattern)) + 1) + 4;
+
+    if( required > Capacity() )
+        throw OutOfBufferMemoryException();
+}
+
+
+void OutboundPacketStream::CheckForAvailableArgumentSpace( long argumentLength )
+{
+    // plus three for extra type tag, comma and null terminator
+     unsigned long required = static_cast<unsigned long>(argumentCurrent_ - data_) + argumentLength
+            + RoundUp4( static_cast<unsigned long>(end_ - typeTagsCurrent_) + 3 );
+
+    if( required > Capacity() )
+        throw OutOfBufferMemoryException();
+}
+
+
+void OutboundPacketStream::Clear()
+{
+    typeTagsCurrent_ = end_;
+    messageCursor_ = data_;
+    argumentCurrent_ = data_;
+    elementSizePtr_ = 0;
+    messageIsInProgress_ = false;
+}
+
+
+unsigned int OutboundPacketStream::Capacity() const
+{
+    return static_cast<int>(end_ - data_);
+}
+
+
+unsigned int OutboundPacketStream::Size() const
+{
+    unsigned int result = static_cast<unsigned long>(argumentCurrent_ - data_);
+    if( IsMessageInProgress() ){
+        // account for the length of the type tag string. the total type tag
+        // includes an initial comma, plus at least one terminating \0
+        result += RoundUp4( static_cast<unsigned long>(end_ - typeTagsCurrent_) + 2 );
+    }
+
+    return result;
+}
+
+
+const char *OutboundPacketStream::Data() const
+{
+    return data_;
+}
+
+
+bool OutboundPacketStream::IsReady() const
+{
+    return (!IsMessageInProgress() && !IsBundleInProgress());
+}
+
+
+bool OutboundPacketStream::IsMessageInProgress() const
+{
+    return messageIsInProgress_;
+}
+
+
+bool OutboundPacketStream::IsBundleInProgress() const
+{
+    return (elementSizePtr_ != 0);
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs )
+{
+    if( IsMessageInProgress() )
+        throw MessageInProgressException();
+
+    CheckForAvailableBundleSpace();
+
+    messageCursor_ = BeginElement( messageCursor_ );
+
+    memcpy( messageCursor_, "#bundle\0", 8 );
+    FromUInt64( messageCursor_ + 8, rhs.timeTag );
+
+    messageCursor_ += 16;
+    argumentCurrent_ = messageCursor_;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs )
+{
+    (void) rhs;
+
+    if( !IsBundleInProgress() )
+        throw BundleNotInProgressException();
+    if( IsMessageInProgress() )
+        throw MessageInProgressException();
+
+    EndElement( messageCursor_ );
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs )
+{
+    if( IsMessageInProgress() )
+        throw MessageInProgressException();
+
+    CheckForAvailableMessageSpace( rhs.addressPattern );
+
+    messageCursor_ = BeginElement( messageCursor_ );
+
+    strcpy( messageCursor_, rhs.addressPattern );
+    unsigned long rhsLength = static_cast<unsigned long>(strlen(rhs.addressPattern));
+    messageCursor_ += rhsLength + 1;
+
+    // zero pad to 4-byte boundary
+    unsigned long i = rhsLength + 1;
+    while( i & 0x3 ){
+        *messageCursor_++ = '\0';
+        ++i;
+    }
+
+    argumentCurrent_ = messageCursor_;
+    typeTagsCurrent_ = end_;
+
+    messageIsInProgress_ = true;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs )
+{
+    (void) rhs;
+
+    if( !IsMessageInProgress() )
+        throw MessageNotInProgressException();
+
+    int typeTagsCount = static_cast<int>(end_ - typeTagsCurrent_);
+
+    if( typeTagsCount ){
+
+        char *tempTypeTags = (char*)alloca(typeTagsCount);
+        memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
+
+        // slot size includes comma and null terminator
+        int typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
+
+        uint32 argumentsSize = static_cast<uint32>(argumentCurrent_ - messageCursor_);
+
+        memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
+
+        messageCursor_[0] = ',';
+        // copy type tags in reverse (really forward) order
+        for( int i=0; i < typeTagsCount; ++i )
+            messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
+
+        char *p = messageCursor_ + 1 + typeTagsCount;
+        for( int i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )
+            *p++ = '\0';
+
+        typeTagsCurrent_ = end_;
+
+        // advance messageCursor_ for next message
+        messageCursor_ += typeTagSlotSize + argumentsSize;
+
+    }else{
+        // send an empty type tags string
+        memcpy( messageCursor_, ",\0\0\0", 4 );
+
+        // advance messageCursor_ for next message
+        messageCursor_ += 4;
+    }
+
+    argumentCurrent_ = messageCursor_;
+
+    EndElement( messageCursor_ );
+
+    messageIsInProgress_ = false;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs )
+{
+    CheckForAvailableArgumentSpace(0);
+
+    *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG);
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs )
+{
+    (void) rhs;
+    CheckForAvailableArgumentSpace(0);
+
+    *(--typeTagsCurrent_) = NIL_TYPE_TAG;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs )
+{
+    (void) rhs;
+    CheckForAvailableArgumentSpace(0);
+
+    *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )
+{
+    CheckForAvailableArgumentSpace(4);
+
+    *(--typeTagsCurrent_) = INT32_TYPE_TAG;
+    FromInt32( argumentCurrent_, rhs );
+    argumentCurrent_ += 4;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
+{
+    CheckForAvailableArgumentSpace(4);
+
+    *(--typeTagsCurrent_) = FLOAT_TYPE_TAG;
+
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        float f;
+        char c[4];
+    } u;
+
+    u.f = rhs;
+
+    argumentCurrent_[3] = u.c[0];
+    argumentCurrent_[2] = u.c[1];
+    argumentCurrent_[1] = u.c[2];
+    argumentCurrent_[0] = u.c[3];
+#else
+    *reinterpret_cast<float*>(argumentCurrent_) = rhs;
+#endif
+
+    argumentCurrent_ += 4;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( char rhs )
+{
+    CheckForAvailableArgumentSpace(4);
+
+    *(--typeTagsCurrent_) = CHAR_TYPE_TAG;
+    FromInt32( argumentCurrent_, rhs );
+    argumentCurrent_ += 4;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs )
+{
+    CheckForAvailableArgumentSpace(4);
+
+    *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG;
+    FromUInt32( argumentCurrent_, rhs );
+    argumentCurrent_ += 4;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs )
+{
+    CheckForAvailableArgumentSpace(4);
+
+    *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG;
+    FromUInt32( argumentCurrent_, rhs );
+    argumentCurrent_ += 4;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )
+{
+    CheckForAvailableArgumentSpace(8);
+
+    *(--typeTagsCurrent_) = INT64_TYPE_TAG;
+    FromInt64( argumentCurrent_, rhs );
+    argumentCurrent_ += 8;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs )
+{
+    CheckForAvailableArgumentSpace(8);
+
+    *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG;
+    FromUInt64( argumentCurrent_, rhs );
+    argumentCurrent_ += 8;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
+{
+    CheckForAvailableArgumentSpace(8);
+
+    *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG;
+
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        double f;
+        char c[8];
+    } u;
+
+    u.f = rhs;
+
+    argumentCurrent_[7] = u.c[0];
+    argumentCurrent_[6] = u.c[1];
+    argumentCurrent_[5] = u.c[2];
+    argumentCurrent_[4] = u.c[3];
+    argumentCurrent_[3] = u.c[4];
+    argumentCurrent_[2] = u.c[5];
+    argumentCurrent_[1] = u.c[6];
+    argumentCurrent_[0] = u.c[7];
+#else
+    *reinterpret_cast<double*>(argumentCurrent_) = rhs;
+#endif
+
+    argumentCurrent_ += 8;
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
+{
+    CheckForAvailableArgumentSpace( RoundUp4(static_cast<long>(strlen(rhs)) + 1) );
+
+    *(--typeTagsCurrent_) = STRING_TYPE_TAG;
+    strcpy( argumentCurrent_, rhs );
+    unsigned long rhsLength = static_cast<unsigned long>(strlen(rhs));
+    argumentCurrent_ += rhsLength + 1;
+
+    // zero pad to 4-byte boundary
+    unsigned long i = rhsLength + 1;
+    while( i & 0x3 ){
+        *argumentCurrent_++ = '\0';
+        ++i;
+    }
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
+{
+    CheckForAvailableArgumentSpace( RoundUp4(static_cast<long>(strlen(rhs)) + 1) );
+
+    *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
+    strcpy( argumentCurrent_, rhs );
+    unsigned long rhsLength = static_cast<unsigned long>(strlen(rhs));
+    argumentCurrent_ += rhsLength + 1;
+
+    // zero pad to 4-byte boundary
+    unsigned long i = rhsLength + 1;
+    while( i & 0x3 ){
+        *argumentCurrent_++ = '\0';
+        ++i;
+    }
+
+    return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
+{
+    CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) );
+
+    *(--typeTagsCurrent_) = BLOB_TYPE_TAG;
+    FromUInt32( argumentCurrent_, rhs.size );
+    argumentCurrent_ += 4;
+    
+    memcpy( argumentCurrent_, rhs.data, rhs.size );
+    argumentCurrent_ += rhs.size;
+
+    // zero pad to 4-byte boundary
+    unsigned long i = rhs.size;
+    while( i & 0x3 ){
+        *argumentCurrent_++ = '\0';
+        ++i;
+    }
+
+    return *this;
+}
+
+} // namespace osc
+
+
index a542445ca0023621728a9c8d6d02a5965b27861a..5faefb901d353344f6740a83d4d4d3161a87fc00 100644 (file)
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#ifndef INCLUDED_OSCOUTBOUNDPACKET_H\r
-#define INCLUDED_OSCOUTBOUNDPACKET_H\r
-\r
-#include "OscTypes.h"\r
-#include "OscException.h"\r
-\r
-\r
-namespace osc{\r
-\r
-class OutOfBufferMemoryException : public Exception{\r
-public:\r
-    OutOfBufferMemoryException( const char *w="out of buffer memory" )\r
-        : Exception( w ) {}\r
-};\r
-\r
-class BundleNotInProgressException : public Exception{\r
-public:\r
-    BundleNotInProgressException(\r
-            const char *w="call to EndBundle when bundle is not in progress" )\r
-        : Exception( w ) {}\r
-};\r
-\r
-class MessageInProgressException : public Exception{\r
-public:\r
-    MessageInProgressException(\r
-            const char *w="opening or closing bundle or message while message is in progress" )\r
-        : Exception( w ) {}\r
-};\r
-\r
-class MessageNotInProgressException : public Exception{\r
-public:\r
-    MessageNotInProgressException(\r
-            const char *w="call to EndMessage when message is not in progress" )\r
-        : Exception( w ) {}\r
-};\r
-\r
-\r
-class OutboundPacketStream{\r
-public:\r
-       OutboundPacketStream( char *buffer, unsigned long capacity );\r
-       ~OutboundPacketStream();\r
-\r
-    void Clear();\r
-\r
-    unsigned int Capacity() const;\r
-\r
-    // invariant: size() is valid even while building a message.\r
-    unsigned int Size() const;\r
-\r
-    const char *Data() const;\r
-\r
-    // indicates that all messages have been closed with a matching EndMessage\r
-    // and all bundles have been closed with a matching EndBundle\r
-    bool IsReady() const;\r
-\r
-    bool IsMessageInProgress() const;\r
-    bool IsBundleInProgress() const;\r
-\r
-    OutboundPacketStream& operator<<( const BundleInitiator& rhs );\r
-    OutboundPacketStream& operator<<( const BundleTerminator& rhs );\r
-    \r
-    OutboundPacketStream& operator<<( const BeginMessage& rhs );\r
-    OutboundPacketStream& operator<<( const MessageTerminator& rhs );\r
-\r
-    OutboundPacketStream& operator<<( bool rhs );\r
-    OutboundPacketStream& operator<<( const NilType& rhs );\r
-    OutboundPacketStream& operator<<( const InfinitumType& rhs );\r
-    OutboundPacketStream& operator<<( int32 rhs );\r
-\r
-//#ifndef __x86_64__\r
-//    OutboundPacketStream& operator<<( int rhs )\r
-//            { *this << (int32)rhs; return *this; }\r
-//#endif\r
-\r
-    OutboundPacketStream& operator<<( float rhs );\r
-    OutboundPacketStream& operator<<( char rhs );\r
-    OutboundPacketStream& operator<<( const RgbaColor& rhs );\r
-    OutboundPacketStream& operator<<( const MidiMessage& rhs );\r
-    OutboundPacketStream& operator<<( int64 rhs );\r
-    OutboundPacketStream& operator<<( const TimeTag& rhs );\r
-    OutboundPacketStream& operator<<( double rhs );\r
-    OutboundPacketStream& operator<<( const char* rhs );\r
-    OutboundPacketStream& operator<<( const Symbol& rhs );\r
-    OutboundPacketStream& operator<<( const Blob& rhs );\r
-\r
-private:\r
-\r
-    char *BeginElement( char *beginPtr );\r
-    void EndElement( char *endPtr );\r
-\r
-    bool ElementSizeSlotRequired() const;\r
-    void CheckForAvailableBundleSpace();\r
-    void CheckForAvailableMessageSpace( const char *addressPattern );\r
-    void CheckForAvailableArgumentSpace( long argumentLength );\r
-\r
-    char *data_;\r
-    char *end_;\r
-\r
-    char *typeTagsCurrent_; // stored in reverse order\r
-    char *messageCursor_;\r
-    char *argumentCurrent_;\r
-\r
-    // elementSizePtr_ has two special values: 0 indicates that a bundle\r
-    // isn't open, and elementSizePtr_==data_ indicates that a bundle is\r
-    // open but that it doesn't have a size slot (ie the outermost bundle)\r
-    uint32 *elementSizePtr_;\r
-\r
-    bool messageIsInProgress_;\r
-};\r
-\r
-} // namespace osc\r
-\r
-#endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSCOUTBOUNDPACKET_H
+#define INCLUDED_OSCOUTBOUNDPACKET_H
+
+#include "OscTypes.h"
+#include "OscException.h"
+
+
+namespace osc{
+
+class OutOfBufferMemoryException : public Exception{
+public:
+    OutOfBufferMemoryException( const char *w="out of buffer memory" )
+        : Exception( w ) {}
+};
+
+class BundleNotInProgressException : public Exception{
+public:
+    BundleNotInProgressException(
+            const char *w="call to EndBundle when bundle is not in progress" )
+        : Exception( w ) {}
+};
+
+class MessageInProgressException : public Exception{
+public:
+    MessageInProgressException(
+            const char *w="opening or closing bundle or message while message is in progress" )
+        : Exception( w ) {}
+};
+
+class MessageNotInProgressException : public Exception{
+public:
+    MessageNotInProgressException(
+            const char *w="call to EndMessage when message is not in progress" )
+        : Exception( w ) {}
+};
+
+
+class OutboundPacketStream{
+public:
+       OutboundPacketStream( char *buffer, unsigned long capacity );
+       ~OutboundPacketStream();
+
+    void Clear();
+
+    unsigned int Capacity() const;
+
+    // invariant: size() is valid even while building a message.
+    unsigned int Size() const;
+
+    const char *Data() const;
+
+    // indicates that all messages have been closed with a matching EndMessage
+    // and all bundles have been closed with a matching EndBundle
+    bool IsReady() const;
+
+    bool IsMessageInProgress() const;
+    bool IsBundleInProgress() const;
+
+    OutboundPacketStream& operator<<( const BundleInitiator& rhs );
+    OutboundPacketStream& operator<<( const BundleTerminator& rhs );
+    
+    OutboundPacketStream& operator<<( const BeginMessage& rhs );
+    OutboundPacketStream& operator<<( const MessageTerminator& rhs );
+
+    OutboundPacketStream& operator<<( bool rhs );
+    OutboundPacketStream& operator<<( const NilType& rhs );
+    OutboundPacketStream& operator<<( const InfinitumType& rhs );
+    OutboundPacketStream& operator<<( int32 rhs );
+
+//#ifndef __x86_64__
+//    OutboundPacketStream& operator<<( int rhs )
+//            { *this << (int32)rhs; return *this; }
+//#endif
+
+    OutboundPacketStream& operator<<( float rhs );
+    OutboundPacketStream& operator<<( char rhs );
+    OutboundPacketStream& operator<<( const RgbaColor& rhs );
+    OutboundPacketStream& operator<<( const MidiMessage& rhs );
+    OutboundPacketStream& operator<<( int64 rhs );
+    OutboundPacketStream& operator<<( const TimeTag& rhs );
+    OutboundPacketStream& operator<<( double rhs );
+    OutboundPacketStream& operator<<( const char* rhs );
+    OutboundPacketStream& operator<<( const Symbol& rhs );
+    OutboundPacketStream& operator<<( const Blob& rhs );
+
+private:
+
+    char *BeginElement( char *beginPtr );
+    void EndElement( char *endPtr );
+
+    bool ElementSizeSlotRequired() const;
+    void CheckForAvailableBundleSpace();
+    void CheckForAvailableMessageSpace( const char *addressPattern );
+    void CheckForAvailableArgumentSpace( long argumentLength );
+
+    char *data_;
+    char *end_;
+
+    char *typeTagsCurrent_; // stored in reverse order
+    char *messageCursor_;
+    char *argumentCurrent_;
+
+    // elementSizePtr_ has two special values: 0 indicates that a bundle
+    // isn't open, and elementSizePtr_==data_ indicates that a bundle is
+    // open but that it doesn't have a size slot (ie the outermost bundle)
+    uint32 *elementSizePtr_;
+
+    bool messageIsInProgress_;
+};
+
+} // namespace osc
+
+#endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */
index bc322b7bd61abef955a33d67fb1a144cd40ddf59..b2d19812b8f6c71c860916e6847c9afe37cf7973 100644 (file)
@@ -1,72 +1,72 @@
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#ifndef INCLUDED_OSCPACKETLISTENER_H\r
-#define INCLUDED_OSCPACKETLISTENER_H\r
-\r
-#include "OscReceivedElements.h"\r
-#include "../ip/PacketListener.h"\r
-\r
-\r
-namespace osc{\r
-\r
-class OscPacketListener : public PacketListener{ \r
-protected:\r
-    virtual void ProcessBundle( const osc::ReceivedBundle& b, \r
-                               const IpEndpointName& remoteEndpoint )\r
-    {\r
-        // ignore bundle time tag for now\r
-\r
-        for( ReceivedBundle::const_iterator i = b.ElementsBegin(); \r
-                               i != b.ElementsEnd(); ++i ){\r
-            if( i->IsBundle() )\r
-                ProcessBundle( ReceivedBundle(*i), remoteEndpoint );\r
-            else\r
-                ProcessMessage( ReceivedMessage(*i), remoteEndpoint );\r
-        }\r
-    }\r
-\r
-    virtual void ProcessMessage( const osc::ReceivedMessage& m, \r
-                               const IpEndpointName& remoteEndpoint ) = 0;\r
-    \r
-public:\r
-       virtual void ProcessPacket( const char *data, int size, \r
-                       const IpEndpointName& remoteEndpoint )\r
-    {\r
-        osc::ReceivedPacket p( data, size );\r
-        if( p.IsBundle() )\r
-            ProcessBundle( ReceivedBundle(p), remoteEndpoint );\r
-        else\r
-            ProcessMessage( ReceivedMessage(p), remoteEndpoint );\r
-    }\r
-};\r
-\r
-} // namespace osc\r
-\r
-#endif /* INCLUDED_OSCPACKETLISTENER_H */\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSCPACKETLISTENER_H
+#define INCLUDED_OSCPACKETLISTENER_H
+
+#include "OscReceivedElements.h"
+#include "../ip/PacketListener.h"
+
+
+namespace osc{
+
+class OscPacketListener : public PacketListener{ 
+protected:
+    virtual void ProcessBundle( const osc::ReceivedBundle& b, 
+                               const IpEndpointName& remoteEndpoint )
+    {
+        // ignore bundle time tag for now
+
+        for( ReceivedBundle::const_iterator i = b.ElementsBegin(); 
+                               i != b.ElementsEnd(); ++i ){
+            if( i->IsBundle() )
+                ProcessBundle( ReceivedBundle(*i), remoteEndpoint );
+            else
+                ProcessMessage( ReceivedMessage(*i), remoteEndpoint );
+        }
+    }
+
+    virtual void ProcessMessage( const osc::ReceivedMessage& m, 
+                               const IpEndpointName& remoteEndpoint ) = 0;
+    
+public:
+       virtual void ProcessPacket( const char *data, int size, 
+                       const IpEndpointName& remoteEndpoint )
+    {
+        osc::ReceivedPacket p( data, size );
+        if( p.IsBundle() )
+            ProcessBundle( ReceivedBundle(p), remoteEndpoint );
+        else
+            ProcessMessage( ReceivedMessage(p), remoteEndpoint );
+    }
+};
+
+} // namespace osc
+
+#endif /* INCLUDED_OSCPACKETLISTENER_H */
index ea7b6628e0100c65eaa920a9d0ff2176e3392057..128cc59ff8bce02a6d78ed807f8987db3a1e69a2 100644 (file)
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#undef _CRT_SECURE_NO_WARNINGS\r
-#define _CRT_SECURE_NO_WARNINGS\r
-\r
-#include "OscPrintReceivedElements.h"\r
-\r
-#include <iostream>\r
-#include <iomanip>\r
-#include <ctime>\r
-#include <cstring>\r
-\r
-\r
-namespace osc{\r
-\r
-\r
-std::ostream& operator<<( std::ostream & os,\r
-        const ReceivedMessageArgument& arg )\r
-{\r
-    switch( arg.TypeTag() ){\r
-        case TRUE_TYPE_TAG:\r
-            os << "bool:true";\r
-            break;\r
-                \r
-        case FALSE_TYPE_TAG:\r
-            os << "bool:false";\r
-            break;\r
-\r
-        case NIL_TYPE_TAG:\r
-            os << "(Nil)";\r
-            break;\r
-\r
-        case INFINITUM_TYPE_TAG:\r
-            os << "(Infinitum)";\r
-            break;\r
-\r
-        case INT32_TYPE_TAG:\r
-            os << "int32:" << arg.AsInt32Unchecked();\r
-            break;\r
-\r
-        case FLOAT_TYPE_TAG:\r
-            os << "float32:" << arg.AsFloatUnchecked();\r
-            break;\r
-\r
-        case CHAR_TYPE_TAG:\r
-            {\r
-                char s[2] = {0};\r
-                s[0] = arg.AsCharUnchecked();\r
-                os << "char:'" << s << "'";\r
-            }\r
-            break;\r
-\r
-        case RGBA_COLOR_TYPE_TAG:\r
-            {\r
-                uint32 color = arg.AsRgbaColorUnchecked();\r
-                \r
-                os << "RGBA:0x"\r
-                        << std::hex << std::setfill('0')\r
-                        << std::setw(2) << (int)((color>>24) & 0xFF)\r
-                        << std::setw(2) << (int)((color>>16) & 0xFF)\r
-                        << std::setw(2) << (int)((color>>8) & 0xFF)\r
-                        << std::setw(2) << (int)(color & 0xFF)\r
-                        << std::setfill(' ');\r
-                os.unsetf(std::ios::basefield);\r
-            }\r
-            break;\r
-\r
-        case MIDI_MESSAGE_TYPE_TAG:\r
-            {\r
-                uint32 m = arg.AsMidiMessageUnchecked();\r
-                os << "midi (port, status, data1, data2):<<"\r
-                        << std::hex << std::setfill('0')\r
-                        << "0x" << std::setw(2) << (int)((m>>24) & 0xFF)\r
-                        << " 0x" << std::setw(2) << (int)((m>>16) & 0xFF)\r
-                        << " 0x" << std::setw(2) << (int)((m>>8) & 0xFF)\r
-                        << " 0x" << std::setw(2) << (int)(m & 0xFF)\r
-                        << std::setfill(' ') << ">>";\r
-                os.unsetf(std::ios::basefield);\r
-            }\r
-            break;\r
-                               \r
-        case INT64_TYPE_TAG:\r
-            os << "int64:" << arg.AsInt64Unchecked();\r
-            break;\r
-\r
-        case TIME_TAG_TYPE_TAG:\r
-            {\r
-                os << "OSC-timetag:" << arg.AsTimeTagUnchecked();\r
-\r
-                std::time_t t =\r
-                        (unsigned long)( arg.AsTimeTagUnchecked() >> 32 );\r
-\r
-                // strip trailing newline from string returned by ctime\r
-                const char *timeString = std::ctime( &t );\r
-                size_t len = strlen( timeString );\r
-                char *s = new char[ len + 1 ];\r
-                strcpy( s, timeString );\r
-                if( len )\r
-                    s[ len - 1 ] = '\0';\r
-                    \r
-                os << " " << s;\r
-            }\r
-            break;\r
-                \r
-        case DOUBLE_TYPE_TAG:\r
-            os << "double:" << arg.AsDoubleUnchecked();\r
-            break;\r
-\r
-        case STRING_TYPE_TAG:\r
-            os << "OSC-string:`" << arg.AsStringUnchecked() << "'";\r
-            break;\r
-                \r
-        case SYMBOL_TYPE_TAG: \r
-            os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'";\r
-            break;\r
-\r
-        case BLOB_TYPE_TAG:\r
-            {\r
-                unsigned long size;\r
-                const void *data;\r
-                arg.AsBlobUnchecked( data, size );\r
-                os << "OSC-blob:<<" << std::hex << std::setfill('0');\r
-                unsigned char *p = (unsigned char*)data;\r
-                for( unsigned long i = 0; i < size; ++i ){\r
-                    os << "0x" << std::setw(2) << int(p[i]);\r
-                    if( i != size-1 )\r
-                        os << ' ';\r
-                }\r
-                os.unsetf(std::ios::basefield);\r
-                os << ">>" << std::setfill(' ');\r
-            }\r
-            break;\r
-\r
-        default:\r
-            os << "unknown";\r
-    }\r
-\r
-    return os;\r
-}\r
-\r
-\r
-std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )\r
-{\r
-    os << "[";\r
-    if( m.AddressPatternIsUInt32() )\r
-        os << m.AddressPatternAsUInt32();\r
-    else\r
-        os << m.AddressPattern();\r
-    \r
-    bool first = true;\r
-    for( ReceivedMessage::const_iterator i = m.ArgumentsBegin();\r
-            i != m.ArgumentsEnd(); ++i ){\r
-        if( first ){\r
-            os << " ";\r
-            first = false;\r
-        }else{\r
-            os << ", ";\r
-        }\r
-\r
-        os << *i;\r
-    }\r
-\r
-    os << "]";\r
-\r
-    return os;\r
-}\r
-\r
-\r
-std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b )\r
-{\r
-    static int indent = 0;\r
-\r
-    for( int j=0; j < indent; ++j )\r
-        os << "  ";\r
-    os << "{ ( ";\r
-    if( b.TimeTag() == 1 )\r
-        os << "immediate";\r
-    else\r
-        os << b.TimeTag();\r
-    os << " )\n";\r
-\r
-    ++indent;\r
-    \r
-    for( ReceivedBundle::const_iterator i = b.ElementsBegin();\r
-            i != b.ElementsEnd(); ++i ){\r
-        if( i->IsBundle() ){\r
-            ReceivedBundle b(*i);\r
-            os << b << "\n";\r
-        }else{\r
-            ReceivedMessage m(*i);\r
-            for( int j=0; j < indent; ++j )\r
-                os << "  ";\r
-            os << m << "\n";\r
-        }\r
-    }\r
-\r
-    --indent;\r
-\r
-    for( int j=0; j < indent; ++j )\r
-        os << "  ";\r
-    os << "}";\r
-\r
-    return os;\r
-}\r
-\r
-\r
-std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p )\r
-{\r
-    if( p.IsBundle() ){\r
-        ReceivedBundle b(p);\r
-        os << b << "\n";\r
-    }else{\r
-        ReceivedMessage m(p);\r
-        os << m << "\n";\r
-    }\r
-\r
-    return os;\r
-}\r
-\r
-} // namespace osc\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#undef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "OscPrintReceivedElements.h"
+
+#include <iostream>
+#include <iomanip>
+#include <ctime>
+#include <cstring>
+
+
+namespace osc{
+
+
+std::ostream& operator<<( std::ostream & os,
+        const ReceivedMessageArgument& arg )
+{
+    switch( arg.TypeTag() ){
+        case TRUE_TYPE_TAG:
+            os << "bool:true";
+            break;
+                
+        case FALSE_TYPE_TAG:
+            os << "bool:false";
+            break;
+
+        case NIL_TYPE_TAG:
+            os << "(Nil)";
+            break;
+
+        case INFINITUM_TYPE_TAG:
+            os << "(Infinitum)";
+            break;
+
+        case INT32_TYPE_TAG:
+            os << "int32:" << arg.AsInt32Unchecked();
+            break;
+
+        case FLOAT_TYPE_TAG:
+            os << "float32:" << arg.AsFloatUnchecked();
+            break;
+
+        case CHAR_TYPE_TAG:
+            {
+                char s[2] = {0};
+                s[0] = arg.AsCharUnchecked();
+                os << "char:'" << s << "'";
+            }
+            break;
+
+        case RGBA_COLOR_TYPE_TAG:
+            {
+                uint32 color = arg.AsRgbaColorUnchecked();
+                
+                os << "RGBA:0x"
+                        << std::hex << std::setfill('0')
+                        << std::setw(2) << (int)((color>>24) & 0xFF)
+                        << std::setw(2) << (int)((color>>16) & 0xFF)
+                        << std::setw(2) << (int)((color>>8) & 0xFF)
+                        << std::setw(2) << (int)(color & 0xFF)
+                        << std::setfill(' ');
+                os.unsetf(std::ios::basefield);
+            }
+            break;
+
+        case MIDI_MESSAGE_TYPE_TAG:
+            {
+                uint32 m = arg.AsMidiMessageUnchecked();
+                os << "midi (port, status, data1, data2):<<"
+                        << std::hex << std::setfill('0')
+                        << "0x" << std::setw(2) << (int)((m>>24) & 0xFF)
+                        << " 0x" << std::setw(2) << (int)((m>>16) & 0xFF)
+                        << " 0x" << std::setw(2) << (int)((m>>8) & 0xFF)
+                        << " 0x" << std::setw(2) << (int)(m & 0xFF)
+                        << std::setfill(' ') << ">>";
+                os.unsetf(std::ios::basefield);
+            }
+            break;
+                               
+        case INT64_TYPE_TAG:
+            os << "int64:" << arg.AsInt64Unchecked();
+            break;
+
+        case TIME_TAG_TYPE_TAG:
+            {
+                os << "OSC-timetag:" << arg.AsTimeTagUnchecked();
+
+                std::time_t t =
+                        (unsigned long)( arg.AsTimeTagUnchecked() >> 32 );
+
+                // strip trailing newline from string returned by ctime
+                const char *timeString = std::ctime( &t );
+                size_t len = strlen( timeString );
+                char *s = new char[ len + 1 ];
+                strcpy( s, timeString );
+                if( len )
+                    s[ len - 1 ] = '\0';
+                    
+                os << " " << s;
+            }
+            break;
+                
+        case DOUBLE_TYPE_TAG:
+            os << "double:" << arg.AsDoubleUnchecked();
+            break;
+
+        case STRING_TYPE_TAG:
+            os << "OSC-string:`" << arg.AsStringUnchecked() << "'";
+            break;
+                
+        case SYMBOL_TYPE_TAG: 
+            os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'";
+            break;
+
+        case BLOB_TYPE_TAG:
+            {
+                unsigned long size;
+                const void *data;
+                arg.AsBlobUnchecked( data, size );
+                os << "OSC-blob:<<" << std::hex << std::setfill('0');
+                unsigned char *p = (unsigned char*)data;
+                for( unsigned long i = 0; i < size; ++i ){
+                    os << "0x" << std::setw(2) << int(p[i]);
+                    if( i != size-1 )
+                        os << ' ';
+                }
+                os.unsetf(std::ios::basefield);
+                os << ">>" << std::setfill(' ');
+            }
+            break;
+
+        default:
+            os << "unknown";
+    }
+
+    return os;
+}
+
+
+std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )
+{
+    os << "[";
+    if( m.AddressPatternIsUInt32() )
+        os << m.AddressPatternAsUInt32();
+    else
+        os << m.AddressPattern();
+    
+    bool first = true;
+    for( ReceivedMessage::const_iterator i = m.ArgumentsBegin();
+            i != m.ArgumentsEnd(); ++i ){
+        if( first ){
+            os << " ";
+            first = false;
+        }else{
+            os << ", ";
+        }
+
+        os << *i;
+    }
+
+    os << "]";
+
+    return os;
+}
+
+
+std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b )
+{
+    static int indent = 0;
+
+    for( int j=0; j < indent; ++j )
+        os << "  ";
+    os << "{ ( ";
+    if( b.TimeTag() == 1 )
+        os << "immediate";
+    else
+        os << b.TimeTag();
+    os << " )\n";
+
+    ++indent;
+    
+    for( ReceivedBundle::const_iterator i = b.ElementsBegin();
+            i != b.ElementsEnd(); ++i ){
+        if( i->IsBundle() ){
+            ReceivedBundle b(*i);
+            os << b << "\n";
+        }else{
+            ReceivedMessage m(*i);
+            for( int j=0; j < indent; ++j )
+                os << "  ";
+            os << m << "\n";
+        }
+    }
+
+    --indent;
+
+    for( int j=0; j < indent; ++j )
+        os << "  ";
+    os << "}";
+
+    return os;
+}
+
+
+std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p )
+{
+    if( p.IsBundle() ){
+        ReceivedBundle b(p);
+        os << b << "\n";
+    }else{
+        ReceivedMessage m(p);
+        os << m << "\n";
+    }
+
+    return os;
+}
+
+} // namespace osc
index c42cfa56a162432329d0db6d7c45904f3fa6a7ab..7ec747c81f4224254d673ad87c670cd99668dae0 100644 (file)
@@ -1,49 +1,49 @@
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H\r
-#define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H\r
-\r
-#include <iosfwd>\r
-\r
-#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H\r
-#include "OscReceivedElements.h"\r
-#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */\r
-\r
-\r
-namespace osc{\r
-\r
-std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p );\r
-std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg );\r
-std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m );\r
-std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b );\r
-\r
-} // namespace osc\r
-\r
-#endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
+#define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
+
+#include <iosfwd>
+
+#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
+#include "OscReceivedElements.h"
+#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
+
+
+namespace osc{
+
+std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p );
+std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg );
+std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m );
+std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b );
+
+} // namespace osc
+
+#endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */
index 9554cc43330ab93a7c12382f9247a540133bd375..cca1e13538a733db51fbc7bd7e8bbd105343f619 100644 (file)
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#undef _CRT_SECURE_NO_WARNINGS\r
-#define _CRT_SECURE_NO_WARNINGS\r
-\r
-#include "OscReceivedElements.h"\r
-\r
-#include <cassert>\r
-\r
-#include "OscHostEndianness.h"\r
-\r
-\r
-namespace osc{\r
-\r
-\r
-// return the first 4 byte boundary after the end of a str4\r
-// be careful about calling this version if you don't know whether\r
-// the string is terminated correctly.\r
-static inline const char* FindStr4End( const char *p )\r
-{\r
-       if( p[0] == '\0' )    // special case for SuperCollider integer address pattern\r
-               return p + 4;\r
-\r
-    p += 3;\r
-\r
-    while( *p )\r
-        p += 4;\r
-\r
-    return p + 1;\r
-}\r
-\r
-\r
-// return the first 4 byte boundary after the end of a str4\r
-// returns 0 if p == end or if the string is unterminated\r
-static inline const char* FindStr4End( const char *p, const char *end )\r
-{\r
-    if( p >= end )\r
-        return 0;\r
-\r
-       if( p[0] == '\0' )    // special case for SuperCollider integer address pattern\r
-               return p + 4;\r
-\r
-    p += 3;\r
-    end -= 1;\r
-\r
-    while( p < end && *p )\r
-        p += 4;\r
-\r
-    if( *p )\r
-        return 0;\r
-    else\r
-        return p + 1;\r
-}\r
-\r
-\r
-static inline unsigned long RoundUp4( unsigned long x )\r
-{\r
-    unsigned long remainder = x & 0x3UL;\r
-    if( remainder )\r
-        return x + (4 - remainder);\r
-    else\r
-        return x;\r
-}\r
-\r
-\r
-static inline int32 ToInt32( const char *p )\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        osc::int32 i;\r
-        char c[4];\r
-    } u;\r
-\r
-    u.c[0] = p[3];\r
-    u.c[1] = p[2];\r
-    u.c[2] = p[1];\r
-    u.c[3] = p[0];\r
-\r
-    return u.i;\r
-#else\r
-       return *(int32*)p;\r
-#endif\r
-}\r
-\r
-\r
-static inline uint32 ToUInt32( const char *p )\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        osc::uint32 i;\r
-        char c[4];\r
-    } u;\r
-\r
-    u.c[0] = p[3];\r
-    u.c[1] = p[2];\r
-    u.c[2] = p[1];\r
-    u.c[3] = p[0];\r
-\r
-    return u.i;\r
-#else\r
-       return *(uint32*)p;\r
-#endif\r
-}\r
-\r
-\r
-int64 ToInt64( const char *p )\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        osc::int64 i;\r
-        char c[8];\r
-    } u;\r
-\r
-    u.c[0] = p[7];\r
-    u.c[1] = p[6];\r
-    u.c[2] = p[5];\r
-    u.c[3] = p[4];\r
-    u.c[4] = p[3];\r
-    u.c[5] = p[2];\r
-    u.c[6] = p[1];\r
-    u.c[7] = p[0];\r
-\r
-    return u.i;\r
-#else\r
-       return *(int64*)p;\r
-#endif\r
-}\r
-\r
-\r
-uint64 ToUInt64( const char *p )\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        osc::uint64 i;\r
-        char c[8];\r
-    } u;\r
-\r
-    u.c[0] = p[7];\r
-    u.c[1] = p[6];\r
-    u.c[2] = p[5];\r
-    u.c[3] = p[4];\r
-    u.c[4] = p[3];\r
-    u.c[5] = p[2];\r
-    u.c[6] = p[1];\r
-    u.c[7] = p[0];\r
-\r
-    return u.i;\r
-#else\r
-       return *(uint64*)p;\r
-#endif\r
-}\r
-\r
-//------------------------------------------------------------------------------\r
-\r
-bool ReceivedPacket::IsBundle() const\r
-{\r
-    return (Size() > 0 && Contents()[0] == '#');\r
-}\r
-\r
-//------------------------------------------------------------------------------\r
-\r
-bool ReceivedBundleElement::IsBundle() const\r
-{\r
-    return (Size() > 0 && Contents()[0] == '#');\r
-}\r
-\r
-\r
-int32 ReceivedBundleElement::Size() const\r
-{\r
-    return ToUInt32( size_ );\r
-}\r
-\r
-//------------------------------------------------------------------------------\r
-\r
-bool ReceivedMessageArgument::AsBool() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == TRUE_TYPE_TAG )\r
-               return true;\r
-       else if( *typeTag_ == FALSE_TYPE_TAG )\r
-               return false;\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-bool ReceivedMessageArgument::AsBoolUnchecked() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == TRUE_TYPE_TAG )\r
-               return true;\r
-    else\r
-           return false;\r
-}\r
-\r
-\r
-int32 ReceivedMessageArgument::AsInt32() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == INT32_TYPE_TAG )\r
-               return AsInt32Unchecked();\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-int32 ReceivedMessageArgument::AsInt32Unchecked() const\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        osc::int32 i;\r
-        char c[4];\r
-    } u;\r
-\r
-    u.c[0] = argument_[3];\r
-    u.c[1] = argument_[2];\r
-    u.c[2] = argument_[1];\r
-    u.c[3] = argument_[0];\r
-\r
-    return u.i;\r
-#else\r
-       return *(int32*)argument_;\r
-#endif\r
-}\r
-\r
-\r
-float ReceivedMessageArgument::AsFloat() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == FLOAT_TYPE_TAG )\r
-               return AsFloatUnchecked();\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-float ReceivedMessageArgument::AsFloatUnchecked() const\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        float f;\r
-        char c[4];\r
-    } u;\r
-\r
-    u.c[0] = argument_[3];\r
-    u.c[1] = argument_[2];\r
-    u.c[2] = argument_[1];\r
-    u.c[3] = argument_[0];\r
-\r
-    return u.f;\r
-#else\r
-       return *(float*)argument_;\r
-#endif\r
-}\r
-\r
-\r
-char ReceivedMessageArgument::AsChar() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == CHAR_TYPE_TAG )\r
-               return AsCharUnchecked();\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-char ReceivedMessageArgument::AsCharUnchecked() const\r
-{\r
-    return (char)ToInt32( argument_ );\r
-}\r
-\r
-\r
-uint32 ReceivedMessageArgument::AsRgbaColor() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == RGBA_COLOR_TYPE_TAG )\r
-               return AsRgbaColorUnchecked();\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const\r
-{\r
-       return ToUInt32( argument_ );\r
-}\r
-\r
-\r
-uint32 ReceivedMessageArgument::AsMidiMessage() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG )\r
-               return AsMidiMessageUnchecked();\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const\r
-{\r
-       return ToUInt32( argument_ );\r
-}\r
-\r
-\r
-int64 ReceivedMessageArgument::AsInt64() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == INT64_TYPE_TAG )\r
-               return AsInt64Unchecked();\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-int64 ReceivedMessageArgument::AsInt64Unchecked() const\r
-{\r
-    return ToInt64( argument_ );\r
-}\r
-\r
-\r
-uint64 ReceivedMessageArgument::AsTimeTag() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == TIME_TAG_TYPE_TAG )\r
-               return AsTimeTagUnchecked();\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const\r
-{\r
-    return ToUInt64( argument_ );\r
-}\r
-\r
-\r
-double ReceivedMessageArgument::AsDouble() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == DOUBLE_TYPE_TAG )\r
-               return AsDoubleUnchecked();\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-double ReceivedMessageArgument::AsDoubleUnchecked() const\r
-{\r
-#ifdef OSC_HOST_LITTLE_ENDIAN\r
-    union{\r
-        double d;\r
-        char c[8];\r
-    } u;\r
-\r
-    u.c[0] = argument_[7];\r
-    u.c[1] = argument_[6];\r
-    u.c[2] = argument_[5];\r
-    u.c[3] = argument_[4];\r
-    u.c[4] = argument_[3];\r
-    u.c[5] = argument_[2];\r
-    u.c[6] = argument_[1];\r
-    u.c[7] = argument_[0];\r
-\r
-    return u.d;\r
-#else\r
-       return *(double*)argument_;\r
-#endif\r
-}\r
-\r
-\r
-const char* ReceivedMessageArgument::AsString() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == STRING_TYPE_TAG )\r
-               return argument_;\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-const char* ReceivedMessageArgument::AsSymbol() const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == SYMBOL_TYPE_TAG )\r
-               return argument_;\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const\r
-{\r
-    if( !typeTag_ )\r
-        throw MissingArgumentException();\r
-       else if( *typeTag_ == BLOB_TYPE_TAG )\r
-               AsBlobUnchecked( data, size );\r
-       else\r
-               throw WrongArgumentTypeException();\r
-}\r
-\r
-\r
-void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const\r
-{\r
-    size = ToUInt32( argument_ );\r
-       data = (void*)(argument_+4);\r
-}\r
-\r
-//------------------------------------------------------------------------------\r
-\r
-void ReceivedMessageArgumentIterator::Advance()\r
-{\r
-    if( !value_.typeTag_ )\r
-        return;\r
-        \r
-    switch( *value_.typeTag_++ ){\r
-        case '\0':\r
-            // don't advance past end\r
-            --value_.typeTag_;\r
-            break;\r
-            \r
-        case TRUE_TYPE_TAG:\r
-        case FALSE_TYPE_TAG:\r
-        case NIL_TYPE_TAG:\r
-        case INFINITUM_TYPE_TAG:\r
-\r
-            // zero length\r
-            break;\r
-\r
-        case INT32_TYPE_TAG:\r
-        case FLOAT_TYPE_TAG:                                   \r
-        case CHAR_TYPE_TAG:\r
-        case RGBA_COLOR_TYPE_TAG:\r
-        case MIDI_MESSAGE_TYPE_TAG:\r
-\r
-            value_.argument_ += 4;\r
-            break;\r
-\r
-        case INT64_TYPE_TAG:\r
-        case TIME_TAG_TYPE_TAG:\r
-        case DOUBLE_TYPE_TAG:\r
-                               \r
-            value_.argument_ += 8;\r
-            break;\r
-\r
-        case STRING_TYPE_TAG: \r
-        case SYMBOL_TYPE_TAG:\r
-\r
-            // we use the unsafe function FindStr4End(char*) here because all of\r
-            // the arguments have already been validated in\r
-            // ReceivedMessage::Init() below.\r
-            \r
-            value_.argument_ = FindStr4End( value_.argument_ );\r
-            break;\r
-\r
-        case BLOB_TYPE_TAG:\r
-            {\r
-                uint32 blobSize = ToUInt32( value_.argument_ );\r
-                value_.argument_ = value_.argument_ + 4 + RoundUp4( (unsigned long)blobSize );\r
-            }\r
-            break;\r
-\r
-        default:    // unknown type tag\r
-            // don't advance\r
-            --value_.typeTag_;\r
-            break;\r
-            \r
-\r
-        //    not handled:\r
-        //    [ Indicates the beginning of an array. The tags following are for\r
-        //        data in the Array until a close brace tag is reached.\r
-        //    ] Indicates the end of an array.\r
-    }\r
-}\r
-\r
-//------------------------------------------------------------------------------\r
-\r
-ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )\r
-    : addressPattern_( packet.Contents() )\r
-{\r
-    Init( packet.Contents(), packet.Size() );\r
-}\r
-\r
-\r
-ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )\r
-    : addressPattern_( bundleElement.Contents() )\r
-{\r
-    Init( bundleElement.Contents(), bundleElement.Size() );\r
-}\r
-\r
-\r
-bool ReceivedMessage::AddressPatternIsUInt32() const\r
-{\r
-       return (addressPattern_[0] == '\0');\r
-}\r
-\r
-\r
-uint32 ReceivedMessage::AddressPatternAsUInt32() const\r
-{\r
-    return ToUInt32( addressPattern_ );\r
-}\r
-\r
-\r
-void ReceivedMessage::Init( const char *message, unsigned long size )\r
-{\r
-    if( size == 0 )\r
-        throw MalformedMessageException( "zero length messages not permitted" );\r
-\r
-    if( (size & 0x03L) != 0 )\r
-        throw MalformedMessageException( "message size must be multiple of four" );\r
-\r
-    const char *end = message + size;\r
-\r
-    typeTagsBegin_ = FindStr4End( addressPattern_, end );\r
-    if( typeTagsBegin_ == 0 ){\r
-        // address pattern was not terminated before end\r
-        throw MalformedMessageException( "unterminated address pattern" );\r
-    }\r
-\r
-    if( typeTagsBegin_ == end ){\r
-        // message consists of only the address pattern - no arguments or type tags.\r
-        typeTagsBegin_ = 0;\r
-        typeTagsEnd_ = 0;\r
-        arguments_ = 0;\r
-            \r
-    }else{\r
-        if( *typeTagsBegin_ != ',' )\r
-            throw MalformedMessageException( "type tags not present" );\r
-\r
-        if( *(typeTagsBegin_ + 1) == '\0' ){\r
-            // zero length type tags\r
-            typeTagsBegin_ = 0;\r
-            typeTagsEnd_ = 0;\r
-            arguments_ = 0;\r
-\r
-        }else{\r
-            // check that all arguments are present and well formed\r
-                \r
-            arguments_ = FindStr4End( typeTagsBegin_, end );\r
-            if( arguments_ == 0 ){\r
-                throw MalformedMessageException( "type tags were not terminated before end of message" );\r
-            }\r
-\r
-            ++typeTagsBegin_; // advance past initial ','\r
-            \r
-            const char *typeTag = typeTagsBegin_;\r
-            const char *argument = arguments_;\r
-                        \r
-            do{\r
-                switch( *typeTag ){\r
-                    case TRUE_TYPE_TAG:\r
-                    case FALSE_TYPE_TAG:\r
-                    case NIL_TYPE_TAG:\r
-                    case INFINITUM_TYPE_TAG:\r
-\r
-                        // zero length\r
-                        break;\r
-\r
-                    case INT32_TYPE_TAG:\r
-                    case FLOAT_TYPE_TAG:\r
-                    case CHAR_TYPE_TAG:\r
-                    case RGBA_COLOR_TYPE_TAG:\r
-                    case MIDI_MESSAGE_TYPE_TAG:\r
-\r
-                        if( argument == end )\r
-                            throw MalformedMessageException( "arguments exceed message size" );\r
-                        argument += 4;\r
-                        if( argument > end )\r
-                            throw MalformedMessageException( "arguments exceed message size" );\r
-                        break;\r
-\r
-                    case INT64_TYPE_TAG:\r
-                    case TIME_TAG_TYPE_TAG:\r
-                    case DOUBLE_TYPE_TAG:\r
-\r
-                        if( argument == end )\r
-                            throw MalformedMessageException( "arguments exceed message size" );\r
-                        argument += 8;\r
-                        if( argument > end )\r
-                            throw MalformedMessageException( "arguments exceed message size" );\r
-                        break;\r
-\r
-                    case STRING_TYPE_TAG: \r
-                    case SYMBOL_TYPE_TAG:\r
-                    \r
-                        if( argument == end )\r
-                            throw MalformedMessageException( "arguments exceed message size" );\r
-                        argument = FindStr4End( argument, end );\r
-                        if( argument == 0 )\r
-                            throw MalformedMessageException( "unterminated string argument" );\r
-                        break;\r
-\r
-                    case BLOB_TYPE_TAG:\r
-                        {\r
-                            if( argument + 4 > end )\r
-                                MalformedMessageException( "arguments exceed message size" );\r
-                                \r
-                            uint32 blobSize = ToUInt32( argument );\r
-                            argument = argument + 4 + RoundUp4( (unsigned long)blobSize );\r
-                            if( argument > end )\r
-                                MalformedMessageException( "arguments exceed message size" );\r
-                        }\r
-                        break;\r
-                        \r
-                    default:\r
-                        throw MalformedMessageException( "unknown type tag" );\r
-\r
-                    //    not handled:\r
-                    //    [ Indicates the beginning of an array. The tags following are for\r
-                    //        data in the Array until a close brace tag is reached.\r
-                    //    ] Indicates the end of an array.\r
-                }\r
-\r
-            }while( *++typeTag != '\0' );\r
-            typeTagsEnd_ = typeTag;\r
-        }\r
-    }\r
-}\r
-\r
-//------------------------------------------------------------------------------\r
-\r
-ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )\r
-    : elementCount_( 0 )\r
-{\r
-    Init( packet.Contents(), packet.Size() );\r
-}\r
-\r
-\r
-ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )\r
-    : elementCount_( 0 )\r
-{\r
-    Init( bundleElement.Contents(), bundleElement.Size() );\r
-}\r
-\r
-\r
-void ReceivedBundle::Init( const char *bundle, unsigned long size )\r
-{\r
-    if( size < 16 )\r
-        throw MalformedBundleException( "packet too short for bundle" );\r
-\r
-    if( (size & 0x03L) != 0 )\r
-        throw MalformedBundleException( "bundle size must be multiple of four" );\r
-\r
-    if( bundle[0] != '#'\r
-        || bundle[1] != 'b'\r
-        || bundle[2] != 'u'\r
-        || bundle[3] != 'n'\r
-        || bundle[4] != 'd'\r
-        || bundle[5] != 'l'\r
-        || bundle[6] != 'e'\r
-        || bundle[7] != '\0' )\r
-            throw MalformedBundleException( "bad bundle address pattern" );    \r
-\r
-    end_ = bundle + size;\r
-\r
-    timeTag_ = bundle + 8;\r
-\r
-    const char *p = timeTag_ + 8;\r
-        \r
-    while( p < end_ ){\r
-        if( p + 4 > end_ )\r
-            throw MalformedBundleException( "packet too short for elementSize" );\r
-\r
-        uint32 elementSize = ToUInt32( p );\r
-        if( (elementSize & 0x03L) != 0 )\r
-            throw MalformedBundleException( "bundle element size must be multiple of four" );\r
-\r
-        p += 4 + elementSize;\r
-        if( p > end_ )\r
-            throw MalformedBundleException( "packet too short for bundle element" );\r
-\r
-        ++elementCount_;\r
-    }\r
-\r
-    if( p != end_ )\r
-        throw MalformedBundleException( "bundle contents " );\r
-}\r
-\r
-\r
-uint64 ReceivedBundle::TimeTag() const\r
-{\r
-    return ToUInt64( timeTag_ );\r
-}\r
-\r
-\r
-} // namespace osc\r
-\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#undef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "OscReceivedElements.h"
+
+#include <cassert>
+
+#include "OscHostEndianness.h"
+
+
+namespace osc{
+
+
+// return the first 4 byte boundary after the end of a str4
+// be careful about calling this version if you don't know whether
+// the string is terminated correctly.
+static inline const char* FindStr4End( const char *p )
+{
+       if( p[0] == '\0' )    // special case for SuperCollider integer address pattern
+               return p + 4;
+
+    p += 3;
+
+    while( *p )
+        p += 4;
+
+    return p + 1;
+}
+
+
+// return the first 4 byte boundary after the end of a str4
+// returns 0 if p == end or if the string is unterminated
+static inline const char* FindStr4End( const char *p, const char *end )
+{
+    if( p >= end )
+        return 0;
+
+       if( p[0] == '\0' )    // special case for SuperCollider integer address pattern
+               return p + 4;
+
+    p += 3;
+    end -= 1;
+
+    while( p < end && *p )
+        p += 4;
+
+    if( *p )
+        return 0;
+    else
+        return p + 1;
+}
+
+
+static inline unsigned long RoundUp4( unsigned long x )
+{
+    unsigned long remainder = x & 0x3UL;
+    if( remainder )
+        return x + (4 - remainder);
+    else
+        return x;
+}
+
+
+static inline int32 ToInt32( const char *p )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        osc::int32 i;
+        char c[4];
+    } u;
+
+    u.c[0] = p[3];
+    u.c[1] = p[2];
+    u.c[2] = p[1];
+    u.c[3] = p[0];
+
+    return u.i;
+#else
+       return *(int32*)p;
+#endif
+}
+
+
+static inline uint32 ToUInt32( const char *p )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        osc::uint32 i;
+        char c[4];
+    } u;
+
+    u.c[0] = p[3];
+    u.c[1] = p[2];
+    u.c[2] = p[1];
+    u.c[3] = p[0];
+
+    return u.i;
+#else
+       return *(uint32*)p;
+#endif
+}
+
+
+int64 ToInt64( const char *p )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        osc::int64 i;
+        char c[8];
+    } u;
+
+    u.c[0] = p[7];
+    u.c[1] = p[6];
+    u.c[2] = p[5];
+    u.c[3] = p[4];
+    u.c[4] = p[3];
+    u.c[5] = p[2];
+    u.c[6] = p[1];
+    u.c[7] = p[0];
+
+    return u.i;
+#else
+       return *(int64*)p;
+#endif
+}
+
+
+uint64 ToUInt64( const char *p )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        osc::uint64 i;
+        char c[8];
+    } u;
+
+    u.c[0] = p[7];
+    u.c[1] = p[6];
+    u.c[2] = p[5];
+    u.c[3] = p[4];
+    u.c[4] = p[3];
+    u.c[5] = p[2];
+    u.c[6] = p[1];
+    u.c[7] = p[0];
+
+    return u.i;
+#else
+       return *(uint64*)p;
+#endif
+}
+
+//------------------------------------------------------------------------------
+
+bool ReceivedPacket::IsBundle() const
+{
+    return (Size() > 0 && Contents()[0] == '#');
+}
+
+//------------------------------------------------------------------------------
+
+bool ReceivedBundleElement::IsBundle() const
+{
+    return (Size() > 0 && Contents()[0] == '#');
+}
+
+
+int32 ReceivedBundleElement::Size() const
+{
+    return ToUInt32( size_ );
+}
+
+//------------------------------------------------------------------------------
+
+bool ReceivedMessageArgument::AsBool() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == TRUE_TYPE_TAG )
+               return true;
+       else if( *typeTag_ == FALSE_TYPE_TAG )
+               return false;
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+bool ReceivedMessageArgument::AsBoolUnchecked() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == TRUE_TYPE_TAG )
+               return true;
+    else
+           return false;
+}
+
+
+int32 ReceivedMessageArgument::AsInt32() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == INT32_TYPE_TAG )
+               return AsInt32Unchecked();
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+int32 ReceivedMessageArgument::AsInt32Unchecked() const
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        osc::int32 i;
+        char c[4];
+    } u;
+
+    u.c[0] = argument_[3];
+    u.c[1] = argument_[2];
+    u.c[2] = argument_[1];
+    u.c[3] = argument_[0];
+
+    return u.i;
+#else
+       return *(int32*)argument_;
+#endif
+}
+
+
+float ReceivedMessageArgument::AsFloat() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == FLOAT_TYPE_TAG )
+               return AsFloatUnchecked();
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+float ReceivedMessageArgument::AsFloatUnchecked() const
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        float f;
+        char c[4];
+    } u;
+
+    u.c[0] = argument_[3];
+    u.c[1] = argument_[2];
+    u.c[2] = argument_[1];
+    u.c[3] = argument_[0];
+
+    return u.f;
+#else
+       return *(float*)argument_;
+#endif
+}
+
+
+char ReceivedMessageArgument::AsChar() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == CHAR_TYPE_TAG )
+               return AsCharUnchecked();
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+char ReceivedMessageArgument::AsCharUnchecked() const
+{
+    return (char)ToInt32( argument_ );
+}
+
+
+uint32 ReceivedMessageArgument::AsRgbaColor() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == RGBA_COLOR_TYPE_TAG )
+               return AsRgbaColorUnchecked();
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
+{
+       return ToUInt32( argument_ );
+}
+
+
+uint32 ReceivedMessageArgument::AsMidiMessage() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG )
+               return AsMidiMessageUnchecked();
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
+{
+       return ToUInt32( argument_ );
+}
+
+
+int64 ReceivedMessageArgument::AsInt64() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == INT64_TYPE_TAG )
+               return AsInt64Unchecked();
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+int64 ReceivedMessageArgument::AsInt64Unchecked() const
+{
+    return ToInt64( argument_ );
+}
+
+
+uint64 ReceivedMessageArgument::AsTimeTag() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == TIME_TAG_TYPE_TAG )
+               return AsTimeTagUnchecked();
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
+{
+    return ToUInt64( argument_ );
+}
+
+
+double ReceivedMessageArgument::AsDouble() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == DOUBLE_TYPE_TAG )
+               return AsDoubleUnchecked();
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+double ReceivedMessageArgument::AsDoubleUnchecked() const
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+    union{
+        double d;
+        char c[8];
+    } u;
+
+    u.c[0] = argument_[7];
+    u.c[1] = argument_[6];
+    u.c[2] = argument_[5];
+    u.c[3] = argument_[4];
+    u.c[4] = argument_[3];
+    u.c[5] = argument_[2];
+    u.c[6] = argument_[1];
+    u.c[7] = argument_[0];
+
+    return u.d;
+#else
+       return *(double*)argument_;
+#endif
+}
+
+
+const char* ReceivedMessageArgument::AsString() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == STRING_TYPE_TAG )
+               return argument_;
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+const char* ReceivedMessageArgument::AsSymbol() const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == SYMBOL_TYPE_TAG )
+               return argument_;
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const
+{
+    if( !typeTag_ )
+        throw MissingArgumentException();
+       else if( *typeTag_ == BLOB_TYPE_TAG )
+               AsBlobUnchecked( data, size );
+       else
+               throw WrongArgumentTypeException();
+}
+
+
+void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const
+{
+    size = ToUInt32( argument_ );
+       data = (void*)(argument_+4);
+}
+
+//------------------------------------------------------------------------------
+
+void ReceivedMessageArgumentIterator::Advance()
+{
+    if( !value_.typeTag_ )
+        return;
+        
+    switch( *value_.typeTag_++ ){
+        case '\0':
+            // don't advance past end
+            --value_.typeTag_;
+            break;
+            
+        case TRUE_TYPE_TAG:
+        case FALSE_TYPE_TAG:
+        case NIL_TYPE_TAG:
+        case INFINITUM_TYPE_TAG:
+
+            // zero length
+            break;
+
+        case INT32_TYPE_TAG:
+        case FLOAT_TYPE_TAG:                                   
+        case CHAR_TYPE_TAG:
+        case RGBA_COLOR_TYPE_TAG:
+        case MIDI_MESSAGE_TYPE_TAG:
+
+            value_.argument_ += 4;
+            break;
+
+        case INT64_TYPE_TAG:
+        case TIME_TAG_TYPE_TAG:
+        case DOUBLE_TYPE_TAG:
+                               
+            value_.argument_ += 8;
+            break;
+
+        case STRING_TYPE_TAG: 
+        case SYMBOL_TYPE_TAG:
+
+            // we use the unsafe function FindStr4End(char*) here because all of
+            // the arguments have already been validated in
+            // ReceivedMessage::Init() below.
+            
+            value_.argument_ = FindStr4End( value_.argument_ );
+            break;
+
+        case BLOB_TYPE_TAG:
+            {
+                uint32 blobSize = ToUInt32( value_.argument_ );
+                value_.argument_ = value_.argument_ + 4 + RoundUp4( (unsigned long)blobSize );
+            }
+            break;
+
+        default:    // unknown type tag
+            // don't advance
+            --value_.typeTag_;
+            break;
+            
+
+        //    not handled:
+        //    [ Indicates the beginning of an array. The tags following are for
+        //        data in the Array until a close brace tag is reached.
+        //    ] Indicates the end of an array.
+    }
+}
+
+//------------------------------------------------------------------------------
+
+ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )
+    : addressPattern_( packet.Contents() )
+{
+    Init( packet.Contents(), packet.Size() );
+}
+
+
+ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
+    : addressPattern_( bundleElement.Contents() )
+{
+    Init( bundleElement.Contents(), bundleElement.Size() );
+}
+
+
+bool ReceivedMessage::AddressPatternIsUInt32() const
+{
+       return (addressPattern_[0] == '\0');
+}
+
+
+uint32 ReceivedMessage::AddressPatternAsUInt32() const
+{
+    return ToUInt32( addressPattern_ );
+}
+
+
+void ReceivedMessage::Init( const char *message, unsigned long size )
+{
+    if( size == 0 )
+        throw MalformedMessageException( "zero length messages not permitted" );
+
+    if( (size & 0x03L) != 0 )
+        throw MalformedMessageException( "message size must be multiple of four" );
+
+    const char *end = message + size;
+
+    typeTagsBegin_ = FindStr4End( addressPattern_, end );
+    if( typeTagsBegin_ == 0 ){
+        // address pattern was not terminated before end
+        throw MalformedMessageException( "unterminated address pattern" );
+    }
+
+    if( typeTagsBegin_ == end ){
+        // message consists of only the address pattern - no arguments or type tags.
+        typeTagsBegin_ = 0;
+        typeTagsEnd_ = 0;
+        arguments_ = 0;
+            
+    }else{
+        if( *typeTagsBegin_ != ',' )
+            throw MalformedMessageException( "type tags not present" );
+
+        if( *(typeTagsBegin_ + 1) == '\0' ){
+            // zero length type tags
+            typeTagsBegin_ = 0;
+            typeTagsEnd_ = 0;
+            arguments_ = 0;
+
+        }else{
+            // check that all arguments are present and well formed
+                
+            arguments_ = FindStr4End( typeTagsBegin_, end );
+            if( arguments_ == 0 ){
+                throw MalformedMessageException( "type tags were not terminated before end of message" );
+            }
+
+            ++typeTagsBegin_; // advance past initial ','
+            
+            const char *typeTag = typeTagsBegin_;
+            const char *argument = arguments_;
+                        
+            do{
+                switch( *typeTag ){
+                    case TRUE_TYPE_TAG:
+                    case FALSE_TYPE_TAG:
+                    case NIL_TYPE_TAG:
+                    case INFINITUM_TYPE_TAG:
+
+                        // zero length
+                        break;
+
+                    case INT32_TYPE_TAG:
+                    case FLOAT_TYPE_TAG:
+                    case CHAR_TYPE_TAG:
+                    case RGBA_COLOR_TYPE_TAG:
+                    case MIDI_MESSAGE_TYPE_TAG:
+
+                        if( argument == end )
+                            throw MalformedMessageException( "arguments exceed message size" );
+                        argument += 4;
+                        if( argument > end )
+                            throw MalformedMessageException( "arguments exceed message size" );
+                        break;
+
+                    case INT64_TYPE_TAG:
+                    case TIME_TAG_TYPE_TAG:
+                    case DOUBLE_TYPE_TAG:
+
+                        if( argument == end )
+                            throw MalformedMessageException( "arguments exceed message size" );
+                        argument += 8;
+                        if( argument > end )
+                            throw MalformedMessageException( "arguments exceed message size" );
+                        break;
+
+                    case STRING_TYPE_TAG: 
+                    case SYMBOL_TYPE_TAG:
+                    
+                        if( argument == end )
+                            throw MalformedMessageException( "arguments exceed message size" );
+                        argument = FindStr4End( argument, end );
+                        if( argument == 0 )
+                            throw MalformedMessageException( "unterminated string argument" );
+                        break;
+
+                    case BLOB_TYPE_TAG:
+                        {
+                            if( argument + 4 > end )
+                                MalformedMessageException( "arguments exceed message size" );
+                                
+                            uint32 blobSize = ToUInt32( argument );
+                            argument = argument + 4 + RoundUp4( (unsigned long)blobSize );
+                            if( argument > end )
+                                MalformedMessageException( "arguments exceed message size" );
+                        }
+                        break;
+                        
+                    default:
+                        throw MalformedMessageException( "unknown type tag" );
+
+                    //    not handled:
+                    //    [ Indicates the beginning of an array. The tags following are for
+                    //        data in the Array until a close brace tag is reached.
+                    //    ] Indicates the end of an array.
+                }
+
+            }while( *++typeTag != '\0' );
+            typeTagsEnd_ = typeTag;
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+
+ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )
+    : elementCount_( 0 )
+{
+    Init( packet.Contents(), packet.Size() );
+}
+
+
+ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
+    : elementCount_( 0 )
+{
+    Init( bundleElement.Contents(), bundleElement.Size() );
+}
+
+
+void ReceivedBundle::Init( const char *bundle, unsigned long size )
+{
+    if( size < 16 )
+        throw MalformedBundleException( "packet too short for bundle" );
+
+    if( (size & 0x03L) != 0 )
+        throw MalformedBundleException( "bundle size must be multiple of four" );
+
+    if( bundle[0] != '#'
+        || bundle[1] != 'b'
+        || bundle[2] != 'u'
+        || bundle[3] != 'n'
+        || bundle[4] != 'd'
+        || bundle[5] != 'l'
+        || bundle[6] != 'e'
+        || bundle[7] != '\0' )
+            throw MalformedBundleException( "bad bundle address pattern" );    
+
+    end_ = bundle + size;
+
+    timeTag_ = bundle + 8;
+
+    const char *p = timeTag_ + 8;
+        
+    while( p < end_ ){
+        if( p + 4 > end_ )
+            throw MalformedBundleException( "packet too short for elementSize" );
+
+        uint32 elementSize = ToUInt32( p );
+        if( (elementSize & 0x03L) != 0 )
+            throw MalformedBundleException( "bundle element size must be multiple of four" );
+
+        p += 4 + elementSize;
+        if( p > end_ )
+            throw MalformedBundleException( "packet too short for bundle element" );
+
+        ++elementCount_;
+    }
+
+    if( p != end_ )
+        throw MalformedBundleException( "bundle contents " );
+}
+
+
+uint64 ReceivedBundle::TimeTag() const
+{
+    return ToUInt64( timeTag_ );
+}
+
+
+} // namespace osc
+
index 07e01943d4e3abb22802e40cf93050a786888134..48364061049a51659c8982680aedb8aeabfe27f2 100644 (file)
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H\r
-#define INCLUDED_OSCRECEIVEDELEMENTS_H\r
-\r
-#include <cstddef>\r
-\r
-#include "OscTypes.h"\r
-#include "OscException.h"\r
-\r
-\r
-namespace osc{\r
-\r
-\r
-class MalformedMessageException : public Exception{\r
-public:\r
-    MalformedMessageException( const char *w="malformed message" )\r
-        : Exception( w ) {}\r
-};\r
-\r
-class MalformedBundleException : public Exception{\r
-public:\r
-    MalformedBundleException( const char *w="malformed bundle" )\r
-        : Exception( w ) {}\r
-};\r
-\r
-class WrongArgumentTypeException : public Exception{\r
-public:\r
-    WrongArgumentTypeException( const char *w="wrong argument type" )\r
-        : Exception( w ) {}\r
-};\r
-\r
-class MissingArgumentException : public Exception{\r
-public:\r
-    MissingArgumentException( const char *w="missing argument" )\r
-        : Exception( w ) {}\r
-};\r
-\r
-class ExcessArgumentException : public Exception{\r
-public:\r
-    ExcessArgumentException( const char *w="too many arguments" )\r
-        : Exception( w ) {}\r
-};\r
-\r
-\r
-class ReceivedPacket{\r
-public:\r
-    ReceivedPacket( const char *contents, int32 size )\r
-        : contents_( contents )\r
-        , size_( size ) {}\r
-\r
-    bool IsMessage() const { return !IsBundle(); }\r
-    bool IsBundle() const;\r
-\r
-    int32 Size() const { return size_; }\r
-    const char *Contents() const { return contents_; }\r
-\r
-private:\r
-    const char *contents_;\r
-    int32 size_;\r
-};\r
-\r
-\r
-class ReceivedBundleElement{\r
-public:\r
-    ReceivedBundleElement( const char *size )\r
-        : size_( size ) {}\r
-\r
-    friend class ReceivedBundleElementIterator;\r
-\r
-    bool IsMessage() const { return !IsBundle(); }\r
-    bool IsBundle() const;\r
-\r
-    int32 Size() const;\r
-    const char *Contents() const { return size_ + 4; }\r
-\r
-private:\r
-    const char *size_;\r
-};\r
-\r
-\r
-class ReceivedBundleElementIterator{\r
-public:\r
-       ReceivedBundleElementIterator( const char *sizePtr )\r
-        : value_( sizePtr ) {}\r
-\r
-       ReceivedBundleElementIterator operator++()\r
-       {\r
-        Advance();\r
-        return *this;\r
-       }\r
-\r
-    ReceivedBundleElementIterator operator++(int)\r
-    {\r
-        ReceivedBundleElementIterator old( *this );\r
-        Advance();\r
-        return old;\r
-    }\r
-\r
-       const ReceivedBundleElement& operator*() const { return value_; }\r
-\r
-    const ReceivedBundleElement* operator->() const { return &value_; }\r
-\r
-       friend bool operator==(const ReceivedBundleElementIterator& lhs,\r
-            const ReceivedBundleElementIterator& rhs );\r
-\r
-private:\r
-       ReceivedBundleElement value_;\r
-\r
-       void Advance() { value_.size_ = value_.Contents() + value_.Size(); }\r
-\r
-    bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const\r
-    {\r
-        return value_.size_ == rhs.value_.size_;\r
-    }\r
-};\r
-\r
-inline bool operator==(const ReceivedBundleElementIterator& lhs,\r
-        const ReceivedBundleElementIterator& rhs )\r
-{      \r
-       return lhs.IsEqualTo( rhs );\r
-}\r
-\r
-inline bool operator!=(const ReceivedBundleElementIterator& lhs,\r
-        const ReceivedBundleElementIterator& rhs )\r
-{\r
-       return !( lhs == rhs );\r
-}\r
-\r
-\r
-class ReceivedMessageArgument{\r
-public:\r
-       ReceivedMessageArgument( const char *typeTag, const char *argument )\r
-               : typeTag_( typeTag )\r
-               , argument_( argument ) {}\r
-\r
-    friend class ReceivedMessageArgumentIterator;\r
-    \r
-       const char TypeTag() const { return *typeTag_; }\r
-\r
-    // the unchecked methods below don't check whether the argument actually\r
-    // is of the specified type. they should only be used if you've already\r
-    // checked the type tag or the associated IsType() method.\r
-\r
-    bool IsBool() const\r
-        { return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; }\r
-    bool AsBool() const;\r
-    bool AsBoolUnchecked() const;\r
-\r
-    bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; }\r
-    bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; }\r
-\r
-    bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; }\r
-    int32 AsInt32() const;\r
-    int32 AsInt32Unchecked() const;\r
-\r
-    bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; }\r
-    float AsFloat() const;\r
-    float AsFloatUnchecked() const;\r
-\r
-    bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; }\r
-    char AsChar() const;\r
-    char AsCharUnchecked() const;\r
-\r
-    bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; }\r
-    uint32 AsRgbaColor() const;\r
-    uint32 AsRgbaColorUnchecked() const;\r
-\r
-    bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; }\r
-    uint32 AsMidiMessage() const;\r
-    uint32 AsMidiMessageUnchecked() const;\r
-\r
-    bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; }\r
-    int64 AsInt64() const;\r
-    int64 AsInt64Unchecked() const;\r
-\r
-    bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; }\r
-    uint64 AsTimeTag() const;\r
-    uint64 AsTimeTagUnchecked() const;\r
-\r
-    bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; }\r
-    double AsDouble() const;\r
-    double AsDoubleUnchecked() const;\r
-\r
-    bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; }\r
-    const char* AsString() const;\r
-    const char* AsStringUnchecked() const { return argument_; }\r
-\r
-    bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; }\r
-    const char* AsSymbol() const;\r
-    const char* AsSymbolUnchecked() const { return argument_; }\r
-\r
-    bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; }\r
-    void AsBlob( const void*& data, unsigned long& size ) const;\r
-    void AsBlobUnchecked( const void*& data, unsigned long& size ) const;\r
-    \r
-private:\r
-       const char *typeTag_;\r
-       const char *argument_;\r
-};\r
-\r
-\r
-class ReceivedMessageArgumentIterator{\r
-public:\r
-       ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments )\r
-        : value_( typeTags, arguments ) {}\r
-\r
-       ReceivedMessageArgumentIterator operator++()\r
-       {\r
-        Advance();\r
-        return *this;\r
-       }\r
-\r
-    ReceivedMessageArgumentIterator operator++(int)\r
-    {\r
-        ReceivedMessageArgumentIterator old( *this );\r
-        Advance();\r
-        return old;\r
-    }\r
-\r
-       const ReceivedMessageArgument& operator*() const { return value_; }\r
-\r
-    const ReceivedMessageArgument* operator->() const { return &value_; }\r
-\r
-       friend bool operator==(const ReceivedMessageArgumentIterator& lhs,\r
-            const ReceivedMessageArgumentIterator& rhs );\r
-\r
-private:\r
-       ReceivedMessageArgument value_;\r
-\r
-       void Advance();\r
-\r
-    bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const\r
-    {\r
-        return value_.typeTag_ == rhs.value_.typeTag_;\r
-    }\r
-};\r
-\r
-inline bool operator==(const ReceivedMessageArgumentIterator& lhs,\r
-        const ReceivedMessageArgumentIterator& rhs )\r
-{      \r
-       return lhs.IsEqualTo( rhs );\r
-}\r
-\r
-inline bool operator!=(const ReceivedMessageArgumentIterator& lhs,\r
-        const ReceivedMessageArgumentIterator& rhs )\r
-{      \r
-       return !( lhs == rhs );\r
-}\r
-\r
-\r
-class ReceivedMessageArgumentStream{\r
-    friend class ReceivedMessage;\r
-    ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin,\r
-            const ReceivedMessageArgumentIterator& end )\r
-        : p_( begin )\r
-        , end_( end ) {}\r
-\r
-    ReceivedMessageArgumentIterator p_, end_;\r
-    \r
-public:\r
-\r
-    // end of stream\r
-    bool Eos() const { return p_ == end_; }\r
-\r
-    ReceivedMessageArgumentStream& operator>>( bool& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs = (*p_++).AsBool();\r
-        return *this;\r
-    }\r
-\r
-    // not sure if it would be useful to stream Nil and Infinitum\r
-    // for now it's not possible\r
-\r
-    ReceivedMessageArgumentStream& operator>>( int32& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs = (*p_++).AsInt32();\r
-        return *this;\r
-    }     \r
-\r
-    ReceivedMessageArgumentStream& operator>>( float& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs = (*p_++).AsFloat();\r
-        return *this;\r
-    }\r
-\r
-    ReceivedMessageArgumentStream& operator>>( char& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs = (*p_++).AsChar();\r
-        return *this;\r
-    }\r
-\r
-    ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs.value = (*p_++).AsRgbaColor();\r
-        return *this;\r
-    }\r
-\r
-    ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs.value = (*p_++).AsMidiMessage();\r
-        return *this;\r
-    }\r
-\r
-    ReceivedMessageArgumentStream& operator>>( int64& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs = (*p_++).AsInt64();\r
-        return *this;\r
-    }\r
-    \r
-    ReceivedMessageArgumentStream& operator>>( TimeTag& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs.value = (*p_++).AsTimeTag();\r
-        return *this;\r
-    }\r
-\r
-    ReceivedMessageArgumentStream& operator>>( double& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs = (*p_++).AsDouble();\r
-        return *this;\r
-    }\r
-\r
-    ReceivedMessageArgumentStream& operator>>( Blob& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        (*p_++).AsBlob( rhs.data, rhs.size );\r
-        return *this;\r
-    }\r
-    \r
-    ReceivedMessageArgumentStream& operator>>( const char*& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs = (*p_++).AsString();\r
-        return *this;\r
-    }\r
-    \r
-    ReceivedMessageArgumentStream& operator>>( Symbol& rhs )\r
-    {\r
-        if( Eos() )\r
-            throw MissingArgumentException();\r
-\r
-        rhs.value = (*p_++).AsSymbol();\r
-        return *this;\r
-    }\r
-\r
-    ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs )\r
-    {\r
-        if( !Eos() )\r
-            throw ExcessArgumentException();\r
-\r
-        return *this;\r
-    }\r
-};\r
-\r
-\r
-class ReceivedMessage{\r
-    void Init( const char *bundle, unsigned long size );\r
-public:\r
-    explicit ReceivedMessage( const ReceivedPacket& packet );\r
-    explicit ReceivedMessage( const ReceivedBundleElement& bundleElement );\r
-\r
-       const char *AddressPattern() const { return addressPattern_; }\r
-\r
-       // Support for non-standad SuperCollider integer address patterns:\r
-       bool AddressPatternIsUInt32() const;\r
-       uint32 AddressPatternAsUInt32() const;\r
-\r
-       unsigned long ArgumentCount() const { return static_cast<unsigned long>(typeTagsEnd_ - typeTagsBegin_); }\r
-\r
-    const char *TypeTags() const { return typeTagsBegin_; }\r
-\r
-\r
-    typedef ReceivedMessageArgumentIterator const_iterator;\r
-    \r
-       ReceivedMessageArgumentIterator ArgumentsBegin() const\r
-    {\r
-        return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ );\r
-    }\r
-     \r
-       ReceivedMessageArgumentIterator ArgumentsEnd() const\r
-    {\r
-        return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 );\r
-    }\r
-\r
-    ReceivedMessageArgumentStream ArgumentStream() const\r
-    {\r
-        return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() );\r
-    }\r
-\r
-private:\r
-       const char *addressPattern_;\r
-       const char *typeTagsBegin_;\r
-       const char *typeTagsEnd_;\r
-    const char *arguments_;\r
-};\r
-\r
-\r
-class ReceivedBundle{\r
-    void Init( const char *message, unsigned long size );\r
-public:\r
-    explicit ReceivedBundle( const ReceivedPacket& packet );\r
-    explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );\r
-\r
-    uint64 TimeTag() const;\r
-\r
-    unsigned long ElementCount() const { return elementCount_; }\r
-\r
-    typedef ReceivedBundleElementIterator const_iterator;\r
-    \r
-       ReceivedBundleElementIterator ElementsBegin() const\r
-    {\r
-        return ReceivedBundleElementIterator( timeTag_ + 8 );\r
-    }\r
-     \r
-       ReceivedBundleElementIterator ElementsEnd() const\r
-    {\r
-        return ReceivedBundleElementIterator( end_ );\r
-    }\r
-\r
-private:\r
-    const char *timeTag_;\r
-    const char *end_;\r
-    unsigned long elementCount_;\r
-};\r
-\r
-\r
-} // namespace osc\r
-\r
-\r
-#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
+#define INCLUDED_OSCRECEIVEDELEMENTS_H
+
+#include <cstddef>
+
+#include "OscTypes.h"
+#include "OscException.h"
+
+
+namespace osc{
+
+
+class MalformedMessageException : public Exception{
+public:
+    MalformedMessageException( const char *w="malformed message" )
+        : Exception( w ) {}
+};
+
+class MalformedBundleException : public Exception{
+public:
+    MalformedBundleException( const char *w="malformed bundle" )
+        : Exception( w ) {}
+};
+
+class WrongArgumentTypeException : public Exception{
+public:
+    WrongArgumentTypeException( const char *w="wrong argument type" )
+        : Exception( w ) {}
+};
+
+class MissingArgumentException : public Exception{
+public:
+    MissingArgumentException( const char *w="missing argument" )
+        : Exception( w ) {}
+};
+
+class ExcessArgumentException : public Exception{
+public:
+    ExcessArgumentException( const char *w="too many arguments" )
+        : Exception( w ) {}
+};
+
+
+class ReceivedPacket{
+public:
+    ReceivedPacket( const char *contents, int32 size )
+        : contents_( contents )
+        , size_( size ) {}
+
+    bool IsMessage() const { return !IsBundle(); }
+    bool IsBundle() const;
+
+    int32 Size() const { return size_; }
+    const char *Contents() const { return contents_; }
+
+private:
+    const char *contents_;
+    int32 size_;
+};
+
+
+class ReceivedBundleElement{
+public:
+    ReceivedBundleElement( const char *size )
+        : size_( size ) {}
+
+    friend class ReceivedBundleElementIterator;
+
+    bool IsMessage() const { return !IsBundle(); }
+    bool IsBundle() const;
+
+    int32 Size() const;
+    const char *Contents() const { return size_ + 4; }
+
+private:
+    const char *size_;
+};
+
+
+class ReceivedBundleElementIterator{
+public:
+       ReceivedBundleElementIterator( const char *sizePtr )
+        : value_( sizePtr ) {}
+
+       ReceivedBundleElementIterator operator++()
+       {
+        Advance();
+        return *this;
+       }
+
+    ReceivedBundleElementIterator operator++(int)
+    {
+        ReceivedBundleElementIterator old( *this );
+        Advance();
+        return old;
+    }
+
+       const ReceivedBundleElement& operator*() const { return value_; }
+
+    const ReceivedBundleElement* operator->() const { return &value_; }
+
+       friend bool operator==(const ReceivedBundleElementIterator& lhs,
+            const ReceivedBundleElementIterator& rhs );
+
+private:
+       ReceivedBundleElement value_;
+
+       void Advance() { value_.size_ = value_.Contents() + value_.Size(); }
+
+    bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const
+    {
+        return value_.size_ == rhs.value_.size_;
+    }
+};
+
+inline bool operator==(const ReceivedBundleElementIterator& lhs,
+        const ReceivedBundleElementIterator& rhs )
+{      
+       return lhs.IsEqualTo( rhs );
+}
+
+inline bool operator!=(const ReceivedBundleElementIterator& lhs,
+        const ReceivedBundleElementIterator& rhs )
+{
+       return !( lhs == rhs );
+}
+
+
+class ReceivedMessageArgument{
+public:
+       ReceivedMessageArgument( const char *typeTag, const char *argument )
+               : typeTag_( typeTag )
+               , argument_( argument ) {}
+
+    friend class ReceivedMessageArgumentIterator;
+    
+       const char TypeTag() const { return *typeTag_; }
+
+    // the unchecked methods below don't check whether the argument actually
+    // is of the specified type. they should only be used if you've already
+    // checked the type tag or the associated IsType() method.
+
+    bool IsBool() const
+        { return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; }
+    bool AsBool() const;
+    bool AsBoolUnchecked() const;
+
+    bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; }
+    bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; }
+
+    bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; }
+    int32 AsInt32() const;
+    int32 AsInt32Unchecked() const;
+
+    bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; }
+    float AsFloat() const;
+    float AsFloatUnchecked() const;
+
+    bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; }
+    char AsChar() const;
+    char AsCharUnchecked() const;
+
+    bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; }
+    uint32 AsRgbaColor() const;
+    uint32 AsRgbaColorUnchecked() const;
+
+    bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; }
+    uint32 AsMidiMessage() const;
+    uint32 AsMidiMessageUnchecked() const;
+
+    bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; }
+    int64 AsInt64() const;
+    int64 AsInt64Unchecked() const;
+
+    bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; }
+    uint64 AsTimeTag() const;
+    uint64 AsTimeTagUnchecked() const;
+
+    bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; }
+    double AsDouble() const;
+    double AsDoubleUnchecked() const;
+
+    bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; }
+    const char* AsString() const;
+    const char* AsStringUnchecked() const { return argument_; }
+
+    bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; }
+    const char* AsSymbol() const;
+    const char* AsSymbolUnchecked() const { return argument_; }
+
+    bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; }
+    void AsBlob( const void*& data, unsigned long& size ) const;
+    void AsBlobUnchecked( const void*& data, unsigned long& size ) const;
+    
+private:
+       const char *typeTag_;
+       const char *argument_;
+};
+
+
+class ReceivedMessageArgumentIterator{
+public:
+       ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments )
+        : value_( typeTags, arguments ) {}
+
+       ReceivedMessageArgumentIterator operator++()
+       {
+        Advance();
+        return *this;
+       }
+
+    ReceivedMessageArgumentIterator operator++(int)
+    {
+        ReceivedMessageArgumentIterator old( *this );
+        Advance();
+        return old;
+    }
+
+       const ReceivedMessageArgument& operator*() const { return value_; }
+
+    const ReceivedMessageArgument* operator->() const { return &value_; }
+
+       friend bool operator==(const ReceivedMessageArgumentIterator& lhs,
+            const ReceivedMessageArgumentIterator& rhs );
+
+private:
+       ReceivedMessageArgument value_;
+
+       void Advance();
+
+    bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const
+    {
+        return value_.typeTag_ == rhs.value_.typeTag_;
+    }
+};
+
+inline bool operator==(const ReceivedMessageArgumentIterator& lhs,
+        const ReceivedMessageArgumentIterator& rhs )
+{      
+       return lhs.IsEqualTo( rhs );
+}
+
+inline bool operator!=(const ReceivedMessageArgumentIterator& lhs,
+        const ReceivedMessageArgumentIterator& rhs )
+{      
+       return !( lhs == rhs );
+}
+
+
+class ReceivedMessageArgumentStream{
+    friend class ReceivedMessage;
+    ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin,
+            const ReceivedMessageArgumentIterator& end )
+        : p_( begin )
+        , end_( end ) {}
+
+    ReceivedMessageArgumentIterator p_, end_;
+    
+public:
+
+    // end of stream
+    bool Eos() const { return p_ == end_; }
+
+    ReceivedMessageArgumentStream& operator>>( bool& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs = (*p_++).AsBool();
+        return *this;
+    }
+
+    // not sure if it would be useful to stream Nil and Infinitum
+    // for now it's not possible
+
+    ReceivedMessageArgumentStream& operator>>( int32& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs = (*p_++).AsInt32();
+        return *this;
+    }     
+
+    ReceivedMessageArgumentStream& operator>>( float& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs = (*p_++).AsFloat();
+        return *this;
+    }
+
+    ReceivedMessageArgumentStream& operator>>( char& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs = (*p_++).AsChar();
+        return *this;
+    }
+
+    ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs.value = (*p_++).AsRgbaColor();
+        return *this;
+    }
+
+    ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs.value = (*p_++).AsMidiMessage();
+        return *this;
+    }
+
+    ReceivedMessageArgumentStream& operator>>( int64& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs = (*p_++).AsInt64();
+        return *this;
+    }
+    
+    ReceivedMessageArgumentStream& operator>>( TimeTag& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs.value = (*p_++).AsTimeTag();
+        return *this;
+    }
+
+    ReceivedMessageArgumentStream& operator>>( double& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs = (*p_++).AsDouble();
+        return *this;
+    }
+
+    ReceivedMessageArgumentStream& operator>>( Blob& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        (*p_++).AsBlob( rhs.data, rhs.size );
+        return *this;
+    }
+    
+    ReceivedMessageArgumentStream& operator>>( const char*& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs = (*p_++).AsString();
+        return *this;
+    }
+    
+    ReceivedMessageArgumentStream& operator>>( Symbol& rhs )
+    {
+        if( Eos() )
+            throw MissingArgumentException();
+
+        rhs.value = (*p_++).AsSymbol();
+        return *this;
+    }
+
+    ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs )
+    {
+        if( !Eos() )
+            throw ExcessArgumentException();
+
+        return *this;
+    }
+};
+
+
+class ReceivedMessage{
+    void Init( const char *bundle, unsigned long size );
+public:
+    explicit ReceivedMessage( const ReceivedPacket& packet );
+    explicit ReceivedMessage( const ReceivedBundleElement& bundleElement );
+
+       const char *AddressPattern() const { return addressPattern_; }
+
+       // Support for non-standad SuperCollider integer address patterns:
+       bool AddressPatternIsUInt32() const;
+       uint32 AddressPatternAsUInt32() const;
+
+       unsigned long ArgumentCount() const { return static_cast<unsigned long>(typeTagsEnd_ - typeTagsBegin_); }
+
+    const char *TypeTags() const { return typeTagsBegin_; }
+
+
+    typedef ReceivedMessageArgumentIterator const_iterator;
+    
+       ReceivedMessageArgumentIterator ArgumentsBegin() const
+    {
+        return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ );
+    }
+     
+       ReceivedMessageArgumentIterator ArgumentsEnd() const
+    {
+        return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 );
+    }
+
+    ReceivedMessageArgumentStream ArgumentStream() const
+    {
+        return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() );
+    }
+
+private:
+       const char *addressPattern_;
+       const char *typeTagsBegin_;
+       const char *typeTagsEnd_;
+    const char *arguments_;
+};
+
+
+class ReceivedBundle{
+    void Init( const char *message, unsigned long size );
+public:
+    explicit ReceivedBundle( const ReceivedPacket& packet );
+    explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );
+
+    uint64 TimeTag() const;
+
+    unsigned long ElementCount() const { return elementCount_; }
+
+    typedef ReceivedBundleElementIterator const_iterator;
+    
+       ReceivedBundleElementIterator ElementsBegin() const
+    {
+        return ReceivedBundleElementIterator( timeTag_ + 8 );
+    }
+     
+       ReceivedBundleElementIterator ElementsEnd() const
+    {
+        return ReceivedBundleElementIterator( end_ );
+    }
+
+private:
+    const char *timeTag_;
+    const char *end_;
+    unsigned long elementCount_;
+};
+
+
+} // namespace osc
+
+
+#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
index 889ab43299700bd45eb88c5417f17d955f808e09..cf8f6986323e1114254c50f212a08b719c87a978 100644 (file)
@@ -1,40 +1,40 @@
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#include "OscTypes.h"\r
-\r
-namespace osc{\r
-\r
-BundleInitiator BeginBundleImmediate(1);\r
-BundleTerminator EndBundle;\r
-MessageTerminator EndMessage;\r
-NilType Nil;\r
-InfinitumType Infinitum;\r
-\r
-} // namespace osc\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#include "OscTypes.h"
+
+namespace osc{
+
+BundleInitiator BeginBundleImmediate(1);
+BundleTerminator EndBundle;
+MessageTerminator EndMessage;
+NilType Nil;
+InfinitumType Infinitum;
+
+} // namespace osc
index a3712bc4ed3448e4d71dca46cd7c5f9fa74814cb..b31911143f43ef505fdba7636ba6e96a60e3eb18 100644 (file)
-/*\r
-       oscpack -- Open Sound Control packet manipulation library\r
-       http://www.audiomulch.com/~rossb/oscpack\r
-\r
-       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>\r
-\r
-       Permission is hereby granted, free of charge, to any person obtaining\r
-       a copy of this software and associated documentation files\r
-       (the "Software"), to deal in the Software without restriction,\r
-       including without limitation the rights to use, copy, modify, merge,\r
-       publish, distribute, sublicense, and/or sell copies of the Software,\r
-       and to permit persons to whom the Software is furnished to do so,\r
-       subject to the following conditions:\r
-\r
-       The above copyright notice and this permission notice shall be\r
-       included in all copies or substantial portions of the Software.\r
-\r
-       Any person wishing to distribute modifications to the Software is\r
-       requested to send the modifications to the original developer so that\r
-       they can be incorporated into the canonical version.\r
-\r
-       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
-       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
-       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
-       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
-       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
-       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
-       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
-*/\r
-#ifndef INCLUDED_OSCTYPES_H\r
-#define INCLUDED_OSCTYPES_H\r
-\r
-\r
-namespace osc{\r
-\r
-// basic types\r
-\r
-#if defined(__BORLANDC__) || defined(_MSC_VER)\r
-\r
-typedef __int64 int64;\r
-typedef unsigned __int64 uint64;\r
-\r
-#elif defined(__x86_64__) || defined(_M_X64)\r
-\r
-typedef long int64;\r
-typedef unsigned long uint64;\r
-\r
-#else\r
-\r
-typedef long long int64;\r
-typedef unsigned long long uint64;\r
-\r
-#endif\r
-\r
-\r
-\r
-#if defined(__x86_64__) || defined(_M_X64)\r
-\r
-typedef signed int int32;\r
-typedef unsigned int uint32;\r
-\r
-#else\r
-\r
-typedef signed long int32;\r
-typedef unsigned long uint32;\r
-\r
-#endif\r
-\r
-\r
-\r
-enum TypeTagValues {\r
-    TRUE_TYPE_TAG = 'T',\r
-    FALSE_TYPE_TAG = 'F',\r
-    NIL_TYPE_TAG = 'N',\r
-    INFINITUM_TYPE_TAG = 'I',\r
-    INT32_TYPE_TAG = 'i',\r
-    FLOAT_TYPE_TAG = 'f',\r
-    CHAR_TYPE_TAG = 'c',\r
-    RGBA_COLOR_TYPE_TAG = 'r',\r
-    MIDI_MESSAGE_TYPE_TAG = 'm',\r
-    INT64_TYPE_TAG = 'h',\r
-    TIME_TAG_TYPE_TAG = 't',\r
-    DOUBLE_TYPE_TAG = 'd',\r
-    STRING_TYPE_TAG = 's',\r
-    SYMBOL_TYPE_TAG = 'S',\r
-    BLOB_TYPE_TAG = 'b'\r
-};\r
-\r
-\r
-\r
-// i/o manipulators used for streaming interfaces\r
-\r
-struct BundleInitiator{\r
-    explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {}\r
-    uint64 timeTag;\r
-};\r
-\r
-extern BundleInitiator BeginBundleImmediate;\r
-\r
-inline BundleInitiator BeginBundle( uint64 timeTag=1 )\r
-{\r
-    return BundleInitiator(timeTag);\r
-}\r
-\r
-\r
-struct BundleTerminator{\r
-};\r
-\r
-extern BundleTerminator EndBundle;\r
-\r
-struct BeginMessage{\r
-    explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {}\r
-    const char *addressPattern;\r
-};\r
-\r
-struct MessageTerminator{\r
-};\r
-\r
-extern MessageTerminator EndMessage;\r
-\r
-\r
-// osc specific types. they are defined as structs so they can be used\r
-// as separately identifiable types with the streaming operators.\r
-\r
-struct NilType{\r
-};\r
-\r
-extern NilType Nil;\r
-\r
-\r
-struct InfinitumType{\r
-};\r
-\r
-extern InfinitumType Infinitum;\r
-\r
-struct RgbaColor{\r
-    RgbaColor() {}\r
-    explicit RgbaColor( uint32 value_ ) : value( value_ ) {}\r
-    uint32 value;\r
-\r
-    operator uint32() const { return value; }\r
-};\r
-\r
-\r
-struct MidiMessage{\r
-    MidiMessage() {}\r
-    explicit MidiMessage( uint32 value_ ) : value( value_ ) {}\r
-    uint32 value;\r
-\r
-    operator uint32() const { return value; }\r
-};\r
-\r
-\r
-struct TimeTag{\r
-    TimeTag() {}\r
-    explicit TimeTag( uint64 value_ ) : value( value_ ) {}\r
-    uint64 value;\r
-\r
-    operator uint64() const { return value; }\r
-};\r
-\r
-\r
-struct Symbol{\r
-    Symbol() {}\r
-    explicit Symbol( const char* value_ ) : value( value_ ) {}\r
-    const char* value;\r
-\r
-    operator const char *() const { return value; }\r
-};\r
-\r
-\r
-struct Blob{\r
-    Blob() {}\r
-    explicit Blob( const void* data_, unsigned long size_ )\r
-            : data( data_ ), size( size_ ) {}\r
-    const void* data;\r
-    unsigned long size;\r
-};\r
-\r
-} // namespace osc\r
-\r
-\r
-#endif /* INCLUDED_OSCTYPES_H */\r
+/*
+       oscpack -- Open Sound Control packet manipulation library
+       http://www.audiomulch.com/~rossb/oscpack
+
+       Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+       Permission is hereby granted, free of charge, to any person obtaining
+       a copy of this software and associated documentation files
+       (the "Software"), to deal in the Software without restriction,
+       including without limitation the rights to use, copy, modify, merge,
+       publish, distribute, sublicense, and/or sell copies of the Software,
+       and to permit persons to whom the Software is furnished to do so,
+       subject to the following conditions:
+
+       The above copyright notice and this permission notice shall be
+       included in all copies or substantial portions of the Software.
+
+       Any person wishing to distribute modifications to the Software is
+       requested to send the modifications to the original developer so that
+       they can be incorporated into the canonical version.
+
+       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+       IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+       ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+       CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+       WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSCTYPES_H
+#define INCLUDED_OSCTYPES_H
+
+
+namespace osc{
+
+// basic types
+
+#if defined(__BORLANDC__) || defined(_MSC_VER)
+
+typedef __int64 int64;
+typedef unsigned __int64 uint64;
+
+#elif defined(__x86_64__) || defined(_M_X64)
+
+typedef long int64;
+typedef unsigned long uint64;
+
+#else
+
+typedef long long int64;
+typedef unsigned long long uint64;
+
+#endif
+
+
+
+#if defined(__x86_64__) || defined(_M_X64)
+
+typedef signed int int32;
+typedef unsigned int uint32;
+
+#else
+
+typedef signed long int32;
+typedef unsigned long uint32;
+
+#endif
+
+
+
+enum TypeTagValues {
+    TRUE_TYPE_TAG = 'T',
+    FALSE_TYPE_TAG = 'F',
+    NIL_TYPE_TAG = 'N',
+    INFINITUM_TYPE_TAG = 'I',
+    INT32_TYPE_TAG = 'i',
+    FLOAT_TYPE_TAG = 'f',
+    CHAR_TYPE_TAG = 'c',
+    RGBA_COLOR_TYPE_TAG = 'r',
+    MIDI_MESSAGE_TYPE_TAG = 'm',
+    INT64_TYPE_TAG = 'h',
+    TIME_TAG_TYPE_TAG = 't',
+    DOUBLE_TYPE_TAG = 'd',
+    STRING_TYPE_TAG = 's',
+    SYMBOL_TYPE_TAG = 'S',
+    BLOB_TYPE_TAG = 'b'
+};
+
+
+
+// i/o manipulators used for streaming interfaces
+
+struct BundleInitiator{
+    explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {}
+    uint64 timeTag;
+};
+
+extern BundleInitiator BeginBundleImmediate;
+
+inline BundleInitiator BeginBundle( uint64 timeTag=1 )
+{
+    return BundleInitiator(timeTag);
+}
+
+
+struct BundleTerminator{
+};
+
+extern BundleTerminator EndBundle;
+
+struct BeginMessage{
+    explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {}
+    const char *addressPattern;
+};
+
+struct MessageTerminator{
+};
+
+extern MessageTerminator EndMessage;
+
+
+// osc specific types. they are defined as structs so they can be used
+// as separately identifiable types with the streaming operators.
+
+struct NilType{
+};
+
+extern NilType Nil;
+
+
+struct InfinitumType{
+};
+
+extern InfinitumType Infinitum;
+
+struct RgbaColor{
+    RgbaColor() {}
+    explicit RgbaColor( uint32 value_ ) : value( value_ ) {}
+    uint32 value;
+
+    operator uint32() const { return value; }
+};
+
+
+struct MidiMessage{
+    MidiMessage() {}
+    explicit MidiMessage( uint32 value_ ) : value( value_ ) {}
+    uint32 value;
+
+    operator uint32() const { return value; }
+};
+
+
+struct TimeTag{
+    TimeTag() {}
+    explicit TimeTag( uint64 value_ ) : value( value_ ) {}
+    uint64 value;
+
+    operator uint64() const { return value; }
+};
+
+
+struct Symbol{
+    Symbol() {}
+    explicit Symbol( const char* value_ ) : value( value_ ) {}
+    const char* value;
+
+    operator const char *() const { return value; }
+};
+
+
+struct Blob{
+    Blob() {}
+    explicit Blob( const void* data_, unsigned long size_ )
+            : data( data_ ), size( size_ ) {}
+    const void* data;
+    unsigned long size;
+};
+
+} // namespace osc
+
+
+#endif /* INCLUDED_OSCTYPES_H */
index 4204a482820662ae357e3356b692f9f4bd1bbc3a..9c72fd0ba8b8a973305ce6fa73d8a8a376170526 100644 (file)
-#include "..\stdafx.h"\r
-\r
-#include "server.h"\r
-\r
-#include "oscpack/oscOutboundPacketStream.h"\r
-\r
-#include <algorithm>\r
-#include <array>\r
-#include <string>\r
-#include <set>\r
-#include <regex>\r
-#include <vector>\r
-\r
-#include <boost/optional.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/asio.hpp>\r
-#include <boost/thread.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/algorithm/string/iter_find.hpp>\r
-#include <boost/algorithm/string/finder.hpp>\r
-#include <boost/algorithm/string/predicate.hpp>\r
-#include <boost/thread/mutex.hpp>\r
-\r
-using namespace boost::asio::ip;\r
-\r
-namespace caspar { namespace protocol { namespace osc {\r
-       \r
-template<typename T>\r
-struct param_visitor : public boost::static_visitor<void>\r
-{\r
-       T& o;\r
-\r
-       param_visitor(T& o)\r
-               : o(o)\r
-       {\r
-       }               \r
-               \r
-       void operator()(const bool value)                                       {o << value;}\r
-       void operator()(const int32_t value)                            {o << value;}\r
-       void operator()(const uint32_t value)                           {o << value;}\r
-       void operator()(const int64_t value)                            {o << value;}\r
-       void operator()(const uint64_t value)                           {o << value;}\r
-       void operator()(const float value)                                      {o << value;}\r
-       void operator()(const double value)                                     {o << static_cast<float>(value);}\r
-       void operator()(const std::string& value)                       {o << value.c_str();}\r
-       void operator()(const std::wstring& value)                      {o << u8(value).c_str();}\r
-       void operator()(const std::vector<int8_t>& value)       {o << ::osc::Blob(value.data(), static_cast<unsigned long>(value.size()));}\r
-       void operator()(const monitor::duration& value)\r
-       {\r
-               o << boost::chrono::duration_cast<boost::chrono::duration<double, boost::ratio<1, 1>>>(value).count();\r
-       }\r
-};\r
-\r
-std::vector<char> write_osc_event(const monitor::event& e)\r
-{\r
-       std::array<char, 4096> buffer;\r
-       ::osc::OutboundPacketStream o(buffer.data(), static_cast<unsigned long>(buffer.size()));\r
-\r
-       o       << ::osc::BeginMessage(e.path().str().c_str());\r
-                               \r
-       param_visitor<decltype(o)> pd_visitor(o);\r
-       BOOST_FOREACH(auto param, e.params())\r
-               boost::apply_visitor(pd_visitor, param);\r
-                               \r
-       o       << ::osc::EndMessage;\r
-               \r
-       return std::vector<char>(o.Data(), o.Data() + o.Size());\r
-}\r
-\r
-class connection;\r
-\r
-typedef std::set<spl::shared_ptr<connection>> connection_set;\r
-\r
-class connection : public spl::enable_shared_from_this<connection>\r
-{    \r
-    const spl::shared_ptr<tcp::socket>         socket_; \r
-       const spl::shared_ptr<connection_set>   connection_set_;\r
-\r
-       boost::optional<std::regex>                             regex_;\r
-       std::array<char, 32768>                                 data_;\r
-       std::string                                                             input_;\r
-\r
-public:\r
-    static spl::shared_ptr<connection> create(spl::shared_ptr<tcp::socket> socket, spl::shared_ptr<connection_set> connection_set)\r
-       {\r
-               auto con = spl::shared_ptr<connection>(new connection(std::move(socket), std::move(connection_set)));\r
-               con->read_some();\r
-               return con;\r
-    }\r
-       \r
-       void stop()\r
-       {\r
-               connection_set_->erase(shared_from_this());\r
-               try\r
-               {\r
-                       socket_->close();\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-               CASPAR_LOG(info) << print() << L" Disconnected.";\r
-       }\r
-               \r
-       std::wstring print() const\r
-       {\r
-               return L"osc[" + (socket_->is_open() ? u16(socket_->local_endpoint().address().to_string() + ":" + boost::lexical_cast<std::string>(socket_->local_endpoint().port())) : L"no-address") + L"]";\r
-       }\r
-               \r
-       void on_next(const monitor::event& e)\r
-       {       \r
-               if(regex_ && std::regex_search(e.path().str(), *regex_))\r
-                       return; \r
-\r
-               auto data_ptr = spl::make_shared<std::vector<char>>(write_osc_event(e));\r
-               int32_t size = static_cast<int32_t>(data_ptr->size());\r
-               char* size_ptr = reinterpret_cast<char*>(&size);\r
-\r
-               data_ptr->insert(data_ptr->begin(), size_ptr, size_ptr + sizeof(int32_t));\r
-               socket_->async_write_some(boost::asio::buffer(*data_ptr), std::bind(&connection::handle_write, shared_from_this(), data_ptr, std::placeholders::_1, std::placeholders::_2));    \r
-       }\r
-       \r
-private:\r
-    connection(spl::shared_ptr<tcp::socket> socket, spl::shared_ptr<connection_set> connection_set) \r
-               : socket_(std::move(socket))\r
-               , connection_set_(std::move(connection_set))\r
-       {\r
-               CASPAR_LOG(info) << print() << L" Connected.";\r
-    }\r
-                                       \r
-    void handle_read(const boost::system::error_code& error, size_t bytes_transferred) \r
-       {               \r
-               if(!error)\r
-               {\r
-                       try\r
-                       {\r
-                               on_read(std::string(data_.begin(), data_.begin() + bytes_transferred));\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }\r
-                       \r
-                       read_some();\r
-               }  \r
-               else if (error != boost::asio::error::operation_aborted)                \r
-                       stop();         \r
-    }\r
-\r
-    void handle_write(const spl::shared_ptr<std::vector<char>>& data, const boost::system::error_code& error, size_t bytes_transferred)\r
-       {\r
-               if(!error)                      \r
-               {\r
-               }\r
-               else if (error != boost::asio::error::operation_aborted)\r
-                       stop();         \r
-    }\r
-\r
-       void read_some()\r
-       {\r
-               socket_->async_read_some(boost::asio::buffer(data_.data(), data_.size()), std::bind(&connection::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2));\r
-       }\r
-               \r
-       void on_read(std::string str)\r
-       {\r
-               input_ += str;\r
-\r
-               std::vector<std::string> split;\r
-               boost::iter_split(split, input_, boost::algorithm::first_finder("\r\n"));\r
-               \r
-               input_ = split.back();\r
-               split.pop_back();       \r
-               \r
-               if(split.empty())\r
-                       return;\r
-\r
-               if(split.back() == ".*")\r
-                       regex_.reset();\r
-               else\r
-                       regex_ = std::regex(split.back());\r
-       }\r
-};\r
-\r
-class tcp_observer : public reactive::observer<monitor::event>\r
-{\r
-       boost::asio::io_service                 service_;\r
-       tcp::acceptor                                   acceptor_;\r
-       spl::shared_ptr<connection_set> connection_set_;\r
-       boost::thread                                   thread_;\r
-       \r
-public:\r
-       tcp_observer(unsigned short port)\r
-               : acceptor_(service_, tcp::endpoint(tcp::v4(), port))\r
-               , thread_(std::bind(&boost::asio::io_service::run, &service_))\r
-       {\r
-               start_accept(); \r
-       }\r
-\r
-       ~tcp_observer()\r
-       {               \r
-               try\r
-               {\r
-                       acceptor_.close();\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-\r
-               service_.post([=]\r
-               {\r
-                       auto connections = *connection_set_;\r
-                       BOOST_FOREACH(auto& connection, connections)\r
-                               connection->stop();                             \r
-               });\r
-\r
-               thread_.join();\r
-       }\r
-       \r
-       void on_next(const monitor::event& e) override\r
-       {\r
-               service_.post([=]\r
-               {                       \r
-                       BOOST_FOREACH(auto& connection, *connection_set_)\r
-                               connection->on_next(e);\r
-               });             \r
-       }       \r
-private:               \r
-    void start_accept() \r
-       {\r
-               auto socket = spl::make_shared<tcp::socket>(service_);\r
-               acceptor_.async_accept(*socket, std::bind(&tcp_observer::handle_accept, this, socket, std::placeholders::_1));\r
-    }\r
-\r
-       void handle_accept(const spl::shared_ptr<tcp::socket>& socket, const boost::system::error_code& error) \r
-       {\r
-               if (!acceptor_.is_open())\r
-                       return;\r
-\r
-        if (!error)            \r
-                       connection_set_->insert(connection::create(socket, connection_set_));\r
-        \r
-               start_accept();\r
-    }\r
-};\r
-\r
-server::server(unsigned short port) \r
-       : impl_(new tcp_observer(port)){}\r
-void server::on_next(const monitor::event& e){impl_->on_next(e);}\r
-\r
+#include "..\stdafx.h"
+
+#include "server.h"
+
+#include "oscpack/oscOutboundPacketStream.h"
+
+#include <algorithm>
+#include <array>
+#include <string>
+#include <set>
+#include <regex>
+#include <vector>
+
+#include <boost/optional.hpp>
+#include <boost/foreach.hpp>
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string/iter_find.hpp>
+#include <boost/algorithm/string/finder.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/thread/mutex.hpp>
+
+using namespace boost::asio::ip;
+
+namespace caspar { namespace protocol { namespace osc {
+       
+template<typename T>
+struct param_visitor : public boost::static_visitor<void>
+{
+       T& o;
+
+       param_visitor(T& o)
+               : o(o)
+       {
+       }               
+               
+       void operator()(const bool value)                                       {o << value;}
+       void operator()(const int32_t value)                            {o << value;}
+       void operator()(const uint32_t value)                           {o << value;}
+       void operator()(const int64_t value)                            {o << value;}
+       void operator()(const uint64_t value)                           {o << value;}
+       void operator()(const float value)                                      {o << value;}
+       void operator()(const double value)                                     {o << static_cast<float>(value);}
+       void operator()(const std::string& value)                       {o << value.c_str();}
+       void operator()(const std::wstring& value)                      {o << u8(value).c_str();}
+       void operator()(const std::vector<int8_t>& value)       {o << ::osc::Blob(value.data(), static_cast<unsigned long>(value.size()));}
+       void operator()(const monitor::duration& value)
+       {
+               o << boost::chrono::duration_cast<boost::chrono::duration<double, boost::ratio<1, 1>>>(value).count();
+       }
+};
+
+std::vector<char> write_osc_event(const monitor::event& e)
+{
+       std::array<char, 4096> buffer;
+       ::osc::OutboundPacketStream o(buffer.data(), static_cast<unsigned long>(buffer.size()));
+
+       o       << ::osc::BeginMessage(e.path().str().c_str());
+                               
+       param_visitor<decltype(o)> pd_visitor(o);
+       BOOST_FOREACH(auto param, e.params())
+               boost::apply_visitor(pd_visitor, param);
+                               
+       o       << ::osc::EndMessage;
+               
+       return std::vector<char>(o.Data(), o.Data() + o.Size());
+}
+
+class connection;
+
+typedef std::set<spl::shared_ptr<connection>> connection_set;
+
+class connection : public spl::enable_shared_from_this<connection>
+{    
+    const spl::shared_ptr<tcp::socket>         socket_; 
+       const spl::shared_ptr<connection_set>   connection_set_;
+
+       boost::optional<std::regex>                             regex_;
+       std::array<char, 32768>                                 data_;
+       std::string                                                             input_;
+
+public:
+    static spl::shared_ptr<connection> create(spl::shared_ptr<tcp::socket> socket, spl::shared_ptr<connection_set> connection_set)
+       {
+               auto con = spl::shared_ptr<connection>(new connection(std::move(socket), std::move(connection_set)));
+               con->read_some();
+               return con;
+    }
+       
+       void stop()
+       {
+               connection_set_->erase(shared_from_this());
+               try
+               {
+                       socket_->close();
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+               CASPAR_LOG(info) << print() << L" Disconnected.";
+       }
+               
+       std::wstring print() const
+       {
+               return L"osc[" + (socket_->is_open() ? u16(socket_->local_endpoint().address().to_string() + ":" + boost::lexical_cast<std::string>(socket_->local_endpoint().port())) : L"no-address") + L"]";
+       }
+               
+       void on_next(const monitor::event& e)
+       {       
+               if(regex_ && std::regex_search(e.path().str(), *regex_))
+                       return; 
+
+               auto data_ptr = spl::make_shared<std::vector<char>>(write_osc_event(e));
+               int32_t size = static_cast<int32_t>(data_ptr->size());
+               char* size_ptr = reinterpret_cast<char*>(&size);
+
+               data_ptr->insert(data_ptr->begin(), size_ptr, size_ptr + sizeof(int32_t));
+               socket_->async_write_some(boost::asio::buffer(*data_ptr), std::bind(&connection::handle_write, shared_from_this(), data_ptr, std::placeholders::_1, std::placeholders::_2));    
+       }
+       
+private:
+    connection(spl::shared_ptr<tcp::socket> socket, spl::shared_ptr<connection_set> connection_set) 
+               : socket_(std::move(socket))
+               , connection_set_(std::move(connection_set))
+       {
+               CASPAR_LOG(info) << print() << L" Connected.";
+    }
+                                       
+    void handle_read(const boost::system::error_code& error, size_t bytes_transferred) 
+       {               
+               if(!error)
+               {
+                       try
+                       {
+                               on_read(std::string(data_.begin(), data_.begin() + bytes_transferred));
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }
+                       
+                       read_some();
+               }  
+               else if (error != boost::asio::error::operation_aborted)                
+                       stop();         
+    }
+
+    void handle_write(const spl::shared_ptr<std::vector<char>>& data, const boost::system::error_code& error, size_t bytes_transferred)
+       {
+               if(!error)                      
+               {
+               }
+               else if (error != boost::asio::error::operation_aborted)
+                       stop();         
+    }
+
+       void read_some()
+       {
+               socket_->async_read_some(boost::asio::buffer(data_.data(), data_.size()), std::bind(&connection::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
+       }
+               
+       void on_read(std::string str)
+       {
+               input_ += str;
+
+               std::vector<std::string> split;
+               boost::iter_split(split, input_, boost::algorithm::first_finder("\r\n"));
+               
+               input_ = split.back();
+               split.pop_back();       
+               
+               if(split.empty())
+                       return;
+
+               if(split.back() == ".*")
+                       regex_.reset();
+               else
+                       regex_ = std::regex(split.back());
+       }
+};
+
+class tcp_observer : public reactive::observer<monitor::event>
+{
+       boost::asio::io_service                 service_;
+       tcp::acceptor                                   acceptor_;
+       spl::shared_ptr<connection_set> connection_set_;
+       boost::thread                                   thread_;
+       
+public:
+       tcp_observer(unsigned short port)
+               : acceptor_(service_, tcp::endpoint(tcp::v4(), port))
+               , thread_(std::bind(&boost::asio::io_service::run, &service_))
+       {
+               start_accept(); 
+       }
+
+       ~tcp_observer()
+       {               
+               try
+               {
+                       acceptor_.close();
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+
+               service_.post([=]
+               {
+                       auto connections = *connection_set_;
+                       BOOST_FOREACH(auto& connection, connections)
+                               connection->stop();                             
+               });
+
+               thread_.join();
+       }
+       
+       void on_next(const monitor::event& e) override
+       {
+               service_.post([=]
+               {                       
+                       BOOST_FOREACH(auto& connection, *connection_set_)
+                               connection->on_next(e);
+               });             
+       }       
+private:               
+    void start_accept() 
+       {
+               auto socket = spl::make_shared<tcp::socket>(service_);
+               acceptor_.async_accept(*socket, std::bind(&tcp_observer::handle_accept, this, socket, std::placeholders::_1));
+    }
+
+       void handle_accept(const spl::shared_ptr<tcp::socket>& socket, const boost::system::error_code& error) 
+       {
+               if (!acceptor_.is_open())
+                       return;
+
+        if (!error)            
+                       connection_set_->insert(connection::create(socket, connection_set_));
+        
+               start_accept();
+    }
+};
+
+server::server(unsigned short port) 
+       : impl_(new tcp_observer(port)){}
+void server::on_next(const monitor::event& e){impl_->on_next(e);}
+
 }}}
\ No newline at end of file
index 59b4d5e3e55fbb995e731f3f997be533d1f3f54c..eec198b217c8230901b6a8a0a9a8a3020d3f7063 100644 (file)
@@ -1,21 +1,21 @@
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <core/monitor/monitor.h>\r
-\r
-#include <functional>\r
-\r
-namespace caspar { namespace protocol { namespace osc {\r
-\r
-class server : public reactive::observer<monitor::event>\r
-{\r
-public:        \r
-       server(unsigned short port);\r
-       \r
-       void on_next(const monitor::event& e) override;\r
-private:\r
-       spl::shared_ptr<observer<monitor::event>> impl_;\r
-};\r
-\r
+#pragma once
+
+#include <common/memory.h>
+
+#include <core/monitor/monitor.h>
+
+#include <functional>
+
+namespace caspar { namespace protocol { namespace osc {
+
+class server : public reactive::observer<monitor::event>
+{
+public:        
+       server(unsigned short port);
+       
+       void on_next(const monitor::event& e) override;
+private:
+       spl::shared_ptr<observer<monitor::event>> impl_;
+};
+
 }}}
\ No newline at end of file
index 81ac747c0998a863d7d3a016ed951aa30ea14ae9..97c5fcfd4ecac5baa63aba85491bb5c789eba54c 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "..\stdafx.h"\r
-\r
-#include "AsyncEventServer.h"\r
-\r
-#include "ProtocolStrategy.h"\r
-\r
-#include <algorithm>\r
-#include <array>\r
-#include <string>\r
-#include <set>\r
-#include <vector>\r
-\r
-#include <boost/asio.hpp>\r
-#include <boost/thread.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/locale.hpp>\r
-#include <boost/algorithm/string/split.hpp>\r
-\r
-using boost::asio::ip::tcp;\r
-\r
-namespace caspar { namespace IO {\r
-       \r
-class connection;\r
-\r
-typedef std::set<spl::shared_ptr<connection>> connection_set;\r
-\r
-class connection : public spl::enable_shared_from_this<connection>, public ClientInfo\r
-{    \r
-    const spl::shared_ptr<tcp::socket>                 socket_; \r
-       const spl::shared_ptr<connection_set>           connection_set_;\r
-       const std::wstring                                                      name_;\r
-       const spl::shared_ptr<IProtocolStrategy>        protocol_;\r
-\r
-       std::array<char, 32768>                                         data_;\r
-       std::string                                                                     input_;\r
-\r
-public:\r
-    static spl::shared_ptr<connection> create(spl::shared_ptr<tcp::socket> socket, const ProtocolStrategyPtr& protocol, spl::shared_ptr<connection_set> connection_set)\r
-       {\r
-               spl::shared_ptr<connection> con(new connection(std::move(socket), std::move(protocol), std::move(connection_set)));\r
-               con->read_some();\r
-               return con;\r
-    }\r
-\r
-       std::wstring print() const\r
-       {\r
-               return L"[" + name_ + L"]";\r
-       }\r
-       \r
-       /* ClientInfo */\r
-       \r
-       virtual void Send(const std::wstring& data)\r
-       {\r
-               write_some(data);\r
-       }\r
-\r
-       virtual void Disconnect()\r
-       {\r
-               stop();\r
-       }\r
-       \r
-       /**************/\r
-       \r
-       void stop()\r
-       {\r
-               connection_set_->erase(shared_from_this());\r
-               try\r
-               {\r
-                       socket_->close();\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-               CASPAR_LOG(info) << print() << L" Disconnected.";\r
-       }\r
-\r
-private:\r
-    connection(const spl::shared_ptr<tcp::socket>& socket, const ProtocolStrategyPtr& protocol, const spl::shared_ptr<connection_set>& connection_set) \r
-               : socket_(socket)\r
-               , name_((socket_->is_open() ? u16(socket_->local_endpoint().address().to_string() + ":" + boost::lexical_cast<std::string>(socket_->local_endpoint().port())) : L"no-address"))\r
-               , connection_set_(connection_set)\r
-               , protocol_(protocol)\r
-       {\r
-               CASPAR_LOG(info) << print() << L" Connected.";\r
-    }\r
-                       \r
-    void handle_read(const boost::system::error_code& error, size_t bytes_transferred) \r
-       {               \r
-               if(!error)\r
-               {\r
-                       try\r
-                       {\r
-                               CASPAR_LOG(trace) << print() << L" Received: " << u16(std::string(data_.begin(), data_.begin() + bytes_transferred));\r
-\r
-                               input_.append(data_.begin(), data_.begin() + bytes_transferred);\r
-                               \r
-                               std::vector<std::string> split;\r
-                               boost::iter_split(split, input_, boost::algorithm::first_finder("\r\n"));\r
-                               \r
-                               input_ = std::move(split.back());\r
-                               split.pop_back();\r
-\r
-                               BOOST_FOREACH(auto cmd, split)\r
-                               {\r
-                                       auto u16cmd = boost::locale::conv::to_utf<wchar_t>(cmd, protocol_->GetCodepage()) + L"\r\n";\r
-                                       protocol_->Parse(u16cmd.data(), static_cast<int>(u16cmd.size()), shared_from_this());\r
-                               }\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }\r
-                       \r
-                       read_some();\r
-               }  \r
-               else if (error != boost::asio::error::operation_aborted)\r
-                       stop();         \r
-    }\r
-\r
-    void handle_write(const spl::shared_ptr<std::string>& data, const boost::system::error_code& error, size_t bytes_transferred)\r
-       {\r
-               if(!error)                      \r
-                       CASPAR_LOG(trace) << print() << L" Sent: " << (data->size() < 512 ? u16(*data) : L"more than 512 bytes.");              \r
-               else if (error != boost::asio::error::operation_aborted)                \r
-                       stop();         \r
-    }\r
-\r
-       void read_some()\r
-       {\r
-               socket_->async_read_some(boost::asio::buffer(data_.data(), data_.size()), std::bind(&connection::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2));\r
-       }\r
-       \r
-       void write_some(const std::wstring& data)\r
-       {\r
-               auto str = spl::make_shared<std::string>(boost::locale::conv::from_utf<wchar_t>(data, protocol_->GetCodepage()));\r
-               socket_->async_write_some(boost::asio::buffer(str->data(), str->size()), std::bind(&connection::handle_write, shared_from_this(), str, std::placeholders::_1, std::placeholders::_2));\r
-       }\r
-};\r
-\r
-struct AsyncEventServer::implementation\r
-{\r
-       boost::asio::io_service                                 service_;\r
-       tcp::acceptor                                                   acceptor_;\r
-       spl::shared_ptr<IProtocolStrategy>              protocol_;\r
-       spl::shared_ptr<connection_set>                 connection_set_;\r
-       boost::thread                                                   thread_;\r
-\r
-       implementation(const spl::shared_ptr<IProtocolStrategy>& protocol, unsigned short port)\r
-               : acceptor_(service_, tcp::endpoint(tcp::v4(), port))\r
-               , protocol_(protocol)\r
-               , thread_(std::bind(&boost::asio::io_service::run, &service_))\r
-       {\r
-               start_accept();\r
-       }\r
-\r
-       ~implementation()\r
-       {\r
-               try\r
-               {\r
-                       acceptor_.close();                      \r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-\r
-               service_.post([=]\r
-               {\r
-                       auto connections = *connection_set_;\r
-                       BOOST_FOREACH(auto& connection, connections)\r
-                               connection->stop();                             \r
-               });\r
-\r
-               thread_.join();\r
-       }\r
-               \r
-    void start_accept() \r
-       {\r
-               spl::shared_ptr<tcp::socket> socket(new tcp::socket(service_));\r
-               acceptor_.async_accept(*socket, std::bind(&implementation::handle_accept, this, socket, std::placeholders::_1));\r
-    }\r
-\r
-       void handle_accept(const spl::shared_ptr<tcp::socket>& socket, const boost::system::error_code& error) \r
-       {\r
-               if (!acceptor_.is_open())\r
-                       return;\r
-               \r
-        if (!error)            \r
-                       connection_set_->insert(connection::create(socket, protocol_, connection_set_));\r
-\r
-               start_accept();\r
-    }\r
-};\r
-\r
-AsyncEventServer::AsyncEventServer(const spl::shared_ptr<IProtocolStrategy>& protocol, unsigned short port) : impl_(new implementation(protocol, port)){}\r
-AsyncEventServer::~AsyncEventServer(){}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "..\stdafx.h"
+
+#include "AsyncEventServer.h"
+
+#include "ProtocolStrategy.h"
+
+#include <algorithm>
+#include <array>
+#include <string>
+#include <set>
+#include <vector>
+
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/locale.hpp>
+#include <boost/algorithm/string/split.hpp>
+
+using boost::asio::ip::tcp;
+
+namespace caspar { namespace IO {
+       
+class connection;
+
+typedef std::set<spl::shared_ptr<connection>> connection_set;
+
+class connection : public spl::enable_shared_from_this<connection>, public ClientInfo
+{    
+    const spl::shared_ptr<tcp::socket>                 socket_; 
+       const spl::shared_ptr<connection_set>           connection_set_;
+       const std::wstring                                                      name_;
+       const spl::shared_ptr<IProtocolStrategy>        protocol_;
+
+       std::array<char, 32768>                                         data_;
+       std::string                                                                     input_;
+
+public:
+    static spl::shared_ptr<connection> create(spl::shared_ptr<tcp::socket> socket, const ProtocolStrategyPtr& protocol, spl::shared_ptr<connection_set> connection_set)
+       {
+               spl::shared_ptr<connection> con(new connection(std::move(socket), std::move(protocol), std::move(connection_set)));
+               con->read_some();
+               return con;
+    }
+
+       std::wstring print() const
+       {
+               return L"[" + name_ + L"]";
+       }
+       
+       /* ClientInfo */
+       
+       virtual void Send(const std::wstring& data)
+       {
+               write_some(data);
+       }
+
+       virtual void Disconnect()
+       {
+               stop();
+       }
+       
+       /**************/
+       
+       void stop()
+       {
+               connection_set_->erase(shared_from_this());
+               try
+               {
+                       socket_->close();
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+               CASPAR_LOG(info) << print() << L" Disconnected.";
+       }
+
+private:
+    connection(const spl::shared_ptr<tcp::socket>& socket, const ProtocolStrategyPtr& protocol, const spl::shared_ptr<connection_set>& connection_set) 
+               : socket_(socket)
+               , name_((socket_->is_open() ? u16(socket_->local_endpoint().address().to_string() + ":" + boost::lexical_cast<std::string>(socket_->local_endpoint().port())) : L"no-address"))
+               , connection_set_(connection_set)
+               , protocol_(protocol)
+       {
+               CASPAR_LOG(info) << print() << L" Connected.";
+    }
+                       
+    void handle_read(const boost::system::error_code& error, size_t bytes_transferred) 
+       {               
+               if(!error)
+               {
+                       try
+                       {
+                               CASPAR_LOG(trace) << print() << L" Received: " << u16(std::string(data_.begin(), data_.begin() + bytes_transferred));
+
+                               input_.append(data_.begin(), data_.begin() + bytes_transferred);
+                               
+                               std::vector<std::string> split;
+                               boost::iter_split(split, input_, boost::algorithm::first_finder("\r\n"));
+                               
+                               input_ = std::move(split.back());
+                               split.pop_back();
+
+                               BOOST_FOREACH(auto cmd, split)
+                               {
+                                       auto u16cmd = boost::locale::conv::to_utf<wchar_t>(cmd, protocol_->GetCodepage()) + L"\r\n";
+                                       protocol_->Parse(u16cmd.data(), static_cast<int>(u16cmd.size()), shared_from_this());
+                               }
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }
+                       
+                       read_some();
+               }  
+               else if (error != boost::asio::error::operation_aborted)
+                       stop();         
+    }
+
+    void handle_write(const spl::shared_ptr<std::string>& data, const boost::system::error_code& error, size_t bytes_transferred)
+       {
+               if(!error)                      
+                       CASPAR_LOG(trace) << print() << L" Sent: " << (data->size() < 512 ? u16(*data) : L"more than 512 bytes.");              
+               else if (error != boost::asio::error::operation_aborted)                
+                       stop();         
+    }
+
+       void read_some()
+       {
+               socket_->async_read_some(boost::asio::buffer(data_.data(), data_.size()), std::bind(&connection::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
+       }
+       
+       void write_some(const std::wstring& data)
+       {
+               auto str = spl::make_shared<std::string>(boost::locale::conv::from_utf<wchar_t>(data, protocol_->GetCodepage()));
+               socket_->async_write_some(boost::asio::buffer(str->data(), str->size()), std::bind(&connection::handle_write, shared_from_this(), str, std::placeholders::_1, std::placeholders::_2));
+       }
+};
+
+struct AsyncEventServer::implementation
+{
+       boost::asio::io_service                                 service_;
+       tcp::acceptor                                                   acceptor_;
+       spl::shared_ptr<IProtocolStrategy>              protocol_;
+       spl::shared_ptr<connection_set>                 connection_set_;
+       boost::thread                                                   thread_;
+
+       implementation(const spl::shared_ptr<IProtocolStrategy>& protocol, unsigned short port)
+               : acceptor_(service_, tcp::endpoint(tcp::v4(), port))
+               , protocol_(protocol)
+               , thread_(std::bind(&boost::asio::io_service::run, &service_))
+       {
+               start_accept();
+       }
+
+       ~implementation()
+       {
+               try
+               {
+                       acceptor_.close();                      
+               }
+               catch(...)
+               {
+                       CASPAR_LOG_CURRENT_EXCEPTION();
+               }
+
+               service_.post([=]
+               {
+                       auto connections = *connection_set_;
+                       BOOST_FOREACH(auto& connection, connections)
+                               connection->stop();                             
+               });
+
+               thread_.join();
+       }
+               
+    void start_accept() 
+       {
+               spl::shared_ptr<tcp::socket> socket(new tcp::socket(service_));
+               acceptor_.async_accept(*socket, std::bind(&implementation::handle_accept, this, socket, std::placeholders::_1));
+    }
+
+       void handle_accept(const spl::shared_ptr<tcp::socket>& socket, const boost::system::error_code& error) 
+       {
+               if (!acceptor_.is_open())
+                       return;
+               
+        if (!error)            
+                       connection_set_->insert(connection::create(socket, protocol_, connection_set_));
+
+               start_accept();
+    }
+};
+
+AsyncEventServer::AsyncEventServer(const spl::shared_ptr<IProtocolStrategy>& protocol, unsigned short port) : impl_(new implementation(protocol, port)){}
+AsyncEventServer::~AsyncEventServer(){}
 }}
\ No newline at end of file
index 8fccd865009aeb7a94fcaf9e95d72e014fedea5e..1212b03fb1a3b91c21a3b7985c19f6d417eeca52 100644 (file)
@@ -1,42 +1,42 @@
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-*  This file is part of CasparCG.\r
-*\r
-*    CasparCG is free software: you can redistribute it and/or modify\r
-*    it under the terms of the GNU General Public License as published by\r
-*    the Free Software Foundation, either version 3 of the License, or\r
-*    (at your option) any later version.\r
-*\r
-*    CasparCG is distributed in the hope that it will be useful,\r
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-*    GNU General Public License for more details.\r
-\r
-*    You should have received a copy of the GNU General Public License\r
-*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
\r
-// AsyncEventServer.h: interface for the AsyncServer class.\r
-//////////////////////////////////////////////////////////////////////\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-namespace caspar { namespace IO {\r
-\r
-class IProtocolStrategy;\r
-       \r
-class AsyncEventServer\r
-{\r
-public:\r
-       explicit AsyncEventServer(const spl::shared_ptr<IProtocolStrategy>& protocol, unsigned short port);\r
-       ~AsyncEventServer();\r
-private:\r
-       struct implementation;\r
-       std::unique_ptr<implementation> impl_;\r
-};\r
-\r
-}}     \r
-\r
+/*
+* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
+*
+*  This file is part of CasparCG.
+*
+*    CasparCG is free software: you can redistribute it and/or modify
+*    it under the terms of the GNU General Public License as published by
+*    the Free Software Foundation, either version 3 of the License, or
+*    (at your option) any later version.
+*
+*    CasparCG is distributed in the hope that it will be useful,
+*    but WITHOUT ANY WARRANTY; without even the implied warranty of
+*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*    GNU General Public License for more details.
+
+*    You should have received a copy of the GNU General Public License
+*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+// AsyncEventServer.h: interface for the AsyncServer class.
+//////////////////////////////////////////////////////////////////////
+#pragma once
+
+#include <common/memory.h>
+
+namespace caspar { namespace IO {
+
+class IProtocolStrategy;
+       
+class AsyncEventServer
+{
+public:
+       explicit AsyncEventServer(const spl::shared_ptr<IProtocolStrategy>& protocol, unsigned short port);
+       ~AsyncEventServer();
+private:
+       struct implementation;
+       std::unique_ptr<implementation> impl_;
+};
+
+}}     
+
index 0b6412ffacaf76e6ef478f48e29809f7bfdd6a5f..f28a9cc71523cbbe7dfafc48d1f7bef9770ecc1a 100644 (file)
@@ -1,58 +1,58 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <memory>\r
-#include <string>\r
-#include <iostream>\r
-\r
-#include <common/log.h>\r
-\r
-namespace caspar { namespace IO {\r
-\r
-class ClientInfo \r
-{\r
-protected:\r
-       ClientInfo(){}\r
-\r
-public:\r
-       virtual ~ClientInfo(){}\r
-\r
-       virtual void Send(const std::wstring& data) = 0;\r
-       virtual void Disconnect() = 0;\r
-       virtual std::wstring print() const = 0;\r
-\r
-       std::wstring            currentMessage_;\r
-};\r
-typedef std::shared_ptr<ClientInfo> ClientInfoPtr;\r
-\r
-struct ConsoleClientInfo : public caspar::IO::ClientInfo \r
-{\r
-       void Send(const std::wstring& data)\r
-       {\r
-               std::wcout << (L"#" + caspar::log::replace_nonprintable_copy(data, L'?'));\r
-       }\r
-       void Disconnect(){}\r
-       virtual std::wstring print() const {return L"Console";}\r
-};\r
-\r
-}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <iostream>
+
+#include <common/log.h>
+
+namespace caspar { namespace IO {
+
+class ClientInfo 
+{
+protected:
+       ClientInfo(){}
+
+public:
+       virtual ~ClientInfo(){}
+
+       virtual void Send(const std::wstring& data) = 0;
+       virtual void Disconnect() = 0;
+       virtual std::wstring print() const = 0;
+
+       std::wstring            currentMessage_;
+};
+typedef std::shared_ptr<ClientInfo> ClientInfoPtr;
+
+struct ConsoleClientInfo : public caspar::IO::ClientInfo 
+{
+       void Send(const std::wstring& data)
+       {
+               std::wcout << (L"#" + caspar::log::replace_nonprintable_copy(data, L'?'));
+       }
+       void Disconnect(){}
+       virtual std::wstring print() const {return L"Console";}
+};
+
+}}
index fd92d8d3694dd806bf421e10d1faeef4f8f11bc2..687d22a235f51ed8a50347b9fb7aa8a959974379 100644 (file)
@@ -1,39 +1,39 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
- #pragma once\r
-\r
-#include <string>\r
-#include "clientInfo.h"\r
-\r
-namespace caspar { namespace IO {\r
-\r
-class IProtocolStrategy\r
-{\r
-public:\r
-       virtual ~IProtocolStrategy(){}\r
-\r
-       virtual void Parse(const wchar_t* pData, int charCount, ClientInfoPtr pClientInfo) = 0;\r
-       virtual std::string GetCodepage() = 0;\r
-};\r
-typedef std::shared_ptr<IProtocolStrategy> ProtocolStrategyPtr;\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+ #pragma once
+
+#include <string>
+#include "clientInfo.h"
+
+namespace caspar { namespace IO {
+
+class IProtocolStrategy
+{
+public:
+       virtual ~IProtocolStrategy(){}
+
+       virtual void Parse(const wchar_t* pData, int charCount, ClientInfoPtr pClientInfo) = 0;
+       virtual std::string GetCodepage() = 0;
+};
+typedef std::shared_ptr<IProtocolStrategy> ProtocolStrategyPtr;
+
 }}     //namespace caspar
\ No newline at end of file
index 6f07d1d173d47ec15de5704a670bc2e5798fdc3e..9a324c5477e4a8ad51f286a8b024bb675a09d90e 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-// tbbmalloc_proxy: \r
-// Replace the standard memory allocation routines in Microsoft* C/C++ RTL \r
-// (malloc/free, global new/delete, etc.) with the TBB memory allocator. \r
-\r
-#include "stdafx.h"\r
-\r
-#ifdef _DEBUG\r
-       #define _CRTDBG_MAP_ALLOC\r
-       #include <stdlib.h>\r
-       #include <crtdbg.h>\r
-#else\r
-       #include <tbb/tbbmalloc_proxy.h>\r
-#endif\r
-\r
-#include "resource.h"\r
-\r
-#include "server.h"\r
-\r
-#include <common/os/windows/windows.h>\r
-#include <winnt.h>\r
-#include <mmsystem.h>\r
-#include <atlbase.h>\r
-\r
-#include <protocol/amcp/AMCPProtocolStrategy.h>\r
-#include <protocol/osc/server.h>\r
-\r
-#include <modules/bluefish/bluefish.h>\r
-#include <modules/decklink/decklink.h>\r
-#include <modules/flash/flash.h>\r
-#include <modules/ffmpeg/ffmpeg.h>\r
-#include <modules/image/image.h>\r
-\r
-#include <common/env.h>\r
-#include <common/except.h>\r
-#include <common/except.h>\r
-#include <common/log.h>\r
-#include <common/gl/gl_check.h>\r
-#include <common/os/windows/current_version.h>\r
-#include <common/os/windows/system_info.h>\r
-\r
-#include <tbb/task_scheduler_init.h>\r
-#include <tbb/task_scheduler_observer.h>\r
-\r
-#include <boost/property_tree/detail/file_parser_error.hpp>\r
-#include <boost/property_tree/xml_parser.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/locale.hpp>\r
-\r
-#include <signal.h>\r
-\r
-using namespace caspar;\r
-       \r
-// NOTE: This is needed in order to make CComObject work since this is not a real ATL project.\r
-CComModule _AtlModule;\r
-extern __declspec(selectany) CAtlModule* _pAtlModule = &_AtlModule;\r
-\r
-void change_icon( const HICON hNewIcon )\r
-{\r
-   auto hMod = ::LoadLibrary(L"Kernel32.dll"); \r
-   typedef DWORD(__stdcall *SCI)(HICON);\r
-   auto pfnSetConsoleIcon = reinterpret_cast<SCI>(::GetProcAddress(hMod, "SetConsoleIcon")); \r
-   pfnSetConsoleIcon(hNewIcon); \r
-   ::FreeLibrary(hMod);\r
-}\r
-\r
-void setup_global_locale()\r
-{\r
-       boost::locale::generator gen;\r
-       gen.categories(boost::locale::codepage_facet);\r
-\r
-       std::locale::global(gen(""));\r
-}\r
-\r
-void setup_console_window()\r
-{       \r
-       auto hOut = GetStdHandle(STD_OUTPUT_HANDLE);\r
-\r
-       // Disable close button in console to avoid shutdown without cleanup.\r
-       EnableMenuItem(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE , MF_GRAYED);\r
-       DrawMenuBar(GetConsoleWindow());\r
-       //SetConsoleCtrlHandler(HandlerRoutine, true);\r
-\r
-       // Configure console size and position.\r
-       auto coord = GetLargestConsoleWindowSize(hOut);\r
-       coord.X /= 2;\r
-\r
-       SetConsoleScreenBufferSize(hOut, coord);\r
-\r
-       SMALL_RECT DisplayArea = {0, 0, 0, 0};\r
-       DisplayArea.Right = coord.X-1;\r
-       DisplayArea.Bottom = (coord.Y-1)/2;\r
-       SetConsoleWindowInfo(hOut, TRUE, &DisplayArea);\r
-                \r
-       change_icon(::LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(101)));\r
-\r
-       // Set console title.\r
-       std::wstringstream str;\r
-       str << "CasparCG Server " << env::version() << L" x64 ";\r
-#ifdef COMPILE_RELEASE\r
-       str << " Release";\r
-#elif  COMPILE_PROFILE\r
-       str << " Profile";\r
-#elif  COMPILE_DEVELOP\r
-       str << " Develop";\r
-#elif  COMPILE_DEBUG\r
-       str << " Debug";\r
-#endif\r
-       SetConsoleTitle(str.str().c_str());\r
-}\r
-\r
-void print_info()\r
-{\r
-       CASPAR_LOG(info) << L"################################################################################";\r
-       CASPAR_LOG(info) << L"Copyright (c) 2010 Sveriges Television AB, www.casparcg.com, <info@casparcg.com>";\r
-       CASPAR_LOG(info) << L"################################################################################";\r
-       CASPAR_LOG(info) << L"Starting CasparCG Video and Graphics Playout Server " << env::version();\r
-       CASPAR_LOG(info) << L"on " << win_product_name() << L" " << win_sp_version();\r
-       CASPAR_LOG(info) << cpu_info();\r
-       CASPAR_LOG(info) << system_product_name();\r
-       \r
-       CASPAR_LOG(info) << L"Decklink " << decklink::version();\r
-       BOOST_FOREACH(auto device, decklink::device_list())\r
-               CASPAR_LOG(info) << L" - " << device;   \r
-               \r
-       CASPAR_LOG(info) << L"Bluefish " << bluefish::version();\r
-       BOOST_FOREACH(auto device, bluefish::device_list())\r
-               CASPAR_LOG(info) << L" - " << device;   \r
-       \r
-       CASPAR_LOG(info) << L"Flash "                   << flash::version();\r
-       CASPAR_LOG(info) << L"FreeImage "               << image::version();\r
-       CASPAR_LOG(info) << L"FFMPEG-avcodec "  << ffmpeg::avcodec_version();\r
-       CASPAR_LOG(info) << L"FFMPEG-avformat " << ffmpeg::avformat_version();\r
-       CASPAR_LOG(info) << L"FFMPEG-avfilter " << ffmpeg::avfilter_version();\r
-       CASPAR_LOG(info) << L"FFMPEG-avutil "   << ffmpeg::avutil_version();\r
-       CASPAR_LOG(info) << L"FFMPEG-swscale "  << ffmpeg::swscale_version();\r
-}\r
-\r
-LONG WINAPI UserUnhandledExceptionFilter(EXCEPTION_POINTERS* info)\r
-{\r
-       try\r
-       {\r
-               CASPAR_LOG(fatal) << L"#######################\n UNHANDLED EXCEPTION: \n" \r
-                       << L"Adress:" << info->ExceptionRecord->ExceptionAddress << L"\n"\r
-                       << L"Code:" << info->ExceptionRecord->ExceptionCode << L"\n"\r
-                       << L"Flag:" << info->ExceptionRecord->ExceptionFlags << L"\n"\r
-                       << L"Info:" << info->ExceptionRecord->ExceptionInformation << L"\n"\r
-                       << L"Continuing execution. \n#######################";\r
-\r
-               CASPAR_LOG_CALL_STACK();\r
-       }\r
-       catch(...){}\r
-\r
-    return EXCEPTION_CONTINUE_EXECUTION;\r
-}\r
-\r
-void run()\r
-{\r
-       // Create server object which initializes channels, protocols and controllers.\r
-       server caspar_server;\r
-                               \r
-       auto server = spl::make_shared<protocol::osc::server>(5253);\r
-       caspar_server.subscribe(server);\r
-                                               \r
-       //auto console_obs = reactive::make_observer([](const monitor::event& e)\r
-       //{\r
-       //      std::stringstream str;\r
-       //      str << e;\r
-       //      CASPAR_LOG(trace) << str.str().c_str();\r
-       //});\r
-\r
-       //caspar_server.subscribe(console_obs);\r
-                                               \r
-       // Create a amcp parser for console commands.\r
-       protocol::amcp::AMCPProtocolStrategy amcp(caspar_server.channels());\r
-\r
-       // Create a dummy client which prints amcp responses to console.\r
-       auto console_client = std::make_shared<IO::ConsoleClientInfo>();\r
-                       \r
-       std::wstring wcmd;\r
-       while(true)\r
-       {\r
-               std::getline(std::wcin, wcmd); // TODO: It's blocking...\r
-                               \r
-               boost::to_upper(wcmd);\r
-\r
-               if(wcmd == L"EXIT" || wcmd == L"Q" || wcmd == L"QUIT" || wcmd == L"BYE")\r
-                       break;\r
-                               \r
-               // This is just dummy code for testing.\r
-               if(wcmd.substr(0, 1) == L"1")\r
-                       wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" SLIDE 100 LOOP \r\nPLAY 1-1";\r
-               else if(wcmd.substr(0, 1) == L"2")\r
-                       wcmd = L"MIXER 1-0 VIDEO IS_KEY 1";\r
-               else if(wcmd.substr(0, 1) == L"3")\r
-                       wcmd = L"CG 1-2 ADD 1 BBTELEFONARE 1";\r
-               else if(wcmd.substr(0, 1) == L"4")\r
-                       wcmd = L"PLAY 1-1 DV FILTER yadif=1:-1 LOOP";\r
-               else if(wcmd.substr(0, 1) == L"5")\r
-               {\r
-                       auto file = wcmd.substr(2, wcmd.length()-1);\r
-                       wcmd = L"PLAY 1-1 " + file + L" LOOP\r\n" \r
-                                       L"PLAY 1-2 " + file + L" LOOP\r\n" \r
-                                       L"PLAY 1-3 " + file + L" LOOP\r\n"\r
-                                       L"PLAY 2-1 " + file + L" LOOP\r\n" \r
-                                       L"PLAY 2-2 " + file + L" LOOP\r\n" \r
-                                       L"PLAY 2-3 " + file + L" LOOP\r\n";\r
-               }\r
-               else if(wcmd.substr(0, 1) == L"7")\r
-               {\r
-                       wcmd = L"";\r
-                       wcmd += L"CLEAR 1\r\n";\r
-                       wcmd += L"MIXER 1 CLEAR\r\n";\r
-                       wcmd += L"PLAY 1-0 GREEN\r\n";\r
-                       wcmd += L"PLAY 1-1 BLUE\r\n";\r
-                       wcmd += L"CG 1-2 ADD 1 ECS_TEST 1\r\n";\r
-                       wcmd += L"MIXER 1-2 FILL 0 -1 1 2\r\n";\r
-               }\r
-               else if(wcmd.substr(0, 1) == L"8")\r
-               {\r
-                       wcmd = L"";\r
-                       wcmd += L"MIXER 1-1 FILL 0.0 0.5 1.0 1.0 500 linear DEFER\r\n";\r
-                       wcmd += L"MIXER 1-2 FILL 0.0 0.0 1.0 1.0 500 linear DEFER\r\n";\r
-                       wcmd += L"MIXER 1 COMMIT\r\n";\r
-               }\r
-               else if(wcmd.substr(0, 1) == L"X")\r
-               {\r
-                       int num = 0;\r
-                       std::wstring file;\r
-                       try\r
-                       {\r
-                               num = boost::lexical_cast<int>(wcmd.substr(1, 2));\r
-                               file = wcmd.substr(4, wcmd.length()-1);\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               num = boost::lexical_cast<int>(wcmd.substr(1, 1));\r
-                               file = wcmd.substr(3, wcmd.length()-1);\r
-                       }\r
-\r
-                       int n = 0;\r
-                       int num2 = num;\r
-                       while(num2 > 0)\r
-                       {\r
-                               num2 >>= 1;\r
-                               n++;\r
-                       }\r
-\r
-                       wcmd = L"MIXER 1 GRID " + boost::lexical_cast<std::wstring>(n);\r
-\r
-                       for(int i = 1; i <= num; ++i)\r
-                               wcmd += L"\r\nPLAY 1-" + boost::lexical_cast<std::wstring>(i) + L" " + file + L" LOOP";// + L" SLIDE 100 LOOP";\r
-               }\r
-\r
-               wcmd += L"\r\n";\r
-               amcp.Parse(wcmd.c_str(), static_cast<int>(wcmd.length()), console_client);\r
-       }       \r
-       CASPAR_LOG(info) << "Successfully shutdown CasparCG Server.";\r
-}\r
-\r
-void on_abort(int)\r
-{\r
-       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("abort called"));\r
-}\r
-\r
-int main(int argc, wchar_t* argv[])\r
-{      \r
-       SetUnhandledExceptionFilter(UserUnhandledExceptionFilter);\r
-       signal(SIGABRT, on_abort);\r
-\r
-       setup_global_locale();\r
-\r
-       std::wcout << L"Type \"q\" to close application." << std::endl;\r
-       \r
-       // Set debug mode.\r
-       #ifdef _DEBUG\r
-               HANDLE hLogFile;\r
-               hLogFile = CreateFile(L"crt_log.txt", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\r
-               std::shared_ptr<void> crt_log(nullptr, [](HANDLE h){::CloseHandle(h);});\r
-\r
-               _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);\r
-               _CrtSetReportMode(_CRT_WARN,    _CRTDBG_MODE_FILE);\r
-               _CrtSetReportFile(_CRT_WARN,    hLogFile);\r
-               _CrtSetReportMode(_CRT_ERROR,   _CRTDBG_MODE_FILE);\r
-               _CrtSetReportFile(_CRT_ERROR,   hLogFile);\r
-               _CrtSetReportMode(_CRT_ASSERT,  _CRTDBG_MODE_FILE);\r
-               _CrtSetReportFile(_CRT_ASSERT,  hLogFile);\r
-       #endif\r
-\r
-       // Increase process priotity.\r
-       SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);\r
-\r
-       // Install structured exception handler.\r
-       win32_exception::install_handler();\r
-                               \r
-       // Increase time precision. This will increase accuracy of function like Sleep(1) from 10 ms to 1 ms.\r
-       struct inc_prec\r
-       {\r
-               inc_prec(){timeBeginPeriod(1);}\r
-               ~inc_prec(){timeEndPeriod(1);}\r
-       } inc_prec;     \r
-\r
-       // Install SEH into all tbb threads.\r
-       struct tbb_thread_installer : public tbb::task_scheduler_observer\r
-       {\r
-               tbb_thread_installer(){observe(true);}\r
-               void on_scheduler_entry(bool is_worker)\r
-               {\r
-                       //detail::SetThreadName(GetCurrentThreadId(), "tbb-worker-thread");\r
-                       win32_exception::install_handler();\r
-               }\r
-       } tbb_thread_installer;\r
-\r
-       tbb::task_scheduler_init init;\r
-       \r
-       try \r
-       {\r
-               // Configure environment properties from configuration.\r
-               env::configure(L"casparcg.config");\r
-                               \r
-               log::set_log_level(env::properties().get(L"configuration.log-level", L"debug"));\r
-\r
-       #ifdef _DEBUG\r
-               if(env::properties().get(L"configuration.debugging.remote", false))\r
-                       MessageBox(nullptr, TEXT("Now is the time to connect for remote debugging..."), TEXT("Debug"), MB_OK | MB_TOPMOST);\r
-       #endif   \r
-\r
-               // Start logging to file.\r
-               log::add_file_sink(env::log_folder());                  \r
-               std::wcout << L"Logging [info] or higher severity to " << env::log_folder() << std::endl << std::endl;\r
-               \r
-               // Setup console window.\r
-               setup_console_window();\r
-\r
-               // Print environment information.\r
-               print_info();\r
-               \r
-               std::wstringstream str;\r
-               boost::property_tree::xml_writer_settings<wchar_t> w(' ', 3);\r
-               boost::property_tree::write_xml(str, env::properties(), w);\r
-               CASPAR_LOG(info) << L"casparcg.config:\n-----------------------------------------\n" << str.str().c_str() << L"-----------------------------------------";\r
-               \r
-               run();\r
-               \r
-               system("pause");        \r
-       }\r
-       catch(boost::property_tree::file_parser_error&)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               CASPAR_LOG(fatal) << L"Unhandled configuration error in main thread. Please check the configuration file (casparcg.config) for errors.";\r
-               system("pause");        \r
-       }\r
-       catch(...)\r
-       {\r
-               CASPAR_LOG_CURRENT_EXCEPTION();\r
-               CASPAR_LOG(fatal) << L"Unhandled exception in main thread. Please report this error on the CasparCG forums (www.casparcg.com/forum).";\r
-               Sleep(1000);\r
-               std::wcout << L"\n\nCasparCG will automatically shutdown. See the log file located at the configured log-file folder for more information.\n\n";\r
-               Sleep(4000);\r
-       }               \r
-       \r
-       return 0;\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+// tbbmalloc_proxy: 
+// Replace the standard memory allocation routines in Microsoft* C/C++ RTL 
+// (malloc/free, global new/delete, etc.) with the TBB memory allocator. 
+
+#include "stdafx.h"
+
+#ifdef _DEBUG
+       #define _CRTDBG_MAP_ALLOC
+       #include <stdlib.h>
+       #include <crtdbg.h>
+#else
+       #include <tbb/tbbmalloc_proxy.h>
+#endif
+
+#include "resource.h"
+
+#include "server.h"
+
+#include <common/os/windows/windows.h>
+#include <winnt.h>
+#include <mmsystem.h>
+#include <atlbase.h>
+
+#include <protocol/amcp/AMCPProtocolStrategy.h>
+#include <protocol/osc/server.h>
+
+#include <modules/bluefish/bluefish.h>
+#include <modules/decklink/decklink.h>
+#include <modules/flash/flash.h>
+#include <modules/ffmpeg/ffmpeg.h>
+#include <modules/image/image.h>
+
+#include <common/env.h>
+#include <common/except.h>
+#include <common/except.h>
+#include <common/log.h>
+#include <common/gl/gl_check.h>
+#include <common/os/windows/current_version.h>
+#include <common/os/windows/system_info.h>
+
+#include <tbb/task_scheduler_init.h>
+#include <tbb/task_scheduler_observer.h>
+
+#include <boost/property_tree/detail/file_parser_error.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <boost/foreach.hpp>
+#include <boost/locale.hpp>
+
+#include <signal.h>
+
+using namespace caspar;
+       
+// NOTE: This is needed in order to make CComObject work since this is not a real ATL project.
+CComModule _AtlModule;
+extern __declspec(selectany) CAtlModule* _pAtlModule = &_AtlModule;
+
+void change_icon( const HICON hNewIcon )
+{
+   auto hMod = ::LoadLibrary(L"Kernel32.dll"); 
+   typedef DWORD(__stdcall *SCI)(HICON);
+   auto pfnSetConsoleIcon = reinterpret_cast<SCI>(::GetProcAddress(hMod, "SetConsoleIcon")); 
+   pfnSetConsoleIcon(hNewIcon); 
+   ::FreeLibrary(hMod);
+}
+
+void setup_global_locale()
+{
+       boost::locale::generator gen;
+       gen.categories(boost::locale::codepage_facet);
+
+       std::locale::global(gen(""));
+}
+
+void setup_console_window()
+{       
+       auto hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+
+       // Disable close button in console to avoid shutdown without cleanup.
+       EnableMenuItem(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE , MF_GRAYED);
+       DrawMenuBar(GetConsoleWindow());
+       //SetConsoleCtrlHandler(HandlerRoutine, true);
+
+       // Configure console size and position.
+       auto coord = GetLargestConsoleWindowSize(hOut);
+       coord.X /= 2;
+
+       SetConsoleScreenBufferSize(hOut, coord);
+
+       SMALL_RECT DisplayArea = {0, 0, 0, 0};
+       DisplayArea.Right = coord.X-1;
+       DisplayArea.Bottom = (coord.Y-1)/2;
+       SetConsoleWindowInfo(hOut, TRUE, &DisplayArea);
+                
+       change_icon(::LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(101)));
+
+       // Set console title.
+       std::wstringstream str;
+       str << "CasparCG Server " << env::version() << L" x64 ";
+#ifdef COMPILE_RELEASE
+       str << " Release";
+#elif  COMPILE_PROFILE
+       str << " Profile";
+#elif  COMPILE_DEVELOP
+       str << " Develop";
+#elif  COMPILE_DEBUG
+       str << " Debug";
+#endif
+       SetConsoleTitle(str.str().c_str());
+}
+
+void print_info()
+{
+       CASPAR_LOG(info) << L"################################################################################";
+       CASPAR_LOG(info) << L"Copyright (c) 2010 Sveriges Television AB, www.casparcg.com, <info@casparcg.com>";
+       CASPAR_LOG(info) << L"################################################################################";
+       CASPAR_LOG(info) << L"Starting CasparCG Video and Graphics Playout Server " << env::version();
+       CASPAR_LOG(info) << L"on " << win_product_name() << L" " << win_sp_version();
+       CASPAR_LOG(info) << cpu_info();
+       CASPAR_LOG(info) << system_product_name();
+       
+       CASPAR_LOG(info) << L"Decklink " << decklink::version();
+       BOOST_FOREACH(auto device, decklink::device_list())
+               CASPAR_LOG(info) << L" - " << device;   
+               
+       CASPAR_LOG(info) << L"Bluefish " << bluefish::version();
+       BOOST_FOREACH(auto device, bluefish::device_list())
+               CASPAR_LOG(info) << L" - " << device;   
+       
+       CASPAR_LOG(info) << L"Flash "                   << flash::version();
+       CASPAR_LOG(info) << L"FreeImage "               << image::version();
+       CASPAR_LOG(info) << L"FFMPEG-avcodec "  << ffmpeg::avcodec_version();
+       CASPAR_LOG(info) << L"FFMPEG-avformat " << ffmpeg::avformat_version();
+       CASPAR_LOG(info) << L"FFMPEG-avfilter " << ffmpeg::avfilter_version();
+       CASPAR_LOG(info) << L"FFMPEG-avutil "   << ffmpeg::avutil_version();
+       CASPAR_LOG(info) << L"FFMPEG-swscale "  << ffmpeg::swscale_version();
+}
+
+LONG WINAPI UserUnhandledExceptionFilter(EXCEPTION_POINTERS* info)
+{
+       try
+       {
+               CASPAR_LOG(fatal) << L"#######################\n UNHANDLED EXCEPTION: \n" 
+                       << L"Adress:" << info->ExceptionRecord->ExceptionAddress << L"\n"
+                       << L"Code:" << info->ExceptionRecord->ExceptionCode << L"\n"
+                       << L"Flag:" << info->ExceptionRecord->ExceptionFlags << L"\n"
+                       << L"Info:" << info->ExceptionRecord->ExceptionInformation << L"\n"
+                       << L"Continuing execution. \n#######################";
+
+               CASPAR_LOG_CALL_STACK();
+       }
+       catch(...){}
+
+    return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+void run()
+{
+       // Create server object which initializes channels, protocols and controllers.
+       server caspar_server;
+                               
+       auto server = spl::make_shared<protocol::osc::server>(5253);
+       caspar_server.subscribe(server);
+                                               
+       //auto console_obs = reactive::make_observer([](const monitor::event& e)
+       //{
+       //      std::stringstream str;
+       //      str << e;
+       //      CASPAR_LOG(trace) << str.str().c_str();
+       //});
+
+       //caspar_server.subscribe(console_obs);
+                                               
+       // Create a amcp parser for console commands.
+       protocol::amcp::AMCPProtocolStrategy amcp(caspar_server.channels());
+
+       // Create a dummy client which prints amcp responses to console.
+       auto console_client = std::make_shared<IO::ConsoleClientInfo>();
+                       
+       std::wstring wcmd;
+       while(true)
+       {
+               std::getline(std::wcin, wcmd); // TODO: It's blocking...
+                               
+               boost::to_upper(wcmd);
+
+               if(wcmd == L"EXIT" || wcmd == L"Q" || wcmd == L"QUIT" || wcmd == L"BYE")
+                       break;
+                               
+               // This is just dummy code for testing.
+               if(wcmd.substr(0, 1) == L"1")
+                       wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" SLIDE 100 LOOP \r\nPLAY 1-1";
+               else if(wcmd.substr(0, 1) == L"2")
+                       wcmd = L"MIXER 1-0 VIDEO IS_KEY 1";
+               else if(wcmd.substr(0, 1) == L"3")
+                       wcmd = L"CG 1-2 ADD 1 BBTELEFONARE 1";
+               else if(wcmd.substr(0, 1) == L"4")
+                       wcmd = L"PLAY 1-1 DV FILTER yadif=1:-1 LOOP";
+               else if(wcmd.substr(0, 1) == L"5")
+               {
+                       auto file = wcmd.substr(2, wcmd.length()-1);
+                       wcmd = L"PLAY 1-1 " + file + L" LOOP\r\n" 
+                                       L"PLAY 1-2 " + file + L" LOOP\r\n" 
+                                       L"PLAY 1-3 " + file + L" LOOP\r\n"
+                                       L"PLAY 2-1 " + file + L" LOOP\r\n" 
+                                       L"PLAY 2-2 " + file + L" LOOP\r\n" 
+                                       L"PLAY 2-3 " + file + L" LOOP\r\n";
+               }
+               else if(wcmd.substr(0, 1) == L"7")
+               {
+                       wcmd = L"";
+                       wcmd += L"CLEAR 1\r\n";
+                       wcmd += L"MIXER 1 CLEAR\r\n";
+                       wcmd += L"PLAY 1-0 GREEN\r\n";
+                       wcmd += L"PLAY 1-1 BLUE\r\n";
+                       wcmd += L"CG 1-2 ADD 1 ECS_TEST 1\r\n";
+                       wcmd += L"MIXER 1-2 FILL 0 -1 1 2\r\n";
+               }
+               else if(wcmd.substr(0, 1) == L"8")
+               {
+                       wcmd = L"";
+                       wcmd += L"MIXER 1-1 FILL 0.0 0.5 1.0 1.0 500 linear DEFER\r\n";
+                       wcmd += L"MIXER 1-2 FILL 0.0 0.0 1.0 1.0 500 linear DEFER\r\n";
+                       wcmd += L"MIXER 1 COMMIT\r\n";
+               }
+               else if(wcmd.substr(0, 1) == L"X")
+               {
+                       int num = 0;
+                       std::wstring file;
+                       try
+                       {
+                               num = boost::lexical_cast<int>(wcmd.substr(1, 2));
+                               file = wcmd.substr(4, wcmd.length()-1);
+                       }
+                       catch(...)
+                       {
+                               num = boost::lexical_cast<int>(wcmd.substr(1, 1));
+                               file = wcmd.substr(3, wcmd.length()-1);
+                       }
+
+                       int n = 0;
+                       int num2 = num;
+                       while(num2 > 0)
+                       {
+                               num2 >>= 1;
+                               n++;
+                       }
+
+                       wcmd = L"MIXER 1 GRID " + boost::lexical_cast<std::wstring>(n);
+
+                       for(int i = 1; i <= num; ++i)
+                               wcmd += L"\r\nPLAY 1-" + boost::lexical_cast<std::wstring>(i) + L" " + file + L" LOOP";// + L" SLIDE 100 LOOP";
+               }
+
+               wcmd += L"\r\n";
+               amcp.Parse(wcmd.c_str(), static_cast<int>(wcmd.length()), console_client);
+       }       
+       CASPAR_LOG(info) << "Successfully shutdown CasparCG Server.";
+}
+
+void on_abort(int)
+{
+       CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("abort called"));
+}
+
+int main(int argc, wchar_t* argv[])
+{      
+       SetUnhandledExceptionFilter(UserUnhandledExceptionFilter);
+       signal(SIGABRT, on_abort);
+
+       setup_global_locale();
+
+       std::wcout << L"Type \"q\" to close application." << std::endl;
+       
+       // Set debug mode.
+       #ifdef _DEBUG
+               HANDLE hLogFile;
+               hLogFile = CreateFile(L"crt_log.txt", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+               std::shared_ptr<void> crt_log(nullptr, [](HANDLE h){::CloseHandle(h);});
+
+               _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+               _CrtSetReportMode(_CRT_WARN,    _CRTDBG_MODE_FILE);
+               _CrtSetReportFile(_CRT_WARN,    hLogFile);
+               _CrtSetReportMode(_CRT_ERROR,   _CRTDBG_MODE_FILE);
+               _CrtSetReportFile(_CRT_ERROR,   hLogFile);
+               _CrtSetReportMode(_CRT_ASSERT,  _CRTDBG_MODE_FILE);
+               _CrtSetReportFile(_CRT_ASSERT,  hLogFile);
+       #endif
+
+       // Increase process priotity.
+       SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
+
+       // Install structured exception handler.
+       win32_exception::install_handler();
+                               
+       // Increase time precision. This will increase accuracy of function like Sleep(1) from 10 ms to 1 ms.
+       struct inc_prec
+       {
+               inc_prec(){timeBeginPeriod(1);}
+               ~inc_prec(){timeEndPeriod(1);}
+       } inc_prec;     
+
+       // Install SEH into all tbb threads.
+       struct tbb_thread_installer : public tbb::task_scheduler_observer
+       {
+               tbb_thread_installer(){observe(true);}
+               void on_scheduler_entry(bool is_worker)
+               {
+                       //detail::SetThreadName(GetCurrentThreadId(), "tbb-worker-thread");
+                       win32_exception::install_handler();
+               }
+       } tbb_thread_installer;
+
+       tbb::task_scheduler_init init;
+       
+       try 
+       {
+               // Configure environment properties from configuration.
+               env::configure(L"casparcg.config");
+                               
+               log::set_log_level(env::properties().get(L"configuration.log-level", L"debug"));
+
+       #ifdef _DEBUG
+               if(env::properties().get(L"configuration.debugging.remote", false))
+                       MessageBox(nullptr, TEXT("Now is the time to connect for remote debugging..."), TEXT("Debug"), MB_OK | MB_TOPMOST);
+       #endif   
+
+               // Start logging to file.
+               log::add_file_sink(env::log_folder());                  
+               std::wcout << L"Logging [info] or higher severity to " << env::log_folder() << std::endl << std::endl;
+               
+               // Setup console window.
+               setup_console_window();
+
+               // Print environment information.
+               print_info();
+               
+               std::wstringstream str;
+               boost::property_tree::xml_writer_settings<wchar_t> w(' ', 3);
+               boost::property_tree::write_xml(str, env::properties(), w);
+               CASPAR_LOG(info) << L"casparcg.config:\n-----------------------------------------\n" << str.str().c_str() << L"-----------------------------------------";
+               
+               run();
+               
+               system("pause");        
+       }
+       catch(boost::property_tree::file_parser_error&)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               CASPAR_LOG(fatal) << L"Unhandled configuration error in main thread. Please check the configuration file (casparcg.config) for errors.";
+               system("pause");        
+       }
+       catch(...)
+       {
+               CASPAR_LOG_CURRENT_EXCEPTION();
+               CASPAR_LOG(fatal) << L"Unhandled exception in main thread. Please report this error on the CasparCG forums (www.casparcg.com/forum).";
+               Sleep(1000);
+               std::wcout << L"\n\nCasparCG will automatically shutdown. See the log file located at the configured log-file folder for more information.\n\n";
+               Sleep(4000);
+       }               
+       
+       return 0;
 }
\ No newline at end of file
index 2da08565a1c8833f8813022900ccf6058182a5ba..8d3cd24c7d818d498e428d3179247ebb8f619f0f 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-#include "stdafx.h"\r
-\r
-#include "server.h"\r
-\r
-#include <accelerator/accelerator.h>\r
-\r
-#include <common/env.h>\r
-#include <common/except.h>\r
-#include <common/utf.h>\r
-\r
-#include <core/video_channel.h>\r
-#include <core/video_format.h>\r
-#include <core/producer/stage.h>\r
-#include <core/consumer/output.h>\r
-\r
-#include <modules/bluefish/bluefish.h>\r
-#include <modules/decklink/decklink.h>\r
-#include <modules/ffmpeg/ffmpeg.h>\r
-#include <modules/flash/flash.h>\r
-#include <modules/oal/oal.h>\r
-#include <modules/screen/screen.h>\r
-#include <modules/image/image.h>\r
-\r
-#include <modules/oal/consumer/oal_consumer.h>\r
-#include <modules/bluefish/consumer/bluefish_consumer.h>\r
-#include <modules/decklink/consumer/decklink_consumer.h>\r
-#include <modules/screen/consumer/screen_consumer.h>\r
-#include <modules/ffmpeg/consumer/ffmpeg_consumer.h>\r
-\r
-#include <protocol/amcp/AMCPProtocolStrategy.h>\r
-#include <protocol/cii/CIIProtocolStrategy.h>\r
-#include <protocol/CLK/CLKProtocolStrategy.h>\r
-#include <protocol/util/AsyncEventServer.h>\r
-\r
-#include <boost/algorithm/string.hpp>\r
-#include <boost/lexical_cast.hpp>\r
-#include <boost/foreach.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/property_tree/xml_parser.hpp>\r
-\r
-namespace caspar {\r
-\r
-using namespace core;\r
-using namespace protocol;\r
-\r
-struct server::impl : boost::noncopyable\r
-{\r
-       monitor::basic_subject                                                          event_subject_;\r
-       accelerator::accelerator                                                        accelerator_;\r
-       std::vector<spl::shared_ptr<IO::AsyncEventServer>>      async_servers_; \r
-       std::vector<spl::shared_ptr<video_channel>>                     channels_;\r
-\r
-       impl()          \r
-               : accelerator_(env::properties().get(L"configuration.accelerator", L"auto"))\r
-       {       \r
-\r
-               ffmpeg::init();\r
-               CASPAR_LOG(info) << L"Initialized ffmpeg module.";\r
-                                                         \r
-               bluefish::init();         \r
-               CASPAR_LOG(info) << L"Initialized bluefish module.";\r
-                                                         \r
-               decklink::init();         \r
-               CASPAR_LOG(info) << L"Initialized decklink module.";\r
-                                                                                                                 \r
-               oal::init();              \r
-               CASPAR_LOG(info) << L"Initialized oal module.";\r
-                                                         \r
-               screen::init();           \r
-               CASPAR_LOG(info) << L"Initialized ogl module.";\r
-\r
-               image::init();            \r
-               CASPAR_LOG(info) << L"Initialized image module.";\r
-\r
-               flash::init();            \r
-               CASPAR_LOG(info) << L"Initialized flash module.";\r
-\r
-               setup_channels(env::properties());\r
-               CASPAR_LOG(info) << L"Initialized channels.";\r
-\r
-               setup_controllers(env::properties());\r
-               CASPAR_LOG(info) << L"Initialized controllers.";\r
-       }\r
-\r
-       ~impl()\r
-       {               \r
-               async_servers_.clear();\r
-               channels_.clear();\r
-\r
-               Sleep(500); // HACK: Wait for asynchronous destruction of producers and consumers.\r
-\r
-               image::uninit();\r
-               ffmpeg::uninit();\r
-       }\r
-                               \r
-       void setup_channels(const boost::property_tree::wptree& pt)\r
-       {   \r
-               using boost::property_tree::wptree;\r
-               BOOST_FOREACH(auto& xml_channel, pt.get_child(L"configuration.channels"))\r
-               {               \r
-                       auto format_desc = video_format_desc(xml_channel.second.get(L"video-mode", L"PAL"));            \r
-                       if(format_desc.format == video_format::invalid)\r
-                               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Invalid video-mode."));\r
-                       \r
-                       auto channel = spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), format_desc, accelerator_.create_image_mixer());\r
-                       \r
-                       BOOST_FOREACH(auto& xml_consumer, xml_channel.second.get_child(L"consumers"))\r
-                       {\r
-                               try\r
-                               {\r
-                                       auto name = xml_consumer.first;\r
-                                       if(name == L"screen")\r
-                                               channel->output().add(caspar::screen::create_consumer(xml_consumer.second));                                    \r
-                                       else if(name == L"bluefish")                                    \r
-                                               channel->output().add(bluefish::create_consumer(xml_consumer.second));                                  \r
-                                       else if(name == L"decklink")                                    \r
-                                               channel->output().add(decklink::create_consumer(xml_consumer.second));                          \r
-                                       else if(name == L"file")                                        \r
-                                               channel->output().add(ffmpeg::create_consumer(xml_consumer.second));                                            \r
-                                       else if(name == L"system-audio")\r
-                                               channel->output().add(oal::create_consumer());          \r
-                                       else if(name != L"<xmlcomment>")\r
-                                               CASPAR_LOG(warning) << "Invalid consumer: " << name;    \r
-                               }\r
-                               catch(...)\r
-                               {\r
-                                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                               }\r
-                       }               \r
-\r
-                   channel->subscribe(monitor::observable::observer_ptr(event_subject_));\r
-                       channels_.push_back(channel);\r
-               }\r
-\r
-               // Dummy diagnostics channel\r
-               if(env::properties().get(L"configuration.channel-grid", false))\r
-                       channels_.push_back(spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), core::video_format_desc(core::video_format::x576p2500), accelerator_.create_image_mixer()));\r
-       }\r
-               \r
-       void setup_controllers(const boost::property_tree::wptree& pt)\r
-       {               \r
-               using boost::property_tree::wptree;\r
-               BOOST_FOREACH(auto& xml_controller, pt.get_child(L"configuration.controllers"))\r
-               {\r
-                       try\r
-                       {\r
-                               auto name = xml_controller.first;\r
-                               auto protocol = xml_controller.second.get<std::wstring>(L"protocol");   \r
-\r
-                               if(name == L"tcp")\r
-                               {                                       \r
-                                       unsigned int port = xml_controller.second.get(L"port", 5250);\r
-                                       auto asyncbootstrapper = spl::make_shared<IO::AsyncEventServer>(create_protocol(protocol), port);\r
-                                       async_servers_.push_back(asyncbootstrapper);\r
-                               }\r
-                               else\r
-                                       CASPAR_LOG(warning) << "Invalid controller: " << name;  \r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       }\r
-               }\r
-       }\r
-\r
-       spl::shared_ptr<IO::IProtocolStrategy> create_protocol(const std::wstring& name) const\r
-       {\r
-               if(boost::iequals(name, L"AMCP"))\r
-                       return spl::make_shared<amcp::AMCPProtocolStrategy>(channels_);\r
-               else if(boost::iequals(name, L"CII"))\r
-                       return spl::make_shared<cii::CIIProtocolStrategy>(channels_);\r
-               else if(boost::iequals(name, L"CLOCK"))\r
-                       return spl::make_shared<CLK::CLKProtocolStrategy>(channels_);\r
-               \r
-               CASPAR_THROW_EXCEPTION(caspar_exception() << arg_name_info(L"name") << arg_value_info(name) << msg_info(L"Invalid protocol"));\r
-       }\r
-};\r
-\r
-server::server() : impl_(new impl()){}\r
-\r
-const std::vector<spl::shared_ptr<video_channel>> server::channels() const\r
-{\r
-       return impl_->channels_;\r
-}\r
-void server::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.subscribe(o);}\r
-void server::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);}\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+#include "stdafx.h"
+
+#include "server.h"
+
+#include <accelerator/accelerator.h>
+
+#include <common/env.h>
+#include <common/except.h>
+#include <common/utf.h>
+
+#include <core/video_channel.h>
+#include <core/video_format.h>
+#include <core/producer/stage.h>
+#include <core/consumer/output.h>
+
+#include <modules/bluefish/bluefish.h>
+#include <modules/decklink/decklink.h>
+#include <modules/ffmpeg/ffmpeg.h>
+#include <modules/flash/flash.h>
+#include <modules/oal/oal.h>
+#include <modules/screen/screen.h>
+#include <modules/image/image.h>
+
+#include <modules/oal/consumer/oal_consumer.h>
+#include <modules/bluefish/consumer/bluefish_consumer.h>
+#include <modules/decklink/consumer/decklink_consumer.h>
+#include <modules/screen/consumer/screen_consumer.h>
+#include <modules/ffmpeg/consumer/ffmpeg_consumer.h>
+
+#include <protocol/amcp/AMCPProtocolStrategy.h>
+#include <protocol/cii/CIIProtocolStrategy.h>
+#include <protocol/CLK/CLKProtocolStrategy.h>
+#include <protocol/util/AsyncEventServer.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+
+namespace caspar {
+
+using namespace core;
+using namespace protocol;
+
+struct server::impl : boost::noncopyable
+{
+       monitor::basic_subject                                                          event_subject_;
+       accelerator::accelerator                                                        accelerator_;
+       std::vector<spl::shared_ptr<IO::AsyncEventServer>>      async_servers_; 
+       std::vector<spl::shared_ptr<video_channel>>                     channels_;
+
+       impl()          
+               : accelerator_(env::properties().get(L"configuration.accelerator", L"auto"))
+       {       
+
+               ffmpeg::init();
+               CASPAR_LOG(info) << L"Initialized ffmpeg module.";
+                                                         
+               bluefish::init();         
+               CASPAR_LOG(info) << L"Initialized bluefish module.";
+                                                         
+               decklink::init();         
+               CASPAR_LOG(info) << L"Initialized decklink module.";
+                                                                                                                 
+               oal::init();              
+               CASPAR_LOG(info) << L"Initialized oal module.";
+                                                         
+               screen::init();           
+               CASPAR_LOG(info) << L"Initialized ogl module.";
+
+               image::init();            
+               CASPAR_LOG(info) << L"Initialized image module.";
+
+               flash::init();            
+               CASPAR_LOG(info) << L"Initialized flash module.";
+
+               setup_channels(env::properties());
+               CASPAR_LOG(info) << L"Initialized channels.";
+
+               setup_controllers(env::properties());
+               CASPAR_LOG(info) << L"Initialized controllers.";
+       }
+
+       ~impl()
+       {               
+               async_servers_.clear();
+               channels_.clear();
+
+               Sleep(500); // HACK: Wait for asynchronous destruction of producers and consumers.
+
+               image::uninit();
+               ffmpeg::uninit();
+       }
+                               
+       void setup_channels(const boost::property_tree::wptree& pt)
+       {   
+               using boost::property_tree::wptree;
+               BOOST_FOREACH(auto& xml_channel, pt.get_child(L"configuration.channels"))
+               {               
+                       auto format_desc = video_format_desc(xml_channel.second.get(L"video-mode", L"PAL"));            
+                       if(format_desc.format == video_format::invalid)
+                               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Invalid video-mode."));
+                       
+                       auto channel = spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), format_desc, accelerator_.create_image_mixer());
+                       
+                       BOOST_FOREACH(auto& xml_consumer, xml_channel.second.get_child(L"consumers"))
+                       {
+                               try
+                               {
+                                       auto name = xml_consumer.first;
+                                       if(name == L"screen")
+                                               channel->output().add(caspar::screen::create_consumer(xml_consumer.second));                                    
+                                       else if(name == L"bluefish")                                    
+                                               channel->output().add(bluefish::create_consumer(xml_consumer.second));                                  
+                                       else if(name == L"decklink")                                    
+                                               channel->output().add(decklink::create_consumer(xml_consumer.second));                          
+                                       else if(name == L"file")                                        
+                                               channel->output().add(ffmpeg::create_consumer(xml_consumer.second));                                            
+                                       else if(name == L"system-audio")
+                                               channel->output().add(oal::create_consumer());          
+                                       else if(name != L"<xmlcomment>")
+                                               CASPAR_LOG(warning) << "Invalid consumer: " << name;    
+                               }
+                               catch(...)
+                               {
+                                       CASPAR_LOG_CURRENT_EXCEPTION();
+                               }
+                       }               
+
+                   channel->subscribe(monitor::observable::observer_ptr(event_subject_));
+                       channels_.push_back(channel);
+               }
+
+               // Dummy diagnostics channel
+               if(env::properties().get(L"configuration.channel-grid", false))
+                       channels_.push_back(spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), core::video_format_desc(core::video_format::x576p2500), accelerator_.create_image_mixer()));
+       }
+               
+       void setup_controllers(const boost::property_tree::wptree& pt)
+       {               
+               using boost::property_tree::wptree;
+               BOOST_FOREACH(auto& xml_controller, pt.get_child(L"configuration.controllers"))
+               {
+                       try
+                       {
+                               auto name = xml_controller.first;
+                               auto protocol = xml_controller.second.get<std::wstring>(L"protocol");   
+
+                               if(name == L"tcp")
+                               {                                       
+                                       unsigned int port = xml_controller.second.get(L"port", 5250);
+                                       auto asyncbootstrapper = spl::make_shared<IO::AsyncEventServer>(create_protocol(protocol), port);
+                                       async_servers_.push_back(asyncbootstrapper);
+                               }
+                               else
+                                       CASPAR_LOG(warning) << "Invalid controller: " << name;  
+                       }
+                       catch(...)
+                       {
+                               CASPAR_LOG_CURRENT_EXCEPTION();
+                       }
+               }
+       }
+
+       spl::shared_ptr<IO::IProtocolStrategy> create_protocol(const std::wstring& name) const
+       {
+               if(boost::iequals(name, L"AMCP"))
+                       return spl::make_shared<amcp::AMCPProtocolStrategy>(channels_);
+               else if(boost::iequals(name, L"CII"))
+                       return spl::make_shared<cii::CIIProtocolStrategy>(channels_);
+               else if(boost::iequals(name, L"CLOCK"))
+                       return spl::make_shared<CLK::CLKProtocolStrategy>(channels_);
+               
+               CASPAR_THROW_EXCEPTION(caspar_exception() << arg_name_info(L"name") << arg_value_info(name) << msg_info(L"Invalid protocol"));
+       }
+};
+
+server::server() : impl_(new impl()){}
+
+const std::vector<spl::shared_ptr<video_channel>> server::channels() const
+{
+       return impl_->channels_;
+}
+void server::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.subscribe(o);}
+void server::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);}
+
 }
\ No newline at end of file
index 74571dbf00c4708330e8c4fe6be979db593931c2..aecb7ebdfb86d86f493ae8027873f88c5c79edd7 100644 (file)
@@ -1,54 +1,54 @@
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include <common/memory.h>\r
-\r
-#include <core/monitor/monitor.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-#include <vector>\r
-\r
-namespace caspar {\r
-\r
-namespace core {\r
-       class video_channel;\r
-}\r
-\r
-class server sealed : public monitor::observable\r
-                                       , boost::noncopyable\r
-{\r
-public:\r
-       server();\r
-       const std::vector<spl::shared_ptr<core::video_channel>> channels() const;\r
-\r
-       // monitor::observable\r
-\r
-       void subscribe(const monitor::observable::observer_ptr& o) override;\r
-       void unsubscribe(const monitor::observable::observer_ptr& o) override;\r
-private:\r
-       struct impl;\r
-       spl::shared_ptr<impl> impl_;\r
-};\r
-\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <core/monitor/monitor.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <vector>
+
+namespace caspar {
+
+namespace core {
+       class video_channel;
+}
+
+class server sealed : public monitor::observable
+                                       , boost::noncopyable
+{
+public:
+       server();
+       const std::vector<spl::shared_ptr<core::video_channel>> channels() const;
+
+       // monitor::observable
+
+       void subscribe(const monitor::observable::observer_ptr& o) override;
+       void unsubscribe(const monitor::observable::observer_ptr& o) override;
+private:
+       struct impl;
+       spl::shared_ptr<impl> impl_;
+};
+
 }
\ No newline at end of file
index 5dcf2cc7babb5c2bdf9deaafa57d9e56ff5c2607..77d1b3b8ccc66b1d3b5d82ddc073bb270b0c9e5c 100644 (file)
@@ -1,4 +1,4 @@
-#pragma once\r
-\r
-#define NOMINMAX\r
+#pragma once
+
+#define NOMINMAX
 #define WIN32_LEAN_AND_MEAN
\ No newline at end of file