diff --git a/effects/internal/blending.frag b/effects/internal/blending.frag deleted file mode 100644 index 8f4dd3201..000000000 --- a/effects/internal/blending.frag +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/effects/internal/internalshaders.qrc b/effects/internal/internalshaders.qrc index 39b1a3aee..ae51e0b27 100644 --- a/effects/internal/internalshaders.qrc +++ b/effects/internal/internalshaders.qrc @@ -1,6 +1,5 @@ - blending.frag common.vert cornerpin.frag cornerpin.vert diff --git a/effects/multiply.blend b/effects/multiply.blend index 0da71e49d..55ed2d341 100644 --- a/effects/multiply.blend +++ b/effects/multiply.blend @@ -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) \ No newline at end of file +#pragma glslify: export(blendMultiply) +#olive name Multiply \ No newline at end of file diff --git a/project/effect.cpp b/project/effect.cpp index 4cf2bdc22..fab503d07 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -69,6 +69,7 @@ QVector olive::effects; QVector 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) { diff --git a/project/effect.h b/project/effect.h index 91600f1d3..9d699d8dd 100644 --- a/project/effect.h +++ b/project/effect.h @@ -62,11 +62,14 @@ struct EffectMeta { struct BlendMode { QString name; QString url; + QString function_name; }; namespace olive { extern QVector effects; extern QVector 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 diff --git a/project/effectloaders.cpp b/project/effectloaders.cpp index 4162a2a6b..0dd3863d1 100644 --- a/project/effectloaders.cpp +++ b/project/effectloaders.cpp @@ -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 entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files); for (int i=0;i blend_mode_entries = effects_dir.entryList(QStringList("*.blend"), QDir::Files); + for (int i=0;ieffects_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"; } diff --git a/project/effectloaders.h b/project/effectloaders.h index 9a4c2a86e..a5370df41 100644 --- a/project/effectloaders.h +++ b/project/effectloaders.h @@ -22,7 +22,15 @@ #define EFFECTLOADERS_H #include +#include void init_effects(); +class EffectInit : public QThread { +public: + EffectInit(); +protected: + void run(); +}; + #endif // EFFECTLOADERS_H diff --git a/rendering/renderfunctions.h b/rendering/renderfunctions.h index 3c1f49734..cde662c6d 100644 --- a/rendering/renderfunctions.h +++ b/rendering/renderfunctions.h @@ -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 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 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 ¶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**. - */ + * @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 diff --git a/rendering/renderthread.cpp b/rendering/renderthread.cpp index 0c3ff96f3..2bfc54006 100644 --- a/rendering/renderthread.cpp +++ b/rendering/renderthread.cpp @@ -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();