]> git.sesse.net Git - casparcg/commitdiff
2.1.0: Merged trunk.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Fri, 23 Dec 2011 20:26:27 +0000 (20:26 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Fri, 23 Dec 2011 20:26:27 +0000 (20:26 +0000)
r1937
Pretty printing.
---------------------
r1936
Pretty printing.
---------------------
r1935
More pretty printing.
---------------------
r1934
More nice printing.
---------------------
r1933
Nicer printing.
---------------------
r1932
executor: Throw on begin_invoke while stopped.
---------------------
r1931

---------------------
r1930

---------------------
r1929
Catch CG command exceptions.
---------------------
r1928
Lock helper now returns value.
---------------------
r1927

---------------------
r1926
Less verbose logging.
---------------------
r1925
graph: Minor improvements. frame_producer: print init and uninit. ffmpeg/input: Use executor instead of explicit thread and cond-var.
---------------------
r1924
Fixed graph memory-leak.
---------------------
r1923
frame_muxer: Use optimal NTSC cadence.
---------------------
r1922

---------------------
r1921

---------------------
r1920

---------------------
r1919
- ogl_consumer: Fixed params for create. - Added channel-grid functionality.
---------------------
r1918
Added channel-grid.
---------------------
r1917

---------------------
r1916

---------------------
r1915

---------------------
r1914

---------------------
r1913
flash_producer: Throw file_not found in creation thread.
---------------------
r1912
Fixed CII encoding.
---------------------
r1911
Fixed wierd include.
---------------------

git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.1.0@1938 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

44 files changed:
common/common.vcxproj
common/common.vcxproj.filters
common/concurrency/executor.h
common/concurrency/lock.h [new file with mode: 0644]
common/diagnostics/graph.cpp
common/log/log.cpp
core/consumer/output.cpp
core/consumer/output.h
core/core.vcxproj
core/core.vcxproj.filters
core/mixer/gpu/ogl_device.cpp
core/mixer/gpu/ogl_device.h
core/mixer/mixer.cpp
core/producer/channel/channel_producer.cpp [new file with mode: 0644]
core/producer/channel/channel_producer.h [new file with mode: 0644]
core/producer/frame_producer.cpp
core/producer/frame_producer.h
core/video_channel.cpp
core/video_channel.h
modules/decklink/producer/decklink_producer.cpp
modules/ffmpeg/consumer/ffmpeg_consumer.cpp
modules/ffmpeg/ffmpeg.cpp
modules/ffmpeg/producer/audio/audio_decoder.cpp
modules/ffmpeg/producer/audio/audio_decoder.h
modules/ffmpeg/producer/audio/audio_resampler.cpp
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/input/input.cpp
modules/ffmpeg/producer/muxer/frame_muxer.cpp
modules/ffmpeg/producer/video/video_decoder.cpp
modules/ffmpeg/producer/video/video_decoder.h
modules/flash/producer/FlashAxContainer.cpp
modules/flash/producer/cg_producer.cpp
modules/flash/producer/flash_producer.cpp
modules/image/producer/image_producer.cpp
modules/ogl/consumer/ogl_consumer.cpp
protocol/amcp/AMCPCommandsImpl.cpp
protocol/amcp/AMCPCommandsImpl.h
protocol/amcp/AMCPProtocolStrategy.cpp
protocol/cii/CIICommandsImpl.cpp
protocol/cii/CIIProtocolStrategy.cpp
protocol/util/AsyncEventServer.cpp
protocol/util/ClientInfo.h
shell/casparcg.config
shell/server.cpp

index 737fc0e0c5e13580a06265873da22144324e6234..fa7504f95479d30d42115277393ef5073604a002 100644 (file)
     <ClInclude Include="compiler\vs\disable_silly_warnings.h" />\r
     <ClInclude Include="concurrency\com_context.h" />\r
     <ClInclude Include="concurrency\executor.h" />\r
+    <ClInclude Include="concurrency\lock.h" />\r
     <ClInclude Include="concurrency\target.h" />\r
     <ClInclude Include="diagnostics\graph.h" />\r
     <ClInclude Include="exception\exceptions.h" />\r
index e28bb9a62a96d86cff47880c5bf716489616e4f7..f2e01bce7caf5e55c1332fc69014daf97c969fba 100644 (file)
     <ClInclude Include="utility\param.h">\r
       <Filter>source\utility</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="concurrency\lock.h">\r
+      <Filter>source\concurrency</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 52bae558e2225be26f3550c5daee12c0f5e909a6..614904c5ae05046e50b81018f2088d44fd1488fb 100644 (file)
@@ -22,6 +22,7 @@
 #pragma once\r
 \r
 #include "../exception/win32_exception.h"\r
+#include "../exception/exceptions.h"\r
 #include "../utility/string.h"\r
 #include "../utility/move_on_copy.h"\r
 #include "../log/log.h"\r
@@ -164,6 +165,9 @@ public:
        template<typename Func>\r
        auto begin_invoke(Func&& func, task_priority priority = normal_priority) -> boost::unique_future<decltype(func())> // noexcept\r
        {       \r
+               if(!is_running_)\r
+                       BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("executor not running."));\r
+\r
                // Create a move on copy adaptor to avoid copying the functor into the queue, tbb::concurrent_queue does not support move semantics.\r
                auto task_adaptor = make_move_on_copy(create_task(func));\r
 \r
diff --git a/common/concurrency/lock.h b/common/concurrency/lock.h
new file mode 100644 (file)
index 0000000..73316b2
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once\r
+\r
+namespace caspar {\r
+\r
+template<typename T, typename F>\r
+auto lock(T& mutex, F&& func) -> decltype(func())\r
+{\r
+       T::scoped_lock lock(mutex);\r
+       return func();\r
+}\r
+\r
+}
\ No newline at end of file
index 238aba355244fa99e8dd0e0178fdec17e949a368..6eac2c00e198adb52ebb878e1e7a25a50345eb22 100644 (file)
@@ -26,6 +26,7 @@
 #pragma warning (disable : 4244)\r
 \r
 #include "../concurrency/executor.h"\r
+#include "../concurrency/lock.h"\r
 #include "../env.h"\r
 \r
 #include <SFML/Graphics.hpp>\r
@@ -39,8 +40,9 @@
 #include <tbb/atomic.h>\r
 #include <tbb/spin_mutex.h>\r
 \r
-#include <numeric>\r
 #include <array>\r
+#include <numeric>\r
+#include <tuple>\r
 \r
 namespace caspar { namespace diagnostics {\r
                \r
@@ -74,7 +76,7 @@ class context : public drawable
 {      \r
        std::unique_ptr<sf::RenderWindow> window_;\r
        \r
-       std::list<std::shared_ptr<drawable>> drawables_;\r
+       std::list<std::weak_ptr<drawable>> drawables_;\r
                \r
        executor executor_;\r
 public:                                        \r
@@ -110,7 +112,7 @@ private:
                {\r
                        if(!window_)\r
                        {\r
-                               window_.reset(new sf::RenderWindow(sf::VideoMode(600, 1000), "CasparCG Diagnostics"));\r
+                               window_.reset(new sf::RenderWindow(sf::VideoMode(750, 750), "CasparCG Diagnostics"));\r
                                window_->SetPosition(0, 0);\r
                                window_->SetActive();\r
                                glEnable(GL_BLEND);\r
@@ -141,7 +143,7 @@ private:
                glClear(GL_COLOR_BUFFER_BIT);\r
                window_->Draw(*this);\r
                window_->Display();\r
-               boost::this_thread::sleep(boost::posix_time::milliseconds(20));\r
+               boost::this_thread::sleep(boost::posix_time::milliseconds(10));\r
                executor_.begin_invoke([this]{tick();});\r
        }\r
 \r
@@ -154,8 +156,8 @@ private:
                int n = 0;\r
                for(auto it = drawables_.begin(); it != drawables_.end(); ++n)\r
                {\r
-                       auto& drawable = *it;\r
-                       if(!drawable.unique())\r
+                       auto drawable = it->lock();\r
+                       if(drawable)\r
                        {\r
                                drawable->SetScale(static_cast<float>(window_->GetWidth()), static_cast<float>(target_dy*window_->GetHeight()));\r
                                float target_y = std::max(last_y, static_cast<float>(n * window_->GetHeight())*target_dy);\r
@@ -170,8 +172,15 @@ private:
        \r
        void do_register_drawable(const std::shared_ptr<drawable>& drawable)\r
        {\r
-               if(std::find(drawables_.begin(), drawables_.end(), drawable) == drawables_.end())\r
-                       drawables_.push_back(drawable);\r
+               drawables_.push_back(drawable);\r
+               auto it = drawables_.begin();\r
+               while(it != drawables_.end())\r
+               {\r
+                       if(it->lock())\r
+                               ++it;\r
+                       else    \r
+                               it = drawables_.erase(it);                      \r
+               }\r
        }\r
        \r
        static context& get_instance()\r
@@ -183,23 +192,23 @@ private:
 \r
 class line : public drawable\r
 {\r
-       boost::circular_buffer<std::pair<double, bool>> line_data_;\r
+       boost::circular_buffer<std::pair<float, bool>> line_data_;\r
 \r
-       tbb::atomic<double>     tick_data_;\r
+       tbb::atomic<float>      tick_data_;\r
        tbb::atomic<bool>       tick_tag_;\r
        tbb::atomic<int>        color_;\r
 public:\r
-       line(size_t res = 600)\r
+       line(size_t res = 1200)\r
                : line_data_(res)\r
        {\r
-               tick_data_      = 0;\r
+               tick_data_      = -1.0f;\r
                color_          = 0xFFFFFFFF;\r
                tick_tag_       = false;\r
 \r
                line_data_.push_back(std::make_pair(-1.0f, false));\r
        }\r
        \r
-       void set_value(double value)\r
+       void set_value(float value)\r
        {\r
                tick_data_ = value;\r
        }\r
@@ -257,15 +266,18 @@ struct graph::impl : public drawable
 \r
        tbb::spin_mutex mutex_;\r
        std::wstring text_;\r
-               \r
+\r
        impl()\r
        {\r
        }\r
-\r
+               \r
        void set_text(const std::wstring& value)\r
        {\r
-               tbb::spin_mutex::scoped_lock lock(mutex_);\r
-               text_ = value;\r
+               auto temp = value;\r
+               lock(mutex_, [&]\r
+               {\r
+                       text_ = std::move(temp);\r
+               });\r
        }\r
 \r
        void set_value(const std::string& name, double value)\r
@@ -331,7 +343,7 @@ private:
                \r
                        glEnable(GL_LINE_STIPPLE);\r
                        glLineStipple(3, 0xAAAA);\r
-                       glColor4f(0.8f, 0.8f, 0.8f, 1.0f);      \r
+                       glColor4f(1.0f, 1.0f, 1.9f, 0.5f);      \r
                        glBegin(GL_LINE_STRIP);         \r
                                glVertex3f(0.0f, (1.0f-0.5f) * 0.8f + 0.1f, 0.0f);              \r
                                glVertex3f(1.0f, (1.0f-0.5f) * 0.8f + 0.1f, 0.0f);      \r
index 645b6e5b5ff6d36da0e57e0713aa2faebfadc6fd..9dd218384ac5ac22254bbfb5d08c974a92fb0a5b 100644 (file)
@@ -85,9 +85,16 @@ void my_formatter(std::wostream& strm, boost::log::basic_record<wchar_t> const&
     if(boost::log::extract<boost::log::attributes::current_thread_id::held_type>(L"ThreadID", rec.attribute_values(), lambda::var(thread_id) = lambda::_1))\r
         strm << L"[" << thread_id << L"] ";\r
 \r
+\r
     severity_level severity;\r
     if(boost::log::extract<severity_level>(boost::log::sources::aux::severity_attribute_name<wchar_t>::get(), rec.attribute_values(), lambda::var(severity) = lambda::_1))\r
+       {\r
+               std::stringstream ss;\r
+               ss << severity;\r
         strm << L"[" << severity << L"] ";\r
+               for(int n = 0; n < 7-static_cast<int>(ss.str().size()); ++n)\r
+                       strm << L" ";\r
+       }\r
 \r
     strm << rec.message();\r
 }\r
index 1a4b3c4b13eb68dec4ef81bdd0396c8e1c00f673..d80ccbdb4c1d9ebd8686c7cb29ddd7501987760b 100644 (file)
@@ -68,7 +68,7 @@ public:
                , format_desc_(format_desc)\r
                , executor_(L"output")\r
        {\r
-               graph_->set_color("consume-time", diagnostics::color(1.0f, 0.4f, 0.0f));\r
+               graph_->set_color("consume-time", diagnostics::color(1.0f, 0.4f, 0.0f, 0.8));\r
        }       \r
        \r
        void add(int index, safe_ptr<frame_consumer> consumer)\r
@@ -254,6 +254,14 @@ public:
                        return info;\r
                }, high_priority));\r
        }\r
+\r
+       bool empty()\r
+       {\r
+               return executor_.invoke([this]\r
+               {\r
+                       return consumers_.empty();\r
+               });\r
+       }\r
 };\r
 \r
 output::output(const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc, int channel_index) : impl_(new impl(graph, format_desc, channel_index)){}\r
@@ -264,4 +272,5 @@ void output::remove(const safe_ptr<frame_consumer>& consumer){impl_->remove(cons
 void output::send(const std::pair<safe_ptr<read_frame>, std::shared_ptr<void>>& frame) {impl_->send(frame); }\r
 void output::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
 boost::unique_future<boost::property_tree::wptree> output::info() const{return impl_->info();}\r
+bool output::empty() const{return impl_->empty();}\r
 }}
\ No newline at end of file
index 447a9375c6dfd11310203026b508d1a5180e1506..2019178af9a9650cbc0b99bfde160cabf65828b9 100644 (file)
@@ -53,6 +53,8 @@ public:
        void set_video_format_desc(const video_format_desc& format_desc);\r
 \r
        boost::unique_future<boost::property_tree::wptree> info() const;\r
+\r
+       bool empty() const;\r
 private:\r
        struct impl;\r
        safe_ptr<impl> impl_;\r
index bd4fa994732e6c6467f3c63a08a253725d69a66b..78315559873f6805fc1d28ac6c46e867bc225fe5 100644 (file)
@@ -44,8 +44,8 @@
     <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)tmp\$(Configuration)\</IntDir>\r
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)tmp\$(Configuration)\</IntDir>\r
-    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\;..\dependencies64\boost\;..\dependencies64\tbb\include\;..\dependencies64\sfml\include\;..\dependencies64\glew\include\;$(IncludePath)</IncludePath>\r
-    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\;..\dependencies64\boost\;..\dependencies64\tbb\include\;..\dependencies64\sfml\include\;..\dependencies64\glew\include\;$(IncludePath)</IncludePath>\r
+    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\;..\dependencies64\boost\;..\dependencies64\tbb\include\;..\dependencies64\sfml\include\;..\dependencies64\glew\include\;..\dependencies64\asmlib\;$(IncludePath)</IncludePath>\r
+    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\;..\dependencies64\boost\;..\dependencies64\tbb\include\;..\dependencies64\sfml\include\;..\dependencies64\glew\include\;..\dependencies64\asmlib\;$(IncludePath)</IncludePath>\r
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectDir)bin\$(Configuration)\</OutDir>\r
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectDir)bin\$(Configuration)\</OutDir>\r
     <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectName)</TargetName>\r
     <ClInclude Include="mixer\image\blend_modes.h" />\r
     <ClInclude Include="mixer\image\shader\blending_glsl.h" />\r
     <ClInclude Include="mixer\image\shader\image_shader.h" />\r
