]> git.sesse.net Git - kdenlive/blob - src/recmonitor.cpp
Fix problem with screengrab
[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 <QMouseEvent>
22 #include <QStylePainter>
23 #include <QMenu>
24 #include <QToolButton>
25 #include <QFile>
26 #include <QDir>
27 #include <QDesktopWidget>
28
29 #include <KDebug>
30 #include <KLocale>
31 #include <KStandardDirs>
32 #include <KComboBox>
33 #include <KIO/NetAccess>
34
35 #include "gentime.h"
36 #include "kdenlivesettings.h"
37 #include "recmonitor.h"
38
39 RecMonitor::RecMonitor(QString name, QWidget *parent)
40         : QWidget(parent), m_name(name), m_isActive(false), m_isCapturing(false), m_isPlaying(false) {
41     ui.setupUi(this);
42
43     ui.video_frame->setAttribute(Qt::WA_PaintOnScreen);
44     ui.device_selector->setCurrentIndex(KdenliveSettings::defaultcapture());
45     connect(ui.device_selector, SIGNAL(currentIndexChanged(int)), this, SLOT(slotVideoDeviceChanged(int)));
46
47
48
49     QToolBar *toolbar = new QToolBar(name, this);
50     QHBoxLayout *layout = new QHBoxLayout;
51
52     m_playIcon = KIcon("media-playback-start");
53     m_pauseIcon = KIcon("media-playback-pause");
54
55     m_discAction = toolbar->addAction(KIcon("network-connect"), i18n("Connect"));
56     connect(m_discAction, SIGNAL(triggered()), this, SLOT(slotDisconnect()));
57
58     m_rewAction = toolbar->addAction(KIcon("media-seek-backward"), i18n("Rewind"));
59     connect(m_rewAction, SIGNAL(triggered()), this, SLOT(slotRewind()));
60
61     m_playAction = toolbar->addAction(m_playIcon, i18n("Play"));
62     connect(m_playAction, SIGNAL(triggered()), this, SLOT(slotStartCapture()));
63
64     m_stopAction = toolbar->addAction(KIcon("media-playback-stop"), i18n("Stop"));
65     connect(m_stopAction, SIGNAL(triggered()), this, SLOT(slotStopCapture()));
66     m_stopAction->setEnabled(false);
67     m_fwdAction = toolbar->addAction(KIcon("media-seek-forward"), i18n("Forward"));
68     connect(m_fwdAction, SIGNAL(triggered()), this, SLOT(slotForward()));
69
70     m_recAction = toolbar->addAction(KIcon("media-record"), i18n("Record"));
71     connect(m_recAction, SIGNAL(triggered()), this, SLOT(slotRecord()));
72     m_recAction->setCheckable(true);
73
74     layout->addWidget(toolbar);
75     ui.control_frame_firewire->setLayout(layout);
76
77     slotVideoDeviceChanged(ui.device_selector->currentIndex());
78     displayProcess = new QProcess;
79     captureProcess = new QProcess;
80
81     connect(captureProcess, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotProcessStatus(QProcess::ProcessState)));
82
83     QStringList env = QProcess::systemEnvironment();
84     env << "SDL_WINDOWID=" + QString::number(ui.video_frame->winId());
85     displayProcess->setEnvironment(env);
86
87     if (KdenliveSettings::video4capture().isEmpty()) {
88         QString captureCommand;
89         if (!KdenliveSettings::video4adevice().isEmpty()) captureCommand = "-f " + KdenliveSettings::video4aformat() + " -i " + KdenliveSettings::video4adevice();
90
91         captureCommand +=  " -f " + KdenliveSettings::video4vformat() + " -s " + KdenliveSettings::video4size() + " -r " + QString::number(KdenliveSettings::video4rate()) + " -i " + KdenliveSettings::video4vdevice() + " -f " + KdenliveSettings::video4vencoding();
92         KdenliveSettings::setVideo4capture(captureCommand);
93     }
94
95     if (KdenliveSettings::video4playback().isEmpty()) {
96         QString playbackCommand;
97         playbackCommand =  "-f " + KdenliveSettings::video4vencoding();
98         KdenliveSettings::setVideo4playback(playbackCommand);
99     }
100     kDebug() << "/////// BUILDING MONITOR, ID: " << ui.video_frame->winId();
101 }
102
103 QString RecMonitor::name() const {
104     return m_name;
105 }
106
107 void RecMonitor::slotVideoDeviceChanged(int ix) {
108     switch (ix) {
109     case SCREENGRAB:
110         m_discAction->setEnabled(false);
111         m_rewAction->setEnabled(false);
112         m_fwdAction->setEnabled(false);
113         m_recAction->setEnabled(true);
114         m_stopAction->setEnabled(false);
115         m_playAction->setEnabled(false);
116         ui.video_frame->setText(i18n("Press record button\nto start screen capture"));
117         break;
118     case VIDEO4LINUX:
119         m_discAction->setEnabled(false);
120         m_rewAction->setEnabled(false);
121         m_fwdAction->setEnabled(false);
122         m_recAction->setEnabled(true);
123         m_stopAction->setEnabled(false);
124         m_playAction->setEnabled(true);
125         checkDeviceAvailability();
126         break;
127     default: // FIREWIRE
128         m_discAction->setEnabled(true);
129         m_recAction->setEnabled(false);
130         m_stopAction->setEnabled(false);
131         m_playAction->setEnabled(false);
132         m_rewAction->setEnabled(false);
133         m_fwdAction->setEnabled(false);
134         ui.video_frame->setText(i18n("Press connect button\nto initialize connection"));
135         break;
136     }
137 }
138
139 void RecMonitor::checkDeviceAvailability() {
140     if (!KIO::NetAccess::exists(KUrl(KdenliveSettings::video4vdevice()), KIO::NetAccess::SourceSide , this)) {
141         m_playAction->setEnabled(false);
142         m_recAction->setEnabled(false);
143         ui.video_frame->setText(i18n("Cannot read from device %1\nPlease check drivers and access rights.", KdenliveSettings::video4vdevice()));
144     } else ui.video_frame->setText(i18n("Press play or record button\nto start video capture"));
145 }
146
147 void RecMonitor::slotDisconnect() {
148     if (captureProcess->state() == QProcess::NotRunning) {
149         slotStartCapture(false);
150         m_discAction->setIcon(KIcon("network-disconnect"));
151         m_discAction->setText(i18n("Disonnect"));
152         m_recAction->setEnabled(true);
153         m_stopAction->setEnabled(true);
154         m_playAction->setEnabled(true);
155         m_rewAction->setEnabled(true);
156         m_fwdAction->setEnabled(true);
157     } else {
158         captureProcess->write("q", 1);
159     }
160 }
161
162 void RecMonitor::slotRewind() {
163     captureProcess->write("a", 1);
164 }
165
166 void RecMonitor::slotForward() {
167     captureProcess->write("z", 1);
168 }
169
170 void RecMonitor::slotStopCapture() {
171     // stop capture
172     switch (ui.device_selector->currentIndex()) {
173     case FIREWIRE:
174         captureProcess->write("\e", 2);
175         m_playAction->setIcon(m_playIcon);
176         m_isPlaying = false;
177         break;
178     case VIDEO4LINUX:
179         captureProcess->write("q\n", 3);
180         QTimer::singleShot(1000, captureProcess, SLOT(kill()));
181
182         break;
183     case SCREENGRAB:
184         captureProcess->write("q\n", 3);
185         QTimer::singleShot(1000, captureProcess, SLOT(kill()));
186         break;
187     default:
188         break;
189     }
190 }
191
192 void RecMonitor::slotStartCapture(bool play) {
193
194     /*
195     *captureProcess<<"dvgrab";
196
197     bool isHdv = false;
198
199     switch (m_recPanel->capture_format->currentItem()){
200         case 0:
201       *captureProcess<<"--format"<<"dv1";
202      break;
203         case 1:
204       *captureProcess<<"--format"<<"dv2";
205      break;
206         case 3:
207       *captureProcess<<"--format"<<"hdv";
208      isHdv = true;
209      break;
210         default:
211             *captureProcess<<"--format"<<"raw";
212      break;
213     }
214
215     if (KdenliveSettings::autosplit()) *captureProcess<<"--autosplit";
216     if (KdenliveSettings::timestamp()) *captureProcess<<"--timestamp";
217     *captureProcess<<"-i"<<"capture"<<"-";*/
218
219     /*
220         QStringList captureArgs;
221         captureArgs<<"--format"<<"hdv"<<"-i"<<"capture"<<"-";
222         QStringList displayArgs;
223
224         displayArgs<<"-f"<<"mpegts"<<"-x"<<QString::number(ui.video_frame->width())<<"-y"<<QString::number(ui.video_frame->height())<<"-";
225
226         captureProcess->setStandardOutputProcess(displayProcess);
227         ui.video_frame->setScaledContents(false);
228         captureProcess->start("dvgrab",captureArgs);
229         displayProcess->start("ffplay",  displayArgs);*/
230
231
232     if (captureProcess->state() != QProcess::NotRunning) {
233         if (ui.device_selector->currentIndex() == FIREWIRE) {
234             if (m_isPlaying) {
235                 captureProcess->write("k", 1);
236                 //captureProcess->write("\e", 2);
237                 m_playAction->setIcon(m_playIcon);
238                 m_isPlaying = false;
239             } else {
240                 captureProcess->write("p", 1);
241                 m_playAction->setIcon(m_pauseIcon);
242                 m_isPlaying = true;
243             }
244         }
245         return;
246     }
247     m_captureArgs.clear();
248     m_displayArgs.clear();
249     m_isPlaying = false;
250
251     switch (ui.device_selector->currentIndex()) {
252     case FIREWIRE:
253         m_captureArgs << "--format" << "hdv" << "-i" << "capture" << "-";
254         m_displayArgs << "-f" << "mpegts" << "-x" << QString::number(ui.video_frame->width()) << "-y" << QString::number(ui.video_frame->height()) << "-";
255         captureProcess->setStandardOutputProcess(displayProcess);
256         captureProcess->setWorkingDirectory(KdenliveSettings::capturefolder());
257         captureProcess->start("dvgrab", m_captureArgs);
258         if (play) captureProcess->write(" ", 1);
259         m_discAction->setEnabled(true);
260         break;
261     case VIDEO4LINUX:
262         m_captureArgs << KdenliveSettings::video4capture().simplified().split(' ') << "-";
263         m_displayArgs << KdenliveSettings::video4playback().simplified().split(' ') << "-x" << QString::number(ui.video_frame->width()) << "-y" << QString::number(ui.video_frame->height()) << "-";
264         captureProcess->setStandardOutputProcess(displayProcess);
265         captureProcess->start("ffmpeg", m_captureArgs);
266         break;
267     default:
268         break;
269     }
270
271     if (ui.device_selector->currentIndex() != SCREENGRAB) {
272         displayProcess->start("ffplay", m_displayArgs);
273         ui.video_frame->setText(i18n("Initialising..."));
274     } else {
275         // do something when starting screen grab
276     }
277 }
278
279 void RecMonitor::slotRecord() {
280     if (captureProcess->state() == QProcess::NotRunning && ui.device_selector->currentIndex() == FIREWIRE) {
281         slotStartCapture();
282     }
283     if (m_isCapturing) {
284         switch (ui.device_selector->currentIndex()) {
285         case FIREWIRE:
286             captureProcess->write("\e", 2);
287             m_playAction->setIcon(m_playIcon);
288             m_isCapturing = false;
289             m_isPlaying = false;
290             m_recAction->setChecked(false);
291             break;
292         case VIDEO4LINUX:
293             slotStopCapture();
294             //m_isCapturing = false;
295             QTimer::singleShot(1000, this, SLOT(slotStartCapture()));
296             break;
297         case SCREENGRAB:
298             captureProcess->write("q\n", 3);
299             // in case ffmpeg doesn't exit with the 'q' command, kill it one second later
300             QTimer::singleShot(1000, captureProcess, SLOT(kill()));
301             break;
302         }
303         return;
304     } else if (ui.device_selector->currentIndex() == FIREWIRE) {
305         m_isCapturing = true;
306         captureProcess->write("c\n", 3);
307         return;
308     }
309     if (captureProcess->state() == QProcess::NotRunning) {
310         m_recAction->setChecked(true);
311         QString extension = "mpg";
312         if (ui.device_selector->currentIndex() == SCREENGRAB) extension = KdenliveSettings::screengrabextension();
313         QString path = KdenliveSettings::capturefolder() + "/capture0000." + extension;
314         int i = 1;
315         while (QFile::exists(path)) {
316             QString num = QString::number(i).rightJustified(4, '0', false);
317             path = KdenliveSettings::capturefolder() + "/capture" + num + "." + extension;
318             i++;
319         }
320
321         m_captureFile = KUrl(path);
322
323         m_captureArgs.clear();
324         m_displayArgs.clear();
325         QString args;
326
327         switch (ui.device_selector->currentIndex()) {
328         case FIREWIRE:
329             m_captureArgs << "--format" << "hdv" << "-i" << "capture" << "-";
330             m_displayArgs << "-f" << "mpegts" << "-x" << QString::number(ui.video_frame->width()) << "-y" << QString::number(ui.video_frame->height()) << "-";
331             captureProcess->setStandardOutputProcess(displayProcess);
332             captureProcess->start("dvgrab", m_captureArgs);
333             break;
334         case VIDEO4LINUX:
335             m_captureArgs << KdenliveSettings::video4capture().simplified().split(' ') << "-y" << m_captureFile.path() << "-f" << KdenliveSettings::video4vencoding() << "-";
336             m_displayArgs << KdenliveSettings::video4playback().simplified().split(' ') << "-x" << QString::number(ui.video_frame->width()) << "-y" << QString::number(ui.video_frame->height()) << "-";
337             captureProcess->setStandardOutputProcess(displayProcess);
338             captureProcess->start("ffmpeg", m_captureArgs);
339             break;
340         case SCREENGRAB:
341             if (KdenliveSettings::fullscreengrab()) {
342                 const QRect rect = QApplication::desktop()->screenGeometry();
343                 args = KdenliveSettings::screengrabcapture().replace("%size", QString::number(rect.width()) + "x" + QString::number(rect.height())).replace("%offset", QString());
344                 kDebug() << "// capture params: " << args;
345                 m_captureArgs << args.simplified().split(' ') << KdenliveSettings::screengrabencoding().simplified().split(' ') << m_captureFile.path();
346                 ui.video_frame->setText(i18n("Capturing..."));
347                 m_isCapturing = true;
348                 captureProcess->start("ffmpeg", m_captureArgs);
349             } else {
350                 ui.video_frame->setText(i18n("Select region..."));
351                 rgnGrab = new RegionGrabber();
352                 connect(rgnGrab, SIGNAL(regionGrabbed(const QRect&)), SLOT(slotStartGrab(const QRect &)));
353             }
354             break;
355         default:
356             break;
357         }
358
359         //ui.video_frame->setScaledContents(false);
360         if (ui.device_selector->currentIndex() != SCREENGRAB) {
361             m_isCapturing = true;
362             displayProcess->start("ffplay", m_displayArgs);
363             ui.video_frame->setText(i18n("Initialising..."));
364         }
365     } else {
366         // stop capture
367         displayProcess->kill();
368         captureProcess->kill();
369         QTimer::singleShot(1000, this, SLOT(slotRecord()));
370     }
371 }
372
373 void RecMonitor::slotStartGrab(const QRect &rect) {
374     rgnGrab->deleteLater();
375     QApplication::restoreOverrideCursor();
376     show();
377     if (rect.isNull()) return;
378     int width = rect.width();
379     int height = rect.height();
380     if (width % 2 != 0) width--;
381     if (height % 2 != 0) height--;
382     QString args = KdenliveSettings::screengrabcapture().replace("%size", QString::number(width) + "x" + QString::number(height)).replace("%offset", "+" + QString::number(rect.x()) + "," + QString::number(rect.y()));
383     kDebug() << "// capture params: " << args;
384     m_captureArgs << args.simplified().split(' ') << KdenliveSettings::screengrabencoding().simplified().split(' ') << m_captureFile.path();
385     m_isCapturing = true;
386     ui.video_frame->setText(i18n("Capturing..."));
387     captureProcess->start("ffmpeg", m_captureArgs);
388 }
389
390 void RecMonitor::slotProcessStatus(QProcess::ProcessState status) {
391     if (status == QProcess::NotRunning) {
392         displayProcess->kill();
393         if (m_isCapturing && ui.device_selector->currentIndex() != FIREWIRE)
394             if (ui.autoaddbox->isChecked()) emit addProjectClip(m_captureFile);
395         if (ui.device_selector->currentIndex() == FIREWIRE) {
396             m_discAction->setIcon(KIcon("network-connect"));
397             m_discAction->setText(i18n("Connect"));
398             m_playAction->setEnabled(false);
399             m_rewAction->setEnabled(false);
400             m_fwdAction->setEnabled(false);
401         }
402         m_isCapturing = false;
403         m_isPlaying = false;
404         m_playAction->setIcon(m_playIcon);
405         m_recAction->setChecked(false);
406         m_stopAction->setEnabled(false);
407         ui.device_selector->setEnabled(true);
408         if (captureProcess && captureProcess->exitStatus() == QProcess::CrashExit) {
409             ui.video_frame->setText(i18n("Capture crashed, please check your parameters"));
410         } else ui.video_frame->setText(i18n("Not connected"));
411     } else {
412         if (ui.device_selector->currentIndex() != SCREENGRAB) m_stopAction->setEnabled(true);
413         ui.device_selector->setEnabled(false);
414     }
415 }
416
417 // virtual
418 void RecMonitor::mousePressEvent(QMouseEvent * event) {
419     slotPlay();
420 }
421
422 void RecMonitor::activateRecMonitor() {
423     //if (!m_isActive) m_monitorManager->activateRecMonitor(m_name);
424 }
425
426 void RecMonitor::stop() {
427     m_isActive = false;
428
429 }
430
431 void RecMonitor::start() {
432     m_isActive = true;
433
434 }
435
436 void RecMonitor::refreshRecMonitor(bool visible) {
437     if (visible) {
438         //if (!m_isActive) m_monitorManager->activateRecMonitor(m_name);
439
440     }
441 }
442
443 void RecMonitor::slotPlay() {
444
445     //if (!m_isActive) m_monitorManager->activateRecMonitor(m_name);
446
447 }
448
449
450 #include "recmonitor.moc"