Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/beta'
Browse files Browse the repository at this point in the history
  • Loading branch information
brunoherbelin committed Nov 10, 2024
2 parents 6e62ce1 + 92c0b44 commit ba75777
Show file tree
Hide file tree
Showing 21 changed files with 200 additions and 211 deletions.
Binary file modified rsc/images/icons.dds
Binary file not shown.
7 changes: 4 additions & 3 deletions share/metainfo/io.github.brunoherbelin.Vimix.metainfo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@
<binary>vimix</binary>
</provides>
<releases>
<release version="0.8.2d" date="2024-04-06">
<release version="0.8.3" date="2024-11-10">
<description>
<p>Stabilized version 0.8.2</p>
<p>Version 0.8.3</p>
</description>
<url>https://github.com/brunoherbelin/vimix/releases/tag/0.8.2d</url>
<url>https://github.com/brunoherbelin/vimix/releases/tag/0.8.3</url>
</release>
<release version="0.8.2d" date="2024-04-06"/>
<release version="0.8.2" date="2024-01-02"/>
<release version="0.8.1" date="2023-09-18"/>
<release version="0.8.0" date="2023-03-31"/>
Expand Down
2 changes: 1 addition & 1 deletion snap/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: vimix
base: core22
version: '0.8.2d'
version: '0.8.3'
summary: Video live mixer
title: vimix
description: |
Expand Down
1 change: 1 addition & 0 deletions src/CloneSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class CloneSource : public Source
void render() override;
glm::ivec2 icon() const override;
std::string info() const override;
bool texturePostProcessed() const override { return true; }

// implementation of cloning mechanism
void detach();
Expand Down
12 changes: 6 additions & 6 deletions src/GeometryView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1019,16 +1019,16 @@ View::Cursor GeometryView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::p
// prepare overlay frame showing full image size
glm::vec3 _c_s = glm::vec3(s->stored_status_->crop_[0]
- s->stored_status_->crop_[1],
s->stored_status_->crop_[3]
- s->stored_status_->crop_[2],
s->stored_status_->crop_[2]
- s->stored_status_->crop_[3],
2.f)
* 0.5f;
overlay_crop_->scale_ = s->stored_status_->scale_ / _c_s;
overlay_crop_->scale_.x *= s->frame()->aspectRatio();
overlay_crop_->rotation_.z = s->stored_status_->rotation_.z;
overlay_crop_->translation_ = s->stored_status_->translation_;
glm::vec3 _t((s->stored_status_->crop_[1] + _c_s.x) * overlay_crop_->scale_.x,
-s->stored_status_->crop_[3] + _c_s.y, 0.f);
(-s->stored_status_->crop_[2] + _c_s.y) * overlay_crop_->scale_.y, 0.f);
_t = glm::rotate(glm::identity<glm::mat4>(),
overlay_crop_->rotation_.z,
glm::vec3(0.f, 0.f, 1.f))
Expand Down Expand Up @@ -1112,16 +1112,16 @@ View::Cursor GeometryView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::p
// prepare overlay frame showing full image size
glm::vec3 _c_s = glm::vec3(s->stored_status_->crop_[0]
- s->stored_status_->crop_[1],
s->stored_status_->crop_[3]
- s->stored_status_->crop_[2],
s->stored_status_->crop_[2]
- s->stored_status_->crop_[3],
2.f)
* 0.5f;
overlay_crop_->scale_ = s->stored_status_->scale_ / _c_s;
overlay_crop_->scale_.x *= s->frame()->aspectRatio();
overlay_crop_->rotation_.z = s->stored_status_->rotation_.z;
overlay_crop_->translation_ = s->stored_status_->translation_;
glm::vec3 _t((s->stored_status_->crop_[1] + _c_s.x) * overlay_crop_->scale_.x,
-s->stored_status_->crop_[3] + _c_s.y, 0.f);
(-s->stored_status_->crop_[2] + _c_s.y) * overlay_crop_->scale_.y, 0.f);
_t = glm::rotate(glm::identity<glm::mat4>(),
overlay_crop_->rotation_.z,
glm::vec3(0.f, 0.f, 1.f))
Expand Down
34 changes: 22 additions & 12 deletions src/MediaPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ MediaPlayer::MediaPlayer()
video_filter_available_ = true;
position_ = GST_CLOCK_TIME_NONE;
loop_ = LoopMode::LOOP_REWIND;
loop_status_ = LoopStatus::LOOP_STATUS_DEFAULT;
fading_mode_ = FadingMode::FADING_COLOR;

