]> git.sesse.net Git - casparcg/commitdiff
2.0.2: Merged ntsc-audio-exp branch for proper/native NTSC audio support.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Tue, 29 Nov 2011 02:07:16 +0000 (02:07 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Tue, 29 Nov 2011 02:07:16 +0000 (02:07 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.2@1709 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

16 files changed:
core/consumer/frame_consumer.cpp
core/consumer/frame_consumer.h
core/consumer/output.cpp
core/mixer/audio/audio_mixer.cpp
core/producer/frame_producer.cpp
core/producer/frame_producer.h
core/video_format.cpp
core/video_format.h
modules/bluefish/consumer/bluefish_consumer.cpp
modules/decklink/consumer/decklink_consumer.cpp
modules/decklink/producer/decklink_producer.cpp
modules/ffmpeg/producer/audio/audio_resampler.cpp
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/muxer/frame_muxer.cpp
modules/flash/producer/flash_producer.cpp
modules/oal/consumer/oal_consumer.cpp

index 4f4b5569353d44352edfe49eaad64766de302ecc..35f651b8f602e54aaf9902af6fff3bc401dfae4d 100644 (file)
 #include <common/env.h>\r
 #include <common/memory/safe_ptr.h>\r
 #include <common/exception/exceptions.h>\r
+#include <core/video_format.h>\r
+#include <core/mixer/read_frame.h>\r
+\r
+#include <boost/circular_buffer.hpp>\r
 \r
 namespace caspar { namespace core {\r
                \r
@@ -59,4 +63,67 @@ safe_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>&
        return consumer;\r
 }\r
 \r
+// This class is used to guarantee that audio cadence is correct. This is important for NTSC audio.\r
+class cadence_guard : public frame_consumer\r
+{\r
+       safe_ptr<frame_consumer>                consumer_;\r
+       std::vector<size_t>                             audio_cadence_;\r
+       boost::circular_buffer<size_t>  sync_buffer_;\r
+       bool                                                    synced_;\r
+public:\r
+       cadence_guard(safe_ptr<frame_consumer>&& consumer)\r
+               : consumer_(std::move(consumer))\r
+       {\r
+       }\r
+       \r
+       virtual void initialize(const video_format_desc& format_desc, int channel_index, int sub_index) override\r
+       {\r
+               audio_cadence_  = format_desc.audio_cadence;\r
+               sync_buffer_    = boost::circular_buffer<size_t>(format_desc.audio_cadence.size());\r
+               consumer_->initialize(format_desc, channel_index, sub_index);\r
+       }\r
+\r
+       virtual bool send(const safe_ptr<read_frame>& frame) override\r
+       {               \r
+               sync_buffer_.push_back(static_cast<size_t>(frame->audio_data().size()));\r
+               \r
+               if(!boost::range::equal(sync_buffer_, audio_cadence_))\r
+               {\r
+                       synced_ = false;\r
+                       CASPAR_LOG(trace) << L"[cadence_guard] Audio cadence unsynced. Skipping frame.";\r
+                       return true;\r
+               }\r
+               else if(!synced_)\r
+               {\r
+                       synced_ = true;\r
+                       boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
+                       return true;\r
+               }\r
+\r
+               boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
+\r
+               return consumer_->send(frame);\r
+       }\r
+\r
+       virtual std::wstring print() const override\r
+       {\r
+               return consumer_->print();\r
+       }\r
+\r
+       virtual bool has_synchronization_clock() const override\r
+       {\r
+               return consumer_->has_synchronization_clock();\r
+       }\r
+\r
+       virtual size_t buffer_depth() const override\r
+       {\r
+               return consumer_->buffer_depth();\r
+       }\r
+};\r
+\r
+safe_ptr<frame_consumer> create_consumer_cadence_guard(safe_ptr<frame_consumer>&& consumer)\r
+{\r
+       return make_safe<cadence_guard>(std::move(consumer));\r
+}\r
+\r
 }}
\ No newline at end of file
index 090c2ff2181b8f7c661cbac0afe56d8a44a5c24f..e4aafca2b8aab4588391f994a95ae14f499d82d4 100644 (file)
@@ -19,8 +19,6 @@
 */\r
 #pragma once\r
 \r
-#include "../video_format.h"\r
-\r
 #include <common/memory/safe_ptr.h>\r
 \r
 #include <boost/noncopyable.hpp>\r
@@ -59,6 +57,8 @@ struct frame_consumer : boost::noncopyable
        }\r
 };\r
 \r
+safe_ptr<frame_consumer> create_consumer_cadence_guard(safe_ptr<frame_consumer>&& consumer);\r
+\r
 typedef std::function<safe_ptr<core::frame_consumer>(const std::vector<std::wstring>&)> consumer_factory_t;\r
 \r
 void register_consumer_factory(const consumer_factory_t& factory);\r
