X-Git-Url: https://git.sesse.net/?p=nageru;a=blobdiff_plain;f=decklink_capture.cpp;h=6dba068fca51108fcbfc3a55050efcc1223880ee;hp=92fd6ae296e567a402928bb3fd15a7e4f9300042;hb=4e3c52ba57c4552a969e71ccdefd9941ce8d6290;hpb=a0083c1e4712a6e9f7c468f0961b292cfd9b69b0 diff --git a/decklink_capture.cpp b/decklink_capture.cpp index 92fd6ae..6dba068 100644 --- a/decklink_capture.cpp +++ b/decklink_capture.cpp @@ -8,6 +8,7 @@ #ifdef __SSE2__ #include #endif +#include #include #include #include @@ -19,6 +20,8 @@ #include "bmusb/bmusb.h" #include "decklink_util.h" +#include "flags.h" +#include "v210_converter.h" #define FRAME_SIZE (8 << 20) // 8 MB. @@ -137,6 +140,18 @@ size_t memcpy_interleaved_fastpath(uint8_t *dest1, uint8_t *dest2, const uint8_t #endif // __SSE2__ +BMDPixelFormat pixel_format_to_bmd(PixelFormat pixel_format) +{ + switch (pixel_format) { + case PixelFormat_8BitYCbCr: + return bmdFormat8BitYUV; + case PixelFormat_10BitYCbCr: + return bmdFormat10BitYUV; + default: + assert(false); + } +} + } // namespace DeckLinkCapture::DeckLinkCapture(IDeckLink *card, int card_index) @@ -301,12 +316,25 @@ HRESULT STDMETHODCALLTYPE DeckLinkCapture::VideoInputFrameArrived( IDeckLinkAudioInputPacket *audio_frame) { if (!done_init) { + char thread_name[16]; + snprintf(thread_name, sizeof(thread_name), "DeckLink_C_%d", card_index); + pthread_setname_np(pthread_self(), thread_name); + + sched_param param; + memset(¶m, 0, sizeof(param)); + param.sched_priority = 1; + if (sched_setscheduler(0, SCHED_RR, ¶m) == -1) { + printf("couldn't set realtime priority for DeckLink thread: %s\n", strerror(errno)); + } + if (has_dequeue_callbacks) { dequeue_init_callback(); } done_init = true; } + steady_clock::time_point now = steady_clock::now(); + FrameAllocator::Frame current_video_frame, current_audio_frame; VideoFormat video_format; AudioFormat audio_format; @@ -320,40 +348,49 @@ HRESULT STDMETHODCALLTYPE DeckLinkCapture::VideoInputFrameArrived( if (video_frame) { video_format.has_signal = !(video_frame->GetFlags() & bmdFrameHasNoInputSource); - int width = video_frame->GetWidth(); - int height = video_frame->GetHeight(); + const int width = video_frame->GetWidth(); + const int height = video_frame->GetHeight(); const int stride = video_frame->GetRowBytes(); - assert(stride == width * 2); + const BMDPixelFormat format = video_frame->GetPixelFormat(); + assert(format == pixel_format_to_bmd(current_pixel_format)); + if (global_flags.ten_bit_input) { + assert(stride == int(v210Converter::get_v210_stride(width))); + } else { + assert(stride == width * 2); + } current_video_frame = video_frame_allocator->alloc_frame(); if (current_video_frame.data != nullptr) { const uint8_t *frame_bytes; video_frame->GetBytes((void **)&frame_bytes); + size_t num_bytes = stride * height; - uint8_t *data = current_video_frame.data; - uint8_t *data2 = current_video_frame.data2; - size_t num_bytes = width * height * 2; + if (current_video_frame.interleaved) { + uint8_t *data = current_video_frame.data; + uint8_t *data2 = current_video_frame.data2; #ifdef __SSE2__ - size_t consumed = memcpy_interleaved_fastpath(data, data2, frame_bytes, num_bytes); - frame_bytes += consumed; - data += consumed / 2; - data2 += consumed / 2; - if (num_bytes % 2) { - swap(data, data2); - } - current_video_frame.len += consumed; - num_bytes -= consumed; + size_t consumed = memcpy_interleaved_fastpath(data, data2, frame_bytes, num_bytes); + frame_bytes += consumed; + data += consumed / 2; + data2 += consumed / 2; + if (num_bytes % 2) { + swap(data, data2); + } + current_video_frame.len += consumed; + num_bytes -= consumed; #endif - if (num_bytes > 0) { - memcpy_interleaved(data, data2, frame_bytes, num_bytes); + if (num_bytes > 0) { + memcpy_interleaved(data, data2, frame_bytes, num_bytes); + } + } else { + memcpy(current_video_frame.data, frame_bytes, num_bytes); } current_video_frame.len += num_bytes; video_format.width = width; video_format.height = height; - - current_video_frame.received_timestamp = steady_clock::now(); + video_format.stride = stride; } } @@ -370,11 +407,12 @@ HRESULT STDMETHODCALLTYPE DeckLinkCapture::VideoInputFrameArrived( audio_format.bits_per_sample = 32; audio_format.num_channels = 2; - - current_audio_frame.received_timestamp = steady_clock::now(); } } + current_video_frame.received_timestamp = now; + current_audio_frame.received_timestamp = now; + if (current_video_frame.data != nullptr || current_audio_frame.data != nullptr) { // TODO: Put into a queue and put into a dequeue thread, if the // BlackMagic drivers don't already do that for us? @@ -404,7 +442,7 @@ void DeckLinkCapture::start_bm_capture() if (running) { return; } - if (input->EnableVideoInput(current_video_mode, bmdFormat8BitYUV, supports_autodetect ? bmdVideoInputEnableFormatDetection : 0) != S_OK) { + if (input->EnableVideoInput(current_video_mode, pixel_format_to_bmd(current_pixel_format), supports_autodetect ? bmdVideoInputEnableFormatDetection : 0) != S_OK) { fprintf(stderr, "Failed to set video mode 0x%04x for card %d\n", current_video_mode, card_index); exit(1); } @@ -443,28 +481,38 @@ void DeckLinkCapture::stop_dequeue_thread() void DeckLinkCapture::set_video_mode(uint32_t video_mode_id) { - if (input->PauseStreams() != S_OK) { - fprintf(stderr, "PauseStreams failed\n"); - exit(1); - } - if (input->FlushStreams() != S_OK) { - fprintf(stderr, "FlushStreams failed\n"); - exit(1); + if (running) { + if (input->PauseStreams() != S_OK) { + fprintf(stderr, "PauseStreams failed\n"); + exit(1); + } + if (input->FlushStreams() != S_OK) { + fprintf(stderr, "FlushStreams failed\n"); + exit(1); + } } set_video_mode_no_restart(video_mode_id); - if (input->StartStreams() != S_OK) { - fprintf(stderr, "StartStreams failed\n"); - exit(1); + if (running) { + if (input->StartStreams() != S_OK) { + fprintf(stderr, "StartStreams failed\n"); + exit(1); + } } } +void DeckLinkCapture::set_pixel_format(PixelFormat pixel_format) +{ + current_pixel_format = pixel_format; + set_video_mode(current_video_mode); +} + void DeckLinkCapture::set_video_mode_no_restart(uint32_t video_mode_id) { BMDDisplayModeSupport support; IDeckLinkDisplayMode *display_mode; - if (input->DoesSupportVideoMode(video_mode_id, bmdFormat8BitYUV, /*flags=*/0, &support, &display_mode)) { + if (input->DoesSupportVideoMode(video_mode_id, pixel_format_to_bmd(current_pixel_format), /*flags=*/0, &support, &display_mode)) { fprintf(stderr, "Failed to query display mode for card %d\n", card_index); exit(1); } @@ -482,7 +530,7 @@ void DeckLinkCapture::set_video_mode_no_restart(uint32_t video_mode_id) field_dominance = display_mode->GetFieldDominance(); if (running) { - if (input->EnableVideoInput(video_mode_id, bmdFormat8BitYUV, supports_autodetect ? bmdVideoInputEnableFormatDetection : 0) != S_OK) { + if (input->EnableVideoInput(video_mode_id, pixel_format_to_bmd(current_pixel_format), supports_autodetect ? bmdVideoInputEnableFormatDetection : 0) != S_OK) { fprintf(stderr, "Failed to set video mode 0x%04x for card %d\n", video_mode_id, card_index); exit(1); }