]> git.sesse.net Git - casparcg/commitdiff
Fixed bug in OSC implementation where the little endian byte order was used in values...
authorHelge Norberg <helge.norberg@gmail.com>
Mon, 27 May 2013 09:14:09 +0000 (11:14 +0200)
committerHelge Norberg <helge.norberg@gmail.com>
Mon, 27 May 2013 09:14:09 +0000 (11:14 +0200)
common/common.vcxproj
common/common.vcxproj.filters
common/memory/byte_order.h [new file with mode: 0644]
protocol/osc/oscpack/OscHostEndianness.h
protocol/osc/oscpack/OscOutboundPacketStream.cpp
shell/server.cpp

index c6109a50ff9bbd40356203e0830c18fe65579898..f5f9ef376a0b2b7caab55142804990cd0f380a8d 100644 (file)
     <ClInclude Include="filesystem\polling_filesystem_monitor.h" />\r
     <ClInclude Include="gl\gl_check.h" />\r
     <ClInclude Include="log\log.h" />\r
+    <ClInclude Include="memory\byte_order.h" />\r
     <ClInclude Include="memory\memclr.h" />\r
     <ClInclude Include="memory\memcpy.h" />\r
     <ClInclude Include="memory\memshfl.h" />\r
index 3eb3745663dd90e875a8b2c987bfc21ca8872313..8778c41c3ae6dcb1d8ff5aeaa3bb4211be6a508f 100644 (file)
     <ClInclude Include="utility\iterator.h">\r
       <Filter>source\utility</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="memory\byte_order.h">\r
+      <Filter>source\memory</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
diff --git a/common/memory/byte_order.h b/common/memory/byte_order.h
new file mode 100644 (file)
index 0000000..622f075
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#pragma once
+
+#include <intrin.h>
+
+namespace caspar {
+
+template<typename T>
+inline T swap_byte_order(T value)
+{
+       T result;
+
+       swap_byte_order<sizeof(T)>(
+                       reinterpret_cast<const char*>(&value),
+                       reinterpret_cast<char*>(&result));
+
+       return result;
+}
+
+template<size_t num_bytes>
+inline void swap_byte_order(const char* src, char* dest)
+{
+       for (int i = 0, j = num_bytes - 1; i != num_bytes; ++i, --j)
+               dest[i] = src[j];
+}
+
+template<>
+inline void swap_byte_order<sizeof(unsigned short)>(const char* src, char* dest)
+{
+       auto result = reinterpret_cast<unsigned short*>(dest);
+       auto value = reinterpret_cast<const unsigned short*>(src);
+       *result = _byteswap_ushort(*value);
+}
+
+template<>
+inline void swap_byte_order<sizeof(unsigned long)>(const char* src, char* dest)
+{
+       auto result = reinterpret_cast<unsigned long*>(dest);
+       auto value = reinterpret_cast<const unsigned long*>(src);
+       *result = _byteswap_ulong(*value);
+}
+
+template<>
+inline void swap_byte_order<sizeof(unsigned __int64)>(const char* src, char* dest)
+{
+       auto result = reinterpret_cast<unsigned __int64*>(dest);
+       auto value = reinterpret_cast<const unsigned __int64*>(src);
+       *result = _byteswap_uint64(*value);
+}
+
+}
index 1ff7bf5899480cbcac571df36a6f61d7fd976b77..a782411966b75b56e29a6684d40b234a5f173e2e 100644 (file)
 #ifndef OSC_HOSTENDIANNESS_H
 #define OSC_HOSTENDIANNESS_H
 
-//#define OSC_HOST_BIG_ENDIAN 1
-
-//*
-//    Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined
-//
-//    If you know a way to enhance the detection below for Linux and/or MacOSX
-//    please let me know! I've tried a few things which don't work.
-//*/
-//
-//#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN)
-//
+#define OSC_HOST_LITTLE_ENDIAN 1
+
+/*
+    Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined
+
+    If you know a way to enhance the detection below for Linux and/or MacOSX
+    please let me know! I've tried a few things which don't work.
+*/
+
+#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN)
+
 // you can define one of the above symbols from the command line
 // then you don't have to edit this file.
-//
-//#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE)
-//
+
+#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE)
+
 // assume that __WIN32__ is only defined on little endian systems
-//
-//#define OSC_HOST_LITTLE_ENDIAN 1
-//#undef OSC_HOST_BIG_ENDIAN
-//
-//#elif defined(__APPLE__)
-//
-//#if defined(__LITTLE_ENDIAN__)
-//
-//#define OSC_HOST_LITTLE_ENDIAN 1
-//#undef OSC_HOST_BIG_ENDIAN
-//
-//#elif defined(__BIG_ENDIAN__)
-//
-//#define OSC_HOST_BIG_ENDIAN 1
-//#undef OSC_HOST_LITTLE_ENDIAN
-//
-//#endif
-//
-//#endif
-//
-//#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN)
-//
-//#error please edit OSCHostEndianness.h to configure endianness
-//
-//#endif
+
+#define OSC_HOST_LITTLE_ENDIAN 1
+#undef OSC_HOST_BIG_ENDIAN
+
+#elif defined(__APPLE__)
+
+#if defined(__LITTLE_ENDIAN__)
+
+#define OSC_HOST_LITTLE_ENDIAN 1
+#undef OSC_HOST_BIG_ENDIAN
+
+#elif defined(__BIG_ENDIAN__)
+
+#define OSC_HOST_BIG_ENDIAN 1
+#undef OSC_HOST_LITTLE_ENDIAN
+
+#endif
+
+#endif
+
+#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN)
+
+#error please edit OSCHostEndianness.h to configure endianness
+
+#endif
 
 #endif /* OSC_HOSTENDIANNESS_H */
