diff --git a/src/capture/mediacapture.cpp b/src/capture/mediacapture.cpp index c7cbb193e..1a24ced5d 100644 --- a/src/capture/mediacapture.cpp +++ b/src/capture/mediacapture.cpp @@ -1,304 +1,306 @@ /* Copyright (C) 2019 Akhil K Gangadharan 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 "mediacapture.h" #include "kdenlivesettings.h" #include "core.h" #include #include #include #include MediaCapture::MediaCapture(QObject *parent) : QObject(parent) , m_volume(1.) , currentState(-1) , m_audioDevice("default:") , m_path(QUrl()) { m_probe = std::make_unique(this); connect(m_probe.get(), &QAudioProbe::audioBufferProbed, this, &MediaCapture::processBuffer); } MediaCapture::~MediaCapture() = default; void MediaCapture::displayErrorMessage() { qDebug() << " !!!!!!!!!!!!!!!! ERROR : QMediarecorder - Capture failed"; } void MediaCapture::recordAudio(bool record) { if (!m_audioRecorder) { m_audioRecorder = std::make_unique(this); + m_probe->setSource(m_audioRecorder.get()); } - m_probe->setSource(m_audioRecorder.get()); if (record && m_audioRecorder->state() == QMediaRecorder::StoppedState) { setAudioCaptureDevice(); m_audioRecorder->setAudioInput(m_audioDevice); setCaptureOutputLocation(); m_audioRecorder->setOutputLocation(m_path); setAudioVolume(); m_audioRecorder->setVolume(m_volume); connect(m_audioRecorder.get(), SIGNAL(error(QMediaRecorder::Error)), this, SLOT(displayErrorMessage())); QAudioEncoderSettings audioSettings; - audioSettings.setBitRate(48000); + audioSettings.setBitRate(48000); // Bit rate is set to 48,0000 QString container = "audio/x-wav"; m_audioRecorder->setEncodingSettings(audioSettings, QVideoEncoderSettings(), container); m_audioRecorder->record(); } else if (m_audioRecorder->state() != QMediaRecorder::PausedState) { m_audioRecorder->stop(); m_audioRecorder.reset(); } else { m_audioRecorder->record(); } } void MediaCapture::recordVideo(bool record) { // TO DO - fix video capture if (!m_videoRecorder) { QList availableCameras = QCameraInfo::availableCameras(); foreach (const QCameraInfo &cameraInfo, availableCameras) { if (cameraInfo == QCameraInfo::defaultCamera()) { m_camera = std::make_unique(cameraInfo, this); break; } } m_videoRecorder = std::make_unique(m_camera.get(), this); } if (record && m_videoRecorder->state() == QMediaRecorder::StoppedState) { setCaptureOutputLocation(); m_videoRecorder->setOutputLocation(m_path); connect(m_videoRecorder.get(), SIGNAL(error(QMediaRecorder::Error)), this, SLOT(displayErrorMessage())); m_camera->setCaptureMode(QCamera::CaptureVideo); m_camera->start(); // QString container = "video/mpeg"; // By default, Qt chooses appropriate parameters m_videoRecorder->record(); } else { m_videoRecorder->stop(); m_camera->stop(); m_videoRecorder.reset(); m_camera.reset(); } } void MediaCapture::setCaptureOutputLocation() { QDir captureFolder; if (KdenliveSettings::capturetoprojectfolder()) { captureFolder = QDir(pCore->getProjectFolderName()); } else { captureFolder = QDir(KdenliveSettings::capturefolder()); } QString extension; if (m_videoRecorder.get() != nullptr) { - extension = QStringLiteral("mpeg"); + extension = QStringLiteral(".mpeg"); } else if (m_audioRecorder.get() != nullptr) { - extension = QStringLiteral("wav"); + extension = QStringLiteral(".wav"); } - QString path = captureFolder.absoluteFilePath("capture0000." + extension); + QString path = captureFolder.absoluteFilePath("capture0000" + extension); int fileCount = 1; while (QFile::exists(path)) { QString num = QString::number(fileCount).rightJustified(4, '0', false); - path = captureFolder.absoluteFilePath("capture" + num + QLatin1Char('.') + extension); + path = captureFolder.absoluteFilePath("capture" + num + extension); ++fileCount; } m_path = std::move(QUrl::fromLocalFile(path)); } QUrl MediaCapture::getCaptureOutputLocation() { return m_path; } + QStringList MediaCapture::getAudioCaptureDevices() { - m_audioRecorder = std::make_unique(this); - QStringList audioDevices = m_audioRecorder->audioInputs(); - m_audioRecorder.reset(); + std::unique_ptr audioRecorder = std::make_unique(this); + QStringList audioDevices = audioRecorder->audioInputs(); + audioRecorder.reset(); return audioDevices; } void MediaCapture::setAudioCaptureDevice() { - QStringList audioDevices = getAudioCaptureDevices(); - int deviceIndex = KdenliveSettings::defaultaudiocapture(); - m_audioDevice = std::move(audioDevices[deviceIndex]); + QString deviceName = KdenliveSettings::defaultaudiocapture(); + if(!deviceName.isNull()) { + m_audioDevice = std::move(deviceName); + } } void MediaCapture::setAudioVolume() { m_volume = KdenliveSettings::audiocapturevolume()/100.0; } int MediaCapture::getState() { if (m_audioRecorder != nullptr) { currentState = m_audioRecorder->state(); } else if (m_videoRecorder != nullptr) { currentState = m_videoRecorder->state(); } return currentState; } template QVector getBufferLevels(const T *buffer, int frames, int channels) { QVector max_values; max_values.fill(0, channels); for (int i = 0; i < frames; ++i) { for (int j = 0; j < channels; ++j) { qreal value = qAbs(qreal(buffer[i * channels + j])); if (value > max_values.at(j)) { max_values.replace(j, value); } } } return max_values; } // This function returns the maximum possible sample value for a given audio format qreal getPeakValue(const QAudioFormat &format) { // Note: Only the most common sample formats are supported if (!format.isValid()) { return qreal(0); } if (format.codec() != "audio/pcm") { return qreal(0); } switch (format.sampleType()) { case QAudioFormat::Unknown: break; case QAudioFormat::Float: if (format.sampleSize() != 32) { // other sample formats are not supported return qreal(0); } return qreal(1.00003); case QAudioFormat::SignedInt: if (format.sampleSize() == 32) { return qreal(INT_MAX); } if (format.sampleSize() == 16) { return qreal(SHRT_MAX); } if (format.sampleSize() == 8) { return qreal(CHAR_MAX); } break; case QAudioFormat::UnSignedInt: if (format.sampleSize() == 32) { return qreal(UINT_MAX); } if (format.sampleSize() == 16) { return qreal(USHRT_MAX); } if (format.sampleSize() == 8) { return qreal(UCHAR_MAX); } break; } return qreal(0); } QVector getBufferLevels(const QAudioBuffer &buffer) { QVector values; if (!buffer.format().isValid() || buffer.format().byteOrder() != QAudioFormat::LittleEndian) { return values; } if (buffer.format().codec() != "audio/pcm") { return values; } int channelCount = buffer.format().channelCount(); values.fill(0, channelCount); qreal peak_value = getPeakValue(buffer.format()); if (qFuzzyCompare(peak_value, qreal(0))) { return values; } switch (buffer.format().sampleType()) { case QAudioFormat::Unknown: case QAudioFormat::UnSignedInt: if (buffer.format().sampleSize() == 32) { values = getBufferLevels(buffer.constData(), buffer.frameCount(), channelCount); } if (buffer.format().sampleSize() == 16) { values = getBufferLevels(buffer.constData(), buffer.frameCount(), channelCount); } if (buffer.format().sampleSize() == 8) { values = getBufferLevels(buffer.constData(), buffer.frameCount(), channelCount); } for (double &value : values) { value = qAbs(value - peak_value / 2) / (peak_value / 2); } break; case QAudioFormat::Float: if (buffer.format().sampleSize() == 32) { values = getBufferLevels(buffer.constData(), buffer.frameCount(), channelCount); for (double &value : values) { value /= peak_value; } } break; case QAudioFormat::SignedInt: if (buffer.format().sampleSize() == 32) { values = getBufferLevels(buffer.constData(), buffer.frameCount(), channelCount); } if (buffer.format().sampleSize() == 16) { values = getBufferLevels(buffer.constData(), buffer.frameCount(), channelCount); } if (buffer.format().sampleSize() == 8) { values = getBufferLevels(buffer.constData(), buffer.frameCount(), channelCount); } for (double &value : values) { value /= peak_value; } break; } return values; } void MediaCapture::processBuffer(const QAudioBuffer &buffer) { m_levels = getBufferLevels(buffer); emit levelsChanged(); } QVector MediaCapture::levels() const { return m_levels; } \ No newline at end of file diff --git a/src/core.cpp b/src/core.cpp index cb6547ad2..71528ddad 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1,722 +1,722 @@ /* Copyright (C) 2014 Till Theato 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 3 of the License, or (at your option) any later version. */ #include "core.h" #include "bin/bin.h" #include "bin/projectitemmodel.h" #include "capture/mediacapture.h" #include "doc/docundostack.hpp" #include "doc/kdenlivedoc.h" #include "jobs/jobmanager.h" #include "kdenlive_debug.h" #include "kdenlivesettings.h" #include "library/librarywidget.h" #include "mainwindow.h" #include "mltconnection.h" #include "mltcontroller/clipcontroller.h" #include "monitor/monitormanager.h" #include "profiles/profilemodel.hpp" #include "profiles/profilerepository.hpp" #include "project/projectmanager.h" #include "timeline2/model/timelineitemmodel.hpp" #include "timeline2/view/timelinecontroller.h" #include "timeline2/view/timelinewidget.h" #include #include #include #include #include #include #include #ifdef Q_OS_MAC #include #endif std::unique_ptr Core::m_self; Core::Core() : m_thumbProfile(nullptr) , m_capture(new MediaCapture(this)) { } void Core::prepareShutdown() { m_guiConstructed = false; } Core::~Core() { if (m_monitorManager) { delete m_monitorManager; } // delete m_binWidget; if (m_projectManager) { delete m_projectManager; } ClipController::mediaUnavailable.reset(); } void Core::build(const QString &MltPath) { if (m_self) { return; } m_self.reset(new Core()); m_self->initLocale(); qRegisterMetaType("audioShortVector"); qRegisterMetaType>("QVector"); qRegisterMetaType("MessageType"); qRegisterMetaType("stringMap"); qRegisterMetaType("audioByteArray"); qRegisterMetaType>("QList"); qRegisterMetaType>("std::shared_ptr"); qRegisterMetaType>(); qRegisterMetaType("QDomElement"); qRegisterMetaType("requestClipInfo"); // Open connection with Mlt MltConnection::construct(MltPath); // load the profile from disk ProfileRepository::get()->refresh(); // load default profile m_self->m_profile = KdenliveSettings::default_profile(); if (m_self->m_profile.isEmpty()) { m_self->m_profile = ProjectManager::getDefaultProjectFormat(); KdenliveSettings::setDefault_profile(m_self->m_profile); } // Init producer shown for unavailable media // TODO make it a more proper image, it currently causes a crash on exit ClipController::mediaUnavailable = std::make_shared(ProfileRepository::get()->getProfile(m_self->m_profile)->profile(), "color:blue"); ClipController::mediaUnavailable->set("length", 99999999); m_self->m_projectItemModel = ProjectItemModel::construct(); // Job manager must be created before bin to correctly connect m_self->m_jobManager.reset(new JobManager(m_self.get())); } void Core::initGUI(const QUrl &Url) { m_guiConstructed = true; m_profile = KdenliveSettings::default_profile(); m_currentProfile = m_profile; profileChanged(); m_mainWindow = new MainWindow(); // load default profile and ask user to select one if not found. if (m_profile.isEmpty()) { m_profile = ProjectManager::getDefaultProjectFormat(); profileChanged(); KdenliveSettings::setDefault_profile(m_profile); } if (!ProfileRepository::get()->profileExists(m_profile)) { KMessageBox::sorry(m_mainWindow, i18n("The default profile of Kdenlive is not set or invalid, press OK to set it to a correct value.")); // TODO this simple widget should be improved and probably use profileWidget // we get the list of profiles QVector> all_profiles = ProfileRepository::get()->getAllProfiles(); QStringList all_descriptions; for (const auto &profile : all_profiles) { all_descriptions << profile.first; } // ask the user bool ok; QString item = QInputDialog::getItem(m_mainWindow, i18n("Select Default Profile"), i18n("Profile:"), all_descriptions, 0, false, &ok); if (ok) { ok = false; for (const auto &profile : all_profiles) { if (profile.first == item) { m_profile = profile.second; ok = true; } } } if (!ok) { KMessageBox::error( m_mainWindow, i18n("The given profile is invalid. We default to the profile \"dv_pal\", but you can change this from Kdenlive's settings panel")); m_profile = QStringLiteral("dv_pal"); } KdenliveSettings::setDefault_profile(m_profile); profileChanged(); } m_projectManager = new ProjectManager(this); m_binWidget = new Bin(m_projectItemModel, m_mainWindow); m_library = new LibraryWidget(m_projectManager, m_mainWindow); connect(m_library, SIGNAL(addProjectClips(QList)), m_binWidget, SLOT(droppedUrls(QList))); connect(this, &Core::updateLibraryPath, m_library, &LibraryWidget::slotUpdateLibraryPath); m_monitorManager = new MonitorManager(this); // Producer queue, creating MLT::Producers on request /* m_producerQueue = new ProducerQueue(m_binController); connect(m_producerQueue, &ProducerQueue::gotFileProperties, m_binWidget, &Bin::slotProducerReady); connect(m_producerQueue, &ProducerQueue::replyGetImage, m_binWidget, &Bin::slotThumbnailReady); connect(m_producerQueue, &ProducerQueue::requestProxy, [this](const QString &id){ m_binWidget->startJob(id, AbstractClipJob::PROXYJOB);}); connect(m_producerQueue, &ProducerQueue::removeInvalidClip, m_binWidget, &Bin::slotRemoveInvalidClip, Qt::DirectConnection); connect(m_producerQueue, SIGNAL(addClip(QString, QMap)), m_binWidget, SLOT(slotAddUrl(QString, QMap))); connect(m_binController.get(), SIGNAL(createThumb(QDomElement, QString, int)), m_producerQueue, SLOT(getFileProperties(QDomElement, QString, int))); connect(m_binWidget, &Bin::producerReady, m_producerQueue, &ProducerQueue::slotProcessingDone, Qt::DirectConnection); // TODO connect(m_producerQueue, SIGNAL(removeInvalidProxy(QString,bool)), m_binWidget, SLOT(slotRemoveInvalidProxy(QString,bool)));*/ m_mainWindow->init(); projectManager()->init(Url, QString()); if (qApp->isSessionRestored()) { // NOTE: we are restoring only one window, because Kdenlive only uses one MainWindow m_mainWindow->restore(1, false); } QMetaObject::invokeMethod(pCore->projectManager(), "slotLoadOnOpen", Qt::QueuedConnection); m_mainWindow->show(); } std::unique_ptr &Core::self() { if (!m_self) { qDebug() << "Error : Core has not been created"; } return m_self; } MainWindow *Core::window() { return m_mainWindow; } ProjectManager *Core::projectManager() { return m_projectManager; } MonitorManager *Core::monitorManager() { return m_monitorManager; } Monitor *Core::getMonitor(int id) { if (id == Kdenlive::ClipMonitor) { return m_monitorManager->clipMonitor(); } return m_monitorManager->projectMonitor(); } Bin *Core::bin() { return m_binWidget; } void Core::selectBinClip(const QString &clipId, int frame, const QPoint &zone) { m_binWidget->selectClipById(clipId, frame, zone); } std::shared_ptr Core::jobManager() { return m_jobManager; } LibraryWidget *Core::library() { return m_library; } void Core::initLocale() { QLocale systemLocale = QLocale(); #ifndef Q_OS_MAC setlocale(LC_NUMERIC, nullptr); #else setlocale(LC_NUMERIC_MASK, nullptr); #endif // localeconv()->decimal_point does not give reliable results on Windows #ifndef Q_OS_WIN char *separator = localeconv()->decimal_point; if (QString::fromUtf8(separator) != QChar(systemLocale.decimalPoint())) { // qCDebug(KDENLIVE_LOG)<<"------\n!!! system locale is not similar to Qt's locale... be prepared for bugs!!!\n------"; // HACK: There is a locale conflict, so set locale to C // Make sure to override exported values or it won't work qputenv("LANG", "C"); #ifndef Q_OS_MAC setlocale(LC_NUMERIC, "C"); #else setlocale(LC_NUMERIC_MASK, "C"); #endif systemLocale = QLocale::c(); } #endif systemLocale.setNumberOptions(QLocale::OmitGroupSeparator); QLocale::setDefault(systemLocale); } std::unique_ptr &Core::getMltRepository() { return MltConnection::self()->getMltRepository(); } std::unique_ptr &Core::getCurrentProfile() const { return ProfileRepository::get()->getProfile(m_currentProfile); } const QString &Core::getCurrentProfilePath() const { return m_currentProfile; } bool Core::setCurrentProfile(const QString &profilePath) { if (m_currentProfile == profilePath) { // no change required return true; } if (ProfileRepository::get()->profileExists(profilePath)) { m_currentProfile = profilePath; m_thumbProfile.reset(); // inform render widget m_mainWindow->updateRenderWidgetProfile(); if (m_guiConstructed && m_mainWindow->getCurrentTimeline()->controller()->getModel()) { m_mainWindow->getCurrentTimeline()->controller()->getModel()->updateProfile(&getCurrentProfile()->profile()); checkProfileValidity(); } return true; } return false; } void Core::checkProfileValidity() { int offset = (getCurrentProfile()->profile().width() % 8) + (getCurrentProfile()->profile().height() % 2); if (offset > 0) { // Profile is broken, warn user if (m_binWidget) { m_binWidget->displayBinMessage(i18n("Your project profile is invalid, rendering might fail."), KMessageWidget::Warning); } } } double Core::getCurrentSar() const { return getCurrentProfile()->sar(); } double Core::getCurrentDar() const { return getCurrentProfile()->dar(); } double Core::getCurrentFps() const { return getCurrentProfile()->fps(); } QSize Core::getCurrentFrameDisplaySize() const { return {(int)(getCurrentProfile()->height() * getCurrentDar() + 0.5), getCurrentProfile()->height()}; } QSize Core::getCurrentFrameSize() const { return {getCurrentProfile()->width(), getCurrentProfile()->height()}; } void Core::requestMonitorRefresh() { if (!m_guiConstructed) return; m_monitorManager->refreshProjectMonitor(); } void Core::refreshProjectRange(QSize range) { if (!m_guiConstructed) return; m_monitorManager->refreshProjectRange(range); } int Core::getItemPosition(const ObjectId &id) { if (!m_guiConstructed) return 0; switch (id.first) { case ObjectType::TimelineClip: if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) { return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipPosition(id.second); } break; case ObjectType::TimelineComposition: if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isComposition(id.second)) { return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getCompositionPosition(id.second); } break; case ObjectType::BinClip: return 0; break; default: qDebug() << "ERROR: unhandled object type"; } return 0; } int Core::getItemIn(const ObjectId &id) { if (!m_guiConstructed) { qDebug() << "/ / // QUERYING ITEM IN BUT GUI NOT BUILD!!"; return 0; } switch (id.first) { case ObjectType::TimelineClip: if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) { return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipIn(id.second); } break; case ObjectType::TimelineComposition: return 0; break; case ObjectType::BinClip: return 0; break; default: qDebug() << "ERROR: unhandled object type"; } return 0; } PlaylistState::ClipState Core::getItemState(const ObjectId &id) { if (!m_guiConstructed) return PlaylistState::Disabled; switch (id.first) { case ObjectType::TimelineClip: if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) { return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipState(id.second); } break; case ObjectType::TimelineComposition: return PlaylistState::VideoOnly; break; case ObjectType::BinClip: return m_binWidget->getClipState(id.second); break; case ObjectType::TimelineTrack: return m_mainWindow->getCurrentTimeline()->controller()->getModel()->isAudioTrack(id.second) ? PlaylistState::AudioOnly : PlaylistState::VideoOnly; default: qDebug() << "ERROR: unhandled object type"; break; } return PlaylistState::Disabled; } int Core::getItemDuration(const ObjectId &id) { if (!m_guiConstructed) return 0; switch (id.first) { case ObjectType::TimelineClip: if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) { return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipPlaytime(id.second); } break; case ObjectType::TimelineComposition: if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isComposition(id.second)) { return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getCompositionPlaytime(id.second); } break; case ObjectType::BinClip: return (int)m_binWidget->getClipDuration(id.second); break; default: qDebug() << "ERROR: unhandled object type"; } return 0; } int Core::getItemTrack(const ObjectId &id) { if (!m_guiConstructed) return 0; switch (id.first) { case ObjectType::TimelineClip: case ObjectType::TimelineComposition: return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getItemTrackId(id.second); break; default: qDebug() << "ERROR: unhandled object type"; } return 0; } void Core::refreshProjectItem(const ObjectId &id) { if (!m_guiConstructed || m_mainWindow->getCurrentTimeline()->loading) return; switch (id.first) { case ObjectType::TimelineClip: if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) { m_mainWindow->getCurrentTimeline()->controller()->refreshItem(id.second); } break; case ObjectType::TimelineComposition: if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isComposition(id.second)) { m_mainWindow->getCurrentTimeline()->controller()->refreshItem(id.second); } break; case ObjectType::TimelineTrack: if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isTrack(id.second)) { requestMonitorRefresh(); } break; case ObjectType::BinClip: m_monitorManager->refreshClipMonitor(); break; default: qDebug() << "ERROR: unhandled object type"; } } bool Core::hasTimelinePreview() const { if (!m_guiConstructed) { return false; } return m_mainWindow->getCurrentTimeline()->controller()->renderedChunks().size() > 0; } KdenliveDoc *Core::currentDoc() { return m_projectManager->current(); } int Core::projectDuration() const { if (!m_guiConstructed) { return 0; } return m_mainWindow->getCurrentTimeline()->controller()->duration(); } void Core::profileChanged() { GenTime::setFps(getCurrentFps()); } void Core::pushUndo(const Fun &undo, const Fun &redo, const QString &text) { undoStack()->push(new FunctionalUndoCommand(undo, redo, text)); } void Core::pushUndo(QUndoCommand *command) { undoStack()->push(command); } void Core::displayMessage(const QString &message, MessageType type, int timeout) { if (m_mainWindow) { m_mainWindow->displayMessage(message, type, timeout); } else { qDebug() << message; } } void Core::displayBinMessage(const QString &text, int type, const QList &actions) { m_binWidget->doDisplayMessage(text, (KMessageWidget::MessageType)type, actions); } void Core::displayBinLogMessage(const QString &text, int type, const QString &logInfo) { m_binWidget->doDisplayMessage(text, (KMessageWidget::MessageType)type, logInfo); } void Core::clearAssetPanel(int itemId) { if (m_guiConstructed) m_mainWindow->clearAssetPanel(itemId); } std::shared_ptr Core::getItemEffectStack(int itemType, int itemId) { if (!m_guiConstructed) return nullptr; switch (itemType) { case (int)ObjectType::TimelineClip: return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipEffectStack(itemId); case (int)ObjectType::TimelineTrack: return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getTrackEffectStackModel(itemId); break; case (int)ObjectType::BinClip: return m_binWidget->getClipEffectStack(itemId); default: return nullptr; } } std::shared_ptr Core::undoStack() { return projectManager()->undoStack(); } QMap Core::getVideoTrackNames() { if (!m_guiConstructed) return QMap(); return m_mainWindow->getCurrentTimeline()->controller()->getTrackNames(true); } QPair Core::getCompositionATrack(int cid) const { if (!m_guiConstructed) return {}; return m_mainWindow->getCurrentTimeline()->controller()->getCompositionATrack(cid); } bool Core::compositionAutoTrack(int cid) const { return m_mainWindow->getCurrentTimeline()->controller()->compositionAutoTrack(cid); } void Core::setCompositionATrack(int cid, int aTrack) { if (!m_guiConstructed) return; m_mainWindow->getCurrentTimeline()->controller()->setCompositionATrack(cid, aTrack); } std::shared_ptr Core::projectItemModel() { return m_projectItemModel; } void Core::invalidateRange(QSize range) { if (!m_mainWindow || m_mainWindow->getCurrentTimeline()->loading) return; m_mainWindow->getCurrentTimeline()->controller()->invalidateZone(range.width(), range.height()); } void Core::invalidateItem(ObjectId itemId) { if (!m_mainWindow || m_mainWindow->getCurrentTimeline()->loading) return; switch (itemId.first) { case ObjectType::TimelineClip: case ObjectType::TimelineComposition: m_mainWindow->getCurrentTimeline()->controller()->invalidateItem(itemId.second); break; case ObjectType::TimelineTrack: // TODO: invalidate all clips in track break; default: // bin clip should automatically be reloaded, compositions should not have effects break; } } double Core::getClipSpeed(int id) const { return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipSpeed(id); } void Core::updateItemKeyframes(ObjectId id) { if (id.first == ObjectType::TimelineClip && m_mainWindow) { m_mainWindow->getCurrentTimeline()->controller()->updateClip(id.second, {TimelineModel::KeyframesRole}); } } void Core::updateItemModel(ObjectId id, const QString &service) { if (m_mainWindow && !m_mainWindow->getCurrentTimeline()->loading && service.startsWith(QLatin1String("fade")) && id.first == ObjectType::TimelineClip) { bool startFade = service == QLatin1String("fadein") || service == QLatin1String("fade_from_black"); m_mainWindow->getCurrentTimeline()->controller()->updateClip(id.second, {startFade ? TimelineModel::FadeInRole : TimelineModel::FadeOutRole}); } } void Core::showClipKeyframes(ObjectId id, bool enable) { if (id.first == ObjectType::TimelineClip) { m_mainWindow->getCurrentTimeline()->controller()->showClipKeyframes(id.second, enable); } else if (id.first == ObjectType::TimelineComposition) { m_mainWindow->getCurrentTimeline()->controller()->showCompositionKeyframes(id.second, enable); } } Mlt::Profile *Core::thumbProfile() { if (!m_thumbProfile) { m_thumbProfile = std::make_unique(m_currentProfile.toStdString().c_str()); m_thumbProfile->set_height(200); int width = 200 * m_thumbProfile->dar(); if (width % 8 > 0) { width += 8 - width % 8; } m_thumbProfile->set_width(width); } return m_thumbProfile.get(); } int Core::getTimelinePosition() const { if (m_mainWindow && m_guiConstructed) { return m_mainWindow->getCurrentTimeline()->controller()->timelinePosition(); } return 0; } void Core::triggerAction(const QString &name) { QAction *action = m_mainWindow->actionCollection()->action(name); if (action) { action->trigger(); } } void Core::clean() { m_self.reset(); } void Core::startMediaCapture(bool checkAudio, bool checkVideo) { if (checkAudio && checkVideo) { m_capture->recordVideo(true); } else if (checkAudio) { m_capture->recordAudio(true); } m_mediaCaptureFile = m_capture->getCaptureOutputLocation(); } void Core::stopMediaCapture(bool checkAudio, bool checkVideo) { if (checkAudio && checkVideo) { m_capture->recordVideo(false); - } else if (checkAudio && !checkVideo) { + } else if (checkAudio) { m_capture->recordAudio(false); } bin()->slotAddClipToProject(m_mediaCaptureFile); } QStringList Core::getAudioCaptureDevices() { return m_capture->getAudioCaptureDevices(); } int Core::getMediaCaptureState() { return m_capture->getState(); } MediaCapture *Core::getAudioDevice() { return m_capture.get(); } QString Core::getProjectFolderName() { return m_monitorManager->getProjectFolder(); } \ No newline at end of file