GstPipeline and bus call

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

GstPipeline and bus call

Yaroslav
Hi all!

Now i need to play udp stream on my imx6 boards and show image(logo) when no data on port.

Server:

gst-launch-1.0 -v filesrc location=/video/0001.mp4 ! decodebin ! vpuenc_h264 bitrate=8192 ! rtph264pay ! udpsink host=192.168.5.255 port=5555

Client (C code):


#define GST_PLAYER_UDP "udpsrc port=5555 caps=\"application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96\"\
                ! rtph264depay ! decodebin ! videoconvert ! autovideosink"
....

static gboolean bus_call (GstBus     *bus, GstMessage *msg, gpointer    data)
{
        printf("msg=%s (from %s)\n",gst_message_type_get_name(GST_MESSAGE_TYPE(msg)), GST_MESSAGE_SRC_NAME(msg));

        return TRUE;
}
...
GstElement* gstLaunch()
{
        GstElement *pipeline;
        GError *error = NULL;

        pipeline = gst_parse_launch (GST_PLAYER_UDP, &error);
        if (!pipeline){
                g_print ("\tParse error: %s\n", error->message);
                return 0;
        }

        gst_element_set_state (pipeline, GST_STATE_PLAYING);

        GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
        guint watch_id = gst_bus_add_watch (bus, bus_call, NULL);
        gst_object_unref (bus);

        return pipeline;
}

-----------------------------------------------------------------------------------------------

When i start streaming all work fine and i can see when streamig start:

display(/dev/fb0) resolution is (1280x800).
====== OVERLAYSINK: 4.0.9 build on May 12 2017 10:36:47. ======
display(/dev/fb0) resolution is (1280x800).
display(/dev/fb0) resolution is (1280x800).
msg=state-changed (from autovideosink0)
msg=state-changed (from videoconvert0)
msg=state-changed (from typefind)
msg=state-changed (from decodebin0)
msg=state-changed (from rtph264depay0)
msg=state-changed (from udpsrc0)
msg=state-changed (from pipeline0)
msg=state-changed (from videoconvert0)
msg=state-changed (from typefind)
msg=state-changed (from rtph264depay0)
msg=stream-status (from src)
msg=state-changed (from udpsrc0)
msg=state-changed (from pipeline0)
msg=stream-status (from src)
msg=new-clock (from pipeline0)
msg=state-changed (from videoconvert0)
msg=state-changed (from rtph264depay0)
msg=state-changed (from udpsrc0)
msg=state-changed (from h264parse0)
msg=state-changed (from h264parse0)
[INFO] Product Info: i.MX6Q/D/S
msg=state-changed (from vpudec0)
[INFO] Product Info: i.MX6Q/D/S
====== VPUDEC: 4.0.9 build on May 12 2017 10:36:53. ======
        wrapper: 1.0.65 (VPUWRAPPER_ARM_LINUX Build on May 12 2017 10:30:05)
        vpulib: 5.4.33
        firmware: 3.1.1.46072
msg=state-changed (from vpudec0)
[INFO] bitstreamMode 1, chromaInterleave 1, mapType 0, tiled2LinearEnable 0
msg=state-changed (from decodebin0)

msg=stream-start (from pipeline0)

msg=state-changed (from autovideosink0-actual-sink-overlay)
msg=state-changed (from autovideosink0)
msg=async-done (from pipeline0)
msg=state-changed (from autovideosink0-actual-sink-overlay)
msg=state-changed (from autovideosink0)
msg=state-changed (from vpudec0)
msg=state-changed (from capsfilter0)
msg=state-changed (from h264parse0)
msg=state-changed (from typefind)
msg=state-changed (from decodebin0)
msg=state-changed (from pipeline0)
msg=qos (from autovideosink0-actual-sink-overlay)
msg=tag (from autovideosink0-actual-sink-overlay)

but when file play all or server not available there is no message on bus
What should I do to understand that the video data is not received by the client(and i need to show splashscreen)??

PS please, help! I spent a lot of time and start despair...
Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

killerrats
This post was updated on .
Looks like your using c++ so this is what is in c++. maybe this will give you at least a start. maybe even work. I don't understand what your saying is wrong. if its not playing or just doesn't quit after the video is done or what but this might work for a template for ya. you can play around with the debug function by replacing the number(max 5). the higher you go the more stuff you get. I don't usually use past 3 or 4.

