]> git.sesse.net Git - kdenlive/blob - src/blackmagic/capture.cpp
f57a48c65bfd1b3492d392cecb43989f812a970b
[kdenlive] / src / blackmagic / capture.cpp
1 /* -LICENSE-START-
2 ** Copyright (c) 2009 Blackmagic Design
3 **
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:
10 **
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.
17 **
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.
25 ** -LICENSE-END-
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <pthread.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34
35 #include <QGLWidget>
36 #include <QDebug>
37 #include <QImage>
38 #include <QMutex>
39 #include <QPaintEvent>
40
41 #include <QtOpenGL>
42
43 #ifndef GL_TEXTURE_RECTANGLE_EXT
44 #define GL_TEXTURE_RECTANGLE_EXT GL_TEXTURE_RECTANGLE_NV
45 #endif
46
47 #include <KDebug>
48 #include <KLocale>
49
50 #include "capture.h"
51 #include "kdenlivesettings.h"
52
53 pthread_mutex_t             sleepMutex;
54 pthread_cond_t              sleepCond;
55 int                 videoOutputFile = -1;
56 int                 audioOutputFile = -1;
57
58 static BMDTimecodeFormat        g_timecodeFormat = 0;
59 static int              g_videoModeIndex = -1;
60 static int              g_audioChannels = 2;
61 static int              g_audioSampleDepth = 16;
62 static int              g_maxFrames = -1;
63 static QString              doCaptureFrame;
64 static double               g_aspect_ratio = 16.0 / 9.0;
65
66 static unsigned long            frameCount = 0;
67
68
69 class CDeckLinkGLWidget : public QGLWidget, public IDeckLinkScreenPreviewCallback
70 {
71 private:
72     QAtomicInt refCount;
73     QMutex mutex;
74     IDeckLinkInput* deckLinkIn;
75     IDeckLinkGLScreenPreviewHelper* deckLinkScreenPreviewHelper;
76     IDeckLinkVideoFrame* m_frame;
77     QColor m_backgroundColor;
78     GLuint m_texture;
79     QImage m_img;
80     double m_zx;
81     double m_zy;
82     int m_pictureWidth;
83     int m_pictureHeight;
84     bool m_transparentOverlay;
85
86 public:
87     CDeckLinkGLWidget(IDeckLinkInput* deckLinkInput, QWidget* parent);
88     // IDeckLinkScreenPreviewCallback
89     virtual HRESULT QueryInterface(REFIID iid, LPVOID *ppv);
90     virtual ULONG AddRef();
91     virtual ULONG Release();
92     virtual HRESULT DrawFrame(IDeckLinkVideoFrame* theFrame);
93     void showOverlay(QImage img, bool transparent);
94     void hideOverlay();
95
96 protected:
97     void initializeGL();
98     void paintGL();
99     void resizeGL(int width, int height);
100     /*void initializeOverlayGL();
101     void paintOverlayGL();
102     void resizeOverlayGL(int width, int height);*/
103 };
104
105 CDeckLinkGLWidget::CDeckLinkGLWidget(IDeckLinkInput* deckLinkInput, QWidget* parent) : QGLWidget(/*QGLFormat(QGL::HasOverlay | QGL::AlphaChannel),*/ parent)
106     , m_backgroundColor(KdenliveSettings::window_background())
107     , m_zx(1.0)
108     , m_zy(1.0)
109     , m_transparentOverlay(true)
110 {
111     refCount = 1;
112     deckLinkIn = deckLinkInput;
113     deckLinkScreenPreviewHelper = CreateOpenGLScreenPreviewHelper();
114 }
115
116 void CDeckLinkGLWidget::showOverlay(QImage img, bool transparent)
117 {
118     m_transparentOverlay = transparent;
119     m_img = convertToGLFormat(img);
120     m_zx = (double)m_pictureWidth / m_img.width();
121     m_zy = (double)m_pictureHeight / m_img.height();
122     if (m_transparentOverlay) {
123         glEnable(GL_BLEND);
124         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
125     } else {
126         glDisable(GL_BLEND);
127     }
128 }
129
130 void CDeckLinkGLWidget::hideOverlay()
131 {
132     m_img = QImage();
133     glDisable(GL_BLEND);
134 }
135
136 void    CDeckLinkGLWidget::initializeGL()
137 {
138     if (deckLinkScreenPreviewHelper != NULL) {
139         mutex.lock();
140         deckLinkScreenPreviewHelper->InitializeGL();
141         glShadeModel(GL_FLAT);
142         glDisable(GL_DEPTH_TEST);
143         glDisable(GL_CULL_FACE);
144         glDisable(GL_LIGHTING);
145         glDisable(GL_DITHER);
146         glDisable(GL_BLEND);
147
148         //Documents/images/alpha2.png");//
149         //m_texture = bindTexture(convertToGLFormat(img), GL_TEXTURE_RECTANGLE_EXT, GL_RGBA8, QGLContext::LinearFilteringBindOption);
150         mutex.unlock();
151     }
152 }
153
154 /*void CDeckLinkGLWidget::initializeOverlayGL ()
155 {
156   glDisable(GL_BLEND);
157   glEnable(GL_TEXTURE_RECTANGLE_EXT);
158
159 }
160
161 void    CDeckLinkGLWidget::paintOverlayGL()
162 {
163     makeOverlayCurrent();
164     glEnable(GL_BLEND);
165     //glClearDepth(0.5f);
166     //glPixelTransferf(GL_ALPHA_SCALE, 10);
167     //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
168
169
170 }*/
171
172 void    CDeckLinkGLWidget::paintGL()
173 {
174     mutex.lock();
175     glLoadIdentity();
176     qglClearColor(m_backgroundColor);
177     //glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
178     glClear(GL_COLOR_BUFFER_BIT);
179     deckLinkScreenPreviewHelper->PaintGL();
180     if (!m_img.isNull()) {
181         glPixelZoom(m_zx, m_zy);
182         glDrawPixels(m_img.width(), m_img.height(), GL_RGBA, GL_UNSIGNED_BYTE, m_img.bits());
183     }
184     mutex.unlock();
185 }
186 /*
187 void CDeckLinkGLWidget::paintEvent(QPaintEvent *event)
188 {
189     mutex.lock();
190     QPainter p(this);
191     QRect r = event->rect();
192     p.setClipRect(r);
193     void *frameBytes;
194     m_frame->GetBytes(&frameBytes);
195     QImage img((uchar*)frameBytes, m_frame->GetWidth(), m_frame->GetHeight(), QImage::Format_ARGB32);//m_frame->GetPixelFormat());
196     QRectF re(0, 0, width(), height());
197     p.drawImage(re, img);
198     p.end();
199     mutex.unlock();
200 }*/
201
202 void    CDeckLinkGLWidget::resizeGL(int width, int height)
203 {
204     mutex.lock();
205     m_pictureHeight = height;
206     m_pictureWidth = width;
207     int calculatedWidth = g_aspect_ratio * height;
208     if (calculatedWidth > width) m_pictureHeight = width / g_aspect_ratio;
209     else {
210         int calculatedHeight = width / g_aspect_ratio;
211         if (calculatedHeight > height) m_pictureWidth = height * g_aspect_ratio;
212     }
213     glViewport((width - m_pictureWidth) / 2, (height - m_pictureHeight) / 2, m_pictureWidth, m_pictureHeight);
214     glMatrixMode(GL_PROJECTION);
215     glLoadIdentity();
216     glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
217     glMatrixMode(GL_MODELVIEW);
218     glRasterPos2i(-1, -1);
219     if (!m_img.isNull()) {
220         m_zx = (double)m_pictureWidth / m_img.width();
221         m_zy = (double)m_pictureHeight / m_img.height();
222     }
223
224     mutex.unlock();
225 }
226
227 /*void CDeckLinkGLWidget::resizeOverlayGL ( int width, int height )
228 {
229   int newwidth = width;
230     int newheight = height;
231     int calculatedWidth = g_aspect_ratio * height;
232     if (calculatedWidth > width) newheight = width / g_aspect_ratio;
233     else {
234         int calculatedHeight = width / g_aspect_ratio;
235         if (calculatedHeight > height) newwidth = height * g_aspect_ratio;
236     }
237     glViewport((width - newwidth) / 2, (height - newheight) / 2, newwidth, newheight);
238     glMatrixMode(GL_PROJECTION);
239     glLoadIdentity();
240     glOrtho(0, width, 0, height, -1.0, 1.0);
241     glMatrixMode(GL_MODELVIEW);
242     updateOverlayGL ();
243 }*/
244
245 HRESULT     CDeckLinkGLWidget::QueryInterface(REFIID iid, LPVOID *ppv)
246 {
247     Q_UNUSED(iid)
248     *ppv = NULL;
249     return E_NOINTERFACE;
250 }
251
252 ULONG       CDeckLinkGLWidget::AddRef()
253 {
254     int     oldValue;
255
256     oldValue = refCount.fetchAndAddAcquire(1);
257     return (ULONG)(oldValue + 1);
258 }
259
260 ULONG       CDeckLinkGLWidget::Release()
261 {
262     int     oldValue;
263
264     oldValue = refCount.fetchAndAddAcquire(-1);
265     if (oldValue == 1) {
266         delete this;
267     }
268
269     return (ULONG)(oldValue - 1);
270 }
271
272 HRESULT     CDeckLinkGLWidget::DrawFrame(IDeckLinkVideoFrame* theFrame)
273 {
274     if (deckLinkScreenPreviewHelper != NULL && theFrame != NULL) {
275         /*mutex.lock();
276         m_frame = theFrame;
277         mutex.unlock();*/
278         deckLinkScreenPreviewHelper->SetFrame(theFrame);
279         update();
280     }
281     return S_OK;
282 }
283
284
285 DeckLinkCaptureDelegate::DeckLinkCaptureDelegate() : m_refCount(0)
286 {
287     pthread_mutex_init(&m_mutex, NULL);
288 }
289
290 DeckLinkCaptureDelegate::~DeckLinkCaptureDelegate()
291 {
292     pthread_mutex_destroy(&m_mutex);
293 }
294
295 ULONG DeckLinkCaptureDelegate::AddRef(void)
296 {
297     pthread_mutex_lock(&m_mutex);
298     m_refCount++;
299     pthread_mutex_unlock(&m_mutex);
300
301     return (ULONG)m_refCount;
302 }
303
304 ULONG DeckLinkCaptureDelegate::Release(void)
305 {
306     pthread_mutex_lock(&m_mutex);
307     m_refCount--;
308     pthread_mutex_unlock(&m_mutex);
309
310     if (m_refCount == 0) {
311         delete this;
312         return 0;
313     }
314
315     return (ULONG)m_refCount;
316 }
317
318
319 inline bool safe_write(int fd, const void* bytes, size_t length) {
320   int rc = 0;
321   size_t written = 0;
322   const char* buf = static_cast<const char*>(bytes);
323   while (rc != -1 && written < length) {
324     rc = write(fd, &(buf[written]), length - written);
325     written += (rc >= 0 ? rc : 0);
326   }
327   return rc != -1;
328 }
329
330 void DeckLinkCaptureDelegate::slotProcessFrame()
331 {
332     if (m_framesList.isEmpty()) return;
333     IDeckLinkVideoInputFrame* videoFrame = m_framesList.takeFirst();
334     QString capturePath = m_framePath.takeFirst();
335     void *frameBytes;
336     videoFrame->GetBytes(&frameBytes);
337     if (capturePath.endsWith("raw")) {
338         // Save as raw uyvy422 imgage
339         videoOutputFile = open(capturePath.toUtf8().constData(), O_WRONLY | O_CREAT/*|O_TRUNC*/, 0664);
340         safe_write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());
341         close(videoOutputFile);
342         emit frameSaved(capturePath);
343     } else {
344         QImage image(videoFrame->GetWidth(), videoFrame->GetHeight(), QImage::Format_ARGB32_Premultiplied);
345         //convert from uyvy422 to rgba
346         CaptureHandler::uyvy2rgb((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight());
347         image.save(capturePath);
348         emit frameSaved(capturePath);
349     }
350     videoFrame->Release();
351 }
352
353 void DeckLinkCaptureDelegate::setAnalyse(bool isOn)
354 {
355     m_analyseFrame = isOn;
356 }
357
358 HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioFrame)
359 {
360     IDeckLinkVideoFrame*                    rightEyeFrame = NULL;
361     IDeckLinkVideoFrame3DExtensions*        threeDExtensions = NULL;
362     void*                   frameBytes;
363     void*                   audioFrameBytes;
364
365     // Handle Video Frame
366     if (videoFrame) {
367         // If 3D mode is enabled we retreive the 3D extensions interface which gives.
368         // us access to the right eye frame by calling GetFrameForRightEye() .
369         if ((videoFrame->QueryInterface(IID_IDeckLinkVideoFrame3DExtensions, (void **) &threeDExtensions) != S_OK) ||
370                 (threeDExtensions->GetFrameForRightEye(&rightEyeFrame) != S_OK)) {
371             rightEyeFrame = NULL;
372         }
373
374         if (videoFrame->GetFlags() & bmdFrameHasNoInputSource) {
375             emit gotMessage(i18n("Frame (%1) - No input signal", frameCount));
376             fprintf(stderr, "Frame received (#%lu) - No input signal detected\n", frameCount);
377         } else {
378             const char *timecodeString = NULL;
379             if (g_timecodeFormat != 0) {
380                 IDeckLinkTimecode *timecode;
381                 if (videoFrame->GetTimecode(g_timecodeFormat, &timecode) == S_OK) {
382                     timecode->GetString(&timecodeString);
383                 }
384             }
385             // There seems to be No timecode with HDMI... Using frame number
386             emit gotTimeCode(frameCount);
387             /*fprintf(stderr, "Frame received (#%lu) [%s] - %s - Size: %li bytes\n",
388                 frameCount,
389                 timecodeString != NULL ? timecodeString : "No timecode",
390                 rightEyeFrame != NULL ? "Valid Frame (3D left/right)" : "Valid Frame",
391                 videoFrame->GetRowBytes() * videoFrame->GetHeight());*/
392
393             if (timecodeString)
394                 free((void*)timecodeString);
395
396             if (!doCaptureFrame.isEmpty()) {
397                 videoFrame->AddRef();
398                 m_framesList.append(videoFrame);
399                 m_framePath.append(doCaptureFrame);
400                 doCaptureFrame.clear();
401                 QtConcurrent::run(this, &DeckLinkCaptureDelegate::slotProcessFrame);
402             }
403             if (m_analyseFrame) {
404                 QImage image(videoFrame->GetWidth(), videoFrame->GetHeight(), QImage::Format_ARGB32_Premultiplied);
405                 //convert from uyvy422 to rgba
406                 videoFrame->GetBytes(&frameBytes);
407                 CaptureHandler::uyvy2rgb((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight());
408                 emit gotFrame(image);
409             }
410
411             if (videoOutputFile != -1) {
412                 if (!m_analyseFrame) videoFrame->GetBytes(&frameBytes);
413                 safe_write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());
414
415                 if (rightEyeFrame) {
416                     rightEyeFrame->GetBytes(&frameBytes);
417                     safe_write(videoOutputFile, frameBytes, videoFrame->GetRowBytes() * videoFrame->GetHeight());
418                 }
419             }
420         }
421         frameCount++;
422
423         if (g_maxFrames > 0 && frameCount >= (uint) g_maxFrames) {
424             pthread_cond_signal(&sleepCond);
425         }
426     }
427
428     // Handle Audio Frame
429     if (audioFrame) {
430         if (audioOutputFile != -1) {
431             audioFrame->GetBytes(&audioFrameBytes);
432             safe_write(audioOutputFile, audioFrameBytes, audioFrame->GetSampleFrameCount() * g_audioChannels *(g_audioSampleDepth / 8));
433         }
434     }
435     return S_OK;
436 }
437
438 HRESULT DeckLinkCaptureDelegate::VideoInputFormatChanged(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, BMDDetectedVideoInputFormatFlags)
439 {
440     Q_UNUSED(events)
441     Q_UNUSED(mode)
442     return S_OK;
443 }
444
445 /*int usage(int status)
446 {
447     HRESULT result;
448     IDeckLinkDisplayMode *displayMode;
449     int displayModeCount = 0;
450
451     fprintf(stderr,
452         "Usage: Capture -m <mode id> [OPTIONS]\n"
453         "\n"
454         "    -m <mode id>:\n"
455     );
456
457     while (displayModeIterator->Next(&displayMode) == S_OK)
458     {
459         char *          displayModeString = NULL;
460
461         result = displayMode->GetName((const char **) &displayModeString);
462         if (result == S_OK)
463         {
464             BMDTimeValue frameRateDuration, frameRateScale;
465             displayMode->GetFrameRate(&frameRateDuration, &frameRateScale);
466
467             fprintf(stderr, "        %2d:  %-20s \t %li x %li \t %g FPS\n",
468                 displayModeCount, displayModeString, displayMode->GetWidth(), displayMode->GetHeight(), (double)frameRateScale / (double)frameRateDuration);
469
470             free(displayModeString);
471             displayModeCount++;
472         }
473
474         // Release the IDeckLinkDisplayMode object to prevent a leak
475         displayMode->Release();
476     }
477
478     fprintf(stderr,
479         "    -p <pixelformat>\n"
480         "         0:  8 bit YUV (4:2:2) (default)\n"
481         "         1:  10 bit YUV (4:2:2)\n"
482         "         2:  10 bit RGB (4:4:4)\n"
483         "    -t <format>          Print timecode\n"
484         "     rp188:  RP 188\n"
485         "      vitc:  VITC\n"
486         "    serial:  Serial Timecode\n"
487         "    -f <filename>        Filename raw video will be written to\n"
488         "    -a <filename>        Filename raw audio will be written to\n"
489         "    -c <channels>        Audio Channels (2, 8 or 16 - default is 2)\n"
490         "    -s <depth>           Audio Sample Depth (16 or 32 - default is 16)\n"
491         "    -n <frames>          Number of frames to capture (default is unlimited)\n"
492         "    -3                   Capture Stereoscopic 3D (Requires 3D Hardware support)\n"
493         "\n"
494         "Capture video and/or audio to a file. Raw video and/or audio can be viewed with mplayer eg:\n"
495         "\n"
496         "    Capture -m2 -n 50 -f video.raw -a audio.raw\n"
497         "    mplayer video.raw -demuxer rawvideo -rawvideo pal:uyvy -audiofile audio.raw -audio-demuxer 20 -rawaudio rate=48000\n"
498     );
499
500     exit(status);
501 }
502 */
503
504
505
506
507 BmdCaptureHandler::BmdCaptureHandler(QVBoxLayout *lay, QWidget *parent):
508     CaptureHandler(lay, parent),
509     previewView(NULL),
510     deckLinkIterator(NULL),
511     delegate(NULL),
512     displayMode(NULL),
513     deckLink(NULL),
514     deckLinkInput(NULL),
515     displayModeIterator(NULL)
516 {
517 }
518
519 QStringList BmdCaptureHandler::getDeviceName(QString)
520 {
521     return QStringList();
522 }
523
524 void BmdCaptureHandler::startPreview(int deviceId, int captureMode, bool audio)
525 {
526     deckLinkIterator = CreateDeckLinkIteratorInstance();
527     BMDVideoInputFlags          inputFlags = 0;
528     BMDDisplayMode              selectedDisplayMode = bmdModeNTSC;
529     BMDPixelFormat              pixelFormat = bmdFormat8BitYUV;
530     int                         displayModeCount = 0;
531     int                         exitStatus = 1;
532     //int                           ch;
533     bool                        foundDisplayMode = false;
534     HRESULT                     result = 1;
535
536     /*pthread_mutex_init(&sleepMutex, NULL);
537     pthread_cond_init(&sleepCond, NULL);*/
538     kDebug() << "/// INIT CAPTURE ON DEV: " << deviceId;
539
540     if (!deckLinkIterator) {
541         emit gotMessage(i18n("This application requires the DeckLink drivers installed."));
542         fprintf(stderr, "This application requires the DeckLink drivers installed.\n");
543         stopCapture();
544         return;
545     }
546
547     /* Connect to selected DeckLink instance */
548     for (int i = 0; i < deviceId + 1; i++)
549         result = deckLinkIterator->Next(&deckLink);
550     if (result != S_OK) {
551         fprintf(stderr, "No DeckLink PCI cards found.\n");
552         emit gotMessage(i18n("No DeckLink PCI cards found."));
553         stopCapture();
554         return;
555     }
556
557     if (deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&deckLinkInput) != S_OK) {
558         stopCapture();
559         return;
560     }
561
562     delegate = new DeckLinkCaptureDelegate();
563     delegate->setAnalyse(m_analyseFrame);
564     connect(delegate, SIGNAL(gotTimeCode(ulong)), this, SIGNAL(gotTimeCode(ulong)));
565     connect(delegate, SIGNAL(gotFrame(QImage)), this, SIGNAL(gotFrame(QImage)));
566     connect(delegate, SIGNAL(gotMessage(const QString &)), this, SIGNAL(gotMessage(const QString &)));
567     connect(delegate, SIGNAL(frameSaved(const QString)), this, SIGNAL(frameSaved(const QString)));
568     deckLinkInput->SetCallback(delegate);
569
570     previewView = new CDeckLinkGLWidget(deckLinkInput, m_parent);
571     m_layout->addWidget(previewView);
572     //previewView->resize(parent->size());
573     previewView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
574     previewView->DrawFrame(NULL);
575
576     // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on output
577     result = deckLinkInput->GetDisplayModeIterator(&displayModeIterator);
578     if (result != S_OK) {
579         emit gotMessage(i18n("Could not obtain the video output display mode iterator - result = ", result));
580         fprintf(stderr, "Could not obtain the video output display mode iterator - result = %08x\n", result);
581         stopCapture();
582         return;
583     }
584
585     g_videoModeIndex = captureMode;
586     /*g_audioChannels = 2;
587     g_audioSampleDepth = 16;*/
588
589     // Parse command line options
590     /*while ((ch = getopt(argc, argv, "?h3c:s:f:a:m:n:p:t:")) != -1)
591     {
592         switch (ch)
593         {
594             case 'm':
595                 g_videoModeIndex = atoi(optarg);
596                 break;
597             case 'c':
598                 g_audioChannels = atoi(optarg);
599                 if (g_audioChannels != 2 &&
600                     g_audioChannels != 8 &&
601                     g_audioChannels != 16)
602                 {
603                     fprintf(stderr, "Invalid argument: Audio Channels must be either 2, 8 or 16\n");
604      stopCapture();
605                 }
606                 break;
607             case 's':
608                 g_audioSampleDepth = atoi(optarg);
609                 if (g_audioSampleDepth != 16 && g_audioSampleDepth != 32)
610                 {
611                     fprintf(stderr, "Invalid argument: Audio Sample Depth must be either 16 bits or 32 bits\n");
612      stopCapture();
613                 }
614                 break;
615             case 'f':
616                 g_videoOutputFile = optarg;
617                 break;
618             case 'a':
619                 g_audioOutputFile = optarg;
620                 break;
621             case 'n':
622                 g_maxFrames = atoi(optarg);
623                 break;
624             case '3':
625                 inputFlags |= bmdVideoInputDualStream3D;
626                 break;
627             case 'p':
628                 switch(atoi(optarg))
629                 {
630                     case 0: pixelFormat = bmdFormat8BitYUV; break;
631                     case 1: pixelFormat = bmdFormat10BitYUV; break;
632                     case 2: pixelFormat = bmdFormat10BitRGB; break;
633                     default:
634                         fprintf(stderr, "Invalid argument: Pixel format %d is not valid", atoi(optarg));
635       stopCapture();
636                 }
637                 break;
638             case 't':
639                 if (!strcmp(optarg, "rp188"))
640                     g_timecodeFormat = bmdTimecodeRP188;
641                 else if (!strcmp(optarg, "vitc"))
642                     g_timecodeFormat = bmdTimecodeVITC;
643                 else if (!strcmp(optarg, "serial"))
644                     g_timecodeFormat = bmdTimecodeSerial;
645                 else
646                 {
647                     fprintf(stderr, "Invalid argument: Timecode format \"%s\" is invalid\n", optarg);
648      stopCapture();
649                 }
650                 break;
651             case '?':
652             case 'h':
653                 usage(0);
654         }
655     }*/
656
657     if (g_videoModeIndex < 0) {
658         emit gotMessage(i18n("No video mode specified"));
659         fprintf(stderr, "No video mode specified\n");
660         stopCapture();
661         return;
662     }
663
664     /*if (g_videoOutputFile != NULL)
665     {
666         videoOutputFile = open(g_videoOutputFile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
667         if (videoOutputFile < 0)
668         {
669             emit gotMessage(i18n("Could not open video output file %1", g_videoOutputFile));
670             fprintf(stderr, "Could not open video output file \"%s\"\n", g_videoOutputFile);
671        stopCapture();
672         }
673     }
674     if (g_audioOutputFile != NULL)
675     {
676         audioOutputFile = open(g_audioOutputFile, O_WRONLY|O_CREAT|O_TRUNC, 0664);
677         if (audioOutputFile < 0)
678         {
679             emit gotMessage(i18n("Could not open audio output file %1", g_audioOutputFile));
680             fprintf(stderr, "Could not open audio output file \"%s\"\n", g_audioOutputFile);
681        stopCapture();
682         }
683     }*/
684
685     while (displayModeIterator->Next(&displayMode) == S_OK) {
686         if (g_videoModeIndex == displayModeCount) {
687             BMDDisplayModeSupport result;
688             const char *displayModeName;
689
690             foundDisplayMode = true;
691             displayMode->GetName(&displayModeName);
692             selectedDisplayMode = displayMode->GetDisplayMode();
693
694             g_aspect_ratio = (double) displayMode->GetWidth() / (double) displayMode->GetHeight();
695
696             deckLinkInput->DoesSupportVideoMode(selectedDisplayMode, pixelFormat, bmdVideoInputFlagDefault, &result, NULL);
697
698             if (result == bmdDisplayModeNotSupported) {
699                 emit gotMessage(i18n("The display mode %1 is not supported with the selected pixel format", displayModeName));
700                 fprintf(stderr, "The display mode %s is not supported with the selected pixel format\n", displayModeName);
701                 stopCapture();
702                 return;
703             }
704
705             if (inputFlags & bmdVideoInputDualStream3D) {
706                 if (!(displayMode->GetFlags() & bmdDisplayModeSupports3D)) {
707                     emit gotMessage(i18n("The display mode %1 is not supported with 3D", displayModeName));
708                     fprintf(stderr, "The display mode %s is not supported with 3D\n", displayModeName);
709                     stopCapture();
710                     return;
711                 }
712             }
713
714             break;
715         }
716         displayModeCount++;
717         displayMode->Release();
718     }
719
720     if (!foundDisplayMode) {
721         emit gotMessage(i18n("Invalid mode %1 specified", g_videoModeIndex));
722         fprintf(stderr, "Invalid mode %d specified\n", g_videoModeIndex);
723         stopCapture();
724         return;
725     }
726
727     result = deckLinkInput->EnableVideoInput(selectedDisplayMode, pixelFormat, inputFlags);
728     if (result != S_OK) {
729         emit gotMessage(i18n("Failed to enable video input. Is another application using the card?"));
730         fprintf(stderr, "Failed to enable video input. Is another application using the card?\n");
731         stopCapture();
732         return;
733     }
734
735     if (audio) {
736         result = deckLinkInput->EnableAudioInput(bmdAudioSampleRate48kHz, g_audioSampleDepth, g_audioChannels);
737         if (result != S_OK) {
738             stopCapture();
739             return;
740         }
741     }
742     deckLinkInput->SetScreenPreviewCallback(previewView);
743     result = deckLinkInput->StartStreams();
744     if (result != S_OK) {
745         qDebug() << "/// CAPTURE FAILED....";
746         emit gotMessage(i18n("Capture failed"));
747     }
748
749     // All Okay.
750     exitStatus = 0;
751
752     // Block main thread until signal occurs
753     /*  pthread_mutex_lock(&sleepMutex);
754         pthread_cond_wait(&sleepCond, &sleepMutex);
755         pthread_mutex_unlock(&sleepMutex);*/
756
757     /*bail:
758
759         if (videoOutputFile)
760             close(videoOutputFile);
761         if (audioOutputFile)
762             close(audioOutputFile);
763
764         if (displayModeIterator != NULL)
765         {
766             displayModeIterator->Release();
767             displayModeIterator = NULL;
768         }
769
770         if (deckLinkInput != NULL)
771         {
772             deckLinkInput->Release();
773             deckLinkInput = NULL;
774         }
775
776         if (deckLink != NULL)
777         {
778             deckLink->Release();
779             deckLink = NULL;
780         }
781
782         if (deckLinkIterator != NULL)
783             deckLinkIterator->Release();
784     */
785 }
786
787 BmdCaptureHandler::~BmdCaptureHandler()
788 {
789     stopCapture();
790 }
791
792 void BmdCaptureHandler::startCapture(const QString &path)
793 {
794     int i = 0;
795     QString videopath = path + "_video_" + QString::number(i).rightJustified(4, '0', false) + ".raw";
796     QString audiopath = path + "_audio_" + QString::number(i).rightJustified(4, '0', false) + ".raw";
797     while (QFile::exists(videopath) || QFile::exists(audiopath)) {
798         i++;
799         videopath = path + "_video_" + QString::number(i).rightJustified(4, '0', false) + ".raw";
800         audiopath = path + "_audio_" + QString::number(i).rightJustified(4, '0', false) + ".raw";
801     }
802     videoOutputFile = open(videopath.toUtf8().constData(), O_WRONLY | O_CREAT | O_TRUNC, 0664);
803     if (videoOutputFile < 0) {
804         emit gotMessage(i18n("Could not open video output file %1", videopath));
805         fprintf(stderr, "Could not open video output file \"%s\"\n", videopath.toUtf8().constData());
806         return;
807     }
808     /*if (KdenliveSettings::hdmicaptureaudio()) {
809         audioOutputFile = open(audiopath.toUtf8().constData(), O_WRONLY | O_CREAT | O_TRUNC, 0664);
810         if (audioOutputFile < 0) {
811             emit gotMessage(i18n("Could not open audio output file %1", audiopath));
812             fprintf(stderr, "Could not open video output file \"%s\"\n", audiopath.toUtf8().constData());
813             return;
814         }
815     }*/
816 }
817
818 void BmdCaptureHandler::stopCapture()
819 {
820     if (videoOutputFile)
821         close(videoOutputFile);
822     if (audioOutputFile)
823         close(audioOutputFile);
824     videoOutputFile = -1;
825     audioOutputFile = -1;
826 }
827
828 void BmdCaptureHandler::captureFrame(const QString &fname)
829 {
830     doCaptureFrame = fname;
831 }
832
833 void BmdCaptureHandler::showOverlay(QImage img, bool transparent)
834 {
835     if (previewView) previewView->showOverlay(img, transparent);
836 }
837
838 void BmdCaptureHandler::hideOverlay()
839 {
840     if (previewView) previewView->hideOverlay();
841 }
842
843 void BmdCaptureHandler::setDevice(const QString , QString)
844 {
845 }
846
847 void BmdCaptureHandler::hidePreview(bool hide)
848 {
849     if (previewView) previewView->setHidden(hide);
850 }
851
852 void BmdCaptureHandler::stopPreview()
853 {
854     if (!previewView) return;
855     if (deckLinkInput != NULL) deckLinkInput->StopStreams();
856     if (videoOutputFile)
857         close(videoOutputFile);
858     if (audioOutputFile)
859         close(audioOutputFile);
860
861     if (displayModeIterator != NULL) {
862         displayModeIterator->Release();
863         displayModeIterator = NULL;
864     }
865
866     if (deckLinkInput != NULL) {
867         deckLinkInput->Release();
868         deckLinkInput = NULL;
869     }
870
871     if (deckLink != NULL) {
872         deckLink->Release();
873         deckLink = NULL;
874     }
875
876     if (deckLinkIterator != NULL) {
877         deckLinkIterator->Release();
878         deckLinkIterator = NULL;
879     }
880
881     if (previewView != NULL) {
882         delete previewView;
883         previewView = NULL;
884     }
885
886     /*if (delegate != NULL)
887     delete delegate;*/
888
889 }