#include <boost/lexical_cast.hpp>
#include <boost/circular_buffer.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/circular_buffer.hpp>
#include <boost/property_tree/ptree.hpp>
bool key_only = false;
int base_buffer_depth = 3;
core::audio_channel_layout out_channel_layout = core::audio_channel_layout::invalid();
bool key_only = false;
int base_buffer_depth = 3;
core::audio_channel_layout out_channel_layout = core::audio_channel_layout::invalid();
else if (FAILED(decklink_keyer->SetLevel(255)))
CASPAR_LOG(error) << print << L" Failed to set key-level to max.";
else
else if (FAILED(decklink_keyer->SetLevel(255)))
CASPAR_LOG(error) << print << L" Failed to set key-level to max.";
else
}
else if (keyer == configuration::keyer_t::external_keyer)
{
BOOL value = true;
if (SUCCEEDED(attributes->GetFlag(BMDDeckLinkSupportsExternalKeying, &value)) && !value)
}
else if (keyer == configuration::keyer_t::external_keyer)
{
BOOL value = true;
if (SUCCEEDED(attributes->GetFlag(BMDDeckLinkSupportsExternalKeying, &value)) && !value)
- CASPAR_LOG(error) << print << L" Failed to enable external keyer.";
- else if (FAILED(decklink_keyer->Enable(TRUE)))
- CASPAR_LOG(error) << print << L" Failed to enable external keyer.";
+ CASPAR_LOG(error) << print << L" Failed to enable external keyer.";
+ else if (FAILED(decklink_keyer->Enable(TRUE)))
+ CASPAR_LOG(error) << print << L" Failed to enable external keyer.";
else if (FAILED(decklink_keyer->SetLevel(255)))
CASPAR_LOG(error) << print << L" Failed to set key-level to max.";
else
else if (FAILED(decklink_keyer->SetLevel(255)))
CASPAR_LOG(error) << print << L" Failed to set key-level to max.";
else
virtual long STDMETHODCALLTYPE GetRowBytes() {return static_cast<long>(format_desc_.width*4);}
virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat() {return bmdFormat8BitBGRA;}
virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags() {return bmdFrameFlagDefault;}
virtual long STDMETHODCALLTYPE GetRowBytes() {return static_cast<long>(format_desc_.width*4);}
virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat() {return bmdFormat8BitBGRA;}
virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags() {return bmdFrameFlagDefault;}
virtual HRESULT STDMETHODCALLTYPE GetTimecode(BMDTimecodeFormat format, IDeckLinkTimecode** timecode) {return S_FALSE;}
virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary** ancillary) {return S_FALSE;}
virtual HRESULT STDMETHODCALLTYPE GetTimecode(BMDTimecodeFormat format, IDeckLinkTimecode** timecode) {return S_FALSE;}
virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary** ancillary) {return S_FALSE;}
template <typename Configuration>
struct decklink_consumer : public IDeckLinkVideoOutputCallback, boost::noncopyable
template <typename Configuration>
struct decklink_consumer : public IDeckLinkVideoOutputCallback, boost::noncopyable
const std::wstring model_name_ = get_model_name(decklink_);
bool will_attempt_dma_;
const core::video_format_desc format_desc_;
const std::wstring model_name_ = get_model_name(decklink_);
bool will_attempt_dma_;
const core::video_format_desc format_desc_;
boost::circular_buffer<std::vector<int32_t>> audio_container_ { buffer_size_ + 1 };
tbb::concurrent_bounded_queue<core::const_frame> frame_buffer_;
boost::circular_buffer<std::vector<int32_t>> audio_container_ { buffer_size_ + 1 };
tbb::concurrent_bounded_queue<core::const_frame> frame_buffer_;
std::packaged_task<bool ()> send_completion_;
reference_signal_detector reference_signal_detector_ { output_ };
tbb::atomic<int64_t> current_presentation_delay_;
std::packaged_task<bool ()> send_completion_;
reference_signal_detector reference_signal_detector_ { output_ };
tbb::atomic<int64_t> current_presentation_delay_;
const configuration& config,
const core::video_format_desc& format_desc,
const core::audio_channel_layout& in_channel_layout,
const configuration& config,
const core::video_format_desc& format_desc,
const core::audio_channel_layout& in_channel_layout,
: channel_index_(channel_index)
, config_(config)
, format_desc_(format_desc)
: channel_index_(channel_index)
, config_(config)
, format_desc_(format_desc)
frame_buffer_.set_capacity(1);
if (config.keyer == configuration::keyer_t::external_separate_device_keyer)
key_context_.reset(new key_video_context<Configuration>(config, print()));
frame_buffer_.set_capacity(1);
if (config.keyer == configuration::keyer_t::external_separate_device_keyer)
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("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f));
graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));
graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));
graph_->set_color("flushed-frame", diagnostics::color(0.4f, 0.3f, 0.8f));
graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));
graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));
graph_->set_color("flushed-frame", diagnostics::color(0.4f, 0.3f, 0.8f));
enable_video(get_display_mode(output_, format_desc_.format, bmdFormat8BitBGRA, bmdVideoOutputFlagDefault, will_attempt_dma_));
enable_video(get_display_mode(output_, format_desc_.format, bmdFormat8BitBGRA, bmdVideoOutputFlagDefault, will_attempt_dma_));
set_keyer(attributes_, keyer_, config.keyer, print());
if(config.embedded_audio)
set_keyer(attributes_, keyer_, config.keyer, print());
if(config.embedded_audio)
{
output_->StopScheduledPlayback(0, nullptr, 0);
if(config_.embedded_audio)
{
output_->StopScheduledPlayback(0, nullptr, 0);
if(config_.embedded_audio)
void enable_audio()
{
if(FAILED(output_->EnableAudioOutput(bmdAudioSampleRate48kHz, bmdAudioSampleType32bitInteger, out_channel_layout_.num_channels, bmdAudioOutputStreamTimestamped)))
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Could not enable audio output."));
void enable_audio()
{
if(FAILED(output_->EnableAudioOutput(bmdAudioSampleRate48kHz, bmdAudioSampleType32bitInteger, out_channel_layout_.num_channels, bmdAudioOutputStreamTimestamped)))
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Could not enable audio output."));
CASPAR_LOG(info) << print() << L" Enabled embedded-audio.";
}
void enable_video(BMDDisplayMode display_mode)
{
CASPAR_LOG(info) << print() << L" Enabled embedded-audio.";
}
void enable_video(BMDDisplayMode display_mode)
{
<< msg_info(print() + L" Failed to set fill playback completion callback.")
<< boost::errinfo_api_function("SetScheduledFrameCompletionCallback"));
<< msg_info(print() + L" Failed to set fill playback completion callback.")
<< boost::errinfo_api_function("SetScheduledFrameCompletionCallback"));
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to schedule fill playback."));
if (key_context_ && FAILED(key_context_->output_->StartScheduledPlayback(0, format_desc_.time_scale, 1.0)))
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to schedule key playback."));
}
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to schedule fill playback."));
if (key_context_ && FAILED(key_context_->output_->StartScheduledPlayback(0, format_desc_.time_scale, 1.0)))
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(print() + L" Failed to schedule key playback."));
}
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID*) {return E_NOINTERFACE;}
virtual ULONG STDMETHODCALLTYPE AddRef() {return 1;}
virtual ULONG STDMETHODCALLTYPE Release() {return 1;}
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID*) {return E_NOINTERFACE;}
virtual ULONG STDMETHODCALLTYPE AddRef() {return 1;}
virtual ULONG STDMETHODCALLTYPE Release() {return 1;}
send_completion_ = std::packaged_task<bool ()>([frame, this] () mutable -> bool
{
frame_buffer_.push(frame);
send_completion_ = std::packaged_task<bool ()>([frame, this] () mutable -> bool
{
frame_buffer_.push(frame);
std::wstring print() const
{
if (config_.keyer == configuration::keyer_t::external_separate_device_keyer)
std::wstring print() const
{
if (config_.keyer == configuration::keyer_t::external_separate_device_keyer)
void initialize(const core::video_format_desc& format_desc, const core::audio_channel_layout& channel_layout, int channel_index) override
{
format_desc_ = format_desc;
executor_.invoke([=]
{
consumer_.reset();
void initialize(const core::video_format_desc& format_desc, const core::audio_channel_layout& channel_layout, int channel_index) override
{
format_desc_ = format_desc;
executor_.invoke([=]
{
consumer_.reset();
- consumer_.reset(new decklink_consumer<Configuration>(config_, format_desc, channel_layout, channel_index));
+ consumer_.reset(new decklink_consumer<Configuration>(config_, format_desc, channel_layout, channel_index));
{
if (params.size() < 1 || !boost::iequals(params.at(0), L"DECKLINK"))
return core::frame_consumer::empty();
{
if (params.size() < 1 || !boost::iequals(params.at(0), L"DECKLINK"))
return core::frame_consumer::empty();
if (contains_param(L"INTERNAL_KEY", params))
config.keyer = configuration::keyer_t::internal_keyer;
else if (contains_param(L"EXTERNAL_KEY", params))
if (contains_param(L"INTERNAL_KEY", params))
config.keyer = configuration::keyer_t::internal_keyer;
else if (contains_param(L"EXTERNAL_KEY", params))
-Thanks for your inquiry. The minimum number of frames that you can preroll
-for scheduled playback is three frames for video and four frames for audio.
+Thanks for your inquiry. The minimum number of frames that you can preroll
+for scheduled playback is three frames for video and four frames for audio.
-playback will be very sporadic. From our experience with Media Express, we
-recommended that at least seven frames are prerolled for smooth playback.
+playback will be very sporadic. From our experience with Media Express, we
+recommended that at least seven frames are prerolled for smooth playback.
Regarding the bmdDeckLinkConfigLowLatencyVideoOutput flag:
There can be around 3 frames worth of latency on scheduled output.
When the bmdDeckLinkConfigLowLatencyVideoOutput flag is used this latency is
Regarding the bmdDeckLinkConfigLowLatencyVideoOutput flag:
There can be around 3 frames worth of latency on scheduled output.
When the bmdDeckLinkConfigLowLatencyVideoOutput flag is used this latency is
-reduced or removed for scheduled playback. If the DisplayVideoFrameSync()
-method is used, the bmdDeckLinkConfigLowLatencyVideoOutput setting will
-guarantee that the provided frame will be output as soon the previous
+reduced or removed for scheduled playback. If the DisplayVideoFrameSync()
+method is used, the bmdDeckLinkConfigLowLatencyVideoOutput setting will
+guarantee that the provided frame will be output as soon the previous
frame output has been completed.
################################################################################
*/
frame output has been completed.
################################################################################
*/
-Thanks for your inquiry. You could try subclassing IDeckLinkMutableVideoFrame
-and providing a pointer to your video buffer when GetBytes() is called.
-This may help to keep copying to a minimum. Please ensure that the pixel
-format is in bmdFormat10BitYUV, otherwise the DeckLink API / driver will
+Thanks for your inquiry. You could try subclassing IDeckLinkMutableVideoFrame
+and providing a pointer to your video buffer when GetBytes() is called.
+This may help to keep copying to a minimum. Please ensure that the pixel
+format is in bmdFormat10BitYUV, otherwise the DeckLink API / driver will
have to colourspace convert which may result in additional copying.
################################################################################
*/
have to colourspace convert which may result in additional copying.
################################################################################
*/