mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-16 12:49:59 +01:00
New support for gstreamer video effects in MediaPlayer
Implementation of the GUI allowing to set the pipeline element description
This commit is contained in:
@@ -1949,6 +1949,12 @@ bool ImGuiToolkit::InputCodeMultiline(const char* label, std::string *str, const
|
|||||||
char hiddenlabel[256];
|
char hiddenlabel[256];
|
||||||
sprintf(hiddenlabel, "##%s", label);
|
sprintf(hiddenlabel, "##%s", label);
|
||||||
|
|
||||||
|
// Draw the label with default font
|
||||||
|
ImVec2 pos_top = ImGui::GetCursorPos();
|
||||||
|
ImGui::SetCursorPosX(pos_top.x + size.x + 8);
|
||||||
|
ImGui::Text("%s", label);
|
||||||
|
|
||||||
|
// Draw code with mono font
|
||||||
ImGuiToolkit::PushFont(FONT_MONO);
|
ImGuiToolkit::PushFont(FONT_MONO);
|
||||||
static ImVec2 onechar = ImGui::CalcTextSize("C");
|
static ImVec2 onechar = ImGui::CalcTextSize("C");
|
||||||
|
|
||||||
@@ -1958,9 +1964,11 @@ bool ImGuiToolkit::InputCodeMultiline(const char* label, std::string *str, const
|
|||||||
// work on a string wrapped to the number of chars in a line
|
// work on a string wrapped to the number of chars in a line
|
||||||
std::string edited = wrapp( *str, (size_t) floor(size.x / onechar.x) - 1);
|
std::string edited = wrapp( *str, (size_t) floor(size.x / onechar.x) - 1);
|
||||||
|
|
||||||
|
ImGui::SetCursorPos(pos_top);
|
||||||
|
|
||||||
// Input text into std::string with callback
|
// Input text into std::string with callback
|
||||||
ImGui::InputTextMultiline(hiddenlabel, (char*)edited.c_str(), edited.capacity() + 1, size, flags, InputTextCallback, &edited);
|
ImGui::InputTextMultiline(hiddenlabel, (char*)edited.c_str(), edited.capacity() + 1, size, flags, InputTextCallback, &edited);
|
||||||
if (ImGui::IsItemDeactivatedAfterEdit() ){
|
if (ImGui::IsItemDeactivated() ){
|
||||||
// unwrap after edit
|
// unwrap after edit
|
||||||
*str = unwrapp(edited);
|
*str = unwrapp(edited);
|
||||||
// return number of lines
|
// return number of lines
|
||||||
@@ -1973,10 +1981,6 @@ bool ImGuiToolkit::InputCodeMultiline(const char* label, std::string *str, const
|
|||||||
|
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
|
|
||||||
// show label
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text("%s", label);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
// ImGui
|
// ImGui
|
||||||
#include "ImGuiToolkit.h"
|
#include "ImGuiToolkit.h"
|
||||||
#include "imgui_internal.h"
|
#include "imgui_internal.h"
|
||||||
@@ -423,8 +425,8 @@ void SourceControlWindow::Render()
|
|||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
// TODO finalize pipeline editor
|
// TODO finalize pipeline editor
|
||||||
// if (ImGui::MenuItem(ICON_FA_HAT_WIZARD " gst pipeline"))
|
if (ImGui::MenuItem(ICON_FA_MAGIC " Video effect"))
|
||||||
// mediaplayer_edit_pipeline_ = true;
|
mediaplayer_edit_pipeline_ = true;
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
@@ -1792,73 +1794,147 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
|||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string _effect_description = "";
|
||||||
|
static bool _effect_description_changed = false;
|
||||||
if (mediaplayer_edit_pipeline_) {
|
if (mediaplayer_edit_pipeline_) {
|
||||||
ImGui::OpenPopup("Edit gstreamer pipeline");
|
// open dialog
|
||||||
|
ImGui::OpenPopup(ICON_FA_MAGIC " Video effect");
|
||||||
mediaplayer_edit_pipeline_ = false;
|
mediaplayer_edit_pipeline_ = false;
|
||||||
|
// initialize dialog
|
||||||
|
_effect_description = mediaplayer_active_->videoEffect();
|
||||||
|
_effect_description_changed = true;
|
||||||
}
|
}
|
||||||
const ImVec2 mpp_dialog_size(buttons_width_ * 3.f, buttons_height_ * 6);
|
const ImVec2 mpp_dialog_size(buttons_width_ * 3.f, buttons_height_ * 6);
|
||||||
ImGui::SetNextWindowSize(mpp_dialog_size, ImGuiCond_Always);
|
ImGui::SetNextWindowSize(mpp_dialog_size, ImGuiCond_Always);
|
||||||
const ImVec2 mpp_dialog_pos = top + rendersize * 0.5f - mpp_dialog_size * 0.5f;
|
const ImVec2 mpp_dialog_pos = top + rendersize * 0.5f - mpp_dialog_size * 0.5f;
|
||||||
ImGui::SetNextWindowPos(mpp_dialog_pos, ImGuiCond_Always);
|
ImGui::SetNextWindowPos(mpp_dialog_pos, ImGuiCond_Always);
|
||||||
if (ImGui::BeginPopupModal("Edit gstreamer pipeline", NULL, ImGuiWindowFlags_NoResize))
|
if (ImGui::BeginPopupModal(ICON_FA_MAGIC " Video effect", NULL, ImGuiWindowFlags_NoResize))
|
||||||
{
|
{
|
||||||
bool update_new_source = false;
|
|
||||||
const ImVec2 pos = ImGui::GetCursorPos();
|
const ImVec2 pos = ImGui::GetCursorPos();
|
||||||
const ImVec2 area = ImGui::GetContentRegionAvail();
|
const ImVec2 area = ImGui::GetContentRegionAvail();
|
||||||
|
static uint _status = 0; // 0:unknown, 1:ok, 2:error
|
||||||
|
static std::string _status_message = "";
|
||||||
static std::vector< std::pair< std::string, std::string> > _examples = { {"Primary color", "frei0r-filter-primaries" },
|
static std::vector< std::pair< std::string, std::string> > _examples = { {"Primary color", "frei0r-filter-primaries" },
|
||||||
{"Histogram", "frei0r-filter-rgb-parade"},
|
{"Histogram", "frei0r-filter-rgb-parade mix=0.5"},
|
||||||
{"Emboss", "frei0r-filter-emboss"},
|
{"Emboss", "frei0r-filter-emboss"},
|
||||||
{"B&W", "frei0r-filter-bw0r"},
|
{"Denoise", "frei0r-filter-hqdn3d spatial=0.05 temporal=0.1"},
|
||||||
{"Gamma", "frei0r-filter-gamma gamma=0.5"},
|
{"Thermal", "coloreffects preset=heat"},
|
||||||
{"Broken tv", "frei0r-filter-nosync0r "}
|
{"Afterimage", "streaktv"}
|
||||||
};
|
};
|
||||||
static std::string _description = _examples[0].second;
|
static ImVec2 fieldsize(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 70);
|
||||||
static ImVec2 fieldsize(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 100);
|
|
||||||
static int numlines = 0;
|
static int numlines = 0;
|
||||||
const ImGuiContext& g = *GImGui;
|
const ImGuiContext& g = *GImGui;
|
||||||
fieldsize.y = MAX(3, numlines) * g.FontSize + g.Style.ItemSpacing.y + g.Style.FramePadding.y;
|
fieldsize.y = MAX(2.5, numlines) * g.FontSize + g.Style.ItemSpacing.y + g.Style.FramePadding.y;
|
||||||
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Text("Enter pipeline element and apply:");
|
ImGui::Text("Enter a gstreamer video effect description and apply.\nLeave empty for no effect.");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGuiToolkit::HelpToolTip("Video effects are directly integrated in the gstreamer pipeline "
|
||||||
|
"and performed on CPU (might be slow). Vimix recommends using "
|
||||||
|
"GPU accelerated filters by cloning the source.");
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
|
|
||||||
// Editor
|
// Editor
|
||||||
if ( ImGuiToolkit::InputCodeMultiline("Filter", &_description, fieldsize, &numlines) )
|
if ( ImGuiToolkit::InputCodeMultiline("Effect", &_effect_description, fieldsize, &numlines) )
|
||||||
update_new_source = true;
|
_effect_description_changed = true;
|
||||||
|
if ( ImGui::IsItemActive() )
|
||||||
|
_status = 0;
|
||||||
|
|
||||||
// Local menu for list of examples
|
// Local menu for list of examples
|
||||||
ImVec2 pos_bot = ImGui::GetCursorPos();
|
ImVec2 pos_bot = ImGui::GetCursorPos();
|
||||||
ImGui::SetCursorPos( pos_bot + ImVec2(fieldsize.x + IMGUI_SAME_LINE, -ImGui::GetFrameHeightWithSpacing()));
|
ImGui::SetCursorPos( pos_bot + ImVec2(fieldsize.x + IMGUI_SAME_LINE, -ImGui::GetFrameHeightWithSpacing()));
|
||||||
if (ImGui::BeginCombo("##Examples", "Examples", ImGuiComboFlags_NoPreview)) {
|
if (ImGui::BeginCombo("##ExamplesVideoEffect", "ExamplesVideoEffect", ImGuiComboFlags_NoPreview | ImGuiComboFlags_HeightLarge)) {
|
||||||
ImGui::TextDisabled("Gstreamer examples");
|
ImGui::TextDisabled("Examples");
|
||||||
ImGui::Separator();
|
|
||||||
for (auto it = _examples.begin(); it != _examples.end(); ++it) {
|
for (auto it = _examples.begin(); it != _examples.end(); ++it) {
|
||||||
if (ImGui::Selectable( it->first.c_str() ) ) {
|
if (ImGui::Selectable( it->first.c_str() ) ) {
|
||||||
_description = it->second;
|
_effect_description = it->second;
|
||||||
update_new_source = true;
|
_effect_description_changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TextDisabled("Explore online");
|
||||||
|
if (ImGui::Selectable( ICON_FA_EXTERNAL_LINK_ALT " Frei0r" ) )
|
||||||
|
SystemToolkit::open("https://gstreamer.freedesktop.org/documentation/frei0r");
|
||||||
|
if (ImGui::Selectable( ICON_FA_EXTERNAL_LINK_ALT " Effectv" ) )
|
||||||
|
SystemToolkit::open("https://gstreamer.freedesktop.org/documentation/effectv");
|
||||||
|
if (ImGui::Selectable( ICON_FA_EXTERNAL_LINK_ALT " Gaudi" ) )
|
||||||
|
SystemToolkit::open("https://gstreamer.freedesktop.org/documentation/gaudieffects");
|
||||||
|
if (ImGui::Selectable( ICON_FA_EXTERNAL_LINK_ALT " Geometric" ) )
|
||||||
|
SystemToolkit::open("https://gstreamer.freedesktop.org/documentation/geometrictransform");
|
||||||
ImGui::EndCombo();
|
ImGui::EndCombo();
|
||||||
}
|
}
|
||||||
|
// Local menu for clearing
|
||||||
|
ImGui::SameLine();
|
||||||
|
if ( ImGuiToolkit::ButtonIcon(11,13,"Clear") ) {
|
||||||
|
_effect_description = "";
|
||||||
|
_effect_description_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO use update_new_source
|
// if desciption changed, start a timeout to test the pipeline
|
||||||
|
if ( _effect_description_changed ){
|
||||||
|
// reset to status 'unknown' and no message
|
||||||
|
_status = 0;
|
||||||
|
_status_message.clear();
|
||||||
|
|
||||||
|
// No description, no effect
|
||||||
|
if ( _effect_description.empty() ) {
|
||||||
|
_status = 1;
|
||||||
|
_status_message = "(no video effect)";
|
||||||
|
}
|
||||||
|
// has a description, we test it
|
||||||
|
else {
|
||||||
|
GError *error = NULL;
|
||||||
|
GstElement *effect = gst_parse_launch( _effect_description.c_str(), &error);
|
||||||
|
// on error
|
||||||
|
if (effect == NULL || error != NULL) {
|
||||||
|
_status = 2;
|
||||||
|
if (error != NULL)
|
||||||
|
_status_message = error->message;
|
||||||
|
g_clear_error (&error);
|
||||||
|
if (effect)
|
||||||
|
gst_object_unref(effect);
|
||||||
|
}
|
||||||
|
// on success
|
||||||
|
else
|
||||||
|
_status = 1;
|
||||||
|
}
|
||||||
|
// done
|
||||||
|
_effect_description_changed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// display message line
|
||||||
|
if (_status > 1) {
|
||||||
|
// On Error
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0, 0.2, 0.2, 0.95f));
|
||||||
|
ImGui::Text("Error - %s", _status_message.c_str());
|
||||||
|
ImGui::PopStyleColor(1);
|
||||||
|
}
|
||||||
|
else if (_status > 0) {
|
||||||
|
// All ok
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.2, 1.0, 0.2, 0.85f));
|
||||||
|
ImGui::Text("Ok %s", _status_message.c_str());
|
||||||
|
ImGui::PopStyleColor(1);
|
||||||
|
}
|
||||||
|
|
||||||
bool close = false;
|
bool close = false;
|
||||||
ImGui::SetCursorPos(pos + ImVec2(0.f, area.y - buttons_height_));
|
ImGui::SetCursorPos(pos + ImVec2(0.f, area.y - buttons_height_));
|
||||||
if (ImGui::Button(ICON_FA_TIMES " Cancel", ImVec2(area.x * 0.3f, 0)))
|
if (ImGui::Button(ICON_FA_TIMES " Cancel", ImVec2(area.x * 0.3f, 0)))
|
||||||
close = true;
|
close = true;
|
||||||
ImGui::SetCursorPos(pos + ImVec2(area.x * 0.7f, area.y - buttons_height_));
|
ImGui::SetCursorPos(pos + ImVec2(area.x * 0.7f, area.y - buttons_height_));
|
||||||
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyleColorVec4(ImGuiCol_Tab));
|
// on success status, offer to apply
|
||||||
if (ImGui::Button(ICON_FA_CHECK " Apply", ImVec2(area.x * 0.3f, 0))
|
if (_status == 1) {
|
||||||
|| ImGui::IsKeyPressedMap(ImGuiKey_Enter) || ImGui::IsKeyPressedMap(ImGuiKey_KeyPadEnter) ) {
|
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyleColorVec4(ImGuiCol_Tab));
|
||||||
close = true;
|
if (ImGui::Button(ICON_FA_CHECK " Apply", ImVec2(area.x * 0.3f, 0))
|
||||||
|
|| ImGui::IsKeyPressedMap(ImGuiKey_Enter) || ImGui::IsKeyPressedMap(ImGuiKey_KeyPadEnter) ) {
|
||||||
|
close = true;
|
||||||
|
|
||||||
// apply to pipeline
|
// apply to pipeline
|
||||||
mediaplayer_active_->setVideoEffect(_description);
|
mediaplayer_active_->setVideoEffect(_effect_description);
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor(1);
|
||||||
}
|
}
|
||||||
ImGui::PopStyleColor(1);
|
else
|
||||||
|
ImGuiToolkit::ButtonDisabled(ICON_FA_CHECK " Apply", ImVec2(area.x * 0.3f, 0));
|
||||||
|
|
||||||
if (close)
|
if (close)
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user