How to flush a bus when removing an element from a pipeline?

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

How to flush a bus when removing an element from a pipeline?

wl2776
Administrator
My application adds an uridecodebin instance to the pipeline, and then removes it, if the element doesn't go to the paused state (this can happen, if a non-media file was supplied to the uridecodebin) and returns GST_STATE_CHANGE_FAILURE.

I call
gst_object_unref(uridecodebin_inst);
uridecodebin_inst=NULL;
after the removal.

And the problem is that my application sometimes crashes with the system error message saying, it attempted writing to the location 0x0000010. Or, the location 0xfeeefef6.
I am using MS Visual Studio 2008, and the latter address is very close to the 0xfeeefeee - the value, CRT fills the just released memory.
Call stack is useless, it contains only some addresses in the GLib DLL and in windows system libraries.

I suspect, this is because the bus contains some messages related to the recently removed uridecodebin.

How can I flush these messages or wait for finishing of all threads, related to the element removal?
Reply | Threaded
Open this post in threaded view
|

Re: How to flush a bus when removing an element from a pipeline?

Edward Hervey
Administrator
On Thu, 2010-04-22 at 22:52 -0800, wl2776 wrote:
> My application adds an uridecodebin instance to the pipeline, and then
> removes it, if the element doesn't go to the paused state (this can happen,
> if a non-media file was supplied to the uridecodebin) and returns
> GST_STATE_CHANGE_FAILURE.
>
> I call
> gst_object_unref(uridecodebin_inst);
> uridecodebin_inst=NULL;
> after the removal.

  Have you set uridecodebin to NULL before removing it ? Have you made
sure it didn't connect to anything ? Did you hold an extra reference to
uridecodebin before adding it to the pipeline (if not, the pipeline
*stole* your reference and you shouldn't have to unref it after removing
it from the pipeline).

>
> And the problem is that my application sometimes crashes with the system
> error message saying, it attempted writing to the location 0x0000010. Or,
> the location 0xfeeefef6.
> I am using MS Visual Studio 2008, and the latter address is very close to
> the 0xfeeefeee - the value, CRT fills the just released memory.
> Call stack is useless, it contains only some addresses in the GLib DLL and
> in windows system libraries.

  Those addresses are really useful... *NOT* !

>
> I suspect, this is because the bus contains some messages related to the
> recently removed uridecodebin.

  Most likely due to the double-unreferencing I explained above.

>
> How can I flush these messages or wait for finishing of all threads, related
> to the element removal?
>



------------------------------------------------------------------------------
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: How to flush a bus when removing an element from a pipeline?

wl2776
Administrator
Edward Hervey wrote
On Thu, 2010-04-22 at 22:52 -0800, wl2776 wrote:
> My application adds an uridecodebin instance to the pipeline, and then
> removes it, if the element doesn't go to the paused state (this can happen,
> if a non-media file was supplied to the uridecodebin) and returns
> GST_STATE_CHANGE_FAILURE.

  Have you set uridecodebin to NULL before removing it ? Have you made
sure it didn't connect to anything ? Did you hold an extra reference to
uridecodebin before adding it to the pipeline (if not, the pipeline
*stole* your reference and you shouldn't have to unref it after removing
it from the pipeline).
The exact code.

while(<have a file in a directory and no video or audio stream>) {
  gboolean rb=FALSE;
  uridecodebin[1]=gst_element_factory_make("uridecodebin",
                                            (m_video_present)?"audio_decodebin":"video_decodebin");
  if(uridecodebin[1])
     rb=gst_bin_add(GST_BIN(m_player),uridecodebin[1]);
  if(rb){
     g_object_set(G_OBJECT(uridecodebin[1]),"uri",file_uri,NULL);
 
     h_id2=g_signal_connect(G_OBJECT(uridecodebin[1]),"no-more-pads",
                                    G_CALLBACK(no_more_pads_cb),this);
     h_id3=g_signal_connect(G_OBJECT(uridecodebin[1]),"unknown-type",
                                    G_CALLBACK(unknown_type_cb),this);
     rs=gst_element_set_state(m_player,GST_STATE_PAUSED);

     while(m_player->current_state!=GST_STATE_PAUSED &&
          !(m_flags & FLAG_DORENDER_COMPLETE) &&
           rs!=GST_STATE_CHANGE_FAILURE){
  g_usleep(100000);
     }
     g_signal_handler_disconnect(G_OBJECT(uridecodebin[1]),h_id2);
     g_signal_handler_disconnect(G_OBJECT(uridecodebin[1]),h_id3);

     if(rs==GST_STATE_CHANGE_FAILURE){
        gst_element_set_state(GST_ELEMENT(m_player),GST_STATE_NULL);
        gst_bin_remove(GST_BIN(m_player),uridecodebin[1]);
        gst_object_unref(uridecodebin[1]);
        uridecodebin[1]=NULL;
     }
  }
}


So, yes, I've put the uridecodebin to NULL.
No, I didn't hold the extra reference - will remove gst_object_unref(uridecodebin[1]);

Edward Hervey wrote
> And the problem is that my application sometimes crashes with the system
> error message saying, it attempted writing to the location 0x0000010. Or,
> the location 0xfeeefef6.
> I am using MS Visual Studio 2008, and the latter address is very close to
> the 0xfeeefeee - the value, CRT fills the just released memory.
> Call stack is useless, it contains only some addresses in the GLib DLL and
> in windows system libraries.

  Those addresses are really useful... *NOT* !
What not?
How can I use these addresses?

