DNxHD 720p 50 fps 115 Mb/s=-s 1280x720 -r 50 -vb 175000k -threads 2 -vcodec dnxhd -acodec copy %1.mov;High quality encoding
DNxHD 720p 59.94 fps 220 Mb/s=-s 1280x720 -r 60000/1001 -vb 220000k -threads 2 -vcodec dnxhd -acodec copy %1.mov;High quality encoding
DNxHD 720p 59.94 fps 145 Mb/s=-s 1280x720 -r 60000/1001 -vb 145000k -threads 2 -vcodec dnxhd -acodec copy %1.mov;High quality encoding
-Fix MPEG-1=-sameq -acodec copy -vcodec mpeg1video %1.mpg;Fix unplayable MPEG-1 files
-Fix Ogg Theora=-sameq -vcodec libtheora -acodec copy %1.ogv;Fix unplayable OGG Theora files
-Remux MPEG-2 PS/VOB=-vcodec copy -acodec copy %1.mpg;Fix audio sync in MPEG-2 vob files
+Fix MPEG-1=-sameq -acodec copy -vcodec mpeg1video %1.mpg;Fix unplayable MPEG-1 files;;vcodec=mpeg1video
+Fix Ogg Theora=-sameq -vcodec libtheora -acodec copy %1.ogv;Fix unplayable OGG Theora files;;vcodec=theora
+Remux MPEG-2 PS/VOB=-vcodec copy -acodec copy %1.mpg;Fix audio sync in MPEG-2 vob files;;vcodec=mpeg2video
Lossless Matroska=-sn -vcodec huffyuv -acodec flac %1.mkv;High quality lossless encoding
Wav 48000Hz=-vn -ar 48000 %1.wav;Extract audio as WAV file;audio
Remux with MKV=-vcodec copy -acodec copy -sn %1.mkv
// Update list of transcoding profiles
loadTranscoders();
- loadStabilize();
+ loadStabilize();
#ifdef USE_JOGSHUTTLE
activateShuttleDevice();
#endif
a = transMenu->addAction(i.key());
}
a->setData(data);
- a->setToolTip(data.at(1));
+ if (data.count() > 1) a->setToolTip(data.at(1));
connect(a, SIGNAL(triggered()), this, SLOT(slotTranscode()));
}
}
QStringList data = action->data().toStringList();
params = data.at(0);
if (data.count() > 1) desc = data.at(1);
- if (data.count() > 2) condition = data.at(2);
- urls << m_projectList->getConditionalUrls(condition);
- urls.removeAll(KUrl());
+ if (data.count() > 3) condition = data.at(3);
+ QStringList ids = m_projectList->getConditionalIds(condition);
+ m_projectList->slotTranscodeClipJob(ids, params, desc);
+ return;
}
if (urls.isEmpty()) {
m_messageLabel->setMessage(i18n("No clip to transcode"), ErrorMessage);
ClipTranscode *d = new ClipTranscode(urls, params, desc);
connect(d, SIGNAL(addClip(KUrl)), this, SLOT(slotAddProjectClip(KUrl)));
d->show();
- //QProcess::startDetached("ffmpeg", parameters);
}
void MainWindow::slotTranscodeClip()
return result;
}
+QStringList ProjectList::getConditionalIds(const QString &condition) const
+{
+ QStringList result;
+ ProjectItem *item;
+ QList<QTreeWidgetItem *> list = m_listView->selectedItems();
+ for (int i = 0; i < list.count(); i++) {
+ if (list.at(i)->type() == PROJECTFOLDERTYPE)
+ continue;
+ if (list.at(i)->type() == PROJECTSUBCLIPTYPE) {
+ // subitem
+ item = static_cast <ProjectItem*>(list.at(i)->parent());
+ } else {
+ item = static_cast <ProjectItem*>(list.at(i));
+ }
+ if (item == NULL || item->type() == COLOR || item->type() == SLIDESHOW || item->type() == TEXT)
+ continue;
+ DocClipBase *clip = item->referencedClip();
+ if (!condition.isEmpty()) {
+ if (condition.startsWith("vcodec") && !clip->hasVideoCodec(condition.section('=', 1, 1)))
+ continue;
+ else if (condition.startsWith("acodec") && !clip->hasAudioCodec(condition.section('=', 1, 1)))
+ continue;
+ }
+ result.append(item->clipId());
+ }
+ return result;
+}
+
void ProjectList::regenerateTemplate(const QString &id)
{
ProjectItem *clip = getItemById(id);
ui.add_clip->setChecked(KdenliveSettings::add_clip_cut());
ui.file_url->fileDialog()->setOperationMode(KFileDialog::Saving);
ui.file_url->setUrl(KUrl(dest));
+ ui.extra_params->setPlainText("-acodec copy -vcodec copy");
QString mess = i18n("Extracting %1 out of %2", timeOut, Timecode::getStringTimecode(max, clipFps, true));
ui.info_label->setText(mess);
if (d->exec() != QDialog::Accepted) {
slotCheckJobProcess();
}
+void ProjectList::slotTranscodeClipJob(QStringList ids, QString params, QString desc)
+{
+ QStringList existingFiles;
+ foreach(const QString &id, ids) {
+ ProjectItem *item = getItemById(id);
+ if (!item) continue;
+ QString newFile = params.section(' ', -1).replace("%1", item->clipUrl().path());
+ if (QFile::exists(newFile)) existingFiles << newFile;
+ }
+ if (!existingFiles.isEmpty()) {
+ if (KMessageBox::warningContinueCancelList(this, i18n("The transcoding job will overwrite the following files:"), existingFiles) == KMessageBox::Cancel) return;
+ }
+
+ foreach(const QString &id, ids) {
+ ProjectItem *item = getItemById(id);
+ if (!item || !item->referencedClip()) continue;
+ QString src = item->clipUrl().path();
+ QString dest = params.section(' ', -1).replace("%1", src);
+ m_processingProxy.append(dest);
+ QStringList jobParams;
+ jobParams << dest << src << QString() << QString();
+ double clipFps = item->referencedClip()->getProperty("fps").toDouble();
+ if (clipFps == 0) clipFps = m_fps;
+ int max = item->clipMaxDuration();
+ QString duration = QString::number(max);
+ jobParams << duration;
+ jobParams << QString::number(KdenliveSettings::add_clip_cut());
+ jobParams << params.section(' ', 0, -2);
+ CutClipJob *job = new CutClipJob(item->clipType(), id, jobParams);
+ m_jobList.append(job);
+ setJobStatus(item, job->jobType, JOBWAITING, 0, job->statusMessage());
+ }
+ slotCheckJobProcess();
+
+}
+
void ProjectList::slotCheckJobProcess()
{
void setupGeneratorMenu(const QHash<QString,QMenu*>& menus);
QString currentClipUrl() const;
KUrl::List getConditionalUrls(const QString &condition) const;
+ /** @brief Get a list of selected clip Id's that match a condition. */
+ QStringList getConditionalIds(const QString &condition) const;
QDomDocument generateTemplateXml(QString data, const QString &replaceString);
void cleanup();
void trashUnusedClips();
void slotDeleteProxy(const QString proxyPath);
/** @brief Start a hard cut clip job. */
void slotCutClipJob(const QString &id, QPoint zone);
+ void slotTranscodeClipJob(QStringList ids, QString params, QString desc);
private:
ProjectListView *m_listView;
CutClipJob::CutClipJob(CLIPTYPE cType, const QString &id, QStringList parameters) : AbstractClipJob(CUTJOB, cType, id, parameters)
{
jobStatus = JOBWAITING;
- description = i18n("clip cut");
m_dest = parameters.at(0);
m_src = parameters.at(1);
m_start = parameters.at(2);
m_end = parameters.at(3);
+ if (m_start.isEmpty()) {
+ // this is a transcoding job
+ description = i18n("Transcode clip");
+ }
+ else description = i18n("Cut clip");
m_jobDuration = parameters.at(4).toInt();
addClipToProject = parameters.at(5).toInt();
if (parameters.count() == 7) m_cutExtraParams = parameters.at(6).simplified();
if (clipType == AV || clipType == AUDIO || clipType == VIDEO) {
QStringList parameters;
parameters << "-i" << m_src;
- parameters << "-ss" << m_start <<"-t" << m_end;
- parameters << "-acodec" << "copy" << "-vcodec" << "copy";
+ if (!m_start.isEmpty())
+ parameters << "-ss" << m_start <<"-t" << m_end;
if (!m_cutExtraParams.isEmpty()) {
foreach(const QString &s, m_cutExtraParams.split(' '))
parameters << s;
{
if (!m_jobProcess || m_jobDuration == 0 || jobStatus == JOBABORTED) return JOBABORTED;
QString log = m_jobProcess->readAll();
+ kDebug()<<"// PROgress: "<<log;
if (!log.isEmpty()) m_errorMessage.append(log + '\n');
int progress;
// Parse FFmpeg output
if (log.contains("frame=")) {
int progress = log.section("frame=", 1, 1).simplified().section(' ', 0, 0).toInt();
- kDebug()<<"// PROgress: "<<progress<<", DUR: "<<m_jobDuration;
return (int) (100.0 * progress / m_jobDuration);
}
else if (log.contains("time=")) {
QString statusInfo;
switch (jobStatus) {
case JOBWORKING:
- statusInfo = i18n("Extracting clip cut");
+ if (m_start.isEmpty()) statusInfo = i18n("Transcoding clip");
+ else statusInfo = i18n("Extracting clip cut");
break;
case JOBWAITING:
- statusInfo = i18n("Waiting - clip cut");
+ if (m_start.isEmpty()) statusInfo = i18n("Waiting - transcode clip");
+ else statusInfo = i18n("Waiting - cut clip");
break;
default:
break;