#include <gst/gst.h>
#include <iostream>

/*************
global values
*****    ***********/

GstElement *pipeline;
GMainLoop *loop;
GstBus *bus;
GstMessage* msg;
GstStateChangeReturn ret;

#define GST_PLAYER_UDP "udpsrc port=5555 caps=\"application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96\"\
                ! rtph264depay ! decodebin ! videoconvert ! autovideosink"

static gboolean bus_cb (GstBus *bus, GstMessage *msg, gpointer *data);
                               
int main()
{
        //debug level 1,2,3,4,5
        gst_debug_set_threshold_from_string("*:3",TRUE);

        /* Initialize GStreamer */
  gst_init (NULL,NULL);
 
  /* Build the pipeline */
  pipeline = gst_parse_launch (GST_PLAYER_UDP, NULL);
  bus = gst_element_get_bus (pipeline);

  /* Start playing */
  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    g_printerr ("Unable to set the pipeline to the playing state.\n");
    gst_object_unref (pipeline);
    return -1;
  }

  loop = g_main_loop_new (NULL, FALSE);

  gst_bus_add_signal_watch (bus);
  g_signal_connect (bus, "message", G_CALLBACK (bus_cb),NULL);

  g_main_loop_run (loop);

  /* Free resources */
  g_main_loop_unref (loop);
  gst_object_unref (bus);
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
 
  return 0;
}


/**********************
    bus method
******************/
gboolean bus_cb (GstBus *bus, GstMessage *msg, gpointer *data) {

  switch (GST_MESSAGE_TYPE (msg)) {
        case GST_MESSAGE_ERROR: {
      GError *err;
      gchar *debug;

      gst_message_parse_error (msg, &err, &debug);
      g_print ("Error: %s\n", err->message);
      g_error_free (err);
      g_free (debug);

      gst_element_set_state (pipeline, GST_STATE_READY);
      g_main_loop_quit (loop);
      return FALSE;
    }
    case GST_MESSAGE_EOS:
      /* end-of-stream */
      gst_element_set_state (pipeline, GST_STATE_READY);
      g_main_loop_quit (loop);
      return FALSE;
   
    default:
      /* Unhandled message */
      break;
    }
      return TRUE;
}
Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

Yaroslav
Thanks for the answer!
The video is played perfectly. My problem is that after the server has finished broadcasting I have no information that this happened. There are no messages on bus_сb and I do not have a chance to understand that I have to ыуе the splash screen and wait for the video to be played again.
Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

Arjen Veenhuizen
Yaroslav wrote
My problem is that after the server has finished broadcasting I have no information that this happened. There are no messages on bus_сb (...)
You mean at the receiving side? Since you are using UDP, there is no way of knowing when the stream has stopped except for waiting for a data timeout (and even in that case, that timeout could have happened due to a temporary interrupted connection)
Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

Yaroslav
This post was updated on .
Yes, on the receiver side. Really in my pipeline there is no element that can give me information that the video is not currently playing?
Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

Arjen Veenhuizen
All you can do afaik is adding a buffer probe on the udpsrc src-pad and track is data is flowing. Udp is connection-less, so there is no connection-close when the stream has ended. You could communicate the end of transmission over the top, or perhaps you can piggyback a magic marker in the udp stream signalling the end of stream.
Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

killerrats
In reply to this post by Yaroslav
edited the code from what i gave you and may be that state change will give you a pause or ready or something. then maybe if it goes to paused 10 times and it will quit the loop.

/*************
global values
*****    ***********/

GstElement *pipeline;
GMainLoop *loop;
GstBus *bus;
GstMessage* msg;
GstState* state;

#define GST_PLAYER_UDP "udpsrc port=5555 caps=\"application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96\"\
                ! rtph264depay ! decodebin ! videoconvert ! autovideosink"

static gboolean bus_cb (GstBus *bus, GstMessage *msg, gpointer *data);
                               
