File: decoder.h

package info (click to toggle)
olive-editor 20200620-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 40,228 kB
  • sloc: cpp: 51,932; sh: 56; makefile: 7; xml: 7
file content (271 lines) | stat: -rw-r--r-- 10,235 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/***

  Olive - Non-Linear Video Editor
  Copyright (C) 2019 Olive Team

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.

***/

#ifndef DECODER_H
#define DECODER_H

extern "C" {
#include <libswresample/swresample.h>
}

#include <QMutex>
#include <QObject>
#include <stdint.h>

#include "codec/frame.h"
#include "codec/samplebuffer.h"
#include "codec/waveoutput.h"
#include "common/rational.h"
#include "project/item/footage/footage.h"

OLIVE_NAMESPACE_ENTER

class Decoder;
using DecoderPtr = std::shared_ptr<Decoder>;

/**
 * @brief A decoder's is the main class for bringing external media into Olive
 *
 * Its responsibilities are to serve as
 * abstraction from codecs/decoders and provide complete frames. These frames can be video or audio data and are
 * provided as Frame objects in shared pointers to alleviate the responsibility of memory handling.
 *
 * The main function in a decoder is Retrieve() which should return complete image/audio data. A decoder should
 * alleviate all the complexities of codec compression from the rest of the application (i.e. a decoder should never
 * return a partial frame or require other parts of the system to interface directly with the codec). Often this will
 * necessitate pre-emptively caching, indexing, or even fully transcoding media before using it which can be implemented
 * through the Analyze() function.
 *
 * A decoder does NOT perform any pixel/sample format conversion. Frames should pass through the PixelService
 * to be utilized in the rest of the rendering pipeline.
 */
class Decoder : public QObject
{
  Q_OBJECT
public:
  enum RetrieveState {
    kReady,
    kFailedToOpen,
    kIndexUnavailable
  };

  Decoder();

  Decoder(Stream* fs);

  DISABLE_COPY_MOVE(Decoder)

  virtual QString id() = 0;

  StreamPtr stream() const;
  void set_stream(StreamPtr fs);

  /**
   * @brief Probe a footage file and dump metadata about it
   *
   * When a Footage file is imported, we'll need to know whether Olive is equipped with a decoder for utilizing it
   * and metadata should be retrieved about it if so. For this purpose, the Footage object is passed through all
   * Probe() functions of available deocders until one returns TRUE. A FALSE return means the Decoder was unable to
   * parse this file and the next should be tried.
   *
   * Probe() differs from Open() since it focuses on a file as a whole rather than one particular stream. Probe()
   * should be able to be run directly without calling Open() or Close() and should free its memory before returning.
   *
   * Probe() will never be called on an object that is also used for decoding. In other words, it will never be called
   * alongside Open() or Close() externally, so Probe() can use variables that would otherwise be used for decoding
   * without conflict.
   *
   * @param f
   *
   * A Footage object to probe. The Footage object will have a valid filename and will be empty prior to being sent
   * to this function (i.e. Footage::Clear() will not have to be called).
   *
   * @return
   *
   * TRUE if the Decoder was able to decode this file. FALSE if not. This function should have filled the Footage
   * object with metadata if it returns TRUE. Otherwise, the Footage object should be untouched.
   */
  virtual bool Probe(Footage* f, const QAtomicInt* cancelled) = 0;

  /**
   * @brief Open media/allocate memory
   *
   * Any file handles or memory allocation that needs to be done before this instance of a Decoder can return data
   * should be done here.
   *
   * @return
   *
   * TRUE if successful and ready to return data, FALSE if failed to open and unable to retrieve data. If the function
   * fails, any memory allocated should be free'd before returning FALSE, possibly by calling Close().
   */
  virtual bool Open() = 0;

  /**
   * @brief Retrieve video frame
   *
   * The main function for retrieving video data from the Decoder. This function should always provide complete frame
   * data (i.e. no partial frames) at the timecode provided. The Decoder should perform any steps required to retrieve
   * a complete frame separate from the rest of the program, using any form of caching/indexing to keep this as
   * performant as possible.
   *
   * It's acceptable for this function to check whether the Decoder is open, and call Open() if not. If Open() returns
   * false, this function should return nullptr.
   *
   * @param timecode
   *
   * The timecode (a rational in seconds) to retrieve the frame at. If there is not a frame at this precise location
   * this should be corrected internally to the closest fit for the timecode.
   *
   * @return
   *
   * A FramePtr of valid data at this timecode or nullptr if there was nothing to retrieve at the provided timecode or
   * the media could not be opened.
   */
  virtual FramePtr RetrieveVideo(const rational& timecode, const int& divider);

