X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Fdecklink_output.cpp;h=4c478fdf8e667353ef5de338a6cbd82a20df878b;hb=e4037149c9a6fbbd6b3747cdbd0909c0ca3b6382;hp=56a184e99b326cc6ab3107c985f59bf0345bd384;hpb=c443b4ca0f527ed039d4b1014c1dd654c230eb15;p=nageru
diff --git a/nageru/decklink_output.cpp b/nageru/decklink_output.cpp
index 56a184e..4c478fd 100644
--- a/nageru/decklink_output.cpp
+++ b/nageru/decklink_output.cpp
@@ -131,10 +131,11 @@ bool DeckLinkOutput::set_device(IDeckLink *decklink, IDeckLinkInput *input_arg)
return true;
}
-void DeckLinkOutput::start_output(uint32_t mode, int64_t base_pts)
+void DeckLinkOutput::start_output(uint32_t mode, int64_t base_pts, bool is_master_card_arg)
{
assert(output);
assert(!playback_initiated);
+ this->is_master_card = is_master_card_arg;
if (video_modes.empty()) {
fprintf(stderr, "ERROR: No matching output modes for %dx%d found\n", width, height);
@@ -171,7 +172,7 @@ void DeckLinkOutput::start_output(uint32_t mode, int64_t base_pts)
BMDDisplayModeSupport support;
IDeckLinkDisplayMode *display_mode;
- BMDPixelFormat pixel_format = global_flags.ten_bit_output ? bmdFormat10BitYUV : bmdFormat8BitYUV;
+ BMDPixelFormat pixel_format = global_flags.bit_depth > 8 ? bmdFormat10BitYUV : bmdFormat8BitYUV;
if (output->DoesSupportVideoMode(mode, pixel_format, bmdVideoOutputFlagDefault,
&support, &display_mode) != S_OK) {
fprintf(stderr, "Couldn't ask for format support\n");
@@ -224,9 +225,13 @@ void DeckLinkOutput::start_output(uint32_t mode, int64_t base_pts)
fprintf(stderr, "Couldn't enable audio output\n");
abort();
}
- if (output->BeginAudioPreroll() != S_OK) {
- fprintf(stderr, "Couldn't begin audio preroll\n");
- abort();
+ if (is_master_card) {
+ if (output->BeginAudioPreroll() != S_OK) {
+ fprintf(stderr, "Couldn't begin audio preroll\n");
+ abort();
+ }
+ } else {
+ playback_started = true;
}
present_thread = thread([this]{
@@ -253,7 +258,9 @@ void DeckLinkOutput::end_output()
present_thread.join();
playback_initiated = false;
- output->StopScheduledPlayback(0, nullptr, 0);
+ if (is_master_card) {
+ output->StopScheduledPlayback(0, nullptr, 0);
+ }
output->DisableVideoOutput();
output->DisableAudioOutput();
@@ -290,7 +297,7 @@ void DeckLinkOutput::send_frame(GLuint y_tex, GLuint cbcr_tex, YCbCrLumaCoeffici
}
unique_ptr frame = get_frame();
- if (global_flags.ten_bit_output) {
+ if (global_flags.bit_depth > 8) {
chroma_subsampler->create_v210(y_tex, cbcr_tex, width, height, frame->uyvy_tex);
} else {
chroma_subsampler->create_uyvy(y_tex, cbcr_tex, width, height, frame->uyvy_tex);
@@ -303,7 +310,7 @@ void DeckLinkOutput::send_frame(GLuint y_tex, GLuint cbcr_tex, YCbCrLumaCoeffici
glBindBuffer(GL_PIXEL_PACK_BUFFER, frame->pbo);
check_error();
- if (global_flags.ten_bit_output) {
+ if (global_flags.bit_depth > 8) {
glBindTexture(GL_TEXTURE_2D, frame->uyvy_tex);
check_error();
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, BUFFER_OFFSET(0));
@@ -348,13 +355,20 @@ void DeckLinkOutput::send_audio(int64_t pts, const std::vector &samples)
}
uint32_t frames_written;
- HRESULT result = output->ScheduleAudioSamples(int_samples.get(), samples.size() / 2,
- pts, TIMEBASE, &frames_written);
+ HRESULT result;
+ if (is_master_card) {
+ result = output->ScheduleAudioSamples(int_samples.get(), samples.size() / 2,
+ pts, TIMEBASE, &frames_written);
+ } else {
+ result = output->WriteAudioSamplesSync(int_samples.get(), samples.size() / 2,
+ &frames_written);
+ }
if (result != S_OK) {
- fprintf(stderr, "ScheduleAudioSamples(pts=%" PRId64 ") failed (result=0x%08x)\n", pts, result);
+ fprintf(stderr, "write audio to DeckLink (pts=%" PRId64 ") failed (result=0x%08x)\n", pts, result);
} else {
- if (frames_written != samples.size() / 2) {
- fprintf(stderr, "ScheduleAudioSamples() returned short write (%u/%zu)\n", frames_written, samples.size() / 2);
+ // Non-master card is not really synchronized on audio at all, so we don't warn on it.
+ if (frames_written != samples.size() / 2 && is_master_card) {
+ fprintf(stderr, "write audio to DeckLink returned short write (%u/%zu)\n", frames_written, samples.size() / 2);
}
}
metric_decklink_output_scheduled_samples += samples.size() / 2;
@@ -526,7 +540,7 @@ unique_ptr DeckLinkOutput::get_frame()
unique_ptr frame(new Frame);
size_t stride;
- if (global_flags.ten_bit_output) {
+ if (global_flags.bit_depth > 8) {
stride = v210Converter::get_v210_stride(width);
GLint v210_width = stride / sizeof(uint32_t);
frame->uyvy_tex = resource_pool->create_2d_texture(GL_RGB10_A2, v210_width, height);
@@ -584,7 +598,7 @@ void DeckLinkOutput::present_thread_func()
check_error();
frame->fence.reset();
- if (global_flags.ten_bit_output) {
+ if (global_flags.bit_depth > 8) {
memcpy(frame->uyvy_ptr_local.get(), frame->uyvy_ptr, v210Converter::get_v210_stride(width) * height);
} else {
memcpy(frame->uyvy_ptr_local.get(), frame->uyvy_ptr, width * height * 2);
@@ -593,16 +607,24 @@ void DeckLinkOutput::present_thread_func()
// Release any input frames we needed to render this frame.
frame->input_frames.clear();
- BMDTimeValue pts = frame->pts;
- BMDTimeValue duration = frame->duration;
- HRESULT res = output->ScheduleVideoFrame(frame.get(), pts, duration, TIMEBASE);
- lock_guard lock(frame_queue_mutex);
- if (res == S_OK) {
- scheduled_frames.insert(frame.release()); // Owned by the driver now.
- ++metric_decklink_output_inflight_frames;
- } else {
- fprintf(stderr, "Could not schedule video frame! (error=0x%08x)\n", res);
+ if (is_master_card) {
+ BMDTimeValue pts = frame->pts;
+ BMDTimeValue duration = frame->duration;
+ HRESULT res = output->ScheduleVideoFrame(frame.get(), pts, duration, TIMEBASE);
+ lock_guard lock(frame_queue_mutex);
+ if (res == S_OK) {
+ scheduled_frames.insert(frame.release()); // Owned by the driver now.
+ ++metric_decklink_output_inflight_frames;
+ } else {
+ fprintf(stderr, "Could not schedule video frame! (error=0x%08x)\n", res);
+ frame_freelist.push(move(frame));
+ }
+ } else {
+ HRESULT res = output->DisplayVideoFrameSync(frame.get());
+ if (res != S_OK) {
+ fprintf(stderr, "Could not schedule video frame! (error=0x%08x)\n", res);
+ }
frame_freelist.push(move(frame));
}
}
@@ -670,7 +692,7 @@ long DeckLinkOutput::Frame::GetHeight()
long DeckLinkOutput::Frame::GetRowBytes()
{
- if (global_flags.ten_bit_output) {
+ if (global_flags.bit_depth > 8) {
return v210Converter::get_v210_stride(global_flags.width);
} else {
return global_flags.width * 2;
@@ -679,7 +701,7 @@ long DeckLinkOutput::Frame::GetRowBytes()
BMDPixelFormat DeckLinkOutput::Frame::GetPixelFormat()
{
- if (global_flags.ten_bit_output) {
+ if (global_flags.bit_depth > 8) {
return bmdFormat10BitYUV;
} else {
return bmdFormat8BitYUV;