Transcoder now accepts URLs for sources.

This commit is contained in:
Lukas Prediger 2021-05-16 15:03:36 +03:00 committed by John Maguire
parent 245f64a882
commit bb618efc5d
10 changed files with 69 additions and 62 deletions

View File

@ -74,8 +74,8 @@ void Organise::Start() {
thread_ = new QThread;
connect(thread_, SIGNAL(started()), SLOT(ProcessSomeFiles()));
connect(transcoder_, SIGNAL(JobComplete(QString, QString, bool)),
SLOT(FileTranscoded(QString, QString, bool)));
connect(transcoder_, SIGNAL(JobComplete(QUrl, QString, bool)),
SLOT(FileTranscoded(QUrl, QString, bool)));
moveToThread(thread_);
thread_->start();
@ -177,7 +177,7 @@ void Organise::ProcessSomeFiles() {
// Start the transcoding - this will happen in the background and
// FileTranscoded() will get called when it's done. At that point the
// task will get re-added to the pending queue with the new filename.
transcoder_->AddJob(task.song_info_.song_.url().toLocalFile(), preset,
transcoder_->AddJob(task.song_info_.song_.url(), preset,
task.transcoded_filename_);
transcoder_->Start();
continue;
@ -262,11 +262,12 @@ void Organise::UpdateProgress() {
const int total = task_count_ * 100;
// Update transcoding progress
QMap<QString, float> transcode_progress = transcoder_->GetProgress();
for (const QString& filename : transcode_progress.keys()) {
QMap<QUrl, float> transcode_progress = transcoder_->GetProgress();
for (const QUrl& fileurl : transcode_progress.keys()) {
QString filename = fileurl.toLocalFile();
if (!tasks_transcoding_.contains(filename)) continue;
tasks_transcoding_[filename].transcode_progress_ =
transcode_progress[filename];
transcode_progress[fileurl];
}
// Count the progress of all tasks that are in the queue. Files that need
@ -287,14 +288,17 @@ void Organise::UpdateProgress() {
task_manager_->SetTaskProgress(task_id_, progress, total);
}
void Organise::FileTranscoded(const QString& input, const QString& output,
void Organise::FileTranscoded(const QUrl& input, const QString& output,
bool success) {
qLog(Info) << "File finished" << input << success;
Q_ASSERT(input.isLocalFile()); // organise only handles local files
QString input_file_path = input.toLocalFile();
qLog(Info) << "File finished" << input_file_path << success;
transcode_progress_timer_.stop();
Task task = tasks_transcoding_.take(input);
Task task = tasks_transcoding_.take(input_file_path);
if (!success) {
files_with_errors_ << input;
files_with_errors_ << input_file_path;
} else {
tasks_pending_ << task;
}

View File

@ -67,8 +67,7 @@ class Organise : public QObject {
private slots:
void ProcessSomeFiles();
void FileTranscoded(const QString& input, const QString& output,
bool success);
void FileTranscoded(const QUrl& input, const QString& output, bool success);
private:
void SetSongProgress(float progress, bool transcoded = false);

View File

@ -53,16 +53,16 @@ SongSender::SongSender(Application* app, RemoteClient* client)
}
qLog(Debug) << "Transcoder preset" << transcoder_preset_.codec_mimetype_;
connect(transcoder_, SIGNAL(JobComplete(QString, QString, bool)),
SLOT(TranscodeJobComplete(QString, QString, bool)));
connect(transcoder_, SIGNAL(JobComplete(QUrl, QString, bool)),
SLOT(TranscodeJobComplete(QUrl, QString, bool)));
connect(transcoder_, SIGNAL(AllJobsComplete()), SLOT(StartTransfer()));
total_transcode_ = 0;
}
SongSender::~SongSender() {
disconnect(transcoder_, SIGNAL(JobComplete(QString, QString, bool)), this,
SLOT(TranscodeJobComplete(QString, QString, bool)));
disconnect(transcoder_, SIGNAL(JobComplete(QUrl, QString, bool)), this,
SLOT(TranscodeJobComplete(QUrl, QString, bool)));
disconnect(transcoder_, SIGNAL(AllJobsComplete()), this,
SLOT(StartTransfer()));
transcoder_->Cancel();
@ -110,11 +110,11 @@ void SongSender::TranscodeLosslessFiles() {
if (!item.song_.IsFileLossless()) continue;
// Add the file to the transcoder
QString local_file = item.song_.url().toLocalFile();
QUrl local_file = item.song_.url();
transcoder_->AddTemporaryJob(local_file, transcoder_preset_);
qLog(Debug) << "transcoding" << local_file;
qLog(Debug) << "transcoding" << local_file.toLocalFile();
total_transcode_++;
}
@ -126,13 +126,14 @@ void SongSender::TranscodeLosslessFiles() {
}
}
void SongSender::TranscodeJobComplete(const QString& input,
const QString& output, bool success) {
qLog(Debug) << input << "transcoded to" << output << success;
void SongSender::TranscodeJobComplete(const QUrl& input, const QString& output,
bool success) {
Q_ASSERT(input.isLocalFile()); // songsender only handles local files
qLog(Debug) << input.toLocalFile() << "transcoded to" << output << success;
// If it wasn't successful send original file
if (success) {
transcoder_map_.insert(input, output);
transcoder_map_.insert(input.toLocalFile(), output);
}
SendTranscoderStatus();

View File

@ -34,7 +34,7 @@ class SongSender : public QObject {
void ResponseSongOffer(bool accepted);
private slots:
void TranscodeJobComplete(const QString& input, const QString& output,
void TranscodeJobComplete(const QUrl& input, const QString& output,
bool success);
void StartTransfer();

View File

@ -19,6 +19,7 @@
#include <QFile>
#include <QMutexLocker>
#include <QUrl>
#include <QtConcurrentRun>
#include "core/closure.h"
@ -47,8 +48,8 @@ Ripper::Ripper(CdIo_t* cdio, QObject* parent)
finished_failed_(0),
files_tagged_(0) {
Q_ASSERT(cdio_); // TODO: error handling
connect(transcoder_, SIGNAL(JobComplete(QString, QString, bool)),
SLOT(TranscodingJobComplete(QString, QString, bool)));
connect(transcoder_, SIGNAL(JobComplete(QUrl, QString, bool)),
SLOT(TranscodingJobComplete(QUrl, QString, bool)));
connect(transcoder_, SIGNAL(AllJobsComplete()),
SLOT(AllTranscodingJobsComplete()));
connect(transcoder_, SIGNAL(LogLine(QString)), SLOT(LogLine(QString)));
@ -111,7 +112,7 @@ void Ripper::Cancel() {
emit Cancelled();
}
void Ripper::TranscodingJobComplete(const QString& input, const QString& output,
void Ripper::TranscodingJobComplete(const QUrl& input, const QString& output,
bool success) {
if (success)
finished_success_++;
@ -125,7 +126,8 @@ void Ripper::TranscodingJobComplete(const QString& input, const QString& output,
// file later on.
for (QList<TrackInformation>::iterator it = tracks_.begin();
it != tracks_.end(); ++it) {
if (it->temporary_filename == input) {
Q_ASSERT(input.isLocalFile());
if (it->temporary_filename == input.toLocalFile()) {
it->transcoded_filename = output;
}
}
@ -232,7 +234,7 @@ void Ripper::Rip() {
UpdateProgress();
it->temporary_filename = filename;
transcoder_->AddJob(it->temporary_filename, it->preset,
transcoder_->AddJob(QUrl::fromLocalFile(it->temporary_filename), it->preset,
it->transcoded_filename, it->overwrite_existing);
}
transcoder_->Start();
@ -249,7 +251,7 @@ void Ripper::SetupProgressInterval() {
void Ripper::UpdateProgress() {
int progress = (finished_success_ + finished_failed_) * 100;
QMap<QString, float> current_jobs = transcoder_->GetProgress();
QMap<QUrl, float> current_jobs = transcoder_->GetProgress();
for (float value : current_jobs.values()) {
progress += qBound(0, static_cast<int>(value * 100), 99);
}

View File

@ -73,7 +73,7 @@ class Ripper : public QObject {
void Cancel();
private slots:
void TranscodingJobComplete(const QString& input, const QString& output,
void TranscodingJobComplete(const QUrl& input, const QString& output,
bool success);
void AllTranscodingJobsComplete();
void LogLine(const QString& message);

View File

@ -121,8 +121,8 @@ TranscodeDialog::TranscodeDialog(QWidget* parent)
connect(ui_->options, SIGNAL(clicked()), SLOT(Options()));
connect(ui_->select, SIGNAL(clicked()), SLOT(AddDestination()));
connect(transcoder_, SIGNAL(JobComplete(QString, QString, bool)),
SLOT(JobComplete(QString, QString, bool)));
connect(transcoder_, SIGNAL(JobComplete(QUrl, QString, bool)),
SLOT(JobComplete(QUrl, QString, bool)));
connect(transcoder_, SIGNAL(LogLine(QString)), SLOT(LogLine(QString)));
connect(transcoder_, SIGNAL(AllJobsComplete()), SLOT(AllJobsComplete()));
}
@ -162,7 +162,8 @@ void TranscodeDialog::Start() {
QFileInfo input_fileinfo(
file_model->index(i, 0).data(Qt::UserRole).toString());
QString output_filename = GetOutputFileName(input_fileinfo, preset);
transcoder_->AddJob(input_fileinfo.filePath(), preset, output_filename);
transcoder_->AddJob(QUrl::fromLocalFile(input_fileinfo.filePath()), preset,
output_filename);
}
// Set up the progressbar
@ -195,7 +196,7 @@ void TranscodeDialog::PipelineDumpAction(bool checked) {
}
}
void TranscodeDialog::JobComplete(const QString& input, const QString& output,
void TranscodeDialog::JobComplete(const QUrl& input, const QString& output,
bool success) {
if (success)
finished_success_++;
@ -210,7 +211,7 @@ void TranscodeDialog::JobComplete(const QString& input, const QString& output,
void TranscodeDialog::UpdateProgress() {
int progress = (finished_success_ + finished_failed_) * 100;
QMap<QString, float> current_jobs = transcoder_->GetProgress();
QMap<QUrl, float> current_jobs = transcoder_->GetProgress();
for (float value : current_jobs.values()) {
progress += qBound(0, int(value * 100), 99);
}

View File

@ -51,7 +51,7 @@ class TranscodeDialog : public QDialog {
void Remove();
void Start();
void Cancel();
void JobComplete(const QString& input, const QString& output, bool success);
void JobComplete(const QUrl& input, const QString& output, bool success);
void LogLine(const QString& message);
void AllJobsComplete();
void Options();

View File

@ -32,6 +32,11 @@
using std::shared_ptr;
static QString UrlToLocalFileIfPossible(QUrl url) {
if (url.isLocalFile()) return url.toLocalFile();
return url.toString();
}
int Transcoder::JobFinishedEvent::sEventType = -1;
TranscoderPreset::TranscoderPreset(Song::FileType type, const QString& name,
@ -210,8 +215,7 @@ void Transcoder::JobState::PostFinished(bool success) {
}
QString Transcoder::JobState::GetDisplayName() {
return QFileInfo(job_.input).fileName() + " => " +
QFileInfo(job_.output).fileName();
return job_.input.fileName() + " => " + QFileInfo(job_.output).fileName();
}
Transcoder::Transcoder(QObject* parent, const QString& settings_postfix)
@ -318,7 +322,7 @@ Song::FileType Transcoder::PickBestFormat(QList<Song::FileType> supported) {
return supported[0];
}
void Transcoder::AddJob(const QString& input, const TranscoderPreset& preset,
void Transcoder::AddJob(const QUrl& input, const TranscoderPreset& preset,
const QString& output, bool overwrite_existing) {
Job job;
job.input = input;
@ -329,7 +333,8 @@ void Transcoder::AddJob(const QString& input, const TranscoderPreset& preset,
if (!output.isEmpty())
job.output = output;
else
job.output = input.section('.', 0, -2) + '.' + preset.extension_;
job.output = UrlToLocalFileIfPossible(input).section('.', 0, -2) + '.' +
preset.extension_;
// Don't overwrite existing files if overwrite_existing is not set
if (!overwrite_existing && QFile::exists(job.output)) {
@ -348,14 +353,9 @@ void Transcoder::AddJob(const QString& input, const TranscoderPreset& preset,
queued_jobs_ << job;
}
void Transcoder::AddTemporaryJob(const QString& input,
void Transcoder::AddTemporaryJob(const QUrl& input,
const TranscoderPreset& preset) {
Job job;
job.input = input;
job.output = Utilities::GetTemporaryFileName();
job.preset = preset;
queued_jobs_ << job;
AddJob(input, preset, Utilities::GetTemporaryFileName());
}
void Transcoder::Start() {
@ -434,13 +434,13 @@ void Transcoder::JobState::ReportError(GstMessage* msg) {
emit parent_->LogLine(
tr("Error processing %1: %2")
.arg(QDir::toNativeSeparators(job_.input), message));
.arg(UrlToLocalFileIfPossible(job_.input), message));
}
bool Transcoder::StartJob(const Job& job) {
shared_ptr<JobState> state(new JobState(job, this));
emit LogLine(tr("Starting %1").arg(QDir::toNativeSeparators(job.input)));
emit LogLine(tr("Starting %1").arg(UrlToLocalFileIfPossible(job.input)));
// Create the pipeline.
// This should be a scoped_ptr, but scoped_ptr doesn't support custom
@ -448,8 +448,7 @@ bool Transcoder::StartJob(const Job& job) {
if (!state->Init()) return false;
// Create all the elements
GstElement* src = CreateElement("filesrc", state->Pipeline());
GstElement* decode = CreateElement("decodebin", state->Pipeline());
GstElement* decode = CreateElement("uridecodebin", state->Pipeline());
GstElement* convert = CreateElement("audioconvert", state->Pipeline());
GstElement* resample = CreateElement("audioresample", state->Pipeline());
GstElement* codec = CreateElementForMimeType(
@ -458,7 +457,7 @@ bool Transcoder::StartJob(const Job& job) {
"Codec/Muxer", job.preset.muxer_mimetype_, state->Pipeline());
GstElement* sink = CreateElement("filesink", state->Pipeline());
if (!src || !decode || !convert || !sink) return false;
if (!decode || !convert || !sink) return false;
if (!codec && !job.preset.codec_mimetype_.isEmpty()) {
emit LogLine(
@ -476,7 +475,6 @@ bool Transcoder::StartJob(const Job& job) {
}
// Join them together
gst_element_link(src, decode);
if (codec && muxer)
gst_element_link_many(convert, resample, codec, muxer, sink, nullptr);
else if (codec)
@ -485,7 +483,8 @@ bool Transcoder::StartJob(const Job& job) {
gst_element_link_many(convert, resample, muxer, sink, nullptr);
// Set properties
g_object_set(src, "location", job.input.toUtf8().constData(), nullptr);
g_object_set(decode, "uri", job.input.toString().toUtf8().constData(),
nullptr);
g_object_set(sink, "location", job.output.toUtf8().constData(), nullptr);
// Create target directory, if it does not exist
@ -528,7 +527,7 @@ bool Transcoder::event(QEvent* e) {
return true;
}
QString input = (*it)->job_.input;
QUrl input = (*it)->job_.input;
QString output = (*it)->job_.output;
// Remove event handlers from the gstreamer pipeline so they don't get
@ -591,8 +590,8 @@ void Transcoder::DumpGraph(int id) {
}
}
QMap<QString, float> Transcoder::GetProgress() const {
QMap<QString, float> ret;
QMap<QUrl, float> Transcoder::GetProgress() const {
QMap<QUrl, float> ret;
for (const auto& state : current_jobs_) {
if (!state->Pipeline()) continue;

View File

@ -24,6 +24,7 @@
#include <QMetaType>
#include <QObject>
#include <QStringList>
#include <QUrl>
#include <memory>
#include "core/song.h"
@ -70,12 +71,12 @@ class Transcoder : public QObject {
int max_threads() const { return max_threads_; }
void set_max_threads(int count) { max_threads_ = count; }
void AddJob(const QString& input, const TranscoderPreset& preset,
void AddJob(const QUrl& input, const TranscoderPreset& preset,
const QString& output = QString(),
bool overwrite_existing = false);
void AddTemporaryJob(const QString& input, const TranscoderPreset& preset);
void AddTemporaryJob(const QUrl& input, const TranscoderPreset& preset);
QMap<QString, float> GetProgress() const;
QMap<QUrl, float> GetProgress() const;
int QueuedJobsCount() const { return queued_jobs_.count(); }
GstPipelineModel* model() { return model_; }
@ -86,7 +87,7 @@ class Transcoder : public QObject {
static QString GetEncoderFactoryForMimeType(const QString& mime_type);
signals:
void JobComplete(const QString& input, const QString& output, bool success);
void JobComplete(const QUrl& input, const QString& output, bool success);
void LogLine(const QString& message);
void AllJobsComplete();
@ -96,7 +97,7 @@ class Transcoder : public QObject {
private:
// The description of a file to transcode - lives in the main thread.
struct Job {
QString input;
QUrl input;
QString output;
TranscoderPreset preset;
};