From b70212bfd82be5f4d9ca43c5bd2c8de6a36fa11d Mon Sep 17 00:00:00 2001 From: brunoherbelin Date: Mon, 9 Mar 2020 23:43:41 +0100 Subject: [PATCH] Cleanup MediaPlayer. --- MediaPlayer.cpp | 329 ++++++------------------------------------------ MediaPlayer.h | 3 +- defines.h | 1 + main.cpp | 9 +- 4 files changed, 41 insertions(+), 301 deletions(-) diff --git a/MediaPlayer.cpp b/MediaPlayer.cpp index 96acf09..7ee18a3 100644 --- a/MediaPlayer.cpp +++ b/MediaPlayer.cpp @@ -17,6 +17,10 @@ #include #include +#ifndef NDEBUG +#define MEDIA_PLAYER_DEBUG +#endif + // opengl texture static GLuint tex_index_black = 0; 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; discoverer = gst_discoverer_new (5 * GST_SECOND, &err); 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); 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()); } else { - Log::Info("%s: Media Player openned %s\n", gst_element_get_name(pipeline), uri.c_str()); - // all good + Log::Info("%s: Media Player openned %s\n", gst_element_get_name(pipeline), uri.c_str()); ready = true; } @@ -200,7 +203,7 @@ void MediaPlayer::Close() if (!ready) return; - /* clean up GST */ + // clean up GST if (pipeline != nullptr) { gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); @@ -261,11 +264,18 @@ GstClockTime MediaPlayer::Position() void MediaPlayer::Play(bool on) { + // cannot play an image if (isimage) return; // 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 ( pipeline == nullptr ) @@ -281,11 +291,13 @@ void MediaPlayer::Play(bool on) GstStateChangeReturn ret = gst_element_set_state (pipeline, desired_state); if (ret == GST_STATE_CHANGE_FAILURE) { UserInterface::Warning("Failed to start up Media %s\n", gst_element_get_name(pipeline)); - } + } +#ifdef MEDIA_PLAYER_DEBUG else if (on) Log::Info("Start Media %s\n", gst_element_get_name(pipeline)); else Log::Info("Stop Media %s\n", gst_element_get_name(pipeline)); +#endif } bool MediaPlayer::isPlaying() const @@ -446,42 +458,42 @@ void MediaPlayer::execute_seek_command(GstClockTime target) // seek position : default to 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 if (target == GST_CLOCK_TIME_NONE) // create seek event with current position (rate changed ?) - seek_pos = position; + seek_pos = Position(); // target is given but useless - else if (target == Position()) + else if ( ABS_DIFF(target, Position()) < frame_duration) { // ignore request +#ifdef MEDIA_PLAYER_DEBUG + Log::Info("%s: Media Player ignored seek to current position\n", id); +#endif return; - + } + + // seek with flush (always) + int seek_flags = GST_SEEK_FLAG_FLUSH; // 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; // create seek event depending on direction - if (seek_rate > 0) { - seek_event = gst_event_new_seek (seek_rate, GST_FORMAT_TIME, (GstSeekFlags) seek_flags, + if (rate > 0) { + seek_event = gst_event_new_seek (rate, GST_FORMAT_TIME, (GstSeekFlags) seek_flags, GST_SEEK_TYPE_SET, seek_pos, GST_SEEK_TYPE_END, 0); } 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); } - /* Send the event */ + // Send the event if (seek_event && !gst_element_send_event(pipeline, seek_event) ) Log::Info("Seek failed in Media %s\n", gst_element_get_name(pipeline)); +#ifdef MEDIA_PLAYER_DEBUG else - { - Log::Info("Seek Media %s %ld %f\n", gst_element_get_name(pipeline), seek_pos, seek_rate); - } - - + Log::Info("Seek Media %s %ld %f\n", gst_element_get_name(pipeline), seek_pos, rate); +#endif } void MediaPlayer::SetPlaySpeed(double s) @@ -551,32 +563,6 @@ bool MediaPlayer::fill_v_frame(GstBuffer *buf) 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 ret = GST_FLOW_OK; @@ -631,11 +617,9 @@ void MediaPlayer::callback_discoverer_process (GstDiscoverer *discoverer, GstDis GstDiscovererResult result = gst_discoverer_info_get_result (info); switch (result) { case GST_DISCOVERER_URI_INVALID: - // g_print ("Invalid URI '%s'\n", uri); m->discoverer_message << "Invalid URI: " << uri; break; case GST_DISCOVERER_ERROR: - // g_print ("Discoverer error: %s\n", err->message); m->discoverer_message << "Error: " << err->message; break; case GST_DISCOVERER_TIMEOUT: @@ -726,246 +710,3 @@ int TimeCounter::framecount() const 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; - // } diff --git a/MediaPlayer.h b/MediaPlayer.h index f307446..e683034 100644 --- a/MediaPlayer.h +++ b/MediaPlayer.h @@ -175,7 +175,6 @@ private: bool fill_v_frame(GstBuffer *buf); 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_discoverer_process (GstDiscoverer *discoverer, GstDiscovererInfo *info, GError *err, MediaPlayer *m); static void callback_discoverer_finished(GstDiscoverer *discoverer, MediaPlayer *m); @@ -184,4 +183,4 @@ private: -#endif // __GST_MEDIA_PLAYER_H_ \ No newline at end of file +#endif // __GST_MEDIA_PLAYER_H_ diff --git a/defines.h b/defines.h index 0b36ea9..c84e36d 100644 --- a/defines.h +++ b/defines.h @@ -8,6 +8,7 @@ #define MINI(a, b) (((a) < (b)) ? (a) : (b)) #define MAXI(a, b) (((a) > (b)) ? (a) : (b)) #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 CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) diff --git a/main.cpp b/main.cpp index b677efc..c8f1339 100644 --- a/main.cpp +++ b/main.cpp @@ -222,7 +222,7 @@ void drawMediaPlayer() // display buttons Play/Stop depending on current playing state if (media_playing) { - if (ImGui::Button(ICON_FA_STOP " Stop") ) + if (ImGui::Button(ICON_FA_STOP " Stop")) testmedia.Play(false); ImGui::SameLine(0, spacing); @@ -233,7 +233,7 @@ void drawMediaPlayer() } else { - if (ImGui::Button(ICON_FA_PLAY " Play") ) + if (ImGui::Button(ICON_FA_PLAY " Play")) testmedia.Play(true); ImGui::SameLine(0, spacing); @@ -270,8 +270,6 @@ void drawMediaPlayer() testmedia.SetPlaySpeed( static_cast(speed) ); } - //ImGuiToolkit::Bar(0.6f, 0.1, 0.8, 0.0, 1.0, "time", true); - guint64 current_t = testmedia.Position(); guint64 t = current_t; guint64 begin = testmedia.Duration() / 5; @@ -329,9 +327,10 @@ int main(int, char**) /// /// GStreamer /// +#ifndef NDEBUG gst_debug_set_active(TRUE); gst_debug_set_default_threshold (GST_LEVEL_WARNING); - +#endif // 1 // testmedia.Open("file:///home/bhbn/Images/2014-10-18_16-46-47.jpg");