Add Alpha fading mode to media player timeline

Fading color (to black) is not useful for media with transparency; there fading of alpha is necessary; the fading mode allows to select fade color or fade alpha. Also the source control window had to be adapted, with a checkerboard to show the alpha effect. The cropping of the image in control window was also fixed.
This commit is contained in:
Bruno Herbelin
2023-12-26 10:57:26 +01:00
parent b3245c967b
commit f610e8ba1e
6 changed files with 70 additions and 10 deletions

View File

@@ -72,6 +72,7 @@ MediaPlayer::MediaPlayer()
video_filter_available_ = true;
position_ = GST_CLOCK_TIME_NONE;
loop_ = LoopMode::LOOP_REWIND;
fading_mode_ = FadingMode::FADING_COLOR;
// default audio disabled
audio_enabled_ = false;

View File

@@ -206,8 +206,19 @@ public:
*/
Timeline *timeline();
void setTimeline(const Timeline &tl);
/**
* Get fading value at current time
* */
float currentTimelineFading();
/**
* Get fading mode
* */
typedef enum { FADING_COLOR = 0, FADING_ALPHA = 1 } FadingMode;
FadingMode timelineFadingMode() { return fading_mode_; }
/**
* Set fading mode
* */
void setTimelineFadingMode(FadingMode m) { fading_mode_ = m; }
/**
* Get framerate of the media
* */
@@ -314,6 +325,7 @@ private:
// general properties of media
MediaInfo media_;
Timeline timeline_;
FadingMode fading_mode_;
std::future<MediaInfo> discoverer_;
// GST & Play status

View File

@@ -197,7 +197,10 @@ void MediaSource::render()
// NB: this also applies the color correction shader
renderbuffer_->begin();
// apply fading
if (mediaplayer_->timelineFadingMode() != MediaPlayer::FADING_ALPHA)
texturesurface_->shader()->color = glm::vec4( glm::vec3(mediaplayer_->currentTimelineFading()), 1.f);
else
texturesurface_->shader()->color = glm::vec4( glm::vec3(1.f), mediaplayer_->currentTimelineFading());
texturesurface_->draw(glm::identity<glm::mat4>(), renderbuffer_->projection());
renderbuffer_->end();
ready_ = true;

View File

@@ -912,6 +912,9 @@ void SessionLoader::visit(MediaPlayer &n)
if (fadingselement) {
XMLElement* array = fadingselement->FirstChildElement("array");
XMLElementDecodeArray(array, tl.fadingArray(), MAX_TIMELINE_ARRAY * sizeof(float));
uint mode = 0;
fadingselement->QueryUnsignedAttribute("mode", &mode);
n.setTimelineFadingMode((MediaPlayer::FadingMode) mode);
}
n.setTimeline(tl);
}

View File

@@ -465,6 +465,7 @@ void SessionVisitor::visit(MediaPlayer &n)
fadingelement->InsertEndChild(array);
timelineelement->InsertEndChild(fadingelement);
newelement->InsertEndChild(timelineelement);
fadingelement->SetAttribute("mode", (uint) n.timelineFadingMode());
}
xmlCurrent_->InsertEndChild(newelement);

View File