int main()
{
        /* Initialize GStreamer */
        gst_init (&argc, &argv);

        /* Build the pipeline */
        pipeline = gst_parse_launch (GST_PLAYER_UDP, &error);
        if (!pipeline){
                        g_print ("\tParse error: %s\n", error->message);
                        return 0;
        }
       
        loop = g_main_loop_new (NULL, FALSE);

        /* Start playing */
        gst_element_set_state (pipeline, GST_STATE_PLAYING);

        /* Wait until error or EOS */
         bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
         if(bus == NULL)
         {
                std::cout << "\nNo Bus\n";
                return 0;
         }
        gst_bus_add_signal_watch(bus);
        g_signal_connect (bus, "message", G_CALLBACK (bus_cb), this->apPipeline);
       
        g_timeout_add_seconds (1, timeout_cb, loop);
       
        g_main_loop_run(loop);
       
        /* Free resources */
        gst_object_unref (bus);
        gst_element_set_state (pipeline, GST_STATE_NULL);
        gst_object_unref (pipeline);
}


/**********************
    bus method
******************/
gboolean bus_cb (GstBus *bus, GstMessage *msg, gpointer *data) {

  switch (GST_MESSAGE_TYPE (msg)) {
        case GST_MESSAGE_ERROR: {
      GError *err;
      gchar *debug;

      gst_message_parse_error (msg, &err, &debug);
      g_print ("Error: %s\n", err->message);
      g_error_free (err);
      g_free (debug);

      gst_element_set_state (pipeline, GST_STATE_READY);
      g_main_loop_quit (loop);
      return FALSE;
    }
    case GST_MESSAGE_EOS:
      /* end-of-stream */
      gst_element_set_state (pipeline, GST_STATE_READY);
      g_main_loop_quit (loop);
      return FALSE;
    case GST_MESSAGE_STATE_CHANGED:
        {
        GstElement* source = gst_bin_get_by_name(GST_BIN(pipeline),"source");

                if (GST_MESSAGE_SRC (msg) == GST_OBJECT(source)) {
            GstState old_state, new_state, pending_state;
            gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
                        std::string oldstate(gst_element_state_get_name (old_state));
                        std::string newstate(gst_element_state_get_name (new_state));
                        std::string changestate = "Pipeline state changed from "+oldstate+" to " + newstate;
                        std::cout << changestate;
                state = new_state;
                gst_object_unref(source);
        }
        break;
    default:
      /* Unhandled message */
      break;
    }
      return TRUE;
}

gboolean PipelineClass::timeout_cb (gpointer user_data)
{
        static int time = 0;
        static int timeout = 0;
        int MaxTimeout = 10;
                                               
                switch (state)
                {
                case GST_STATE_READY:
                {
                   std::cout << "STATE Ready";
                 }
                case GST_STATE_PLAYING:
                        {
                               std::cout << "STATE Playing":
                          timeout = 0;
                        }
                        break;
                case GST_STATE_PAUSED:
                        {
                               std::cout << "STATE Paused":
                                if(timeout == MaxTimeout)
                                {
                                   g_main_loop_quit(loop);
                                }
                                timeout++;
                                break;
                        }
                case GST_STATE_NULL:
                               std::cout << "STATE Null":
                        return FALSE;
                default:
                        break;
                }
  return TRUE;
}
Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

Yaroslav
Thank you very much for your help, but this also does not work. Even when the stream does not exist, that state does not change.

STATE Ready
STATE Playing
STATE Ready
STATE Playing
....
STATE Ready
STATE Playing



Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

killerrats
you might have to do some c++ application on the server side. i'll probably use the same pipeline you have and try for myself. see if I can figure it out.
Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

killerrats
In reply to this post by Yaroslav
okay I have figured it out and sending the link to the .cpp file.

UdpVideoPlayer.cpp

this will tee the rtph264depay and go to the autovideosink then go to the appsink. as the appsink get buffer it will make a count for the appsinkCount. I have a preAppsinkCount the see if appsinkCount equals preAppsinkCount. if they are both same 4 times it will quit the application.

finding:
checking the appsinkCount to preAppsinkCount in timeout_cb function
appsinkCount is counting in appsink_signal function
appsinkCount and preAppsinkCount declared global at top.
ImmediateLoopQuit function will g_main_quit(loop);

I hope this works.
Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

Yaroslav
It's work!!!!!!!!!!!!!!!!!! thanks a lot!!!!
I am infinitely grateful to you for your help.
Reply | Threaded
Open this post in threaded view
|

Re: GstPipeline and bus call

killerrats
glad it helped. there is probably a better way to do it.