Files
oak-editor/app/decoder/decoder.h
T
itsmattkc 1a9ae53181 separated decoder retrieve functions for video and audio
It became increasingly clear that video and audio retrieval require different
parameters so it started to make sense to separate these functions out.
2019-11-30 02:46:49 +11:00

230 lines
9.0 KiB
C++

/***
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
#include <QObject>
#include <stdint.h>
#include "common/constructors.h"
#include "common/rational.h"
#include "project/item/footage/footage.h"
#include "decoder/frame.h"
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 PixelFormatConverter
* (olive::pix_fmt_conv) to be utilized in the rest of the rendering pipeline.
*/
class Decoder : public QObject
{
Q_OBJECT
public:
Decoder();
Decoder(Stream* fs);
// Necessary for subclassing, it's empty
virtual ~Decoder();
DISABLE_COPY_MOVE(Decoder)
virtual QString id() = 0;
StreamPtr stream();
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) = 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);
/**
* @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 FramePtr RetrieveAudio(const rational& timecode, const rational& length, const AudioRenderingParams& 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 Get a media file's internal timestamp
*
* Used to determine which frame will be served at a given time, useful for caching.
*/
virtual int64_t GetTimestampFromTime(const rational& time) = 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);
/**
* @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 Conform an audio stream to match certain parameters (audio only)
*
* 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 void Conform(const AudioRenderingParams& params);
protected:
bool open_;
private:
StreamPtr stream_;
};
#endif // DECODER_H