\r
struct frame_muxer::implementation : boost::noncopyable\r
{ \r
- std::queue<safe_ptr<write_frame>> video_frames_;\r
- std::vector<int16_t> audio_samples_;\r
- std::deque<safe_ptr<basic_frame>> frame_buffer_;\r
- display_mode::type display_mode_;\r
- const double in_fps_;\r
- const video_format_desc format_desc_;\r
- bool auto_mode_;\r
-\r
- size_t audio_sample_count_;\r
- size_t video_frame_count_;\r
-\r
- std::unique_ptr<filter> filter_;\r
- safe_ptr<core::frame_factory> frame_factory_;\r
+ std::deque<std::queue<safe_ptr<write_frame>>> video_streams_;\r
+ std::deque<std::vector<int16_t>> audio_streams_;\r
+ std::deque<safe_ptr<basic_frame>> frame_buffer_;\r
+ display_mode::type display_mode_;\r
+ const double in_fps_;\r
+ const video_format_desc format_desc_;\r
+ bool auto_mode_;\r
+\r
+ size_t audio_sample_count_;\r
+ size_t video_frame_count_;\r
+ \r
+ size_t processed_audio_sample_count_;\r
+ size_t processed_video_frame_count_;\r
+\r
+ std::unique_ptr<filter> filter_;\r
+ safe_ptr<core::frame_factory> frame_factory_;\r
\r
implementation(double in_fps, const video_format_desc& format_desc, const safe_ptr<core::frame_factory>& frame_factory)\r
: display_mode_(display_mode::invalid)\r
, auto_mode_(env::properties().get("configuration.auto-mode", false))\r
, audio_sample_count_(0)\r
, video_frame_count_(0)\r
+ , processed_audio_sample_count_(0)\r
+ , processed_video_frame_count_(0)\r
, frame_factory_(frame_factory)\r
+ , video_streams_(1)\r
+ , audio_streams_(1)\r
{\r
}\r
\r
{ \r
if(!video_frame)\r
{ \r
- CASPAR_LOG(debug) << L"video-frame-count: " << video_frame_count_;\r
+ CASPAR_LOG(debug) << L"video-frame-count: " << static_cast<float>(video_frame_count_) << L":" << processed_video_frame_count_;\r
video_frame_count_ = 0;\r
+ processed_video_frame_count_ = 0;\r
+ video_streams_.push_back(std::queue<safe_ptr<write_frame>>());\r
return;\r
}\r
\r
if(display_mode_ == display_mode::invalid)\r
+ {\r
display_mode_ = auto_mode_ ? get_display_mode(video_frame->get_type(), in_fps_, format_desc_.mode, format_desc_.fps) : display_mode::simple;\r
- \r
+ CASPAR_LOG(info) << L"display_mode: " << display_mode::print(display_mode_);\r
+ } \r
+\r
++video_frame_count_;\r
\r
// Fix field-order if needed\r
else if(video_frame->get_type() == core::video_mode::upper && format_desc_.mode == core::video_mode::lower)\r
video_frame->get_image_transform().set_fill_translation(0.0f, -0.5/static_cast<double>(video_frame->get_pixel_format_desc().planes[0].height));\r
\r
- video_frames_.push(make_safe(video_frame));\r
+ video_streams_.back().push(make_safe(video_frame));\r
\r
process(frame_buffer_);\r
\r
{\r
if(!audio_samples) \r
{\r
- auto truncate = audio_sample_count_ % format_desc_.audio_samples_per_frame;\r
- if(truncate > 0)\r
- {\r
- audio_samples_.erase(audio_samples_.end() - truncate, audio_samples_.end());\r
- CASPAR_LOG(info) << L"frame_muxer: Truncating " << truncate << L" audio samples.";\r
- }\r
-\r
- CASPAR_LOG(debug) << L"audio-chunk-count: " << audio_sample_count_/format_desc_.audio_samples_per_frame;\r
+ CASPAR_LOG(debug) << L"audio-chunk-count: " << static_cast<float>(audio_sample_count_)/format_desc_.audio_samples_per_frame << L":" << processed_audio_sample_count_/format_desc_.audio_samples_per_frame;\r
+ CASPAR_LOG(debug) << L"audio-sample-count: " << audio_sample_count_ << L":" << processed_audio_sample_count_;\r
+ audio_streams_.push_back(std::vector<int16_t>());\r
+ processed_audio_sample_count_ = 0;\r
audio_sample_count_ = 0;\r
return;\r
}\r
\r
audio_sample_count_ += audio_samples->size();\r
\r
- boost::range::push_back(audio_samples_, *audio_samples);\r
- std::deque<safe_ptr<basic_frame>> frames;\r
- process(frames);\r
- boost::range::push_back(frame_buffer_, frames);\r
+ boost::range::push_back(audio_streams_.back(), *audio_samples);\r
+ process(frame_buffer_);\r
}\r
\r
safe_ptr<basic_frame> pop()\r
{ \r
auto frame = frame_buffer_.front();\r
- frame_buffer_.pop_front();\r
+ frame_buffer_.pop_front(); \r
return frame;\r
}\r
\r
\r
safe_ptr<core::write_frame> pop_video()\r
{\r
- auto frame = video_frames_.front();\r
- video_frames_.pop();\r
+ auto frame = video_streams_.front().front();\r
+ video_streams_.front().pop();\r
+\r
+ ++processed_video_frame_count_;\r
+\r
return frame;\r
}\r
\r
std::vector<int16_t> pop_audio()\r
{\r
- CASPAR_VERIFY(audio_samples_.size() >= format_desc_.audio_samples_per_frame);\r
+ CASPAR_VERIFY(audio_streams_.front().size() >= format_desc_.audio_samples_per_frame);\r
\r
- auto begin = audio_samples_.begin();\r
+ auto begin = audio_streams_.front().begin();\r
auto end = begin + format_desc_.audio_samples_per_frame;\r
\r
auto samples = std::vector<int16_t>(begin, end);\r
- audio_samples_.erase(begin, end);\r
+ audio_streams_.front().erase(begin, end);\r
+\r
+ processed_audio_sample_count_ += format_desc_.audio_samples_per_frame;\r
\r
return samples;\r
}\r
+\r
+ bool video_ready() const\r
+ {\r
+ return video_frames() > 1 && video_streams_.size() >= audio_streams_.size();\r
+ }\r
+ \r
+ bool audio_ready() const\r
+ {\r
+ return audio_chunks() > 1 && audio_streams_.size() >= video_streams_.size();\r
+ }\r
+\r
+ size_t video_frames() const\r
+ {\r
+ return video_streams_.back().size();\r
+ }\r
+\r
+ size_t audio_chunks() const\r
+ {\r
+ return audio_streams_.back().size() / format_desc_.audio_samples_per_frame;\r
+ }\r
\r
void process(std::deque<safe_ptr<basic_frame>>& dest)\r
{\r
- if(video_frames_.empty() || audio_samples_.size() < format_desc_.audio_samples_per_frame)\r
+ if(video_streams_.size() > 1 && audio_streams_.size() > 1 &&\r
+ (video_streams_.front().empty() || audio_streams_.front().empty()))\r
+ {\r
+ if(!video_streams_.front().empty() || !audio_streams_.front().empty())\r
+ CASPAR_LOG(debug) << " Truncating: " << video_streams_.front().size() << L" video-frames, " << audio_streams_.front().size() << L" audio-samples.";\r
+\r
+ video_streams_.pop_front();\r
+ audio_streams_.pop_front();\r
+ }\r
+\r
+ if(video_streams_.front().empty() || audio_streams_.front().size() < format_desc_.audio_samples_per_frame)\r
return;\r
\r
switch(display_mode_)\r
\r
void simple(std::deque<safe_ptr<basic_frame>>& dest)\r
{\r
- if(video_frames_.empty() || audio_samples_.size() < format_desc_.audio_samples_per_frame)\r
+ if(video_streams_.front().empty() || audio_streams_.front().size() < format_desc_.audio_samples_per_frame)\r
return;\r
\r
- if(video_frames_.front()->get_type() != core::video_mode::progressive && format_desc_.mode != core::video_mode::progressive &&\r
- video_frames_.front()->get_pixel_format_desc().planes.at(0).height != format_desc_.height )\r
+ if(video_streams_.front().front()->get_type() != core::video_mode::progressive && format_desc_.mode != core::video_mode::progressive &&\r
+ video_streams_.front().front()->get_pixel_format_desc().planes.at(0).height != format_desc_.height )\r
{ // The frame will most likely be scaled, we need to deinterlace->reinterlace\r
if(!filter_)\r
filter_.reset(new filter(L"YADIF=1:-1"));\r
\r
void duplicate(std::deque<safe_ptr<basic_frame>>& dest)\r
{ \r
- if(video_frames_.empty() || audio_samples_.size()/2 < format_desc_.audio_samples_per_frame)\r
+ if(video_streams_.front().empty() || audio_streams_.front().size()/2 < format_desc_.audio_samples_per_frame)\r
return;\r
\r
auto frame = pop_video();\r
\r
void half(std::deque<safe_ptr<basic_frame>>& dest)\r
{ \r
- if(video_frames_.size() < 2 || audio_samples_.size() < format_desc_.audio_samples_per_frame)\r
+ if(video_streams_.front().size() < 2 || audio_streams_.front().size() < format_desc_.audio_samples_per_frame)\r
return;\r
\r
auto frame1 = pop_video();\r
frame1->commit();\r
frame1->audio_data() = pop_audio();\r
\r
- video_frames_.pop(); // Throw away\r
+ video_streams_.front().pop(); // Throw away\r
\r
dest.push_back(frame1);\r
}\r
\r
void interlace(std::deque<safe_ptr<basic_frame>>& dest)\r
{ \r
- if(video_frames_.size() < 2 || audio_samples_.size() < format_desc_.audio_samples_per_frame)\r
+ if(video_streams_.front().size() < 2 || audio_streams_.front().size() < format_desc_.audio_samples_per_frame)\r
return;\r
\r
auto frame1 = pop_video();\r
\r
void deinterlace_bob(std::deque<safe_ptr<basic_frame>>& dest)\r
{\r
- if(video_frames_.empty() || audio_samples_.size()/2 < format_desc_.audio_samples_per_frame)\r
+ if(video_streams_.front().empty() || audio_streams_.front().size()/2 < format_desc_.audio_samples_per_frame)\r
return;\r
\r
if(!filter_)\r
\r
void deinterlace(std::deque<safe_ptr<basic_frame>>& dest)\r
{\r
- if(video_frames_.empty() || audio_samples_.size() < format_desc_.audio_samples_per_frame)\r
+ if(video_streams_.front().empty() || audio_streams_.front().size() < format_desc_.audio_samples_per_frame)\r
return;\r
\r
if(!filter_)\r
safe_ptr<basic_frame> frame_muxer::pop(){return impl_->pop();}\r
size_t frame_muxer::size() const {return impl_->size();}\r
bool frame_muxer::empty() const {return impl_->size() == 0;}\r
-size_t frame_muxer::video_frames() const{return impl_->video_frames_.size();}\r
-size_t frame_muxer::audio_chunks() const{return impl_->audio_samples_.size() / impl_->format_desc_.audio_samples_per_frame;}\r
+bool frame_muxer::video_ready() const{return impl_->video_ready();}\r
+bool frame_muxer::audio_ready() const{return impl_->audio_ready();}\r
\r
}
\ No newline at end of file