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