From bb618efc5d1ee29e1cd95f19ff3ae77bd507bbc5 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Sun, 16 May 2021 15:03:36 +0300 Subject: [PATCH] Transcoder now accepts URLs for sources. --- src/core/organise.cpp | 24 +++++++++-------- src/core/organise.h | 3 +-- src/networkremote/songsender.cpp | 21 +++++++-------- src/networkremote/songsender.h | 2 +- src/ripper/ripper.cpp | 14 +++++----- src/ripper/ripper.h | 2 +- src/transcoder/transcodedialog.cpp | 11 ++++---- src/transcoder/transcodedialog.h | 2 +- src/transcoder/transcoder.cpp | 41 +++++++++++++++--------------- src/transcoder/transcoder.h | 11 ++++---- 10 files changed, 69 insertions(+), 62 deletions(-) diff --git a/src/core/organise.cpp b/src/core/organise.cpp index a55677406..5c40457e1 100644 --- a/src/core/organise.cpp +++ b/src/core/organise.cpp @@ -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 transcode_progress = transcoder_->GetProgress(); - for (const QString& filename : transcode_progress.keys()) { + QMap 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; } diff --git a/src/core/organise.h b/src/core/organise.h index 1f0033c0d..26a19ab66 100644 --- a/src/core/organise.h +++ b/src/core/organise.h @@ -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); diff --git a/src/networkremote/songsender.cpp b/src/networkremote/songsender.cpp index 682a11b09..78f905af7 100644 --- a/src/networkremote/songsender.cpp +++ b/src/networkremote/songsender.cpp @@ -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(); diff --git a/src/networkremote/songsender.h b/src/networkremote/songsender.h index 115ca94fe..ec828cbc0 100644 --- a/src/networkremote/songsender.h +++ b/src/networkremote/songsender.h @@ -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(); diff --git a/src/ripper/ripper.cpp b/src/ripper/ripper.cpp index 1333c0469..4d51ae9f6 100644 --- a/src/ripper/ripper.cpp +++ b/src/ripper/ripper.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #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::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 current_jobs = transcoder_->GetProgress(); + QMap current_jobs = transcoder_->GetProgress(); for (float value : current_jobs.values()) { progress += qBound(0, static_cast(value * 100), 99); } diff --git a/src/ripper/ripper.h b/src/ripper/ripper.h index a4f8d8af8..c50497d5d 100644 --- a/src/ripper/ripper.h +++ b/src/ripper/ripper.h @@ -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); diff --git a/src/transcoder/transcodedialog.cpp b/src/transcoder/transcodedialog.cpp index 7485fc5fe..6ee7685c4 100644 --- a/src/transcoder/transcodedialog.cpp +++ b/src/transcoder/transcodedialog.cpp @@ -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 current_jobs = transcoder_->GetProgress(); + QMap current_jobs = transcoder_->GetProgress(); for (float value : current_jobs.values()) { progress += qBound(0, int(value * 100), 99); } diff --git a/src/transcoder/transcodedialog.h b/src/transcoder/transcodedialog.h index d0b77c748..c75067124 100644 --- a/src/transcoder/transcodedialog.h +++ b/src/transcoder/transcodedialog.h @@ -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(); diff --git a/src/transcoder/transcoder.cpp b/src/transcoder/transcoder.cpp index 8b148a6d0..3b0e55d20 100644 --- a/src/transcoder/transcoder.cpp +++ b/src/transcoder/transcoder.cpp @@ -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 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 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 Transcoder::GetProgress() const { - QMap ret; +QMap Transcoder::GetProgress() const { + QMap ret; for (const auto& state : current_jobs_) { if (!state->Pipeline()) continue; diff --git a/src/transcoder/transcoder.h b/src/transcoder/transcoder.h index cde7917f5..4932cbeb4 100644 --- a/src/transcoder/transcoder.h +++ b/src/transcoder/transcoder.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #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 GetProgress() const; + QMap 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; };