index 4da6f05bdc65121affd0388b42c21ce4458b58a6..ff16c280e9ca763800715bc679b17aac77d8f6c9 100644 (file)
@@ -40,7 +40,7 @@
 #include <boost/timer.hpp>\r
 \r
 namespace caspar { namespace core {\r
-\r
+       \r
 struct output::implementation\r
 {      \r
        typedef std::pair<safe_ptr<read_frame>, safe_ptr<read_frame>> fill_and_key;\r
@@ -79,6 +79,7 @@ public:
                        consumers_.erase(index);\r
                });\r
 \r
+               consumer = create_consumer_cadence_guard(std::move(consumer));\r
                consumer->initialize(format_desc_, channel_index_, index);\r
 \r
                executor_.invoke([&]\r
index 627826b052962772ea8f5d70f88e5fb38e3573a1..60e7dd812701519252fa782de1828ad2fed0ec50 100644 (file)
 #include <core/mixer/write_frame.h>\r
 #include <core/producer/frame/frame_transform.h>\r
 \r
-#include <stack>\r
+#include <tbb/cache_aligned_allocator.h>\r
+\r
+#include <boost/range.hpp>\r
+#include <boost/range/algorithm_ext/push_back.hpp>\r
+\r
+#include <array>\r
 #include <map>\r
+#include <stack>\r
 #include <vector>\r
+#include <valarray>\r
 \r
 namespace caspar { namespace core {\r
 \r
@@ -35,16 +42,38 @@ struct audio_item
        const void*                     tag;\r
        frame_transform         transform;\r
        audio_buffer            audio_data;\r
+\r
+       audio_item()\r
+       {\r
+       }\r
+\r
+       audio_item(audio_item&& other)\r
+               : tag(std::move(other.tag))\r
+               , transform(std::move(other.transform))\r
+               , audio_data(std::move(other.audio_data))\r
+       {\r
+       }\r
 };\r
+\r
+typedef std::vector<float, tbb::cache_aligned_allocator<float>> audio_buffer_ps;\r
        \r
-struct audio_mixer::implementation\r
+struct audio_stream\r
 {\r
-       std::stack<core::frame_transform>                               transform_stack_;\r
-       std::map<const void*, core::frame_transform>    prev_frame_transforms_;\r
-       std::vector<audio_item>                                                 items_;\r
+       frame_transform         transform;\r
+       audio_buffer_ps         audio_data;\r
+};\r
 \r
+struct audio_mixer::implementation\r
+{\r
+       std::stack<core::frame_transform>       transform_stack_;\r
+       std::map<const void*, audio_stream>     audio_streams_;\r
+       std::vector<audio_item>                         items_;\r
+       std::vector<size_t>                                     audio_cadence_;\r
+       video_format_desc                                       format_desc_;\r
+       \r
 public:\r
        implementation()\r
+               : format_desc_(video_format_desc::get(video_format::invalid))\r
        {\r
                transform_stack_.push(core::frame_transform());\r
        }\r
@@ -63,8 +92,8 @@ public:
                item.tag                = frame.tag();\r
                item.transform  = transform_stack_.top();\r
                item.audio_data = std::move(frame.audio_data()); // Note: We don't need to care about upper/lower since audio_data is removed/moved from the last field.\r
-\r
-               items_.push_back(item);         \r
+               \r
+               items_.push_back(std::move(item));              \r
        }\r
 \r
        void begin(const core::frame_transform& transform)\r
@@ -79,74 +108,81 @@ public:
        \r
        audio_buffer mix(const video_format_desc& format_desc)\r
        {       \r
-               //CASPAR_ASSERT(format_desc.audio_channels == 2);\r
-               //CASPAR_ASSERT(format_desc.audio_samples_per_frame % 4 == 0);\r
-\r
-               // NOTE: auto data should be larger than format_desc_.audio_samples_per_frame to allow sse to read/write beyond size.\r
-\r
-               auto intermediate       = std::vector<float, tbb::cache_aligned_allocator<float>>(format_desc.audio_samples_per_frame+128, 0.0f);\r
-               auto result                     = audio_buffer(format_desc.audio_samples_per_frame+128);        \r
-               auto result_128         = reinterpret_cast<__m128i*>(result.data());\r
+               if(format_desc_ != format_desc)\r
+               {\r
+                       audio_streams_.clear();\r
+                       audio_cadence_ = format_desc.audio_cadence;\r
+                       format_desc_ = format_desc;\r
+               }               \r
+               \r
+               std::map<const void*, audio_stream>     next_audio_streams_;\r
 \r
-               std::map<const void*, core::frame_transform> next_frame_transforms;\r
-                               \r
                BOOST_FOREACH(auto& item, items_)\r
-               {                                               \r
-                       auto next = item.transform;\r
-                       auto prev = next;\r
+               {                       \r
+                       audio_buffer_ps next_audio;\r
 \r
-                       const auto it = prev_frame_transforms_.find(item.tag);\r
-                       if(it != prev_frame_transforms_.end())\r
-                               prev = it->second;\r
-                               \r
-                       next_frame_transforms[item.tag] = next; // Store all active tags, inactive tags will be removed at the end.\r
-                                       \r
-                       if(prev.volume < 0.001 && next.volume < 0.001)\r
-                               continue;\r
+                       auto next_transform = item.transform;\r
+                       auto prev_transform = next_transform;\r
 \r
-                       if(item.audio_data.size() != format_desc.audio_samples_per_frame)\r
-                               continue;\r
+                       const auto it = audio_streams_.find(item.tag);\r
+                       if(it != audio_streams_.end())\r
+                       {       \r
+                               prev_transform  = it->second.transform;\r
+                               next_audio              = std::move(it->second.audio_data);\r
+                       }\r
 \r
-                       const float prev_volume = static_cast<float>(prev.volume);\r
-                       const float next_volume = static_cast<float>(next.volume);\r
+                       if(prev_transform.volume < 0.001 && next_transform.volume < 0.001)\r
+                               continue;\r
+                       \r
+                       const float prev_volume = static_cast<float>(prev_transform.volume);\r
+                       const float next_volume = static_cast<float>(next_transform.volume);\r
                                                                        \r
-                       auto alpha              = (next_volume-prev_volume)/static_cast<float>(format_desc.audio_samples_per_frame/format_desc.audio_channels);\r
-                       auto alpha_ps   = _mm_set_ps1(alpha*2.0f);\r
-                       auto volume_ps  = _mm_setr_ps(prev_volume, prev_volume, prev_volume+alpha, prev_volume+alpha);\r
-\r
-                       if(&item != &items_.back())\r
+                       auto alpha              = (next_volume-prev_volume)/static_cast<float>(item.audio_data.size()/format_desc.audio_channels);\r
+                       \r
+                       audio_buffer_ps result;\r
+                       result.reserve(item.audio_data.size());\r
+                       for(size_t n = 0; n < item.audio_data.size()/2; ++n)\r
                        {\r
-                               for(size_t n = 0; n < format_desc.audio_samples_per_frame/4; ++n)\r
-                               {               \r
-                                       auto sample_ps          = _mm_cvtepi32_ps(_mm_load_si128(reinterpret_cast<__m128i*>(&item.audio_data[n*4])));\r
-                                       auto res_sample_ps      = _mm_load_ps(&intermediate[n*4]);                                                                                      \r
-                                       sample_ps                       = _mm_mul_ps(sample_ps, volume_ps);     \r
-                                       res_sample_ps           = _mm_add_ps(sample_ps, res_sample_ps); \r
-\r
-                                       volume_ps                       = _mm_add_ps(volume_ps, alpha_ps);\r
-\r
-                                       _mm_store_ps(&intermediate[n*4], res_sample_ps);\r
-                               }\r
+                               result.push_back(item.audio_data[n*2+0] * (prev_volume + n * alpha));\r
+                               result.push_back(item.audio_data[n*2+1] * (prev_volume + n * alpha));\r
                        }\r
-                       else\r
+                                               \r
+                       boost::range::push_back(next_audio, std::move(result));\r
+                               \r
+                       next_audio_streams_[item.tag].transform  = std::move(next_transform); // Store all active tags, inactive tags will be removed at the end.\r
+                       next_audio_streams_[item.tag].audio_data = std::move(next_audio);                       \r
+               }                               \r
+               items_.clear();\r
+\r
+               audio_streams_  = std::move(next_audio_streams_);\r
+               next_audio_streams_.clear();\r
+               \r
+               if(audio_streams_.empty())              \r
+                       audio_streams_[nullptr].audio_data = audio_buffer_ps(audio_cadence_.front(), 0.0f);\r
+                               \r
+               std::vector<float> result_ps(audio_cadence_.front(), 0.0f);\r
+               BOOST_FOREACH(auto& stream, audio_streams_)\r
+               {\r
+                       auto& audio_data        = stream.second.audio_data;\r
+                       \r
+                       if(audio_data.size() < audio_cadence_.front())\r
                        {\r
-                               for(size_t n = 0; n < format_desc.audio_samples_per_frame/4; ++n)\r
-                               {               \r
-                                       auto sample_ps          = _mm_cvtepi32_ps(_mm_load_si128(reinterpret_cast<__m128i*>(&item.audio_data[n*4])));\r
-                                       auto res_sample_ps      = _mm_load_ps(&intermediate[n*4]);                                                                                      \r
-                                       sample_ps                       = _mm_mul_ps(sample_ps, volume_ps);     \r
-                                       res_sample_ps           = _mm_add_ps(sample_ps, res_sample_ps); \r
-                                       \r
-                                       _mm_stream_si128(result_128++, _mm_cvtps_epi32(res_sample_ps));\r
-                               }\r
+                               CASPAR_LOG(warning) << "[audio_mixer] Incorrect frame audio cadence, prepending silence: " << audio_cadence_.front()-audio_data.size();\r
+                               boost::range::push_back(audio_data, audio_buffer_ps(audio_cadence_.front()-audio_data.size(), 0.0f));\r
                        }\r
-               }                               \r
 \r
-               items_.clear();\r
-               prev_frame_transforms_ = std::move(next_frame_transforms);      \r
+                       for(size_t n = 0; n < audio_cadence_.front(); ++n)\r
+                               result_ps[n] += audio_data[n];\r
 \r
-               result.resize(format_desc.audio_samples_per_frame);\r
-               return std::move(result);\r
+                       audio_data.erase(std::begin(audio_data), std::begin(audio_data) + audio_cadence_.front());\r
+               }               \r
+               \r
+               boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
+               \r
+               audio_buffer result;\r
+               result.reserve(result_ps.size());\r
+               boost::range::transform(result_ps, std::back_inserter(result), [](float sample){return static_cast<int32_t>(sample);});                                         \r
+               return result;\r
        }\r
 };\r
 \r
index 772d5647bc1825e66a5d8b7dbf6060b37880c9cf..ef93ee8cde6e9de9170500a1f50314e37a12f5da 100644 (file)
@@ -103,7 +103,7 @@ public:
        virtual int64_t                                                         file_frame_number() const override                                                                              {return (*producer_)->file_frame_number();}\r
 };\r
 \r
-safe_ptr<core::frame_producer> create_destroy_proxy(safe_ptr<core::frame_producer>&& producer)\r
+safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer>&& producer)\r
 {\r
        return make_safe<destroy_producer_proxy>(std::move(producer));\r
 }\r
