mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
Fixed seek behavior: sync if necessary in update.
This commit is contained in:
100
MediaPlayer.cpp
100
MediaPlayer.cpp
@@ -19,6 +19,8 @@ using namespace std;
|
|||||||
#define MEDIA_PLAYER_DEBUG
|
#define MEDIA_PLAYER_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define USE_GST_APPSINK_CALLBACKS
|
||||||
|
|
||||||
std::list<MediaPlayer*> MediaPlayer::registered_;
|
std::list<MediaPlayer*> MediaPlayer::registered_;
|
||||||
|
|
||||||
MediaPlayer::MediaPlayer(string name) : id_(name)
|
MediaPlayer::MediaPlayer(string name) : id_(name)
|
||||||
@@ -33,11 +35,13 @@ MediaPlayer::MediaPlayer(string name) : id_(name)
|
|||||||
ready_ = false;
|
ready_ = false;
|
||||||
failed_ = false;
|
failed_ = false;
|
||||||
seekable_ = false;
|
seekable_ = false;
|
||||||
|
seeking_ = false;
|
||||||
isimage_ = false;
|
isimage_ = false;
|
||||||
interlaced_ = false;
|
interlaced_ = false;
|
||||||
enabled_ = true;
|
enabled_ = true;
|
||||||
rate_ = 1.0;
|
rate_ = 1.0;
|
||||||
framerate_ = 0.0;
|
framerate_ = 0.0;
|
||||||
|
bitrate_ = 0;
|
||||||
|
|
||||||
width_ = par_width_ = 640;
|
width_ = par_width_ = 640;
|
||||||
height_ = 480;
|
height_ = 480;
|
||||||
@@ -100,17 +104,21 @@ void MediaPlayer::open(string path)
|
|||||||
g_signal_connect (discoverer_, "discovered", G_CALLBACK (callback_discoverer_process), this);
|
g_signal_connect (discoverer_, "discovered", G_CALLBACK (callback_discoverer_process), this);
|
||||||
// set callback when finished discovering
|
// set callback when finished discovering
|
||||||
g_signal_connect (discoverer_, "finished", G_CALLBACK (callback_discoverer_finished), this);
|
g_signal_connect (discoverer_, "finished", G_CALLBACK (callback_discoverer_finished), this);
|
||||||
|
|
||||||
// start discoverer
|
// start discoverer
|
||||||
gst_discoverer_start(discoverer_);
|
gst_discoverer_start(discoverer_);
|
||||||
|
|
||||||
// Add the request to process asynchronously the URI
|
// Add the request to process asynchronously the URI
|
||||||
if (!gst_discoverer_discover_uri_async (discoverer_, uri_.c_str())) {
|
if (!gst_discoverer_discover_uri_async (discoverer_, uri_.c_str())) {
|
||||||
Log::Warning("MediaPlayer %s Failed to start discovering URI '%s'\n", id_.c_str(), uri_.c_str());
|
Log::Warning("MediaPlayer %s Failed to open file '%s'\n", id_.c_str(), uri_.c_str());
|
||||||
g_object_unref (discoverer_);
|
g_object_unref (discoverer_);
|
||||||
discoverer_ = nullptr;
|
discoverer_ = nullptr;
|
||||||
failed_ = true;
|
failed_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MEDIA_PLAYER_DEBUG
|
||||||
|
Log::Info("MediaPlayer %s checking '%s'", id_.c_str(), uri_.c_str());
|
||||||
|
#endif
|
||||||
// and wait for discoverer to finish...
|
// and wait for discoverer to finish...
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,30 +171,30 @@ void MediaPlayer::execute_open()
|
|||||||
gst_app_sink_set_caps (GST_APP_SINK(sink), caps);
|
gst_app_sink_set_caps (GST_APP_SINK(sink), caps);
|
||||||
|
|
||||||
// Instruct appsink to drop old buffers when the maximum amount of queued buffers is reached.
|
// Instruct appsink to drop old buffers when the maximum amount of queued buffers is reached.
|
||||||
gst_app_sink_set_max_buffers( GST_APP_SINK(sink), 100);
|
gst_app_sink_set_max_buffers( GST_APP_SINK(sink), 50);
|
||||||
gst_app_sink_set_drop (GST_APP_SINK(sink), true);
|
gst_app_sink_set_drop (GST_APP_SINK(sink), true);
|
||||||
|
|
||||||
// // set the callbacks
|
#ifdef USE_GST_APPSINK_CALLBACKS
|
||||||
// GstAppSinkCallbacks callbacks;
|
// set the callbacks
|
||||||
// callbacks.new_preroll = callback_new_preroll;
|
GstAppSinkCallbacks callbacks;
|
||||||
// if (isimage_) {
|
callbacks.new_preroll = callback_new_preroll;
|
||||||
// callbacks.eos = NULL;
|
if (isimage_) {
|
||||||
// callbacks.new_sample = NULL;
|
callbacks.eos = NULL;
|
||||||
// }
|
callbacks.new_sample = NULL;
|
||||||
// else {
|
}
|
||||||
// callbacks.eos = callback_end_of_stream;
|
else {
|
||||||
// callbacks.new_sample = callback_new_sample;
|
callbacks.eos = callback_end_of_stream;
|
||||||
// }
|
callbacks.new_sample = callback_new_sample;
|
||||||
// gst_app_sink_set_callbacks (GST_APP_SINK(sink), &callbacks, this, NULL);
|
}
|
||||||
// gst_app_sink_set_emit_signals (GST_APP_SINK(sink), false);
|
gst_app_sink_set_callbacks (GST_APP_SINK(sink), &callbacks, this, NULL);
|
||||||
|
gst_app_sink_set_emit_signals (GST_APP_SINK(sink), false);
|
||||||
// connect callbacks
|
#else
|
||||||
|
// connect signals callbacks
|
||||||
g_signal_connect(G_OBJECT(sink), "new-sample", G_CALLBACK (callback_new_sample), this);
|
g_signal_connect(G_OBJECT(sink), "new-sample", G_CALLBACK (callback_new_sample), this);
|
||||||
g_signal_connect(G_OBJECT(sink), "new-preroll", G_CALLBACK (callback_new_preroll), this);
|
g_signal_connect(G_OBJECT(sink), "new-preroll", G_CALLBACK (callback_new_preroll), this);
|
||||||
g_signal_connect(G_OBJECT(sink), "eos", G_CALLBACK (callback_end_of_stream), this);
|
g_signal_connect(G_OBJECT(sink), "eos", G_CALLBACK (callback_end_of_stream), this);
|
||||||
gst_app_sink_set_emit_signals (GST_APP_SINK(sink), true);
|
gst_app_sink_set_emit_signals (GST_APP_SINK(sink), true);
|
||||||
|
#endif
|
||||||
|
|
||||||
// done with ref to sink
|
// done with ref to sink
|
||||||
gst_object_unref (sink);
|
gst_object_unref (sink);
|
||||||
}
|
}
|
||||||
@@ -203,7 +211,7 @@ void MediaPlayer::execute_open()
|
|||||||
// set to desired state (PLAY or PAUSE)
|
// set to desired state (PLAY or PAUSE)
|
||||||
GstStateChangeReturn ret = gst_element_set_state (pipeline_, desired_state_);
|
GstStateChangeReturn ret = gst_element_set_state (pipeline_, desired_state_);
|
||||||
if (ret == GST_STATE_CHANGE_FAILURE) {
|
if (ret == GST_STATE_CHANGE_FAILURE) {
|
||||||
Log::Warning("MediaPlayer %s Could not open %s", id_.c_str(), uri_.c_str());
|
Log::Warning("MediaPlayer %s Could not open '%s'", id_.c_str(), uri_.c_str());
|
||||||
failed_ = true;
|
failed_ = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -216,10 +224,9 @@ void MediaPlayer::execute_open()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 Opened '%s' (%s %d x %d)", id_.c_str(), uri_.c_str(), codec_name_.c_str(), width_, height_);
|
||||||
ready_ = true;
|
ready_ = true;
|
||||||
|
|
||||||
|
|
||||||
// register media player
|
// register media player
|
||||||
MediaPlayer::registered_.push_back(this);
|
MediaPlayer::registered_.push_back(this);
|
||||||
}
|
}
|
||||||
@@ -324,8 +331,10 @@ void MediaPlayer::enable(bool on)
|
|||||||
|
|
||||||
enabled_ = on;
|
enabled_ = on;
|
||||||
|
|
||||||
|
// default to pause
|
||||||
GstState requested_state = GST_STATE_PAUSED;
|
GstState requested_state = GST_STATE_PAUSED;
|
||||||
|
|
||||||
|
// unpause only if enabled
|
||||||
if (enabled_) {
|
if (enabled_) {
|
||||||
requested_state = desired_state_;
|
requested_state = desired_state_;
|
||||||
}
|
}
|
||||||
@@ -353,7 +362,7 @@ bool MediaPlayer::isImage() const
|
|||||||
|
|
||||||
void MediaPlayer::play(bool on)
|
void MediaPlayer::play(bool on)
|
||||||
{
|
{
|
||||||
// cannot play an image
|
// ignore if disabled, and cannot play an image
|
||||||
if (!enabled_ || isimage_)
|
if (!enabled_ || isimage_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -443,7 +452,7 @@ void MediaPlayer::step()
|
|||||||
if (!enabled_ || isPlaying())
|
if (!enabled_ || isPlaying())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( position_ == ( rate_ < 0.0 ? timeline.start() : timeline.end() ) )
|
if ( ( rate_ < 0.0 && position_ <= timeline.start() ) || ( rate_ > 0.0 && position_ >= timeline.end() ) )
|
||||||
rewind();
|
rewind();
|
||||||
|
|
||||||
// step
|
// step
|
||||||
@@ -651,11 +660,18 @@ void MediaPlayer::update()
|
|||||||
if (isimage_)
|
if (isimage_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (seeking_) {
|
||||||
|
GstState state;
|
||||||
|
gst_element_get_state (pipeline_, &state, NULL, GST_CLOCK_TIME_NONE);
|
||||||
|
seeking_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
// manage loop mode
|
// manage loop mode
|
||||||
if (need_loop) {
|
if (need_loop) {
|
||||||
execute_loop_command();
|
execute_loop_command();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// manage timeline
|
// manage timeline
|
||||||
// TimeInterval gap;
|
// TimeInterval gap;
|
||||||
// if (position_ != GST_CLOCK_TIME_NONE && timeline.gapAt(position_, gap)) {
|
// if (position_ != GST_CLOCK_TIME_NONE && timeline.gapAt(position_, gap)) {
|
||||||
@@ -706,24 +722,6 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
|
|||||||
if ( ABS(rate_) > 1.0 )
|
if ( ABS(rate_) > 1.0 )
|
||||||
seek_flags |= GST_SEEK_FLAG_TRICKMODE;
|
seek_flags |= GST_SEEK_FLAG_TRICKMODE;
|
||||||
|
|
||||||
// bool ret = false;
|
|
||||||
|
|
||||||
// if (rate_ > 0) {
|
|
||||||
|
|
||||||
// ret = gst_element_seek (pipeline_, rate_, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
|
|
||||||
// GST_SEEK_TYPE_SET, seek_pos,
|
|
||||||
// GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
|
|
||||||
// ret = gst_element_seek (pipeline_, rate_, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
|
|
||||||
// GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE,
|
|
||||||
// GST_SEEK_TYPE_SET, seek_pos);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (!ret)
|
|
||||||
// Log::Warning("MediaPlayer %s Seek failed", gst_element_get_name(pipeline_));
|
|
||||||
|
|
||||||
// create seek event depending on direction
|
// create seek event depending on direction
|
||||||
GstEvent *seek_event = nullptr;
|
GstEvent *seek_event = nullptr;
|
||||||
if (rate_ > 0) {
|
if (rate_ > 0) {
|
||||||
@@ -739,6 +737,7 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
|
|||||||
if (seek_event && !gst_element_send_event(pipeline_, seek_event) )
|
if (seek_event && !gst_element_send_event(pipeline_, seek_event) )
|
||||||
Log::Warning("MediaPlayer %s Seek failed", id_.c_str());
|
Log::Warning("MediaPlayer %s Seek failed", id_.c_str());
|
||||||
else {
|
else {
|
||||||
|
seeking_ = true;
|
||||||
#ifdef MEDIA_PLAYER_DEBUG
|
#ifdef MEDIA_PLAYER_DEBUG
|
||||||
Log::Info("MediaPlayer %s Seek %ld %f", id_.c_str(), seek_pos, rate_);
|
Log::Info("MediaPlayer %s Seek %ld %f", id_.c_str(), seek_pos, rate_);
|
||||||
#endif
|
#endif
|
||||||
@@ -832,8 +831,10 @@ bool MediaPlayer::fill_frame(GstBuffer *buf, FrameStatus status)
|
|||||||
frame_[write_index_].position = buf->pts;
|
frame_[write_index_].position = buf->pts;
|
||||||
|
|
||||||
// set the start position (i.e. pts of first frame we got)
|
// set the start position (i.e. pts of first frame we got)
|
||||||
if (timeline.start() == GST_CLOCK_TIME_NONE)
|
if (timeline.start() == GST_CLOCK_TIME_NONE) {
|
||||||
timeline.setStart(buf->pts);
|
timeline.setStart(buf->pts);
|
||||||
|
Log::Info("Timeline %ld [%ld %ld]", timeline.numFrames(), timeline.start(), timeline.end());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// full but invalid frame : will be deleted next iteration
|
// full but invalid frame : will be deleted next iteration
|
||||||
// (should never happen)
|
// (should never happen)
|
||||||
@@ -954,7 +955,7 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
|
|||||||
m->discoverer_message_ << "Invalid URI: " << uri;
|
m->discoverer_message_ << "Invalid URI: " << uri;
|
||||||
break;
|
break;
|
||||||
case GST_DISCOVERER_ERROR:
|
case GST_DISCOVERER_ERROR:
|
||||||
m->discoverer_message_ << "Error: " << err->message;
|
m->discoverer_message_ << "Warning: " << err->message;
|
||||||
break;
|
break;
|
||||||
case GST_DISCOVERER_TIMEOUT:
|
case GST_DISCOVERER_TIMEOUT:
|
||||||
m->discoverer_message_ << "Time out";
|
m->discoverer_message_ << "Time out";
|
||||||
@@ -966,10 +967,11 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
|
|||||||
{
|
{
|
||||||
const GstStructure *s = gst_discoverer_info_get_misc (info);
|
const GstStructure *s = gst_discoverer_info_get_misc (info);
|
||||||
gchar *str = gst_structure_to_string (s);
|
gchar *str = gst_structure_to_string (s);
|
||||||
m->discoverer_message_ << "Unknown file format / " << str;
|
m->discoverer_message_ << "Warning: Unknown file format / " << str;
|
||||||
g_free (str);
|
g_free (str);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
case GST_DISCOVERER_OK:
|
case GST_DISCOVERER_OK:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -988,12 +990,12 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
|
|||||||
GstDiscovererVideoInfo* vinfo = GST_DISCOVERER_VIDEO_INFO(tmpinf);
|
GstDiscovererVideoInfo* vinfo = GST_DISCOVERER_VIDEO_INFO(tmpinf);
|
||||||
m->width_ = gst_discoverer_video_info_get_width(vinfo);
|
m->width_ = gst_discoverer_video_info_get_width(vinfo);
|
||||||
m->height_ = gst_discoverer_video_info_get_height(vinfo);
|
m->height_ = gst_discoverer_video_info_get_height(vinfo);
|
||||||
m->isimage_ = gst_discoverer_video_info_is_image(vinfo);
|
|
||||||
m->interlaced_ = gst_discoverer_video_info_is_interlaced(vinfo);
|
m->interlaced_ = gst_discoverer_video_info_is_interlaced(vinfo);
|
||||||
m->bitrate_ = gst_discoverer_video_info_get_bitrate(vinfo);
|
m->bitrate_ = gst_discoverer_video_info_get_bitrate(vinfo);
|
||||||
guint parn = gst_discoverer_video_info_get_par_num(vinfo);
|
guint parn = gst_discoverer_video_info_get_par_num(vinfo);
|
||||||
guint pard = gst_discoverer_video_info_get_par_denom(vinfo);
|
guint pard = gst_discoverer_video_info_get_par_denom(vinfo);
|
||||||
m->par_width_ = (m->width_ * parn) / pard;
|
m->par_width_ = (m->width_ * parn) / pard;
|
||||||
|
m->isimage_ = gst_discoverer_video_info_is_image(vinfo);
|
||||||
// if its a video, it duration, framerate, etc.
|
// if its a video, it duration, framerate, etc.
|
||||||
if ( !m->isimage_ ) {
|
if ( !m->isimage_ ) {
|
||||||
m->timeline.setEnd( gst_discoverer_info_get_duration (info) );
|
m->timeline.setEnd( gst_discoverer_info_get_duration (info) );
|
||||||
@@ -1028,7 +1030,7 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
|
|||||||
gst_discoverer_stream_info_list_free(streams);
|
gst_discoverer_stream_info_list_free(streams);
|
||||||
|
|
||||||
if (!foundvideostream) {
|
if (!foundvideostream) {
|
||||||
m->discoverer_message_ << "No video stream.";
|
m->discoverer_message_ << "Warning: No video stream.";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1042,7 +1044,7 @@ void MediaPlayer::callback_discoverer_finished(GstDiscoverer *discoverer, MediaP
|
|||||||
if ( m->discoverer_message_.str().empty())
|
if ( m->discoverer_message_.str().empty())
|
||||||
m->execute_open();
|
m->execute_open();
|
||||||
else {
|
else {
|
||||||
Log::Warning("MediaPlayer %s Failed to open %s\n%s", m->id_.c_str(), m->uri_.c_str(), m->discoverer_message_.str().c_str());
|
Log::Warning("MediaPlayer %s Failed to open '%s'\n%s", m->id_.c_str(), m->uri_.c_str(), m->discoverer_message_.str().c_str());
|
||||||
m->discoverer_message_.clear();
|
m->discoverer_message_.clear();
|
||||||
m->failed_ = true;
|
m->failed_ = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define __GST_MEDIA_PLAYER_H_
|
#define __GST_MEDIA_PLAYER_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
// GStreamer
|
// GStreamer
|
||||||
@@ -199,11 +200,6 @@ private:
|
|||||||
guint par_width_; // width to match pixel aspect ratio
|
guint par_width_; // width to match pixel aspect ratio
|
||||||
guint bitrate_;
|
guint bitrate_;
|
||||||
GstClockTime position_;
|
GstClockTime position_;
|
||||||
|
|
||||||
// GstClockTime start_position_;
|
|
||||||
// GstClockTime duration_;
|
|
||||||
// GstClockTime frame_duration_;
|
|
||||||
|
|
||||||
gdouble rate_;
|
gdouble rate_;
|
||||||
LoopMode loop_;
|
LoopMode loop_;
|
||||||
gdouble framerate_;
|
gdouble framerate_;
|
||||||
@@ -215,9 +211,10 @@ private:
|
|||||||
GstVideoInfo v_frame_video_info_;
|
GstVideoInfo v_frame_video_info_;
|
||||||
|
|
||||||
// status
|
// status
|
||||||
bool ready_;
|
std::atomic<bool> ready_;
|
||||||
bool failed_;
|
std::atomic<bool> failed_;
|
||||||
bool seekable_;
|
bool seekable_;
|
||||||
|
bool seeking_;
|
||||||
bool isimage_;
|
bool isimage_;
|
||||||
bool interlaced_;
|
bool interlaced_;
|
||||||
bool enabled_;
|
bool enabled_;
|
||||||
|
|||||||
Reference in New Issue
Block a user