[gst-devel] Re: gst 0.10 / avisynth 3.0 : thread problem (I think)

Vincent Torri Vincent.Torri at iecn.u-nancy.fr
Mon Mar 27 02:00:05 CEST 2006


Ok, there was no explanation about what i'm trying to do.

Avisynth needs to access to frames of video files. So, it has to open a
video file, read its information (size, framerate, etc...) and access to
frame N when requested. I use gstreamer (0.10) for that. Avisynth and
gstreamer are running in their own thread.

What I want to do is to stop the execution of avs3 when gstreamer is
seeking to the requested frame. Basically, I do that :

1) I seek to frame N
2) I set the pipeline to PLAY
3) I stop the avs3 thread
4) In the handoff callback, I store the buffer that contains the video
data
5) I set the pipeline to PAUSE
6) I allow avs3 to run again.

More precisely, I use 2 classes for that stuff :

class Pipeline
{
  avs::gstreamer::PPipeline pipeline_;
  avs::gstreamer::SignalHandler detectPad_;
  avs::gstreamer::Pad * pad_;
  avs::gstreamer::Element * sink_;
  long int frameNbr_;  // used in FillData

  bool got_signal_;
  GCond *cond_;
  GMutex *mutex_;

  Pipeline(std::string const& filename);

  void GoToFrame (int frame_number, Fraction& fps);
}

I've given only 2 methods of that class. That class builds the pipeline,
that is : filesrc ! decodebin ! fakesink(s)

The GoToFrame method is the following :

void Pipeline::GoToFrame (int frame_number, Fraction& fps)
{
  frameNbr_ = frame_number;
  uint64 time = GST_SECOND*frame_number*fps.denominator() /
fps.numerator();
  avs::gstreamer::Element& elementPipeline = pipeline_->operator
avs::gstreamer::Element&();

  Lock();

  if (!elementPipeline.Seek(time))
    throw exception::Generic( "Gstreamer: can not seek" );

  elementPipeline.SetStatePlaying();

  while ( !IsBufferFound() )
    Wait();

  BufferFound( false );
  Unlock();
}

Lock() and UnLock() lock and unlock the mutex. IsBufferFound returns the
value of got_signal_ and BufferFound set its value.

Seek () is just a call to gst_element_seek

So, got signal_ is set to false by default. I do exactly :

1) I lock the mutex,
2) I seek
3) I set the pipeline to PLAY
4) I'm waiting for the handoff signal to be sent (avs3 is stopped here, at
the while loop)
5) Once the callback is finished, i let avs3 going on
6) I set got_signal_ to false
7) I unlock the mutex

Now, for the callback, I use another class : GstreamerSource. Here is a
part of it :

class GstreamerSource : public clip::NoChild
                      , public clip::framemaker::Concrete
{
  source::gstreamer::PPipeline pipelineVideo_;

  mutable avs::gstreamer::PBuffer buffer_;

  static void FillVideoDataCallback(GObject * obj, GstBuffer *buffer,
GstPad * pad, void * data);
}

It stores the video pipeline and the buffer of the requested frame

The callback is FillVideoDataCallback :

void GstreamerSource::FillVideoDataCallback(GObject * obj, GstBuffer
*buffer, GstPad * pad, void * data)
{
  GstreamerSource const * this_ = static_cast<GstreamerSource *>(data);
  Fraction fps = this_->vi_->GetFPS();
  uint64 frameNbr = this_->pipelineVideo_->GetFrameNbr();

  g_print ("Timestamp :  %lld\n", GST_BUFFER_TIMESTAMP (buffer));
  g_print ("seek to   :  %lld\n", (GST_SECOND * frameNbr *
fps.denominator()) / fps.numerator());

  if ( (GST_BUFFER_TIMESTAMP (buffer) * fps.numerator()) < (GST_SECOND *
frameNbr * fps.denominator()) )
  {
    //    g_print ("skipping frame with timestamp %.5fs < %.5fs\n",
    //	     (gdouble) GST_BUFFER_TIMESTAMP (buffer), GST_SECOND *
(double)frameNbr / fps);
    return;
  }
  this_->pipelineVideo_->Lock();
  this_->buffer_ = avs::gstreamer::Buffer::Create( buffer );

  g_print ("pause\n");
  this_->pipelineVideo_->SetStatePaused();
  g_print ("pause fin\n");

  this_->pipelineVideo_->BufferFound( true );
  this_->pipelineVideo_->Broadcast();
  this_->pipelineVideo_->Unlock();
}

In this callback, I'm doing this :

1) I skipp all the unneeded frames
2) Once the correct frame is found :
  a) I lock the mutex
  b) I store the buffer. The Create method increase its ref count
automatically (and decrease its refcount when the buffer is not needed
anymore)
  c) I set the pipeline to PAUSE
  d) I set got_signal_ to true, so that avs3 can start again
  e) I broadcast
  f) I unlock the mutex

During the execution, I works well until the step 2) c). That is the file
is correctly opened, the pipeline is correctly built, I get all the info
I need, it seeks to the correct frame. Then 2) a) and 2)b) are executed.

But when I set the pipeline to PAUSE, the program hangs. I print "pause"
before, and "pause fin" after. Only "pause" if displayed.

So I think that the pipeline is not happy to be set to the PAUSE state.

I'm not an expert at all of the threads. It's a method that Ronald Bultje
gave me for my seek test program.

I hope that, this time, I was clearer than in the previous mail.

thank you

Vincent




More information about the gstreamer-devel mailing list