]> git.sesse.net Git - casparcg/commitdiff
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 20 Oct 2011 10:45:44 +0000 (10:45 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 20 Oct 2011 10:45:44 +0000 (10:45 +0000)
39 files changed:
common/common.vcxproj.filters
common/memory/safe_ptr.h
common/utility/assert.h
core/StdAfx.h
core/mixer/gpu/ogl_device.cpp
core/mixer/image/image_shader.cpp
core/producer/frame_producer.cpp
core/producer/frame_producer.h
core/producer/separated/separated_producer.cpp
core/producer/stage.cpp
core/producer/transition/transition_producer.cpp
core/video_channel.cpp
core/video_channel_context.cpp
core/video_channel_context.h
modules/decklink/consumer/decklink_consumer.cpp
modules/decklink/interop/DeckLinkAPI_h.h
modules/decklink/interop/DeckLinkAPI_i.c
modules/decklink/producer/decklink_producer.cpp
modules/ffmpeg/ffmpeg.vcxproj
modules/ffmpeg/ffmpeg.vcxproj.filters
modules/ffmpeg/ffmpeg_error.h
modules/ffmpeg/producer/audio/audio_decoder.cpp
modules/ffmpeg/producer/audio/audio_resampler.cpp
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/filter/filter.cpp
modules/ffmpeg/producer/filter/filter.h
modules/ffmpeg/producer/frame_muxer.cpp
modules/ffmpeg/producer/frame_muxer.h
modules/ffmpeg/producer/input.cpp
modules/ffmpeg/producer/input.h
modules/ffmpeg/producer/util.cpp
modules/ffmpeg/producer/util.h
modules/ffmpeg/producer/video/video_decoder.cpp
modules/ffmpeg/producer/video/video_decoder.h
modules/ffmpeg/tbb_avcodec.cpp [deleted file]
modules/ffmpeg/tbb_avcodec.h [deleted file]
modules/ogl/consumer/ogl_consumer.cpp
protocol/amcp/AMCPCommandsImpl.cpp
shell/casparcg.config

index 54cce3a53fc4219395c28ca04e27ecfe0f2136df..9efe3db954cd7d0370447458a2ab49e63da0a8ba 100644 (file)
@@ -37,6 +37,9 @@
     <Filter Include="source\compiler\vs">\r
       <UniqueIdentifier>{28c25c8a-1277-4d2c-9e85-5af33f9938ea}</UniqueIdentifier>\r
     </Filter>\r
+    <Filter Include="source\com">\r
+      <UniqueIdentifier>{f9a52080-be84-43f9-939d-855c6fd02414}</UniqueIdentifier>\r
+    </Filter>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="exception\win32_exception.cpp">\r
index e4269e69bd2166f96f984fb8287e930b77aafa7a..f4454b451ce8a9c0564c949ab8332d37ecf0a650 100644 (file)
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-*  This file is part of CasparCG.\r
-*\r
-*    CasparCG is free software: you can redistribute it and/or modify\r
-*    it under the terms of the GNU General Public License as published by\r
-*    the Free Software Foundation, either version 3 of the License, or\r
-*    (at your option) any later version.\r
-*\r
-*    CasparCG is distributed in the hope that it will be useful,\r
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-*    GNU General Public License for more details.\r
-\r
-*    You should have received a copy of the GNU General Public License\r
-*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
 #pragma once\r
 \r
 #include <memory>\r
+#include <stdexcept>\r
 #include <type_traits>\r
-#include <exception>\r
 \r
-namespace caspar {\r
-       \r
+namespace caspar\r
+{\r
+\r
 template<typename T>\r
 class safe_ptr\r
-{      \r
-       std::shared_ptr<T> impl_;\r
-       template <typename> friend class safe_ptr;\r
+{   \r
+    template <typename> friend class safe_ptr;\r
 public:\r
-       typedef T element_type;\r
-       \r
-       safe_ptr() : impl_(std::make_shared<T>()){}     \r
-       \r
-       safe_ptr(const safe_ptr<T>& other) : impl_(other.impl_){}  // noexcept\r
-       safe_ptr(safe_ptr<T>&& other) : impl_(std::move(other.impl_)){}\r
-\r
-       template<typename U>\r
-       safe_ptr(const safe_ptr<U>& other, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(other.impl_){}  // noexcept\r
-               \r
-       template<typename U>    \r
-       safe_ptr(const U& impl, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0)\r
-               : impl_(std::make_shared<U>(impl)) {}\r
-       \r
-       template<typename U, typename D>                \r
-       safe_ptr(const U& impl, D dtor, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0)\r
-               : impl_(new U(impl), dtor) {}\r
-\r
-       template<typename U>    \r
-       safe_ptr(U&& impl, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0)\r
-               : impl_(std::make_shared<U>(std::forward<U>(impl))) {}\r
-\r
-       template<typename U, typename D>        \r
-       safe_ptr(U&& impl, D dtor, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0)\r
-               : impl_(new U(std::forward<U>(impl)), dtor) {}\r
-                       \r
-       template<typename U>    \r
-       explicit safe_ptr(const std::shared_ptr<U>& impl, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(impl)\r
-       {\r
-               if(!impl_)\r
-                       throw std::invalid_argument("impl");\r
-       }\r
-       \r
-       template<typename U>    \r
-       explicit safe_ptr(std::shared_ptr<U>&& impl, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(std::move(impl))\r
-       {\r
-               if(!impl_)\r
-                       throw std::invalid_argument("impl");\r
-       }\r
-\r
-       template<typename U>    \r
-       explicit safe_ptr(U* impl, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(impl)\r
-       {\r
-               if(!impl_)\r
-                       throw std::invalid_argument("impl");\r
-       }\r
-\r
-       template<typename U, typename D>        \r
-       explicit safe_ptr(U* impl, D dtor, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(impl, dtor)\r
-       {\r
-               if(!impl_)\r
-                       throw std::invalid_argument("impl");\r
-       }\r
-\r
-       template<typename U>\r
-       typename std::enable_if<std::is_convertible<U*, T*>::value, safe_ptr<T>&>::type\r
-       operator=(const safe_ptr<U>& other)\r
-       {\r
-               safe_ptr<T> temp(other);\r
-               temp.swap(*this);\r
-               return *this;\r
-       }\r
-\r
-       template <typename U>\r
-       typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, safe_ptr<T>&>::type\r
-       operator=(U&& impl)\r
-       {\r
-               safe_ptr<T> temp(std::forward<T>(impl));\r
-               temp.swap(*this);\r
-               return *this;\r
-       }\r
-\r
-       T& operator*() const // noexcept\r
-       {\r
-               return *impl_.get();\r
-       } \r
-\r
-       T* operator->() const // noexcept\r
-       {\r
-               return impl_.get();\r
-       } \r
-\r
-       T* get() const // noexcept\r
-       {\r
-               return impl_.get();\r
-       }  \r
-\r
-       bool unique() const { return impl_.unique();}  // noexcept\r
-\r
-       long use_count() const { return impl_.use_count();}  // noexcept\r
-                               \r
-       void swap(safe_ptr& other) { impl_.swap(other.impl_); }  // noexcept\r
-       \r
-       operator const std::shared_ptr<T>&() const { return impl_;}  // noexcept\r
-\r
-       template<class U>\r
-       bool owner_before(const safe_ptr<T>& ptr){ return impl_.owner_before(ptr.impl_); }  // noexcept\r
-\r
-       template<class U>\r
-       bool owner_before(const std::shared_ptr<U>& ptr){ return impl_.owner_before(ptr); }  // noexcept\r
-       \r
-       template<class D, class U> \r
-       D* get_deleter(safe_ptr<U> const& ptr) { return impl_.get_deleter(); }  // noexcept\r
+    typedef T  element_type;\r
+\r
+    safe_ptr(); // will construct new T object using make_safe<T>()\r
+\r
+    safe_ptr(const safe_ptr& other) \r
+        : p_(other.p_)\r
+    {\r
+    }\r
+\r
+    template<typename U>\r
+    safe_ptr(const safe_ptr<U>& other, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
+        : p_(other.p_)\r
+    {\r
+    }\r
+\r
+    safe_ptr(safe_ptr&& other) \r
+        : p_(other.p_)\r
+    {\r
+    }\r
+\r
+    template<typename U>\r
+    safe_ptr(safe_ptr<U>&& other, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
+        : p_(other.p_)\r
+    {\r
+    }\r
+\r
+    template<typename U>    \r
+    safe_ptr(U&& v, typename std::enable_if<std::is_convertible<U*, T*>::value, void>::type* = 0)\r
+        : p_(std::make_shared<U>(std::forward<U>(v))) \r
+    {\r
+    }\r
+\r
+    template<typename U, typename D>    \r
+    safe_ptr(U&& v, D d, typename std::enable_if<std::is_convertible<U*, T*>::value, void>::type* = 0)\r
+        : p_(new U(std::forward<U>(v)), d) \r
+    {\r
+    }\r
+\r
+    template<typename U>    \r
+    explicit safe_ptr(const std::shared_ptr<U>& p, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
+        : p_(p)\r
+    {\r
+        if(!p)\r
+            throw std::invalid_argument("p");\r
+    }\r
+\r
+    template<typename U>    \r
+    explicit safe_ptr(std::shared_ptr<U>&& p, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
+        : p_(std::move(p))\r
+    {\r
+        if(!p_)\r
+            throw std::invalid_argument("p");\r
+    }\r
+\r
+    template<typename U>    \r
+    explicit safe_ptr(U* p, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
+        : p_(p)\r
+    {\r
+        if(!p)\r
+            throw std::invalid_argument("p");\r
+    }\r
+\r
+    template<typename U, typename D>    \r
+    explicit safe_ptr(U* p, D d, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
+        : p_(p, d)\r
+    {\r
+        if(!p)\r
+            throw std::invalid_argument("p");\r
+    }\r
+    \r
+    template<typename U>\r
+    typename std::enable_if<std::is_convertible<U*, T*>::value, safe_ptr&>::type\r
+    operator=(const safe_ptr<U>& other)\r
+    {\r
+        safe_ptr(other).swap(*this);\r
+        return *this;\r
+    }\r
+\r
+    template<typename U>\r
+    typename std::enable_if<std::is_convertible<U*, T*>::value, safe_ptr&>::type\r
+    operator=(safe_ptr<U>&& other)\r
+    {\r
+        safe_ptr<T>(std::move(other)).swap(*this);\r
+        return *this;\r
+    }\r
+\r
+    template <typename U>\r
+    typename std::enable_if<std::is_convertible<U*, T*>::value, safe_ptr&>::type\r
+    operator=(U&& v)\r
+    {\r
+        safe_ptr(std::forward<U>(v)).swap(*this);\r
+        return *this;\r
+    }\r
+\r
+    T& operator*() const \r
+    { \r
+        return *p_.get();\r
+    }\r
+\r
+    T* operator->() const \r
+    { \r
+        return p_.get();\r
+    }\r
+\r
+    T* get() const \r
+    { \r
+        return p_.get();\r
+    }\r
+\r
+    bool unique() const \r
+    { \r
+        return p_.unique();\r
+    }\r
+\r
+    long use_count() const \r
+    {\r
+        return p_.use_count();\r
+    }\r
+\r
+    void swap(safe_ptr& other) \r
+    { \r
+        p_.swap(other.p_); \r
+    } \r
+\r
+    operator std::shared_ptr<T>() const \r
+    { \r
+        return p_;\r
+    }\r
+\r
+    operator std::weak_ptr<T>() const \r
+    { \r
+        return std::weak_ptr<T>(p_);\r
+    }\r
+    \r
+    template<class U>\r
+    bool owner_before(const safe_ptr& ptr)\r
+    { \r
+        return p_.owner_before(ptr.p_); \r
+    }\r
+\r
+    template<class U>\r
+    bool owner_before(const std::shared_ptr<U>& ptr)\r
+    { \r
+        return p_.owner_before(ptr); \r
+    }\r
+\r
+    template<class D, class U> \r
+    D* get_deleter(safe_ptr<U> const& ptr) \r
+    { \r
+        return p_.get_deleter(); \r
+    }\r
+\r
+private:    \r
+    std::shared_ptr<T> p_;\r
 };\r
 \r
 template<class T, class U>\r
-bool operator==(const std::shared_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
+bool operator==(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
+{\r
+    return a.get() == b.get();\r
+}\r
+\r
+template<class T, class U>\r
+bool operator==(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
+{\r
+    return a.get() == b.get();\r
+}\r
+\r
+template<class T, class U>\r
+bool operator==(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
+{\r
+    return a.get() == b.get();\r
+}\r
+\r
+template<class T, class U>\r
+bool operator!=(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
+{\r
+    return a.get() != b.get();\r
+}\r
+\r
+template<class T, class U>\r
+bool operator!=(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
+{\r
+    return a.get() != b.get();\r
+}\r
+\r
+template<class T, class U>\r
+bool operator!=(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
 {\r
-       return a.get() == b.get();\r
+    return a.get() != b.get();\r
 }\r
 \r
 template<class T, class U>\r
-bool operator==(const safe_ptr<T>& a, const std::shared_ptr<U>& b)  // noexcept\r
+bool operator<(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
 {\r
-       return a.get() == b.get();\r
+    return a.get() < b.get();\r
 }\r
 \r
 template<class T, class U>\r
-bool operator==(const safe_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
+bool operator<(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
 {\r
-       return a.get() == b.get();\r
+    return a.get() < b.get();\r
 }\r
 \r
 template<class T, class U>\r
-bool operator!=(const std::shared_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
+bool operator<(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
 {\r
-       return a.get() != b.get();\r
+    return a.get() < b.get();\r
 }\r
 \r
 template<class T, class U>\r
-bool operator!=(const safe_ptr<T>& a, const std::shared_ptr<U>& b)  // noexcept\r
+bool operator>(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
 {\r
-       return a.get() != b.get();\r
+    return a.get() > b.get();\r
 }\r
 \r
 template<class T, class U>\r
-bool operator!=(const safe_ptr<T>& a, const safe_ptr<U>& b) // noexcept\r
+bool operator>(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
 {\r
-       return a.get() != b.get();\r
+    return a.get() > b.get();\r
 }\r
 \r
 template<class T, class U>\r
-bool operator<(const safe_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
+bool operator>(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
 {\r
-       return a.get() < b.get();\r
+    return a.get() > b.get();\r
 }\r
 \r
 template<class T, class U>\r
-bool operator>(const safe_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
+bool operator>=(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
 {\r
-       return a.get() > b.get();\r
+    return a.get() >= b.get();\r
 }\r
 \r
 template<class T, class U>\r
-bool operator>=(const safe_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
+bool operator>=(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
 {\r
-       return a.get() >= b.get();\r
+    return a.get() >= b.get();\r
 }\r
 \r
 template<class T, class U>\r
-bool operator<=(const safe_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
+bool operator>=(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
 {\r
-       return a.get() <= b.get();\r
+    return a.get() >= b.get();\r
+}\r
+\r
+template<class T, class U>\r
+bool operator<=(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
+{\r
+    return a.get() <= b.get();\r
+}\r
+\r
+template<class T, class U>\r
+bool operator<=(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
+{\r
+    return a.get() <= b.get();\r
+}\r
+\r
+template<class T, class U>\r
+bool operator<=(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
+{\r
+    return a.get() <= b.get();\r
 }\r
 \r
 template<class E, class T, class U>\r
-std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& out,    const safe_ptr<U>& p)\r
+std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& out, const safe_ptr<U>& p)\r
 {\r
-       return out << p.get();\r
+    return out << p.get();\r
 }\r
 \r
 template<class T> \r
-void swap(safe_ptr<T>& a, safe_ptr<T>& b)  // noexcept\r
+void swap(safe_ptr<T>& a, safe_ptr<T>& b)\r
 {\r
-       a.swap(b);\r
+    a.swap(b);\r
 }\r
 \r
 template<class T> \r
-T* get_pointer(safe_ptr<T> const& p)  // noexcept\r
+T* get_pointer(safe_ptr<T> const& p)\r
 {\r
-       return p.get();\r
+    return p.get();\r
 }\r
 \r
 template <class T, class U>\r
-safe_ptr<T> static_pointer_cast(const safe_ptr<U>& p)  // noexcept\r
+safe_ptr<T> static_pointer_cast(const safe_ptr<U>& p)\r
 {\r
-       return safe_ptr<T>(std::static_pointer_cast<T>(std::shared_ptr<U>(p)));\r
+    return safe_ptr<T>(std::static_pointer_cast<T>(std::shared_ptr<U>(p)));\r
 }\r
 \r
 template <class T, class U>\r
-safe_ptr<T> const_pointer_cast(const safe_ptr<U>& p)  // noexcept\r
+safe_ptr<T> const_pointer_cast(const safe_ptr<U>& p)\r
 {\r
-       return safe_ptr<T>(std::const_pointer_cast<T>(std::shared_ptr<U>(p)));\r
+    return safe_ptr<T>(std::const_pointer_cast<T>(std::shared_ptr<U>(p)));\r
 }\r
 \r
 template <class T, class U>\r
 safe_ptr<T> dynamic_pointer_cast(const safe_ptr<U>& p)\r
 {\r
-       auto temp = std::dynamic_pointer_cast<T>(std::shared_ptr<U>(p));\r
-       if(!temp)\r
-               throw std::bad_cast();\r
-       return safe_ptr<T>(temp);\r
+    auto temp = std::dynamic_pointer_cast<T>(std::shared_ptr<U>(p));\r
+    if(!temp)\r
+        throw std::bad_cast();\r
+    return safe_ptr<T>(std::move(temp));\r
 }\r
 \r
+//\r
+// enable_safe_this \r
+//\r
+// A safe_ptr version of enable_shared_from_this.\r
+// So that an object may get safe_ptr objects to itself.\r
+//\r
+\r
+template<class T>\r
+class enable_safe_from_this : public std::enable_shared_from_this<T>\r
+{\r
+public:\r
+    safe_ptr<T> safe_from_this() \r
+    {\r
+        return safe_ptr<T>(this->shared_from_this());\r
+    }\r
+\r
+    safe_ptr<T const> safe_from_this() const \r
+    {\r
+        return safe_ptr<T const>(this->shared_from_this());\r
+    }\r
+protected:\r
+    enable_safe_from_this()\r
+    {\r
+    }\r
+    \r
+    enable_safe_from_this(const enable_safe_from_this&)\r
+    {\r
+    }\r
+    \r
+    enable_safe_from_this& operator=(const enable_safe_from_this&)\r
+    {        \r
+        return *this;\r
+    }\r
+    \r
+    ~enable_safe_from_this ()\r
+    {\r
+    }\r
+};\r
+\r
+//\r
+// make_safe\r
+//\r
+// safe_ptr equivalents to make_shared\r
+//\r
+\r
 template<typename T>\r
-safe_ptr<T> make_safe(const std::shared_ptr<T>& ptr)\r
+safe_ptr<T> make_safe_ptr(const std::shared_ptr<T>& ptr)\r
 {\r
        return safe_ptr<T>(ptr);\r
 }\r
 \r
 template<typename T>\r
-safe_ptr<T> make_safe(std::shared_ptr<T>&& ptr)\r
+safe_ptr<T> make_safe_ptr(std::shared_ptr<T>&& ptr)\r
 {\r
-       return safe_ptr<T>(std::move(ptr));\r
+       return safe_ptr<T>(ptr);\r
 }\r
 \r
 template<typename T>\r
 safe_ptr<T> make_safe()\r
 {\r
-       return safe_ptr<T>();\r
+    return safe_ptr<T>(std::make_shared<T>());\r
 }\r
 \r
 template<typename T, typename P0>\r
 safe_ptr<T> make_safe(P0&& p0)\r
 {\r
-       return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0)));\r
+    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0)));\r
 }\r
 \r
 template<typename T, typename P0, typename P1>\r
 safe_ptr<T> make_safe(P0&& p0, P1&& p1)\r
 {\r
-       return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1)));\r
+    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1)));\r
 }\r
 \r
 template<typename T, typename P0, typename P1, typename P2>\r
 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2)\r
 {\r
-       return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)));\r
+    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)));\r
 }\r
 \r
 template<typename T, typename P0, typename P1, typename P2, typename P3>\r
 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3)\r
 {\r
-       return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3)));\r
+    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3)));\r
 }\r
 \r
 template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4>\r
 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4)\r
 {\r
-       return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4)));\r
+    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4)));\r
 }\r
 \r
 template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>\r
 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5)\r
 {\r
-       return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5)));\r
+    return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5)));\r
 }\r
 \r
