X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fprojectlist.cpp;h=319a15243e418b792aa46b009d5490f4fa20e382;hb=c2ff32876591d3e015410ac619b4d8e3746571dc;hp=201e2cfd4221ee2949f855cc3dbefe70300bd107;hpb=525c7c608d9f74d569ecbe88f8565eee5d3bfec4;p=kdenlive diff --git a/src/projectlist.cpp b/src/projectlist.cpp index 201e2cfd..319a1524 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -44,6 +44,7 @@ #include "ui_templateclip_ui.h" #include "ui_cutjobdialog_ui.h" +#include "ui_scenecutdialog_ui.h" #include #include @@ -310,8 +311,9 @@ ProjectList::ProjectList(QWidget *parent) : connect(m_listView, SIGNAL(projectModified()), this, SIGNAL(projectModified())); connect(m_listView, SIGNAL(itemSelectionChanged()), this, SLOT(slotClipSelected())); connect(m_listView, SIGNAL(focusMonitor()), this, SIGNAL(raiseClipMonitor())); - connect(m_listView, SIGNAL(pauseMonitor()), this, SLOT(slotPauseMonitor())); + connect(m_listView, SIGNAL(pauseMonitor()), this, SIGNAL(pauseMonitor())); connect(m_listView, SIGNAL(requestMenu(const QPoint &, QTreeWidgetItem *)), this, SLOT(slotContextMenu(const QPoint &, QTreeWidgetItem *))); + connect(m_listView, SIGNAL(addClip()), this, SIGNAL(pauseMonitor())); connect(m_listView, SIGNAL(addClip()), this, SLOT(slotAddClip())); connect(m_listView, SIGNAL(addClip(const QList , const QString &, const QString &)), this, SLOT(slotAddClip(const QList , const QString &, const QString &))); connect(this, SIGNAL(addClip(const QString, const QString &, const QString &)), this, SLOT(slotAddClip(const QString, const QString &, const QString &))); @@ -424,8 +426,8 @@ void ProjectList::setupGeneratorMenu(const QHash& menus) transcodeMenu->setEnabled(false); m_transcodeAction = transcodeMenu; } - if (menus.contains("stabilizeMenu") && menus.value("stabilizeMenu") ){ - QMenu* stabilizeMenu=menus.value("stabilizeMenu"); + if (menus.contains("clipActionsMenu") && menus.value("clipActionsMenu") ){ + QMenu* stabilizeMenu=menus.value("clipActionsMenu"); m_menu->addMenu(stabilizeMenu); if (stabilizeMenu->isEmpty()) stabilizeMenu->setEnabled(false); @@ -585,7 +587,7 @@ void ProjectList::editClipSelection(QList list) kDebug() << "Result: " << p.key() << " = " << p.value(); }*/ if (clipList.isEmpty()) { - emit displayMessage(i18n("No available clip selected"), -2); + emit displayMessage(i18n("No available clip selected"), -2); } else emit showClipProperties(clipList, commonproperties); } @@ -902,7 +904,7 @@ void ProjectList::adjustProxyActions(ProjectItem *clip) const void ProjectList::adjustStabilizeActions(ProjectItem *clip) const { - if (clip == NULL || clip->type() != PROJECTCLIPTYPE || clip->clipType() == COLOR || clip->clipType() == TEXT || clip->clipType() == PLAYLIST || clip->clipType() == SLIDESHOW) { + if (clip == NULL || clip->type() != PROJECTCLIPTYPE || clip->clipType() == COLOR || clip->clipType() == TEXT || clip->clipType() == SLIDESHOW) { m_stabilizeAction->setEnabled(false); return; } @@ -1619,7 +1621,7 @@ QString ProjectList::getExtensions() QStringList mimeTypes = QStringList() << "application/x-kdenlive" << "application/x-kdenlivetitle" << "video/mlt-playlist" << "text/plain"; // Video mimes - mimeTypes << "video/x-flv" << "application/vnd.rn-realmedia" << "video/x-dv" << "video/dv" << "video/x-msvideo" << "video/x-matroska" << "video/mpeg" << "video/ogg" << "video/x-ms-wmv" << "video/mp4" << "video/quicktime" << "video/webm" << "video/3gpp"; + mimeTypes << "video/x-flv" << "application/vnd.rn-realmedia" << "video/x-dv" << "video/dv" << "video/x-msvideo" << "video/x-matroska" << "video/mpeg" << "video/ogg" << "video/x-ms-wmv" << "video/mp4" << "video/quicktime" << "video/webm" << "video/3gpp" << "video/mp2t"; // Audio mimes mimeTypes << "audio/x-flac" << "audio/x-matroska" << "audio/mp4" << "audio/mpeg" << "audio/x-mp3" << "audio/ogg" << "audio/x-wav" << "audio/x-aiff" << "audio/aiff" << "application/ogg" << "application/mxf" << "application/x-shockwave-flash" << "audio/ac3"; @@ -2111,12 +2113,12 @@ void ProjectList::slotRefreshClipThumbnail(QTreeWidgetItem *it, bool update) int dwidth = (int)(height * m_render->dar() + 0.5); if (clip->clipType() == AUDIO) pix = KIcon("audio-x-generic").pixmap(QSize(dwidth, height)); - else if (clip->clipType() == IMAGE) + else if (clip->clipType() == IMAGE) { img = KThumb::getFrame(item->referencedClip()->getProducer(), 0, swidth, dwidth, height); + } else { img = item->referencedClip()->extractImage(frame, dwidth, height); } - if (!pix.isNull() || !img.isNull()) { monitorItemEditing(false); if (!img.isNull()) { @@ -2315,7 +2317,15 @@ void ProjectList::slotReplyGetImage(const QString &clipId, const QImage &img) { ProjectItem *item = getItemById(clipId); if (item && !img.isNull()) { - QPixmap pix = QPixmap::fromImage(img); + QPixmap pix(img.width(), img.height()); + pix.fill(Qt::transparent); + QPainter p(&pix); + p.setRenderHint(QPainter::Antialiasing, true); + QPainterPath path; + path.addRoundedRect(0.5, 0.5, pix.width() - 1, pix.height() - 1, 2, 2); + p.setClipPath(path); + p.drawImage(0, 0, img); + p.end(); processThumbOverlays(item, pix); monitorItemEditing(false); item->setData(0, Qt::DecorationRole, pix); @@ -2724,8 +2734,12 @@ void ProjectList::slotCreateProxy(const QString id) slotGotProxy(path); return; } - - ProxyJob *job = new ProxyJob(item->clipType(), id, QStringList() << path << item->clipUrl().path() << item->referencedClip()->producerProperty("_exif_orientation") << m_doc->getDocumentProperty("proxyparams").simplified() << QString::number(m_render->frameRenderWidth()) << QString::number(m_render->renderHeight())); + QString sourcePath = item->clipUrl().path(); + if (item->clipType() == PLAYLIST) { + // Special case: playlists use the special 'consumer' producer to support resizing + sourcePath.prepend("consumer:"); + } + ProxyJob *job = new ProxyJob(item->clipType(), id, QStringList() << path << sourcePath << item->referencedClip()->producerProperty("_exif_orientation") << m_doc->getDocumentProperty("proxyparams").simplified() << QString::number(m_render->frameRenderWidth()) << QString::number(m_render->renderHeight())); if (job->isExclusive() && hasPendingJob(item, job->jobType)) { delete job; return; @@ -2760,7 +2774,7 @@ void ProjectList::slotCutClipJob(const QString &id, QPoint zone) Ui::CutJobDialog_UI ui; ui.setupUi(d); ui.extra_params->setVisible(false); - ui.add_clip->setChecked(KdenliveSettings::add_clip_cut()); + ui.add_clip->setChecked(KdenliveSettings::add_new_clip()); ui.file_url->fileDialog()->setOperationMode(KFileDialog::Saving); ui.extra_params->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5); ui.file_url->setUrl(KUrl(dest)); @@ -2793,11 +2807,11 @@ void ProjectList::slotCutClipJob(const QString &id, QPoint zone) } } QString extraParams = ui.extra_params->toPlainText().simplified(); - KdenliveSettings::setAdd_clip_cut(ui.add_clip->isChecked()); + KdenliveSettings::setAdd_new_clip(ui.add_clip->isChecked()); delete d; QStringList jobParams; - jobParams << dest << item->clipUrl().path() << timeIn << timeOut << QString::number(duration) << QString::number(KdenliveSettings::add_clip_cut()); + jobParams << dest << item->clipUrl().path() << timeIn << timeOut << QString::number(duration) << QString::number(KdenliveSettings::add_new_clip()); if (!extraParams.isEmpty()) jobParams << extraParams; CutClipJob *job = new CutClipJob(item->clipType(), id, jobParams); if (job->isExclusive() && hasPendingJob(item, job->jobType)) { @@ -2841,7 +2855,7 @@ void ProjectList::slotTranscodeClipJob(const QString &condition, QString params, ui.extra_params->setVisible(false); d->adjustSize(); ui.button_more->setIcon(KIcon("configure")); - ui.add_clip->setChecked(KdenliveSettings::add_clip_cut()); + ui.add_clip->setChecked(KdenliveSettings::add_new_clip()); ui.extra_params->setPlainText(params.simplified().section(' ', 0, -2)); QString mess = desc; mess.append(' ' + i18np("(%1 clip)", "(%1 clips)", ids.count())); @@ -2851,14 +2865,17 @@ void ProjectList::slotTranscodeClipJob(const QString &condition, QString params, return; } params = ui.extra_params->toPlainText().simplified(); - KdenliveSettings::setAdd_clip_cut(ui.add_clip->isChecked()); - + KdenliveSettings::setAdd_new_clip(ui.add_clip->isChecked()); + int index = 0; foreach(const QString &id, ids) { ProjectItem *item = getItemById(id); if (!item || !item->referencedClip()) continue; QString src = item->clipUrl().path(); QString dest; - if (ids.count() > 1) dest = params.section(' ', -1).replace("%1", src); + if (ids.count() > 1) { + dest = destinations.at(index); + index++; + } else dest = ui.file_url->url().path(); QStringList jobParams; jobParams << dest << src << QString() << QString(); @@ -2867,7 +2884,7 @@ void ProjectList::slotTranscodeClipJob(const QString &condition, QString params, int max = item->clipMaxDuration(); QString duration = QString::number(max); jobParams << duration; - jobParams << QString::number(KdenliveSettings::add_clip_cut()); + jobParams << QString::number(KdenliveSettings::add_new_clip()); jobParams << params; CutClipJob *job = new CutClipJob(item->clipType(), id, jobParams); if (job->isExclusive() && hasPendingJob(item, job->jobType)) { @@ -2973,11 +2990,14 @@ void ProjectList::slotProcessJobs() } connect(job, SIGNAL(jobProgress(QString, int, int)), this, SIGNAL(processLog(QString, int, int))); connect(job, SIGNAL(cancelRunningJob(const QString, stringMap)), this, SIGNAL(cancelRunningJob(const QString, stringMap))); - connect(job, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap)), this, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap))); if (job->jobType == MLTJOB) { MeltJob *jb = static_cast (job); jb->setProducer(currentClip->getProducer(), currentClip->fileURL()); + if (jb->isProjectFilter()) + connect(job, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap,QStringList)), this, SLOT(slotGotFilterJobResults(QString,int, int, QString,stringMap,QStringList))); + else + connect(job, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap,QStringList)), this, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap,QStringList))); } job->startJob(); if (job->jobStatus == JOBDONE) { @@ -3402,14 +3422,14 @@ void ProjectList::discardJobs(const QString &id, JOBTYPE type) { } } -void ProjectList::slotStartFilterJob(ItemInfo info, const QString&id, const QString&filterName, const QString&filterParams, const QString&finalFilterName, const QString&consumer, const QString&consumerParams, const QString&properties) +void ProjectList::slotStartFilterJob(ItemInfo info, const QString&id, const QString&filterName, const QString&filterParams, const QString&finalFilterName, const QString&consumer, const QString&consumerParams, const QStringList &extraParams) { ProjectItem *item = getItemById(id); if (!item) return; QStringList jobParams; jobParams << QString::number(info.cropStart.frames(m_fps)) << QString::number((info.cropStart + info.cropDuration).frames(m_fps)); - jobParams << QString() << filterName << filterParams << consumer << consumerParams << properties << QString::number(info.startPos.frames(m_fps)) << QString::number(info.track) << finalFilterName; - MeltJob *job = new MeltJob(item->clipType(), id, jobParams); + jobParams << QString() << filterName << filterParams << consumer << consumerParams << QString::number(info.startPos.frames(m_fps)) << QString::number(info.track) << finalFilterName; + MeltJob *job = new MeltJob(item->clipType(), id, jobParams, extraParams); if (job->isExclusive() && hasPendingJob(item, job->jobType)) { delete job; return; @@ -3435,14 +3455,55 @@ void ProjectList::startClipFilterJob(const QString &filterName, const QString &c else { destination = item->clipUrl().directory(); } - QPointer d = new ClipStabilize(destination, ids.count(), filterName); - if (d->exec() == QDialog::Accepted) { - processClipJob(ids, d->destination(), d->autoAddClip(), d->params(), d->desc()); + if (filterName == "motion_est") { + // Show config dialog + QPointer d = new QDialog(this); + Ui::SceneCutDialog_UI ui; + ui.setupUi(d); + // Set up categories + for (int i = 0; i < 5; ++i) { + ui.marker_type->insertItem(i, i18n("Category %1", i)); + ui.marker_type->setItemData(i, CommentedTime::markerColor(i), Qt::DecorationRole); + } + ui.marker_type->setCurrentIndex(KdenliveSettings::default_marker_type()); + if (d->exec() != QDialog::Accepted) { + delete d; + return; + } + // Autosplit filter + QStringList jobParams; + // Producer params + jobParams << QString(); + // Filter params, use a smaller region of the image to speed up operation + jobParams << filterName << "bounding=\"25%x25%:25%x25\" shot_change_list=0"; + // Consumer + jobParams << "null" << "all=1 terminate_on_pause=1 real_time=-1"; + QStringList extraParams; + extraParams << "key:shot_change_list"; + extraParams << "projecttreefilter"; + if (ui.add_markers->isChecked()) { + // We want to create markers + extraParams << QString("addmarkers:%1").arg(ui.marker_type->currentIndex()); + } + if (ui.cut_scenes->isChecked()) { + // We want to cut scenes + extraParams << "cutscenes"; + } + + processClipJob(ids, QString(), false, jobParams, i18n("Auto split"), extraParams); + } + else { + QPointer d = new ClipStabilize(destination, ids.count(), filterName); + if (d->exec() == QDialog::Accepted) { + QStringList extraParams; + extraParams << "producer_profile"; + processClipJob(ids, d->destination(), d->autoAddClip(), d->params(), d->desc(), extraParams); + } + delete d; } - delete d; } -void ProjectList::processClipJob(QStringList ids, const QString&destination, bool autoAdd, QStringList jobParams, const QString &description) +void ProjectList::processClipJob(QStringList ids, const QString&destination, bool autoAdd, QStringList jobParams, const QString &description, QStringList extraParams) { QStringList preParams; // in and out @@ -3459,20 +3520,23 @@ void ProjectList::processClipJob(QStringList ids, const QString&destination, boo foreach(const QString&id, ids) { ProjectItem *item = getItemById(id); if (!item) continue; + QStringList jobArgs; + jobArgs << preParams; if (ids.count() == 1) { - consumer += ':' + destination; + jobArgs << consumer + ':' + destination; } else { - consumer += ':' + destination + item->clipUrl().fileName() + ".mlt"; + jobArgs << consumer + ':' + destination + item->clipUrl().fileName() + ".mlt"; } - preParams << consumer << jobParams; + jobArgs << jobParams; - MeltJob *job = new MeltJob(item->clipType(), id, preParams); + MeltJob *job = new MeltJob(item->clipType(), id, jobArgs, extraParams); if (autoAdd) { job->setAddClipToProject(true); kDebug()<<"// ADDING TRUE"; } else kDebug()<<"// ADDING FALSE!!!"; + if (job->isExclusive() && hasPendingJob(item, job->jobType)) { delete job; return; @@ -3533,4 +3597,74 @@ void ProjectList::slotClosePopup() m_errorLog.clear(); } +void ProjectList::slotGotFilterJobResults(QString id, int , int , QString filter, stringMap results, QStringList extra) +{ + ProjectItem *clip = getItemById(id); + if (!clip) return; + // Check for return value + QString returnKey; + int markersType = -1; + for (int i = 0; i < extra.count(); i++) { + if (extra.at(i).startsWith("key:")) + returnKey = extra.at(i).section(':', 1); + if (extra.at(i).startsWith("addmarkers:")) { + markersType = extra.at(i).section(':', 1).toInt(); + } + } + if (returnKey.isEmpty()) { + emit displayMessage(i18n("No data returned from clip analysis"), 2); + return; + } + QStringList returnData = results.value(returnKey).split(';', QString::SkipEmptyParts); + if (returnData.isEmpty()) { + emit displayMessage(i18n("No data returned from clip analysis"), 2); + return; + } + bool dataProcessed = false; + if (extra.contains("cutscenes")) { + // Check if we want to cut scenes from returned data + dataProcessed = true; + int cutPos = 0; + QUndoCommand *command = new QUndoCommand(); + command->setText(i18n("Auto Split Clip")); + foreach (QString pos, returnData) { + if (!pos.contains("=")) continue; + int newPos = pos.section("=", 0, 0).toInt(); + // Don't use scenes shorter than 1 second + if (newPos - cutPos < 24) continue; + (void) new AddClipCutCommand(this, id, cutPos, newPos, QString(), true, false, command); + cutPos = newPos; + } + if (command->childCount() == 0) + delete command; + else m_commandStack->push(command); + } + if (markersType >= 0) { + // Add markers from returned data + dataProcessed = true; + int cutPos = 0; + QUndoCommand *command = new QUndoCommand(); + command->setText(i18n("Add Markers")); + QList markersList; + int index = 1; + foreach (QString pos, returnData) { + if (!pos.contains("=")) continue; + int newPos = pos.section("=", 0, 0).toInt(); + // Don't use scenes shorter than 1 second + if (newPos - cutPos < 24) continue; + CommentedTime m(GenTime(newPos, m_fps), QString::number(index), markersType); + markersList << m; + index++; + cutPos = newPos; + } + emit addMarkers(id, markersList); + } + if (!dataProcessed || extra.contains("storedata")) { + // Store returned data as clip extra data + + clip->referencedClip()->setAnalysisData(i18n("Motion vectors"), results.value(returnKey)); + emit updateAnalysisData(clip->referencedClip()); + } +} + #include "projectlist.moc"