+ static boost::regex prot_exp("^.+:.*" );
+
+ if(!boost::regex_match(
+ path_,
+ prot_exp))
+ {
+ if(!full_path_.is_complete())
+ {
+ full_path_ =
+ u8(
+ env::media_folder()) +
+ path_;
+ }
+
+ if(boost::filesystem::exists(full_path_))
+ boost::filesystem::remove(full_path_);
+
+ boost::filesystem::create_directories(full_path_.parent_path());
+ }
+
+ graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
+ graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));
+ graph_->set_text(print());
+ diagnostics::register_graph(graph_);
+
+ const auto oformat_name =
+ try_remove_arg<std::string>(
+ options_,
+ boost::regex("^f|format$"));
+
+ AVFormatContext* oc;
+
+ FF(avformat_alloc_output_context2(
+ &oc,
+ nullptr,
+ oformat_name && !oformat_name->empty() ? oformat_name->c_str() : nullptr,
+ full_path_.string().c_str()));
+
+ oc_.reset(
+ oc,
+ avformat_free_context);
+
+ CASPAR_VERIFY(oc_->oformat);
+
+ oc_->interrupt_callback.callback = ffmpeg_consumer::interrupt_cb;
+ 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 =
+ try_remove_arg<std::string>(
+ options_,
+ boost::regex("^c:v|codec:v|vcodec$"));
+
+ 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 =
+ try_remove_arg<std::string>(
+ options_,
+ boost::regex("^c:a|codec:a|acodec$"));
+
+ const auto audio_codec =
+ audio_codec_name
+ ? avcodec_find_encoder_by_name(audio_codec_name->c_str())
+ : (is_pcm_s24le_not_supported(*oc_)
+ ? avcodec_find_encoder(oc_->oformat->audio_codec)
+ : avcodec_find_encoder_by_name("pcm_s24le"));
+
+ if (!video_codec)
+ CASPAR_THROW_EXCEPTION(user_error() << msg_info(
+ "Failed to find video codec " + (video_codec_name
+ ? *video_codec_name
+ : "with id " + boost::lexical_cast<std::string>(
+ oc_->oformat->video_codec))));
+ if (!audio_codec)
+ CASPAR_THROW_EXCEPTION(user_error() << msg_info(
+ "Failed to find audio codec " + (audio_codec_name
+ ? *audio_codec_name
+ : "with id " + boost::lexical_cast<std::string>(
+ oc_->oformat->audio_codec))));
+
+ // Filters
+
+ {
+ configure_video_filters(
+ *video_codec,
+ try_remove_arg<std::string>(options_,
+ boost::regex("vf|f:v|filter:v")).get_value_or(""));
+
+ configure_audio_filters(
+ *audio_codec,
+ try_remove_arg<std::string>(options_,
+ boost::regex("af|f:a|filter:a")).get_value_or(""));
+ }
+
+ // Encoders
+
+ {
+ auto video_options = options_;
+ auto audio_options = options_;
+
+ video_st_ = open_encoder(
+ *video_codec,
+ video_options,
+ 0);
+
+ for (int i = 0; i < audio_filter_->get_num_output_pads(); ++i)
+ audio_sts_.push_back(open_encoder(
+ *audio_codec,
+ audio_options,
+ i));
+
+ auto it = options_.begin();
+ while(it != options_.end())
+ {
+ if(video_options.find(it->first) == video_options.end() || audio_options.find(it->first) == audio_options.end())
+ it = options_.erase(it);
+ else
+ ++it;
+ }
+ }
+
+ // Output
+ {
+ AVDictionary* av_opts = nullptr;
+
+ to_dict(
+ &av_opts,
+ std::move(options_));
+
+ CASPAR_SCOPE_EXIT
+ {
+ av_dict_free(&av_opts);
+ };
+
+ if (!(oc_->oformat->flags & AVFMT_NOFILE))
+ {
+ FF(avio_open2(
+ &oc_->pb,
+ full_path_.string().c_str(),
+ AVIO_FLAG_WRITE,
+ &oc_->interrupt_callback,
+ &av_opts));
+ }
+
+ FF(avformat_write_header(
+ oc_.get(),
+ &av_opts));
+
+ options_ = to_map(av_opts);
+ }
+
+ // Dump Info
+
+ av_dump_format(
+ oc_.get(),
+ 0,
+ oc_->filename,
+ 1);
+
+ for (const auto& option : options_)
+ {
+ CASPAR_LOG(warning)
+ << L"Invalid option: -"
+ << u16(option.first)
+ << L" "
+ << u16(option.second);
+ }