bool DeckLinkOutput::set_device(IDeckLink *decklink)
{
+ if (decklink->QueryInterface(IID_IDeckLinkInput, (void**)&input) != S_OK) {
+ input = nullptr;
+ }
if (decklink->QueryInterface(IID_IDeckLinkOutput, (void**)&output) != S_OK) {
fprintf(stderr, "Warning: Card %u has no outputs\n", card_index);
return false;
if (video_modes.empty()) {
fprintf(stderr, "ERROR: No matching output modes for %dx%d found\n", width, height);
- exit(1);
+ abort();
}
should_quit.unquit();
IDeckLinkConfiguration *config = nullptr;
if (output->QueryInterface(IID_IDeckLinkConfiguration, (void**)&config) != S_OK) {
fprintf(stderr, "Failed to get configuration interface for output card\n");
- exit(1);
+ abort();
}
if (config->SetFlag(bmdDeckLinkConfigLowLatencyVideoOutput, true) != S_OK) {
fprintf(stderr, "Failed to set low latency output\n");
- exit(1);
+ abort();
}
if (config->SetInt(bmdDeckLinkConfigVideoOutputConnection, video_connection) != S_OK) {
fprintf(stderr, "Failed to set video output connection for card %u\n", card_index);
- exit(1);
+ abort();
}
if (config->SetFlag(bmdDeckLinkConfigUse1080pNotPsF, true) != S_OK) {
fprintf(stderr, "Failed to set PsF flag for card\n");
- exit(1);
+ abort();
}
if (config->SetFlag(bmdDeckLinkConfigSMPTELevelAOutput, true) != S_OK) {
// This affects at least some no-name SDI->HDMI converters.
if (output->DoesSupportVideoMode(mode, pixel_format, bmdVideoOutputFlagDefault,
&support, &display_mode) != S_OK) {
fprintf(stderr, "Couldn't ask for format support\n");
- exit(1);
+ abort();
}
if (support == bmdDisplayModeNotSupported) {
fprintf(stderr, "Requested display mode not supported\n");
- exit(1);
+ abort();
}
current_mode_flags = display_mode->GetFlags();
BMDTimeScale time_scale;
if (display_mode->GetFrameRate(&time_value, &time_scale) != S_OK) {
fprintf(stderr, "Couldn't get frame rate\n");
- exit(1);
+ abort();
}
metric_decklink_output_width_pixels = width;
display_mode->Release();
+ if (input != nullptr) {
+ if (input->DisableVideoInput() != S_OK) {
+ fprintf(stderr, "Warning: Failed to disable video input for card %d\n", card_index);
+ }
+ if (input->DisableAudioInput() != S_OK) {
+ fprintf(stderr, "Warning: Failed to disable audio input for card %d\n", card_index);
+ }
+ }
+
HRESULT result = output->EnableVideoOutput(mode, bmdVideoOutputFlagDefault);
if (result != S_OK) {
fprintf(stderr, "Couldn't enable output with error 0x%x\n", result);
- exit(1);
+ abort();
}
if (output->SetScheduledFrameCompletionCallback(this) != S_OK) {
fprintf(stderr, "Couldn't set callback\n");
- exit(1);
+ abort();
}
assert(OUTPUT_FREQUENCY == 48000);
if (output->EnableAudioOutput(bmdAudioSampleRate48kHz, bmdAudioSampleType32bitInteger, 2, bmdAudioOutputStreamTimestamped) != S_OK) {
fprintf(stderr, "Couldn't enable audio output\n");
- exit(1);
+ abort();
}
if (output->BeginAudioPreroll() != S_OK) {
fprintf(stderr, "Couldn't begin audio preroll\n");
- exit(1);
+ abort();
}
present_thread = thread([this]{
if (!make_current(context, this->surface)) {
printf("display=%p surface=%p context=%p curr=%p err=%d\n", eglGetCurrentDisplay(), this->surface, context, eglGetCurrentContext(),
eglGetError());
- exit(1);
+ abort();
}
present_thread_func();
delete_context(context);
frame_freelist.pop();
}
}
+
+ if (input != nullptr) {
+ input->Release();
+ input = nullptr;
+ }
+ if (output != nullptr) {
+ output->Release();
+ output = nullptr;
+ }
}
void DeckLinkOutput::send_frame(GLuint y_tex, GLuint cbcr_tex, YCbCrLumaCoefficients output_ycbcr_coefficients, const vector<RefCountedFrame> &input_frames, int64_t pts, int64_t duration)
HRESULT result = output->ScheduleAudioSamples(int_samples.get(), samples.size() / 2,
pts, TIMEBASE, &frames_written);
if (result != S_OK) {
- fprintf(stderr, "ScheduleAudioSamples(pts=%ld) failed (result=0x%08x)\n", pts, result);
+ fprintf(stderr, "ScheduleAudioSamples(pts=%" PRId64 ") failed (result=0x%08x)\n", pts, result);
} else {
if (frames_written != samples.size() / 2) {
- fprintf(stderr, "ScheduleAudioSamples() returned short write (%u/%ld)\n", frames_written, samples.size() / 2);
+ fprintf(stderr, "ScheduleAudioSamples() returned short write (%u/%zu)\n", frames_written, samples.size() / 2);
}
}
metric_decklink_output_scheduled_samples += samples.size() / 2;
if (!playback_started) {
if (output->EndAudioPreroll() != S_OK) {
fprintf(stderr, "Could not end audio preroll\n");
- exit(1); // TODO
+ abort(); // TODO
}
if (output->StartScheduledPlayback(base_pts, TIMEBASE, 1.0) != S_OK) {
fprintf(stderr, "Could not start playback\n");
- exit(1); // TODO
+ abort(); // TODO
}
playback_started = true;
}
++metric_decklink_output_completed_frames_completed;
break;
case bmdOutputFrameDisplayedLate:
- fprintf(stderr, "Output frame displayed late (pts=%ld)\n", frame->pts);
+ fprintf(stderr, "Output frame displayed late (pts=%" PRId64 ")\n", frame->pts);
fprintf(stderr, "Consider increasing --output-buffer-frames if this persists.\n");
++metric_decklink_output_completed_frames_late;
break;
case bmdOutputFrameDropped:
- fprintf(stderr, "Output frame was dropped (pts=%ld)\n", frame->pts);
+ fprintf(stderr, "Output frame was dropped (pts=%" PRId64 ")\n", frame->pts);
fprintf(stderr, "Consider increasing --output-buffer-frames if this persists.\n");
++metric_decklink_output_completed_frames_dropped;
break;
case bmdOutputFrameFlushed:
- fprintf(stderr, "Output frame was flushed (pts=%ld)\n", frame->pts);
+ fprintf(stderr, "Output frame was flushed (pts=%" PRId64 ")\n", frame->pts);
++metric_decklink_output_completed_frames_flushed;
break;
default: