1 /******************************************************************************
2     Copyright (C) 2014 by Ruwen Hahn <palana@stunned.de>
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17 
18 #pragma once
19 
20 #include <QFileInfo>
21 #include <QMutex>
22 #include <QPointer>
23 #include <QThread>
24 #include <QStyledItemDelegate>
25 #include <memory>
26 #include "ui_OBSRemux.h"
27 
28 #include <media-io/media-remux.h>
29 #include <util/threading.h>
30 
31 class RemuxQueueModel;
32 class RemuxWorker;
33 
34 enum RemuxEntryState {
35 	Empty,
36 	Ready,
37 	Pending,
38 	InProgress,
39 	Complete,
40 	InvalidPath,
41 	Error
42 };
43 Q_DECLARE_METATYPE(RemuxEntryState);
44 
45 class OBSRemux : public QDialog {
46 	Q_OBJECT
47 
48 	QPointer<RemuxQueueModel> queueModel;
49 	QThread remuxer;
50 	QPointer<RemuxWorker> worker;
51 
52 	std::unique_ptr<Ui::OBSRemux> ui;
53 
54 	const char *recPath;
55 
56 	virtual void closeEvent(QCloseEvent *event) override;
57 	virtual void reject() override;
58 
59 	bool autoRemux;
60 	QString autoRemuxFile;
61 
62 public:
63 	explicit OBSRemux(const char *recPath, QWidget *parent = nullptr,
64 			  bool autoRemux = false);
65 	virtual ~OBSRemux() override;
66 
67 	using job_t = std::shared_ptr<struct media_remux_job>;
68 
69 	void AutoRemux(QString inFile, QString outFile);
70 
71 protected:
72 	virtual void dropEvent(QDropEvent *ev) override;
73 	virtual void dragEnterEvent(QDragEnterEvent *ev) override;
74 
75 	void remuxNextEntry();
76 
77 private slots:
78 	void rowCountChanged(const QModelIndex &parent, int first, int last);
79 
80 public slots:
81 	void updateProgress(float percent);
82 	void remuxFinished(bool success);
83 	void beginRemux();
84 	bool stopRemux();
85 	void clearFinished();
86 	void clearAll();
87 
88 signals:
89 	void remux(const QString &source, const QString &target);
90 };
91 
92 class RemuxQueueModel : public QAbstractTableModel {
93 	Q_OBJECT
94 
95 	friend class OBSRemux;
96 
97 public:
RemuxQueueModel(QObject * parent=0)98 	RemuxQueueModel(QObject *parent = 0)
99 		: QAbstractTableModel(parent), isProcessing(false)
100 	{
101 	}
102 
103 	int rowCount(const QModelIndex &parent = QModelIndex()) const;
104 	int columnCount(const QModelIndex &parent = QModelIndex()) const;
105 	QVariant data(const QModelIndex &index, int role) const;
106 	QVariant headerData(int section, Qt::Orientation orientation,
107 			    int role = Qt::DisplayRole) const;
108 	Qt::ItemFlags flags(const QModelIndex &index) const;
109 	bool setData(const QModelIndex &index, const QVariant &value, int role);
110 
111 	QFileInfoList checkForOverwrites() const;
112 	bool checkForErrors() const;
113 	void beginProcessing();
114 	void endProcessing();
115 	bool beginNextEntry(QString &inputPath, QString &outputPath);
116 	void finishEntry(bool success);
117 	bool canClearFinished() const;
118 	void clearFinished();
119 	void clearAll();
120 
121 	bool autoRemux = false;
122 
123 private:
124 	struct RemuxQueueEntry {
125 		RemuxEntryState state;
126 
127 		QString sourcePath;
128 		QString targetPath;
129 	};
130 
131 	QList<RemuxQueueEntry> queue;
132 	bool isProcessing;
133 
134 	static QVariant getIcon(RemuxEntryState state);
135 
136 	void checkInputPath(int row);
137 };
138 
139 class RemuxWorker : public QObject {
140 	Q_OBJECT
141 
142 	QMutex updateMutex;
143 
144 	bool isWorking;
145 
146 	float lastProgress;
147 	void UpdateProgress(float percent);
148 
RemuxWorker()149 	explicit RemuxWorker() : isWorking(false) {}
~RemuxWorker()150 	virtual ~RemuxWorker(){};
151 
152 private slots:
153 	void remux(const QString &source, const QString &target);
154 
155 signals:
156 	void updateProgress(float percent);
157 	void remuxFinished(bool success);
158 
159 	friend class OBSRemux;
160 };
161 
162 class RemuxEntryPathItemDelegate : public QStyledItemDelegate {
163 	Q_OBJECT
164 
165 public:
166 	RemuxEntryPathItemDelegate(bool isOutput, const QString &defaultPath);
167 
168 	virtual QWidget *createEditor(QWidget *parent,
169 				      const QStyleOptionViewItem & /* option */,
170 				      const QModelIndex &index) const override;
171 
172 	virtual void setEditorData(QWidget *editor,
173 				   const QModelIndex &index) const override;
174 	virtual void setModelData(QWidget *editor, QAbstractItemModel *model,
175 				  const QModelIndex &index) const override;
176 	virtual void paint(QPainter *painter,
177 			   const QStyleOptionViewItem &option,
178 			   const QModelIndex &index) const override;
179 
180 private:
181 	bool isOutput;
182 	QString defaultPath;
183 	const char *PATH_LIST_PROP = "pathList";
184 
185 	void handleBrowse(QWidget *container);
186 	void handleClear(QWidget *container);
187 
188 private slots:
189 	void updateText();
190 };
191