1 /*
2  * Strawberry Music Player
3  * This file was part of Clementine.
4  * Copyright 2010, David Sansome <me@davidsansome.com>
5  * Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net>
6  *
7  * Strawberry is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Strawberry is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Strawberry.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef TRANSCODER_H
23 #define TRANSCODER_H
24 
25 #include "config.h"
26 
27 #include <memory>
28 #include <glib.h>
29 #include <glib-object.h>
30 #include <gst/gst.h>
31 
32 #include <QObject>
33 #include <QList>
34 #include <QMap>
35 #include <QMetaType>
36 #include <QSet>
37 #include <QString>
38 #include <QEvent>
39 
40 #include "core/song.h"
41 
42 struct TranscoderPreset {
TranscoderPresetTranscoderPreset43   explicit TranscoderPreset() : filetype_(Song::FileType_Unknown) {}
44   TranscoderPreset(const Song::FileType filetype, const QString &name, const QString &extension, const QString &codec_mimetype, const QString &muxer_mimetype_ = QString());
45 
46   Song::FileType filetype_;
47   QString name_;
48   QString extension_;
49   QString codec_mimetype_;
50   QString muxer_mimetype_;
51 };
Q_DECLARE_METATYPE(TranscoderPreset)52 Q_DECLARE_METATYPE(TranscoderPreset)
53 
54 class Transcoder : public QObject {
55   Q_OBJECT
56 
57  public:
58   explicit Transcoder(QObject *parent = nullptr, const QString &settings_postfix = "");
59 
60   static TranscoderPreset PresetForFileType(const Song::FileType filetype);
61   static QList<TranscoderPreset> GetAllPresets();
62   static Song::FileType PickBestFormat(const QList<Song::FileType> &supported);
63 
64   int max_threads() const { return max_threads_; }
65   void set_max_threads(int count) { max_threads_ = count; }
66 
67   static QString GetFile(const QString &input, const TranscoderPreset &preset, const QString &output = QString());
68   void AddJob(const QString &input, const TranscoderPreset &preset, const QString &output);
69 
70   QMap<QString, float> GetProgress() const;
71   int QueuedJobsCount() const { return queued_jobs_.count(); }
72 
73  public slots:
74   void Start();
75   void Cancel();
76 
77  signals:
78   void JobComplete(QString input, QString output, bool success);
79   void LogLine(QString message);
80   void AllJobsComplete();
81 
82  protected:
83   bool event(QEvent *e) override;
84 
85  private:
86   // The description of a file to transcode - lives in the main thread.
87   struct Job {
88     QString input;
89     QString output;
90     TranscoderPreset preset;
91   };
92 
93   // State held by a job and shared across gstreamer callbacks - lives in the job's thread.
94   struct JobState {
95     explicit JobState(const Job &job, Transcoder *parent)
96         : job_(job),
97           parent_(parent),
98           pipeline_(nullptr),
99           convert_element_(nullptr) {}
100     ~JobState();
101 
102     void PostFinished(const bool success);
103     void ReportError(GstMessage *msg) const;
104 
105     Job job_;
106     Transcoder *parent_;
107     GstElement *pipeline_;
108     GstElement *convert_element_;
109    private:
110     Q_DISABLE_COPY(JobState)
111   };
112 
113   // Event passed from a GStreamer callback to the Transcoder when a job finishes.
114   struct JobFinishedEvent : public QEvent {
115     explicit JobFinishedEvent(JobState *state, bool success);
116 
117     static int sEventType;
118 
119     JobState *state_;
120     bool success_;
121    private:
122     Q_DISABLE_COPY(JobFinishedEvent)
123   };
124 
125   enum StartJobStatus {
126     StartedSuccessfully,
127     FailedToStart,
128     NoMoreJobs,
129     AllThreadsBusy,
130   };
131 
132   StartJobStatus MaybeStartNextJob();
133   bool StartJob(const Job &job);
134 
135   GstElement *CreateElement(const QString &factory_name, GstElement *bin = nullptr, const QString &name = QString());
136   GstElement *CreateElementForMimeType(const QString &element_type, const QString &mime_type, GstElement *bin = nullptr);
137   void SetElementProperties(const QString &name, GObject *object);
138 
139   static void NewPadCallback(GstElement*, GstPad *pad, gpointer data);
140   static GstBusSyncReply BusCallbackSync(GstBus*, GstMessage *msg, gpointer data);
141 
142  private:
143   typedef QList<std::shared_ptr<JobState>> JobStateList;
144 
145   int max_threads_;
146   QList<Job> queued_jobs_;
147   JobStateList current_jobs_;
148   QString settings_postfix_;
149 };
150 
151 #endif  // TRANSCODER_H
152