diff --git a/src/monitor/recmanager.cpp b/src/monitor/recmanager.cpp
index 4a0088372..35cfcc9df 100644
--- a/src/monitor/recmanager.cpp
+++ b/src/monitor/recmanager.cpp
@@ -1,442 +1,467 @@
/***************************************************************************
* Copyright (C) 2015 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
* This file is part of Kdenlive. See www.kdenlive.org. *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License or (at your option) version 3 or any later version *
* accepted by the membership of KDE e.V. (or its successor approved *
* by the membership of KDE e.V.), which shall act as a proxy *
* defined in Section 14 of version 3 of the license. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
***************************************************************************/
#include "recmanager.h"
#include "capture/managecapturesdialog.h"
#include "capture/mltdevicecapture.h"
#include "core.h"
#include "dialogs/profilesdialog.h"
#include "kdenlivesettings.h"
#include "monitor.h"
#include "klocalizedstring.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
RecManager::RecManager(Monitor *parent)
: QObject(parent)
, m_monitor(parent)
, m_recToolbar(new QToolBar(parent))
, m_checkAudio(false)
, m_checkVideo(false)
, m_screenIndex(-1)
{
m_playAction = m_recToolbar->addAction(QIcon::fromTheme(QStringLiteral("media-playback-start")), i18n("Preview"));
m_playAction->setCheckable(true);
connect(m_playAction, &QAction::toggled, this, &RecManager::slotPreview);
m_recAction = new QAction(QIcon::fromTheme(QStringLiteral("media-record")), i18n("Record"));
m_recAction->setCheckable(true);
connect(m_recAction, &QAction::toggled, this, &RecManager::slotRecord);
m_showLogAction = new QAction(i18n("Show log"), this);
connect(m_showLogAction, &QAction::triggered, this, &RecManager::slotShowLog);
m_recVideo = new QCheckBox(i18n("Video"));
m_recAudio = new QCheckBox(i18n("Audio"));
m_recToolbar->addWidget(m_recVideo);
m_recToolbar->addWidget(m_recAudio);
m_recAudio->setChecked(KdenliveSettings::v4l_captureaudio());
m_recVideo->setChecked(KdenliveSettings::v4l_capturevideo());
QWidget *spacer = new QWidget(parent);
spacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
m_recToolbar->addWidget(spacer);
m_audio_device = new QComboBox(parent);
QStringList audioDevices = pCore->getAudioCaptureDevices();
m_audio_device->addItems(audioDevices);
connect(m_audio_device, static_cast(&QComboBox::currentIndexChanged), this, &RecManager::slotAudioDeviceChanged);
QString selectedDevice = KdenliveSettings::defaultaudiocapture();
int selectedIndex = m_audio_device->findText(selectedDevice);
if (!selectedDevice.isNull() && selectedIndex > -1) {
m_audio_device->setCurrentIndex(selectedIndex);
}
m_recToolbar->addWidget(m_audio_device);
m_audioCaptureSlider = new QSlider(Qt::Vertical);
m_audioCaptureSlider->setRange(0, 100);
m_audioCaptureSlider->setValue(KdenliveSettings::audiocapturevolume());
connect(m_audioCaptureSlider, &QSlider::valueChanged, this, &RecManager::slotSetVolume);
auto *widgetslider = new QWidgetAction(parent);
widgetslider->setText(i18n("Audio Capture Volume"));
widgetslider->setDefaultWidget(m_audioCaptureSlider);
auto *menu = new QMenu(parent);
menu->addAction(widgetslider);
m_audioCaptureButton = new QToolButton(parent);
m_audioCaptureButton->setMenu(menu);
m_audioCaptureButton->setToolTip(i18n("Audio Capture Volume"));
m_audioCaptureButton->setPopupMode(QToolButton::InstantPopup);
QIcon icon;
if (KdenliveSettings::audiocapturevolume() == 0) {
icon = QIcon::fromTheme(QStringLiteral("audio-volume-muted"));
} else {
icon = QIcon::fromTheme(QStringLiteral("audio-volume-medium"));
}
m_audioCaptureButton->setIcon(icon);
m_recToolbar->addWidget(m_audioCaptureButton);
m_recToolbar->addSeparator();
m_device_selector = new QComboBox(parent);
// TODO: re-implement firewire / decklink capture
// m_device_selector->addItems(QStringList() << i18n("Firewire") << i18n("Webcam") << i18n("Screen Grab") << i18n("Blackmagic Decklink"));
m_device_selector->addItem(i18n("Webcam"), Video4Linux);
m_device_selector->addItem(i18n("Screen Grab"), ScreenGrab);
selectedIndex = m_device_selector->findData(KdenliveSettings::defaultcapture());
if (selectedIndex > -1) {
m_device_selector->setCurrentIndex(selectedIndex);
}
connect(m_device_selector, static_cast(&QComboBox::currentIndexChanged), this, &RecManager::slotVideoDeviceChanged);
m_recToolbar->addWidget(m_device_selector);
QAction *configureRec = m_recToolbar->addAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure Recording"));
connect(configureRec, &QAction::triggered, this, &RecManager::showRecConfig);
m_recToolbar->addSeparator();
m_switchRec = m_recToolbar->addAction(QIcon::fromTheme(QStringLiteral("list-add")), i18n("Show Record Control"));
m_switchRec->setCheckable(true);
connect(m_switchRec, &QAction::toggled, m_monitor, &Monitor::slotSwitchRec);
m_recToolbar->setVisible(false);
slotVideoDeviceChanged();
connect(m_monitor, &Monitor::screenChanged, this, &RecManager::slotSetScreen);
}
RecManager::~RecManager() = default;
void RecManager::showRecConfig()
{
pCore->showConfigDialog(4, m_device_selector->currentData().toInt());
}
QToolBar *RecManager::toolbar() const
{
return m_recToolbar;
}
QAction *RecManager::recAction() const
{
return m_recAction;
}
void RecManager::stopCapture()
{
if (m_captureProcess) {
slotRecord(false);
} else if (pCore->getMediaCaptureState() == 1 && (m_checkAudio || m_checkVideo)) {
// QMediaRecorder::RecordingState value is 1
pCore->stopMediaCapture(m_checkAudio, m_checkVideo);
m_monitor->slotOpenClip(nullptr);
}
}
void RecManager::stop()
{
if (m_captureProcess) {
// Don't stop screen rec when hiding rec toolbar
} else {
stopCapture();
m_switchRec->setChecked(false);
}
toolbar()->setVisible(false);
}
void RecManager::slotRecord(bool record)
{
/*if (m_device_selector->currentData().toInt() == Video4Linux) {
if (record) {
m_checkAudio = m_recAudio->isChecked();
m_checkVideo = m_recVideo->isChecked();
pCore->startMediaCapture(m_checkAudio, m_checkVideo);
} else {
stopCapture();
}
return;
}*/
if (!record) {
if (!m_captureProcess) {
return;
}
m_captureProcess->write("q");
if (!m_captureProcess->waitForFinished()) {
m_captureProcess->terminate();
QTimer::singleShot(1500, m_captureProcess, &QProcess::kill);
}
return;
}
if (m_captureProcess) {
return;
}
m_recError.clear();
QString extension = KdenliveSettings::grab_extension();
QDir captureFolder;
if (KdenliveSettings::capturetoprojectfolder()) {
captureFolder = QDir(m_monitor->projectFolder());
} else {
captureFolder = QDir(KdenliveSettings::capturefolder());
}
QFileInfo checkCaptureFolder(captureFolder.absolutePath());
if (!checkCaptureFolder.isWritable()) {
emit warningMessage(i18n("The directory %1, could not be created.\nPlease "
"make sure you have the required permissions.",
captureFolder.absolutePath()));
m_recAction->blockSignals(true);
m_recAction->setChecked(false);
m_recAction->blockSignals(false);
return;
}
m_captureProcess = new QProcess;
connect(m_captureProcess, QOverload::of(&QProcess::finished), this, &RecManager::slotProcessStatus);
connect(m_captureProcess, &QProcess::readyReadStandardError, this, &RecManager::slotReadProcessInfo);
QString path = captureFolder.absoluteFilePath("capture0000." + extension);
int i = 1;
while (QFile::exists(path)) {
QString num = QString::number(i).rightJustified(4, '0', false);
path = captureFolder.absoluteFilePath("capture" + num + QLatin1Char('.') + extension);
++i;
}
m_captureFile = QUrl::fromLocalFile(path);
QString captureSize;
QRect screenSize = QApplication::desktop()->screenGeometry(m_screenIndex);
QStringList captureArgs;
#ifdef Q_OS_WIN
captureArgs << QStringLiteral("-f") << QStringLiteral("gdigrab");
// fps
captureArgs << QStringLiteral("-framerate") << QString::number(KdenliveSettings::grab_fps());
captureSize = QStringLiteral("desktop");
+ captureArgs << QStringLiteral("-i") << captureSize;
+ if (KdenliveSettings::grab_parameters().contains(QLatin1String("alsa"))) {
+ // Add audio device
+ QString params = KdenliveSettings::grab_parameters().simplified();
+ // Use Windows dshow for audio capture
+ params.replace(QLatin1String("alsa"), QStringLiteral("dshow"));
+ // Remove vorbis codec
+ params.replace(QLatin1String("-acodec libvorbis"), QString());
+
+ // Find first audio device
+ QProcess tst;
+ tst.start(KdenliveSettings::ffmpegpath(), {"-hide_banner","-list_devices","true","-f","dshow","-i","dummy"});
+ tst.waitForFinished(4000);
+ QString dshowOutput = QString::fromUtf8(tst.readAll());
+ if (dshowOutput.contains(QLatin1String("audio devices"))) {
+ dshowOutput = dshowOutput.section(QLatin1String("audio devices"), 1);
+ dshowOutput = dshowOutput.section(QLatin1Char('"'), 1, 1);
+ params.replace(QLatin1String("default"), QString("audio=\"%1\"").arg(dshowOutput));
+ }
+ captureArgs << params.split(QLatin1Char(' '));
+ } else if (!KdenliveSettings::grab_parameters().simplified().isEmpty()) {
+ captureArgs << KdenliveSettings::grab_parameters().simplified().split(QLatin1Char(' '));
+ }
+ qDebug()<<"== STARTING WIN CAPTURE: "<start(KdenliveSettings::ffmpegpath(), captureArgs);
if (!m_captureProcess->waitForStarted()) {
// Problem launching capture app
emit warningMessage(i18n("Failed to start the capture application:\n%1", KdenliveSettings::ffmpegpath()));
// delete m_captureProcess;
}
}
void RecManager::slotProcessStatus(int exitCode, QProcess::ExitStatus exitStatus)
{
m_recAction->setEnabled(true);
m_recAction->setChecked(false);
m_device_selector->setEnabled(true);
if (exitStatus == QProcess::CrashExit) {
emit warningMessage(i18n("Capture crashed, please check your parameters"), -1, QList() << m_showLogAction);
} else {
if (exitCode != 0 && exitCode != 255) {
emit warningMessage(i18n("Capture crashed, please check your parameters"), -1, QList() << m_showLogAction);
} else {
// Capture successful, add clip to project
emit addClipToProject(m_captureFile);
}
}
if (m_captureProcess) {
delete m_captureProcess;
m_captureProcess = nullptr;
}
}
void RecManager::slotReadProcessInfo()
{
QString data = m_captureProcess->readAllStandardError().simplified();
m_recError.append(data + QLatin1Char('\n'));
}
void RecManager::slotAudioDeviceChanged(int)
{
QString currentDevice = m_audio_device->currentText();
KdenliveSettings::setDefaultaudiocapture(currentDevice);
}
void RecManager::slotSetVolume(int volume)
{
KdenliveSettings::setAudiocapturevolume(volume);
QIcon icon;
if (volume == 0) {
icon = QIcon::fromTheme(QStringLiteral("audio-volume-muted"));
} else {
icon = QIcon::fromTheme(QStringLiteral("audio-volume-medium"));
}
m_audioCaptureButton->setIcon(icon);
}
void RecManager::slotVideoDeviceChanged(int)
{
int currentItem = m_device_selector->currentData().toInt();
KdenliveSettings::setDefaultcapture(currentItem);
switch (currentItem) {
case Video4Linux:
m_playAction->setEnabled(true);
break;
case BlackMagic:
m_playAction->setEnabled(false);
break;
default:
m_playAction->setEnabled(false);
break;
}
/*
m_previewSettings->setEnabled(ix == Video4Linux || ix == BlackMagic);
control_frame->setVisible(ix == Video4Linux);
monitor_box->setVisible(ix == ScreenBag && monitor_box->count() > 0);
m_playAction->setVisible(ix != ScreenBag);
m_fwdAction->setVisible(ix == Firewire);
m_discAction->setVisible(ix == Firewire);
m_rewAction->setVisible(ix == Firewire);
m_recAction->setEnabled(ix != Firewire);
m_logger.setVisible(ix == BlackMagic);
if (m_captureDevice) {
// MLT capture still running, abort
m_monitorManager->clearScopeSource();
m_captureDevice->stop();
delete m_captureDevice;
m_captureDevice = nullptr;
}
// The m_videoBox container has to be shown once before the MLT consumer is build, or preview will fail
switch (ix) {
case ScreenBag:
}
*/
}
Mlt::Producer *RecManager::createV4lProducer()
{
QString profilePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/profiles/video4linux");
Mlt::Profile *vidProfile = new Mlt::Profile(profilePath.toUtf8().constData());
Mlt::Producer *prod = nullptr;
if (m_recVideo->isChecked()) {
prod = new Mlt::Producer(*vidProfile, QStringLiteral("video4linux2:%1").arg(KdenliveSettings::video4vdevice()).toUtf8().constData());
if ((prod == nullptr) || !prod->is_valid()) {
return nullptr;
}
prod->set("width", vidProfile->width());
prod->set("height", vidProfile->height());
prod->set("framerate", vidProfile->fps());
/*p->set("standard", ui->v4lStandardCombo->currentText().toLatin1().constData());
p->set("channel", ui->v4lChannelSpinBox->value());
p->set("audio_ix", ui->v4lAudioComboBox->currentIndex());*/
prod->set("force_seekable", 0);
}
if (m_recAudio->isChecked() && (prod != nullptr) && prod->is_valid()) {
// Add audio track
Mlt::Producer *audio = new Mlt::Producer(
*vidProfile,
QStringLiteral("alsa:%1?channels=%2").arg(KdenliveSettings::v4l_alsadevicename()).arg(KdenliveSettings::alsachannels()).toUtf8().constData());
audio->set("mlt_service", "avformat-novalidate");
audio->set("audio_index", 0);
audio->set("video_index", -1);
auto *tractor = new Mlt::Tractor(*vidProfile);
tractor->set_track(*prod, 0);
delete prod;
tractor->set_track(*audio, 1);
delete audio;
prod = new Mlt::Producer(tractor->get_producer());
delete tractor;
}
return prod;
}
void RecManager::slotSetScreen(int screenIndex)
{
m_screenIndex = screenIndex;
}
void RecManager::slotPreview(bool preview)
{
if (m_device_selector->currentData().toInt() == Video4Linux) {
if (preview) {
std::shared_ptr prod(createV4lProducer());
if (prod && prod->is_valid()) {
m_monitor->updateClipProducer(prod);
} else {
emit warningMessage(i18n("Capture crashed, please check your parameters"));
}
} else {
m_monitor->slotOpenClip(nullptr);
}
}
/*
buildMltDevice(path);
bool isXml;
producer = getV4lXmlPlaylist(profile, &isXml);
//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);
if (!m_captureDevice->slotStartPreview(producer, isXml)) {
// v4l capture failed to start
video_frame->setText(i18n("Failed to start Video4Linux,\ncheck your parameters..."));
} else {
m_playAction->setEnabled(false);
m_stopAction->setEnabled(true);
m_isPlaying = true;
}
}*/
}
void RecManager::slotShowLog()
{
KMessageBox::information(QApplication::activeWindow(), m_recError);
}