mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
New Generalize option to restart on deactivation to any StreamSource
StreamSource now have the option 'restart on deactivation' like MediaPlayer. This option is saved in XML (added Visitors for Stream and StreamSource). The GUI is added as sub-menu in play bar (like for MediaPlayer). Some StreamSource subclasses needed to be fixed to allow this feature (e.g. MultiFileSource).
This commit is contained in:
@@ -526,7 +526,7 @@ void DeviceSource::setActive (bool on)
|
||||
|
||||
void DeviceSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
StreamSource::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -129,6 +129,16 @@ void MultiFile::close ()
|
||||
Stream::close();
|
||||
}
|
||||
|
||||
void MultiFile::rewind ()
|
||||
{
|
||||
if (src_) {
|
||||
int begin = 0;
|
||||
g_object_get (src_, "start-index", &begin, NULL);
|
||||
setIndex (begin);
|
||||
}
|
||||
Stream::rewind();
|
||||
}
|
||||
|
||||
void MultiFile::setIndex(int val)
|
||||
{
|
||||
if (src_) {
|
||||
@@ -219,10 +229,8 @@ void MultiFileSource::setRange (int begin, int end)
|
||||
|
||||
void MultiFileSource::replay ()
|
||||
{
|
||||
if (multifile()) {
|
||||
multifile()->setIndex (begin_);
|
||||
stream_->rewind();
|
||||
}
|
||||
if (multifile())
|
||||
multifile()->rewind();
|
||||
}
|
||||
|
||||
guint64 MultiFileSource::playtime () const
|
||||
@@ -240,7 +248,7 @@ guint64 MultiFileSource::playtime () const
|
||||
|
||||
void MultiFileSource::accept (Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
StreamSource::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
MultiFile ();
|
||||
void open (const MultiFileSequence &sequence, uint framerate = 30);
|
||||
void close () override;
|
||||
void rewind () override;
|
||||
|
||||
// dynamic change of gstreamer multifile source properties
|
||||
void setProperties(int begin, int end, int loop);
|
||||
|
||||
@@ -341,7 +341,7 @@ std::string NetworkSource::connection() const
|
||||
|
||||
void NetworkSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
StreamSource::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ void PatternSource::setPattern(uint type, glm::ivec2 resolution)
|
||||
|
||||
void PatternSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
StreamSource::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "NetworkSource.h"
|
||||
#include "SrtReceiverSource.h"
|
||||
#include "MultiFileSource.h"
|
||||
#include "StreamSource.h"
|
||||
#include "RenderSource.h"
|
||||
#include "Session.h"
|
||||
#include "ImageShader.h"
|
||||
@@ -1169,6 +1168,24 @@ void SessionLoader::visit (RenderSource& s)
|
||||
s.setSession( session_ );
|
||||
}
|
||||
|
||||
void SessionLoader::visit(Stream &n)
|
||||
{
|
||||
XMLElement* streamNode = xmlCurrent_->FirstChildElement("Stream");
|
||||
|
||||
if (streamNode) {
|
||||
bool rewind_on_disabled = false;
|
||||
streamNode->QueryBoolAttribute("rewind_on_disabled", &rewind_on_disabled);
|
||||
n.setRewindOnDisabled(rewind_on_disabled);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionLoader::visit (StreamSource& s)
|
||||
{
|
||||
// set config stream
|
||||
if (s.stream() != nullptr)
|
||||
s.stream()->accept(*this);
|
||||
}
|
||||
|
||||
void SessionLoader::visit (PatternSource& s)
|
||||
{
|
||||
uint t = xmlCurrent_->UnsignedAttribute("pattern");
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
|
||||
// Elements with attributes
|
||||
void visit (MediaPlayer& n) override;
|
||||
void visit (Stream& n) override;
|
||||
void visit (Shader& n) override;
|
||||
void visit (ImageShader& n) override;
|
||||
void visit (MaskShader& n) override;
|
||||
@@ -53,6 +54,7 @@ public:
|
||||
// Sources
|
||||
void visit (Source& s) override;
|
||||
void visit (MediaSource& s) override;
|
||||
void visit (StreamSource& s) override;
|
||||
void visit (SessionFileSource& s) override;
|
||||
void visit (SessionGroupSource& s) override;
|
||||
void visit (RenderSource& s) override;
|
||||
|
||||
@@ -405,6 +405,18 @@ void SessionVisitor::visit(FrameBufferSurface &)
|
||||
xmlCurrent_->SetAttribute("type", "FrameBufferSurface");
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(Stream &n)
|
||||
{
|
||||
XMLElement *newelement = xmlDoc_->NewElement("Stream");
|
||||
newelement->SetAttribute("id", n.id());
|
||||
|
||||
if (!n.singleFrame()) {
|
||||
newelement->SetAttribute("rewind_on_disabled", n.rewindOnDisabled());
|
||||
}
|
||||
|
||||
xmlCurrent_->InsertEndChild(newelement);
|
||||
}
|
||||
|
||||
void SessionVisitor::visit(MediaPlayer &n)
|
||||
{
|
||||
XMLElement *newelement = xmlDoc_->NewElement("MediaPlayer");
|
||||
@@ -808,6 +820,12 @@ void SessionVisitor::visit (CloneSource& s)
|
||||
xmlCurrent_ = cloneNode; // parent for next visits (other subtypes of Source)
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (StreamSource& s)
|
||||
{
|
||||
if (s.stream() != nullptr)
|
||||
s.stream()->accept(*this);
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (PatternSource& s)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("type", "PatternSource");
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
|
||||
// Elements with attributes
|
||||
void visit (MediaPlayer& n) override;
|
||||
void visit (Stream& n) override;
|
||||
void visit (Shader& n) override;
|
||||
void visit (ImageShader& n) override;
|
||||
void visit (MaskShader& n) override;
|
||||
@@ -58,6 +59,7 @@ public:
|
||||
// Sources
|
||||
void visit (Source& s) override;
|
||||
void visit (MediaSource& s) override;
|
||||
void visit (StreamSource& s) override;
|
||||
void visit (SessionFileSource& s) override;
|
||||
void visit (SessionGroupSource& s) override;
|
||||
void visit (RenderSource&) override;
|
||||
|
||||
@@ -375,8 +375,8 @@ void SourceControlWindow::Render()
|
||||
if (ImGui::BeginMenu(ICON_FA_PHOTO_VIDEO " Media", mediaplayer_active_) )
|
||||
{
|
||||
if ( !mediaplayer_active_->singleFrame() ) {
|
||||
if (ImGui::MenuItem( ICON_FA_REDO_ALT " Reload" ))
|
||||
mediaplayer_active_->reopen();
|
||||
// if (ImGui::MenuItem( ICON_FA_REDO_ALT " Reload" ))
|
||||
// mediaplayer_active_->reopen();
|
||||
if (ImGuiToolkit::MenuItemIcon(16, 16, "Gstreamer effect", nullptr,
|
||||
false, mediaplayer_active_->videoEffectAvailable()) )
|
||||
mediaplayer_edit_pipeline_ = true;
|
||||
@@ -390,16 +390,6 @@ void SourceControlWindow::Render()
|
||||
mediaplayer_active_->setSoftwareDecodingForced(true);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
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();
|
||||
}
|
||||
ImGui::Separator();
|
||||
ImGui::TextDisabled("Timeline");
|
||||
|
||||
@@ -1410,8 +1400,10 @@ void SourceControlWindow::RenderSingleSource(Source *s)
|
||||
///
|
||||
DrawButtonBar(bottom, rendersize.x);
|
||||
|
||||
// If possibly a media source, but is not playable
|
||||
// then offer to make it playable by adding a timeline
|
||||
///
|
||||
/// Special possibly : selected a media source that is not playable
|
||||
/// then offer to make it playable by adding a timeline
|
||||
///
|
||||
if ( ms != nullptr )
|
||||
{
|
||||
if (ms->mediaplayer()->isImage()) {
|
||||
@@ -1450,6 +1442,43 @@ void SourceControlWindow::RenderSingleSource(Source *s)
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
}
|
||||
///
|
||||
/// Not a media source, but playable source
|
||||
/// Offer context menu if it is a Stream source
|
||||
///
|
||||
else if ( s->active() && s->playable() ) {
|
||||
StreamSource *ss = dynamic_cast<StreamSource *>(s);
|
||||
if ( ss != nullptr ) {
|
||||
|
||||
static uint counter_menu_timeout = 0;
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(rendersize.x - buttons_height_ / 1.4f);
|
||||
if (ImGuiToolkit::IconButton(5, 8) || ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) {
|
||||
counter_menu_timeout=0;
|
||||
ImGui::OpenPopup( "MenuStreamOptions" );
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup( "MenuStreamOptions" ))
|
||||
{
|
||||
// NB: ss is playable (tested above), and thus ss->stream() is not null
|
||||
if (ImGui::MenuItem( ICON_FA_REDO_ALT " Reload" )) {
|
||||
ss->stream()->reopen();
|
||||
}
|
||||
bool option = ss->stream()->rewindOnDisabled();
|
||||
if (ImGui::MenuItem(ICON_FA_SNOWFLAKE " Restart on deactivation", NULL, &option )) {
|
||||
ss->stream()->setRewindOnDisabled(option);
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowHovered())
|
||||
counter_menu_timeout=0;
|
||||
else if (++counter_menu_timeout > 10)
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1740,7 +1769,7 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
||||
ImGui::SetCursorPosX(rendersize.x - buttons_height_ / 1.4f);
|
||||
if (ImGuiToolkit::IconButton(5, 8) || ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) {
|
||||
counter_menu_timeout=0;
|
||||
ImGui::OpenPopup( "MenuPlaySpeed" );
|
||||
ImGui::OpenPopup( "MenuMediaPlayerOptions" );
|
||||
}
|
||||
|
||||
// restore buttons style
|
||||
@@ -1784,7 +1813,7 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
||||
DrawButtonBar(bottom, rendersize.x);
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup( "MenuPlaySpeed" ))
|
||||
if (ImGui::BeginPopup( "MenuMediaPlayerOptions" ))
|
||||
{
|
||||
if (ImGuiToolkit::MenuItemIcon(8,0, "Play forward", nullptr, current_play_speed>0)) {
|
||||
mediaplayer_active_->setPlaySpeed( ABS(mediaplayer_active_->playSpeed()) );
|
||||
@@ -1801,6 +1830,15 @@ void SourceControlWindow::RenderMediaPlayer(MediaSource *ms)
|
||||
oss << ": Speed x 1.0";
|
||||
Action::manager().store(oss.str());
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem( ICON_FA_REDO_ALT " Reload" ))
|
||||
mediaplayer_active_->reopen();
|
||||
|
||||
bool option = mediaplayer_active_->rewindOnDisabled();
|
||||
if (ImGui::MenuItem(ICON_FA_SNOWFLAKE " Restart on deactivation", NULL, &option )) {
|
||||
mediaplayer_active_->setRewindOnDisabled(option);
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowHovered())
|
||||
counter_menu_timeout=0;
|
||||
|
||||
@@ -54,7 +54,7 @@ std::string SrtReceiverSource::uri() const
|
||||
|
||||
void SrtReceiverSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
StreamSource::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ Stream::Stream()
|
||||
single_frame_ = false;
|
||||
live_ = false;
|
||||
failed_ = false;
|
||||
rewind_on_disable_ = false;
|
||||
decoder_name_ = "";
|
||||
|
||||
// start index in frame_ stack
|
||||
@@ -216,6 +217,15 @@ void Stream::open(const std::string &gstreamer_description, guint w, guint h)
|
||||
|
||||
}
|
||||
|
||||
void Stream::reopen()
|
||||
{
|
||||
// re-openning is meaningfull only if it was already open
|
||||
if (pipeline_ != nullptr) {
|
||||
// reload : terminate pipeline and re-create it
|
||||
close();
|
||||
execute_open();
|
||||
}
|
||||
}
|
||||
|
||||
std::string Stream::description() const
|
||||
{
|
||||
@@ -407,6 +417,10 @@ void Stream::enable(bool on)
|
||||
|
||||
if ( enabled_ != on ) {
|
||||
|
||||
// option to automatically rewind each time the player is disabled
|
||||
if (!on && rewind_on_disable_ && desired_state_ == GST_STATE_PLAYING)
|
||||
rewind();
|
||||
|
||||
enabled_ = on;
|
||||
|
||||
// default to pause
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
* Open a media using gstreamer pipeline keyword
|
||||
* */
|
||||
void open(const std::string &gstreamer_description, guint w = 0, guint h = 0);
|
||||
void reopen ();
|
||||
/**
|
||||
* Get description string
|
||||
* */
|
||||
@@ -143,6 +144,12 @@ public:
|
||||
* NB: perform request on pipeline on first call
|
||||
* */
|
||||
std::string decoderName();
|
||||
/**
|
||||
* Option to automatically rewind each time the player is disabled
|
||||
* (i.e. when enable(false) is called )
|
||||
* */
|
||||
inline void setRewindOnDisabled(bool on) { rewind_on_disable_ = on; }
|
||||
inline bool rewindOnDisabled() const { return rewind_on_disable_; }
|
||||
/**
|
||||
* Get logs
|
||||
* */
|
||||
@@ -176,6 +183,7 @@ protected:
|
||||
std::atomic<bool> opened_;
|
||||
std::atomic<bool> failed_;
|
||||
bool enabled_;
|
||||
bool rewind_on_disable_;
|
||||
std::string decoder_name_;
|
||||
|
||||
// fps counter
|
||||
|
||||
@@ -68,7 +68,7 @@ std::list<std::string> GenericStreamSource::gstElements() const
|
||||
|
||||
void GenericStreamSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
StreamSource::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
@@ -197,3 +197,9 @@ void StreamSource::update(float dt)
|
||||
if ( stream_ )
|
||||
stream_->update();
|
||||
}
|
||||
|
||||
void StreamSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ public:
|
||||
// pure virtual interface
|
||||
virtual Stream *stream() const = 0;
|
||||
|
||||
// Source interface
|
||||
virtual void accept (Visitor& v) override;
|
||||
|
||||
protected:
|
||||
void init() override;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ class ImageProcessingShader;
|
||||
|
||||
class Source;
|
||||
class MediaSource;
|
||||
class StreamSource;
|
||||
class PatternSource;
|
||||
class DeviceSource;
|
||||
class GenericStreamSource;
|
||||
@@ -101,6 +102,7 @@ public:
|
||||
virtual void visit (MixingGroup&) {}
|
||||
virtual void visit (Source&) {}
|
||||
virtual void visit (MediaSource&) {}
|
||||
virtual void visit (StreamSource&) {}
|
||||
virtual void visit (NetworkSource&) {}
|
||||
virtual void visit (SrtReceiverSource&) {}
|
||||
virtual void visit (GenericStreamSource&) {}
|
||||
|
||||
Reference in New Issue
Block a user