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