Cleanup of Media Player class

This commit is contained in:
brunoherbelin
2020-08-06 23:17:22 +02:00
parent 2863a1f3c9
commit 3f568f714a
2 changed files with 110 additions and 184 deletions

View File

@@ -1,24 +1,19 @@
#include "MediaPlayer.h"
#include <algorithm>
#include <thread> #include <thread>
using namespace std; using namespace std;
// Desktop OpenGL function loader
#include <glad/glad.h>
// vmix // vmix
#include "defines.h" #include "defines.h"
#include "Log.h" #include "Log.h"
#include "RenderingManager.h"
#include "Resource.h" #include "Resource.h"
#include "Visitor.h" #include "Visitor.h"
#include "UserInterfaceManager.h"
#include "SystemToolkit.h" #include "SystemToolkit.h"
#include "GstToolkit.h"
// Desktop OpenGL function loader #include "MediaPlayer.h"
#include <glad/glad.h>
// GStreamer
#include <gst/pbutils/gstdiscoverer.h>
#ifndef NDEBUG #ifndef NDEBUG
#define MEDIA_PLAYER_DEBUG #define MEDIA_PLAYER_DEBUG
@@ -52,7 +47,6 @@ MediaPlayer::MediaPlayer(string name) : id_(name)
frame_duration_ = GST_CLOCK_TIME_NONE; frame_duration_ = GST_CLOCK_TIME_NONE;
desired_state_ = GST_STATE_PAUSED; desired_state_ = GST_STATE_PAUSED;
loop_ = LoopMode::LOOP_REWIND; loop_ = LoopMode::LOOP_REWIND;
current_segment_ = segments_.begin();
// start index in frame_ stack // start index in frame_ stack
write_index_ = 0; write_index_ = 0;
@@ -210,6 +204,9 @@ void MediaPlayer::execute_open()
return; return;
} }
// create & init segment array
// all good // all good
Log::Info("MediaPlayer %s Open %s (%s %d x %d)", id_.c_str(), uri_.c_str(), codec_name_.c_str(), width_, height_); Log::Info("MediaPlayer %s Open %s (%s %d x %d)", id_.c_str(), uri_.c_str(), codec_name_.c_str(), width_, height_);
ready_ = true; ready_ = true;
@@ -436,7 +433,7 @@ void MediaPlayer::rewind()
} }
void MediaPlayer::seekNextFrame() void MediaPlayer::step()
{ {
// useful only when Paused // useful only when Paused
if (!enabled_ || isPlaying()) 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)); 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_) if (!enabled_ || !seekable_)
return; return;
@@ -460,54 +457,14 @@ void MediaPlayer::seekTo(GstClockTime pos)
} }
void MediaPlayer::fastForward() void MediaPlayer::jump()
{ {
if (!enabled_ || !seekable_) if (!enabled_ || !isPlaying())
return; return;
gst_element_send_event (pipeline_, gst_event_new_step (GST_FORMAT_BUFFERS, 1, 30.f * ABS(rate_), TRUE, FALSE)); 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) void MediaPlayer::init_texture(guint index)
{ {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
@@ -695,6 +652,12 @@ void MediaPlayer::update()
execute_loop_command(); 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(); reset();
} }
void TimeCounter::tic () void MediaPlayer::TimeCounter::tic ()
{ {
// how long since last time // how long since last time
GstClockTime t = gst_util_get_timestamp (); 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 t = gst_util_get_timestamp ();
GstClockTime dt = t - tic_time; GstClockTime dt = t - tic_time;
@@ -1093,7 +1056,7 @@ GstClockTime TimeCounter::dt ()
return dt; return dt;
} }
void TimeCounter::reset () void MediaPlayer::TimeCounter::reset ()
{ {
last_time = gst_util_get_timestamp ();; last_time = gst_util_get_timestamp ();;
tic_time = last_time; tic_time = last_time;
@@ -1101,7 +1064,7 @@ void TimeCounter::reset ()
fps = 0.0; fps = 0.0;
} }
double TimeCounter::frameRate() const double MediaPlayer::TimeCounter::frameRate() const
{ {
return fps; return fps;
} }

View File

@@ -2,14 +2,14 @@
#define __GST_MEDIA_PLAYER_H_ #define __GST_MEDIA_PLAYER_H_
#include <string> #include <string>
#include <sstream>
#include <set>
#include <list>
#include <mutex> #include <mutex>
// GStreamer
#include <gst/pbutils/gstdiscoverer.h>
#include <gst/pbutils/pbutils.h> #include <gst/pbutils/pbutils.h>
#include <gst/app/gstappsink.h> #include <gst/app/gstappsink.h>
#include "Timeline.h"
// Forward declare classes referenced // Forward declare classes referenced
class Visitor; class Visitor;
@@ -18,81 +18,13 @@ class Visitor;
#define MIN_PLAY_SPEED 0.1 #define MIN_PLAY_SPEED 0.1
#define N_VFRAME 3 #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 { class MediaPlayer {
public: public:
/** /**
* Constructor of a GStreamer Media * Constructor of a GStreamer Media Player
*/ */
MediaPlayer( std::string name = std::string() ); MediaPlayer( std::string name = std::string() );
/** /**
@@ -103,6 +35,14 @@ public:
* Open a media using gstreamer URI * Open a media using gstreamer URI
* */ * */
void open( std::string path); 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 * True if a media was oppenned
* */ * */
@@ -120,19 +60,24 @@ public:
* Must be called in update loop * Must be called in update loop
* */ * */
void update(); void update();
void update_old(); /**
* Enable / Disable
* Suspend playing activity
* (restores playing state when re-enabled)
* */
void enable(bool on); void enable(bool on);
/**
* True if enabled
* */
bool isEnabled() const; bool isEnabled() const;
/** /**
* Pause / Play * Pause / Play
* Can play backward if play speed is negative * Can play backward if play speed is negative
* */ * */
void play(bool on); 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; bool isPlaying(bool testpipeline = false) const;
/** /**
@@ -146,36 +91,42 @@ public:
* */ * */
void setPlaySpeed(double s); void setPlaySpeed(double s);
/** /**
* True if the player will loop when at begin or end * Loop Mode: Behavior when reaching an extremity
* */ * */
typedef enum { typedef enum {
LOOP_NONE = 0, LOOP_NONE = 0,
LOOP_REWIND = 1, LOOP_REWIND = 1,
LOOP_BIDIRECTIONAL = 2 LOOP_BIDIRECTIONAL = 2
} LoopMode; } LoopMode;
/**
* Get the current loop mode
* */
LoopMode loop() const; LoopMode loop() const;
/** /**
* Set the player to loop * Set the loop mode
* */ * */
void setLoop(LoopMode mode); void setLoop(LoopMode mode);
/**
* Restart from zero
* */
void rewind();
/** /**
* Seek to next frame when paused * Seek to next frame when paused
* (aka next frame)
* Can go backward if play speed is negative * 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 * Seek to any position in media
* pos in nanoseconds. * pos in nanoseconds.
* */ * */
void seekTo(GstClockTime pos); void seek(GstClockTime pos);
/**
* Jump by 10% of the duration
* */
void fastForward();
/** /**
* Get position time * Get position time
* */ * */
@@ -192,38 +143,39 @@ public:
* Get framerate of the media * Get framerate of the media
* */ * */
double frameRate() const; double frameRate() const;
/**
* Get name of Codec of the media
* */
std::string codec() const;
/** /**
* Get rendering update framerate * Get rendering update framerate
* measured during play * measured during play
* */ * */
double updateFrameRate() const; 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 * Get the OpenGL texture
* Must be called in OpenGL context * Must be called in OpenGL context
* */ * */
guint texture() const; 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 * Accept visitors
* Used for saving session file
* */ * */
void accept(Visitor& v); void accept(Visitor& v);
/** /**
* @brief registered * @brief registered
* @return list of media players currently registered * @return list of media players currently registered
@@ -234,12 +186,7 @@ public:
private: private:
bool addPlaySegment(GstClockTime begin, GstClockTime end); // video player description
bool addPlaySegment(MediaSegment s);
bool removePlaySegmentAt(GstClockTime t);
bool removeAllPlaySegmentOverlap(MediaSegment s);
std::list< std::pair<guint64, guint64> > getPlaySegments() const;
std::string id_; std::string id_;
std::string filename_; std::string filename_;
std::string uri_; std::string uri_;
@@ -254,7 +201,6 @@ private:
GstClockTime frame_duration_; GstClockTime frame_duration_;
gdouble rate_; gdouble rate_;
LoopMode loop_; LoopMode loop_;
TimeCounter timecount_;
gdouble framerate_; gdouble framerate_;
GstState desired_state_; GstState desired_state_;
GstElement *pipeline_; GstElement *pipeline_;
@@ -263,6 +209,30 @@ private:
std::string codec_name_; std::string codec_name_;
GstVideoInfo v_frame_video_info_; 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 // frame stack
typedef enum { typedef enum {
EMPTY = 0, EMPTY = 0,
@@ -293,16 +263,7 @@ private:
guint pbo_index_, pbo_next_index_; guint pbo_index_, pbo_next_index_;
guint pbo_size_; guint pbo_size_;
MediaSegmentSet segments_; // gst pipeline control
MediaSegmentSet::iterator current_segment_;
bool ready_;
bool failed_;
bool seekable_;
bool isimage_;
bool interlaced_;
bool enabled_;
void execute_open(); void execute_open();
void execute_loop_command(); void execute_loop_command();
void execute_seek_command(GstClockTime target = GST_CLOCK_TIME_NONE); void execute_seek_command(GstClockTime target = GST_CLOCK_TIME_NONE);
@@ -311,13 +272,15 @@ private:
void init_texture(guint index); void init_texture(guint index);
void fill_texture(guint index); void fill_texture(guint index);
bool fill_frame(GstBuffer *buf, FrameStatus status); bool fill_frame(GstBuffer *buf, FrameStatus status);
// gst callbacks
static void callback_end_of_stream (GstAppSink *, gpointer); static void callback_end_of_stream (GstAppSink *, gpointer);
static GstFlowReturn callback_new_preroll (GstAppSink *, gpointer ); static GstFlowReturn callback_new_preroll (GstAppSink *, gpointer );
static GstFlowReturn callback_new_sample (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_process (GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, MediaPlayer *m);
static void callback_discoverer_finished(GstDiscoverer *discoverer, MediaPlayer *m); static void callback_discoverer_finished(GstDiscoverer *discoverer, MediaPlayer *m);
// global list of registered media player
static std::list<MediaPlayer*> registered_; static std::list<MediaPlayer*> registered_;
}; };