#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
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
*/\r
#pragma once\r
\r
-#include "../video_format.h"\r
-\r
#include <common/memory/safe_ptr.h>\r
\r
#include <boost/noncopyable.hpp>\r
}\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
#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
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
#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
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
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
\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
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
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
#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
\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
\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
#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
#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
\r
const bool embedded_audio_;\r
const bool key_only_;\r
+\r
+ uint64_t frame_number_;\r
\r
executor executor_;\r
public:\r
, 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
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
{\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
});\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
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
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
: 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
{\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
\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
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
\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
, 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
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
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
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
{\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
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
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
, 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
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
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
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
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
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
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
, 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
{\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
\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
\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
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
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
\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
{\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
\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
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
~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
\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
\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