@@ -32,6 +32,8 @@
#include "SystemToolkit.h"
#include "DialogToolkit.h"
#include "GstToolkit.h"
#include "Resource.h"
#include "PatternSource.h"
#include "Mixer.h"
#include "CloneSource.h"
@@ -43,6 +45,8 @@
#include "SourceControlWindow.h"
#define CHECKER_RESOLUTION 6000
class Stream *checker_background_ = new Stream;
void DrawSource(Source *s, ImVec2 framesize, ImVec2 top_image, bool withslider = false, bool withinspector = false);
ImRect DrawSourceWithSlider(Source *s, ImVec2 top, ImVec2 rendersize, bool with_inspector);
@@ -59,6 +63,14 @@ SourceControlWindow::SourceControlWindow() : WorkspaceWindow("SourceController")
info_.setExtendedStringMode();
captureFolderDialog = new DialogToolkit::OpenFolderDialog("Capture frame Location");
// initialize checkerboard background texture
checker_background_->open("videotestsrc pattern=checkers-8 ! "
"videobalance saturation=0 contrast=1",
CHECKER_RESOLUTION, CHECKER_RESOLUTION);
checker_background_->play(true);
while (checker_background_->texture() == Resource::getTextureBlack())
checker_background_->update();
}
@@ -401,6 +413,13 @@ void SourceControlWindow::Render()
Action::manager().store(oss.str());
}
bool _alpha_fading = mediaplayer_active_->timelineFadingMode()
== MediaPlayer::FADING_ALPHA;
if (ImGui::MenuItem(ICON_FA_FONT " Alpha fading", NULL, &_alpha_fading)) {
mediaplayer_active_->setTimelineFadingMode(
_alpha_fading ? MediaPlayer::FADING_ALPHA : MediaPlayer::FADING_COLOR);
}
if (ImGui::MenuItem(LABEL_EDIT_FADING))
mediaplayer_edit_fading_ = true;
@@ -1010,9 +1029,19 @@ void DrawSource(Source *s, ImVec2 framesize, ImVec2 top_image, bool withslider,
{
ImDrawList* draw_list = ImGui::GetWindowDrawList();
// pre-draw background with checkerboard pattern
ImGui::Image((void*)(uintptr_t) checker_background_->texture(), framesize,
ImVec2(0,0), ImVec2(framesize.x/CHECKER_RESOLUTION, framesize.y/CHECKER_RESOLUTION));
// get back to top image corner to draw
ImGui::SetCursorScreenPos(top_image);
// info on source
CloneSource *cloned = dynamic_cast<CloneSource *>(s);
// 100% opacity for the image (ensure true colors)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 1.f);
// draw pre and post-processed parts if necessary
if (s->imageProcessingEnabled() || s->textureTransformed() || cloned != nullptr) {
@@ -1027,8 +1056,14 @@ void DrawSource(Source *s, ImVec2 framesize, ImVec2 top_image, bool withslider,
//
// RIGHT of slider : post-processed image (after crop and color correction)
//
ImVec2 cropsize = framesize * ImVec2 ( s->frame()->projectionSize().x, s->frame()->projectionSize().y);
ImVec2 croptop = (framesize - cropsize) * 0.5f;
glm::vec4 _crop = s->frame()->projectionArea();
ImVec2 cropsize = ImVec2(0.5f * (_crop[1] - _crop[0]),
0.5f * (_crop[2] - _crop[3]));
ImVec2 croptop = ImVec2(0.5f * (1.f + _crop[0]),
0.5f * (1.f - _crop[2]) );
cropsize = framesize * cropsize;
croptop = framesize * croptop;
// no overlap of slider with cropped area
if (slider.x < croptop.x) {
// draw cropped area
@@ -1076,6 +1111,8 @@ void DrawSource(Source *s, ImVec2 framesize, ImVec2 top_image, bool withslider,
if ( withinspector && ImGui::IsItemHovered() )
DrawInspector(s->texture(), framesize, framesize, top_image);
}
ImGui::PopStyleVar();
}
ImRect DrawSourceWithSlider(Source *s, ImVec2 top, ImVec2 rendersize, bool with_inspector)
@@ -1105,11 +1142,14 @@ ImRect DrawSourceWithSlider(Source *s, ImVec2 top, ImVec2 rendersize, bool with_
const ImVec2 top_image = top + corner;
ImGui::SetCursorScreenPos(top_image);
// pre-draw background with checkerboard pattern
ImGui::Image((void*)(uintptr_t) checker_background_->texture(), framesize,
ImVec2(0,0), ImVec2(framesize.x/CHECKER_RESOLUTION, framesize.y/CHECKER_RESOLUTION));
// draw source
if (s->ready()) {
// 100% opacity for the image (ensure true colors)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 1.f);
ImGui::SetCursorScreenPos(top_image);
DrawSource(s, framesize, top_image, true, with_inspector);
ImGui::PopStyleVar();
}
return ImRect( top_image, top_image + framesize);
@@ -1643,14 +1683,14 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
bottom += ImVec2(scrollwindow.x + 2.f, 0.f);
draw_list->AddRectFilled(bottom, bottom + ImVec2(slider_zoom_width, timeline_height_ -1.f), ImGui::GetColorU32(ImGuiCol_FrameBg));
ImGui::SetCursorScreenPos(bottom + ImVec2(1.f, 0.f));
const char *tooltip[2] = {"Draw opacity tool", "Cut tool"};
const char *tooltip[2] = {"Fading draw tool", "Timeline cut tool"};
ImGuiToolkit::IconToggle(7,4,8,3, &Settings::application.widget.media_player_timeline_editmode, tooltip);
ImGui::SetCursorScreenPos(bottom + ImVec2(1.f, 0.5f * timeline_height_));
if (Settings::application.widget.media_player_timeline_editmode) {
// action cut
if (mediaplayer_active_->isPlaying()) {
ImGuiToolkit::Indication("Pause video to enable cut options", 9, 3);
ImGuiToolkit::Indication("Pause to enable cut at cursor", 9, 3);
}
else if (ImGuiToolkit::IconButton(9, 3, "Cut at cursor")) {
ImGui::OpenPopup("timeline_cut_context_menu");
@@ -1676,7 +1716,7 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
// action smooth
ImGui::PushButtonRepeat(true);
if (ImGuiToolkit::IconButton(13, 12, "Smooth")){
if (ImGuiToolkit::IconButton(13, 12, "Smooth fading curve")){
mediaplayer_active_->timeline()->smoothFading( 5 );
++_actionsmooth;
}