7 #include "PlusConfigure.h" 11 #include "vtkIGSIOAccurateTimer.h" 17 #include <vtkImageAppendComponents.h> 18 #include <vtkImageExtractComponents.h> 19 #include <vtkImageImport.h> 20 #include <vtkObject.h> 32 class vtkPlusDeckLinkVideoSource::vtkInternal :
public vtkObject
36 vtkTypeMacro(vtkInternal, vtkObject);
42 : External(external) {}
44 virtual ~vtkInternal() {}
47 bool PreviousFrameValid =
false;
48 std::string DeviceName =
"";
49 FrameSizeType RequestedFrameSize = { 1920, 1080, 1 };
50 BMDPixelFormat RequestedPixelFormat = bmdFormatUnspecified;
51 BMDVideoConnection RequestedVideoConnection = bmdVideoConnectionUnspecified;
52 BMDDisplayMode RequestedDisplayMode = bmdModeUnknown;
54 IDeckLink* DeckLink =
nullptr;
55 IDeckLinkInput* DeckLinkInput =
nullptr;
56 IDeckLinkDisplayMode* DeckLinkDisplayMode =
nullptr;
57 IDeckLinkVideoConversion* DeckLinkVideoConversion =
nullptr;
61 unsigned char* RGBBytes =
nullptr;
62 unsigned char* GrayBytes =
nullptr;
64 std::atomic_bool COMInitialized =
false;
67 static vtkPlusDeckLinkVideoSource::vtkInternal*
New();
68 vtkInternal() : External(nullptr) {}
74 bool AreSame(
double a,
double b)
76 return std::abs(a -
b) < 0.0001;
80 bool InitCOM(std::atomic_bool& comInit)
86 HRESULT result = CoInitializeEx(NULL, COINIT_MULTITHREADED);
89 LOG_ERROR(
"Initialization of COM failed - result = " << std::hex << std::setw(8) << std::setfill(
'0') << result);
99 void ShutdownCOM(std::atomic_bool& comInit)
116 vtkPlusDeckLinkVideoSource::vtkPlusDeckLinkVideoSource::vtkInternal* vtkPlusDeckLinkVideoSource::vtkInternal::New(
vtkPlusDeckLinkVideoSource* _arg)
118 vtkPlusDeckLinkVideoSource::vtkInternal* result =
new vtkPlusDeckLinkVideoSource::vtkInternal();
119 result->InitializeObjectBase();
120 result->External = _arg;
127 , Internal(vtkInternal::New(this))
130 LOG_TRACE(
"vtkPlusDeckLinkVideoSource::vtkPlusDeckLinkVideoSource()");
139 LOG_TRACE(
"vtkPlusDeckLinkVideoSource::~vtkPlusDeckLinkVideoSource()");
141 if (this->Internal->DeckLinkDisplayMode !=
nullptr)
143 this->Internal->DeckLinkDisplayMode->Release();
145 if (this->Internal->DeckLinkInput !=
nullptr)
147 this->Internal->DeckLinkInput->Release();
149 if (this->Internal->DeckLink !=
nullptr)
151 this->Internal->DeckLink->Release();
154 ShutdownCOM(this->Internal->COMInitialized);
156 this->Internal->Delete();
157 this->Internal =
nullptr;
163 HRESULT result = E_NOINTERFACE;
174 if (iid == IID_IUnknown)
180 else if (iid == IID_IDeckLinkInputCallback)
182 *ppv = (IDeckLinkInputCallback*)
this;
203 if (newRefValue == 0)
215 LOG_TRACE(
"vtkPlusDeckLinkVideoSource::PrintSelf(ostream& os, vtkIndent indent)");
234 LOG_TRACE(
"vtkPlusDeckLinkVideoSource::ReadConfiguration");
238 XML_FIND_NESTED_ELEMENT_REQUIRED(dataSourcesElement, deviceConfig,
"DataSources");
241 XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_OPTIONAL(
int, DeviceIndex, devIndex, deviceConfig);
244 this->Internal->DeviceIndex = devIndex;
247 std::string devName(
"");
248 XML_READ_STRING_ATTRIBUTE_NONMEMBER_OPTIONAL(DeviceName, devName, deviceConfig);
249 if (!devName.empty())
251 this->Internal->DeviceName = devName;
254 int size[3] = {-1, -1, -1};
255 XML_READ_VECTOR_ATTRIBUTE_NONMEMBER_OPTIONAL(
int, 2, FrameSize, size, deviceConfig);
256 if (size[0] != -1 && size[1] != -1)
258 this->Internal->RequestedFrameSize[0] = static_cast<unsigned int>(size[0]);
259 this->Internal->RequestedFrameSize[1] = static_cast<unsigned int>(size[1]);
260 this->Internal->RequestedFrameSize[2] = 1;
263 std::string pixelFormat(
"");
264 XML_READ_STRING_ATTRIBUTE_NONMEMBER_OPTIONAL(PixelFormat, pixelFormat, deviceConfig);
265 if (!pixelFormat.empty())
268 if (this->Internal->RequestedPixelFormat == bmdFormatUnspecified)
270 LOG_ERROR(
"Unknown pixel format requested. Please see device page documentation for supported pixel formats.");
275 std::string videoConnection(
"");
276 XML_READ_STRING_ATTRIBUTE_NONMEMBER_OPTIONAL(VideoConnection, videoConnection, deviceConfig);
277 if (!videoConnection.empty())
280 if (this->Internal->RequestedVideoConnection == bmdVideoConnectionUnspecified)
282 LOG_ERROR(
"Unknown connection type requested. Please see device page documentation for supported connections.");
287 std::string displayMode(
"");
288 XML_READ_STRING_ATTRIBUTE_NONMEMBER_OPTIONAL(
DisplayMode, displayMode, deviceConfig);
289 if (!displayMode.empty())
292 if (this->Internal->RequestedDisplayMode == bmdModeUnknown)
294 LOG_ERROR(
"Unable to recognize requested display mode. Please see device documentation for valid entries.");
305 LOG_TRACE(
"vtkPlusDeckLinkVideoSource::WriteConfiguration");
313 LOG_TRACE(
"vtkPlusDeckLinkVideoSource::InternalConnect");
315 IDeckLink* deckLink(
nullptr);
316 IDeckLinkIterator* deckLinkIterator(
nullptr);
317 IDeckLinkInput* deckLinkInput(
nullptr);
318 IDeckLinkDisplayModeIterator* deckLinkDisplayModeIterator(
nullptr);
319 IDeckLinkDisplayMode* deckLinkDisplayMode(
nullptr);
322 if (!InitCOM(this->Internal->COMInitialized))
333 while (deckLinkIterator->Next(&deckLink) == S_OK)
335 if (this->Internal->DeviceIndex == -1 ||
count == this->Internal->DeviceIndex)
338 result = deckLink->QueryInterface(IID_IDeckLinkInput, (
void**)&deckLinkInput);
341 LOG_ERROR(
"Could not obtain the IDeckLinkInput interface - result = " << std::hex << std::setw(8) << std::setfill(
'0') << result);
345 if (deckLinkInput->GetDisplayModeIterator(&deckLinkDisplayModeIterator) != S_OK)
347 LOG_ERROR(
"Unable to iterate display modes. Cannot select input display mode.");
351 while (deckLinkDisplayModeIterator->Next(&deckLinkDisplayMode) == S_OK)
353 if (this->Internal->RequestedDisplayMode != bmdModeUnknown && deckLinkDisplayMode->GetDisplayMode() == this->Internal->RequestedDisplayMode)
356 if (deckLinkInput->DoesSupportVideoMode(this->Internal->RequestedVideoConnection, this->Internal->RequestedDisplayMode, this->Internal->RequestedPixelFormat, bmdSupportedVideoModeDefault, &supported) == S_OK && supported)
359 this->Internal->DeckLink = deckLink;
360 this->Internal->DeckLinkInput = deckLinkInput;
361 this->Internal->DeckLinkDisplayMode = deckLinkDisplayMode;
365 else if (this->Internal->RequestedDisplayMode == bmdModeUnknown)
367 BMDTimeValue frameDuration;
368 BMDTimeScale timeScale;
369 if (deckLinkDisplayMode->GetFrameRate(&frameDuration, &timeScale) != S_OK)
371 LOG_WARNING(
"Unable to retrieve frame rate for display mode. Skipping.");
375 double frameRate = (double)timeScale / (
double)frameDuration;
376 if (deckLinkDisplayMode->GetWidth() == this->Internal->RequestedFrameSize[0] &&
377 deckLinkDisplayMode->GetHeight() == this->Internal->RequestedFrameSize[1] &&
381 if (deckLinkInput->DoesSupportVideoMode(bmdVideoConnectionUnspecified, deckLinkDisplayMode->GetDisplayMode(), bmdFormatUnspecified, bmdSupportedVideoModeDefault, &supported) && supported)
384 this->Internal->DeckLink = deckLink;
385 this->Internal->DeckLinkInput = deckLinkInput;
386 this->Internal->DeckLinkDisplayMode = deckLinkDisplayMode;
391 deckLinkDisplayMode->Release();
394 deckLinkDisplayModeIterator->Release();
395 deckLinkInput->Release();
402 LOG_ERROR(
"Unable to locate requested capture parameters.")
405 if (deckLinkDisplayModeIterator)
407 deckLinkDisplayModeIterator->Release();
409 if (deckLinkIterator)
411 deckLinkIterator->Release();
414 if (this->Internal->DeckLinkInput)
417 BMDTimeValue frameDuration;
418 BMDTimeScale timeScale;
419 this->Internal->DeckLinkDisplayMode->GetFrameRate(&frameDuration, &timeScale);
422 source->SetInputFrameSize(this->Internal->RequestedFrameSize);
423 source->SetPixelType(VTK_UNSIGNED_CHAR);
425 if (
source->GetImageType() == US_IMG_RGB_COLOR)
427 source->SetNumberOfScalarComponents(3);
428 this->Internal->RGBBytes = (
unsigned char*)malloc(this->Internal->RequestedFrameSize[0] * this->Internal->RequestedFrameSize[1] * 3 *
sizeof(
unsigned char));
432 source->SetNumberOfScalarComponents(1);
433 this->Internal->GrayBytes = (
unsigned char*)malloc(this->Internal->RequestedFrameSize[0] * this->Internal->RequestedFrameSize[1] * 1 *
sizeof(
unsigned char));
436 this->Internal->DeckLinkInput->SetCallback(
this);
437 this->Internal->DeckLinkInput->SetScreenPreviewCallback(
nullptr);
438 this->Internal->DeckLinkInput->DisableAudioInput();
440 HRESULT res = this->Internal->DeckLinkInput->EnableVideoInput(this->Internal->DeckLinkDisplayMode->GetDisplayMode(), this->Internal->RequestedPixelFormat, bmdVideoInputFlagDefault);
443 LPTSTR errorMsgPtr = 0;
444 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, res, 0, (LPTSTR)&errorMsgPtr, 0, NULL);
445 LOG_ERROR(
"Unable to convert video frame: " << errorMsgPtr);
446 LocalFree(errorMsgPtr);
447 this->Internal->DeckLinkDisplayMode->Release();
448 this->Internal->DeckLinkDisplayMode =
nullptr;
449 this->Internal->DeckLinkInput->Release();
450 this->Internal->DeckLinkInput =
nullptr;
451 this->Internal->DeckLink->Release();
452 this->Internal->DeckLink =
nullptr;
456 this->Internal->OutputFrame =
new PlusOutputVideoFrame(this->Internal->DeckLinkDisplayMode->GetWidth(), this->Internal->DeckLinkDisplayMode->GetHeight(), bmdFormat8BitBGRA, bmdFrameFlagDefault);
465 LOG_TRACE(
"vtkPlusDeckLinkVideoSource::InternalDisconnect");
467 free(this->Internal->RGBBytes);
468 free(this->Internal->GrayBytes);
470 this->Internal->DeckLinkVideoConversion->Release();
471 this->Internal->DeckLinkVideoConversion =
nullptr;
473 if (this->Internal->OutputFrame !=
nullptr)
475 delete this->Internal->OutputFrame;
476 this->Internal->OutputFrame =
nullptr;
480 this->Internal->DeckLinkInput->SetScreenPreviewCallback(NULL);
481 this->Internal->DeckLinkInput->SetCallback(NULL);
483 if (this->Internal->DeckLinkDisplayMode !=
nullptr)
485 this->Internal->DeckLinkDisplayMode->Release();
486 this->Internal->DeckLinkDisplayMode =
nullptr;
488 if (this->Internal->DeckLinkInput !=
nullptr)
490 this->Internal->DeckLinkInput->Release();
491 this->Internal->DeckLinkInput =
nullptr;
493 if (this->Internal->DeckLink !=
nullptr)
495 this->Internal->DeckLink->Release();
496 this->Internal->DeckLink =
nullptr;
499 ShutdownCOM(this->Internal->COMInitialized);
507 LOG_TRACE(
"vtkPlusDeckLinkVideoSource::InternalStartRecording");
509 if (this->Internal->DeckLinkInput !=
nullptr)
511 if (this->Internal->DeckLinkInput->StartStreams() != S_OK)
527 LOG_TRACE(
"vtkPlusDeckLinkVideoSource::InternalStopRecording");
529 if (this->Internal->DeckLinkInput !=
nullptr)
531 if (this->Internal->DeckLinkInput->StopStreams() != S_OK)
547 LOG_TRACE(
"vtkPlusDeckLinkVideoSource::Probe");
549 bool comInit = this->Internal->COMInitialized;
550 if (!InitCOM(this->Internal->COMInitialized))
557 IDeckLink* deckLink(
nullptr);
559 if (deckLinkIterator ==
nullptr)
566 if (deckLinkIterator->Next(&deckLink) == S_OK)
573 ShutdownCOM(this->Internal->COMInitialized);
584 LOG_ERROR(
"DeckLinkVideoSource requires at least one video source. Please correct configuration file.");
590 LOG_ERROR(
"DeckLinkVideoSource requires at least one output channel. Please correct configuration file.");
613 this->Internal->OutputFrame->SetFlags(videoFrame->GetFlags());
615 bool inputFrameValid = ((videoFrame->GetFlags() & bmdFrameHasNoInputSource) == 0);
617 if (inputFrameValid && !this->Internal->PreviousFrameValid)
619 this->Internal->DeckLinkInput->StopStreams();
620 this->Internal->DeckLinkInput->FlushStreams();
621 this->Internal->DeckLinkInput->StartStreams();
626 HRESULT res = this->Internal->DeckLinkVideoConversion->ConvertFrame(videoFrame, this->Internal->OutputFrame);
629 LPTSTR errorMsgPtr = 0;
630 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, res, 0, (LPTSTR)&errorMsgPtr, 0, NULL);
631 LOG_ERROR(
"Unable to convert video frame: " << errorMsgPtr);
632 LocalFree(errorMsgPtr);
635 if (this->Internal->PreviousFrameValid && res == S_OK)
638 if (this->Internal->OutputFrame->GetBytes(&buffer) == S_OK)
643 if (
source->GetImageType() == US_IMG_RGB_COLOR)
646 PixelCodec::BGRA32ToRGB24(this->Internal->RequestedFrameSize[0], this->Internal->RequestedFrameSize[1], (
unsigned char*)buffer, this->Internal->RGBBytes);
650 PixelCodec::RGBA32ToGray(this->Internal->RequestedFrameSize[0], this->Internal->RequestedFrameSize[1], (
unsigned char*)buffer, this->Internal->GrayBytes);
653 if (
source->AddItem(
source->GetImageType() == US_IMG_RGB_COLOR ? this->Internal->RGBBytes : this->Internal->GrayBytes,
654 source->GetInputImageOrientation(),
655 this->Internal->RequestedFrameSize,
656 VTK_UNSIGNED_CHAR,
source->GetNumberOfScalarComponents(),
661 LOG_ERROR(
"Unable to add video item to buffer.");
669 this->Internal->PreviousFrameValid = inputFrameValid;
virtual PlusStatus InternalDisconnect()
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)
Abstract interface for tracker and video devices.
static void BGRA32ToRGB24(int width, int height, unsigned char *s, unsigned char *d)
static IDeckLinkIterator *BMD_PUBLIC CreateDeckLinkIterator()
virtual int GetNumberOfVideoSources() const
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
~vtkPlusDeckLinkVideoSource()
static BMDVideoConnection VideoConnectionFromString(const std::string &)
virtual PlusStatus InternalStopRecording()
virtual PlusStatus Probe()
virtual PlusStatus InternalStartRecording()
static IDeckLinkVideoConversion *BMD_PUBLIC CreateVideoConversion()
static void RGBA32ToGray(int width, int height, unsigned char *s, unsigned char *d)
Initial rotation matrix b
PlusStatus GetFirstVideoSource(vtkPlusDataSource *&anImage)
virtual PlusStatus InternalConnect()
virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioPacket)
virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents notificationEvents, IDeckLinkDisplayMode *newDisplayMode, BMDDetectedVideoInputFormatFlags detectedSignalFlags)
static vtkPlusDeckLinkVideoSource * New()
unsigned long FrameNumber
vtkStandardNewMacro(vtkPlusDeckLinkVideoSource)
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv)
virtual PlusStatus StopRecording()
virtual bool IsVirtual() const
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
void PrintSelf(ostream &os, vtkIndent indent)
Phidget_ChannelClass uint32_t * count
virtual bool IsRecording() const
bool StartThreadForInternalUpdates
static BMDDisplayMode DisplayModeFromString(const std::string &)
virtual ULONG STDMETHODCALLTYPE Release()
std::atomic< ULONG > ReferenceCount
static BMDPixelFormat PixelFormatFromString(const std::string &)
virtual ULONG STDMETHODCALLTYPE AddRef()
Interface to a BlackMagic DeckLink capture card.
virtual int OutputChannelCount() const
vtkPlusDeckLinkVideoSource()
virtual PlusStatus NotifyConfigured()
virtual bool IsTracker() const
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
Interface to a 3D positioning tool, video source, or generalized data stream.