From BlenderWiki

Jump to: navigation, search
Note: This is an archived version of the Blender Developer Wiki. The current and active wiki is available on wiki.blender.org.

Proposal for a timer API for Blender 2.5

Background

Correct timing is needed to sync audio and video. As the frame sample rate is much higher that the video frame rate the audio typically does the timing.

The problem is that Blender currently supports two different timing methods at the moment:

  • Clock based playback with a slowdown in playback if updating is too slow
  • Clock based playback (currently called "Sync" although it doesn't sync)

Well for those two there's no API needed, but I have at least three timer types in mind and the API I have in mind would make it easily possible to switch between those, I have the following three timers in mind:

  • Clock based playback with the slowdown as it is default atm
  • Default audio playback based timer (syncing)
  • Jack Transport timer (when the Jack output device is used)

API

I designed the API with jack transport in mind so that it suits all needs it has. That pretty much should suit all needs any timer implementation has.

There is one timer per Scene and the timer is always valid (so created when the Scene struct is allocated and deleted when the Scene struct is deleted)

The following functions are implemented by a timer:

  • int isPlaying(timer*) - returns non-zero if the scene is currently playing back
  • float getPosition(timer*) - returns the current playback position in seconds
  • void start(timer*) - requests the timer to start playback
  • void stop(timer*) - requests the timer to stop playback
  • void seek(timer*, float position) - requests the timer to seek to a specific position (in seconds)

All of those functions can be called at any time. As the timer keeps the position now, the scene->r.cfra should always have the video frame value that fits with the timer position.

The following functions are called by the timer:

  • void update(Scene*) - called whenever the timer "ticks" or playback/starts stops

So to provide the timer functions I'd say we define a struct with function pointers, the Scene it belongs to and a type field. The timers have their own structs that include this one and this struct is passed to the timer functions.

The update function called by the timer is blender internal. It is very important that it is non-blocking ("realtime") and thread safe as it will be called from the audio mixing thread for the audio timers and for jack transport it has to be non-blocking. That's also why the update function doesn't give tell the time or playing state, more on that later.

How this should work

As an example I'll show here how it generally should work.

Where currently cfra is changed the timer seek function will be called, not updating the cfra directly. Same is true for the play and stop functions. The call itself just tells the timer to start/stop, but doesn't apply this yet. That is done when updating.

The timer then internally does the seeking and playback start-/stoping and calls the update function as soon as the timing position is really changed. For the clock based timer for example this happens immediately.

Now as the update function can be called from the audio mixing thread and has to be non-blocking (that means it is not allowed to do a thread lock and wait for another thread), we need to simply place something like an event for blender so that it does the updating. I'm not into the internals of blender here, but I guess it has an event queue where this could be added (however we still have to make sure that is threading save and non-blocking!).

The updating itself then looks like this: the current time is read from the timer and cfra is set to the specific value. If it has been changed the display is updated, etc., including the check for if the end frame has been reached. If so seek has to be called to move back to the start frame. Moreover the playing state has to be processed. So if that changes, the playback button is changed to a pause button and vice versa, the "Anim" button in the header is shown or hidden and whatever else has to be done.

Reverse Playback

Is something to think further about. Could be an extension for the clock based timer only as this is not possible with jack transport and I think it's not useful for the audio playback. The problem with playing audio reverse is that the seeking that would be required to play backwards (seek blocksize backwards, read block, reverse, play, seek again ...) is pretty slow with audio files and videos read from disk via ffmpeg.

PS: Yet another thought

Instead of the complicated (non-blocking + thread safe) update mechanism, we could simply do polling for a cfra and playstate change. That would remove the need of a complicated routine to fullfill those needs.