transform_stack_.pop();\r
}\r
\r
- std::vector<int32_t> mix()\r
+ audio_buffer mix()\r
{\r
- auto result = std::vector<int32_t>(format_desc_.audio_samples_per_frame, 0);\r
+ auto result = audio_buffer(format_desc_.audio_samples_per_frame, 0);\r
\r
std::map<const void*, core::frame_transform> next_frame_transforms;\r
\r
\r
if(next.volume < 0.001 && prev.volume < 0.001)\r
continue;\r
- \r
- static const int BASE = 1<<31;\r
-\r
- const auto next_volume = static_cast<int64_t>(next.volume*BASE);\r
- const auto prev_volume = static_cast<int64_t>(prev.volume*BASE);\r
- \r
- const int n_samples = result.size();\r
- \r
- const auto in_size = static_cast<size_t>(item.audio_data.size());\r
- CASPAR_VERIFY(in_size == 0 || in_size == result.size());\r
-\r
- if(in_size > result.size())\r
+ \r
+ if(static_cast<size_t>(item.audio_data.size()) != format_desc_.audio_samples_per_frame)\r
continue;\r
\r
+ CASPAR_ASSERT(format_desc_.audio_channels == 2);\r
+ \r
+ const float prev_volume = static_cast<float>(prev.volume);\r
+ const float next_volume = static_cast<float>(next.volume);\r
+ const float delta = 1.0f/static_cast<float>(format_desc_.audio_samples_per_frame/2);\r
+ \r
tbb::parallel_for\r
(\r
- tbb::blocked_range<size_t>(0, item.audio_data.size()),\r
+ tbb::blocked_range<size_t>(0, format_desc_.audio_samples_per_frame/2),\r
[&](const tbb::blocked_range<size_t>& r)\r
{\r
for(size_t n = r.begin(); n < r.end(); ++n)\r
{\r
- const auto sample_volume = (prev_volume - (prev_volume * n)/n_samples) + (next_volume * n)/n_samples;\r
- const auto sample = static_cast<int32_t>((static_cast<int64_t>(item.audio_data[n])*sample_volume)/BASE);\r
- result[n] = result[n] + sample;\r
+ const float alpha = n * delta;\r
+ const float volume = prev_volume * (1.0f - alpha) + next_volume * alpha;\r
+\r
+ auto sample_epi32 = _mm_loadl_epi64(reinterpret_cast<__m128i*>(&item.audio_data[n*2]));\r
+\r
+ auto sample_ps = _mm_cvtepi32_ps(sample_epi32); \r
+ sample_ps = _mm_mul_ps(sample_ps, _mm_set1_ps(volume)); \r
+\r
+ auto res_sample_epi32 = _mm_loadl_epi64(reinterpret_cast<__m128i*>(&result[n*2]));\r
+ auto res_sample_ps = _mm_cvtepi32_ps(res_sample_epi32); \r
+\r
+ res_sample_ps = _mm_add_ps(sample_ps, res_sample_ps);\r
+ res_sample_epi32 = _mm_cvtps_epi32(res_sample_ps);\r
+ \r
+ _mm_storel_epi64(reinterpret_cast<__m128i*>(&result[n*2]), res_sample_epi32);\r
}\r
}\r
);\r
items.clear();\r
prev_frame_transforms_ = std::move(next_frame_transforms); \r
\r
+ result.resize(format_desc_.audio_samples_per_frame);\r
return std::move(result);\r
}\r
};\r
void audio_mixer::begin(core::basic_frame& frame){impl_->begin(frame);}\r
void audio_mixer::visit(core::write_frame& frame){impl_->visit(frame);}\r
void audio_mixer::end(){impl_->end();}\r
-std::vector<int32_t> audio_mixer::mix(){return impl_->mix();}\r
+audio_buffer audio_mixer::mix(){return impl_->mix();}\r
audio_mixer& audio_mixer::operator=(audio_mixer&& other)\r
{\r
impl_ = std::move(other.impl_);\r
\r
#include <boost/noncopyable.hpp>\r
\r
+#include <tbb/cache_aligned_allocator.h>\r
+\r
#include <vector>\r
\r
namespace caspar { namespace core {\r
\r
struct video_format_desc;\r
\r
+typedef std::vector<int32_t, tbb::cache_aligned_allocator<int32_t>> audio_buffer;\r
+\r
class audio_mixer : public core::frame_visitor, boost::noncopyable\r
{\r
public:\r
virtual void visit(core::write_frame& frame);\r
virtual void end();\r
\r
- std::vector<int32_t> mix();\r
+ audio_buffer mix();\r
\r
audio_mixer& operator=(audio_mixer&& other);\r
private:\r
std::unordered_map<int, tweened_transform<core::frame_transform>> transforms_; \r
std::unordered_map<int, blend_mode::type> blend_modes_;\r
\r
- std::queue<std::pair<boost::unique_future<safe_ptr<host_buffer>>, std::vector<int32_t>>> buffer_;\r
+ std::queue<std::pair<boost::unique_future<safe_ptr<host_buffer>>, core::audio_buffer>> buffer_;\r
\r
const size_t buffer_size_;\r
\r
size_t size_;\r
safe_ptr<host_buffer> image_data_;\r
tbb::mutex mutex_;\r
- std::vector<int32_t> audio_data_;\r
+ audio_buffer audio_data_;\r
\r
public:\r
- implementation(ogl_device& ogl, size_t size, safe_ptr<host_buffer>&& image_data, std::vector<int32_t>&& audio_data) \r
+ implementation(ogl_device& ogl, size_t size, safe_ptr<host_buffer>&& image_data, audio_buffer&& audio_data) \r
: ogl_(ogl)\r
, size_(size)\r
, image_data_(std::move(image_data))\r
}\r
};\r
\r
-read_frame::read_frame(ogl_device& ogl, size_t size, safe_ptr<host_buffer>&& image_data, std::vector<int32_t>&& audio_data) \r
+read_frame::read_frame(ogl_device& ogl, size_t size, safe_ptr<host_buffer>&& image_data, audio_buffer&& audio_data) \r
: impl_(new implementation(ogl, size, std::move(image_data), std::move(audio_data))){}\r
read_frame::read_frame(){}\r
const boost::iterator_range<const uint8_t*> read_frame::image_data()\r
\r
#include <common/memory/safe_ptr.h>\r
\r
+#include <core/mixer/audio/audio_mixer.h>\r
+\r
#include <boost/noncopyable.hpp>\r
#include <boost/range/iterator_range.hpp>\r
\r
{\r
public:\r
read_frame();\r
- read_frame(ogl_device& ogl, size_t size, safe_ptr<host_buffer>&& image_data, std::vector<int32_t>&& audio_data);\r
+ read_frame(ogl_device& ogl, size_t size, safe_ptr<host_buffer>&& image_data, audio_buffer&& audio_data);\r
\r
virtual const boost::iterator_range<const uint8_t*> image_data();\r
virtual const boost::iterator_range<const int32_t*> audio_data();\r
ogl_device* ogl_;\r
std::vector<std::shared_ptr<host_buffer>> buffers_;\r
std::vector<safe_ptr<device_buffer>> textures_;\r
- std::vector<int32_t> audio_data_;\r
+ audio_buffer audio_data_;\r
const core::pixel_format_desc desc_;\r
const void* tag_;\r
core::field_mode::type mode_;\r
void write_frame::swap(write_frame& other){impl_.swap(other.impl_);}\r
\r
boost::iterator_range<uint8_t*> write_frame::image_data(size_t index){return impl_->image_data(index);}\r
-std::vector<int32_t>& write_frame::audio_data() { return impl_->audio_data_; }\r
+audio_buffer& write_frame::audio_data() { return impl_->audio_data_; }\r
const boost::iterator_range<const uint8_t*> write_frame::image_data(size_t index) const\r
{\r
return boost::iterator_range<const uint8_t*>(impl_->image_data(index).begin(), impl_->image_data(index).end());\r
\r
#include <core/producer/frame/basic_frame.h>\r
#include <core/video_format.h>\r
+#include <core/mixer/audio/audio_mixer.h>\r
\r
#include <boost/noncopyable.hpp>\r
#include <boost/range/iterator_range.hpp>\r
boost::iterator_range<uint8_t*> image_data(size_t plane_index = 0); \r
const boost::iterator_range<const uint8_t*> image_data(size_t plane_index = 0) const;\r
\r
- std::vector<int32_t>& audio_data();\r
+ audio_buffer& audio_data();\r
const boost::iterator_range<const int32_t*> audio_data() const;\r
\r
void commit(uint32_t plane_index);\r
<< msg_info(narrow(print()) + " Could not enable video input.")\r
<< boost::errinfo_api_function("EnableVideoInput"));\r
\r
- if(FAILED(input_->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2))) \r
+ if(FAILED(input_->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType32bitInteger, 2))) \r
BOOST_THROW_EXCEPTION(caspar_exception() \r
<< msg_info(narrow(print()) + " Could not enable audio input.")\r
<< boost::errinfo_api_function("EnableAudioInput"));\r
if(audio && SUCCEEDED(audio->GetBytes(&bytes)))\r
{\r
auto sample_frame_count = audio->GetSampleFrameCount();\r
- auto audio_data = reinterpret_cast<short*>(bytes);\r
- muxer_.push(std::make_shared<std::vector<int32_t>>(audio_data, audio_data + sample_frame_count*2));\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*sizeof(int32_t)));\r
}\r
else\r
- muxer_.push(std::make_shared<std::vector<int32_t>>(frame_factory_->get_video_format_desc().audio_samples_per_frame, 0));\r
+ muxer_.push(std::make_shared<core::audio_buffer>(frame_factory_->get_video_format_desc().audio_samples_per_frame, 0));\r
\r
muxer_.commit();\r
\r
packets_.push(packet);\r
} \r
\r
- std::vector<std::shared_ptr<std::vector<int32_t>>> poll()\r
+ std::vector<std::shared_ptr<core::audio_buffer>> poll()\r
{\r
- std::vector<std::shared_ptr<std::vector<int32_t>>> result;\r
+ std::vector<std::shared_ptr<core::audio_buffer>> result;\r
\r
if(packets_.empty())\r
return result;\r
return result;\r
}\r
\r
- std::vector<std::shared_ptr<std::vector<int32_t>>> empty_poll()\r
+ std::vector<std::shared_ptr<core::audio_buffer>> empty_poll()\r
{\r
auto packet = packets_.front();\r
packets_.pop();\r
if(!packet) \r
return boost::assign::list_of(nullptr);\r
\r
- return boost::assign::list_of(std::make_shared<std::vector<int32_t>>(format_desc_.audio_samples_per_frame, 0)); \r
+ return boost::assign::list_of(std::make_shared<core::audio_buffer>(format_desc_.audio_samples_per_frame, 0)); \r
}\r
\r
- std::shared_ptr<std::vector<int32_t>> decode(AVPacket& pkt)\r
+ std::shared_ptr<core::audio_buffer> decode(AVPacket& pkt)\r
{ \r
buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2);\r
int written_bytes = buffer1_.size() - FF_INPUT_BUFFER_PADDING_SIZE;\r
const auto n_samples = buffer1_.size() / av_get_bytes_per_sample(AV_SAMPLE_FMT_S32);\r
const auto samples = reinterpret_cast<int32_t*>(buffer1_.data());\r
\r
- return std::make_shared<std::vector<int32_t>>(samples, samples + n_samples);\r
+ return std::make_shared<core::audio_buffer>(samples, samples + n_samples);\r
}\r
\r
bool ready() const\r
audio_decoder::audio_decoder(const safe_ptr<AVFormatContext>& context, const core::video_format_desc& format_desc) : impl_(new implementation(context, format_desc)){}\r
void audio_decoder::push(const std::shared_ptr<AVPacket>& packet){impl_->push(packet);}\r
bool audio_decoder::ready() const{return impl_->ready();}\r
-std::vector<std::shared_ptr<std::vector<int32_t>>> audio_decoder::poll(){return impl_->poll();}\r
+std::vector<std::shared_ptr<core::audio_buffer>> audio_decoder::poll(){return impl_->poll();}\r
int64_t audio_decoder::nb_frames() const{return impl_->nb_frames_;}\r
}
\ No newline at end of file
*/\r
#pragma once\r
\r
+#include <core/mixer/audio/audio_mixer.h>\r
+\r
#include <common/memory/safe_ptr.h>\r
\r
#include <boost/noncopyable.hpp>\r
\r
void push(const std::shared_ptr<AVPacket>& packet);\r
bool ready() const;\r
- std::vector<std::shared_ptr<std::vector<int32_t>>> poll();\r
+ std::vector<std::shared_ptr<core::audio_buffer>> poll();\r
\r
int64_t nb_frames() const;\r
\r
struct frame_muxer::implementation : boost::noncopyable\r
{ \r
std::deque<std::queue<safe_ptr<write_frame>>> video_streams_;\r
- std::deque<std::vector<int32_t>> audio_streams_;\r
+ std::deque<core::audio_buffer> audio_streams_;\r
std::deque<safe_ptr<basic_frame>> frame_buffer_;\r
display_mode::type display_mode_;\r
const double in_fps_;\r
BOOST_THROW_EXCEPTION(invalid_operation() << source_info("frame_muxer") << msg_info("video-stream overflow. This can be caused by incorrect frame-rate. Check clip meta-data."));\r
}\r
\r
- void push(const std::shared_ptr<std::vector<int32_t>>& audio_samples)\r
+ void push(const std::shared_ptr<core::audio_buffer>& audio_samples)\r
{\r
if(!audio_samples) \r
{\r
CASPAR_LOG(debug) << L"audio-chunk-count: " << audio_sample_count_/format_desc_.audio_samples_per_frame;\r
- audio_streams_.push_back(std::vector<int32_t>());\r
+ audio_streams_.push_back(core::audio_buffer());\r
audio_sample_count_ = 0;\r
return;\r
}\r
return frame;\r
}\r
\r
- std::vector<int32_t> pop_audio()\r
+ core::audio_buffer pop_audio()\r
{\r
CASPAR_VERIFY(audio_streams_.front().size() >= format_desc_.audio_samples_per_frame);\r
\r
auto begin = audio_streams_.front().begin();\r
auto end = begin + format_desc_.audio_samples_per_frame;\r
\r
- auto samples = std::vector<int32_t>(begin, end);\r
+ auto samples = core::audio_buffer(begin, end);\r
audio_streams_.front().erase(begin, end);\r
\r
return samples;\r
frame_muxer::frame_muxer(double in_fps, const safe_ptr<core::frame_factory>& frame_factory)\r
: impl_(new implementation(in_fps, frame_factory)){}\r
void frame_muxer::push(const std::shared_ptr<AVFrame>& video_frame, int hints){impl_->push(video_frame, hints);}\r
-void frame_muxer::push(const std::shared_ptr<std::vector<int32_t>>& audio_samples){return impl_->push(audio_samples);}\r
+void frame_muxer::push(const std::shared_ptr<core::audio_buffer>& audio_samples){return impl_->push(audio_samples);}\r
void frame_muxer::commit(){impl_->commit();}\r
safe_ptr<basic_frame> frame_muxer::pop(){return impl_->pop();}\r
size_t frame_muxer::size() const {return impl_->size();}\r
\r
#include <common/memory/safe_ptr.h>\r
\r
+#include <core/mixer/audio/audio_mixer.h>\r
+\r
#include <boost/noncopyable.hpp>\r
\r
#include <vector>\r
frame_muxer(double in_fps, const safe_ptr<core::frame_factory>& frame_factory);\r
\r
void push(const std::shared_ptr<AVFrame>& video_frame, int hints = 0);\r
- void push(const std::shared_ptr<std::vector<int32_t>>& audio_samples);\r
+ void push(const std::shared_ptr<core::audio_buffer>& audio_samples);\r
\r
void commit();\r
\r