<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<TreatWarningAsError>true</TreatWarningAsError>\r
<SmallerTypeCheck>true</SmallerTypeCheck>\r
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+ <MinimalRebuild>false</MinimalRebuild>\r
</ClCompile>\r
<Link>\r
<SubSystem>Windows</SubSystem>\r
<ClInclude Include="config.h" />\r
<ClInclude Include="exception\exceptions.h" />\r
<ClInclude Include="exception\win32_exception.h" />\r
+ <ClInclude Include="gl\utility.h" />\r
<ClInclude Include="hardware\cpuid.h" />\r
<ClInclude Include="image\clear.h" />\r
<ClInclude Include="image\copy.h" />\r
<ClInclude Include="image\copy_field.h" />\r
<ClInclude Include="image\image.h" />\r
- <ClInclude Include="image\lerp.h" />\r
- <ClInclude Include="image\over.h" />\r
- <ClInclude Include="image\pre_multiply.h" />\r
- <ClInclude Include="image\shuffle.h" />\r
<ClInclude Include="io\AsyncEventServer.h" />\r
<ClInclude Include="io\ClientInfo.h" />\r
<ClInclude Include="io\ProtocolStrategy.h" />\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="image\lerp.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
- <ClCompile Include="image\over.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
- <ClCompile Include="image\pre_multiply.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
- <ClCompile Include="image\shuffle.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
<ClCompile Include="io\AsyncEventServer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<Filter Include="Source\hardware">\r
<UniqueIdentifier>{5115d125-61f1-4fdd-9924-0f1bdced5d27}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="Source\gl">\r
+ <UniqueIdentifier>{0d94bbc2-e196-4618-a90b-19392a3a0a8e}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="stdafx.cpp">\r
<ClCompile Include="image\image.cpp">\r
<Filter>Source\image</Filter>\r
</ClCompile>\r
- <ClCompile Include="image\lerp.cpp">\r
- <Filter>Source\image</Filter>\r
- </ClCompile>\r
- <ClCompile Include="image\over.cpp">\r
- <Filter>Source\image</Filter>\r
- </ClCompile>\r
- <ClCompile Include="image\pre_multiply.cpp">\r
- <Filter>Source\image</Filter>\r
- </ClCompile>\r
- <ClCompile Include="image\shuffle.cpp">\r
- <Filter>Source\image</Filter>\r
- </ClCompile>\r
<ClCompile Include="image\clear.cpp">\r
<Filter>Source\image</Filter>\r
</ClCompile>\r
<ClInclude Include="image\image.h">\r
<Filter>Source\image</Filter>\r
</ClInclude>\r
- <ClInclude Include="image\lerp.h">\r
- <Filter>Source\image</Filter>\r
- </ClInclude>\r
- <ClInclude Include="image\over.h">\r
- <Filter>Source\image</Filter>\r
- </ClInclude>\r
- <ClInclude Include="image\pre_multiply.h">\r
- <Filter>Source\image</Filter>\r
- </ClInclude>\r
- <ClInclude Include="image\shuffle.h">\r
- <Filter>Source\image</Filter>\r
- </ClInclude>\r
<ClInclude Include="image\clear.h">\r
<Filter>Source\image</Filter>\r
</ClInclude>\r
<ClInclude Include="utility\find_file.h">\r
<Filter>Source\utility</Filter>\r
</ClInclude>\r
+ <ClInclude Include="gl\utility.h">\r
+ <Filter>Source\gl</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include <Glee.h>\r
+\r
+#include "../exception/exceptions.h"\r
+\r
+#include <boost/lexical_cast.hpp>\r
+\r
+namespace caspar { namespace common { namespace gpu {\r
+\r
+#ifdef _DEBUG\r
+ \r
+#define CASPAR_GL_CHECK(expr) \\r
+ do \\r
+ { \\r
+ expr; \\r
+ auto error = glGetError(); \\r
+ if(error != GL_NO_ERROR) \\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(boost::lexical_cast<std::string>(glGetError()))); \\r
+ }while(0);\r
+#else\r
+#define CASPAR_GL_CHECK(expr) expr\r
+#endif\r
+\r
+}}}
\ No newline at end of file
\r
#include "image.h"\r
\r
-#include "over.h"\r
-#include "lerp.h"\r
-#include "shuffle.h"\r
-#include "pre_multiply.h"\r
#include "copy.h"\r
#include "copy_field.h"\r
#include "clear.h"\r
namespace detail\r
{\r
cpuid my_cpuid;\r
- pre_over_fun pre_over = get_pre_over_fun(my_cpuid.SIMD);\r
- shuffle_fun shuffle = get_shuffle_fun(my_cpuid.SIMD);\r
- lerp_fun lerp = get_lerp_fun(my_cpuid.SIMD);\r
- pre_multiply_fun pre_multiply = get_pre_multiply_fun(my_cpuid.SIMD);\r
copy_fun copy = get_copy_fun(my_cpuid.SIMD);\r
copy_field_fun copy_field = get_copy_field_fun(my_cpuid.SIMD);\r
clear_fun clear = get_clear_fun(my_cpuid.SIMD);\r
}\r
\r
-void shuffle(void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha)\r
-{\r
- (*detail::shuffle)(dest, source, size, red, green, blue, alpha);\r
-}\r
-\r
-void pre_over(void* dest, const void* source1, const void* source2, size_t size)\r
-{\r
- (*detail::pre_over)(dest, source1, source2, size);\r
-}\r
-\r
-void lerp(void* dest, const void* source1, const void* source2, float alpha, size_t size)\r
-{\r
- (*detail::lerp)(dest, source1, source2, alpha, size);\r
-}\r
-\r
-void pre_multiply(void* dest, const void* source, size_t size)\r
-{\r
- (*detail::pre_multiply)(dest, source, size);\r
-}\r
-\r
void copy(void* dest, const void* source, size_t size)\r
{\r
(*detail::copy)(dest, source, size);\r
\r
void set_version(SIMD simd = AUTO);\r
\r
-void shuffle(void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha);\r
-void pre_over(void* dest, const void* source1, const void* source2, size_t size);\r
-void lerp(void* dest, const void* source1, const void* source2, float alpha, size_t size);\r
-void pre_multiply(void* dest, const void* source, size_t size);\r
void copy(void* dest, const void* source, size_t size);\r
void clear(void* dest, size_t size);\r
void copy_field(unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height);\r
\r
namespace detail\r
{\r
- typedef void(*pre_over_fun)(void*, const void*, const void*, size_t);\r
- typedef void(*shuffle_fun)(void*, const void*, size_t, const u8, const u8, const u8, const u8);\r
- typedef void(*lerp_fun)(void*, const void*, const void*, float, size_t);\r
- typedef void(*pre_multiply_fun)(void*, const void*, size_t);\r
typedef void(*copy_fun)(void*, const void*, size_t);\r
typedef void(*copy_field_fun)(unsigned char* pDest, const unsigned char* pSrc, size_t fieldIndex, size_t width, size_t height);\r
typedef void(*clear_fun)(void*, size_t);\r
\r
- extern pre_over_fun pre_over;\r
- extern shuffle_fun shuffle;\r
- extern lerp_fun lerp;\r
- extern pre_multiply_fun pre_multiply;\r
extern copy_fun copy;\r
extern copy_field_fun copy_field;\r
extern clear_fun clear;\r
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
- \r
-#include "../stdafx.h"\r
-\r
-#include "lerp.h"\r
-\r
-#include "../utility/types.h"\r
-\r
-#include "tbb/parallel_for.h"\r
-#include "tbb/blocked_range.h"\r
-\r
-#include <cassert>\r
-#include <intrin.h>\r
-#include <functional>\r
-\r
-using namespace std::tr1::placeholders;\r
-\r
-namespace caspar{\r
-namespace common{\r
-namespace image{\r
-\r
-static const size_t STRIDE = sizeof(__m128i)*4;\r
-\r
-void DolerpParallel(const tbb::blocked_range<size_t>& r, const std::tr1::function<void(void*, const void*, const void*, float, size_t)>& func, void* dest, const void* source1, const void* source2, float alpha)\r
-{\r
- size_t offset = r.begin()*STRIDE;\r
- size_t size = r.size()*STRIDE;\r
- func(reinterpret_cast<s8*>(dest) + offset, reinterpret_cast<const s8*>(source1) + offset, reinterpret_cast<const s8*>(source2) + offset, alpha, size);\r
-}\r
-\r
-void lerpParallel(const std::tr1::function<void(void*, const void*, const void*, float, size_t)>& func, void* dest, const void* source1, const void* source2, float alpha, size_t size)\r
-{\r
- tbb::parallel_for(tbb::blocked_range<size_t>(0, size/STRIDE), std::bind(&DolerpParallel, std::placeholders::_1, func, dest, source1, source2, alpha)); \r
-}\r
-\r
-lerp_fun get_lerp_fun(SIMD simd)\r
-{\r
- if(simd >= SSE2)\r
- return lerpParallel_SSE2;\r
- else\r
- return lerpParallel_REF;\r
-}\r
-\r
-void lerp_SSE2(void* dest, const void* source1, const void* source2, float alpha, size_t size)\r
-{\r
- static const u32 PSD = 64;\r
- \r
- static const __m128i lomask = _mm_set1_epi32(0x00FF00FF);\r
- static const __m128i round = _mm_set1_epi16(128);\r
-\r
- assert(source1 != NULL && source2 != NULL && dest != NULL);\r
- assert(size % STRIDE == 0);\r
- assert(alpha >= 0.0 && alpha <= 1.0);\r
-\r
- const __m128i* source128_1 = reinterpret_cast<const __m128i*>(source1);\r
- const __m128i* source128_2 = reinterpret_cast<const __m128i*>(source2);\r
- __m128i* dest128 = reinterpret_cast<__m128i*>(dest);\r
-\r
- __m128i s = _mm_setzero_si128();\r
- __m128i d = _mm_setzero_si128();\r
- const __m128i a = _mm_set1_epi16(static_cast<u8>(alpha*256.0f+0.5f));\r
- \r
- __m128i drb, dga, srb, sga;\r
- \r
- for (size_t k = 0, length = size/STRIDE; k < length; ++k)\r
- { \r
- _mm_prefetch(reinterpret_cast<const char*>(source128_1 + PSD), _MM_HINT_NTA); \r
- _mm_prefetch(reinterpret_cast<const char*>(source128_2 + PSD), _MM_HINT_NTA);\r
- // TODO: assembly optimization use PSHUFD on moves before calculations, lower latency than MOVDQA (R.N) http://software.intel.com/en-us/articles/fast-simd-integer-move-for-the-intel-pentiumr-4-processor/\r
-\r
- for(int n = 0; n < 4; ++n, ++dest128, ++source128_1, ++source128_2)\r
- {\r
- // r = d + (s-d)*alpha/256\r
- s = _mm_load_si128(source128_1); // AABBGGRR\r
- d = _mm_load_si128(source128_2); // AABBGGRR\r
-\r
- srb = _mm_and_si128(lomask, s); // 00BB00RR // unpack\r
- sga = _mm_srli_epi16(s, 8); // AA00GG00 // unpack\r
- \r
- drb = _mm_and_si128(lomask, d); // 00BB00RR // unpack\r
- dga = _mm_srli_epi16(d, 8); // AA00GG00 // unpack\r
-\r
- srb = _mm_sub_epi16(srb, drb); // BBBBRRRR // sub\r
- srb = _mm_mullo_epi16(srb, a); // BBBBRRRR // mul\r
- srb = _mm_add_epi16(srb, round);\r
- \r
- sga = _mm_sub_epi16(sga, dga); // AAAAGGGG // sub\r
- sga = _mm_mullo_epi16(sga, a); // AAAAGGGG // mul\r
- sga = _mm_add_epi16(sga, round);\r
-\r
- srb = _mm_srli_epi16(srb, 8); // 00BB00RR // prepack and div\r
- sga = _mm_andnot_si128(lomask, sga);// AA00GG00 // prepack and div\r
-\r
- srb = _mm_or_si128(srb, sga); // AABBGGRR // pack\r
-\r
- srb = _mm_add_epi8(srb, d); // AABBGGRR // add there is no overflow(R.N)\r
-\r
- _mm_stream_si128(dest128, srb);\r
- }\r
- }\r
- _mm_mfence(); //ensure last WC buffers get flushed to memory\r
-}\r
-\r
-void lerpParallel_SSE2(void* dest, const void* source1, const void* source2, float alpha, size_t size)\r
-{\r
- lerpParallel(&lerp_SSE2, dest, source1, source2, alpha, size);\r
-}\r
-\r
-void lerp_REF(void* dest, const void* source1, const void* source2, float alpha, size_t size)\r
-{\r
- assert(source1 != NULL && source2 != NULL && dest != NULL);\r
- assert(size % 4 == 0);\r
- assert(alpha >= 0.0f && alpha <= 1.0f);\r
-\r
- const u8* source8_1 = reinterpret_cast<const u8*>(source1);\r
- const u8* source8_2 = reinterpret_cast<const u8*>(source2);\r
- u8* dest8 = reinterpret_cast<u8*>(dest);\r
-\r
- u8 a = static_cast<u8>(alpha*256.0f);\r
- for(size_t n = 0; n < size; n+=4)\r
- {\r
- // s\r
- u32 sr = source8_1[n+0];\r
- u32 sg = source8_1[n+1];\r
- u32 sb = source8_1[n+2];\r
- u32 sa = source8_1[n+3];\r
-\r
- // d\r
- u32 dr = source8_2[n+0];\r
- u32 dg = source8_2[n+1];\r
- u32 db = source8_2[n+2];\r
- u32 da = source8_2[n+3];\r
-\r
- //dest8[n+0] = dr + ((sr-dr)*a)/256;\r
- //dest8[n+1] = dg + ((sg-dg)*a)/256;\r
- //dest8[n+2] = db + ((sb-db)*a)/256;\r
- //dest8[n+3] = da + ((sa-da)*a)/256;\r
-\r
- dest8[n+0] = static_cast<u8>( dr + int(float((sr-dr)*a)/256.0f+0.5f));\r
- dest8[n+1] = static_cast<u8>( dg + int(float((sg-dg)*a)/256.0f+0.5f));\r
- dest8[n+2] = static_cast<u8>( db + int(float((sb-db)*a)/256.0f+0.5f));\r
- dest8[n+3] = static_cast<u8>(da + int(float((sa-da)*a)/256.0f+0.5f));\r
-\r
- }\r
-}\r
-\r
-void lerpParallel_REF(void* dest, const void* source1, const void* source2, float alpha, size_t size)\r
-{\r
- lerpParallel(&lerp_REF, dest, source1, source2, alpha, size);\r
-}\r
-\r
-} // namespace image\r
-} // namespace common\r
-} // namespace caspar\r
-\r
-\r
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
-#pragma once\r
-\r
-#include "../hardware/cpuid.h"\r
-\r
-namespace caspar{ namespace common{ namespace image{\r
- \r
-void lerp_SSE2(void* dest, const void* source1, const void* source2, float alpha, size_t size);\r
-void lerp_REF (void* dest, const void* source1, const void* source2, float alpha, size_t size);\r
-void lerpParallel_SSE2(void* dest, const void* source1, const void* source2, float alpha, size_t size);\r
-void lerpParallel_REF (void* dest, const void* source1, const void* source2, float alpha, size_t size);\r
-void lerp_OLD (void* dest, const void* source1, const void* source2, float alpha, size_t size);\r
-\r
-typedef void(*lerp_fun)(void*, const void*, const void*, float, size_t);\r
-lerp_fun get_lerp_fun(SIMD simd = REF);\r
-\r
-}}}\r
-\r
-\r
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
- \r
-#include "../stdafx.h"\r
-\r
-#include "over.h"\r
-\r
-#include "../hardware/cpuid.h"\r
-#include "../utility/types.h"\r
-\r
-#include "tbb/parallel_for.h"\r
-#include "tbb/blocked_range.h"\r
-\r
-#include <cassert>\r
-#include <intrin.h>\r
-#include <functional>\r
-\r
-using namespace std::placeholders;\r
-\r
-namespace caspar{ namespace common{ namespace image {\r
-\r
-static const size_t STRIDE = sizeof(__m128i)*4;\r
-\r
-void Dopre_overParallel(const tbb::blocked_range<size_t>& r, const std::tr1::function<void(void*, const void*, const void*, size_t)>& func, void* dest, const void* source1, const void* source2)\r
-{\r
- size_t offset = r.begin()*STRIDE;\r
- size_t size = r.size()*STRIDE;\r
- func(reinterpret_cast<s8*>(dest) + offset, reinterpret_cast<const s8*>(source1) + offset, reinterpret_cast<const s8*>(source2) + offset, size);\r
-}\r
-\r
-void pre_overParallel(const std::tr1::function<void(void*, const void*, const void*, size_t)>& func, void* dest, const void* source1, const void* source2, size_t size)\r
-{\r
- tbb::parallel_for(tbb::blocked_range<size_t>(0, size/STRIDE), std::bind(&Dopre_overParallel, std::placeholders::_1, func, dest, source1, source2)); \r
-}\r
-\r
-pre_over_fun get_pre_over_fun(SIMD simd)\r
-{\r
- if(simd >= SSE2)\r
- return pre_overParallel_SSE2;\r
- else\r
- return pre_overParallel_REF;\r
-}\r
-\r
-// this function performs precise calculations\r
-void pre_over_SSE2(void* dest, const void* source1, const void* source2, size_t size)\r
-{\r
- static const u32 PSD = 64;\r
-\r
- static const __m128i round = _mm_set1_epi16(128);\r
- static const __m128i lomask = _mm_set1_epi32(0x00FF00FF);\r
-\r
- assert(source1 != NULL && source2 != NULL && dest != NULL);\r
- assert(size % STRIDE == 0);\r
-\r
- const __m128i* source128_1 = reinterpret_cast<const __m128i*>(source1);\r
- const __m128i* source128_2 = reinterpret_cast<const __m128i*>(source2);\r
- __m128i* dest128 = reinterpret_cast<__m128i*>(dest); \r
- \r
- __m128i d, s, a, rb, ag, t;\r
-\r
- // TODO: dynamic prefetch schedluing distance? needs to be optimized (R.N)\r
-\r
- for(size_t k = 0, length = size/STRIDE; k < length; ++k) \r
- {\r
- // TODO: put prefetch between calculations?(R.N)\r
- _mm_prefetch(reinterpret_cast<const s8*>(source128_1+PSD), _MM_HINT_NTA);\r
- _mm_prefetch(reinterpret_cast<const s8*>(source128_2+PSD), _MM_HINT_NTA); \r
-\r
- // work on entire cacheline before next prefetch\r
- for(int n = 0; n < 4; ++n, ++dest128, ++source128_1, ++source128_2)\r
- {\r
- // TODO: assembly optimization use PSHUFD on moves before calculations, lower latency than MOVDQA (R.N) http://software.intel.com/en-us/articles/fast-simd-integer-move-for-the-intel-pentiumr-4-processor/\r
-\r
- // TODO: load entire cacheline at the same time? are there enough registers? 32 bit mode (special compile for 64bit?) (R.N)\r
- s = _mm_load_si128(source128_1); // AABGGRR\r
- d = _mm_load_si128(source128_2); // AABGGRR\r
- \r
- // PRELERP(S, D) = S+D - ((S*D[A]+0x80)>>8)+(S*D[A]+0x80))>>8\r
- // T = S*D[A]+0x80 => PRELERP(S,D) = S+D - ((T>>8)+T)>>8\r
-\r
- // set alpha to lo16 from dest_\r
- a = _mm_srli_epi32(d, 24); // 000000AA \r
- rb = _mm_slli_epi32(a, 16); // 00AA0000\r
- a = _mm_or_si128(rb, a); // 00AA00AA\r
-\r
- rb = _mm_and_si128(lomask, s); // 00BB00RR \r
- rb = _mm_mullo_epi16(rb, a); // BBBBRRRR \r
- rb = _mm_add_epi16(rb, round); // BBBBRRRR\r
- t = _mm_srli_epi16(rb, 8); \r
- t = _mm_add_epi16(t, rb);\r
- rb = _mm_srli_epi16(t, 8); // 00BB00RR \r
-\r
- ag = _mm_srli_epi16(s, 8); // 00AA00GG \r
- ag = _mm_mullo_epi16(ag, a); // AAAAGGGG \r
- ag = _mm_add_epi16(ag, round);\r
- t = _mm_srli_epi16(ag, 8);\r
- t = _mm_add_epi16(t, ag);\r
- ag = _mm_andnot_si128(lomask, t); // AA00GG00 \r
- \r
- rb = _mm_or_si128(rb, ag); // AABGGRR pack\r
- \r
- rb = _mm_sub_epi8(s, rb); // sub S-[(D[A]*S)/255]\r
- d = _mm_add_epi8(d, rb); // add D+[S-(D[A]*S)/255]\r
-\r
- _mm_stream_si128(dest128, d);\r
- }\r
- } \r
- _mm_mfence(); //ensure last WC buffers get flushed to memory \r
-}\r
-\r
-void pre_overParallel_SSE2(void* dest, const void* source1, const void* source2, size_t size)\r
-{\r
- pre_overParallel(&pre_over_SSE2, dest, source1, source2, size); \r
-}\r
-\r
-// TODO: optimize\r
-void pre_over_REF(void* dest, const void* source1, const void* source2, size_t size)\r
-{ \r
- assert(source1 != NULL && source2 != NULL && dest != NULL);\r
- assert(size % 4 == 0);\r
-\r
- const u8* source8_1 = reinterpret_cast<const u8*>(source1);\r
- const u8* source8_2 = reinterpret_cast<const u8*>(source2);\r
- u8* dest8 = reinterpret_cast<u8*>(dest);\r
-\r
- for(size_t n = 0; n < size; n+=4)\r
- {\r
- u32 r1 = source8_1[n+0];\r
- u32 g1 = source8_1[n+1];\r
- u32 b1 = source8_1[n+2];\r
- u32 a1 = source8_1[n+3];\r
-\r
- u32 r2 = source8_2[n+0];\r
- u32 g2 = source8_2[n+1];\r
- u32 b2 = source8_2[n+2];\r
- u32 a2 = source8_2[n+3];\r
-\r
- dest8[n+0] = static_cast<u8>(r2 + r1 - (a2*r1)/255);\r
- dest8[n+1] = static_cast<u8>(g2 + g1 - (a2*g1)/255);\r
- dest8[n+2] = static_cast<u8>(b2 + b1 - (a2*b1)/255);\r
- dest8[n+3] = static_cast<u8>(a2 + a1 - (a2*a1)/255);\r
-\r
- // PRECISE\r
- //if(a2 > 0)\r
- //{\r
- // dest8[n+0] = r2 + r1 - int(float(a2*r1)/255.0f+0.5f);\r
- // dest8[n+1] = g2 + g1 - int(float(a2*g1)/255.0f+0.5f);\r
- // dest8[n+2] = b2 + b1 - int(float(a2*b1)/255.0f+0.5f);\r
- // dest8[n+3] = a2 + a1 - int(float(a2*a1)/255.0f+0.5f);\r
- //}\r
- //else\r
- //{\r
- // dest8[n+0] = r1;\r
- // dest8[n+1] = g1;\r
- // dest8[n+2] = b1;\r
- // dest8[n+3] = a1;\r
- //}\r
- }\r
-}\r
-\r
-void pre_overParallel_REF(void* dest, const void* source1, const void* source2, size_t size)\r
-{\r
- pre_overParallel(&pre_over_REF, dest, source1, source2, size); \r
-}\r
-\r
-}}}\r
-\r
-\r
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
-#pragma once\r
-\r
-#include "../hardware/cpuid.h"\r
-\r
-namespace caspar{ namespace common{ namespace image{\r
- \r
-void pre_over_SSE2(void* dest, const void* source1, const void* source2, size_t size);\r
-void pre_overParallel_SSE2(void* dest, const void* source1, const void* source2, size_t size);\r
-void pre_over_FastSSE2(void* dest, const void* source1, const void* source2, size_t size);\r
-void pre_over_REF(void* dest, const void* source1, const void* source2, size_t size);\r
-void pre_overParallel_REF(void* dest, const void* source1, const void* source2, size_t size);\r
-\r
-typedef void(*pre_over_fun)(void*, const void*, const void*, size_t);\r
-pre_over_fun get_pre_over_fun(SIMD simd = REF);\r
-\r
-}}}
\ No newline at end of file
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
- \r
-#include "../stdafx.h"\r
-\r
-#include "pre_multiply.h"\r
-\r
-#include "../utility/types.h"\r
-\r
-#include "tbb/parallel_for.h"\r
-#include "tbb/blocked_range.h"\r
-\r
-#include <cassert>\r
-#include <intrin.h>\r
-#include <functional>\r
-\r
-using namespace std::tr1::placeholders;\r
-\r
-namespace caspar{ namespace common{ namespace image{\r
-\r
-static const size_t STRIDE = sizeof(__m128i)*4;\r
-\r
-void Dopre_multiplyParallel(const tbb::blocked_range<size_t>& r, const std::tr1::function<void(void*, const void*, size_t)>& func, void* dest, const void* source)\r
-{\r
- size_t offset = r.begin()*STRIDE;\r
- size_t size = r.size()*STRIDE;\r
- func(reinterpret_cast<s8*>(dest) + offset, reinterpret_cast<const s8*>(source) + offset, size);\r
-}\r
-\r
-void pre_multiplyParallel(const std::tr1::function<void(void*, const void*, size_t)>& func, void* dest, const void* source, size_t size)\r
-{\r
- tbb::parallel_for(tbb::blocked_range<size_t>(0, size/STRIDE), std::bind(&Dopre_multiplyParallel, std::placeholders::_1, func, dest, source)); \r
-}\r
-\r
-pre_multiply_fun get_pre_multiply_fun(SIMD simd)\r
-{\r
- if(simd >= SSE2)\r
- return pre_multiplyParallel_SSE2;\r
- else\r
- return pre_multiplyParallel_REF;\r
-}\r
-\r
-// this function performs precise calculations\r
-void pre_multiply_SSE2(void* dest, const void* source, size_t size)\r
-{\r
- static const u32 PSD = 64;\r
-\r
- static const __m128i lomask = _mm_set1_epi32(0x00FF00FF);\r
- static const __m128i amask = _mm_set1_epi32(0xFF000000);\r
- static const __m128i round = _mm_set1_epi16(128); \r
-\r
- assert(source != NULL && dest != NULL);\r
- assert(size % STRIDE == 0);\r
- \r
- const __m128i* source128 = reinterpret_cast<const __m128i*>(source);\r
- __m128i* dest128 = reinterpret_cast<__m128i*>(dest); \r
-\r
- __m128i s, rb, ag, a, t; \r
- \r
- for(size_t k = 0, length = size/STRIDE; k != length; ++k) \r
- {\r
- // TODO: put prefetch between calculations?(R.N)\r
- _mm_prefetch(reinterpret_cast<const s8*>(source128 + PSD), _MM_HINT_NTA);\r
-\r
- // prefetch fetches entire cacheline (512bit). work on entire cacheline before next prefetch. 512/128 = 4, unroll four times = 16 pixels\r
-\r
- // TODO: assembly optimization use PSHUFD on moves before calculations, lower latency than MOVDQA (R.N) http://software.intel.com/en-us/articles/fast-simd-integer-move-for-the-intel-pentiumr-4-processor/\r
-\r
- for(int n = 0; n < 4; ++n, ++dest128, ++source128)\r
- {\r
- s = _mm_load_si128(source128); // AABBGGRR\r
-\r
- // set alpha to lo16 from source\r
- rb = _mm_srli_epi32(s, 24); // 000000AA\r
- a = _mm_slli_epi32(rb, 16); // 00AA0000\r
- a = _mm_or_si128(rb, a); // 00AA00AA\r
-\r
- rb = _mm_and_si128(lomask, s); // 00BB00RR \r
- rb = _mm_mullo_epi16(rb, a); // BBBBRRRR \r
- rb = _mm_add_epi16(rb, round); // BBBBRRRR\r
- t = _mm_srli_epi16(rb, 8); // 00BB00RR \r
- t = _mm_add_epi16(t, rb);\r
- rb = _mm_srli_epi16(t, 8);\r
-\r
- ag = _mm_srli_epi16(s, 8); // 00AA00GG \r
- ag = _mm_mullo_epi16(ag, a); // AAAAGGGG \r
- ag = _mm_add_epi16(ag, round);\r
- t = _mm_srli_epi16(ag, 8);\r
- t = _mm_add_epi16(t, ag);\r
- ag = _mm_andnot_si128(lomask, t); // AA00GG00 \r
- \r
- a = _mm_or_si128(rb, ag); // XXBBGGRR\r
- a = _mm_andnot_si128(amask, a); // 00BBGGRR\r
-\r
- s = _mm_and_si128(amask, s); // AA000000\r
-\r
- s = _mm_or_si128(a, s); // AABBGGRR pack\r
-\r
- // TODO: store entire cache line at the same time (write-combining => burst)? are there enough registers? 32 bit mode (special compile for 64bit?) (R.N)\r
- _mm_stream_si128(dest128, s);\r
- } \r
- }\r
- _mm_mfence(); //ensure last WC buffers get flushed to memory\r
-}\r
-\r
-void pre_multiplyParallel_SSE2(void* dest, const void* source1, size_t size)\r
-{\r
- pre_multiplyParallel(&pre_multiply_SSE2, dest, source1, size);\r
-}\r
-\r
-void pre_multiply_REF(void* dest, const void* source, size_t size)\r
-{\r
- assert(source != NULL && dest != NULL);\r
- assert(size % 4 == 0);\r
-\r
- const u8* source8 = reinterpret_cast<const u8*>(source);\r
- u8* dest8 = reinterpret_cast<u8*>(dest);\r
-\r
- for(size_t n = 0; n < size; n+=4)\r
- {\r
- u32 r = source8[n+0];\r
- u32 g = source8[n+1];\r
- u32 b = source8[n+2];\r
- u32 a = source8[n+3];\r
-\r
- dest8[n+0] = static_cast<u8>((r*a)/255);\r
- dest8[n+1] = static_cast<u8>((g*a)/255);\r
- dest8[n+2] = static_cast<u8>((b*a)/255);\r
- dest8[n+3] = static_cast<u8>(a);\r
- }\r
-}\r
-\r
-void pre_multiplyParallel_REF(void* dest, const void* source1, size_t size)\r
-{\r
- pre_multiplyParallel(&pre_multiply_REF, dest, source1, size);\r
-}\r
-\r
-}}}\r
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
-#pragma once\r
-\r
-#include "../hardware/cpuid.h"\r
-\r
-namespace caspar{ namespace common{ namespace image{\r
- \r
-void pre_multiply_SSE2 (void* dest, const void* source, size_t size);\r
-void pre_multiplyParallel_SSE2 (void* dest, const void* source, size_t size);\r
-void pre_multiply_FastSSE2(void* dest, const void* source, size_t size);\r
-void pre_multiply_REF (void* dest, const void* source, size_t size);\r
-void pre_multiplyParallel_REF (void* dest, const void* source, size_t size);\r
-\r
-typedef void(*pre_multiply_fun)(void*, const void*, size_t);\r
-pre_multiply_fun get_pre_multiply_fun(SIMD simd = REF);\r
-\r
-}}}\r
-\r
-\r
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
- \r
-#include "../stdafx.h"\r
-\r
-#include "shuffle.h"\r
-\r
-#include "../utility/types.h"\r
-\r
-#include "tbb/parallel_for.h"\r
-#include "tbb/blocked_range.h"\r
-\r
-#include <cassert>\r
-#include <intrin.h>\r
-#include <functional>\r
-\r
-using namespace std::tr1::placeholders;\r
-\r
-namespace caspar{ namespace common{ namespace image{\r
-\r
-static const size_t STRIDE = sizeof(__m128i)*4;\r
-\r
-void DoshuffleParallel(const tbb::blocked_range<size_t>& r, const std::tr1::function<void(void*, const void*, size_t, const u8, const u8, const u8, const u8)>& func, void* dest, const void* source, const u8 red, const u8 green, const u8 blue, const u8 alpha)\r
-{\r
- size_t offset = r.begin()*STRIDE;\r
- size_t size = r.size()*STRIDE;\r
- func(reinterpret_cast<s8*>(dest) + offset, reinterpret_cast<const s8*>(source) + offset, size, red, green, blue, alpha);\r
-}\r
-\r
-void shuffleParallel(const std::tr1::function<void(void*, const void*, size_t, const u8, const u8, const u8, const u8)>& func, void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha)\r
-{\r
- tbb::parallel_for(tbb::blocked_range<size_t>(0, size/STRIDE), std::bind(&DoshuffleParallel, std::placeholders::_1, func, dest, source, red, green, blue, alpha)); \r
-}\r
-\r
-shuffle_fun get_shuffle_fun(SIMD simd)\r
-{\r
- if(simd >= SSSE3)\r
- return shuffleParallel_SSSE3;\r
- else if(simd >= SSE2)\r
- return shuffleParallel_SSE2;\r
- else\r
- return shuffleParallel_REF;\r
-}\r
-\r
-void shuffle_SSSE3(void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha)\r
-{\r
- static const unsigned int PSD = 64; \r
-\r
- assert(source != NULL && dest != NULL);\r
- assert(red > -1 && red < 4 && green > -1 && green < 4 && blue > -1 && blue < 4 && alpha > -1 && alpha < 4 && "Invalid mask");\r
- assert(size % STRIDE == 0);\r
-\r
- const __m128i* source128 = reinterpret_cast<const __m128i*>(source);\r
- __m128i* dest128 = reinterpret_cast<__m128i*>(dest); \r
-\r
- __m128i reg0 = _mm_setzero_si128(); \r
- __m128i reg1 = _mm_setzero_si128(); \r
- __m128i reg2 = _mm_setzero_si128(); \r
- __m128i reg3 = _mm_setzero_si128(); \r
-\r
- const __m128i mask128 = _mm_set_epi8(alpha+12, blue+12, green+12, red+12, alpha+8, blue+8, green+8, red+8, alpha+4, blue+4, green+4, red+4, alpha, blue, green, red);\r
-\r
- for(size_t k = 0, length = size/STRIDE; k < length; ++k) \r
- {\r
- // TODO: put prefetch between calculations?(R.N)\r
- _mm_prefetch(reinterpret_cast<const s8*>(source128 + PSD), _MM_HINT_NTA);\r
-\r
- // work on entire cacheline before next prefetch\r
-\r
- // TODO: assembly optimization use PSHUFD on moves before calculations, lower latency than MOVDQA (R.N) http://software.intel.com/en-us/articles/fast-simd-integer-move-for-the-intel-pentiumr-4-processor/\r
-\r
- reg0 = _mm_load_si128(source128++); \r
- reg1 = _mm_load_si128(source128++); \r
-\r
- _mm_stream_si128(dest128++, _mm_shuffle_epi8(reg0, mask128));\r
-\r
- reg2 = _mm_load_si128(source128++); \r
-\r
- _mm_stream_si128(dest128++, _mm_shuffle_epi8(reg1, mask128));\r
-\r
- reg3 = _mm_load_si128(source128++); \r
- \r
- _mm_stream_si128(dest128++, _mm_shuffle_epi8(reg2, mask128)); \r
- _mm_stream_si128(dest128++, _mm_shuffle_epi8(reg3, mask128)); \r
- }\r
- _mm_mfence(); //ensure last WC buffers get flushed to memory\r
-}\r
-\r
-void shuffleParallel_SSSE3(void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha)\r
-{\r
- shuffleParallel(&shuffle_SSSE3, dest, source, size, red, green, blue, alpha);\r
-}\r
-\r
-// TODO: should be optimized for different combinations (R.N)\r
-void shuffle_SSE2(void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha)\r
-{\r
- static const size_t stride = sizeof(__m128i)*4;\r
- static const u32 PSD = 64;\r
-\r
- static const __m128i himask = _mm_set1_epi32(0xFF000000); \r
- static const __m128i lomask = _mm_set1_epi32(0x000000FF);\r
- \r
- assert(source != NULL && dest != NULL);\r
- assert(red > -1 && red < 4 && green > -1 && green < 4 && blue > -1 && blue < 4 && alpha > -1 && alpha < 4);\r
- assert(size % stride == 0);\r
-\r
- const __m128i* source128 = reinterpret_cast<const __m128i*>(source);\r
- __m128i* dest128 = reinterpret_cast<__m128i*>(dest); \r
-\r
- __m128i s, m0, m1, r;\r
-\r
- const int shft0 = (red)*8;\r
- const int shft1 = (green)*8;\r
- const int shft2 = (3-blue)*8;\r
- const int shft3 = (3-alpha)*8;\r
-\r
- for(int k = 0, length = size/stride; k < length; ++k) \r
- {\r
- // TODO: dynamic prefetch schedluing distance? needs to be optimized (R.N) \r
- // TODO: put prefetch between calculations?(R.N)\r
- _mm_prefetch(reinterpret_cast<const s8*>(source128 + PSD), _MM_HINT_NTA);\r
-\r
- // work on entire cacheline before next prefetch\r
-\r
- // TODO: assembly optimization use PSHUFD on moves before calculations, lower latency than MOVDQA (R.N) http://software.intel.com/en-us/articles/fast-simd-integer-move-for-the-intel-pentiumr-4-processor/\r
-\r
- for(int n = 0; n < 4; ++n, ++dest128, ++source128)\r
- {\r
- s = _mm_load_si128(source128);\r
- \r
- m0 = _mm_srli_epi32(s, shft0);\r
- m0 = _mm_and_si128(m0, lomask);\r
-\r
- m1 = _mm_srli_epi32(s, shft1);\r
- m1 = _mm_and_si128(m1, lomask);\r
- m1 = _mm_slli_epi32(m1, 8);\r
- \r
- r = _mm_or_si128(m0, m1);\r
-\r
- m0 = _mm_slli_epi32(s, shft2);\r
- m0 = _mm_and_si128(m0, himask);\r
- m0 = _mm_srli_epi32(m0, 8); \r
-\r
- m1 = _mm_slli_epi32(s, shft3);\r
- m1 = _mm_and_si128(m1, himask);\r
- \r
- m0 = _mm_or_si128(m0, m1);\r
-\r
- r = _mm_or_si128(r, m0);\r
-\r
- _mm_stream_si128(dest128, r);\r
- }\r
- }\r
- _mm_mfence(); //ensure last WC buffers get flushed to memory\r
-}\r
-\r
-void shuffleParallel_SSE2(void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha)\r
-{\r
- shuffleParallel(&shuffle_SSE2, dest, source, size, red, green, blue, alpha);\r
-}\r
-\r
-void shuffle_REF(void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha)\r
-{\r
- assert(source != NULL && dest != NULL);\r
- assert(red > -1 && red < 4 && green > -1 && green < 4 && blue > -1 && blue < 4 && alpha > -1 && alpha < 4);\r
- assert(size % 4 == 0);\r
-\r
- const u8* source8 = reinterpret_cast<const u8*>(source);\r
- u8* dest8 = reinterpret_cast<u8*>(dest); \r
-\r
- for(size_t n = 0; n < size; n+=4)\r
- {\r
- u8 r = source8[n+red];\r
- u8 g = source8[n+green];\r
- u8 b = source8[n+blue];\r
- u8 a = source8[n+alpha];\r
-\r
- dest8[n+0] = r;\r
- dest8[n+1] = g;\r
- dest8[n+2] = b;\r
- dest8[n+3] = a;\r
- }\r
-}\r
-\r
-void shuffleParallel_REF(void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha)\r
-{\r
- shuffleParallel(&shuffle_REF, dest, source, size, red, green, blue, alpha);\r
-}\r
-\r
-}}}\r
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
-#pragma once\r
-\r
-#include "../hardware/cpuid.h"\r
-#include "../utility/types.h"\r
-\r
-namespace caspar{ namespace common{ namespace image{\r
-\r
-void shuffle_SSSE3(void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha);\r
-void shuffle_SSE2 (void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha);\r
-void shuffle_REF (void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha);\r
-void shuffleParallel_SSSE3(void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha);\r
-void shuffleParallel_SSE2 (void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha);\r
-void shuffleParallel_REF (void* dest, const void* source, size_t size, const u8 red, const u8 green, const u8 blue, const u8 alpha);\r
-\r
-typedef void(*shuffle_fun)(void*, const void*, size_t, const u8, const u8, const u8, const u8);\r
-shuffle_fun get_shuffle_fun(SIMD simd = REF);\r
-\r
-}}}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>\r
<configuration>\r
<paths>\r
- <media-path>C:\\casparcg\\Repository\\media\\</media-path>\r
- <log-path>C:\\casparcg\\Repository\\log\\</log-path>\r
- <template-path>C:\\casparcg\\Repository\\templates\\</template-path>\r
- <data-path>C:\\casparcg\\Repository\\data\\</data-path>\r
+ <media-path>C:\\Casparcg\\_media\\</media-path>\r
+ <log-path>C:\\Casparcg\\_log\\</log-path>\r
+ <template-path>C:\\Casparcg\\_templates\\</template-path>\r
+ <data-path>C:\\Casparcg\\_data\\</data-path>\r
</paths>\r
<channels>\r
<channel>\r
\r
#define TBB_USE_THREADING_TOOLS 1\r
\r
-//#define DISABLE_BLUEFISH\r
+#define DISABLE_BLUEFISH\r
}\r
}\r
\r
-void BlueFishVideoConsumer::display(const frame_ptr& frame)\r
+void BlueFishVideoConsumer::display(const gpu_frame_ptr& frame)\r
{\r
if(frame == nullptr)\r
return;\r
{\r
try\r
{\r
- frame_ptr frame;\r
+ gpu_frame_ptr frame;\r
frameBuffer_.pop(frame);\r
if(frame == nullptr)\r
return;\r
static int EnumerateDevices();\r
static frame_consumer_ptr Create(const frame_format_desc& format_desc, unsigned int deviceIndex);\r
\r
- void display(const frame_ptr&);\r
+ void display(const gpu_frame_ptr&);\r
\r
const frame_format_desc& get_frame_format_desc() const { return format_desc_; }\r
\r
\r
std::exception_ptr pException_;\r
boost::thread thread_;\r
- tbb::concurrent_bounded_queue<frame_ptr> frameBuffer_;\r
+ tbb::concurrent_bounded_queue<gpu_frame_ptr> frameBuffer_;\r
};\r
typedef std::tr1::shared_ptr<BlueFishVideoConsumer> BlueFishFrameConsumerPtr;\r
\r
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
- \r
-#ifndef _CASPAR_BLUEFISHVIDEOFRAMEFACTORY_H__\r
-#define _CASPAR_BLUEFISHVIDEOFRAMEFACTORY_H__\r
-\r
-#pragma once\r
-\r
-#include "..\..\frame\system_frame.h"\r
-#include "..\..\frame\frame_format.h"\r
-#include <list>\r
-#include <memory>\r
-#include "BluefishException.h"\r
-\r
-#include <tbb\mutex.h>\r
-\r
-class CBlueVelvet4;\r
-\r
-namespace caspar {\r
-namespace bluefish {\r
-\r
-typedef std::tr1::shared_ptr<CBlueVelvet4> BlueVelvetPtr;\r
-\r
-class VideoFrameInfo\r
-{\r
-public:\r
- VideoFrameInfo() {}\r
- virtual ~VideoFrameInfo() {}\r
-\r
- virtual unsigned char* GetPtr() const = 0;\r
- virtual int GetBufferID() const = 0;\r
- virtual int size() const = 0;\r
-};\r
-typedef std::tr1::shared_ptr<VideoFrameInfo> VideoFrameInfoPtr;\r
-\r
-class CardFrameInfo : public VideoFrameInfo\r
-{\r
-public:\r
- CardFrameInfo(BlueVelvetPtr pSDK, int dataSize, int bufferID);\r
- ~CardFrameInfo();\r
-\r
- unsigned char* GetPtr() const {\r
- return pData_;\r
- }\r
- int GetBufferID() const {\r
- return bufferID_;\r
- }\r
- int size() const {\r
- return dataSize_;\r
- }\r
-\r
-private:\r
- BlueVelvetPtr pSDK_;\r
- unsigned char* pData_;\r
- int bufferID_;\r
- int dataSize_;\r
-};\r
-\r
-class SystemFrameInfo : public VideoFrameInfo\r
-{\r
-public:\r
- SystemFrameInfo(int dataSize, int bufferID);\r
- ~SystemFrameInfo();\r
-\r
- unsigned char* GetPtr() const {\r
- return pData_;\r
- }\r
- int GetBufferID() const {\r
- return bufferID_;\r
- }\r
- int size() const {\r
- return dataSize_;\r
- }\r
-\r
-private:\r
- unsigned char* pData_;\r
- int bufferID_;\r
- int dataSize_;\r
-};\r
-\r
-class BluefishFrameManager\r
-{\r
- friend class BluefishVideoFrame;\r
- typedef std::list<VideoFrameInfoPtr> FrameInfoList;\r
-\r
- BluefishFrameManager(const BluefishFrameManager&);\r
- const BluefishFrameManager& operator=(const BluefishFrameManager&);\r
-\r
-public:\r
- BluefishFrameManager(BlueVelvetPtr pSDK, frame_format fmt, unsigned long optimalLength);\r
- virtual ~BluefishFrameManager();\r
-\r
- virtual std::shared_ptr<BluefishVideoFrame> CreateFrame();\r
- virtual const frame_format_desc& get_frame_format_desc() const;\r
-\r
-private:\r
- VideoFrameInfoPtr GetBuffer();\r
- void ReturnBuffer(VideoFrameInfoPtr);\r
-\r
- BlueVelvetPtr pSDK_;\r
- frame_format format_;\r
- FrameInfoList frameBuffers_;\r
- tbb::mutex mutex_;\r
-};\r
-typedef std::tr1::shared_ptr<BluefishFrameManager> BluefishFrameManagerPtr;\r
-\r
-\r
-class BluefishVideoFrame : public frame\r
-{\r
-public:\r
- explicit BluefishVideoFrame(BluefishFrameManager* pFrameManager);\r
-\r
- virtual ~BluefishVideoFrame();\r
-\r
- unsigned char* data() { return data_; }\r
-\r
- unsigned int size() const { return size_; }\r
- \r
- long meta_data() const { return buffer_id_; }\r
-\r
- void* tag() const\r
- {\r
- return pFrameManager_;\r
- }\r
-private:\r
- unsigned char* data_;\r
- long buffer_id_;\r
- size_t size_;\r
- VideoFrameInfoPtr pInfo_;\r
- BluefishFrameManager* pFrameManager_;\r
-};\r
-\r
-\r
-} //namespace bluefish\r
-} //namespace caspar\r
-\r
-#endif //_CASPAR_BLUEFISHVIDEOFRAMEFACTORY_H__
\ No newline at end of file
return frame;\r
}\r
\r
- void DisplayFrame(const frame_ptr& frame)\r
+ void DisplayFrame(const gpu_frame_ptr& frame)\r
{\r
if(frame != nullptr) {\r
if(pConsumer_->pFrameManager_.get() == reinterpret_cast<BluefishFrameManager*>(frame->tag())) {\r
// return pImpl_->pConsumer_;\r
//}\r
//\r
-//frame_ptr BluefishPlaybackStrategy::GetReservedFrame() {\r
+//gpu_frame_ptr BluefishPlaybackStrategy::GetReservedFrame() {\r
// return pImpl_->GetReservedFrame();\r
//}\r
\r
-void BluefishPlaybackStrategy::display(const frame_ptr& frame) \r
+void BluefishPlaybackStrategy::display(const gpu_frame_ptr& frame) \r
{\r
return pImpl_->DisplayFrame(frame);\r
}\r
\r
#pragma once\r
\r
-#include "../../frame/frame.h"\r
+#include "../../frame/gpu_frame.h"\r
#include "../../consumer/frame_consumer.h"\r
\r
namespace caspar {\r
explicit BluefishPlaybackStrategy(BlueFishVideoConsumer* pConsumer);\r
virtual ~BluefishPlaybackStrategy();\r
\r
- void display(const frame_ptr&);\r
+ void display(const gpu_frame_ptr&);\r
};\r
\r
} //namespace bluefish\r
#include "DecklinkVideoConsumer.h"\r
#include "DeckLinkAPI_h.h"\r
\r
-#include "../../frame/system_frame.h"\r
#include "../../frame/frame_format.h"\r
#include "../../../common/image/image.h"\r
\r
struct DecklinkVideoConsumer::Implementation : public IDeckLinkVideoOutputCallback\r
{\r
struct DecklinkFrameManager;\r
- struct DecklinkVideoFrame : public frame\r
+ struct DecklinkVideoFrame\r
{\r
explicit DecklinkVideoFrame(DecklinkFrameManager* pFactory)\r
{\r
{\r
return pBytes_;\r
}\r
+ \r
+ size_t width() const { return 0; }\r
+ size_t height() const { return 0; }\r
\r
bool valid() const \r
{\r
return pResult;\r
}\r
\r
- void DisplayFrame(const frame_ptr& frame)\r
+ void DisplayFrame(const gpu_frame_ptr& frame)\r
{\r
if(frame != NULL) \r
{\r
- if(pConsumerImpl_->pFrameManager_.get() == reinterpret_cast<DecklinkFrameManager*>(frame->tag()))\r
- {\r
- DoRender(std::static_pointer_cast<DecklinkVideoFrame>(frame));\r
- }\r
- else \r
+ std::shared_ptr<DecklinkVideoFrame> pTempFrame = GetReservedFrame();\r
+ if(pTempFrame && frame->size() == pTempFrame->size())\r
{\r
- std::shared_ptr<DecklinkVideoFrame> pTempFrame = GetReservedFrame();\r
- if(pTempFrame && frame->size() == pTempFrame->size())\r
- {\r
- common::image::copy(pTempFrame->data(), frame->data(), pTempFrame->size());\r
- DoRender(pTempFrame);\r
- }\r
- else\r
- CASPAR_LOG(error) << "DECKLINK: Failed to get reserved frame";\r
+ common::image::copy(pTempFrame->data(), frame->data(), pTempFrame->size());\r
+ DoRender(pTempFrame);\r
}\r
+ else\r
+ CASPAR_LOG(error) << "DECKLINK: Failed to get reserved frame"; \r
}\r
else \r
{\r
explicit DecklinkFrameManager(Implementation* pConsumerImpl) : pConsumerImpl_(pConsumerImpl)\r
{\r
}\r
-\r
- frame_ptr CreateFrame() {\r
- return std::make_shared<system_frame>(pConsumerImpl_->get_frame_format_desc().size);\r
- }\r
-\r
+ \r
std::shared_ptr<DecklinkVideoFrame> CreateReservedFrame() {\r
return std::make_shared<DecklinkVideoFrame>(this);\r
}\r
\r
std::exception_ptr pException_;\r
boost::thread thread_;\r
- tbb::concurrent_bounded_queue<frame_ptr> frameBuffer_;\r
+ tbb::concurrent_bounded_queue<gpu_frame_ptr> frameBuffer_;\r
\r
// IDeckLinkMutableVideoFrame* pNextFrame_;\r
\r
ReleaseDevice();\r
}\r
\r
- void DisplayFrame(const frame_ptr& frame)\r
+ void DisplayFrame(const gpu_frame_ptr& frame)\r
{\r
if(frame == nullptr)\r
return; \r
{\r
try\r
{ \r
- frame_ptr frame;\r
+ gpu_frame_ptr frame;\r
frameBuffer_.pop(frame);\r
if(frame == nullptr)\r
return;\r
DecklinkVideoConsumer::DecklinkVideoConsumer(const caspar::frame_format_desc& format_desc, bool internalKey) : pImpl_(new Implementation(format_desc, internalKey))\r
{}\r
\r
-void DecklinkVideoConsumer::display(const frame_ptr& frame)\r
+void DecklinkVideoConsumer::display(const gpu_frame_ptr& frame)\r
{\r
pImpl_->DisplayFrame(frame);\r
}\r
public:\r
explicit DecklinkVideoConsumer(const caspar::frame_format_desc& format_desc, bool internalKey = false);\r
\r
- void display(const frame_ptr&);\r
+ void display(const gpu_frame_ptr&);\r
const frame_format_desc& get_frame_format_desc() const;\r
private:\r
struct Implementation;\r
virtual ~frame_consumer() {}\r
\r
virtual const frame_format_desc& get_frame_format_desc() const = 0;\r
- virtual void prepare(const frame_ptr&){};\r
- virtual void display(const frame_ptr&){};\r
+ virtual void prepare(const gpu_frame_ptr&){};\r
+ virtual void display(const gpu_frame_ptr&){};\r
};\r
typedef std::shared_ptr<frame_consumer> frame_consumer_ptr;\r
typedef std::shared_ptr<const frame_consumer> frame_consumer_const_ptr;\r
\r
#include "oal_frame_consumer.h"\r
\r
-#include "../../frame/audio_chunk.h"\r
-#include "../../frame/frame.h"\r
+#include "../../frame/gpu_frame.h"\r
#include "../../frame/frame_format.h"\r
\r
#include <SFML/Audio.hpp>\r
class sound_channel : public sf::SoundStream\r
{\r
public:\r
- sound_channel() : internal_chunks_(5)\r
+ sound_channel() : internal_chunks_(5), silence_(1920*2, 0)\r
{\r
external_chunks_.set_capacity(3);\r
+ sf::SoundStream::Initialize(2, 48000);\r
}\r
\r
~sound_channel()\r
external_chunks_.push(nullptr);\r
Stop();\r
}\r
-\r
- void Initialize(const sound_channel_info_ptr& info)\r
+ \r
+ void push(const gpu_frame_ptr& frame)\r
{\r
- sf::SoundStream::Initialize(info->channels_count, info->sample_rate);\r
- assert(info->bits_per_sample/(8*sizeof(char)) == sizeof(sf::Int16));\r
- }\r
+ if(frame->audio_data().empty())\r
+ frame->audio_data() = silence_;\r
\r
- void Push(const audio_chunk_ptr& paudio_chunk)\r
- {\r
- if(!external_chunks_.try_push(paudio_chunk))\r
- {\r
+ //if(!external_chunks_.try_push(frame))\r
+ //{\r
//CASPAR_LOG(debug) << "Sound Buffer Overrun";\r
- external_chunks_.push(paudio_chunk);\r
- }\r
+ external_chunks_.push(frame);\r
+ //}\r
\r
if(GetStatus() != Playing && external_chunks_.size() >= 3)\r
Play();\r
\r
bool OnGetData(sf::SoundStream::Chunk& data)\r
{\r
- audio_chunk_ptr pChunk;\r
- if(!external_chunks_.try_pop(pChunk))\r
- {\r
- CASPAR_LOG(trace) << "Sound Buffer Underrun";\r
- external_chunks_.pop(pChunk);\r
- }\r
+ gpu_frame_ptr frame;\r
+ //if(!external_chunks_.try_pop(frame))\r
+ //{\r
+ //CASPAR_LOG(trace) << "Sound Buffer Underrun";\r
+ external_chunks_.pop(frame);\r
+ //}\r
\r
- if(pChunk == nullptr)\r
+ if(frame == nullptr)\r
{\r
external_chunks_.clear();\r
return false;\r
}\r
\r
- internal_chunks_.push_back(pChunk);\r
- SetVolume(pChunk->volume());\r
- data.Samples = reinterpret_cast<sf::Int16*>(pChunk->data());\r
- data.NbSamples = pChunk->size()/sizeof(sf::Int16);\r
+ internal_chunks_.push_back(frame);\r
+ //SetVolume(pChunk->volume());\r
+ data.Samples = reinterpret_cast<sf::Int16*>(frame->audio_data().data());\r
+ data.NbSamples = frame->audio_data().size();\r
return true;\r
}\r
\r
- boost::circular_buffer<audio_chunk_ptr> internal_chunks_;\r
- tbb::concurrent_bounded_queue<audio_chunk_ptr> external_chunks_;\r
+ std::vector<short> silence_;\r
+ boost::circular_buffer<gpu_frame_ptr> internal_chunks_;\r
+ tbb::concurrent_bounded_queue<gpu_frame_ptr> external_chunks_;\r
};\r
typedef std::shared_ptr<sound_channel> sound_channelPtr;\r
\r
{ \r
implementation(const frame_format_desc& format_desc) : format_desc_(format_desc)\r
{\r
- for(int n = 0; n < 3; ++n)\r
- channel_pool_.push(std::make_shared<sound_channel>());\r
}\r
\r
- void push(const frame_ptr& frame)\r
+ void push(const gpu_frame_ptr& frame)\r
{\r
- if(frame == nullptr)\r
- return;\r
-\r
- decltype(channels_) active_channels;\r
- BOOST_FOREACH(const audio_chunk_ptr& pChunk, frame->audio_data())\r
- {\r
- auto info = pChunk->sound_channel_info();\r
- auto it = channels_.find(info);\r
- sound_channelPtr channel;\r
- if(it == channels_.end())\r
- {\r
- if(channel_pool_.size() <= 1)\r
- channel_pool_.push(std::make_shared<sound_channel>());\r
- \r
- sound_channelPtr pNewChannel;\r
- channel_pool_.pop(pNewChannel);\r
-\r
- channel = sound_channelPtr(pNewChannel.get(), [=](sound_channel*)\r
- {\r
- channel_pool_.push(pNewChannel);\r
- pNewChannel->Push(nullptr);\r
- });\r
- channel->Initialize(info);\r
- }\r
- else\r
- channel = it->second;\r
-\r
- active_channels.insert(std::make_pair(info, channel));\r
- channel->Push(pChunk); // Could Block\r
- }\r
-\r
- channels_ = std::move(active_channels);\r
+ channel_.push(frame);\r
}\r
\r
- tbb::concurrent_bounded_queue<sound_channelPtr> channel_pool_;\r
- std::map<sound_channel_info_ptr, sound_channelPtr> channels_;\r
+ sound_channel channel_;\r
\r
caspar::frame_format_desc format_desc_;\r
};\r
\r
oal_frame_consumer::oal_frame_consumer(const caspar::frame_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
const caspar::frame_format_desc& oal_frame_consumer::get_frame_format_desc() const{return impl_->format_desc_;}\r
-void oal_frame_consumer::prepare(const frame_ptr& frame){impl_->push(frame);}\r
+void oal_frame_consumer::prepare(const gpu_frame_ptr& frame){impl_->push(frame);}\r
}}\r
explicit oal_frame_consumer(const frame_format_desc& format_desc);\r
\r
const frame_format_desc& get_frame_format_desc() const; \r
- void prepare(const frame_ptr& frame);\r
+ void prepare(const gpu_frame_ptr& frame);\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
\r
#include "ogl_frame_consumer.h"\r
\r
-#include "../../frame/system_frame.h"\r
#include "../../frame/frame_format.h"\r
+#include "../../frame/gpu_frame.h"\r
#include "../../../common/image/image.h"\r
\r
#include <boost/thread.hpp>\r
return std::make_pair(width, height);\r
}\r
\r
- void render(const frame_ptr& frame)\r
+ void render(const gpu_frame_ptr& frame)\r
{ \r
// Render\r
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
pbo_index_ = nextPboIndex;\r
}\r
\r
- void display(const frame_ptr& frame)\r
+ void display(const gpu_frame_ptr& frame)\r
{\r
if(frame == nullptr)\r
return; \r
auto period = boost::posix_time::microseconds(static_cast<long>(get_frame_format_period(format_desc_)*1000000.0));\r
auto time = boost::posix_time::microsec_clock::local_time();\r
\r
- frame_ptr frame;\r
+ gpu_frame_ptr frame;\r
do\r
{\r
try\r
\r
std::exception_ptr exception_;\r
boost::thread thread_;\r
- tbb::concurrent_bounded_queue<frame_ptr> frame_buffer_;\r
+ tbb::concurrent_bounded_queue<gpu_frame_ptr> frame_buffer_;\r
};\r
\r
ogl_frame_consumer::ogl_frame_consumer(const caspar::frame_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)\r
: impl_(new implementation(format_desc, screen_index, stretch, windowed)){}\r
const caspar::frame_format_desc& ogl_frame_consumer::get_frame_format_desc() const{return impl_->format_desc_;}\r
-void ogl_frame_consumer::display(const frame_ptr& frame){impl_->display(frame);}\r
+void ogl_frame_consumer::display(const gpu_frame_ptr& frame){impl_->display(frame);}\r
}}\r
explicit ogl_frame_consumer(const frame_format_desc& format_desc, unsigned int screen_index = 0, stretch stretch = stretch::fill, bool windowed = false);\r
\r
const frame_format_desc& get_frame_format_desc() const; \r
- void display(const frame_ptr& frame);\r
+ void display(const gpu_frame_ptr& frame);\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
<ClCompile>\r
<Optimization>Disabled</Optimization>\r
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <MinimalRebuild>true</MinimalRebuild>\r
+ <MinimalRebuild>false</MinimalRebuild>\r
<ExceptionHandling>Async</ExceptionHandling>\r
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
<SmallerTypeCheck>true</SmallerTypeCheck>\r
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>\r
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;TBB_USE_THREADING_TOOLS=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
<TreatWarningAsError>true</TreatWarningAsError>\r
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
</ClCompile>\r
<Link>\r
<AdditionalDependencies>sfml-audio-d.lib;sfml-window-d.lib;OpenGL32.lib;FreeImage.lib;GLee.lib;Winmm.lib;Ws2_32.lib;BlueVelvet3_d.lib;avformat-52.lib;avcodec-52.lib;avutil-50.lib;swscale-0.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
<TargetMachine>MachineX86</TargetMachine>\r
</Link>\r
<PostBuildEvent>\r
- <Command>copy "$(TargetPath)" "$(SolutionDir)build\"\r
-copy "$(ProjectDir)caspar.config" "$(SolutionDir)build\"</Command>\r
+ <Command>\r
+ </Command>\r
</PostBuildEvent>\r
</ItemDefinitionGroup>\r
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
<TargetMachine>MachineX86</TargetMachine>\r
</Link>\r
<PostBuildEvent>\r
- <Command>copy "$(TargetPath)" "$(SolutionDir)build\"\r
-copy "$(ProjectDir)caspar.config" "$(SolutionDir)build\"</Command>\r
+ <Command>\r
+ </Command>\r
</PostBuildEvent>\r
</ItemDefinitionGroup>\r
<ItemGroup>\r
<ClInclude Include="config.h" />\r
<ClInclude Include="consumer\bluefish\BluefishException.h" />\r
- <ClInclude Include="consumer\bluefish\BluefishFrameManager.h" />\r
<ClInclude Include="consumer\bluefish\BluefishPlaybackStrategy.h" />\r
<ClInclude Include="consumer\bluefish\BlueFishVideoConsumer.h" />\r
<ClInclude Include="consumer\decklink\DeckLinkAPI_h.h" />\r
<ClInclude Include="consumer\frame_consumer.h" />\r
<ClInclude Include="consumer\oal\oal_frame_consumer.h" />\r
<ClInclude Include="consumer\ogl\ogl_frame_consumer.h" />\r
- <ClInclude Include="frame\frame.h" />\r
+ <ClInclude Include="frame\composite_gpu_frame.h" />\r
+ <ClInclude Include="frame\frame_factory.h" />\r
<ClInclude Include="frame\frame_format.h" />\r
- <ClInclude Include="frame\audio_chunk.h" />\r
<ClInclude Include="frame\frame_fwd.h" />\r
+ <ClInclude Include="frame\gpu_frame.h" />\r
+ <ClInclude Include="frame\gpu_frame_processor.h" />\r
<ClInclude Include="producer\color\color_producer.h" />\r
<ClInclude Include="producer\ffmpeg\audio\audio_decoder.h" />\r
<ClInclude Include="producer\ffmpeg\ffmpeg_producer.h" />\r
<ClInclude Include="producer\ffmpeg\packet.h" />\r
<ClInclude Include="producer\ffmpeg\video\video_decoder.h" />\r
<ClInclude Include="producer\ffmpeg\video\video_deinterlacer.h" />\r
- <ClInclude Include="producer\ffmpeg\video\video_scaler.h" />\r
+ <ClInclude Include="producer\ffmpeg\video\video_transformer.h" />\r
<ClInclude Include="producer\flash\axflash.h" />\r
+ <ClInclude Include="producer\flash\bitmap.h" />\r
<ClInclude Include="producer\flash\cg_producer.h" />\r
<ClInclude Include="producer\flash\ct_producer.h" />\r
<ClInclude Include="producer\flash\FlashAxContainer.h" />\r
<ClInclude Include="producer\flash\flash_producer.h" />\r
<ClInclude Include="producer\flash\TimerHelper.h" />\r
+ <ClInclude Include="producer\frame_producer.h" />\r
<ClInclude Include="producer\image\image_loader.h" />\r
<ClInclude Include="producer\image\image_producer.h" />\r
<ClInclude Include="producer\image\image_scroll_producer.h" />\r
<ClInclude Include="protocol\clk\CLKCommand.h" />\r
<ClInclude Include="protocol\clk\CLKProtocolStrategy.h" />\r
<ClInclude Include="protocol\media.h" />\r
- <ClInclude Include="protocol\monitor\Monitor.h" />\r
<ClInclude Include="renderer\renderer_fwd.h" />\r
<ClInclude Include="renderer\render_device.h" />\r
<ClInclude Include="renderer\layer.h" />\r
<CustomBuildStep Include="consumers\bluefish\BluefishFrameManager.h" />\r
<CustomBuildStep Include="consumers\bluefish\BluefishPlaybackStrategy.h" />\r
<CustomBuildStep Include="consumers\bluefish\BlueFishVideoConsumer.h" />\r
- <ClInclude Include="frame\bitmap_frame.h" />\r
- <ClInclude Include="frame\system_frame.h" />\r
<CustomBuildStep Include="PlaybackControl.h" />\r
<ClInclude Include="StdAfx.h" />\r
</ItemGroup>\r
<ItemGroup>\r
- <ClCompile Include="consumer\bluefish\BluefishFrameManager.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
<ClCompile Include="consumer\bluefish\BluefishPlaybackStrategy.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="consumer\bluefish\BlueFishVideoConsumer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
+ <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
</ClCompile>\r
<ClCompile Include="consumer\decklink\DeckLinkAPI_i.c">\r
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="frame\audio_chunk.cpp">\r
+ <ClCompile Include="frame\composite_gpu_frame.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\stdafx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\stdafx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
+ <ClCompile Include="frame\gpu_frame.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../stdafx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../stdafx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
+ <ClCompile Include="frame\gpu_frame_processor.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../stdafx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../stdafx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
<ClCompile Include="producer\color\color_producer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="producer\ffmpeg\video\video_scaler.cpp">\r
+ <ClCompile Include="producer\ffmpeg\video\video_transformer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
+ <ClCompile Include="producer\flash\bitmap.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
<ClCompile Include="producer\flash\cg_producer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="protocol\monitor\Monitor.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
<ClCompile Include="renderer\render_device.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<ExpandAttributedSource Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExpandAttributedSource>\r
<PreprocessToFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</PreprocessToFile>\r
</ClCompile>\r
- <ClCompile Include="frame\bitmap_frame.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
- <ClCompile Include="frame\system_frame.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
<ClCompile Include="main.cpp" />\r
<ClCompile Include="StdAfx.cpp">\r
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>\r
<Filter Include="Source\protocol\amcp">\r
<UniqueIdentifier>{d33e8ddc-ccb4-4f4f-ad20-e788a796bb7b}</UniqueIdentifier>\r
</Filter>\r
- <Filter Include="Source\protocol\monitor">\r
- <UniqueIdentifier>{300c491b-4f95-4b15-8d77-eff22fb4cd60}</UniqueIdentifier>\r
- </Filter>\r
<Filter Include="Source\protocol\clk">\r
<UniqueIdentifier>{8355a891-c4db-4a0e-8ecc-795314127cdc}</UniqueIdentifier>\r
</Filter>\r
<Filter Include="Source\protocol\osc">\r
<UniqueIdentifier>{23166bfa-06eb-4da9-8a0d-1ae5eac4348b}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="Source\frame\gpu">\r
+ <UniqueIdentifier>{91076088-a8dc-43e2-b401-ca2b8462fd06}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="StdAfx.h">\r
<ClInclude Include="protocol\clk\CLKProtocolStrategy.h">\r
<Filter>Source\protocol\clk</Filter>\r
</ClInclude>\r
- <ClInclude Include="protocol\monitor\Monitor.h">\r
- <Filter>Source\protocol\monitor</Filter>\r
- </ClInclude>\r
<ClInclude Include="renderer\render_device.h">\r
<Filter>Source\renderer</Filter>\r
</ClInclude>\r
<ClInclude Include="frame\frame_format.h">\r
<Filter>Source\frame</Filter>\r
</ClInclude>\r
- <ClInclude Include="frame\bitmap_frame.h">\r
- <Filter>Source\frame</Filter>\r
- </ClInclude>\r
- <ClInclude Include="frame\system_frame.h">\r
- <Filter>Source\frame</Filter>\r
- </ClInclude>\r
- <ClInclude Include="frame\audio_chunk.h">\r
- <Filter>Source\frame</Filter>\r
- </ClInclude>\r
- <ClInclude Include="frame\frame.h">\r
- <Filter>Source\frame</Filter>\r
- </ClInclude>\r
<ClInclude Include="config.h">\r
<Filter>Source</Filter>\r
</ClInclude>\r
<ClInclude Include="consumer\bluefish\BluefishException.h">\r
<Filter>Source\consumer\bluefish</Filter>\r
</ClInclude>\r
- <ClInclude Include="consumer\bluefish\BluefishFrameManager.h">\r
- <Filter>Source\consumer\bluefish</Filter>\r
- </ClInclude>\r
<ClInclude Include="consumer\decklink\DecklinkVideoConsumer.h">\r
<Filter>Source\consumer\decklink</Filter>\r
</ClInclude>\r
<ClInclude Include="producer\ffmpeg\video\video_deinterlacer.h">\r
<Filter>Source\producer\ffmpeg\video</Filter>\r
</ClInclude>\r
- <ClInclude Include="producer\ffmpeg\video\video_scaler.h">\r
- <Filter>Source\producer\ffmpeg\video</Filter>\r
- </ClInclude>\r
<ClInclude Include="producer\flash\ct_producer.h">\r
<Filter>Source\producer\flash</Filter>\r
</ClInclude>\r
<ClInclude Include="protocol\media.h">\r
<Filter>Source\protocol</Filter>\r
</ClInclude>\r
+ <ClInclude Include="frame\gpu_frame.h">\r
+ <Filter>Source\frame\gpu</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="frame\gpu_frame_processor.h">\r
+ <Filter>Source\frame\gpu</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="frame\frame_factory.h">\r
+ <Filter>Source\frame</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="producer\frame_producer.h">\r
+ <Filter>Source\producer</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="producer\ffmpeg\video\video_transformer.h">\r
+ <Filter>Source\producer\ffmpeg\video</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="producer\flash\bitmap.h">\r
+ <Filter>Source\producer\flash</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="frame\composite_gpu_frame.h">\r
+ <Filter>Source\frame\gpu</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="StdAfx.cpp">\r
<ClCompile Include="protocol\clk\CLKCommand.cpp">\r
<Filter>Source\protocol\clk</Filter>\r
</ClCompile>\r
- <ClCompile Include="protocol\monitor\Monitor.cpp">\r
- <Filter>Source\protocol\monitor</Filter>\r
- </ClCompile>\r
<ClCompile Include="renderer\render_device.cpp">\r
<Filter>Source\renderer</Filter>\r
</ClCompile>\r
<ClCompile Include="renderer\layer.cpp">\r
<Filter>Source\renderer</Filter>\r
</ClCompile>\r
- <ClCompile Include="frame\system_frame.cpp">\r
- <Filter>Source\frame</Filter>\r
- </ClCompile>\r
<ClCompile Include="frame\frame_format.cpp">\r
<Filter>Source\frame</Filter>\r
</ClCompile>\r
- <ClCompile Include="frame\bitmap_frame.cpp">\r
- <Filter>Source\frame</Filter>\r
- </ClCompile>\r
- <ClCompile Include="frame\audio_chunk.cpp">\r
- <Filter>Source\frame</Filter>\r
- </ClCompile>\r
<ClCompile Include="main.cpp">\r
<Filter>Source</Filter>\r
</ClCompile>\r
<ClCompile Include="consumer\bluefish\BlueFishVideoConsumer.cpp">\r
<Filter>Source\consumer\bluefish</Filter>\r
</ClCompile>\r
- <ClCompile Include="consumer\bluefish\BluefishFrameManager.cpp">\r
- <Filter>Source\consumer\bluefish</Filter>\r
- </ClCompile>\r
<ClCompile Include="consumer\decklink\DecklinkVideoConsumer.cpp">\r
<Filter>Source\consumer\decklink</Filter>\r
</ClCompile>\r
<ClCompile Include="producer\ffmpeg\video\video_deinterlacer.cpp">\r
<Filter>Source\producer\ffmpeg\video</Filter>\r
</ClCompile>\r
- <ClCompile Include="producer\ffmpeg\video\video_scaler.cpp">\r
- <Filter>Source\producer\ffmpeg\video</Filter>\r
- </ClCompile>\r
<ClCompile Include="producer\ffmpeg\video\video_decoder.cpp">\r
<Filter>Source\producer\ffmpeg\video</Filter>\r
</ClCompile>\r
<ClCompile Include="protocol\media.cpp">\r
<Filter>Source\protocol</Filter>\r
</ClCompile>\r
+ <ClCompile Include="frame\gpu_frame_processor.cpp">\r
+ <Filter>Source\frame\gpu</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="frame\gpu_frame.cpp">\r
+ <Filter>Source\frame\gpu</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="producer\ffmpeg\video\video_transformer.cpp">\r
+ <Filter>Source\producer\ffmpeg\video</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="producer\flash\bitmap.cpp">\r
+ <Filter>Source\producer\flash</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="frame\composite_gpu_frame.cpp">\r
+ <Filter>Source\frame\gpu</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<Midl Include="consumer\decklink\DeckLinkAPI_v7_3.idl">\r
+++ /dev/null
-#include "../StdAfx.h"\r
-\r
-#include "audio_chunk.h"\r
-\r
-#include <tbb/scalable_allocator.h>\r
-\r
-namespace caspar{\r
-\r
-audio_chunk::audio_chunk(size_t dataSize, const sound_channel_info_ptr& snd_channel_info) \r
- : size_(dataSize), snd_channel_info_(snd_channel_info), data_(static_cast<unsigned char*>(scalable_aligned_malloc(dataSize, 16))), volume_(100.0f)\r
-{}\r
-\r
-audio_chunk::~audio_chunk() \r
-{\r
- scalable_aligned_free(data_);\r
-}\r
-\r
-const unsigned char* audio_chunk::data() const\r
-{\r
- return data_;\r
-}\r
-\r
-unsigned char* audio_chunk::data()\r
-{\r
- return data_;\r
-}\r
-\r
-size_t audio_chunk::size() const\r
-{\r
- return size_;\r
-}\r
-\r
-float audio_chunk::volume() const\r
-{\r
- return volume_;\r
-}\r
-\r
-void audio_chunk::set_volume(float volume)\r
-{\r
- assert(volume_ > 0.0f);\r
- assert(volume_ < (100.0f + std::numeric_limits<float>::epsilon()));\r
- volume_ = volume;\r
-}\r
- \r
-const sound_channel_info_ptr& audio_chunk::sound_channel_info() const\r
-{\r
- return snd_channel_info_;\r
-}\r
-\r
-}
\ No newline at end of file
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
-#pragma once\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-#include <memory>\r
-\r
-namespace caspar{\r
- \r
-struct sound_channel_info : boost::noncopyable\r
-{\r
-public:\r
- sound_channel_info(size_t channels_count, size_t bits_per_sample, size_t sample_rate)\r
- : channels_count(channels_count), bits_per_sample(bits_per_sample), sample_rate(sample_rate){}\r
- const size_t channels_count;\r
- const size_t bits_per_sample;\r
- const size_t sample_rate;\r
-};\r
-typedef std::shared_ptr<sound_channel_info> sound_channel_info_ptr;\r
-typedef std::unique_ptr<sound_channel_info> sound_channel_info_uptr;\r
-\r
-class audio_chunk : boost::noncopyable\r
-{\r
-public:\r
- audio_chunk(size_t dataSize, const sound_channel_info_ptr& snd_channel_info);\r
- ~audio_chunk();\r
-\r
- const unsigned char* data() const;\r
- unsigned char* data();\r
- size_t size() const;\r
- float volume() const;\r
- void set_volume(float volume);\r
- const sound_channel_info_ptr& sound_channel_info() const;\r
-\r
-private:\r
- float volume_;\r
- const sound_channel_info_ptr snd_channel_info_;\r
- unsigned char* const data_;\r
- const int size_;\r
-};\r
-typedef std::shared_ptr<audio_chunk> audio_chunk_ptr;\r
-typedef std::unique_ptr<audio_chunk> audio_chunk_uptr;\r
-\r
-}
\ No newline at end of file
--- /dev/null
+#include "../StdAfx.h"\r
+\r
+#include "composite_gpu_frame.h"\r
+#include "../../common/image/copy.h"\r
+#include "../../common/gl/utility.h"\r
+\r
+#include <algorithm>\r
+#include <numeric>\r
+\r
+namespace caspar {\r
+ \r
+struct composite_gpu_frame::implementation\r
+{\r
+ implementation(composite_gpu_frame* self) : self_(self){}\r
+\r
+ void write_lock()\r
+ {\r
+ std::for_each(frames_.begin(), frames_.end(), std::mem_fn(&gpu_frame::write_lock)); \r
+ }\r
+\r
+ bool write_unlock()\r
+ {\r
+ return std::all_of(frames_.begin(), frames_.end(), std::mem_fn(&gpu_frame::write_unlock)); \r
+ }\r
+ \r
+ void read_lock(GLenum mode)\r
+ { \r
+ std::for_each(frames_.begin(), frames_.end(), std::bind(&gpu_frame::read_lock, std::placeholders::_1, mode)); \r
+ }\r
+\r
+ bool read_unlock()\r
+ {\r
+ return std::all_of(frames_.begin(), frames_.end(), std::mem_fn(&gpu_frame::read_unlock)); \r
+ }\r
+\r
+ void draw()\r
+ {\r
+ glPushMatrix();\r
+ glTranslatef(self_->x()*2.0f, self_->y()*2.0f, 0.0f);\r
+ std::for_each(frames_.begin(), frames_.end(), std::mem_fn(&gpu_frame::draw));\r
+ glPopMatrix();\r
+ }\r
+ \r
+ void add(const gpu_frame_ptr& frame)\r
+ {\r
+ frames_.push_back(frame);\r
+ mix_audio_safe(audio_data_, frame->audio_data());\r
+ }\r
+\r
+ unsigned char* data()\r
+ {\r
+ BOOST_THROW_EXCEPTION(invalid_operation());\r
+ }\r
+\r
+ composite_gpu_frame* self_;\r
+ std::vector<gpu_frame_ptr> frames_;\r
+ size_t size_;\r
+ std::vector<short> audio_data_;\r
+};\r
+\r
+#pragma warning (disable : 4355)\r
+\r
+composite_gpu_frame::composite_gpu_frame(size_t width, size_t height) : gpu_frame(width, height), impl_(new implementation(this)){}\r
+void composite_gpu_frame::write_lock(){impl_->write_lock();}\r
+bool composite_gpu_frame::write_unlock(){return impl_->write_unlock();} \r
+void composite_gpu_frame::read_lock(GLenum mode){impl_->read_lock(mode);}\r
+bool composite_gpu_frame::read_unlock(){return impl_->read_unlock();}\r
+void composite_gpu_frame::draw(){impl_->draw();}\r
+unsigned char* composite_gpu_frame::data(){return impl_->data();}\r
+const std::vector<short>& composite_gpu_frame::audio_data() const { return impl_->audio_data_; } \r
+std::vector<short>& composite_gpu_frame::audio_data() { return impl_->audio_data_; }\r
+void composite_gpu_frame::reset(){impl_->audio_data_.clear();}\r
+void composite_gpu_frame::add(const gpu_frame_ptr& frame){impl_->add(frame);}\r
+\r
+}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include <memory>\r
+\r
+#include <Glee.h>\r
+\r
+#include "gpu_frame.h"\r
+\r
+namespace caspar {\r
+ \r
+class composite_gpu_frame : public gpu_frame\r
+{\r
+public:\r
+ composite_gpu_frame(size_t width, size_t height);\r
+\r
+ void write_lock();\r
+ bool write_unlock();\r
+ void read_lock(GLenum mode);\r
+ bool read_unlock();\r
+ void draw();\r
+ void reset();\r
+ \r
+ unsigned char* data();\r
+ \r
+ const std::vector<short>& audio_data() const; \r
+ std::vector<short>& audio_data();\r
+\r
+ void add(const gpu_frame_ptr& frame);\r
+ \r
+private:\r
+ struct implementation;\r
+ std::shared_ptr<implementation> impl_;\r
+};\r
+typedef std::shared_ptr<composite_gpu_frame> composite_gpu_frame_ptr;\r
+ \r
+}
\ No newline at end of file
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
-#pragma once\r
-\r
-#include <memory>\r
-#include <vector>\r
-\r
-#include "audio_chunk.h"\r
-#include "frame_format.h"\r
-\r
-#include "../../common/image/image.h"\r
-\r
-#include <tbb/parallel_invoke.h>\r
-\r
-#include <boost/range/algorithm.hpp>\r
-\r
-namespace caspar {\r
-\r
-// NOTE: audio data is ALWAYS shallow copy\r
-class frame : boost::noncopyable\r
-{\r
-public:\r
- virtual ~frame(){}\r
- \r
- virtual const unsigned char* data() const { return const_cast<frame&>(*this).data(); }\r
- virtual unsigned char* data() = 0;\r
- virtual size_t size() const = 0;\r
- virtual void* tag() const { return nullptr; }\r
- virtual const std::vector<audio_chunk_ptr>& audio_data() const { return audioData_; } \r
- virtual std::vector<audio_chunk_ptr>& audio_data() { return audioData_; } \r
-\r
- static std::shared_ptr<frame> null()\r
- {\r
- class null_frame : public frame\r
- {\r
- unsigned char* data() { return nullptr; };\r
- size_t size() const { return 0; };\r
- };\r
- static auto my_null_frame = std::make_shared<null_frame>();\r
- return my_null_frame;\r
- }\r
-private: \r
- std::vector<audio_chunk_ptr> audioData_;\r
-};\r
-typedef std::shared_ptr<frame> frame_ptr;\r
-typedef std::shared_ptr<const frame> frame_const_ptr;\r
-typedef std::unique_ptr<frame> frame_uptr;\r
-typedef std::unique_ptr<const frame> frame_const_uptr;\r
-\r
-inline bool operator==(const frame& lhs, const frame& rhs)\r
-{\r
- return lhs.data() == rhs.data() && (lhs.data() == nullptr || lhs.size() == rhs.size());\r
-}\r
-\r
-template<typename frame_ptr_type>\r
-frame_ptr_type& set_frame_volume(frame_ptr_type& result_frame, float volume)\r
-{\r
- assert(result_frame != nullptr);\r
- assert(boost::range::find(result_frame->audio_data(), nullptr) == result_frame->audio_data().end());\r
- boost::range::for_each(result_frame->audio_data(), std::bind(&audio_chunk::set_volume, std::placeholders::_1, volume));\r
- return result_frame;\r
-}\r
-\r
-template<typename frame_ptr_type>\r
-frame_ptr_type& clear_frame(frame_ptr_type& result_frame)\r
-{\r
- assert(result_frame != nullptr);\r
- common::image::clear(result_frame->data(), result_frame->size());\r
- result_frame->audio_data().clear();\r
- return result_frame;\r
-}\r
-\r
-template<typename frame_ptr_type>\r
-frame_ptr_type& pre_over_frame(frame_ptr_type& result_frame, const frame_const_ptr& frame1, const frame_const_ptr& frame2)\r
-{\r
- assert(result_frame != nullptr && frame1 != nullptr && frame2 != nullptr);\r
- assert(result_frame->size() == frame1->size());\r
- assert(result_frame->size() == frame2->size());\r
- assert(boost::range::find(frame1->audio_data(), nullptr) == frame1->audio_data().end());\r
- assert(boost::range::find(frame2->audio_data(), nullptr) == frame2->audio_data().end());\r
- tbb::parallel_invoke(\r
- [&]{common::image::pre_over(result_frame->data(), frame1->data(), frame2->data(), result_frame->size());},\r
- [&]\r
- {\r
- if(result_frame != frame1)\r
- boost::range::copy(frame1->audio_data(), std::back_inserter(result_frame->audio_data()));\r
- if(result_frame != frame2)\r
- boost::range::copy(frame2->audio_data(), std::back_inserter(result_frame->audio_data()));\r
- });\r
- return result_frame;\r
-}\r
-\r
-template<typename frame_ptr_type>\r
-frame_ptr_type& copy_frame(frame_ptr_type& result_frame, const frame_const_ptr& frame)\r
-{ \r
- assert(result_frame != nullptr && frame != nullptr);\r
- assert(result_frame->size() == frame->size());\r
- if(result_frame == frame)\r
- return result_frame;\r
- tbb::parallel_invoke(\r
- [&]{common::image::copy(result_frame->data(), frame->data(), result_frame->size());},\r
- [&]{boost::range::copy(frame->audio_data(), std::back_inserter(result_frame->audio_data()));});\r
- return result_frame;\r
-} \r
-\r
-template<typename frame_ptr_type>\r
-frame_ptr_type& copy_frame(frame_ptr_type& result_frame, const frame_const_ptr& frame, const frame_format_desc& format_desc)\r
-{ \r
- assert(result_frame != nullptr && frame != nullptr);\r
- assert(result_frame->size() == format_desc.size);\r
- assert(frame->size() == format_desc.size);\r
- if(result_frame == frame)\r
- return result_frame;\r
- tbb::parallel_invoke(\r
- [&]\r
- {\r
- if(format_desc.mode == video_mode::progressive)\r
- common::image::copy(result_frame->data(), frame->data(), result_frame->size());\r
- else\r
- common::image::copy_field(result_frame->data(), frame->data(), format_desc.mode == video_mode::upper ? 1 : 0, format_desc.width, format_desc.height);\r
- },\r
- [&]{boost::range::copy(frame->audio_data(), std::back_inserter(result_frame->audio_data()));});\r
- return result_frame;\r
-} \r
-\r
-template<typename frame_ptr_type, typename frame_container>\r
-frame_ptr_type& compose_frames(frame_ptr_type& result_frame, const frame_container& frames)\r
-{\r
- assert(boost::range::find(frames, nullptr) == frames.end());\r
- assert(boost::range::find_if(frames, [&](const frame_ptr& frame) { return frame->size() != result_frame->size();}) == frames.end());\r
- if(frames.empty()) \r
- clear_frame(result_frame); \r
- else if(frames.size() == 1) \r
- copy_frame(result_frame, frames[0]); \r
- else if(frames.size() == 2) \r
- pre_over_frame(result_frame, frames[0], frames[1]); \r
- else\r
- {\r
- for(size_t n = 0; n < frames.size() - 2; ++n)\r
- pre_over_frame(frames[0], frames[n], frames[n+1]);\r
- pre_over_frame(result_frame, frames[0], frames[frames.size()-1]);\r
- }\r
- return result_frame;\r
-}\r
-\r
-}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include "gpu_frame.h"\r
+#include "frame_format.h"\r
+\r
+#include <memory>\r
+\r
+namespace caspar { \r
+\r
+struct frame_factory\r
+{\r
+ virtual gpu_frame_ptr create_frame(size_t width, size_t height) = 0;\r
+ gpu_frame_ptr create_frame(const frame_format_desc format_desc)\r
+ {\r
+ return create_frame(format_desc.width, format_desc.height);\r
+ }\r
+};\r
+\r
+typedef std::shared_ptr<frame_factory> frame_factory_ptr;\r
+\r
+}
\ No newline at end of file
\r
namespace caspar{\r
\r
-class frame;\r
-typedef std::shared_ptr<frame> frame_ptr;\r
-typedef std::shared_ptr<const frame> frame_const_ptr;\r
-typedef std::unique_ptr<frame> frame_uptr;\r
-typedef std::unique_ptr<const frame> frame_const_uptr;\r
+class gpu_frame;\r
+typedef std::shared_ptr<gpu_frame> gpu_frame_ptr;\r
+\r
+struct frame_factory;\r
+typedef std::shared_ptr<frame_factory> frame_factory_ptr;\r
\r
struct frame_format_desc;\r
\r
--- /dev/null
+#include "../StdAfx.h"\r
+\r
+#include "gpu_frame.h"\r
+#include "../../common/image/copy.h"\r
+#include "../../common/gl/utility.h"\r
+\r
+namespace caspar {\r
+ \r
+struct gpu_frame::implementation\r
+{\r
+ implementation(size_t width, size_t height) \r
+ : pbo_(0), data_(nullptr), width_(width), height_(height), size_(width*height*4), reading_(false), texture_(0), alpha_(1.0f)\r
+ { \r
+ }\r
+\r
+ ~implementation()\r
+ {\r
+ if(pbo_ != 0)\r
+ glDeleteBuffers(1, &pbo_);\r
+ if(texture_ != 0)\r
+ glDeleteTextures(1, &texture_);\r
+ }\r
+\r
+ GLuint pbo()\r
+ { \r
+ if(pbo_ == 0)\r
+ CASPAR_GL_CHECK(glGenBuffers(1, &pbo_));\r
+ return pbo_;\r
+ }\r
+\r
+ void write_lock()\r
+ {\r
+ if(texture_ == 0)\r
+ {\r
+ CASPAR_GL_CHECK(glGenTextures(1, &texture_));\r
+\r
+ CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_));\r
+\r
+ CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
+ CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\r
+ CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));\r
+ CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));\r
+\r
+ CASPAR_GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width_, height_, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
+ }\r
+\r
+ CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo()));\r
+ if(data_ != nullptr)\r
+ {\r
+ CASPAR_GL_CHECK(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));\r
+ data_ = nullptr;\r
+ }\r
+ CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_));\r
+ CASPAR_GL_CHECK(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
+ CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
+ }\r
+\r
+ bool write_unlock()\r
+ {\r
+ if(data_ != nullptr)\r
+ return false;\r
+ CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo()));\r
+ CASPAR_GL_CHECK(glBufferData(GL_PIXEL_UNPACK_BUFFER, size_, NULL, GL_STREAM_DRAW));\r
+ void* ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);\r
+ CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));\r
+ data_ = reinterpret_cast<unsigned char*>(ptr);\r
+ if(!data_)\r
+ BOOST_THROW_EXCEPTION(std::bad_alloc());\r
+ return true;\r
+ }\r
+ \r
+ void read_lock(GLenum mode)\r
+ { \r
+ CASPAR_GL_CHECK(glReadBuffer(mode));\r
+ CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo()));\r
+ if(data_ != nullptr) \r
+ { \r
+ CASPAR_GL_CHECK(glUnmapBuffer(GL_PIXEL_PACK_BUFFER)); \r
+ data_ = nullptr;\r
+ }\r
+ CASPAR_GL_CHECK(glBufferData(GL_PIXEL_PACK_BUFFER, size_, NULL, GL_STREAM_READ)); \r
+ CASPAR_GL_CHECK(glReadPixels(0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
+ CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));\r
+ reading_ = true;\r
+ }\r
+\r
+ bool read_unlock()\r
+ {\r
+ if(data_ != nullptr || !reading_)\r
+ return false;\r
+ CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo()));\r
+ void* ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); \r
+ CASPAR_GL_CHECK(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));\r
+ data_ = reinterpret_cast<unsigned char*>(ptr);\r
+ if(!data_)\r
+ BOOST_THROW_EXCEPTION(std::bad_alloc());\r
+ reading_ = false;\r
+ return true;\r
+ }\r
+\r
+ void draw()\r
+ {\r
+ glPushMatrix();\r
+ glTranslatef(x_*2.0f, y_*2.0f, 0.0f);\r
+ glColor4f(1.0f, 1.0f, 1.0f, alpha_);\r
+ CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_));\r
+ glBegin(GL_QUADS);\r
+ glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);\r
+ glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f);\r
+ glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f, 1.0f);\r
+ glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f, 1.0f);\r
+ glEnd();\r
+ glPopMatrix();\r
+ }\r
+ \r
+ unsigned char* data()\r
+ {\r
+ if(data_ == nullptr)\r
+ BOOST_THROW_EXCEPTION(invalid_operation());\r
+ return data_;\r
+ }\r
+\r
+ void reset()\r
+ {\r
+ audio_data_.clear();\r
+ alpha_ = 1.0f;\r
+ x_ = 0.0f;\r
+ y_ = 0.0f;\r
+ }\r
+\r
+ gpu_frame* self_;\r
+ GLuint pbo_;\r
+ GLuint texture_;\r
+ unsigned char* data_;\r
+ size_t width_;\r
+ size_t height_;\r
+ size_t size_;\r
+ bool reading_;\r
+ std::vector<short> audio_data_;\r
+\r
+ float alpha_;\r
+ float x_;\r
+ float y_;\r
+};\r
+\r
+gpu_frame::gpu_frame(size_t width, size_t height) : impl_(new implementation(width, height)){}\r
+void gpu_frame::write_lock(){impl_->write_lock();}\r
+bool gpu_frame::write_unlock(){return impl_->write_unlock();} \r
+void gpu_frame::read_lock(GLenum mode){impl_->read_lock(mode);}\r
+bool gpu_frame::read_unlock(){return impl_->read_unlock();}\r
+void gpu_frame::draw(){impl_->draw();}\r
+unsigned char* gpu_frame::data(){return impl_->data();}\r
+size_t gpu_frame::size() const { return impl_->size_; }\r
+size_t gpu_frame::width() const { return impl_->width_;}\r
+size_t gpu_frame::height() const { return impl_->height_;}\r
+const std::vector<short>& gpu_frame::audio_data() const { return impl_->audio_data_; } \r
+std::vector<short>& gpu_frame::audio_data() { return impl_->audio_data_; }\r
+void gpu_frame::reset(){impl_->reset();}\r
+float gpu_frame::alpha() const{ return impl_->alpha_;}\r
+void gpu_frame::alpha(float value){ impl_->alpha_ = value;}\r
+float gpu_frame::x() const { return impl_->x_;}\r
+float gpu_frame::y() const { return impl_->y_;}\r
+void gpu_frame::translate(float x, float y) { impl_->x_ += x; impl_->y_ += y; }\r
+}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include <memory>\r
+\r
+#include <Glee.h>\r
+\r
+namespace caspar {\r
+ \r
+class gpu_frame\r
+{\r
+public:\r
+ gpu_frame(size_t width, size_t height);\r
+\r
+ virtual void write_lock();\r
+ virtual bool write_unlock();\r
+ virtual void read_lock(GLenum mode);\r
+ virtual bool read_unlock();\r
+ virtual void draw();\r
+ \r
+ virtual unsigned char* data();\r
+ virtual size_t size() const;\r
+ virtual size_t width() const;\r
+ virtual size_t height() const;\r
+ \r
+ virtual void reset();\r
+ \r
+ virtual const std::vector<short>& audio_data() const; \r
+ virtual std::vector<short>& audio_data();\r
+\r
+ virtual float alpha() const;\r
+ virtual void alpha(float value);\r
+\r
+ virtual float x() const;\r
+ virtual float y() const;\r
+ virtual void translate(float x, float y);\r
+\r
+ static std::shared_ptr<gpu_frame> null()\r
+ {\r
+ static auto my_null_frame = std::make_shared<gpu_frame>(0,0);\r
+ return my_null_frame;\r
+ }\r
+ \r
+private:\r
+ struct implementation;\r
+ std::shared_ptr<implementation> impl_;\r
+};\r
+typedef std::shared_ptr<gpu_frame> gpu_frame_ptr;\r
+ \r
+inline void mix_audio_safe(std::vector<short>& frame1, const std::vector<short>& frame2)\r
+{\r
+ if(frame1.empty())\r
+ frame1 = std::move(frame2);\r
+ else if(!frame2.empty())\r
+ {\r
+ for(size_t n = 0; n < frame1.size(); ++n)\r
+ frame1[n] = static_cast<short>(static_cast<int>(frame1[n]) + static_cast<int>(frame2[n]) & 0xFFFF); \r
+ }\r
+}\r
+\r
+template<typename frame_ptr_type>\r
+frame_ptr_type& mix_audio_safe(frame_ptr_type& frame1, const gpu_frame_ptr& frame2)\r
+{\r
+ mix_audio_safe(frame1->audio_data(), frame2->audio_data());\r
+ return frame1;\r
+}\r
+\r
+}
\ No newline at end of file
--- /dev/null
+#include "../StdAfx.h"\r
+\r
+#include "gpu_frame_processor.h"\r
+\r
+#include "gpu_frame.h"\r
+#include "frame_format.h"\r
+\r
+#include "../../common/exception/exceptions.h"\r
+#include "../../common/concurrency/executor.h"\r
+#include "../../common/image/image.h"\r
+#include "../../common/gl/utility.h"\r
+\r
+#include <Glee.h>\r
+#include <SFML/Window.hpp>\r
+\r
+#include <tbb/concurrent_queue.h>\r
+#include <tbb/concurrent_unordered_map.h>\r
+\r
+#include <boost/lexical_cast.hpp>\r
+#include <boost/thread/once.hpp>\r
+#include <boost/thread.hpp>\r
+#include <boost/range.hpp>\r
+#include <boost/foreach.hpp>\r
+#include <boost/range/algorithm_ext/erase.hpp>\r
+#include <boost/range/algorithm.hpp>\r
+\r
+#include <functional>\r
+#include <unordered_map>\r
+#include <numeric>\r
+\r
+namespace caspar {\r
+ \r
+class frame_buffer\r
+{\r
+public:\r
+ frame_buffer(size_t width, size_t height)\r
+ {\r
+ CASPAR_GL_CHECK(glGenTextures(1, &texture_)); \r
+\r
+ CASPAR_GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture_));\r
+\r
+ CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));\r
+ CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));\r
+ CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));\r
+ CASPAR_GL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));\r
+\r
+ CASPAR_GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL));\r
+\r
+ glGenFramebuffersEXT(1, &fbo_);\r
+ \r
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);\r
+ glBindTexture(GL_TEXTURE_2D, texture_);\r
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture_, 0);\r
+ }\r
+\r
+ ~frame_buffer()\r
+ {\r
+ glDeleteFramebuffersEXT(1, &fbo_);\r
+ }\r
+ \r
+ GLuint handle() { return fbo_; }\r
+ GLenum attachement() { return GL_COLOR_ATTACHMENT0_EXT; }\r
+ \r
+private:\r
+ GLuint texture_;\r
+ GLuint fbo_;\r
+};\r
+typedef std::shared_ptr<frame_buffer> frame_buffer_ptr;\r
+\r
+struct gpu_frame_processor::implementation\r
+{ \r
+ implementation(const frame_format_desc& format_desc) : format_desc_(format_desc)\r
+ { \r
+ executor_.start();\r
+ executor_.begin_invoke([=]\r
+ {\r
+ context_.reset(new sf::Context());\r
+ context_->SetActive(true);\r
+ glEnable(GL_TEXTURE_2D);\r
+ glEnable(GL_BLEND);\r
+ glDisable(GL_DEPTH_TEST);\r
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); \r
+ glClearColor(0.0, 0.0, 0.0, 0.0);\r
+ glViewport(0, 0, format_desc_.width, format_desc_.height);\r
+ glLoadIdentity();\r
+\r
+ input_.resize(2);\r
+ writing_.resize(2);\r
+ fbo_ = std::make_shared<frame_buffer>(format_desc_.width, format_desc_.height);\r
+ output_frame_ = std::make_shared<gpu_frame>(format_desc_.width, format_desc_.height);\r
+ index_ = 0;\r
+ });\r
+\r
+ empty_frame_ = create_frame(format_desc.width, format_desc.height);\r
+ common::image::clear(empty_frame_->data(), empty_frame_->size());\r
+ // Fill pipeline length\r
+ for(int n = 0; n < 3; ++n)\r
+ finished_frames_.push(empty_frame_);\r
+ }\r
+\r
+ ~implementation()\r
+ {\r
+ finished_frames_.push(nullptr);\r
+ executor_.stop();\r
+ }\r
+ \r
+ void pop(gpu_frame_ptr& frame)\r
+ {\r
+ finished_frames_.pop(frame);\r
+ } \r
+ \r
+ void composite(std::vector<gpu_frame_ptr> frames)\r
+ {\r
+ boost::range::remove_erase(frames, nullptr);\r
+ boost::range::remove_erase(frames, gpu_frame::null());\r
+\r
+ executor_.begin_invoke([=]\r
+ {\r
+ try\r
+ {\r
+ index_ = (index_ + 1) % 2;\r
+ int next_index = (index_ + 1) % 2;\r
+\r
+ // 2. Start asynchronous DMA transfer to video memory\r
+ // Lock frames and give pointer ownership to OpenGL \r
+ boost::range::for_each(input_[index_], std::mem_fn(&gpu_frame::write_lock));\r
+ writing_[index_] = input_[index_]; \r
+ input_[index_].clear();\r
+ \r
+ // 1. Copy to page-locked memory\r
+ input_[next_index] = frames;\r
+ \r
+ // 4. Output to external buffer\r
+ if(output_frame_->read_unlock())\r
+ finished_frames_.push(output_frame_);\r
+ output_frame_ = nullptr;\r
+ \r
+ // 3. Draw to framebuffer and start asynchronous DMA transfer to page-locked memory \r
+ // Clear framebuffer\r
+ glClear(GL_COLOR_BUFFER_BIT); \r
+\r
+ // Draw all frames to framebuffer\r
+ glLoadIdentity();\r
+ boost::range::for_each(writing_[next_index], std::mem_fn(&gpu_frame::draw));\r
+ \r
+ // Create an output frame\r
+ output_frame_ = create_output_frame();\r
+ \r
+ // Read from framebuffer into page-locked memory\r
+ output_frame_->read_lock(GL_COLOR_ATTACHMENT0_EXT);\r
+\r
+ // Unlock frames and give back pointer ownership\r
+ boost::range::for_each(writing_[next_index], std::mem_fn(&gpu_frame::write_unlock));\r
+ \r
+ // Mix audio from composite frames into output frame\r
+ std::accumulate(writing_[next_index].begin(), writing_[next_index].end(), output_frame_, mix_audio_safe<gpu_frame_ptr>); \r
+\r
+ // Return frames to pool\r
+ writing_[next_index].clear();\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ }\r
+ }); \r
+ }\r
+\r
+ gpu_frame_ptr create_output_frame()\r
+ { \r
+ gpu_frame_ptr frame;\r
+ if(!out_frame_pool_.try_pop(frame)) \r
+ frame = std::make_shared<gpu_frame>(format_desc_.width, format_desc_.height);\r
+\r
+ return gpu_frame_ptr(frame.get(), [=](gpu_frame*)\r
+ {\r
+ frame->reset();\r
+ out_frame_pool_.push(frame);\r
+ });\r
+ }\r
+ \r
+ gpu_frame_ptr create_frame(size_t width, size_t height)\r
+ {\r
+ size_t key = width | (height << 16);\r
+ auto& pool = input_frame_pools_[key];\r
+ \r
+ gpu_frame_ptr frame;\r
+ if(!pool.try_pop(frame))\r
+ {\r
+ frame = executor_.invoke([=]() -> gpu_frame_ptr\r
+ {\r
+ auto frame = std::make_shared<gpu_frame>(width, height);\r
+ frame->write_unlock();\r
+ return frame;\r
+ });\r
+ }\r
+ \r
+ auto destructor = [=]\r
+ {\r
+ frame->reset();\r
+ input_frame_pools_[key].push(frame);\r
+ };\r
+\r
+ return gpu_frame_ptr(frame.get(), [=](gpu_frame*)\r
+ {\r
+ executor_.begin_invoke(destructor);\r
+ });\r
+ }\r
+ \r
+ tbb::concurrent_unordered_map<size_t, tbb::concurrent_bounded_queue<gpu_frame_ptr>> input_frame_pools_;\r
+\r
+ tbb::concurrent_bounded_queue<gpu_frame_ptr> out_frame_pool_;\r
+ \r
+ frame_buffer_ptr fbo_;\r
+\r
+ int index_;\r
+ std::vector<std::vector<gpu_frame_ptr>> input_;\r
+ std::vector<std::vector<gpu_frame_ptr>> writing_;\r
+\r
+ gpu_frame_ptr output_frame_;\r
+ tbb::concurrent_bounded_queue<gpu_frame_ptr> finished_frames_;\r
+ \r
+ frame_format_desc format_desc_;\r
+ \r
+ std::unique_ptr<sf::Context> context_;\r
+ common::executor executor_;\r
+\r
+ gpu_frame_ptr empty_frame_;\r
+};\r
+ \r
+gpu_frame_processor::gpu_frame_processor(const frame_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
+void gpu_frame_processor::push(const std::vector<gpu_frame_ptr>& frames){ impl_->composite(frames);}\r
+void gpu_frame_processor::pop(gpu_frame_ptr& frame){ impl_->pop(frame);}\r
+gpu_frame_ptr gpu_frame_processor::create_frame(size_t width, size_t height){return impl_->create_frame(width, height);}\r
+\r
+}
\ No newline at end of file
*/\r
#pragma once\r
\r
-#include "frame.h"\r
-\r
#include <memory>\r
+#include <vector>\r
+\r
+#include "frame_fwd.h"\r
+#include "frame_factory.h"\r
\r
namespace caspar {\r
\r
-class system_frame : public frame\r
+class gpu_frame_processor : public frame_factory, boost::noncopyable\r
{\r
public:\r
- explicit system_frame(unsigned int dataSize);\r
- ~system_frame();\r
+ gpu_frame_processor(const frame_format_desc& format_desc);\r
+\r
+ void push(const std::vector<gpu_frame_ptr>& frames);\r
+ void pop(gpu_frame_ptr& frame);\r
\r
- unsigned char* data();\r
- unsigned int size() const;\r
+ gpu_frame_ptr create_frame(size_t width, size_t height);\r
private:\r
- unsigned char* const data_;\r
- const size_t size_;\r
+ struct implementation;\r
+ std::shared_ptr<implementation> impl_;\r
};\r
+typedef std::shared_ptr<gpu_frame_processor> gpu_frame_processor_ptr;\r
\r
}
\ No newline at end of file
+++ /dev/null
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG.\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
- \r
-#include "../stdafx.h"\r
-\r
-#include "system_frame.h"\r
-\r
-#include <tbb/scalable_allocator.h>\r
-\r
-namespace caspar {\r
-\r
-system_frame::system_frame(unsigned int dataSize) \r
- : size_(dataSize), data_(static_cast<unsigned char*>(scalable_aligned_malloc(dataSize, 16))){}\r
-system_frame::~system_frame(){scalable_aligned_free(data_);}\r
-unsigned char* system_frame::data() {return data_;} \r
-unsigned int system_frame::size() const{return size_;}\r
-\r
-}\r
-\r
std::getline(std::wcin, wcmd); // TODO: It's blocking...\r
is_running = wcmd != L"exit" && wcmd != L"q";\r
if(wcmd == L"1")\r
- wcmd = L"LOADBG 1-1 DV SLIDE 50 LOOP AUTOPLAY";\r
+ wcmd = L"LOADBG 1-1 DV SLIDE 100 LOOP AUTOPLAY";\r
else if(wcmd == L"2")\r
+ wcmd = L"LOADBG 1-1 DV PUSH 100 LOOP AUTOPLAY";\r
+ else if(wcmd == L"3")\r
+ wcmd = L"LOADBG 1-1 DV MIX 100 LOOP AUTOPLAY";\r
+ else if(wcmd == L"4")\r
+ wcmd = L"LOADBG 1-1 DV WIPE 100 LOOP AUTOPLAY";\r
+ else if(wcmd == L"5")\r
+ wcmd = L"LOADBG 1-1 DV CUT 100 LOOP AUTOPLAY";\r
+ else if(wcmd == L"6")\r
wcmd = L"CG 1-2 ADD 1 BBTELEFONARE 1";\r
\r
wcmd += L"\r\n";\r
\r
#include "color_producer.h"\r
\r
-#include "../../frame/system_frame.h"\r
#include "../../frame/frame_format.h"\r
\r
#include <intrin.h>\r
class color_producer : public frame_producer\r
{\r
public:\r
- explicit color_producer(unsigned long color_value, const frame_format_desc& format_desc) : format_desc_(format_desc)\r
+ explicit color_producer(unsigned long color_value, const frame_format_desc& format_desc) : format_desc_(format_desc){}\r
+\r
+ gpu_frame_ptr get_frame() { return frame_; }\r
+ const frame_format_desc& get_frame_format_desc() const { return format_desc_; }\r
+ \r
+ void initialize(const frame_factory_ptr& factory)\r
{\r
- frame_ = std::make_shared<system_frame>(format_desc.size);\r
+ frame_ = factory->create_frame(format_desc_);\r
__stosd(reinterpret_cast<unsigned long*>(frame_->data()), color_value_, frame_->size() / sizeof(unsigned long));\r
}\r
\r
- frame_ptr get_frame() { return frame_; }\r
- const frame_format_desc& get_frame_format_desc() const { return format_desc_; }\r
-\r
frame_format_desc format_desc_;\r
- frame_ptr frame_;\r
+ gpu_frame_ptr frame_;\r
unsigned long color_value_;\r
};\r
\r
\r
struct audio_decoder::implementation : boost::noncopyable\r
{\r
- implementation(const sound_channel_info_ptr& snd_channel_info) : discard_bytes_(0), current_audio_chunk_offset_(0), snd_channel_info_(snd_channel_info)\r
+ implementation() : discard_bytes_(0), current_audio_chunk_offset_(0), current_chunk_(1920*2), current_chunk_data_(reinterpret_cast<char*>(current_chunk_.data()))\r
{\r
audio_decomp_buffer_.resize(audio_decoder::AUDIO_DECOMP_BUFFER_SIZE);\r
int alignment_offset_ = static_cast<unsigned char>(audio_decoder::ALIGNMENT - (reinterpret_cast<size_t>(&audio_decomp_buffer_.front()) % audio_decoder::ALIGNMENT));\r
\r
while(written_bytes > 0)\r
{\r
- //if we're starting on a new chunk, allocate it\r
- if(current_chunk_ == nullptr) \r
- {\r
- current_chunk_ = std::make_shared<audio_chunk>(audio_packet->audio_frame_size, snd_channel_info_);\r
- current_audio_chunk_offset_ = 0;\r
- }\r
-\r
//either fill what's left of the chunk or copy all written_bytes that are left\r
int targetLength = std::min((max_chunk_length - current_audio_chunk_offset_), written_bytes);\r
- common::image::copy(current_chunk_->data() + current_audio_chunk_offset_, pDecomp, targetLength);\r
+ common::image::copy(current_chunk_data_ + current_audio_chunk_offset_, pDecomp, targetLength);\r
written_bytes -= targetLength;\r
\r
current_audio_chunk_offset_ += targetLength;\r
if(current_audio_chunk_offset_ >= max_chunk_length) \r
{\r
if(max_chunk_length < static_cast<int>(audio_packet->audio_frame_size)) \r
- common::image::clear(current_chunk_->data() + max_chunk_length, audio_packet->audio_frame_size-max_chunk_length); \r
+ common::image::clear(current_chunk_data_ + max_chunk_length, audio_packet->audio_frame_size-max_chunk_length); \r
else if(audio_packet->audio_frame_size < audio_packet->src_audio_frame_size) \r
discard_bytes_ = audio_packet->src_audio_frame_size-audio_packet->audio_frame_size;\r
-\r
+ \r
+ current_audio_chunk_offset_ = 0;\r
audio_packet->audio_chunks.push_back(current_chunk_);\r
- current_chunk_.reset();\r
}\r
}\r
\r
\r
std::vector<unsigned char> audio_decomp_buffer_;\r
unsigned char* aligned_audio_decomp_addr_;\r
-\r
- audio_chunk_ptr current_chunk_;\r
+ \r
+ std::vector<short> current_chunk_;\r
+ char* current_chunk_data_;\r
int current_audio_chunk_offset_;\r
- sound_channel_info_ptr snd_channel_info_;\r
};\r
\r
-audio_decoder::audio_decoder(const sound_channel_info_ptr& snd_channel_info) : impl_(new implementation(snd_channel_info)){}\r
+audio_decoder::audio_decoder() : impl_(new implementation()){}\r
audio_packet_ptr audio_decoder::execute(const audio_packet_ptr& audio_packet){return impl_->execute(audio_packet);}\r
}}
\ No newline at end of file
#pragma once\r
\r
#include "../packet.h"\r
-#include "../../../frame/audio_chunk.h"\r
\r
namespace caspar{ namespace ffmpeg {\r
\r
class audio_decoder : boost::noncopyable\r
{\r
public:\r
- audio_decoder(const sound_channel_info_ptr& snd_channel_info);\r
+ audio_decoder();\r
audio_packet_ptr execute(const audio_packet_ptr& audio_packet);\r
\r
/// <summary> The alignment </summary>\r
#include "audio/audio_decoder.h"\r
#include "video/video_decoder.h"\r
#include "video/video_deinterlacer.h"\r
-#include "video/video_scaler.h"\r
+#include "video/video_transformer.h"\r
\r
#include "../../frame/frame_format.h"\r
#include "../../../common/utility/find_file.h"\r
\r
static boost::once_flag flag = BOOST_ONCE_INIT;\r
boost::call_once(av_register_all, flag); \r
- \r
- input_.reset(new input(format_desc));\r
+ \r
+ input_.reset(new input(format_desc_));\r
input_->set_loop(std::find(params.begin(), params.end(), L"LOOP") != params.end());\r
input_->load(common::narrow(filename_));\r
-\r
- sound_channel_info_ptr snd_channel_info = input_->get_audio_codec_context() != nullptr ? \r
- std::make_shared<sound_channel_info>\r
- (\r
- input_->get_audio_codec_context()->channels, \r
- input_->get_audio_codec_context()->bits_per_coded_sample, \r
- input_->get_audio_codec_context()->sample_rate\r
- ) : nullptr;\r
- \r
video_decoder_.reset(new video_decoder());\r
- video_scaler_.reset(new video_scaler());\r
- audio_decoder_.reset(new audio_decoder(snd_channel_info));\r
+ video_transformer_.reset(new video_transformer());\r
+ audio_decoder_.reset(new audio_decoder());\r
has_audio_ = input_->get_audio_codec_context() != nullptr;\r
}\r
\r
- frame_ptr get_frame()\r
+ void initialize(const frame_factory_ptr& factory)\r
+ {\r
+ video_transformer_->initialize(factory);\r
+ }\r
+ \r
+ gpu_frame_ptr get_frame()\r
{\r
while(ouput_channel_.empty() && !input_->is_eof())\r
{ \r
if(video_packet)\r
{\r
video_packet = video_decoder_->execute(video_packet);\r
- auto frame = video_scaler_->execute(video_packet)->frame;\r
+ auto frame = video_transformer_->execute(video_packet)->frame;\r
video_frame_channel_.push_back(std::move(frame)); \r
}\r
}, \r
auto audio_packet = input_->get_audio_packet();\r
if(audio_packet)\r
{\r
- auto audio_chunks = audio_decoder_->execute(audio_packet);\r
- audio_chunk_channel_.insert(audio_chunk_channel_.end(), audio_packet->audio_chunks.begin(), audio_packet->audio_chunks.end());\r
+ audio_decoder_->execute(audio_packet);\r
+ for(size_t n = 0; n < audio_packet->audio_chunks.size(); ++n)\r
+ audio_chunk_channel_.push_back(std::move(audio_packet->audio_chunks[n]));\r
}\r
});\r
\r
{\r
if(has_audio_)\r
{\r
- video_frame_channel_.front()->audio_data().push_back(audio_chunk_channel_.front());\r
+ video_frame_channel_.front()->audio_data() = std::move(audio_chunk_channel_.front());\r
audio_chunk_channel_.pop_front();\r
}\r
\r
- frame_ptr frame = video_frame_channel_.front();\r
+ gpu_frame_ptr frame = video_frame_channel_.front();\r
video_frame_channel_.pop_front();\r
ouput_channel_.push(std::move(frame));\r
} \r
}\r
\r
- frame_ptr frame;\r
+ gpu_frame_ptr frame;\r
if(!ouput_channel_.empty())\r
{\r
frame = ouput_channel_.front();\r
bool has_audio_;\r
\r
// Filter 1 : Input\r
- input_uptr input_; \r
+ input_uptr input_; \r
\r
// Filter 2 : Video Decoding and Scaling\r
- video_decoder_uptr video_decoder_;\r
- video_scaler_uptr video_scaler_;\r
- //std::deque<video_packet_ptr> videoDecodedPacketChannel_;\r
- std::deque<frame_ptr> video_frame_channel_;\r
+ video_decoder_uptr video_decoder_;\r
+ video_transformer_uptr video_transformer_;\r
+ //std::deque<video_packet_ptr> videoDecodedPacketChannel_;\r
+ std::deque<gpu_frame_ptr> video_frame_channel_;\r
\r
// Filter 3 : Audio Decoding\r
- audio_decoder_uptr audio_decoder_;\r
- std::deque<audio_chunk_ptr> audio_chunk_channel_;\r
+ audio_decoder_uptr audio_decoder_;\r
+ std::deque<std::vector<short>> audio_chunk_channel_;\r
\r
// Filter 4 : Merge Video and Audio\r
- std::queue<frame_ptr> ouput_channel_;\r
+ std::queue<gpu_frame_ptr> ouput_channel_;\r
\r
- std::wstring filename_;\r
- frame_format_desc format_desc_;\r
+ std::wstring filename_;\r
+ frame_format_desc format_desc_;\r
};\r
\r
frame_producer_ptr create_ffmpeg_producer(const std::vector<std::wstring>& params, const frame_format_desc& format_desc)\r
\r
#include "input.h"\r
\r
-#include "../../frame/system_frame.h"\r
#include "../../frame/frame_format.h"\r
#include "../../../common/image/image.h"\r
#include "../../../common/utility/scope_exit.h"\r
if (av_read_frame(format_context.get(), packet.get()) >= 0) // NOTE: Packet is only valid until next call of av_read_frame or av_close_input_file\r
{\r
if(packet->stream_index == video_s_index_) \r
- video_packet_buffer_.push(std::make_shared<video_packet>(packet, std::make_shared<system_frame>(format_desc_.size), format_desc_, video_codec_context_.get(), video_codec_)); // NOTE: video_packet makes a copy of AVPacket\r
+ video_packet_buffer_.push(std::make_shared<video_packet>(packet, nullptr, format_desc_, video_codec_context_.get(), video_codec_)); // NOTE: video_packet makes a copy of AVPacket\r
else if(packet->stream_index == audio_s_index_) \r
audio_packet_buffer_.push(std::make_shared<audio_packet>(packet, audio_codex_context.get(), audio_codec_a, video_frame_rate_)); \r
}\r
#include "packet.h"\r
\r
#include <system_error>\r
+#include "../../frame/frame_fwd.h"\r
\r
namespace caspar{ namespace ffmpeg{ \r
\r
video_packet_ptr get_video_packet();\r
audio_packet_ptr get_audio_packet();\r
\r
+ void initialize(const frame_factory_ptr& factory);\r
+\r
bool is_eof() const;\r
void set_loop(bool value);\r
private:\r
#pragma once\r
\r
-#include "../../frame/audio_chunk.h"\r
-#include "../../frame/frame.h"\r
+#include "../../frame/gpu_frame.h"\r
+#include "../../frame/frame_format.h"\r
\r
#include <tbb/scalable_allocator.h>\r
#include <type_traits>\r
\r
struct video_packet : boost::noncopyable\r
{\r
- video_packet(const AVPacketPtr& packet, frame_ptr&& frame, const frame_format_desc& format_desc, AVCodecContext* codec_context, AVCodec* codec) \r
+ video_packet(const AVPacketPtr& packet, gpu_frame_ptr&& frame, const frame_format_desc& format_desc, AVCodecContext* codec_context, AVCodec* codec) \r
: size(packet->size), codec_context(codec_context), codec(codec), frame(std::move(frame)), format_desc(format_desc), \r
data(static_cast<uint8_t*>(scalable_aligned_malloc(packet->size, 16)))\r
{\r
const uint8_t* const data;\r
AVCodecContext* const codec_context;\r
const AVCodec* const codec;\r
- const frame_ptr frame;\r
+ gpu_frame_ptr frame;\r
AVFramePtr decoded_frame;\r
const frame_format_desc& format_desc;\r
}; \r
const size_t size;\r
const uint8_t* const data;\r
\r
- std::vector<audio_chunk_ptr> audio_chunks;\r
+ std::vector<std::vector<short>> audio_chunks;\r
};\r
typedef std::shared_ptr<audio_packet> audio_packet_ptr;\r
\r
struct video_decoder::implementation : boost::noncopyable\r
{\r
video_packet_ptr execute(const video_packet_ptr& video_packet)\r
- { \r
- if(video_packet->codec->id == CODEC_ID_RAWVIDEO) // TODO: doesnt sws_scale do this?\r
- common::image::shuffle(video_packet->frame->data(), video_packet->data, video_packet->size, 3, 2, 1, 0);\r
- else\r
- {\r
- video_packet->decoded_frame.reset(avcodec_alloc_frame(), av_free);\r
-\r
- int frame_finished = 0;\r
- if((-avcodec_decode_video(video_packet->codec_context, video_packet->decoded_frame.get(), &frame_finished, video_packet->data, video_packet->size)) > 0) \r
- video_packet->decoded_frame.reset(); \r
- }\r
+ { \r
+ video_packet->decoded_frame.reset(avcodec_alloc_frame(), av_free);\r
\r
+ int frame_finished = 0;\r
+ if((-avcodec_decode_video(video_packet->codec_context, video_packet->decoded_frame.get(), &frame_finished, video_packet->data, video_packet->size)) > 0) \r
+ video_packet->decoded_frame.reset(); \r
+ \r
return video_packet; \r
}\r
};\r
+++ /dev/null
-#pragma once\r
-\r
-#include "../packet.h"\r
-\r
-namespace caspar{ namespace ffmpeg{\r
-\r
-class video_scaler : boost::noncopyable\r
-{\r
-public:\r
- video_scaler();\r
- video_packet_ptr execute(const video_packet_ptr& video_packet);\r
-private:\r
- struct implementation;\r
- std::shared_ptr<implementation> impl_;\r
-};\r
-typedef std::shared_ptr<video_scaler> video_scaler_ptr;\r
-typedef std::unique_ptr<video_scaler> video_scaler_uptr;\r
-\r
-}}
\ No newline at end of file
#include "../../../stdafx.h"\r
\r
-#include "video_scaler.h"\r
+#include "video_transformer.h"\r
\r
#include "../../../frame/frame_format.h"\r
#include "../../../../common/image/image.h"\r
+#include "../../../frame/gpu_frame.h"\r
+#include "../../../frame/gpu_frame.h"\r
+#include "../../../frame/frame_factory.h"\r
\r
#include <tbb/parallel_for.h>\r
#include <tbb/atomic.h>\r
};\r
typedef std::shared_ptr<fill_frame> fill_frame_ptr;\r
\r
-struct video_scaler::implementation : boost::noncopyable\r
+struct video_transformer::implementation : boost::noncopyable\r
{\r
video_packet_ptr execute(const video_packet_ptr video_packet)\r
{ \r
//avcodec_get_frame_defaults(avFrame);\r
//avpicture_fill(reinterpret_cast<AVPicture*>(&avFrame), video_packet->frame->data(), PIX_FMT_BGRA, video_packet->frameFormat.width, video_packet->frameFormat.height);\r
\r
- fill_frame fill_frame(video_packet->format_desc.width, video_packet->format_desc.height);\r
+ auto format_desc = video_packet->format_desc;\r
+\r
+ fill_frame fill_frame(format_desc.width, format_desc.height);\r
+ video_packet->frame = factory_->create_frame(format_desc.width, format_desc.height);\r
int result = sws_scale(sws_context_.get(), video_packet->decoded_frame->data, video_packet->decoded_frame->linesize, 0, video_packet->codec_context->height, fill_frame.frame->data, fill_frame.frame->linesize);\r
video_packet->decoded_frame.reset(); // Free memory\r
\r
if(video_packet->codec->id == CODEC_ID_DVVIDEO) // Move up one field\r
{\r
- size_t size = video_packet->format_desc.width * video_packet->format_desc.height * 4;\r
- size_t linesize = video_packet->format_desc.width * 4;\r
+ size_t size = format_desc.width * format_desc.height * 4;\r
+ size_t linesize = format_desc.width * 4;\r
common::image::copy(video_packet->frame->data(), fill_frame.buffer.get() + linesize, size - linesize);\r
common::image::clear(video_packet->frame->data() + size - linesize, linesize);\r
}\r
return video_packet; \r
}\r
\r
-private:\r
+ frame_factory_ptr factory_;\r
SwsContextPtr sws_context_;\r
};\r
\r
-video_scaler::video_scaler() : impl_(new implementation()){}\r
-video_packet_ptr video_scaler::execute(const video_packet_ptr& video_packet){return impl_->execute(video_packet);}\r
+video_transformer::video_transformer() : impl_(new implementation()){}\r
+video_packet_ptr video_transformer::execute(const video_packet_ptr& video_packet){return impl_->execute(video_packet);}\r
+void video_transformer::initialize(const frame_factory_ptr& factory){impl_->factory_ = factory; }\r
}}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include "../packet.h"\r
+\r
+#include "../../../frame/frame_fwd.h"\r
+\r
+namespace caspar{ namespace ffmpeg{\r
+\r
+class video_transformer : boost::noncopyable\r
+{\r
+public:\r
+ video_transformer();\r
+ video_packet_ptr execute(const video_packet_ptr& video_packet); \r
+ void initialize(const frame_factory_ptr& factory);\r
+private:\r
+ struct implementation;\r
+ std::shared_ptr<implementation> impl_;\r
+};\r
+typedef std::shared_ptr<video_transformer> video_transformer_ptr;\r
+typedef std::unique_ptr<video_transformer> video_transformer_uptr;\r
+\r
+}}
\ No newline at end of file
\r
#include "FlashAxContainer.h"\r
#include "..\..\frame\frame_format.h"\r
-#include "..\..\protocol\monitor\Monitor.h"\r
#include "flash_producer.h"\r
#include "TimerHelper.h"\r
\r
\r
#pragma warning(push)\r
\r
-#include "..\..\frame\frame.h"\r
+#include "..\..\frame\gpu_frame.h"\r
+#include "..\..\frame\frame_format.h"\r
\r
#include <ocmm.h>\r
#include <vector>\r
*\r
*/\r
\r
-#include "../StdAfx.h"\r
+#include "../../StdAfx.h"\r
\r
-#include "bitmap_frame.h"\r
+#include "bitmap.h"\r
\r
#include <windows.h>\r
\r
namespace caspar{\r
\r
-class scoped_hdc : boost::noncopyable\r
-{ \r
-public:\r
- scoped_hdc(HDC hdc) : hdc_(hdc){}\r
- void operator=(scoped_hdc&& other) \r
- { \r
- hdc_ = other.hdc_;\r
- other.hdc_ = nullptr; \r
- }\r
- ~scoped_hdc()\r
- { \r
- if(hdc_ != nullptr)\r
- DeleteDC(hdc_);\r
- }\r
- operator HDC() { return hdc_; }\r
-private:\r
- HDC hdc_;\r
-};\r
-\r
-class scoped_bitmap : boost::noncopyable\r
-{ \r
-public:\r
- scoped_bitmap(HBITMAP bmp) : bmp_(bmp){}\r
- void operator=(scoped_bitmap&& other) \r
- { \r
- bmp_ = other.bmp_;\r
- other.bmp_ = nullptr; \r
- }\r
- ~scoped_bitmap() \r
- { \r
- if(bmp_ != nullptr) \r
- DeleteObject(bmp_);\r
- }\r
- operator HBITMAP() const { return bmp_; }\r
-private:\r
- HBITMAP bmp_;\r
-};\r
-\r
-struct bitmap_frame::implementation : boost::noncopyable\r
+struct bitmap::implementation : boost::noncopyable\r
{\r
- implementation(size_t width, size_t height) : size_(width*height*4), hdc_(CreateCompatibleDC(nullptr)), bitmap_(nullptr)\r
+ implementation(size_t width, size_t height) \r
+ : size_(width*height*4), width_(width), height_(height), hdc_(CreateCompatibleDC(nullptr)), bitmap_handle_(nullptr)\r
{ \r
if(hdc_ == nullptr)\r
throw std::bad_alloc();\r
-\r
+ \r
BITMAPINFO bitmapInfo;\r
bitmapInfo.bmiHeader.biBitCount = 32;\r
bitmapInfo.bmiHeader.biClrImportant = 0;\r
bitmapInfo.bmiHeader.biXPelsPerMeter = 0;\r
bitmapInfo.bmiHeader.biYPelsPerMeter = 0;\r
\r
- bitmap_ = std::move(CreateDIBSection(hdc_, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&bitmap_data_), NULL, 0));\r
- SelectObject(hdc_, bitmap_); \r
+ bitmap_handle_ = CreateDIBSection(hdc_, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&bitmap_data_), NULL, 0);\r
+ SelectObject(hdc_, bitmap_handle_); \r
+ }\r
+ \r
+ ~implementation()\r
+ {\r
+ if(bitmap_handle_ != nullptr) \r
+ DeleteObject(bitmap_handle_);\r
+ if(hdc_ != nullptr)\r
+ DeleteDC(hdc_);\r
}\r
\r
const size_t size_;\r
+ const size_t width_;\r
+ const size_t height_;\r
unsigned char* bitmap_data_;\r
- scoped_hdc hdc_;\r
- scoped_bitmap bitmap_;\r
+ HDC hdc_;\r
+ HBITMAP bitmap_handle_;\r
};\r
\r
-bitmap_frame::bitmap_frame(size_t width, size_t height) : impl_(new implementation(width, height)){}\r
-unsigned int bitmap_frame::size() const { return impl_->size_; }\r
-unsigned char* bitmap_frame::data() { return impl_->bitmap_data_; }\r
-HDC bitmap_frame::hdc() { return impl_->hdc_; }\r
+bitmap::bitmap(size_t width, size_t height) : impl_(new implementation(width, height)){}\r
+size_t bitmap::size() const { return impl_->size_; }\r
+size_t bitmap::width() const { return impl_->width_; }\r
+size_t bitmap::height() const { return impl_->height_; }\r
+unsigned char* bitmap::data() { return impl_->bitmap_data_; }\r
+HDC bitmap::hdc() { return impl_->hdc_; }\r
\r
}
\ No newline at end of file
*/\r
#pragma once\r
\r
-#include "frame.h"\r
-\r
#include <memory>\r
\r
namespace caspar{\r
\r
-class bitmap_frame : public frame\r
+class bitmap\r
{\r
public:\r
- bitmap_frame(size_t width, size_t height);\r
+ bitmap(size_t width, size_t height);\r
\r
unsigned char* data();\r
- unsigned int size() const; \r
+ size_t size() const; \r
+ size_t width() const;\r
+ size_t height() const;\r
HDC hdc();\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
-typedef std::shared_ptr<bitmap_frame> bitmap_frame_ptr;\r
-typedef std::unique_ptr<bitmap_frame> bitmap_frame_uptr;\r
+typedef std::shared_ptr<bitmap> bitmap_ptr;\r
+typedef std::unique_ptr<bitmap> bitmap_uptr;\r
\r
}\r
\r
\r
#include "../../renderer/render_device.h"\r
#include "../../frame/frame_format.h"\r
-#include "../../frame/frame.h"\r
+#include "../../frame/gpu_frame.h"\r
#include "../../Server.h"\r
\r
#include <boost/filesystem.hpp>\r
{\r
public:\r
\r
- implementation(const frame_format_desc& fmtDesc, Monitor* pMonitor) : format_desc_(fmtDesc)\r
+ implementation(const frame_format_desc& fmtDesc) : format_desc_(fmtDesc)\r
{\r
if(boost::filesystem::exists(server::template_folder()+TEXT("cg.fth.18")))\r
{\r
- flash_producer_ = std::make_shared<flash_producer>(server::template_folder()+TEXT("cg.fth.18"), fmtDesc, pMonitor);\r
+ flash_producer_ = std::make_shared<flash_producer>(server::template_folder()+TEXT("cg.fth.18"), fmtDesc);\r
proxy_.reset(new flash_cg_proxy18());\r
CASPAR_LOG(info) << L"Running version 1.8 template graphics.";\r
}\r
else if(boost::filesystem::exists(server::template_folder()+TEXT("cg.fth.17")))\r
{\r
- flash_producer_ = std::make_shared<flash_producer>(server::template_folder()+TEXT("cg.fth.17"), fmtDesc, pMonitor);\r
+ flash_producer_ = std::make_shared<flash_producer>(server::template_folder()+TEXT("cg.fth.17"), fmtDesc);\r
proxy_.reset(new flash_cg_proxy17());\r
CASPAR_LOG(info) << L"Running version 1.7 template graphics.";\r
}\r
else if(boost::filesystem::exists(server::template_folder()+TEXT("cg.fth"))) \r
{\r
- flash_producer_ = std::make_shared<flash_producer>(server::template_folder()+TEXT("cg.fth"), fmtDesc, pMonitor);\r
+ flash_producer_ = std::make_shared<flash_producer>(server::template_folder()+TEXT("cg.fth"), fmtDesc);\r
proxy_.reset(new flash_cg_proxy16());\r
CASPAR_LOG(info) << L"Running version 1.6 template graphics.";\r
}\r
flash_producer_->param(proxy_->invoke(layer, label));\r
}\r
\r
- frame_ptr get_frame()\r
+ gpu_frame_ptr get_frame()\r
{\r
return flash_producer_ ? flash_producer_->get_frame() : nullptr;\r
}\r
\r
+ \r
+ void initialize(const frame_factory_ptr& factory)\r
+ {\r
+ factory_ = factory;\r
+ if(flash_producer_)\r
+ flash_producer_->initialize(factory_);\r
+ }\r
+\r
frame_format_desc format_desc_;\r
flash_producer_ptr flash_producer_;\r
std::unique_ptr<flash_cg_proxy> proxy_;\r
+ frame_factory_ptr factory_;\r
};\r
\r
\r
auto pProducer = std::dynamic_pointer_cast<cg_producer>(prender_device->active(exLayer));\r
if(!pProducer) \r
{\r
- pProducer = std::make_shared<cg_producer>(prender_device->frame_format_desc(), &prender_device->monitor()); \r
+ pProducer = std::make_shared<cg_producer>(prender_device->frame_format_desc()); \r
prender_device->load(exLayer, pProducer, renderer::load_option::auto_play); \r
}\r
\r
return pProducer;\r
}\r
\r
-cg_producer::cg_producer(const frame_format_desc& fmtDesc, Monitor* pMonitor) : impl_(new implementation(fmtDesc, pMonitor)){}\r
-frame_ptr cg_producer::get_frame(){return impl_->get_frame();}\r
+cg_producer::cg_producer(const frame_format_desc& fmtDesc) : impl_(new implementation(fmtDesc)){}\r
+gpu_frame_ptr cg_producer::get_frame(){return impl_->get_frame();}\r
void cg_producer::clear(){impl_->clear();}\r
void cg_producer::add(int layer, const std::wstring& templateName, bool playOnLoad, const std::wstring& startFromLabel, const std::wstring& data){impl_->add(layer, templateName, playOnLoad, startFromLabel, data);}\r
void cg_producer::remove(int layer){impl_->remove(layer);}\r
void cg_producer::update(int layer, const std::wstring& data){impl_->update(layer, data);}\r
void cg_producer::invoke(int layer, const std::wstring& label){impl_->invoke(layer, label);}\r
const frame_format_desc& cg_producer::get_frame_format_desc() const { return impl_->format_desc_; }\r
+void cg_producer::initialize(const caspar::frame_factory_ptr& factory){impl_->initialize(factory);}\r
}}
\ No newline at end of file
class cg_producer : public frame_producer\r
{\r
public:\r
- cg_producer(const frame_format_desc& format_desc, Monitor* pMonitor);\r
+ cg_producer(const frame_format_desc& format_desc);\r
\r
- frame_ptr get_frame();\r
+ gpu_frame_ptr get_frame();\r
\r
void clear();\r
void add(int layer, const std::wstring& template_name, bool play_on_load, const std::wstring& start_from_label = TEXT(""), const std::wstring& data = TEXT(""));\r
void invoke(int layer, const std::wstring& label);\r
\r
const frame_format_desc& get_frame_format_desc() const;\r
+ void initialize(const caspar::frame_factory_ptr& factory);\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
#include "cg_producer.h"\r
\r
#include "../../../common/utility/find_file.h"\r
-#include "../../frame/frame.h"\r
+#include "../../frame/gpu_frame.h"\r
#include "../../server.h"\r
\r
#include <boost/assign/list_of.hpp>\r
while((pos = fixed_filename.find(TEXT('\\'), pos)) != std::wstring::npos) \r
fixed_filename[pos] = TEXT('/');\r
\r
- cg_producer_ptr cg_producer(new cg_producer(format_desc, nullptr));\r
+ cg_producer_ptr cg_producer(new cg_producer(format_desc));\r
cg_producer->add(0, filename, 1);\r
return cg_producer;\r
}\r
#include "flash_producer.h"\r
#include "FlashAxContainer.h"\r
#include "TimerHelper.h"\r
+#include "bitmap.h"\r
\r
-#include "../../frame/bitmap_frame.h"\r
#include "../../frame/frame_format.h"\r
-#include "../../frame/system_frame.h"\r
#include "../../../common/utility/find_file.h"\r
#include "../../server.h"\r
#include "../../../common/concurrency/executor.h"\r
\r
struct flash_producer::implementation\r
{ \r
- implementation(flash_producer* self, const std::wstring& filename, const frame_format_desc& format_desc, Monitor* monitor) \r
- : flashax_container_(nullptr), filename_(filename), self_(self), format_desc_(format_desc), monitor_(monitor),\r
+ implementation(flash_producer* self, const std::wstring& filename, const frame_format_desc& format_desc) \r
+ : flashax_container_(nullptr), filename_(filename), self_(self), format_desc_(format_desc),\r
bitmap_pool_(new bitmap_pool), executor_([=]{run();}), invalid_count_(0)\r
{ \r
if(!boost::filesystem::exists(filename))\r
BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(common::narrow(filename)));\r
\r
frame_buffer_.set_capacity(flash_producer::DEFAULT_BUFFER_SIZE);\r
- last_frame_ = std::make_shared<bitmap_frame>(format_desc_.width, format_desc_.height);\r
+ last_frame_ = std::make_shared<bitmap>(format_desc_.width, format_desc_.height);\r
\r
start();\r
}\r
}\r
}\r
\r
- frame_ptr render_interlace_frame()\r
+ bitmap_ptr render_interlace_frame()\r
{ \r
- return copy_frame(render_frame(), render_frame(), format_desc_);\r
+ bitmap_ptr frame1 = render_frame();\r
+ bitmap_ptr frame2 = render_frame();\r
+ common::image::copy(frame1->data(), frame2->data(), frame1->size());\r
+ return frame1;\r
}\r
\r
- frame_ptr render_frame()\r
+ bitmap_ptr render_frame()\r
{\r
flashax_container_->Tick();\r
invalid_count_ = !flashax_container_->InvalidRectangle() ? std::min(2, invalid_count_+1) : 0;\r
if(current_frame_ == nullptr || invalid_count_ < 2)\r
{ \r
- bitmap_frame_ptr frame; \r
+ bitmap_ptr frame; \r
if(!bitmap_pool_->try_pop(frame)) \r
{ \r
- CASPAR_LOG(trace) << "Allocated bitmap_frame";\r
- frame = clear_frame(std::make_shared<bitmap_frame>(format_desc_.width, format_desc_.height)); \r
+ CASPAR_LOG(trace) << "Allocated bitmap";\r
+ frame = std::make_shared<bitmap>(format_desc_.width, format_desc_.height); \r
+ common::image::clear(frame->data(), frame->size());\r
}\r
flashax_container_->DrawControl(frame->hdc());\r
\r
auto pool = bitmap_pool_;\r
- current_frame_.reset(frame.get(), [=](bitmap_frame*)\r
+ current_frame_.reset(frame.get(), [=](bitmap*)\r
{\r
- common::function_task::enqueue([=]{pool->try_push(clear_frame(frame));});\r
+ common::function_task::enqueue([=]\r
+ {\r
+ if(pool->try_push(frame))\r
+ common::image::clear(frame->data(), frame->size());\r
+ });\r
});\r
} \r
return current_frame_;\r
}\r
\r
- frame_ptr get_frame()\r
+ gpu_frame_ptr get_frame()\r
{\r
- return frame_buffer_.try_pop(last_frame_) || !is_empty_ ? last_frame_ : frame::null();\r
+ if(!frame_buffer_.try_pop(last_frame_) && is_empty_)\r
+ return gpu_frame::null();\r
+ \r
+ auto frame = factory_->create_frame(format_desc_);\r
+ common::image::copy(frame->data(), last_frame_->data(), last_frame_->size()); \r
+ \r
+ return frame;\r
+ }\r
+\r
+ void initialize(const frame_factory_ptr& factory)\r
+ {\r
+ factory_ = factory;\r
}\r
\r
- typedef tbb::concurrent_bounded_queue<bitmap_frame_ptr> bitmap_pool;\r
+ typedef tbb::concurrent_bounded_queue<bitmap_ptr> bitmap_pool;\r
std::shared_ptr<bitmap_pool> bitmap_pool_;\r
frame_format_desc format_desc_;\r
\r
CComObject<caspar::flash::FlashAxContainer>* flashax_container_;\r
\r
- tbb::concurrent_bounded_queue<frame_ptr> frame_buffer_;\r
- frame_ptr last_frame_;\r
- frame_ptr current_frame_;\r
+ tbb::concurrent_bounded_queue<bitmap_ptr> frame_buffer_;\r
+ bitmap_ptr last_frame_;\r
+ bitmap_ptr current_frame_;\r
\r
std::wstring filename_;\r
flash_producer* self_;\r
- Monitor* monitor_;\r
\r
tbb::atomic<bool> is_empty_;\r
common::executor executor_;\r
int invalid_count_;\r
+\r
+ frame_factory_ptr factory_;\r
};\r
\r
-flash_producer::flash_producer(const std::wstring& filename, const frame_format_desc& format_desc, Monitor* monitor) : impl_(new implementation(this, filename, format_desc, monitor)){}\r
-frame_ptr flash_producer::get_frame(){return impl_->get_frame();}\r
-Monitor* flash_producer::get_monitor(){return impl_->monitor_; }\r
+flash_producer::flash_producer(const std::wstring& filename, const frame_format_desc& format_desc) : impl_(new implementation(this, filename, format_desc)){}\r
+gpu_frame_ptr flash_producer::get_frame(){return impl_->get_frame();}\r
void flash_producer::param(const std::wstring& param){impl_->param(param);}\r
const frame_format_desc& flash_producer::get_frame_format_desc() const { return impl_->format_desc_; } \r
+void flash_producer::initialize(const frame_factory_ptr& factory) { impl_->initialize(factory);}\r
\r
std::wstring flash_producer::find_template(const std::wstring& template_name)\r
{\r
/// <summary> Timeout for blocking while trying to stop the producer. </summary>\r
static const int STOP_TIMEOUT = 2000;\r
\r
- flash_producer(const std::wstring& filename, const frame_format_desc& format_desc, Monitor* monitor = nullptr);\r
- frame_ptr get_frame();\r
+ flash_producer(const std::wstring& filename, const frame_format_desc& format_desc);\r
+ gpu_frame_ptr get_frame();\r
const frame_format_desc& get_frame_format_desc() const;\r
+ void initialize(const frame_factory_ptr& factory);\r
\r
void param(const std::wstring& param);\r
\r
private: \r
friend class flash::FlashAxContainer;\r
\r
- Monitor* get_monitor();\r
-\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
\r
#pragma once\r
\r
#include "../frame/frame_fwd.h"\r
+#include "../frame/gpu_frame.h"\r
+#include "../frame/frame_factory.h"\r
\r
#include <boost/noncopyable.hpp>\r
\r
#include <memory>\r
\r
namespace caspar {\r
-\r
-class Monitor;\r
-\r
+ \r
class frame_producer : boost::noncopyable\r
{\r
public:\r
virtual ~frame_producer(){} \r
- virtual frame_ptr get_frame() = 0;\r
+ virtual gpu_frame_ptr get_frame() = 0;\r
virtual std::shared_ptr<frame_producer> get_following_producer() const { return nullptr; }\r
virtual void set_leading_producer(const std::shared_ptr<frame_producer>&) {}\r
virtual const frame_format_desc& get_frame_format_desc() const = 0;\r
+ virtual void initialize(const frame_factory_ptr& factory) = 0;\r
};\r
typedef std::shared_ptr<frame_producer> frame_producer_ptr;\r
\r
\r
#include "../../../common/exception/Exceptions.h"\r
\r
-#include "../../frame/frame.h"\r
-#include "../../frame/system_frame.h"\r
+#include "../../frame/gpu_frame.h"\r
#include "../../../common/image/image.h"\r
\r
#if defined(_MSC_VER)\r
#include "image_producer.h"\r
#include "image_loader.h"\r
\r
-#include "../../frame/system_frame.h"\r
+#include "../../frame/frame_factory.h"\r
#include "../../frame/frame_format.h"\r
#include "../../server.h"\r
#include "../../../common/utility/find_file.h"\r
\r
struct image_producer : public frame_producer\r
{\r
- image_producer(const std::wstring& filename, const frame_format_desc& format_desc) : format_desc_(format_desc)\r
- {\r
- auto bitmap = load_image(filename);\r
+ image_producer(const std::wstring& filename, const frame_format_desc& format_desc) : format_desc_(format_desc), filename_(filename) {}\r
+\r
+ gpu_frame_ptr get_frame(){return frame_;}\r
\r
- if(FreeImage_GetWidth(bitmap.get()) != format_desc.width || FreeImage_GetHeight(bitmap.get()) == format_desc.height)\r
+ void initialize(const frame_factory_ptr& factory)\r
+ {\r
+ auto bitmap = load_image(filename_);\r
+ if(FreeImage_GetWidth(bitmap.get()) != format_desc_.width || FreeImage_GetHeight(bitmap.get()) == format_desc_.height)\r
{\r
- bitmap = std::shared_ptr<FIBITMAP>(FreeImage_Rescale(bitmap.get(), format_desc.width, format_desc.width, FILTER_BICUBIC), FreeImage_Unload);\r
+ bitmap = std::shared_ptr<FIBITMAP>(FreeImage_Rescale(bitmap.get(), format_desc_.width, format_desc_.width, FILTER_BICUBIC), FreeImage_Unload);\r
if(!bitmap)\r
BOOST_THROW_EXCEPTION(invalid_argument() << msg_info("Unsupported image format."));\r
}\r
\r
FreeImage_FlipVertical(bitmap.get());\r
-\r
- frame_ = std::make_shared<system_frame>(format_desc.size);\r
+ frame_ = factory->create_frame(format_desc_);\r
common::image::copy(frame_->data(), FreeImage_GetBits(bitmap.get()), frame_->size());\r
}\r
\r
- frame_ptr get_frame()\r
- {\r
- return frame_;\r
- }\r
-\r
const frame_format_desc& get_frame_format_desc() const { return format_desc_; } \r
\r
+ std::wstring filename_;\r
frame_format_desc format_desc_;\r
- frame_ptr frame_;\r
+ gpu_frame_ptr frame_;\r
};\r
\r
frame_producer_ptr create_image_producer(const std::vector<std::wstring>& params, const frame_format_desc& format_desc)\r
#include "image_loader.h"\r
\r
#include "../../frame/frame_format.h"\r
-#include "../../frame/system_frame.h"\r
+#include "../../frame/frame_factory.h"\r
#include "../../server.h"\r
#include "../../../common/utility/find_file.h"\r
#include "../../../common/image/image.h"\r
common::image::copy(&image_.get()[i * image_width_ * 4], &pBits[i* width * 4], width * 4);\r
}\r
\r
- frame_ptr render_frame()\r
+ gpu_frame_ptr render_frame()\r
{\r
- frame_ptr frame = std::make_shared<system_frame>(format_desc_.size);\r
+ gpu_frame_ptr frame = factory_->create_frame(format_desc_);\r
common::image::clear(frame->data(), frame->size());\r
\r
const int delta_x = direction_ == direction::Left ? speed_ : -speed_;\r
return frame;\r
}\r
\r
- frame_ptr render_interlaced_frame()\r
+ gpu_frame_ptr render_interlaced_frame()\r
{\r
- frame_ptr next_frame1;\r
- frame_ptr next_frame2;\r
+ gpu_frame_ptr next_frame1;\r
+ gpu_frame_ptr next_frame2;\r
tbb::parallel_invoke([&]{ next_frame1 = render_frame(); }, [&]{ next_frame2 = render_frame(); });\r
\r
- return copy_frame(next_frame1, next_frame2, format_desc_);\r
+ common::image::copy_field(next_frame1->data(), next_frame2->data(), format_desc_.mode == video_mode::upper ? 1 : 0, format_desc_.width, format_desc_.height);\r
+ return next_frame1;\r
}\r
\r
- frame_ptr get_frame()\r
+ gpu_frame_ptr get_frame()\r
{\r
return format_desc_.mode == video_mode::progressive ? render_frame() : render_interlaced_frame();\r
}\r
\r
+ \r
+ void initialize(const frame_factory_ptr& factory)\r
+ {\r
+ factory_ = factory;\r
+ }\r
+\r
const frame_format_desc& get_frame_format_desc() const { return format_desc_; } \r
\r
int image_width_;\r
tbb::atomic<bool> loop_;\r
std::shared_ptr<unsigned char> image_;\r
frame_format_desc format_desc_;\r
+\r
+ frame_factory_ptr factory_;\r
};\r
\r
frame_producer_ptr create_image_scroll_producer(const std::vector<std::wstring>& params, const frame_format_desc& format_desc)\r
#include "transition_producer.h"\r
\r
#include "../../frame/frame_format.h"\r
+#include "../../frame/gpu_frame.h"\r
+#include "../../frame/composite_gpu_frame.h"\r
+#include "../../frame/frame_factory.h"\r
\r
#include "../../../common/image/image.h"\r
-#include "../../frame/system_frame.h"\r
-#include "../../frame/audio_chunk.h"\r
#include "../../renderer/render_device.h"\r
\r
#include <boost/range/algorithm/copy.hpp>\r
\r
namespace caspar{ \r
- \r
-class empty_producer : public frame_producer\r
-{\r
-public:\r
- explicit empty_producer(const frame_format_desc& format_desc) \r
- : format_desc_(format_desc), frame_(clear_frame(std::make_shared<system_frame>(format_desc_.size)))\r
- {} \r
-\r
- frame_ptr get_frame() { return frame_; }\r
- const frame_format_desc& get_frame_format_desc() const { return format_desc_; }\r
-private:\r
- frame_format_desc format_desc_;\r
- frame_ptr frame_;\r
-};\r
\r
struct transition_producer::implementation : boost::noncopyable\r
{\r
implementation(const frame_producer_ptr& dest, const transition_info& info, const frame_format_desc& format_desc) \r
- : current_frame_(0), info_(info), border_color_(0), format_desc_(format_desc), \r
- empty_(std::make_shared<empty_producer>(format_desc)), source_(empty_), dest_(dest)\r
+ : current_frame_(0), info_(info), border_color_(0), format_desc_(format_desc), dest_(dest)\r
{\r
if(!dest)\r
BOOST_THROW_EXCEPTION(null_argument() << arg_name_info("dest"));\r
\r
void set_leading_producer(const frame_producer_ptr& producer)\r
{\r
- source_ = producer != nullptr ? producer : empty_;\r
+ source_ = producer;\r
}\r
\r
- frame_ptr get_frame()\r
+ gpu_frame_ptr get_frame()\r
{\r
if(++current_frame_ >= info_.duration)\r
return nullptr;\r
return compose(get_producer_frame(dest_), get_producer_frame(source_));\r
}\r
\r
- frame_ptr get_producer_frame(frame_producer_ptr& producer)\r
+ gpu_frame_ptr get_producer_frame(frame_producer_ptr& producer)\r
{\r
- assert(producer != nullptr);\r
+ if(producer == nullptr)\r
+ { \r
+ auto frame = factory_->create_frame(format_desc_);\r
+ common::image::clear(frame->data(), frame->size());\r
+ return frame;\r
+ }\r
\r
- frame_ptr frame;\r
+ gpu_frame_ptr frame;\r
try\r
{\r
frame = producer->get_frame();\r
return frame;\r
}\r
\r
- frame_ptr compose(const frame_ptr& dest_frame, const frame_ptr& src_frame) \r
+ gpu_frame_ptr compose(const gpu_frame_ptr& dest_frame, const gpu_frame_ptr& src_frame) \r
{ \r
- frame_ptr result_frame = dest_frame; \r
- if(src_frame != nullptr && dest_frame != nullptr)\r
- {\r
- result_frame = std::make_shared<system_frame>(format_desc_.size);\r
- tbb::parallel_invoke(\r
- [&]\r
- {\r
- GenerateFrame(result_frame->data(), src_frame->data(), dest_frame->data());\r
- },\r
- [&]\r
- {\r
- float delta = static_cast<float>(current_frame_)/static_cast<float>(info_.duration);\r
- set_frame_volume(dest_frame, delta*100.0f);\r
- set_frame_volume(src_frame, (1.0f-delta)*100.0f); \r
-\r
- boost::range::copy(src_frame->audio_data(), std::back_inserter(result_frame->audio_data())); \r
- boost::range::copy(dest_frame->audio_data(), std::back_inserter(result_frame->audio_data()));;\r
- });\r
- }\r
- return result_frame;\r
- }\r
- \r
- void GenerateFrame(unsigned char* pResultData, const unsigned char* pSourceData, const unsigned char* pDestData)\r
- {\r
- if(info_.type == transition_type::cut)\r
- {\r
- common::image::copy(pResultData, pSourceData, format_desc_.size);\r
- return;\r
- }\r
-\r
- if(current_frame_ >= info_.duration) \r
- {\r
- common::image::copy(pResultData, pDestData, format_desc_.size);\r
- return;\r
- }\r
-\r
+ if(info_.type == transition_type::cut) \r
+ return src_frame;\r
+ \r
+ int volume = static_cast<int>(static_cast<float>(current_frame_)/static_cast<float>(info_.duration)*256.0f);\r
+ \r
+ for(size_t n = 0; n < dest_frame->audio_data().size(); ++n)\r
+ dest_frame->audio_data()[n] = static_cast<short>((static_cast<int>(dest_frame->audio_data()[n])*volume)>>8);\r
+\r
+ for(size_t n = 0; n < src_frame->audio_data().size(); ++n)\r
+ src_frame->audio_data()[n] = static_cast<short>((static_cast<int>(src_frame->audio_data()[n])*(256-volume))>>8);\r
+ \r
+ float alpha = static_cast<float>(current_frame_)/static_cast<float>(info_.duration);\r
+ auto composite = std::make_shared<composite_gpu_frame>(format_desc_.width, format_desc_.height);\r
+ composite->add(src_frame);\r
+ composite->add(dest_frame);\r
if(info_.type == transition_type::mix)\r
{\r
- common::image::lerp(pResultData, pSourceData, pDestData, 1.0f-static_cast<float>(current_frame_)/static_cast<float>(info_.duration), format_desc_.size);\r
- return;\r
+ src_frame->alpha(1.0f-alpha);\r
+ dest_frame->alpha(alpha);\r
}\r
-\r
- size_t totalWidth = format_desc_.width + info_.border_width;\r
- \r
- float fStep = totalWidth / static_cast<float>(info_.duration);\r
- float fOffset = fStep * static_cast<float>(current_frame_);\r
-\r
- size_t halfStep = static_cast<size_t>(fStep/2.0);\r
- size_t offset = static_cast<size_t>(fOffset+0.5f);\r
- \r
- //read source to buffer\r
- for(size_t row = 0, even = 0; row < format_desc_.height; ++row, even ^= 1)\r
+ else if(info_.type == transition_type::slide)\r
{\r
- size_t fieldCorrectedOffset = offset + (halfStep*even);\r
- if(fieldCorrectedOffset < format_desc_.width)\r
- {\r
- if(info_.direction != transition_direction::from_left)\r
- {\r
- if(info_.type == transition_type::push)\r
- memcpy(&(pResultData[4*row*format_desc_.width]), &(pSourceData[4*(row*format_desc_.width+fieldCorrectedOffset)]), (format_desc_.width-fieldCorrectedOffset)*4);\r
- else //Slide | Wipe\r
- memcpy(&(pResultData[4*row*format_desc_.width]), &(pSourceData[4*row*format_desc_.width]), (format_desc_.width-fieldCorrectedOffset)*4);\r
- }\r
- else // if (direction == LEFT)\r
- { \r
- if(info_.type == transition_type::push)\r
- memcpy(&(pResultData[4*(row*format_desc_.width+fieldCorrectedOffset)]), &(pSourceData[4*(row*format_desc_.width)]), (format_desc_.width-fieldCorrectedOffset)*4);\r
- else //slide eller wipe\r
- memcpy(&(pResultData[4*(row*format_desc_.width+fieldCorrectedOffset)]), &(pSourceData[4*(row*format_desc_.width+fieldCorrectedOffset)]), (format_desc_.width-fieldCorrectedOffset)*4);\r
- }\r
- }\r
+ dest_frame->translate(-1.0f+alpha, 0.0f);\r
}\r
-\r
- //write border to buffer\r
- if(info_.border_width > 0)\r
+ else if(info_.type == transition_type::push)\r
{\r
- for(size_t row = 0, even = 0; row < format_desc_.height; ++row, even ^= 1)\r
- {\r
- size_t fieldCorrectedOffset = offset + (halfStep*even);\r
- size_t length = info_.border_width;\r
- size_t start = 0;\r
-\r
- if(info_.direction != transition_direction::from_left)\r
- {\r
- if(fieldCorrectedOffset > format_desc_.width)\r
- {\r
- length -= fieldCorrectedOffset-format_desc_.width;\r
- start += fieldCorrectedOffset-format_desc_.width;\r
- fieldCorrectedOffset = format_desc_.width;\r
- }\r
- else if(fieldCorrectedOffset < length)\r
- {\r
- length = fieldCorrectedOffset;\r
- }\r
-\r
- for(size_t i = 0; i < length; ++i)\r
- memcpy(&(pResultData[4*(row*format_desc_.width+format_desc_.width-fieldCorrectedOffset+i)]), &border_color_, 4);\r
- \r
- }\r
- else // if (direction == LEFT)\r
- {\r
- if(fieldCorrectedOffset > format_desc_.width)\r
- {\r
- length -= fieldCorrectedOffset-format_desc_.width;\r
- start = 0;\r
- fieldCorrectedOffset -= info_.border_width-length;\r
- }\r
- else if(fieldCorrectedOffset < length)\r
- {\r
- length = fieldCorrectedOffset;\r
- start = info_.border_width-fieldCorrectedOffset;\r
- }\r
-\r
- for(size_t i = 0; i < length; ++i)\r
- memcpy(&(pResultData[4*(row*format_desc_.width+fieldCorrectedOffset-length+i)]), &border_color_, 4); \r
- }\r
-\r
- }\r
- }\r
-\r
- //read dest to buffer\r
- offset -= info_.border_width;\r
- if(offset > 0)\r
- {\r
- for(size_t row = 0, even = 0; row < format_desc_.height; ++row, even ^= 1)\r
- {\r
- int fieldCorrectedOffset = offset + (halfStep*even);\r
-\r
- if(info_.direction != transition_direction::from_left)\r
- {\r
- if(info_.type == transition_type::wipe)\r
- memcpy(&(pResultData[4*(row*format_desc_.width+format_desc_.width-fieldCorrectedOffset)]), &(pDestData[4*(row*format_desc_.width+format_desc_.width-fieldCorrectedOffset)]), fieldCorrectedOffset*4);\r
- else\r
- memcpy(&(pResultData[4*(row*format_desc_.width+format_desc_.width-fieldCorrectedOffset)]), &(pDestData[4*row*format_desc_.width]), fieldCorrectedOffset*4);\r
- }\r
- else // if (direction == LEFT)\r
- { \r
- if(info_.type == transition_type::wipe)\r
- memcpy(&(pResultData[4*(row*format_desc_.width)]), &(pDestData[4*(row*format_desc_.width)]), fieldCorrectedOffset*4);\r
- else\r
- memcpy(&(pResultData[4*(row*format_desc_.width)]), &(pDestData[4*(row*format_desc_.width+format_desc_.width-fieldCorrectedOffset)]), fieldCorrectedOffset*4); \r
- }\r
- }\r
+ dest_frame->translate(-1.0f+alpha, 0.0f);\r
+ src_frame->translate(alpha, 0.0f);\r
}\r
+ return composite;\r
+ }\r
+ \r
+ void initialize(const frame_factory_ptr& factory)\r
+ {\r
+ dest_->initialize(factory);\r
+ factory_ = factory;\r
}\r
\r
const frame_format_desc format_desc_;\r
\r
- frame_producer_ptr empty_;\r
frame_producer_ptr source_;\r
frame_producer_ptr dest_;\r
\r
\r
const transition_info info_;\r
const unsigned long border_color_;\r
+ frame_factory_ptr factory_;\r
};\r
\r
transition_producer::transition_producer(const frame_producer_ptr& dest, const transition_info& info, const frame_format_desc& format_desc) \r
: impl_(new implementation(dest, info, format_desc)){}\r
-frame_ptr transition_producer::get_frame(){return impl_->get_frame();}\r
+gpu_frame_ptr transition_producer::get_frame(){return impl_->get_frame();}\r
frame_producer_ptr transition_producer::get_following_producer() const{return impl_->get_following_producer();}\r
void transition_producer::set_leading_producer(const frame_producer_ptr& producer) { impl_->set_leading_producer(producer); }\r
const frame_format_desc& transition_producer::get_frame_format_desc() const { return impl_->format_desc_; } \r
+void transition_producer::initialize(const frame_factory_ptr& factory) { impl_->initialize(factory);}\r
+\r
+}\r
\r
-}
\ No newline at end of file
public:\r
transition_producer(const frame_producer_ptr& destination, const transition_info& info, const frame_format_desc& fmt);\r
\r
- frame_ptr get_frame();\r
+ gpu_frame_ptr get_frame();\r
\r
frame_producer_ptr get_following_producer() const;\r
void set_leading_producer(const frame_producer_ptr& producer);\r
const frame_format_desc& get_frame_format_desc() const;\r
+ virtual void initialize(const frame_factory_ptr& factory);\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
#include "../../producer/flash/flash_producer.h"\r
#include "../../producer/transition/transition_producer.h"\r
#include <boost/lexical_cast.hpp>\r
-#include "../monitor/Monitor.h"\r
#include "../../producer/flash/cg_producer.h"\r
#include "../media.h"\r
#include "../../Server.h"\r
\r
SetReplyString(TEXT("202 LOAD OK\r\n"));\r
\r
- GetChannel()->monitor().Inform(LOAD, _parameters[0]);\r
return true;\r
}\r
catch(file_not_found&)\r
CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully to background");\r
SetReplyString(TEXT("202 LOADBG OK\r\n"));\r
\r
- GetChannel()->monitor().Inform(LOADBG, _parameters[0]);\r
return true;\r
}\r
catch(file_not_found&)\r
GetChannel()->clear(GetLayerIndex());\r
SetReplyString(TEXT("202 CLEAR OK\r\n"));\r
\r
- GetChannel()->monitor().Inform(CLEAR);\r
return true;\r
}\r
\r
\r
flash::get_default_cg_producer(GetChannel(), GetLayerIndex(flash::CG_DEFAULT_LAYER))->add(layer, filename, bDoStart, label, (pDataString!=0) ? pDataString : TEXT(""));\r
SetReplyString(TEXT("202 CG OK\r\n"));\r
-\r
- GetChannel()->monitor().Inform(CG_ADD, _parameters[2]);\r
}\r
else\r
{\r
{\r
flash::get_default_cg_producer(GetChannel(), GetLayerIndex(flash::CG_DEFAULT_LAYER))->clear();\r
SetReplyString(TEXT("202 CG OK\r\n"));\r
- GetChannel()->monitor().Inform(CG_CLEAR);\r
return true;\r
}\r
\r
return true;\r
}\r
\r
-bool MonitorCommand::DoExecute()\r
-{\r
- std::wstring cmd = _parameters[0];\r
-\r
- if(cmd == TEXT("START")) {\r
- GetChannel()->monitor().AddListener(GetClientInfo());\r
- SetReplyString(TEXT("202 MONITOR START OK\r\n"));\r
- }\r
- else if(cmd == TEXT("STOP")) {\r
- GetChannel()->monitor().RemoveListener(GetClientInfo());\r
- SetReplyString(TEXT("202 MONITOR STOP OK\r\n"));\r
- }\r
- else\r
- SetReplyString(TEXT("403 MONITOR ERROR\r\n"));\r
-\r
- return true;\r
-}\r
\r
} //namespace amcp\r
} //namespace caspar
\ No newline at end of file
bool DoExecute();\r
};\r
\r
-class MonitorCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
-{\r
- bool DoExecute();\r
-};\r
-\r
//class KillCommand : public AMCPCommand\r
//{\r
//public:\r
\r
#include "../producer/frame_producer.h"\r
\r
-#include "../frame/system_frame.h"\r
#include "../frame/frame_format.h"\r
\r
namespace caspar { namespace renderer {\r
background_ = nullptr;\r
}\r
\r
- frame_ptr get_frame()\r
+ gpu_frame_ptr get_frame()\r
{ \r
if(!active_)\r
return preview_frame_;\r
\r
- frame_ptr frame;\r
+ gpu_frame_ptr frame;\r
try\r
{\r
frame = active_->get_frame();\r
return frame;\r
} \r
\r
- frame_ptr preview_frame_;\r
+ gpu_frame_ptr preview_frame_;\r
frame_producer_ptr active_;\r
frame_producer_ptr background_;\r
};\r
void layer::play(){impl_->play();}\r
void layer::stop(){impl_->stop();}\r
void layer::clear(){impl_->clear();}\r
-frame_ptr layer::get_frame() {return impl_->get_frame();}\r
+gpu_frame_ptr layer::get_frame() {return impl_->get_frame();}\r
frame_producer_ptr layer::active() const { return impl_->active_;}\r
frame_producer_ptr layer::background() const { return impl_->background_;}\r
}}
\ No newline at end of file
frame_producer_ptr active() const;\r
frame_producer_ptr background() const;\r
\r
- frame_ptr get_frame();\r
+ gpu_frame_ptr get_frame();\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
#include "render_device.h"\r
#include "layer.h"\r
\r
-#include "../protocol/monitor/Monitor.h"\r
#include "../consumer/frame_consumer.h"\r
\r
-#include "../frame/system_frame.h"\r
#include "../frame/frame_format.h"\r
+#include "../frame/gpu_frame_processor.h"\r
\r
#include "../../common/utility/scope_exit.h"\r
#include "../../common/image/image.h"\r
\r
namespace caspar{ namespace renderer{\r
\r
-std::vector<frame_ptr> render_frames(std::map<int, layer>& layers)\r
+std::vector<gpu_frame_ptr> render_frames(std::map<int, layer>& layers)\r
{ \r
- std::vector<frame_ptr> frames(layers.size(), nullptr);\r
+ std::vector<gpu_frame_ptr> frames(layers.size(), nullptr);\r
tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size()), [&](const tbb::blocked_range<size_t>& r)\r
{\r
auto it = layers.begin();\r
for(size_t i = r.begin(); i != r.end(); ++i, ++it)\r
frames[i] = it->second.get_frame();\r
}); \r
- boost::range::remove_erase(frames, nullptr);\r
- boost::range::remove_erase_if(frames, [](const frame_const_ptr& frame) { return *frame == *frame::null();});\r
return frames;\r
}\r
\r
struct render_device::implementation : boost::noncopyable\r
{ \r
implementation(const caspar::frame_format_desc& format_desc, unsigned int index, const std::vector<frame_consumer_ptr>& consumers) \r
- : consumers_(consumers), monitor_(index), fmt_(format_desc)\r
+ : consumers_(consumers), fmt_(format_desc), frame_processor_(new gpu_frame_processor(format_desc))\r
{ \r
is_running_ = true;\r
if(consumers.empty())\r
CASPAR_LOG(info) << L"Started render_device::render Thread";\r
win32_exception::install_handler();\r
\r
- std::vector<frame_ptr> current_frames;\r
-\r
while(is_running_)\r
{\r
try\r
{ \r
- std::vector<frame_ptr> next_frames;\r
- frame_ptr composite_frame; \r
+ std::vector<gpu_frame_ptr> next_frames;\r
+ gpu_frame_ptr composite_frame; \r
\r
{\r
tbb::mutex::scoped_lock lock(layers_mutex_); \r
- tbb::parallel_invoke(\r
- [&]{next_frames = render_frames(layers_);}, \r
- [&]{composite_frame = compose_frames(current_frames.empty() ? std::make_shared<system_frame>(fmt_.size) : current_frames[0], current_frames);});\r
+ next_frames = render_frames(layers_);\r
}\r
-\r
- current_frames = std::move(next_frames); \r
+ frame_processor_->push(next_frames);\r
+ frame_processor_->pop(composite_frame); \r
frame_buffer_.push(std::move(composite_frame));\r
}\r
catch(...)\r
CASPAR_LOG(info) << L"Started render_device::display Thread";\r
win32_exception::install_handler();\r
\r
- frame_ptr frame = clear_frame(std::make_shared<system_frame>(fmt_.size));\r
- std::deque<frame_ptr> prepared(3, frame);\r
+ gpu_frame_ptr frame = frame_processor_->create_frame(fmt_.width, fmt_.height);\r
+ common::image::clear(frame->data(), frame->size());\r
+ std::deque<gpu_frame_ptr> prepared(3, frame);\r
\r
while(is_running_)\r
{\r
CASPAR_LOG(info) << L"Ended render_device::display Thread";\r
}\r
\r
- void send_frame(const frame_ptr& pPreparedFrame, const frame_ptr& pNextFrame)\r
+ void send_frame(const gpu_frame_ptr& prepared_frame, const gpu_frame_ptr& next_frame)\r
{\r
BOOST_FOREACH(const frame_consumer_ptr& consumer, consumers_)\r
{\r
try\r
{\r
- consumer->prepare(pNextFrame); // Could block\r
- consumer->display(pPreparedFrame); // Could block\r
+ consumer->prepare(next_frame); // Could block\r
+ consumer->display(prepared_frame); // Could block\r
}\r
catch(...)\r
{\r
if(producer->get_frame_format_desc() != fmt_)\r
BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("pProducer") << msg_info("Invalid frame format"));\r
\r
+ producer->initialize(frame_processor_);\r
tbb::mutex::scoped_lock lock(layers_mutex_);\r
layers_[exLayer].load(producer, option);\r
}\r
boost::thread display_thread_;\r
\r
caspar::frame_format_desc fmt_;\r
- tbb::concurrent_bounded_queue<frame_ptr> frame_buffer_;\r
+ tbb::concurrent_bounded_queue<gpu_frame_ptr> frame_buffer_;\r
\r
std::vector<frame_consumer_ptr> consumers_;\r
\r
\r
tbb::atomic<bool> is_running_; \r
\r
- caspar::Monitor monitor_;\r
+ gpu_frame_processor_ptr frame_processor_;\r
};\r
\r
render_device::render_device(const caspar::frame_format_desc& format_desc, unsigned int index, const std::vector<frame_consumer_ptr>& consumers) \r
frame_producer_ptr render_device::active(int exLayer) const {return impl_->active(exLayer);}\r
frame_producer_ptr render_device::background(int exLayer) const {return impl_->background(exLayer);}\r
const frame_format_desc& render_device::frame_format_desc() const{return impl_->fmt_;}\r
-caspar::Monitor& render_device::monitor(){return impl_->monitor_;}\r
}}\r
\r
frame_producer_ptr active(int exLayer) const;\r
frame_producer_ptr background(int exLayer) const;\r
\r
- const frame_format_desc& frame_format_desc() const; \r
- Monitor& monitor();\r
+ const frame_format_desc& frame_format_desc() const; \r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
#include "protocol/cii/CIIProtocolStrategy.h"\r
#include "protocol/CLK/CLKProtocolStrategy.h"\r
#include "producer/flash/FlashAxContainer.h"\r
-#include "protocol/monitor/Monitor.h"\r
\r
#include "../common/io/AsyncEventServer.h"\r
#include "../common/io/SerialPort.h"\r
unsigned int port = xml_controller.second.get<unsigned int>("port");\r
port = port != 0 ? port : 5250;\r
auto asyncserver = std::make_shared<caspar::IO::AsyncEventServer>(create_protocol(protocol), port);\r
- asyncserver->SetClientDisconnectHandler(std::tr1::bind(&Monitor::ClearListener, std::tr1::placeholders::_1));\r
asyncserver->Start();\r
async_servers_.push_back(asyncserver);\r
}\r