index d07ce3258b35931cbd5e5179160f7d70ddb689e6..ac7ba1ea6dc16f2b9cdad3617b59f225fbbd3f99 100644 (file)
@@ -82,7 +82,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
 safe_ptr<core::frame_producer> create_producer(const safe_ptr<frame_factory>&, const std::wstring& params);\r
-safe_ptr<core::frame_producer> create_destroy_proxy(safe_ptr<core::frame_producer>&& producer);\r
+safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer>&& producer);\r
 \r
 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 cb160fff6e85f909e0fedf8ae0bd313bde35ecde..ee33c19c6fe23da0a2516011c0be284a2aacaf64 100644 (file)
@@ -23,8 +23,9 @@
 #include "video_format.h"\r
 \r
 #include <boost/algorithm/string.hpp>\r
+#include <boost/assign.hpp>\r
 \r
-#define DEFINE_VIDEOFORMATDESC(fmt, w, h, sw, sh, m, scale, duration, name) \\r
+#define DEFINE_VIDEOFORMATDESC(fmt, w, h, sw, sh, m, scale, duration, audio_samples, name) \\r
 { \\r
        (fmt), \\r
        (w), \\r
        (name),\\r
        (48000),\\r
        (2),\\r
-       (static_cast<size_t>(48000.0/((double)scale/(double)duration)+0.99)*2)\\r
+       (audio_samples)\\r
 }\r
 \r
