-/*\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
-/*\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>
-#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
-#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
-#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
-#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
-/*\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, ¶m), 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, ¶m), 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
-#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
-#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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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);
+}
+
+}}}
-/*\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
-/*\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
-/*\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
-/*\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();}
+
+
+}}}
+
+
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-#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);
+}
+
+}
+
-/*\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
-/*\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
+
-/**********************************************************************\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);
+}
-/**********************************************************************\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
-/*\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
-/*\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
-#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
-/*\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
-/*\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
-#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
-/*\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
-/*\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
-#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
-#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
-#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);
-///////////////////////////\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
-///////////////////////////\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
-#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
-/*\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
-/*\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
-/*\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>())
+{
+}
+
+}}
-/*\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
-/*\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
-/*\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
-#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
-#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
-/*\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
-#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
-/*\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
-/*\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
-#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
-/*\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"
-/*\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
-/*\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;
+}
+
+}}
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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>
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-#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
-#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
-#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
-/*\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
-/*\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
-/*\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
-#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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-#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
-#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
-/*\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
-/*\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);
+
+}}
-/*\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
-/*\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);
+
+}}
-/*\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
-/*\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
-/*\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);
+}
+
+}}
+
-/*\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
-/*\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
-/*\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
-/*\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);
+}
+
+}}
+
-/*\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
-/*\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
-/*\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
-/*\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;
+}
+
+
+}}
+
-/*\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
-/*\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
-/*\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>
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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"
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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);
+
+}}
-/*\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
-/*\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"
-/*\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)
-/*\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);
+}
+
+}}
-/*\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
-/*\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
-/*\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
-#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
-/*\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; \
+ }()
+
+}}
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-#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>
* 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)
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;
-#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
-/*\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_;}
+}}
-/*\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_;
+};
+
+
+}}
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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, ¶m), 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, ¶m), 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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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"
-/*\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;
+}
+
+}}
-/*\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
-/*\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
-\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
+
+
-/*\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
-/*\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
-/*\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
-/*\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);
+
+}}
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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>();
+}
+
+}}
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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);
+ }
+ });
+}
+
+}}
-/*\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
-/*\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);
+
+}}
-/*\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_;
+};
+
+}}
-/*\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>();
+}
+
+}}
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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);
+
+}}
-// 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
-#pragma once\r
+#pragma once
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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
-/*\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;
+ };
+
+}}}
-/*\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
-/*\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;
+
+}}}
-/*\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
-/*\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
-/*\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
-/*\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;
+};
+
+}}}
-/*\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
-/*\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
-/*\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
-/*\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("""); \r
- else if(message[charIndex] == TEXT('<')) \r
- currentToken << TEXT("<"); \r
- else if(message[charIndex] == TEXT('>')) \r
- currentToken << TEXT(">"); \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(""");
+ else if(message[charIndex] == TEXT('<'))
+ currentToken << TEXT("<");
+ else if(message[charIndex] == TEXT('>'))
+ currentToken << TEXT(">");
+ 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;
+}
+
+}}}
-/*\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
-/*\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
-/*\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
-/*\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("<");\r
- else if(currentByte == TEXT('>'))\r
- currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT(">");\r
- else if(currentByte == TEXT('\"'))\r
- currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT(""");\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("<");
+ else if(currentByte == TEXT('>'))
+ currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT(">");
+ else if(currentByte == TEXT('\"'))
+ currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT(""");
+ 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
-/*\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_;
+};
+
+}}}
-/*\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
-/*\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 */
-/*\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 */
-/*\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
+
+
-/*\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 */
-/*\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 */
-/*\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
-/*\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 */
-/*\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
+
-/*\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 */
-/*\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
-/*\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 */
-#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
-#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
-/*\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
-/*\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_;
+};
+
+}}
+
-/*\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";}
+};
+
+}}
-/*\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
-/*\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
-/*\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
-/*\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
-#pragma once\r
-\r
-#define NOMINMAX\r
+#pragma once
+
+#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
\ No newline at end of file