// start index in frame_ stack
Expand Down Expand Up @@ -513,13 +514,13 @@ void MediaPlayer::execute_open()
if (media_.hasaudio)
Log::Info("MediaPlayer %s Audio track %s", std::to_string(id_).c_str(), audio_enabled_ ? "enabled" : "disabled");

opened_ = true;

// keep name in pipeline
gst_element_set_name(pipeline_, std::to_string(id_).c_str());

// register media player
MediaPlayer::registered_.push_back(pipeline_);

opened_ = true;
}

#else
Expand Down Expand Up @@ -956,7 +957,7 @@ void MediaPlayer::execute_play_command(bool on)
desired_state_ = requested_state;

// if not ready yet, the requested state will be handled later
if ( pipeline_ == nullptr )
if ( !opened_ || pipeline_ == nullptr )
return;

// requesting to play, but stopped at end of stream : rewind first !
Expand All @@ -980,6 +981,9 @@ void MediaPlayer::execute_play_command(bool on)
Log::Info("MediaPlayer %s Stop [%ld]", std::to_string(id_).c_str(), position());
#endif

// Revert loop status to default when playing
if (on)
loop_status_ = LoopStatus::LOOP_STATUS_DEFAULT;
}

void MediaPlayer::play(bool on)
Expand All @@ -992,6 +996,7 @@ void MediaPlayer::play(bool on)
if (metro_sync_ > Metronome::SYNC_NONE) {
// busy with this delayed action
pending_ = true;

// delayed execution function
std::function<void()> playlater = std::bind([](MediaPlayer *p, bool o) {
p->execute_play_command(o); p->pending_=false; }, this, on);
Expand All @@ -1013,7 +1018,7 @@ bool MediaPlayer::isPlaying(bool testpipeline) const
return false;

// if not ready yet, answer with requested state
if ( !testpipeline || pipeline_ == nullptr || !enabled_)
if ( !testpipeline || !opened_ || pipeline_ == nullptr || !enabled_)
return desired_state_ == GST_STATE_PLAYING;

// if ready, answer with actual state
Expand Down Expand Up @@ -1399,14 +1404,19 @@ void MediaPlayer::execute_loop_command()
rate_ *= -1.f;
execute_seek_command();
}
else { //LOOP_NONE
else {
if (loop_ == LOOP_BLACKOUT)
loop_status_ = LoopStatus::LOOP_STATUS_BLACKOUT;
else
loop_status_ = LoopStatus::LOOP_STATUS_STOPPED;
// stop
play(false);
}
}

