2 ** Copyright (c) 2009 Blackmagic Design
4 ** Permission is hereby granted, free of charge, to any person or organization
5 ** obtaining a copy of the software and accompanying documentation covered by
6 ** this license (the "Software") to use, reproduce, display, distribute,
7 ** execute, and transmit the Software, and to prepare derivative works of the
8 ** Software, and to permit third-parties to whom the Software is furnished to
9 ** do so, all subject to the following:
11 ** The copyright notices in the Software and this entire statement, including
12 ** the above license grant, this restriction and the following disclaimer,
13 ** must be included in all copies of the Software, in whole or in part, and
14 ** all derivative works of the Software, unless such copies or derivative
15 ** works are solely in the form of machine-executable object code generated by
16 ** a source language processor.
18 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
21 ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
22 ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
23 ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 ** DEALINGS IN THE SOFTWARE.
39 #include <QPaintEvent>
43 #ifndef GL_TEXTURE_RECTANGLE_EXT
44 #define GL_TEXTURE_RECTANGLE_EXT GL_TEXTURE_RECTANGLE_NV
50 #include "kdenlivesettings.h"
52 pthread_mutex_t sleepMutex;
53 pthread_cond_t sleepCond;
54 int videoOutputFile = -1;
55 int audioOutputFile = -1;
57 static BMDTimecodeFormat g_timecodeFormat = 0;
58 static int g_videoModeIndex = -1;
59 static int g_audioChannels = 2;
60 static int g_audioSampleDepth = 16;
61 const char * g_videoOutputFile = NULL;
62 const char * g_audioOutputFile = NULL;
63 static int g_maxFrames = -1;
64 static QString doCaptureFrame;
65 static double g_aspect_ratio = 16.0 / 9.0;
67 static unsigned long frameCount = 0;
69 void yuv2rgb_int(unsigned char *yuv_buffer, unsigned char *rgb_buffer, int width, int height)
81 for (t=0; t<len; t++) /* process 2 pixels at a time */
83 /* Compute parts of the UV components */
85 U = yuv_buffer[y_ptr];
86 Y = yuv_buffer[y_ptr+1];
87 V = yuv_buffer[y_ptr+2];
88 Y2 = yuv_buffer[y_ptr+3];
92 /*r = 1.164*(Y-16) + 1.596*(V-128);
93 g = 1.164*(Y-16) - 0.813*(V-128) - 0.391*(U-128);
94 b = 1.164*(Y-16) + 2.018*(U-128);*/
97 r = (( 298*(Y-16) + 409*(V-128) + 128) >> 8);
99 g = (( 298*(Y-16) - 100*(U-128) - 208*(V-128) + 128) >> 8);
101 b = (( 298*(Y-16) + 516*(U-128) + 128) >> 8);
111 rgb_buffer[rgb_ptr]=b;
112 rgb_buffer[rgb_ptr+1]=g;
113 rgb_buffer[rgb_ptr+2]=r;
114 rgb_buffer[rgb_ptr+3]=255;
117 /*r = 1.164*(Y2-16) + 1.596*(V-128);
118 g = 1.164*(Y2-16) - 0.813*(V-128) - 0.391*(U-128);
119 b = 1.164*(Y2-16) + 2.018*(U-128);*/
122 r = (( 298*(Y2-16) + 409*(V-128) + 128) >> 8);
124 g = (( 298*(Y2-16) - 100*(U-128) - 208*(V-128) + 128) >> 8);
126 b = (( 298*(Y2-16) + 516*(U-128) + 128) >> 8);
136 rgb_buffer[rgb_ptr]=b;
137 rgb_buffer[rgb_ptr+1]=g;
138 rgb_buffer[rgb_ptr+2]=r;
139 rgb_buffer[rgb_ptr+3]=255;
145 class CDeckLinkGLWidget : public QGLWidget, public IDeckLinkScreenPreviewCallback
150 IDeckLinkInput* deckLinkIn;
151 IDeckLinkGLScreenPreviewHelper* deckLinkScreenPreviewHelper;
152 IDeckLinkVideoFrame* m_frame;
153 QColor m_backgroundColor;
160 bool m_transparentOverlay;
163 CDeckLinkGLWidget(IDeckLinkInput* deckLinkInput, QWidget* parent);
164 // IDeckLinkScreenPreviewCallback
165 virtual HRESULT QueryInterface(REFIID iid, LPVOID *ppv);
166 virtual ULONG AddRef();
167 virtual ULONG Release();
168 virtual HRESULT DrawFrame(IDeckLinkVideoFrame* theFrame);
169 void showOverlay(QImage img, bool transparent);
175 void resizeGL(int width, int height);
176 /*void initializeOverlayGL();
177 void paintOverlayGL();
178 void resizeOverlayGL(int width, int height);*/
181 CDeckLinkGLWidget::CDeckLinkGLWidget(IDeckLinkInput* deckLinkInput, QWidget* parent) : QGLWidget(/*QGLFormat(QGL::HasOverlay | QGL::AlphaChannel),*/ parent)
182 , m_backgroundColor(KdenliveSettings::window_background())
185 , m_transparentOverlay(true)
188 deckLinkIn = deckLinkInput;
189 deckLinkScreenPreviewHelper = CreateOpenGLScreenPreviewHelper();
192 void CDeckLinkGLWidget::showOverlay(QImage img, bool transparent)
194 m_transparentOverlay = transparent;
195 m_img = convertToGLFormat(img);
196 m_zx = (double)m_pictureWidth / m_img.width();
197 m_zy = (double)m_pictureHeight / m_img.height();
198 if (m_transparentOverlay) {
200 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_COLOR);
207 void CDeckLinkGLWidget::hideOverlay()
213 void CDeckLinkGLWidget::initializeGL ()
215 if (deckLinkScreenPreviewHelper != NULL)
218 deckLinkScreenPreviewHelper->InitializeGL();
219 glShadeModel(GL_FLAT);
220 glDisable(GL_DEPTH_TEST);
221 glDisable(GL_CULL_FACE);
222 glDisable(GL_LIGHTING);
223 glDisable(GL_DITHER);
226 //Documents/images/alpha2.png");//
227 //m_texture = bindTexture(convertToGLFormat(img), GL_TEXTURE_RECTANGLE_EXT, GL_RGBA8, QGLContext::LinearFilteringBindOption);
232 /*void CDeckLinkGLWidget::initializeOverlayGL ()
235 glEnable(GL_TEXTURE_RECTANGLE_EXT);
239 void CDeckLinkGLWidget::paintOverlayGL()
241 makeOverlayCurrent();
243 //glClearDepth(0.5f);
244 //glPixelTransferf(GL_ALPHA_SCALE, 10);
245 //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
250 void CDeckLinkGLWidget::paintGL ()
254 qglClearColor(m_backgroundColor);
255 //glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
256 glClear(GL_COLOR_BUFFER_BIT);
257 deckLinkScreenPreviewHelper->PaintGL();
258 if (!m_img.isNull()) {
259 glPixelZoom(m_zx, m_zy);
260 glDrawPixels(m_img.width(), m_img.height(), GL_RGBA, GL_UNSIGNED_BYTE, m_img.bits());
265 void CDeckLinkGLWidget::paintEvent(QPaintEvent *event)
269 QRect r = event->rect();
272 m_frame->GetBytes(&frameBytes);
273 QImage img((uchar*)frameBytes, m_frame->GetWidth(), m_frame->GetHeight(), QImage::Format_ARGB32);//m_frame->GetPixelFormat());
274 QRectF re(0, 0, width(), height());
275 p.drawImage(re, img);
280 void CDeckLinkGLWidget::resizeGL (int width, int height)
283 m_pictureHeight = height;
284 m_pictureWidth = width;
285 int calculatedWidth = g_aspect_ratio * height;
286 if (calculatedWidth > width) m_pictureHeight = width / g_aspect_ratio;
288 int calculatedHeight = width / g_aspect_ratio;
289 if (calculatedHeight > height) m_pictureWidth = height * g_aspect_ratio;
291 glViewport((width - m_pictureWidth) / 2, (height - m_pictureHeight) / 2, m_pictureWidth, m_pictureHeight);
292 glMatrixMode(GL_PROJECTION);
294 glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
295 glMatrixMode(GL_MODELVIEW);
296 glRasterPos2i(-1, -1);
297 if (!m_img.isNull()) {
298 m_zx = (double)m_pictureWidth / m_img.width();
299 m_zy = (double)m_pictureHeight / m_img.height();
305 /*void CDeckLinkGLWidget::resizeOverlayGL ( int width, int height )
307 int newwidth = width;
308 int newheight = height;
309 int calculatedWidth = g_aspect_ratio * height;
310 if (calculatedWidth > width) newheight = width / g_aspect_ratio;
312 int calculatedHeight = width / g_aspect_ratio;
313 if (calculatedHeight > height) newwidth = height * g_aspect_ratio;
315 glViewport((width - newwidth) / 2, (height - newheight) / 2, newwidth, newheight);
316 glMatrixMode(GL_PROJECTION);
318 glOrtho(0, width, 0, height, -1.0, 1.0);
319 glMatrixMode(GL_MODELVIEW);
323 HRESULT CDeckLinkGLWidget::QueryInterface (REFIID iid, LPVOID *ppv)
327 return E_NOINTERFACE;
330 ULONG CDeckLinkGLWidget::AddRef ()
334 oldValue = refCount.fetchAndAddAcquire(1);
335 return (ULONG)(oldValue + 1);
338 ULONG CDeckLinkGLWidget::Release ()
342 oldValue = refCount.fetchAndAddAcquire(-1);
348 return (ULONG)(oldValue - 1);
351 HRESULT CDeckLinkGLWidget::DrawFrame (IDeckLinkVideoFrame* theFrame)
353 if (deckLinkScreenPreviewHelper != NULL && theFrame != NULL)
358 deckLinkScreenPreviewHelper->SetFrame(theFrame);
365 DeckLinkCaptureDelegate::DeckLinkCaptureDelegate() : m_refCount(0)
367 pthread_mutex_init(&m_mutex, NULL);
370 DeckLinkCaptureDelegate::~DeckLinkCaptureDelegate()
372 pthread_mutex_destroy(&m_mutex);
375 ULONG DeckLinkCaptureDelegate::AddRef(void)
377 pthread_mutex_lock(&m_mutex);
379 pthread_mutex_unlock(&m_mutex);
381 return (ULONG)m_refCount;
384 ULONG DeckLinkCaptureDelegate::Release(void)
386 pthread_mutex_lock(&m_mutex);
388 pthread_mutex_unlock(&m_mutex);
396 return (ULONG)m_refCount;
399 HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame)
401 IDeckLinkVideoFrame* rightEyeFrame = NULL;
402 IDeckLinkVideoFrame3DExtensions* threeDExtensions = NULL;
404 void* audioFrameBytes;
406 // Handle Video Frame
409 // If 3D mode is enabled we retreive the 3D extensions interface which gives.
410 // us access to the right eye frame by calling GetFrameForRightEye() .
411 if ( (videoFrame->QueryInterface(IID_IDeckLinkVideoFrame3DExtensions, (void **) &threeDExtensions) != S_OK) ||
412 (threeDExtensions->GetFrameForRightEye(&rightEyeFrame) != S_OK))
414 rightEyeFrame = NULL;
417 if (videoFrame->GetFlags() & bmdFrameHasNoInputSource)
419 fprintf(stderr, "Frame received (#%lu) - No input signal detected\n", frameCount);
423 const char *timecodeString = NULL;
424 if (g_timecodeFormat != 0)
426 IDeckLinkTimecode *timecode;
427 if (videoFrame->GetTimecode(g_timecodeFormat, &timecode) == S_OK)
429 timecode->GetString(&timecodeString);
433 /*fprintf(stderr, "Frame received (#%lu) [%s] - %s - Size: %li bytes\n",
435 timecodeString != NULL ? timecodeString : "No timecode",
436 rightEyeFrame != NULL ? "Valid Frame (3D left/right)" : "Valid Frame",
437 videoFrame->GetRowBytes() * videoFrame->GetHeight());*/
440 free((void*)timecodeString);
442 if (!doCaptureFrame.isEmpty()) {
443 videoFrame->GetBytes(&frameBytes);
444 if (doCaptureFrame.endsWith("raw")) {
445 // Save as raw uyvy422 imgage
446 videoOutputFile = open(doCaptureFrame.toUtf8().constData(), O_WRONLY|O_CREAT/*|O_TRUNC*/, 0664);
447 write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());
448 close(videoOutputFile);
451 QImage image(videoFrame->GetWidth(), videoFrame->GetHeight(), QImage::Format_ARGB32_Premultiplied);
452 //convert from uyvy422 to rgba
453 yuv2rgb_int((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight());
454 image.save(doCaptureFrame);
456 doCaptureFrame.clear();
459 if (videoOutputFile != -1)
461 videoFrame->GetBytes(&frameBytes);
462 write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());
466 rightEyeFrame->GetBytes(&frameBytes);
467 write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());
473 if (g_maxFrames > 0 && frameCount >= g_maxFrames)
475 pthread_cond_signal(&sleepCond);
479 // Handle Audio Frame
482 if (audioOutputFile != -1)
484 audioFrame->GetBytes(&audioFrameBytes);
485 write(audioOutputFile, audioFrameBytes, audioFrame->GetSampleFrameCount() * g_audioChannels * (g_audioSampleDepth / 8));
491 HRESULT DeckLinkCaptureDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, BMDDetectedVideoInputFormatFlags)
498 /*int usage(int status)
501 IDeckLinkDisplayMode *displayMode;
502 int displayModeCount = 0;
505 "Usage: Capture -m <mode id> [OPTIONS]\n"
510 while (displayModeIterator->Next(&displayMode) == S_OK)
512 char * displayModeString = NULL;
514 result = displayMode->GetName((const char **) &displayModeString);
517 BMDTimeValue frameRateDuration, frameRateScale;
518 displayMode->GetFrameRate(&frameRateDuration, &frameRateScale);
520 fprintf(stderr, " %2d: %-20s \t %li x %li \t %g FPS\n",
521 displayModeCount, displayModeString, displayMode->GetWidth(), displayMode->GetHeight(), (double)frameRateScale / (double)frameRateDuration);
523 free(displayModeString);
527 // Release the IDeckLinkDisplayMode object to prevent a leak
528 displayMode->Release();
532 " -p <pixelformat>\n"
533 " 0: 8 bit YUV (4:2:2) (default)\n"
534 " 1: 10 bit YUV (4:2:2)\n"
535 " 2: 10 bit RGB (4:4:4)\n"
536 " -t <format> Print timecode\n"
539 " serial: Serial Timecode\n"
540 " -f <filename> Filename raw video will be written to\n"
541 " -a <filename> Filename raw audio will be written to\n"
542 " -c <channels> Audio Channels (2, 8 or 16 - default is 2)\n"
543 " -s <depth> Audio Sample Depth (16 or 32 - default is 16)\n"
544 " -n <frames> Number of frames to capture (default is unlimited)\n"
545 " -3 Capture Stereoscopic 3D (Requires 3D Hardware support)\n"
547 "Capture video and/or audio to a file. Raw video and/or audio can be viewed with mplayer eg:\n"
549 " Capture -m2 -n 50 -f video.raw -a audio.raw\n"
550 " mplayer video.raw -demuxer rawvideo -rawvideo pal:uyvy -audiofile audio.raw -audio-demuxer 20 -rawaudio rate=48000\n"
560 CaptureHandler::CaptureHandler(QVBoxLayout *lay, QWidget *parent):
562 deckLinkIterator(NULL),
567 displayModeIterator(NULL),
573 void CaptureHandler::startPreview(int deviceId, int captureMode)
575 deckLinkIterator = CreateDeckLinkIteratorInstance();
576 BMDVideoInputFlags inputFlags = 0;
577 BMDDisplayMode selectedDisplayMode = bmdModeNTSC;
578 BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
579 int displayModeCount = 0;
582 bool foundDisplayMode = false;
585 /*pthread_mutex_init(&sleepMutex, NULL);
586 pthread_cond_init(&sleepCond, NULL);*/
587 kDebug()<<"/// INIT CAPTURE ON DEV: "<<deviceId;
589 if (!deckLinkIterator)
591 fprintf(stderr, "This application requires the DeckLink drivers installed.\n");
596 /* Connect to selected DeckLink instance */
597 for (int i = 0; i < deviceId + 1; i++)
598 result = deckLinkIterator->Next(&deckLink);
601 fprintf(stderr, "No DeckLink PCI cards found.\n");
606 if (deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&deckLinkInput) != S_OK)
612 delegate = new DeckLinkCaptureDelegate();
613 deckLinkInput->SetCallback(delegate);
615 previewView = new CDeckLinkGLWidget(deckLinkInput, m_parent);
616 m_layout->addWidget(previewView);
617 //previewView->resize(parent->size());
618 previewView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
619 previewView->DrawFrame(NULL);
621 // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on output
622 result = deckLinkInput->GetDisplayModeIterator(&displayModeIterator);
625 fprintf(stderr, "Could not obtain the video output display mode iterator - result = %08x\n", result);
630 g_videoModeIndex = captureMode;
631 /*g_audioChannels = 2;
632 g_audioSampleDepth = 16;*/
634 // Parse command line options
635 /*while ((ch = getopt(argc, argv, "?h3c:s:f:a:m:n:p:t:")) != -1)
640 g_videoModeIndex = atoi(optarg);
643 g_audioChannels = atoi(optarg);
644 if (g_audioChannels != 2 &&
645 g_audioChannels != 8 &&
646 g_audioChannels != 16)
648 fprintf(stderr, "Invalid argument: Audio Channels must be either 2, 8 or 16\n");
653 g_audioSampleDepth = atoi(optarg);
654 if (g_audioSampleDepth != 16 && g_audioSampleDepth != 32)
656 fprintf(stderr, "Invalid argument: Audio Sample Depth must be either 16 bits or 32 bits\n");
661 g_videoOutputFile = optarg;
664 g_audioOutputFile = optarg;
667 g_maxFrames = atoi(optarg);
670 inputFlags |= bmdVideoInputDualStream3D;
675 case 0: pixelFormat = bmdFormat8BitYUV; break;
676 case 1: pixelFormat = bmdFormat10BitYUV; break;
677 case 2: pixelFormat = bmdFormat10BitRGB; break;
679 fprintf(stderr, "Invalid argument: Pixel format %d is not valid", atoi(optarg));
684 if (!strcmp(optarg, "rp188"))
685 g_timecodeFormat = bmdTimecodeRP188;
686 else if (!strcmp(optarg, "vitc"))
687 g_timecodeFormat = bmdTimecodeVITC;
688 else if (!strcmp(optarg, "serial"))
689 g_timecodeFormat = bmdTimecodeSerial;
692 fprintf(stderr, "Invalid argument: Timecode format \"%s\" is invalid\n", optarg);
702 if (g_videoModeIndex < 0)
704 fprintf(stderr, "No video mode specified\n");
708 //g_videoOutputFile="/home/one/bm.raw";
709 if (g_videoOutputFile != NULL)
711 videoOutputFile = open(g_videoOutputFile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
712 if (videoOutputFile < 0)
714 fprintf(stderr, "Could not open video output file \"%s\"\n", g_videoOutputFile);
718 if (g_audioOutputFile != NULL)
720 audioOutputFile = open(g_audioOutputFile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
721 if (audioOutputFile < 0)
723 fprintf(stderr, "Could not open audio output file \"%s\"\n", g_audioOutputFile);
728 while (displayModeIterator->Next(&displayMode) == S_OK)
730 if (g_videoModeIndex == displayModeCount)
732 BMDDisplayModeSupport result;
733 const char *displayModeName;
735 foundDisplayMode = true;
736 displayMode->GetName(&displayModeName);
737 selectedDisplayMode = displayMode->GetDisplayMode();
739 g_aspect_ratio = (double) displayMode->GetWidth() / (double) displayMode->GetHeight();
741 deckLinkInput->DoesSupportVideoMode(selectedDisplayMode, pixelFormat, bmdVideoInputFlagDefault, &result, NULL);
743 if (result == bmdDisplayModeNotSupported)
745 fprintf(stderr, "The display mode %s is not supported with the selected pixel format\n", displayModeName);
750 if (inputFlags & bmdVideoInputDualStream3D)
752 if (!(displayMode->GetFlags() & bmdDisplayModeSupports3D))
754 fprintf(stderr, "The display mode %s is not supported with 3D\n", displayModeName);
763 displayMode->Release();
766 if (!foundDisplayMode)
768 fprintf(stderr, "Invalid mode %d specified\n", g_videoModeIndex);
773 result = deckLinkInput->EnableVideoInput(selectedDisplayMode, pixelFormat, inputFlags);
776 fprintf(stderr, "Failed to enable video input. Is another application using the card?\n");
781 result = deckLinkInput->EnableAudioInput(bmdAudioSampleRate48kHz, g_audioSampleDepth, g_audioChannels);
787 deckLinkInput->SetScreenPreviewCallback(previewView);
788 result = deckLinkInput->StartStreams();
791 qDebug()<<"/// CAPTURE FAILED....";
797 // Block main thread until signal occurs
798 /* pthread_mutex_lock(&sleepMutex);
799 pthread_cond_wait(&sleepCond, &sleepMutex);
800 pthread_mutex_unlock(&sleepMutex);*/
805 close(videoOutputFile);
807 close(audioOutputFile);
809 if (displayModeIterator != NULL)
811 displayModeIterator->Release();
812 displayModeIterator = NULL;
815 if (deckLinkInput != NULL)
817 deckLinkInput->Release();
818 deckLinkInput = NULL;
821 if (deckLink != NULL)
827 if (deckLinkIterator != NULL)
828 deckLinkIterator->Release();
832 CaptureHandler::~CaptureHandler()
837 void CaptureHandler::startCapture()
841 void CaptureHandler::stopCapture()
845 void CaptureHandler::captureFrame(const QString &fname)
847 doCaptureFrame = fname;
850 void CaptureHandler::showOverlay(QImage img, bool transparent)
852 if (previewView) previewView->showOverlay(img, transparent);
855 void CaptureHandler::hideOverlay()
857 if (previewView) previewView->hideOverlay();
860 void CaptureHandler::hidePreview(bool hide)
862 if (previewView) previewView->setHidden(hide);
865 void CaptureHandler::stopPreview()
867 if (!previewView) return;
868 if (deckLinkInput != NULL) deckLinkInput->StopStreams();
870 close(videoOutputFile);
872 close(audioOutputFile);
874 if (displayModeIterator != NULL)
876 displayModeIterator->Release();
877 displayModeIterator = NULL;
880 if (deckLinkInput != NULL)
882 deckLinkInput->Release();
883 deckLinkInput = NULL;
886 if (deckLink != NULL)
892 if (deckLinkIterator != NULL) {
893 deckLinkIterator->Release();
894 deckLinkIterator = NULL;
897 if (previewView != NULL) {
902 /*if (delegate != NULL)