+\r
 namespace caspar { namespace core {\r
        \r
 const video_format_desc format_descs[video_format::count] =  \r
 {                                                                         \r
-       DEFINE_VIDEOFORMATDESC(video_format::pal                ,720,  576,  1024,  576,  field_mode::upper,            25,             1,              L"PAL"), \r
-       DEFINE_VIDEOFORMATDESC(video_format::ntsc               ,720,  486,  720,  534,  field_mode::lower,                     30000,  1001,   L"NTSC"), \r
-       DEFINE_VIDEOFORMATDESC(video_format::x576p2500  ,720,  576,  720,  576,  field_mode::progressive,       25,             1,              L"576p2500"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x720p2500  ,1280, 720,  1280, 720,  field_mode::progressive,       25,             1,              L"720p2500"), \r
-       DEFINE_VIDEOFORMATDESC(video_format::x720p5000  ,1280, 720,  1280, 720,  field_mode::progressive,       50,             1,              L"720p5000"), \r
-       DEFINE_VIDEOFORMATDESC(video_format::x720p5994  ,1280, 720,  1280, 720,  field_mode::progressive,       60000,  1001,   L"720p5994"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x720p6000  ,1280, 720,  1280, 720,  field_mode::progressive,       60,             1,              L"720p6000"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x1080p2397 ,1920, 1080, 1920, 1080, field_mode::progressive,       24000,  1001,   L"1080p2398"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x1080p2400 ,1920, 1080, 1920, 1080, field_mode::progressive,       24,             1,              L"1080p2400"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x1080i5000 ,1920, 1080, 1920, 1080, field_mode::upper,                     25,             1,              L"1080i5000"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x1080i5994 ,1920, 1080, 1920, 1080, field_mode::upper,                     30000,  1001,   L"1080i5994"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x1080i6000 ,1920, 1080, 1920, 1080, field_mode::upper,                     30,             1,              L"1080i6000"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x1080p2500 ,1920, 1080, 1920, 1080, field_mode::progressive,       25,             1,              L"1080p2500"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x1080p2997 ,1920, 1080, 1920, 1080, field_mode::progressive,       30000,  1001,   L"1080p2997"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x1080p3000 ,1920, 1080, 1920, 1080, field_mode::progressive,       30,             1,              L"1080p3000"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::x1080p5000 ,1920, 1080, 1920, 1080, field_mode::progressive,       50,             1,              L"1080p5000"),\r
-       DEFINE_VIDEOFORMATDESC(video_format::invalid    ,0,             0,   0,         0,   field_mode::progressive,   1,              1,              L"invalid")\r
+       DEFINE_VIDEOFORMATDESC(video_format::pal                ,720,  576,  1024, 576,  field_mode::upper,                     25,             1,               boost::assign::list_of(3840),                                                  L"PAL"), \r
+       DEFINE_VIDEOFORMATDESC(video_format::ntsc               ,720,  486,  720,  534,  field_mode::lower,                     30000,  1001,    boost::assign::list_of(3204)(3202)(3204)(3202)(3204),  L"NTSC"), \r
+       DEFINE_VIDEOFORMATDESC(video_format::x576p2500  ,720,  576,  720,  576,  field_mode::progressive,       25,             1,               boost::assign::list_of(3840),                                                  L"576p2500"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x720p2500  ,1280, 720,  1280, 720,  field_mode::progressive,       25,             1,               boost::assign::list_of(3840),                                                  L"720p2500"), \r
+       DEFINE_VIDEOFORMATDESC(video_format::x720p5000  ,1280, 720,  1280, 720,  field_mode::progressive,       50,             1,               boost::assign::list_of(1920),                                                  L"720p5000"), \r
+       DEFINE_VIDEOFORMATDESC(video_format::x720p5994  ,1280, 720,  1280, 720,  field_mode::progressive,       60000,  1001,    boost::assign::list_of(1602)(1601)(1602)(1601)(1602),  L"720p5994"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x720p6000  ,1280, 720,  1280, 720,  field_mode::progressive,       60,             1,               boost::assign::list_of(1600),                                                  L"720p6000"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x1080p2397 ,1920, 1080, 1920, 1080, field_mode::progressive,       24000,  1001,    boost::assign::list_of(4004),                                                  L"1080p2398"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x1080p2400 ,1920, 1080, 1920, 1080, field_mode::progressive,       24,             1,               boost::assign::list_of(4000),                                                  L"1080p2400"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x1080i5000 ,1920, 1080, 1920, 1080, field_mode::upper,                     25,             1,               boost::assign::list_of(3840),                                                  L"1080i5000"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x1080i5994 ,1920, 1080, 1920, 1080, field_mode::upper,                     30000,  1001,    boost::assign::list_of(3204)(3202)(3204)(3202)(3204),  L"1080i5994"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x1080i6000 ,1920, 1080, 1920, 1080, field_mode::upper,                     30,             1,               boost::assign::list_of(3200),                                                  L"1080i6000"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x1080p2500 ,1920, 1080, 1920, 1080, field_mode::progressive,       25,             1,               boost::assign::list_of(3840),                                                  L"1080p2500"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x1080p2997 ,1920, 1080, 1920, 1080, field_mode::progressive,       30000,  1001,    boost::assign::list_of(3204)(3202)(3204)(3202)(3204),  L"1080p2997"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x1080p3000 ,1920, 1080, 1920, 1080, field_mode::progressive,       30,             1,               boost::assign::list_of(3200),                                                  L"1080p3000"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::x1080p5000 ,1920, 1080, 1920, 1080, field_mode::progressive,       50,             1,               boost::assign::list_of(1920),                                                  L"1080p5000"),\r
+       DEFINE_VIDEOFORMATDESC(video_format::invalid    ,0,             0,   0,         0,   field_mode::progressive,   1,              1,               boost::assign::list_of(1),                                                             L"invalid")\r
 };\r
 \r
 const video_format_desc& video_format_desc::get(video_format::type format)     \r
index 58634a827ba742f361900a434051e3ab9fde9418..c809a2b65d3d2015c450d15b1f956d3604890783 100644 (file)
 \r
 #pragma once\r
 \r
+#include <vector>\r
 #include <string>\r
 \r
-#include <common/compiler/vs/disable_silly_warnings.h>\r
-\r
 namespace caspar { namespace core {\r
        \r
 struct video_format \r
@@ -95,21 +94,21 @@ struct video_format_desc
 \r
        size_t                                  audio_sample_rate;\r
        size_t                                  audio_channels;\r
-       size_t                                  audio_samples_per_frame;\r
+       std::vector<size_t>             audio_cadence;\r
 \r
        static const video_format_desc& get(video_format::type format);\r
        static const video_format_desc& get(const std::wstring& name);\r
-};\r
-\r
-inline bool operator==(const video_format_desc& rhs, const video_format_desc& lhs)\r
-{\r
-       return rhs.format == lhs.format;\r
-}\r
+       \r
+       bool operator==(const video_format_desc& lhs)\r
+       {\r
+               return format == lhs.format;\r
+       }\r
 \r
-inline bool operator!=(const video_format_desc& rhs, const video_format_desc& lhs)\r
-{\r
-       return !(rhs == lhs);\r
-}\r
+       bool operator!=(const video_format_desc& lhs)\r
+       {\r
+               return !(*this == lhs);\r
+       }\r
+};\r
 \r
 inline std::wostream& operator<<(std::wostream& out, const video_format_desc& format_desc)\r
 {\r
index d95c956bc49728bbc5b93710343d1ab3316a4886..1312a0eff5f730efd66bd158e24b2e1f7630b275 100644 (file)
@@ -24,6 +24,7 @@
 #include "../util/blue_velvet.h"\r
 #include "../util/memory.h"\r
 \r
+#include <core/video_format.h>\r
 #include <core/mixer/read_frame.h>\r
 \r
 #include <common/concurrency/executor.h>\r
@@ -39,6 +40,7 @@
 #include <tbb/concurrent_queue.h>\r
 \r
 #include <boost/timer.hpp>\r
+#include <boost/range/algorithm/rotate.hpp>\r
 \r
 #include <memory>\r
 #include <array>\r
@@ -67,6 +69,8 @@ struct bluefish_consumer : boost::noncopyable
        \r
        const bool                                                      embedded_audio_;\r
        const bool                                                      key_only_;\r
+\r
+       uint64_t                                                        frame_number_;\r
        \r
        executor                                                        executor_;\r
 public:\r
@@ -80,6 +84,7 @@ public:
                , vid_fmt_(get_video_mode(*blue_, format_desc))\r
                , embedded_audio_(embedded_audio)\r
                , key_only_(key_only)\r
+               , frame_number_(0)\r
                , executor_(print())\r
        {\r
                executor_.set_capacity(1);\r
@@ -146,9 +151,9 @@ public:
                if(blue_->GetHDCardType(device_index_) != CRD_HD_INVALID) \r
                        blue_->Set_DownConverterSignalType(vid_fmt_ == VID_FMT_PAL ? SD_SDI : HD_SDI);  \r
        \r
-               unsigned long engine_mode = VIDEO_ENGINE_FRAMESTORE;\r
-               if(BLUE_FAIL(blue_->set_video_engine(engine_mode)))\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Failed to set video engine."));\r
+               //unsigned long engine_mode = VIDEO_ENGINE_FRAMESTORE;\r
+               //if(BLUE_FAIL(blue_->set_video_engine(engine_mode)))\r
+               //      BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Failed to set video engine."));\r
 \r
                enable_video_output();\r
                                                \r
@@ -193,61 +198,10 @@ public:
                {\r
                        try\r
                        {\r
-                               frame_timer_.restart();\r
-                               \r
-                               // Copy to local buffers\r
-\r
-                               if(!frame->image_data().empty())\r
-                               {\r
-                                       if(key_only_)                                           \r
-                                               fast_memshfl(reserved_frames_.front()->image_data(), frame->image_data().begin(), frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
-                                       else\r
-                                               fast_memcpy(reserved_frames_.front()->image_data(), frame->image_data().begin(), frame->image_data().size());\r
-                               }\r
-                               else\r
-                                       fast_memclr(reserved_frames_.front()->image_data(), reserved_frames_.front()->image_size());\r
-                                                               \r
-                               // Sync\r
-\r
-                               sync_timer_.restart();\r
-                               unsigned long n_field = 0;\r
-                               blue_->wait_output_video_synch(UPD_FMT_FRAME, n_field);\r
-                               graph_->update_value("sync-time", sync_timer_.elapsed()*format_desc_.fps*0.5);\r
+                               frame_timer_.restart();                 \r
 \r
-                               // Send and display\r
+                               display_frame(frame);\r
 \r
-                               if(embedded_audio_)\r
-                               {               \r
-                                       auto frame_audio16 = core::audio_32_to_16_sse(frame->audio_data());\r
-\r
-                                       encode_hanc(reinterpret_cast<BLUE_UINT32*>(reserved_frames_.front()->hanc_data()), frame_audio16.data(), frame->audio_data().size(), format_desc_.audio_channels);\r
-                                                               \r
-                                       blue_->system_buffer_write_async(const_cast<uint8_t*>(reserved_frames_.front()->image_data()), \r
-                                                                                                       reserved_frames_.front()->image_size(), \r
-                                                                                                       nullptr, \r
-                                                                                                       BlueImage_HANC_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_IMAGE));\r
-\r
-                                       blue_->system_buffer_write_async(reserved_frames_.front()->hanc_data(),\r
-                                                                                                       reserved_frames_.front()->hanc_size(), \r
-                                                                                                       nullptr,                 \r
-                                                                                                       BlueImage_HANC_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_HANC));\r
-\r
-                                       if(BLUE_FAIL(blue_->render_buffer_update(BlueBuffer_Image_HANC(reserved_frames_.front()->id()))))\r
-                                               CASPAR_LOG(warning) << print() << TEXT(" render_buffer_update failed.");\r
-                               }\r
-                               else\r
-                               {\r
-                                       blue_->system_buffer_write_async(const_cast<uint8_t*>(reserved_frames_.front()->image_data()),\r
-                                                                                                       reserved_frames_.front()->image_size(), \r
-                                                                                                       nullptr,                 \r
-                                                                                                       BlueImage_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_IMAGE));\r
-                       \r
-                                       if(BLUE_FAIL(blue_->render_buffer_update(BlueBuffer_Image(reserved_frames_.front()->id()))))\r
-                                               CASPAR_LOG(warning) << print() << TEXT(" render_buffer_update failed.");\r
-                               }\r
-\r
-                               std::rotate(reserved_frames_.begin(), reserved_frames_.begin() + 1, reserved_frames_.end());\r
-                               \r
                                graph_->update_value("frame-time", static_cast<float>(frame_timer_.elapsed()*format_desc_.fps*0.5));\r
 \r
                                graph_->update_value("tick-time", static_cast<float>(tick_timer_.elapsed()*format_desc_.fps*0.5));\r
@@ -260,9 +214,80 @@ public:
                });\r
        }\r
 \r
+       void display_frame(const safe_ptr<core::read_frame>& frame)\r
+       {\r
+               // Copy to local buffers\r
+\r
+               if(!frame->image_data().empty())\r
+               {\r
+                       if(key_only_)                                           \r
+                               fast_memshfl(reserved_frames_.front()->image_data(), frame->image_data().begin(), frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
+                       else\r
+                               fast_memcpy(reserved_frames_.front()->image_data(), frame->image_data().begin(), frame->image_data().size());\r
+               }\r
+               else\r
+                       fast_memclr(reserved_frames_.front()->image_data(), reserved_frames_.front()->image_size());\r
+                                                               \r
+               // Sync\r
+\r
+               sync_timer_.restart();\r
+               unsigned long n_field = 0;\r
+               blue_->wait_output_video_synch(UPD_FMT_FRAME, n_field);\r
+               graph_->update_value("sync-time", sync_timer_.elapsed()*format_desc_.fps*0.5);\r
+\r
+               // Send and display\r
+\r
+               if(embedded_audio_)\r
+               {               \r
+                       auto frame_audio = core::audio_32_to_16_sse(frame->audio_data());\r
+\r
+                       if(format_desc_.format == core::video_format::ntsc)\r
+                       {\r
+                               size_t cadence[] = {1602,1601,1602,1601,1602};\r
+                               CASPAR_VERIFY(cadence[(frame_number_++) % 5] == (frame->audio_data().size()/format_desc_.audio_channels));\r
+                       }\r
+\r
+                       // 24 bit audio causes access violation in encode_hanc.\r
+                       //auto frame_audio24 = core::audio_32_to_24(frame->audio_data());\r
+\r
+                       //static_assert(sizeof(frame_audio24.front()) == 1, "");\r
+                       //static_assert(sizeof(frame->audio_data().front()) == 4, "");\r
+                       //CASPAR_VERIFY(frame_audio24.size() / 3 == static_cast<size_t>(frame->audio_data().size()));\r
+\r
+                       // audio cadence is guaranteed by input, see output.cpp and frame_producer.cpp - cadence_guard.\r
+\r
+                       encode_hanc(reinterpret_cast<BLUE_UINT32*>(reserved_frames_.front()->hanc_data()), frame_audio.data(), frame->audio_data().size(), format_desc_.audio_channels);\r
+                                                               \r
+                       blue_->system_buffer_write_async(const_cast<uint8_t*>(reserved_frames_.front()->image_data()), \r
+                                                                                       reserved_frames_.front()->image_size(), \r
+                                                                                       nullptr, \r
+                                                                                       BlueImage_HANC_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_IMAGE));\r
+\r
+                       blue_->system_buffer_write_async(reserved_frames_.front()->hanc_data(),\r
+                                                                                       reserved_frames_.front()->hanc_size(), \r
+                                                                                       nullptr,                 \r
+                                                                                       BlueImage_HANC_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_HANC));\r
+\r
+                       if(BLUE_FAIL(blue_->render_buffer_update(BlueBuffer_Image_HANC(reserved_frames_.front()->id()))))\r
+                               CASPAR_LOG(warning) << print() << TEXT(" render_buffer_update failed.");\r
+               }\r
+               else\r
+               {\r
+                       blue_->system_buffer_write_async(const_cast<uint8_t*>(reserved_frames_.front()->image_data()),\r
+                                                                                       reserved_frames_.front()->image_size(), \r
+                                                                                       nullptr,                 \r
+                                                                                       BlueImage_DMABuffer(reserved_frames_.front()->id(), BLUE_DATA_IMAGE));\r
+                       \r
+                       if(BLUE_FAIL(blue_->render_buffer_update(BlueBuffer_Image(reserved_frames_.front()->id()))))\r
+                               CASPAR_LOG(warning) << print() << TEXT(" render_buffer_update failed.");\r
+               }\r
+\r
+               std::rotate(reserved_frames_.begin(), reserved_frames_.begin() + 1, reserved_frames_.end());\r
+       }\r
+\r
        void encode_hanc(BLUE_UINT32* hanc_data, void* audio_data, size_t audio_samples, size_t audio_nchannels)\r
        {       \r
-               const auto sample_type = AUDIO_CHANNEL_16BIT | AUDIO_CHANNEL_LITTLEENDIAN;\r
+               const auto sample_type = AUDIO_CHANNEL_16BIT | AUDIO_CHANNEL_LITTLEENDIAN; // AUDIO_CHANNEL_24BIT | AUDIO_CHANNEL_LITTLEENDIAN;\r
                const auto emb_audio_flag = blue_emb_audio_enable | blue_emb_audio_group1_enable;\r
                \r
                hanc_stream_info_struct hanc_stream_info;\r
@@ -294,6 +319,7 @@ struct bluefish_consumer_proxy : public core::frame_consumer
        const size_t                                            device_index_;\r
        const bool                                                      embedded_audio_;\r
        const bool                                                      key_only_;\r
+       std::vector<size_t>                                     audio_cadence_;\r
 public:\r
 \r
        bluefish_consumer_proxy(size_t device_index, bool embedded_audio, bool key_only)\r
@@ -318,11 +344,15 @@ public:
        virtual void initialize(const core::video_format_desc& format_desc, int channel_index, int sub_index) override\r
        {\r
                consumer_.reset(new bluefish_consumer(format_desc, device_index_, embedded_audio_, key_only_, channel_index, sub_index));\r
+               audio_cadence_ = format_desc.audio_cadence;\r
                CASPAR_LOG(info) << print() << L" Successfully Initialized.";   \r
        }\r
        \r
        virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
        {\r
+               CASPAR_VERIFY(audio_cadence_.front() == static_cast<size_t>(frame->audio_data().size()));\r
+               boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
+\r
                consumer_->send(frame);\r
                return true;\r
        }\r
index 4861946b3ffffd2c025789de5e5a240c1ed8cdca..85a191d07cca3e4025d2c89d92e023783fffc7ed 100644 (file)
@@ -59,7 +59,7 @@ struct configuration
                : device_index(1)\r
                , embedded_audio(false)\r
                , internal_key(false)\r
-               , low_latency(false)\r
+               , low_latency(true)\r
                , key_only(false)\r
                , base_buffer_depth(3)\r
                , buffer_depth(base_buffer_depth + (low_latency ? 0 : 1) + (embedded_audio ? 1 : 0)){}\r
@@ -81,6 +81,11 @@ public:
        {\r
                ref_count_ = 0;\r
        }\r
+\r
+       const boost::iterator_range<const int32_t*> audio_data()\r
+       {\r
+               return frame_->audio_data();\r
+       }\r
        \r
        STDMETHOD (QueryInterface(REFIID, LPVOID*))             {return E_NOINTERFACE;}\r
        STDMETHOD_(ULONG,                       AddRef())                       \r
@@ -132,9 +137,9 @@ public:
 \r
 struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable\r
 {              \r
-       const configuration                                     config_;\r
        const int                                                       channel_index_;\r
        const int                                                       sub_index_;\r
+       const configuration                                     config_;\r
 \r
        CComPtr<IDeckLink>                                      decklink_;\r
        CComQIPtr<IDeckLinkOutput>                      output_;\r
@@ -150,7 +155,7 @@ struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLink
        const core::video_format_desc           format_desc_;\r
        const size_t                                            buffer_size_;\r
 \r
-       long long                                                       frames_scheduled_;\r
+       long long                                                       video_scheduled_;\r
        long long                                                       audio_scheduled_;\r
 \r
        size_t                                                          preroll_count_;\r
@@ -165,9 +170,9 @@ struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLink
 \r
 public:\r
        decklink_consumer(const configuration& config, const core::video_format_desc& format_desc, int channel_index, int sub_index) \r
-               : config_(config)\r
-               , channel_index_(channel_index)\r
+               : channel_index_(channel_index)\r
                , sub_index_(sub_index)\r
+               , config_(config)\r
                , decklink_(get_device(config.device_index))\r
                , output_(decklink_)\r
                , configuration_(decklink_)\r
@@ -175,7 +180,7 @@ public:
                , model_name_(get_model_name(decklink_))\r
                , format_desc_(format_desc)\r
                , buffer_size_(config.buffer_depth) // Minimum buffer-size 3.\r
-               , frames_scheduled_(0)\r
+               , video_scheduled_(0)\r
                , audio_scheduled_(0)\r
                , preroll_count_(0)\r
                , audio_container_(buffer_size_+1)\r
@@ -313,8 +318,11 @@ public:
                        if(result == bmdOutputFrameDisplayedLate)\r
                        {\r
                                graph_->add_tag("late-frame");\r
-                               ++frames_scheduled_;\r
-                               ++audio_scheduled_;\r
+                               video_scheduled_ += format_desc_.duration;\r
+                               audio_scheduled_ += reinterpret_cast<decklink_frame*>(completed_frame)->audio_data().size()/format_desc_.audio_channels;\r
+                               //++video_scheduled_;\r
+                               //audio_scheduled_ += format_desc_.audio_cadence[0];\r
+                               //++audio_scheduled_;\r
                        }\r
                        else if(result == bmdOutputFrameDropped)\r
                                graph_->add_tag("dropped-frame");\r
@@ -354,18 +362,18 @@ public:
                                        start_playback();                               \r
                                }\r
                                else\r
-                                       schedule_next_audio(make_safe<core::read_frame>());     \r
+                                       schedule_next_audio(core::audio_buffer(format_desc_.audio_cadence[preroll % format_desc_.audio_cadence.size()], 0));    \r
                        }\r
                        else\r
                        {\r
                                std::shared_ptr<core::read_frame> frame;\r
                                audio_frame_buffer_.pop(frame);\r
-                               schedule_next_audio(make_safe_ptr(frame));      \r
+                               schedule_next_audio(frame->audio_data());\r
                        }\r
 \r
                        unsigned long buffered;\r
                        output_->GetBufferedAudioSampleFrameCount(&buffered);\r