void MediaPlayer::execute_seek_command(GstClockTime target, bool force)
{
if ( pipeline_ == nullptr || !media_.seekable )
if ( !opened_ || pipeline_ == nullptr || !media_.seekable )
return;

// ignore request to current position
Expand All @@ -1420,15 +1430,12 @@ void MediaPlayer::execute_seek_command(GstClockTime target, bool force)
int seek_flags = GST_SEEK_FLAG_FLUSH;

// no target given
if (target == GST_CLOCK_TIME_NONE) {
if (target == GST_CLOCK_TIME_NONE)
// create seek event with current position (called for rate changed)
// CLAMP the time to ensure we do not bounce outside of timeline
seek_pos = CLAMP(position_, timeline_.first(), timeline_.last() - timeline_.step());
// seek with KEY mode if playing
seek_flags |= GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_SNAP_AFTER;
}
else
// seek with accurate timing if paused
// seek with accurate timing if given target
seek_flags |= GST_SEEK_FLAG_ACCURATE;

// create seek event depending on direction
Expand Down Expand Up @@ -1538,6 +1545,9 @@ Timeline *MediaPlayer::timeline()

float MediaPlayer::currentTimelineFading()
{
if (loop_status_ == LOOP_STATUS_BLACKOUT && !isPlaying())
return 0.f;

return timeline_.fadingAt(position_);
}

Expand Down Expand Up @@ -1748,7 +1758,7 @@ void MediaPlayer::setAudioEnabled(bool on)
// toggle
audio_enabled_ = on;
// if openned
if (media_.hasaudio ) {
if ( media_.hasaudio && opened_) {
// apply
reopen();
}
Expand Down
10 changes: 9 additions & 1 deletion src/MediaPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ class MediaPlayer {
typedef enum {
LOOP_NONE = 0,
LOOP_REWIND = 1,
LOOP_BIDIRECTIONAL = 2
LOOP_BIDIRECTIONAL = 2,
LOOP_BLACKOUT = 3
} LoopMode;
/**
* Get the current loop mode
Expand All @@ -161,6 +162,12 @@ class MediaPlayer {
* Set the loop mode
* */
void setLoop(LoopMode mode);

typedef enum { LOOP_STATUS_DEFAULT = 0,
LOOP_STATUS_STOPPED = 1,
LOOP_STATUS_BLACKOUT = 2
} LoopStatus;
LoopStatus loopStatus() const { return loop_status_; }
/**
* Step when paused
* (aka next frame)
Expand Down Expand Up @@ -320,6 +327,7 @@ class MediaPlayer {
// GST & Play status
GstClockTime position_;
LoopMode loop_;
LoopStatus loop_status_;
GstState desired_state_;
GstElement *pipeline_;
GstBus *bus_;
Expand Down
11 changes: 10 additions & 1 deletion src/MediaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ void MediaSource::setPath(const std::string &p)

// open gstreamer
mediaplayer_->open(path_);
mediaplayer_->play(true);

// will be ready after init and one frame rendered
ready_ = false;
Expand Down Expand Up @@ -243,3 +242,13 @@ void MediaSource::accept(Visitor& v)
Source::accept(v);
v.visit(*this);
}

bool MediaSource::texturePostProcessed() const
{
if (Source::texturePostProcessed())
return true;

return !mediaplayer_->timeline()->fadingIsClear() ||
mediaplayer_->loopStatus() == MediaPlayer::LOOP_STATUS_BLACKOUT;
}

1 change: 1 addition & 0 deletions src/MediaSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class MediaSource : public Source
uint texture() const override;
void accept (Visitor& v) override;
void updateAudio() override;
bool texturePostProcessed () const override;

// Media specific interface
void setPath(const std::string &p);
Expand Down
1 change: 1 addition & 0 deletions src/Mixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ Source * Mixer::createSourceFile(const std::string &path, bool disable_hw_decodi
MediaSource *ms = new MediaSource;
ms->mediaplayer()->setSoftwareDecodingForced(disable_hw_decoding);
ms->setPath(path);
ms->play(true);
s = ms;
}
// propose a new name based on uri
Expand Down
4 changes: 2 additions & 2 deletions src/SessionCreator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,7 @@ void SessionLoader::visit (Source& s)
s.call( new Lock(l) );
bool p = true;
sourceNode->QueryBoolAttribute("play", &p);
s.call( new Play(p) );
s.call( new Play(p, session_) );

xmlCurrent_ = sourceNode->FirstChildElement("Mixing");
if (xmlCurrent_) s.groupNode(View::MIXING)->accept(*this);
Expand Down Expand Up @@ -1150,7 +1150,7 @@ void SessionLoader::visit (MediaSource& s)
s.mediaplayer()->accept(*this);

// add a callback to activate play speed
s.call( new PlaySpeed( s.mediaplayer()->playSpeed(), 300 ) );
s.call( new PlaySpeed( s.mediaplayer()->playSpeed() ) );
}

void SessionLoader::visit (SessionFileSource& s)
Expand Down
5 changes: 5 additions & 0 deletions src/SessionVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,11 @@ void SessionVisitor::visit(MediaPlayer &n)

if (!n.singleFrame()) {
newelement->SetAttribute("loop", (int) n.loop());
// special case; if media player stopped by loop (not by user)
// then override the play status of the Source to play the video
if (n.loopStatus() != MediaPlayer::LOOP_STATUS_DEFAULT)
xmlCurrent_->SetAttribute("play", true );

newelement->SetAttribute("speed", n.playSpeed());
newelement->SetAttribute("video_effect", n.videoEffect().c_str());
newelement->SetAttribute("software_decoding", n.softwareDecodingForced());
Expand Down
7 changes: 5 additions & 2 deletions src/Source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ bool Source::textureMirrored ()
return texturesurface_->mirrorTexture();
}

bool Source::imageProcessingEnabled()
bool Source::imageProcessingEnabled() const
{
return ( renderingshader_ == processingshader_ );
}
Expand Down Expand Up @@ -733,8 +733,11 @@ bool Source::visible() const
}


bool Source::textureTransformed () const
bool Source::texturePostProcessed () const
{
if (imageProcessingEnabled())
return true;

return frame()->projectionArea() != glm::vec4(-1.f, 1.f, 1.f, -1.f) || // cropped
group(View::TEXTURE)->rotation_.z != 0.f || // rotation
group(View::TEXTURE)->scale_ != glm::vec3(1.f) || // scaled
Expand Down
4 changes: 2 additions & 2 deletions src/Source.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class Source : public SourceCore
// the image processing shader can be enabled or disabled
// (NB: when disabled, a simple ImageShader is applied)
void setImageProcessingEnabled (bool on);
bool imageProcessingEnabled ();
bool imageProcessingEnabled () const;

// a Source has a shader to control mixing effects
inline ImageShader *blendingShader () const { return blendingshader_; }
Expand Down Expand Up @@ -223,7 +223,7 @@ class Source : public SourceCore
float depth () const;
float alpha () const;
bool visible() const;
bool textureTransformed () const;
virtual bool texturePostProcessed () const;

// groups for mixing
MixingGroup *mixingGroup() const { return mixinggroup_; }
Expand Down
12 changes: 7 additions & 5 deletions src/SourceCallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ void ValueSourceCallback::update(Source *s, float dt)
}

// update when active
if ( status_ == ACTIVE ) {
if ( status_ == ACTIVE && s->ready() ) {

// time passed since start
float progress = elapsed_ - delay_;
Expand Down Expand Up @@ -494,7 +494,8 @@ void SetDepth::accept(Visitor& v)
v.visit(*this);
}

Play::Play(bool on, bool revert) : SourceCallback(), play_(on), bidirectional_(revert)
Play::Play(bool on, Session *parentsession, bool revert) : SourceCallback(),
session_(parentsession), play_(on), bidirectional_(revert)
{
}

Expand All @@ -503,7 +504,8 @@ void Play::update(Source *s, float dt)
SourceCallback::update(s, dt);

// toggle play status when ready
if ( status_ == READY ){
if ( status_ == READY && s->ready() &&
(session_ ? session_->ready() : true) ){

if (s->playing() != play_)
// call play function
Expand All @@ -516,7 +518,7 @@ void Play::update(Source *s, float dt)

SourceCallback *Play::clone() const
{
return new Play(play_, bidirectional_);
return new Play(play_, session_, bidirectional_);
}

SourceCallback *Play::reverse(Source *s) const
Expand Down Expand Up @@ -574,7 +576,7 @@ void PlaySpeed::writeValue(Source *s, float val)
{
// access media player if target source is a media source
MediaSource *ms = dynamic_cast<MediaSource *>(s);
if (ms != nullptr && ms->ready()) {
if (ms != nullptr) {
ms->mediaplayer()->setPlaySpeed((double) val);
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/SourceCallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,12 @@ class SetDepth : public SourceCallback

class Play : public SourceCallback
{
class Session *session_;
bool play_;
bool bidirectional_;

public:
Play (bool on = true, bool revert = false);
Play (bool on = true, Session *parentsession = nullptr, bool revert = false);

bool value () const { return play_;}
void setValue (bool on) { play_ = on; }
Expand Down
Loading

0 comments on commit ba75777

Please sign in to comment.