- Extracted duplicated code to reusable function.
{\r
}\r
\r
- virtual void initialize(const video_format_desc& format_desc, int channel_index) override\r
+ virtual void initialize(\r
+ const video_format_desc& format_desc,\r
+ const channel_layout& audio_channel_layout,\r
+ int channel_index) override\r
{\r
audio_cadence_ = format_desc.audio_cadence;\r
sync_buffer_ = boost::circular_buffer<size_t>(format_desc.audio_cadence.size());\r
format_desc_ = format_desc;\r
- consumer_->initialize(format_desc, channel_index);\r
+ consumer_->initialize(format_desc, audio_channel_layout, channel_index);\r
}\r
\r
virtual int64_t presentation_frame_age_millis() const\r
struct empty_frame_consumer : public frame_consumer\r
{\r
virtual boost::unique_future<bool> send(const safe_ptr<read_frame>&) override { return caspar::wrap_as_future(false); }\r
- virtual void initialize(const video_format_desc&, int) override{}\r
+ virtual void initialize(const video_format_desc&, const channel_layout&, int) override{}\r
virtual int64_t presentation_frame_age_millis() const { return 0; }\r
virtual std::wstring print() const override {return L"empty";}\r
virtual bool has_synchronization_clock() const override {return false;}\r
class read_frame;\r
class parameters;\r
struct video_format_desc;\r
+struct channel_layout;\r
\r
struct frame_consumer : boost::noncopyable\r
{\r
virtual ~frame_consumer() {}\r
\r
virtual boost::unique_future<bool> send(const safe_ptr<read_frame>& frame) = 0;\r
- virtual void initialize(const video_format_desc& format_desc, int channel_index) = 0;\r
+ virtual void initialize(const video_format_desc& format_desc, const channel_layout& audio_channel_layout, int channel_index) = 0;\r
virtual int64_t presentation_frame_age_millis() const = 0;\r
virtual std::wstring print() const = 0;\r
virtual boost::property_tree::wptree info() const = 0;\r
boost::timer consume_timer_;\r
\r
video_format_desc format_desc_;\r
+ channel_layout audio_channel_layout_;\r
\r
std::map<int, safe_ptr<frame_consumer>> consumers_;\r
\r
executor executor_;\r
\r
public:\r
- implementation(const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc, int channel_index) \r
+ implementation(\r
+ const safe_ptr<diagnostics::graph>& graph,\r
+ const video_format_desc& format_desc,\r
+ const channel_layout& audio_channel_layout,\r
+ int channel_index) \r
: channel_index_(channel_index)\r
, graph_(graph)\r
, monitor_subject_("/output")\r
, format_desc_(format_desc)\r
+ , audio_channel_layout_(audio_channel_layout)\r
, executor_(L"output")\r
{\r
graph_->set_color("consume-time", diagnostics::color(1.0f, 0.4f, 0.0f, 0.8));\r
remove(index);\r
\r
consumer = create_consumer_cadence_guard(consumer);\r
- consumer->initialize(format_desc_, channel_index_);\r
+ consumer->initialize(format_desc_, audio_channel_layout_, channel_index_);\r
\r
executor_.invoke([&]\r
{\r
{ \r
try\r
{\r
- it->second->initialize(format_desc, channel_index_);\r
+ it->second->initialize(format_desc, audio_channel_layout_, channel_index_);\r
++it;\r
}\r
catch(...)\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
try\r
{\r
- consumer->initialize(format_desc_, channel_index_);\r
+ consumer->initialize(format_desc_, audio_channel_layout_, channel_index_);\r
if(!consumer->send(frame).get())\r
{\r
CASPAR_LOG(info) << print() << L" " << consumer->print() << L" Removed.";\r
}\r
};\r
\r
-output::output(const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc, int channel_index) : impl_(new implementation(graph, format_desc, channel_index)){}\r
+output::output(const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc, const channel_layout& audio_channel_layout, int channel_index) : impl_(new implementation(graph, format_desc, audio_channel_layout, channel_index)){}\r
void output::add(int index, const safe_ptr<frame_consumer>& consumer){impl_->add(index, consumer);}\r
void output::add(const safe_ptr<frame_consumer>& consumer){impl_->add(consumer);}\r
void output::remove(int index){impl_->remove(index);}\r
, boost::noncopyable\r
{\r
public:\r
- explicit output(const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc, int channel_index);\r
+ explicit output(const safe_ptr<diagnostics::graph>& graph, const video_format_desc& format_desc, const channel_layout& audio_channel_layout, int channel_index);\r
\r
// target\r
\r
}\r
}\r
\r
+template<typename SrcView>\r
+std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>> get_rearranged_and_mixed(\r
+ const SrcView& view,\r
+ const channel_layout& destination_layout,\r
+ int num_out_channels)\r
+{\r
+ const int sample_frame_count = view.num_samples();\r
+\r
+ if (needs_rearranging(view, destination_layout, num_out_channels))\r
+ {\r
+ std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>> resulting_audio_data;\r
+ resulting_audio_data.resize(sample_frame_count * num_out_channels);\r
+\r
+ auto dest_view = make_multichannel_view<int32_t>(\r
+ resulting_audio_data.begin(), \r
+ resulting_audio_data.end(),\r
+ destination_layout,\r
+ num_out_channels);\r
+\r
+ rearrange_or_rearrange_and_mix(\r
+ view, dest_view, default_mix_config_repository());\r
+\r
+ if (destination_layout.num_channels == 1 && num_out_channels >= 2)\r
+ {\r
+ // mono: duplicate L to R\r
+ boost::copy( \r
+ dest_view.channel(0),\r
+ dest_view.channel(1).begin());\r
+ }\r
+\r
+ return std::move(resulting_audio_data);\r
+ }\r
+ else\r
+ {\r
+ return std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>>(view.raw_begin(), view.raw_end());\r
+ }\r
+}\r
+\r
channel_layout create_custom_channel_layout(\r
const std::wstring& custom_channel_order,\r
const channel_layout_repository& repository);\r
return caspar::wrap_as_future(is_running_.load());\r
}\r
\r
- virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
+ virtual void initialize(\r
+ const video_format_desc& format_desc,\r
+ const channel_layout& audio_channel_layout,\r
+ int channel_index) override\r
{\r
format_desc_ = format_desc;\r
channel_index_ = channel_index;\r
, index_(index)\r
, format_desc_(format_desc)\r
, ogl_(ogl)\r
- , output_(new caspar::core::output(graph_, format_desc, index))\r
+ , output_(new caspar::core::output(graph_, format_desc, audio_channel_layout, index))\r
, mixer_(new caspar::core::mixer(graph_, output_, format_desc, ogl, audio_channel_layout))\r
, stage_(new caspar::core::stage(graph_, mixer_, format_desc)) \r
, monitor_subject_(make_safe<monitor::subject>("/channel/" + boost::lexical_cast<std::string>(index)))\r
if(embedded_audio_)\r
{\r
auto src_view = frame->multichannel_view();\r
+ auto frame_audio = core::audio_32_to_24(\r
+ core::get_rearranged_and_mixed(\r
+ src_view,\r
+ channel_layout_,\r
+ channel_layout_.num_channels));\r
+ encode_hanc(\r
+ reinterpret_cast<BLUE_UINT32*>(reserved_frames_.front()->hanc_data()),\r
+ frame_audio.data(),\r
+ src_view.num_samples(),\r
+ channel_layout_.num_channels);\r
\r
- if (core::needs_rearranging(src_view, channel_layout_, channel_layout_.num_channels))\r
- {\r
- std::vector<int32_t> resulting_audio_data;\r
- resulting_audio_data.resize(src_view.num_samples() * channel_layout_.num_channels, 0);\r
-\r
- auto dest_view = core::make_multichannel_view<int32_t>(\r
- resulting_audio_data.begin(), \r
- resulting_audio_data.end(),\r
- channel_layout_);\r
-\r
- core::rearrange_or_rearrange_and_mix(\r
- src_view,\r
- dest_view,\r
- core::default_mix_config_repository());\r
-\r
- auto frame_audio = core::audio_32_to_24(resulting_audio_data);\r
- encode_hanc(\r
- reinterpret_cast<BLUE_UINT32*>(reserved_frames_.front()->hanc_data()),\r
- frame_audio.data(),\r
- src_view.num_samples(),\r
- channel_layout_.num_channels);\r
- }\r
- else\r
- {\r
- auto frame_audio = core::audio_32_to_24(frame->audio_data());\r
- encode_hanc(\r
- reinterpret_cast<BLUE_UINT32*>(reserved_frames_.front()->hanc_data()),\r
- frame_audio.data(),\r
- src_view.num_samples(),\r
- channel_layout_.num_channels);\r
- }\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
\r
// frame_consumer\r
\r
- virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
+ virtual void initialize(\r
+ const core::video_format_desc& format_desc,\r
+ const core::channel_layout& audio_channel_layout,\r
+ int channel_index) override\r
{\r
consumer_.reset(new bluefish_consumer(\r
format_desc,\r
namespace caspar { namespace decklink {
// second is the index in the array to consume the next time
-typedef std::pair<std::vector<int32_t>, size_t> audio_buffer;
+typedef std::pair<
+ std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>>,
+ size_t> audio_buffer;
struct blocking_decklink_consumer : boost::noncopyable
{
buffered_audio_samples_ = 0;
}
- if (core::needs_rearranging(
- view, config_.audio_layout, config_.num_out_channels()))
- {
- std::vector<int32_t> resulting_audio_data;
- resulting_audio_data.resize(
- sample_frame_count * config_.num_out_channels());
-
- auto dest_view = core::make_multichannel_view<int32_t>(
- resulting_audio_data.begin(),
- resulting_audio_data.end(),
- config_.audio_layout,
- config_.num_out_channels());
-
- core::rearrange_or_rearrange_and_mix(
- view, dest_view, core::default_mix_config_repository());
-
- if (config_.audio_layout.num_channels == 1) // mono
- boost::copy( // duplicate L to R
- dest_view.channel(0),
- dest_view.channel(1).begin());
-
- audio_samples_.push_back(
- std::make_pair(std::move(resulting_audio_data), 0));
- }
- else
- {
- audio_samples_.push_back(std::make_pair(
- std::vector<int32_t>(
- frame->audio_data().begin(),
- frame->audio_data().end()),
- 0));
- }
+ audio_samples_.push_back(
+ std::make_pair(
+ core::get_rearranged_and_mixed(
+ view,
+ config_.audio_layout,
+ config_.num_out_channels()),
+ 0));
buffered_audio_samples_ += sample_frame_count;
graph_->set_value("buffered-audio",
/ format_desc_.audio_cadence[0] * 0.5);
}
- bool try_consume_audio(std::pair<std::vector<int32_t>, size_t>& buffer)
+ template<typename Buffer>
+ bool try_consume_audio(Buffer& buffer)
{
size_t to_offer = (buffer.first.size() - buffer.second)
/ config_.num_out_channels();
{
while (!audio_samples_.empty())
{
- auto buffer = audio_samples_.front();
+ auto& buffer = audio_samples_.front();
if (try_consume_audio(buffer))
audio_samples_.pop_front();
// frame_consumer
- virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override
+ virtual void initialize(
+ const core::video_format_desc& format_desc,
+ const core::channel_layout& audio_channel_layout,
+ int channel_index) override
{
context_.reset([&]{return new blocking_decklink_consumer(config_, format_desc, channel_index);});
audio_cadence_ = format_desc.audio_cadence;
\r
size_t preroll_count_;\r
\r
- boost::circular_buffer<std::vector<int32_t>> audio_container_;\r
+ boost::circular_buffer<std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>>> audio_container_;\r
\r
tbb::concurrent_bounded_queue<std::shared_ptr<core::read_frame>> video_frame_buffer_;\r
tbb::concurrent_bounded_queue<std::shared_ptr<core::read_frame>> audio_frame_buffer_;\r
{\r
const int sample_frame_count = view.num_samples();\r
\r
- if (core::needs_rearranging(\r
- view, config_.audio_layout, config_.num_out_channels()))\r
- {\r
- std::vector<int32_t> resulting_audio_data;\r
- resulting_audio_data.resize(\r
- sample_frame_count * config_.num_out_channels());\r
-\r
- auto dest_view = core::make_multichannel_view<int32_t>(\r
- resulting_audio_data.begin(), \r
- resulting_audio_data.end(),\r
- config_.audio_layout,\r
- config_.num_out_channels());\r
-\r
- core::rearrange_or_rearrange_and_mix(\r
- view, dest_view, core::default_mix_config_repository());\r
-\r
- if (config_.audio_layout.num_channels == 1) // mono\r
- boost::copy( // duplicate L to R\r
- dest_view.channel(0),\r
- dest_view.channel(1).begin());\r
-\r
- audio_container_.push_back(std::move(resulting_audio_data));\r
- }\r
- else\r
- {\r
- audio_container_.push_back(\r
- std::vector<int32_t>(view.raw_begin(), view.raw_end()));\r
- }\r
+ audio_container_.push_back(core::get_rearranged_and_mixed(\r
+ view,\r
+ config_.audio_layout,\r
+ config_.num_out_channels()));\r
\r
if(FAILED(output_->ScheduleAudioSamples(\r
audio_container_.back().data(),\r
\r
// frame_consumer\r
\r
- virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
+ virtual void initialize(\r
+ const core::video_format_desc& format_desc,\r
+ const core::channel_layout& audio_channel_layout,\r
+ int channel_index) override\r
{\r
context_.reset([&]{return new decklink_consumer(config_, format_desc, channel_index);}); \r
audio_cadence_ = format_desc.audio_cadence; \r
const std::wstring filename_;\r
const std::vector<option> options_;\r
const bool separate_key_;\r
- core::video_format_desc format_desc_;\r
\r
std::unique_ptr<ffmpeg_consumer> consumer_;\r
std::unique_ptr<ffmpeg_consumer> key_only_consumer_;\r
{\r
}\r
\r
- virtual void initialize(const core::video_format_desc& format_desc, int)\r
+ virtual void initialize(\r
+ const core::video_format_desc& format_desc,\r
+ const core::channel_layout& audio_channel_layout,\r
+ int)\r
{\r
- format_desc_ = format_desc;\r
+ consumer_.reset();\r
+ key_only_consumer_.reset();\r
+ consumer_.reset(new ffmpeg_consumer(\r
+ narrow(filename_),\r
+ format_desc,\r
+ options_,\r
+ false,\r
+ audio_channel_layout));\r
+\r
+ if (separate_key_)\r
+ {\r
+ boost::filesystem::wpath fill_file(filename_);\r
+ auto without_extension = fill_file.stem();\r
+ auto key_file = env::media_folder() + without_extension + L"_A" + fill_file.extension();\r
+ \r
+ key_only_consumer_.reset(new ffmpeg_consumer(\r
+ narrow(key_file),\r
+ format_desc,\r
+ options_,\r
+ true,\r
+ audio_channel_layout));\r
+ }\r
}\r
\r
virtual int64_t presentation_frame_age_millis() const override\r
\r
virtual boost::unique_future<bool> send(const safe_ptr<core::read_frame>& frame) override\r
{\r
- if (!consumer_)\r
- do_initialize(frame->multichannel_view().channel_layout());\r
-\r
bool ready_for_frame = consumer_->ready_for_frame();\r
\r
if (ready_for_frame && separate_key_)\r
private:\r
void do_initialize(const core::channel_layout& channel_layout)\r
{\r
- consumer_.reset();\r
- key_only_consumer_.reset();\r
- consumer_.reset(new ffmpeg_consumer(\r
- narrow(filename_),\r
- format_desc_,\r
- options_,\r
- false,\r
- channel_layout));\r
-\r
- if (separate_key_)\r
- {\r
- boost::filesystem::wpath fill_file(filename_);\r
- auto without_extension = fill_file.stem();\r
- auto key_file = env::media_folder() + without_extension + L"_A" + fill_file.extension();\r
- \r
- key_only_consumer_.reset(new ffmpeg_consumer(\r
- narrow(key_file),\r
- format_desc_,\r
- options_,\r
- true,\r
- channel_layout));\r
- }\r
}\r
}; \r
\r
if(boost::to_upper_copy(filters).find(L"YADIF=3") != std::string::npos)\r
return true;\r
\r
+ if(boost::to_upper_copy(filters).find(L"SEPARATEFIELDS") != std::string::npos)\r
+ return true;\r
+\r
return false;\r
}\r
\r
{\r
}\r
\r
- virtual void initialize(const core::video_format_desc& format_desc, int) override\r
+ virtual void initialize(const core::video_format_desc& format_desc, const core::channel_layout&, int) override\r
{\r
format_desc_ = format_desc;\r
}\r
// frame_consumer
- virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override
+ virtual void initialize(
+ const core::video_format_desc& format_desc,
+ const core::channel_layout& audio_channel_layout,
+ int channel_index) override
{
air_send_.reset(
airsend::create(
// AUDIO
- std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>> audio_buffer;
-
- if (core::needs_rearranging(
- frame->multichannel_view(),
- channel_layout_,
- channel_layout_.num_channels))
- {
- core::audio_buffer downmixed;
-
- downmixed.resize(
- frame->multichannel_view().num_samples()
- * channel_layout_.num_channels,
- 0);
-
- auto dest_view = core::make_multichannel_view<int32_t>(
- downmixed.begin(), downmixed.end(), channel_layout_);
-
- core::rearrange_or_rearrange_and_mix(
- frame->multichannel_view(),
- dest_view,
- core::default_mix_config_repository());
-
- audio_buffer = core::audio_32_to_16(downmixed);
- }
- else
- {
- audio_buffer = core::audio_32_to_16(frame->audio_data());
- }
+ auto audio_buffer = core::audio_32_to_16(
+ core::get_rearranged_and_mixed(
+ frame->multichannel_view(),
+ channel_layout_,
+ channel_layout_.num_channels));
airsend::add_audio(air_send_.get(), audio_buffer.data(), audio_buffer.size() / channel_layout_.num_channels);
// frame consumer
- virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override
+ virtual void initialize(
+ const core::video_format_desc& format_desc,
+ const core::channel_layout& audio_channel_layout,
+ int channel_index) override
{
format_desc_ = format_desc;
channel_index_ = channel_index;
virtual boost::unique_future<bool> send(const safe_ptr<core::read_frame>& frame) override
{
- std::shared_ptr<audio_buffer_16> buffer;
-
- if (core::needs_rearranging(
- frame->multichannel_view(),
- channel_layout_,
- channel_layout_.num_channels))
- {
- core::audio_buffer downmixed;
- downmixed.resize(
- frame->multichannel_view().num_samples()
- * channel_layout_.num_channels,
- 0);
-
- auto dest_view = core::make_multichannel_view<int32_t>(
- downmixed.begin(), downmixed.end(), channel_layout_);
-
- core::rearrange_or_rearrange_and_mix(
- frame->multichannel_view(),
- dest_view,
- core::default_mix_config_repository());
-
- buffer = std::make_shared<audio_buffer_16>(
- core::audio_32_to_16(downmixed));
- }
- else
- {
- buffer = std::make_shared<audio_buffer_16>(
- core::audio_32_to_16(frame->audio_data()));
- }
+ auto buffer = std::make_shared<audio_buffer_16>(
+ core::audio_32_to_16(core::get_rearranged_and_mixed(frame->multichannel_view(), channel_layout_, channel_layout_.num_channels)));
if (!input_.try_push(std::make_pair(frame, buffer)))
graph_->set_tag("dropped-frame");
\r
// frame_consumer\r
\r
- virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
+ virtual void initialize(\r
+ const core::video_format_desc& format_desc,\r
+ const core::channel_layout& audio_channel_layout,\r
+ int channel_index) override\r
{\r
consumer_.reset();\r
consumer_.reset(new ogl_consumer(config_, format_desc, channel_index));\r