decklink-out: preroll frames before StartScheduledPlayback, detect output format
This commit is contained in:
@@ -126,20 +126,6 @@ bool DeckLinkOutNode::open_device() {
|
|||||||
callback_ = std::make_unique<OutputCallback>(*this);
|
callback_ = std::make_unique<OutputCallback>(*this);
|
||||||
output_->SetScheduledFrameCompletionCallback(callback_.get());
|
output_->SetScheduledFrameCompletionCallback(callback_.get());
|
||||||
|
|
||||||
{
|
|
||||||
BMDDisplayMode actual_mode = bmdModeUnknown;
|
|
||||||
bool supported = false;
|
|
||||||
auto hr = output_->DoesSupportVideoMode(bmdVideoConnectionUnspecified, display_mode_, bmdFormat10BitYUV,
|
|
||||||
bmdNoVideoOutputConversion, bmdSupportedVideoModeDefault, &actual_mode, &supported);
|
|
||||||
if (hr == S_OK) {
|
|
||||||
spdlog::info("DeckLink-out: mode 0x{:x} V210 supported={} actual=0x{:x}",
|
|
||||||
static_cast<uint32_t>(display_mode_), supported, static_cast<uint32_t>(actual_mode));
|
|
||||||
if (!supported) {
|
|
||||||
spdlog::error("DeckLink-out: display mode not supported for V210 output");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output_->EnableVideoOutput(display_mode_, bmdVideoOutputFlagDefault) != S_OK) {
|
if (output_->EnableVideoOutput(display_mode_, bmdVideoOutputFlagDefault) != S_OK) {
|
||||||
spdlog::error("DeckLink-out: failed to enable video output");
|
spdlog::error("DeckLink-out: failed to enable video output");
|
||||||
return false;
|
return false;
|
||||||
@@ -171,6 +157,39 @@ bool DeckLinkOutNode::open_device() {
|
|||||||
is_interlaced_);
|
is_interlaced_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preroll_frames_ = 3;
|
||||||
|
for (int i = 0; i < preroll_frames_; ++i) {
|
||||||
|
IDeckLinkMutableVideoFrame* frame = nullptr;
|
||||||
|
int32_t out_row_bytes = out_width_ * 16 / 6;
|
||||||
|
if (output_->CreateVideoFrame(out_width_, out_height_, out_row_bytes,
|
||||||
|
bmdFormat10BitYUV, bmdFrameFlagDefault, &frame) != S_OK || !frame) {
|
||||||
|
out_row_bytes = out_width_ * 2;
|
||||||
|
if (output_->CreateVideoFrame(out_width_, out_height_, out_row_bytes,
|
||||||
|
bmdFormat8BitYUV, bmdFrameFlagDefault, &frame) != S_OK || !frame) {
|
||||||
|
spdlog::error("DeckLink-out: failed to create preroll frame");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
spdlog::info("DeckLink-out: using 8BitYUV output format");
|
||||||
|
output_format_ = bmdFormat8BitYUV;
|
||||||
|
} else {
|
||||||
|
output_format_ = bmdFormat10BitYUV;
|
||||||
|
}
|
||||||
|
IDeckLinkVideoBuffer* buf = nullptr;
|
||||||
|
if (frame->QueryInterface(IID_IDeckLinkVideoBuffer, (void**)&buf) == S_OK && buf) {
|
||||||
|
buf->StartAccess(bmdBufferAccessWrite);
|
||||||
|
void* dst = nullptr;
|
||||||
|
buf->GetBytes(&dst);
|
||||||
|
if (dst) {
|
||||||
|
std::memset(dst, 0, out_row_bytes * out_height_);
|
||||||
|
}
|
||||||
|
buf->EndAccess(bmdBufferAccessWrite);
|
||||||
|
buf->Release();
|
||||||
|
}
|
||||||
|
auto stream_time = i * frame_duration_;
|
||||||
|
output_->ScheduleVideoFrame(frame, stream_time, frame_duration_, time_scale_);
|
||||||
|
frame->Release();
|
||||||
|
}
|
||||||
|
|
||||||
if (output_->StartScheduledPlayback(0, time_scale_, 1.0) != S_OK) {
|
if (output_->StartScheduledPlayback(0, time_scale_, 1.0) != S_OK) {
|
||||||
spdlog::error("DeckLink-out: failed to start scheduled playback");
|
spdlog::error("DeckLink-out: failed to start scheduled playback");
|
||||||
return false;
|
return false;
|
||||||
@@ -201,24 +220,23 @@ void DeckLinkOutNode::schedule_frame(void* mxl_payload, long width, long height,
|
|||||||
if (!output_) return;
|
if (!output_) return;
|
||||||
|
|
||||||
int32_t out_row_bytes = 0;
|
int32_t out_row_bytes = 0;
|
||||||
HRESULT row_hr = output_->RowBytesForPixelFormat(bmdFormat10BitYUV, width, &out_row_bytes);
|
if (output_format_ == bmdFormat10BitYUV) {
|
||||||
if (row_hr != S_OK || out_row_bytes <= 0) {
|
if (output_->RowBytesForPixelFormat(bmdFormat10BitYUV, width, &out_row_bytes) != S_OK || out_row_bytes <= 0) {
|
||||||
spdlog::warn("DeckLink-out: RowBytesForPixelFormat failed hr=0x{:08x}", static_cast<uint32_t>(row_hr));
|
|
||||||
out_row_bytes = ((width + 5) / 6) * 16;
|
out_row_bytes = ((width + 5) / 6) * 16;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
out_row_bytes = width * 2;
|
||||||
|
}
|
||||||
|
|
||||||
IDeckLinkMutableVideoFrame* frame = nullptr;
|
IDeckLinkMutableVideoFrame* frame = nullptr;
|
||||||
HRESULT hr = output_->CreateVideoFrame(width, height, out_row_bytes, bmdFormat10BitYUV,
|
HRESULT hr = output_->CreateVideoFrame(width, height, out_row_bytes, output_format_,
|
||||||
bmdFrameFlagDefault, &frame);
|
bmdFrameFlagDefault, &frame);
|
||||||
if (hr != S_OK || !frame) {
|
if (hr != S_OK || !frame) {
|
||||||
if (create_fail_count_ < 5) {
|
if (create_fail_count_ < 5) {
|
||||||
spdlog::error("DeckLink-out: CreateVideoFrame {}x{} row_bytes={} fmt=V210 hr=0x{:08x}",
|
spdlog::error("DeckLink-out: CreateVideoFrame {}x{} row_bytes={} fmt=0x{:x} hr=0x{:08x}",
|
||||||
width, height, out_row_bytes, static_cast<uint32_t>(hr));
|
width, height, out_row_bytes, static_cast<uint32_t>(output_format_), static_cast<uint32_t>(hr));
|
||||||
create_fail_count_++;
|
create_fail_count_++;
|
||||||
}
|
}
|
||||||
if (create_fail_count_ == 5) {
|
|
||||||
spdlog::error("DeckLink-out: suppressing further CreateVideoFrame errors");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ private:
|
|||||||
IDeckLinkOutput* output_ = nullptr;
|
IDeckLinkOutput* output_ = nullptr;
|
||||||
BMDTimeValue frame_duration_ = 1000;
|
BMDTimeValue frame_duration_ = 1000;
|
||||||
BMDTimeScale time_scale_ = 50000;
|
BMDTimeScale time_scale_ = 50000;
|
||||||
|
BMDPixelFormat output_format_ = bmdFormat10BitYUV;
|
||||||
|
int preroll_frames_ = 3;
|
||||||
|
|
||||||
std::atomic<bool> playing_{false};
|
std::atomic<bool> playing_{false};
|
||||||
int create_fail_count_ = 0;
|
int create_fail_count_ = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user