+    <ClInclude Include="producer\channel\channel_producer.h" />\r
     <ClInclude Include="producer\playlist\playlist_producer.h" />\r
     <ClInclude Include="video_channel.h" />\r
     <ClInclude Include="consumer\output.h" />\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../../stdafx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../../stdafx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
+    <ClCompile Include="producer\channel\channel_producer.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
     <ClCompile Include="producer\playlist\playlist_producer.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../stdafx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../stdafx.h</PrecompiledHeaderFile>\r
index a14d4f50caffaa0f6e020868be30800f849bed46..d6afc6710b8ff5ab584cf46f0eabe1d996ab5656 100644 (file)
@@ -40,7 +40,7 @@
     <Filter Include="source\mixer\image\shader">\r
       <UniqueIdentifier>{e0a140f8-e217-465c-a934-163b7ea786be}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="source\producer\reroute">\r
+    <Filter Include="source\producer\channel">\r
       <UniqueIdentifier>{e5def302-a2b5-4e1f-8565-d6ef3927b31f}</UniqueIdentifier>\r
     </Filter>\r
   </ItemGroup>\r
     <ClInclude Include="mixer\image\shader\blending_glsl.h">\r
       <Filter>source\mixer\image\shader</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="producer\channel\channel_producer.h">\r
+      <Filter>source\producer\channel</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="producer\transition\transition_producer.cpp">\r
     <ClCompile Include="mixer\image\blend_modes.cpp">\r
       <Filter>source\mixer\image</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="producer\channel\channel_producer.cpp">\r
+      <Filter>source\producer\channel</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 12248a0a261a71d47ca9c4eb279038be2055262a..29d627ce042803ab27824f716b769293a77496e2 100644 (file)
@@ -66,9 +66,11 @@ ogl_device::ogl_device()
        \r
                CASPAR_LOG(info) << L"Successfully initialized GLEW.";\r
 \r
-               GL(glGenFramebuffers(1, &fbo_));                \r
-               GL(glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo_));\r
-        //GL(glDisable(GL_MULTISAMPLE_ARB));\r
+               glGenFramebuffers(1, &fbo_);    \r
+\r
+               CASPAR_LOG(debug) << "Created framebuffer.";\r
+\r
+               glBindFramebuffer(GL_FRAMEBUFFER, fbo_);\r
 \r
                CASPAR_LOG(info) << L"Successfully initialized OpenGL Device.";\r
        });\r
@@ -82,7 +84,7 @@ ogl_device::~ogl_device()
                        pool.clear();\r
                BOOST_FOREACH(auto& pool, host_pools_)\r
                        pool.clear();\r
-               glDeleteFramebuffersEXT(1, &fbo_);\r
+               glDeleteFramebuffers(1, &fbo_);\r
        });\r
 }\r
 \r
@@ -350,10 +352,10 @@ void ogl_device::clear(device_buffer& texture)
 \r
 void ogl_device::read_buffer(device_buffer&)\r
 {\r
-       if(read_buffer_ != GL_COLOR_ATTACHMENT0_EXT)\r
+       if(read_buffer_ != GL_COLOR_ATTACHMENT0)\r
        {\r
-               GL(glReadBuffer(GL_COLOR_ATTACHMENT0_EXT));\r
-               read_buffer_ = GL_COLOR_ATTACHMENT0_EXT;\r
+               GL(glReadBuffer(GL_COLOR_ATTACHMENT0));\r
+               read_buffer_ = GL_COLOR_ATTACHMENT0;\r
        }\r
 }\r
 \r
index e23e607ba6240f2e6e4b9e6838d8415b21c5e03f..98cf080d17bf9e6ec7e3162df3bd569c18e840d5 100644 (file)
 #include <common/concurrency/executor.h>\r
 #include <common/memory/safe_ptr.h>\r
 \r
+#include <gl/glew.h>\r
+\r
+#include <SFML/Window/Context.hpp>\r
+\r
 #include <tbb/concurrent_unordered_map.h>\r
 #include <tbb/concurrent_queue.h>\r
 \r
 #include <array>\r
 #include <unordered_map>\r
 \r
-#include <gl/glew.h>\r
-\r
-#include "../../dependencies\SFML-1.6\include\SFML/Window/Context.hpp"\r
-\r
 namespace caspar { namespace core {\r
 \r
 class shader;\r
index 41e94b835154dada7b460d54343e6137f564c097..fbc2a7cf295108da7c03461df5bcd3988a2d9e40 100644 (file)
@@ -84,7 +84,7 @@ public:
                , audio_mixer_(graph_)\r
                , executor_(L"mixer")\r
        {                       \r
-               graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f));\r
+               graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8));\r
        }\r
        \r
        void send(const std::pair<std::map<int, safe_ptr<core::basic_frame>>, std::shared_ptr<void>>& packet)\r
