Skip to content

Commit

Permalink
Add a video quality measurement job to the encode job results.
Browse files Browse the repository at this point in the history
  • Loading branch information
ddennedy committed Jan 26, 2015
1 parent 65a60b2 commit 1d608d5
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 2 deletions.
72 changes: 72 additions & 0 deletions src/jobs/encodejob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,15 @@
#include <QUrl>
#include <QDesktopServices>
#include <QFileInfo>
#include <QFileDialog>
#include <QTemporaryFile>
#include <QDir>
#include <QDomDocument>
#include <QTextStream>
#include "mainwindow.h"
#include "settings.h"
#include "jobqueue.h"
#include "jobs/videoqualityjob.h"

EncodeJob::EncodeJob(const QString &name, const QString &xml)
: MeltJob(name, xml)
Expand All @@ -35,6 +43,10 @@ EncodeJob::EncodeJob(const QString &name, const QString &xml)
action->setToolTip(tr("Show In Folder"));
connect(action, &QAction::triggered, this, &EncodeJob::onShowFolderTriggered);
m_successActions << action;

action = new QAction(tr("Measure Video Quality..."), this);
connect(action, &QAction::triggered, this, &EncodeJob::onVideoQualityTriggered);
m_successActions << action;
}

void EncodeJob::onOpenTiggered()
Expand All @@ -48,3 +60,63 @@ void EncodeJob::onShowFolderTriggered()
QUrl url(QString("file://").append(fi.path()), QUrl::TolerantMode);
QDesktopServices::openUrl(url);
}

void EncodeJob::onVideoQualityTriggered()
{
// Get the location and file name for the report.
QString directory = Settings.encodePath();
directory += "/.txt";
QString reportPath= QFileDialog::getSaveFileName(&MAIN, tr("Video Quality Report"), directory);
if (!reportPath.isEmpty()) {
QFileInfo fi(reportPath);
if (fi.suffix().isEmpty())
reportPath += ".txt";

// Get temp filename for the new XML.
QTemporaryFile tmp(QDir::tempPath().append("/shotcut-XXXXXX"));
tmp.open();
QString tmpName = tmp.fileName();
tmp.close();
tmpName.append(".mlt");

// Generate the XML for the comparison.
Mlt::Tractor tractor;
Mlt::Producer original(MLT.profile(), xmlPath().toUtf8().constData());
Mlt::Producer encoded(MLT.profile(), objectName().toUtf8().constData());
Mlt::Transition vqm(MLT.profile(), "vqm");
if (original.is_valid() && encoded.is_valid() && vqm.is_valid()) {
tractor.set_profile(MLT.profile());
tractor.set_track(original, 0);
tractor.set_track(encoded, 1);
tractor.plant_transition(vqm);
vqm.set("render", 0);
MLT.saveXML(tmpName, &tractor);

// Add consumer element to XML.
QFile f1(tmpName);
f1.open(QIODevice::ReadOnly);
QDomDocument dom(tmpName);
dom.setContent(&f1);
f1.close();

QDomElement consumerNode = dom.createElement("consumer");
QDomNodeList profiles = dom.elementsByTagName("profile");
if (profiles.isEmpty())
dom.documentElement().insertAfter(consumerNode, dom.documentElement());
else
dom.documentElement().insertAfter(consumerNode, profiles.at(profiles.length() - 1));
consumerNode.setAttribute("mlt_service", "null");
consumerNode.setAttribute("real_time", -1);
consumerNode.setAttribute("terminate_on_pause", 1);

// Save the new XML.
f1.open(QIODevice::WriteOnly);
QTextStream ts(&f1);
dom.save(ts, 2);
f1.close();

// Create job and add it to the queue.
JOBS.add(new VideoQualityJob(objectName(), tmpName, reportPath));
}
}
}
1 change: 1 addition & 0 deletions src/jobs/encodejob.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class EncodeJob : public MeltJob
private slots:
void onOpenTiggered();
void onShowFolderTriggered();
void onVideoQualityTriggered();
};

#endif // ENCODEJOB_H
1 change: 1 addition & 0 deletions src/jobs/meltjob.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class MeltJob : public AbstractJob
virtual ~MeltJob();
void start();
QString xml() const;
QString xmlPath() const { return m_xml; }

