Cleanup MediaPlayer.

This commit is contained in:
brunoherbelin
2020-03-09 23:43:41 +01:00
parent 26b1d79478
commit b70212bfd8
4 changed files with 41 additions and 301 deletions

View File

@@ -17,6 +17,10 @@
#include <gst/pbutils/gstdiscoverer.h> #include <gst/pbutils/gstdiscoverer.h>
#include <gst/app/gstappsink.h> #include <gst/app/gstappsink.h>
#ifndef NDEBUG
#define MEDIA_PLAYER_DEBUG
#endif
// opengl texture // opengl texture
static GLuint tex_index_black = 0; static GLuint tex_index_black = 0;
static GstStaticCaps gl_render_caps = GST_STATIC_CAPS ("video/x-raw(memory:GLMemory),format=RGBA,texture-target=2D"); static GstStaticCaps gl_render_caps = GST_STATIC_CAPS ("video/x-raw(memory:GLMemory),format=RGBA,texture-target=2D");
@@ -92,7 +96,7 @@ void MediaPlayer::Open(string uri)
GError *err = NULL; GError *err = NULL;
discoverer = gst_discoverer_new (5 * GST_SECOND, &err); discoverer = gst_discoverer_new (5 * GST_SECOND, &err);
if (!discoverer) { if (!discoverer) {
Log::Info("Error creating discoverer instance: %s\n", err->message); UserInterface::Warning("Error creating discoverer instance: %s\n", err->message);
g_clear_error (&err); g_clear_error (&err);
return; return;
} }
@@ -174,9 +178,8 @@ void MediaPlayer::execute_open()
UserInterface::Warning("%s: Failed to open media %s \n%s\n", gst_element_get_name(pipeline), uri.c_str(), discoverer_message.str().c_str()); UserInterface::Warning("%s: Failed to open media %s \n%s\n", gst_element_get_name(pipeline), uri.c_str(), discoverer_message.str().c_str());
} }
else { else {
Log::Info("%s: Media Player openned %s\n", gst_element_get_name(pipeline), uri.c_str());
// all good // all good
Log::Info("%s: Media Player openned %s\n", gst_element_get_name(pipeline), uri.c_str());
ready = true; ready = true;
} }
@@ -200,7 +203,7 @@ void MediaPlayer::Close()
if (!ready) if (!ready)
return; return;
/* clean up GST */ // clean up GST
if (pipeline != nullptr) { if (pipeline != nullptr) {
gst_element_set_state (pipeline, GST_STATE_NULL); gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline); gst_object_unref (pipeline);
@@ -261,11 +264,18 @@ GstClockTime MediaPlayer::Position()
void MediaPlayer::Play(bool on) void MediaPlayer::Play(bool on)
{ {
// cannot play an image
if (isimage) if (isimage)
return; return;
// request state // request state
desired_state = on ? GST_STATE_PLAYING : GST_STATE_PAUSED; GstState requested_state = on ? GST_STATE_PLAYING : GST_STATE_PAUSED;
// ignore if requesting twice same state
if (desired_state == requested_state)
return;
// accept request to the desired state
desired_state = requested_state;
// if not ready yet, the requested state will be handled later // if not ready yet, the requested state will be handled later
if ( pipeline == nullptr ) if ( pipeline == nullptr )
@@ -282,10 +292,12 @@ void MediaPlayer::Play(bool on)
if (ret == GST_STATE_CHANGE_FAILURE) { if (ret == GST_STATE_CHANGE_FAILURE) {
UserInterface::Warning("Failed to start up Media %s\n", gst_element_get_name(pipeline)); UserInterface::Warning("Failed to start up Media %s\n", gst_element_get_name(pipeline));
} }
#ifdef MEDIA_PLAYER_DEBUG
else if (on) else if (on)
Log::Info("Start Media %s\n", gst_element_get_name(pipeline)); Log::Info("Start Media %s\n", gst_element_get_name(pipeline));
else else
Log::Info("Stop Media %s\n", gst_element_get_name(pipeline)); Log::Info("Stop Media %s\n", gst_element_get_name(pipeline));
#endif
} }
bool MediaPlayer::isPlaying() const bool MediaPlayer::isPlaying() const
@@ -446,42 +458,42 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
// seek position : default to target // seek position : default to target
GstClockTime seek_pos = target; GstClockTime seek_pos = target;
// seek speed rate
gdouble seek_rate = rate;
// seek with flush (always)
int seek_flags = GST_SEEK_FLAG_FLUSH;
// no target given // no target given
if (target == GST_CLOCK_TIME_NONE) if (target == GST_CLOCK_TIME_NONE)
// create seek event with current position (rate changed ?) // create seek event with current position (rate changed ?)
seek_pos = position; seek_pos = Position();
// target is given but useless // target is given but useless
else if (target == Position()) else if ( ABS_DIFF(target, Position()) < frame_duration) {
// ignore request // ignore request
#ifdef MEDIA_PLAYER_DEBUG
Log::Info("%s: Media Player ignored seek to current position\n", id);
#endif
return; return;
}
// seek with flush (always)
int seek_flags = GST_SEEK_FLAG_FLUSH;
// seek with trick mode if fast speed // seek with trick mode if fast speed
if ( ABS(seek_rate) > 2.0 ) if ( ABS(rate) > 2.0 )
seek_flags |= GST_SEEK_FLAG_TRICKMODE | GST_SEEK_FLAG_TRICKMODE_NO_AUDIO; seek_flags |= GST_SEEK_FLAG_TRICKMODE | GST_SEEK_FLAG_TRICKMODE_NO_AUDIO;
// create seek event depending on direction // create seek event depending on direction
if (seek_rate > 0) { if (rate > 0) {
seek_event = gst_event_new_seek (seek_rate, GST_FORMAT_TIME, (GstSeekFlags) seek_flags, seek_event = gst_event_new_seek (rate, GST_FORMAT_TIME, (GstSeekFlags) seek_flags,
GST_SEEK_TYPE_SET, seek_pos, GST_SEEK_TYPE_END, 0); GST_SEEK_TYPE_SET, seek_pos, GST_SEEK_TYPE_END, 0);
} else { } else {
seek_event = gst_event_new_seek (seek_rate, GST_FORMAT_TIME, (GstSeekFlags) seek_flags, seek_event = gst_event_new_seek (rate, GST_FORMAT_TIME, (GstSeekFlags) seek_flags,
GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, seek_pos); GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, seek_pos);
} }
/* Send the event */ // Send the event
if (seek_event && !gst_element_send_event(pipeline, seek_event) ) if (seek_event && !gst_element_send_event(pipeline, seek_event) )
Log::Info("Seek failed in Media %s\n", gst_element_get_name(pipeline)); Log::Info("Seek failed in Media %s\n", gst_element_get_name(pipeline));
#ifdef MEDIA_PLAYER_DEBUG
else else
{ Log::Info("Seek Media %s %ld %f\n", gst_element_get_name(pipeline), seek_pos, rate);
Log::Info("Seek Media %s %ld %f\n", gst_element_get_name(pipeline), seek_pos, seek_rate); #endif
}
} }
void MediaPlayer::SetPlaySpeed(double s) void MediaPlayer::SetPlaySpeed(double s)
@@ -551,32 +563,6 @@ bool MediaPlayer::fill_v_frame(GstBuffer *buf)
return true; return true;
} }
GstFlowReturn MediaPlayer::callback_get_last_sample_video (GstElement *bin, MediaPlayer *m)
{
GstFlowReturn ret = GST_FLOW_OK;
if (m && !m->v_frame_is_full) {
// get last sample (non blocking)
GstSample *sample = nullptr;
g_object_get (bin, "last-sample", &sample, NULL);
if (sample != nullptr) {
GstBuffer *buf;
buf = gst_buffer_ref ( gst_sample_get_buffer (sample) );
gst_sample_unref (sample);
if ( !m->fill_v_frame(buf) )
ret = GST_FLOW_ERROR;
gst_buffer_unref (buf);
}
}
return ret;
}
GstFlowReturn MediaPlayer::callback_pull_sample_video (GstElement *bin, MediaPlayer *m) GstFlowReturn MediaPlayer::callback_pull_sample_video (GstElement *bin, MediaPlayer *m)
{ {
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
@@ -631,11 +617,9 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis
GstDiscovererResult result = gst_discoverer_info_get_result (info); GstDiscovererResult result = gst_discoverer_info_get_result (info);
switch (result) { switch (result) {
case GST_DISCOVERER_URI_INVALID: case GST_DISCOVERER_URI_INVALID:
// g_print ("Invalid URI '%s'\n", uri);
m->discoverer_message << "Invalid URI: " << uri; m->discoverer_message << "Invalid URI: " << uri;
break; break;
case GST_DISCOVERER_ERROR: case GST_DISCOVERER_ERROR:
// g_print ("Discoverer error: %s\n", err->message);
m->discoverer_message << "Error: " << err->message; m->discoverer_message << "Error: " << err->message;
break; break;
case GST_DISCOVERER_TIMEOUT: case GST_DISCOVERER_TIMEOUT:
@@ -726,246 +710,3 @@ int TimeCounter::framecount() const
return nbFrames; return nbFrames;
} }
// /* TESTING */
// static void cb_new_pad (GstElement* decodebin, GstPad* pad, GstElement* target)
// {
// GstPad* target_pad = gst_element_get_static_pad (target, "sink");
// if (!target_pad)
// g_warning ("target has no sink\n");
// //only link once
// if (GST_PAD_IS_LINKED (target_pad))
// {
// gst_object_unref (target_pad);
// g_warning ("target not free\n");
// return;
// }
// GstCaps* caps = gst_pad_get_current_caps (pad);
// GstStructure* str = gst_caps_get_structure (caps, 0);
// if (!g_strrstr (gst_structure_get_name (str), "video"))
// {
// gst_caps_unref (caps);
// gst_object_unref (target_pad);
// g_warning ("decodebin not a video %s\n", gst_structure_get_name (str));
// return;
// }
// gst_caps_unref (caps);
// GstPadLinkReturn ret = gst_pad_link (pad, target_pad);
// if (ret != GST_PAD_LINK_OK)
// g_warning ("Failed to link decodebin %s with target %s ! %d\n", gst_pad_get_name(pad), gst_pad_get_name(target_pad), ret);
// }
// GstElement* videosrc = gst_element_factory_make ("filesrc", "filesrc0");
// GstElement* decodebin = gst_element_factory_make ("decodebin", "decodebin0");
// // GstElement* convertbin = gst_element_factory_make ("videoconvert", "converterbin0");
// GstElement* convertbin = gst_element_factory_make ("glupload", "converterbin0");
// // GstElement* glimagesink = gst_element_factory_make ("glimagesink", "glimagesink0");
// GstElement* glimagesink = gst_element_factory_make ("glimagesinkelement", "glimagesink0");
// // GstElement* glimagesink = gst_element_factory_make ("fakesink", "glimagesink0");
// if (!videosrc || !decodebin || !convertbin || !glimagesink)
// {
// UserInterface::Error ("A Gstreamer element could not be found \n");
// return 1;
// }
// /* configure elements */
// g_object_set(G_OBJECT(videosrc), "num-buffers", 800, NULL);
// g_object_set(G_OBJECT(videosrc), "location", video_location.c_str(), NULL);
// g_signal_connect(G_OBJECT(decodebin), "drained", G_CALLBACK (endVideoCallback), NULL);
// // glimagesink
// // g_signal_connect(G_OBJECT(glimagesink), "client-draw", G_CALLBACK (drawCallback), NULL);
// // glimagesinkelement
// // g_signal_connect(G_OBJECT(glimagesink), "client-reshape", G_CALLBACK (scaleTextureCallback), NULL);
// g_signal_connect(G_OBJECT(glimagesink), "client-draw", G_CALLBACK (textureCallback), NULL);
// // // g_object_set(G_OBJECT(glimagesink), "show-preroll-frame", TRUE, NULL);
// g_object_set(G_OBJECT(glimagesink), "sync", TRUE, NULL);
// g_object_set(G_OBJECT(glimagesink), "handle-events", FALSE, NULL);
// // fakesink
// // g_signal_connect(G_OBJECT(glimagesink), "handoff", G_CALLBACK (fakesinkCallback), NULL);
// // g_object_set(G_OBJECT(glimagesink), "signal-handoffs", TRUE, NULL);
// // g_object_set(G_OBJECT(glimagesink), "sync", TRUE, NULL);
// /* add elements */
// gst_bin_add_many (GST_BIN (pipeline), videosrc, decodebin, convertbin, glimagesink, NULL);
// /* link elements */
// if (!gst_element_link (videosrc, decodebin) )
// // if (!gst_element_link_pads (videosrc, "src", decodebin, "sink") )
// {
// g_warning ("Failed to link videosrc to decodebin !\n");
// return -1;
// }
// g_signal_connect (decodebin, "pad-added", G_CALLBACK (cb_new_pad), convertbin);
// if(!gst_element_link (convertbin, glimagesink))
// {
// g_warning("Failed to link convertbin to glimagesink!\n") ;
// return -1 ;
// }
// static gboolean drawTextureCallback (GstElement *object, guint texture, guint width, guint height, GstElement *pipeline)
// {
// //printStreamPosition(pipeline);
// texture_gst = texture;
// //std::cerr << "Texture " << width << " x " << height << std::endl;
// return TRUE;
// }
// static void fakesinkCallback (GstElement *bin, GstBuffer buffer, GstPad pad, GstElement *pipeline)
// {
// static GstClockTime current_time;
// static GstClockTime last_time = gst_util_get_timestamp();
// static gint nbFrames = 0;
// current_time = gst_util_get_timestamp ();
// nbFrames++ ;
// if ((current_time - last_time) >= GST_SECOND)
// {
// //std::cerr << nbFrames << " frame / s" << std::endl;
// // GstElement *pipeline = (GstElement*)data;
// last_time = current_time;
// nbFrames = 0;
// // if (!gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
// // GST_SEEK_TYPE_SET, 0,
// // GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
// // g_print ("Seek failed!\n");
// // }
// }
// }
// static void endVideoCallback (GstElement *bin, GstElement *pipeline)
// {
// g_warning ("end of stream %s\n", gst_element_get_name(pipeline));
// printStreamPosition(pipeline);
// }
// video
// gchar *descr;
// // descr = g_strdup_printf ("videotestsrc pattern=ball ! video/x-raw,format=RGBA ! glimagesink");
// // descr = g_strdup_printf ("videotestsrc ! glupload ! glfilterapp name=capture ! fakesink name=sink");
// descr = g_strdup_printf ("uridecodebin uri=file:///home/bhbn/Videos/glmixervideo180324111104.mp4 name=decoder ! videoconvert ! "
// "video/x-raw,format=RGBA ! glupload ! glfilterapp name=capture ! fakesink name=sink");
// g_print ("pipeline: %s\n", descr);
// GError *error = NULL;
// GstElement *pipeline = gst_parse_launch (descr, &error);
// if (error != NULL) {
// g_print ("could not construct pipeline: %s\n", error->message);
// g_clear_error (&error);
// exit (-1);
// }
// g_object_set(G_OBJECT(pipeline), "name", "vmixpipeline", NULL);
// GstElement *capture = gst_bin_get_by_name (GST_BIN (pipeline), "capture");
// if (capture)
// g_signal_connect(G_OBJECT(capture), "client-draw", G_CALLBACK (drawTextureCallback), pipeline);
// GstElement *sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
// if (sink) {
// g_signal_connect(G_OBJECT(sink), "handoff", G_CALLBACK (fakesinkCallback), pipeline);
// g_object_set(G_OBJECT(sink), "signal-handoffs", TRUE, NULL);
// g_object_set(G_OBJECT(sink), "sync", TRUE, NULL);
// }
// GstElement *decoder = gst_bin_get_by_name (GST_BIN (pipeline), "decoder");
// if (decoder)
// g_signal_connect(G_OBJECT(decoder), "drained", G_CALLBACK (endVideoCallback), pipeline);
// // g_signal_connect(G_OBJECT(decoder), "about-to-finish", G_CALLBACK (endVideoCallback), pipeline);
// // g_timeout_add (200, (GSourceFunc) printStreamPosition, pipeline);
// // /* WORKING PIPELINE PURE OGL */
// // GstElement* pipeline = gst_pipeline_new ("pipeline");
// // GstElement *src = gst_element_factory_make ("gltestsrc", NULL);
// // // GstElement *sink = gst_element_factory_make ("glimagesinkelement", NULL);
// // // g_signal_connect(G_OBJECT(sink), "client-draw", G_CALLBACK (drawCallback), NULL);
// // // g_object_set(G_OBJECT(sink), "show-preroll-frame", FALSE, NULL);
// // // g_object_set(G_OBJECT(sink), "handle-events", FALSE, NULL);
// // GstElement *capture = gst_element_factory_make ("glfilterapp", NULL);
// // g_signal_connect(G_OBJECT(capture), "client-draw", G_CALLBACK (drawTextureCallback), NULL);
// // GstElement* sink = gst_element_factory_make ("fakesink", NULL);
// // g_signal_connect(G_OBJECT(sink), "handoff", G_CALLBACK (fakesinkCallback), NULL);
// // g_object_set(G_OBJECT(sink), "signal-handoffs", TRUE, NULL);
// // g_object_set(G_OBJECT(sink), "sync", TRUE, NULL);
// // gst_bin_add_many (GST_BIN (pipeline), src, capture, sink, NULL);
// // gst_element_link_many (src, capture, sink, NULL);
// // capture bus signals to force a unique opengl context for all GST elements
// Rendering::LinkPipeline(GST_PIPELINE (pipeline));
// /* run */
// GstStateChangeReturn ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
// if (ret == GST_STATE_CHANGE_FAILURE)
// {
// g_warning ("Failed to start up pipeline!\n");
// return -1;
// }
// string description = "uridecodebin uri=" + uri + " name=decoder ! videoconvert ! "
// "video/x-raw,format=RGBA ! glupload ! glfilterapp name=capture ! appsink name=sink";
// GError *error = NULL;
// pipeline = gst_parse_launch (description.c_str(), &error);
// if (error != NULL) {
// ImGuiToolkit::Log("Could not construct pipeline %s:\n%s\n", description.c_str(), error->message);
// g_clear_error (&error);
// return false;
// }
// g_object_set(G_OBJECT(pipeline), "name", id.c_str(), NULL);
// GstElement *capture = gst_bin_get_by_name (GST_BIN (pipeline), "capture");
// if (capture) {
// g_signal_connect(G_OBJECT(capture), "client-draw", G_CALLBACK (textureCallback), this);
// }
// GstElement *sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
// if (sink) {
// GstCaps *caps = gst_static_caps_get (&render_caps);
// g_object_set (sink, "emit-signals", TRUE, "enable-last-sample", TRUE, "sync", TRUE, "wait-on-eos", FALSE, "caps", caps, NULL);
// g_signal_connect(G_OBJECT(sink), "new-sample", G_CALLBACK (sampleCallback), this);
// g_signal_connect(G_OBJECT(sink), "new-preroll", G_CALLBACK (sampleCallback), this);
// g_signal_connect(G_OBJECT(sink), "eos", G_CALLBACK (endMediaCallback), this);
// gst_object_unref (sink);
// gst_caps_unref (caps);
// }
// // capture bus signals to force a unique opengl context for all GST elements
// Rendering::LinkPipeline(GST_PIPELINE (pipeline));
// /* set to PAUSED to make the first frame arrive in the sink */
// GstStateChangeReturn ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
// if (ret == GST_STATE_CHANGE_FAILURE) {
// ImGuiToolkit::Log("%s: Failed to open media %s\n", gst_element_get_name(pipeline), uri.c_str());
// return false;
// }

View File

@@ -175,7 +175,6 @@ private:
bool fill_v_frame(GstBuffer *buf); bool fill_v_frame(GstBuffer *buf);
static GstFlowReturn callback_pull_sample_video (GstElement *bin, MediaPlayer *m); static GstFlowReturn callback_pull_sample_video (GstElement *bin, MediaPlayer *m);
static GstFlowReturn callback_get_last_sample_video (GstElement *bin, MediaPlayer *m);
static void callback_end_of_video (GstElement *bin, MediaPlayer *m); static void callback_end_of_video (GstElement *bin, MediaPlayer *m);
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);

View File

@@ -8,6 +8,7 @@
#define MINI(a, b) (((a) < (b)) ? (a) : (b)) #define MINI(a, b) (((a) < (b)) ? (a) : (b))
#define MAXI(a, b) (((a) > (b)) ? (a) : (b)) #define MAXI(a, b) (((a) > (b)) ? (a) : (b))
#define ABS(a) (((a) < 0) ? -(a) : (a)) #define ABS(a) (((a) < 0) ? -(a) : (a))
#define ABS_DIFF(a, b) ( (a) < (b) ? (b - a) : (a - b) )
#define SIGN(a) (((a) < 0) ? -1.0 : 1.0) #define SIGN(a) (((a) < 0) ? -1.0 : 1.0)
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))