index 20bc386dda010d11a135b4a35286229e3c7a3bc9..611cf43fd67760c6a6acaa1443e02cae191bc4be 100644 (file)
@@ -36,6 +36,8 @@
 #include <stdlib.h>
 #include <assert.h>
 
+#include <common/memory/byte_order.h>
+
 #if defined(__WIN32__) || defined(WIN32)
 #include <malloc.h> // for alloca
 #endif
@@ -48,7 +50,8 @@ namespace osc{
 static void FromInt32( char *p, int32 x )
 {
 #ifdef OSC_HOST_LITTLE_ENDIAN
-    union{
+       *reinterpret_cast<int32*>(p) = caspar::swap_byte_order(x);
+    /*union{
         osc::int32 i;
         char c[4];
     } u;
@@ -58,7 +61,7 @@ static void FromInt32( char *p, int32 x )
     p[3] = u.c[0];
     p[2] = u.c[1];
     p[1] = u.c[2];
-    p[0] = u.c[3];
+    p[0] = u.c[3];*/
 #else
     *reinterpret_cast<int32*>(p) = x;
 #endif
@@ -68,7 +71,8 @@ static void FromInt32( char *p, int32 x )
 static void FromUInt32( char *p, uint32 x )
 {
 #ifdef OSC_HOST_LITTLE_ENDIAN
-    union{
+       *reinterpret_cast<uint32*>(p) = caspar::swap_byte_order(x);
+    /*union{
         osc::uint32 i;
         char c[4];
     } u;
@@ -78,7 +82,7 @@ static void FromUInt32( char *p, uint32 x )
     p[3] = u.c[0];
     p[2] = u.c[1];
     p[1] = u.c[2];
-    p[0] = u.c[3];
+    p[0] = u.c[3];*/
 #else
     *reinterpret_cast<uint32*>(p) = x;
 #endif
@@ -88,7 +92,8 @@ static void FromUInt32( char *p, uint32 x )
 static void FromInt64( char *p, int64 x )
 {
 #ifdef OSC_HOST_LITTLE_ENDIAN
-    union{
+       *reinterpret_cast<int64*>(p) = caspar::swap_byte_order(x);
+    /*union{
         osc::int64 i;
         char c[8];
     } u;
@@ -102,7 +107,7 @@ static void FromInt64( char *p, int64 x )
     p[3] = u.c[4];
     p[2] = u.c[5];
     p[1] = u.c[6];
-    p[0] = u.c[7];
+    p[0] = u.c[7];*/
 #else
     *reinterpret_cast<int64*>(p) = x;
 #endif
@@ -112,7 +117,8 @@ static void FromInt64( char *p, int64 x )
 static void FromUInt64( char *p, uint64 x )
 {
 #ifdef OSC_HOST_LITTLE_ENDIAN
-    union{
+       *reinterpret_cast<uint64*>(p) = caspar::swap_byte_order(x);
+    /*union{
         osc::uint64 i;
         char c[8];
     } u;
@@ -126,7 +132,7 @@ static void FromUInt64( char *p, uint64 x )
     p[3] = u.c[4];
     p[2] = u.c[5];
     p[1] = u.c[6];
-    p[0] = u.c[7];
+    p[0] = u.c[7];*/
 #else
     *reinterpret_cast<uint64*>(p) = x;
 #endif
@@ -463,7 +469,8 @@ OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
     *(--typeTagsCurrent_) = FLOAT_TYPE_TAG;
 
 #ifdef OSC_HOST_LITTLE_ENDIAN
-    union{
+       *reinterpret_cast<float*>(argumentCurrent_) = caspar::swap_byte_order(rhs);
+    /*union{
         float f;
         char c[4];
     } u;
@@ -473,7 +480,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
     argumentCurrent_[3] = u.c[0];
     argumentCurrent_[2] = u.c[1];
     argumentCurrent_[1] = u.c[2];
-    argumentCurrent_[0] = u.c[3];
+    argumentCurrent_[0] = u.c[3];*/
 #else
     *reinterpret_cast<float*>(argumentCurrent_) = rhs;
 #endif
@@ -551,7 +558,8 @@ OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
     *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG;
 
 #ifdef OSC_HOST_LITTLE_ENDIAN
-    union{
+       *reinterpret_cast<double*>(argumentCurrent_) = caspar::swap_byte_order(rhs);
+    /*union{
         double f;
         char c[8];
     } u;
@@ -565,7 +573,7 @@ OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
     argumentCurrent_[3] = u.c[4];
     argumentCurrent_[2] = u.c[5];
     argumentCurrent_[1] = u.c[6];
-    argumentCurrent_[0] = u.c[7];
+    argumentCurrent_[0] = u.c[7];*/
 #else
     *reinterpret_cast<double*>(argumentCurrent_) = rhs;
 #endif
index 3da068160b186b35bd6037fd103a7ba907214427..a9f74d5150569ebb839278af7fb8c28b40d1b149 100644 (file)
@@ -34,6 +34,7 @@
 #include <core/video_channel.h>\r
 #include <core/producer/stage.h>\r
 #include <core/consumer/output.h>\r
+#include <core/consumer/synchronizing/synchronizing_consumer.h>\r
 #include <core/thumbnail_generator.h>\r
 \r
 #include <modules/bluefish/bluefish.h>\r
@@ -151,34 +152,66 @@ struct server::implementation : boost::noncopyable
                        \r
                        channels_.back()->monitor_output().link_target(&monitor_subject_);\r
 \r
-                       BOOST_FOREACH(auto& xml_consumer, xml_channel.second.get_child(L"consumers"))\r
-                       {\r
-                               try\r
-                               {\r
-                                       auto name = xml_consumer.first;\r
-                                       if(name == L"screen")\r
-                                               channels_.back()->output()->add(ogl::create_consumer(xml_consumer.second));                                     \r
-                                       else if(name == L"bluefish")                                    \r
-                                               channels_.back()->output()->add(bluefish::create_consumer(xml_consumer.second));                                        \r
-                                       else if(name == L"decklink")                                    \r
-                                               channels_.back()->output()->add(decklink::create_consumer(xml_consumer.second));                                \r
-                                       else if(name == L"file")                                        \r
-                                               channels_.back()->output()->add(ffmpeg::create_consumer(xml_consumer.second));                                          \r
-                                       else if(name == L"system-audio")\r
-                                               channels_.back()->output()->add(oal::create_consumer());                \r
-                                       else if(name != L"<xmlcomment>")\r
-                                               CASPAR_LOG(warning) << "Invalid consumer: " << widen(name);     \r
-                               }\r
-                               catch(...)\r
+                       create_consumers(\r
+                               xml_channel.second.get_child(L"consumers"),\r
+                               [&] (const safe_ptr<core::frame_consumer>& consumer)\r
                                {\r
-                                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                               }\r
-                       }                                                       \r
+                                       channels_.back()->output()->add(consumer);\r
+                               });\r
+\r
+                       // Add all consumers before starting channel.\r
+                       channels_.back()->start_channel();\r
                }\r
 \r
                // Dummy diagnostics channel\r
                if(env::properties().get(L"configuration.channel-grid", false))\r
+               {\r
                        channels_.push_back(make_safe<video_channel>(channels_.size()+1, core::video_format_desc::get(core::video_format::x576p2500), ogl_, default_channel_layout_repository().get_by_name(L"STEREO")));\r
+                       channels_.back()->start_channel();\r
+               }\r
+       }\r
+\r
+       template<typename Base>\r
+       std::vector<safe_ptr<Base>> create_consumers(const boost::property_tree::wptree& pt)\r
+       {\r
+               std::vector<safe_ptr<Base>> consumers;\r
+\r
+               create_consumers(pt, [&] (const safe_ptr<core::frame_consumer>& consumer)\r
+               {\r
+                       consumers.push_back(dynamic_pointer_cast<Base>(consumer));\r
+               });\r
+\r
+               return consumers;\r
+       }\r
+\r
+       template<class Func>\r
+       void create_consumers(const boost::property_tree::wptree& pt, const Func& on_consumer)\r
+       {\r
+               BOOST_FOREACH(auto& xml_consumer, pt)\r
+               {\r
+                       try\r
+                       {\r
+                               auto name = xml_consumer.first;\r
+                               if (name == L"screen")\r
+                                       on_consumer(ogl::create_consumer(xml_consumer.second));\r
+                               else if (name == L"bluefish")                                   \r
+                                       on_consumer(bluefish::create_consumer(xml_consumer.second));                                    \r
+                               else if (name == L"decklink")                                   \r
+                                       on_consumer(decklink::create_consumer(xml_consumer.second));                            \r
+                               else if (name == L"file")                                       \r
+                                       on_consumer(ffmpeg::create_consumer(xml_consumer.second));                                              \r
+                               else if (name == L"system-audio")\r
+                                       on_consumer(oal::create_consumer());\r
+                               else if (name == L"synchronizing")\r
+                                       on_consumer(make_safe<core::synchronizing_consumer>(create_consumers<core::synchronizable_consumer>(xml_consumer.second)));\r
+                               else if (name != L"<xmlcomment>")\r
+                                       CASPAR_LOG(warning) << "Invalid consumer: " << widen(name);     \r
+                       }\r
+                       catch(...)\r
+                       {\r
+                               CASPAR_LOG_CURRENT_EXCEPTION();\r
+                       }\r
+               }\r
        }\r
                \r
        void setup_controllers(const boost::property_tree::wptree& pt)\r