QuickTime 6.4 introduces several new features that support execution of background tasks on multiple threads in a preemptive multitasking environment. This makes it possible to offload many tasks from your program's main thread to forestall blocking the user interface. Typical thread-safe tasks include importing still images or image sequences, exporting movies, and rendering to the offscreen graphics world a movie that is not currently being played.
The new threading features allow a degree of concurrent tasking in QuickTime that was not previously possible. In the past, QuickTime could be used on separate threads only by serializing access to the QuickTime API, either by the application itself or through the use of a cooperative threading manager such as the Carbon Thread Manager. While serializing allowed QuickTime to be used safely on multiple threads, it did not support concurrent QuickTime operations; if one thread was executing a QuickTime function, other threads needing to call QuickTime were blocked.
Getting Ready to Use QuickTime from a Thread
User Interface Limited to the Main Thread
Error Handling
Using QuickTime From a Thread
Cleaning Up
Backward Compatibility
Thread Safety Issues
To use QuickTime in the background on a preemptive thread,
make a call to EnterMoviesOnThread from
the thread before calling any other QuickTime functions from that
thread. It is important that you call EnterMovies on
your main thread before spawning any threads that call EnterMoviesOnThread.
EnterMoviesOnThread initializes
QuickTime with an environment that is private to the thread. Calls
to GetMoviesError or MoviesTask(null),
for example, will not obtain errors or task movies in other threads.
Currently, only the main thread can access the user interface. You can play movies or open user dialogs only from the main thread.
To perform an export operation that requires a user dialog, for example, you need to first execute the dialog on the main thread. You can then perform the actual export operation on a separate thread without tying up the user interface. You can pass the information returned by the dialog to another thread by passing an atom container, using functions that get settings as atom containers and set settings from atom containers.
Calling EnterMoviesOnThread indicates
that QuickTime should perform additional thread-safety checks on
components opened and operations performed on the thread. If you
call a function that requires use of a non-thread-safe component,
or requires access to the user interface, or performs another thread-unsafe
operation, QuickTime returns a distinguished error (componentNotThreadSafeErr =
-2098).
Not all QuickTime components are thread-safe, so your code should be designed to detect threading error messages and transfer necessary tasks to the main thread. For example, you might spawn a thread to import a list of image files. The thread would import all the image files that have thread-safe importer components and return a list of any unhandled cases to the main thread, which could then import any remaining image files in the foreground.
From the main thread, your application can call CSSetComponentsThreadMode,
passing it kCSAcceptThreadSafeComponentsOnlyMode,
to see if opening a movie or other QuickTime object will succeed
when attempted from a preemptive thread. You can do this only with Mac
OS X version 10.3 or later.
It is important that you use multiple threads to perform tasks on different movies. Do not use multiple threads to act on the same movie concurrently.
You can work on a given movie in separate threads sequentially, for example to perform an export in the background after playing a movie in the foreground, by passing a data reference from one thread to another when you are through operating on the movie in the first thread.
QuickTime 6.4 includes the following functions that you can use to associate movies and time bases with threads:
AttachMovieToCurrentThread attaches
a movie to the current thread.
AttachTimeBaseToCurrentThread attaches
a time base to the current thread.
DetachMovieFromCurrentThread detaches
a movie from the current thread.
DetachTimeBaseFromCurrentThread detaches
a time base from the current thread.
GetMovieThreadAttachState determines
whether a given movie is attached to a thread.
GetTimeBaseThreadAttachState determines
whether a given time base is attached to a thread.
You can open movies in separate threads from the same source file, but each thread creates its own movie from the file. You can, however, play one movie while exporting the other, for example, which allows your application to behave as if it could concurrently process the same movie on different threads. This currently works with movies whose data is accessed from files, but not with movies accessed from a URL. The URL data handler is not currently thread-safe, so it is not possible to work with separate movies from the same URL in different threads.
Similarly, a thread-safe component type can be used by multiple threads at the same time, but each thread must instantiate its own instance of the component. Do not call a single component instance from multiple threads.
Many QuickTime functions that expect a component instance as a parameter also accept a component in that parameter. This ambiguity should generally be avoided when using different instances of the same component from multiple threads.
When your thread is done working with QuickTime, call ExitMoviesOnThread prior
to closing the thread. Failure to do so may cause a memory leak,
because resources allocated by EnterMoviesOnThread for
the private QuickTime environment may fail to be released.
You may call EnterMoviesOnThread multiple
times, which allows libraries to use this function without needing
to know if their host thread has already done so. Subsequent calls
do little more than increment a counter. To prevent memory leaks,
one call to ExitMoviesOnThread should
be made for each call to EnterMoviesOnThread.
Never call ExitMoviesOnThread without
a prior call to EnterMoviesOnThread.
Calls may be nested, but each instance of ExitMoviesOnThread must
be balanced by a prior call to EnterMoviesOnThread.
Because QuickTime did not previously support concurrent use
from multiple threads, programs that already use QuickTime in preemptive
threads may, accidentally or intentionally, make use of formerly
global QuickTime states and data structures. For example, in older
versions of QuickTime a call to MoviesTask(null) gives
processor time to all movies in any thread. Similarly, an error
handling routine in one thread might successfully detect errors
in another.
While this kind of cross-thread interaction is more likely
to do harm than good, the possibility exists that existing applications
may rely on it. Consequently, if a thread makes calls to QuickTime
without calling EnterMoviesOnThread,
the thread shares QuickTime’s state and data structures on the
main thread and any other threads that have not called EnterMoviesOnThread.
It is strongly recomended that you transition existing code
away from any dependance on QuickTime states and data structures
across threads as quickly as possible. When writing new code, threads
that call QuickTime should use EnterMoviesOnThread to
create private, thread-specific versions of the QuickTime environment.
For developers who are not familiar with QuickTime’s existing API, it’s possible to assume––largely because Mac OS X is multithreaded––that QuickTime is thread-safe. This is not the case. Your application can’t call QuickTime from arbitrary threads.
However, in some cases and with great care, in QuickTime 6.4 you are able to perform a few operations on secondary threads. The key point is that you can’t do it willy-nilly. If you need to use QuickTime on secondary threads, in limited cases, it is now possible.
The rules for new threads that call QuickTime are as follows:
Call CSSetComponentsThreadMode(kCSAcceptThreadSafeComponentsOnlyMode) early
on. This will instruct the Component Manager not to open non-thread-safe
components from this thread.
If you get componentNotThreadSafeErr from
a QuickTime API call, the main thread must do the work instead.
Component developers should make their components thread-safe
and set the new component flag cmThreadSafe.
The following parts of Mac OS X are newly thread-safe:
QuickDraw
the Component Manager
the Alias Manager
the Memory Manager (MemError is
now per-thread.)
The following are not thread-safe:
the Resource Manager
Component RefCons for shared
globals
In summary, you should unblock your user interface by moving slow QuickTime processing to other threads, cope with dynamic discovery of non-thread-safe media, and make your components thread-safe.
Last updated: 2003-09-01