405 lines
14 KiB
C
405 lines
14 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 RENDERFUNCTIONS_H
|
|
#define RENDERFUNCTIONS_H
|
|
|
|
#include <QOpenGLContext>
|
|
#include <QVector>
|
|
#include <QOpenGLShaderProgram>
|
|
|
|
#include "timeline/sequence.h"
|
|
#include "effects/effect.h"
|
|
#include "panels/viewer.h"
|
|
|
|
/**
|
|
* @brief The ComposeSequenceParams struct
|
|
*
|
|
* Struct sent to the compose_sequence() function.
|
|
*/
|
|
struct ComposeSequenceParams {
|
|
|
|
/**
|
|
* @brief Reference to the Viewer class that's calling compose_sequence()
|
|
*
|
|
* Primarily used for calling Viewer::play_wake() when appropriate.
|
|
*/
|
|
Viewer* viewer;
|
|
|
|
/**
|
|
* @brief The OpenGL context to use while rendering.
|
|
*
|
|
* For video rendering, this must be a valid OpenGL context. For audio, this variable is never accessed.
|
|
*
|
|
* \see ComposeSequenceParams::video
|
|
*/
|
|
QOpenGLContext* ctx;
|
|
|
|
/**
|
|
* @brief The sequence to compose
|
|
*
|
|
* In addition to clips, sequences also contain the playhead position so compose_sequence() knows which frame
|
|
* to render.
|
|
*/
|
|
Sequence* seq;
|
|
|
|
/**
|
|
* @brief Array to store the nested sequence hierarchy
|
|
*
|
|
* Should be left empty. This array gets passed around compose_sequence() as it calls itself recursively to
|
|
* handle nested sequences.
|
|
*/
|
|
QVector<Clip*> nests;
|
|
|
|
/**
|
|
* @brief Set compose mode to video or audio
|
|
*
|
|
* **TRUE** if this function should render video, **FALSE** if this function should render audio.
|
|
*/
|
|
bool video;
|
|
|
|
/**
|
|
* @brief Set to the Effect whose gizmos were chosen to be drawn on screen
|
|
*
|
|
* The currently active Effect that compose_sequence() will update the gizmos of.
|
|
*/
|
|
Effect* gizmos;
|
|
|
|
/**
|
|
* @brief A variable that compose_sequence() will set to **TRUE** if any of the clips couldn't be shown.
|
|
*
|
|
* A footage item or shader may not be ready at the time this frame is drawn. If compose_sequence() couldn't draw
|
|
* any of the clips in the scene, this variable is set to **TRUE** indicating that the image rendered is a
|
|
* "best effort", but not the actual image.
|
|
*
|
|
* This variable should be checked after compose_sequence() and a repaint should be triggered if it's **TRUE**.
|
|
*
|
|
* \note This variable is probably bad design and is a relic of an earlier rendering backend. There may be a better
|
|
* way to communicate this information.
|
|
*
|
|
* Additionally, since
|
|
* compose_sequence() for video will now always run in a separate thread anyway, there's no real issue with
|
|
* stalling it to wait for footage to complete opening or whatever may be lagging behind. A possible side effect
|
|
* of this though is that the preview may become less responsive if it's stuck trying to render one frame. With
|
|
* the current system, the preview may show incomplete frames occasionally but at least it will show something.
|
|
* This may be preferable. See ComposeSequenceParams::single_threaded for a similar function that could be
|
|
* removed.
|
|
*/
|
|
bool texture_failed;
|
|
|
|
/**
|
|
* @brief Run all cachers in the same thread that compose_sequence() is in
|
|
*
|
|
* Standard behavior is that all clips cache frames in their own thread and signals are sent between
|
|
* compose_sequence() and the clip's cacher thread regarding which frames to display and cache without stalling
|
|
* the compose_sequence() thread. Setting this to **TRUE** will run all cachers in the same thread creating a
|
|
* technically more "perfect" connection between them that will also stall the compose_sequence() thread. Used
|
|
* when rendering as timing isn't as important as creating output frames as quickly as possible.
|
|
*
|
|
* \note Exporting should probably be rewritten without this. While running all the cachers in one thread makes
|
|
* it easier to synchronize everything, export performance could probably benefit from keeping them in separate
|
|
* threads and syncing up with them. See ComposeSequenceParams::texture_failed for a similar function that could
|
|
* be removed.
|
|
*/
|
|
bool wait_for_mutexes;
|
|
|
|
/**
|
|
* @brief Set the current playback speed (adjusted with Shuttle Left/Right)
|
|
*
|
|
* Only used for audio rendering to determine how many samples to skip in order to play audio at the correct speed.
|
|
*
|
|
* \see ComposeSequenceParams::video
|
|
*/
|
|
int playback_speed;
|
|
|
|
/**
|
|
* @brief Blending mode shader
|
|
*
|
|
* Used only for video rendering. Never accessed with audio rendering.
|
|
*
|
|
* A program containing the current active
|
|
* blending mode shader that can be bound during rendering. Must be compiled and linked beforehand. See
|
|
* RenderThread::blend_mode_program for how this is properly set up.
|
|
*
|
|
* \see ComposeSequenceParams::video
|
|
*/
|
|
QOpenGLShaderProgram* blend_mode_program;
|
|
|
|
/**
|
|
* @brief Premultiply alpha shader
|
|
*
|
|
* Used only for video rendering. Never accessed with audio rendering.
|
|
*
|
|
* compose_sequence()'s internal composition
|
|
* expects premultipled alpha, but it will pre-emptively multiply any footage that is not set as already
|
|
* premultiplied (see Footage::alpha_is_premultiplied) using this shader. Must be compiled and linked beforehand.
|
|
* See RenderThread::premultiply_program for how this is properly set up.
|
|
*/
|
|
QOpenGLShaderProgram* premultiply_program;
|
|
|
|
/**
|
|
* @brief The OpenGL framebuffer object that the final texture to be shown is rendered to.
|
|
*
|
|
* Used only for video rendering. Never accessed with audio rendering.
|
|
*
|
|
* When compose_sequence() is rendering the final image, this framebuffer will be bound.
|
|
*/
|
|
GLuint main_buffer;
|
|
|
|
/**
|
|
* @brief The attachment to the framebuffer in main_buffer
|
|
*
|
|
* Used only for video rendering. Never accessed with audio rendering.
|
|
*
|
|
* The OpenGL texture attached to the framebuffer referenced by main_buffer.
|
|
*/
|
|
GLuint main_attachment;
|
|
|
|
/**
|
|
* @brief Backend OpenGL framebuffer 1 used for further processing before rendering to main_buffer
|
|
*
|
|
* In some situations, compose_sequence() will do some processing through shaders that requires "ping-ponging"
|
|
* between framebuffers. backend_buffer1 and backend_buffer2 are used for this purpose.
|
|
*/
|
|
GLuint backend_buffer1;
|
|
|
|
/**
|
|
* @brief Backend OpenGL framebuffer 1's texture attachment
|
|
*
|
|
* The texture that ComposeSequenceParams::backend_buffer1 renders to. Bound and drawn to
|
|
* ComposeSequenceParams::backend_buffer2 to "ping-pong" between them and various shaders.
|
|
*/
|
|
GLuint backend_attachment1;
|
|
|
|
/**
|
|
* @brief Backend OpenGL framebuffer 2 used for further processing before rendering to main_buffer
|
|
*
|
|
* In some situations, compose_sequence() will do some processing through shaders that requires "ping-ponging"
|
|
* between framebuffers. backend_buffer1 and backend_buffer2 are used for this purpose.
|
|
*/
|
|
GLuint backend_buffer2;
|
|
|
|
/**
|
|
* @brief Backend OpenGL framebuffer 2's texture attachment
|
|
*
|
|
* The texture that ComposeSequenceParams::backend_buffer2 renders to. Bound and drawn to
|
|
* ComposeSequenceParams::backend_buffer1 to "ping-pong" between them and various shaders.
|
|
*/
|
|
GLuint backend_attachment2;
|
|
|
|
/**
|
|
* @brief OpenGL shader containing OpenColorIO shader information
|
|
*/
|
|
QOpenGLShaderProgram* ocio_shader;
|
|
|
|
/**
|
|
* @brief OpenGL texture containing LUT obtained form OpenColorIO
|
|
*/
|
|
GLuint ocio_lut_texture;
|
|
};
|
|
|
|
/**
|
|
* @brief Compose a frame of a given sequence
|
|
*
|
|
* For any given Sequence, this function will render the current frame indicated by Sequence::playhead. Will
|
|
* automatically open and close clips (memory allocation and file handles) as necessary, communicate with the
|
|
* Clip::cacher objects to retrieve upcoming frames and store them in memory, run Effect processing functions, and
|
|
* finally composite all the currently active clips together into a final texture.
|
|
*
|
|
* Will sometimes render a frame incomplete or inaccurately, e.g. if a video file hadn't finished opening by the time
|
|
* of the render or a clip's cacher didn't have the requested frame available at the time of the render. If so,
|
|
* the `texture_failed` variable of `params` will be set to **TRUE**. Check this after calling compose_sequence() and
|
|
* if it is **TRUE**, compose_sequence() should be called again later to attempt another render (unless the Sequence
|
|
* is being played, in which case just play the next frame rather than redrawing an old frame).
|
|
*
|
|
* @param params
|
|
*
|
|
* A struct of parameters to use while rendering.
|
|
*
|
|
* @return A reference to the OpenGL texture resulting from the render. Will usually be equal to
|
|
* ComposeSequenceParams::main_attachment unless it's rendering a nested sequence, in which case it'll be a reference
|
|
* to one of the textures referenced by Clip::fbo. Can be used directly to draw the rendered frame.
|
|
*/
|
|
GLuint compose_sequence(ComposeSequenceParams ¶ms);
|
|
|
|
/**
|
|
* @brief Convenience wrapper function for compose_sequence() to render audio
|
|
*
|
|
* Much of the functionality provided (and parameters required) by compose_sequence() is only useful/necessary for
|
|
* video rendering. For audio rendering, this function is easier to handle and will correctly set up
|
|
* compose_sequence() to render audio without the cumbersome effort of setting up a ComposeSequenceParams object.
|
|
*
|
|
* @param viewer
|
|
*
|
|
* The Viewer object calling this function
|
|
*
|
|
* @param seq
|
|
*
|
|
* The Sequence whose audio to render.
|
|
*
|
|
* @param playback_speed
|
|
*
|
|
* The current playback speed (controlled by Shuttle Left/Right)
|
|
*
|
|
* @param
|
|
*
|
|
* Whether to wait for media to open or simply fail if the media is not yet open. This should usually be **FALSE**.
|
|
*/
|
|
void compose_audio(Viewer* viewer, Sequence *seq, int playback_speed, bool wait_for_mutexes);
|
|
|
|
/**
|
|
* @brief Rescale a frame number between two frame rates
|
|
*
|
|
* Converts a frame number from one frame rate to its equivalent in another frame rate
|
|
*
|
|
* @param framenumber
|
|
*
|
|
* The frame number to convert
|
|
*
|
|
* @param source_frame_rate
|
|
*
|
|
* Frame rate that the frame number is currently in
|
|
*
|
|
* @param target_frame_rate
|
|
*
|
|
* Frame rate to convert to
|
|
*
|
|
* @return
|
|
*
|
|
* Rescaled frame number
|
|
*/
|
|
long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate);
|
|
|
|
/**
|
|
* @brief Get timecode
|
|
*
|
|
* Get the current clip/media time from the Timeline playhead in seconds. For instance if the playhead was at the start
|
|
* of a clip (whose in point wasn't trimmed), this would be 0.0 as it's the start of the clip/media;
|
|
*
|
|
* @param c
|
|
*
|
|
* Clip to get the timecode of
|
|
*
|
|
* @param playhead
|
|
*
|
|
* Sequence playhead to convert to a clip/media timecode
|
|
*
|
|
* @return
|
|
*
|
|
* Timecode in seconds
|
|
*/
|
|
double get_timecode(Clip *c, long playhead);
|
|
|
|
/**
|
|
* @brief Convert playhead frame number to a clip frame number
|
|
*
|
|
* Converts a Timeline playhead to a the current clip's frame. Equivalent to
|
|
* `PLAYHEAD - CLIP_TIMELINE_IN + CLIP_MEDIA_IN`. All keyframes are in clip frames.
|
|
*
|
|
* @param c
|
|
*
|
|
* The clip to get the current frame number of
|
|
*
|
|
* @param playhead
|
|
*
|
|
* The current Timeline frame number
|
|
*
|
|
* @return
|
|
*
|
|
* The curren frame number of the clip at `playhead`
|
|
*/
|
|
long playhead_to_clip_frame(Clip* c, long playhead);
|
|
|
|
/**
|
|
* @brief Converts the playhead to clip seconds
|
|
*
|
|
* Get the current timecode at the playhead in terms of clip seconds.
|
|
*
|
|
* FIXME: Possible duplicate of get_timecode()? Will need to research this more.
|
|
*
|
|
* @param c
|
|
*
|
|
* Clip to return clip seconds of.
|
|
*
|
|
* @param playhead
|
|
*
|
|
* Current Timeline playhead to convert to clip seconds
|
|
*
|
|
* @return
|
|
*
|
|
* Clip time in seconds
|
|
*/
|
|
double playhead_to_clip_seconds(Clip *c, long playhead);
|
|
|
|
/**
|
|
* @brief Convert seconds to FFmpeg timestamp
|
|
*
|
|
* Used for interaction with FFmpeg, converts seconds in a floating-point value to a timestamp in AVStream->time_base
|
|
* units.
|
|
*
|
|
* @param c
|
|
*
|
|
* Clip to get timestamp of
|
|
*
|
|
* @param seconds
|
|
*
|
|
* Clip time in seconds
|
|
*
|
|
* @return
|
|
*
|
|
* An FFmpeg-compatible timestamp in AVStream->time_base units.
|
|
*/
|
|
int64_t seconds_to_timestamp(Clip* c, double seconds);
|
|
|
|
/**
|
|
* @brief Convert Timeline playhead to FFmpeg timestamp
|
|
*
|
|
* Used for interaction with FFmpeg, converts the Timeline playhead to a timestamp in AVStream->time_base
|
|
* units.
|
|
*
|
|
* @param c
|
|
*
|
|
* Clip to get timestamp of
|
|
*
|
|
* @param playhead
|
|
*
|
|
* Timeline playhead to convert to a timestamp
|
|
*
|
|
* @return
|
|
*
|
|
* An FFmpeg-compatible timestamp in AVStream->time_base units.
|
|
*/
|
|
int64_t playhead_to_timestamp(Clip *c, long playhead);
|
|
|
|
/**
|
|
* @brief Close all open clips in a Sequence
|
|
*
|
|
* Closes any currently open clips on a Sequence and waits for them to close before returning. This may be slow as a
|
|
* result on large Sequence objects. If a Clip is a nested Sequence, this function calls itself recursively on that
|
|
* Sequence too.
|
|
*
|
|
* @param s
|
|
*
|
|
* The Sequence to close all clips on.
|
|
*/
|
|
void close_active_clips(Sequence* s);
|
|
|
|
#endif // RENDERFUNCTIONS_H
|