1 /*
2     SPDX-FileCopyrightText: 2016 Jean-Baptiste Mardelle <jb@kdenlive.org>
3 
4 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5 */
6 
7 #ifndef PREVIEWMANAGER_H
8 #define PREVIEWMANAGER_H
9 
10 #include "definitions.h"
11 
12 #include <QDir>
13 #include <QFuture>
14 #include <QMutex>
15 #include <QProcess>
16 #include <QTimer>
17 
18 class TimelineController;
19 
20 namespace Mlt {
21 class Tractor;
22 class Playlist;
23 class Producer;
24 } // namespace Mlt
25 
26 /** @class PreviewManager
27     @brief Handles timeline preview.
28     This manager creates an additional video track on top of the current timeline and renders
29     chunks (small video files of 25 frames) that are added on this track when rendered.
30     This allow us to get a preview with a smooth playback of our project.
31     Only the preview zone is rendered. Once defined, a preview zone shows as a red line below
32     the timeline ruler. As chunks are rendered, the zone turns to green.
33  */
34 class PreviewManager : public QObject
35 {
36     Q_OBJECT
37 
38 public:
39     friend class TimelineController;
40 
41     explicit PreviewManager(TimelineController *controller, Mlt::Tractor *tractor);
42     ~PreviewManager() override;
43     /** @brief: initialize base variables, return false if error. */
44     bool initialize();
45     /** @brief: a timeline operation caused changes to frames between startFrame and endFrame. */
46     void invalidatePreview(int startFrame, int endFrame);
47     /** @brief: after a small  delay (some operations trigger several invalidatePreview calls), take care of these invalidated chunks. */
48     void invalidatePreviews();
49     /** @brief: user adds current timeline zone to the preview zone. */
50     void addPreviewRange(const QPoint zone, bool add);
51     /** @brief: Remove all existing previews. */
52     void clearPreviewRange(bool resetZones);
53     /** @brief: stops current rendering process. */
54     void abortRendering();
55     /** @brief: rendering parameters have changed, reload them. */
56     bool loadParams();
57     /** @brief: Create the preview track if not existing. */
58     bool buildPreviewTrack();
59     /** @brief: Delete the preview track. */
60     void deletePreviewTrack();
61     /** @brief: Whenever we save or render our project, we remove the preview track so it is not saved. */
62     void reconnectTrack();
63     /** @brief: After project save or render, re-add our preview track. */
64     void disconnectTrack();
65     /** @brief: Returns directory currently used to store the preview files. */
66     const QDir getCacheDir() const;
67     /** @brief: Load existing ruler chunks. */
68     void loadChunks(QVariantList previewChunks, QVariantList dirtyChunks, const QDateTime &documentDate, Mlt::Playlist &playlist);
69     int setOverlayTrack(Mlt::Playlist *overlay);
70     /** @brief Remove the effect compare overlay track */
71     void removeOverlayTrack();
72     /** @brief The current preview chunk being processed, -1 if none */
73     int workingPreview;
74     /** @brief Returns the list of existing chunks */
75     QPair<QStringList, QStringList> previewChunks() const;
76     bool hasOverlayTrack() const;
77     bool hasPreviewTrack() const;
78     int addedTracks() const;
79 
80 private:
81     TimelineController *m_controller;
82     Mlt::Tractor *m_tractor;
83     Mlt::Playlist *m_previewTrack;
84     Mlt::Playlist *m_overlayTrack;
85     int m_previewTrackIndex;
86     /** @brief: The kdenlive renderer app. */
87     QString m_renderer;
88     /** @brief: The kdenlive timeline preview process. */
89     QProcess m_previewProcess;
90     /** @brief: The directory used to store the preview files. */
91     QDir m_cacheDir;
92     /** @brief: The directory used to store undo history of preview files (child of m_cacheDir). */
93     QDir m_undoDir;
94     QMutex m_previewMutex;
95     QStringList m_consumerParams;
96     QString m_extension;
97     /** @brief: Timer used to autostart preview rendering. */
98     QTimer m_previewTimer;
99     /** @brief: Since some timeline operations generate several invalidate calls, use a timer to get them all. */
100     QTimer m_previewGatherTimer;
101     bool m_initialized;
102     QList<int> m_waitingThumbs;
103     QFuture<void> m_previewThread;
104     /** @brief: The count of chunks to process - to calculate job progress */
105     int m_chunksToRender;
106     /** @brief: The count of already processed chunks - to calculate job progress */
107     int m_processedChunks;
108     /** @brief: The render process output, useful in case of failure */
109     QString m_errorLog;
110     /** @brief: After an undo/redo, if we have preview history, use it. */
111     void reloadChunks(const QVariantList chunks);
112     /** @brief: A chunk failed to render, abort. */
113     void corruptedChunk(int workingPreview, const QString &fileName);
114     /** @brief: Re-enable timeline preview track. */
115     void enable();
116     /** @brief: Temporarily disable timeline preview track. */
117     void disable();
118 
119 private slots:
120     /** @brief: To avoid filling the hard drive, remove preview undo history after 5 steps. */
121     void doCleanupOldPreviews();
122     /** @brief: Start the real rendering process. */
123     void doPreviewRender(const QString &scene); // std::shared_ptr<Mlt::Producer> sourceProd);
124     /** @brief: If user does an undo, then makes a new timeline operation, delete undo history of more recent stack . */
125     void slotRemoveInvalidUndo(int ix);
126     /** @brief: When the timer collecting invalid zones is done, process. */
127     void slotProcessDirtyChunks();
128     /** @brief: Process preview rendering output. */
129     void receivedStderr();
130     void processEnded(int, QProcess::ExitStatus status);
131 
132 public slots:
133     /** @brief: Prepare and start rendering. */
134     void startPreviewRender();
135     /** @brief: A chunk has been created, notify ruler. */
136     void gotPreviewRender(int frame, const QString &file, int progress);
137 
138 protected:
139     QVariantList m_renderedChunks;
140     QVariantList m_dirtyChunks;
141     mutable QMutex m_dirtyMutex;
142 
143 signals:
144     void abortPreview();
145     void cleanupOldPreviews();
146     void previewRender(int frame, const QString &file, int progress);
147 };
148 
149 #endif
150