X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Fffmpeg_producer.cpp;h=ee30e2bbcf634acd34d07f6874b367163cb5850f;hb=58439eaecd6ed455b187e9965cf333073ead46de;hp=3b62cf40319dd8dcd5da9608260b8b039f39d56b;hpb=9f83209c149b6e99e0c8c449b621a2c41df61206;p=casparcg diff --git a/modules/ffmpeg/producer/ffmpeg_producer.cpp b/modules/ffmpeg/producer/ffmpeg_producer.cpp index 3b62cf403..ee30e2bbc 100644 --- a/modules/ffmpeg/producer/ffmpeg_producer.cpp +++ b/modules/ffmpeg/producer/ffmpeg_producer.cpp @@ -27,6 +27,7 @@ #include "audio/audio_decoder.h" #include "video/video_decoder.h" +#include #include #include #include @@ -36,6 +37,7 @@ #include #include +#include #include #include #include @@ -43,91 +45,84 @@ #include #include -#include +#include +#include -namespace caspar { +namespace caspar { namespace ffmpeg { + +template +struct buffer_alias +{ + typedef Concurrency::bounded_buffer> type; +}; struct ffmpeg_producer : public core::frame_producer -{ - const std::wstring filename_; - - const safe_ptr graph_; - boost::timer frame_timer_; - boost::timer video_timer_; - boost::timer audio_timer_; +{ + const std::wstring filename_; + const int start_; + const bool loop_; + const size_t length_; + + buffer_alias::type video_packets_; + buffer_alias::type audio_packets_; + buffer_alias::type video_frames_; + buffer_alias::type audio_buffers_; + buffer_alias::type muxed_frames_; + Concurrency::overwrite_buffer active_token_; + + const safe_ptr graph_; - const safe_ptr frame_factory_; - const core::video_format_desc format_desc_; + input input_; + video_decoder video_decoder_; + audio_decoder audio_decoder_; + frame_muxer2 muxer_; - input input_; - video_decoder video_decoder_; - audio_decoder audio_decoder_; - double fps_; - frame_muxer muxer_; - - int late_frames_; - const int start_; - const bool loop_; - const size_t length_; - - safe_ptr last_frame_; - - const size_t width_; - const size_t height_; - bool is_progressive_; + safe_ptr last_frame_; public: explicit ffmpeg_producer(const safe_ptr& frame_factory, const std::wstring& filename, const std::wstring& filter, bool loop, int start, size_t length) : filename_(filename) - , graph_(diagnostics::create_graph([this]{return print();})) - , frame_factory_(frame_factory) - , format_desc_(frame_factory->get_video_format_desc()) - , input_(graph_, filename_, loop, start, length) - , video_decoder_(input_.context(), frame_factory, filter) - , audio_decoder_(input_.context(), frame_factory->get_video_format_desc()) - , fps_(video_decoder_.fps()) - , muxer_(fps_, frame_factory) - , late_frames_(0) , start_(start) , loop_(loop) , length_(length) + , video_packets_(25) + , audio_packets_(25) + , video_frames_(2) + , audio_buffers_(2) + , muxed_frames_(2) + , graph_(diagnostics::create_graph([this]{return print();}, false)) + , input_(active_token_, video_packets_, audio_packets_, graph_, filename_, loop, start, length) + , video_decoder_(active_token_, video_packets_, video_frames_, input_.context(), frame_factory->get_video_format_desc().fps, filter) + , audio_decoder_(active_token_, audio_packets_, audio_buffers_, input_.context(), frame_factory->get_video_format_desc()) + , muxer_(active_token_, video_frames_, audio_buffers_, muxed_frames_, video_decoder_.fps(), frame_factory) , last_frame_(core::basic_frame::empty()) - , width_(video_decoder_.width()) - , height_(video_decoder_.height()) - , is_progressive_(true) { - graph_->add_guide("frame-time", 0.5); - graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f)); graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f)); - - for(int n = 0; n < 32 && muxer_.empty(); ++n) - decode_frame(0); + graph_->start(); + + Concurrency::send(active_token_, true); } - + + ~ffmpeg_producer() + { + Concurrency::send(active_token_, false); + std::shared_ptr frame; + Concurrency::try_receive(muxed_frames_, frame); + } + virtual safe_ptr receive(int hints) { auto frame = core::basic_frame::late(); - frame_timer_.restart(); - - for(int n = 0; n < 64 && muxer_.empty(); ++n) - decode_frame(hints); - - graph_->update_value("frame-time", static_cast(frame_timer_.elapsed()*format_desc_.fps*0.5)); - - if(!muxer_.empty()) - frame = last_frame_ = muxer_.pop(); - else - { - if(input_.eof()) - return core::basic_frame::eof(); - else - { - graph_->add_tag("underflow"); - ++late_frames_; - } + try + { + frame = last_frame_ = safe_ptr(Concurrency::receive(muxed_frames_, 8)); } - + catch(Concurrency::operation_timed_out&) + { + graph_->add_tag("underflow"); + } + return frame; } @@ -135,46 +130,8 @@ public: { return disable_audio(last_frame_); } - - void decode_frame(int hints) - { - for(int n = 0; n < 16 && ((!muxer_.video_ready() && !video_decoder_.ready()) || (!muxer_.audio_ready() && !audio_decoder_.ready())); ++n) - { - std::shared_ptr pkt; - if(input_.try_pop(pkt)) - { - video_decoder_.push(pkt); - audio_decoder_.push(pkt); - } - } - - tbb::parallel_invoke( - [&] - { - if(muxer_.video_ready()) - return; - - auto video_frames = video_decoder_.poll(); - BOOST_FOREACH(auto& video, video_frames) - { - is_progressive_ = video ? video->interlaced_frame == 0 : is_progressive_; - muxer_.push(video, hints); - } - }, - [&] - { - if(muxer_.audio_ready()) - return; - - auto audio_samples = audio_decoder_.poll(); - BOOST_FOREACH(auto& audio, audio_samples) - muxer_.push(audio); - }); - - muxer_.commit(); - } - - virtual int64_t nb_frames() const + + virtual int64_t nb_frames() const { if(loop_) return std::numeric_limits::max(); @@ -194,22 +151,34 @@ public: // TODO: Might need to scale nb_frames av frame_muxer transformations. - return nb_frames + late_frames_ - start_; + return nb_frames - start_; } virtual std::wstring print() const { return L"ffmpeg[" + boost::filesystem::wpath(filename_).filename() + L"|" - + boost::lexical_cast(width_) + L"x" + boost::lexical_cast(height_) - + (is_progressive_ ? L"p" : L"i") + boost::lexical_cast(fps_) + + boost::lexical_cast(video_decoder_.width()) + L"x" + boost::lexical_cast(video_decoder_.height()) + + (video_decoder_.is_progressive() ? L"p" : L"i") + boost::lexical_cast(video_decoder_.is_progressive() ? video_decoder_.fps() : 2.0 * video_decoder_.fps()) + L"]"; } }; -safe_ptr create_ffmpeg_producer(const safe_ptr& frame_factory, const std::vector& params) +safe_ptr create_producer(const safe_ptr& frame_factory, const std::vector& params) { static const std::vector extensions = boost::assign::list_of - (L"mpg")(L"mpeg")(L"avi")(L"mov")(L"qt")(L"webm")(L"dv")(L"mp4")(L"f4v")(L"flv")(L"mkv")(L"mka")(L"wmv")(L"wma")(L"ogg")(L"divx")(L"xvid")(L"wav")(L"mp3")(L"m2v"); + (L"mpg")(L"mpeg")(L"m2v")(L"m4v")(L"mp3")(L"mp4")(L"mpga") + (L"avi") + (L"mov") + (L"qt") + (L"webm") + (L"dv") + (L"f4v")(L"flv") + (L"mkv")(L"mka") + (L"wmv")(L"wma")(L"wav") + (L"rm")(L"ram") + (L"ogg")(L"ogv")(L"oga")(L"ogx") + (L"divx")(L"xvid"); + std::wstring filename = env::media_folder() + L"\\" + params[0]; auto ext = boost::find_if(extensions, [&](const std::wstring& ex) @@ -220,35 +189,16 @@ safe_ptr create_ffmpeg_producer(const safe_ptr::max(); - - auto seek_it = boost::find(params, L"SEEK"); - if(seek_it != params.end()) - { - if(++seek_it != params.end()) - start = boost::lexical_cast(*seek_it); - } + auto path = filename + L"." + *ext; + auto loop = boost::range::find(params, L"LOOP") != params.end(); + auto start = core::get_param(L"SEEK", params, 0); + auto length = core::get_param(L"LENGTH", params, std::numeric_limits::max()); + auto filter_str = core::get_param(L"FILTER", params, L""); + + boost::replace_all(filter_str, L"DEINTERLACE", L"YADIF=0:-1"); + boost::replace_all(filter_str, L"DEINTERLACE_BOB", L"YADIF=1:-1"); - auto length_it = boost::find(params, L"LENGTH"); - if(length_it != params.end()) - { - if(++length_it != params.end()) - length = boost::lexical_cast(*length_it); - } - - std::wstring filter = L""; - auto filter_it = boost::find(params, L"FILTER"); - if(filter_it != params.end()) - { - if(++filter_it != params.end()) - filter = *filter_it; - } - - return make_safe(frame_factory, path, filter, loop, start, length); + return make_safe(frame_factory, path, filter_str, loop, start, length); } -} \ No newline at end of file +}} \ No newline at end of file