+int crc16(const std::string& str)
+{
+ boost::crc_16_type result;
+
+ result.process_bytes(str.data(), str.length());
+
+ return result.checksum();
+}
+
+struct ffmpeg_consumer_proxy : public core::frame_consumer
+{
+ const std::string path_;
+ const std::string options_;
+ const bool separate_key_;
+ const bool compatibility_mode_;
+ int consumer_index_offset_;
+
+ std::unique_ptr<ffmpeg_consumer> consumer_;
+ std::unique_ptr<ffmpeg_consumer> key_only_consumer_;
+
+public:
+
+ ffmpeg_consumer_proxy(const std::string& path, const std::string& options, bool separate_key, bool compatibility_mode)
+ : path_(path)
+ , options_(options)
+ , separate_key_(separate_key)
+ , compatibility_mode_(compatibility_mode)
+ , consumer_index_offset_(crc16(path))
+ {
+ }
+
+ void initialize(const core::video_format_desc& format_desc, const core::audio_channel_layout& channel_layout, int) override
+ {
+ if (consumer_)
+ CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Cannot reinitialize ffmpeg-consumer."));
+
+ consumer_.reset(new ffmpeg_consumer(path_, options_));
+ consumer_->initialize(format_desc, channel_layout);
+
+ if (separate_key_)
+ {
+ boost::filesystem::path fill_file(path_);
+ auto without_extension = u16(fill_file.parent_path().string() + "/" + fill_file.stem().string());
+ auto key_file = without_extension + L"_A" + u16(fill_file.extension().string());
+
+ key_only_consumer_.reset(new ffmpeg_consumer(u8(key_file), options_));
+ key_only_consumer_->initialize(format_desc, channel_layout);
+ }
+ }
+
+ int64_t presentation_frame_age_millis() const override
+ {
+ return consumer_ ? static_cast<int64_t>(consumer_->presentation_frame_age_millis()) : 0;
+ }
+
+ std::future<bool> send(core::const_frame frame) override
+ {
+ bool ready_for_frame = consumer_->ready_for_frame();
+
+ if (ready_for_frame && separate_key_)
+ ready_for_frame = ready_for_frame && key_only_consumer_->ready_for_frame();
+
+ if (ready_for_frame)
+ {
+ consumer_->send(frame);
+
+ if (separate_key_)
+ key_only_consumer_->send(frame.key_only());
+ }
+ else
+ {
+ consumer_->mark_dropped();
+
+ if (separate_key_)
+ key_only_consumer_->mark_dropped();
+ }
+
+ return make_ready_future(true);
+ }
+
+ std::wstring print() const override
+ {
+ return consumer_ ? consumer_->print() : L"[ffmpeg_consumer]";
+ }
+
+ std::wstring name() const override
+ {
+ return L"ffmpeg";
+ }
+
+ boost::property_tree::wptree info() const override
+ {
+ boost::property_tree::wptree info;
+ info.add(L"type", L"ffmpeg");
+ info.add(L"path", u16(path_));
+ info.add(L"separate_key", separate_key_);
+ return info;
+ }
+
+ bool has_synchronization_clock() const override
+ {
+ return false;
+ }
+
+ int buffer_depth() const override
+ {
+ return -1;
+ }
+
+ int index() const override
+ {
+ return compatibility_mode_ ? 200 : 100000 + consumer_index_offset_;
+ }
+
+ core::monitor::subject& monitor_output()
+ {
+ return consumer_->monitor_output();
+ }
+};
+
+}
+