public slots:
void onViewXmlTriggered();
Expand Down
101 changes: 101 additions & 0 deletions src/jobs/videoqualityjob.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2012-2015 Meltytech, LLC
* Author: Dan Dennedy <dan@dennedy.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.
*
* 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 <http://www.gnu.org/licenses/>.
*/

#include "videoqualityjob.h"
#include <QAction>
#include <QFile>
#include <QDomDocument>
#include <QTextStream>
#include <QFileInfo>
#include <QUrl>
#include <QDesktopServices>
#include "mainwindow.h"
#include "dialogs/textviewerdialog.h"

VideoQualityJob::VideoQualityJob(const QString& name, const QString& xmlPath,
const QString& reportPath)
: MeltJob(name, xmlPath)
, m_reportPath(reportPath)
{
QAction* action = new QAction(tr("Open"), this);
action->setToolTip(tr("Open original and encoded side-by-side in the Shotcut player"));
connect(action, &QAction::triggered, this, &VideoQualityJob::onOpenTiggered);
m_successActions << action;

action = new QAction(tr("View Report"), this);
connect(action, &QAction::triggered, this, &VideoQualityJob::onViewReportTriggered);
m_successActions << action;

action = new QAction(tr("Show In Folder"), this);
connect(action, &QAction::triggered, this, &VideoQualityJob::onShowFolderTriggered);
m_successActions << action;

setLabel(tr("Measure %1").arg(objectName()));
setStandardOutputFile(reportPath);
}

void VideoQualityJob::onOpenTiggered()
{
// Parse the XML.
QFile file(xmlPath());
file.open(QIODevice::ReadOnly);
QDomDocument dom(xmlPath());
dom.setContent(&file);
file.close();

// Locate the VQM transition.
QDomNodeList transitions = dom.elementsByTagName("transition");
for (int i = 0; i < transitions.length(); i++ ) {
QDomElement property = transitions.at(i).firstChildElement("property");
while (!property.isNull()) {
// Change the render property to 1.
if (property.attribute("name") == "render") {
property.firstChild().setNodeValue("1");

// Save the new XML.
file.open(QIODevice::WriteOnly);
QTextStream textStream(&file);
dom.save(textStream, 2);
file.close();

MAIN.open(xmlPath().toUtf8().constData());
break;
}
property = property.nextSiblingElement("property");
}
}
}

void VideoQualityJob::onViewReportTriggered()
{
TextViewerDialog dialog(&MAIN);
dialog.setWindowTitle(tr("Video Quality Measurement"));
QFile f(m_reportPath);
f.open(QIODevice::ReadOnly);
QString s(f.readAll());
f.close();
dialog.setText(s);
dialog.exec();
}

void VideoQualityJob::onShowFolderTriggered()
{
QFileInfo fi(m_reportPath);
QUrl url(QString("file://").append(fi.path()), QUrl::TolerantMode);
QDesktopServices::openUrl(url);
}
39 changes: 39 additions & 0 deletions src/jobs/videoqualityjob.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2012-2015 Meltytech, LLC
* Author: Dan Dennedy <dan@dennedy.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.
*
* 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 <http://www.gnu.org/licenses/>.
*/

#ifndef VIDEOQUALITYJOB_H
#define VIDEOQUALITYJOB_H

#include "meltjob.h"

class VideoQualityJob : public MeltJob
{
public:
VideoQualityJob(const QString& name, const QString& xmlPath,
const QString& reportPath);

private slots:
void onOpenTiggered();
void onViewReportTriggered();
void onShowFolderTriggered();

private:
QString m_reportPath;
};

#endif // VIDEOQUALITYJOB_H
6 changes: 4 additions & 2 deletions src/src.pro
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ SOURCES += main.cpp\
widgets/directshowvideowidget.cpp \
jobs/abstractjob.cpp \
jobs/meltjob.cpp \
jobs/encodejob.cpp
jobs/encodejob.cpp \
jobs/videoqualityjob.cpp

HEADERS += mainwindow.h \
mltcontroller.h \
Expand Down Expand Up @@ -166,7 +167,8 @@ HEADERS += mainwindow.h \
widgets/directshowvideowidget.h \
jobs/abstractjob.h \
jobs/meltjob.h \
jobs/encodejob.h
jobs/encodejob.h \
jobs/videoqualityjob.h

FORMS += mainwindow.ui \
openotherdialog.ui \
Expand Down

0 comments on commit 1d608d5

Please sign in to comment.