diff --git a/core/producer/channel/channel_producer.cpp b/core/producer/channel/channel_producer.cpp
new file mode 100644 (file)
index 0000000..883a8ac
--- /dev/null
@@ -0,0 +1,218 @@
+/*\r
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG (www.casparcg.com).\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+* Author: Robert Nagy, ronag89@gmail.com\r
+*/\r
+\r
+#include "../../stdafx.h"\r
+\r
+#include "channel_producer.h"\r
+\r
+#include "../../consumer/frame_consumer.h"\r
+#include "../../consumer/output.h"\r
+#include "../../video_channel.h"\r
+\r
+#include "../frame/basic_frame.h"\r
+#include "../frame/frame_factory.h"\r
+#include "../frame/pixel_format.h"\r
+#include "../../mixer/write_frame.h"\r
+#include "../../mixer/read_frame.h"\r
+\r
+#include <common/exception/exceptions.h>\r
+\r
+#include <asmlib.h>\r
+\r
+#include <tbb/concurrent_queue.h>\r
+\r
+namespace caspar { namespace core {\r
+\r
+class channel_consumer : public frame_consumer\r
+{      \r
+       tbb::concurrent_bounded_queue<std::shared_ptr<read_frame>>      frame_buffer_;\r
+       core::video_format_desc                                                                         format_desc_;\r
+       int                                                                                                                     channel_index_;\r
+       tbb::atomic<bool>                                                                                       is_running_;\r
+\r
+public:\r
+       channel_consumer() \r
+       {\r
+               is_running_ = true;\r
+               frame_buffer_.set_capacity(3);\r
+       }\r
+\r
+       ~channel_consumer()\r
+       {\r
+               stop();\r
+       }\r
+\r
+       // frame_consumer\r
+\r
+       virtual bool send(const safe_ptr<read_frame>& frame) override\r
+       {\r
+               frame_buffer_.try_push(frame);\r
+               return is_running_;\r
+       }\r
+\r
+       virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
+       {\r
+               format_desc_    = format_desc;\r
+               channel_index_  = channel_index;\r
+       }\r
+\r
+       virtual std::wstring print() const override\r
+       {\r
+               return L"[channel-consumer|" + boost::lexical_cast<std::wstring>(channel_index_) + L"]";\r
+       }\r
+\r
+       virtual boost::property_tree::wptree info() const override\r
+       {\r
+               boost::property_tree::wptree info;\r
+               info.add(L"type", L"channel-consumer");\r
+               info.add(L"channel-index", channel_index_);\r
+               return info;\r
+       }\r
+       \r
+       virtual bool has_synchronization_clock() const override\r
+       {\r
+               return false;\r
+       }\r
+\r
+       virtual int buffer_depth() const override\r
+       {\r
+               return 1;\r
+       }\r
+\r
+       virtual int index() const override\r
+       {\r
+               return 78500 + channel_index_;\r
+       }\r
+\r
+       // channel_consumer\r
+\r
+       void stop()\r
+       {\r
+               is_running_ = false;\r
+               frame_buffer_.try_push(make_safe<read_frame>());\r
+       }\r
+       \r
+       const core::video_format_desc& get_video_format_desc()\r
+       {\r
+               return format_desc_;\r
+       }\r
+\r
+       std::shared_ptr<read_frame> receive()\r
+       {\r
+               if(!is_running_)\r
+                       return make_safe<read_frame>();\r
+               std::shared_ptr<read_frame> frame;\r
+               frame_buffer_.try_pop(frame);\r
+               return frame;\r
+       }\r
+};\r
+       \r
+class channel_producer : public frame_producer\r
+{\r
+       const safe_ptr<frame_factory>           frame_factory_;\r
+       const safe_ptr<channel_consumer>        consumer_;\r
+\r
+       std::queue<safe_ptr<basic_frame>>       frame_buffer_;\r
+       safe_ptr<basic_frame>                           last_frame_;\r
+       uint64_t                                                        frame_number_;\r
+\r
+public:\r
+       explicit channel_producer(const safe_ptr<frame_factory>& frame_factory, const safe_ptr<video_channel>& channel) \r
+               : frame_factory_(frame_factory)\r
+               , consumer_(make_safe<channel_consumer>())\r
+               , last_frame_(basic_frame::empty())\r
+               , frame_number_(0)\r
+       {\r
+               channel->output()->add(consumer_);\r
+               CASPAR_LOG(info) << print() << L" Initialized";\r
+       }\r
+\r
+       ~channel_producer()\r
+       {\r
+               consumer_->stop();\r
+               CASPAR_LOG(info) << print() << L" Uninitialized";\r
+       }\r
+\r
+       // frame_producer\r
+                       \r
+       virtual safe_ptr<basic_frame> receive(int) override\r
+       {\r
+               auto format_desc = consumer_->get_video_format_desc();\r
+\r
+               if(frame_buffer_.size() > 1)\r
+               {\r
+                       auto frame = frame_buffer_.front();\r
+                       frame_buffer_.pop();\r
+                       return last_frame_ = frame;\r
+               }\r
+               \r
+               auto read_frame = consumer_->receive();\r
+               if(!read_frame || read_frame->image_data().empty())\r
+                       return basic_frame::late();             \r
+\r
+               frame_number_++;\r
+               \r
+               core::pixel_format_desc desc;\r
+               bool double_speed       = std::abs(frame_factory_->get_video_format_desc().fps / 2.0 - format_desc.fps) < 0.01;         \r
+               bool half_speed         = std::abs(format_desc.fps / 2.0 - frame_factory_->get_video_format_desc().fps) < 0.01;\r
+\r
+               if(half_speed && frame_number_ % 2 == 0) // Skip frame\r
+                       return receive(0);\r
+\r
+               desc.pix_fmt = core::pixel_format::bgra;\r
+               desc.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));\r
+               auto frame = frame_factory_->create_frame(this, desc);\r
+\r
+               A_memcpy(frame->image_data().begin(), read_frame->image_data().begin(), read_frame->image_data().size());\r
+               frame->commit();\r
+\r
+               frame_buffer_.push(frame);      \r
+               \r
+               if(double_speed)        \r
+                       frame_buffer_.push(frame);\r
+\r
+               return receive(0);\r
+       }       \r
+\r
+       virtual safe_ptr<basic_frame> last_frame() const override\r
+       {\r
+               return last_frame_; \r
+       }       \r
+\r
+       virtual std::wstring print() const override\r
+       {\r
+               return L"channel[]";\r
+       }\r
+\r
+       virtual boost::property_tree::wptree info() const override\r
+       {\r
+               boost::property_tree::wptree info;\r
+               info.add(L"type", L"channel-producer");\r
+               return info;\r
+       }\r
+};\r
+\r
+safe_ptr<frame_producer> create_channel_producer(const safe_ptr<core::frame_factory>& frame_factory, const safe_ptr<video_channel>& channel)\r
+{\r
+       return make_safe<channel_producer>(frame_factory, channel);\r
+}\r
+\r
+}}
\ No newline at end of file
diff --git a/core/producer/channel/channel_producer.h b/core/producer/channel/channel_producer.h
new file mode 100644 (file)
index 0000000..6d39ce6
--- /dev/null
@@ -0,0 +1,36 @@
+/*\r
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG (www.casparcg.com).\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+* Author: Robert Nagy, ronag89@gmail.com\r
+*/\r
+\r
+#pragma once\r
+\r
+#include "../frame_producer.h"\r
+\r
+#include <string>\r
+#include <vector>\r
+\r
+namespace caspar { namespace core {\r
+\r
+class video_channel;\r
+struct frame_factory;\r
+\r
+safe_ptr<frame_producer> create_channel_producer(const safe_ptr<core::frame_factory>& frame_factory, const safe_ptr<video_channel>& channel);\r
+\r
+}}\r
index b549007321c7c8d5a8285bf58b9447b68826dfa0..c48ef43e7c9e4cc46f1c5bcf489631c333eaf1f4 100644 (file)
@@ -81,7 +81,6 @@ public:
                                catch(...){}\r
                                                                \r
                                producer2.reset();\r
-                               CASPAR_LOG(debug) << str << L" Destroyed.";\r
                                pool->push(destroyer);\r
                        }); \r
                }\r
@@ -98,7 +97,7 @@ public:
                }\r
        }\r
 \r
-       virtual safe_ptr<basic_frame>                                                           receive(int flags) override                                                                                             {return (*producer_)->receive(flags);}\r
+       virtual safe_ptr<basic_frame>                                                           receive(int hints) override                                                                                             {return (*producer_)->receive(hints);}\r
        virtual safe_ptr<basic_frame>                                                           last_frame() const override                                                                                             {return (*producer_)->last_frame();}\r
        virtual std::wstring                                                                            print() const override                                                                                                  {return (*producer_)->print();}\r
        virtual boost::property_tree::wptree                                            info() const override                                                                                                   {return (*producer_)->info();}\r
@@ -108,11 +107,68 @@ public:
        virtual uint32_t                                                                                        nb_frames() const override                                                                                              {return (*producer_)->nb_frames();}\r
 };\r
 \r
-safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer>&& producer)\r
+safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer> producer)\r
 {\r
        return make_safe<destroy_producer_proxy>(std::move(producer));\r
 }\r
 \r
+class print_producer_proxy : public frame_producer\r
+{      \r
+       std::shared_ptr<frame_producer> producer_;\r
+public:\r
+       print_producer_proxy(safe_ptr<frame_producer>&& producer) \r
+               : producer_(std::move(producer))\r
+       {\r
+               CASPAR_LOG(info) << producer_->print() << L" Initialized";\r
+       }\r
+\r
+       ~print_producer_proxy()\r
+       {               \r
+               auto str = producer_->print();\r
+               producer_.reset();\r
+               CASPAR_LOG(info) << str << L" Uninitialized";\r
+       }\r
+\r
+       virtual safe_ptr<basic_frame>                                                           receive(int hints) override                                                                                             {return (producer_)->receive(hints);}\r
+       virtual safe_ptr<basic_frame>                                                           last_frame() const override                                                                                             {return (producer_)->last_frame();}\r
+       virtual std::wstring                                                                            print() const override                                                                                                  {return (producer_)->print();}\r
+       virtual boost::property_tree::wptree                                            info() const override                                                                                                   {return (producer_)->info();}\r
+       virtual boost::unique_future<std::wstring>                                      call(const std::wstring& str) override                                                                  {return (producer_)->call(str);}\r
+       virtual safe_ptr<frame_producer>                                                        get_following_producer() const override                                                                 {return (producer_)->get_following_producer();}\r
+       virtual void                                                                                            set_leading_producer(const safe_ptr<frame_producer>& producer) override {(producer_)->set_leading_producer(producer);}\r
+       virtual uint32_t                                                                                        nb_frames() const override                                                                                              {return (producer_)->nb_frames();}\r
+};\r
+\r
+safe_ptr<core::frame_producer> create_producer_print_proxy(safe_ptr<core::frame_producer> producer)\r
+{\r
+       return make_safe<print_producer_proxy>(std::move(producer));\r
+}\r
+\r
+class last_frame_producer : public frame_producer\r
+{\r
+       const std::wstring                      print_;\r
+       const safe_ptr<basic_frame>     frame_;\r
+       const uint32_t                          nb_frames_;\r
+public:\r
+       last_frame_producer(const safe_ptr<frame_producer>& producer) \r
+               : print_(producer->print())\r
+               , frame_(producer->last_frame() != basic_frame::eof() ? producer->last_frame() : basic_frame::empty())\r
+               , nb_frames_(producer->nb_frames())\r
+       {\r
+       }\r
+       \r
+       virtual safe_ptr<basic_frame> receive(int){return frame_;}\r
+       virtual safe_ptr<core::basic_frame> last_frame() const{return frame_;}\r
+       virtual std::wstring print() const{return L"dummy[" + print_ + L"]";}\r
+       virtual uint32_t nb_frames() const {return nb_frames_;} \r
+       virtual boost::property_tree::wptree info() const override\r
+       {\r
+               boost::property_tree::wptree info;\r
+               info.add(L"type", L"last-frame-producer");\r
+               return info;\r
+       }\r
+};\r
+\r
 struct empty_frame_producer : public frame_producer\r
 {\r
        virtual safe_ptr<basic_frame> receive(int){return basic_frame::empty();}\r
@@ -135,18 +191,24 @@ const safe_ptr<frame_producer>& frame_producer::empty() // nothrow
        return producer;\r
 }      \r
 \r