View File

@@ -222,7 +222,7 @@ void drawMediaPlayer()
// display buttons Play/Stop depending on current playing state // display buttons Play/Stop depending on current playing state
if (media_playing) { if (media_playing) {
if (ImGui::Button(ICON_FA_STOP " Stop") ) if (ImGui::Button(ICON_FA_STOP " Stop"))
testmedia.Play(false); testmedia.Play(false);
ImGui::SameLine(0, spacing); ImGui::SameLine(0, spacing);
@@ -233,7 +233,7 @@ void drawMediaPlayer()
} }
else { else {
if (ImGui::Button(ICON_FA_PLAY " Play") ) if (ImGui::Button(ICON_FA_PLAY " Play"))
testmedia.Play(true); testmedia.Play(true);
ImGui::SameLine(0, spacing); ImGui::SameLine(0, spacing);
@@ -270,8 +270,6 @@ void drawMediaPlayer()
testmedia.SetPlaySpeed( static_cast<double>(speed) ); testmedia.SetPlaySpeed( static_cast<double>(speed) );
} }
//ImGuiToolkit::Bar(0.6f, 0.1, 0.8, 0.0, 1.0, "time", true);
guint64 current_t = testmedia.Position(); guint64 current_t = testmedia.Position();
guint64 t = current_t; guint64 t = current_t;
guint64 begin = testmedia.Duration() / 5; guint64 begin = testmedia.Duration() / 5;
@@ -329,9 +327,10 @@ int main(int, char**)
/// ///
/// GStreamer /// GStreamer
/// ///
#ifndef NDEBUG
gst_debug_set_active(TRUE); gst_debug_set_active(TRUE);
gst_debug_set_default_threshold (GST_LEVEL_WARNING); gst_debug_set_default_threshold (GST_LEVEL_WARNING);
#endif
// 1 // 1
// testmedia.Open("file:///home/bhbn/Images/2014-10-18_16-46-47.jpg"); // testmedia.Open("file:///home/bhbn/Images/2014-10-18_16-46-47.jpg");