auto-generate blending shader

This commit is contained in:
itsmattkc
2019-03-10 09:48:34 +11:00
parent 53f3f03e1d
commit c056c9d803
9 changed files with 429 additions and 375 deletions
-40
View File
@@ -1,40 +0,0 @@
#version 110
/*
This main stump is combined with another shader loaded externally to produce a blending mode.
For a custom blend mode, the function blend() MUST be available, and use the following syntax:
blend(vec3 base_color, vec3 blend_color, float opacity)
*/
void main(void) {
vec4 bg_color = texture2D(background, vTexCoord);
vec4 fg_color = texture2D(foreground, vTexCoord);
// blend textures together
vec3 composite = blend(bg_color.rgb, fg_color.rgb);
if (blendmode == BLEND_MODE_OVERLAY
|| blendmode == BLEND_MODE_LIGHTEN
|| blendmode == BLEND_MODE_SCREEN
|| blendmode == BLEND_MODE_COLORDODGE
|| blendmode == BLEND_MODE_LINEARDODGE
|| blendmode == BLEND_MODE_ADD
|| blendmode == BLEND_MODE_SOFTLIGHT
|| blendmode == BLEND_MODE_NEGATION
|| blendmode == BLEND_MODE_AVERAGE
|| blendmode == BLEND_MODE_REFLECT
|| blendmode == BLEND_MODE_EXCLUSION
|| blendmode == BLEND_MODE_DIFFERENCE) {
composite *= fg_color.a;
}
vec4 full_composite = vec4(composite + bg_color.rgb*(1.0-fg_color.a), bg_color.a + fg_color.a);
full_composite = mix(bg_color, full_composite, opacity);
// output to color
gl_FragColor = full_composite;
}
-1
View File
@@ -1,6 +1,5 @@
<RCC>
<qresource prefix="/internalshaders">
<file>blending.frag</file>
<file>common.vert</file>
<file>cornerpin.frag</file>
<file>cornerpin.vert</file>
+2 -1
View File
@@ -6,4 +6,5 @@ vec3 blendMultiply(vec3 base, vec3 blend, float opacity) {
return (blendMultiply(base, blend) * opacity + base * (1.0 - opacity));
}
#pragma glslify: export(blendMultiply)
#pragma glslify: export(blendMultiply)
#olive name Multiply
+1
View File
@@ -69,6 +69,7 @@
QVector<EffectMeta> olive::effects;
QVector<BlendMode> olive::blend_modes;
QString olive::generated_blending_shader;
EffectPtr Effect::Create(Clip* c, const EffectMeta* em) {
if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) {
+3 -7
View File
@@ -62,11 +62,14 @@ struct EffectMeta {
struct BlendMode {
QString name;
QString url;
QString function_name;
};
namespace olive {
extern QVector<EffectMeta> effects;
extern QVector<BlendMode> blend_modes;
extern QString generated_blending_shader;
}
double log_volume(double linear);
@@ -260,11 +263,4 @@ private:
void validate_meta_path();
};
class EffectInit : public QThread {
public:
EffectInit();
protected:
void run();
};
#endif // EFFECT_H
+89
View File
@@ -137,6 +137,7 @@ void load_shader_effects() {
const QString& effects_path = effects_paths.at(h);
QDir effects_dir(effects_path);
if (effects_dir.exists()) {
// Load XML metadata for GLSL shader effects
QList<QString> entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files);
for (int i=0;i<entries.size();i++) {
QFile file(effects_path + "/" + entries.at(i));
@@ -178,6 +179,15 @@ void load_shader_effects() {
file.close();
}
// Load blending mode shaders from file
QList<QString> blend_mode_entries = effects_dir.entryList(QStringList("*.blend"), QDir::Files);
for (int i=0;i<blend_mode_entries.size();i++) {
BlendMode b;
b.url = effects_dir.filePath(blend_mode_entries.at(i));
b.name = QFileInfo(b.url).baseName();
olive::blend_modes.append(b);
}
}
}
}
@@ -255,6 +265,84 @@ void load_frei0r_effects() {
}
#endif
void GenerateBlendingShader()
{
olive::generated_blending_shader = "#version 110\n" // Start with GLSL version identifier
"\n"
"uniform sampler2D background;\n" // background (base) texture color
"uniform sampler2D foreground;\n" // foreground (blend) texture color
"varying vec2 vTexCoord;\n" // texture coordinate
"uniform float opacity;\n" // foreground opacity setting
"uniform int blendmode;\n" // blending mode switcher
"\n"
"\n";
// Import code from each blend mode file
for (int i=0;i<olive::blend_modes.size();i++) {
QFile blending_file(olive::blend_modes.at(i).url);
if (blending_file.open(QFile::ReadOnly)) {
QTextStream stream(&blending_file);
while (!stream.atEnd()) {
QString line = stream.readLine();
if (line.startsWith("#olive name ")) {
// The blending mode can specify its own name
olive::blend_modes[i].name = line.mid(12);
} else if (line.startsWith("#pragma glslify: export(")) {
// Get function name
olive::blend_modes[i].function_name = line.mid(24, line.length()-25);
} else {
// Assume this line is code and add it to the shader
olive::generated_blending_shader.append(line);
olive::generated_blending_shader.append("\n");
}
}
blending_file.close();
} else {
qWarning() << "Failed to open blending shader" << olive::blend_modes.at(i).url;
}
}
// Create monolithic switcher function
olive::generated_blending_shader.append("vec3 blend(vec3 base, vec3 blend) {\n");
for (int i=0;i<olive::blend_modes.size();i++) {
if (i == 0) {
olive::generated_blending_shader.append(" if (blendmode == 0) {\n");
} else {
olive::generated_blending_shader.append(QString(" else if (blendmode == %1) {\n").arg(i));
}
olive::generated_blending_shader.append(QString(" return %1(base, blend)\n").arg(olive::blend_modes.at(i).function_name));
olive::generated_blending_shader.append(" }");
}
olive::generated_blending_shader.append("\n return blend;\n" // default return value
"}\n"
"\n"
"void main() {\n"
" vec4 bg_color = texture2D(background, vTexCoord);\n" // Get background texture color
" vec4 fg_color = texture2D(foreground, vTexCoord);\n" // Get foreground texture color
" vec3 composite = blend(bg_color.rgb, fg_color.rgb);\n" // Use switcher function above to blend RGBs
" vec4 full_composite = vec4(composite + bg_color.rgb*(1.0-fg_color.a), bg_color.a + fg_color.a);\n"
" full_composite = mix(bg_color, full_composite, opacity);\n"
" gl_FragColor = full_composite;\n"
"}\n");
qDebug() << olive::generated_blending_shader;
}
EffectInit::EffectInit() {
panel_effect_controls->effects_loaded.lock();
}
@@ -266,6 +354,7 @@ void EffectInit::run() {
#ifndef NOFREI0R
load_frei0r_effects();
#endif
GenerateBlendingShader();
panel_effect_controls->effects_loaded.unlock();
qInfo() << "Finished initializing effects";
}
+8
View File
@@ -22,7 +22,15 @@
#define EFFECTLOADERS_H
#include <QList>
#include <QThread>
void init_effects();
class EffectInit : public QThread {
public:
EffectInit();
protected:
void run();
};
#endif // EFFECTLOADERS_H
+325 -325
View File
@@ -31,375 +31,375 @@
#include "panels/viewer.h"
/**
* @brief The ComposeSequenceParams struct
*
* Struct sent to the compose_sequence() function.
*/
* @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 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 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.
*/
SequencePtr seq;
/**
* @brief The sequence to compose
*
* In addition to clips, sequences also contain the playhead position so compose_sequence() knows which frame
* to render.
*/
SequencePtr 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 shader containing OpenColorIO shader information
*/
QOpenGLShaderProgram* ocio_shader;
/**
* @brief OpenGL texture containing LUT obtained form OpenColorIO
*/
GLuint ocio_lut_texture;
/**
* @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.
*/
* @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 &params);
/**
* @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**.
*/
* @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, SequencePtr 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
*/
* @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 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`
*/
* @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 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.
*/
* @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 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.
*/
* @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(SequencePtr s);
#endif // RENDERFUNCTIONS_H
+1 -1
View File
@@ -99,7 +99,7 @@ void RenderThread::run() {
blend_mode_program = new QOpenGLShaderProgram();
blend_mode_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/internalshaders/common.vert");
blend_mode_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/internalshaders/blending.frag");
blend_mode_program->addShaderFromSourceCode(QOpenGLShader::Fragment, olive::generated_blending_shader);
blend_mode_program->link();
premultiply_program = new QOpenGLShaderProgram();