-safe_ptr<basic_frame> receive_and_follow(safe_ptr<frame_producer>& producer, int flags)\r
+safe_ptr<basic_frame> receive_and_follow(safe_ptr<frame_producer>& producer, int hints)\r
 {      \r
-       auto frame = producer->receive(flags);\r
-       if(frame != basic_frame::eof())\r
-               return frame;\r
-               \r
-       CASPAR_LOG(info) << producer->print() << " End Of File.";\r
-       auto following = producer->get_following_producer();\r
-       following->set_leading_producer(producer);\r
-       producer = std::move(following);\r
-\r
-       return receive_and_follow(producer, flags);     \r
+       auto frame = producer->receive(hints);\r
+       if(frame == basic_frame::eof())\r
+       {\r
+               CASPAR_LOG(info) << producer->print() << " End Of File.";\r
+               auto following = producer->get_following_producer();\r
+               if(following != frame_producer::empty())\r
+               {\r
+                       following->set_leading_producer(producer);\r
+                       producer = std::move(following);\r
+               }\r
+               else\r
+                       producer = make_safe<last_frame_producer>(producer);\r
+\r
+               return receive_and_follow(producer, hints);\r
+       }\r
+       return frame;\r
 }\r
 \r
 void register_producer_factory(const producer_factory_t& factory)\r
@@ -178,6 +240,9 @@ safe_ptr<core::frame_producer> do_create_producer(const safe_ptr<frame_factory>&
        \r
        if(producer == frame_producer::empty())\r
                producer = create_playlist_producer(my_frame_factory, params);\r
+       \r
+       if(producer != frame_producer::empty())\r
+               producer = create_producer_print_proxy(producer);\r
 \r
        return producer;\r
 }\r
@@ -212,7 +277,7 @@ safe_ptr<core::frame_producer> create_producer(const safe_ptr<frame_factory>& my
                std::wstring str;\r
                BOOST_FOREACH(auto& param, params)\r
                        str += param + L" ";\r
-               BOOST_THROW_EXCEPTION(file_not_found() << msg_info("No match found for supplied commands. Check syntax.") << warg_value_info(str));\r
+               BOOST_THROW_EXCEPTION(file_not_found() << msg_info("No match found for supplied commands. Check syntax.") << arg_value_info(u8(str)));\r
        }\r
 \r
        return producer;\r
index a87e6537b8edad881f5d61da6346f9f4de24c95b..9cc59f0e0edf9d8901250576069149659d69c875 100644 (file)
@@ -82,6 +82,6 @@ typedef std::function<safe_ptr<core::frame_producer>(const safe_ptr<frame_factor
 void register_producer_factory(const producer_factory_t& factory); // Not thread-safe.\r
 safe_ptr<core::frame_producer> create_producer(const safe_ptr<frame_factory>&, const std::vector<std::wstring>& params);\r
 safe_ptr<core::frame_producer> create_producer(const safe_ptr<frame_factory>&, const std::wstring& params);\r
-safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer>&& producer);\r
+safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer> producer);\r
 \r
 }}\r
index 45d8339a7f0c69a0790fc8975c28e1a729440235..6d83d3e76dcc4f5148f816c676437f9176fe712a 100644 (file)
@@ -42,14 +42,14 @@ namespace caspar { namespace core {
 \r
 struct video_channel::impl sealed : public frame_factory\r
 {\r
-       const int                                               index_;\r
-       video_format_desc                               format_desc_;\r
-       const safe_ptr<ogl_device>              ogl_;\r
-       safe_ptr<diagnostics::graph>    graph_;\r
-\r
-       safe_ptr<caspar::core::output>  output_;\r
-       safe_ptr<caspar::core::mixer>   mixer_;\r
-       safe_ptr<caspar::core::stage>   stage_;\r
+       const int                                                               index_;\r
+       video_format_desc                                               format_desc_;\r
+       const safe_ptr<ogl_device>                              ogl_;\r
+       const safe_ptr<diagnostics::graph>              graph_;\r
+\r
+       const safe_ptr<caspar::core::output>    output_;\r
+       const safe_ptr<caspar::core::mixer>             mixer_;\r
+       const safe_ptr<caspar::core::stage>             stage_;\r
        \r
 public:\r
        impl(int index, const video_format_desc& format_desc, const safe_ptr<ogl_device>& ogl)  \r
@@ -136,5 +136,6 @@ safe_ptr<output> video_channel::output() { return impl_->output_;}
 video_format_desc video_channel::get_video_format_desc() const{return impl_->format_desc_;}\r
 void video_channel::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
 boost::property_tree::wptree video_channel::info() const{return impl_->info();}\r
+int video_channel::index() const {return impl_->index_;}\r
 \r
 }}
\ No newline at end of file
index 2f31728f0dfb95f626686c12d90a5dc1d5c547ba..474f7198f5cac0a82ff9871d199a9d3a3d158494 100644 (file)
@@ -51,6 +51,8 @@ public:
        \r
        boost::property_tree::wptree info() const;\r
 \r
+       int index() const;\r
+\r
 private:\r
        struct impl;\r
        safe_ptr<impl> impl_;\r
index a7576303c5a9288f646b379af19176e31ff73f1d..717bf31b87095ec727cf1b71f087c4eb4d6722bc 100644 (file)
@@ -146,8 +146,6 @@ public:
                        BOOST_THROW_EXCEPTION(caspar_exception() \r
                                                                        << wmsg_info(print() + L" Failed to start input stream.")\r
                                                                        << boost::errinfo_api_function("StartStreams"));\r
-               \r
-               CASPAR_LOG(info) << print() << L" Successfully Initialized.";\r
        }\r
 \r
        ~decklink_producer()\r
@@ -279,14 +277,7 @@ public:
        {\r
                context_.reset([&]{return new decklink_producer(format_desc, device_index, frame_factory, filter_str);}); \r
        }\r
-\r
-       ~decklink_producer_proxy()\r
-       {\r
-               auto str = print();\r
-               context_.reset();\r
-               CASPAR_LOG(info) << str << L" Successfully Uninitialized.";     \r
-       }\r
-\r
+       \r
        // frame_producer\r
                                \r
        virtual safe_ptr<core::basic_frame> receive(int flags) override\r
index a9d8f43babace3ac0d9b34ca7c08d7b387b3d690..ba0f42283e6845c63ecc1e5cdbb10ab1b1a0c9f8 100644 (file)
@@ -225,6 +225,10 @@ public:
 \r
                        THROW_ON_ERROR2(av_set_options_string(c->priv_data, options.c_str(), "=", ":"), "[ffmpeg_consumer]");\r
                }\r
+               else if(c->codec_id == CODEC_ID_QTRLE)\r
+               {\r
+                       c->pix_fmt = PIX_FMT_ARGB;\r
+               }\r
                else\r
                {\r
                        THROW_ON_ERROR2(av_set_options_string(c->priv_data, options.c_str(), "=", ":"), "[ffmpeg_consumer]");\r
index d8d1e61a4b8a3abc198e3c74a18ed0b0f8d12067..6c8dd5a825ea78d17488f052bf4fe1d2b6305ad9 100644 (file)
@@ -135,6 +135,10 @@ void log_callback(void* ptr, int level, const char* fmt, va_list vl)
     //}\r
     strcpy(prev, line);\r
     sanitize((uint8_t*)line);\r
+\r
+       auto len = strlen(line);\r
+       if(len > 0)\r
+               line[len-1] = 0;\r
        \r
        if(level == AV_LOG_DEBUG)\r
                CASPAR_LOG(debug) << L"[ffmpeg] " << line;\r
index 3fbcb42c3fbdb78b02dad3a6c7f6bf28d5e4f67d..d2f040a368d85117cde3b1dcd667157a559910f5 100644 (file)
@@ -75,8 +75,7 @@ public:
                , buffer1_(AVCODEC_MAX_AUDIO_FRAME_SIZE*2)\r
                , nb_frames_(0)//context->streams[index_]->nb_frames)\r
        {               \r
-               file_frame_number_ = 0;\r
-               CASPAR_LOG(debug) << "[audio_decoder] " << context->streams[index_]->codec->codec->long_name;      \r
+               file_frame_number_ = 0;   \r
        }\r
 \r
        void push(const std::shared_ptr<AVPacket>& packet)\r
@@ -143,6 +142,11 @@ public:
        {\r
                return 0;//std::max<int64_t>(nb_frames_, file_frame_number_);\r
        }\r
+\r
+       std::wstring print() const\r
+       {               \r
+               return L"[audio-decoder] " + u16(codec_context_->codec->long_name);\r
+       }\r
 };\r
 \r
 audio_decoder::audio_decoder(const safe_ptr<AVFormatContext>& context, const core::video_format_desc& format_desc) : impl_(new impl(context, format_desc)){}\r
@@ -151,5 +155,6 @@ bool audio_decoder::ready() const{return impl_->ready();}
 std::shared_ptr<core::audio_buffer> audio_decoder::poll(){return impl_->poll();}\r
 uint32_t audio_decoder::nb_frames() const{return impl_->nb_frames();}\r
 uint32_t audio_decoder::file_frame_number() const{return impl_->file_frame_number_;}\r
+std::wstring audio_decoder::print() const{return impl_->print();}\r
 \r
 }}
\ No newline at end of file
index 102e20c9dae23fba86a82452fb322e7f96d84f49..1396f663fcc7bbe79996887c39490c7f7cf11e95 100644 (file)
@@ -52,6 +52,8 @@ public:
        uint32_t nb_frames() const;\r
        \r
        uint32_t file_frame_number() const;\r
+\r
+       std::wstring print() const;\r
 private:\r
        struct impl;\r
        safe_ptr<impl> impl_;\r
index f60234b99c1e3c3cb6f09c6115e5806654e97e22..0a44c8769b083f84ab8b71a1b77b1f3a8d9038f9 100644 (file)
@@ -70,10 +70,13 @@ struct audio_resampler::impl
 \r
                        buffer2_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2);\r
 \r
-                       CASPAR_LOG(warning) << L"Resampling." <<\r
-                                                                       L" sample_rate:" << input_sample_rate  <<\r
-                                                                       L" audio_channels:" << input_channels  <<\r
-                                                                       L" sample_fmt:" << input_sample_format;\r
+                       char sample_fmt_string[200];\r
+                       av_get_sample_fmt_string(sample_fmt_string, 200, input_sample_format);\r
+\r
+                       CASPAR_LOG(warning) << L"[audio-resampler]"             \r
+                                                               << L" sample-rate: "    << input_sample_rate \r
+                                                               << L" channels: "               << input_channels \r
+                                                               << L" sample-fmt: "             << u16(sample_fmt_string);\r
 \r
                        if(resampler)\r
                                resampler_.reset(resampler, audio_resample_close);\r
index 8ce8a9f4217cc75293cfc7d7d87a8fcad1380f96..232bb3098fffcd9a22b2c9eca2014a0f9f6ef6cb 100644 (file)
@@ -105,29 +105,31 @@ public:
                try\r
                {\r
                        video_decoder_.reset(new video_decoder(input_.context()));\r
+                       CASPAR_LOG(info) << print() << L" " << video_decoder_->print();\r
                }\r
                catch(averror_stream_not_found&)\r
                {\r
-                       CASPAR_LOG(warning) << "No video-stream found. Running without video."; \r
+                       //CASPAR_LOG(warning) << print() << " No video-stream found. Running without video.";   \r
                }\r
                catch(...)\r
                {\r
                        CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       CASPAR_LOG(warning) << "Failed to open video-stream. Running without video.";   \r
+                       CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";        \r
                }\r
 \r
                try\r
                {\r
                        audio_decoder_.reset(new audio_decoder(input_.context(), frame_factory->get_video_format_desc()));\r
+                       CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();\r
                }\r
                catch(averror_stream_not_found&)\r
                {\r
-                       CASPAR_LOG(warning) << "No audio-stream found. Running without audio."; \r
+                       //CASPAR_LOG(warning) << print() << " No audio-stream found. Running without audio.";   \r
                }\r
                catch(...)\r
                {\r
                        CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       CASPAR_LOG(warning) << "Failed to open audio-stream. Running without audio.";           \r
+                       CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";               \r
                }       \r
 \r
                if(!video_decoder_ && !audio_decoder_)\r
