<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://commons.oreilly.com/wiki/skins/common/feed.css?97"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>QuickTime for Java: A Developer's Notebook/Playing Movies - Revision history</title>
		<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies&amp;action=history</link>
		<description>Revision history for this page on the wiki</description>
		<language>en</language>
		<generator>MediaWiki 1.11.0</generator>
		<lastBuildDate>Mon, 20 May 2013 14:06:40 GMT</lastBuildDate>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies&amp;diff=7237&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 13:22, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 13:22:47 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies&amp;diff=7158&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 13:17, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 13:17:34 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies</comments>		</item>
		<item>
			<title>Evanlenz: 1 revision(s)</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies&amp;diff=4457&amp;oldid=prev</link>
			<description>&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:25, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 00:25:56 GMT</pubDate>			<dc:creator>Evanlenz</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies&amp;diff=4456&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:17, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 73:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 73:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-1. QuickTime file selector'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-1. QuickTime file selector'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_2_tt22.png|QuickTime file selector]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_2_tt22.png|QuickTime file selector]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 81:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 81:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-2. Simple movie player'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-2. Simple movie player'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_2_tt23.png|Simple movie player]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_2_tt23.png|Simple movie player]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 148:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 148:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-3. Movie with on-screen controller'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-3. Movie with on-screen controller'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_2_tt26.png|Movie with on-screen controller]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_2_tt26.png|Movie with on-screen controller]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 219:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 219:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-4. Playing a movie with a Swing JComponent'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-4. Playing a movie with a Swing JComponent'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_2_tt27.png|Playing a movie with a Swing JComponent]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_2_tt27.png|Playing a movie with a Swing JComponent]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 359:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 359:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-5. Controlling movie play rate with AWT buttons'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-5. Controlling movie play rate with AWT buttons'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_2_tt28.png|Controlling movie play rate with AWT buttons]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_2_tt28.png|Controlling movie play rate with AWT buttons]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 472:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 472:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-6. Displaying the current time of a movie'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-6. Displaying the current time of a movie'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_2_tt29.png|Displaying the current time of a movie]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_2_tt29.png|Displaying the current time of a movie]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 552:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 552:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-7. Disabling buttons via callbacks'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-7. Disabling buttons via callbacks'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_2_tt34.png|Disabling buttons via callbacks]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_2_tt34.png|Disabling buttons via callbacks]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 749:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 749:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-8. Movie played from a URL DataRef'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 2-8. Movie played from a URL DataRef'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_2_tt37.png|Movie played from a URL DataRef]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_2_tt37.png|Movie played from a URL DataRef]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 00:17:35 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies</comments>		</item>
		<item>
			<title>Evanlenz: 1 revision(s)</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies&amp;diff=4305&amp;oldid=prev</link>
			<description>&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:16, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 00:16:18 GMT</pubDate>			<dc:creator>Evanlenz</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies&amp;diff=4304&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:15, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 00:15:32 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies</comments>		</item>
		<item>
			<title>Evanlenz: 1 revision(s)</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies&amp;diff=4153&amp;oldid=prev</link>
			<description>&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 23:57, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Thu, 06 Mar 2008 23:57:55 GMT</pubDate>			<dc:creator>Evanlenz</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies&amp;diff=4152&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{QuickTime for Java: A Developer's Notebook/TOC}}&lt;br /&gt;
Even if you have more elaborate plans for QuickTime for Java, I'm going to assume that your plans will, at some point in time, require reading in a movie or other QuickTime-compatible file, locally or from the network. This chapter presents basic techniques of getting a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; object, getting it into the Java display space, and adding more sophisticated controls so that your user (or just your code) can know what's happening inside a playing movie and take control.&lt;br /&gt;
&lt;br /&gt;
== Building a Simple Movie Player ==&lt;br /&gt;
&lt;br /&gt;
I'll begin with &amp;quot;the simplest thing that could possibly work:&amp;quot; an application to ask the user for the location of a QuickTime file, which is then opened and put in a Java AWT &amp;lt;tt&amp;gt;Frame&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
[[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-EX-1|Example 2-1]] shows the code for a simple movie player.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-EX-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 2-1. Simple movie player'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch02;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.app.view.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
  &lt;br /&gt;
 import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
  &lt;br /&gt;
 import java.awt.*;&lt;br /&gt;
  &lt;br /&gt;
 public class BasicQTPlayer extends Frame {&lt;br /&gt;
   public BasicQTPlayer (Movie m) throws QTException {&lt;br /&gt;
       super (&amp;quot;Basic QT Player&amp;quot;);&lt;br /&gt;
       QTComponent qc = QTFactory.makeQTComponent (m);&lt;br /&gt;
       Component c = qc.asComponent( );&lt;br /&gt;
       add (c);&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public static void main (String[  ] args) {&lt;br /&gt;
       try {&lt;br /&gt;
           QTSessionCheck.check( );&lt;br /&gt;
           QTFile file =&lt;br /&gt;
               QTFile.standardGetFilePreview (&lt;br /&gt;
           QTFile.kStandardQTFileTypes);&lt;br /&gt;
           OpenMovieFile omFile = OpenMovieFile.asRead (file);&lt;br /&gt;
           Movie m = Movie.fromFile (omFile);&lt;br /&gt;
           Frame f = new BasicQTPlayer (m);&lt;br /&gt;
           f.pack( );&lt;br /&gt;
           f.setVisible(true);&lt;br /&gt;
           m.start( );&lt;br /&gt;
       } catch (Exception e) {&lt;br /&gt;
           e.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Compile this from the command line (remember, as shown in the previous chapter, you must specify &amp;lt;tt&amp;gt;QTJava.zip&amp;lt;/tt&amp;gt; in the classpath; this is the Mac OS X version):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''If you've downloaded the book code, compile and run with ant run-ch02-basicqtplayer''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 cadamson% javac -d classes -classpath &lt;br /&gt;
   src:/System/Library/Java/Extensions/QTJava.zip &lt;br /&gt;
   src/com/oreilly/qtjnotebook/ch02/BasicQTPlayer.java&lt;br /&gt;
&lt;br /&gt;
Then run the program from the command line:&lt;br /&gt;
&lt;br /&gt;
 cadamson% java -classpath classes&lt;br /&gt;
   com.oreilly.qtjnotebook.ch02.BasicQTPlayer&lt;br /&gt;
&lt;br /&gt;
When the program starts up, the user will initially see QuickTime's file selector, shown in [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-FIG-1|Figure 2-1]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-FIG-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 2-1. QuickTime file selector'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_2_tt22.png|QuickTime file selector]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After the user selects a file (note that I have not provided any error handling if the user clicks Cancel!), the movie will open in a window at its default size and start playing, as seen in [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-FIG-2|Figure 2-2]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-FIG-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 2-2. Simple movie player'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_2_tt23.png|Simple movie player]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this program does not provide any means of quitting the application once the movie finishes playing (or before then, for that matter). Press Ctrl-C from the command line to kill the app. Mac users will also get a &amp;quot;Quit com.oreilly.qtjnotebook.ch02.BasicQTPlayer&amp;quot; menu item.&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
Take a look at the application. The class extends &amp;lt;tt&amp;gt;java.awt.Frame&amp;lt;/tt&amp;gt; and supplies a constructor that takes a &amp;lt;tt&amp;gt;quicktime.std.movies.Movie&amp;lt;/tt&amp;gt; object. Given this &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; , it asks the &amp;lt;tt&amp;gt;QTFactory&amp;lt;/tt&amp;gt; (in package &amp;lt;tt&amp;gt;quicktime.app.view&amp;lt;/tt&amp;gt;) for a &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt;. From this object, it gets a &amp;lt;tt&amp;gt;java.awt.Component&amp;lt;/tt&amp;gt; , which is added to the &amp;lt;tt&amp;gt;Frame&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;main( )&amp;lt;/tt&amp;gt; method starts by doing the QuickTime session check from the last chapter. Then it brings up a file selector dialog, from which it gets a &amp;lt;tt&amp;gt;quicktime.io.QTFile&amp;lt;/tt&amp;gt; , from which it gets an &amp;lt;tt&amp;gt;OpenMovieFile&amp;lt;/tt&amp;gt;, which leads to the creation of a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; object with &amp;lt;tt&amp;gt;Movie.fromFile( )&amp;lt;/tt&amp;gt; . This &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; is then passed to the &amp;lt;tt&amp;gt;QTBasicPlayer&amp;lt;/tt&amp;gt; constructor, and the resulting &amp;lt;tt&amp;gt;Frame&amp;lt;/tt&amp;gt; is &amp;lt;tt&amp;gt;pack( )&amp;lt;/tt&amp;gt;ed and shown. Finally, &amp;lt;tt&amp;gt;main( )&amp;lt;/tt&amp;gt; calls the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;'s &amp;lt;tt&amp;gt;start()&amp;lt;/tt&amp;gt; method to play the movie.&lt;br /&gt;
&lt;br /&gt;
Notice how practically every line of code in this application either declares that it throws &amp;lt;tt&amp;gt;QTException&amp;lt;/tt&amp;gt; or is wrapped in a try-catch block. That's because pretty much every QuickTime Java call can potentially throw a &amp;lt;tt&amp;gt;QTException&amp;lt;/tt&amp;gt;, which means you either need to catch it or (more frequently) declare that your method throws it to the caller. Presumably at some point further up the call chain, you'll catch the exception and do something responsible with it, such as bringing up an error dialog.&lt;br /&gt;
&lt;br /&gt;
Another point of interest is the &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; . This is an interface that exposes methods that allow you to change the movie (or image) displayed by an on-screen widget. &amp;lt;tt&amp;gt;asComponent()&amp;lt;/tt&amp;gt; returns an AWT &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt; that can be added to an AWT layout just like any other component. Now here's the dirty little secret: all &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt;s received from the &amp;lt;tt&amp;gt;QTFactory&amp;lt;/tt&amp;gt; really are AWT &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;s, and can be cast safely. That means the &amp;lt;tt&amp;gt;asComponent( )&amp;lt;/tt&amp;gt; call:&lt;br /&gt;
&lt;br /&gt;
 Component c = qc.asComponent( );&lt;br /&gt;
&lt;br /&gt;
is functionally equivalent to:&lt;br /&gt;
&lt;br /&gt;
 Component c = (Component) qc;&lt;br /&gt;
&lt;br /&gt;
Meaning that &amp;lt;tt&amp;gt;asComponent( )&amp;lt;/tt&amp;gt; is really there just for compile-time type safety.&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...using the AWT or Swing file selector? Sure, you can use these—they'll return a &amp;lt;tt&amp;gt;java.io.File&amp;lt;/tt&amp;gt; object, which can then be used to get a &amp;lt;tt&amp;gt;QTFile&amp;lt;/tt&amp;gt;. But the QuickTime file selector is arguably nicer, because on Windows it shows a little preview of the selected movie. Another thing to notice is the odd little constant &amp;lt;tt&amp;gt;kStandardQTFileTypes&amp;lt;/tt&amp;gt;. The &amp;lt;tt&amp;gt;standardGetFilePreview( )&amp;lt;/tt&amp;gt; call takes an &amp;lt;tt&amp;gt;int[ ]&amp;lt;/tt&amp;gt; of up to four &amp;quot;types&amp;quot; of files to allow the user to select. The constant is a very convenient way to specify &amp;quot;just show typical file types that QuickTime can handle.&amp;quot; You can also pass in &amp;lt;tt&amp;gt;null&amp;lt;/tt&amp;gt; to show all files.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''[[QuickTime for Java: A Developer's Notebook/Working with Components|Chapter 4]] has more on the FOUR_CHAR_CODE integers used for these &amp;quot;types.''&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding a Controller ==&lt;br /&gt;
&lt;br /&gt;
This application isn't particularly user-friendly yet—the user can't start or stop the movie, move through it, or set the volume. Fortunately, it's easy to use a &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; to get the standard QuickTime controller bar, an on-screen control widget that provides a play/pause button, a volume control, and the movie position control (typically called a &amp;quot;scrubber&amp;quot; in QuickTime parlance).&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
Create a new class in the source file ''BasicQTController.java''. The &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt; is exactly the same as before, while the constructor adds one new line and changes another, as seen in [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-EX-2|Example 2-2]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-EX-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 2-2. Getting a movie component with a controller'''&lt;br /&gt;
&lt;br /&gt;
 public class BasicQTController extends Frame {&lt;br /&gt;
  &lt;br /&gt;
   public BasicQTController (Movie m) throws QTException {&lt;br /&gt;
       super (&amp;quot;Basic QT Controller&amp;quot;);&lt;br /&gt;
       MovieController mc = new MovieController(m);&lt;br /&gt;
       QTComponent qc = QTFactory.makeQTComponent (mc);&lt;br /&gt;
       Component c = qc.asComponent( );&lt;br /&gt;
       add (c);&lt;br /&gt;
       pack( );&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch02-basicqtcontroller''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The result, when run, looks like the application in [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-FIG-3|Figure 2-3]]. Notice the presence of the classic QuickTime control bar at the bottom of the window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-FIG-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 2-3. Movie with on-screen controller'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_2_tt26.png|Movie with on-screen controller]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
This time, instead of asking the &amp;lt;tt&amp;gt;QTFactory&amp;lt;/tt&amp;gt; to make a &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; from the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;, the program creates a &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; object from the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; and asks the &amp;lt;tt&amp;gt;QTFactory&amp;lt;/tt&amp;gt; to make a &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; from that. This eliminates the need for &amp;lt;tt&amp;gt;main( )&amp;lt;/tt&amp;gt; to call &amp;lt;tt&amp;gt;start( )&amp;lt;/tt&amp;gt;, because the user can start and stop the movie from the play/pause button on the control bar.&lt;br /&gt;
&lt;br /&gt;
== Getting a Movie-Playing JComponent ==&lt;br /&gt;
&lt;br /&gt;
The previous tasks have used the AWT, which seemingly nobody uses anymore. Many developers will want to create a Swing GUI, and thus they need a movie-playing &amp;lt;tt&amp;gt;JComponent&amp;lt;/tt&amp;gt;. QuickTime for Java can provide one.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
[[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-EX-3|Example 2-3]] presents a rewrite of the previous &amp;lt;tt&amp;gt;BasicQTPlayer&amp;lt;/tt&amp;gt; that does everything with Swing equivalents (&amp;lt;tt&amp;gt;JFrame&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;Frame&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;JComponent&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, etc.).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-EX-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 2-3. All-Swing simple movie player'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch02;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.app.view.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
  &lt;br /&gt;
 import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
  &lt;br /&gt;
 import java.awt.*;&lt;br /&gt;
 import javax.swing.*;&lt;br /&gt;
  &lt;br /&gt;
 public class BasicSwingQTPlayer extends JFrame {&lt;br /&gt;
  &lt;br /&gt;
   public BasicSwingQTPlayer (Movie m) throws QTException {&lt;br /&gt;
       super (&amp;quot;Basic Swing QT Player&amp;quot;);&lt;br /&gt;
       MoviePlayer mp = new MoviePlayer (m);&lt;br /&gt;
       QTJComponent qc = QTFactory.makeQTJComponent (mp);&lt;br /&gt;
       JComponent jc = qc.asJComponent( );&lt;br /&gt;
       getContentPane( ).add (jc);&lt;br /&gt;
       pack( );&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public static void main (String[  ] args) {&lt;br /&gt;
       try {&lt;br /&gt;
           QTSessionCheck.check( );&lt;br /&gt;
           QTFile file =&lt;br /&gt;
               QTFile.standardGetFilePreview (&lt;br /&gt;
           QTFile.kStandardQTFileTypes);&lt;br /&gt;
           OpenMovieFile omFile = OpenMovieFile.asRead (file);&lt;br /&gt;
           Movie m = Movie.fromFile (omFile);&lt;br /&gt;
           JFrame f = new BasicSwingQTPlayer (m);&lt;br /&gt;
           f.pack( );&lt;br /&gt;
           f.setVisible(true);&lt;br /&gt;
           m.start( );&lt;br /&gt;
       } catch (Exception e) {&lt;br /&gt;
           e.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch02-basicswingqtplayer''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This produces a simple movie-player window—as seen in [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-FIG-4|Figure 2-4]]—using Swing, but visually indistinguishable from its AWT equivalent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-FIG-4&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 2-4. Playing a movie with a Swing JComponent'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_2_tt27.png|Playing a movie with a Swing JComponent]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
Creating a &amp;lt;tt&amp;gt;QTJComponent&amp;lt;/tt&amp;gt; (read that as &amp;quot;QT JComponent,&amp;quot; not &amp;quot;QTJ Component&amp;quot;—I know, it confused everyone on the developer list at first, too) requires an object called a &amp;lt;tt&amp;gt;MoviePlayer&amp;lt;/tt&amp;gt;, which can be simply created from a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;. This is passed to &amp;lt;tt&amp;gt;QTFactory&amp;lt;/tt&amp;gt; 's &amp;lt;tt&amp;gt;makeQTJComponent()&amp;lt;/tt&amp;gt; method to get a &amp;lt;tt&amp;gt;QTJComponent&amp;lt;/tt&amp;gt;, which in turn can be turned into a Swing &amp;lt;tt&amp;gt;JComponent&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;asJComponent( )&amp;lt;/tt&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...getting a control bar? Good question. QTJ doesn't provide one for Swing. Remember, the movie's display and the control bar are both native widgets—to display the movie in Swing, the movie has to be drawn to an off-screen region, then painted by Java onto the &amp;lt;tt&amp;gt;JComponent&amp;lt;/tt&amp;gt; so that everything is &amp;quot;lightweight,&amp;quot; in Java parlance. QTJ provides this for the movie but not for the control bar (perhaps because it would be difficult for the native QuickTime to keep track of your mouse movements in the Java space), so a developer would need to roll her own Swing widget for controlling the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;, trapping mouse actions and calling appropriate methods on the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Methods to control a Movie or MovieController are introduced in the next task''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And what about the awful performance? Good catch—depending on your source, the frame rate of this version might be far worse than the AWT equivalent. Think about the earlier paragraph that says the movie needs to be drawn into an off-screen buffer and then reimaged into Swing. Doesn't that sound a little redundant? Think the overhead is going to add up if you need to do it 30 times a second? It is, and it does. Performance of the &amp;lt;tt&amp;gt;QTJComponent&amp;lt;/tt&amp;gt; is ''awful'' compared to that of the &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; . Not only does QTJ have to do extra work, but it also doesn't score hardware-accelerated graphics benefits it might otherwise be able to achieve by using its native rendering pipeline.&lt;br /&gt;
&lt;br /&gt;
So, I'm going to tell you something that clashes with every other Java GUI book you've ever read: ''go ahead and mix Swing and AWT widgets'' . That's right. It's not going to cause blindness, the end of the world, or a drop in your home's resale value.&lt;br /&gt;
&lt;br /&gt;
To be specific, you can freely mix AWT widgets, like the &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt;, and Swing widgets in the same container as long as they don't overlap. Unless you're doing something tricky with Swing's &amp;quot;glass pane,&amp;quot; or possibly the &amp;lt;tt&amp;gt;JLayeredPane&amp;lt;/tt&amp;gt;, you're probably safe.&lt;br /&gt;
&lt;br /&gt;
The common overlap problem comes from menus, both those that descend from the menu bar and pop-up menus. A lightweight Swing menu will go behind any AWT component, and the result isn't pretty. The way around this is to call &amp;lt;tt&amp;gt;setLightweightPopupEnabled(false)&amp;lt;/tt&amp;gt; on all your menus that might overlap with your &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
By the way, this problem isn't limited to QTJ. Most Java toolkits that use native drawing spaces for performance reasons run into the same issue. Sun's JMF defaults to heavyweight components, as does the OpenGL-to-Java library JOGL. Getting AWT and Swing to play nice is a common issue for Java multimedia developers.&lt;br /&gt;
&lt;br /&gt;
== Controlling a Movie Programmatically ==&lt;br /&gt;
&lt;br /&gt;
For various reasons, an application might want to control the movie via its own method calls, in lieu of or in addition to the GUI provided by QuickTime's &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt;. One example of this is &amp;lt;tt&amp;gt;Movie.start( )&amp;lt;/tt&amp;gt;. You can programmatically issue many more commands, some of which you can't issue with the default control.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
[[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-EX-4|Example 2-4]] shows a new class, &amp;lt;tt&amp;gt;BasicQTButtons.java&amp;lt;/tt&amp;gt;. The &amp;lt;tt&amp;gt;main()&amp;lt;/tt&amp;gt; is exactly the same as &amp;lt;tt&amp;gt;BasicQTPlayer&amp;lt;/tt&amp;gt;, but the constructor has extra work to create some control buttons, and an &amp;lt;tt&amp;gt;actionPerformed( )&amp;lt;/tt&amp;gt; method implements AWT's &amp;lt;tt&amp;gt;ActionListener&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch02-basicqtbuttons.''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-EX-4&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 2-4. Programmatic control of a movie'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch02;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.app.view.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
  &lt;br /&gt;
 import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
  &lt;br /&gt;
 import java.awt.*;&lt;br /&gt;
 import java.awt.event.*;&lt;br /&gt;
  &lt;br /&gt;
 public class BasicQTButtons extends Frame&lt;br /&gt;
   implements ActionListener {&lt;br /&gt;
  &lt;br /&gt;
   Button revButton,&lt;br /&gt;
       stopButton,&lt;br /&gt;
       startButton,&lt;br /&gt;
       fwdButton;&lt;br /&gt;
  &lt;br /&gt;
   Movie theMovie;&lt;br /&gt;
  &lt;br /&gt;
   public BasicQTButtons (Movie m) throws QTException {&lt;br /&gt;
       super (&amp;quot;Basic QT Player&amp;quot;);&lt;br /&gt;
       theMovie = m;&lt;br /&gt;
       QTComponent qc = QTFactory.makeQTComponent (m);&lt;br /&gt;
       Component c = qc.asComponent( );&lt;br /&gt;
       setLayout (new BorderLayout( ));&lt;br /&gt;
       add (c, BorderLayout.CENTER);&lt;br /&gt;
       Panel buttons = new Panel( );&lt;br /&gt;
       revButton = new Button(&amp;quot;&amp;lt;&amp;quot;);&lt;br /&gt;
       revButton.addActionListener (this);&lt;br /&gt;
       stopButton = new Button (&amp;quot;0&amp;quot;);&lt;br /&gt;
       stopButton.addActionListener (this);&lt;br /&gt;
       startButton = new Button (&amp;quot;1&amp;quot;);&lt;br /&gt;
       startButton.addActionListener (this);&lt;br /&gt;
       fwdButton = new Button (&amp;quot;&amp;gt;&amp;quot;);&lt;br /&gt;
       fwdButton.addActionListener (this);&lt;br /&gt;
       buttons.add (revButton);&lt;br /&gt;
       buttons.add (stopButton);&lt;br /&gt;
       buttons.add (startButton);&lt;br /&gt;
       buttons.add (fwdButton);&lt;br /&gt;
       add (buttons, BorderLayout.SOUTH);&lt;br /&gt;
       pack( );&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public void actionPerformed (ActionEvent e) {&lt;br /&gt;
       try {&lt;br /&gt;
           if (e.getSource( ) =  = revButton)&lt;br /&gt;
               theMovie.setRate (theMovie.getRate( ) - 0.5f);&lt;br /&gt;
           else if (e.getSource( ) =  = stopButton)&lt;br /&gt;
               theMovie.stop( );&lt;br /&gt;
           else if (e.getSource( ) =  = startButton)&lt;br /&gt;
               theMovie.start( );&lt;br /&gt;
           else if (e.getSource( ) =  = fwdButton)&lt;br /&gt;
               theMovie.setRate (theMovie.getRate( ) + 0.5f);&lt;br /&gt;
       } catch (QTException qte) {&lt;br /&gt;
           qte.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public static void main (String[  ] args) {&lt;br /&gt;
       try {&lt;br /&gt;
           QTSessionCheck.check( );&lt;br /&gt;
           QTFile file =&lt;br /&gt;
               QTFile.standardGetFilePreview (&lt;br /&gt;
                 QTFile.kStandardQTFileTypes);&lt;br /&gt;
           OpenMovieFile omFile = OpenMovieFile.asRead (file);&lt;br /&gt;
           Movie m = Movie.fromFile (omFile);&lt;br /&gt;
           Frame f = new BasicQTButtons (m);&lt;br /&gt;
           f.pack( );&lt;br /&gt;
           f.setVisible(true);&lt;br /&gt;
           m.start( );&lt;br /&gt;
       } catch (Exception e) {&lt;br /&gt;
           e.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run this program to see a display like that shown in [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-FIG-5|Figure 2-5]]. The buttons call functions to set the rate of the movie. The rate is 0 for a stopped movie, a negative number for a movie playing backward, and a positive number for a movie playing forward. A rate of 1.0 represents normal playing speed, so 0.5 would be half speed, and 2.0 would be double speed. The buttons have the following functions:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;&lt;br /&gt;
: Reduces the rate by 0.5. For a playing movie (rate = 1.0), clicking this once will cut it to half speed (0.5), twice will stop it (0.0), three times will go to half-speed reverse (-0.5), four times to normal-speed reverse (-1.0), etc.&lt;br /&gt;
;0&lt;br /&gt;
: Stops the movie, by way of a call to &amp;lt;tt&amp;gt;Movie.stop()&amp;lt;/tt&amp;gt;, which is the same as &amp;lt;tt&amp;gt;Movie.setRate(0)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
;1&lt;br /&gt;
: Plays the movie forward at normal speed, equivalent to &amp;lt;tt&amp;gt;Movie.setRate(1)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
;&amp;gt;&lt;br /&gt;
: Increases the rate by 0.5.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-FIG-5&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 2-5. Controlling movie play rate with AWT buttons'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_2_tt28.png|Controlling movie play rate with AWT buttons]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
This is a very simple example of methods that can be called to affect a movie's playback. These are the methods a developer creating his own control widget (i.e., ignoring the warning in the previous section) would need to use.&lt;br /&gt;
&lt;br /&gt;
Another useful method is &amp;lt;tt&amp;gt;setVolume( )&amp;lt;/tt&amp;gt;, a self-explanatory method that takes values from 0.0 (silence) to 1.0 (maximum). Also useful is a &amp;lt;tt&amp;gt;setTime( )&amp;lt;/tt&amp;gt; method, which changes the current position in the movie.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''The next task covers QuickTime's concept of time, which is used as the parameter for setTime( )''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...using some similar methods in &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; ? A &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; object, even if it's not used to get an on-screen control widget, provides some methods with equivalent functionality, but with different names and conventions. For example, &amp;lt;tt&amp;gt;stop()&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;start( )&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;setRate( )&amp;lt;/tt&amp;gt; are all effectively wrapped by a single method, &amp;lt;tt&amp;gt;play( )&amp;lt;/tt&amp;gt; , which takes a rate argument. &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; also has some unique functionality, such as only playing the selection, setting &amp;quot;looping&amp;quot; behavior (immediately returning to the beginning when the end is reached, or vice versa), and a method called &amp;lt;tt&amp;gt;setPlayEveryFrame()&amp;lt;/tt&amp;gt; , which will force the movie to not drop frames, even if that requires it to play more slowly than it should.&lt;br /&gt;
&lt;br /&gt;
== Showing a Movie's Current Time ==&lt;br /&gt;
&lt;br /&gt;
Advanced users, particularly those doing editing, would like to know a movie's current time—i.e., where they are in the movie. The scrubber can provide a general idea of the movie's current time, but certain applications call for an exact value.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
[[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-EX-5|Example 2-5]]s &amp;lt;tt&amp;gt;BasicQTTimeDisplay&amp;lt;/tt&amp;gt; code extends the &amp;lt;tt&amp;gt;BasicQTController&amp;lt;/tt&amp;gt; by adding a &amp;lt;tt&amp;gt;Label&amp;lt;/tt&amp;gt; to the bottom of the &amp;lt;tt&amp;gt;Frame&amp;lt;/tt&amp;gt; . A Swing &amp;lt;tt&amp;gt;Timer&amp;lt;/tt&amp;gt; calls &amp;lt;tt&amp;gt;actionPerformed( )&amp;lt;/tt&amp;gt; every 250 milliseconds, and this method checks the current time of the movie and resets the label.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''The Swing version of Timer is used to ensure that changing the label occurs on the AWT event-dispatch thread''.&lt;br /&gt;
&lt;br /&gt;
Compile and run this examnple with ant run-ch02-basicqttimedisplay.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-EX-5&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 2-5. Displaying the current time of a movie'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch02;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.app.view.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
  &lt;br /&gt;
 import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
  &lt;br /&gt;
 import java.awt.*;&lt;br /&gt;
 import java.awt.event.*;&lt;br /&gt;
  &lt;br /&gt;
 public class BasicQTTimeDisplay extends Frame&lt;br /&gt;
   implements ActionListener {&lt;br /&gt;
   Movie theMovie;&lt;br /&gt;
   Label timeLabel;&lt;br /&gt;
  &lt;br /&gt;
   public BasicQTTimeDisplay (Movie m) throws QTException {&lt;br /&gt;
       super (&amp;quot;Basic QT Controller&amp;quot;);&lt;br /&gt;
       theMovie = m;&lt;br /&gt;
       MovieController mc = new MovieController(m);&lt;br /&gt;
       QTComponent qc = QTFactory.makeQTComponent (mc);&lt;br /&gt;
       Component c = qc.asComponent( );&lt;br /&gt;
       setLayout (new BorderLayout( ));&lt;br /&gt;
       add (c, BorderLayout.CENTER);&lt;br /&gt;
       timeLabel = new Label (&amp;quot;-:--&amp;quot;, Label.CENTER);&lt;br /&gt;
       add (timeLabel, BorderLayout.SOUTH);&lt;br /&gt;
       javax.swing.Timer timer =&lt;br /&gt;
           new javax.swing.Timer (250, this);&lt;br /&gt;
       timer.start( );&lt;br /&gt;
       pack( );&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public void actionPerformed (ActionEvent e) {&lt;br /&gt;
       if (theMovie =  = null)&lt;br /&gt;
                   return;&lt;br /&gt;
       try {&lt;br /&gt;
           int totalSeconds = theMovie.getTime( ) /&lt;br /&gt;
                              theMovie.getTimeScale( );&lt;br /&gt;
           int seconds = totalSeconds % 60;&lt;br /&gt;
           int minutes = totalSeconds / 60;&lt;br /&gt;
           String secString = (seconds &amp;gt; 9) ?&lt;br /&gt;
               Integer.toString (seconds) :&lt;br /&gt;
               (&amp;quot;0&amp;quot; + Integer.toString (seconds));&lt;br /&gt;
           String minString = Integer.toString (minutes);&lt;br /&gt;
           timeLabel.setText (minString + &amp;quot;:&amp;quot; + secString);&lt;br /&gt;
       } catch (QTException qte) {&lt;br /&gt;
           qte.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public static void main (String[  ] args) {&lt;br /&gt;
       try {&lt;br /&gt;
           QTSessionCheck.check( );&lt;br /&gt;
           QTFile file =&lt;br /&gt;
               QTFile.standardGetFilePreview (&lt;br /&gt;
                  QTFile.kStandardQTFileTypes);&lt;br /&gt;
           OpenMovieFile omFile = OpenMovieFile.asRead (file);&lt;br /&gt;
           Movie m = Movie.fromFile (omFile);&lt;br /&gt;
           Frame f = new BasicQTTimeDisplay (m);&lt;br /&gt;
           f.pack( );&lt;br /&gt;
           f.setVisible(true);&lt;br /&gt;
           m.start( );&lt;br /&gt;
       } catch (Exception e) {&lt;br /&gt;
           e.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This produces the application seen in [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-FIG-6|Figure 2-6]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-FIG-6&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 2-6. Displaying the current time of a movie'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_2_tt29.png|Displaying the current time of a movie]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
Obviously, some funky math is happening in the &amp;lt;tt&amp;gt;actionPerformed( )&amp;lt;/tt&amp;gt; method, which uses the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; 's &amp;lt;tt&amp;gt;getTime()&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getTimeScale( )&amp;lt;/tt&amp;gt; methods to figure out the current time in seconds, from which the program calculates the minutes and seconds portions of label.&lt;br /&gt;
&lt;br /&gt;
QuickTime has a concept of a &amp;quot;time scale,&amp;quot; which represents the time-keeping system of a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;. For a given time scale, ''n'', one unit of time in that time scale is 1/''n'' seconds. So, if a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; had a time scale of 1,000, the units would be milliseconds. &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;s actually default to a time scale of 600, but the actual value is irrelevant—you just have to be sure to work with whatever value the movie uses. &amp;lt;tt&amp;gt;getTime( )&amp;lt;/tt&amp;gt; returns the movie's current time in terms of the time scale, so for a time scale of 600, if &amp;lt;tt&amp;gt;getTime( )&amp;lt;/tt&amp;gt; returns 3,600, the current time is exactly 6 seconds into the movie. Other prominent methods that work with the time scale are &amp;lt;tt&amp;gt;setTime()&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getDuration( )&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''When we work with editing commands, we'll see that the Movie selection is also represented with time-scale values like these''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...just using milliseconds or nanoseconds or something ''normal'' instead of this crazy time-scale stuff? Actually, this flexible system of time scales is one of the best things about QuickTime. There needs to be some system of keeping track of time in a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;, and it's generally desirable for the units to be of a sufficient resolution so that all important times divide evenly—i.e., they can be represented as &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;s.&lt;br /&gt;
&lt;br /&gt;
Most Java programmers are used to thinking about time in terms of milliseconds, but that's totally inadequate for media. For example, CD audio has 44,100 samples a second, meaning that each sample takes 0.02267 . . . ms. So, that's obviously not going to work. Insisting on some smaller unit (microseconds, nanoseconds, picoseconds, etc.) won't help, because you can never know that it will be good enough for some arbitrary piece of time-based data. QuickTime's system of time scales allows the system of measurement to be ideally suited to the media itself.&lt;br /&gt;
&lt;br /&gt;
An interesting thought about the preceding example is that &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;'s default time base of 600 is also inadequate for CD audio. As it turns out, the tracks of a movie (more accurately, the &amp;quot;media&amp;quot; they refer to) can have their own time scales. So, a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; can have one time scale, its video can have another, and the audio can have a third.&lt;br /&gt;
&lt;br /&gt;
So, why is the default time scale 600? It appears to have originated with the 60 &amp;quot;ticks&amp;quot; per second used for time keeping on the oldest Macs, but it turns out to be a wonderfully common multiple of:&lt;br /&gt;
&lt;br /&gt;
* 24 (frames per second in film)&lt;br /&gt;
* 25 (frames per second in PAL and SECAM video, used in Europe, Africa, South America, and parts of Asia)&lt;br /&gt;
* 30 (frames per second in NTSC video, used in North America and Japan)&lt;br /&gt;
&lt;br /&gt;
Actually, that last example is not entirely true. NTSC color video is broadcast at an overall rate of 29.97 frames/sec, so to keep things straight, two frame numbers are dropped every minute (except for every 10th minute) to compensate for a synchronization problem in the color signal. QuickTime can handle these &amp;quot;drop-frame&amp;quot; video tracks by making the time scale 2,997 and each frame 100 units long. I told you it was handy!&lt;br /&gt;
&lt;br /&gt;
== Listening for Movie State-Changes ==&lt;br /&gt;
&lt;br /&gt;
One problem with polling to show the current time in the movie is that it's wasteful and inaccurate: it's optimal to check the time only when the movie's playing, and to eliminate latency, it would be nice to be notified when there's a sudden change in the current time, such as when the user slides the scrubber. Fortunately, there's a callback API to notify a program when things like this occur.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
This example revises the &amp;lt;tt&amp;gt;BasicQTButtons&amp;lt;/tt&amp;gt; program. The new version, &amp;lt;tt&amp;gt;BasicQTCallback&amp;lt;/tt&amp;gt;, asks to be notified when the rate changes. When the rate is 0, it will disable the stop button (labeled &amp;quot;0&amp;quot;), and when the rate is 1, it disables the play button (labeled &amp;quot;1&amp;quot;). For space, I'll list only the lines that have changed from &amp;lt;tt&amp;gt;BasicQTButtons&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
First, there are two new imports: &amp;lt;tt&amp;gt;quicktime.std.clocks&amp;lt;/tt&amp;gt;, which is where callbacks are defined, and &amp;lt;tt&amp;gt;quicktime.std&amp;lt;/tt&amp;gt;, whose &amp;lt;tt&amp;gt;StdQTConstants&amp;lt;/tt&amp;gt; provides constants to specify the callbacks' behavior:&lt;br /&gt;
&lt;br /&gt;
 import quicktime.std.*;&lt;br /&gt;
 import quicktime.std.clocks.*;&lt;br /&gt;
&lt;br /&gt;
Next, the constructor is changed to pass the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; to an inner class' constructor:&lt;br /&gt;
&lt;br /&gt;
 MyQTCallback myCallback = new MyQTCallback (m);&lt;br /&gt;
&lt;br /&gt;
And here's the inner class. It has a constructor that takes a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; argument and an &amp;lt;tt&amp;gt;execute( )&amp;lt;/tt&amp;gt; method:&lt;br /&gt;
&lt;br /&gt;
 class MyQTCallback extends RateCallBack {&lt;br /&gt;
   public MyQTCallback (Movie m) throws QTException {&lt;br /&gt;
       super (m.getTimeBase( ),&lt;br /&gt;
              0,&lt;br /&gt;
              StdQTConstants.triggerRateChange);&lt;br /&gt;
       callMeWhen( );&lt;br /&gt;
   }&lt;br /&gt;
   public void execute( ) {&lt;br /&gt;
       if (rateWhenCalled =  = 0.0) {&lt;br /&gt;
           startButton.setEnabled (true);&lt;br /&gt;
           stopButton.setEnabled (false);&lt;br /&gt;
       } else if (rateWhenCalled =  = 1.0) {&lt;br /&gt;
           startButton.setEnabled (false);&lt;br /&gt;
           stopButton.setEnabled (true);&lt;br /&gt;
       }&lt;br /&gt;
       // indicate that we want to be called again&lt;br /&gt;
       try {&lt;br /&gt;
           callMeWhen( );&lt;br /&gt;
       } catch (QTException qte) {&lt;br /&gt;
           qte.printStackTrace( );&lt;br /&gt;
&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
The result looks like the window in [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-FIG-7|Figure 2-7]]. Notice how in the screenshot, the stop button (&amp;quot;0&amp;quot;) is dimmed, indicating that the movie is already stopped. If the user hits &amp;quot;1,&amp;quot; the movie will play and the play button will be disabled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-FIG-7&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 2-7. Disabling buttons via callbacks'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_2_tt34.png|Disabling buttons via callbacks]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
The inner class creates a &amp;lt;tt&amp;gt;QTCallBack&amp;lt;/tt&amp;gt; , specifically a subclass of &amp;lt;tt&amp;gt;RateCallBack&amp;lt;/tt&amp;gt; . In its constructor, it indicates the conditions under which it wants to be called—by passing the &amp;lt;tt&amp;gt;triggerRateChange&amp;lt;/tt&amp;gt; flag, it asks to be called any time the rate changes. It then invokes &amp;lt;tt&amp;gt;callMeWhen( )&amp;lt;/tt&amp;gt; to actually register the callback.&lt;br /&gt;
&lt;br /&gt;
QuickTime invokes the callback via the &amp;lt;tt&amp;gt;execute()&amp;lt;/tt&amp;gt; method. This implementation checks the &amp;lt;tt&amp;gt;rateWhenCalled&amp;lt;/tt&amp;gt; value, inherited from &amp;lt;tt&amp;gt;RateCallBack&amp;lt;/tt&amp;gt;, to determine if the movie is stopped or started, and enables or disables buttons appropriately. Finally, it issues a new &amp;lt;tt&amp;gt;callMeWhen( )&amp;lt;/tt&amp;gt; call to ask to get called back on future rate changes—QuickTime callbacks are one-time-only deals, not like the &amp;lt;tt&amp;gt;EventListener&amp;lt;/tt&amp;gt;s that are typical in Java, so programmers have to remember to reregister for new callbacks after every &amp;lt;tt&amp;gt;execute()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...that &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; argument to the &amp;lt;tt&amp;gt;RateCallBack&amp;lt;/tt&amp;gt;'s constructor? Good question. This is one of those times where all the interesting values are defined only in the native documentation, not the Javadocs. The third argument, used to trigger the callback on any rate change, can be used with the constants &amp;lt;tt&amp;gt;triggerRateEquals&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;triggerRateNotEqual&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;triggerRateLT&amp;lt;/tt&amp;gt; (&amp;quot;less than&amp;quot;), &amp;lt;tt&amp;gt;triggerRateLTE&amp;lt;/tt&amp;gt; (&amp;quot;less than or equals&amp;quot;), etc., to define a behavior when the callback is made only when a certain condition is true. When using these triggers, the middle argument specifies the rate to be compared. For example, a callback could be set up to run only when the movie is playing, by passing &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;triggerRateNotEquals&amp;lt;/tt&amp;gt; as the second and third arguments, respectively.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''In the previous lab, a &amp;quot;rate not equal to 0&amp;quot; callback could be used to start or stop the time-label polling thread, so it would run only when the movie has a non-zero rate''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Are there other kinds of callbacks? Glad you asked. There are four major callbacks, each with its own class in &amp;lt;tt&amp;gt;quicktime.std.clocks&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;RateCallBack&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calls back when the rate changes, as seen in the earlier example.&lt;br /&gt;
;&amp;lt;tt&amp;gt;ExtremesCallBack&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calls back when playback reaches the beginning or end of the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;. Behavior is specified with &amp;lt;tt&amp;gt;triggerAtStart&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;triggerAtStop&amp;lt;/tt&amp;gt;.&lt;br /&gt;
;&amp;lt;tt&amp;gt;TimeCallBack&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calls back when playback reaches a specific time in the movie. The behavior flag determines if the callback occurs when moving forward (&amp;lt;tt&amp;gt;triggerTimeFwd&amp;lt;/tt&amp;gt;), backward (&amp;lt;tt&amp;gt;triggerTimeBwd&amp;lt;/tt&amp;gt;), or either forward or backward (&amp;lt;tt&amp;gt;triggerTimeEither&amp;lt;/tt&amp;gt;).&lt;br /&gt;
;&amp;lt;tt&amp;gt;TimeJumpCallBack&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calls back when the movie's current time changes in a way that is not consistent with its current play rate. The typical case here is that the user is grabbing the scrubber to move around the movie. Setting up this callback takes no parameters or behavior flags.&lt;br /&gt;
&lt;br /&gt;
And what about more sophisticated callback setup and teardown? This example doesn't need to clean up anything, but a more sophisticated application, one that opens and closes multiple movies, would need to release callback resources. This is done with a call to the &amp;lt;tt&amp;gt;QTCallBack&amp;lt;/tt&amp;gt; 's &amp;lt;tt&amp;gt;cancelAndCleanup()&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
There is also a simple &amp;lt;tt&amp;gt;cancel()&amp;lt;/tt&amp;gt; method that can be used to cancel a callback previously registered with &amp;lt;tt&amp;gt;callMeWhen()&amp;lt;/tt&amp;gt; . To change a callback, you must &amp;lt;tt&amp;gt;cancel( )&amp;lt;/tt&amp;gt; it, then construct a new callback and register it with &amp;lt;tt&amp;gt;callMeWhen( )&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Moving Frame by Frame ==&lt;br /&gt;
&lt;br /&gt;
One popular feature for playback is the ability to step forward exactly one frame. It turns out to be trickier than one might initially expect: it's not like there's a &amp;lt;tt&amp;gt;Movie.nextFrame( )&amp;lt;/tt&amp;gt; method. Indeed, a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; might not have a video track at all, if it represents an MP3 or some other audio-only media. So, finding the next frame requires being a little smarter about looking inside the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;'s structure.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
This example builds on the earlier &amp;lt;tt&amp;gt;BasicQTButtons&amp;lt;/tt&amp;gt; code. In this example, the implementations of the forward and back buttons are altered so that instead of changing the play rate, they change the current time to be the next frame before or after the current time. For space, this example shows only the changes from the original &amp;lt;tt&amp;gt;BasicQTButtons&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This example needs to import &amp;lt;tt&amp;gt;quicktime.std&amp;lt;/tt&amp;gt; to use &amp;lt;tt&amp;gt;StdQTConstants&amp;lt;/tt&amp;gt; , and &amp;lt;tt&amp;gt;quicktime.std.clocks&amp;lt;/tt&amp;gt; for some time-related classes. It also adds an instance variable &amp;lt;tt&amp;gt;visualTrack&amp;lt;/tt&amp;gt;, which is found with the following call:&lt;br /&gt;
&lt;br /&gt;
 theMovie = m;&lt;br /&gt;
 // find video track&lt;br /&gt;
 visualTrack =&lt;br /&gt;
   m.getIndTrackType (1,&lt;br /&gt;
                      StdQTConstants.visualMediaCharacteristic,&lt;br /&gt;
                      StdQTConstants.movieTrackCharacteristic);&lt;br /&gt;
&lt;br /&gt;
If a visual track isn't found, the &amp;lt;tt&amp;gt;revButton&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;fwdButton&amp;lt;/tt&amp;gt; are disabled later in the constructor.&lt;br /&gt;
&lt;br /&gt;
Finally, a new implementation of &amp;lt;tt&amp;gt;actionPerformed()&amp;lt;/tt&amp;gt; does the frame-step logic when the &amp;lt;tt&amp;gt;revButton&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;fwdButton&amp;lt;/tt&amp;gt; is clicked:&lt;br /&gt;
&lt;br /&gt;
 if (e.getSource( ) =  = revButton) {&lt;br /&gt;
   TimeInfo ti =&lt;br /&gt;
       visualTrack.getNextInterestingTime (&lt;br /&gt;
             StdQTConstants.nextTimeMediaSample,&lt;br /&gt;
             theMovie.getTime( ),&lt;br /&gt;
             -1);&lt;br /&gt;
   theMovie.setTime (new TimeRecord (theMovie.getTimeScale( ),&lt;br /&gt;
                                     ti.time));&lt;br /&gt;
 }&lt;br /&gt;
 else if (e.getSource( ) =  = stopButton)&lt;br /&gt;
   theMovie.stop( );&lt;br /&gt;
 else if (e.getSource( ) =  = startButton)&lt;br /&gt;
   theMovie.start( );&lt;br /&gt;
 else if (e.getSource( ) =  = fwdButton) {&lt;br /&gt;
   TimeInfo ti =&lt;br /&gt;
       visualTrack.getNextInterestingTime (&lt;br /&gt;
             StdQTConstants.nextTimeMediaSample,&lt;br /&gt;
             theMovie.getTime( ),&lt;br /&gt;
             1);&lt;br /&gt;
   theMovie.setTime (new TimeRecord (theMovie.getTimeScale( ),&lt;br /&gt;
                                     ti.time));&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch02-basicqtstepper''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There's no screenshot for this example, because it's difficult to show a frame step in a static medium like a book.&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
This program finds the video track with a call to &amp;lt;tt&amp;gt;Movie.getIndTrackType()&amp;lt;/tt&amp;gt; , which takes three arguments:&lt;br /&gt;
&lt;br /&gt;
;Which instance to find&lt;br /&gt;
: This is 1-based, so passing &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt; means &amp;quot;find the first matching track.&amp;quot;&lt;br /&gt;
;A search criterion&lt;br /&gt;
: This is a constant from &amp;lt;tt&amp;gt;StdQTConstants&amp;lt;/tt&amp;gt; that can be a media &amp;quot;type&amp;quot; (&amp;lt;tt&amp;gt;videoMediaType&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;soundMediaType&amp;lt;/tt&amp;gt;, etc.), or it can be a &amp;quot;characteristic&amp;quot; (&amp;lt;tt&amp;gt;videoMediaCharacteristic&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;audioMediaCharacteristic&amp;lt;/tt&amp;gt;). The characteristics are helpful in cases like this when several kinds of media are acceptable matches (&amp;quot;visual&amp;quot; media includes video, MPEG, Flash, and more).&lt;br /&gt;
;Flags to control the search&lt;br /&gt;
: This should be the value &amp;lt;tt&amp;gt;movieTrackMediaType&amp;lt;/tt&amp;gt; if the previous argument is a media type or &amp;lt;tt&amp;gt;movieTrackCharacteristic&amp;lt;/tt&amp;gt; if it is a characteristic.&lt;br /&gt;
&lt;br /&gt;
An alternative way to find a suitable track would be to iterate over the tracks with &amp;lt;tt&amp;gt;Movie.getIndTrack( )&amp;lt;/tt&amp;gt;, get the &amp;lt;tt&amp;gt;Media&amp;lt;/tt&amp;gt; object from each discovered track, and use &amp;lt;tt&amp;gt;instanceof&amp;lt;/tt&amp;gt; to see if it matches a given media class (&amp;lt;tt&amp;gt;VideoMedia&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;SoundMedia&amp;lt;/tt&amp;gt;, etc.).&lt;br /&gt;
&lt;br /&gt;
Assuming you can find such a track, the trick to finding the next frame is to use the media's &amp;lt;tt&amp;gt;getNextInterestingTime()&amp;lt;/tt&amp;gt; method. There are several kinds of &amp;quot;interesting times,&amp;quot; and to indicate interest in the next frame, which is more accurately the next &amp;quot;sample,&amp;quot; you pass the behavior flag &amp;lt;tt&amp;gt;nextTimeMediaSample&amp;lt;/tt&amp;gt;. The method also takes a parameter representing the time in the movie where it should start searching for the next frame (in this case, it's the current time) and the desired search direction (any positive &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; for a forward search, and any negative &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; for a backward search).&lt;br /&gt;
&lt;br /&gt;
The value returned by &amp;lt;tt&amp;gt;getNextInterestingTime( )&amp;lt;/tt&amp;gt; is a &amp;lt;tt&amp;gt;TimeInfo&amp;lt;/tt&amp;gt; object. This program is interested only in the time field of this object, which is represented in the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;'s time scale (not the &amp;lt;tt&amp;gt;Media&amp;lt;/tt&amp;gt;'s, interestingly enough). It takes that value and advances the movie to the interesting time—i.e., the next frame—with a call to &amp;lt;tt&amp;gt;Movie.setTime( )&amp;lt;/tt&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...other kinds of times? The native &amp;lt;tt&amp;gt;GetMediaNextInterestingTime&amp;lt;/tt&amp;gt; function offers the following behavior flags:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;NextTimeMediaSample&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The behavior used in this example.&lt;br /&gt;
;&amp;lt;tt&amp;gt;NextTimeMediaEdit&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Finds the next group of samples—i.e., the next thing that has been edited into the movie (editing is covered in the next chapter).&lt;br /&gt;
;&amp;lt;tt&amp;gt;NextTimeSyncSample&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Finds the next &amp;quot;sync sample&amp;quot;—i.e., the next sample that is completely self-contained. Many video compression formats send a sync sample (also known as a &amp;quot;key frame&amp;quot;), which is a complete image, while subsequent samples are just information about what has changed since the sync sample. In other words, these later frames aren't complete and cannot be rendered without information from one or more other samples.&lt;br /&gt;
;&amp;lt;tt&amp;gt;NextTimeEdgeOK&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Can be &amp;lt;tt&amp;gt;OR&amp;lt;/tt&amp;gt;'ed in with other flags to indicate that it's OK to return the beginning or the end of the media as a valid &amp;quot;interesting time.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
What's up with the first track being 1 instead of 0? As a curious legacy, one that feels more like Pascal than Java, most QuickTime methods that do an index-based &amp;lt;tt&amp;gt;get&amp;lt;/tt&amp;gt; are one-based, not zero-based. In fact, if you try to &amp;lt;tt&amp;gt;getTrack(0)&amp;lt;/tt&amp;gt;, you'll get a &amp;lt;tt&amp;gt;QTException&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;warning&amp;quot;&amp;gt;&lt;br /&gt;
'''Warning'''&lt;br /&gt;
&lt;br /&gt;
The other gotcha is that although this example is written to work with any visual media, it won't work for MPEG-1 or MPEG-2 files. These files multiplex (or &amp;quot;mux&amp;quot;) the audio and video into one stream, and QuickTime doesn't de-mux them in memory, so it has no easy way to find the next video sample. This is why there are separate &amp;lt;tt&amp;gt;MPEGMedia&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;MPEGMediaHandler&amp;lt;/tt&amp;gt; classes in QTJ; the latter is a subclass of &amp;lt;tt&amp;gt;VisualMediaHandler&amp;lt;/tt&amp;gt;, but it is also implementing &amp;lt;tt&amp;gt;AudioMediaHandler&amp;lt;/tt&amp;gt; . Fortunately, MPEG-4, whose internal structure is friendlier to QuickTime, appears as separate audio and video tracks just like other QuickTime movies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Playing Movies from URLs ==&lt;br /&gt;
&lt;br /&gt;
Along with loading movies from disk, QuickTime can also load them from URLs, and is pretty smart about network latency.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
[[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-EX-6|Example 2-6]] shows a totally new class, &amp;lt;tt&amp;gt;BasicQTURLController.java&amp;lt;/tt&amp;gt;. This is a significant rethinking of the earlier &amp;lt;tt&amp;gt;BasicQTController&amp;lt;/tt&amp;gt; class. This example creates a GUI from an empty &amp;quot;dummy&amp;quot; movie, then asks the user for a URL, gets a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; from that, and replaces the dummy movie. By getting the movie last, it tempts fate to see how well QTJ can deal with loading a movie over the network.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-EX-6&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 2-6. Loading and playing a movie from a URL'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch02;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.std.*;&lt;br /&gt;
 import quicktime.app.view.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
 import quicktime.std.movies.media.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
  &lt;br /&gt;
 import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
  &lt;br /&gt;
 import java.awt.*;&lt;br /&gt;
  &lt;br /&gt;
 public class BasicQTURLController extends Frame {&lt;br /&gt;
  &lt;br /&gt;
   QTComponent qc;&lt;br /&gt;
  &lt;br /&gt;
   public BasicQTURLController ( ) throws QTException {&lt;br /&gt;
       super (&amp;quot;Basic QT DataRef/Controller&amp;quot;);&lt;br /&gt;
       Movie dummyMovie = new Movie( );&lt;br /&gt;
       qc = QTFactory.makeQTComponent (dummyMovie);&lt;br /&gt;
       Component c = qc.asComponent( );&lt;br /&gt;
       add (c);&lt;br /&gt;
       pack( );&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public static void main (String[  ] args) {&lt;br /&gt;
       try {&lt;br /&gt;
           QTSessionCheck.check( );&lt;br /&gt;
           BasicQTURLController f =&lt;br /&gt;
               new BasicQTURLController ( );&lt;br /&gt;
           String url =&lt;br /&gt;
               javax.swing.JOptionPane.showInputDialog (f,&lt;br /&gt;
                                               &amp;quot;Enter URL&amp;quot;);&lt;br /&gt;
           DataRef dr = new DataRef (url);&lt;br /&gt;
           Movie m = Movie.fromDataRef (dr,&lt;br /&gt;
                                  StdQTConstants.newMovieActive);&lt;br /&gt;
           MovieController mc = new MovieController (m);&lt;br /&gt;
           f.qc.setMovieController (mc);&lt;br /&gt;
           f.setVisible(true);&lt;br /&gt;
           f.pack( );&lt;br /&gt;
           m.prePreroll(0, 1.0f);&lt;br /&gt;
           m.preroll(0, 1.0f);&lt;br /&gt;
           m.start( );&lt;br /&gt;
       } catch (Exception e) {&lt;br /&gt;
           e.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Compile and run this example with ant run-ch02-basicqturlcontroller''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When this app is first run, the user sees a dialog asking for a URL. Enter a valid URL (notice that again, for simplicity, the examples don't meaningfully check input or handle errors gracefully). Assuming the URL has valid QuickTime content, the user will see a window like the one shown in [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-FIG-8|Figure 2-8]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-FIG-8&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 2-8. Movie played from a URL DataRef'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_2_tt37.png|Movie played from a URL DataRef]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
Some different techniques are in play in this example, the most important of which is showing that the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; displayed by a &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; can be replaced. The constructor creates a &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; from the empty &amp;lt;tt&amp;gt;dummyMovie&amp;lt;/tt&amp;gt;, but after creating a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; from the URL, a &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; is created for it and is used to replace the contents of the visible &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; via the &amp;lt;tt&amp;gt;setMovieController( )&amp;lt;/tt&amp;gt; call.&lt;br /&gt;
&lt;br /&gt;
Two helper calls, &amp;lt;tt&amp;gt;prePreroll( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;preroll( )&amp;lt;/tt&amp;gt;, allocate movie-playing resources up front, to reduce jitter and dropped frames when the movie starts playing. These methods take the same two arguments: the movie time and the rate that the program intends to start playing at.&lt;br /&gt;
&lt;br /&gt;
This example uses a &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; to make a point. As seen in [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-FIG-8|Figure 2-8]], the scrubber has an inner bar that is only partially filled in. This is a graphic representation of how much of the movie data has been downloaded. This example goes ahead and plays the movie immediately, trusting that it will download data faster than we can consume it. This isn't a safe assumption at all—dial-up users will stop almost immediately, though the controller gives them the ability to see how much they have and to play when they're ready.&lt;br /&gt;
&lt;br /&gt;
As for getting the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;, it's a pretty simple process: pass the URL to a &amp;lt;tt&amp;gt;DataRef&amp;lt;/tt&amp;gt; constructor. These &amp;lt;tt&amp;gt;DataRef&amp;lt;/tt&amp;gt; objects are something of a general-purpose media locator in QuickTime, used here for network access. The new &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; is then created with the &amp;lt;tt&amp;gt;fromDataRef( )&amp;lt;/tt&amp;gt; call.&lt;br /&gt;
&lt;br /&gt;
Notice the second argument to &amp;lt;tt&amp;gt;fromDataRef( )&amp;lt;/tt&amp;gt;. This is an example of using QuickTime ''behavior flags'' , which are found throughout QuickTime. One of the more interesting concepts about the flags is that these behaviors can be combined. The flags are &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;s with a single bit turned on (meaning their actual values are powers of 2). The idea is that you can mathematically &amp;lt;tt&amp;gt;OR&amp;lt;/tt&amp;gt; them together to combine multiple behaviors. The constants of the &amp;lt;tt&amp;gt;java.awt.Font&amp;lt;/tt&amp;gt; class, like &amp;lt;tt&amp;gt;BOLD&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;ITALIC&amp;lt;/tt&amp;gt;, work pretty much the same way. In this case, in addition to making the movie active, the program could set a behavior flag to tell QuickTime not to enable alternate tracks (if there are any), by making a call like this:&lt;br /&gt;
&lt;br /&gt;
 Movie m = Movie.fromDataRef (dr,&lt;br /&gt;
              StdQTConstants.newMovieActive |&lt;br /&gt;
              StdQTConstants.newMovieDontAutoAlternate);&lt;br /&gt;
&lt;br /&gt;
The other flags mentioned for this call, &amp;lt;tt&amp;gt;newMovieDontResolveDataRefs&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;newMovieDontAskUnresolvedDataRefs&amp;lt;/tt&amp;gt;, deal with esoteric cases where a movie is not self-contained and some of the media it refers to can't be found.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;warning&amp;quot;&amp;gt;&lt;br /&gt;
'''Warning'''&lt;br /&gt;
&lt;br /&gt;
The Javadocs for &amp;lt;tt&amp;gt;Movie.fromDataRef( )&amp;lt;/tt&amp;gt; advocate using the behavior flag &amp;lt;tt&amp;gt;StdQTConstants4.newMovieAsyncOK&amp;lt;/tt&amp;gt; . That was useful in the old QTJ, but when used in this example in QTJ 6.1, it might allow the &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; to decide that your movie has zero height and zero width, because the movie gets handed to the &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; before the size metadata gets downloaded. As [[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-FIG-8|Figure 2-8]] shows, the preceding code does ''not'' block and wait for the whole movie to be downloaded. Advice for now: don't use it unless you think you're blocking on &amp;lt;tt&amp;gt;Movie.fromDataRef( )&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preventing &amp;quot;Tasking&amp;quot; Problems ==&lt;br /&gt;
&lt;br /&gt;
All the tasks in this chapter have managed to avoid one of the more obscure hazards in QuickTime. This example tempts fate and exposes the problem by playing a movie that would otherwise freeze up.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
[[QuickTime for Java: A Developer's Notebook/Playing Movies#quicktimejvaadn-CHP-2-EX-7|Example 2-7]] reprises the command-line audio player from the first chapter, which takes a path to a file as a command-line argument, builds a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;, and plays it, without getting any kind of GUI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-2-EX-7&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 2-7. Playing audio from the command line'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch01;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.app.time.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
 import quicktime.std.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
  &lt;br /&gt;
 import java.io.*;&lt;br /&gt;
  &lt;br /&gt;
 public class BasicAudioPlayer {&lt;br /&gt;
  &lt;br /&gt;
   public static void main (String[  ] args) {&lt;br /&gt;
       if (args.length != 1) {&lt;br /&gt;
           System.out.println (&lt;br /&gt;
               &amp;quot;Usage: BasicAudioPlayer &amp;lt;file&amp;gt;&amp;quot;);&lt;br /&gt;
           return;&lt;br /&gt;
       }&lt;br /&gt;
       try {&lt;br /&gt;
           QTSessionCheck.check( );&lt;br /&gt;
           QTFile f = new QTFile (new File(args[0]));&lt;br /&gt;
           OpenMovieFile omf = OpenMovieFile.asRead(f);&lt;br /&gt;
           Movie movie = Movie.fromFile (omf);&lt;br /&gt;
           '''TaskAllMovies.addMovieAndStart( );'''&lt;br /&gt;
           movie.start( );&lt;br /&gt;
       } catch (QTException e) {&lt;br /&gt;
           e.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice the line in bold. Take it out, recompile, and watch what happens. The program will likely hang or immediately exit, playing just a spurt of audio or none at all.&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
QuickTime movies need to explicitly be given CPU time to do their work: reading from disk or the network, decompressing and decoding, rendering to the screen, or playing to the speakers. This process is called &amp;quot;tasking.&amp;quot; Looking at the Javadocs reveals that the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; class has a &amp;lt;tt&amp;gt;task( )&amp;lt;/tt&amp;gt; method that could be called to give time to a specific movie, and a static &amp;lt;tt&amp;gt;taskAll( )&amp;lt;/tt&amp;gt; method that tasks all active movies.&lt;br /&gt;
&lt;br /&gt;
Managing all these calls manually and being sure to call them frequently enough would be, of course, incredibly tedious. That's why QTJ provides &amp;lt;tt&amp;gt;TaskAllMovies&amp;lt;/tt&amp;gt; , a wrapper for a &amp;lt;tt&amp;gt;Thread&amp;lt;/tt&amp;gt; whose job is to call &amp;lt;tt&amp;gt;task()&amp;lt;/tt&amp;gt; on all active movies. This example kicks off &amp;lt;tt&amp;gt;TaskAllMovies&amp;lt;/tt&amp;gt; (assuming nothing else has done so), thereafter allowing it to be blissfully unaware of tasking.&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...all the other examples? Why are we only hearing about this now? Well, &amp;lt;tt&amp;gt;TaskAllMovies&amp;lt;/tt&amp;gt; is so useful that QTJ itself uses it extensively. Any time a program works with QTJ's GUI classes, by getting a &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt; for a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt;, it picks up calls to &amp;lt;tt&amp;gt;TaskAllMovies&amp;lt;/tt&amp;gt; automatically. In fact, it's a little difficult not to pick up automatic tasking calls from QTJ, short of opening audio-only movies with non-QTJ GUI widgets, or no GUI at all, as seen here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''It's still important to know about tasking in case you stumble intosuch a case and can't figure out why your application is just sitting there''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tip&amp;quot;&amp;gt;&lt;br /&gt;
'''Tip'''&lt;br /&gt;
&lt;br /&gt;
In the last section, a warning mentioned an edge case where using the &amp;lt;tt&amp;gt;newMovieAsyncOK&amp;lt;/tt&amp;gt; flag might give you a &amp;lt;tt&amp;gt;QTComponent&amp;lt;/tt&amp;gt; with zero size because &amp;lt;tt&amp;gt;Movie.fromDataRef( )&amp;lt;/tt&amp;gt; returned immediately, before enough of the movie could be loaded to know how big it was.&lt;br /&gt;
&lt;br /&gt;
Tasking helps you solve this problem. After &amp;lt;tt&amp;gt;fromDataRef()&amp;lt;/tt&amp;gt;, you would go into a &amp;lt;tt&amp;gt;while&amp;lt;/tt&amp;gt; loop, testing whether &amp;lt;tt&amp;gt;Movie.getBox( )&amp;lt;/tt&amp;gt; returns non-zero dimensions. If it doesn't, call &amp;lt;tt&amp;gt;task( )&amp;lt;/tt&amp;gt; on the movie to give QuickTime a chance to load more of it, maybe do a &amp;lt;tt&amp;gt;Thread.sleep()&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;Thread.yield( )&amp;lt;/tt&amp;gt; to keep Java happy, and go back to the top of the &amp;lt;tt&amp;gt;while&amp;lt;/tt&amp;gt;. Because QuickTime movies usually, but don't always, have metadata early in the file, an alternative to testing the size of the movie would be to call &amp;lt;tt&amp;gt;maxLoadedTimeInMovie()&amp;lt;/tt&amp;gt; on the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; object and wait for a non-zero value—this would also be better if there's any chance the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; is audio only.&lt;br /&gt;
&lt;br /&gt;
But seriously, it's not going to happen because you don't need &amp;lt;tt&amp;gt;newMovieAsyncOK&amp;lt;/tt&amp;gt;. Chill.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In QTJ 6.0 and earlier, there were also URL-loading scenarios where a program might need to &amp;lt;tt&amp;gt;task( )&amp;lt;/tt&amp;gt; a few times to download enough of the &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; to read in the metadata and get a valid size, but this behavior seems to have changed in 6.1, making explicit tasking even more of an edge case.&lt;/div&gt;</description>
			<pubDate>Thu, 06 Mar 2008 23:50:56 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Playing_Movies</comments>		</item>
	</channel>
</rss>