-}
\ No newline at end of file
+template<typename T>\r
+safe_ptr<T>::safe_ptr() \r
+    : p_(make_safe<T>())\r
+{\r
+} \r
+\r
+} // namespace
\ No newline at end of file
index c30bcf94ba43bc6eabe27ffd718109bfa15acce1..4c5e79561917622bff361921239305d2234be29d 100644 (file)
@@ -20,6 +20,7 @@
 #pragma once\r
 \r
 #include "../log/log.h"\r
+#include "../exception/exceptions.h"\r
 \r
 #ifdef _MSC_VER\r
 #define _CASPAR_DBG_BREAK _CrtDbgBreak()\r
@@ -29,7 +30,9 @@
 \r
 #define CASPAR_VERIFY_EXPR_STR(str) #str\r
 \r
-#define CASPAR_VERIFY(expr) do{if(!(expr)){ CASPAR_LOG(warning) << "Assertion Failed: " << \\r
+#define CASPAR_VERIFY(expr, exception) do{if(!(expr)){ BOOST_THROW_EXCEPTION(exception << msg_info(CASPAR_VERIFY_EXPR_STR(expr)));}}while(0);\r
+\r
+#define CASPAR_ASSERT2(expr) do{if(!(expr)){ CASPAR_LOG(warning) << "Assertion Failed: " << \\r
        CASPAR_VERIFY_EXPR_STR(expr) << " " \\r
        << "file:" << __FILE__ << " " \\r
        << "line:" << __LINE__ << " "; \\r
@@ -37,7 +40,7 @@
        }}while(0);\r
 \r
 #ifdef _DEBUG\r
-#define CASPAR_ASSERT(expr) CASPAR_VERIFY(expr)\r
+#define CASPAR_ASSERT(expr) CASPAR_ASSERT2(expr)\r
 #else\r
 #define CASPAR_ASSERT(expr)\r
 #endif
\ No newline at end of file
index 2cd385119b51193e9923ce08f9d6d4804d6f8d70..95c1d3489284c4cf4cb54a19b6c5827054ed07bb 100644 (file)
 #include <string>\r
 #include <vector>\r
 \r
+#include <agents.h>\r
+#include <agents_extras.h>\r
+#include <concrt.h>\r
+#include <concrt_extras.h>\r
+#include <ppl.h>\r
+\r
 #include <tbb/atomic.h>\r
 #include <tbb/concurrent_queue.h>\r
 #include <tbb/concurrent_unordered_map.h>\r
index 9f83317d91f2645e33e13530e6c354d93c549ee5..a94f154207790a79602f3b60358f4f714121374c 100644 (file)
@@ -99,13 +99,13 @@ safe_ptr<device_buffer> ogl_device::allocate_device_buffer(size_t width, size_t
                        throw;\r
                }\r
        }\r
-       return make_safe(buffer);\r
+       return make_safe_ptr(buffer);\r
 }\r
                                \r
 safe_ptr<device_buffer> ogl_device::create_device_buffer(size_t width, size_t height, size_t stride)\r
 {\r
-       CASPAR_VERIFY(stride > 0 && stride < 5);\r
-       CASPAR_VERIFY(width > 0 && height > 0);\r
+       CASPAR_VERIFY(stride > 0 && stride < 5, invalid_argument());\r
+       CASPAR_VERIFY(width > 0 && height > 0, invalid_argument());\r
        auto& pool = device_pools_[stride-1][((width << 16) & 0xFFFF0000) | (height & 0x0000FFFF)];\r
        std::shared_ptr<device_buffer> buffer;\r
        if(!pool->items.try_pop(buffer))                \r
@@ -152,13 +152,13 @@ safe_ptr<host_buffer> ogl_device::allocate_host_buffer(size_t size, host_buffer:
                }\r
        }\r
 \r
-       return make_safe(buffer);\r
+       return make_safe_ptr(buffer);\r
 }\r
        \r
 safe_ptr<host_buffer> ogl_device::create_host_buffer(size_t size, host_buffer::usage_t usage)\r
 {\r
-       CASPAR_VERIFY(usage == host_buffer::write_only || usage == host_buffer::read_only);\r
-       CASPAR_VERIFY(size > 0);\r
+       CASPAR_VERIFY(usage == host_buffer::write_only || usage == host_buffer::read_only, invalid_argument());\r
+       CASPAR_VERIFY(size > 0, invalid_argument());\r
        auto& pool = host_pools_[usage][size];\r
        std::shared_ptr<host_buffer> buffer;\r
        if(!pool->items.try_pop(buffer))        \r
index 6d89630c2c2da0a54a550ac7b2537109d1c1d3ca..dc59a74162b6ed417a1cab17c7a367a021bd46b7 100644 (file)
@@ -261,7 +261,7 @@ safe_ptr<shader> get_image_shader(ogl_device& ogl, bool& blend_modes)
        if(g_shader)\r
        {\r
                blend_modes = g_blend_modes;\r
-               return make_safe(g_shader);\r
+               return make_safe_ptr(g_shader);\r
        }\r
                \r
        try\r
@@ -288,7 +288,7 @@ safe_ptr<shader> get_image_shader(ogl_device& ogl, bool& blend_modes)
        }\r
 \r
        blend_modes = g_blend_modes;\r
-       return make_safe(g_shader);\r
+       return make_safe_ptr(g_shader);\r
 }\r
 \r
 }}
\ No newline at end of file
index cae3c0bcf2c56c5578e7a00492a562acab5d4d87..d9a80f8926449aec359ac8e6101d8fbe2d011a43 100644 (file)
 #include <common/exception/exceptions.h>\r
 #include <common/utility/move_on_copy.h>\r
 \r