  /**
   * @brief Retrieve video frame
   *
   * The main function for retrieving audio data from the Decoder. This function should always provide complete frame
   * data (i.e. no missing samples) at the timecode and length requested. The Decoder should perform any steps
   * required to retrieve a complete frame separate from the rest of the program, using any form of caching/indexing
   * to keep this as performant as possible.
   *
   * It's acceptable for this function to check whether the Decoder is open, and call Open() if not. If Open() returns
   * false, this function should return nullptr.
   *
   * @param timecode
   *
   * The starting timecode (a rational in seconds) to retrieve the data at.
   *
   * @param length
   *
   * The total length of audio data to retrieve (a rational in seconds).
   *
   * @return
   *
   * A FramePtr of valid data at this timecode of the requested length or nullptr if there was nothing to retrieve at
   * the provided timecode or the media could not be opened.
   */
  virtual SampleBufferPtr RetrieveAudio(const rational& timecode, const rational& length, const AudioParams& params);

  virtual bool SupportsVideo();
  virtual bool SupportsAudio();

  /**
   * @brief Close media/deallocate memory
   *
   * Any file handles or memory allocations opened in Open() should be cleaned up here.
   *
   * As the main memory freeing function, it's good practice to call this in Open() if there's an error that prevents
   * correct function before Open() returns. As such, Close() should be prepared for not all memory/file handles to
   * have been opened successfully.
   */
  virtual void Close() = 0;

  /**
   * @brief Try to probe a Footage file by passing it through all available Decoders
   *
   * This is a helper function designed to abstract the process of communicating with several Decoders from the rest of
   * the application. This function will take a Footage file and manually pass it through the available Decoders' Probe()
   * functions until one indicates that it can decode this file. That Decoder will then dump information about the file
   * into the Footage object for use throughout the program.
   *
   * Probing may be a lengthy process and it's recommended to run this in a separate thread.
   *
   * @param f
   *
   * A Footage object with a valid filename. If the Footage does not have a valid filename (e.g. is empty or file doesn't
   * exist), this function will return FALSE.
   *
   * @return
   *
   * TRUE if a Decoder was successfully able to parse and probe this file. FALSE if not.
   */
  static bool ProbeMedia(Footage* f, const QAtomicInt *cancelled);

  /**
   * @brief Create a Decoder instance using a Decoder ID
   *
   * @return
   *
   * A Decoder instance or nullptr if a Decoder with this ID does not exist
   */
  static DecoderPtr CreateFromID(const QString& id);

  /**
   * @brief AUDIO ONLY: Produces a complete PCM extraction of the audio stream
   *
   * Internally, our render engine only deals with PCM since it provides the least headaches and
   * modern computers have the processing power to do it.
   *
   * Resamples and converts the currently open audio to match the params. If the audio doesn't need
   * conforming (e.g. audio params already match or a conformed match already exists), this function
   * will return immediately. Otherwise it will block the calling thread until the conform is
   * complete. This function should therefore only be called from a background render thread.
   *
   * All audio decoders must override this. It's not pure since video decoders don't need to use
   * this, but default behavior will abort since it should never be called.
   */
  virtual bool ConformAudio(const QAtomicInt* cancelled, const AudioParams &params);

  /**
   * @brief AUDIO ONLY: Returns whether a transcode of this audio matching the specified params
   * already exists
   */
  bool HasConformedVersion(const AudioParams& params);

signals:
  /**
   * @brief While indexing, this signal will provide progress as a percentage (0-100 inclusive) if
   * available
   */
  void IndexProgress(double);

protected:
  void SignalProcessingProgress(const int64_t& ts);

  /**
   * @brief Returns the filename for the index
   *
   * Retrieves the absolute filename of the index file for this stream. Decoder must be open for
   * this to work correctly.
   */
  virtual QString GetIndexFilename() const = 0;

  /**
   * @brief Get the destination filename of an audio stream conformed to a set of parameters
   */
  QString GetConformedFilename(const AudioParams &params);

  bool open_;

  QMutex mutex_;

private:
  StreamPtr stream_;

};

OLIVE_NAMESPACE_EXIT

Q_DECLARE_METATYPE(OLIVE_NAMESPACE::Decoder::RetrieveState)

#endif // DECODER_H