X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fconsumer%2Fstreaming_consumer.cpp;h=41cc3e79899fccc38679cffb8085f3caf384661a;hb=b8c8660af595b9897af41183fe8b12786d45af98;hp=39904a05f9aad28b5c53bbbfe35102682e1216fe;hpb=3eefdca43ad463fd035c144af2a289808eff5367;p=casparcg diff --git a/modules/ffmpeg/consumer/streaming_consumer.cpp b/modules/ffmpeg/consumer/streaming_consumer.cpp index 39904a05f..41cc3e798 100644 --- a/modules/ffmpeg/consumer/streaming_consumer.cpp +++ b/modules/ffmpeg/consumer/streaming_consumer.cpp @@ -3,6 +3,7 @@ #include "ffmpeg_consumer.h" #include "../ffmpeg_error.h" +#include "../producer/util/util.h" #include #include @@ -43,7 +44,7 @@ #pragma warning(push) #pragma warning(disable: 4244) -extern "C" +extern "C" { #define __STDC_CONSTANT_MACROS #define __STDC_LIMIT_MACROS @@ -76,7 +77,7 @@ class streaming_consumer final : public core::frame_consumer { public: // Static Members - + private: core::monitor::subject subject_; boost::filesystem::path path_; @@ -84,29 +85,29 @@ private: std::map options_; bool compatibility_mode_; - + core::video_format_desc in_video_format_; core::audio_channel_layout in_channel_layout_ = core::audio_channel_layout::invalid(); std::shared_ptr oc_; tbb::atomic abort_request_; - + std::shared_ptr video_st_; std::shared_ptr audio_st_; std::int64_t video_pts_; std::int64_t audio_pts_; - - AVFilterContext* audio_graph_in_; - AVFilterContext* audio_graph_out_; - std::shared_ptr audio_graph_; - std::shared_ptr audio_bitstream_filter_; - - AVFilterContext* video_graph_in_; - AVFilterContext* video_graph_out_; - std::shared_ptr video_graph_; + + AVFilterContext* audio_graph_in_; + AVFilterContext* audio_graph_out_; + std::shared_ptr audio_graph_; + std::shared_ptr audio_bitstream_filter_; + + AVFilterContext* video_graph_in_; + AVFilterContext* video_graph_out_; + std::shared_ptr video_graph_; std::shared_ptr video_bitstream_filter_; - + executor executor_; executor video_encoder_executor_; @@ -118,11 +119,11 @@ private: tbb::atomic current_encoding_delay_; executor write_executor_; - + public: streaming_consumer( - std::string path, + std::string path, std::string options, bool compatibility_mode) : path_(path) @@ -134,32 +135,32 @@ public: , audio_encoder_executor_(print() + L" audio_encoder") , video_encoder_executor_(print() + L" video_encoder") , write_executor_(print() + L" io") - { + { abort_request_ = false; current_encoding_delay_ = 0; - for(auto it = + for(auto it = boost::sregex_iterator( - options.begin(), - options.end(), - boost::regex("-(?[^-\\s]+)(\\s+(?[^\\s]+))?")); - it != boost::sregex_iterator(); + options.begin(), + options.end(), + boost::regex("-(?[^-\\s]+)(\\s+(?[^\\s]+))?")); + it != boost::sregex_iterator(); ++it) - { + { options_[(*it)["NAME"].str()] = (*it)["VALUE"].matched ? (*it)["VALUE"].str() : ""; } - + if (options_.find("threads") == options_.end()) options_["threads"] = "auto"; - tokens_ = + tokens_ = std::max( - 1, + 1, try_remove_arg( - options_, - boost::regex("tokens")).get_value_or(2)); + options_, + boost::regex("tokens")).get_value_or(2)); } - + ~streaming_consumer() { if(oc_) @@ -197,84 +198,84 @@ public: int channel_index) override { try - { + { static boost::regex prot_exp("^.+:.*" ); - - const auto overwrite = + + const auto overwrite = try_remove_arg( options_, boost::regex("y")) != boost::none; if(!boost::regex_match( - path_.string(), + path_.string(), prot_exp)) { if(!path_.is_complete()) { - path_ = + path_ = u8( - env::media_folder()) + + env::media_folder()) + path_.string(); } - + if(boost::filesystem::exists(path_)) { if(!overwrite && !compatibility_mode_) BOOST_THROW_EXCEPTION(invalid_argument() << msg_info("File exists")); - + boost::filesystem::remove(path_); } } - - const auto oformat_name = + + const auto oformat_name = try_remove_arg( - options_, + options_, boost::regex("^f|format$")); - + AVFormatContext* oc; FF(avformat_alloc_output_context2( - &oc, - nullptr, - oformat_name && !oformat_name->empty() ? oformat_name->c_str() : nullptr, + &oc, + nullptr, + oformat_name && !oformat_name->empty() ? oformat_name->c_str() : nullptr, path_.string().c_str())); oc_.reset( - oc, + oc, avformat_free_context); - + CASPAR_VERIFY(oc_->oformat); oc_->interrupt_callback.callback = streaming_consumer::interrupt_cb; - oc_->interrupt_callback.opaque = this; + oc_->interrupt_callback.opaque = this; CASPAR_VERIFY(format_desc.format != core::video_format::invalid); in_video_format_ = format_desc; in_channel_layout_ = channel_layout; - + CASPAR_VERIFY(oc_->oformat); - - const auto video_codec_name = + + const auto video_codec_name = try_remove_arg( - options_, + options_, boost::regex("^c:v|codec:v|vcodec$")); - const auto video_codec = - video_codec_name + const auto video_codec = + video_codec_name ? avcodec_find_encoder_by_name(video_codec_name->c_str()) : avcodec_find_encoder(oc_->oformat->video_codec); - - const auto audio_codec_name = + + const auto audio_codec_name = try_remove_arg( - options_, + options_, boost::regex("^c:a|codec:a|acodec$")); - - const auto audio_codec = - audio_codec_name + + const auto audio_codec = + audio_codec_name ? avcodec_find_encoder_by_name(audio_codec_name->c_str()) : avcodec_find_encoder(oc_->oformat->audio_codec); - + if (!video_codec) CASPAR_THROW_EXCEPTION(user_error() << msg_info( "Failed to find video codec " + (video_codec_name @@ -287,17 +288,17 @@ public: ? *audio_codec_name : "with id " + boost::lexical_cast( oc_->oformat->audio_codec)))); - + // Filters { configure_video_filters( - *video_codec, - try_remove_arg(options_, + *video_codec, + try_remove_arg(options_, boost::regex("vf|f:v|filter:v")).get_value_or("")); configure_audio_filters( - *audio_codec, + *audio_codec, try_remove_arg(options_, boost::regex("af|f:a|filter:a")).get_value_or("")); } @@ -315,11 +316,11 @@ public: auto audio_options = options_; video_st_ = open_encoder( - *video_codec, + *video_codec, video_options); audio_st_ = open_encoder( - *audio_codec, + *audio_codec, audio_options); auto it = options_.begin(); @@ -337,7 +338,7 @@ public: AVDictionary* av_opts = nullptr; to_dict( - &av_opts, + &av_opts, std::move(options_)); CASPAR_SCOPE_EXIT @@ -345,37 +346,37 @@ public: av_dict_free(&av_opts); }; - if (!(oc_->oformat->flags & AVFMT_NOFILE)) + if (!(oc_->oformat->flags & AVFMT_NOFILE)) { FF(avio_open2( - &oc_->pb, - path_.string().c_str(), - AVIO_FLAG_WRITE, - &oc_->interrupt_callback, + &oc_->pb, + path_.string().c_str(), + AVIO_FLAG_WRITE, + &oc_->interrupt_callback, &av_opts)); } - + FF(avformat_write_header( - oc_.get(), + oc_.get(), &av_opts)); - + options_ = to_map(av_opts); } // Dump Info - + av_dump_format( - oc_.get(), - 0, - oc_->filename, - 1); + oc_.get(), + 0, + oc_->filename, + 1); for (const auto& option : options_) { - CASPAR_LOG(warning) - << L"Invalid option: -" - << u16(option.first) - << L" " + CASPAR_LOG(warning) + << L"Invalid option: -" + << u16(option.first) + << L" " << u16(option.second); } } @@ -399,12 +400,12 @@ public: } std::future send(core::const_frame frame) override - { + { CASPAR_VERIFY(in_video_format_.format != core::video_format::invalid); - + --tokens_; std::shared_ptr token( - nullptr, + nullptr, [this, frame](void*) { ++tokens_; @@ -422,17 +423,17 @@ public: video_encoder_executor_.begin_invoke([=]() mutable { encode_video( - frame, + frame, token); }); - + audio_encoder_executor_.begin_invoke([=]() mutable { encode_audio( - frame, + frame, token); }); - + return true; }); } @@ -441,7 +442,7 @@ public: { return L"streaming_consumer[" + u16(path_.string()) + L"]"; } - + virtual boost::property_tree::wptree info() const override { boost::property_tree::wptree info; @@ -475,26 +476,26 @@ private: static int interrupt_cb(void* ctx) { CASPAR_ASSERT(ctx); - return reinterpret_cast(ctx)->abort_request_; + return reinterpret_cast(ctx)->abort_request_; } - + std::shared_ptr open_encoder( const AVCodec& codec, std::map& options) - { - auto st = + { + auto st = avformat_new_stream( - oc_.get(), + oc_.get(), &codec); - if (!st) + if (!st) CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Could not allocate video-stream.") << boost::errinfo_api_function("av_new_stream")); auto enc = st->codec; - + CASPAR_VERIFY(enc); - + switch(enc->codec_type) { case AVMEDIA_TYPE_VIDEO: @@ -505,7 +506,7 @@ private: enc->width = video_graph_out_->inputs[0]->w; enc->height = video_graph_out_->inputs[0]->h; enc->bit_rate_tolerance = 400 * 1000000; - + break; } case AVMEDIA_TYPE_AUDIO: @@ -515,27 +516,27 @@ private: enc->sample_rate = audio_graph_out_->inputs[0]->sample_rate; enc->channel_layout = audio_graph_out_->inputs[0]->channel_layout; enc->channels = audio_graph_out_->inputs[0]->channels; - + break; } } - + if(oc_->oformat->flags & AVFMT_GLOBALHEADER) enc->flags |= CODEC_FLAG_GLOBAL_HEADER; - + static const std::array char_id_map = {{"v", "a", "d", "s"}}; const auto char_id = char_id_map.at(enc->codec_type); - - const auto codec_opts = + + const auto codec_opts = remove_options( - options, + options, boost::regex("^(" + char_id + "?[^:]+):" + char_id + "$")); - + AVDictionary* av_codec_opts = nullptr; to_dict( - &av_codec_opts, + &av_codec_opts, options); to_dict( @@ -543,19 +544,19 @@ private: codec_opts); options.clear(); - + FF(avcodec_open2( - enc, - &codec, - av_codec_opts ? &av_codec_opts : nullptr)); + enc, + &codec, + av_codec_opts ? &av_codec_opts : nullptr)); if(av_codec_opts) { - auto t = + auto t = av_dict_get( - av_codec_opts, - "", - nullptr, + av_codec_opts, + "", + nullptr, AV_DICT_IGNORE_SUFFIX); while(t) @@ -563,22 +564,22 @@ private: options[t->key + (codec_opts.find(t->key) != codec_opts.end() ? ":" + char_id : "")] = t->value; t = av_dict_get( - av_codec_opts, - "", - t, + av_codec_opts, + "", + t, AV_DICT_IGNORE_SUFFIX); } av_dict_free(&av_codec_opts); } - + if(enc->codec_type == AVMEDIA_TYPE_AUDIO && !(codec.capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) { CASPAR_ASSERT(enc->frame_size > 0); - av_buffersink_set_frame_size(audio_graph_out_, + av_buffersink_set_frame_size(audio_graph_out_, enc->frame_size); } - + return std::shared_ptr(st, [this](AVStream* st) { avcodec_close(st->codec); @@ -588,14 +589,14 @@ private: void configue_audio_bistream_filters( std::map& options) { - const auto audio_bitstream_filter_str = + const auto audio_bitstream_filter_str = try_remove_arg( - options, + options, boost::regex("^bsf:a|absf$")); - const auto audio_bitstream_filter = - audio_bitstream_filter_str - ? av_bitstream_filter_init(audio_bitstream_filter_str->c_str()) + const auto audio_bitstream_filter = + audio_bitstream_filter_str + ? av_bitstream_filter_init(audio_bitstream_filter_str->c_str()) : nullptr; CASPAR_VERIFY(!audio_bitstream_filter_str || audio_bitstream_filter); @@ -603,25 +604,25 @@ private: if(audio_bitstream_filter) { audio_bitstream_filter_.reset( - audio_bitstream_filter, + audio_bitstream_filter, av_bitstream_filter_close); } - + if(audio_bitstream_filter_str && !audio_bitstream_filter_) options["bsf:a"] = *audio_bitstream_filter_str; } - + void configue_video_bistream_filters( std::map& options) { - const auto video_bitstream_filter_str = + const auto video_bitstream_filter_str = try_remove_arg( - options, + options, boost::regex("^bsf:v|vbsf$")); - const auto video_bitstream_filter = - video_bitstream_filter_str - ? av_bitstream_filter_init(video_bitstream_filter_str->c_str()) + const auto video_bitstream_filter = + video_bitstream_filter_str + ? av_bitstream_filter_init(video_bitstream_filter_str->c_str()) : nullptr; CASPAR_VERIFY(!video_bitstream_filter_str || video_bitstream_filter); @@ -629,25 +630,25 @@ private: if(video_bitstream_filter) { video_bitstream_filter_.reset( - video_bitstream_filter, + video_bitstream_filter, av_bitstream_filter_close); } - + if(video_bitstream_filter_str && !video_bitstream_filter_) options["bsf:v"] = *video_bitstream_filter_str; } - + void configure_video_filters( const AVCodec& codec, const std::string& filtergraph) { video_graph_.reset( - avfilter_graph_alloc(), + avfilter_graph_alloc(), [](AVFilterGraph* p) { avfilter_graph_free(&p); }); - + video_graph_->nb_threads = boost::thread::hardware_concurrency()/2; video_graph_->thread_type = AVFILTER_THREAD_SLICE; @@ -658,57 +659,57 @@ private: boost::rational( in_video_format_.width, in_video_format_.height); - + const auto vsrc_options = (boost::format("video_size=%1%x%2%:pix_fmt=%3%:time_base=%4%/%5%:pixel_aspect=%6%/%7%:frame_rate=%8%/%9%") % in_video_format_.width % in_video_format_.height % AV_PIX_FMT_BGRA % in_video_format_.duration % in_video_format_.time_scale % sample_aspect_ratio.numerator() % sample_aspect_ratio.denominator() % in_video_format_.time_scale % in_video_format_.duration).str(); - - AVFilterContext* filt_vsrc = nullptr; + + AVFilterContext* filt_vsrc = nullptr; FF(avfilter_graph_create_filter( &filt_vsrc, - avfilter_get_by_name("buffer"), + avfilter_get_by_name("buffer"), "ffmpeg_consumer_buffer", - vsrc_options.c_str(), - nullptr, + vsrc_options.c_str(), + nullptr, video_graph_.get())); - + AVFilterContext* filt_vsink = nullptr; FF(avfilter_graph_create_filter( &filt_vsink, - avfilter_get_by_name("buffersink"), + avfilter_get_by_name("buffersink"), "ffmpeg_consumer_buffersink", - nullptr, - nullptr, + nullptr, + nullptr, video_graph_.get())); - + #pragma warning (push) #pragma warning (disable : 4245) FF(av_opt_set_int_list( - filt_vsink, - "pix_fmts", - codec.pix_fmts, + filt_vsink, + "pix_fmts", + codec.pix_fmts, -1, AV_OPT_SEARCH_CHILDREN)); #pragma warning (pop) - + configure_filtergraph( - *video_graph_, + *video_graph_, filtergraph, *filt_vsrc, *filt_vsink); video_graph_in_ = filt_vsrc; video_graph_out_ = filt_vsink; - + CASPAR_LOG(info) - << u16(std::string("\n") + << u16(std::string("\n") + avfilter_graph_dump( - video_graph_.get(), + video_graph_.get(), nullptr)); } @@ -717,88 +718,88 @@ private: const std::string& filtergraph) { audio_graph_.reset( - avfilter_graph_alloc(), + avfilter_graph_alloc(), [](AVFilterGraph* p) { avfilter_graph_free(&p); }); - + audio_graph_->nb_threads = boost::thread::hardware_concurrency()/2; audio_graph_->thread_type = AVFILTER_THREAD_SLICE; - + const auto asrc_options = (boost::format("sample_rate=%1%:sample_fmt=%2%:channels=%3%:time_base=%4%/%5%:channel_layout=%6%") % in_video_format_.audio_sample_rate % av_get_sample_fmt_name(AV_SAMPLE_FMT_S32) % in_channel_layout_.num_channels % 1 % in_video_format_.audio_sample_rate % boost::io::group( - std::hex, - std::showbase, + std::hex, + std::showbase, av_get_default_channel_layout(in_channel_layout_.num_channels))).str(); AVFilterContext* filt_asrc = nullptr; FF(avfilter_graph_create_filter( &filt_asrc, - avfilter_get_by_name("abuffer"), + avfilter_get_by_name("abuffer"), "ffmpeg_consumer_abuffer", - asrc_options.c_str(), - nullptr, + asrc_options.c_str(), + nullptr, audio_graph_.get())); - + AVFilterContext* filt_asink = nullptr; FF(avfilter_graph_create_filter( &filt_asink, - avfilter_get_by_name("abuffersink"), + avfilter_get_by_name("abuffersink"), "ffmpeg_consumer_abuffersink", - nullptr, - nullptr, + nullptr, + nullptr, audio_graph_.get())); - + #pragma warning (push) #pragma warning (disable : 4245) FF(av_opt_set_int( - filt_asink, + filt_asink, "all_channel_counts", - 1, + 1, AV_OPT_SEARCH_CHILDREN)); FF(av_opt_set_int_list( - filt_asink, - "sample_fmts", - codec.sample_fmts, - -1, + filt_asink, + "sample_fmts", + codec.sample_fmts, + -1, AV_OPT_SEARCH_CHILDREN)); FF(av_opt_set_int_list( filt_asink, - "channel_layouts", - codec.channel_layouts, - -1, + "channel_layouts", + codec.channel_layouts, + -1, AV_OPT_SEARCH_CHILDREN)); FF(av_opt_set_int_list( - filt_asink, - "sample_rates" , - codec.supported_samplerates, - -1, + filt_asink, + "sample_rates" , + codec.supported_samplerates, + -1, AV_OPT_SEARCH_CHILDREN)); #pragma warning (pop) - + configure_filtergraph( - *audio_graph_, - filtergraph, - *filt_asrc, + *audio_graph_, + filtergraph, + *filt_asrc, *filt_asink); audio_graph_in_ = filt_asrc; audio_graph_out_ = filt_asink; - CASPAR_LOG(info) - << u16(std::string("\n") + CASPAR_LOG(info) + << u16(std::string("\n") + avfilter_graph_dump( - audio_graph_.get(), + audio_graph_.get(), nullptr)); } @@ -831,23 +832,23 @@ private: inputs->next = nullptr; FF(avfilter_graph_parse( - &graph, - filtergraph.c_str(), + &graph, + filtergraph.c_str(), inputs, outputs, nullptr)); - } - else + } + else { FF(avfilter_link( - &source_ctx, - 0, - &sink_ctx, + &source_ctx, + 0, + &sink_ctx, 0)); } FF(avfilter_graph_config( - &graph, + &graph, nullptr)); } catch(...) @@ -857,33 +858,24 @@ private: throw; } } - + void encode_video(core::const_frame frame_ptr, std::shared_ptr token) - { + { if(!video_st_) return; auto enc = video_st_->codec; - - std::shared_ptr src_av_frame; if(frame_ptr != core::const_frame::empty()) { - src_av_frame.reset( - av_frame_alloc(), - [frame_ptr](AVFrame* frame) - { - av_frame_free(&frame); - }); + auto src_av_frame = create_frame(); - avcodec_get_frame_defaults(src_av_frame.get()); - - const auto sample_aspect_ratio = + const auto sample_aspect_ratio = boost::rational( - in_video_format_.square_width, + in_video_format_.square_width, in_video_format_.square_height) / boost::rational( - in_video_format_.width, + in_video_format_.width, in_video_format_.height); src_av_frame->format = AV_PIX_FMT_BGRA; @@ -899,31 +891,26 @@ private: src_av_frame->data, src_av_frame->linesize, frame_ptr.image_data().begin(), - static_cast(src_av_frame->format), - in_video_format_.width, - in_video_format_.height, + static_cast(src_av_frame->format), + in_video_format_.width, + in_video_format_.height, 1)); FF(av_buffersrc_add_frame( - video_graph_in_, + video_graph_in_, src_av_frame.get())); - } + } int ret = 0; while(ret >= 0) { - std::shared_ptr filt_frame( - av_frame_alloc(), - [](AVFrame* p) - { - av_frame_free(&p); - }); + auto filt_frame = create_frame(); ret = av_buffersink_get_frame( - video_graph_out_, + video_graph_out_, filt_frame.get()); - + video_encoder_executor_.begin_invoke([=] { if(ret == AVERROR_EOF) @@ -931,26 +918,26 @@ private: if(enc->codec->capabilities & CODEC_CAP_DELAY) { while(encode_av_frame( - *video_st_, + *video_st_, video_bitstream_filter_.get(), - avcodec_encode_video2, + avcodec_encode_video2, nullptr, token)) { boost::this_thread::yield(); // TODO: } - } + } } else if(ret != AVERROR(EAGAIN)) { FF_RET(ret, "av_buffersink_get_frame"); - - if (filt_frame->interlaced_frame) + + if (filt_frame->interlaced_frame) { if (enc->codec->id == AV_CODEC_ID_MJPEG) enc->field_order = filt_frame->top_field_first ? AV_FIELD_TT : AV_FIELD_BB; else enc->field_order = filt_frame->top_field_first ? AV_FIELD_TB : AV_FIELD_BT; - } + } else enc->field_order = AV_FIELD_PROGRESSIVE; @@ -958,12 +945,12 @@ private: if (!enc->me_threshold) filt_frame->pict_type = AV_PICTURE_TYPE_NONE; - + encode_av_frame( *video_st_, video_bitstream_filter_.get(), avcodec_encode_video2, - filt_frame, + filt_frame, token); boost::this_thread::yield(); // TODO: @@ -971,25 +958,18 @@ private: }); } } - + void encode_audio(core::const_frame frame_ptr, std::shared_ptr token) - { + { if(!audio_st_) return; - + auto enc = audio_st_->codec; - - std::shared_ptr src_av_frame; if(frame_ptr != core::const_frame::empty()) { - src_av_frame.reset( - av_frame_alloc(), - [](AVFrame* p) - { - av_frame_free(&p); - }); - + auto src_av_frame = create_frame(); + src_av_frame->channels = in_channel_layout_.num_channels; src_av_frame->channel_layout = av_get_default_channel_layout(in_channel_layout_.num_channels); src_av_frame->sample_rate = in_video_format_.audio_sample_rate; @@ -1007,9 +987,9 @@ private: src_av_frame->nb_samples, static_cast(src_av_frame->format), 16)); - + FF(av_buffersrc_add_frame( - audio_graph_in_, + audio_graph_in_, src_av_frame.get())); } @@ -1017,28 +997,23 @@ private: while(ret >= 0) { - std::shared_ptr filt_frame( - av_frame_alloc(), - [](AVFrame* p) - { - av_frame_free(&p); - }); + auto filt_frame = create_frame(); ret = av_buffersink_get_frame( - audio_graph_out_, + audio_graph_out_, filt_frame.get()); - + audio_encoder_executor_.begin_invoke([=] - { + { if(ret == AVERROR_EOF) { if(enc->codec->capabilities & CODEC_CAP_DELAY) { while(encode_av_frame( - *audio_st_, - audio_bitstream_filter_.get(), - avcodec_encode_audio2, - nullptr, + *audio_st_, + audio_bitstream_filter_.get(), + avcodec_encode_audio2, + nullptr, token)) { boost::this_thread::yield(); // TODO: @@ -1048,14 +1023,14 @@ private: else if(ret != AVERROR(EAGAIN)) { FF_RET( - ret, + ret, "av_buffersink_get_frame"); encode_av_frame( - *audio_st_, - audio_bitstream_filter_.get(), - avcodec_encode_audio2, - filt_frame, + *audio_st_, + audio_bitstream_filter_.get(), + avcodec_encode_audio2, + filt_frame, token); boost::this_thread::yield(); // TODO: @@ -1063,13 +1038,13 @@ private: }); } } - + template bool encode_av_frame( AVStream& st, - AVBitStreamFilterContext* bsfc, - const F& func, - const std::shared_ptr& src_av_frame, + AVBitStreamFilterContext* bsfc, + const F& func, + const std::shared_ptr& src_av_frame, std::shared_ptr token) { AVPacket pkt = {}; @@ -1078,16 +1053,16 @@ private: int got_packet = 0; FF(func( - st.codec, - &pkt, - src_av_frame.get(), + st.codec, + &pkt, + src_av_frame.get(), &got_packet)); - + if(!got_packet || pkt.size <= 0) return false; pkt.stream_index = st.index; - + if(bsfc) { auto new_pkt = pkt; @@ -1102,25 +1077,25 @@ private: pkt.size, pkt.flags & AV_PKT_FLAG_KEY); - if(a == 0 && new_pkt.data != pkt.data && new_pkt.destruct) + if(a == 0 && new_pkt.data != pkt.data && new_pkt.destruct) { auto t = reinterpret_cast(av_malloc(new_pkt.size + FF_INPUT_BUFFER_PADDING_SIZE)); - if(t) + if(t) { memcpy( - t, + t, new_pkt.data, new_pkt.size); memset( - t + new_pkt.size, - 0, + t + new_pkt.size, + 0, FF_INPUT_BUFFER_PADDING_SIZE); new_pkt.data = t; new_pkt.buf = nullptr; - } + } else a = AVERROR(ENOMEM); } @@ -1128,52 +1103,52 @@ private: av_free_packet(&pkt); FF_RET( - a, + a, "av_bitstream_filter_filter"); new_pkt.buf = av_buffer_create( - new_pkt.data, + new_pkt.data, new_pkt.size, - av_buffer_default_free, - nullptr, + av_buffer_default_free, + nullptr, 0); CASPAR_VERIFY(new_pkt.buf); pkt = new_pkt; } - + if (pkt.pts != AV_NOPTS_VALUE) { - pkt.pts = + pkt.pts = av_rescale_q( pkt.pts, - st.codec->time_base, + st.codec->time_base, st.time_base); } if (pkt.dts != AV_NOPTS_VALUE) { - pkt.dts = + pkt.dts = av_rescale_q( - pkt.dts, - st.codec->time_base, + pkt.dts, + st.codec->time_base, st.time_base); } - - pkt.duration = + + pkt.duration = static_cast( av_rescale_q( - pkt.duration, + pkt.duration, st.codec->time_base, st.time_base)); write_packet( std::shared_ptr( - new AVPacket(pkt), + new AVPacket(pkt), [](AVPacket* p) { - av_free_packet(p); + av_free_packet(p); delete p; }), token); @@ -1183,22 +1158,22 @@ private: void write_packet( const std::shared_ptr& pkt_ptr, std::shared_ptr token) - { + { write_executor_.begin_invoke([this, pkt_ptr, token]() mutable { FF(av_interleaved_write_frame( - oc_.get(), + oc_.get(), pkt_ptr.get())); - }); - } - + }); + } + template static boost::optional try_remove_arg( - std::map& options, + std::map& options, const boost::regex& expr) { for(auto it = options.begin(); it != options.end(); ++it) - { + { if(boost::regex_search(it->first, expr)) { auto arg = it->second; @@ -1209,22 +1184,22 @@ private: return boost::optional(); } - + static std::map remove_options( - std::map& options, + std::map& options, const boost::regex& expr) { std::map result; - + auto it = options.begin(); while(it != options.end()) - { + { boost::smatch what; if(boost::regex_search(it->first, what, expr)) { result[ - what.size() > 0 && what[1].matched - ? what[1].str() + what.size() > 0 && what[1].matched + ? what[1].str() : it->first] = it->second; it = options.erase(it); } @@ -1234,14 +1209,14 @@ private: return result; } - + static void to_dict(AVDictionary** dest, const std::map& c) - { + { for (const auto& entry : c) { av_dict_set( - dest, - entry.first.c_str(), + dest, + entry.first.c_str(), entry.second.c_str(), 0); } } @@ -1249,18 +1224,18 @@ private: static std::map to_map(AVDictionary* dict) { std::map result; - - for(auto t = dict + + for(auto t = dict ? av_dict_get( - dict, - "", - nullptr, - AV_DICT_IGNORE_SUFFIX) + dict, + "", + nullptr, + AV_DICT_IGNORE_SUFFIX) : nullptr; - t; + t; t = av_dict_get( - dict, - "", + dict, + "", t, AV_DICT_IGNORE_SUFFIX)) { @@ -1285,7 +1260,7 @@ void describe_streaming_consumer(core::help_sink& sink, const core::help_reposit spl::shared_ptr create_streaming_consumer( const std::vector& params, core::interaction_sink*) -{ +{ if (params.size() < 1 || (!boost::iequals(params.at(0), L"STREAM") && !boost::iequals(params.at(0), L"FILE"))) return core::frame_consumer::empty(); @@ -1298,9 +1273,9 @@ spl::shared_ptr create_streaming_consumer( spl::shared_ptr create_preconfigured_streaming_consumer( const boost::property_tree::wptree& ptree, core::interaction_sink*) -{ +{ return spl::make_shared( - u8(ptree_get(ptree, L"path")), + u8(ptree_get(ptree, L"path")), u8(ptree.get(L"args", L"")), false); }