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)
326 return E_NOINTERFACE;
329 ULONG CDeckLinkGLWidget::AddRef ()
333 oldValue = refCount.fetchAndAddAcquire(1);
334 return (ULONG)(oldValue + 1);
337 ULONG CDeckLinkGLWidget::Release ()
341 oldValue = refCount.fetchAndAddAcquire(-1);
347 return (ULONG)(oldValue - 1);
350 HRESULT CDeckLinkGLWidget::DrawFrame (IDeckLinkVideoFrame* theFrame)
352 if (deckLinkScreenPreviewHelper != NULL && theFrame != NULL)
357 deckLinkScreenPreviewHelper->SetFrame(theFrame);
364 DeckLinkCaptureDelegate::DeckLinkCaptureDelegate() : m_refCount(0)
366 pthread_mutex_init(&m_mutex, NULL);
369 DeckLinkCaptureDelegate::~DeckLinkCaptureDelegate()
371 pthread_mutex_destroy(&m_mutex);
374 ULONG DeckLinkCaptureDelegate::AddRef(void)
376 pthread_mutex_lock(&m_mutex);
378 pthread_mutex_unlock(&m_mutex);
380 return (ULONG)m_refCount;
383 ULONG DeckLinkCaptureDelegate::Release(void)
385 pthread_mutex_lock(&m_mutex);
387 pthread_mutex_unlock(&m_mutex);
395 return (ULONG)m_refCount;
398 HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame)
400 IDeckLinkVideoFrame* rightEyeFrame = NULL;
401 IDeckLinkVideoFrame3DExtensions* threeDExtensions = NULL;
403 void* audioFrameBytes;
405 // Handle Video Frame
408 // If 3D mode is enabled we retreive the 3D extensions interface which gives.
409 // us access to the right eye frame by calling GetFrameForRightEye() .
410 if ( (videoFrame->QueryInterface(IID_IDeckLinkVideoFrame3DExtensions, (void **) &threeDExtensions) != S_OK) ||
411 (threeDExtensions->GetFrameForRightEye(&rightEyeFrame) != S_OK))
413 rightEyeFrame = NULL;
416 if (videoFrame->GetFlags() & bmdFrameHasNoInputSource)
418 fprintf(stderr, "Frame received (#%lu) - No input signal detected\n", frameCount);
422 const char *timecodeString = NULL;
423 if (g_timecodeFormat != 0)
425 IDeckLinkTimecode *timecode;
426 if (videoFrame->GetTimecode(g_timecodeFormat, &timecode) == S_OK)
428 timecode->GetString(&timecodeString);
432 /*fprintf(stderr, "Frame received (#%lu) [%s] - %s - Size: %li bytes\n",
434 timecodeString != NULL ? timecodeString : "No timecode",
435 rightEyeFrame != NULL ? "Valid Frame (3D left/right)" : "Valid Frame",
436 videoFrame->GetRowBytes() * videoFrame->GetHeight());*/
439 free((void*)timecodeString);
441 if (!doCaptureFrame.isEmpty()) {
442 videoFrame->GetBytes(&frameBytes);
443 if (doCaptureFrame.endsWith("raw")) {
444 // Save as raw uyvy422 imgage
445 videoOutputFile = open(doCaptureFrame.toUtf8().constData(), O_WRONLY|O_CREAT/*|O_TRUNC*/, 0664);
446 write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());
447 close(videoOutputFile);
450 QImage image(videoFrame->GetWidth(), videoFrame->GetHeight(), QImage::Format_ARGB32_Premultiplied);
451 //convert from uyvy422 to rgba
452 yuv2rgb_int((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight());
453 image.save(doCaptureFrame);
455 doCaptureFrame.clear();
458 if (videoOutputFile != -1)
460 videoFrame->GetBytes(&frameBytes);
461 write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());
465 rightEyeFrame->GetBytes(&frameBytes);
466 write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());
472 if (g_maxFrames > 0 && frameCount >= g_maxFrames)
474 pthread_cond_signal(&sleepCond);
478 // Handle Audio Frame
481 if (audioOutputFile != -1)
483 audioFrame->GetBytes(&audioFrameBytes);
484 write(audioOutputFile, audioFrameBytes, audioFrame->GetSampleFrameCount() * g_audioChannels * (g_audioSampleDepth / 8));
490 HRESULT DeckLinkCaptureDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, BMDDetectedVideoInputFormatFlags)
495 /*int usage(int status)
498 IDeckLinkDisplayMode *displayMode;
499 int displayModeCount = 0;
502 "Usage: Capture -m <mode id> [OPTIONS]\n"
507 while (displayModeIterator->Next(&displayMode) == S_OK)
509 char * displayModeString = NULL;
511 result = displayMode->GetName((const char **) &displayModeString);
514 BMDTimeValue frameRateDuration, frameRateScale;
515 displayMode->GetFrameRate(&frameRateDuration, &frameRateScale);
517 fprintf(stderr, " %2d: %-20s \t %li x %li \t %g FPS\n",
518 displayModeCount, displayModeString, displayMode->GetWidth(), displayMode->GetHeight(), (double)frameRateScale / (double)frameRateDuration);
520 free(displayModeString);
524 // Release the IDeckLinkDisplayMode object to prevent a leak
525 displayMode->Release();
529 " -p <pixelformat>\n"
530 " 0: 8 bit YUV (4:2:2) (default)\n"
531 " 1: 10 bit YUV (4:2:2)\n"
532 " 2: 10 bit RGB (4:4:4)\n"
533 " -t <format> Print timecode\n"
536 " serial: Serial Timecode\n"
537 " -f <filename> Filename raw video will be written to\n"
538 " -a <filename> Filename raw audio will be written to\n"
539 " -c <channels> Audio Channels (2, 8 or 16 - default is 2)\n"
540 " -s <depth> Audio Sample Depth (16 or 32 - default is 16)\n"
541 " -n <frames> Number of frames to capture (default is unlimited)\n"
542 " -3 Capture Stereoscopic 3D (Requires 3D Hardware support)\n"
544 "Capture video and/or audio to a file. Raw video and/or audio can be viewed with mplayer eg:\n"
546 " Capture -m2 -n 50 -f video.raw -a audio.raw\n"
547 " mplayer video.raw -demuxer rawvideo -rawvideo pal:uyvy -audiofile audio.raw -audio-demuxer 20 -rawaudio rate=48000\n"
557 CaptureHandler::CaptureHandler(QVBoxLayout *lay, QWidget *parent):
561 , deckLinkInput(NULL)
562 , displayModeIterator(NULL)
566 , deckLinkIterator(NULL)
570 void CaptureHandler::startPreview(int deviceId, int captureMode)
572 deckLinkIterator = CreateDeckLinkIteratorInstance();
573 BMDVideoInputFlags inputFlags = 0;
574 BMDDisplayMode selectedDisplayMode = bmdModeNTSC;
575 BMDPixelFormat pixelFormat = bmdFormat8BitYUV;
576 int displayModeCount = 0;
579 bool foundDisplayMode = false;
582 /*pthread_mutex_init(&sleepMutex, NULL);
583 pthread_cond_init(&sleepCond, NULL);*/
584 kDebug()<<"/// INIT CAPTURE ON DEV: "<<deviceId;
586 if (!deckLinkIterator)
588 fprintf(stderr, "This application requires the DeckLink drivers installed.\n");
593 /* Connect to selected DeckLink instance */
594 for (int i = 0; i < deviceId + 1; i++)
595 result = deckLinkIterator->Next(&deckLink);
598 fprintf(stderr, "No DeckLink PCI cards found.\n");
603 if (deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&deckLinkInput) != S_OK)
609 delegate = new DeckLinkCaptureDelegate();
610 deckLinkInput->SetCallback(delegate);
612 previewView = new CDeckLinkGLWidget(deckLinkInput, m_parent);
613 m_layout->addWidget(previewView);
614 //previewView->resize(parent->size());
615 previewView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
616 previewView->DrawFrame(NULL);
618 // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on output
619 result = deckLinkInput->GetDisplayModeIterator(&displayModeIterator);
622 fprintf(stderr, "Could not obtain the video output display mode iterator - result = %08x\n", result);
627 g_videoModeIndex = captureMode;
628 /*g_audioChannels = 2;
629 g_audioSampleDepth = 16;*/
631 // Parse command line options
632 /*while ((ch = getopt(argc, argv, "?h3c:s:f:a:m:n:p:t:")) != -1)
637 g_videoModeIndex = atoi(optarg);
640 g_audioChannels = atoi(optarg);
641 if (g_audioChannels != 2 &&
642 g_audioChannels != 8 &&
643 g_audioChannels != 16)
645 fprintf(stderr, "Invalid argument: Audio Channels must be either 2, 8 or 16\n");
650 g_audioSampleDepth = atoi(optarg);
651 if (g_audioSampleDepth != 16 && g_audioSampleDepth != 32)
653 fprintf(stderr, "Invalid argument: Audio Sample Depth must be either 16 bits or 32 bits\n");
658 g_videoOutputFile = optarg;
661 g_audioOutputFile = optarg;
664 g_maxFrames = atoi(optarg);
667 inputFlags |= bmdVideoInputDualStream3D;
672 case 0: pixelFormat = bmdFormat8BitYUV; break;
673 case 1: pixelFormat = bmdFormat10BitYUV; break;
674 case 2: pixelFormat = bmdFormat10BitRGB; break;
676 fprintf(stderr, "Invalid argument: Pixel format %d is not valid", atoi(optarg));
681 if (!strcmp(optarg, "rp188"))
682 g_timecodeFormat = bmdTimecodeRP188;
683 else if (!strcmp(optarg, "vitc"))
684 g_timecodeFormat = bmdTimecodeVITC;
685 else if (!strcmp(optarg, "serial"))
686 g_timecodeFormat = bmdTimecodeSerial;
689 fprintf(stderr, "Invalid argument: Timecode format \"%s\" is invalid\n", optarg);
699 if (g_videoModeIndex < 0)
701 fprintf(stderr, "No video mode specified\n");
705 //g_videoOutputFile="/home/one/bm.raw";
706 if (g_videoOutputFile != NULL)
708 videoOutputFile = open(g_videoOutputFile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
709 if (videoOutputFile < 0)
711 fprintf(stderr, "Could not open video output file \"%s\"\n", g_videoOutputFile);
715 if (g_audioOutputFile != NULL)
717 audioOutputFile = open(g_audioOutputFile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
718 if (audioOutputFile < 0)
720 fprintf(stderr, "Could not open audio output file \"%s\"\n", g_audioOutputFile);
725 while (displayModeIterator->Next(&displayMode) == S_OK)
727 if (g_videoModeIndex == displayModeCount)
729 BMDDisplayModeSupport result;
730 const char *displayModeName;
732 foundDisplayMode = true;
733 displayMode->GetName(&displayModeName);
734 selectedDisplayMode = displayMode->GetDisplayMode();
736 g_aspect_ratio = (double) displayMode->GetWidth() / (double) displayMode->GetHeight();
738 deckLinkInput->DoesSupportVideoMode(selectedDisplayMode, pixelFormat, bmdVideoInputFlagDefault, &result, NULL);
740 if (result == bmdDisplayModeNotSupported)
742 fprintf(stderr, "The display mode %s is not supported with the selected pixel format\n", displayModeName);
747 if (inputFlags & bmdVideoInputDualStream3D)
749 if (!(displayMode->GetFlags() & bmdDisplayModeSupports3D))
751 fprintf(stderr, "The display mode %s is not supported with 3D\n", displayModeName);
760 displayMode->Release();
763 if (!foundDisplayMode)
765 fprintf(stderr, "Invalid mode %d specified\n", g_videoModeIndex);
770 result = deckLinkInput->EnableVideoInput(selectedDisplayMode, pixelFormat, inputFlags);
773 fprintf(stderr, "Failed to enable video input. Is another application using the card?\n");
778 result = deckLinkInput->EnableAudioInput(bmdAudioSampleRate48kHz, g_audioSampleDepth, g_audioChannels);
784 deckLinkInput->SetScreenPreviewCallback(previewView);
785 result = deckLinkInput->StartStreams();
788 qDebug()<<"/// CAPTURE FAILED....";
794 // Block main thread until signal occurs
795 /* pthread_mutex_lock(&sleepMutex);
796 pthread_cond_wait(&sleepCond, &sleepMutex);
797 pthread_mutex_unlock(&sleepMutex);*/
802 close(videoOutputFile);
804 close(audioOutputFile);
806 if (displayModeIterator != NULL)
808 displayModeIterator->Release();
809 displayModeIterator = NULL;
812 if (deckLinkInput != NULL)
814 deckLinkInput->Release();
815 deckLinkInput = NULL;
818 if (deckLink != NULL)
824 if (deckLinkIterator != NULL)
825 deckLinkIterator->Release();
829 CaptureHandler::~CaptureHandler()
834 void CaptureHandler::startCapture()
838 void CaptureHandler::stopCapture()
842 void CaptureHandler::captureFrame(const QString &fname)
844 doCaptureFrame = fname;
847 void CaptureHandler::showOverlay(QImage img, bool transparent)
849 if (previewView) previewView->showOverlay(img, transparent);
852 void CaptureHandler::hideOverlay()
854 if (previewView) previewView->hideOverlay();
857 void CaptureHandler::hidePreview(bool hide)
859 if (previewView) previewView->setHidden(hide);
862 void CaptureHandler::stopPreview()
864 if (!previewView) return;
865 if (deckLinkInput != NULL) deckLinkInput->StopStreams();
867 close(videoOutputFile);
869 close(audioOutputFile);
871 if (displayModeIterator != NULL)
873 displayModeIterator->Release();
874 displayModeIterator = NULL;
877 if (deckLinkInput != NULL)
879 deckLinkInput->Release();
880 deckLinkInput = NULL;
883 if (deckLink != NULL)
889 if (deckLinkIterator != NULL) {
890 deckLinkIterator->Release();
891 deckLinkIterator = NULL;
894 if (previewView != NULL) {
899 /*if (delegate != NULL)