-                       graph_->update_value("buffered-audio", static_cast<double>(buffered)/(format_desc_.audio_samples_per_frame*2));\r
+                       graph_->update_value("buffered-audio", static_cast<double>(buffered)/(format_desc_.audio_cadence[0]*2));\r
                }\r
                catch(...)\r
                {\r
@@ -377,22 +385,27 @@ public:
                return S_OK;\r
        }\r
 \r
-       void schedule_next_audio(const safe_ptr<core::read_frame>& frame)\r
+       template<typename T>\r
+       void schedule_next_audio(const T& audio_data)\r
        {\r
-               const int sample_frame_count = frame->audio_data().size()/format_desc_.audio_channels;\r
+               const int sample_frame_count = audio_data.size()/format_desc_.audio_channels;\r
 \r
-               audio_container_.push_back(std::vector<int32_t>(frame->audio_data().begin(), frame->audio_data().end()));\r
+               audio_container_.push_back(std::vector<int32_t>(audio_data.begin(), audio_data.end()));\r
 \r
-               if(FAILED(output_->ScheduleAudioSamples(audio_container_.back().data(), sample_frame_count, (audio_scheduled_++) * sample_frame_count, format_desc_.audio_sample_rate, nullptr)))\r
+               if(FAILED(output_->ScheduleAudioSamples(audio_container_.back().data(), sample_frame_count, audio_scheduled_, format_desc_.audio_sample_rate, nullptr)))\r
                        CASPAR_LOG(error) << print() << L" Failed to schedule audio.";\r
+\r
+               audio_scheduled_ += sample_frame_count;\r
        }\r
                        \r
        void schedule_next_video(const safe_ptr<core::read_frame>& frame)\r
        {\r
                CComPtr<IDeckLinkVideoFrame> frame2(new decklink_frame(frame, format_desc_, config_.key_only));\r
-               if(FAILED(output_->ScheduleVideoFrame(frame2, (frames_scheduled_++) * format_desc_.duration, format_desc_.duration, format_desc_.time_scale)))\r
+               if(FAILED(output_->ScheduleVideoFrame(frame2, video_scheduled_, format_desc_.duration, format_desc_.time_scale)))\r
                        CASPAR_LOG(error) << print() << L" Failed to schedule video.";\r
 \r
+               video_scheduled_ += format_desc_.duration;\r
+\r
                graph_->update_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5);\r
                tick_timer_.restart();\r
        }\r