index 13fc0e80de31077691653fdf0194ccc9c071e913..a1a334df6a17782fb38fa1515e63d1c9c6a5e223 100644 (file)
@@ -27,6 +27,7 @@
 #include "../../ffmpeg_error.h"\r
 \r
 #include <common/diagnostics/graph.h>\r
+#include <common/concurrency/executor.h>\r
 #include <common/exception/exceptions.h>\r
 #include <common/exception/win32_exception.h>\r
 #include <common/log/log.h>\r
@@ -56,39 +57,31 @@ extern "C"
 #pragma warning (pop)\r
 #endif\r
 \r
-#pragma warning (disable : 4146)\r
-\r
-namespace caspar { namespace ffmpeg {\r
-\r
 static const size_t MAX_BUFFER_COUNT = 100;\r
 static const size_t MIN_BUFFER_COUNT = 4;\r
 static const size_t MAX_BUFFER_SIZE  = 16 * 1000000;\r
-       \r
+\r
+namespace caspar { namespace ffmpeg {\r
+               \r
 struct input::impl : boost::noncopyable\r
 {              \r
-       safe_ptr<diagnostics::graph>                                                            graph_;\r
+       const safe_ptr<diagnostics::graph>                                                      graph_;\r
 \r
        const safe_ptr<AVFormatContext>                                                         format_context_; // Destroy this last\r
        const int                                                                                                       default_stream_index_;\r
                        \r
        const std::wstring                                                                                      filename_;\r
-       tbb::atomic<bool>                                                                                       loop_;\r
        const uint32_t                                                                                          start_;         \r
        const uint32_t                                                                                          length_;\r
+       tbb::atomic<bool>                                                                                       loop_;\r
        uint32_t                                                                                                        frame_number_;\r
        \r
        tbb::concurrent_bounded_queue<std::shared_ptr<AVPacket>>        buffer_;\r
        tbb::atomic<size_t>                                                                                     buffer_size_;\r
-       boost::condition_variable                                                                       buffer_cond_;\r
-       boost::mutex                                                                                            buffer_mutex_;\r
                \r
-       boost::thread                                                                                           thread_;\r
-       tbb::atomic<bool>                                                                                       is_running_;\r
-       tbb::atomic<bool>                                                                                       is_eof_;\r
-\r
-       tbb::recursive_mutex                                                                            mutex_;\r
-\r
-       explicit impl(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, uint32_t start, uint32_t length) \r
+       executor                                                                                                        executor_;\r
+       \r
+       impl(const safe_ptr<diagnostics::graph> graph, const std::wstring& filename, bool loop, uint32_t start, uint32_t length) \r
                : graph_(graph)\r
                , format_context_(open_input(filename))         \r
                , default_stream_index_(av_find_default_stream_index(format_context_.get()))\r
@@ -96,127 +89,128 @@ struct input::impl : boost::noncopyable
                , start_(start)\r
                , length_(length)\r
                , frame_number_(0)\r
+               , executor_(print())\r
        {               \r
-               is_eof_                 = false;\r
                loop_                   = loop;\r
                buffer_size_    = 0;\r
 \r
                if(start_ > 0)                  \r
-                       do_seek(start_);\r
+                       queued_seek(start_);\r
                                                                \r
                graph_->set_color("seek", diagnostics::color(1.0f, 0.5f, 0.0f));        \r
                graph_->set_color("buffer-count", diagnostics::color(0.7f, 0.4f, 0.4f));\r
                graph_->set_color("buffer-size", diagnostics::color(1.0f, 1.0f, 0.0f)); \r
-               \r
-               is_running_ = true;\r
-               thread_ = boost::thread([this]{run();});\r
 \r
-               CASPAR_LOG(info) << print() << L" Initialized.";\r
-       }\r
-\r
-       ~impl()\r
-       {\r
-               is_running_ = false;\r
-               buffer_cond_.notify_all();\r
-               thread_.join();\r
+               tick();\r
        }\r
-               \r
+       \r
        bool try_pop(std::shared_ptr<AVPacket>& packet)\r
        {\r
-               const bool result = buffer_.try_pop(packet);\r
-\r
+               auto result = buffer_.try_pop(packet);\r
+               \r
                if(result)\r
                {\r
                        if(packet)\r
                                buffer_size_ -= packet->size;\r
-                       buffer_cond_.notify_all();\r
+                       tick();\r
                }\r
 \r
                graph_->set_value("buffer-size", (static_cast<double>(buffer_size_)+0.001)/MAX_BUFFER_SIZE);\r
                graph_->set_value("buffer-count", (static_cast<double>(buffer_.size()+0.001)/MAX_BUFFER_COUNT));\r
-\r
+               \r
                return result;\r
        }\r
-                       \r
-       void run()\r
-       {               \r
-               caspar::win32_exception::install_handler();\r
 \r
-               try\r
+       void seek(uint32_t target)\r
+       {\r
+               executor_.begin_invoke([=]\r
                {\r
-                       CASPAR_LOG(info) << print() << " Thread Started.";\r
+                       std::shared_ptr<AVPacket> packet;\r
+                       while(buffer_.try_pop(packet) && packet)\r
+                               buffer_size_ -= packet->size;\r
 \r
-                       while(is_running_)\r
-                       {\r
-                               {\r
-                                       boost::unique_lock<boost::mutex> lock(buffer_mutex_);\r
-                                       while(full())\r
-                                               buffer_cond_.timed_wait(lock, boost::posix_time::millisec(20));\r
-                               }\r
-                               read_next_packet();                     \r
-                       }\r
+                       queued_seek(target);\r
 \r
-                       CASPAR_LOG(info) << print() << " Thread Stopped.";\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       is_running_ = false;\r
-               }\r
+                       tick();\r
+               }, high_priority);\r
+       }\r
+       \r
+       std::wstring print() const\r
+       {\r
+               return L"ffmpeg_input[" + filename_ + L")]";\r
+       }\r
+       \r
+       bool full() const\r
+       {\r
+               return (buffer_size_ > MAX_BUFFER_SIZE || buffer_.size() > MAX_BUFFER_COUNT) && buffer_.size() > MIN_BUFFER_COUNT;\r
        }\r
-                       \r
-       void read_next_packet()\r
-       {               \r
-               tbb::recursive_mutex::scoped_lock lock(mutex_);\r
 \r
-               auto packet = create_packet();\r
-               auto ret        = av_read_frame(format_context_.get(), packet.get()); // packet is only valid until next call of av_read_frame. Use av_dup_packet to extend its life.   \r
+       void tick()\r
+       {       \r
+               if(!executor_.is_running())\r
+                       return;\r
                \r
-               if(is_eof(ret))                                                                                                              \r
-               {\r
-                       frame_number_   = 0;\r
-                       is_eof_                 = true;\r
+               executor_.begin_invoke([this]\r
+               {                       \r
+                       if(full())\r
+                               return;\r
 \r
-                       if(loop_)\r
+                       try\r
                        {\r
-                               do_seek(start_);\r
-                               graph_->set_tag("seek");                \r
-                               CASPAR_LOG(trace) << print() << " Looping.";                    \r
-                       }                                       \r
-               }\r
-               else\r
-               {               \r
-                       THROW_ON_ERROR(ret, "av_read_frame", print());\r
+                               auto packet = create_packet();\r
+               \r
+                               auto ret = av_read_frame(format_context_.get(), packet.get()); // packet is only valid until next call of av_read_frame. Use av_dup_packet to extend its life.  \r
+               \r
+                               if(is_eof(ret))                                                                                                              \r
+                               {\r
+                                       frame_number_   = 0;\r
+\r
+                                       if(loop_)\r
+                                       {\r
+                                               queued_seek(start_);\r
+                                               graph_->set_tag("seek");                \r
+                                               CASPAR_LOG(trace) << print() << " Looping.";                    \r
+                                       }               \r
+                                       else\r
+                                               executor_.stop();\r
+                               }\r
+                               else\r
+                               {               \r
+                                       THROW_ON_ERROR(ret, "av_read_frame", print());\r
 \r
-                       if(packet->stream_index == default_stream_index_)\r
-                               ++frame_number_;\r
+                                       if(packet->stream_index == default_stream_index_)\r
+                                               ++frame_number_;\r
 \r
-                       THROW_ON_ERROR2(av_dup_packet(packet.get()), print());\r
+                                       THROW_ON_ERROR2(av_dup_packet(packet.get()), print());\r
                                \r
-                       // Make sure that the packet is correctly deallocated even if size and data is modified during decoding.\r
-                       auto size = packet->size;\r
-                       auto data = packet->data;\r
+                                       // Make sure that the packet is correctly deallocated even if size and data is modified during decoding.\r
+                                       auto size = packet->size;\r
+                                       auto data = packet->data;\r
                        \r
-                       packet = safe_ptr<AVPacket>(packet.get(), [packet, size, data](AVPacket*)\r
-                       {\r
-                               packet->size = size;\r
-                               packet->data = data;\r
-                       });\r
-\r
-                       buffer_.try_push(packet);\r
-                       buffer_size_ += packet->size;\r
+                                       packet = safe_ptr<AVPacket>(packet.get(), [packet, size, data](AVPacket*)\r
+                                       {\r
+                                               packet->size = size;\r
+                                               packet->data = data;                            \r
+                                       });\r
+\r
+                                       buffer_.try_push(packet);\r
+                                       buffer_size_ += packet->size;\r
                                \r
-                       graph_->set_value("buffer-size", (static_cast<double>(buffer_size_)+0.001)/MAX_BUFFER_SIZE);\r
-                       graph_->set_value("buffer-count", (static_cast<double>(buffer_.size()+0.001)/MAX_BUFFER_COUNT));\r
-               }                       \r
-       }\r
-\r
-       bool full() const\r
-       {\r
-               return is_running_ && (is_eof_ || (buffer_size_ > MAX_BUFFER_SIZE || buffer_.size() > MAX_BUFFER_COUNT) && buffer_.size() > MIN_BUFFER_COUNT);\r
-       }\r
-       \r
-       void do_seek(const uint32_t target)\r
+                                       graph_->set_value("buffer-size", (static_cast<double>(buffer_size_)+0.001)/MAX_BUFFER_SIZE);\r
+                                       graph_->set_value("buffer-count", (static_cast<double>(buffer_.size()+0.001)/MAX_BUFFER_COUNT));\r
+                               }       \r
+               \r
+                               tick();         \r
+                       }\r
+                       catch(...)\r
+                       {\r
+                               CASPAR_LOG_CURRENT_EXCEPTION();\r
+                               executor_.stop();\r
+                       }\r
+               });\r
+       }       \r
+                       \r
+       void queued_seek(const uint32_t target)\r
        {       \r
                CASPAR_LOG(debug) << print() << " Seeking: " << target;\r
 \r
@@ -238,10 +232,7 @@ struct input::impl : boost::noncopyable
                auto fixed_target = (target*stream->time_base.den*codec->time_base.num)/(stream->time_base.num*codec->time_base.den)*codec->ticks_per_frame;\r
                \r
                THROW_ON_ERROR2(avformat_seek_file(format_context_.get(), default_stream_index_, std::numeric_limits<int64_t>::min(), fixed_target, std::numeric_limits<int64_t>::max(), 0), print());          \r
-\r
-               is_eof_ = false;\r
-               buffer_cond_.notify_all();\r
-\r
+               \r
                auto flush_packet       = create_packet();\r
                flush_packet->data      = nullptr;\r
                flush_packet->size      = 0;\r
@@ -250,20 +241,10 @@ struct input::impl : boost::noncopyable
                buffer_.push(flush_packet);\r
        }       \r
 \r
-       void seek(uint32_t target)\r
-       {\r
-               tbb::recursive_mutex::scoped_lock lock(mutex_);\r
-\r
-               std::shared_ptr<AVPacket> packet;\r
-               while(try_pop(packet))\r
-               {\r
-               }\r
-\r
-               do_seek(target);\r
-       }\r
-\r
        bool is_eof(int ret)\r
        {\r
+               #pragma warning (disable : 4146)\r
+\r
                if(ret == AVERROR(EIO))\r
                        CASPAR_LOG(trace) << print() << " Received EIO, assuming EOF. ";\r
                if(ret == AVERROR_EOF)\r
@@ -271,16 +252,11 @@ struct input::impl : boost::noncopyable
 \r
                return ret == AVERROR_EOF || ret == AVERROR(EIO) || frame_number_ >= length_; // av_read_frame doesn't always correctly return AVERROR_EOF;\r
        }\r
-       \r
-       std::wstring print() const\r
-       {\r
-               return L"ffmpeg_input[" + filename_ + L")]";\r
-       }\r
 };\r
 \r
 input::input(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, uint32_t start, uint32_t length) \r
        : impl_(new impl(graph, filename, loop, start, length)){}\r
-bool input::eof() const {return impl_->is_eof_;}\r
+bool input::eof() const {return !impl_->executor_.is_running();}\r
 bool input::try_pop(std::shared_ptr<AVPacket>& packet){return impl_->try_pop(packet);}\r
 safe_ptr<AVFormatContext> input::context(){return impl_->format_context_;}\r
 void input::loop(bool value){impl_->loop_ = value;}\r
index 86a132ea43da9035a9fb0b8649a40b639d32ff05..22887f0f32d2e163ab1ec16e10923ad1b70f71ab 100644 (file)
@@ -97,8 +97,10 @@ struct frame_muxer::impl : boost::noncopyable
        {\r
                video_streams_.push(std::queue<safe_ptr<write_frame>>());\r
                audio_streams_.push(core::audio_buffer());\r
-               boost::range::sort(audio_cadence_);\r
-               boost::range::reverse(audio_cadence_);\r
+               \r
+               // Note: Uses 1 step rotated cadence for 1001 modes (1602, 1602, 1601, 1602, 1601)\r
+               // This cadence fills the audio mixer most optimally.\r
+               boost::range::rotate(audio_cadence_, std::end(audio_cadence_)-1);\r
        }\r
 \r
        void push(const std::shared_ptr<AVFrame>& video_frame, int flags)\r
index e5d8f07cbe7f841d66dfe02bbdc6c9fcd4b12438..4036c4232b05d2d7c5097ca0b8d0f19df2e85667 100644 (file)
@@ -74,7 +74,6 @@ public:
                , height_(codec_context_->height)\r
        {\r
                file_frame_number_ = 0;\r
-               CASPAR_LOG(debug) << "[video_decoder] " << context->streams[index_]->codec->codec->long_name;\r
        }\r
 \r
        void push(const std::shared_ptr<AVPacket>& packet)\r
@@ -138,13 +137,18 @@ public:
        \r
        bool ready() const\r
        {\r
-               return packets_.size() > 10;\r
+               return packets_.size() >= 8;\r
        }\r
 \r
        uint32_t nb_frames() const\r
        {\r
                return std::max<uint32_t>(nb_frames_, file_frame_number_);\r
        }\r
+\r
+       std::wstring print() const\r
+       {               \r
+               return L"[video-decoder] " + u16(codec_context_->codec->long_name);\r
+       }\r
 };\r
 \r
 video_decoder::video_decoder(const safe_ptr<AVFormatContext>& context) : impl_(new impl(context)){}\r
@@ -156,5 +160,6 @@ int video_decoder::height() const{return impl_->height_;}
 uint32_t video_decoder::nb_frames() const{return impl_->nb_frames();}\r
 uint32_t video_decoder::file_frame_number() const{return impl_->file_frame_number_;}\r
 bool   video_decoder::is_progressive() const{return impl_->is_progressive_;}\r
+std::wstring video_decoder::print() const{return impl_->print();}\r
 \r
 }}
