Hi Julien,
On Thu, 2009-01-22 at 20:03 +0100, Julien Pauty wrote:
> One benefit of the idle call is that clutter drawing is done in the
> clutter main thread. I've remarked that, on some driver, even putting
> clutter_thread_enter/leave does not prevent crashes. Making sure that
> everything happens in the main thread seems to be the safest way.
You get the same benefit with the fifo approach I described, because the
fifo is monitored via g_io_add_watch(), so when there is activity ("a
new frame is available") the main thread wakes up and the callback you
attach to the IO watch is invoked from the main thread.
The actual design I'm using is slightly more complicated (I had
simplified it in my last email). There are 3 components:
Producer: mplayer or xine runs as a separate process and copies frames
into a shared memory frame buffer (that has space for multiple frames),
and then writes to a fifo a packet that contains the shmem id and the
offset within the shmem buffer where the frame starts.
Consumer: a thread running in the clutter process that does nothing but
read from the fifo, and updates the frame queue as new frame packets
come in over the fifo. When it's finished reading whatever is in the
fifo, it writes a byte to a pipe (created by pipe(2)) called the "frame
notification pipe" whose read end had been previously registered with
g_io_add_watch().
Clutter: the main clutter thread gets woken up (assuming it is sleeping
in select()) when there's activity on the frame notification pipe. It
prepares the frame at the head of the frame queue by performing software
colorspace conversion and setting the RGB data (if shaders are not
supported), or uploading the Y/U/V textures (if shaders are supported).
By virtue of setting data on the video texture, a redraw is queued,
which clutter does by attaching an idle handler at
CLUTTER_PRIORITY_REDRAW. After all I/O handlers and timers are
completed within the glib mainloop, the idle handler is called and the
stage is painted and GL buffers swapped.
So we are not relying on an idle handler for _timing_ delivery of the
frame, which is what clutter-gst appears to do. I suppose this is sane
if glib will only sleep inside select() for a maximum of a few ms, but
it doesn't seem sensible to wake up that frequently for no reason at
all.
Thanks to the newly added ::queue-redraw signal now in git master, I'm
able to implement my own redraw functionality, which, when there are no
timelines currently running, will wait the appropriate number of
vertical retraces (based on the pts of the current frame waiting to be
drawn) and then proceed into clutter_redraw(), which flips the buffers.
This allows timing frames at the exact retrace they're supposed to be.
When the refresh rate is an integer multiple of the frame rate (which is
really the only situation it's worth going through all this trouble
for), the video is silky smooth. :)
Cheers,
Jason.
--
To unsubscribe send a mail to [email protected]