@@ -424,6 +437,7 @@ struct decklink_consumer_proxy : public core::frame_consumer
 {\r
        const configuration                             config_;\r
        com_context<decklink_consumer>  context_;\r
+       std::vector<size_t>                             audio_cadence_;\r
 public:\r
 \r
        decklink_consumer_proxy(const configuration& config)\r
@@ -447,12 +461,16 @@ public:
        virtual void initialize(const core::video_format_desc& format_desc, int channel_index, int sub_index) override\r
        {\r
                context_.reset([&]{return new decklink_consumer(config_, format_desc, channel_index, sub_index);});             \r
-                               \r
+               audio_cadence_ = format_desc.audio_cadence;             \r
+\r
                CASPAR_LOG(info) << print() << L" Successfully Initialized.";   \r
        }\r
        \r
        virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
        {\r
+               CASPAR_VERIFY(audio_cadence_.front() == static_cast<size_t>(frame->audio_data().size()));\r
+               boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
+\r
                context_->send(frame);\r
                return true;\r
        }\r
index 97892034c0ce2ed8a99005badbafe99eeed86174..105f8d05a172b929e4230bfc816f5404f73a04df 100644 (file)
@@ -87,6 +87,7 @@ class decklink_producer : boost::noncopyable, public IDeckLinkInputCallback
        boost::timer                                                                                            frame_timer_;\r
                \r
        safe_ptr<core::frame_factory>                                                           frame_factory_;\r
+       std::vector<size_t>                                                                                     audio_cadence_;\r
 \r
        tbb::concurrent_bounded_queue<safe_ptr<core::basic_frame>>      frame_buffer_;\r
 \r
@@ -102,6 +103,7 @@ public:
                , format_desc_(format_desc)\r
                , device_index_(device_index)\r
                , frame_factory_(frame_factory)\r
+               , audio_cadence_(frame_factory->get_video_format_desc().audio_cadence)\r
                , muxer_(format_desc.fps, frame_factory, filter)\r
        {\r
                frame_buffer_.set_capacity(2);\r
@@ -137,10 +139,7 @@ public:
                        BOOST_THROW_EXCEPTION(caspar_exception() \r
                                                                        << msg_info(narrow(print()) + " Failed to start input stream.")\r
                                                                        << boost::errinfo_api_function("StartStreams"));\r
-\r
-               if(format_desc_.duration == 1001)\r
-                       CASPAR_LOG(warning) << print() << L"Audio not supported in NTSC frame-rates.";\r
-\r
+               \r
                CASPAR_LOG(info) << print() << L" Successfully Initialized.";\r
        }\r
 \r
@@ -192,15 +191,18 @@ public:
                        muxer_.push(av_frame);          \r
                                                                        \r
                        // It is assumed that audio is always equal or ahead of video.\r
-                       if(audio && SUCCEEDED(audio->GetBytes(&bytes)) && format_desc_.duration != 1001)\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
+                       {\r
+                               muxer_.push(std::make_shared<core::audio_buffer>(audio_cadence_.front(), 0));\r
+                               std::rotate(std::begin(audio_cadence_), std::begin(audio_cadence_)+1, std::end(audio_cadence_));\r
+                       }\r
+\r
                        for(auto frame = muxer_.poll(); frame; frame = muxer_.poll())\r
                        {\r
                                if(!frame_buffer_.try_push(make_safe_ptr(frame)))\r
@@ -303,7 +305,7 @@ safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factor
        if(format_desc.format == core::video_format::invalid)\r
                format_desc = frame_factory->get_video_format_desc();\r
                        \r
-       return create_destroy_proxy(make_safe<decklink_producer_proxy>(frame_factory, format_desc, device_index, filter_str, length));\r
+       return create_producer_destroy_proxy(make_safe<decklink_producer_proxy>(frame_factory, format_desc, device_index, filter_str, length));\r
 }\r
 \r
 }}