\ No newline at end of file
index 65127b6ea298e29cf6c35574a162b96ac472fb04..ed84594d81c61bd7f26287bd196af98bd012da59 100644 (file)
@@ -55,6 +55,8 @@ public:
 \r
        bool     is_progressive() const;\r
 \r
+       std::wstring print() const;\r
+\r
 private:\r
        struct impl;\r
        safe_ptr<impl> impl_;\r
index d742336739ab27cca3c32dc16ef4ec7391a26498..25ab53cad1dba3fcdd5e0a71f4565205666c3ad8 100644 (file)
@@ -608,12 +608,12 @@ void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request)
        }\r
        else if(str.find(TEXT("OnCommand")) != std::wstring::npos) {\r
                //this is how templatehost 1.8 reports that a command has been received\r
-               CASPAR_LOG(debug)  << print_()  << L" Command: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
+               CASPAR_LOG(debug)  << print_()  << L" [command]      " << str;\r
                bCallSuccessful_ = true;\r
        }\r
        else if(str.find(TEXT("Activity")) != std::wstring::npos)\r
        {\r
-               CASPAR_LOG(debug) << print_() << L" Activity: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
+               CASPAR_LOG(debug) << print_() << L" [activity]     " << str;\r
 \r
                //this is how templatehost 1.7 reports that a command has been received\r
                if(str.find(TEXT("Command recieved")) != std::wstring::npos)\r
@@ -627,7 +627,7 @@ void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request)
        }\r
        else if(str.find(TEXT("OnNotify")) != std::wstring::npos)\r
        {\r
-               CASPAR_LOG(info) << print_() << L" Notification: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
+               CASPAR_LOG(info) << print_() << L" [notification] " << str;\r
 \r
                //if(pFlashProducer_ != 0 && pFlashProducer_->pMonitor_) {\r
                //      std::wstring::size_type pos = str.find(TEXT('@'));\r
@@ -637,17 +637,17 @@ void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request)
        }\r
        else if(str.find(TEXT("IsEmpty")) != std::wstring::npos)\r
        {\r
-               CASPAR_LOG(info) << print_() << L" Empty.";\r
+               CASPAR_LOG(trace) << print_() << L" Empty.";\r
                ATLTRACE(_T("ShockwaveFlash::IsEmpty\n"));\r
                bIsEmpty_ = true;\r
        }\r
        else if(str.find(TEXT("OnError")) != std::wstring::npos)\r
        {\r
-               CASPAR_LOG(error) << print_() << L" Error: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
+               CASPAR_LOG(error) << print_() << L" [error]        " << str;\r
        }\r
        else if(str.find(TEXT("OnDebug")) != std::wstring::npos)\r
        {\r
-               CASPAR_LOG(error) << print_() << L" Debug: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
+               CASPAR_LOG(debug) << print_() << L" [debug]        " << str;\r
        }\r
        //else if(str.find(TEXT("OnTemplateDescription")) != std::wstring::npos)\r
        //{\r
index a7fdd2fed20c143edf1ed64843d5e38620363c98..745a9141f8fbe11e1487f4a583063fcd1ac900a8 100644 (file)
@@ -201,7 +201,7 @@ safe_ptr<cg_producer> get_default_cg_producer(const safe_ptr<core::video_channel
        {\r
                if(flash_producer->print().find(L"flash[") == std::string::npos) // UGLY hack\r
                {\r
-                       flash_producer = make_safe<cg_producer>(flash::create_producer(video_channel->frame_factory(), boost::assign::list_of<std::wstring>()));        \r
+                       flash_producer = flash::create_producer(video_channel->frame_factory(), boost::assign::list_of<std::wstring>());        \r
                        video_channel->stage()->load(render_layer, flash_producer); \r
                        video_channel->stage()->play(render_layer);\r
                }\r
@@ -212,7 +212,7 @@ safe_ptr<cg_producer> get_default_cg_producer(const safe_ptr<core::video_channel
                throw;\r
        }\r
 \r
-       return static_pointer_cast<cg_producer>(flash_producer);\r
+       return make_safe<cg_producer>(flash_producer);\r
 }\r
 \r
 safe_ptr<core::frame_producer> create_ct_producer(const safe_ptr<core::frame_factory> frame_factory, const std::vector<std::wstring>& params) \r
index c709430448a7b5f4a1462c75dae240663873ddc5..2f26ecf3bff30fd982e13ff74960c1bfba5c0690 100644 (file)
@@ -180,7 +180,7 @@ public:
                if(FAILED(CComObject<caspar::flash::FlashAxContainer>::CreateInstance(&ax_)))\r
                        BOOST_THROW_EXCEPTION(caspar_exception() << wmsg_info(print() + L" Failed to create FlashAxContainer"));\r
                \r
-               ax_->set_print([this]{return L"flash_renderer";});\r
+               ax_->set_print([this]{return print();});\r
 \r
                if(FAILED(ax_->CreateAxControl()))\r
                        BOOST_THROW_EXCEPTION(caspar_exception() << wmsg_info(print() + L" Failed to Create FlashAxControl"));\r
@@ -200,7 +200,7 @@ public:
                                                \r
                ax_->SetSize(width_, height_);          \r
        \r
-               CASPAR_LOG(info) << print() << L" Successfully initialized with template-host: " << filename << L" width: " << width_ << L" height: " << height_ << L".";\r
+               CASPAR_LOG(info) << print() << L" Initialized.";\r
        }\r
 \r
        ~flash_renderer()\r
@@ -218,7 +218,7 @@ public:
                std::wstring result;\r
 \r
                if(!ax_->FlashCall(param, result))\r
-                       CASPAR_LOG(warning) << print() << L" Flash call failed:" << param;//BOOST_THROW_EXCEPTION(invalid_operation() << wmsg_info("Flash function call failed.") << arg_name_info("param") << arg_value_info(u8(param)));\r
+                       CASPAR_LOG(warning) << print() << L" Flash call failed:" << param;//BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Flash function call failed.") << arg_name_info("param") << arg_value_info(narrow(param)));\r
                graph_->set_tag("param");\r
 \r
                return result;\r
