EndProject\r
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcxproj", "{02308602-7FE0-4253-B96E-22134919F56A}"\r
EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reroute", "modules\reroute\reroute.vcxproj", "{7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}"\r
+EndProject\r
Global\r
GlobalSection(SubversionScc) = preSolution\r
Svn-Managed = True\r
Manager = AnkhSVN - Subversion Support for Visual Studio\r
EndGlobalSection\r
GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+ Debug|Mixed Platforms = Debug|Mixed Platforms\r
+ Debug|Win32 = Debug|Win32\r
Debug|x64 = Debug|x64\r
+ Release|Mixed Platforms = Release|Mixed Platforms\r
+ Release|Win32 = Release|Win32\r
Release|x64 = Release|x64\r
EndGlobalSection\r
GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+ {79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Debug|Win32.ActiveCfg = Debug|x64\r
{79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Debug|x64.ActiveCfg = Debug|x64\r
{79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Debug|x64.Build.0 = Debug|x64\r
+ {79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Release|Win32.ActiveCfg = Release|x64\r
{79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Release|x64.ActiveCfg = Release|x64\r
{79388C20-6499-4BF6-B8B9-D8C33D7D4DDD}.Release|x64.Build.0 = Release|x64\r
+ {8C26C94F-8092-4769-8D84-DEA479721C5B}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {8C26C94F-8092-4769-8D84-DEA479721C5B}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {8C26C94F-8092-4769-8D84-DEA479721C5B}.Debug|Win32.ActiveCfg = Debug|x64\r
{8C26C94F-8092-4769-8D84-DEA479721C5B}.Debug|x64.ActiveCfg = Debug|x64\r
{8C26C94F-8092-4769-8D84-DEA479721C5B}.Debug|x64.Build.0 = Debug|x64\r
+ {8C26C94F-8092-4769-8D84-DEA479721C5B}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {8C26C94F-8092-4769-8D84-DEA479721C5B}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {8C26C94F-8092-4769-8D84-DEA479721C5B}.Release|Win32.ActiveCfg = Release|x64\r
{8C26C94F-8092-4769-8D84-DEA479721C5B}.Release|x64.ActiveCfg = Release|x64\r
{8C26C94F-8092-4769-8D84-DEA479721C5B}.Release|x64.Build.0 = Release|x64\r
+ {2040B361-1FB6-488E-84A5-38A580DA90DE}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {2040B361-1FB6-488E-84A5-38A580DA90DE}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {2040B361-1FB6-488E-84A5-38A580DA90DE}.Debug|Win32.ActiveCfg = Debug|x64\r
{2040B361-1FB6-488E-84A5-38A580DA90DE}.Debug|x64.ActiveCfg = Debug|x64\r
{2040B361-1FB6-488E-84A5-38A580DA90DE}.Debug|x64.Build.0 = Debug|x64\r
+ {2040B361-1FB6-488E-84A5-38A580DA90DE}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {2040B361-1FB6-488E-84A5-38A580DA90DE}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {2040B361-1FB6-488E-84A5-38A580DA90DE}.Release|Win32.ActiveCfg = Release|x64\r
{2040B361-1FB6-488E-84A5-38A580DA90DE}.Release|x64.ActiveCfg = Release|x64\r
{2040B361-1FB6-488E-84A5-38A580DA90DE}.Release|x64.Build.0 = Release|x64\r
+ {69313D25-9F54-4FC9-9872-628A4DD79464}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {69313D25-9F54-4FC9-9872-628A4DD79464}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {69313D25-9F54-4FC9-9872-628A4DD79464}.Debug|Win32.ActiveCfg = Debug|x64\r
{69313D25-9F54-4FC9-9872-628A4DD79464}.Debug|x64.ActiveCfg = Debug|x64\r
{69313D25-9F54-4FC9-9872-628A4DD79464}.Debug|x64.Build.0 = Debug|x64\r
+ {69313D25-9F54-4FC9-9872-628A4DD79464}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {69313D25-9F54-4FC9-9872-628A4DD79464}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {69313D25-9F54-4FC9-9872-628A4DD79464}.Release|Win32.ActiveCfg = Release|x64\r
{69313D25-9F54-4FC9-9872-628A4DD79464}.Release|x64.ActiveCfg = Release|x64\r
{69313D25-9F54-4FC9-9872-628A4DD79464}.Release|x64.Build.0 = Release|x64\r
+ {D3611658-8F54-43CF-B9AF-A5CF8C1102EA}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {D3611658-8F54-43CF-B9AF-A5CF8C1102EA}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {D3611658-8F54-43CF-B9AF-A5CF8C1102EA}.Debug|Win32.ActiveCfg = Debug|x64\r
{D3611658-8F54-43CF-B9AF-A5CF8C1102EA}.Debug|x64.ActiveCfg = Debug|x64\r
{D3611658-8F54-43CF-B9AF-A5CF8C1102EA}.Debug|x64.Build.0 = Debug|x64\r
+ {D3611658-8F54-43CF-B9AF-A5CF8C1102EA}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {D3611658-8F54-43CF-B9AF-A5CF8C1102EA}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {D3611658-8F54-43CF-B9AF-A5CF8C1102EA}.Release|Win32.ActiveCfg = Release|x64\r
{D3611658-8F54-43CF-B9AF-A5CF8C1102EA}.Release|x64.ActiveCfg = Release|x64\r
{D3611658-8F54-43CF-B9AF-A5CF8C1102EA}.Release|x64.Build.0 = Release|x64\r
+ {F6223AF3-BE0B-4B61-8406-98922CE521C2}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {F6223AF3-BE0B-4B61-8406-98922CE521C2}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {F6223AF3-BE0B-4B61-8406-98922CE521C2}.Debug|Win32.ActiveCfg = Debug|x64\r
{F6223AF3-BE0B-4B61-8406-98922CE521C2}.Debug|x64.ActiveCfg = Debug|x64\r
{F6223AF3-BE0B-4B61-8406-98922CE521C2}.Debug|x64.Build.0 = Debug|x64\r
+ {F6223AF3-BE0B-4B61-8406-98922CE521C2}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {F6223AF3-BE0B-4B61-8406-98922CE521C2}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {F6223AF3-BE0B-4B61-8406-98922CE521C2}.Release|Win32.ActiveCfg = Release|x64\r
{F6223AF3-BE0B-4B61-8406-98922CE521C2}.Release|x64.ActiveCfg = Release|x64\r
{F6223AF3-BE0B-4B61-8406-98922CE521C2}.Release|x64.Build.0 = Release|x64\r
+ {816DEABA-3757-4306-AFE0-C27CF96C4DEA}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {816DEABA-3757-4306-AFE0-C27CF96C4DEA}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {816DEABA-3757-4306-AFE0-C27CF96C4DEA}.Debug|Win32.ActiveCfg = Debug|x64\r
{816DEABA-3757-4306-AFE0-C27CF96C4DEA}.Debug|x64.ActiveCfg = Debug|x64\r
{816DEABA-3757-4306-AFE0-C27CF96C4DEA}.Debug|x64.Build.0 = Debug|x64\r
+ {816DEABA-3757-4306-AFE0-C27CF96C4DEA}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {816DEABA-3757-4306-AFE0-C27CF96C4DEA}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {816DEABA-3757-4306-AFE0-C27CF96C4DEA}.Release|Win32.ActiveCfg = Release|x64\r
{816DEABA-3757-4306-AFE0-C27CF96C4DEA}.Release|x64.ActiveCfg = Release|x64\r
{816DEABA-3757-4306-AFE0-C27CF96C4DEA}.Release|x64.Build.0 = Release|x64\r
+ {82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68}.Debug|Win32.ActiveCfg = Debug|x64\r
{82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68}.Debug|x64.ActiveCfg = Debug|x64\r
{82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68}.Debug|x64.Build.0 = Debug|x64\r
+ {82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68}.Release|Win32.ActiveCfg = Release|x64\r
{82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68}.Release|x64.ActiveCfg = Release|x64\r
{82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68}.Release|x64.Build.0 = Release|x64\r
+ {88F974F0-D09F-4788-8CF8-F563209E60C1}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {88F974F0-D09F-4788-8CF8-F563209E60C1}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {88F974F0-D09F-4788-8CF8-F563209E60C1}.Debug|Win32.ActiveCfg = Debug|x64\r
{88F974F0-D09F-4788-8CF8-F563209E60C1}.Debug|x64.ActiveCfg = Debug|x64\r
{88F974F0-D09F-4788-8CF8-F563209E60C1}.Debug|x64.Build.0 = Debug|x64\r
+ {88F974F0-D09F-4788-8CF8-F563209E60C1}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {88F974F0-D09F-4788-8CF8-F563209E60C1}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {88F974F0-D09F-4788-8CF8-F563209E60C1}.Release|Win32.ActiveCfg = Release|x64\r
{88F974F0-D09F-4788-8CF8-F563209E60C1}.Release|x64.ActiveCfg = Release|x64\r
{88F974F0-D09F-4788-8CF8-F563209E60C1}.Release|x64.Build.0 = Release|x64\r
+ {3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2}.Debug|Win32.ActiveCfg = Debug|x64\r
{3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2}.Debug|x64.ActiveCfg = Debug|x64\r
{3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2}.Debug|x64.Build.0 = Debug|x64\r
+ {3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2}.Release|Win32.ActiveCfg = Release|x64\r
{3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2}.Release|x64.ActiveCfg = Release|x64\r
{3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2}.Release|x64.Build.0 = Release|x64\r
+ {02308602-7FE0-4253-B96E-22134919F56A}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {02308602-7FE0-4253-B96E-22134919F56A}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {02308602-7FE0-4253-B96E-22134919F56A}.Debug|Win32.ActiveCfg = Debug|x64\r
{02308602-7FE0-4253-B96E-22134919F56A}.Debug|x64.ActiveCfg = Debug|x64\r
{02308602-7FE0-4253-B96E-22134919F56A}.Debug|x64.Build.0 = Debug|x64\r
+ {02308602-7FE0-4253-B96E-22134919F56A}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {02308602-7FE0-4253-B96E-22134919F56A}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {02308602-7FE0-4253-B96E-22134919F56A}.Release|Win32.ActiveCfg = Release|x64\r
{02308602-7FE0-4253-B96E-22134919F56A}.Release|x64.ActiveCfg = Release|x64\r
{02308602-7FE0-4253-B96E-22134919F56A}.Release|x64.Build.0 = Release|x64\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}.Debug|Win32.ActiveCfg = Debug|x64\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}.Debug|x64.ActiveCfg = Debug|x64\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}.Debug|x64.Build.0 = Debug|x64\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}.Release|Mixed Platforms.Build.0 = Release|x64\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}.Release|Win32.ActiveCfg = Release|x64\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}.Release|x64.ActiveCfg = Release|x64\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E}.Release|x64.Build.0 = Release|x64\r
EndGlobalSection\r
GlobalSection(SolutionProperties) = preSolution\r
HideSolutionNode = FALSE\r
{82ED7ED6-8A15-40EC-A8AF-F5E712E0DA68} = {C54DA43E-4878-45DB-B76D-35970553672C}\r
{88F974F0-D09F-4788-8CF8-F563209E60C1} = {C54DA43E-4878-45DB-B76D-35970553672C}\r
{3E11FF65-A9DA-4F80-87F2-A7C6379ED5E2} = {C54DA43E-4878-45DB-B76D-35970553672C}\r
+ {7D58BD57-FDD5-46E6-A23B-ED14B5314A0E} = {C54DA43E-4878-45DB-B76D-35970553672C}\r
EndGlobalSection\r
EndGlobal\r
<ClInclude Include="concurrency\com_context.h" />\r
<ClInclude Include="concurrency\executor.h" />\r
<ClInclude Include="concurrency\lock.h" />\r
- <ClInclude Include="concurrency\target.h" />\r
<ClInclude Include="diagnostics\graph.h" />\r
<ClInclude Include="exception\exceptions.h" />\r
<ClInclude Include="exception\win32_exception.h" />\r
<ClInclude Include="os\windows\system_info.h" />\r
<ClInclude Include="enum_class.h" />\r
<ClInclude Include="os\windows\windows.h" />\r
+ <ClInclude Include="reactive.h" />\r
<ClInclude Include="stdafx.h" />\r
<ClInclude Include="utf.h" />\r
<ClInclude Include="prec_timer.h" />\r
<ClInclude Include="utility\move_on_copy.h">\r
<Filter>source\utility</Filter>\r
</ClInclude>\r
- <ClInclude Include="concurrency\target.h">\r
- <Filter>source\concurrency</Filter>\r
- </ClInclude>\r
<ClInclude Include="utility\param.h">\r
<Filter>source\utility</Filter>\r
</ClInclude>\r
<ClInclude Include="os\windows\windows.h">\r
<Filter>source\os\windows</Filter>\r
</ClInclude>\r
+ <ClInclude Include="reactive.h">\r
+ <Filter>source</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
\r
return begin_invoke(std::forward<Func>(func), prioriy).get();\r
}\r
- \r
- function_queue::size_type capacity() const /*noexcept*/ { return execution_queue_[normal_priority].capacity(); }\r
- function_queue::size_type size() const /*noexcept*/ { return execution_queue_[normal_priority].size(); }\r
- bool empty() const /*noexcept*/ { return execution_queue_[normal_priority].empty(); }\r
- bool is_running() const /*noexcept*/ { return is_running_; } \r
- \r
-private:\r
- \r
- void execute() // noexcept\r
+\r
+ void yield() // noexcept\r
{\r
+ if(boost::this_thread::get_id() != thread_.get_id())\r
+ BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Executor can only yield inside of thread context."));\r
+\r
std::function<void()> func;\r
execution_queue_[normal_priority].pop(func); \r
\r
if(func)\r
func();\r
}\r
+ \r
+ function_queue::size_type capacity() const /*noexcept*/ { return execution_queue_[normal_priority].capacity(); }\r
+ function_queue::size_type size() const /*noexcept*/ { return execution_queue_[normal_priority].size(); }\r
+ bool empty() const /*noexcept*/ { return execution_queue_[normal_priority].empty(); }\r
+ bool is_running() const /*noexcept*/ { return is_running_; } \r
+ \r
+private:\r
+ \r
\r
void run() // noexcept\r
{\r
{\r
try\r
{\r
- execute();\r
+ yield();\r
}\r
catch(...)\r
{\r
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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
-template<typename T>\r
-struct target\r
-{\r
- virtual void send(const T&) = 0;\r
-};\r
-\r
-}
\ No newline at end of file
--- /dev/null
+#pragma once\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
+ typedef T value_type;\r
+ \r
+ observer()\r
+ {\r
+ }\r
+\r
+ virtual ~observer()\r
+ {\r
+ }\r
+\r
+ virtual void on_next(const T&) = 0;\r
+};\r
+\r
+template<typename T>\r
+class observable\r
+{\r
+ observable(const observable&);\r
+ observable& operator=(const observable&);\r
+public:\r
+ typedef T value_type;\r
+ typedef observer<T> observer;\r
+ typedef std::weak_ptr<observer> observer_ptr;\r
+\r
+ observable()\r
+ {\r
+ }\r
+\r
+ virtual ~observable()\r
+ {\r
+ }\r
+\r
+ virtual void subscribe(const observer_ptr&) = 0;\r
+ virtual void unsubscribe(const observer_ptr&) = 0;\r
+};\r
+\r
+template<typename I, typename O = I>\r
+struct subject : public observer<I>, public observable<O>\r
+{\r
+ typedef typename observable<O>::observer observer;\r
+ typedef typename observable<O>::observer_ptr observer_ptr;\r
+\r
+ virtual ~subject()\r
+ {\r
+ }\r
+};\r
+\r
+namespace detail {\r
+\r
+template<typename T>\r
+struct true_func\r
+{\r
+ bool operator()(T)\r
+ {\r
+ return true;\r
+ }\r
+};\r
+\r
+template<typename T>\r
+struct void_func\r
+{\r
+ void operator()(T)\r
+ {\r
+ }\r
+};\r
+\r
+template<typename I, typename O>\r
+struct forward_func\r
+{\r
+ forward_func(std::function<O(const I&)> func)\r
+ : func_(std::move(func))\r
+ {\r
+ }\r
+\r
+ O operator()(const I& value)\r
+ {\r
+ return func_(value);\r
+ }\r
+\r
+ std::function<O(const I&)> func_;\r
+};\r
+\r
+template<typename I>\r
+struct forward_func<I, I>\r
+{\r
+ const I& operator()(const I& value)\r
+ {\r
+ return value;\r
+ }\r
+};\r
+\r
+}\r
+\r
+template<typename T, typename C, typename F = detail::true_func<T>>\r
+class observer_function : public observer<T>\r
+{\r
+public:\r
+ observer_function()\r
+ {\r
+ }\r
+\r
+ observer_function(C func)\r
+ : func_(std::move(func))\r
+ {\r
+ }\r
+\r
+ observer_function(C func, F filter)\r
+ : func_(std::move(func))\r
+ , filter_(std::move(filter))\r
+ {\r
+ }\r
+\r
+ observer_function(const observer_function& other)\r
+ : func_(other.func_)\r
+ , filter_(other.filter_)\r
+ {\r
+ }\r
+\r
+ observer_function(observer_function&& other)\r
+ : func_(std::move(other.func_))\r
+ , filter_(std::move(other.filter_))\r
+ {\r
+ }\r
+\r
+ observer_function& operator=(observer_function other)\r
+ {\r
+ other.swap(*this);\r
+ }\r
+\r
+ void swap(observer_function& other)\r
+ {\r
+ std::swap(func_, other.func_);\r
+ std::swap(filter_, other.filter_);\r
+ }\r
+ \r
+ virtual void on_next(const T& e) override\r
+ {\r
+ if(!filter_(e))\r
+ return;\r
+\r
+ func_(e);\r
+ }\r
+private:\r
+ C func_;\r
+ F filter_;\r
+};\r
+\r
+template<typename T, typename F>\r
+class observer_function<T, detail::void_func<T>, F> : public observer<T>\r
+{\r
+public: \r
+ virtual void on_next(const T& e) override\r
+ {\r
+ }\r
+};\r
+\r
+template<typename I, typename O = I, typename F = detail::true_func<const I&>, typename T = detail::forward_func<I, O>>\r
+class basic_subject : public subject<I, O>\r
+{ \r
+ template <typename, typename, typename, typename> friend class basic_subject;\r
+\r
+ basic_subject(const basic_subject&);\r
+ basic_subject& operator=(const basic_subject&);\r
+public: \r
+ typedef typename subject<I, O>::observer observer;\r
+ typedef typename subject<I, O>::observer_ptr observer_ptr;\r
+ typedef F filter;\r
+ typedef T transform;\r
+\r
+ basic_subject()\r
+ {\r
+ }\r
+ \r
+ basic_subject(F filter)\r
+ : filter_(std::move(filter))\r
+ {\r
+ }\r
+ \r
+ basic_subject(T transform)\r
+ : transform_(std::move(transform))\r
+ {\r
+ }\r
+ \r
+ basic_subject(std::function<O(const I&)> transform)\r
+ : transform_(std::move(transform))\r
+ {\r
+ }\r
+\r
+ basic_subject(F filter, T transform)\r
+ : filter_(std::move(filter))\r
+ , transform_(std::move(transform))\r
+ {\r
+ }\r
+ \r
+ virtual ~basic_subject()\r
+ {\r
+ }\r
+ \r
+ template<typename F1, typename T1>\r
+ basic_subject(basic_subject<typename observer::value_type, typename observable::value_type, F1, T1>&& other)\r
+ : observers_(std::move(other.observers_))\r
+ , filter_(std::move(other.filter_))\r
+ , transform_(std::move(other.transform_))\r
+ {\r
+ }\r
+ \r
+ template<typename F1, typename T1>\r
+ basic_subject& operator=(basic_subject<typename observer::value_type, typename observable::value_type, F1, T1>&& other)\r
+ {\r
+ other.swap(*this);\r
+ return *this;\r
+ }\r
+ \r
+ template<typename F1, typename T1>\r
+ void swap(basic_subject<typename observer::value_type, typename observable::value_type, F1, T1>& other)\r
+ { \r
+ tbb::spin_rw_mutex::scoped_lock lock(mutex_, true);\r
+ tbb::spin_rw_mutex::scoped_lock other_lock(other.mutex_, true);\r
+\r
+ std::swap(observers_, other.observers_);\r
+ std::swap(filter_, other.filter_); \r
+ }\r
+\r
+ virtual void clear()\r
+ {\r
+ tbb::spin_rw_mutex::scoped_lock lock(mutex_, true);\r
+\r
+ observers_.clear();\r
+ }\r
+ \r
+ virtual 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
+ virtual 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
+ virtual void on_next(const I& e) override\r
+ { \r
+ if(!filter_(e))\r
+ return;\r
+\r
+ std::vector<std::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(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
+ const auto& e2 = transform_(e);\r
+ for(auto it = std::begin(observers); it != std::end(observers); ++it)\r
+ (*it)->on_next(e2);\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
+ F filter_;\r
+ T transform_;\r
+};\r
+\r
+template<typename F>\r
+std::shared_ptr<basic_subject<typename std::decay<typename detail::function_traits<F>::arg1_type>::type, typename std::decay<typename detail::function_traits<F>::arg1_type>::type, F>> \r
+make_filter(F filter)\r
+{\r
+ return std::make_shared<basic_subject<std::decay<typename detail::function_traits<F>::arg1_type>::type, typename std::decay<typename detail::function_traits<F>::arg1_type>::type, F>>(std::move(filter));\r
+}\r
+\r
+template<typename F>\r
+std::shared_ptr<observer_function<typename std::decay<typename detail::function_traits<F>::arg1_type>::type, F>> \r
+make_observer(F func)\r
+{\r
+ return std::make_shared<observer_function<std::decay<typename detail::function_traits<F>::arg1_type>::type, F>>(std::move(func));\r
+}\r
+\r
+template<typename F1, typename F2>\r
+std::shared_ptr<observer_function<typename std::decay<typename detail::function_traits<F1>::arg1_type>::type, F1, F2>> \r
+make_observer(F1 func, F2 filter)\r
+{\r
+ return std::make_shared<observer_function<std::decay<typename detail::function_traits<F1>::arg1_type>::type, F1, F2>>(std::move(func), std::move(filter));\r
+}\r
+\r
+}}\r
+\r
+namespace std {\r
+ \r
+template <typename T, typename F1, typename F2>\r
+void swap(caspar::reactive::observer_function<T, F1>& lhs, caspar::reactive::observer_function<T, F2>& rhs) \r
+{\r
+ lhs.swap(rhs);\r
+}\r
+\r
+template <typename I, typename O, typename F1, typename F2, typename T1, typename T2>\r
+void swap(caspar::reactive::basic_subject<I, O, F1, T1>& lhs, caspar::reactive::basic_subject<I, O, F2, T2>& rhs) \r
+{\r
+ lhs.swap(rhs);\r
+}\r
+\r
+} // std\r
#include <common/memory/safe_ptr.h>\r
#include <common/exception/exceptions.h>\r
#include <core/video_format.h>\r
-#include <core/mixer/read_frame.h>\r
+#include <core/frame.h>\r
\r
#include <boost/circular_buffer.hpp>\r
\r
consumer_->initialize(format_desc, channel_index);\r
}\r
\r
- virtual bool send(const safe_ptr<read_frame>& frame) override\r
+ virtual bool send(const safe_ptr<const frame>& frame) override\r
{ \r
if(audio_cadence_.size() == 1)\r
return consumer_->send(frame);\r
{\r
struct empty_frame_consumer : public frame_consumer\r
{\r
- virtual bool send(const safe_ptr<read_frame>&) override {return false;}\r
+ virtual bool send(const safe_ptr<const frame>&) override {return false;}\r
virtual void initialize(const video_format_desc&, int) override{}\r
virtual std::wstring print() const override {return L"empty";}\r
virtual bool has_synchronization_clock() const override {return false;}\r
frame_consumer(){}\r
virtual ~frame_consumer() {}\r
\r
- virtual bool send(const safe_ptr<class read_frame>& frame) = 0;\r
+ virtual bool send(const safe_ptr<const struct frame>& frame) = 0;\r
virtual void initialize(const struct video_format_desc& format_desc, int channel_index) = 0;\r
virtual std::wstring print() const = 0;\r
virtual boost::property_tree::wptree info() const = 0;\r
#include "frame_consumer.h"\r
\r
#include "../video_format.h"\r
-#include "../mixer/gpu/ogl_device.h"\r
+#include "../mixer/gpu/accelerator.h"\r
#include "../mixer/read_frame.h"\r
\r
#include <common/concurrency/executor.h>\r
struct output::impl\r
{ \r
const int channel_index_;\r
- const safe_ptr<diagnostics::graph> graph_;\r
- boost::timer consume_timer_;\r
\r
video_format_desc format_desc_;\r
\r
\r
prec_timer sync_timer_;\r
\r
- boost::circular_buffer<safe_ptr<read_frame>> frames_;\r
+ boost::circular_buffer<safe_ptr<const frame>> frames_;\r
\r
executor executor_;\r
\r
public:\r
- impl(const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc, int channel_index) \r
+ impl(const video_format_desc& format_desc, int channel_index) \r
: channel_index_(channel_index)\r
- , graph_(graph)\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
+ executor_.set_capacity(1);\r
} \r
\r
void add(int index, safe_ptr<frame_consumer> consumer)\r
{\r
return boost::range::count_if(consumers_ | boost::adaptors::map_values, [](const safe_ptr<frame_consumer>& x){return x->has_synchronization_clock();}) > 0;\r
}\r
-\r
- void send(const std::pair<safe_ptr<read_frame>, std::shared_ptr<void>>& packet)\r
+ \r
+ void operator()(safe_ptr<const frame> input_frame, const video_format_desc& format_desc)\r
{\r
executor_.begin_invoke([=]\r
{\r
try\r
- {\r
- consume_timer_.restart();\r
-\r
- auto input_frame = packet.first;\r
-\r
+ { \r
if(!has_synchronization_clock())\r
sync_timer_.tick(1.0/format_desc_.fps);\r
+ \r
+ if(format_desc_ != format_desc)\r
+ set_video_format_desc(format_desc);\r
\r
if(input_frame->image_data().size() != format_desc_.size)\r
{\r
}\r
}\r
}\r
- \r
- graph_->set_value("consume-time", consume_timer_.elapsed()*format_desc_.fps*0.5);\r
}\r
catch(...)\r
{\r
}\r
};\r
\r
-output::output(const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc, int channel_index) : impl_(new impl(graph, format_desc, channel_index)){}\r
+output::output(const video_format_desc& format_desc, int channel_index) : impl_(new impl(format_desc, channel_index)){}\r
void output::add(int index, const safe_ptr<frame_consumer>& consumer){impl_->add(index, consumer);}\r
void output::add(const safe_ptr<frame_consumer>& consumer){impl_->add(consumer);}\r
void output::remove(int index){impl_->remove(index);}\r
void output::remove(const safe_ptr<frame_consumer>& consumer){impl_->remove(consumer);}\r
-void output::send(const std::pair<safe_ptr<read_frame>, std::shared_ptr<void>>& frame) {impl_->send(frame); }\r
-void output::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
boost::unique_future<boost::property_tree::wptree> output::info() const{return impl_->info();}\r
+void output::operator()(safe_ptr<const frame> frame, const video_format_desc& format_desc){(*impl_)(std::move(frame), format_desc);}\r
}}
\ No newline at end of file
\r
#include <common/forward.h>\r
#include <common/memory/safe_ptr.h>\r
-#include <common/concurrency/target.h>\r
+#include <common/reactive.h>\r
\r
#include <boost/noncopyable.hpp>\r
#include <boost/property_tree/ptree_fwd.hpp>\r
\r
namespace caspar { namespace core {\r
\r
-class output sealed : public target<std::pair<safe_ptr<class read_frame>, std::shared_ptr<void>>>\r
- , boost::noncopyable\r
+class output sealed : boost::noncopyable\r
{\r
public:\r
- explicit output(const safe_ptr<diagnostics::graph>& graph, const struct video_format_desc& format_desc, int channel_index);\r
-\r
- // target\r
+ explicit output(const struct video_format_desc& format_desc, int channel_index);\r
\r
- virtual void send(const std::pair<safe_ptr<class read_frame>, std::shared_ptr<void>>& frame) override;\r
-\r
// output\r
+\r
+ void operator()(safe_ptr<const struct frame> frame, const struct video_format_desc& format_desc);\r
\r
void add(const safe_ptr<struct frame_consumer>& consumer);\r
void add(int index, const safe_ptr<struct frame_consumer>& consumer);\r
void remove(const safe_ptr<struct frame_consumer>& consumer);\r
void remove(int index);\r
\r
- void set_video_format_desc(const struct video_format_desc& format_desc);\r
-\r
boost::unique_future<boost::property_tree::wptree> info() const;\r
+\r
private:\r
struct impl;\r
safe_ptr<impl> impl_;\r
</Lib>\r
</ItemDefinitionGroup>\r
<ItemGroup>\r
+ <ClInclude Include="frame.h" />\r
<ClInclude Include="mixer\audio\audio_util.h" />\r
+ <ClInclude Include="mixer\gpu\device_buffer.h" />\r
+ <ClInclude Include="mixer\gpu\host_buffer.h" />\r
+ <ClInclude Include="mixer\gpu\image\blending_glsl.h" />\r
+ <ClInclude Include="mixer\gpu\image\image_kernel.h" />\r
+ <ClInclude Include="mixer\gpu\image\image_mixer.h" />\r
+ <ClInclude Include="mixer\gpu\image\image_shader.h" />\r
+ <ClInclude Include="mixer\gpu\accelerator.h" />\r
<ClInclude Include="mixer\gpu\shader.h" />\r
<ClInclude Include="mixer\image\blend_modes.h" />\r
- <ClInclude Include="mixer\image\shader\blending_glsl.h" />\r
- <ClInclude Include="mixer\image\shader\image_shader.h" />\r
- <ClInclude Include="producer\channel\channel_producer.h" />\r
- <ClInclude Include="producer\playlist\playlist_producer.h" />\r
<ClInclude Include="video_channel.h" />\r
<ClInclude Include="consumer\output.h" />\r
<ClInclude Include="consumer\frame_consumer.h" />\r
<ClInclude Include="mixer\audio\audio_mixer.h" />\r
<ClInclude Include="mixer\mixer.h" />\r
- <ClInclude Include="mixer\gpu\device_buffer.h" />\r
- <ClInclude Include="mixer\gpu\host_buffer.h" />\r
- <ClInclude Include="mixer\gpu\ogl_device.h" />\r
- <ClInclude Include="mixer\image\image_kernel.h" />\r
<ClInclude Include="mixer\image\image_mixer.h" />\r
<ClInclude Include="mixer\read_frame.h" />\r
<ClInclude Include="mixer\write_frame.h" />\r
<ClInclude Include="StdAfx.h" />\r
</ItemGroup>\r
<ItemGroup>\r
- <ClCompile Include="mixer\gpu\shader.cpp">\r
+ <ClCompile Include="mixer\gpu\device_buffer.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
+ <ClCompile Include="mixer\gpu\host_buffer.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
+ <ClCompile Include="mixer\gpu\image\image_kernel.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="mixer\image\blend_modes.cpp">\r
+ <ClCompile Include="mixer\gpu\image\image_mixer.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
+ <ClCompile Include="mixer\gpu\image\image_shader.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
+ <ClCompile Include="mixer\gpu\accelerator.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="mixer\image\shader\image_shader.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../../stdafx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../../stdafx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
- <ClCompile Include="producer\channel\channel_producer.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <ClCompile Include="mixer\gpu\shader.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="producer\playlist\playlist_producer.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../stdafx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../stdafx.h</PrecompiledHeaderFile>\r
+ <ClCompile Include="mixer\image\blend_modes.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
<ClCompile Include="video_channel.cpp" />\r
<ClCompile Include="consumer\frame_consumer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="mixer\gpu\device_buffer.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
- <ClCompile Include="mixer\gpu\host_buffer.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
- <ClCompile Include="mixer\gpu\ogl_device.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
- <ClCompile Include="mixer\image\image_kernel.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
- <ClCompile Include="mixer\image\image_mixer.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
<ClCompile Include="mixer\read_frame.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../StdAfx.h</PrecompiledHeaderFile>\r
<Filter Include="source">\r
<UniqueIdentifier>{cc341f3a-7ea0-424a-bacd-c40aa8e7822b}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="source\mixer">\r
+ <UniqueIdentifier>{e480e128-a351-4dc6-a7ab-f58b480f6afd}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="source\mixer\audio">\r
+ <UniqueIdentifier>{0951ac32-6cd0-4a9f-865d-6f86600f12f8}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="source\mixer\image">\r
+ <UniqueIdentifier>{1cca1d41-f9b1-4b7b-b34f-8a88dcb5b904}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="source\consumer">\r
+ <UniqueIdentifier>{35d7835f-f813-4b4b-8d8d-8a35dfef68d3}</UniqueIdentifier>\r
+ </Filter>\r
<Filter Include="source\producer">\r
<UniqueIdentifier>{71accefc-1437-4e1d-9ff7-9de654a32df9}</UniqueIdentifier>\r
</Filter>\r
<Filter Include="source\producer\separated">\r
<UniqueIdentifier>{cf834e89-32d6-47bc-8d5a-10e032f88e15}</UniqueIdentifier>\r
</Filter>\r
- <Filter Include="source\mixer">\r
- <UniqueIdentifier>{e480e128-a351-4dc6-a7ab-f58b480f6afd}</UniqueIdentifier>\r
- </Filter>\r
- <Filter Include="source\mixer\audio">\r
- <UniqueIdentifier>{0951ac32-6cd0-4a9f-865d-6f86600f12f8}</UniqueIdentifier>\r
- </Filter>\r
- <Filter Include="source\mixer\image">\r
- <UniqueIdentifier>{1cca1d41-f9b1-4b7b-b34f-8a88dcb5b904}</UniqueIdentifier>\r
- </Filter>\r
<Filter Include="source\mixer\gpu">\r
- <UniqueIdentifier>{2d2ae7ff-03d7-4e8c-a298-fb41ee42a885}</UniqueIdentifier>\r
+ <UniqueIdentifier>{b2af87a2-9528-4f82-b3f1-b7409ca15acd}</UniqueIdentifier>\r
</Filter>\r
- <Filter Include="source\consumer">\r
- <UniqueIdentifier>{35d7835f-f813-4b4b-8d8d-8a35dfef68d3}</UniqueIdentifier>\r
- </Filter>\r
- <Filter Include="source\producer\playlist">\r
- <UniqueIdentifier>{80ce21ca-5ecd-48c1-97d2-c20ea8e2f2b6}</UniqueIdentifier>\r
- </Filter>\r
- <Filter Include="source\mixer\image\shader">\r
- <UniqueIdentifier>{e0a140f8-e217-465c-a934-163b7ea786be}</UniqueIdentifier>\r
- </Filter>\r
- <Filter Include="source\producer\channel">\r
- <UniqueIdentifier>{e5def302-a2b5-4e1f-8565-d6ef3927b31f}</UniqueIdentifier>\r
+ <Filter Include="source\mixer\gpu\image">\r
+ <UniqueIdentifier>{d8d99a8a-42f9-48a3-b8a5-c07228226eab}</UniqueIdentifier>\r
</Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="producer\frame\frame_factory.h">\r
<Filter>source\producer\frame</Filter>\r
</ClInclude>\r
- <ClInclude Include="mixer\image\image_kernel.h">\r
- <Filter>source\mixer\image</Filter>\r
- </ClInclude>\r
<ClInclude Include="mixer\image\image_mixer.h">\r
<Filter>source\mixer\image</Filter>\r
</ClInclude>\r
- <ClInclude Include="mixer\gpu\host_buffer.h">\r
- <Filter>source\mixer\gpu</Filter>\r
- </ClInclude>\r
- <ClInclude Include="mixer\gpu\ogl_device.h">\r
- <Filter>source\mixer\gpu</Filter>\r
- </ClInclude>\r
- <ClInclude Include="mixer\gpu\device_buffer.h">\r
- <Filter>source\mixer\gpu</Filter>\r
- </ClInclude>\r
<ClInclude Include="mixer\audio\audio_mixer.h">\r
<Filter>source\mixer\audio</Filter>\r
</ClInclude>\r
<ClInclude Include="video_channel.h">\r
<Filter>source</Filter>\r
</ClInclude>\r
- <ClInclude Include="mixer\gpu\shader.h">\r
- <Filter>source\mixer\gpu</Filter>\r
- </ClInclude>\r
<ClInclude Include="producer\frame\frame_transform.h">\r
<Filter>source\producer\frame</Filter>\r
</ClInclude>\r
<ClInclude Include="mixer\audio\audio_util.h">\r
<Filter>source\mixer\audio</Filter>\r
</ClInclude>\r
- <ClInclude Include="producer\playlist\playlist_producer.h">\r
- <Filter>source\producer\playlist</Filter>\r
+ <ClInclude Include="producer\separated\separated_producer.h">\r
+ <Filter>source\producer\separated</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="mixer\gpu\device_buffer.h">\r
+ <Filter>source\mixer\gpu</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="mixer\gpu\host_buffer.h">\r
+ <Filter>source\mixer\gpu</Filter>\r
</ClInclude>\r
- <ClInclude Include="mixer\image\shader\image_shader.h">\r
- <Filter>source\mixer\image\shader</Filter>\r
+ <ClInclude Include="mixer\gpu\shader.h">\r
+ <Filter>source\mixer\gpu</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="mixer\gpu\image\image_mixer.h">\r
+ <Filter>source\mixer\gpu\image</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="mixer\gpu\image\image_kernel.h">\r
+ <Filter>source\mixer\gpu\image</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="mixer\gpu\image\blending_glsl.h">\r
+ <Filter>source\mixer\gpu\image</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="mixer\gpu\image\image_shader.h">\r
+ <Filter>source\mixer\gpu\image</Filter>\r
</ClInclude>\r
<ClInclude Include="mixer\image\blend_modes.h">\r
<Filter>source\mixer\image</Filter>\r
</ClInclude>\r
- <ClInclude Include="mixer\image\shader\blending_glsl.h">\r
- <Filter>source\mixer\image\shader</Filter>\r
- </ClInclude>\r
- <ClInclude Include="producer\channel\channel_producer.h">\r
- <Filter>source\producer\channel</Filter>\r
+ <ClInclude Include="mixer\gpu\accelerator.h">\r
+ <Filter>source\mixer\gpu</Filter>\r
</ClInclude>\r
- <ClInclude Include="producer\separated\separated_producer.h">\r
- <Filter>source\producer\separated</Filter>\r
+ <ClInclude Include="frame.h">\r
+ <Filter>source</Filter>\r
</ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="producer\frame\basic_frame.cpp">\r
<Filter>source\producer\frame</Filter>\r
</ClCompile>\r
- <ClCompile Include="mixer\image\image_mixer.cpp">\r
- <Filter>source\mixer\image</Filter>\r
- </ClCompile>\r
- <ClCompile Include="mixer\image\image_kernel.cpp">\r
- <Filter>source\mixer\image</Filter>\r
- </ClCompile>\r
- <ClCompile Include="mixer\gpu\host_buffer.cpp">\r
- <Filter>source\mixer\gpu</Filter>\r
- </ClCompile>\r
- <ClCompile Include="mixer\gpu\ogl_device.cpp">\r
- <Filter>source\mixer\gpu</Filter>\r
- </ClCompile>\r
- <ClCompile Include="mixer\gpu\device_buffer.cpp">\r
- <Filter>source\mixer\gpu</Filter>\r
- </ClCompile>\r
<ClCompile Include="mixer\audio\audio_mixer.cpp">\r
<Filter>source\mixer\audio</Filter>\r
</ClCompile>\r
<ClCompile Include="video_format.cpp">\r
<Filter>source</Filter>\r
</ClCompile>\r
- <ClCompile Include="mixer\gpu\shader.cpp">\r
- <Filter>source\mixer\gpu</Filter>\r
- </ClCompile>\r
<ClCompile Include="producer\frame\frame_transform.cpp">\r
<Filter>source\producer\frame</Filter>\r
</ClCompile>\r
- <ClCompile Include="producer\playlist\playlist_producer.cpp">\r
- <Filter>source\producer\playlist</Filter>\r
- </ClCompile>\r
<ClCompile Include="producer\frame_producer.cpp">\r
<Filter>source\producer</Filter>\r
</ClCompile>\r
- <ClCompile Include="mixer\image\shader\image_shader.cpp">\r
- <Filter>source\mixer\image\shader</Filter>\r
+ <ClCompile Include="mixer\gpu\device_buffer.cpp">\r
+ <Filter>source\mixer\gpu</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="mixer\gpu\host_buffer.cpp">\r
+ <Filter>source\mixer\gpu</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="mixer\gpu\shader.cpp">\r
+ <Filter>source\mixer\gpu</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="mixer\gpu\image\image_shader.cpp">\r
+ <Filter>source\mixer\gpu\image</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="mixer\gpu\image\image_mixer.cpp">\r
+ <Filter>source\mixer\gpu\image</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="mixer\gpu\image\image_kernel.cpp">\r
+ <Filter>source\mixer\gpu\image</Filter>\r
</ClCompile>\r
<ClCompile Include="mixer\image\blend_modes.cpp">\r
<Filter>source\mixer\image</Filter>\r
</ClCompile>\r
- <ClCompile Include="producer\channel\channel_producer.cpp">\r
- <Filter>source\producer\channel</Filter>\r
+ <ClCompile Include="mixer\gpu\accelerator.cpp">\r
+ <Filter>source\mixer\gpu</Filter>\r
</ClCompile>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include <boost/noncopyable.hpp>\r
+#include <boost/range.hpp>\r
+\r
+#include <stdint.h>\r
+\r
+#include "producer/frame/pixel_format.h"\r
+#include "video_format.h"\r
+\r
+namespace caspar { namespace core {\r
+\r
+struct 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
+}}
\ No newline at end of file
audio_buffer_ps audio_data;\r
};\r
\r
-struct audio_mixer::impl\r
+struct audio_mixer::impl : boost::noncopyable\r
{\r
- safe_ptr<diagnostics::graph> graph_;\r
std::stack<core::frame_transform> transform_stack_;\r
std::map<const void*, audio_stream> audio_streams_;\r
std::vector<audio_item> items_;\r
video_format_desc format_desc_;\r
\r
public:\r
- impl(const safe_ptr<diagnostics::graph>& graph)\r
- : graph_(graph)\r
+ impl()\r
{\r
- graph_->set_color("volume", diagnostics::color(1.0f, 0.8f, 0.1f));\r
transform_stack_.push(core::frame_transform());\r
}\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
- auto max = boost::range::max_element(result);\r
-\r
- graph_->set_value("volume", static_cast<double>(std::abs(*max))/std::numeric_limits<int32_t>::max());\r
-\r
+ \r
return result;\r
}\r
};\r
\r
-audio_mixer::audio_mixer(const safe_ptr<diagnostics::graph>& graph) : impl_(new impl(graph)){}\r
+audio_mixer::audio_mixer() : impl_(new impl()){}\r
void audio_mixer::begin(core::basic_frame& frame){impl_->begin(frame);}\r
void audio_mixer::visit(core::write_frame& frame){impl_->visit(frame);}\r
void audio_mixer::end(){impl_->end();}\r
class audio_mixer sealed : public frame_visitor\r
{\r
public:\r
- audio_mixer(const safe_ptr<diagnostics::graph>& graph);\r
+ audio_mixer();\r
\r
virtual void begin(core::basic_frame& frame);\r
virtual void visit(core::write_frame& frame);\r
\r
#include "../../stdafx.h"\r
\r
-#include "ogl_device.h"\r
+#include "accelerator.h"\r
\r
#include "shader.h"\r
\r
\r
#include <gl/glew.h>\r
\r
-namespace caspar { namespace core {\r
+namespace caspar { namespace core { namespace gpu {\r
\r
-ogl_device::ogl_device() \r
- : executor_(L"ogl_device")\r
+accelerator::accelerator() \r
+ : executor_(L"accelerator")\r
, attached_texture_(0)\r
, attached_fbo_(0)\r
, active_shader_(0)\r
});\r
}\r
\r
-ogl_device::~ogl_device()\r
+accelerator::~accelerator()\r
{\r
invoke([=]\r
{\r
});\r
}\r
\r
-safe_ptr<device_buffer> ogl_device::allocate_device_buffer(int width, int height, int stride)\r
+safe_ptr<device_buffer> accelerator::allocate_device_buffer(int width, int height, int stride)\r
{\r
std::shared_ptr<device_buffer> buffer;\r
try\r
return make_safe_ptr(buffer);\r
}\r
\r
-safe_ptr<device_buffer> ogl_device::create_device_buffer(int width, int height, int stride)\r
+safe_ptr<device_buffer> accelerator::create_device_buffer(int width, int height, int stride)\r
{\r
CASPAR_VERIFY(stride > 0 && stride < 5);\r
CASPAR_VERIFY(width > 0 && height > 0);\r
});\r
}\r
\r
-safe_ptr<host_buffer> ogl_device::allocate_host_buffer(int size, host_buffer::usage usage)\r
+safe_ptr<host_buffer> accelerator::allocate_host_buffer(int size, host_buffer::usage usage)\r
{\r
std::shared_ptr<host_buffer> buffer;\r
\r
return make_safe_ptr(buffer);\r
}\r
\r
-safe_ptr<host_buffer> ogl_device::create_host_buffer(int size, host_buffer::usage usage)\r
+safe_ptr<host_buffer> accelerator::create_host_buffer(int size, host_buffer::usage usage)\r
{\r
CASPAR_VERIFY(usage == host_buffer::usage::write_only || usage == host_buffer::usage::read_only);\r
CASPAR_VERIFY(size > 0);\r
});\r
}\r
\r
-safe_ptr<ogl_device> ogl_device::create()\r
+safe_ptr<accelerator> accelerator::create()\r
{\r
- return safe_ptr<ogl_device>(new ogl_device());\r
+ return safe_ptr<accelerator>(new accelerator());\r
}\r
\r
-boost::unique_future<void> ogl_device::gc()\r
+boost::unique_future<void> accelerator::gc()\r
{ \r
return begin_invoke([=]\r
{\r
}, high_priority);\r
}\r
\r
-std::wstring ogl_device::version()\r
+std::wstring accelerator::version()\r
{ \r
static std::wstring ver = L"Not found";\r
try\r
}\r
\r
\r
-void ogl_device::enable(GLenum cap)\r
+void accelerator::enable(GLenum cap)\r
{\r
auto& val = caps_[cap];\r
if(!val)\r
}\r
}\r
\r
-void ogl_device::disable(GLenum cap)\r
+void accelerator::disable(GLenum cap)\r
{\r
auto& val = caps_[cap];\r
if(val)\r
}\r
}\r
\r
-void ogl_device::viewport(int x, int y, int width, int height)\r
+void accelerator::viewport(int x, int y, int width, int height)\r
{\r
std::array<GLint, 4> viewport = {{x, y, width, height}};\r
if(viewport != viewport_)\r
}\r
}\r
\r
-void ogl_device::scissor(int x, int y, int width, int height)\r
+void accelerator::scissor(int x, int y, int width, int height)\r
{\r
std::array<GLint, 4> scissor = {{x, y, width, height}};\r
if(scissor != scissor_)\r
}\r
}\r
\r
-void ogl_device::stipple_pattern(const std::array<GLubyte, 32*32>& pattern)\r
+void accelerator::stipple_pattern(const std::array<GLubyte, 32*32>& pattern)\r
{\r
if(pattern_ != pattern)\r
{ \r
}\r
}\r
\r
-void ogl_device::attach(device_buffer& texture)\r
+void accelerator::attach(device_buffer& texture)\r
{ \r
if(attached_texture_ != texture.id())\r
{\r
}\r
}\r
\r
-void ogl_device::clear(device_buffer& texture)\r
+void accelerator::clear(device_buffer& texture)\r
{ \r
attach(texture);\r
GL(glClear(GL_COLOR_BUFFER_BIT));\r
}\r
\r
-void ogl_device::use(shader& shader)\r
+void accelerator::use(shader& shader)\r
{\r
if(active_shader_ != shader.id())\r
{ \r
}\r
}\r
\r
-void ogl_device::blend_func(int c1, int c2, int a1, int a2)\r
+void accelerator::blend_func(int c1, int c2, int a1, int a2)\r
{\r
std::array<int, 4> func = {c1, c2, a1, a2};\r
\r
}\r
}\r
\r
-void ogl_device::blend_func(int c1, int c2)\r
+void accelerator::blend_func(int c1, int c2)\r
{\r
blend_func(c1, c2, c1, c2);\r
}\r
+ \r
+boost::unique_future<safe_ptr<device_buffer>> accelerator::copy_async(safe_ptr<host_buffer>&& source, int width, int height, int stride)\r
+{\r
+ return executor_.begin_invoke([=]() -> safe_ptr<device_buffer>\r
+ {\r
+ auto result = create_device_buffer(width, height, stride);\r
+ result->copy_from(source);\r
+ return result;\r
+ }, high_priority);\r
+}\r
\r
-}}\r
+}}}\r
\r
\r
FORWARD1(boost, template<typename> class unique_future);\r
\r
-namespace caspar { namespace core {\r
+namespace caspar { namespace core { namespace gpu {\r
\r
class shader;\r
\r
}\r
};\r
\r
-class ogl_device : public std::enable_shared_from_this<ogl_device>\r
+class accelerator : public std::enable_shared_from_this<accelerator>\r
, boost::noncopyable\r
{ \r
std::array<GLubyte, 32*32> pattern_;\r
\r
executor executor_;\r
\r
- ogl_device();\r
+ accelerator();\r
public: \r
- static safe_ptr<ogl_device> create();\r
- ~ogl_device();\r
+ static safe_ptr<accelerator> create();\r
+ ~accelerator();\r
\r
// Not thread-safe, must be called inside of context\r
void enable(GLenum cap);\r
\r
std::wstring version();\r
\r
+ boost::unique_future<safe_ptr<device_buffer>> copy_async(safe_ptr<host_buffer>&& source, int width, int height, int stride);\r
+\r
private:\r
safe_ptr<device_buffer> allocate_device_buffer(int width, int height, int stride);\r
safe_ptr<host_buffer> allocate_host_buffer(int size, host_buffer::usage usage);\r
};\r
\r
-}}
\ No newline at end of file
+}}}
\ No newline at end of file
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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 "device_buffer.h"\r
-#include "ogl_device.h"\r
-\r
-#include <common/exception/exceptions.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 core {\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
-unsigned int format(int stride)\r
-{\r
- return FORMAT[stride];\r
-}\r
-\r
-static tbb::atomic<int> g_total_count;\r
-\r
-struct device_buffer::impl : boost::noncopyable\r
-{\r
- std::weak_ptr<ogl_device> parent_;\r
- GLuint id_;\r
-\r
- const int width_;\r
- const int height_;\r
- const int stride_;\r
-public:\r
- impl(std::weak_ptr<ogl_device> parent, int width, int height, int stride) \r
- : parent_(parent)\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) << "[device_buffer] [" << ++g_total_count << L"] allocated size:" << width*height*stride; \r
- } \r
-\r
- ~impl()\r
- {\r
- try\r
- {\r
- GL(glDeleteTextures(1, &id_));\r
- //CASPAR_LOG(trace) << "[device_buffer] [" << --g_total_count << L"] deallocated size:" << width_*height_*stride_;\r
- }\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- }\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 copy_from(const safe_ptr<host_buffer>& source)\r
- {\r
- auto ogl = parent_.lock();\r
- if(!ogl)\r
- BOOST_THROW_EXCEPTION(invalid_operation());\r
-\r
- ogl->begin_invoke([=]\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
- }, high_priority);\r
- }\r
-\r
- void copy_to(const safe_ptr<host_buffer>& dest)\r
- {\r
- auto ogl = parent_.lock();\r
- if(!ogl)\r
- BOOST_THROW_EXCEPTION(invalid_operation());\r
-\r
- ogl->begin_invoke([=]\r
- {\r
- dest->unmap();\r
- dest->bind();\r
- GL(glBindTexture(GL_TEXTURE_2D, id_));\r
- GL(glReadPixels(0, 0, width_, height_, FORMAT[stride_], TYPE[stride_], NULL));\r
- GL(glBindTexture(GL_TEXTURE_2D, 0));\r
- dest->unbind();\r
- }, high_priority);\r
- }\r
-};\r
-\r
-device_buffer::device_buffer(std::weak_ptr<ogl_device> parent, int width, int height, int stride) : impl_(new impl(parent, width, height, stride)){}\r
-int device_buffer::stride() const { return impl_->stride_; }\r
-int device_buffer::width() const { return impl_->width_; }\r
-int device_buffer::height() const { return impl_->height_; }\r
-void device_buffer::bind(int index){impl_->bind(index);}\r
-void device_buffer::unbind(){impl_->unbind();}\r
-void device_buffer::copy_from(const safe_ptr<host_buffer>& source){impl_->copy_from(source);}\r
-void device_buffer::copy_to(const safe_ptr<host_buffer>& dest){impl_->copy_to(dest);}\r
-int device_buffer::id() const{ return impl_->id_;}\r
-\r
-\r
-}}
\ No newline at end of file
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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 "host_buffer.h"\r
-\r
-#include "device_buffer.h"\r
-#include "ogl_device.h"\r
-\r
-#include <common/exception/exceptions.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 core {\r
-\r
-static tbb::atomic<int> g_w_total_count;\r
-static tbb::atomic<int> g_r_total_count;\r
- \r
-struct host_buffer::impl : boost::noncopyable\r
-{ \r
- GLuint pbo_;\r
- const int size_;\r
- tbb::atomic<void*> data_;\r
- GLenum usage_;\r
- GLenum target_;\r
- std::weak_ptr<ogl_device> parent_;\r
-\r
-public:\r
- impl(std::weak_ptr<ogl_device> parent, int size, host_buffer::usage usage) \r
- : parent_(parent)\r
- , size_(size)\r
- , pbo_(0)\r
- , target_(usage == host_buffer::usage::write_only ? GL_PIXEL_UNPACK_BUFFER : GL_PIXEL_PACK_BUFFER)\r
- , usage_(usage == host_buffer::usage::write_only ? GL_STREAM_DRAW : GL_STREAM_READ)\r
- {\r
- data_ = nullptr;\r
- GL(glGenBuffers(1, &pbo_));\r
- bind();\r
- if(usage_ != GL_STREAM_DRAW) \r
- GL(glBufferData(target_, size_, NULL, usage_)); \r
- unbind();\r
-\r
- if(!pbo_)\r
- BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Failed to allocate buffer."));\r
-\r
- CASPAR_LOG(trace) << "[host_buffer] [" << ++(usage_ == host_buffer::usage::write_only ? g_w_total_count : g_r_total_count) << L"] allocated size:" << size_ << " usage: " << (usage == host_buffer::usage::write_only ? "write_only" : "read_only");\r
- } \r
-\r
- ~impl()\r
- {\r
- try\r
- {\r
- GL(glDeleteBuffers(1, &pbo_));\r
- //CASPAR_LOG(trace) << "[host_buffer] [" << --(usage_ == write_only ? g_w_total_count : g_r_total_count) << L"] deallocated size:" << size_ << " usage: " << (usage_ == write_only ? "write_only" : "read_only");\r
- }\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- }\r
- }\r
-\r
- void* map()\r
- {\r
- if(data_ != nullptr)\r
- return data_;\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_ = GL2(glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY)); \r
- GL(glBindBuffer(target_, 0));\r
- if(!data_)\r
- BOOST_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
- void* data()\r
- {\r
- if(data_ != nullptr)\r
- return data_;\r
-\r
- auto ogl = parent_.lock();\r
-\r
- if(!ogl)\r
- BOOST_THROW_EXCEPTION(invalid_operation());\r
- \r
- return ogl->invoke([&]\r
- {\r
- return map();\r
- }, high_priority);\r
- }\r
-};\r
-\r
-host_buffer::host_buffer(std::weak_ptr<ogl_device> parent, int size, usage usage) : impl_(new impl(parent, size, usage)){}\r
-const void* host_buffer::data() const {return impl_->data_;}\r
-void* host_buffer::data() {return impl_->data();}\r
-void host_buffer::map(){impl_->map();}\r
-void host_buffer::unmap(){impl_->unmap();}\r
-void host_buffer::bind(){impl_->bind();}\r
-void host_buffer::unbind(){impl_->unbind();}\r
-int host_buffer::size() const { return impl_->size_; }\r
-\r
-}}
\ No newline at end of file
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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/safe_ptr.h>\r
-#include <common/enum_class.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-namespace caspar { namespace core {\r
- \r
-class host_buffer : boost::noncopyable\r
-{\r
-public:\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
- const void* data() const;\r
- void* data();\r
- int size() const; \r
- \r
-private:\r
- friend class ogl_device;\r
- friend class device_buffer;\r
-\r
- void bind();\r
- void unbind();\r
-\r
- void map();\r
- void unmap();\r
-\r
- host_buffer(std::weak_ptr<ogl_device> parent, int size, usage usage);\r
-\r
- struct impl;\r
- safe_ptr<impl> impl_;\r
-};\r
-\r
-}}
\ No newline at end of file
* Author: Robert Nagy, ronag89@gmail.com\r
*/\r
\r
-#include "../../stdafx.h"\r
+#include "../../../stdafx.h"\r
\r
#include "image_kernel.h"\r
\r
-#include "shader/image_shader.h"\r
-#include "shader/blending_glsl.h"\r
+#include "blending_glsl.h"\r
+#include "image_shader.h"\r
\r
-#include "../gpu/shader.h"\r
-#include "../gpu/device_buffer.h"\r
-#include "../gpu/ogl_device.h"\r
+#include "../shader.h"\r
+#include "../device_buffer.h"\r
+#include "../accelerator.h"\r
\r
#include <common/exception/exceptions.h>\r
#include <common/gl/gl_check.h>\r
#include <boost/noncopyable.hpp>\r
#include <common/assert.h>\r
\r
-namespace caspar { namespace core {\r
+namespace caspar { namespace core { namespace gpu {\r
\r
__declspec(align(16)) std::array<GLubyte, 32*32> 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
\r
struct image_kernel::impl : boost::noncopyable\r
{ \r
- safe_ptr<ogl_device> ogl_;\r
+ safe_ptr<accelerator> ogl_;\r
safe_ptr<shader> shader_;\r
bool blend_modes_;\r
\r
- impl(const safe_ptr<ogl_device>& ogl)\r
+ impl(const safe_ptr<accelerator>& ogl)\r
: ogl_(ogl)\r
, shader_(ogl_->invoke([&]{return get_image_shader(*ogl, blend_modes_);}))\r
{\r
}\r
};\r
\r
-image_kernel::image_kernel(const safe_ptr<ogl_device>& ogl) : impl_(new impl(ogl)){}\r
+image_kernel::image_kernel(const safe_ptr<accelerator>& ogl) : impl_(new impl(ogl)){}\r
void image_kernel::draw(draw_params&& params)\r
{\r
impl_->draw(std::move(params));\r
}\r
\r
-}}
\ No newline at end of file
+}}}
\ No newline at end of file
\r
#pragma once\r
\r
-#include "blend_modes.h"\r
+#include "../../image/blend_modes.h"\r
\r
#include <common/enum_class.h>\r
#include <common/memory/safe_ptr.h>\r
\r
#include <boost/noncopyable.hpp>\r
\r
-namespace caspar { namespace core {\r
+namespace caspar { namespace core { namespace gpu {\r
\r
struct keyer_def\r
{\r
class image_kernel sealed : boost::noncopyable\r
{\r
public:\r
- image_kernel(const safe_ptr<class ogl_device>& ogl);\r
+ image_kernel(const safe_ptr<class accelerator>& ogl);\r
void draw(draw_params&& params);\r
private:\r
struct impl;\r
safe_ptr<impl> impl_;\r
};\r
\r
-}}
\ No newline at end of file
+}}}
\ No newline at end of file
* Author: Robert Nagy, ronag89@gmail.com\r
*/\r
\r
-#include "../../stdafx.h"\r
+#include "../../../stdafx.h"\r
\r
#include "image_mixer.h"\r
\r
#include "image_kernel.h"\r
-#include "../write_frame.h"\r
-#include "../gpu/ogl_device.h"\r
-#include "../gpu/host_buffer.h"\r
-#include "../gpu/device_buffer.h"\r
+#include "../accelerator.h"\r
+#include "../host_buffer.h"\r
+#include "../device_buffer.h"\r
+#include "../../write_frame.h"\r
\r
#include <common/gl/gl_check.h>\r
\r
\r
using namespace boost::assign;\r
\r
-namespace caspar { namespace core {\r
+namespace caspar { namespace core { namespace gpu {\r
\r
struct item\r
{\r
- pixel_format_desc pix_desc;\r
- std::vector<safe_ptr<device_buffer>> textures;\r
- frame_transform transform;\r
+ pixel_format_desc pix_desc;\r
+ std::vector<boost::shared_future<safe_ptr<device_buffer>>> textures;\r
+ frame_transform transform;\r
};\r
\r
typedef std::pair<blend_mode, std::vector<item>> layer;\r
\r
class image_renderer\r
{\r
- safe_ptr<ogl_device> ogl_;\r
+ safe_ptr<accelerator> ogl_;\r
image_kernel kernel_; \r
public:\r
- image_renderer(const safe_ptr<ogl_device>& ogl)\r
+ image_renderer(const safe_ptr<accelerator>& ogl)\r
: ogl_(ogl)\r
, kernel_(ogl_)\r
{\r
{ \r
draw_params draw_params;\r
draw_params.pix_desc = std::move(item.pix_desc);\r
- draw_params.textures = std::move(item.textures);\r
+ BOOST_FOREACH(auto& future_texture, item.textures)\r
+ draw_params.textures.push_back(future_texture.get());\r
draw_params.transform = std::move(item.transform);\r
\r
if(item.transform.is_key)\r
\r
struct image_mixer::impl : boost::noncopyable\r
{ \r
- safe_ptr<ogl_device> ogl_;\r
+ safe_ptr<accelerator> ogl_;\r
image_renderer renderer_;\r
std::vector<frame_transform> transform_stack_;\r
std::vector<layer> layers_; // layer/stream/items\r
public:\r
- impl(const safe_ptr<ogl_device>& ogl) \r
+ impl(const safe_ptr<accelerator>& ogl) \r
: ogl_(ogl)\r
, renderer_(ogl)\r
, transform_stack_(1) \r
}\r
};\r
\r
-image_mixer::image_mixer(const safe_ptr<ogl_device>& ogl) : impl_(new impl(ogl)){}\r
+image_mixer::image_mixer(const safe_ptr<accelerator>& ogl) : impl_(new impl(ogl)){}\r
void image_mixer::begin(basic_frame& frame){impl_->begin(frame);}\r
void image_mixer::visit(write_frame& frame){impl_->visit(frame);}\r
void image_mixer::end(){impl_->end();}\r
void image_mixer::begin_layer(blend_mode blend_mode){impl_->begin_layer(blend_mode);}\r
void image_mixer::end_layer(){impl_->end_layer();}\r
\r
-}}
\ No newline at end of file
+}}}
\ No newline at end of file
\r
#pragma once\r
\r
-#include <common/memory/safe_ptr.h>\r
+#include "../../image/blend_modes.h"\r
+#include "../../image/image_mixer.h"\r
+\r
#include <common/forward.h>\r
+#include <common/memory/safe_ptr.h>\r
\r
-#include <boost/noncopyable.hpp>\r
+#include <core/producer/frame/frame_visitor.h>\r
\r
FORWARD1(boost, template<typename> class unique_future);\r
\r
-namespace caspar { namespace core {\r
- \r
-class host_buffer;\r
-class ogl_device;\r
-\r
-class device_buffer : boost::noncopyable\r
+namespace caspar { namespace core { namespace gpu {\r
+ \r
+class image_mixer sealed : public core::image_mixer\r
{\r
-public: \r
- int stride() const; \r
- int width() const;\r
- int height() const;\r
+public:\r
+ image_mixer(const safe_ptr<class accelerator>& ogl);\r
+ \r
+ virtual void begin(class basic_frame& frame);\r
+ virtual void visit(class write_frame& frame);\r
+ virtual void end();\r
+\r
+ void begin_layer(blend_mode blend_mode);\r
+ void end_layer();\r
+ \r
+ virtual boost::unique_future<safe_ptr<class host_buffer>> operator()(const struct video_format_desc& format_desc) override;\r
\r
- void copy_from(const safe_ptr<host_buffer>& source);\r
- void copy_to(const safe_ptr<host_buffer>& dest);\r
private:\r
- friend class ogl_device;\r
- friend class image_kernel;\r
- device_buffer(std::weak_ptr<ogl_device> parent, int width, int height, int stride);\r
- \r
- void bind(int index);\r
- void unbind();\r
- int id() const;\r
-\r
struct impl;\r
safe_ptr<impl> impl_;\r
};\r
- \r
-unsigned int format(int stride);\r
\r
-}}
\ No newline at end of file
+}}}
\ No newline at end of file
#include "image_shader.h"\r
\r
#include "../../gpu/shader.h"\r
-#include "../../gpu/ogl_device.h"\r
+#include "../../gpu/accelerator.h"\r
\r
#include "blending_glsl.h"\r
\r
\r
#include <tbb/mutex.h>\r
\r
-namespace caspar { namespace core {\r
+namespace caspar { namespace core { namespace gpu {\r
\r
std::shared_ptr<shader> g_shader;\r
tbb::mutex g_shader_mutex;\r
"} \n";\r
}\r
\r
-safe_ptr<shader> get_image_shader(ogl_device& ogl, bool& blend_modes)\r
+safe_ptr<shader> get_image_shader(accelerator& ogl, bool& blend_modes)\r
{\r
tbb::mutex::scoped_lock lock(g_shader_mutex);\r
\r
return make_safe_ptr(g_shader);\r
}\r
\r
-}}\r
+}}}\r
\r
#include <common/memory/safe_ptr.h>\r
\r
-namespace caspar { namespace core {\r
+namespace caspar { namespace core { namespace gpu {\r
\r
class shader;\r
-class ogl_device;\r
+class accelerator;\r
\r
struct texture_id\r
{\r
};\r
};\r
\r
-safe_ptr<shader> get_image_shader(ogl_device& ogl, bool& blend_modes);\r
+safe_ptr<shader> get_image_shader(accelerator& ogl, bool& blend_modes);\r
\r
\r
-}}
\ No newline at end of file
+}}}
\ No newline at end of file
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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 core {\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
- BOOST_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
- BOOST_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
- BOOST_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, double value)\r
- {\r
- GL(glUniform1f(get_location(name.c_str()), static_cast<float>(value)));\r
- }\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
-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, double value){impl_->set(name, value);}\r
-int shader::id() const{return impl_->program_;}\r
-\r
-}}
\ No newline at end of file
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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/safe_ptr.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-#include <string>\r
-\r
-namespace caspar { namespace core {\r
- \r
-class shader : boost::noncopyable\r
-{\r
-public:\r
- shader(const std::string& vertex_source_str, const std::string& fragment_source_str);\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, double value);\r
-private:\r
- friend class ogl_device;\r
- struct impl;\r
- safe_ptr<impl> impl_;\r
-\r
- int id() const;\r
-};\r
-\r
-}}
\ No newline at end of file
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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
-}}
\ No newline at end of file
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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
-}}
\ No newline at end of file
#include <core/producer/frame/frame_visitor.h>\r
\r
FORWARD1(boost, template<typename> class unique_future);\r
+FORWARD3(caspar, core, gpu, class host_buffer);\r
\r
namespace caspar { namespace core {\r
\r
-class image_mixer sealed : public frame_visitor\r
+struct image_mixer : public frame_visitor\r
{\r
-public:\r
- image_mixer(const safe_ptr<class ogl_device>& ogl);\r
+ virtual ~image_mixer(){}\r
\r
- virtual void begin(class basic_frame& frame);\r
- virtual void visit(class write_frame& frame);\r
- virtual void end();\r
+ virtual void begin(class basic_frame& frame) = 0;\r
+ virtual void visit(class write_frame& frame) = 0;\r
+ virtual void end() = 0;\r
\r
- void begin_layer(blend_mode blend_mode);\r
- void end_layer();\r
+ virtual void begin_layer(blend_mode blend_mode) = 0;\r
+ virtual void end_layer() = 0;\r
\r
- boost::unique_future<safe_ptr<class host_buffer>> operator()(const struct video_format_desc& format_desc);\r
- \r
-private:\r
- struct impl;\r
- safe_ptr<impl> impl_;\r
+ virtual boost::unique_future<safe_ptr<gpu::host_buffer>> operator()(const struct video_format_desc& format_desc) = 0;\r
};\r
\r
}}
\ No newline at end of file
\r
#include "audio/audio_mixer.h"\r
#include "image/image_mixer.h"\r
+#include "gpu/image/image_mixer.h"\r
+#include "gpu/accelerator.h"\r
\r
#include <common/env.h>\r
#include <common/concurrency/executor.h>\r
#include <common/gl/gl_check.h>\r
#include <common/utility/tweener.h>\r
\r
-#include <core/mixer/read_frame.h>\r
-#include <core/mixer/write_frame.h>\r
#include <core/producer/frame/basic_frame.h>\r
#include <core/producer/frame/frame_factory.h>\r
#include <core/producer/frame/frame_transform.h>\r
namespace caspar { namespace core {\r
\r
struct mixer::impl : boost::noncopyable\r
-{ \r
- safe_ptr<mixer::target_t> target_;\r
-\r
- safe_ptr<diagnostics::graph> graph_;\r
- boost::timer mix_timer_; \r
-\r
- video_format_desc format_desc_;\r
- safe_ptr<ogl_device> ogl_;\r
+{ \r
+ safe_ptr<gpu::accelerator> ogl_;\r
\r
- audio_mixer audio_mixer_;\r
- image_mixer image_mixer_;\r
+ audio_mixer audio_mixer_;\r
+ safe_ptr<image_mixer> image_mixer_;\r
\r
std::unordered_map<int, blend_mode> blend_modes_;\r
\r
executor executor_;\r
\r
public:\r
- impl(const safe_ptr<mixer::target_t>& target, const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc, const safe_ptr<ogl_device>& ogl) \r
- : target_(target)\r
- , graph_(graph)\r
- , format_desc_(format_desc)\r
- , ogl_(ogl)\r
- , image_mixer_(ogl)\r
- , audio_mixer_(graph_)\r
+ impl(const safe_ptr<gpu::accelerator>& ogl) \r
+ : ogl_(ogl)\r
+ , audio_mixer_()\r
+ , image_mixer_(make_safe<gpu::image_mixer>(ogl_))\r
, executor_(L"mixer")\r
{ \r
- graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8));\r
- }\r
+ } \r
\r
- void send(const std::pair<std::map<int, safe_ptr<core::basic_frame>>, std::shared_ptr<void>>& packet)\r
- { \r
- executor_.begin_invoke([=]\r
+ safe_ptr<const frame> operator()(std::map<int, safe_ptr<basic_frame>> frames, const video_format_desc& format_desc)\r
+ { \r
+ return executor_.invoke([=]() mutable -> safe_ptr<const struct frame>\r
{ \r
try\r
- {\r
- mix_timer_.restart();\r
-\r
- auto frames = packet.first;\r
- \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
+ 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
+ frame.second->accept(*image_mixer_);\r
\r
- image_mixer_.end_layer();\r
+ image_mixer_->end_layer();\r
}\r
\r
- auto image = image_mixer_(format_desc_);\r
- auto audio = audio_mixer_(format_desc_);\r
+ auto image = (*image_mixer_)(format_desc);\r
+ auto audio = audio_mixer_(format_desc);\r
\r
- graph_->set_value("mix-time", mix_timer_.elapsed()*format_desc_.fps*0.5);\r
- \r
- target_->send(std::make_pair(make_safe<read_frame>(format_desc_.width, format_desc_.height, std::move(image), std::move(audio)), packet.second)); \r
+ return read_frame::create(std::move(image), std::move(audio), format_desc); \r
}\r
catch(...)\r
{\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
+ return frame::empty();\r
} \r
}); \r
}\r
}, high_priority);\r
}\r
\r
- void set_video_format_desc(const video_format_desc& format_desc)\r
- {\r
- executor_.begin_invoke([=]\r
- {\r
- format_desc_ = format_desc;\r
- });\r
- }\r
-\r
boost::unique_future<boost::property_tree::wptree> info() const\r
{\r
boost::promise<boost::property_tree::wptree> info;\r
}\r
};\r
\r
-mixer::mixer(const safe_ptr<target_t>& target, const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc, const safe_ptr<ogl_device>& ogl) \r
- : impl_(new impl(target, graph, format_desc, ogl)){}\r
-void mixer::send(const std::pair<std::map<int, safe_ptr<core::basic_frame>>, std::shared_ptr<void>>& frames){ impl_->send(frames);}\r
+mixer::mixer(const safe_ptr<gpu::accelerator>& ogl) \r
+ : impl_(new impl(ogl)){}\r
void mixer::set_blend_mode(int index, blend_mode value){impl_->set_blend_mode(index, value);}\r
-void mixer::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
boost::unique_future<boost::property_tree::wptree> mixer::info() const{return impl_->info();}\r
+safe_ptr<const frame> mixer::operator()(std::map<int, safe_ptr<basic_frame>> frames, const struct video_format_desc& format_desc){return (*impl_)(std::move(frames), format_desc);}\r
}}
\ No newline at end of file
\r
#include <common/forward.h>\r
#include <common/memory/safe_ptr.h>\r
-#include <common/concurrency/target.h>\r
+#include <common/reactive.h>\r
\r
#include <boost/noncopyable.hpp>\r
#include <boost/property_tree/ptree_fwd.hpp>\r
+#include <boost/thread/future.hpp>\r
\r
#include <map>\r
\r
-FORWARD2(caspar, diagnostics, class graph);\r
FORWARD1(boost, template<typename> class unique_future);\r
+FORWARD2(caspar, diagnostics, class graph);\r
+FORWARD3(caspar, core, gpu, class accelerator);\r
\r
namespace caspar { namespace core {\r
\r
-class mixer sealed : public target<std::pair<std::map<int, safe_ptr<class basic_frame>>, std::shared_ptr<void>>>\r
- , boost::noncopyable\r
+class mixer sealed : boost::noncopyable\r
{\r
public: \r
- typedef target<std::pair<safe_ptr<class read_frame>, std::shared_ptr<void>>> target_t;\r
-\r
- explicit mixer(const safe_ptr<target_t>& target, const safe_ptr<diagnostics::graph>& graph, const struct video_format_desc& format_desc, const safe_ptr<class ogl_device>& ogl);\r
- \r
- // target\r
-\r
- virtual void send(const std::pair<std::map<int, safe_ptr<class basic_frame>>, std::shared_ptr<void>>& frames) override; \r
- \r
+ explicit mixer(const safe_ptr<gpu::accelerator>& ogl);\r
+ \r
// mixer\r
- \r
- void set_video_format_desc(const struct video_format_desc& format_desc);\r
- \r
+ \r
void set_blend_mode(int index, blend_mode value);\r
\r
boost::unique_future<boost::property_tree::wptree> info() const;\r
\r
+ // subject\r
+\r
+ safe_ptr<const struct frame> operator()(std::map<int, safe_ptr<class basic_frame>> frames, const struct video_format_desc& format_desc);\r
+\r
private:\r
struct impl;\r
safe_ptr<impl> impl_;\r
#include "../stdafx.h"\r
\r
#include "read_frame.h"\r
+#include "../video_format.h"\r
+#include "../producer/frame/pixel_format.h"\r
\r
#include "gpu/host_buffer.h" \r
\r
\r
struct read_frame::impl : boost::noncopyable\r
{\r
- int width_;\r
- int height_;\r
- boost::unique_future<safe_ptr<host_buffer>> image_data_;\r
- audio_buffer audio_data_;\r
+ boost::unique_future<safe_ptr<gpu::host_buffer>> image_data_;\r
+ const audio_buffer audio_data_;\r
+ const video_format_desc video_desc_;\r
+ pixel_format_desc pixel_desc_;\r
\r
public:\r
- impl( int width, int height, boost::unique_future<safe_ptr<host_buffer>>&& image_data, audio_buffer&& audio_data) \r
- : width_(width)\r
- , height_(height)\r
- , image_data_(std::move(image_data))\r
- , audio_data_(std::move(audio_data)){} \r
+ impl(boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const video_format_desc& format_desc) \r
+ : image_data_(std::move(image_data))\r
+ , audio_data_(std::move(audio_data))\r
+ , video_desc_(format_desc)\r
+ {\r
+ pixel_desc_.pix_fmt = core::pixel_format::bgra;\r
+ pixel_desc_.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));\r
+ } \r
\r
const boost::iterator_range<const uint8_t*> image_data()\r
{\r
}\r
};\r
\r
-read_frame::read_frame(int width, int height, boost::unique_future<safe_ptr<host_buffer>>&& image_data, audio_buffer&& audio_data) \r
- : impl_(new impl(width, height, std::move(image_data), std::move(audio_data))){}\r
-read_frame::read_frame(){}\r
-const boost::iterator_range<const uint8_t*> read_frame::image_data()\r
-{\r
- return impl_ ? impl_->image_data() : boost::iterator_range<const uint8_t*>();\r
-}\r
+read_frame::read_frame(boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const video_format_desc& format_desc) \r
+ : impl_(new impl(std::move(image_data), std::move(audio_data), format_desc)){}\r
+const boost::iterator_range<const uint8_t*> read_frame::image_data() const{ return impl_->image_data();}\r
+const boost::iterator_range<const int32_t*> read_frame::audio_data() const{ return impl_->audio_data();}\r
+const pixel_format_desc& read_frame::get_pixel_format_desc() const{ return impl_->pixel_desc_;}\r
+double read_frame::get_frame_rate() const {return impl_->video_desc_.fps;}\r
+field_mode read_frame::get_field_mode() const {return impl_->video_desc_.field_mode;}\r
+int read_frame::width() const {return impl_->video_desc_.width;}\r
+int read_frame::height() const {return impl_->video_desc_.height;}\r
\r
-const boost::iterator_range<const int32_t*> read_frame::audio_data()\r
+safe_ptr<const read_frame> read_frame::create(boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const struct video_format_desc& format_desc)\r
{\r
- return impl_ ? impl_->audio_data() : boost::iterator_range<const int32_t*>();\r
+ return safe_ptr<const read_frame>(new read_frame(std::move(image_data), std::move(audio_data), format_desc));\r
}\r
\r
-int read_frame::width() const{return impl_ ? impl_->width_ : 0;}\r
-int read_frame::height() const{return impl_ ? impl_->height_ : 0;}\r
-\r
//#include <tbb/scalable_allocator.h>\r
//#include <tbb/parallel_for.h>\r
//#include <tbb/enumerable_thread_specific.h>\r
//\r
//void CopyFrame( void * pSrc, void * pDest, UINT width, UINT height, UINT pitch );\r
//\r
-//void* copy_frame(void* dest, const safe_ptr<read_frame>& frame)\r
+//void* copy_frame(void* dest, const safe_ptr<const frame>& frame)\r
//{\r
// auto src = frame->image_data().begin();\r
// auto height = 720;\r
\r
#pragma once\r
\r
+#include "../frame.h"\r
+\r
#include <common/memory/safe_ptr.h>\r
#include <common/forward.h>\r
+#include <common/exception/exceptions.h>\r
\r
#include <core/mixer/audio/audio_mixer.h>\r
\r
#include <vector>\r
\r
FORWARD1(boost, template<typename> class unique_future);\r
+FORWARD3(caspar, core, gpu, class host_buffer);\r
\r
namespace caspar { namespace core {\r
\r
-class read_frame sealed : boost::noncopyable\r
+class read_frame sealed : public frame\r
{\r
+ read_frame(boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const struct video_format_desc& format_desc);\r
public:\r
- read_frame();\r
- read_frame(int width, int height, boost::unique_future<safe_ptr<class host_buffer>>&& image_data, audio_buffer&& audio_data);\r
+ static safe_ptr<const read_frame> create(boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const struct video_format_desc& format_desc);\r
+ \r
+ virtual const struct pixel_format_desc& get_pixel_format_desc() const override;\r
\r
- const boost::iterator_range<const uint8_t*> image_data();\r
- const boost::iterator_range<const int32_t*> audio_data();\r
+ virtual const boost::iterator_range<const uint8_t*> image_data() const override;\r
+ virtual const boost::iterator_range<const int32_t*> audio_data() const override;\r
+ \r
+ virtual double get_frame_rate() const override;\r
+ virtual field_mode get_field_mode() const override;\r
\r
- int width() const;\r
- int height() const;\r
- \r
+ virtual int width() const override;\r
+ virtual int height() const override;\r
+\r
+ virtual const boost::iterator_range<uint8_t*> image_data() override\r
+ {\r
+ BOOST_THROW_EXCEPTION(invalid_operation());\r
+ }\r
+ virtual const boost::iterator_range<int32_t*> audio_data() override\r
+ {\r
+ BOOST_THROW_EXCEPTION(invalid_operation());\r
+ }\r
+ \r
private:\r
struct impl;\r
std::shared_ptr<impl> impl_;\r
\r
#include "write_frame.h"\r
\r
-#include "gpu/ogl_device.h"\r
+#include "gpu/accelerator.h"\r
#include "gpu/host_buffer.h"\r
#include "gpu/device_buffer.h"\r
\r
+#include <common/exception/exceptions.h>\r
#include <core/producer/frame/frame_visitor.h>\r
#include <core/producer/frame/pixel_format.h>\r
\r
\r
struct write_frame::impl : boost::noncopyable\r
{ \r
- std::shared_ptr<ogl_device> ogl_;\r
- std::vector<std::shared_ptr<host_buffer>> buffers_;\r
- std::vector<safe_ptr<device_buffer>> textures_;\r
- audio_buffer audio_data_;\r
- const core::pixel_format_desc desc_;\r
- const void* tag_;\r
- core::field_mode mode_;\r
+ std::shared_ptr<gpu::accelerator> ogl_;\r
+ std::vector<std::shared_ptr<gpu::host_buffer>> buffers_;\r
+ std::vector<boost::shared_future<safe_ptr<gpu::device_buffer>>> textures_;\r
+ audio_buffer audio_data_;\r
+ const core::pixel_format_desc desc_;\r
+ const void* tag_;\r
+ core::field_mode mode_;\r
\r
impl(const void* tag)\r
: tag_(tag)\r
{\r
}\r
\r
- impl(const safe_ptr<ogl_device>& ogl, const void* tag, const core::pixel_format_desc& desc, const field_mode& mode) \r
+ impl(const safe_ptr<gpu::accelerator>& ogl, const void* tag, const core::pixel_format_desc& desc, const field_mode& mode) \r
: ogl_(ogl)\r
, desc_(desc)\r
, tag_(tag)\r
{\r
std::transform(desc.planes.begin(), desc.planes.end(), std::back_inserter(buffers_), [&](const core::pixel_format_desc::plane& plane)\r
{\r
- return ogl_->create_host_buffer(plane.size, host_buffer::usage::write_only);\r
- });\r
- std::transform(desc.planes.begin(), desc.planes.end(), std::back_inserter(textures_), [&](const core::pixel_format_desc::plane& plane)\r
- {\r
- return ogl_->create_device_buffer(plane.width, plane.height, plane.channels); \r
+ return ogl_->create_host_buffer(plane.size, gpu::host_buffer::usage::write_only);\r
});\r
+ textures_.resize(desc.planes.size());\r
}\r
\r
void accept(write_frame& self, core::frame_visitor& visitor)\r
boost::iterator_range<uint8_t*> image_data(int index)\r
{\r
if(index >= buffers_.size() || !buffers_[index]->data())\r
- return boost::iterator_range<uint8_t*>();\r
+ BOOST_THROW_EXCEPTION(out_of_range());\r
auto ptr = static_cast<uint8_t*>(buffers_[index]->data());\r
return boost::iterator_range<uint8_t*>(ptr, ptr+buffers_[index]->size());\r
}\r
if(!buffer)\r
return;\r
\r
- textures_.at(plane_index)->copy_from(make_safe_ptr(buffer));\r
+ auto plane = desc_.planes.at(plane_index);\r
+ textures_.at(plane_index) = ogl_->copy_async(make_safe_ptr(std::move(buffer)), plane.width, plane.height, plane.channels);\r
}\r
};\r
\r
write_frame::write_frame(const void* tag) : impl_(new impl(tag)){}\r
-write_frame::write_frame(const safe_ptr<ogl_device>& ogl, const void* tag, const core::pixel_format_desc& desc, const field_mode& mode) \r
+write_frame::write_frame(const safe_ptr<gpu::accelerator>& ogl, const void* tag, const core::pixel_format_desc& desc, const field_mode& mode) \r
: impl_(new impl(ogl, tag, desc, mode)){}\r
write_frame::write_frame(write_frame&& other) : impl_(std::move(other.impl_)){}\r
write_frame& write_frame::operator=(write_frame&& other)\r
audio_buffer& write_frame::audio_data() { return impl_->audio_data_; }\r
const void* write_frame::tag() const {return impl_->tag_;}\r
const core::pixel_format_desc& write_frame::get_pixel_format_desc() const{return impl_->desc_;}\r
-const std::vector<safe_ptr<device_buffer>>& write_frame::get_textures() const{return impl_->textures_;}\r
+const std::vector<boost::shared_future<safe_ptr<gpu::device_buffer>>>& write_frame::get_textures() const{return impl_->textures_;}\r
void write_frame::commit(int plane_index){impl_->commit(plane_index);}\r
void write_frame::commit(){impl_->commit();}\r
-core::field_mode write_frame::get_type() const{return impl_->mode_;}\r
+core::field_mode write_frame::get_field_mode() const{return impl_->mode_;}\r
void write_frame::accept(core::frame_visitor& visitor){impl_->accept(*this, visitor);}\r
\r
}}
\ No newline at end of file
#pragma once\r
\r
#include <common/memory/safe_ptr.h>\r
+#include <common/forward.h>\r
\r
#include <core/producer/frame/basic_frame.h>\r
#include <core/video_format.h>\r
#include <stdint.h>\r
#include <vector>\r
\r
+FORWARD1(boost, template<typename> class shared_future);\r
+FORWARD3(caspar, core, gpu, class accelerator);\r
+FORWARD3(caspar, core, gpu, class device_buffer);\r
+\r
namespace caspar { namespace core {\r
\r
class write_frame sealed : public core::basic_frame\r
{\r
public: \r
explicit write_frame(const void* tag);\r
- explicit write_frame(const safe_ptr<class ogl_device>& ogl, const void* tag, const struct pixel_format_desc& desc, const field_mode& mode = field_mode::progressive);\r
+ explicit write_frame(const safe_ptr<gpu::accelerator>& ogl, const void* tag, const struct pixel_format_desc& desc, const field_mode& mode = field_mode::progressive);\r
\r
write_frame(write_frame&& other);\r
write_frame& operator=(write_frame&& other);\r
void commit(int plane_index);\r
void commit();\r
\r
- field_mode get_type() const;\r
+ field_mode get_field_mode() const;\r
\r
const void* tag() const;\r
\r
const struct pixel_format_desc& get_pixel_format_desc() const;\r
\r
+ const std::vector<boost::shared_future<safe_ptr<gpu::device_buffer>>>& get_textures() const;\r
private:\r
- friend class image_mixer;\r
- \r
- const std::vector<safe_ptr<class device_buffer>>& get_textures() const;\r
-\r
struct impl;\r
safe_ptr<impl> impl_;\r
};\r
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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 "channel_producer.h"\r
-\r
-#include "../../consumer/frame_consumer.h"\r
-#include "../../consumer/output.h"\r
-#include "../../video_channel.h"\r
-\r
-#include "../frame_producer.h"\r
-#include "../frame/basic_frame.h"\r
-#include "../frame/frame_factory.h"\r
-#include "../frame/pixel_format.h"\r
-#include "../../mixer/write_frame.h"\r
-#include "../../mixer/read_frame.h"\r
-\r
-#include <common/exception/exceptions.h>\r
-\r
-#include <asmlib.h>\r
-\r
-#include <tbb/concurrent_queue.h>\r
-\r
-namespace caspar { namespace core {\r
-\r
-class channel_consumer : public frame_consumer\r
-{ \r
- tbb::concurrent_bounded_queue<std::shared_ptr<read_frame>> frame_buffer_;\r
- core::video_format_desc format_desc_;\r
- int channel_index_;\r
- tbb::atomic<bool> is_running_;\r
-\r
-public:\r
- channel_consumer() \r
- {\r
- is_running_ = true;\r
- frame_buffer_.set_capacity(3);\r
- }\r
-\r
- ~channel_consumer()\r
- {\r
- stop();\r
- }\r
-\r
- // frame_consumer\r
-\r
- virtual bool send(const safe_ptr<read_frame>& frame) override\r
- {\r
- frame_buffer_.try_push(frame);\r
- return is_running_;\r
- }\r
-\r
- virtual 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
- }\r
-\r
- virtual std::wstring print() const override\r
- {\r
- return L"[channel-consumer|" + boost::lexical_cast<std::wstring>(channel_index_) + L"]";\r
- }\r
-\r
- virtual boost::property_tree::wptree info() const override\r
- {\r
- boost::property_tree::wptree info;\r
- info.add(L"type", L"channel-consumer");\r
- info.add(L"channel-index", channel_index_);\r
- return info;\r
- }\r
- \r
- virtual bool has_synchronization_clock() const override\r
- {\r
- return false;\r
- }\r
-\r
- virtual int buffer_depth() const override\r
- {\r
- return 1;\r
- }\r
-\r
- virtual int index() const override\r
- {\r
- return 78500 + channel_index_;\r
- }\r
-\r
- // channel_consumer\r
-\r
- void stop()\r
- {\r
- is_running_ = false;\r
- frame_buffer_.try_push(make_safe<read_frame>());\r
- }\r
- \r
- const core::video_format_desc& get_video_format_desc()\r
- {\r
- return format_desc_;\r
- }\r
-\r
- std::shared_ptr<read_frame> receive()\r
- {\r
- if(!is_running_)\r
- return make_safe<read_frame>();\r
- std::shared_ptr<read_frame> frame;\r
- frame_buffer_.try_pop(frame);\r
- return frame;\r
- }\r
-};\r
- \r
-class channel_producer : public frame_producer\r
-{\r
- const safe_ptr<frame_factory> frame_factory_;\r
- const safe_ptr<channel_consumer> consumer_;\r
-\r
- std::queue<safe_ptr<basic_frame>> frame_buffer_;\r
- safe_ptr<basic_frame> last_frame_;\r
- uint64_t frame_number_;\r
-\r
-public:\r
- explicit channel_producer(const safe_ptr<frame_factory>& frame_factory, const safe_ptr<video_channel>& channel) \r
- : frame_factory_(frame_factory)\r
- , consumer_(make_safe<channel_consumer>())\r
- , last_frame_(basic_frame::empty())\r
- , frame_number_(0)\r
- {\r
- channel->output()->add(consumer_);\r
- CASPAR_LOG(info) << print() << L" Initialized";\r
- }\r
-\r
- ~channel_producer()\r
- {\r
- consumer_->stop();\r
- CASPAR_LOG(info) << print() << L" Uninitialized";\r
- }\r
-\r
- // frame_producer\r
- \r
- virtual safe_ptr<basic_frame> receive(int) override\r
- {\r
- auto format_desc = consumer_->get_video_format_desc();\r
-\r
- if(frame_buffer_.size() > 1)\r
- {\r
- auto frame = frame_buffer_.front();\r
- frame_buffer_.pop();\r
- return last_frame_ = frame;\r
- }\r
- \r
- auto read_frame = consumer_->receive();\r
- if(!read_frame || read_frame->image_data().empty())\r
- return basic_frame::late(); \r
-\r
- frame_number_++;\r
- \r
- core::pixel_format_desc desc;\r
- bool double_speed = std::abs(frame_factory_->get_video_format_desc().fps / 2.0 - format_desc.fps) < 0.01; \r
- bool half_speed = std::abs(format_desc.fps / 2.0 - frame_factory_->get_video_format_desc().fps) < 0.01;\r
-\r
- if(half_speed && frame_number_ % 2 == 0) // Skip frame\r
- return receive(0);\r
-\r
- desc.pix_fmt = core::pixel_format::bgra;\r
- desc.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));\r
- auto frame = frame_factory_->create_frame(this, desc);\r
-\r
- A_memcpy(frame->image_data().begin(), read_frame->image_data().begin(), read_frame->image_data().size());\r
- frame->commit();\r
-\r
- frame_buffer_.push(frame); \r
- \r
- if(double_speed) \r
- frame_buffer_.push(frame);\r
-\r
- return receive(0);\r
- } \r
-\r
- virtual safe_ptr<basic_frame> last_frame() const override\r
- {\r
- return last_frame_; \r
- } \r
-\r
- virtual std::wstring print() const override\r
- {\r
- return L"channel[]";\r
- }\r
-\r
- virtual boost::property_tree::wptree info() const override\r
- {\r
- boost::property_tree::wptree info;\r
- info.add(L"type", L"channel-producer");\r
- return info;\r
- }\r
-};\r
-\r
-safe_ptr<core::frame_producer> create_channel_producer(const safe_ptr<core::frame_factory>& frame_factory, const safe_ptr<core::video_channel>& channel)\r
-{\r
- return create_producer_print_proxy(\r
- make_safe<channel_producer>(frame_factory, channel));\r
-}\r
-\r
-}}
\ No newline at end of file
\r
#include <common/memory/safe_ptr.h>\r
\r
+#include <core/video_format.h>\r
+\r
#include <boost/noncopyable.hpp>\r
\r
namespace caspar { namespace core {\r
#include "frame/frame_transform.h"\r
\r
#include "color/color_producer.h"\r
-#include "playlist/playlist_producer.h"\r
#include "separated/separated_producer.h"\r
\r
#include <common/memory/safe_ptr.h>\r
\r
if(producer == frame_producer::empty())\r
producer = create_color_producer(my_frame_factory, params);\r
- \r
- if(producer == frame_producer::empty())\r
- producer = create_playlist_producer(my_frame_factory, params);\r
- \r
+ \r
return producer;\r
}\r
\r
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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 "playlist_producer.h"\r
-\r
-#include "../frame_producer.h"\r
-#include "../frame_producer.h"\r
-#include "../frame/basic_frame.h"\r
-\r
-#include <boost/regex.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/thread/future.hpp>\r
-\r
-#include <deque>\r
-\r
-namespace caspar { namespace core { \r
-\r
-struct playlist_producer : public frame_producer\r
-{ \r
- safe_ptr<frame_factory> factory_;\r
- safe_ptr<basic_frame> last_frame_;\r
- safe_ptr<frame_producer> current_;\r
- bool loop_;\r
-\r
- std::deque<safe_ptr<frame_producer>> producers_;\r
-\r
- playlist_producer(const safe_ptr<frame_factory>& factory, bool loop) \r
- : factory_(factory)\r
- , last_frame_(basic_frame::empty())\r
- , current_(frame_producer::empty())\r
- , loop_(loop)\r
- {\r
- }\r
-\r
- // frame_producer\r
- \r
- virtual safe_ptr<basic_frame> receive(int flags) override\r
- {\r
- if(current_ == frame_producer::empty() && !producers_.empty())\r
- next();\r
-\r
- auto frame = current_->receive(flags);\r
- if(frame == basic_frame::eof())\r
- {\r
- current_ = frame_producer::empty();\r
- return receive(flags);\r
- }\r
-\r
- return last_frame_ = frame;\r
- }\r
-\r
- virtual safe_ptr<core::basic_frame> last_frame() const override\r
- {\r
- return last_frame_;\r
- }\r
-\r
- virtual std::wstring print() const override\r
- {\r
- return L"playlist[" + current_->print() + L"]";\r
- } \r
-\r
- virtual boost::property_tree::wptree info() const override\r
- {\r
- boost::property_tree::wptree info;\r
- info.add(L"type", L"playlist-producer");\r
- return info;\r
- }\r
-\r
- virtual uint32_t nb_frames() const override\r
- {\r
- return std::numeric_limits<uint32_t>::max();\r
- }\r
- \r
- virtual boost::unique_future<std::wstring> call(const std::wstring& param) override\r
- {\r
- boost::promise<std::wstring> promise;\r
- promise.set_value(do_call(param));\r
- return promise.get_future();\r
- } \r
-\r
- // playlist_producer\r
-\r
- std::wstring do_call(const std::wstring& param)\r
- { \r
- static const boost::wregex push_front_exp (L"PUSH_FRONT (?<PARAM>.+)"); \r
- static const boost::wregex push_back_exp (L"(PUSH_BACK|PUSH) (?<PARAM>.+)");\r
- static const boost::wregex pop_front_exp (L"POP_FRONT"); \r
- static const boost::wregex pop_back_exp (L"(POP_BACK|POP)");\r
- static const boost::wregex clear_exp (L"CLEAR");\r
- static const boost::wregex next_exp (L"NEXT");\r
- static const boost::wregex insert_exp (L"INSERT (?<POS>\\d+) (?<PARAM>.+)"); \r
- static const boost::wregex remove_exp (L"REMOVE (?<POS>\\d+) (?<PARAM>.+)"); \r
- static const boost::wregex list_exp (L"LIST"); \r
- static const boost::wregex loop_exp (L"LOOP\\s*(?<VALUE>\\d?)");\r
- \r
- boost::wsmatch what;\r
-\r
- if(boost::regex_match(param, what, push_front_exp))\r
- return push_front(what["PARAM"].str()); \r
- else if(boost::regex_match(param, what, push_back_exp))\r
- return push_back(what["PARAM"].str()); \r
- if(boost::regex_match(param, what, pop_front_exp))\r
- return pop_front(); \r
- else if(boost::regex_match(param, what, pop_back_exp))\r
- return pop_back(); \r
- else if(boost::regex_match(param, what, clear_exp))\r
- return clear();\r
- else if(boost::regex_match(param, what, next_exp))\r
- return next(); \r
- else if(boost::regex_match(param, what, insert_exp))\r
- return insert(boost::lexical_cast<size_t>(what["POS"].str()), what["PARAM"].str());\r
- else if(boost::regex_match(param, what, remove_exp))\r
- return erase(boost::lexical_cast<size_t>(what["POS"].str()));\r
- else if(boost::regex_match(param, what, list_exp))\r
- return list();\r
- else if(boost::regex_match(param, what, loop_exp))\r
- {\r
- if(!what["VALUE"].str().empty())\r
- loop_ = boost::lexical_cast<bool>(what["VALUE"].str());\r
- return boost::lexical_cast<std::wstring>(loop_);\r
- }\r
-\r
- BOOST_THROW_EXCEPTION(invalid_argument());\r
- }\r
- \r
- std::wstring push_front(const std::wstring& str)\r
- {\r
- producers_.push_front(create_producer(factory_, str)); \r
- return L"";\r
- }\r
-\r
- std::wstring push_back(const std::wstring& str)\r
- {\r
- producers_.push_back(create_producer(factory_, str)); \r
- return L"";\r
- }\r
-\r
- std::wstring pop_front()\r
- {\r
- producers_.pop_front();\r
- return L"";\r
- }\r
-\r
- std::wstring pop_back()\r
- {\r
- producers_.pop_back();\r
- return L"";\r
- }\r
- \r
- std::wstring clear()\r
- {\r
- producers_.clear();\r
- return L"";\r
- }\r
-\r
- std::wstring next()\r
- {\r
- if(!producers_.empty())\r
- {\r
- current_ = producers_.front();\r
- producers_.pop_front();\r
- //if(loop_)\r
- // producers_.push_back(current_);\r
- }\r
- return L"";\r
- }\r
- \r
- std::wstring insert(size_t pos, const std::wstring& str)\r
- {\r
- if(pos >= producers_.size())\r
- BOOST_THROW_EXCEPTION(out_of_range());\r
- producers_.insert(std::begin(producers_) + pos, create_producer(factory_, str));\r
- return L"";\r
- }\r
-\r
- std::wstring erase(size_t pos)\r
- {\r
- if(pos >= producers_.size())\r
- BOOST_THROW_EXCEPTION(out_of_range());\r
- producers_.erase(std::begin(producers_) + pos);\r
- return L"";\r
- }\r
-\r
- std::wstring list() const\r
- {\r
- std::wstring result = L"<playlist>\n";\r
- BOOST_FOREACH(auto& producer, producers_) \r
- result += L"\t<producer>" + producer->print() + L"</producer>\n";\r
- return result + L"</playlist>";\r
- }\r
-};\r
-\r
-safe_ptr<frame_producer> create_playlist_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
-{\r
- if(boost::range::find(params, L"[PLAYLIST]") == params.end())\r
- return core::frame_producer::empty();\r
-\r
- bool loop = boost::range::find(params, L"LOOP") != params.end();\r
-\r
- return make_safe<playlist_producer>(frame_factory, loop);\r
-}\r
-\r
-}}\r
-\r
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public 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/safe_ptr.h>\r
-\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
- \r
-safe_ptr<struct frame_producer> create_playlist_producer(const safe_ptr<struct frame_factory>& frame_factory, const std::vector<std::wstring>& params);\r
-\r
-}}
\ No newline at end of file
\r
struct stage::impl : public std::enable_shared_from_this<impl>\r
, boost::noncopyable\r
-{ \r
- safe_ptr<stage::target_t> target_;\r
- video_format_desc format_desc_;\r
- \r
- safe_ptr<diagnostics::graph> graph_;\r
-\r
- boost::timer produce_timer_;\r
- boost::timer tick_timer_;\r
-\r
+{ \r
std::map<int, layer> layers_; \r
std::map<int, tweened_transform<core::frame_transform>> transforms_; \r
\r
executor executor_;\r
public:\r
- impl(const safe_ptr<stage::target_t>& target, const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc) \r
- : target_(target)\r
- , graph_(graph)\r
- , format_desc_(format_desc)\r
- , executor_(L"stage")\r
- {\r
- graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f)); \r
- graph_->set_color("produce-time", diagnostics::color(0.0f, 1.0f, 0.0f));\r
- }\r
-\r
- void start(int tokens)\r
+ impl() \r
+ : executor_(L"stage")\r
{\r
- std::weak_ptr<impl> self = shared_from_this();\r
- for(int n = 0; n < tokens; ++n)\r
- executor_.begin_invoke([=]{tick(self);});\r
}\r
- \r
- void tick(const std::weak_ptr<impl>& self)\r
+ \r
+ std::map<int, safe_ptr<basic_frame>> operator()(const struct video_format_desc& format_desc)\r
{ \r
- try\r
+ return executor_.invoke([=]() -> std::map<int, safe_ptr<basic_frame>>\r
{\r
- produce_timer_.restart();\r
+ std::map<int, safe_ptr<class basic_frame>> result;\r
\r
- std::map<int, safe_ptr<basic_frame>> frames;\r
- \r
- BOOST_FOREACH(auto& layer, layers_) \r
- frames[layer.first] = basic_frame::empty(); \r
+ try\r
+ { \r
+ BOOST_FOREACH(auto& layer, layers_) \r
+ result[layer.first] = basic_frame::empty(); \r
\r
- tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer) \r
- {\r
- auto transform = transforms_[layer.first].fetch_and_tick(1);\r
+ auto format_desc2 = format_desc;\r
\r
- int flags = frame_producer::flags::none;\r
- if(format_desc_.field_mode != field_mode::progressive)\r
+ tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer)\r
{\r
- flags |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::flags::deinterlace : frame_producer::flags::none;\r
- flags |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::flags::deinterlace : frame_producer::flags::none;\r
- }\r
+ auto transform = transforms_[layer.first].fetch_and_tick(1);\r
+\r
+ int flags = frame_producer::flags::none;\r
+ if(format_desc2.field_mode != field_mode::progressive)\r
+ {\r
+ flags |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::flags::deinterlace : frame_producer::flags::none;\r
+ flags |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::flags::deinterlace : frame_producer::flags::none;\r
+ }\r
\r
- if(transform.is_key)\r
- flags |= frame_producer::flags::alpha_only;\r
+ if(transform.is_key)\r
+ flags |= frame_producer::flags::alpha_only;\r
\r
- auto frame = layer.second.receive(flags); \r
+ auto frame = layer.second.receive(flags); \r
\r
- auto frame1 = make_safe<core::basic_frame>(frame);\r
- frame1->get_frame_transform() = transform;\r
-\r
- if(format_desc_.field_mode != core::field_mode::progressive)\r
- { \r
- auto frame2 = make_safe<core::basic_frame>(frame);\r
- frame2->get_frame_transform() = transforms_[layer.first].fetch_and_tick(1);\r
- frame1 = core::basic_frame::interlace(frame1, frame2, format_desc_.field_mode);\r
- }\r
-\r
- frames[layer.first] = frame1;\r
- });\r
- \r
- graph_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5);\r
- \r
- std::shared_ptr<void> ticket(nullptr, [self](void*)\r
+ auto frame1 = make_safe<core::basic_frame>(frame);\r
+ frame1->get_frame_transform() = transform;\r
+\r
+ if(format_desc2.field_mode != core::field_mode::progressive)\r
+ { \r
+ auto frame2 = make_safe<core::basic_frame>(frame);\r
+ frame2->get_frame_transform() = transforms_[layer.first].fetch_and_tick(1);\r
+ frame1 = core::basic_frame::interlace(frame1, frame2, format_desc2.field_mode);\r
+ }\r
+\r
+ result[layer.first] = frame1;\r
+ }); \r
+ }\r
+ catch(...)\r
{\r
- auto self2 = self.lock();\r
- if(self2) \r
- self2->executor_.begin_invoke([=]{tick(self);}); \r
- });\r
- \r
- target_->send(std::make_pair(frames, ticket));\r
+ layers_.clear();\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ } \r
\r
- graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5);\r
- tick_timer_.restart();\r
- }\r
- catch(...)\r
- {\r
- layers_.clear();\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- } \r
+ return result;\r
+ });\r
}\r
\r
void apply_transforms(const std::vector<std::tuple<int, stage::transform_func_t, unsigned int, std::wstring>>& transforms)\r
return layers_[index].background();\r
}, high_priority);\r
}\r
- \r
- void set_video_format_desc(const video_format_desc& format_desc)\r
- {\r
- executor_.begin_invoke([=]\r
- {\r
- format_desc_ = format_desc;\r
- }, high_priority);\r
- }\r
\r
boost::unique_future<boost::property_tree::wptree> info()\r
{\r
{\r
return layers_[index].info();\r
}, high_priority));\r
- }\r
+ } \r
};\r
\r
-stage::stage(const safe_ptr<stage::target_t>& target, const safe_ptr<diagnostics::graph>& graph, const struct video_format_desc& format_desc) : impl_(new impl(target, graph, format_desc)){}\r
-void stage::start(int tokens){impl_->start(tokens);}\r
+stage::stage() : impl_(new impl()){}\r
void stage::apply_transforms(const std::vector<stage::transform_tuple_t>& transforms){impl_->apply_transforms(transforms);}\r
void stage::apply_transform(int index, const std::function<core::frame_transform(core::frame_transform)>& transform, unsigned int mix_duration, const std::wstring& tween){impl_->apply_transform(index, transform, mix_duration, tween);}\r
void stage::clear_transforms(int index){impl_->clear_transforms(index);}\r
boost::unique_future<safe_ptr<frame_producer>> stage::foreground(int index) {return impl_->foreground(index);}\r
boost::unique_future<safe_ptr<frame_producer>> stage::background(int index) {return impl_->background(index);}\r
boost::unique_future<std::wstring> stage::call(int index, bool foreground, const std::wstring& param){return impl_->call(index, foreground, param);}\r
-void stage::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\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, safe_ptr<class basic_frame>> stage::operator()(const video_format_desc& format_desc){return (*impl_)(format_desc);}\r
}}
\ No newline at end of file
\r
#include "frame_producer.h"\r
\r
-#include <common/concurrency/target.h>\r
#include <common/forward.h>\r
#include <common/memory/safe_ptr.h>\r
\r
class stage sealed : boost::noncopyable\r
{\r
public: \r
- typedef std::function<struct frame_transform(struct frame_transform)> transform_func_t;\r
- typedef std::tuple<int, transform_func_t, unsigned int, std::wstring> transform_tuple_t;\r
- typedef target<std::pair<std::map<int, safe_ptr<class basic_frame>>, std::shared_ptr<void>>> target_t;\r
+ typedef std::function<struct frame_transform(struct frame_transform)> transform_func_t;\r
+ typedef std::tuple<int, transform_func_t, unsigned int, std::wstring> transform_tuple_t;\r
\r
- explicit stage(const safe_ptr<target_t>& target, const safe_ptr<diagnostics::graph>& graph, const struct video_format_desc& format_desc);\r
+ stage();\r
\r
- void start(int tokens);\r
+ std::map<int, safe_ptr<class basic_frame>> operator()(const struct video_format_desc& format_desc);\r
\r
void apply_transforms(const std::vector<transform_tuple_t>& transforms);\r
void apply_transform(int index, const transform_func_t& transform, unsigned int mix_duration = 0, const std::wstring& tween = L"linear");\r
boost::unique_future<boost::property_tree::wptree> info() const;\r
boost::unique_future<boost::property_tree::wptree> info(int layer) const;\r
\r
- void set_video_format_desc(const struct video_format_desc& format_desc);\r
private:\r
struct impl;\r
safe_ptr<impl> impl_;\r
\r
#include "consumer/output.h"\r
#include "mixer/mixer.h"\r
-#include "mixer/gpu/ogl_device.h"\r
#include "mixer/write_frame.h"\r
+#include "mixer/gpu/accelerator.h"\r
+#include "frame.h"\r
#include "producer/stage.h"\r
#include "producer/frame/frame_factory.h"\r
\r
#include <common/diagnostics/graph.h>\r
#include <common/env.h>\r
+#include <common/concurrency/lock.h>\r
+\r
+#include <tbb/spin_mutex.h>\r
\r
#include <boost/property_tree/ptree.hpp>\r
\r
\r
struct video_channel::impl sealed : public frame_factory\r
{\r
+ reactive::basic_subject<safe_ptr<const frame>> frame_subject_;\r
const int index_;\r
+\r
+ mutable tbb::spin_mutex format_desc_mutex_;\r
video_format_desc format_desc_;\r
- const safe_ptr<ogl_device> ogl_;\r
+ \r
+ const safe_ptr<gpu::accelerator> ogl_;\r
const safe_ptr<diagnostics::graph> graph_;\r
\r
const safe_ptr<caspar::core::output> output_;\r
const safe_ptr<caspar::core::mixer> mixer_;\r
const safe_ptr<caspar::core::stage> stage_; \r
+\r
+ boost::timer tick_timer_;\r
+ boost::timer produce_timer_;\r
+ boost::timer mix_timer_;\r
+ boost::timer consume_timer_;\r
+\r
+ executor executor_;\r
public:\r
- impl(int index, const video_format_desc& format_desc, const safe_ptr<ogl_device>& ogl) \r
- : index_(index)\r
+ impl(int index, const video_format_desc& format_desc, const safe_ptr<gpu::accelerator>& ogl) \r
+ : index_(index)\r
, format_desc_(format_desc)\r
, ogl_(ogl)\r
- , output_(new caspar::core::output(graph_, format_desc, index))\r
- , mixer_(new caspar::core::mixer(output_, graph_, format_desc, ogl))\r
- , stage_(new caspar::core::stage(mixer_, graph_, format_desc)) \r
+ , output_(new caspar::core::output(format_desc, index))\r
+ , mixer_(new caspar::core::mixer(ogl))\r
+ , stage_(new caspar::core::stage()) \r
+ , executor_(L"video_channel")\r
{\r
+ graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8));\r
+ graph_->set_color("produce-time", diagnostics::color(0.0f, 1.0f, 0.0f));\r
+ graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f)); \r
+ graph_->set_color("consume-time", diagnostics::color(1.0f, 0.4f, 0.0f, 0.8));\r
graph_->set_text(print());\r
diagnostics::register_graph(graph_);\r
\r
- stage_->start(std::max(1, env::properties().get(L"configuration.pipeline-tokens", 2)));\r
+ executor_.begin_invoke([=]{tick();});\r
\r
CASPAR_LOG(info) << print() << " Successfully Initialized.";\r
}\r
-\r
+ \r
// frame_factory\r
\r
virtual safe_ptr<write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc, field_mode mode) override\r
\r
virtual core::video_format_desc get_video_format_desc() const override\r
{\r
- return format_desc_;\r
+ return lock(format_desc_mutex_, [&]\r
+ {\r
+ return format_desc_;\r
+ });\r
}\r
\r
// video_channel\r
\r
- void set_video_format_desc(const video_format_desc& format_desc)\r
+ void tick()\r
{\r
- if(format_desc.format == core::video_format::invalid)\r
- BOOST_THROW_EXCEPTION(invalid_argument() << msg_info("Invalid video-format"));\r
+ tick_timer_.restart();\r
\r
- try\r
- {\r
- output_->set_video_format_desc(format_desc);\r
- mixer_->set_video_format_desc(format_desc);\r
- stage_->set_video_format_desc(format_desc);\r
- ogl_->gc();\r
- }\r
- catch(...)\r
+ // Produce\r
+\r
+ produce_timer_.restart();\r
+\r
+ auto stage_frames = (*stage_)(format_desc_);\r
+ \r
+ graph_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5);\r
+\r
+ // Mix\r
+\r
+ mix_timer_.restart();\r
+\r
+ auto mixed_frame = (*mixer_)(std::move(stage_frames), format_desc_);\r
+ \r
+ graph_->set_value("mix-time", mix_timer_.elapsed()*format_desc_.fps*0.5);\r
+\r
+ // Consume\r
+\r
+ consume_timer_.restart();\r
+\r
+ frame_subject_.on_next(mixed_frame);\r
+\r
+ graph_->set_value("consume-time", consume_timer_.elapsed()*format_desc_.fps*0.5);\r
+\r
+ (*output_)(std::move(mixed_frame), format_desc_);\r
+ \r
+ graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5);\r
+\r
+ executor_.begin_invoke([=]{tick();});\r
+ }\r
+\r
+ void set_video_format_desc(const video_format_desc& format_desc)\r
+ {\r
+ ogl_->gc();\r
+ lock(format_desc_mutex_, [&]\r
{\r
- output_->set_video_format_desc(format_desc_);\r
- mixer_->set_video_format_desc(format_desc_);\r
- stage_->set_video_format_desc(format_desc_);\r
- throw;\r
- }\r
- format_desc_ = format_desc;\r
+ format_desc_ = format_desc;\r
+ });\r
}\r
\r
std::wstring print() const\r
}\r
};\r
\r
-video_channel::video_channel(int index, const video_format_desc& format_desc, const safe_ptr<ogl_device>& ogl) : impl_(new impl(index, format_desc, ogl)){}\r
+video_channel::video_channel(int index, const video_format_desc& format_desc, const safe_ptr<gpu::accelerator>& ogl) : impl_(new impl(index, format_desc, ogl)){}\r
safe_ptr<stage> video_channel::stage() { return impl_->stage_;} \r
safe_ptr<mixer> video_channel::mixer() { return impl_->mixer_;} \r
safe_ptr<frame_factory> video_channel::frame_factory() { return impl_;} \r
video_format_desc video_channel::get_video_format_desc() const{return impl_->format_desc_;}\r
void video_channel::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
boost::property_tree::wptree video_channel::info() const{return impl_->info();}\r
+void video_channel::subscribe(const observer_ptr& o) {impl_->frame_subject_.subscribe(o);}\r
+void video_channel::unsubscribe(const observer_ptr& o) {impl_->frame_subject_.unsubscribe(o);}\r
\r
}}
\ No newline at end of file
#pragma once\r
\r
#include <common/memory/safe_ptr.h>\r
+#include <common/reactive.h>\r
+#include <common/forward.h>\r
\r
#include <boost/noncopyable.hpp>\r
#include <boost/property_tree/ptree_fwd.hpp>\r
\r
+FORWARD3(caspar, core, gpu, class accelerator);\r
+\r
namespace caspar { namespace core {\r
\r
-class video_channel sealed : boost::noncopyable\r
+class video_channel sealed : public reactive::observable<safe_ptr<const struct frame>>\r
+ , boost::noncopyable\r
{\r
public:\r
- explicit video_channel(int index, const struct video_format_desc& format_desc, const safe_ptr<class ogl_device>& ogl);\r
+ explicit video_channel(int index, const struct video_format_desc& format_desc, const safe_ptr<gpu::accelerator>& ogl);\r
\r
safe_ptr<class stage> stage();\r
safe_ptr<class mixer> mixer();\r
\r
boost::property_tree::wptree info() const;\r
\r
- //int index() const;\r
+ // observable\r
+ \r
+ virtual void subscribe(const observer_ptr& o) override;\r
+ virtual void unsubscribe(const observer_ptr& o) override;\r
private:\r
struct impl;\r
safe_ptr<impl> impl_;\r
#include "../util/memory.h"\r
\r
#include <core/video_format.h>\r
-#include <core/mixer/read_frame.h>\r
+#include <core/frame.h>\r
\r
#include <common/concurrency/executor.h>\r
#include <common/diagnostics/graph.h>\r
unsigned int vid_fmt_;\r
\r
std::array<blue_dma_buffer_ptr, 4> reserved_frames_; \r
- tbb::concurrent_bounded_queue<std::shared_ptr<core::read_frame>> frame_buffer_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<const core::frame>> frame_buffer_;\r
\r
const bool embedded_audio_;\r
const bool key_only_;\r
CASPAR_LOG(error)<< print() << TEXT(" Failed to disable video output."); \r
}\r
\r
- void send(const safe_ptr<core::read_frame>& frame)\r
+ void send(const safe_ptr<const core::frame>& frame)\r
{ \r
executor_.begin_invoke([=]\r
{\r
});\r
}\r
\r
- void display_frame(const safe_ptr<core::read_frame>& frame)\r
+ void display_frame(const safe_ptr<const core::frame>& frame)\r
{\r
// Sync\r
\r
CASPAR_LOG(info) << print() << L" Successfully Initialized."; \r
}\r
\r
- virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
+ virtual bool send(const safe_ptr<const core::frame>& frame) override\r
{\r
CASPAR_VERIFY(audio_cadence_.front() == static_cast<size_t>(frame->audio_data().size()));\r
boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
\r
#include "../interop/DeckLinkAPI_h.h"\r
\r
-#include <core/mixer/read_frame.h>\r
+#include <core/frame.h>\r
+#include <core/mixer/audio/audio_mixer.h>\r
\r
#include <common/concurrency/executor.h>\r
#include <common/concurrency/lock.h>\r
class decklink_frame : public IDeckLinkVideoFrame\r
{\r
tbb::atomic<int> ref_count_;\r
- std::shared_ptr<core::read_frame> frame_;\r
+ std::shared_ptr<const core::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(const safe_ptr<core::read_frame>& frame, const core::video_format_desc& format_desc, bool key_only)\r
+ decklink_frame(const safe_ptr<const core::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
const std::wstring model_name_;\r
const core::video_format_desc format_desc_;\r
- const int buffer_size_;\r
+ const int buffer_size_;\r
\r
long long video_scheduled_;\r
long long audio_scheduled_;\r
\r
- int preroll_count_;\r
+ int preroll_count_;\r
\r
boost::circular_buffer<std::vector<int32_t>> audio_container_;\r
\r
- tbb::concurrent_bounded_queue<std::shared_ptr<core::read_frame>> video_frame_buffer_;\r
- tbb::concurrent_bounded_queue<std::shared_ptr<core::read_frame>> audio_frame_buffer_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<const core::frame>> video_frame_buffer_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<const core::frame>> audio_frame_buffer_;\r
\r
safe_ptr<diagnostics::graph> graph_;\r
boost::timer tick_timer_;\r
output_->BeginAudioPreroll(); \r
\r
for(int n = 0; n < buffer_size_; ++n)\r
- schedule_next_video(make_safe<core::read_frame>());\r
+ schedule_next_video(core::frame::empty());\r
\r
if(!config.embedded_audio)\r
start_playback();\r
~decklink_consumer()\r
{ \r
is_running_ = false;\r
- video_frame_buffer_.try_push(std::make_shared<core::read_frame>());\r
- audio_frame_buffer_.try_push(std::make_shared<core::read_frame>());\r
+ video_frame_buffer_.try_push(core::frame::empty());\r
+ audio_frame_buffer_.try_push(core::frame::empty());\r
\r
if(output_ != nullptr) \r
{\r
else if(result == bmdOutputFrameFlushed)\r
graph_->set_tag("flushed-frame");\r
\r
- std::shared_ptr<core::read_frame> frame; \r
+ std::shared_ptr<const core::frame> frame; \r
video_frame_buffer_.pop(frame); \r
schedule_next_video(make_safe_ptr(frame)); \r
\r
}\r
else\r
{\r
- std::shared_ptr<core::read_frame> frame;\r
+ std::shared_ptr<const core::frame> frame;\r
audio_frame_buffer_.pop(frame);\r
schedule_next_audio(frame->audio_data());\r
}\r
audio_scheduled_ += sample_frame_count;\r
}\r
\r
- void schedule_next_video(const safe_ptr<core::read_frame>& frame)\r
+ void schedule_next_video(const safe_ptr<const core::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
tick_timer_.restart();\r
}\r
\r
- void send(const safe_ptr<core::read_frame>& frame)\r
+ void send(const safe_ptr<const core::frame>& frame)\r
{\r
auto exception = lock(exception_mutex_, [&]\r
{\r
});\r
}\r
\r
- virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
+ virtual bool send(const safe_ptr<const core::frame>& frame) override\r
{\r
CASPAR_VERIFY(audio_cadence_.front() == static_cast<int>(frame->audio_data().size()));\r
boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
\r
#include "ffmpeg_consumer.h"\r
\r
-#include <core/mixer/read_frame.h>\r
+#include <core/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
}\r
\r
- std::shared_ptr<AVFrame> convert_video_frame(const safe_ptr<core::read_frame>& frame, AVCodecContext* c)\r
+ std::shared_ptr<AVFrame> convert_video_frame(const safe_ptr<const core::frame>& frame, AVCodecContext* c)\r
{\r
if(!sws_) \r
{\r
return local_av_frame;\r
}\r
\r
- std::shared_ptr<AVPacket> encode_video_frame(const safe_ptr<core::read_frame>& frame)\r
+ std::shared_ptr<AVPacket> encode_video_frame(const safe_ptr<const core::frame>& frame)\r
{ \r
auto c = video_st_->codec;\r
\r
return nullptr;\r
}\r
\r
- std::shared_ptr<AVPacket> encode_audio_frame(const safe_ptr<core::read_frame>& frame)\r
+ std::shared_ptr<AVPacket> encode_audio_frame(const safe_ptr<const core::frame>& frame)\r
{ \r
auto c = audio_st_->codec;\r
\r
return pkt;\r
}\r
\r
- void send(const safe_ptr<core::read_frame>& frame)\r
+ void send(const safe_ptr<const core::frame>& frame)\r
{\r
executor_.begin_invoke([=]\r
{ \r
consumer_.reset(new ffmpeg_consumer(filename_, format_desc, codec_, options_));\r
}\r
\r
- virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
+ virtual bool send(const safe_ptr<const core::frame>& frame) override\r
{\r
consumer_->send(frame);\r
return true;\r
}\r
\r
// Fix field-order if needed\r
- if(write->get_type() == core::field_mode::lower && frame_factory->get_video_format_desc().field_mode == core::field_mode::upper)\r
+ if(write->get_field_mode() == core::field_mode::lower && frame_factory->get_video_format_desc().field_mode == core::field_mode::upper)\r
write->get_frame_transform().fill_translation[1] += 1.0/static_cast<double>(frame_factory->get_video_format_desc().height);\r
- else if(write->get_type() == core::field_mode::upper && frame_factory->get_video_format_desc().field_mode == core::field_mode::lower)\r
+ else if(write->get_field_mode() == core::field_mode::upper && frame_factory->get_video_format_desc().field_mode == core::field_mode::lower)\r
write->get_frame_transform().fill_translation[1] -= 1.0/static_cast<double>(frame_factory->get_video_format_desc().height);\r
\r
return make_safe_ptr(write);\r
\r
#include <core/consumer/frame_consumer.h>\r
#include <core/video_format.h>\r
-#include <core/mixer/read_frame.h>\r
+#include <core/frame.h>\r
\r
#include <boost/date_time/posix_time/posix_time.hpp>\r
#include <boost/thread.hpp>\r
{\r
}\r
\r
- virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
+ virtual bool send(const safe_ptr<const core::frame>& frame) override\r
{ \r
boost::thread async([frame]\r
{\r
\r
#include <core/consumer/frame_consumer.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 <core/mixer/read_frame.h>\r
+#include <core/frame.h>\r
\r
#include <SFML/Audio/SoundStream.hpp>\r
\r
CASPAR_LOG(info) << print() << " Sucessfully Initialized.";\r
}\r
\r
- virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
+ virtual bool send(const safe_ptr<const core::frame>& frame) override\r
{ \r
input_.push(std::make_shared<audio_buffer_16>(core::audio_32_to_16(frame->audio_data())));\r
return true;\r
#include <ffmpeg/producer/filter/filter.h>\r
\r
#include <core/video_format.h>\r
-#include <core/mixer/read_frame.h>\r
+#include <core/frame.h>\r
#include <core/consumer/frame_consumer.h>\r
\r
#include <boost/timer.hpp>\r
unsigned int screen_y_;\r
unsigned int screen_width_;\r
unsigned int screen_height_;\r
- int square_width_;\r
- int square_height_; \r
+ int square_width_;\r
+ int square_height_; \r
\r
sf::Window window_;\r
\r
boost::timer perf_timer_;\r
boost::timer tick_timer_;\r
\r
- tbb::concurrent_bounded_queue<safe_ptr<core::read_frame>> frame_buffer_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<const core::frame>> frame_buffer_;\r
\r
boost::thread thread_;\r
tbb::atomic<bool> is_running_;\r
~ogl_consumer()\r
{\r
is_running_ = false;\r
- frame_buffer_.try_push(make_safe<core::read_frame>());\r
+ frame_buffer_.try_push(core::frame::empty());\r
thread_.join();\r
}\r
\r
is_running_ = false;\r
}\r
\r
- safe_ptr<core::read_frame> frame;\r
+ std::shared_ptr<const core::frame> frame;\r
frame_buffer_.pop(frame);\r
\r
perf_timer_.restart();\r
- render(frame);\r
+ render(make_safe_ptr(frame));\r
graph_->set_value("frame-time", perf_timer_.elapsed()*format_desc_.fps*0.5); \r
\r
window_.Display();\r
return av_frame;\r
}\r
\r
- void render(const safe_ptr<core::read_frame>& frame)\r
+ void render(const safe_ptr<const core::frame>& frame)\r
{ \r
if(static_cast<int>(frame->image_data().size()) != format_desc_.size)\r
return;\r
std::rotate(pbos_.begin(), pbos_.begin() + 1, pbos_.end());\r
}\r
\r
- bool send(const safe_ptr<core::read_frame>& frame)\r
+ bool send(const safe_ptr<const core::frame>& frame)\r
{\r
if(!frame_buffer_.try_push(frame))\r
graph_->set_tag("dropped-frame");\r
CASPAR_LOG(info) << print() << L" Successfully Initialized."; \r
}\r
\r
- virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
+ virtual bool send(const safe_ptr<const core::frame>& frame) override\r
{\r
return consumer_->send(frame);\r
}\r
--- /dev/null
+/*\r
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG (www.casparcg.com).\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public 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/producer/frame/basic_frame.h>\r
+#include <core/producer/frame/frame_factory.h>\r
+#include <core/producer/frame/pixel_format.h>\r
+#include <core/mixer/write_frame.h>\r
+#include <core/frame.h>\r
+\r
+#include <common/exception/exceptions.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/range/algorithm_ext/push_back.hpp>\r
+\r
+#include <queue>\r
+\r
+namespace caspar { namespace reroute {\r
+ \r
+class reroute_producer : public reactive::observer<safe_ptr<const core::frame>>\r
+ , public core::frame_producer\r
+ , public enable_safe_from_this<reroute_producer>\r
+{\r
+ const safe_ptr<diagnostics::graph> graph_;\r
+ const safe_ptr<core::frame_factory> frame_factory_;\r
+ \r
+ tbb::concurrent_bounded_queue<std::shared_ptr<const core::frame>> input_buffer_;\r
+ std::queue<safe_ptr<core::basic_frame>> frame_buffer_;\r
+ safe_ptr<core::basic_frame> last_frame_;\r
+ uint64_t frame_number_;\r
+\r
+public:\r
+ explicit reroute_producer(const safe_ptr<core::frame_factory>& frame_factory) \r
+ : frame_factory_(frame_factory)\r
+ , last_frame_(core::basic_frame::empty())\r
+ , frame_number_(0)\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 safe_ptr<const core::frame>& frame)\r
+ {\r
+ if(!input_buffer_.try_push(frame))\r
+ graph_->set_tag("dropped-frame");\r
+ }\r
+\r
+ // frame_producer\r
+ \r
+ virtual safe_ptr<core::basic_frame> receive(int) override\r
+ {\r
+ if(!frame_buffer_.empty())\r
+ {\r
+ auto frame = frame_buffer_.front();\r
+ frame_buffer_.pop();\r
+ return last_frame_ = frame;\r
+ }\r
+ \r
+ std::shared_ptr<const core::frame> read_frame;\r
+ if(input_buffer_.try_pop(read_frame) || read_frame->image_data().empty())\r
+ {\r
+ graph_->set_tag("late-frame");\r
+ return core::basic_frame::late(); \r
+ }\r
+ \r
+ frame_number_++;\r
+ \r
+ core::pixel_format_desc desc;\r
+ bool double_speed = std::abs(frame_factory_->get_video_format_desc().fps / 2.0 - read_frame->get_frame_rate()) < 0.01; \r
+ bool half_speed = std::abs(read_frame->get_frame_rate() / 2.0 - frame_factory_->get_video_format_desc().fps) < 0.01;\r
+\r
+ if(half_speed && frame_number_ % 2 == 0) // Skip frame\r
+ return receive(0);\r
+\r
+ desc.pix_fmt = core::pixel_format::bgra;\r
+ desc.planes.push_back(core::pixel_format_desc::plane(read_frame->width(), read_frame->height(), 4));\r
+ auto frame = frame_factory_->create_frame(this, desc);\r
+\r
+ A_memcpy(frame->image_data().begin(), read_frame->image_data().begin(), read_frame->image_data().size());\r
+ frame->commit();\r
+ boost::push_back(frame->audio_data(), read_frame->audio_data());\r
+\r
+ frame_buffer_.push(frame); \r
+ \r
+ if(double_speed) \r
+ frame_buffer_.push(frame);\r
+\r
+ return receive(0);\r
+ } \r
+\r
+ virtual safe_ptr<core::basic_frame> last_frame() const override\r
+ {\r
+ return last_frame_; \r
+ } \r
+\r
+ virtual std::wstring print() const override\r
+ {\r
+ return L"reroute[]";\r
+ }\r
+\r
+ virtual 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
+\r
+safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factory>& frame_factory, reactive::observable<safe_ptr<const core::frame>>& o)\r
+{\r
+ auto producer = make_safe<reroute_producer>(frame_factory);\r
+ o.subscribe(producer);\r
+ return create_producer_print_proxy(producer);\r
+}\r
+\r
+}}
\ No newline at end of file
\r
#pragma once\r
\r
-#include "../../video_channel.h"\r
-\r
#include <common/memory/safe_ptr.h>\r
+#include <common/reactive.h>\r
+#include <common/forward.h>\r
\r
-#include <string>\r
-#include <vector>\r
+#include <core/producer/frame/frame_factory.h>\r
+#include <core/producer/frame_producer.h>\r
+#include <core/frame.h>\r
\r
-namespace caspar { namespace core {\r
+namespace caspar { namespace reroute {\r
\r
-safe_ptr<struct frame_producer> create_channel_producer(const safe_ptr<struct frame_factory>& frame_factory, const safe_ptr<video_channel>& channel);\r
+safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factory>& frame_factory, reactive::observable<safe_ptr<const core::frame>>& o);\r
\r
}}\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <ItemGroup>\r
+ <Filter Include="source">\r
+ <UniqueIdentifier>{5475f6ab-bba4-49d3-822f-af300d1a550d}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="source\producer">\r
+ <UniqueIdentifier>{4f56d221-1d96-432f-97f8-d2d274a6310f}</UniqueIdentifier>\r
+ </Filter>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ClCompile Include="stdafx.cpp">\r
+ <Filter>source</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="producer\reroute_producer.cpp">\r
+ <Filter>source\producer</Filter>\r
+ </ClCompile>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ClInclude Include="stdafx.h">\r
+ <Filter>source</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="producer\reroute_producer.h">\r
+ <Filter>source\producer</Filter>\r
+ </ClInclude>\r
+ </ItemGroup>\r
+</Project>
\ No newline at end of file
--- /dev/null
+// 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
--- /dev/null
+#pragma once\r
#include <core/producer/frame_producer.h>\r
#include <core/video_format.h>\r
#include <core/producer/transition/transition_producer.h>\r
-#include <core/producer/channel/channel_producer.h>\r
#include <core/producer/frame/frame_transform.h>\r
#include <core/producer/stage.h>\r
#include <core/producer/layer.h>\r
#include <modules/ffmpeg/producer/util/util.h>\r
#include <modules/image/image.h>\r
#include <modules/ogl/ogl.h>\r
+#include <modules/reroute/producer/reroute_producer.h>\r
\r
#include <algorithm>\r
#include <locale>\r
{\r
if(channel != self)\r
{\r
- auto producer = create_channel_producer(self->frame_factory(), channel); \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
<ProjectReference Include="..\modules\flash\flash.vcxproj">\r
<Project>{816deaba-3757-4306-afe0-c27cf96c4dea}</Project>\r
</ProjectReference>\r
+ <ProjectReference Include="..\modules\reroute\reroute.vcxproj">\r
+ <Project>{7d58bd57-fdd5-46e6-a23b-ed14b5314a0e}</Project>\r
+ </ProjectReference>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="amcp\AMCPCommand.h" />\r
#include <common/exception/exceptions.h>\r
#include <common/utf.h>\r
\r
-#include <core/mixer/gpu/ogl_device.h>\r
+#include <core/mixer/gpu/accelerator.h>\r
#include <core/video_channel.h>\r
#include <core/video_format.h>\r
#include <core/producer/stage.h>\r
\r
struct server::impl : boost::noncopyable\r
{\r
- safe_ptr<ogl_device> ogl_;\r
+ safe_ptr<gpu::accelerator> ogl_;\r
std::vector<safe_ptr<IO::AsyncEventServer>> async_servers_; \r
std::vector<safe_ptr<video_channel>> channels_;\r
\r
impl() \r
- : ogl_(ogl_device::create())\r
+ : ogl_(gpu::accelerator::create())\r
{ \r
ffmpeg::init();\r
CASPAR_LOG(info) << L"Initialized ffmpeg module.";\r
<ProjectReference Include="..\modules\ogl\ogl.vcxproj">\r
<Project>{88f974f0-d09f-4788-8cf8-f563209e60c1}</Project>\r
</ProjectReference>\r
+ <ProjectReference Include="..\modules\reroute\reroute.vcxproj">\r
+ <Project>{7d58bd57-fdd5-46e6-a23b-ed14b5314a0e}</Project>\r
+ </ProjectReference>\r
<ProjectReference Include="..\protocol\protocol.vcxproj">\r
<Project>{2040b361-1fb6-488e-84a5-38a580da90de}</Project>\r
</ProjectReference>\r