[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