@@ -228,7 +228,7 @@ public:
        {\r
                float frame_time = 1.0f/ax_->GetFPS();\r
 \r
-               graph_->set_value("tick-time", (tick_timer_.elapsed()/frame_time)*0.5f);\r
+               graph_->set_value("tick-time", static_cast<float>(tick_timer_.elapsed()/frame_time)*0.5f);\r
                tick_timer_.restart();\r
 \r
                if(ax_->IsEmpty())\r
@@ -273,7 +273,10 @@ public:
        \r
        std::wstring print()\r
        {\r
-               return L"flash[" + boost::filesystem::path(filename_).filename().wstring() + L"]";              \r
+               return L"flash-player[" + boost::filesystem::wpath(filename_).filename().wstring() \r
+                                 + L"|" + boost::lexical_cast<std::wstring>(width_)\r
+                                 + L"x" + boost::lexical_cast<std::wstring>(height_)\r
+                                 + L"]";               \r
        }\r
 };\r
 \r
@@ -305,9 +308,6 @@ public:
                , height_(height > 0 ? height : frame_factory->get_video_format_desc().height)\r
                , context_(L"flash_producer")\r
        {       \r
-               if(!boost::filesystem::exists(filename))\r
-                       BOOST_THROW_EXCEPTION(file_not_found() << werr_file_name_info(filename));       \r
-\r
                fps_ = 0;\r
 \r
                graph_->set_color("output-buffer-count", diagnostics::color(1.0f, 1.0f, 0.0f));          \r
@@ -454,7 +454,12 @@ safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factor
 {\r
        auto template_host = get_template_host(frame_factory->get_video_format_desc());\r
        \r
-       return create_producer_destroy_proxy(make_safe<flash_producer>(frame_factory, env::template_folder() + L"\\" + template_host.filename, template_host.width, template_host.height));\r
+       auto filename = env::template_folder() + L"\\" + template_host.filename;\r
+       \r
+       if(!boost::filesystem::exists(filename))\r
+               BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(u8(filename)));      \r
+\r
+       return create_producer_destroy_proxy(make_safe<flash_producer>(frame_factory, filename, template_host.width, template_host.height));\r
 }\r
 \r
 std::wstring find_template(const std::wstring& template_name)\r
index 2797960ebd092e3c554e1a6553cd5e67ac9ecc05..e93aeddb4a9a407701df116e7ecfe07f4a4ff78a 100644 (file)
@@ -63,8 +63,6 @@ struct image_producer : public core::frame_producer
                std::copy_n(FreeImage_GetBits(bitmap.get()), frame->image_data().size(), frame->image_data().begin());\r
                frame->commit();\r
                frame_ = std::move(frame);\r
-\r
-               CASPAR_LOG(info) << print() << L" Initialized";\r
        }\r
        \r
        // frame_producer\r
index 7a4b367b2e661d77be8a5d71fba57efae935d4d8..2406c62d12885cda72000bba9ea036fdf9437c44 100644 (file)
@@ -502,14 +502,17 @@ safe_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>&
        \r
        configuration config;\r
                \r
-       if(params.size() > 1) \r
-               config.screen_index = lexical_cast_or_default<int>(params[2], config.screen_index);\r
-\r
-       if(params.size() > 2) \r
-               config.windowed = lexical_cast_or_default<bool>(params[3], config.windowed);\r
-\r
+       auto device_it = std::find(params.begin(), params.end(), L"DEVICE");\r
+       if(device_it != params.end() && ++device_it != params.end())\r
+               config.screen_index = boost::lexical_cast<int>(*device_it);\r
+               \r
+       config.key_only = std::find(params.begin(), params.end(), L"WINDOWED") != params.end();\r
        config.key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();\r
 \r
+       auto name_it    = std::find(params.begin(), params.end(), L"NAME");\r
+       if(name_it != params.end() && ++name_it != params.end())\r
+               config.name = *name_it;\r
+\r
        return make_safe<ogl_consumer_proxy>(config);\r
 }\r
 \r
index a03b440e72ae1a9db38127c4c6d89aa956eb557a..e0116d7e8874cab4556b403bc2420171698bd2d2 100644 (file)
@@ -38,6 +38,7 @@
 #include <core/producer/frame_producer.h>\r
 #include <core/video_format.h>\r
 #include <core/producer/transition/transition_producer.h>\r
+#include <core/producer/channel/channel_producer.h>\r
 #include <core/producer/frame/frame_transform.h>\r
 #include <core/producer/stage.h>\r
 #include <core/producer/layer.h>\r
@@ -53,6 +54,7 @@
 #include <modules/flash/producer/cg_producer.h>\r
 #include <modules/ffmpeg/producer/util/util.h>\r
 #include <modules/image/image.h>\r
+#include <modules/ogl/ogl.h>\r
 \r
 #include <algorithm>\r
 #include <locale>\r
@@ -221,6 +223,56 @@ bool DiagnosticsCommand::DoExecute()
        }\r
 }\r
 \r
