--- /dev/null
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <boost/array.hpp>
+#include <boost/algorithm/string/split.hpp>
+
+namespace caspar {
+
+template<size_t NUM>
+class software_version
+{
+ boost::array<int, NUM> numbers_;
+ std::string version_;
+public:
+ software_version(std::string version)
+ : version_(std::move(version))
+ {
+ std::fill(numbers_.begin(), numbers_.end(), 0);
+ std::vector<std::string> tokens;
+ boost::split(tokens, version_, boost::is_any_of("."));
+ auto num = std::min(NUM, tokens.size());
+
+ for (size_t i = 0; i < num; ++i)
+ {
+ try
+ {
+ numbers_[i] = boost::lexical_cast<int>(tokens[i]);
+ }
+ catch (const boost::bad_lexical_cast&)
+ {
+ return;
+ }
+ }
+ };
+
+ const std::string& to_string() const
+ {
+ return version_;
+ }
+
+ bool operator<(const software_version<NUM>& other) const
+ {
+ for (int i = 0; i < NUM; ++i)
+ {
+ int this_num = numbers_[i];
+ int other_num = other.numbers_[i];
+
+ if (this_num < other_num)
+ return true;
+ else if (this_num > other_num)
+ return false;
+ }
+
+ return false;
+ }
+};
+
+}
#include "decklink_consumer.h"
#include "../util/util.h"
+#include "../decklink.h"
#include "../decklink_api.h"
#include <common/cache_aligned_vector.h>
#include <common/timer.h>
#include <common/param.h>
+#include <common/software_version.h>
#include <tbb/concurrent_queue.h>
}
};
+template <typename Configuration>
void set_latency(
- const com_iface_ptr<IDeckLinkConfiguration_v10_2>& config,
+ const com_iface_ptr<Configuration>& config,
configuration::latency_t latency,
const std::wstring& print)
{
}
};
+template <typename Configuration>
struct key_video_context : public IDeckLinkVideoOutputCallback, boost::noncopyable
{
- const configuration config_;
- com_ptr<IDeckLink> decklink_ = get_device(config_.key_device_index());
- com_iface_ptr<IDeckLinkOutput> output_ = iface_cast<IDeckLinkOutput>(decklink_);
- com_iface_ptr<IDeckLinkKeyer> keyer_ = iface_cast<IDeckLinkKeyer>(decklink_);
- com_iface_ptr<IDeckLinkAttributes> attributes_ = iface_cast<IDeckLinkAttributes>(decklink_);
- com_iface_ptr<IDeckLinkConfiguration_v10_2> configuration_ = iface_cast<IDeckLinkConfiguration_v10_2>(decklink_);
- tbb::atomic<int64_t> current_presentation_delay_;
- tbb::atomic<int64_t> scheduled_frames_completed_;
+ const configuration config_;
+ com_ptr<IDeckLink> decklink_ = get_device(config_.key_device_index());
+ com_iface_ptr<IDeckLinkOutput> output_ = iface_cast<IDeckLinkOutput>(decklink_);
+ com_iface_ptr<IDeckLinkKeyer> keyer_ = iface_cast<IDeckLinkKeyer>(decklink_);
+ com_iface_ptr<IDeckLinkAttributes> attributes_ = iface_cast<IDeckLinkAttributes>(decklink_);
+ com_iface_ptr<Configuration> configuration_ = iface_cast<Configuration>(decklink_);
+ tbb::atomic<int64_t> current_presentation_delay_;
+ tbb::atomic<int64_t> scheduled_frames_completed_;
key_video_context(const configuration& config, const std::wstring& print)
: config_(config)
}
};
+template <typename Configuration>
struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable
{
const int channel_index_;
com_ptr<IDeckLink> decklink_ = get_device(config_.device_index);
com_iface_ptr<IDeckLinkOutput> output_ = iface_cast<IDeckLinkOutput>(decklink_);
- com_iface_ptr<IDeckLinkConfiguration_v10_2> configuration_ = iface_cast<IDeckLinkConfiguration_v10_2>(decklink_);
+ com_iface_ptr<Configuration> configuration_ = iface_cast<Configuration>(decklink_);
com_iface_ptr<IDeckLinkKeyer> keyer_ = iface_cast<IDeckLinkKeyer>(decklink_);
com_iface_ptr<IDeckLinkAttributes> attributes_ = iface_cast<IDeckLinkAttributes>(decklink_);
reference_signal_detector reference_signal_detector_ { output_ };
tbb::atomic<int64_t> current_presentation_delay_;
tbb::atomic<int64_t> scheduled_frames_completed_;
- std::unique_ptr<key_video_context> key_context_;
+ std::unique_ptr<key_video_context<Configuration>> key_context_;
public:
decklink_consumer(
audio_frame_buffer_.set_capacity((format_desc.fps > 50.0) ? 2 : 1);
if (config.keyer == configuration::keyer_t::external_separate_device_keyer)
- key_context_.reset(new key_video_context(config, print()));
+ key_context_.reset(new key_video_context<Configuration>(config, print()));
graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));
graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));
}
};
+template <typename Configuration>
struct decklink_consumer_proxy : public core::frame_consumer
{
- core::monitor::subject monitor_subject_;
- const configuration config_;
- std::unique_ptr<decklink_consumer> consumer_;
- core::video_format_desc format_desc_;
- executor executor_;
+ core::monitor::subject monitor_subject_;
+ const configuration config_;
+ std::unique_ptr<decklink_consumer<Configuration>> consumer_;
+ core::video_format_desc format_desc_;
+ executor executor_;
public:
decklink_consumer_proxy(const configuration& config)
executor_.invoke([=]
{
consumer_.reset();
- consumer_.reset(new decklink_consumer(config_, format_desc, channel_layout, channel_index));
+ consumer_.reset(new decklink_consumer<Configuration>(config_, format_desc, channel_layout, channel_index));
});
}
{
return monitor_subject_;
}
-};
+};
+
+const software_version<3>& get_driver_version()
+{
+ static software_version<3> version(u8(get_version()));
+
+ return version;
+}
+
+const software_version<3> get_new_configuration_api_version()
+{
+ static software_version<3> NEW_CONFIGURATION_API("10.2");
+
+ return NEW_CONFIGURATION_API;
+}
void describe_consumer(core::help_sink& sink, const core::help_repository& repo)
{
config.out_channel_layout = *found_layout;
}
- return spl::make_shared<decklink_consumer_proxy>(config);
+ bool old_configuration_api = get_driver_version() < get_new_configuration_api_version();
+
+ if (old_configuration_api)
+ return spl::make_shared<decklink_consumer_proxy<IDeckLinkConfiguration_v10_2>>(config);
+ else
+ return spl::make_shared<decklink_consumer_proxy<IDeckLinkConfiguration>>(config);
}
spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
config.embedded_audio = ptree.get(L"embedded-audio", config.embedded_audio);
config.base_buffer_depth = ptree.get(L"buffer-depth", config.base_buffer_depth);
- return spl::make_shared<decklink_consumer_proxy>(config);
+ bool old_configuration_api = get_driver_version() < get_new_configuration_api_version();
+
+ if (old_configuration_api)
+ return spl::make_shared<decklink_consumer_proxy<IDeckLinkConfiguration_v10_2>>(config);
+ else
+ return spl::make_shared<decklink_consumer_proxy<IDeckLinkConfiguration>>(config);
}
}}