Files
vimix/MediaPlayer.h

308 lines
7.0 KiB
C++

#ifndef __GST_MEDIA_PLAYER_H_
#define __GST_MEDIA_PLAYER_H_
#include <string>
#include <atomic>
#include <sstream>
#include <set>
#include <list>
#include <map>
#include <utility>
#include <mutex>
#include <gst/gst.h>
#include <gst/gl/gl.h>
#include <gst/pbutils/pbutils.h>
// Forward declare classes referenced
class Visitor;
#define MAX_PLAY_SPEED 20.0
#define MIN_PLAY_SPEED 0.1
#define N_VFRAME 3
struct TimeCounter {
GstClockTime last_time;
GstClockTime tic_time;
int nbFrames;
float fps;
public:
TimeCounter();
GstClockTime dt();
void tic();
void reset();
float 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
*/
MediaPlayer( std::string name = std::string() );
/**
* Destructor.
*/
~MediaPlayer();
/**
* Open a media using gstreamer URI
* */
void open( std::string path);
/**
* True if a media was oppenned
* */
bool isOpen() const;
/**
* True if problem occured
* */
bool failed() const;
/**
* Close the Media
* */
void close();
/**
* Update status
* Must be called in update loop
* */
void update();
void enable(bool on);
bool isEnabled() const;
/**
* Pause / Play
* Can play backward if play speed is negative
* */
void play(bool on);
/**
* Get Pause / Play
* */
bool isPlaying(bool testpipeline = false) const;
/**
* Speed factor for playing
* Can be negative.
* */
double playSpeed() const;
/**
* Set the speed factor for playing
* Can be negative.
* */
void setPlaySpeed(double s);
/**
* True if the player will loop when at begin or end
* */
typedef enum {
LOOP_NONE = 0,
LOOP_REWIND = 1,
LOOP_BIDIRECTIONAL = 2
} LoopMode;
LoopMode loop() const;
/**
* Set the player to loop
* */
void setLoop(LoopMode mode);
/**
* Restart from zero
* */
void rewind();
/**
* Seek to next frame when paused
* Can go backward if play speed is negative
* */
void seekNextFrame();
/**
* Seek to any position in media
* pos in nanoseconds.
* */
void seekTo(GstClockTime pos);
/**
* Jump by 10% of the duration
* */
void fastForward();
/**
* Get position time
* */
GstClockTime position();
/**
* Get total duration time
* */
GstClockTime duration();
/**
* Get duration of one frame
* */
GstClockTime frameDuration();
/**
* 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 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
* */
void accept(Visitor& v);
/**
* @brief registered
* @return list of media players currently registered
*/
static std::list<MediaPlayer*> registered() { return registered_; }
static std::list<MediaPlayer*>::const_iterator begin() { return registered_.cbegin(); }
static std::list<MediaPlayer*>::const_iterator end() { return registered_.cend(); }
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;
std::string id_;
std::string filename_;
std::string uri_;
guint textureindex_;
guint width_;
guint height_;
guint par_width_; // width to match pixel aspect ratio
GstClockTime position_;
GstClockTime start_position_;
GstClockTime duration_;
GstClockTime frame_duration_;
bool (*TimeComparator_)(GstClockTime,GstClockTime);
gdouble rate_;
LoopMode loop_;
std::atomic<bool> need_loop_;
TimeCounter timecount_;
gdouble framerate_;
GstState desired_state_;
GstElement *pipeline_;
GstDiscoverer *discoverer_;
std::stringstream discoverer_message_;
std::string codec_name_;
GstVideoInfo v_frame_video_info_;
guint vframe_read_index_;
guint vframe_write_index_;
GstVideoFrame vframe_[N_VFRAME];
std::atomic<bool> vframe_is_full_[N_VFRAME];
GstClockTime vframe_position_[N_VFRAME];
std::mutex vframe_lock_[N_VFRAME];
// for PBO
guint pbo_[2];
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_;
void init_texture();
void execute_open();
void execute_loop_command();
void execute_seek_command(GstClockTime target = GST_CLOCK_TIME_NONE);
bool fill_v_frame(GstBuffer *buf);
static GstFlowReturn callback_pull_sample_video (GstElement *bin, MediaPlayer *m);
static void callback_end_of_video (GstElement *, 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 std::list<MediaPlayer*> registered_;
};
#endif // __GST_MEDIA_PLAYER_H_