const int n_samples = audio_data_.back().size();\r
\r
const auto in_size = static_cast<size_t>(audio_data.size());\r
+ CASPAR_VERIFY(in_size == 0 || in_size == audio_data_.back().size());\r
\r
- if(in_size != 0 && in_size != audio_data_.back().size())\r
- { \r
- CASPAR_LOG(warning) << L" audio_mixer[] : Invalid sample count detected. Discarding audio chunk.";\r
+ if(in_size > audio_data_.back().size())\r
return;\r
- }\r
\r
tbb::parallel_for\r
(\r
#include "frame/pixel_format.h"\r
#include "../mixer/write_frame.h"\r
\r
-#include <boost/range/algorithm_ext/push_back.hpp>\r
-\r
#include <common/env.h>\r
\r
namespace caspar { namespace core {\r
if(video_frames_.empty() || audio_chunks_.empty())\r
return;\r
\r
- auto frame1 = std::move(video_frames_.front());\r
+ auto frame1 = video_frames_.front();\r
video_frames_.pop();\r
\r
- frame1->audio_data() = std::move(audio_chunks_.front());\r
+ frame1->audio_data() = audio_chunks_.front();\r
audio_chunks_.pop();\r
\r
frame_buffer_.push(frame1);\r
\r
void duplicate()\r
{ \r
- if(video_frames_.empty() || audio_chunks_.empty())\r
+ if(video_frames_.empty() || audio_chunks_.size() < 2)\r
return;\r
\r
- auto frame = std::move(video_frames_.front());\r
+ auto frame = video_frames_.front();\r
video_frames_.pop();\r
\r
- auto audio_chunk = std::move(audio_chunks_.front());\r
- audio_chunks_.pop();\r
-\r
auto frame1 = make_safe<core::write_frame>(*frame); // make a copy\r
- frame1->audio_data().insert(frame1->audio_data().end(), audio_chunk.begin(), audio_chunk.begin() + audio_chunk.size()/2);\r
+ frame1->audio_data() = audio_chunks_.front();\r
+ audio_chunks_.pop();\r
\r
auto frame2 = frame;\r
- frame1->audio_data().insert(frame1->audio_data().end(), audio_chunk.begin() + audio_chunk.size()/2, audio_chunk.end());\r
+ frame2->audio_data() = audio_chunks_.front();\r
+ audio_chunks_.pop();\r
\r
frame_buffer_.push(frame1);\r
frame_buffer_.push(frame2);\r
\r
void half()\r
{ \r
- if(video_frames_.size() < 2 || audio_chunks_.size() < 2)\r
+ if(video_frames_.size() < 2 || audio_chunks_.empty())\r
return;\r
\r
- auto frame1 = std::move(video_frames_.front());\r
+ auto frame1 = video_frames_.front();\r
video_frames_.pop();\r
-\r
- video_frames_.pop(); // Throw away\r
- \r
- boost::range::push_back(frame1->audio_data(), std::move(audio_chunks_.front()));\r
+ frame1->audio_data() = audio_chunks_.front();\r
audio_chunks_.pop();\r
-\r
- boost::range::push_back(frame1->audio_data(), std::move(audio_chunks_.front()));\r
- audio_chunks_.pop(); \r
+ \r
+ video_frames_.pop(); // Throw away\r
\r
frame_buffer_.push(frame1);\r
}\r
\r
void interlace()\r
{ \r
- if(video_frames_.size() < 2 || audio_chunks_.size() < 2)\r
+ if(video_frames_.size() < 2 || audio_chunks_.empty())\r
return;\r
\r
auto frame1 = video_frames_.front();\r
video_frames_.pop();\r
+\r
+ frame1->audio_data() = audio_chunks_.front();\r
+ audio_chunks_.pop();\r
\r
auto frame2 = video_frames_.front();\r
video_frames_.pop();\r
- \r
- boost::range::push_back(frame2->audio_data(), std::move(audio_chunks_.front()));\r
- audio_chunks_.pop();\r
-\r
- boost::range::push_back(frame2->audio_data(), std::move(audio_chunks_.front()));\r
- audio_chunks_.pop();\r
\r
frame_buffer_.push(core::basic_frame::interlace(frame1, frame2, out_mode_)); \r
}\r
// It is assumed that audio is always equal or ahead of video.\r
if(audio && SUCCEEDED(audio->GetBytes(&bytes)))\r
{\r
+ auto sample_frame_count = audio->GetSampleFrameCount();\r
auto audio_data = reinterpret_cast<short*>(bytes);\r
- muxer_.push(std::vector<int16_t>(audio_data, audio_data + audio->GetSampleFrameCount()*2));\r
+ audio_samples_.insert(audio_samples_.end(), audio_data, audio_data + sample_frame_count*2);\r
+\r
+ if(audio_samples_.size() > frame_factory_->get_video_format_desc().audio_samples_per_frame)\r
+ {\r
+ const auto begin = audio_samples_.begin();\r
+ const auto end = begin + frame_factory_->get_video_format_desc().audio_samples_per_frame;\r
+ muxer_.push(std::vector<int16_t>(begin, end));\r
+ audio_samples_.erase(begin, end);\r
+ }\r
}\r
else\r
muxer_.push(std::vector<int16_t>(frame_factory_->get_video_format_desc().audio_samples_per_frame, 0));\r
\r
std::vector<int8_t, tbb::cache_aligned_allocator<int8_t>> buffer1_;\r
std::vector<int8_t, tbb::cache_aligned_allocator<int8_t>> buffer2_;\r
+ std::vector<int16_t, tbb::cache_aligned_allocator<int16_t>> audio_samples_; \r
std::queue<std::shared_ptr<AVPacket>> packets_;\r
- size_t sample_count_;\r
public:\r
explicit implementation(const std::shared_ptr<AVFormatContext>& context, const core::video_format_desc& format_desc) \r
: format_desc_(format_desc) \r
- , sample_count_(0)\r
{ \r
AVCodec* dec;\r
index_ = av_find_best_stream(context.get(), AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0);\r
\r
+ if(index_ < 0)\r
+ return;\r
+\r
int errn = avcodec_open(context->streams[index_]->codec, dec);\r
if(errn < 0)\r
return;\r
pkt.size = packets_.front()->size;\r
\r
for(int n = 0; n < 64 && pkt.size > 0; ++n)\r
- decode(pkt, result);\r
+ decode(pkt);\r
}\r
else\r
- avcodec_flush_buffers(codec_context_.get());\r
+ flush();\r
\r
packets_.pop();\r
+\r
+ while(audio_samples_.size() > format_desc_.audio_samples_per_frame)\r
+ {\r
+ const auto begin = audio_samples_.begin();\r
+ const auto end = audio_samples_.begin() + format_desc_.audio_samples_per_frame;\r
+\r
+ result.push_back(std::vector<int16_t>(begin, end));\r
+ audio_samples_.erase(begin, end);\r
+ }\r
}\r
\r
return result;\r
}\r
\r
- void decode(AVPacket& pkt, std::vector<std::vector<int16_t>>& audio_chunks)\r
+ void decode(AVPacket& pkt)\r
{ \r
buffer1_.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE*2, 0);\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_S16);\r
const auto samples = reinterpret_cast<int16_t*>(buffer1_.data());\r
\r
- sample_count_ = std::max(sample_count_, n_samples);\r
+ audio_samples_.insert(audio_samples_.end(), samples, samples + n_samples);\r
+ }\r
\r
- if(sample_count_ == 0 || n_samples == sample_count_)\r
- audio_chunks.push_back(std::vector<int16_t>(samples, samples + n_samples));\r
- else\r
- CASPAR_LOG(warning) << L" audio_decoder: Discarding " << n_samples << L" samples.";\r
+ void flush()\r
+ {\r
+ auto truncate = audio_samples_.size() % format_desc_.audio_samples_per_frame;\r
+ if(truncate > 0)\r
+ {\r
+ audio_samples_.resize(audio_samples_.size() - truncate); \r
+ CASPAR_LOG(info) << L"Truncating " << truncate << L" audio-samples."; \r
+ }\r
+ avcodec_flush_buffers(codec_context_.get());\r
}\r
\r
bool ready() const\r
if(packet) // eof\r
decode(*packet, av_frames); \r
else\r
- {\r
- if(codec_context_->codec->capabilities | CODEC_CAP_DELAY)\r
- {\r
- // TODO: This might cause bad performance.\r
- AVPacket pkt = {0};\r
- for(int n = 0; n < 8 && decode(pkt, av_frames); ++n){}\r
- }\r
-\r
- avcodec_flush_buffers(codec_context_.get());\r
- }\r
+ flush(av_frames);\r
\r
if(filter_)\r
{\r
return result;\r
}\r
\r
- bool decode(AVPacket& packet, std::vector<safe_ptr<AVFrame>>& av_frames)\r
+ void decode(AVPacket& packet, std::vector<safe_ptr<AVFrame>>& av_frames)\r
{\r
std::shared_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\r
\r
\r
if(frame_finished != 0) \r
av_frames.push_back(make_safe(decoded_frame));\r
+ }\r
\r
- return frame_finished != 0;\r
+ void flush(std::vector<safe_ptr<AVFrame>>& av_frames)\r
+ {\r
+ if(codec_context_->codec->capabilities | CODEC_CAP_DELAY)\r
+ {\r
+ // FIXME: This might cause bad performance.\r
+ AVPacket pkt = {0};\r
+ decode(pkt, av_frames);\r
+ }\r
+\r
+ avcodec_flush_buffers(codec_context_.get());\r
}\r
- \r
+\r
bool ready() const\r
{\r
return !codec_context_ || !packet_buffer_.empty();\r