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; thread_ = new QThread;
connect(thread_, SIGNAL(started()), SLOT(ProcessSomeFiles())); connect(thread_, SIGNAL(started()), SLOT(ProcessSomeFiles()));
connect(transcoder_, SIGNAL(JobComplete(QString, QString, bool)), connect(transcoder_, SIGNAL(JobComplete(QUrl, QString, bool)),
SLOT(FileTranscoded(QString, QString, bool))); SLOT(FileTranscoded(QUrl, QString, bool)));
moveToThread(thread_); moveToThread(thread_);
thread_->start(); thread_->start();
@ -177,7 +177,7 @@ void Organise::ProcessSomeFiles() {
// Start the transcoding - this will happen in the background and // Start the transcoding - this will happen in the background and
// FileTranscoded() will get called when it's done. At that point the // 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. // 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_); task.transcoded_filename_);
transcoder_->Start(); transcoder_->Start();
continue; continue;
@ -262,11 +262,12 @@ void Organise::UpdateProgress() {
const int total = task_count_ * 100; const int total = task_count_ * 100;
// Update transcoding progress // Update transcoding progress
QMap<QString, float> transcode_progress = transcoder_->GetProgress(); QMap<QUrl, float> transcode_progress = transcoder_->GetProgress();
for (const QString& filename : transcode_progress.keys()) { for (const QUrl& fileurl : transcode_progress.keys()) {
QString filename = fileurl.toLocalFile();
if (!tasks_transcoding_.contains(filename)) continue; if (!tasks_transcoding_.contains(filename)) continue;
tasks_transcoding_[filename].transcode_progress_ = 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 // 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); 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) { 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(); transcode_progress_timer_.stop();
Task task = tasks_transcoding_.take(input); Task task = tasks_transcoding_.take(input_file_path);
if (!success) { if (!success) {
files_with_errors_ << input; files_with_errors_ << input_file_path;
} else { } else {
tasks_pending_ << task; tasks_pending_ << task;
} }

View File

@ -67,8 +67,7 @@ class Organise : public QObject {
private slots: private slots:
void ProcessSomeFiles(); void ProcessSomeFiles();
void FileTranscoded(const QString& input, const QString& output, void FileTranscoded(const QUrl& input, const QString& output, bool success);
bool success);
private: private:
void SetSongProgress(float progress, bool transcoded = false); 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_; qLog(Debug) << "Transcoder preset" << transcoder_preset_.codec_mimetype_;
connect(transcoder_, SIGNAL(JobComplete(QString, QString, bool)), connect(transcoder_, SIGNAL(JobComplete(QUrl, QString, bool)),
SLOT(TranscodeJobComplete(QString, QString, bool))); SLOT(TranscodeJobComplete(QUrl, QString, bool)));
connect(transcoder_, SIGNAL(AllJobsComplete()), SLOT(StartTransfer())); connect(transcoder_, SIGNAL(AllJobsComplete()), SLOT(StartTransfer()));
total_transcode_ = 0; total_transcode_ = 0;
} }
SongSender::~SongSender() { SongSender::~SongSender() {
disconnect(transcoder_, SIGNAL(JobComplete(QString, QString, bool)), this, disconnect(transcoder_, SIGNAL(JobComplete(QUrl, QString, bool)), this,
SLOT(TranscodeJobComplete(QString, QString, bool))); SLOT(TranscodeJobComplete(QUrl, QString, bool)));
disconnect(transcoder_, SIGNAL(AllJobsComplete()), this, disconnect(transcoder_, SIGNAL(AllJobsComplete()), this,
SLOT(StartTransfer())); SLOT(StartTransfer()));
transcoder_->Cancel(); transcoder_->Cancel();
@ -110,11 +110,11 @@ void SongSender::TranscodeLosslessFiles() {
if (!item.song_.IsFileLossless()) continue; if (!item.song_.IsFileLossless()) continue;
// Add the file to the transcoder // 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_); transcoder_->AddTemporaryJob(local_file, transcoder_preset_);
qLog(Debug) << "transcoding" << local_file; qLog(Debug) << "transcoding" << local_file.toLocalFile();
total_transcode_++; total_transcode_++;
} }
@ -126,13 +126,14 @@ void SongSender::TranscodeLosslessFiles() {
} }
} }
void SongSender::TranscodeJobComplete(const QString& input, void SongSender::TranscodeJobComplete(const QUrl& input, const QString& output,
const QString& output, bool success) { bool success) {
qLog(Debug) << input << "transcoded to" << output << 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 it wasn't successful send original file
if (success) { if (success) {
transcoder_map_.insert(input, output); transcoder_map_.insert(input.toLocalFile(), output);
} }
SendTranscoderStatus(); SendTranscoderStatus();

View File

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

View File

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

View File

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

View File

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

View File

@ -51,7 +51,7 @@ class TranscodeDialog : public QDialog {
void Remove(); void Remove();
void Start(); void Start();
void Cancel(); 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 LogLine(const QString& message);
void AllJobsComplete(); void AllJobsComplete();
void Options(); void Options();

View File

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

View File

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