\ No newline at end of file
index 9f953f130b7a274a8ed5e645092b1684df6b6146..e92d3a8b02d51c6ca8aed4f05213e7c8bbf3ed0d 100644 (file)
@@ -49,7 +49,7 @@ struct audio_resampler::implementation
                        buffer2_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2);\r
 \r
                        CASPAR_LOG(warning) << L"Resampling." <<\r
-                                                                       L" sample_rate:" << input_channels  <<\r
+                                                                       L" sample_rate:" << input_sample_rate  <<\r
                                                                        L" audio_channels:" << input_channels  <<\r
                                                                        L" sample_fmt:" << input_sample_format;\r
 \r
index 48e8e7f6d410a982360141f4063eec8b90d5242c..8ba264c35c56aa8219eb0b021a393fe4233763d2 100644 (file)
@@ -340,7 +340,7 @@ safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factor
        boost::replace_all(filter_str, L"DEINTERLACE", L"YADIF=0:-1");\r
        boost::replace_all(filter_str, L"DEINTERLACE_BOB", L"YADIF=1:-1");\r
        \r
-       return create_destroy_proxy(make_safe<ffmpeg_producer>(frame_factory, path, filter_str, loop, start, length));\r
+       return create_producer_destroy_proxy(make_safe<ffmpeg_producer>(frame_factory, path, filter_str, loop, start, length));\r
 }\r
 \r
 }}
\ No newline at end of file
index 3f5deef5cbe15d10fed8e4f6962ce2278acee82a..ca6f4a44a0bf4d194145aaff024df2635f2a4b74 100644 (file)
@@ -53,6 +53,8 @@ struct frame_muxer::implementation : boost::noncopyable
        const double                                                                    in_fps_;\r
        const video_format_desc                                                 format_desc_;\r
        bool                                                                                    auto_transcode_;\r
+       \r
+       std::vector<size_t>                                                             audio_cadence_;\r
 \r
        size_t                                                                                  audio_sample_count_;\r
        size_t                                                                                  video_frame_count_;\r
@@ -67,6 +69,7 @@ struct frame_muxer::implementation : boost::noncopyable
                , in_fps_(in_fps)\r
                , format_desc_(frame_factory->get_video_format_desc())\r
                , auto_transcode_(env::properties().get("configuration.auto-transcode", true))\r
