]> git.sesse.net Git - kdenlive/blob - src/recmonitor.cpp
Use enum instead of string to identify monitors
[kdenlive] / src / recmonitor.cpp
1 /***************************************************************************
2  *   Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
18  ***************************************************************************/
19
20
21 #include "recmonitor.h"
22 #include "gentime.h"
23 #include "mltdevicecapture.h"
24 #include "kdenlivesettings.h"
25 #include "managecapturesdialog.h"
26 #include "monitormanager.h"
27 #include "monitor.h"
28 #include "profilesdialog.h"
29
30 #include <KDebug>
31 #include <KLocale>
32 #include <KStandardDirs>
33 #include <KComboBox>
34 #include <KIO/NetAccess>
35 #include <KFileItem>
36 #include <KMessageBox>
37 #include <KApplication>
38 #include <KDiskFreeSpaceInfo>
39 #include <QMouseEvent>
40 #include <QMenu>
41 #include <QToolButton>
42 #include <QFile>
43 #include <QDir>
44
45
46 RecMonitor::RecMonitor(Kdenlive::MONITORID name, MonitorManager *manager, QWidget *parent) :
47     AbstractMonitor(name, parent),
48     m_isCapturing(false),
49     m_didCapture(false),
50     m_isPlaying(false),
51     m_manager(manager),
52     m_captureDevice(NULL),
53     m_analyse(false)
54 {
55     setupUi(this);
56
57     video_frame->setAttribute(Qt::WA_PaintOnScreen);
58     device_selector->setCurrentIndex(KdenliveSettings::defaultcapture());
59     connect(device_selector, SIGNAL(currentIndexChanged(int)), this, SLOT(slotVideoDeviceChanged(int)));
60
61     // Video widget holder
62     QVBoxLayout *l = new QVBoxLayout;
63     l->setContentsMargins(0, 0, 0, 0);
64     l->setSpacing(0);
65     m_videoBox = new VideoPreviewContainer();
66     m_videoBox->setContentsMargins(0, 0, 0, 0);
67     m_videoBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
68     l->addWidget(m_videoBox);
69     video_frame->setLayout(l);
70
71     QToolBar *toolbar = new QToolBar(this);
72     QHBoxLayout *layout = new QHBoxLayout;
73     layout->setContentsMargins(0, 0, 0, 0);
74     m_playIcon = KIcon("media-playback-start");
75     m_pauseIcon = KIcon("media-playback-pause");
76
77     m_discAction = toolbar->addAction(KIcon("network-connect"), i18n("Connect"));
78     connect(m_discAction, SIGNAL(triggered()), this, SLOT(slotDisconnect()));
79
80     m_rewAction = toolbar->addAction(KIcon("media-seek-backward"), i18n("Rewind"));
81     connect(m_rewAction, SIGNAL(triggered()), this, SLOT(slotRewind()));
82
83     m_playAction = toolbar->addAction(m_playIcon, i18n("Play"));
84     connect(m_playAction, SIGNAL(triggered()), this, SLOT(slotStartPreview()));
85
86     m_stopAction = toolbar->addAction(KIcon("media-playback-stop"), i18n("Stop"));
87     connect(m_stopAction, SIGNAL(triggered()), this, SLOT(slotStopCapture()));
88     m_stopAction->setEnabled(false);
89     m_fwdAction = toolbar->addAction(KIcon("media-seek-forward"), i18n("Forward"));
90     connect(m_fwdAction, SIGNAL(triggered()), this, SLOT(slotForward()));
91
92     m_recAction = toolbar->addAction(KIcon("media-record"), i18n("Record"));
93     connect(m_recAction, SIGNAL(triggered()), this, SLOT(slotRecord()));
94     m_recAction->setCheckable(true);
95
96     rec_options->setIcon(KIcon("system-run"));
97     QMenu *menu = new QMenu(this);
98     m_addCapturedClip = new QAction(i18n("Add Captured File to Project"), this);
99     m_addCapturedClip->setCheckable(true);
100     m_addCapturedClip->setChecked(true);
101     menu->addAction(m_addCapturedClip);
102
103     rec_audio->setChecked(KdenliveSettings::v4l_captureaudio());
104     rec_video->setChecked(KdenliveSettings::v4l_capturevideo());
105
106     m_previewSettings = new QAction(i18n("Recording Preview"), this);
107     m_previewSettings->setCheckable(true);
108
109
110     rec_options->setMenu(menu);
111     menu->addAction(m_previewSettings);
112
113     toolbar->addSeparator();
114
115     QAction *configAction = toolbar->addAction(KIcon("configure"), i18n("Configure"));
116     connect(configAction, SIGNAL(triggered()), this, SLOT(slotConfigure()));
117     configAction->setCheckable(false);
118
119     layout->addWidget(toolbar);
120     layout->addWidget(&m_logger);
121     layout->addWidget(&m_dvinfo);
122     m_logger.setMaxCount(10);
123     m_logger.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
124     m_logger.setFrame(false);
125     //m_logger.setInsertPolicy(QComboBox::InsertAtTop);
126
127     m_freeSpace = new KCapacityBar(KCapacityBar::DrawTextInline, this);
128     m_freeSpace->setMaximumWidth(150);
129     QFontMetricsF fontMetrics(font());
130     m_freeSpace->setMaximumHeight(fontMetrics.height() * 1.2);
131     slotUpdateFreeSpace();
132     layout->addWidget(m_freeSpace);
133     connect(&m_spaceTimer, SIGNAL(timeout()), this, SLOT(slotUpdateFreeSpace()));
134     m_spaceTimer.setInterval(30000);
135     m_spaceTimer.setSingleShot(false);
136
137     control_frame_firewire->setLayout(layout);
138     m_displayProcess = new QProcess;
139     m_captureProcess = new QProcess;
140
141     connect(m_captureProcess, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotProcessStatus(QProcess::ProcessState)));
142     connect(m_captureProcess, SIGNAL(readyReadStandardError()), this, SLOT(slotReadDvgrabInfo()));
143
144
145     QString videoDriver = KdenliveSettings::videodrivername();
146 #if QT_VERSION >= 0x040600
147     QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
148     env.insert("SDL_WINDOWID", QString::number(video_frame->winId()));
149     if (!videoDriver.isEmpty()) {
150         if (videoDriver == "x11_noaccel") {
151             env.insert("SDL_VIDEO_YUV_HWACCEL", "0");
152             env.insert("SDL_VIDEODRIVER", "x11");
153         } else env.insert("SDL_VIDEODRIVER", videoDriver);
154     }
155     m_displayProcess->setProcessEnvironment(env);
156 #else
157     QStringList env = QProcess::systemEnvironment();
158     env << "SDL_WINDOWID=" + QString::number(video_frame->winId());
159     if (!videoDriver.isEmpty()) {
160         if (videoDriver == "x11_noaccel") {
161             env << "SDL_VIDEO_YUV_HWACCEL=0";
162             env << "SDL_VIDEODRIVER=x11";
163         } else env << "SDL_VIDEODRIVER=" + videoDriver;
164     }
165     m_displayProcess->setEnvironment(env);
166 #endif
167     setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
168
169     kDebug() << "/////// BUILDING MONITOR, ID: " << video_frame->winId();
170     slotVideoDeviceChanged(device_selector->currentIndex());
171     m_previewSettings->setChecked(KdenliveSettings::enable_recording_preview());
172     connect(m_previewSettings, SIGNAL(triggered(bool)), this, SLOT(slotChangeRecordingPreview(bool)));
173 }
174
175 RecMonitor::~RecMonitor()
176 {
177     m_spaceTimer.stop();
178     delete m_captureProcess;
179     delete m_displayProcess;
180     if (m_captureDevice) delete m_captureDevice;
181 }
182
183
184 void RecMonitor::stop()
185 {
186     slotStopCapture();
187 }
188
189 void RecMonitor::start()
190 {
191 }
192
193 void RecMonitor::slotConfigure()
194 {
195     emit showConfigDialog(4, device_selector->currentIndex());
196 }
197
198 void RecMonitor::slotUpdateCaptureFolder(const QString &currentProjectFolder)
199 {
200     if (KdenliveSettings::capturetoprojectfolder()) m_capturePath = currentProjectFolder;
201     else m_capturePath = KdenliveSettings::capturefolder();
202     if (m_captureProcess) m_captureProcess->setWorkingDirectory(m_capturePath);
203     if (m_captureProcess->state() != QProcess::NotRunning) {
204         if (device_selector->currentIndex() == FIREWIRE)
205             KMessageBox::information(this, i18n("You need to disconnect and reconnect in the capture monitor to apply your changes"), i18n("Capturing"));
206         else KMessageBox::information(this, i18n("You need to stop capture before your changes can be applied"), i18n("Capturing"));
207     } else slotVideoDeviceChanged(device_selector->currentIndex());
208
209     // update free space info
210     slotUpdateFreeSpace();
211 }
212
213 void RecMonitor::slotVideoDeviceChanged(int ix)
214 {
215     QString capturefile;
216     QString capturename;
217     m_previewSettings->setEnabled(ix == VIDEO4LINUX || ix == BLACKMAGIC);
218     rec_audio->setVisible(ix == VIDEO4LINUX);
219     rec_video->setVisible(ix == VIDEO4LINUX);
220     m_fwdAction->setVisible(ix == FIREWIRE);
221     m_discAction->setVisible(ix == FIREWIRE);
222     m_rewAction->setVisible(ix == FIREWIRE);
223     m_recAction->setEnabled(ix != FIREWIRE);
224     m_logger.setVisible(ix == BLACKMAGIC);
225     if (m_captureDevice) {
226         // MLT capture still running, abort
227         m_captureDevice->stop();
228         delete m_captureDevice;
229         m_captureDevice = NULL;
230         m_manager->clearScopeSource();
231     }
232
233     // The m_videoBox container has to be shown once before the MLT consumer is build, or preview will fail
234     m_videoBox->setHidden(ix != VIDEO4LINUX && ix != BLACKMAGIC);
235     m_videoBox->setHidden(true);
236     switch (ix) {
237     case SCREENGRAB:
238         m_discAction->setEnabled(false);
239         m_rewAction->setEnabled(false);
240         m_fwdAction->setEnabled(false);
241         m_stopAction->setEnabled(false);
242         m_playAction->setEnabled(false);
243         if (KdenliveSettings::rmd_path().isEmpty()) {
244             QString rmdpath = KStandardDirs::findExe("recordmydesktop");
245             if (rmdpath.isEmpty()) video_frame->setPixmap(mergeSideBySide(KIcon("dialog-warning").pixmap(QSize(50, 50)), i18n("Recordmydesktop utility not found,\n please install it for screen grabs")));
246             else KdenliveSettings::setRmd_path(rmdpath);
247         }
248         if (!KdenliveSettings::rmd_path().isEmpty()) video_frame->setPixmap(mergeSideBySide(KIcon("video-display").pixmap(QSize(50, 50)), i18n("Press record button\nto start screen capture\nFiles will be saved in:\n%1", m_capturePath)));
249         //video_frame->setText(i18n("Press record button\nto start screen capture"));
250         break;
251     case VIDEO4LINUX:
252         m_stopAction->setEnabled(false);
253         m_playAction->setEnabled(true);
254         checkDeviceAvailability();
255         break;
256     case BLACKMAGIC:
257         m_stopAction->setEnabled(false);
258         m_playAction->setEnabled(true);
259         capturefile = m_capturePath;
260         if (!capturefile.endsWith("/")) capturefile.append("/");
261         capturename = KdenliveSettings::decklink_filename();
262         capturename.append("xxx.");
263         capturename.append(KdenliveSettings::decklink_extension());
264         capturefile.append(capturename);
265         video_frame->setPixmap(mergeSideBySide(KIcon("camera-photo").pixmap(QSize(50, 50)), i18n("Plug your camcorder and\npress play button\nto start preview.\nFiles will be saved in:\n%1", capturefile)));
266         break;
267     default: // FIREWIRE
268         m_discAction->setEnabled(true);
269         m_stopAction->setEnabled(false);
270         m_playAction->setEnabled(false);
271         m_rewAction->setEnabled(false);
272         m_fwdAction->setEnabled(false);
273
274         // Check that dvgab is available
275         if (KdenliveSettings::dvgrab_path().isEmpty()) {
276             QString dvgrabpath = KStandardDirs::findExe("dvgrab");
277             if (dvgrabpath.isEmpty()) video_frame->setPixmap(mergeSideBySide(KIcon("dialog-warning").pixmap(QSize(50, 50)), i18n("dvgrab utility not found,\n please install it for firewire capture")));
278             else KdenliveSettings::setDvgrab_path(dvgrabpath);
279         } else {
280             // Show capture info
281             capturefile = m_capturePath;
282             if (!capturefile.endsWith("/")) capturefile.append("/");
283             capturename = KdenliveSettings::dvgrabfilename();
284             if (capturename.isEmpty()) capturename = "capture";
285             QString extension;
286             switch (KdenliveSettings::firewireformat()) {
287             case 0:
288                 extension = ".dv";
289                 break;
290             case 1:
291             case 2:
292                 extension = ".avi";
293                 break;
294             case 3:
295                 extension = ".m2t";
296                 break;
297             }
298             capturename.append("xxx" + extension);
299             capturefile.append(capturename);
300             video_frame->setPixmap(mergeSideBySide(KIcon("network-connect").pixmap(QSize(50, 50)), i18n("Plug your camcorder and\npress connect button\nto initialize connection\nFiles will be saved in:\n%1", capturefile)));
301         }
302         break;
303     }
304 }
305
306 void RecMonitor::slotSetInfoMessage(const QString &message)
307 {
308     m_logger.insertItem(0, message);
309 }
310
311 QPixmap RecMonitor::mergeSideBySide(const QPixmap& pix, const QString &txt)
312 {
313     QPainter p;
314     QRect r = QApplication::fontMetrics().boundingRect(QRect(0, 0, video_frame->width(), video_frame->height()), Qt::AlignLeft, txt);
315     int strWidth = r.width();
316     int strHeight = r.height();
317     int pixWidth = pix.width();
318     int pixHeight = pix.height();
319     QPixmap res(strWidth + 8 + pixWidth, qMax(strHeight, pixHeight));
320     res.fill(Qt::transparent);
321     p.begin(&res);
322     p.drawPixmap(0, 0, pix);
323     p.setPen(kapp->palette().text().color());
324     p.drawText(QRect(pixWidth + 8, 0, strWidth, strHeight), 0, txt);
325     p.end();
326     return res;
327 }
328
329
330 void RecMonitor::checkDeviceAvailability()
331 {
332     if (!KIO::NetAccess::exists(KUrl(KdenliveSettings::video4vdevice()), KIO::NetAccess::SourceSide , this)) {
333         m_playAction->setEnabled(false);
334         m_recAction->setEnabled(false);
335         video_frame->setPixmap(mergeSideBySide(KIcon("camera-web").pixmap(QSize(50, 50)), i18n("Cannot read from device %1\nPlease check drivers and access rights.", KdenliveSettings::video4vdevice())));
336     } else {
337         video_frame->setPixmap(mergeSideBySide(KIcon("camera-web").pixmap(QSize(50, 50)), i18n("Press play or record button\nto start video capture\nFiles will be saved in:\n%1", m_capturePath)));
338     }
339 }
340
341 void RecMonitor::slotDisconnect()
342 {
343     if (m_captureProcess->state() == QProcess::NotRunning) {
344         m_captureTime = KDateTime::currentLocalDateTime();
345         kDebug() << "CURRENT TIME: " << m_captureTime.toString();
346         m_didCapture = false;
347         slotStartPreview(false);
348         m_discAction->setIcon(KIcon("network-disconnect"));
349         m_discAction->setText(i18n("Disconnect"));
350         m_recAction->setEnabled(true);
351         m_stopAction->setEnabled(true);
352         m_playAction->setEnabled(true);
353         m_rewAction->setEnabled(true);
354         m_fwdAction->setEnabled(true);
355     } else {
356         m_captureProcess->write("q", 1);
357         QTimer::singleShot(1000, m_captureProcess, SLOT(kill()));
358         if (m_didCapture) manageCapturedFiles();
359         m_didCapture = false;
360     }
361 }
362
363 void RecMonitor::slotRewind()
364 {
365     m_captureProcess->write("a", 1);
366 }
367
368 void RecMonitor::slotForward()
369 {
370     m_captureProcess->write("z", 1);
371 }
372
373 void RecMonitor::slotStopCapture()
374 {
375     // stop capture
376     if (!m_isCapturing && !m_isPlaying) return;
377     m_videoBox->setHidden(true);
378     rec_audio->setEnabled(true);
379     rec_video->setEnabled(true);
380     switch (device_selector->currentIndex()) {
381     case FIREWIRE:
382         m_captureProcess->write("\e", 2);
383         m_playAction->setIcon(m_playIcon);
384         m_isPlaying = false;
385         break;
386     case SCREENGRAB:
387         m_captureProcess->write("q\n", 3);
388         m_captureProcess->terminate();
389         video_frame->setText(i18n("Encoding captured video..."));
390         QTimer::singleShot(1000, m_captureProcess, SLOT(kill()));
391         break;
392     case VIDEO4LINUX:
393     case BLACKMAGIC:
394         if (m_captureDevice) {
395             m_captureDevice->stop();
396         }
397         m_previewSettings->setEnabled(true);
398         m_isCapturing = false;
399         m_isPlaying = false;
400         m_playAction->setEnabled(true);
401         m_stopAction->setEnabled(false);
402         m_recAction->setEnabled(true);
403         slotSetInfoMessage(i18n("Capture stopped"));
404         m_isCapturing = false;
405         m_recAction->setChecked(false);
406         if (m_addCapturedClip->isChecked() && !m_captureFile.isEmpty() && QFile::exists(m_captureFile.path())) {
407             emit addProjectClip(m_captureFile);
408             m_captureFile.clear();
409         }
410         break;
411     default:
412         break;
413     }
414 }
415
416 void RecMonitor::slotStartPreview(bool play)
417 {
418     if (m_captureProcess->state() != QProcess::NotRunning) {
419         if (device_selector->currentIndex() == FIREWIRE) {
420             if (m_isPlaying) {
421                 m_captureProcess->write("k", 1);
422                 //captureProcess->write("\e", 2);
423                 m_playAction->setIcon(m_playIcon);
424                 m_isPlaying = false;
425             } else {
426                 m_captureProcess->write("p", 1);
427                 m_playAction->setIcon(m_pauseIcon);
428                 m_isPlaying = true;
429             }
430         }
431         return;
432     }
433     m_captureArgs.clear();
434     m_displayArgs.clear();
435     m_isPlaying = false;
436     QString capturename = KdenliveSettings::dvgrabfilename();
437     QString path;
438     MltVideoProfile profile;
439     QString producer;
440     QStringList dvargs = KdenliveSettings::dvgrabextra().simplified().split(" ", QString::SkipEmptyParts);
441     int ix = device_selector->currentIndex();
442     m_videoBox->setHidden(ix != VIDEO4LINUX && ix != BLACKMAGIC);
443     switch (ix) {
444     case FIREWIRE:
445         switch (KdenliveSettings::firewireformat()) {
446         case 0:
447             // RAW DV CAPTURE
448             m_captureArgs << "--format" << "raw";
449             m_displayArgs << "-f" << "dv";
450             break;
451         case 1:
452             // DV type 1
453             m_captureArgs << "--format" << "dv1";
454             m_displayArgs << "-f" << "dv";
455             break;
456         case 2:
457             // DV type 2
458             m_captureArgs << "--format" << "dv2";
459             m_displayArgs << "-f" << "dv";
460             break;
461         case 3:
462             // HDV CAPTURE
463             m_captureArgs << "--format" << "hdv";
464             m_displayArgs << "-f" << "mpegts";
465             break;
466         }
467         if (KdenliveSettings::firewireautosplit()) m_captureArgs << "--autosplit";
468         if (KdenliveSettings::firewiretimestamp()) m_captureArgs << "--timestamp";
469         if (!dvargs.isEmpty()) {
470             m_captureArgs << dvargs;
471         }
472         m_captureArgs << "-i";
473         if (capturename.isEmpty()) capturename = "capture";
474         m_captureArgs << capturename << "-";
475
476         m_displayArgs << "-x" << QString::number(video_frame->width()) << "-y" << QString::number(video_frame->height()) << "-";
477
478         m_captureProcess->setStandardOutputProcess(m_displayProcess);
479         m_captureProcess->setWorkingDirectory(m_capturePath);
480         kDebug() << "Capture: Running dvgrab " << m_captureArgs.join(" ");
481
482         m_captureProcess->start(KdenliveSettings::dvgrab_path(), m_captureArgs);
483         if (play) m_captureProcess->write(" ", 1);
484         m_discAction->setEnabled(true);
485         break;
486     case VIDEO4LINUX:
487         path = KStandardDirs::locateLocal("appdata", "profiles/video4linux");
488         m_manager->activateMonitor(Kdenlive::recordMonitor);
489         buildMltDevice(path);
490         profile = ProfilesDialog::getVideoProfile(path);
491         producer = getV4lXmlPlaylist(profile);
492
493         //producer = QString("avformat-novalidate:video4linux2:%1?width:%2&height:%3&frame_rate:%4").arg(KdenliveSettings::video4vdevice()).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den);
494         if (!m_captureDevice->slotStartPreview(producer, true)) {
495             // v4l capture failed to start
496             video_frame->setText(i18n("Failed to start Video4Linux,\ncheck your parameters..."));
497             m_videoBox->setHidden(true);
498
499         } else {
500             m_playAction->setEnabled(false);
501             m_stopAction->setEnabled(true);
502             m_isPlaying = true;
503         }
504
505         break;
506     case BLACKMAGIC:
507         path = KdenliveSettings::current_profile();
508         m_manager->activateMonitor(Kdenlive::recordMonitor);
509         buildMltDevice(path);
510         producer = QString("decklink:%1").arg(KdenliveSettings::decklink_capturedevice());
511         if (!m_captureDevice->slotStartPreview(producer)) {
512             // v4l capture failed to start
513             video_frame->setText(i18n("Failed to start Decklink,\ncheck your parameters..."));
514             m_videoBox->setHidden(true);
515
516         } else {
517             m_playAction->setEnabled(false);
518             m_stopAction->setEnabled(true);
519             m_isPlaying = true;
520         }
521         break;
522     default:
523         break;
524     }
525
526     rec_audio->setEnabled(false);
527     rec_video->setEnabled(false);
528
529     if (device_selector->currentIndex() == FIREWIRE) {
530         kDebug() << "Capture: Running ffplay " << m_displayArgs.join(" ");
531         m_displayProcess->start("ffplay", m_displayArgs);
532         video_frame->setText(i18n("Initialising..."));
533     } else {
534         // do something when starting screen grab
535     }
536 }
537
538 void RecMonitor::slotRecord()
539 {
540     rec_audio->setEnabled(false);
541     rec_video->setEnabled(false);
542
543     if (m_captureProcess->state() == QProcess::NotRunning && device_selector->currentIndex() == FIREWIRE) {
544         slotStartPreview();
545     }
546     if (m_isCapturing) {
547         // User stopped capture
548         slotStopCapture();
549         return;
550     } else if (device_selector->currentIndex() == FIREWIRE) {
551         m_isCapturing = true;
552         m_didCapture = true;
553         m_captureProcess->write("c\n", 3);
554         m_spaceTimer.start();
555         return;
556     }
557     if (m_captureProcess->state() == QProcess::NotRunning) {
558         m_logger.clear();
559         m_recAction->setChecked(true);
560         QString extension = "mpg";
561         if (device_selector->currentIndex() == SCREENGRAB) extension = "ogv"; //KdenliveSettings::screengrabextension();
562         else if (device_selector->currentIndex() == VIDEO4LINUX) {
563             // TODO: when recording audio only, allow configuration?
564             if (!rec_video->isChecked()) extension = "wav";
565             else extension = KdenliveSettings::v4l_extension();
566         }
567         else if (device_selector->currentIndex() == BLACKMAGIC) extension = KdenliveSettings::decklink_extension();
568         QString path = KUrl(m_capturePath).path(KUrl::AddTrailingSlash) + "capture0000." + extension;
569         int i = 1;
570         while (QFile::exists(path)) {
571             QString num = QString::number(i).rightJustified(4, '0', false);
572             path = KUrl(m_capturePath).path(KUrl::AddTrailingSlash) + "capture" + num + '.' + extension;
573             i++;
574         }
575         m_captureFile = KUrl(path);
576
577         m_captureArgs.clear();
578         m_displayArgs.clear();
579         QString args;
580         QString playlist;
581         QString v4lparameters;
582         MltVideoProfile profile;
583         bool showPreview;
584         QString capturename = KdenliveSettings::dvgrabfilename();
585         if (capturename.isEmpty()) capturename = "capture";
586
587         switch (device_selector->currentIndex()) {
588         case VIDEO4LINUX:
589             m_manager->activateMonitor(Kdenlive::recordMonitor);
590             path = KStandardDirs::locateLocal("appdata", "profiles/video4linux");
591             profile = ProfilesDialog::getVideoProfile(path);
592             m_videoBox->setRatio((double) profile.display_aspect_num / profile.display_aspect_den);
593             buildMltDevice(path);
594             playlist = getV4lXmlPlaylist(profile);
595
596             v4lparameters = KdenliveSettings::v4l_parameters();
597
598             // TODO: when recording audio only, allow param configuration?
599             if (!rec_video->isChecked()) v4lparameters.clear();
600
601             // Add alsa audio capture
602             if (!rec_audio->isChecked()) {
603                 // if we do not want audio, make sure that we don't have audio encoding parameters
604                 // this is required otherwise the MLT avformat consumer will not close properly
605                 if (v4lparameters.contains("acodec")) {
606                     QString endParam = v4lparameters.section("acodec", 1);
607                     int vcodec = endParam.indexOf(" vcodec");
608                     int format = endParam.indexOf(" f=");
609                     int cutPosition = -1;
610                     if (vcodec > -1) {
611                         if (format  > -1) {
612                             cutPosition = qMin(vcodec, format);
613                         }
614                         else cutPosition = vcodec;
615                     }
616                     else if (format  > -1) {
617                         cutPosition = format;
618                     }
619                     else {
620                         // nothing interesting in end params
621                         endParam.clear();
622                     }
623                     if (cutPosition > -1) {
624                         endParam.remove(0, cutPosition);
625                     }
626                     v4lparameters = QString(v4lparameters.section("acodec", 0, 0) + "an=1 " + endParam).simplified();
627                 }
628             }
629
630             showPreview = m_previewSettings->isChecked();
631             if (!rec_video->isChecked()) showPreview = false;
632
633             if (m_captureDevice->slotStartCapture(v4lparameters, m_captureFile.path(), playlist, showPreview)) {
634                 m_videoBox->setHidden(false);
635                 m_isCapturing = true;
636                 m_recAction->setEnabled(false);
637                 m_stopAction->setEnabled(true);
638                 m_previewSettings->setEnabled(false);
639             }
640             else {
641                 video_frame->setText(i18n("Failed to start Video4Linux,\ncheck your parameters..."));
642                 m_videoBox->setHidden(true);
643                 m_isCapturing = false;
644             }
645             break;
646
647         case BLACKMAGIC:
648             m_manager->activateMonitor(Kdenlive::recordMonitor);
649             path = KdenliveSettings::current_profile();
650             profile = ProfilesDialog::getVideoProfile(path);
651             m_videoBox->setRatio((double) profile.display_aspect_num / profile.display_aspect_den);
652             buildMltDevice(path);
653
654             playlist = QString("<producer id=\"producer0\" in=\"0\" out=\"99999\"><property name=\"mlt_type\">producer</property><property name=\"length\">100000</property><property name=\"eof\">pause</property><property name=\"resource\">%1</property><property name=\"mlt_service\">decklink</property></producer>").arg(KdenliveSettings::decklink_capturedevice());
655
656             if (m_captureDevice->slotStartCapture(KdenliveSettings::decklink_parameters(), m_captureFile.path(), QString("decklink:%1").arg(KdenliveSettings::decklink_capturedevice()), m_previewSettings->isChecked(), false)) {
657                 m_videoBox->setHidden(false);
658                 m_isCapturing = true;
659                 slotSetInfoMessage(i18n("Capturing to %1", m_captureFile.fileName()));
660                 m_recAction->setEnabled(false);
661                 m_stopAction->setEnabled(true);
662                 m_previewSettings->setEnabled(false);
663             }
664             else {
665                 video_frame->setText(i18n("Failed to start Decklink,\ncheck your parameters..."));
666                 slotSetInfoMessage(i18n("Failed to start capture"));
667                 m_videoBox->setHidden(true);
668                 m_isCapturing = false;
669             }
670             break;
671
672         case SCREENGRAB:
673             switch (KdenliveSettings::rmd_capture_type()) {
674             case 0:
675                 // Full screen capture, nothing special to do
676                 break;
677             default:
678                 // Region capture
679                 m_captureArgs << "--width" << QString::number(KdenliveSettings::rmd_width()) << "--height" << QString::number(KdenliveSettings::rmd_height());
680                 if (!KdenliveSettings::rmd_follow_mouse()) {
681                     m_captureArgs << "-x" << QString::number(KdenliveSettings::rmd_offsetx()) << "-y" << QString::number(KdenliveSettings::rmd_offsety());
682                 } else {
683                     m_captureArgs << "--follow-mouse";
684                     if (KdenliveSettings::rmd_hide_frame()) m_captureArgs << "--no-frame";
685                 }
686                 break;
687             }
688             if (KdenliveSettings::rmd_hide_mouse()) m_captureArgs << "--no-cursor";
689             m_isCapturing = true;
690             if (KdenliveSettings::rmd_capture_audio()) {
691                 m_captureArgs << "--freq" << KdenliveSettings::rmd_freq();
692                 m_captureArgs << "--channels" << QString::number(KdenliveSettings::rmd_audio_channels());
693                 if (KdenliveSettings::rmd_use_jack()) {
694                     m_captureArgs << "--use-jack";
695                     QStringList ports = KdenliveSettings::rmd_jackports().split(" ", QString::SkipEmptyParts);
696                     for (int i = 0; i < ports.count(); ++i) {
697                         m_captureArgs << ports.at(i);
698                     }
699                     if (KdenliveSettings::rmd_jack_buffer() > 0.0)
700                         m_captureArgs << "--ring-buffer-size" << QString::number(KdenliveSettings::rmd_jack_buffer());
701                 } else {
702                     if (!KdenliveSettings::rmd_alsadevicename().isEmpty())
703                         m_captureArgs << "--device" << KdenliveSettings::rmd_alsadevicename();
704                     if (KdenliveSettings::rmd_alsa_buffer() > 0)
705                         m_captureArgs << "--buffer-size" << QString::number(KdenliveSettings::rmd_alsa_buffer());
706                 }
707             } else m_captureArgs << "--no-sound";
708
709             if (KdenliveSettings::rmd_fullshots()) m_captureArgs << "--full-shots";
710             m_captureArgs << "--v_bitrate" << QString::number(KdenliveSettings::rmd_bitrate());
711             m_captureArgs << "--v_quality" << QString::number(KdenliveSettings::rmd_quality());
712             m_captureArgs << "--workdir" << KdenliveSettings::currenttmpfolder();
713             m_captureArgs << "--fps" << QString::number(KdenliveSettings::rmd_fps()) << "-o" << m_captureFile.path();
714             m_captureProcess->start(KdenliveSettings::rmd_path(), m_captureArgs);
715             kDebug() << "// RecordMyDesktop params: " << m_captureArgs;
716             break;
717         default:
718             break;
719         }
720
721
722         if (device_selector->currentIndex() == FIREWIRE) {
723             m_isCapturing = true;
724             kDebug() << "Capture: Running ffplay " << m_displayArgs.join(" ");
725             m_displayProcess->start("ffplay", m_displayArgs);
726             video_frame->setText(i18n("Initialising..."));
727         }
728     } else {
729         // stop capture
730         m_displayProcess->kill();
731         //captureProcess->kill();
732         QTimer::singleShot(1000, this, SLOT(slotRecord()));
733     }
734 }
735
736 const QString RecMonitor::getV4lXmlPlaylist(MltVideoProfile profile) {
737
738     QString playlist = QString("<mlt title=\"capture\" LC_NUMERIC=\"C\"><profile description=\"v4l\" width=\"%1\" height=\"%2\" progressive=\"%3\" sample_aspect_num=\"%4\" sample_aspect_den=\"%5\" display_aspect_num=\"%6\" display_aspect_den=\"%7\" frame_rate_num=\"%8\" frame_rate_den=\"%9\" colorspace=\"%10\"/>").arg(profile.width).arg(profile.height).arg(profile.progressive).arg(profile.sample_aspect_num).arg(profile.sample_aspect_den).arg(profile.display_aspect_num).arg(profile.display_aspect_den).arg(profile.frame_rate_num).arg(profile.frame_rate_den).arg(profile.colorspace);
739
740     if (rec_video->isChecked()) {
741         playlist.append(QString("<producer id=\"producer0\" in=\"0\" out=\"999999\"><property name=\"mlt_type\">producer</property><property name=\"length\">1000000</property><property name=\"eof\">loop</property><property name=\"resource\">video4linux2:%1?width:%2&amp;height:%3&amp;frame_rate:%4</property><property name=\"mlt_service\">avformat-novalidate</property></producer><playlist id=\"playlist0\"><entry producer=\"producer0\" in=\"0\" out=\"999999\"/></playlist>").arg(KdenliveSettings::video4vdevice()).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den));
742     }
743
744     if (rec_audio->isChecked()) {
745         playlist.append(QString("<producer id=\"producer1\" in=\"0\" out=\"999999\"><property name=\"mlt_type\">producer</property><property name=\"length\">1000000</property><property name=\"eof\">loop</property><property name=\"resource\">alsa:%5</property><property name=\"audio_index\">0</property><property name=\"video_index\">-1</property><property name=\"mlt_service\">avformat-novalidate</property></producer><playlist id=\"playlist1\"><entry producer=\"producer1\" in=\"0\" out=\"999999\"/></playlist>").arg(KdenliveSettings::v4l_alsadevicename()));
746     }
747     playlist.append("<tractor id=\"tractor0\" title=\"video0\" global_feed=\"1\" in=\"0\" out=\"999999\">");
748     if (rec_video->isChecked()) playlist.append("<track producer=\"playlist0\"/>");
749     if (rec_audio->isChecked()) playlist.append("<track producer=\"playlist1\"/>");
750     playlist.append("</tractor></mlt>");
751
752     return playlist;
753 }
754
755 /*
756 void RecMonitor::slotStartGrab(const QRect &rect) {
757     rgnGrab->deleteLater();
758     QApplication::restoreOverrideCursor();
759     show();
760     if (rect.isNull()) return;
761     int width = rect.width();
762     int height = rect.height();
763     if (width % 2 != 0) width--;
764     if (height % 2 != 0) height--;
765     QString args = KdenliveSettings::screengrabcapture().replace("%size", QString::number(width) + "x" + QString::number(height)).replace("%offset", "+" + QString::number(rect.x()) + "," + QString::number(rect.y()));
766     if (KdenliveSettings::screengrabenableaudio()) {
767         // also capture audio
768         if (KdenliveSettings::useosscapture()) m_captureArgs << KdenliveSettings::screengrabosscapture().simplified().split(' ');
769         else m_captureArgs << KdenliveSettings::screengrabalsacapture2().simplified().split(' ');
770     }
771     m_captureArgs << args.simplified().split(' ') << KdenliveSettings::screengrabencoding().simplified().split(' ') << m_captureFile.path();
772     m_isCapturing = true;
773     video_frame->setText(i18n("Capturing..."));
774     if (KdenliveSettings::screengrabenableaudio() && !KdenliveSettings::useosscapture()) {
775         QStringList alsaArgs = KdenliveSettings::screengrabalsacapture().simplified().split(' ');
776         alsaProcess->setStandardOutputProcess(captureProcess);
777         kDebug() << "Capture: Running arecord " << alsaArgs.join(" ");
778         alsaProcess->start("arecord", alsaArgs);
779     }
780     kDebug() << "Capture: Running ffmpeg " << m_captureArgs.join(" ");
781     captureProcess->start("ffmpeg", m_captureArgs);
782 }*/
783
784 void RecMonitor::slotProcessStatus(QProcess::ProcessState status)
785 {
786     if (status == QProcess::NotRunning) {
787         m_displayProcess->kill();
788         if (m_isCapturing && device_selector->currentIndex() != FIREWIRE)
789             if (m_addCapturedClip->isChecked() && !m_captureFile.isEmpty() && QFile::exists(m_captureFile.path())) {
790                 emit addProjectClip(m_captureFile);
791                 m_captureFile.clear();
792             }
793         if (device_selector->currentIndex() == FIREWIRE) {
794             m_discAction->setIcon(KIcon("network-connect"));
795             m_discAction->setText(i18n("Connect"));
796             m_playAction->setEnabled(false);
797             m_rewAction->setEnabled(false);
798             m_fwdAction->setEnabled(false);
799             m_recAction->setEnabled(false);
800         }
801         m_isPlaying = false;
802         m_playAction->setIcon(m_playIcon);
803         m_recAction->setChecked(false);
804         m_stopAction->setEnabled(false);
805         device_selector->setEnabled(true);
806         if (m_captureProcess && m_captureProcess->exitStatus() == QProcess::CrashExit) {
807             video_frame->setText(i18n("Capture crashed, please check your parameters"));
808         } else {
809             if (device_selector->currentIndex() != SCREENGRAB) {
810                 video_frame->setText(i18n("Not connected"));
811             } else {
812                 if (m_captureProcess->exitCode() != 0) {
813                     video_frame->setText(i18n("Capture crashed, please check your parameters\nRecordMyDesktop exit code: %1", QString::number(m_captureProcess->exitCode())));
814                 } else {
815                     video_frame->setPixmap(mergeSideBySide(KIcon("video-display").pixmap(QSize(50, 50)), i18n("Press record button\nto start screen capture\nFiles will be saved in:\n%1", m_capturePath)));
816                 }
817             }
818         }
819         m_isCapturing = false;
820
821         m_spaceTimer.stop();
822         // update free space info
823         slotUpdateFreeSpace();
824     } else {
825         if (device_selector->currentIndex() != SCREENGRAB) m_stopAction->setEnabled(true);
826         device_selector->setEnabled(false);
827     }
828 }
829
830 void RecMonitor::manageCapturedFiles()
831 {
832     QString extension;
833     switch (KdenliveSettings::firewireformat()) {
834     case 0:
835         extension = ".dv";
836         break;
837     case 1:
838     case 2:
839         extension = ".avi";
840         break;
841     case 3:
842         extension = ".m2t";
843         break;
844     }
845     QDir dir(m_capturePath);
846     QStringList filters;
847     QString capturename = KdenliveSettings::dvgrabfilename();
848     if (capturename.isEmpty()) capturename = "capture";
849     filters << capturename + "*" + extension;
850     const QStringList result = dir.entryList(filters, QDir::Files, QDir::Time);
851     KUrl::List capturedFiles;
852     foreach(const QString & name, result) {
853         KUrl url = KUrl(dir.filePath(name));
854         if (KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, this)) {
855             KFileItem file(KFileItem::Unknown, KFileItem::Unknown, url, true);
856             if (file.time(KFileItem::ModificationTime) > m_captureTime) {
857                 // The file was captured in the last batch
858                 if (url.fileName().contains(':')) {
859                     // Several dvgrab options (--timecode,...) use : in the file name, which is
860                     // not supported by MLT, so rename them
861                     QString newUrl = url.directory(KUrl::AppendTrailingSlash) + url.fileName().replace(':', '_');
862                     if (QFile::rename(url.path(), newUrl)) {
863                         url = KUrl(newUrl);
864                     }
865
866                 }
867                 capturedFiles.append(url);
868             }
869         }
870     }
871     kDebug() << "Found : " << capturedFiles.count() << " new capture files";
872     kDebug() << capturedFiles;
873
874     if (capturedFiles.count() > 0) {
875         ManageCapturesDialog *d = new ManageCapturesDialog(capturedFiles, this);
876         if (d->exec() == QDialog::Accepted) {
877             emit addProjectClipList(d->importFiles());
878         }
879         delete d;
880     }
881 }
882
883 // virtual
884 void RecMonitor::mousePressEvent(QMouseEvent * /*event*/)
885 {
886     if (m_freeSpace->underMouse()) slotUpdateFreeSpace();
887 }
888
889 void RecMonitor::slotUpdateFreeSpace()
890 {
891     KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo(m_capturePath);
892     if (info.isValid() && info.size() > 0) {
893         m_freeSpace->setValue(100 * info.used() / info.size());
894         m_freeSpace->setText(i18n("Free space: %1", KIO::convertSize(info.available())));
895         m_freeSpace->update();
896     }
897 }
898
899 void RecMonitor::refreshRecMonitor(bool visible)
900 {
901     if (visible) {
902         //if (!m_isActive) m_monitorManager->activateRecMonitor(m_name);
903
904     }
905 }
906
907 void RecMonitor::slotPlay()
908 {
909
910     //if (!m_isActive) m_monitorManager->activateRecMonitor(m_name);
911
912 }
913
914 void RecMonitor::slotReadDvgrabInfo()
915 {
916     QString data = m_captureProcess->readAllStandardError().simplified();
917     data = data.section('"', 2, 2).simplified();
918     m_dvinfo.setText(data.left(11));
919     m_dvinfo.updateGeometry();
920 }
921
922 AbstractRender *RecMonitor::abstractRender()
923 {
924     return m_captureDevice;
925 }
926
927
928 void RecMonitor::analyseFrames(bool analyse)
929 {
930     m_analyse = analyse;
931     if (m_captureDevice) m_captureDevice->sendFrameForAnalysis = analyse;
932 }
933
934 void RecMonitor::slotDroppedFrames(int dropped)
935 {
936     slotSetInfoMessage(i18n("%1 dropped frames", dropped));
937 }
938
939 void RecMonitor::buildMltDevice(const QString &path)
940 {
941     if (m_captureDevice == NULL) {
942         m_captureDevice = new MltDeviceCapture(path, m_videoBox, this);
943         connect(m_captureDevice, SIGNAL(droppedFrames(int)), this, SLOT(slotDroppedFrames(int)));
944         m_captureDevice->sendFrameForAnalysis = m_analyse;
945         m_manager->updateScopeSource();
946     }
947 }
948
949 void RecMonitor::slotChangeRecordingPreview(bool enable)
950 {
951     KdenliveSettings::setEnable_recording_preview(enable);
952 }
953
954 #include "recmonitor.moc"
955