+bool ChannelGridCommand::DoExecute()\r
+{\r
+       int index = 1;\r
+       auto self = GetChannels().back();\r
+       \r
+       std::vector<std::wstring> params;\r
+       params.push_back(L"SCREEN");\r
+       params.push_back(L"NAME");\r
+       params.push_back(L"Channel Grid Window");\r
+       auto screen = create_consumer(params);\r
+\r
+       self->output()->add(screen);\r
+\r
+       BOOST_FOREACH(auto channel, GetChannels())\r
+       {\r
+               if(channel != self)\r
+               {\r
+                       auto producer = create_channel_producer(self->frame_factory(), channel);                \r
+                       self->stage()->load(index, producer, false);\r
+                       self->stage()->play(index);\r
+                       index++;\r
+               }\r
+       }\r
+\r
+       int n = GetChannels().size()-1;\r
+       double delta = 1.0/static_cast<double>(n);\r
+       for(int x = 0; x < n; ++x)\r
+       {\r
+               for(int y = 0; y < n; ++y)\r
+               {\r
+                       int index = x+y*n+1;\r
+                       auto transform = [=](frame_transform transform) -> frame_transform\r
+                       {               \r
+                               transform.fill_translation[0]   = x*delta;\r
+                               transform.fill_translation[1]   = y*delta;\r
+                               transform.fill_scale[0]                 = delta;\r
+                               transform.fill_scale[1]                 = delta;\r
+                               transform.clip_translation[0]   = x*delta;\r
+                               transform.clip_translation[1]   = y*delta;\r
+                               transform.clip_scale[0]                 = delta;\r
+                               transform.clip_scale[1]                 = delta;                        \r
+                               return transform;\r
+                       };\r
+                       self->stage()->apply_frame_transform(index, transform);\r
+               }\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
 bool CallCommand::DoExecute()\r
 {      \r
        //Perform loading of the clip\r
@@ -833,25 +885,32 @@ bool LogCommand::DoExecute()
 \r
 bool CGCommand::DoExecute()\r
 {\r
-       std::wstring command = _parameters[0];\r
-       if(command == TEXT("ADD"))\r
-               return DoExecuteAdd();\r
-       else if(command == TEXT("PLAY"))\r
-               return DoExecutePlay();\r
-       else if(command == TEXT("STOP"))\r
-               return DoExecuteStop();\r
-       else if(command == TEXT("NEXT"))\r
-               return DoExecuteNext();\r
-       else if(command == TEXT("REMOVE"))\r
-               return DoExecuteRemove();\r
-       else if(command == TEXT("CLEAR"))\r
-               return DoExecuteClear();\r
-       else if(command == TEXT("UPDATE"))\r
-               return DoExecuteUpdate();\r
-       else if(command == TEXT("INVOKE"))\r
-               return DoExecuteInvoke();\r
-       else if(command == TEXT("INFO"))\r
-               return DoExecuteInfo();\r
+       try\r
+       {\r
+               std::wstring command = _parameters[0];\r
+               if(command == TEXT("ADD"))\r
+                       return DoExecuteAdd();\r
+               else if(command == TEXT("PLAY"))\r
+                       return DoExecutePlay();\r
+               else if(command == TEXT("STOP"))\r
+                       return DoExecuteStop();\r
+               else if(command == TEXT("NEXT"))\r
+                       return DoExecuteNext();\r
+               else if(command == TEXT("REMOVE"))\r
+                       return DoExecuteRemove();\r
+               else if(command == TEXT("CLEAR"))\r
+                       return DoExecuteClear();\r
+               else if(command == TEXT("UPDATE"))\r
+                       return DoExecuteUpdate();\r
+               else if(command == TEXT("INVOKE"))\r
+                       return DoExecuteInvoke();\r
+               else if(command == TEXT("INFO"))\r
+                       return DoExecuteInfo();\r
+       }\r
+       catch(...)\r
+       {\r
+               CASPAR_LOG_CURRENT_EXCEPTION();\r
+       }\r
 \r
        SetReplyString(TEXT("403 CG ERROR\r\n"));\r
        return false;\r
index c17766880ed5a0e85224ff33614e92cdef2bae40..62e569710a06b68a989e2ae38c9837d0135d3f5c 100644 (file)
@@ -32,6 +32,12 @@ std::wstring ListTemplates();
 \r
 namespace amcp {\r
        \r
+class ChannelGridCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
+{\r
+       std::wstring print() const { return L"ChannelGridCommand";}\r
+       bool DoExecute();\r
+};\r
+\r
 class DiagnosticsCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
 {\r
        std::wstring print() const { return L"DiagnosticsCommand";}\r
index d7ed9a6452bf0ce30292165f7e9a5e3d71cf6291..d7bc190edef200f547493c7c6ce784c8f241fe4e 100644 (file)
@@ -156,8 +156,6 @@ AMCPCommandPtr AMCPProtocolStrategy::InterpretCommandString(const std::wstring&
        AMCPCommandPtr pCommand;\r
        MessageParserState state = New;\r
 \r
-       CASPAR_LOG(info) << L"Received: " << message;\r
-\r
        std::size_t tokensInMessage = TokenizeMessage(message, &tokens);\r
 \r
        //parse the message one token at the time\r
@@ -185,6 +183,7 @@ AMCPCommandPtr AMCPProtocolStrategy::InterpretCommandString(const std::wstring&
                        }\r
                        else\r
                        {\r
+                               pCommand->SetChannels(channels_);\r
                                //Set scheduling\r
                                if(commandSwitch.size() > 0) {\r
                                        transform(commandSwitch.begin(), commandSwitch.end(), commandSwitch.begin(), toupper);\r
@@ -249,7 +248,6 @@ AMCPCommandPtr AMCPProtocolStrategy::InterpretCommandString(const std::wstring&
                                }\r
 \r
                                pCommand->SetChannel(pChannel);\r
-                               pCommand->SetChannels(channels_);\r
                                pCommand->SetChannelIndex(channelIndex);\r
                                pCommand->SetLayerIntex(layerIndex);\r
 \r
@@ -298,29 +296,30 @@ AMCPCommandPtr AMCPProtocolStrategy::CommandFactory(const std::wstring& str)
        std::wstring s = str;\r
        transform(s.begin(), s.end(), s.begin(), toupper);\r
        \r
-       if         (s == TEXT("MIXER"))         return std::make_shared<MixerCommand>();\r
-       else if(s == TEXT("DIAG"))              return std::make_shared<DiagnosticsCommand>();\r
-       else if(s == TEXT("CALL"))              return std::make_shared<CallCommand>();\r
-       else if(s == TEXT("SWAP"))              return std::make_shared<SwapCommand>();\r
-       else if(s == TEXT("LOAD"))              return std::make_shared<LoadCommand>();\r
-       else if(s == TEXT("LOADBG"))    return std::make_shared<LoadbgCommand>();\r
-       else if(s == TEXT("ADD"))               return std::make_shared<AddCommand>();\r
-       else if(s == TEXT("REMOVE"))    return std::make_shared<RemoveCommand>();\r
-       else if(s == TEXT("PAUSE"))             return std::make_shared<PauseCommand>();\r
-       else if(s == TEXT("PLAY"))              return std::make_shared<PlayCommand>();\r
-       else if(s == TEXT("STOP"))              return std::make_shared<StopCommand>();\r
-       else if(s == TEXT("CLEAR"))             return std::make_shared<ClearCommand>();\r
-       else if(s == TEXT("PRINT"))             return std::make_shared<PrintCommand>();\r
-       else if(s == TEXT("LOG"))               return std::make_shared<LogCommand>();\r
-       else if(s == TEXT("CG"))                return std::make_shared<CGCommand>();\r
-       else if(s == TEXT("DATA"))              return std::make_shared<DataCommand>();\r
-       else if(s == TEXT("CINF"))              return std::make_shared<CinfCommand>();\r
-       else if(s == TEXT("INFO"))              return std::make_shared<InfoCommand>(channels_);\r
-       else if(s == TEXT("CLS"))               return std::make_shared<ClsCommand>();\r
-       else if(s == TEXT("TLS"))               return std::make_shared<TlsCommand>();\r
-       else if(s == TEXT("VERSION"))   return std::make_shared<VersionCommand>();\r
-       else if(s == TEXT("BYE"))               return std::make_shared<ByeCommand>();\r
-       else if(s == TEXT("SET"))               return std::make_shared<SetCommand>();\r
+       if         (s == TEXT("MIXER"))                 return std::make_shared<MixerCommand>();\r
+       else if(s == TEXT("DIAG"))                      return std::make_shared<DiagnosticsCommand>();\r
+       else if(s == TEXT("CHANNEL_GRID"))      return std::make_shared<ChannelGridCommand>();\r
+       else if(s == TEXT("CALL"))                      return std::make_shared<CallCommand>();\r
+       else if(s == TEXT("SWAP"))                      return std::make_shared<SwapCommand>();\r
+       else if(s == TEXT("LOAD"))                      return std::make_shared<LoadCommand>();\r
+       else if(s == TEXT("LOADBG"))            return std::make_shared<LoadbgCommand>();\r
+       else if(s == TEXT("ADD"))                       return std::make_shared<AddCommand>();\r
+       else if(s == TEXT("REMOVE"))            return std::make_shared<RemoveCommand>();\r
+       else if(s == TEXT("PAUSE"))                     return std::make_shared<PauseCommand>();\r
+       else if(s == TEXT("PLAY"))                      return std::make_shared<PlayCommand>();\r
+       else if(s == TEXT("STOP"))                      return std::make_shared<StopCommand>();\r
+       else if(s == TEXT("CLEAR"))                     return std::make_shared<ClearCommand>();\r
+       else if(s == TEXT("PRINT"))                     return std::make_shared<PrintCommand>();\r
+       else if(s == TEXT("LOG"))                       return std::make_shared<LogCommand>();\r
+       else if(s == TEXT("CG"))                        return std::make_shared<CGCommand>();\r
+       else if(s == TEXT("DATA"))                      return std::make_shared<DataCommand>();\r
+       else if(s == TEXT("CINF"))                      return std::make_shared<CinfCommand>();\r
+       else if(s == TEXT("INFO"))                      return std::make_shared<InfoCommand>(channels_);\r
+       else if(s == TEXT("CLS"))                       return std::make_shared<ClsCommand>();\r
+       else if(s == TEXT("TLS"))                       return std::make_shared<TlsCommand>();\r
+       else if(s == TEXT("VERSION"))           return std::make_shared<VersionCommand>();\r
+       else if(s == TEXT("BYE"))                       return std::make_shared<ByeCommand>();\r
+       else if(s == TEXT("SET"))                       return std::make_shared<SetCommand>();\r
        //else if(s == TEXT("MONITOR"))\r
        //{\r
        //      result = AMCPCommandPtr(new MonitorCommand());\r
index 7fd1b7d286fc10cb2ed723abfc482ea81fe7d936..f921dd19bf5115428a09c3785a37f3ee09dc69f4 100644 (file)
  \r
 #include "../StdAfx.h"\r
 \r
+#pragma warning (disable: 4244)\r
+\r
 #include "CIIProtocolStrategy.h"\r
 #include "CIICommandsImpl.h"\r
 #include <sstream>\r
 #include <algorithm>\r
 #include <modules/flash/producer/cg_producer.h>\r
+#include <boost/locale.hpp>\r
 \r
 namespace caspar { namespace protocol { namespace cii {\r
 \r
@@ -145,8 +148,12 @@ void MiscellaneousCommand::Execute()
                pCIIStrategy_->DisplayMediaFile(filename_);     \r
 \r
        //TODO: Need to be checked for validity\r
-       else if(state_ == 1)\r
-               flash::get_default_cg_producer(pCIIStrategy_->GetChannel())->add(layer_, filename_, false, TEXT(""), xmlData_);\r
+       else if(state_ == 1)            \r
+       {\r
+               // HACK fix. The data sent is UTF8, however the protocol is implemented for ISO-8859-1. Instead of doing risky changes we simply convert into proper encoding when leaving protocol code.\r
+               auto xmlData2 = boost::locale::conv::utf_to_utf<wchar_t, char>(std::string(xmlData_.begin(), xmlData_.end()));\r
+               flash::get_default_cg_producer(pCIIStrategy_->GetChannel())->add(layer_, filename_, false, TEXT(""), xmlData2);\r
+       }\r
 }\r
 \r
 \r
index 8abf9758b47ea470246c257ae38f96fb3321e603..005bbe1135dc356c6e9f1d8bc4a38593dbb84e5d 100644 (file)
@@ -83,8 +83,6 @@ void CIIProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInf
 \r
 void CIIProtocolStrategy::ProcessMessage(const std::wstring& message)\r
 {\r
-       CASPAR_LOG(debug) << L"Received: " << message.c_str();\r
-\r
        std::vector<std::wstring> tokens;\r
        int tokenCount = TokenizeMessage(message, &tokens);\r
 \r
index c50bdbe07a8bcae6787220684243b906c1798569..13993fe0a5626f106065665c3ccf749f9f1e6730 100644 (file)
@@ -31,6 +31,8 @@
 \r
 #include <common/log/log.h>\r
 \r
+#include <boost/algorithm/string/replace.hpp>\r
+\r
 #include <string>\r
 #include <algorithm>\r
 \r
@@ -355,12 +357,17 @@ bool AsyncEventServer::OnRead(SocketInfoPtr& pSI) {
 \r
                //Convert to widechar\r
                if(ConvertMultiByteToWideChar(pProtocolStrategy_->GetCodepage(), pSI->recvBuffer_, recvResult + pSI->recvLeftoverOffset_, pSI->wideRecvBuffer_, pSI->recvLeftoverOffset_))\r
+               {\r
+                       auto msg =      std::wstring(pSI->wideRecvBuffer_.begin(), pSI->wideRecvBuffer_.end());\r
+                       boost::replace_all(msg, L"\n", L"\\n");\r
+                       boost::replace_all(msg, L"\r", L"\\r");\r
+\r
+                       CASPAR_LOG(info) << L"Received message from " << pSI->host_.c_str() << ": "<< msg;\r
                        pProtocolStrategy_->Parse(&pSI->wideRecvBuffer_[0], pSI->wideRecvBuffer_.size(), pSI);\r
+               }\r
                else                    \r
                        CASPAR_LOG(error) << "Read from " << pSI->host_.c_str() << TEXT(" failed, could not convert command to UNICODE");\r
                        \r
-               \r
-\r
                maxRecvLength = sizeof(pSI->recvBuffer_)-pSI->recvLeftoverOffset_;\r
                recvResult = recv(pSI->socket_, pSI->recvBuffer_+pSI->recvLeftoverOffset_, maxRecvLength, 0);\r
        }\r
@@ -434,8 +441,13 @@ void AsyncEventServer::DoSend(SocketInfo& socketInfo) {
                        }\r
                        else {\r
                                if(sentBytes == bytesToSend) {\r
+                                       \r
                                        if(sentBytes < 512)\r
-                                               CASPAR_LOG(info) << "Sent: " << socketInfo.sendQueue_.front().c_str() << TEXT(" to ") << socketInfo.host_.c_str();\r
+                                       {\r
+                                               boost::replace_all(socketInfo.sendQueue_.front(), L"\n", L"\\n");\r
+                                               boost::replace_all(socketInfo.sendQueue_.front(), L"\r", L"\\r");\r
+                                               CASPAR_LOG(info) << L"Sent message to " << socketInfo.host_.c_str() << L": " << socketInfo.sendQueue_.front().c_str();\r
+                                       }\r
                                        else\r
                                                CASPAR_LOG(info) << "Sent more than 512 bytes to " << socketInfo.host_.c_str();\r
 \r
index 392195fd9590cf365798074df0a020da645c08f5..5278d34c3103626aae4f3cacbc678bd1cede0b5f 100644 (file)
@@ -46,7 +46,7 @@ struct ConsoleClientInfo : public caspar::IO::ClientInfo
 {\r
        void Send(const std::wstring& data)\r
        {\r
-               std::wcout << (L"\n--------------------\n" + data + L"--------------------\n");\r
+               std::wcout << (L"#" + data);\r
        }\r
        void Disconnect(){}\r
 };\r
index e51cf898b28d01fd6a354ea1ec243f1dbf6c2868..9aa5e31e3c1ebb17bf036d7d9aa6fe7b59c59814 100644 (file)
@@ -7,11 +7,13 @@
     <template-path>D:\casparcg\_templates\</template-path>\r
   </paths>\r
   <log-level>trace</log-level>\r
+  <channel-grid>true</channel-grid>\r
   <channels>\r
     <channel>\r
       <video-mode>720p5000</video-mode>\r
       <consumers>\r
         <screen></screen>\r
+        <system-audio></system-audio>\r
       </consumers>\r
     </channel>\r
   </channels>\r
index 57b5f41c9652a918fff5c9ed2fb9942947cad6e4..407a12f5d6a650184d76fe19917e88d4e51744dc 100644 (file)
@@ -141,6 +141,10 @@ struct server::impl : boost::noncopyable
                                }\r
                        }                                                       \r
                }\r
+\r
+               // Dummy diagnostics channel\r
+               if(env::properties().get(L"configuration.channel-grid", false))\r
+                       channels_.push_back(make_safe<video_channel>(static_cast<int>(channels_.size()+1), core::video_format_desc(core::video_format::x576p2500), ogl_));\r
        }\r
                \r
        void setup_controllers(const boost::property_tree::wptree& pt)\r