From ebd59e38ce3cf1fa26a56bf544b23d44a0ab752f Mon Sep 17 00:00:00 2001 From: Bruno Herbelin Date: Tue, 8 Aug 2023 23:02:34 +0200 Subject: [PATCH] Improve UI Play Direction and speed Play speed slider changes the speed without changing direction (not working well). Change play direction is now in a play sub-menu (mouse over) in play bar. Video menu changed, with Timeline section --- rsc/images/icons.dds | Bin 1638528 -> 1638528 bytes src/MediaPlayer.cpp | 24 ++++++--- src/ShaderEditWindow.cpp | 2 +- src/SourceControlWindow.cpp | 99 +++++++++++++++++++++++------------- 4 files changed, 82 insertions(+), 43 deletions(-) diff --git a/rsc/images/icons.dds b/rsc/images/icons.dds index 8c393e07ec4e1a5fd614ac438d8abdf0fc01187e..3d4d75e7c1ecf55c0b5e39f4aef3f1a311e58a69 100644 GIT binary patch delta 3556 zcmb7HZBSEJ8b0Udk`MX1$&G}ySqZfYevM(rDp;zaV_n1rLutD}s~f~&%67XO>UOQ2 z5fkk|cYoB}ru8@#MW3vra+KoIU4;a}(O> zk3Dx@xX(H7`<&-|z30Z`-RSXdJo2_)zFQ{l<>ZkvaX%+{X9e!2wxmhERY+T`-HDDF z;2D&&Yg)SeeVMq2lWSys7DP6Q=L2`Msh=bBJ$|5Z01seV+DQQbf;Avykt=2WeE4$# z1R5T&Hv6*ha!j8|U&&Ju*zt>06X8L_r5d9pNLylsa%n&##A|Q_Ri-ClTLW!Sy08o3 zqd2PgQ9KcgK%=Fa-v+#^(p5hHh&c-e(d9ZQ@>CN#Y=9Td0yvr=X(CLc{bBPw1j{t; zfK-i*OpjkGxBpnvo2sVP89%Lw#5ySBw!r@14<|CNC5qtDWHDt8h*)UfbO@5CmgqXz zpbUyu*e7}wUCrgyl*JP`usxE<;u36aF{K z>k-_b@ddheg%WvI%?L7I9Kp-BLX8@0@n_e%Ee${^%qfcB!$L2xqunnWsu28>=B+@W zy+4t0v6!GLlu<(V0|0d94+j_%QvTBy-LYwu!}&e> zCpOKQpqp1IA)Hc6CV-!-&2&ZmI%O#E5(v$w*3Bf-Pa}ysUy#3>PZ`lAJqaa;FR;$ zfsVVhGxQa&0~dL0=!F-JE9ACax;_&-2NaBudQvYB{t}Pknjw_CH@T|KJEVhc-ms2(zFa1dq1l&SPO?9MiYh-le2CNO7!CtO13f6GnJC<|@gXC7(*u zpEgNe*ERu2!kDCZQb%rZfg@cOKjHm5RVmOve;~5UQZWxOsuUS6!u>N1<4$VQ~&$u+Jt)fqju-kfjC?JI@ znxGeKagfIyvAS3-IP*(;XnL$p(TzVH0aFI^(sL}~#jFQXs5%CLL$S5#AiD%t+Mg6zTxw(--98z4#ALoy{sQG z*~w=@BJukz%1y1F_vsGXE&Bzaj&}lGw)5tPLKl~@u0#AfGLi9Rl04;zoX(K!YSw3) zESr_or0U>EV$y=*NBx<#uR^1Lq{AuLXlAN-o$+l(4SS$Xmfj`HK@wXuQ5|l@ofOmD z_?dVQkK-w=Akw_4Lr=^=Y#Om-VkyK@iKP)sCngXx%9}b&2Wzs`Q$%PUeyjh!Dw9C2 ze*s=jJGvv!Hj39wvz)-kGz#GWO)x=*$^VOuAM>XtzaQ4gw%Ou!Q;rY#fFnLLk<4F_ zO&7;xdn*qbE7iOtzmqSfh-(G#H}G*hmjN%o71^0X2*Hwe4CnGi_Q%6!rZ!;&XY zm(WW+^6u6KWoM~aZdyTNX<@Es*W14aS3$y*B)Llm@2J#+^E0G&5$j5}{aN&qth)l8n$696rW_0aZ$XYc(d~ANhl4VMG(r#C`(FJNAl=riuYjlsM;+?^do%#NYj&IK(Z6^3$@u Y5H|a|L}F%Q(}`sev&g=#%;B>C0k>z=IsgCw delta 4275 zcmZu#4^&gv8Ncr(f5eI9qj_hEt_gL9up4cBT?- zOY6=KiEny~vsJN`m3Bc++s_ve21d-qZ0T3_W_fAY^-bqVOQNlQ%ZDn>MxJP+%Om{ICtZFgd1PI8)9J461e z8Q=d#9Znw8*WQOnC#?au6wt_`GWeXNTjzOwPNt=z9Fb0!D=OrlF*+CRCSBB)d?7e3 z-IR}S-H!$lf{QcMOQk{+yIfXkCq`ZJ-JN(eS-g4Qm>Nhy?@~OX8~_%SF+m$f+X4AI zEYC$(A>7BD@wmA(3snGku-`c->yz#75Ic_=Vc~f7EZ^Q)qXZ0Z%??oPIM+&1P=Npd zFu(>V?WuAMQ|c9pEsrS!-%%$!#fgTwaK(7_OrLAfXaTy{s~zyto*fg zd_SSdJh*yX_C-)DxQ8=8&#C;YiYO?Rdml_;JpD2k(aGCmohAT(8FfMXX%9+t?{AlNyqFds%Q8AbrCwEvVw+jCj>{gl<&~+%$DlY~ zUDSsT@y*JOQGC1a@|9*8f8{uDU<}m|B=*M{`eW(3?@4dEk#hjl0iJ@8C-J7ba%oiC za^KBcCuME9aoz+`X(Jo+#)iFFH_V$4QY}B~4c`H^qG67lVIG&m*V*5w!v}n_;Kc<5 zHxjR)t&DghawV0+aL>S#o%$5haI=XpjW+oymn)CUDcwtEjt~`GTD!s$L}f!=(3R8> zRT`5;E{f4z!~BsVDbsRstjNU$?H{R@Zr~icRfA|h;#=X840Zk!MY2V@Ihi?`%yrpH zh={b<#I9zbB`Zc)Y~+n zkbI;F&W*m2FEA<<1Ir(2?t0u7=dV9We)fXjPw8t{ z^Ov?>i&S?qH`f1*Ie+elJ#_u-)eE-mCqf}g<3h0+yD$5n3E!T>RxR=Ol~@nozI~Xo zgl?R$=7d5ylwRGouc-CfwN^^kw!LA^_xtlHP2Ah=^=_A(bJ^3vqTdFOr+#+eLwT4C8kx>6D%Ub!(Gem8u)KegV3g z*zDYLGvwDMZL4?rIX!{0UYKq~{1k>>gIYz^ldR1|~ z>kh}%ySlhYq^$OT5|d&~A5CT~7+Be-(}Q93`6iu02jF~@W(?%M<3_2BrfabJ4X@JtpObIxMtm3~(bR9E1`!bO4y(9rlIN}v!PyrPn zG-(RGU?@F+9-#jsS)XiHJKXk4!b0iqChflk9smAN=3eMIJt8}`jg5d(OkyzU;_bq` zsm1{Za-%C`O$J1bq?BD(XaH0|1JdB)d8$oPQ;zno;Bncx7(&);9#}vX74Ji#K)4Za z7H-79gQy4@2Z3^>DgZU0oe3tuCG%7}q?V-w&uxvvGta&P9)Ny}d{PJknt^jRTIvXm zSFbFLmO^N@ReRoh9v$;yNn@kC;sON6D8}LT89qb z8H`7PBfc&WvqR_;#r)sEW1HA)c=woU;*=FX$YG_P$we54gVOC_3qBPpsp61!gkIE@ zY}MO)p1kGVfqS>I4r7pnfXW5ulrr%&{$0J@tHmP`j}dqz;V}}AQFtWdF&YmZ51q8# zE4)|isU9uxzoKvi3V@Z9A^x1~l_u--H-)G0MBK97c>5F~|gZTCCJp7s0 zA{i&^JB6thU?-h&;nLU~82d{FWtT_g2DlR`k9)RsAWuJ14=-C;Jyd_7nJDnUNkxe@ z2Cx?XYq9!iP8N!YLC2kh`Ox!~rcrV%(-#W%@}b4h&vs37dBLN290sJtaJ$O=x3c_7 zF_{kMk7evnYQUyB_38R-mkh25AL;6De%RP1Un@w?kz&n&pD6x$s^-Tdk-&(2)mSO_ zcluIcHgQRT0=Jz0TXWh})XwQ1c1Te_!gQw|tKs|Ml2@7hCqX6STY8tke>pTyriX884vqzpz){(q3gNPFMW z?-Isd2A6S_9`X_J1wOm*?Ma-C;}CZ-LB|k*Jf_;+q{qX6M+zQe@E9w(n^Nx<{2$1l BYy1EJ diff --git a/src/MediaPlayer.cpp b/src/MediaPlayer.cpp index 3b4b6d8..d060017 100644 --- a/src/MediaPlayer.cpp +++ b/src/MediaPlayer.cpp @@ -319,6 +319,7 @@ typedef enum { GST_PLAY_FLAG_SW_DECODER = 0x00001000 } GstPlayFlags; + // // Setup a media player using gstreamer playbin // @@ -368,7 +369,7 @@ void MediaPlayer::execute_open() } // setup appsink - GstElement *sink = gst_element_factory_make ("appsink", NULL); + GstElement *sink = gst_element_factory_make ("appsink", "appsink"); if (!sink) { Log::Warning("MediaPlayer %s Could not configure sink", std::to_string(id_).c_str()); failed_ = true; @@ -1358,10 +1359,8 @@ void MediaPlayer::setPlaySpeed(double s) GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); - if (seek_event && gst_element_send_event(pipeline_, seek_event) ) { + if (seek_event && gst_element_send_event(pipeline_, seek_event) ) seeking_ = true; - Log::Info("MediaPlayer %s; instant rate to %f", std::to_string(id_).c_str(), rate_); - } else { Log::Info("MediaPlayer %s; cannot perform instantaneous speed change. Change of play speed will not be smooth.", std::to_string(id_).c_str()); rate_change_ = RATE_CHANGE_FLUSH; @@ -1370,10 +1369,8 @@ void MediaPlayer::setPlaySpeed(double s) // Generic way is a flush seek // following the example from // https://gstreamer.freedesktop.org/documentation/tutorials/basic/playback-speed.html - else { - Log::Info("MediaPlayer %s; flush rate to %f", std::to_string(id_).c_str(), rate_); + else execute_seek_command(); - } // Set after initialization (will be used next time) if (rate_change_ == RATE_CHANGE_NONE) @@ -1616,3 +1613,16 @@ void MediaPlayer::TimeCounter::tic () } } + +//static void audio_changed_callback (GstElement *pipeline, MediaPlayer *mp) +//{ +// gint n_audio; +// g_object_get (G_OBJECT (pipeline), "n-audio", &n_audio, NULL); +// if ( n_audio > 0 ) { +// Log::Info("MediaPlayer %d Audio stream muted", std::to_string( mp->id() ).c_str() ); +// gst_stream_volume_set_volume (GST_STREAM_VOLUME (pipeline), GST_STREAM_VOLUME_FORMAT_LINEAR, 0.); +// gst_stream_volume_set_mute (GST_STREAM_VOLUME (pipeline), true); +// } +//} +// flags |= GST_PLAY_FLAG_AUDIO; +// g_signal_connect ( G_OBJECT (pipeline_), "audio-changed", G_CALLBACK (audio_changed_callback), this); diff --git a/src/ShaderEditWindow.cpp b/src/ShaderEditWindow.cpp index 01a0f20..f5532a5 100644 --- a/src/ShaderEditWindow.cpp +++ b/src/ShaderEditWindow.cpp @@ -140,7 +140,7 @@ void ShaderEditWindow::Render() if (ImGui::BeginMenu(IMGUI_TITLE_SHADEREDITOR)) { // reload code from GPU - if (ImGui::MenuItem( ICON_FA_SYNC " Reload", nullptr, nullptr, current_ != nullptr)) { + if (ImGui::MenuItem( ICON_FA_REDO_ALT " Reload", nullptr, nullptr, current_ != nullptr)) { // force reload if ( current_ != nullptr ) filters_.erase(current_); diff --git a/src/SourceControlWindow.cpp b/src/SourceControlWindow.cpp index d75a28f..f56ee30 100644 --- a/src/SourceControlWindow.cpp +++ b/src/SourceControlWindow.cpp @@ -374,7 +374,33 @@ void SourceControlWindow::Render() // if (ImGui::BeginMenu(ICON_FA_FILM " Video", mediaplayer_active_) ) { - if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset timeline")){ + if (ImGui::MenuItem( ICON_FA_REDO_ALT " Reload" )) + mediaplayer_active_->reopen(); + if (ImGuiToolkit::MenuItemIcon(16, 16, "Gstreamer effect") ) + mediaplayer_edit_pipeline_ = true; + if (ImGui::BeginMenu(ICON_FA_SNOWFLAKE " On deactivation")) + { + bool option = !mediaplayer_active_->rewindOnDisabled(); + if (ImGui::MenuItem(ICON_FA_STOP " Stop", NULL, &option )) + mediaplayer_active_->setRewindOnDisabled(false); + option = mediaplayer_active_->rewindOnDisabled(); + if (ImGui::MenuItem(ICON_FA_FAST_BACKWARD " Rewind & Stop", NULL, &option )) + mediaplayer_active_->setRewindOnDisabled(true); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu(ICON_FA_MICROCHIP " Hardware decoding")) + { + bool hwdec = !mediaplayer_active_->softwareDecodingForced(); + if (ImGui::MenuItem("Auto", "", &hwdec )) + mediaplayer_active_->setSoftwareDecodingForced(false); + hwdec = mediaplayer_active_->softwareDecodingForced(); + if (ImGui::MenuItem("Disabled", "", &hwdec )) + mediaplayer_active_->setSoftwareDecodingForced(true); + ImGui::EndMenu(); + } + ImGui::Separator(); + ImGui::TextDisabled("Timeline"); + if (ImGui::MenuItem(ICON_FA_WINDOW_CLOSE " Reset")){ mediaplayer_timeline_zoom_ = 1.f; mediaplayer_active_->timeline()->clearFading(); mediaplayer_active_->timeline()->clearGaps(); @@ -402,32 +428,6 @@ void SourceControlWindow::Render() ImGui::EndMenu(); } - ImGui::Separator(); - if (ImGui::BeginMenu(ICON_FA_SNOWFLAKE " Deactivation")) - { - bool option = !mediaplayer_active_->rewindOnDisabled(); - if (ImGui::MenuItem(ICON_FA_STOP " Stop", NULL, &option )) - mediaplayer_active_->setRewindOnDisabled(false); - option = mediaplayer_active_->rewindOnDisabled(); - if (ImGui::MenuItem(ICON_FA_FAST_BACKWARD " Rewind & Stop", NULL, &option )) - mediaplayer_active_->setRewindOnDisabled(true); - ImGui::EndMenu(); - } - // always allow for hardware decoding to be disabled - if (ImGui::BeginMenu(ICON_FA_MICROCHIP " Hardware decoding")) - { - bool hwdec = !mediaplayer_active_->softwareDecodingForced(); - if (ImGui::MenuItem("Auto", "", &hwdec )) - mediaplayer_active_->setSoftwareDecodingForced(false); - hwdec = mediaplayer_active_->softwareDecodingForced(); - if (ImGui::MenuItem("Disabled", "", &hwdec )) - mediaplayer_active_->setSoftwareDecodingForced(true); - ImGui::EndMenu(); - } - // TODO finalize pipeline editor - if (ImGui::MenuItem(ICON_FA_MAGIC " Video effect")) - mediaplayer_edit_pipeline_ = true; - ImGui::EndMenu(); } @@ -1491,6 +1491,8 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms) /// /// media player timelines /// + double current_play_speed = mediaplayer_active_->playSpeed(); + static uint counter_menu_timeout = 0; const ImVec2 scrollwindow = ImVec2(ImGui::GetContentRegionAvail().x - slider_zoom_width - 3.0, 2.f * timeline_height_ + scrollbar_ ); @@ -1656,12 +1658,12 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms) ImGui::SameLine(0, MAX(h_space_ * 2.f, rendersize.x - min_width_ * 1.4f) ); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - buttons_height_ ); // speed slider - float speed = static_cast(mediaplayer_active_->playSpeed()); - if (ImGui::DragFloat( "##Speed", &speed, 0.01f, -10.f, 10.f, UNICODE_MULTIPLY " %.2f")) - mediaplayer_active_->setPlaySpeed( static_cast(speed) ); + float s = fabs(static_cast(current_play_speed)); + if (ImGui::DragFloat( "##Speed", &s, 0.01f, 0.1f, 10.f, UNICODE_MULTIPLY " %.2f")) + mediaplayer_active_->setPlaySpeed( SIGN(current_play_speed) * static_cast(s) ); // store action on mouse release if (ImGui::IsItemDeactivatedAfterEdit()){ - oss << ": Speed x" << std::setprecision(3) << speed; + oss << ": Speed x" << std::setprecision(3) << s; Action::manager().store(oss.str()); } if (ImGui::IsItemHovered()) @@ -1670,8 +1672,9 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms) ImGui::SameLine(); ImGui::SetCursorPosX(rendersize.x - buttons_height_ / 1.4f); - if (ImGuiToolkit::IconButton(12,14,"Reset" )) { - mediaplayer_active_->reopen(); + if (ImGuiToolkit::IconButton(5, 8) || ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) { + counter_menu_timeout=0; + ImGui::OpenPopup( "MenuPlaySpeed" ); } // restore buttons style @@ -1715,6 +1718,32 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms) DrawButtonBar(bottom, rendersize.x); } + if (ImGui::BeginPopup( "MenuPlaySpeed" )) + { + if (ImGuiToolkit::MenuItemIcon(8,0, "Play forward", nullptr, current_play_speed>0)) { + mediaplayer_active_->setPlaySpeed( ABS(mediaplayer_active_->playSpeed()) ); + oss << ": Play forward"; + Action::manager().store(oss.str()); + } + if (ImGuiToolkit::MenuItemIcon(9,0, "Play backward", nullptr, current_play_speed<0)) { + mediaplayer_active_->setPlaySpeed( - ABS(mediaplayer_active_->playSpeed()) ); + oss << ": Play backward"; + Action::manager().store(oss.str()); + } + if (ImGuiToolkit::MenuItemIcon(19,15, "Reset speed")) { + mediaplayer_active_->setPlaySpeed(1.0); + oss << ": Speed x 1.0"; + Action::manager().store(oss.str()); + } + + if (ImGui::IsWindowHovered()) + counter_menu_timeout=0; + else if (++counter_menu_timeout > 10) + ImGui::CloseCurrentPopup(); + + ImGui::EndPopup(); + } + if (mediaplayer_edit_fading_) { ImGui::OpenPopup(LABEL_EDIT_FADING); @@ -1798,7 +1827,7 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms) static bool _effect_description_changed = false; if (mediaplayer_edit_pipeline_) { // open dialog - ImGui::OpenPopup(ICON_FA_MAGIC " Video effect"); + ImGui::OpenPopup("Gstreamer Video effect"); mediaplayer_edit_pipeline_ = false; // initialize dialog _effect_description = mediaplayer_active_->videoEffect(); @@ -1808,7 +1837,7 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms) ImGui::SetNextWindowSize(mpp_dialog_size, ImGuiCond_Always); const ImVec2 mpp_dialog_pos = top + rendersize * 0.5f - mpp_dialog_size * 0.5f; ImGui::SetNextWindowPos(mpp_dialog_pos, ImGuiCond_Always); - if (ImGui::BeginPopupModal(ICON_FA_MAGIC " Video effect", NULL, ImGuiWindowFlags_NoResize)) + if (ImGui::BeginPopupModal("Gstreamer Video effect", NULL, ImGuiWindowFlags_NoResize)) { const ImVec2 pos = ImGui::GetCursorPos(); const ImVec2 area = ImGui::GetContentRegionAvail();