+#include <concrt_extras.h>\r
+\r
 namespace caspar { namespace core {\r
        \r
 std::vector<const producer_factory_t> g_factories;\r
        \r
+struct destruction_context\r
+{\r
+       std::shared_ptr<frame_producer> producer;\r
+       Concurrency::event                              event;\r
+\r
+       destruction_context(std::shared_ptr<frame_producer>&& producer) : producer(producer){}\r
+};\r
+\r
+void __cdecl destroy_producer(LPVOID lpParam)\r
+{\r
+       auto destruction = std::unique_ptr<destruction_context>(static_cast<destruction_context*>(lpParam));\r
+       \r
+       try\r
+       {               \r
+               if(destruction->producer.unique())\r
+               {\r
+                       Concurrency::scoped_oversubcription_token oversubscribe;\r
+                       destruction->producer.reset();\r
+               }\r
+               else\r
+                       CASPAR_LOG(warning) << destruction->producer->print() << " Not destroyed asynchronously.";              \r
+       }\r
+       catch(...)\r
+       {\r
+               CASPAR_LOG_CURRENT_EXCEPTION();\r
+       }\r
+       \r
+       destruction->event.set();\r
+}\r
+\r
+void __cdecl destroy_and_wait_producer(LPVOID lpParam)\r
+{\r
+       try\r
+       {\r
+               auto destruction = static_cast<destruction_context*>(lpParam);\r
+               Concurrency::CurrentScheduler::ScheduleTask(destroy_producer, lpParam);\r
+               if(destruction->event.wait(1000) == Concurrency::COOPERATIVE_WAIT_TIMEOUT)\r
+                       CASPAR_LOG(warning) << " Potential destruction deadlock detected. Might leak resources.";\r
+       }\r
+       catch(...)\r
+       {\r
+               CASPAR_LOG_CURRENT_EXCEPTION();\r
+       }\r
+}\r
+\r
 class destroy_producer_proxy : public frame_producer\r
 {\r
-       safe_ptr<frame_producer> producer_;\r
-       executor& destroy_context_;\r
+       std::shared_ptr<frame_producer> producer_;\r
 public:\r
-       destroy_producer_proxy(executor& destroy_context, const safe_ptr<frame_producer>& producer) \r
-               : producer_(producer)\r
-               , destroy_context_(destroy_context){}\r
+       destroy_producer_proxy(const std::shared_ptr<frame_producer>& producer) \r
+               : producer_(producer){}\r
 \r
        ~destroy_producer_proxy()\r
        {               \r
-               if(destroy_context_.size() > 4)\r
-                       CASPAR_LOG(error) << L" Potential destroyer deadlock.";\r
-\r
-               // Hacks to bypass compiler bugs.\r
-               auto mov_producer = make_move_on_copy<safe_ptr<frame_producer>>(std::move(producer_));\r
-               auto empty_producer = frame_producer::empty();\r
-               destroy_context_.begin_invoke([=]\r
-               {                       \r
-                       //if(!mov_producer.value.unique())\r
-                       //      CASPAR_LOG(debug) << mov_producer.value->print() << L" Not destroyed on safe asynchronous destruction thread.";\r
-                       //else\r
-                       //      CASPAR_LOG(debug) << mov_producer.value->print() << L" Destroying on safe asynchronous destruction thread.";\r
-       \r
-                       mov_producer.value = empty_producer;\r
-               });\r
+               Concurrency::CurrentScheduler::ScheduleTask(destroy_producer, new destruction_context(std::move(producer_)));\r
        }\r
 \r
        virtual safe_ptr<basic_frame>           receive(int hints)                                                                                              {return producer_->receive(hints);}\r
@@ -73,9 +104,9 @@ public:
        virtual int64_t                                         nb_frames() const                                                                                               {return producer_->nb_frames();}\r
 };\r
 \r
-safe_ptr<core::frame_producer> create_destroy_producer_proxy(executor& destroy_context, const safe_ptr<frame_producer>& producer)\r
+safe_ptr<core::frame_producer> create_destroy_producer_proxy(const safe_ptr<frame_producer>& producer)\r
 {\r
-       return make_safe<destroy_producer_proxy>(destroy_context, producer);\r
+       return make_safe<destroy_producer_proxy>(producer);\r
 }\r
 \r
 class last_frame_producer : public frame_producer\r
index 3cf7e50107fcc7ad38a2acf8de243e6569b9ac27..067a4ee5f9cfe490cc75a94102d8b965b5428537 100644 (file)
@@ -71,7 +71,7 @@ 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
 \r
-safe_ptr<core::frame_producer> create_destroy_producer_proxy(executor& destroy_context, const safe_ptr<frame_producer>& producer);\r
+safe_ptr<core::frame_producer> create_destroy_producer_proxy(const safe_ptr<frame_producer>& producer);\r
 \r
 template<typename T>\r
 typename std::decay<T>::type get_param(const std::wstring& name, const std::vector<std::wstring>& params, T fail_value)\r
index e03c83d4f8bb1c206929a908136cfd08e9989709..519df14b10850b7479aec5f0f65f331dbb69b1d2 100644 (file)
@@ -23,7 +23,7 @@
 \r
 #include <core/producer/frame/basic_frame.h>\r
 \r
-#include <tbb/parallel_invoke.h>\r
+#include <ppl.h>\r
 \r
 namespace caspar { namespace core {    \r
 \r
@@ -47,7 +47,7 @@ struct separated_producer : public frame_producer
        \r
        virtual safe_ptr<basic_frame> receive(int hints)\r
        {\r
-               tbb::parallel_invoke(\r
+               Concurrency::parallel_invoke(\r
                [&]\r
                {\r
                        if(fill_ == core::basic_frame::late())\r
index 9fe30bbd45b917d03a901138cba211c987a16e9f..db82c2ce96181b3fbc8690e7f8f09afdee719ba8 100644 (file)
@@ -34,7 +34,7 @@
 \r
 #include <boost/foreach.hpp>\r
 \r
-#include <tbb/parallel_for_each.h>\r
+#include <ppl.h>\r
 \r
 #include <map>\r
 #include <set>\r
@@ -60,7 +60,7 @@ public:
                        BOOST_FOREACH(auto& layer, layers_)                     \r
                                frames[layer.first] = basic_frame::empty();     \r
 \r
-                       tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer) \r
+                       Concurrency::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer) \r
                        {\r
                                frames[layer.first] = layer.second.receive();   \r
                        });\r
@@ -78,7 +78,7 @@ public:
        {\r
                channel_.execution().invoke([&]\r
                {\r
-                       layers_[index].load(create_destroy_producer_proxy(channel_.destruction(), producer), preview, auto_play_delta);\r
+                       layers_[index].load(create_destroy_producer_proxy(producer), preview, auto_play_delta);\r
                }, high_priority);\r
        }\r
 \r
index 24cf9287533810a4854657b8f5cab816ac344fb8..c0bd9b1662ce9d13f77da79c5d0481d6672c97b7 100644 (file)
@@ -26,7 +26,7 @@
 #include <core/producer/frame/basic_frame.h>\r
 #include <core/producer/frame/frame_transform.h>\r
 \r
-#include <tbb/parallel_invoke.h>\r
+#include <ppl.h>\r
 \r
 #include <boost/assign.hpp>\r
 \r
@@ -74,7 +74,7 @@ struct transition_producer : public frame_producer
                auto dest = basic_frame::empty();\r
                auto source = basic_frame::empty();\r
 \r
-               tbb::parallel_invoke(\r
+               Concurrency::parallel_invoke(\r
                [&]\r
                {\r
                        dest = receive_and_follow(dest_producer_, hints);\r
index 476a73eb32190af8e0f2ba8954ebe2eb1a49829e..e48f857326ffdee91f9b19ec664b1f3c3815e0b1 100644 (file)
@@ -78,8 +78,6 @@ public:
                // Stop context before destroying devices.\r
                context_.execution().stop();\r
                context_.execution().join();\r
-               context_.destruction().stop();\r
-               context_.destruction().join();\r
        }\r
 \r
        void tick()\r
@@ -152,7 +150,7 @@ public:
 video_channel::video_channel(int index, const video_format_desc& format_desc, ogl_device& ogl) : impl_(new implementation(index, format_desc, ogl)){}\r
 video_channel::video_channel(video_channel&& other) : impl_(std::move(other.impl_)){}\r
 safe_ptr<stage> video_channel::stage() { return impl_->stage_;} \r
-safe_ptr<mixer> video_channel::mixer() { return make_safe(impl_->mixer_);} \r
+safe_ptr<mixer> video_channel::mixer() { return make_safe_ptr(impl_->mixer_);} \r
 safe_ptr<output> video_channel::output() { return impl_->output_;} \r
 video_format_desc video_channel::get_video_format_desc() const{return impl_->context_.get_format_desc();}\r
 void video_channel::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
index 84806b2a3c8db3705a0aa7713026415c5fc90f10..d46e689ae32b57bda8a1821876a426f71e7c3143 100644 (file)
@@ -10,18 +10,15 @@ struct video_channel_context::implementation
        const int                                       index_;\r
        video_format_desc                       format_desc_;\r
        executor                                        execution_;\r
-       executor                                        destruction_;\r
        ogl_device&                                     ogl_;\r
 \r
        implementation(int index, ogl_device& ogl, const video_format_desc& format_desc)\r
                : index_(index)\r
                , format_desc_(format_desc)\r
                , execution_(print() + L"/execution")\r
-               , destruction_(print() + L"/destruction")\r
                , ogl_(ogl)\r
        {\r
                execution_.set_priority_class(above_normal_priority_class);\r
-               destruction_.set_priority_class(below_normal_priority_class);\r
        }\r
 \r
        std::wstring print() const\r
@@ -49,9 +46,15 @@ void video_channel_context::set_format_desc(const video_format_desc& format_desc
        impl_->format_desc_ = format_desc;\r
 }\r
 \r
-executor& video_channel_context::execution() {return impl_->execution_;}\r
-executor& video_channel_context::destruction() {return impl_->destruction_;}\r
-ogl_device& video_channel_context::ogl() { return impl_->ogl_;}\r
+executor& video_channel_context::execution()\r
+{\r
+       return impl_->execution_;\r
+}\r
+\r
+ogl_device& video_channel_context::ogl()\r
+{\r
+       return impl_->ogl_;\r
+}\r
 \r
 std::wstring video_channel_context::print() const\r
 {\r
index 4c06e3a9f3801dd9fafee0c48bd8232bec31d2c3..97812952f086e662487dbe70ab55c81fbffb37e1 100644 (file)
@@ -29,7 +29,6 @@ public:
        video_format_desc       get_format_desc();\r
        void                            set_format_desc(const video_format_desc& format_desc);\r
        executor&                       execution();\r
-       executor&                       destruction();\r
        ogl_device&                     ogl();\r
        std::wstring            print() const;\r
 private:\r
index d4abdfa526204955e90d243f4dbd97fa3ee2efc5..dcfbde7f3afcf5dde5bcbe44f6d99e5574b275b8 100644 (file)
@@ -319,7 +319,7 @@ public:
 \r
                        std::shared_ptr<core::read_frame> frame;        \r
                        video_frame_buffer_.pop(frame);                                 \r
-                       schedule_next_video(make_safe(frame));  \r
+                       schedule_next_video(make_safe_ptr(frame));      \r
                }\r
                catch(...)\r
                {\r
@@ -352,7 +352,7 @@ public:
                        {\r
                                std::shared_ptr<core::read_frame> frame;\r
                                audio_frame_buffer_.pop(frame);\r
-                               schedule_next_audio(make_safe(frame));  \r
+                               schedule_next_audio(make_safe_ptr(frame));      \r
                        }\r
                }\r
                catch(...)\r
index a2c27983ae11df23bf141e9d3401d2ad93cd62dd..34e2dd68eac8b17b57831571cb320e1a418b0a6f 100644 (file)
@@ -4,7 +4,7 @@
 \r
 \r
  /* File created by MIDL compiler version 7.00.0555 */\r
-/* at Tue Oct 18 13:46:11 2011\r
+/* at Tue Oct 18 16:33:45 2011\r
  */\r
 /* Compiler settings for interop\DeckLinkAPI.idl:\r
     Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 \r
index ed4bb97a7434fe5302d14776b0bd3045225d3272..ef725e0b9d6148afd3588b384a9f74f02fcdc524 100644 (file)
@@ -6,7 +6,7 @@
 \r
 \r
  /* File created by MIDL compiler version 7.00.0555 */\r
-/* at Tue Oct 18 13:46:11 2011\r
+/* at Tue Oct 18 16:33:45 2011\r
  */\r
 /* Compiler settings for interop\DeckLinkAPI.idl:\r
     Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 \r
index 902d78e210e30e1f1dd9681045747a47b7f14a0b..34d8913fde9d1d830d359ca208c97c9793abcf25 100644 (file)
@@ -39,7 +39,8 @@
 #include <core/producer/frame/frame_transform.h>\r
 #include <core/producer/frame/frame_factory.h>\r
 \r
-#include <tbb/concurrent_queue.h>\r
+#include <agents.h>\r
+#include <agents_extras.h>\r
 \r
 #include <boost/algorithm/string.hpp>\r
 #include <boost/foreach.hpp>\r
@@ -73,41 +74,32 @@ extern "C"
 \r
 namespace caspar { namespace decklink {\r
                \r
+typedef std::pair<CComPtr<IDeckLinkVideoInputFrame>, CComPtr<IDeckLinkAudioInputPacket>> frame_packet;\r
+\r
 class decklink_producer : boost::noncopyable, public IDeckLinkInputCallback\r
 {      \r
-       CComPtr<IDeckLink>                                                                                      decklink_;\r
-       CComQIPtr<IDeckLinkInput>                                                                       input_;\r
-       \r
-       const std::wstring                                                                                      model_name_;\r
-       const core::video_format_desc                                                           format_desc_;\r
-       const size_t                                                                                            device_index_;\r
+       Concurrency::ITarget<frame_packet>&     target_;\r
 \r
-       std::shared_ptr<diagnostics::graph>                                                     graph_;\r
-       boost::timer                                                                                            tick_timer_;\r
-       boost::timer                                                                                            frame_timer_;\r
-               \r
-       safe_ptr<core::frame_factory>                                                           frame_factory_;\r
-\r
-       tbb::concurrent_bounded_queue<safe_ptr<core::basic_frame>>      frame_buffer_;\r
+       CComPtr<IDeckLink>                                      decklink_;\r
+       CComQIPtr<IDeckLinkInput>                       input_;\r
+       \r
+       const std::wstring                                      model_name_;\r
+       const core::video_format_desc           format_desc_;\r
+       const size_t                                            device_index_;\r
 \r
-       std::exception_ptr                                                                                      exception_;\r
-       ffmpeg::filter                                                                                          filter_;\r
-               \r
-       ffmpeg::frame_muxer                                                                                     muxer_;\r
+       std::shared_ptr<diagnostics::graph>     graph_;\r
+       boost::timer                                            tick_timer_;\r
+       boost::timer                                            frame_timer_;\r
 \r
 public:\r
-       decklink_producer(const core::video_format_desc& format_desc, size_t device_index, const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filter)\r
-               : decklink_(get_device(device_index))\r
+       decklink_producer(Concurrency::ITarget<frame_packet>& target, const core::video_format_desc& format_desc, size_t device_index)\r
+               : target_(target)\r
+               , decklink_(get_device(device_index))\r
                , input_(decklink_)\r
                , model_name_(get_model_name(decklink_))\r
                , format_desc_(format_desc)\r
                , device_index_(device_index)\r
-               , frame_factory_(frame_factory)\r
-               , filter_(filter)\r
-               , muxer_(ffmpeg::double_rate(filter) ? format_desc.fps * 2.0 : format_desc.fps, frame_factory)\r
-       {\r
-               frame_buffer_.set_capacity(2);\r
-               \r
+       {               \r
                graph_ = diagnostics::create_graph(boost::bind(&decklink_producer::print, this));\r
                graph_->add_guide("tick-time", 0.5);\r
                graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));   \r
@@ -115,7 +107,7 @@ public:
                graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
                graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));\r
                graph_->set_color("output-buffer", diagnostics::color(0.0f, 1.0f, 0.0f));\r
-               \r
+\r
                auto display_mode = get_display_mode(input_, format_desc_.format, bmdFormat8BitYUV, bmdVideoInputFlagDefault);\r
                \r
                // NOTE: bmdFormat8BitARGB is currently not supported by any decklink card. (2011-05-08)\r
@@ -144,6 +136,7 @@ public:
 \r
        ~decklink_producer()\r
        {\r
+               Concurrency::scoped_oversubcription_token oversubscribe;\r
                if(input_ != nullptr) \r
                {\r
                        input_->StopStreams();\r
@@ -151,6 +144,7 @@ public:
                }\r
        }\r
 \r
+\r
        virtual HRESULT STDMETHODCALLTYPE       QueryInterface (REFIID, LPVOID*)        {return E_NOINTERFACE;}\r
        virtual ULONG STDMETHODCALLTYPE         AddRef ()                                                       {return 1;}\r
        virtual ULONG STDMETHODCALLTYPE         Release ()                                                      {return 1;}\r
@@ -162,110 +156,72 @@ public:
 \r
        virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame* video, IDeckLinkAudioInputPacket* audio)\r
        {       \r
-               if(!video)\r
-                       return S_OK;\r
-\r
-               try\r
-               {\r
-                       graph_->update_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5);\r
-                       tick_timer_.restart();\r
-\r
-                       frame_timer_.restart();\r
-\r
-                       void* bytes = nullptr;\r
-                       if(FAILED(video->GetBytes(&bytes)) || !bytes)\r
-                               return S_OK;\r
-                       \r
-                       safe_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);     \r
-                       avcodec_get_frame_defaults(av_frame.get());\r
-                                               \r
-                       av_frame->data[0]                       = reinterpret_cast<uint8_t*>(bytes);\r
-                       av_frame->linesize[0]           = video->GetRowBytes();                 \r
-                       av_frame->format                        = PIX_FMT_UYVY422;\r
-                       av_frame->width                         = video->GetWidth();\r
-                       av_frame->height                        = video->GetHeight();\r
-                       av_frame->interlaced_frame      = format_desc_.field_mode != core::field_mode::progressive;\r
-                       av_frame->top_field_first       = format_desc_.field_mode == core::field_mode::upper ? 1 : 0;\r
-                                       \r
-                       BOOST_FOREACH(auto& av_frame2, filter_.execute(av_frame))\r
-                               muxer_.push(av_frame2);         \r
-                                                                       \r
-                       // It is assumed that audio is always equal or ahead of video.\r
-                       if(audio && SUCCEEDED(audio->GetBytes(&bytes)))\r
-                       {\r
-                               auto sample_frame_count = audio->GetSampleFrameCount();\r
-                               auto audio_data = reinterpret_cast<int32_t*>(bytes);\r
-                               muxer_.push(std::make_shared<core::audio_buffer>(audio_data, audio_data + sample_frame_count*format_desc_.audio_channels));\r
-                       }\r
-                       else\r
-                               muxer_.push(std::make_shared<core::audio_buffer>(frame_factory_->get_video_format_desc().audio_samples_per_frame, 0));\r
-                                       \r
-                       muxer_.commit();\r
-\r
-                       while(!muxer_.empty())\r
-                       {\r
-                               if(!frame_buffer_.try_push(muxer_.pop()))\r
-                                       graph_->add_tag("dropped-frame");\r
-                       }\r
-\r
-                       graph_->update_value("frame-time", frame_timer_.elapsed()*format_desc_.fps*0.5);\r
-\r
-                       graph_->set_value("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));      \r
-               }\r
-               catch(...)\r
-               {\r
-                       exception_ = std::current_exception();\r
-                       return E_FAIL;\r
-               }\r
-\r
+               if(!Concurrency::asend(target_, frame_packet(CComPtr<IDeckLinkVideoInputFrame>(video), CComPtr<IDeckLinkAudioInputPacket>(audio))))\r
+                       graph_->add_tag("dropped-frame");\r
                return S_OK;\r
        }\r
-       \r
-       safe_ptr<core::basic_frame> get_frame()\r
-       {\r
-               if(exception_ != nullptr)\r
-                       std::rethrow_exception(exception_);\r
-\r
-               safe_ptr<core::basic_frame> frame = core::basic_frame::late();\r
-               if(!frame_buffer_.try_pop(frame))\r
-                       graph_->add_tag("late-frame");\r
-               graph_->set_value("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));      \r
-               return frame;\r
-       }\r
-       \r
+               \r
        std::wstring print() const\r
        {\r
                return model_name_ + L" [" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
        }\r
 };\r
        \r
-class decklink_producer_proxy : public core::frame_producer\r
+class decklink_producer_proxy : public Concurrency::agent, public core::frame_producer\r
 {              \r
-       safe_ptr<core::basic_frame>             last_frame_;\r
-       com_context<decklink_producer>  context_;\r
-       const int64_t                                   length_;\r
+       std::shared_ptr<Concurrency::bounded_buffer<std::shared_ptr<AVFrame>>>                    video_frames_;\r
+       std::shared_ptr<Concurrency::bounded_buffer<std::shared_ptr<core::audio_buffer>>> audio_buffers_;\r
+       Concurrency::bounded_buffer<std::shared_ptr<core::basic_frame>>  muxed_frames_;\r
+\r
+       const core::video_format_desc           format_desc_;\r
+       const size_t                                            device_index_;\r
+\r
+       safe_ptr<core::basic_frame>                     last_frame_;\r
+       const int64_t                                           length_;\r
+\r
+       ffmpeg::filter                                          filter_;\r
+               \r
+       ffmpeg::frame_muxer2                            muxer_;\r
+\r
+       mutable Concurrency::single_assignment<std::wstring> print_;\r
+\r
+       volatile bool is_running_;\r
 public:\r
 \r
        explicit decklink_producer_proxy(const safe_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, size_t device_index, const std::wstring& filter_str, int64_t length)\r
-               : context_(L"decklink_producer[" + boost::lexical_cast<std::wstring>(device_index) + L"]")\r
+               : video_frames_(std::make_shared<Concurrency::bounded_buffer<std::shared_ptr<AVFrame>>>(1))\r
+               , audio_buffers_(std::make_shared<Concurrency::bounded_buffer<std::shared_ptr<core::audio_buffer>>>(1))\r
+               , muxed_frames_(1)\r
+               , format_desc_(format_desc)\r
+               , device_index_(device_index)\r
                , last_frame_(core::basic_frame::empty())\r
                , length_(length)\r
+               , filter_(filter_str)\r
+               , muxer_(video_frames_, audio_buffers_, muxed_frames_, ffmpeg::double_rate(filter_str) ? format_desc.fps * 2.0 : format_desc.fps, frame_factory)\r
+               , is_running_(true)\r
        {\r
-               context_.reset([&]{return new decklink_producer(format_desc, device_index, frame_factory, filter_str);}); \r
+               agent::start();\r
        }\r
 \r
        ~decklink_producer_proxy()\r
        {\r
-               auto str = print();\r
-               context_.reset();\r
-               CASPAR_LOG(info) << str << L" Successfully Uninitialized.";     \r
+               is_running_ = false;\r
+               agent::wait(this);\r
        }\r
                                \r
        virtual safe_ptr<core::basic_frame> receive(int)\r
        {\r
-               auto frame = context_->get_frame();\r
-               if(frame != core::basic_frame::late())\r
-                       last_frame_ = frame;\r
+               auto frame = core::basic_frame::late();\r
+\r
+               try\r
+               {\r
+                       last_frame_ = frame = safe_ptr<core::basic_frame>(Concurrency::receive(muxed_frames_));\r
+               }\r
+               catch(Concurrency::operation_timed_out&)\r
+               {               \r
+                       //graph_->add_tag("underflow"); \r
+               }\r
+\r
                return frame;\r
        }\r
 \r
@@ -281,7 +237,78 @@ public:
        \r
        std::wstring print() const\r
        {\r
-               return context_->print();\r
+               return print_.value();\r
+       }\r
+\r
+       virtual void run()\r
+       {\r
+               try\r
+               {\r
+                       CoInitializeEx(NULL, COINIT_MULTITHREADED);\r
+                       \r
+                       Concurrency::bounded_buffer<frame_packet> input_buffer(2);\r
+\r
+                       std::unique_ptr<decklink_producer> producer;\r
+                       {                               \r
+                               Concurrency::scoped_oversubcription_token oversubscribe;\r
+                               producer.reset(new decklink_producer(input_buffer, format_desc_, device_index_));\r
+                       }\r
+\r
+                       Concurrency::send(print_, producer->print());\r
+\r
+                       while(is_running_)\r
+                       {\r
+                               auto packet = Concurrency::receive(input_buffer);\r
+                               auto video  = packet.first;\r
+                               auto audio  = packet.second;\r
+                               \r
+                               void* bytes = nullptr;\r
+                               if(FAILED(video->GetBytes(&bytes)) || !bytes)\r
+                                       continue;\r
+                       \r
+                               safe_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);     \r
+                               avcodec_get_frame_defaults(av_frame.get());\r
+                                               \r
+                               av_frame->data[0]                       = reinterpret_cast<uint8_t*>(bytes);\r
+                               av_frame->linesize[0]           = video->GetRowBytes();                 \r
+                               av_frame->format                        = PIX_FMT_UYVY422;\r
+                               av_frame->width                         = video->GetWidth();\r
+                               av_frame->height                        = video->GetHeight();\r
+                               av_frame->interlaced_frame      = format_desc_.field_mode != core::field_mode::progressive;\r
+                               av_frame->top_field_first       = format_desc_.field_mode == core::field_mode::upper ? 1 : 0;\r
+                                       \r
+                               filter_.push(av_frame);\r
+\r
+                               while(true)\r
+                               {\r
+                                       auto frame = filter_.poll();\r
+                                       if(!frame)\r
+                                               break;\r
+                                       Concurrency::send<std::shared_ptr<AVFrame>>(*video_frames_, frame);\r
+                               }\r
+                                                                                                       \r
+                               // It is assumed that audio is always equal or ahead of video.\r
+                               if(audio && SUCCEEDED(audio->GetBytes(&bytes)))\r
+                               {\r
+                                       auto sample_frame_count = audio->GetSampleFrameCount();\r
+                                       auto audio_data = reinterpret_cast<int32_t*>(bytes);\r
+                                       Concurrency::send(*audio_buffers_, std::make_shared<core::audio_buffer>(audio_data, audio_data + sample_frame_count*format_desc_.audio_channels));\r
+                               }\r
+                               else\r
+                                       Concurrency::send(*audio_buffers_, ffmpeg::empty_audio());      \r
+                       }\r
+\r
+               }\r
+               catch(...)\r
+               {\r
+                       CASPAR_LOG_CURRENT_EXCEPTION();\r
+               }\r
+\r
+               CoUninitialize();\r
+\r
+               CASPAR_LOG(info) << print() << L" Successfully Uninitialized."; \r
+\r
+               done();\r
        }\r
 };\r
 \r
index 21bd2e7c57247a7517373d963aab24f566661e92..9abb7f0a39b661dff9929adb4e5ee4f8276cdcfc 100644 (file)
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">Create</PrecompiledHeader>\r
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>\r
     </ClCompile>\r
-    <ClCompile Include="tbb_avcodec.cpp" />\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="consumer\ffmpeg_consumer.h" />\r
     <ClInclude Include="producer\util.h" />\r
     <ClInclude Include="producer\video\video_decoder.h" />\r
     <ClInclude Include="StdAfx.h" />\r
-    <ClInclude Include="tbb_avcodec.h" />\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ProjectReference Include="..\..\common\common.vcxproj">\r
index 86ea6ace6d47707f21ccfce771d31eedc1bb887a..a1f226e14351134c71c2089cd6b2dbb907eac42e 100644 (file)
@@ -27,9 +27,6 @@
     <ClCompile Include="producer\ffmpeg_producer.cpp">\r
       <Filter>source\producer</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="producer\input.cpp">\r
-      <Filter>source\producer</Filter>\r
-    </ClCompile>\r
     <ClCompile Include="producer\video\video_decoder.cpp">\r
       <Filter>source\producer\video</Filter>\r
     </ClCompile>\r
@@ -40,9 +37,6 @@
       <Filter>source\consumer</Filter>\r
     </ClCompile>\r
     <ClCompile Include="StdAfx.cpp" />\r
-    <ClCompile Include="tbb_avcodec.cpp">\r
-      <Filter>source</Filter>\r
-    </ClCompile>\r
     <ClCompile Include="ffmpeg.cpp">\r
       <Filter>source</Filter>\r
     </ClCompile>\r
     <ClCompile Include="producer\audio\audio_resampler.cpp">\r
       <Filter>source\producer\audio</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="producer\input.cpp">\r
+      <Filter>source\producer</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="producer\ffmpeg_producer.h">\r
       <Filter>source\producer</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="producer\input.h">\r
-      <Filter>source\producer</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="producer\video\video_decoder.h">\r
       <Filter>source\producer\video</Filter>\r
     </ClInclude>\r
@@ -82,9 +76,6 @@
       <Filter>source\consumer</Filter>\r
     </ClInclude>\r
     <ClInclude Include="StdAfx.h" />\r
-    <ClInclude Include="tbb_avcodec.h">\r
-      <Filter>source</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="ffmpeg_error.h">\r
       <Filter>source</Filter>\r
     </ClInclude>\r
     <ClInclude Include="producer\audio\audio_resampler.h">\r
       <Filter>source\producer\audio</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="producer\input.h">\r
+      <Filter>source\producer</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 017b13c75f5dd10d41ccca413e8d43c6b17f0874..2591098666ea255c28a3e4487f8ee19a062b2df0 100644 (file)
@@ -16,6 +16,7 @@ extern "C"
 namespace caspar { namespace ffmpeg {\r
 \r
 struct ffmpeg_error : virtual caspar_exception{};\r
+struct ffmpeg_stream_not_found : virtual ffmpeg_error{};\r
 \r
 static std::string av_error_str(int errn)\r
 {\r
@@ -40,14 +41,14 @@ static std::string av_error_str(int errn)
 #define THROW_ON_ERROR_STR_(call) #call\r
 #define THROW_ON_ERROR_STR(call) THROW_ON_ERROR_STR_(call)\r
 \r
-#define THROW_ON_ERROR2(call, source)                                                                          \\r
+#define THROW_ON_ERROR3(call, source, exception)                                                                               \\r
        [&]() -> int                                                                                                                    \\r
        {                                                                                                                                               \\r
                int ret = call;                                                                                                         \\r
                if(ret < 0)                                                                                                                     \\r
                {                                                                                                                                       \\r
                        BOOST_THROW_EXCEPTION(                                                                                  \\r
-                               ffmpeg_error() <<                                                                                       \\r
+                               exception() <<                                                                                  \\r
                                msg_info(av_error_str(ret)) <<                                                          \\r
                                source_info(narrow(source)) <<                                                          \\r
                                boost::errinfo_api_function(THROW_ON_ERROR_STR(call)) <<        \\r
@@ -55,5 +56,6 @@ static std::string av_error_str(int errn)
                }                                                                                                                                       \\r
                return ret;                                                                                                                     \\r
        }();\r
+#define THROW_ON_ERROR2(call, source) THROW_ON_ERROR3(call, source, ffmpeg_error)\r
 \r
 }}
\ No newline at end of file
index 1f517476a038dbfc1d56bd891613beb20ccaa315..dd3f5fd4300e756492ad6e3c62cccd169ad49ef6 100644 (file)
@@ -57,6 +57,7 @@ struct audio_decoder::implementation : public Concurrency::agent, boost::noncopy
        std::vector<int8_t,  tbb::cache_aligned_allocator<int8_t>>      buffer1_;\r
        \r
        int64_t                                                                                                         nb_frames_;\r
+\r
 public:\r
        explicit implementation(audio_decoder::source_t& source,\r
                                                        audio_decoder::target_t& target,\r
@@ -67,28 +68,22 @@ public:
                , format_desc_(format_desc)     \r
                , nb_frames_(0)\r
        {                               \r
-               try\r
-               {\r
-                       AVCodec* dec;\r
-                       index_ = THROW_ON_ERROR2(av_find_best_stream(context.get(), AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0), "[audio_decoder]");\r
+               \r
+               AVCodec* dec;\r
+               index_ = THROW_ON_ERROR3(av_find_best_stream(context.get(), AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0), "[audio_decoder]", ffmpeg_stream_not_found);\r
+               CASPAR_VERIFY(index_ > -1, ffmpeg_error());\r
 \r
-                       THROW_ON_ERROR2(avcodec_open(context->streams[index_]->codec, dec), "[audio_decoder]");\r
+               THROW_ON_ERROR2(avcodec_open(context->streams[index_]->codec, dec), "[audio_decoder]");\r
+               CASPAR_VERIFY(context->streams[index_]->codec, ffmpeg_error());\r
                        \r
-                       codec_context_.reset(context->streams[index_]->codec, avcodec_close);\r
+               codec_context_.reset(context->streams[index_]->codec, avcodec_close);\r
 \r
-                       buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2);\r
-\r
-                       resampler_.reset(new audio_resampler(format_desc_.audio_channels,    codec_context_->channels,\r
-                                                                                                format_desc_.audio_sample_rate, codec_context_->sample_rate,\r
-                                                                                                AV_SAMPLE_FMT_S32,                              codec_context_->sample_fmt));  \r
-               }\r
-               catch(...)\r
-               {\r
-                       index_ = THROW_ON_ERROR2(av_find_best_stream(context.get(), AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0), "[audio_decoder]");\r
+               buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2);\r
 \r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       CASPAR_LOG(warning) << "[audio_decoder] Failed to open audio-stream. Running without audio.";                   \r
-               }\r
+               resampler_.reset(new audio_resampler(format_desc_.audio_channels,    codec_context_->channels,\r
+                                                                                               format_desc_.audio_sample_rate, codec_context_->sample_rate,\r
+                                                                                               AV_SAMPLE_FMT_S32,                               codec_context_->sample_fmt));                  \r
+               CASPAR_VERIFY(resampler_, ffmpeg_error());\r
 \r
                start();\r
        }\r
@@ -104,22 +99,23 @@ public:
                {\r
                        while(true)\r
                        {\r
-                               auto packet = Concurrency::receive(source_, 5000);\r
-                               if(packet == eof_packet())                              \r
+                               auto packet = Concurrency::receive(source_, [this](const std::shared_ptr<AVPacket>& packet)\r
+                               {\r
+                                       return packet && packet->stream_index == index_;\r
+                               });\r
+\r
+                               if(packet == eof_packet(index_))                                \r
                                        break;\r
                                \r
-                               if(packet == loop_packet())     \r
+                               if(packet == loop_packet(index_))       \r
                                {       \r
-                                       if(codec_context_)\r
-                                               avcodec_flush_buffers(codec_context_.get());\r
+                                       avcodec_flush_buffers(codec_context_.get());\r
                                        Concurrency::send(target_, loop_audio());\r
                                }       \r
                                else if(packet->stream_index == index_)\r
                                {\r
-                                       if(!codec_context_)\r
-                                               Concurrency::send(target_, empty_audio());                                      \r
-                                       else            \r
-                                               Concurrency::send(target_, decode(*packet));    \r
+                                       Concurrency::send(target_, decode(*packet));            \r
+                                       Concurrency::wait(0);\r
                                }\r
                        }\r
                }\r
@@ -151,7 +147,7 @@ public:
                const auto n_samples = buffer1_.size() / av_get_bytes_per_sample(AV_SAMPLE_FMT_S32);\r
                const auto samples = reinterpret_cast<int32_t*>(buffer1_.data());\r
 \r
-               return std::make_shared<core::audio_buffer>(samples, samples + n_samples);\r
+               return n_samples > 0 ? std::make_shared<core::audio_buffer>(samples, samples + n_samples) : nullptr;\r
        }\r
 };\r
 \r
index 9f953f130b7a274a8ed5e645092b1684df6b6146..bef47926e039839ae27e9f876bb2123ffaceeee2 100644 (file)
@@ -53,10 +53,9 @@ struct audio_resampler::implementation
                                                                        L" audio_channels:" << input_channels  <<\r
                                                                        L" sample_fmt:" << input_sample_format;\r
 \r
-                       if(resampler)\r
-                               resampler_.reset(resampler, audio_resample_close);\r
-                       else\r
-                               BOOST_THROW_EXCEPTION(caspar_exception());\r
+                       CASPAR_VERIFY(resampler, caspar_exception());\r
+\r
+                       resampler_.reset(resampler, audio_resample_close);\r
                }               \r
        }\r
 \r
index 73c76e1551c8e06db6d99639ab22ab8521e409da..0ac5660cdc76c36ac4edbbecb76c079eef7a0cf6 100644 (file)
@@ -26,6 +26,7 @@
 #include "util.h"\r
 #include "audio/audio_decoder.h"\r
 #include "video/video_decoder.h"\r
+#include "../ffmpeg_error.h"\r
 \r
 #include <common/env.h>\r
 #include <common/utility/assert.h>\r
 using namespace Concurrency;\r
 \r
 namespace caspar { namespace ffmpeg {\r
-       \r
+               \r
 struct ffmpeg_producer : public core::frame_producer\r
 {      \r
        const std::wstring                                              filename_;\r
        const int                                                               start_;\r
        const bool                                                              loop_;\r
        const size_t                                                    length_;\r
-\r
-       Concurrency::bounded_buffer<std::shared_ptr<AVPacket>>                          pre_video_packets_;\r
-       Concurrency::bounded_buffer<std::shared_ptr<AVPacket>>                          post_video_packets_;\r
-       Concurrency::bounded_buffer<std::shared_ptr<AVFrame>>                           video_frames_;\r
-       Concurrency::bounded_buffer<std::shared_ptr<core::audio_buffer>>        audio_buffers_;\r
-       Concurrency::bounded_buffer<std::shared_ptr<core::basic_frame>>         muxed_frames_;\r
+       \r
+       Concurrency::unbounded_buffer<std::shared_ptr<AVPacket>>                                        packet_stream_;\r
+       std::shared_ptr<Concurrency::ISource<std::shared_ptr<AVFrame>>>                         video_stream_;\r
+       std::shared_ptr<Concurrency::ISource<std::shared_ptr<core::audio_buffer>>>      audio_stream_;\r
+       Concurrency::bounded_buffer<std::shared_ptr<core::basic_frame>>                         frame_stream_;\r
                \r
        const safe_ptr<diagnostics::graph>              graph_;\r
                                        \r
        input                                                                   input_; \r
-       video_decoder                                                   video_decoder_;\r
-       audio_decoder                                                   audio_decoder_; \r
-       frame_muxer2                                                    muxer_;\r
+       std::unique_ptr<video_decoder>                  video_decoder_;\r
+       std::unique_ptr<audio_decoder>                  audio_decoder_; \r
+       std::unique_ptr<frame_muxer2>                   muxer_;\r
 \r
        safe_ptr<core::basic_frame>                             last_frame_;\r
        \r
@@ -80,26 +80,57 @@ public:
                , start_(start)\r
                , loop_(loop)\r
                , length_(length)\r
-               , pre_video_packets_(25)\r
-               , post_video_packets_(25)\r
-               , video_frames_(2)\r
-               , audio_buffers_(2)\r
-               , muxed_frames_(2)\r
+               , frame_stream_(2)\r
                , graph_(diagnostics::create_graph([this]{return print();}, false))\r
-               , input_(pre_video_packets_, graph_, filename_, loop, start, length)\r
-               , video_decoder_(pre_video_packets_, post_video_packets_, video_frames_, input_.context(), frame_factory->get_video_format_desc().fps, filter)\r
-               , audio_decoder_(post_video_packets_, audio_buffers_, input_.context(), frame_factory->get_video_format_desc())\r
-               , muxer_(video_frames_, audio_buffers_, muxed_frames_, video_decoder_.fps(), frame_factory)\r
+               , input_(packet_stream_, graph_, filename_, loop, start, length)\r
                , last_frame_(core::basic_frame::empty())\r
        {\r
+               try\r
+               {\r
+                       auto target = std::make_shared<Concurrency::bounded_buffer<std::shared_ptr<AVFrame>>>(2);\r
+                       video_decoder_.reset(new video_decoder(packet_stream_, *target, input_.context(), frame_factory->get_video_format_desc().fps));\r
+                       video_stream_ = target;\r
+               }\r
+               catch(ffmpeg_stream_not_found&)\r
+               {\r
+                       CASPAR_LOG(warning) << "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
+               }\r
+\r
+               try\r
+               {\r
+                       auto target = std::make_shared<Concurrency::bounded_buffer<std::shared_ptr<core::audio_buffer>>>(25);\r
+                       audio_decoder_.reset(new audio_decoder(packet_stream_, *target, input_.context(), frame_factory->get_video_format_desc()));\r
+                       audio_stream_ = target;\r
+               }\r
+               catch(ffmpeg_stream_not_found&)\r
+               {\r
+                       CASPAR_LOG(warning) << "No audio-stream found. Running without video."; \r
+               }\r
+               catch(...)\r
+               {\r
+                       CASPAR_LOG_CURRENT_EXCEPTION();\r
+                       CASPAR_LOG(warning) << "Failed to open audio-stream. Running without audio.";           \r
+               }\r
+\r
+               CASPAR_VERIFY(video_decoder_ || audio_decoder_, ffmpeg_error());\r
+\r
+               muxer_.reset(new frame_muxer2(video_stream_, audio_stream_, frame_stream_, video_decoder_ ? video_decoder_->fps() : frame_factory->get_video_format_desc().fps, frame_factory));\r
+                               \r
                graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));   \r
                graph_->start();\r
+\r
+               input_.start();\r
        }\r
 \r
        ~ffmpeg_producer()\r
        {\r
-               input_.stop();\r
-               while(Concurrency::receive(muxed_frames_) != core::basic_frame::eof())\r
+               input_.stop();                  \r
+               while(Concurrency::receive(frame_stream_) != core::basic_frame::eof())\r
                {\r
                }\r
        }\r
@@ -110,7 +141,7 @@ public:
                \r
                try\r
                {               \r
-                       frame = last_frame_ = safe_ptr<core::basic_frame>(Concurrency::receive(muxed_frames_, 8));\r
+                       frame = last_frame_ = safe_ptr<core::basic_frame>(Concurrency::receive(frame_stream_, 10));\r
                }\r
                catch(Concurrency::operation_timed_out&)\r
                {               \r
@@ -135,13 +166,13 @@ public:
                int64_t nb_frames = input_.nb_frames();\r
                if(input_.nb_loops() < 1) // input still hasn't counted all frames\r
                {\r
-                       int64_t video_nb_frames = video_decoder_.nb_frames();\r
-                       int64_t audio_nb_frames = audio_decoder_.nb_frames();\r
+                       int64_t video_nb_frames = video_decoder_->nb_frames();\r
+                       int64_t audio_nb_frames = audio_decoder_->nb_frames();\r
 \r
                        nb_frames = std::min(static_cast<int64_t>(length_), std::max(nb_frames, std::max(video_nb_frames, audio_nb_frames)));\r
                }\r
 \r
-               nb_frames = muxer_.calc_nb_frames(nb_frames);\r
+               nb_frames = muxer_->calc_nb_frames(nb_frames);\r
 \r
                // TODO: Might need to scale nb_frames av frame_muxer transformations.\r
 \r
@@ -150,10 +181,15 @@ public:
                                \r
        virtual std::wstring print() const\r
        {\r
-               return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"|" \r
-                                                 + boost::lexical_cast<std::wstring>(video_decoder_.width()) + L"x" + boost::lexical_cast<std::wstring>(video_decoder_.height())\r
-                                                 + (video_decoder_.is_progressive() ? L"p" : L"i")  + boost::lexical_cast<std::wstring>(video_decoder_.is_progressive() ? video_decoder_.fps() : 2.0 * video_decoder_.fps())\r
-                                                 + L"]";\r
+               if(video_decoder_)\r
+               {\r
+                       return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"|" \r
+                                                         + boost::lexical_cast<std::wstring>(video_decoder_->width()) + L"x" + boost::lexical_cast<std::wstring>(video_decoder_->height())\r
+                                                         + (video_decoder_->is_progressive() ? L"p" : L"i")  + boost::lexical_cast<std::wstring>(video_decoder_->is_progressive() ? video_decoder_->fps() : 2.0 * video_decoder_->fps())\r
+                                                         + L"]";\r
+               }\r
+               \r
+               return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"]";\r
        }\r
 };\r
 \r
index 0b6b38d54ff1894becb962dc12c0edf6bfafdf03..06ec5908bc812d114dad0e4a8c29cddace451aa6 100644 (file)
@@ -39,6 +39,7 @@ struct filter::implementation
        AVFilterContext*                                buffersrc_ctx_;\r
        std::shared_ptr<void>                   parallel_yadif_ctx_;\r
        std::vector<PixelFormat>                pix_fmts_;\r
+       std::queue<std::shared_ptr<AVFrame>> bypass_;\r
                \r
        implementation(const std::wstring& filters, const std::vector<PixelFormat>& pix_fmts) \r
                : filters_(narrow(filters))\r
@@ -64,20 +65,17 @@ struct filter::implementation
                std::transform(filters_.begin(), filters_.end(), filters_.begin(), ::tolower);\r
        }\r
        \r
-       std::vector<safe_ptr<AVFrame>> execute(const std::shared_ptr<AVFrame>& frame)\r
-       {\r
+       void push(const std::shared_ptr<AVFrame>& frame)\r
+       {               \r
                if(!frame)\r
-                       return std::vector<safe_ptr<AVFrame>>();\r
+                       return;\r
 \r
                if(filters_.empty())\r
-                       return boost::assign::list_of(frame);\r
-\r
-               push(frame);\r
-               return poll();\r
-       }\r
+               {\r
+                       bypass_.push(frame);\r
+                       return;\r
+               }\r
 \r
-       void push(const std::shared_ptr<AVFrame>& frame)\r
-       {               \r
                if(!graph_)\r
                {\r
                        graph_.reset(avfilter_graph_alloc(), [](AVFilterGraph* p){avfilter_graph_free(&p);});\r
@@ -119,18 +117,25 @@ struct filter::implementation
                                        parallel_yadif_ctx_ = make_parallel_yadif(graph_->filters[n]);\r
                        }\r
                }\r
-       \r
+                       \r
                THROW_ON_ERROR2(av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0), "[filter]");\r
        }\r
 \r
-       std::vector<safe_ptr<AVFrame>> poll()\r
+       std::shared_ptr<AVFrame> poll()\r
        {\r
-               std::vector<safe_ptr<AVFrame>> result;\r
+               if(filters_.empty())\r
+               {\r
+                       if(bypass_.empty())\r
+                               return nullptr;\r
+                       auto frame = bypass_.front();\r
+                       bypass_.pop();\r
+                       return frame;\r
+               }\r
 \r
                if(!graph_)\r
-                       return result;\r
+                       return nullptr;\r
                \r
-               while (avfilter_poll_frame(buffersink_ctx_->inputs[0])) \r
+               if(avfilter_poll_frame(buffersink_ctx_->inputs[0])) \r
                {\r
                        AVFilterBufferRef *picref;\r
                        THROW_ON_ERROR2(av_buffersink_get_buffer_ref(buffersink_ctx_, &picref, 0), "[filter]");\r
@@ -157,17 +162,18 @@ struct filter::implementation
                                frame->pict_type                        = picref->video->pict_type;\r
                                frame->sample_aspect_ratio      = picref->video->sample_aspect_ratio;\r
 \r
-                               result.push_back(frame);\r
+                               return frame;\r
             }\r
         }\r
 \r
-               return result;\r
+               return nullptr;\r
        }\r
 };\r
 \r
 filter::filter(const std::wstring& filters, const std::vector<PixelFormat>& pix_fmts) : impl_(new implementation(filters, pix_fmts)){}\r
 filter::filter(filter&& other) : impl_(std::move(other.impl_)){}\r
 filter& filter::operator=(filter&& other){impl_ = std::move(other.impl_); return *this;}\r
-std::vector<safe_ptr<AVFrame>> filter::execute(const std::shared_ptr<AVFrame>& frame) {return impl_->execute(frame);}\r
+void filter::push(const std::shared_ptr<AVFrame>& frame){impl_->push(frame);}\r
+std::shared_ptr<AVFrame> filter::poll(){return impl_->poll();}\r
 \r
 }}
\ No newline at end of file
index 7b3078518aef29cab2a3cd5945bca2442bcd7254..37d8ccfe6a6f5d80084360a15af290846fd6e04c 100644 (file)
@@ -30,7 +30,8 @@ public:
        filter(filter&& other);\r
        filter& operator=(filter&& other);\r
 \r
-       std::vector<safe_ptr<AVFrame>> execute(const std::shared_ptr<AVFrame>& frame);\r
+       void push(const std::shared_ptr<AVFrame>& frame);\r
+       std::shared_ptr<AVFrame> poll();\r
 \r
 private:\r
        struct implementation;\r
index 1992674dbdc02f627e09cde8cb2bba6cf7f94ca3..37bbf4656339aee13dee2b1a94bdfff1c9d2bf7d 100644 (file)
@@ -136,297 +136,10 @@ display_mode::type get_display_mode(const core::field_mode::type in_mode, double
        return display_mode::invalid;\r
 }\r
 \r
-struct frame_muxer::implementation : boost::noncopyable\r
-{      \r
-       std::deque<std::queue<safe_ptr<write_frame>>>   video_streams_;\r
-       std::deque<core::audio_buffer>                                  audio_streams_;\r
-       std::deque<safe_ptr<basic_frame>>                               frame_buffer_;\r
-       display_mode::type                                                              display_mode_;\r
-       const double                                                                    in_fps_;\r
-       const video_format_desc                                                 format_desc_;\r
-       bool                                                                                    auto_transcode_;\r
-\r
-       size_t                                                                                  audio_sample_count_;\r
-       size_t                                                                                  video_frame_count_;\r
-               \r
-       size_t                                                                                  processed_audio_sample_count_;\r
-       size_t                                                                                  processed_video_frame_count_;\r
-\r
-       filter                                                                                  filter_;\r
-       safe_ptr<core::frame_factory>                                   frame_factory_;\r
-               \r
-       implementation(double in_fps, const safe_ptr<core::frame_factory>& frame_factory)\r
-               : video_streams_(1)\r
-               , audio_streams_(1)\r
-               , display_mode_(display_mode::invalid)\r
-               , in_fps_(in_fps)\r
-               , format_desc_(frame_factory->get_video_format_desc())\r
-               , auto_transcode_(env::properties().get("configuration.producers.auto-transcode", false))\r
-               , audio_sample_count_(0)\r
-               , video_frame_count_(0)\r
-               , frame_factory_(frame_factory)\r
-       {\r
-       }\r
-\r
-       void push(const std::shared_ptr<AVFrame>& video_frame, int hints)\r
-       {               \r
-               if(!video_frame)\r
-               {       \r
-                       CASPAR_LOG(debug) << L"video-frame-count: " << static_cast<float>(video_frame_count_);\r
-                       video_frame_count_ = 0;\r
-                       video_streams_.push_back(std::queue<safe_ptr<write_frame>>());\r
-                       return;\r
-               }\r
-\r
-               if(video_frame->data[0] == nullptr)\r
-               {\r
-                       video_streams_.back().push(make_safe<core::write_frame>(this));\r
-                       ++video_frame_count_;\r
-                       display_mode_ = display_mode::simple;\r
-                       return;\r
-               }\r
-\r
-               if(display_mode_ == display_mode::invalid)\r
-               {\r
-                       if(auto_transcode_)\r
-                       {\r
-                               auto in_mode = get_mode(*video_frame);\r
-                               display_mode_ = get_display_mode(in_mode, in_fps_, format_desc_.field_mode, format_desc_.fps);\r
-                       \r
-                               if(display_mode_ == display_mode::simple && in_mode != core::field_mode::progressive && format_desc_.field_mode != core::field_mode::progressive && video_frame->height != static_cast<int>(format_desc_.height))\r
-                                       display_mode_ = display_mode::deinterlace_bob_reinterlace; // The frame will most likely be scaled, we need to deinterlace->reinterlace \r
-                               \r
-                               if(display_mode_ == display_mode::deinterlace)\r
-                                       filter_ = filter(L"YADIF=0:-1");\r
-                               else if(display_mode_ == display_mode::deinterlace_bob || display_mode_ == display_mode::deinterlace_bob_reinterlace)\r
-                                       filter_ = filter(L"YADIF=1:-1");\r
-                       }\r
-                       else\r
-                               display_mode_ = display_mode::simple;\r
-\r
-                       if(display_mode_ == display_mode::invalid)\r
-                       {\r
-                               CASPAR_LOG(warning) << L"[frame_muxer] Failed to detect display-mode.";\r
-                               display_mode_ = display_mode::simple;\r
-                       }\r
-\r
-                       CASPAR_LOG(info) << "[frame_muxer] " << display_mode::print(display_mode_);\r
-               }\r
-\r
-                               \r
-               if(hints & core::frame_producer::ALPHA_HINT)\r
-                       video_frame->format = make_alpha_format(video_frame->format);\r
-               \r
-               auto format = video_frame->format;\r
-               if(video_frame->format == CASPAR_PIX_FMT_LUMA) // CASPAR_PIX_FMT_LUMA is not valid for filter, change it to GRAY8\r
-                       video_frame->format = PIX_FMT_GRAY8;\r
-\r
-               BOOST_FOREACH(auto& av_frame, filter_.execute(video_frame))\r
-               {\r
-                       av_frame->format = format;\r
-\r
-                       auto frame = make_write_frame(this, av_frame, frame_factory_, hints);\r
-\r
-                       // Fix field-order if needed\r
-                       if(frame->get_type() == core::field_mode::lower && format_desc_.field_mode == core::field_mode::upper)\r
-                               frame->get_frame_transform().fill_translation[1] += 1.0/static_cast<double>(format_desc_.height);\r
-                       else if(frame->get_type() == core::field_mode::upper && format_desc_.field_mode == core::field_mode::lower)\r
-                               frame->get_frame_transform().fill_translation[1] -= 1.0/static_cast<double>(format_desc_.height);\r
-\r
-                       video_streams_.back().push(frame);\r
-                       ++video_frame_count_;\r
-               }\r
-\r
-               if(video_streams_.back().size() > 8)\r
-                       BOOST_THROW_EXCEPTION(invalid_operation() << source_info("frame_muxer") << msg_info("video-stream overflow. This can be caused by incorrect frame-rate. Check clip meta-data."));\r
-       }\r
-\r
-       void push(const std::shared_ptr<core::audio_buffer>& audio_samples)\r
-       {\r
-               if(!audio_samples)      \r
-               {\r
-                       CASPAR_LOG(debug) << L"audio-chunk-count: " << audio_sample_count_/format_desc_.audio_samples_per_frame;\r
-                       audio_streams_.push_back(core::audio_buffer());\r
-                       audio_sample_count_ = 0;\r
-                       return;\r
-               }\r
-\r
-               audio_sample_count_ += audio_samples->size();\r
-\r
-               boost::range::push_back(audio_streams_.back(), *audio_samples);\r
-\r
-               if(audio_streams_.back().size() > 8*format_desc_.audio_samples_per_frame)\r
-                       BOOST_THROW_EXCEPTION(invalid_operation() << source_info("frame_muxer") << msg_info("audio-stream overflow. This can be caused by incorrect frame-rate. Check clip meta-data."));\r
-       }\r
-\r
-       safe_ptr<basic_frame> pop()\r
-       {               \r
-               auto frame = frame_buffer_.front();\r
-               frame_buffer_.pop_front();              \r
-               return frame;\r
-       }\r
-\r
-       size_t size() const\r
-       {\r
-               return frame_buffer_.size();\r
-       }\r
-\r
-       safe_ptr<core::write_frame> pop_video()\r
-       {\r
-               auto frame = video_streams_.front().front();\r
-               video_streams_.front().pop();\r
-               \r
-               return frame;\r
-       }\r
-\r
-       core::audio_buffer pop_audio()\r
-       {\r
-               CASPAR_VERIFY(audio_streams_.front().size() >= format_desc_.audio_samples_per_frame);\r
-\r
-               auto begin = audio_streams_.front().begin();\r
-               auto end   = begin + format_desc_.audio_samples_per_frame;\r
-\r
-               auto samples = core::audio_buffer(begin, end);\r
-               audio_streams_.front().erase(begin, end);\r
-\r
-               return samples;\r
-       }\r
-       \r
-       bool video_ready() const\r
-       {               \r
-               return video_streams_.size() > 1 || (video_streams_.size() >= audio_streams_.size() && video_ready2());\r
-       }\r
-       \r
-       bool audio_ready() const\r
-       {\r
-               return audio_streams_.size() > 1 || (audio_streams_.size() >= video_streams_.size() && audio_ready2());\r
-       }\r
-\r
-       bool video_ready2() const\r
-       {               \r
-               switch(display_mode_)\r
-               {\r
-               case display_mode::deinterlace_bob_reinterlace:                                 \r
-               case display_mode::interlace:                                   \r
-                       return video_streams_.front().size() >= 2;\r
-               default:                                                                                \r
-                       return !video_streams_.front().empty();\r
-               }\r
-       }\r
-       \r
-       bool audio_ready2() const\r
-       {\r
-               switch(display_mode_)\r
-               {\r
-               case display_mode::duplicate:                                   \r
-                       return audio_streams_.front().size()/2 >= format_desc_.audio_samples_per_frame;\r
-               default:                                                                                \r
-                       return audio_streams_.front().size() >= format_desc_.audio_samples_per_frame;\r
-               }\r
-       }\r
-               \r
-       void commit()\r
-       {\r
-               if(video_streams_.size() > 1 && audio_streams_.size() > 1 && (!video_ready2() || !audio_ready2()))\r
-               {\r
-                       if(!video_streams_.front().empty() || !audio_streams_.front().empty())\r
-                               CASPAR_LOG(debug) << "Truncating: " << video_streams_.front().size() << L" video-frames, " << audio_streams_.front().size() << L" audio-samples.";\r
-\r
-                       video_streams_.pop_front();\r
-                       audio_streams_.pop_front();\r
-               }\r
-\r
-               if(!video_ready2() || !audio_ready2())\r
-                       return;\r
-               \r
-               switch(display_mode_)\r
-               {\r
-               case display_mode::simple:                                              return simple(frame_buffer_);\r
-               case display_mode::duplicate:                                   return duplicate(frame_buffer_);\r
-               case display_mode::half:                                                return half(frame_buffer_);\r
-               case display_mode::interlace:                                   return interlace(frame_buffer_);\r
-               case display_mode::deinterlace_bob:                             return simple(frame_buffer_);\r
-               case display_mode::deinterlace_bob_reinterlace: return interlace(frame_buffer_);\r
-               case display_mode::deinterlace:                                 return simple(frame_buffer_);\r
-               default:                                                                                BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("invalid display-mode"));\r
-               }\r
-       }\r
-       \r
-       void simple(std::deque<safe_ptr<basic_frame>>& dest)\r
-       {               \r
-               auto frame1 = pop_video();\r
-               frame1->audio_data() = pop_audio();\r
-\r
-               dest.push_back(frame1);         \r
-       }\r
-\r
-       void duplicate(std::deque<safe_ptr<basic_frame>>& dest)\r
-       {               \r
-               auto frame = pop_video();\r
-\r
-               auto frame1 = make_safe<core::write_frame>(*frame); // make a copy\r
-               frame1->audio_data() = pop_audio();\r
-\r
-               auto frame2 = frame;\r
-               frame2->audio_data() = pop_audio();\r
-\r
-               dest.push_back(frame1);\r
-               dest.push_back(frame2);\r
-       }\r
-\r
-       void half(std::deque<safe_ptr<basic_frame>>& dest)\r
-       {                                                       \r
-               auto frame1 = pop_video();\r
-               frame1->audio_data() = pop_audio();\r
-                               \r
-               video_streams_.front().pop(); // Throw away\r
-\r
-               dest.push_back(frame1);\r
-       }\r
-       \r
-       void interlace(std::deque<safe_ptr<basic_frame>>& dest)\r
-       {                               \r
-               auto frame1 = pop_video();\r
-               frame1->audio_data() = pop_audio();\r
-                               \r
-               auto frame2 = pop_video();\r
-\r
-               dest.push_back(core::basic_frame::interlace(frame1, frame2, format_desc_.field_mode));          \r
-       }\r
-       \r
-       int64_t calc_nb_frames(int64_t nb_frames) const\r
-       {\r
-               switch(display_mode_)\r
-               {\r
-               case display_mode::interlace:\r
-               case display_mode::half:\r
-                       return nb_frames/2;\r
-               case display_mode::duplicate:\r
-               case display_mode::deinterlace_bob:\r
-                       return nb_frames*2;\r
-               default:\r
-                       return nb_frames;\r
-               }\r
-       }\r
-};\r
-\r
-frame_muxer::frame_muxer(double in_fps, const safe_ptr<core::frame_factory>& frame_factory)\r
-       : impl_(new implementation(in_fps, frame_factory)){}\r
-void frame_muxer::push(const std::shared_ptr<AVFrame>& video_frame, int hints){impl_->push(video_frame, hints);}\r
-void frame_muxer::push(const std::shared_ptr<core::audio_buffer>& audio_samples){return impl_->push(audio_samples);}\r
-void frame_muxer::commit(){impl_->commit();}\r
-safe_ptr<basic_frame> frame_muxer::pop(){return impl_->pop();}\r
-size_t frame_muxer::size() const {return impl_->size();}\r
-bool frame_muxer::empty() const {return impl_->size() == 0;}\r
-bool frame_muxer::video_ready() const{return impl_->video_ready();}\r
-bool frame_muxer::audio_ready() const{return impl_->audio_ready();}\r
-int64_t frame_muxer::calc_nb_frames(int64_t nb_frames) const {return impl_->calc_nb_frames(nb_frames);}\r
-\r
-\r
 struct frame_muxer2::implementation : public Concurrency::agent, boost::noncopyable\r
 {      \r
-       frame_muxer2::video_source_t&   video_source_;\r
-       frame_muxer2::audio_source_t&   audio_source_;\r
+       const std::shared_ptr<frame_muxer2::video_source_t>&    video_source_;\r
+       const std::shared_ptr<frame_muxer2::audio_source_t>&    audio_source_;\r
        frame_muxer2::target_t&                 target_;\r
 \r
        std::deque<std::queue<safe_ptr<write_frame>>>   video_streams_;\r
@@ -446,8 +159,8 @@ struct frame_muxer2::implementation : public Concurrency::agent, boost::noncopya
        filter                                                                                  filter_;\r
        safe_ptr<core::frame_factory>                                   frame_factory_;\r
                                \r
-       implementation(frame_muxer2::video_source_t& video_source,\r
-                                  frame_muxer2::audio_source_t& audio_source,\r
+       implementation(const std::shared_ptr<frame_muxer2::video_source_t>& video_source,\r
+                                  const std::shared_ptr<frame_muxer2::audio_source_t>& audio_source,\r
                                   frame_muxer2::target_t& target,\r
                                   double in_fps, \r
                                   const safe_ptr<core::frame_factory>& frame_factory)\r
@@ -483,24 +196,34 @@ struct frame_muxer2::implementation : public Concurrency::agent, boost::noncopya
                                {\r
                                        while(!video_ready())\r
                                        {\r
-                                               auto video = Concurrency::receive(video_source_, 5000);\r
-                                               if(video == eof_video())\r
-                                                       break;\r
-                                               push(video, 0); \r
+                                               if(video_source_)\r
+                                               {\r
+                                                       auto video = Concurrency::receive(*video_source_);\r
+                                                       if(video == eof_video())\r
+                                                               break;\r
+                                                       push(video, 0); \r
+                                               }\r
+                                               else\r
+                                                       push(empty_video(), 0); \r
                                        }\r
                                },\r
                                [&]\r
                                {\r
                                        while(!audio_ready())\r
                                        {\r
-                                               auto audio = Concurrency::receive(audio_source_, 5000);\r
-                                               if(audio == eof_audio())\r
-                                                       break;\r
-                                               push(audio);    \r
+                                               if(audio_source_)\r
+                                               {\r
+                                                       auto audio = Concurrency::receive(*audio_source_);\r
+                                                       if(audio == eof_audio())\r
+                                                               break;\r
+                                                       push(audio);    \r
+                                               }\r
+                                               else\r
+                                                       push(empty_audio());    \r
                                        }                                       \r
                                });\r
 \r
-                               if(!video_ready() || !audio_ready())                            \r
+                               if((video_source_ && !video_ready()) || (audio_source_ && !audio_ready()))                              \r
                                        break;                          \r
 \r
                                commit();\r
@@ -524,6 +247,9 @@ struct frame_muxer2::implementation : public Concurrency::agent, boost::noncopya
 \r
        void push(const std::shared_ptr<AVFrame>& video_frame, int hints)\r
        {               \r
+               if(!video_frame)\r
+                       return;\r
+\r
                if(video_frame == loop_video())\r
                {       \r
                        CASPAR_LOG(debug) << L"video-frame-count: " << static_cast<float>(video_frame_count_);\r
@@ -575,11 +301,17 @@ struct frame_muxer2::implementation : public Concurrency::agent, boost::noncopya
                if(video_frame->format == CASPAR_PIX_FMT_LUMA) // CASPAR_PIX_FMT_LUMA is not valid for filter, change it to GRAY8\r
                        video_frame->format = PIX_FMT_GRAY8;\r
 \r
-               BOOST_FOREACH(auto& av_frame, filter_.execute(video_frame))\r
+               filter_.push(video_frame);\r
+\r
+               while(true)\r
                {\r
+                       auto av_frame = filter_.poll();\r
+                       if(!av_frame)\r
+                               break;\r
+               \r
                        av_frame->format = format;\r
 \r
-                       auto frame = make_write_frame(this, av_frame, frame_factory_, hints);\r
+                       auto frame = make_write_frame(this, make_safe_ptr(av_frame), frame_factory_, hints);\r
 \r
                        // Fix field-order if needed\r
                        if(frame->get_type() == core::field_mode::lower && format_desc_.field_mode == core::field_mode::upper)\r
@@ -597,6 +329,9 @@ struct frame_muxer2::implementation : public Concurrency::agent, boost::noncopya
 \r
        void push(std::shared_ptr<core::audio_buffer> audio_samples)\r
        {\r
+               if(!audio_samples)\r
+                       return;\r
+\r
                if(audio_samples == loop_audio())       \r
                {\r
                        CASPAR_LOG(debug) << L"audio-chunk-count: " << audio_sample_count_/format_desc_.audio_samples_per_frame;\r
@@ -626,7 +361,7 @@ struct frame_muxer2::implementation : public Concurrency::agent, boost::noncopya
 \r
        core::audio_buffer pop_audio()\r
        {\r
-               CASPAR_VERIFY(audio_streams_.front().size() >= format_desc_.audio_samples_per_frame);\r
+               CASPAR_ASSERT(audio_streams_.front().size() >= format_desc_.audio_samples_per_frame);\r
 \r
                auto begin = audio_streams_.front().begin();\r
                auto end   = begin + format_desc_.audio_samples_per_frame;\r
@@ -755,8 +490,8 @@ struct frame_muxer2::implementation : public Concurrency::agent, boost::noncopya
        }\r
 };\r
 \r
-frame_muxer2::frame_muxer2(video_source_t& video_source, \r
-                                                  audio_source_t& audio_source,\r
+frame_muxer2::frame_muxer2(const std::shared_ptr<video_source_t>& video_source, \r
+                                                  const std::shared_ptr<audio_source_t>& audio_source,\r
                                                   target_t& target,\r
                                                   double in_fps, \r
                                                   const safe_ptr<core::frame_factory>& frame_factory)\r
index 6bb3c08ec58ead7180199aa514c9b89be07b077f..e9cb937fdd5f5f3945b832cb87ecf2106f96fc8b 100644 (file)
@@ -23,30 +23,6 @@ struct frame_factory;
 \r
 namespace ffmpeg {\r
 \r
-class frame_muxer : boost::noncopyable\r
-{\r
-public:\r
-       frame_muxer(double in_fps, const safe_ptr<core::frame_factory>& frame_factory);\r
-       \r
-       void push(const std::shared_ptr<AVFrame>& video_frame, int hints = 0);\r
-       void push(const std::shared_ptr<core::audio_buffer>& audio_samples);\r
-       \r
-       void commit();\r
-\r
-       bool video_ready() const;\r
-       bool audio_ready() const;\r
-\r
-       size_t size() const;\r
-       bool empty() const;\r
-\r
-       int64_t calc_nb_frames(int64_t nb_frames) const;\r
-\r
-       safe_ptr<core::basic_frame> pop();\r
-private:\r
-       struct implementation;\r
-       safe_ptr<implementation> impl_;\r
-};\r
-\r
 class frame_muxer2 : boost::noncopyable\r
 {\r
 public:\r
@@ -55,8 +31,8 @@ public:
        typedef Concurrency::ISource<std::shared_ptr<core::audio_buffer>>       audio_source_t;\r
        typedef Concurrency::ITarget<std::shared_ptr<core::basic_frame>>        target_t;\r
 \r
-       frame_muxer2(video_source_t& video_source,\r
-                                audio_source_t& audio_source, \r
+       frame_muxer2(const std::shared_ptr<video_source_t>& video_source,\r
+                                const std::shared_ptr<audio_source_t>& audio_source, \r
                                 target_t& target,\r
                                 double in_fps, \r
                                 const safe_ptr<core::frame_factory>& frame_factory);\r
index 412ba58a848a48790a943cf9e18cbf54bd7976a5..f4b906b57b46a652872d9ace09b50cb45b68f464 100644 (file)
@@ -26,7 +26,6 @@
 #include "input.h"\r
 #include "util.h"\r
 #include "../ffmpeg_error.h"\r
-#include "../tbb_avcodec.h"\r
 \r
 #include <core/video_format.h>\r
 \r
@@ -57,9 +56,7 @@ using namespace Concurrency;
 \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
+static const size_t MAX_BUFFER_COUNT = 16;\r
        \r
 struct input::implementation : public Concurrency::agent, boost::noncopyable\r
 {              \r
@@ -78,13 +75,16 @@ struct input::implementation : public Concurrency::agent, boost::noncopyable
                \r
        tbb::atomic<size_t>                                                                                     nb_frames_;\r
        tbb::atomic<size_t>                                                                                     nb_loops_;\r
-\r
-       std::deque<std::shared_ptr<AVPacket>>                                           buffer_;\r
-       size_t                                                                                                          buffer_size_;\r
+       \r
+       tbb::atomic<size_t>                                                                                     packets_count_;\r
 \r
        bool                                                                                                            eof_;\r
        bool                                                                                                            stop_;\r
 \r
+       Concurrency::unbounded_buffer<int>                                                      tickets_;\r
+\r
+       boost::iterator_range<AVStream**>                                                       streams_;\r
+\r
 public:\r
        explicit implementation(input::target_t& target,\r
                                                        const safe_ptr<diagnostics::graph>& graph, \r
@@ -99,35 +99,37 @@ public:
                , start_(start)\r
                , length_(length)\r
                , frame_number_(0)\r
-               , buffer_size_(0)\r
                , eof_(false)\r
                , stop_(false)\r
        {                       \r
+               packets_count_ = 0;\r
                nb_frames_      = 0;\r
                nb_loops_       = 0;\r
                \r
                AVFormatContext* weak_format_context_ = nullptr;\r
                THROW_ON_ERROR2(avformat_open_input(&weak_format_context_, narrow(filename).c_str(), nullptr, nullptr), print());\r
+               CASPAR_VERIFY(weak_format_context_, ffmpeg_error());\r
 \r
                format_context_.reset(weak_format_context_, av_close_input_file);\r
-\r
+               \r
                av_dump_format(weak_format_context_, 0, narrow(filename).c_str(), 0);\r
                        \r
                THROW_ON_ERROR2(avformat_find_stream_info(format_context_.get(), nullptr), print());\r
                \r
+               streams_ = boost::make_iterator_range(format_context_->streams, format_context_->streams + format_context_->nb_streams);\r
                default_stream_index_ = THROW_ON_ERROR2(av_find_default_stream_index(format_context_.get()), print());\r
                \r
+               for(int n = 0; n < MAX_BUFFER_COUNT; ++n)\r
+                       tickets_.enqueue(0);\r
+\r
                if(start_ > 0)                  \r
                        seek_frame(start_);\r
-               \r
-               for(int n = 0; n < 16; ++n)\r
-                       read_next_packet();\r
-                                               \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
+               graph_->set_color("buffer-size", diagnostics::color(1.0f, 1.0f, 0.0f)); \r
 \r
-               agent::start();\r
+               CASPAR_VERIFY(default_stream_index_ > -1, ffmpeg_error());\r
        }\r
 \r
        ~implementation()\r
@@ -142,24 +144,8 @@ public:
                        while(!stop_)\r
                        {\r
                                read_next_packet();\r
-\r
-                               if(buffer_.empty())\r
-                                       break;\r
-\r
-                               if(buffer_.size() < MIN_BUFFER_COUNT || (buffer_.size() < MAX_BUFFER_COUNT && buffer_size_ < MAX_BUFFER_SIZE))\r
-                               {\r
-                                       if(Concurrency::asend(target_, buffer_.front()))\r
-                                               buffer_.pop_front();\r
-                                       Concurrency::wait(2);\r
-                               }\r
-                               else\r
-                               {\r
-                                       Concurrency::send(target_, buffer_.front());\r
-                                       buffer_.pop_front();\r
-                               }       \r
-\r
-                               graph_->update_value("buffer-size", (static_cast<double>(buffer_size_)+0.001)/MAX_BUFFER_SIZE);\r
-                               graph_->update_value("buffer-count", (static_cast<double>(buffer_.size()+0.001)/MAX_BUFFER_COUNT));                     \r
+                                                                                                       \r
+                               graph_->update_value("buffer-count", (static_cast<double>(packets_count_)+0.001)/MAX_BUFFER_COUNT);                     \r
                        }                               \r
                }\r
                catch(...)\r
@@ -167,7 +153,10 @@ public:
                        CASPAR_LOG_CURRENT_EXCEPTION();\r
                }       \r
        \r
-               Concurrency::send(target_, eof_packet());       \r
+               std::for_each(streams_.begin(), streams_.end(), [this](const AVStream* stream)\r
+               {\r
+                       Concurrency::send(target_, eof_packet(stream->index));  \r
+               });\r
                                                \r
                done();\r
        }\r
@@ -179,11 +168,11 @@ public:
 \r
                int ret = 0;\r
 \r
-               auto read_packet = create_packet();\r
+               auto packet = create_packet();\r
 \r
                {\r
                        Concurrency::scoped_oversubcription_token oversubscribe;\r
-                       ret = av_read_frame(format_context_.get(), read_packet.get()); // read_packet is only valid until next call of av_read_frame. Use av_dup_packet to extend its life.     \r
+                       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
 \r
                if(is_eof(ret))                                                                                                              \r
@@ -217,30 +206,33 @@ public:
                {               \r
                        THROW_ON_ERROR(ret, print(), "av_read_frame");\r
 \r
-                       if(read_packet->stream_index == default_stream_index_)\r
+                       if(packet->stream_index == default_stream_index_)\r
                        {\r
                                if(nb_loops_ == 0)\r
                                        ++nb_frames_;\r
                                ++frame_number_;\r
                        }\r
 \r
-                       THROW_ON_ERROR2(av_dup_packet(read_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 = read_packet->size;\r
-                       auto data = read_packet->data;\r
+                       auto size = packet->size;\r
+                       auto data = packet->data;                       \r
 \r
-                       read_packet = std::shared_ptr<AVPacket>(read_packet.get(), [=](AVPacket*)\r
+                       packet = std::shared_ptr<AVPacket>(packet.get(), [=](AVPacket*)\r
                        {\r
-                               read_packet->size = size;\r
-                               read_packet->data = data;\r
+                               packet->size = size;\r
+                               packet->data = data;\r
+                               tickets_.enqueue(0);\r
+                               --packets_count_;\r
                        });\r
-       \r
-                       buffer_.push_back(read_packet);\r
-                       buffer_size_ += read_packet->size;\r
-                               \r
-                       graph_->update_value("buffer-size", (static_cast<double>(buffer_size_)+0.001)/MAX_BUFFER_SIZE);\r
-                       graph_->update_value("buffer-count", (static_cast<double>(buffer_.size()+0.001)/MAX_BUFFER_COUNT));\r
+\r
+                       tickets_.dequeue();\r
+                       ++packets_count_;\r
+\r
+                       Concurrency::send(target_, packet);\r
+                                       \r
+                       graph_->update_value("buffer-count", (static_cast<double>(packets_count_)+0.001)/MAX_BUFFER_COUNT);\r
                }       \r
        }\r
 \r
@@ -249,7 +241,11 @@ public:
                THROW_ON_ERROR2(av_seek_frame(format_context_.get(), default_stream_index_, frame, flags), print());    \r
                auto packet = create_packet();\r
                packet->size = 0;\r
-               buffer_.push_back(loop_packet());\r
+\r
+               std::for_each(streams_.begin(), streams_.end(), [this](const AVStream* stream)\r
+               {\r
+                       Concurrency::send(target_, loop_packet(stream->index)); \r
+               });\r
        }               \r
 \r
        bool is_eof(int ret)\r
@@ -259,6 +255,8 @@ public:
                if(ret == AVERROR_EOF)\r
                        CASPAR_LOG(trace) << print() << " Received EOF. " << nb_frames_;\r
 \r
+               CASPAR_VERIFY(ret >= 0 || ret == AVERROR_EOF || ret == AVERROR(EIO), ffmpeg_error() << source_info(narrow(print())));\r
+\r
                return ret == AVERROR_EOF || ret == AVERROR(EIO) || frame_number_ >= length_; // av_read_frame doesn't always correctly return AVERROR_EOF;\r
        }\r
        \r
@@ -293,6 +291,11 @@ size_t input::nb_loops() const
        return impl_->nb_loops_;\r
 }\r
 \r
+void input::start()\r
+{\r
+       impl_->start();\r
+}\r
+\r
 void input::stop()\r
 {\r
        impl_->stop_ = true;\r
index 30a214d4907bc62f2d465b36d8099504dcdb6e79..c6a4d770389770edc78940e07649b6cdcf2a8a8f 100644 (file)
@@ -40,7 +40,7 @@ class graph;
 }\r
         \r
 namespace ffmpeg {\r
-                       \r
+                               \r
 class input : boost::noncopyable\r
 {\r
 public:\r
@@ -58,6 +58,7 @@ public:
        \r
        safe_ptr<AVFormatContext> context();\r
 \r
+       void start();\r
        void stop();\r
 private:\r
        friend struct implemenation;\r
index a156062c2751d9dc577f77d36e8eb0bd9a92142d..9bb9680128ac40c2980d012855a0f67193820f1a 100644 (file)
@@ -297,16 +297,38 @@ std::shared_ptr<AVPacket> create_packet()
        return packet;\r
 }\r
 \r
-const std::shared_ptr<AVPacket>& loop_packet()\r
+const std::shared_ptr<AVPacket>& loop_packet(int index)\r
 {\r
-       static auto packet1 = create_packet();\r
-       return packet1;\r
+       static Concurrency::critical_section mutex;\r
+       static std::map<int, std::shared_ptr<AVPacket>> packets;\r
+\r
+       Concurrency::critical_section::scoped_lock lock(mutex);\r
+\r
+       auto& packet = packets[index];\r
+       if(!packet)\r
+       {\r
+               packet = create_packet();\r
+               packet->stream_index = index;\r
+       }\r
+\r
+       return packet;\r
 }\r
 \r
-const std::shared_ptr<AVPacket>& eof_packet()\r
+const std::shared_ptr<AVPacket>& eof_packet(int index)\r
 {\r
-       static auto packet2 = create_packet();\r
-       return packet2;\r
+       static Concurrency::critical_section mutex;\r
+       static std::map<int, std::shared_ptr<AVPacket>> packets;\r
+\r
+       Concurrency::critical_section::scoped_lock lock(mutex);\r
+\r
+       auto& packet = packets[index];\r
+       if(!packet)\r
+       {\r
+               packet = create_packet();\r
+               packet->stream_index = index;\r
+       }\r
+\r
+       return packet;\r
 }\r
 \r
 const std::shared_ptr<AVFrame>& loop_video()\r
index 1811413db8b46baddf79c6b4a8249ba4ecbbca10..60c015cb9ad939094dfe6112285e49650d8f9495 100644 (file)
@@ -47,8 +47,10 @@ safe_ptr<core::write_frame> make_write_frame(const void* tag, const safe_ptr<AVF
 void fix_meta_data(AVFormatContext& context);\r
 \r
 std::shared_ptr<AVPacket> create_packet();\r
-const std::shared_ptr<AVPacket>& loop_packet();\r
-const std::shared_ptr<AVPacket>& eof_packet();\r
+\r
+const std::shared_ptr<AVPacket>& loop_packet(int index);\r
+const std::shared_ptr<AVPacket>& eof_packet(int index);\r
+\r
 const std::shared_ptr<AVFrame>& loop_video();\r
 const std::shared_ptr<AVFrame>& empty_video();\r
 const std::shared_ptr<AVFrame>& eof_video();\r
index 6f0ada7bc5fb37e583b60f8ac7d9a73137d16f73..19c46cb65e9f30dfabf08474ee68382f77db3e4b 100644 (file)
@@ -25,7 +25,6 @@
 #include "../filter/filter.h"\r
 \r
 #include "../../ffmpeg_error.h"\r
-#include "../../tbb_avcodec.h"\r
 \r
 #include <core/producer/frame/basic_frame.h>\r
 \r
@@ -47,14 +46,11 @@ namespace caspar { namespace ffmpeg {
 struct video_decoder::implementation : public Concurrency::agent, boost::noncopyable\r
 {\r
        video_decoder::source_t&                                source_;\r
-       video_decoder::forward_t&                               forward_;\r
        video_decoder::target_t&                                target_;\r
 \r
        std::shared_ptr<AVCodecContext>                 codec_context_;\r
        int                                                                             index_;\r
-\r
-       filter                                                                  filter_;\r
-\r
+       \r
        double                                                                  fps_;\r
        int64_t                                                                 nb_frames_;\r
 \r
@@ -62,54 +58,46 @@ struct video_decoder::implementation : public Concurrency::agent, boost::noncopy
        size_t                                                                  height_;\r
        bool                                                                    is_progressive_;\r
 \r
+       Concurrency::event                                              event_;\r
+\r
 public:\r
        explicit implementation(video_decoder::source_t& source,\r
-                                                       video_decoder::forward_t& forward,\r
                                                        video_decoder::target_t& target,\r
                                                        const safe_ptr<AVFormatContext>& context,\r
-                                                       double fps,\r
-                                                       const std::wstring& filter) \r
+                                                       double fps) \r
                : source_(source)\r
-               , forward_(forward)\r
                , target_(target)\r
-               , filter_(filter.empty() ? L"copy" : filter)\r
                , fps_(fps)\r
                , nb_frames_(0)\r
                , width_(0)\r
                , height_(0)\r
                , is_progressive_(true)\r
        {\r
-               try\r
-               {\r
-                       AVCodec* dec;\r
-                       index_ = THROW_ON_ERROR2(av_find_best_stream(context.get(), AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0), "[video_decoder]");\r
+               event_.set();\r
+\r
+               AVCodec* dec;\r
+               index_ = THROW_ON_ERROR3(av_find_best_stream(context.get(), AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0), "[video_decoder]", ffmpeg_stream_not_found);\r
+               CASPAR_VERIFY(index_ > -1, ffmpeg_error());\r
                                                \r
-                       THROW_ON_ERROR2(tbb_avcodec_open(context->streams[index_]->codec, dec), "[video_decoder]");\r
+               THROW_ON_ERROR2(avcodec_open(context->streams[index_]->codec, dec), "[video_decoder]");\r
+               CASPAR_VERIFY(context->streams[index_]->codec, ffmpeg_error())\r
                                                                \r
-                       codec_context_.reset(context->streams[index_]->codec, tbb_avcodec_close);\r
+               codec_context_.reset(context->streams[index_]->codec, avcodec_close);\r
                \r
-                       CASPAR_LOG(debug) << "[video_decoder] " << context->streams[index_]->codec->codec->long_name;\r
+               CASPAR_LOG(debug) << "[video_decoder] " << context->streams[index_]->codec->codec->long_name;\r
 \r
-                       // Some files give an invalid time_base numerator, try to fix it.\r
+               // Some files give an invalid time_base numerator, try to fix it.\r
 \r
-                       fix_meta_data(*context);\r
+               fix_meta_data(*context);\r
                        \r
-                       fps_ = static_cast<double>(codec_context_->time_base.den) / static_cast<double>(codec_context_->time_base.num);\r
-                       nb_frames_ = context->streams[index_]->nb_frames;\r
+               fps_ = static_cast<double>(codec_context_->time_base.den) / static_cast<double>(codec_context_->time_base.num);\r
+               nb_frames_ = context->streams[index_]->nb_frames;\r
+                       \r
+               width_  = codec_context_->width;\r
+               height_ = codec_context_->height;\r
 \r
-                       if(double_rate(filter))\r
-                               fps_ *= 2;\r
-\r
-                       width_  = codec_context_->width;\r
-                       height_ = codec_context_->height;\r
-               }\r
-               catch(...)\r
-               {\r
-                       index_ = THROW_ON_ERROR2(av_find_best_stream(context.get(), AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0), "[video_decoder]");\r
-\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                       CASPAR_LOG(warning) << "[video_decoder] Failed to open video-stream. Running without video.";   \r
-               }\r
+               CASPAR_VERIFY(width_ > 0, ffmpeg_error());\r
+               CASPAR_VERIFY(height_ > 0, ffmpeg_error());\r
 \r
                start();\r
        }\r
@@ -125,54 +113,35 @@ public:
                {\r
                        while(true)\r
                        {\r
-                               auto packet = Concurrency::receive(source_, 5000);\r
-\r
-                               if(packet == eof_packet() || packet == loop_packet() || packet->stream_index != index_)\r
-                                       Concurrency::send(forward_, packet);\r
-                               \r
-                               if(packet == eof_packet())                              \r
+                               auto packet = Concurrency::receive(source_, [this](const std::shared_ptr<AVPacket>& packet)\r
+                               {\r
+                                       return packet && packet->stream_index == index_;\r
+                               });\r
+\r
+                               //if(packet == eof_packet(index_) || packet == loop_packet(index_))\r
+                               //{\r
+                               //      if(codec_context_->codec->capabilities & CODEC_CAP_DELAY)\r
+                               //      {\r
+                               //              AVPacket pkt;\r
+                               //              av_init_packet(&pkt);\r
+                               //              pkt.data = nullptr;\r
+                               //              pkt.size = 0;\r
+                               //\r
+                               //              while(decode(pkt)){}\r
+                               //      }\r
+                               //}\r
+                                                               \r
+                               if(packet == eof_packet(index_))                                \r
                                        break;\r
                                                                \r
-                               if(packet == loop_packet())\r
+                               if(packet == loop_packet(index_))\r
                                {       \r
-                                       if(codec_context_)\r
-                                       {\r
-                                               if(codec_context_->codec->capabilities & CODEC_CAP_DELAY)\r
-                                               {\r
-                                                       AVPacket pkt;\r
-                                                       av_init_packet(&pkt);\r
-                                                       pkt.data = nullptr;\r
-                                                       pkt.size = 0;\r
-                               \r
-                                                       BOOST_FOREACH(auto& frame1, decode(pkt))\r
-                                                       {\r
-                                                               BOOST_FOREACH(auto& frame2, filter_.execute(frame1))\r
-                                                                       Concurrency::send(target_, std::shared_ptr<AVFrame>(frame2));\r
-                                                       }       \r
-                                               }\r
-\r
-                                               avcodec_flush_buffers(codec_context_.get());\r
-                                       }\r
-                                       \r
+                                       avcodec_flush_buffers(codec_context_.get());                                    \r
                                        Concurrency::send(target_, loop_video());       \r
                                }\r
                                else if(packet->stream_index == index_)\r
-                               {\r
-                                       if(!codec_context_)\r
-                                       {\r
-                                               Concurrency::send(target_, empty_video());      \r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               while(packet->size > 0)\r
-                                               {\r
-                                                       BOOST_FOREACH(auto& frame1, decode(*packet))\r
-                                                       {\r
-                                                               BOOST_FOREACH(auto& frame2, filter_.execute(frame1))\r
-                                                                       Concurrency::send(target_, std::shared_ptr<AVFrame>(frame2));\r
-                                                       }\r
-                                               }\r
-                                       }\r
+                               {                                       \r
+                                       Concurrency::send(target_, decode(*packet));    \r
                                }\r
                        }\r
                }\r
@@ -186,13 +155,20 @@ public:
                done();\r
        }\r
 \r
-       std::vector<std::shared_ptr<AVFrame>> decode(AVPacket& pkt)\r
+       std::shared_ptr<AVFrame> decode(AVPacket& pkt)\r
        {\r
-               std::shared_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\r
+               event_.wait();\r
+\r
+               std::shared_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), [this](AVFrame* frame)\r
+               {\r
+                       av_free(frame);\r
+                       event_.set();\r
+               });\r
 \r
                int frame_finished = 0;\r
                THROW_ON_ERROR2(avcodec_decode_video2(codec_context_.get(), decoded_frame.get(), &frame_finished, &pkt), "[video_decocer]");\r
-               \r
+               event_.reset();\r
+\r
                // If a decoder consumes less then the whole packet then something is wrong\r
                // that might be just harmless padding at the end, or a problem with the\r
                // AVParser or demuxer which puted more then one frame in a AVPacket.\r
@@ -200,14 +176,14 @@ public:
                pkt.size = 0;\r
 \r
                if(frame_finished == 0) \r
-                       return std::vector<std::shared_ptr<AVFrame>>();\r
+                       return nullptr;\r
 \r
-               if(decoded_frame->repeat_pict % 2 > 0)\r
+               if(decoded_frame->repeat_pict > 0)\r
                        CASPAR_LOG(warning) << "[video_decoder]: Field repeat_pict not implemented.";\r
                \r
                is_progressive_ = decoded_frame->interlaced_frame == 0;\r
-\r
-               return std::vector<std::shared_ptr<AVFrame>>(1 + decoded_frame->repeat_pict/2, decoded_frame);\r
+                               \r
+               return decoded_frame;\r
        }\r
                \r
        double fps() const\r
@@ -217,12 +193,10 @@ public:
 };\r
 \r
 video_decoder::video_decoder(source_t& source,\r
-                                                        forward_t& forward,\r
                                                         target_t& target,\r
                                                         const safe_ptr<AVFormatContext>& context, \r
-                                                        double fps, \r
-                                                        const std::wstring& filter) \r
-       : impl_(new implementation(source, forward, target, context, fps, filter))\r
+                                                        double fps) \r
+       : impl_(new implementation(source, target, context, fps))\r
 {\r
 }\r
 \r
index 550d042f7cdf28afdbfe804abb3b168737a26037..e53e0463b270b044d27efe67c15a14406b6215fb 100644 (file)
@@ -45,15 +45,12 @@ class video_decoder : boost::noncopyable
 public:\r
 \r
        typedef Concurrency::ISource<std::shared_ptr<AVPacket>> source_t;\r
-       typedef Concurrency::ITarget<std::shared_ptr<AVPacket>> forward_t;\r
        typedef Concurrency::ITarget<std::shared_ptr<AVFrame>>  target_t;\r
 \r
        explicit video_decoder(source_t& source,\r
-                                                  forward_t& forward,\r
                                                   target_t& target,\r
                                                   const safe_ptr<AVFormatContext>& context, \r
-                                                  double fps, \r
-                                                  const std::wstring& filter); \r
+                                                  double fps); \r
 \r
        size_t width() const;\r
        size_t height() const;\r
diff --git a/modules/ffmpeg/tbb_avcodec.cpp b/modules/ffmpeg/tbb_avcodec.cpp
deleted file mode 100644 (file)
index 961c06f..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-// Author Robert Nagy\r
-\r
-#include "stdafx.h"\r
-\r
-#include "tbb_avcodec.h"\r
-\r
-#include <common/log/log.h>\r
-#include <common/env.h>\r
-#include <common/utility/assert.h>\r
-\r
-#include <ppl.h>\r
-\r
-#include <tbb/atomic.h>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
-       #define __STDC_CONSTANT_MACROS\r
-       #define __STDC_LIMIT_MACROS\r
-       #include <libavformat/avformat.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar { namespace ffmpeg {\r
-               \r
-int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)\r
-{\r
-       Concurrency::parallel_for(0, count, [&](size_t n)\r
-       {\r
-               int r = func(s, reinterpret_cast<uint8_t*>(arg) + n*size);\r
-               if(ret)\r
-                       ret[n] = r;\r
-       });\r
-\r
-       return 0;\r
-}\r
-\r
-int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)\r
-{      \r
-       tbb::atomic<int> counter;   \r
-    counter = 0;   \r
-\r
-       // Note: this will probably only work when tbb::task_scheduler_init::num_threads() < 16.\r
-    Concurrency::parallel_for(0, count, 2, [&](int jobnr)    \r
-    {   \r
-        int threadnr = counter++;   \r
-        int r = func(s, arg, jobnr, threadnr);   \r
-        if (ret)   \r
-            ret[jobnr] = r;  \r
-        --counter;\r
-    });   \r
-\r
-    return 0;  \r
-}\r
-\r
-void thread_init(AVCodecContext* s)\r
-{\r
-       static const size_t MAX_THREADS = 16; // See mpegvideo.h\r
-       static int dummy_opaque;\r
-\r
-    s->active_thread_type = FF_THREAD_SLICE;\r
-       s->thread_opaque          = &dummy_opaque; \r
-    s->execute                   = thread_execute;\r
-    s->execute2                          = thread_execute2;\r
-    s->thread_count              = MAX_THREADS; // We are using a task-scheduler, so use as many "threads/tasks" as possible. \r
-\r
-       CASPAR_LOG(info) << "Initialized ffmpeg tbb context.";\r
-}\r
-\r
-void thread_free(AVCodecContext* s)\r
-{\r
-       if(!s->thread_opaque)\r
-               return;\r
-\r
-       s->thread_opaque = nullptr;\r
-       \r
-       CASPAR_LOG(info) << "Released ffmpeg tbb context.";\r
-}\r
-\r
-int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)\r
-{\r
-       avctx->thread_count = 1;\r
-       // Some codecs don't like to have multiple multithreaded decoding instances. Only enable for those we know work.\r
-       if((codec->id == CODEC_ID_MPEG2VIDEO) && \r
-         (codec->capabilities & CODEC_CAP_SLICE_THREADS) && \r
-         (avctx->thread_type & FF_THREAD_SLICE))\r
-       {\r
-               thread_init(avctx);\r
-       }       \r
-       // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1.\r
-       return avcodec_open(avctx, codec); \r
-}\r
-\r
-int tbb_avcodec_close(AVCodecContext* avctx)\r
-{\r
-       thread_free(avctx);\r
-       // ff_thread_free will not be executed since thread_opaque == nullptr.\r
-       return avcodec_close(avctx); \r
-}\r
-\r
-}}
\ No newline at end of file
diff --git a/modules/ffmpeg/tbb_avcodec.h b/modules/ffmpeg/tbb_avcodec.h
deleted file mode 100644 (file)
index 2b2ab39..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once\r
-\r
-struct AVCodecContext;\r
-struct AVCodec;\r
-\r
-namespace caspar { namespace ffmpeg {\r
-       \r
-int tbb_avcodec_open(AVCodecContext *avctx, AVCodec *codec);\r
-int tbb_avcodec_close(AVCodecContext *avctx);\r
-\r
-}}
\ No newline at end of file
index 9550a5a1e81f99e783f7f444ee066021b83a3a7c..d29e3bd6707fbd44f28371d6d3ac09b23aaa0c85 100644 (file)
@@ -294,8 +294,16 @@ public:
                auto av_frame = get_av_frame();\r
                av_frame->data[0] = const_cast<uint8_t*>(frame->image_data().begin());\r
 \r
-               auto frames = filter_.execute(av_frame);\r
-\r
+               std::vector<safe_ptr<AVFrame>> frames;\r
+               filter_.push(av_frame);\r
+               while(true)\r
+               {\r
+                       auto frame = filter_.poll();\r
+                       if(!frame)\r
+                               break;\r
+                       frames.push_back(make_safe_ptr(frame));\r
+               }\r
+               \r
                if(frames.empty())\r
                        return;\r
 \r
index d3c8760532fa98be0bdbdc20b3cc0cb4aab70e42..19911e488ba2c94694ace4c484de53056b3cafc8 100644 (file)
@@ -650,7 +650,7 @@ bool LoadbgCommand::DoExecute()
 \r
                bool auto_play = std::find(_parameters.begin(), _parameters.end(), L"AUTO") != _parameters.end();\r
 \r
-               auto pFP2 = create_transition_producer(GetChannel()->get_video_format_desc().field_mode, create_destroy_producer_proxy(GetChannel()->context().destruction(), pFP), transitionInfo);\r
+               auto pFP2 = create_transition_producer(GetChannel()->get_video_format_desc().field_mode, create_destroy_producer_proxy(pFP), transitionInfo);\r
                GetChannel()->stage()->load(GetLayerIndex(), pFP2, false, auto_play ? transitionInfo.duration : -1); // TODO: LOOP\r
        \r
                CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully to background");\r
index 697cb628867cf289128b53a6080b862c8371c870..576d4264c39ab8d6d811f2a71a5c60c4c8ef819b 100644 (file)
     </producers>\r
     <channels>\r
       <channel>\r
-        <video-mode>720p5000</video-mode>\r
+        <video-mode>1080p5000</video-mode>\r
         <consumers>\r
           <decklink>\r
             <device>1</device>\r
             <embedded-audio>true</embedded-audio>\r
-            <low-latency>true</low-latency>\r
           </decklink>\r
-          <audio></audio>\r
         </consumers>\r
       </channel>\r
     </channels>\r