Edward Hervey wrote
> I suspect, this is because the bus contains some messages related to the
> recently removed uridecodebin.

  Most likely due to the double-unreferencing I explained above.
It shouldn't be a problem, gst_object_unref() contains the checks for ref_count field and doesn't do anything if it's <=0

void
gst_object_unref (gpointer object)
{
  g_return_if_fail (object != NULL);
  g_return_if_fail (((GObject *) object)->ref_count > 0);
...
Reply | Threaded
Open this post in threaded view
|

Re: How to flush a bus when removing an element from a pipeline?

wl2776
Administrator
wl2776 wrote
Edward Hervey wrote
On Thu, 2010-04-22 at 22:52 -0800, wl2776 wrote:
> My application adds an uridecodebin instance to the pipeline, and then
> removes it, if the element doesn't go to the paused state (this can happen,
> if a non-media file was supplied to the uridecodebin) and returns
> GST_STATE_CHANGE_FAILURE.

  Have you set uridecodebin to NULL before removing it ? Have you made
sure it didn't connect to anything ? Did you hold an extra reference to
uridecodebin before adding it to the pipeline (if not, the pipeline
*stole* your reference and you shouldn't have to unref it after removing
it from the pipeline).
The exact code.

while(<have a file in a directory and no video or audio stream>) {
  gboolean rb=FALSE;
  uridecodebin[1]=gst_element_factory_make("uridecodebin",
                                            (m_video_present)?"audio_decodebin":"video_decodebin");
  if(uridecodebin[1])
     rb=gst_bin_add(GST_BIN(m_player),uridecodebin[1]);
  if(rb){
     g_object_set(G_OBJECT(uridecodebin[1]),"uri",file_uri,NULL);
 
     h_id2=g_signal_connect(G_OBJECT(uridecodebin[1]),"no-more-pads",
                                    G_CALLBACK(no_more_pads_cb),this);
     h_id3=g_signal_connect(G_OBJECT(uridecodebin[1]),"unknown-type",
                                    G_CALLBACK(unknown_type_cb),this);
     rs=gst_element_set_state(m_player,GST_STATE_PAUSED);

     while(m_player->current_state!=GST_STATE_PAUSED &&
          !(m_flags & FLAG_DORENDER_COMPLETE) &&
           rs!=GST_STATE_CHANGE_FAILURE){
  g_usleep(100000);
     }
     g_signal_handler_disconnect(G_OBJECT(uridecodebin[1]),h_id2);
     g_signal_handler_disconnect(G_OBJECT(uridecodebin[1]),h_id3);

     if(rs==GST_STATE_CHANGE_FAILURE){
        gst_element_set_state(GST_ELEMENT(m_player),GST_STATE_NULL);
        gst_bin_remove(GST_BIN(m_player),uridecodebin[1]);
        gst_object_unref(uridecodebin[1]);
        uridecodebin[1]=NULL;
     }
  }
}


So, yes, I've put the uridecodebin to NULL.
No, I didn't hold the extra reference - will remove gst_object_unref(uridecodebin[1]);
I have removed gst_object_unref(uridecodebin[1]);
Then, the application run successfully two times, and I've got an Error message box from GLib, saying it has "recursed", on the third run.
Unfortunately, I could not read the whole message, as this message box was covered by the Studio's windows and didn't redraw completely.
Studio's debug output contained about 10 messages about the first chance exception Reading location 0xaddress and Writing location 0xanoter_address
The my system has become almost unresponsive, only Alt-Tab has shown a window, but nothing else happens, so I had to reboot it.
Reply | Threaded
Open this post in threaded view
|

Re: How to flush a bus when removing an element from a pipeline?

wl2776
Administrator
wl2776 wrote
Then, the application run successfully two times, and I've got an Error message box from GLib, saying it has "recursed", on the third run.
Looks like I have won :)
The problem was a bit earlier, related to the similar memory freeing.
My application created playbin2 instance, then looked at its n-video and n-audio properties, and depending on them, destroyed playbin2 and created a pipeline with two uridecodebins and two playing chains for video and audio.

However, I wanted to save the video-sink, since it was created separately, as my player is embedded.

Currently the code is the following, seems it's stable.

GstElement *m_player;
GstBus *m_bus;
GstElement *m_videosink;

m_player=gst_element_factory_make("playbin2","player");
m_bus = gst_pipeline_get_bus(GST_PIPELINE(m_player));
gst_bus_enable_sync_message_emission(m_bus);
gst_bus_set_sync_handler (m_bus, (GstBusSyncHandler)gst_bus_sync_handler, this);
gst_bus_add_watch (m_bus, bus_call, this);

if(!m_videosink){
  m_videosink = gst_element_factory_make("directdrawsink","videosink");
  if(m_videosink){
    gst_object_ref(m_videosink);
    g_object_set(m_videosink,"sync",TRUE,"force-aspect-ratio",TRUE,"preroll-queue-len",1,NULL);
   
   if(!m_hwnd && m_parent)
     m_hwnd=m_parent->hwnd();
 
   if(m_hwnd)
      gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (m_videosink),m_hwnd);

   g_object_set(G_OBJECT(m_player),"video-sink",m_videosink,NULL);
  }
}

.....

rs=gst_element_set_state(GST_ELEMENT(m_player),GST_STATE_NULL);
GstElement *bin=(GstElement *)gst_element_get_parent(m_videosink);
if(bin){
  rb=gst_bin_remove(GST_BIN(bin),GST_ELEMENT(m_videosink));
}
gst_object_unref(GST_OBJECT(m_player));
gst_object_unref(GST_OBJECT(m_bus));