+               , audio_cadence_(format_desc_.audio_cadence)\r
                , audio_sample_count_(0)\r
                , video_frame_count_(0)\r
                , frame_factory_(frame_factory)\r
@@ -74,6 +77,8 @@ struct frame_muxer::implementation : boost::noncopyable
        {\r
                video_streams_.push(std::queue<safe_ptr<write_frame>>());\r
                audio_streams_.push(core::audio_buffer());\r
+               boost::range::sort(audio_cadence_);\r
+               boost::range::reverse(audio_cadence_);\r
        }\r
 \r
        void push(const std::shared_ptr<AVFrame>& video_frame, int hints)\r
@@ -83,7 +88,6 @@ struct frame_muxer::implementation : boost::noncopyable
                \r
                if(video_frame == flush_video())\r
                {       \r
-                       CASPAR_LOG(trace) << L"video-frame-count: " << static_cast<float>(video_frame_count_);\r
                        video_frame_count_ = 0;\r
                        video_streams_.push(std::queue<safe_ptr<write_frame>>());\r
                }\r
@@ -127,13 +131,12 @@ struct frame_muxer::implementation : boost::noncopyable
 \r
                if(audio == flush_audio())\r
                {\r
-                       CASPAR_LOG(trace) << L"audio-frame-count: " << audio_sample_count_/format_desc_.audio_samples_per_frame;\r
                        audio_sample_count_ = 0;\r
                        audio_streams_.push(core::audio_buffer());\r
                }\r
                else if(audio == empty_audio())\r
                {\r
-                       boost::range::push_back(audio_streams_.back(), core::audio_buffer(format_desc_.audio_samples_per_frame, 0));\r
+                       boost::range::push_back(audio_streams_.back(), core::audio_buffer(audio_cadence_.front(), 0));\r
                        audio_sample_count_ += audio->size();\r
                }\r
                else\r
@@ -142,7 +145,7 @@ struct frame_muxer::implementation : boost::noncopyable
                        audio_sample_count_ += audio->size();\r
                }\r
 \r
-               if(audio_streams_.back().size() > 32*format_desc_.audio_samples_per_frame)\r
+               if(audio_streams_.back().size() > 32*audio_cadence_.front())\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
@@ -174,9 +177,9 @@ struct frame_muxer::implementation : boost::noncopyable
                switch(display_mode_)\r
                {\r
                case display_mode::duplicate:                                   \r
-                       return audio_streams_.front().size()/2 >= format_desc_.audio_samples_per_frame;\r
+                       return audio_streams_.front().size()/2 >= audio_cadence_.front();\r
                default:                                                                                \r
-                       return audio_streams_.front().size() >= format_desc_.audio_samples_per_frame;\r
+                       return audio_streams_.front().size() >= audio_cadence_.front();\r
                }\r
        }\r
                \r
@@ -253,13 +256,15 @@ struct frame_muxer::implementation : boost::noncopyable
 \r
        core::audio_buffer pop_audio()\r
        {\r
-               CASPAR_VERIFY(audio_streams_.front().size() >= format_desc_.audio_samples_per_frame);\r
+               CASPAR_VERIFY(audio_streams_.front().size() >= audio_cadence_.front());\r
 \r
                auto begin = audio_streams_.front().begin();\r
-               auto end   = begin + format_desc_.audio_samples_per_frame;\r
+               auto end   = begin + audio_cadence_.front();\r
 \r
-               auto samples = core::audio_buffer(begin, end);\r
+               core::audio_buffer samples(begin, end);\r
                audio_streams_.front().erase(begin, end);\r
+               \r
+               boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
 \r
                return samples;\r
        }\r
index 8078464a893b13a88c9325bdf15fc15e817dd325..da8a34d26e89691d5d43b2aafc85f3c2cef7fadd 100644 (file)
@@ -443,7 +443,7 @@ safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factor
 {\r
        auto template_host = get_template_host(frame_factory->get_video_format_desc());\r
        \r
-       return create_destroy_proxy(make_safe<flash_producer>(frame_factory, env::template_folder() + L"\\" + widen(template_host.filename), template_host.width, template_host.height));\r
+       return create_producer_destroy_proxy(make_safe<flash_producer>(frame_factory, env::template_folder() + L"\\" + widen(template_host.filename), template_host.width, template_host.height));\r
 }\r
 \r
 std::wstring find_template(const std::wstring& template_name)\r
index 85f365fe0d74f80aebb0e6729cd026199969cc32..86e954cfdcc1b6f444c3cc4e138f8d593b030517 100644 (file)
@@ -41,6 +41,8 @@
 \r
 namespace caspar { namespace oal {\r
 \r
+typedef std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>> audio_buffer_16;\r
+\r
 struct oal_consumer : public core::frame_consumer,  public sf::SoundStream\r
 {\r
        safe_ptr<diagnostics::graph>                                            graph_;\r
@@ -48,9 +50,10 @@ struct oal_consumer : public core::frame_consumer,  public sf::SoundStream
        int                                                                                                     channel_index_;\r
        int                                                                                                     sub_index_;\r
 \r
-       tbb::concurrent_bounded_queue<std::shared_ptr<std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>>>     input_;\r
-       boost::circular_buffer<std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>>                     container_;\r
+       tbb::concurrent_bounded_queue<std::shared_ptr<audio_buffer_16>> input_;\r
+       boost::circular_buffer<audio_buffer_16>                 container_;\r
        tbb::atomic<bool>                                                                       is_running_;\r
+       core::audio_buffer                                                                      temp;\r
 \r
        core::video_format_desc                                                         format_desc_;\r
 public:\r
@@ -71,11 +74,11 @@ public:
        ~oal_consumer()\r
        {\r
                is_running_ = false;\r
-               input_.try_push(std::make_shared<std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>>());\r
-               input_.try_push(std::make_shared<std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>>());\r
+               input_.try_push(std::make_shared<audio_buffer_16>());\r
+               input_.try_push(std::make_shared<audio_buffer_16>());\r
                Stop();\r
-               input_.try_push(std::make_shared<std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>>());\r
-               input_.try_push(std::make_shared<std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>>());\r
+               input_.try_push(std::make_shared<audio_buffer_16>());\r
+               input_.try_push(std::make_shared<audio_buffer_16>());\r
 \r
                CASPAR_LOG(info) << print() << L" Successfully Uninitialized."; \r
        }\r
@@ -97,8 +100,7 @@ public:
        \r
        virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
        {                       \r
-               input_.push(std::make_shared<std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>>(core::audio_32_to_16_sse(frame->audio_data())));\r
-\r
+               input_.push(std::make_shared<audio_buffer_16>(core::audio_32_to_16_sse(frame->audio_data())));\r
                return true;\r
        }\r
        \r
@@ -116,7 +118,7 @@ public:
        \r
        virtual bool OnGetData(sf::SoundStream::Chunk& data) override\r
        {               \r
-               std::shared_ptr<std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>>> audio_data;                \r
+               std::shared_ptr<audio_buffer_16> audio_data;            \r
                input_.pop(audio_data);\r
                                \r
                container_.push_back(std::move(*audio_data));\r