mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-13 19:29:58 +01:00
Cleanup of Media Player class
This commit is contained in:
@@ -1,24 +1,19 @@
|
||||
#include "MediaPlayer.h"
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Desktop OpenGL function loader
|
||||
#include <glad/glad.h>
|
||||
|
||||
|
||||
// vmix
|
||||
#include "defines.h"
|
||||
#include "Log.h"
|
||||
#include "RenderingManager.h"
|
||||
#include "Resource.h"
|
||||
#include "Visitor.h"
|
||||
#include "UserInterfaceManager.h"
|
||||
#include "SystemToolkit.h"
|
||||
#include "GstToolkit.h"
|
||||
|
||||
// Desktop OpenGL function loader
|
||||
#include <glad/glad.h>
|
||||
|
||||
// GStreamer
|
||||
#include <gst/pbutils/gstdiscoverer.h>
|
||||
#include "MediaPlayer.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define MEDIA_PLAYER_DEBUG
|
||||
@@ -52,7 +47,6 @@ MediaPlayer::MediaPlayer(string name) : id_(name)
|
||||
frame_duration_ = GST_CLOCK_TIME_NONE;
|
||||
desired_state_ = GST_STATE_PAUSED;
|
||||
loop_ = LoopMode::LOOP_REWIND;
|
||||
current_segment_ = segments_.begin();
|
||||
|
||||
// start index in frame_ stack
|
||||
write_index_ = 0;
|
||||
@@ -210,6 +204,9 @@ void MediaPlayer::execute_open()
|
||||
return;
|
||||
}
|
||||
|
||||
// create & init segment array
|
||||
|
||||
|
||||
// all good
|
||||
Log::Info("MediaPlayer %s Open %s (%s %d x %d)", id_.c_str(), uri_.c_str(), codec_name_.c_str(), width_, height_);
|
||||
ready_ = true;
|
||||
@@ -436,7 +433,7 @@ void MediaPlayer::rewind()
|
||||
}
|
||||
|
||||
|
||||
void MediaPlayer::seekNextFrame()
|
||||
void MediaPlayer::step()
|
||||
{
|
||||
// useful only when Paused
|
||||
if (!enabled_ || isPlaying())
|
||||
@@ -449,7 +446,7 @@ void MediaPlayer::seekNextFrame()
|
||||
gst_element_send_event (pipeline_, gst_event_new_step (GST_FORMAT_BUFFERS, 1, ABS(rate_), TRUE, FALSE));
|
||||
}
|
||||
|
||||
void MediaPlayer::seekTo(GstClockTime pos)
|
||||
void MediaPlayer::seek(GstClockTime pos)
|
||||
{
|
||||
if (!enabled_ || !seekable_)
|
||||
return;
|
||||
@@ -460,54 +457,14 @@ void MediaPlayer::seekTo(GstClockTime pos)
|
||||
|
||||
}
|
||||
|
||||
void MediaPlayer::fastForward()
|
||||
void MediaPlayer::jump()
|
||||
{
|
||||
if (!enabled_ || !seekable_)
|
||||
if (!enabled_ || !isPlaying())
|
||||
return;
|
||||
|
||||
gst_element_send_event (pipeline_, gst_event_new_step (GST_FORMAT_BUFFERS, 1, 30.f * ABS(rate_), TRUE, FALSE));
|
||||
}
|
||||
|
||||
bool MediaPlayer::addPlaySegment(GstClockTime begin, GstClockTime end)
|
||||
{
|
||||
return addPlaySegment( MediaSegment(begin, end) );
|
||||
}
|
||||
|
||||
bool MediaPlayer::addPlaySegment(MediaSegment s)
|
||||
{
|
||||
if ( s.is_valid() )
|
||||
return segments_.insert(s).second;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MediaPlayer::removeAllPlaySegmentOverlap(MediaSegment s)
|
||||
{
|
||||
bool ret = removePlaySegmentAt(s.begin);
|
||||
return removePlaySegmentAt(s.end) || ret;
|
||||
}
|
||||
|
||||
bool MediaPlayer::removePlaySegmentAt(GstClockTime t)
|
||||
{
|
||||
MediaSegmentSet::const_iterator s = std::find_if(segments_.begin(), segments_.end(), containsTime(t));
|
||||
|
||||
if ( s != segments_.end() ) {
|
||||
segments_.erase(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::list< std::pair<guint64, guint64> > MediaPlayer::getPlaySegments() const
|
||||
{
|
||||
std::list< std::pair<guint64, guint64> > ret;
|
||||
for (MediaSegmentSet::iterator it = segments_.begin(); it != segments_.end(); it++)
|
||||
ret.push_back( std::make_pair( it->begin, it->end ) );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MediaPlayer::init_texture(guint index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
@@ -695,6 +652,12 @@ void MediaPlayer::update()
|
||||
execute_loop_command();
|
||||
}
|
||||
|
||||
// manage timeline
|
||||
// if (position_!=GST_CLOCK_TIME_NONE) {
|
||||
|
||||
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1055,12 +1018,12 @@ void MediaPlayer::callback_discoverer_finished(GstDiscoverer *discoverer, MediaP
|
||||
}
|
||||
}
|
||||
|
||||
TimeCounter::TimeCounter() {
|
||||
MediaPlayer::TimeCounter::TimeCounter() {
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void TimeCounter::tic ()
|
||||
void MediaPlayer::TimeCounter::tic ()
|
||||
{
|
||||
// how long since last time
|
||||
GstClockTime t = gst_util_get_timestamp ();
|
||||
@@ -1083,7 +1046,7 @@ void TimeCounter::tic ()
|
||||
}
|
||||
}
|
||||
|
||||
GstClockTime TimeCounter::dt ()
|
||||
GstClockTime MediaPlayer::TimeCounter::dt ()
|
||||
{
|
||||
GstClockTime t = gst_util_get_timestamp ();
|
||||
GstClockTime dt = t - tic_time;
|
||||
@@ -1093,7 +1056,7 @@ GstClockTime TimeCounter::dt ()
|
||||
return dt;
|
||||
}
|
||||
|
||||
void TimeCounter::reset ()
|
||||
void MediaPlayer::TimeCounter::reset ()
|
||||
{
|
||||
last_time = gst_util_get_timestamp ();;
|
||||
tic_time = last_time;
|
||||
@@ -1101,7 +1064,7 @@ void TimeCounter::reset ()
|
||||
fps = 0.0;
|
||||
}
|
||||
|
||||
double TimeCounter::frameRate() const
|
||||
double MediaPlayer::TimeCounter::frameRate() const
|
||||
{
|
||||
return fps;
|
||||
}
|
||||
|
||||
211
MediaPlayer.h
211
MediaPlayer.h
@@ -2,14 +2,14 @@
|
||||
#define __GST_MEDIA_PLAYER_H_
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
// GStreamer
|
||||
#include <gst/pbutils/gstdiscoverer.h>
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/app/gstappsink.h>
|
||||
|
||||
#include "Timeline.h"
|
||||
|
||||
// Forward declare classes referenced
|
||||
class Visitor;
|
||||
@@ -18,81 +18,13 @@ class Visitor;
|
||||
#define MIN_PLAY_SPEED 0.1
|
||||
#define N_VFRAME 3
|
||||
|
||||
struct TimeCounter {
|
||||
|
||||
GstClockTime last_time;
|
||||
GstClockTime tic_time;
|
||||
int nbFrames;
|
||||
gdouble fps;
|
||||
public:
|
||||
TimeCounter();
|
||||
GstClockTime dt();
|
||||
void tic();
|
||||
void reset();
|
||||
gdouble frameRate() const;
|
||||
};
|
||||
|
||||
struct MediaSegment
|
||||
{
|
||||
GstClockTime begin;
|
||||
GstClockTime end;
|
||||
|
||||
MediaSegment()
|
||||
{
|
||||
begin = GST_CLOCK_TIME_NONE;
|
||||
end = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
MediaSegment(GstClockTime b, GstClockTime e)
|
||||
{
|
||||
if ( b < e ) {
|
||||
begin = b;
|
||||
end = e;
|
||||
} else {
|
||||
begin = GST_CLOCK_TIME_NONE;
|
||||
end = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
}
|
||||
inline bool is_valid() const
|
||||
{
|
||||
return begin != GST_CLOCK_TIME_NONE && end != GST_CLOCK_TIME_NONE && begin < end;
|
||||
}
|
||||
inline bool operator < (const MediaSegment b) const
|
||||
{
|
||||
return (this->is_valid() && b.is_valid() && this->end < b.begin);
|
||||
}
|
||||
inline bool operator == (const MediaSegment b) const
|
||||
{
|
||||
return (this->begin == b.begin && this->end == b.end);
|
||||
}
|
||||
inline bool operator != (const MediaSegment b) const
|
||||
{
|
||||
return (this->begin != b.begin || this->end != b.end);
|
||||
}
|
||||
};
|
||||
|
||||
struct containsTime: public std::unary_function<MediaSegment, bool>
|
||||
{
|
||||
inline bool operator()(const MediaSegment s) const
|
||||
{
|
||||
return ( s.is_valid() && _t > s.begin && _t < s.end );
|
||||
}
|
||||
|
||||
containsTime(GstClockTime t) : _t(t) { }
|
||||
|
||||
private:
|
||||
GstClockTime _t;
|
||||
};
|
||||
|
||||
|
||||
typedef std::set<MediaSegment> MediaSegmentSet;
|
||||
|
||||
class MediaPlayer {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor of a GStreamer Media
|
||||
* Constructor of a GStreamer Media Player
|
||||
*/
|
||||
MediaPlayer( std::string name = std::string() );
|
||||
/**
|
||||
@@ -103,6 +35,14 @@ public:
|
||||
* Open a media using gstreamer URI
|
||||
* */
|
||||
void open( std::string path);
|
||||
/**
|
||||
* Get name of the media
|
||||
* */
|
||||
std::string uri() const;
|
||||
/**
|
||||
* Get name of the file
|
||||
* */
|
||||
std::string filename() const;
|
||||
/**
|
||||
* True if a media was oppenned
|
||||
* */
|
||||
@@ -120,19 +60,24 @@ public:
|
||||
* Must be called in update loop
|
||||
* */
|
||||
void update();
|
||||
void update_old();
|
||||
|
||||
/**
|
||||
* Enable / Disable
|
||||
* Suspend playing activity
|
||||
* (restores playing state when re-enabled)
|
||||
* */
|
||||
void enable(bool on);
|
||||
|
||||
/**
|
||||
* True if enabled
|
||||
* */
|
||||
bool isEnabled() const;
|
||||
|
||||
/**
|
||||
* Pause / Play
|
||||
* Can play backward if play speed is negative
|
||||
* */
|
||||
void play(bool on);
|
||||
/**
|
||||
* Get Pause / Play
|
||||
* Get Pause / Play status
|
||||
* Performs a full check of the Gstreamer pipeline if testpipeline is true
|
||||
* */
|
||||
bool isPlaying(bool testpipeline = false) const;
|
||||
/**
|
||||
@@ -146,36 +91,42 @@ public:
|
||||
* */
|
||||
void setPlaySpeed(double s);
|
||||
/**
|
||||
* True if the player will loop when at begin or end
|
||||
* Loop Mode: Behavior when reaching an extremity
|
||||
* */
|
||||
typedef enum {
|
||||
LOOP_NONE = 0,
|
||||
LOOP_REWIND = 1,
|
||||
LOOP_BIDIRECTIONAL = 2
|
||||
} LoopMode;
|
||||
/**
|
||||
* Get the current loop mode
|
||||
* */
|
||||
LoopMode loop() const;
|
||||
/**
|
||||
* Set the player to loop
|
||||
* Set the loop mode
|
||||
* */
|
||||
void setLoop(LoopMode mode);
|
||||
/**
|
||||
* Restart from zero
|
||||
* */
|
||||
void rewind();
|
||||
/**
|
||||
* Seek to next frame when paused
|
||||
* (aka next frame)
|
||||
* Can go backward if play speed is negative
|
||||
* */
|
||||
void seekNextFrame();
|
||||
void step();
|
||||
/**
|
||||
* Jump fast when playing
|
||||
* (aka fast-forward)
|
||||
* Can go backward if play speed is negative
|
||||
* */
|
||||
void jump();
|
||||
/**
|
||||
* Seek to zero
|
||||
* */
|
||||
void rewind();
|
||||
/**
|
||||
* Seek to any position in media
|
||||
* pos in nanoseconds.
|
||||
* */
|
||||
void seekTo(GstClockTime pos);
|
||||
/**
|
||||
* Jump by 10% of the duration
|
||||
* */
|
||||
void fastForward();
|
||||
void seek(GstClockTime pos);
|
||||
/**
|
||||
* Get position time
|
||||
* */
|
||||
@@ -192,38 +143,39 @@ public:
|
||||
* Get framerate of the media
|
||||
* */
|
||||
double frameRate() const;
|
||||
/**
|
||||
* Get name of Codec of the media
|
||||
* */
|
||||
std::string codec() const;
|
||||
/**
|
||||
* Get rendering update framerate
|
||||
* measured during play
|
||||
* */
|
||||
double updateFrameRate() const;
|
||||
/**
|
||||
* Get name of Codec of the media
|
||||
* */
|
||||
std::string codec() const;
|
||||
/**
|
||||
* Get frame width
|
||||
* */
|
||||
guint width() const;
|
||||
/**
|
||||
* Get frame height
|
||||
* */
|
||||
guint height() const;
|
||||
/**
|
||||
* Get frames displayt aspect ratio
|
||||
* NB: can be different than width() / height()
|
||||
* */
|
||||
float aspectRatio() const;
|
||||
/**
|
||||
* Get the OpenGL texture
|
||||
* Must be called in OpenGL context
|
||||
* */
|
||||
guint texture() const;
|
||||
/**
|
||||
* Get Image properties
|
||||
* */
|
||||
guint width() const;
|
||||
guint height() const;
|
||||
float aspectRatio() const;
|
||||
|
||||
/**
|
||||
* Get name of the media
|
||||
* */
|
||||
std::string uri() const;
|
||||
std::string filename() const;
|
||||
|
||||
/**
|
||||
* Accept visitors
|
||||
* Used for saving session file
|
||||
* */
|
||||
void accept(Visitor& v);
|
||||
|
||||
/**
|
||||
* @brief registered
|
||||
* @return list of media players currently registered
|
||||
@@ -234,12 +186,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
bool addPlaySegment(GstClockTime begin, GstClockTime end);
|
||||
bool addPlaySegment(MediaSegment s);
|
||||
bool removePlaySegmentAt(GstClockTime t);
|
||||
bool removeAllPlaySegmentOverlap(MediaSegment s);
|
||||
std::list< std::pair<guint64, guint64> > getPlaySegments() const;
|
||||
|
||||
// video player description
|
||||
std::string id_;
|
||||
std::string filename_;
|
||||
std::string uri_;
|
||||
@@ -254,7 +201,6 @@ private:
|
||||
GstClockTime frame_duration_;
|
||||
gdouble rate_;
|
||||
LoopMode loop_;
|
||||
TimeCounter timecount_;
|
||||
gdouble framerate_;
|
||||
GstState desired_state_;
|
||||
GstElement *pipeline_;
|
||||
@@ -263,6 +209,30 @@ private:
|
||||
std::string codec_name_;
|
||||
GstVideoInfo v_frame_video_info_;
|
||||
|
||||
// status
|
||||
bool ready_;
|
||||
bool failed_;
|
||||
bool seekable_;
|
||||
bool isimage_;
|
||||
bool interlaced_;
|
||||
bool enabled_;
|
||||
|
||||
// fps counter
|
||||
struct TimeCounter {
|
||||
|
||||
GstClockTime last_time;
|
||||
GstClockTime tic_time;
|
||||
int nbFrames;
|
||||
gdouble fps;
|
||||
public:
|
||||
TimeCounter();
|
||||
GstClockTime dt();
|
||||
void tic();
|
||||
void reset();
|
||||
gdouble frameRate() const;
|
||||
};
|
||||
TimeCounter timecount_;
|
||||
|
||||
// frame stack
|
||||
typedef enum {
|
||||
EMPTY = 0,
|
||||
@@ -293,16 +263,7 @@ private:
|
||||
guint pbo_index_, pbo_next_index_;
|
||||
guint pbo_size_;
|
||||
|
||||
MediaSegmentSet segments_;
|
||||
MediaSegmentSet::iterator current_segment_;
|
||||
|
||||
bool ready_;
|
||||
bool failed_;
|
||||
bool seekable_;
|
||||
bool isimage_;
|
||||
bool interlaced_;
|
||||
bool enabled_;
|
||||
|
||||
// gst pipeline control
|
||||
void execute_open();
|
||||
void execute_loop_command();
|
||||
void execute_seek_command(GstClockTime target = GST_CLOCK_TIME_NONE);
|
||||
@@ -311,13 +272,15 @@ private:
|
||||
void init_texture(guint index);
|
||||
void fill_texture(guint index);
|
||||
bool fill_frame(GstBuffer *buf, FrameStatus status);
|
||||
|
||||
// gst callbacks
|
||||
static void callback_end_of_stream (GstAppSink *, gpointer);
|
||||
static GstFlowReturn callback_new_preroll (GstAppSink *, gpointer );
|
||||
static GstFlowReturn callback_new_sample (GstAppSink *, gpointer);
|
||||
|
||||
static void callback_discoverer_process (GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, MediaPlayer *m);
|
||||
static void callback_discoverer_finished(GstDiscoverer *discoverer, MediaPlayer *m);
|
||||
|
||||
// global list of registered media player
|
||||
static std::list<MediaPlayer*> registered_;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user