<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>More Than Technical &#187; linux</title>
	<atom:link href="http://www.morethantechnical.com/category/linux/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.morethantechnical.com</link>
	<description>On software, code, the internet and more.</description>
	<lastBuildDate>Sun, 05 Feb 2012 07:04:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="http://superfeedr.com/hubbub"/>		<item>
		<title>Download all your Last.fm loved tracks in two simple steps</title>
		<link>http://www.morethantechnical.com/2011/03/14/download-all-you-last-fm-loved-tracks-in-a-single-command/</link>
		<comments>http://www.morethantechnical.com/2011/03/14/download-all-you-last-fm-loved-tracks-in-a-single-command/#comments</comments>
		<pubDate>Mon, 14 Mar 2011 04:27:48 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Recommended]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[Website]]></category>
		<category><![CDATA[download]]></category>
		<category><![CDATA[encoding]]></category>
		<category><![CDATA[lame]]></category>
		<category><![CDATA[mp3]]></category>
		<category><![CDATA[mp4]]></category>
		<category><![CDATA[mplayer]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[youtube]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=844</guid>
		<description><![CDATA[I&#8217;m a fan of Last.fm online radio, and I have a habit of marking every good song that I hear as a &#8220;loved track&#8221;. Over the years I got quite a list, and so I decided to turn it into my jogging playlist. But for that, I need all the songs downloaded to my computer [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a fan of <a href="http://www.last.fm/home">Last.fm</a> online radio, and I have a habit of marking every good song that I hear as a &#8220;loved track&#8221;. Over the years I got quite a list, and so I decided to turn it into my jogging playlist. But for that, I need all the songs downloaded to my computer so I can put them on my mobile. While Last.fm does link to Amazon for downloading all the loved songs for pay, I&#8217;m going to walk the fine moral line here and suggest how you can download every song from existing free YouTube videos.<br />
If it really bothers you, think of it as if I created a YouTube playlist and now I&#8217;m using my data plan to stream the songs off YT itself..<br />
Moral issues resolved, we can move on to the scripting.<br />
<span id="more-844"></span><br />
What you need to have:<br />
Linux-like system, <a href="http://www.mplayerhq.hu/design7/news.html">MPlayer</a>, <a href="http://lame.sourceforge.net/">Lame MP3 encoder</a>, some command-line experience or at least adventure-ness.</p>
<p>So first you&#8217;ll need to export your loved tracks from Last.fm in tab separated format &#8211; a mere button press.<br />
<a href="http://www.morethantechnical.com/wp-content/uploads/2011/03/Screen-shot-2011-03-14-at-12.03.26-AM.png" rel="lightbox[844]"><img src="http://www.morethantechnical.com/wp-content/uploads/2011/03/Screen-shot-2011-03-14-at-12.03.26-AM-300x111.png" alt="" title="Screen shot 2011-03-14 at 12.03.26 AM" width="300" height="111" class="aligncenter size-medium wp-image-849" /></a></p>
<p>The &#8220;tsv&#8221; (tab separated values) file has a simple format: <code>&lt;song name&gt; &lt;artist&gt; &lt;Last.fm url&gt;</code></p>
<p>And now for the script, first, the loved tracks file is tab separated, so we use AWK to get the 2 first fields which are song-name and song-artist.<br />
Then we use a neat command-line tool to download YT movies: <a href="http://rg3.github.com/youtube-dl/documentation.html">http://rg3.github.com/youtube-dl/documentation.html</a>.</p>
<pre class="brush: plain; title: ; notranslate">
mkdir mylovedtracks
cd mylovedtracks
awk -F\t '{print &quot;../youtube-dl.py -f 18 -t \&quot;ytsearch:&quot; $1 &quot; &quot; $2 &quot;\&quot;&quot;}' ../my_lovedtracks.tsv | csh
</pre>
<p>The single-liner will download all the loved tracks from the tsv file into the current directory, given that <code>youtube-dl.py &#038; my_lovedtracks.tsv</code> exist in the parent directory. <code>-f 18</code> says it will download only MP4s and <code>ytsearch</code> says it will try to search YT for the term &#8220;song-name song-artist&#8221; and download the 1st result. The <code>| csh</code> says it will send this command AWK formatted into a new shell process.</p>
<p>The saved MP4 will be named after the name of the video, with addition of the YT hash string.</p>
<p>All the mp4s have been downloaded, so let&#8217;s batch convert them to mp3s:</p>
<pre class="brush: plain; title: ; notranslate">
mkdir sound
for f in *.mp4 ; do n=`echo $f | cut -d '.' -f1`; if [ ! -e sound/$n.mp3 ]; then `mplayer $n.mp4 -vc dummy -vo null -ao pcm:file=sound/temp.wav; lame -V2 sound/temp.wav sound/$n.mp3; rm sound/temp.wav`; fi ; done
</pre>
<p>This single-liner will extract audio from the mp4 into a PCM temp.wav file using MEncoder, and then convert to VBR MP3 using Lame.<br />
You can run this command many times, as it checks if the file has not been converted yet. So you&#8217;re impatient (like me) on converting some of the MP4s before everything was downloaded &#8211; just run it, and later run it again.</p>
<p>Congrats, all your loved tracks were downloaded.</p>
<p>A few limitation to this method:<br />
* Sometimes downloaded songs are not exactly what you wanted, especially specific versions. The search is arbitrary, and can&#8217;t be controlled too much.<br />
* ID3 tags are non existent, although something can probably be done about that in the Lame encoding phase.<br />
* Very high potential for parallelization that is unexploited. Mostly in the YT download phase, where YT pushes the first ~15% of the video very fast (I saw 1200Kb/s even), and then maintains a steady d/l rate to get the video downloaded by ~1:00 minute (may be as low as 50Kb/s). Downloading many videos at once could help.<br />
* Still not a true single-liner, it is a two-step thing. But that can be done by modifying the 2nd step a bit and putting into the AWK print of the 1st step.<br />
* MP3&#8242;s volume normalization &#8211; very important! else every songs sounds different and you must do vol-up vol-down all the time&#8230;</p>
<p>Still, did a nice quick job for me&#8230;</p>
<p>Roy.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2011%2F03%2F14%2Fdownload-all-you-last-fm-loved-tracks-in-a-single-command%2F&amp;title=Download%20all%20your%20Last.fm%20loved%20tracks%20in%20two%20simple%20steps" id="wpa2a_2"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2011/03/14/download-all-you-last-fm-loved-tracks-in-a-single-command/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to rotate a video using MEncoder and FFmpeg and live to tell the tale</title>
		<link>http://www.morethantechnical.com/2011/02/08/how-to-rotate-a-video-using-mencoder-and-ffmpeg-and-live-to-tell-the-tale/</link>
		<comments>http://www.morethantechnical.com/2011/02/08/how-to-rotate-a-video-using-mencoder-and-ffmpeg-and-live-to-tell-the-tale/#comments</comments>
		<pubDate>Tue, 08 Feb 2011 16:43:07 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[ffmpeg]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Recommended]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[command line]]></category>
		<category><![CDATA[encoding]]></category>
		<category><![CDATA[mencoder]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=811</guid>
		<description><![CDATA[Hi I&#8217;d like to share a quick tip on rotating video files. I&#8217;m always frustrated with taking videos with my phone. Single handedly it&#8217;s easiest to do it when the phone is upright and not in landscape mode. But the files are always saved in landscape mode, which makes them rotated when you watch. Although [...]]]></description>
			<content:encoded><![CDATA[<p>Hi</p>
<p>I&#8217;d like to share a quick tip on rotating video files.</p>
<p>I&#8217;m always frustrated with taking videos with my phone. Single handedly it&#8217;s easiest to do it when the phone is upright and not in landscape mode. But the files are always saved in landscape mode, which makes them rotated when you watch.<br />
Although there are plenty of GUI software to do it, using the command line is faster and can also be batched!</p>
<p><span id="more-811"></span></p>
<h2>Using FFmpeg</h2>
<p>This is the basic syntax<br />
<code>./ffmpeg -vf transpose=0 -i input.mp4 output.avi</code></p>
<p>Just using <code>-vf transpose=0</code> to rotate 90 deg clockwise. If you get the &#8220;Unrecognized option &#8216;vf&#8217;&#8221; error, you need to configure &#038; build ffmpeg with <code>--enable-filters</code> (or at least without<code> --disable-filters</code>), and check with <code>ffmpeg -filters</code> that you get them to show up.</p>
<p>Also, I always get very lousy video quality when using the plain vanilla settings. It turns out the problem is with the frame rate. If you leave it as-is the (default) mpeg compression makes a lot of I and P frames, and too few B frames. So set it up explicitly.</p>
<p>I ended up with<br />
<code>ffmpeg -vf transpose=0 -i input.mp4 -r 30 output.avi</code></p>
<p>Easy.</p>
<p>Update [3/1/11]: Actually just using <code>-vf transpose=0</code> will flip the video horizontally as well, which is undesirable in some cases. To counter that I use: <code>-vf "transpose=0,hflip=0"</code>, and it resolves the problem.</p>
<h2>Using MEncoder</h2>
<p>Again, pretty simple thing to do:<br />
<code>mencoder input.mp4 -nosound -o characters-resize-turn.avi -vf rotate=0 -ovc lavc -lavcopts vcodec=mpeg4 -ofps 30</code></p>
<p>Note that I kill the audio with <code>-nosound</code>, and again set the frame rate<code>-ofps 30</code> or else I get the &#8220;duplicate frames&#8221; problem.</p>
<p>Enjoy<br />
Roy.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2011%2F02%2F08%2Fhow-to-rotate-a-video-using-mencoder-and-ffmpeg-and-live-to-tell-the-tale%2F&amp;title=How%20to%20rotate%20a%20video%20using%20MEncoder%20and%20FFmpeg%20and%20live%20to%20tell%20the%20tale" id="wpa2a_4"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2011/02/08/how-to-rotate-a-video-using-mencoder-and-ffmpeg-and-live-to-tell-the-tale/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Some things I learned about Android&#8217;s Frame animation</title>
		<link>http://www.morethantechnical.com/2011/02/07/some-things-i-learned-about-androids-frame-animation/</link>
		<comments>http://www.morethantechnical.com/2011/02/07/some-things-i-learned-about-androids-frame-animation/#comments</comments>
		<pubDate>Mon, 07 Feb 2011 07:09:21 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Mobile phones]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[animation]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[mogrify]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=804</guid>
		<description><![CDATA[Hi Just a quick share of lessons learned about Android&#8217;s Frame-by-Frame animations. Some of the functionality is poorly documented, as many people point out, so the web is the only place for answers. Having looked for some answers to these questions and couldn&#8217;t find any &#8211; here&#8217;s what I found out myself. Update [2/3/11]: A [...]]]></description>
			<content:encoded><![CDATA[<p>Hi</p>
<p>Just a quick share of lessons learned about Android&#8217;s Frame-by-Frame animations. Some of the functionality is poorly documented, as many people point out, so the web is the only place for answers. Having looked for some answers to these questions and couldn&#8217;t find any &#8211; here&#8217;s what I found out myself.</p>
<p>Update [2/3/11]: A <a href="http://www.morethantechnical.com/2011/03/01/the-woes-of-frame-animation-on-android-w-code/">new post</a> on this topic gives a more broad view of my experience.<br />
<span id="more-804"></span></p>
<h2>Resetting Frame Animation</h2>
<p>The API is a bit weird here, because the restart function is inside the setVisible function of AnimationDrawable. If you don&#8217;t restart and just do another <code>start()</code> on an already finished animation &#8211; it will just jump to the last frame. You must reset the animation before starting it.</p>
<p>However if you do <code>setVisible(true,true)</code> your animation will run twice!, so you must do <code>setVisible(false,true);</code>. This will reset the animation for a <code>start()</code> operation.</p>
<h2>Preloading Animations</h2>
<p>I got to preloading animations after understating that trying to fire an animation &#8220;right off the XML&#8221;, has a lag of over a second. This must be due to the inflation process. And I was looking for snappy smooth animations right away, without waiting for them to inflate, so naturally I needed to preload them. But how?</p>
<p>So I loaded the frame animation into an ImageView with <code>android:visibility="gone"</code>, and &#8220;hijacked&#8221; its drawable when I needed to fire it:</p>
<p>The XML, just put it somewhere in your main xml so it will be inflated when the app starts.</p>
<pre class="brush: plain; title: ; notranslate">
&lt;!-- Preload animations --&gt;
&lt;ImageView android:id=&quot;@+id/anim_preloaded_imgview&quot;
	android:layout_width=&quot;wrap_content&quot;
	android:layout_height=&quot;wrap_content&quot;
	android:src=&quot;@drawable/myanim&quot;
	android:visibility=&quot;gone&quot; /&gt;
</pre>
<p>The Java:</p>
<pre class="brush: plain; title: ; notranslate">
ImageView animateHere = (ImageView) findViewById(R.id.animate_here);
animateHere.setImageDrawable(((ImageView)findViewById(R.id.anim_preloaded_imgview).getDrawable());
AnimationDrawable anim = (AnimationDrawable) animateHere.getDrawable();
anim.setVisible(false, true); //reset! see previous section
anim.start(); //now good to start, even if already fired before
</pre>
<p>Voila.</p>
<h2>OutOfMemory expection? srsly?</h2>
<p>So at the beginning I was getting a lot of OutOfMemory exceptions on the loading of the animations. Probably due to loading many big bitmaps into the memory. So I reduced the size of my PNGs to ~80,000 pixels (images are ~200&#215;400), and then I was able to load as many as I wanted! Strange&#8230;<br />
I didn&#8217;t really research what&#8217;s the limit, but using ~140,000 pixels did not fly.</p>
<p>In these cases <code>mogrify</code> is your friend. This will resize all images beginning with &#8220;myanim&#8221; to 200xWhatever keeping aspect ratio:</p>
<pre class="brush: plain; title: ; notranslate">
mogrify -resize 200 myanim*
</pre>
<p>That&#8217;s it for now<br />
But tomorrow I will learn more. Android is surprising..</p>
<p>Please comment if you [dis]agree, and share your own experience!<br />
Roy.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2011%2F02%2F07%2Fsome-things-i-learned-about-androids-frame-animation%2F&amp;title=Some%20things%20I%20learned%20about%20Android%26%238217%3Bs%20Frame%20animation" id="wpa2a_6"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2011/02/07/some-things-i-learned-about-androids-frame-animation/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>SmartHome &#8211; Embedded computing course project</title>
		<link>http://www.morethantechnical.com/2010/02/21/smarthome-embedded-computing-course-project/</link>
		<comments>http://www.morethantechnical.com/2010/02/21/smarthome-embedded-computing-course-project/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 16:42:09 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[code]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[school]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[Website]]></category>
		<category><![CDATA[arm]]></category>
		<category><![CDATA[embedded]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[swt]]></category>
		<category><![CDATA[zigbee]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=580</guid>
		<description><![CDATA[Hi In the past few weeks I have been working hard at a few projects for end-of-term at Uni. One of the projects is what I called &#8220;SmartHome&#8221;, for Embedded computing [link] course, is a home monitoring [link] application. In the course the students were given an LPC2148 arm7-MCU (NXP) based education board, implemented by [...]]]></description>
			<content:encoded><![CDATA[<p>Hi<br />
In the past few weeks I have been working hard at a few projects for end-of-term at Uni. One of the projects is what I called &#8220;SmartHome&#8221;, for Embedded computing [<a href="http://www.tau.ac.il/~stoledo/Courses/Embedded/announcement.html" target="_blank">link</a>] course, is a home monitoring [<a href="http://en.wikipedia.org/wiki/Home_automation" target="_blank">link</a>] application. In the course the students were given an LPC2148 arm7-MCU (NXP) based education board, implemented by Embedded Artists [<a href="http://www.embeddedartists.com/products/education/edu_2148.php" target="_blank">link</a>]. My partner Gil and I decided to work with ZigBee extension modules [<a href="http://en.wikipedia.org/wiki/ZigBee" target="_blank">link</a>] to enable remote communication.</p>
<p>Here are the steps we took to bring this project to life.<br />
<span id="more-580"></span></p>
<h2>The Idea</h2>
<p>Our vision is to create a home monitoring and controlling system, that will enable tracking different sensors around the house and also control switches.The system should be centralized by a master controller, and also wireless so it will not need cumbersome wiring throughout the house. We would also like the system to be easily controlled by a PC, so visual information could be displayed to the user, as well as allow manual control of the electronic switches.</p>
<p>Such a system will be able to automatically:</p>
<ul>
<li>Turn off the garden lighting when the light outside is bright enough,</li>
<li>Control the lawn watering system,</li>
<li>Control air conditioning in the house according to the temperature,</li>
<li>etc.</li>
</ul>
<h2>The Hardware</h2>
<p style="text-align: left;">As I mentioned, we were given an LPC2148 education board [<a href="http://www.embeddedartists.com/products/education/edu_2148.php" target="_blank">link</a>], implemented by Embedded Artists, that boasts a 12Mhz ARM CPU, and many peripheral subsystems. Among the systems are: LCD screen, numerous LEDs, a LED matrix, a fan, analog dials, USB and UART I/O and more. The boards also has a port for connecting a ZigBee module to enable RF communication, but it doesn&#8217;t contain the actual module. Since we needed remote communication between our stations, we bought 3 XBee modules from Maxstream [<a href="http://www.digi.com/products/wireless/point-multipoint/xbee-series1-module.jsp#overview" target="_blank">link</a>].</p>
<p style="text-align: center;"><a href="http://www.morethantechnical.com/wp-content/uploads/2010/02/Image096.jpg" rel="lightbox[580]"><img class="size-medium wp-image-586 alignnone" title="XBee module by MaxStream" src="http://www.morethantechnical.com/wp-content/uploads/2010/02/Image096-300x225.jpg" alt="" width="210" height="158" /></a><a href="http://www.morethantechnical.com/wp-content/uploads/2010/02/Image097.jpg" rel="lightbox[580]"> <img class="size-medium wp-image-588 alignnone" title="LPC2148 board by Embedded Artists" src="http://www.morethantechnical.com/wp-content/uploads/2010/02/Image097-300x225.jpg" alt="" width="210" height="158" /></a><a href="http://www.morethantechnical.com/wp-content/uploads/2010/02/Image098.jpg" rel="lightbox[580]"> <img class="alignnone size-medium wp-image-589" title="XBee module on LPC2148 board" src="http://www.morethantechnical.com/wp-content/uploads/2010/02/Image098-300x225.jpg" alt="" width="210" height="158" /></a></p>
<h2>The Software</h2>
<p>The LPC boards can be programmed very easily using tools provided by Embedded Artists, such as GCC with Newlib for compiling (both Win and Linux), and <a href="http://www.flashmagictool.com/" target="_blank">Flashmagic</a> (for windows) or lpc21isp for loading the compiled program. We used these tools for programing the &#8220;embedded&#8221; part of the application, for the PC client we used Java with <a href="http://www.eclipse.org/swt/" target="_blank">SWT</a> and serial port connectivity (<a href="http://rxtx.qbang.org/wiki/index.php/Download" target="_blank">RxTx</a> for Windows and Linux).</p>
<h3>Embedded program</h3>
<p>The embedded program on the LPC board has two parts: A master and A client. The system has only one master, and up to 3 clients. The master gathers information from the clients, and controls their behavior according to the user requests. For communication between the master and clients we created a communication protocol that has only a few simple messages:</p>
<ul>
<li>INIT &#8211; The master sends this request to initialize the connection between itself and a client.</li>
<li>ACK &#8211; This is the response for every request.</li>
<li>POLL &#8211; The clients answers this request with the data from all it&#8217;s sensors.</li>
<li>OPERATE &#8211; The master commands the client to switch something on or off.</li>
<li>ERROR &#8211; A general error response.</li>
</ul>
<p>All commands / responses have a unified structure described here:</p>
<pre class="brush: plain; title: ; notranslate">
General struct:
 ___________________________________________ _____
|    OP   | To | From | &lt;----- DATA ------&gt; | EOM
|_________|____|______|_____________________|_____

Data:

POLL (response)
_ ____________ ______ ______ ________
 | Temperature| ADC0 | ADC1 | Button |
_|____________|______|______|________|

OPERATE
_ _________
 | BITMASK |
_|_________|
</pre>
<p>This way we had a very easy implementation of the communication module, since we always had to look for only 14 bytes on the wire.</p>
<h3>Communication with ZigBee module</h3>
<p>To jumpstart our implementation we used the examples provided by Embedded Artists for operating the ZigBee module [<a href="http://www.embeddedartists.com/support/LPC2148_EDU/XBee_example.zip" target="_blank">link</a>]. The communication with the ZigBee module is on the UART1 port of the MCU. The example code takes care of opening the correct GPIO pins, setting the IRQ masks to enable interrupts and provides a very simple API for transmitting and receiving characters with the XBee over UART  (described in uart.h and uart.c files).</p>
<p>We took the XBee example code and expanded it to be able to recieve and send data between two stations. That means setting up each station&#8217;s module with it&#8217;s ID, address, channel and target address by AT commands [<a href="http://ftp1.digi.com/support/documentation/90000982_B.pdf" target="_blank">spec</a>, see page. 28]: ATID, ATCH, ATMY and ATDL. Two other key features are putting the module into command mode (rather than transmit mode) to set the mentioned parameters, this is done by &#8216;+++&#8217; to enter command mode and ATCN to exit. Once we had a decent framework to communicate between the stations, we started to build the logic.</p>
<p>The master station logic is like so:</p>
<ol>
<li>Initialize XBee module.</li>
<li>INIT all client stations, and see which station answers &#8211; these will be our &#8220;up&#8221; stations.</li>
<li>Loop:
<ol>
<li>POLL each &#8220;up&#8221; station in a loop.</li>
<li>Take care of any OPERATE requests from the PC client.</li>
</ol>
</li>
</ol>
<p>This way, the client&#8217;s logic boils down to just looping, testing for any request and taking care of it. Both client and master share most of the code, so only the main process code is essentially different. The example code uses a framework called &#8220;Preemtive OS&#8221; to allow multitasking / processes (code was bundled in the examples).</p>
<h3>Communication with PC</h3>
<p>Communication between the master and PC client also required some lightweight &#8220;protocol&#8221;. The communication is again over UART (0 this time, 1 is used by XBee), only now the PC is doing a UART-over-USB with the board. The protocol we ended up with supports these features:</p>
<ul>
<li>Commands the PC wants the master to perform look like &#8220;m=&lt;command&gt;=&lt;parameters&gt;&#8221;, such commands can be:
<ul>
<li>&#8220;poll=&lt;i&gt;&#8221;, send a POLL to the station indexed i</li>
<li>&#8220;test=&lt;i&gt;&#8221;, send an INIT to the station indexed i</li>
<li>&#8220;toggle=&lt;i&gt;_&lt;sw&gt;_&lt;onoff&gt;&#8221;, set the switch <em>sw</em> on the station indexed <em>i</em> to <em>onoff</em> status</li>
</ul>
</li>
<li>Notifications the master would like to share with the user (PC) look like &#8220;pc=&lt;notification&gt;&#8221;, such notifications can be:
<ul>
<li> &#8220;up=&lt;i&gt;&#8221;, the station indexed <em>i</em> is up</li>
<li>&#8220;master_online&#8221;,</li>
<li>&#8220;temp=&lt;i&gt; &lt;temp&gt;&#8221;, the station indexed <em>i</em> has a temperature reading of <em>temp</em></li>
<li>&#8220;e=&lt;error message&gt;&#8221;, error message from the master</li>
</ul>
</li>
</ul>
<p>This is an incomplete set of features, but it&#8217;s representative of the idea we want to present.</p>
<h3>PC client program</h3>
<p>The PC client we built using Java, so it would (and should) be portable between OSs. The GUI was built with the SWT, using the eclipse Visual Editor plug-in which simplified the process. Communication with the LPC board is done over the serial port of the board, as I mentioned the PC creates a virtual COM port using a USB-to-UART driver (FTDI, bundled with windows) [<a href="http://en.wikipedia.org/wiki/FTDI" target="_blank">link</a>].</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="344" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/1ZC2SuYb7P0&amp;hl=en_US&amp;fs=1&amp;" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="425" height="344" src="http://www.youtube.com/v/1ZC2SuYb7P0&amp;hl=en_US&amp;fs=1&amp;" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>To test the GUI we created a &#8220;simulator&#8221;, that mimics the operation of a master station, that is shown in the video above.</p>
<p>The high-level design of the program is described in this inheritance UML diagram:</p>
<p style="text-align: center;"><a href="http://www.morethantechnical.com/wp-content/uploads/2010/02/smart_home_uml.png" rel="lightbox[580]"><img class="size-medium wp-image-593 aligncenter" title="smart_home_uml" src="http://www.morethantechnical.com/wp-content/uploads/2010/02/smart_home_uml-251x300.png" alt="" width="251" height="300" /></a></p>
<p>Our PC client uses serial-port connectivity based on the old javax.serial APIs. Though these APIs have been abandoned by Sun, and there is no official Win32 implementation bundled with the JDK (only for *NIXs/Solaris), a project named RxTx is upkeeping an implementation of this API for windows [<a href="http://rxtx.qbang.org/wiki/index.php/Download" target="_blank">link</a>].</p>
<h2>The Code</h2>
<p>We are releasing the code under the BSD license, for everyone to use, enjoy, learn and expand.</p>
<p>It is available via the blog&#8217;s SVN repo:</p>
<p>PC Client (requires RxTx serial port impl and SWT)</p>
<pre class="brush: plain; title: ; notranslate">
svn checkout http://morethantechnical.googlecode.com/svn/trunk/SmartHomePCClient
</pre>
<p>Embedded program (includes all dependencies)</p>
<pre class="brush: plain; title: ; notranslate">
svn checkout http://morethantechnical.googlecode.com/svn/trunk/smarthome_embedded/final project
</pre>
<p>To compile the master program &#8220;make&#8221; in the master directory, and you&#8217;ll get an &#8220;xbee_master.hex&#8221; file, same goes for the client in the client directory (these directories don&#8217;t contain code, only a makefile). Then you have to upload the hex into the board, this is done either by &#8220;make deploy&#8221; (if you have lpc21isp), or FlashMagic on Win.</p>
<p>Java is compiled as usual&#8230; just remember the dependencies.</p>
<p>We would like to thank Sivan Toledo for the guidance, loaned hardware and inspiration.</p>
<p>And thanks all for listening!<br />
Roy S. &amp; Gil Ramon</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2010%2F02%2F21%2Fsmarthome-embedded-computing-course-project%2F&amp;title=SmartHome%20%26%238211%3B%20Embedded%20computing%20course%20project" id="wpa2a_8"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2010/02/21/smarthome-embedded-computing-course-project/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Qt &amp; OpenCV combined for face detecting QWidgets</title>
		<link>http://www.morethantechnical.com/2009/03/05/qt-opencv-combined-for-face-detecting-qwidgets/</link>
		<comments>http://www.morethantechnical.com/2009/03/05/qt-opencv-combined-for-face-detecting-qwidgets/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 12:19:37 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[gui]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[qt]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[face detection]]></category>
		<category><![CDATA[opencv]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=212</guid>
		<description><![CDATA[As my search for the best platform to roll-out my new face detection concept continues, I decided to give ol&#8217; Qt framework a go. I like Qt. It&#8217;s cross-platform, a clear a nice API, straightforward, and remindes me somewhat of Apple&#8217;s Cocoa. My intention is to get some serious face detection going on mobile devices. [...]]]></description>
			<content:encoded><![CDATA[<p>As my search for the best platform to roll-out my new face detection concept continues, I decided to give ol&#8217; Qt framework a go.</p>
<p>I like Qt. It&#8217;s cross-platform, a clear a nice API, straightforward, and remindes me somewhat of Apple&#8217;s Cocoa.</p>
<p>My intention is to get some serious face detection going on mobile devices. So that means either the iPhone, which so far did a crummy job performance-wise, or some other mobile device, preferably linux-based.<br />
This led me to the decision to go with Qt. I believe you can get it to work on any linux-ish platform (limo, moblin, android), and since Nokia baught Trolltech &#8211; it&#8217;s gonna work on Nokia phones soon, awesome!</p>
<p>Lets get to the details, shall we?<br />
<span id="more-212"></span><br />
First thing&#8217;s first: face detection.</p>
<p>I ripped OpenCV&#8217;s facedetect.c sample and extracted only the detect_and_draw() function. Originally the function detects the faces and draws a circle over them, but I needed only the face detection and the result bounding rectangle. So in the end I was left with this:</p>
<pre class="brush: cpp; title: ; notranslate">

CvRect detect_and_draw( IplImage* img, CvMemStorage* storage, CvHaarClassifierCascade* cascade )
{
IplImage *gray, *small_img;
int i = 0;

gray = cvCreateImage( cvSize(img-&gt;width,img-&gt;height), 8, 1 );
small_img = cvCreateImage( cvSize( cvRound (img-&gt;width/scale),
cvRound (img-&gt;height/scale)), 8, 1 );

cvCvtColor( img, gray, CV_RGB2GRAY );
cvResize( gray, small_img, CV_INTER_LINEAR );
cvEqualizeHist( small_img, small_img );
cvClearMemStorage( storage );

CvRect* r = NULL;

if( cascade )
{
double t = (double)cvGetTickCount();
CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
1.1, 2, 0
|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
//|CV_HAAR_DO_CANNY_PRUNING
//|CV_HAAR_SCALE_IMAGE
,
cvSize(30, 30) );
t = (double)cvGetTickCount() - t;

printf( &quot;detection time = %gms\n&quot;, t/((double)cvGetTickFrequency()*1000.) );

r = (CvRect*)cvGetSeqElem( faces, i );

cvReleaseImage( &amp;amp;amp;amp;amp;amp;gray );
cvReleaseImage( &amp;amp;amp;amp;amp;amp;small_img );

if(r) {
return cvRect(r-&gt;x,r-&gt;y,r-&gt;width,r-&gt;height);
} else {
return cvRect(-1,-1,0,0);
}

}
</pre>
<p>This can go anywhere in the code base, as it&#8217;s totally independant (as long as you train the cascade and allocate a MemStorage).Note that I am assuming only one face in the input image, and also that it will be the largest detected object. This bring my benchmark to about 25ms per frame, using the original general detection approach of facedetect.c benchmarked at about 160ms per frame.</p>
<p>OK, done with pure OpenCV, on to Qt.</p>
<p>I subclassed a QWidget, who&#8217;s sole purpose is to show the input video with the detected face. For starters, I needed to have a QImage and an IplImage instances as members, they can also share the same buffer (how awesome is that..). I also need a CvCapture, CvMemStorage and a CvHaarCalssifierCascade:</p>
<pre class="brush: cpp; title: ; notranslate">

class FaceRecognizer : public QWidget
{
Q_OBJECT

public:
FaceRecognizer(QWidget *parent = 0);
~FaceRecognizer();

private:
Ui::FaceRecognizerClass ui;

QImage m_i;

QRect faceLoc;

CvMemStorage* storage;
CvHaarClassifierCascade* cascade;
CvCapture* capture;
IplImage* m_opencvimg;

QTimer* m_timer;

void paintEvent(QPaintEvent* e);

public slots:
void queryFrame();
};
</pre>
<p>You can see that I&#8217;m gonna use a QTimer to query the frames from the CvCapture and also I override paintEvent to paint the frame onto the canvas. In fact in my QWidget I have a QFrame, that the image will painted over it. UI was generated in Qt Designer.</p>
<p>First, some initialization in the constructor:</p>
<pre class="brush: cpp; title: ; notranslate">

FaceRecognizer::FaceRecognizer(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);

capture = cvCaptureFromAVI( &quot;/home/user/Desktop/video.avi&quot; );
//grab one frame to get width and height

IplImage* frame = cvQueryFrame( capture );

m_i = QImage(QSize(frame-&gt;width,frame-&gt;height),QImage::Format_RGB888);
ui.frame-&gt;setMinimumSize(m_i.width(),m_i.height());
ui.frame-&gt;setMaximumSize(ui.frame-&gt;minimumSize());
//create only the header, as the data buffer is shared, and was allocated by QImage

m_opencvimg = cvCreateImageHeader(cvSize(m_i.width(),m_i.height()),8,3);
m_opencvimg-&gt;imageData = (char*)m_i.bits(); // share buffers

if( frame-&gt;origin == IPL_ORIGIN_TL )
cvCopy( frame, m_opencvimg, 0 );
else
cvFlip( frame, m_opencvimg, 0 );

//images from cvQueryFrame come in BGR form and not what Qt expects - RGB

//and since the buffers are shared - format should be consistent
cvCvtColor(m_opencvimg,m_opencvimg,CV_BGR2RGB);

//we need memstorage and a cascade
storage = cvCreateMemStorage(0);
cascade = (CvHaarClassifierCascade*)cvLoad( CASCADE_NAME, 0, 0, 0 );

//set timer for 50ms intervals

m_timer = new QTimer(this);
connect(m_timer,SIGNAL(timeout()),this,SLOT(queryFrame()));
m_timer-&gt;start(50);
}
</pre>
<p>And now, querying the frame: query CvCapture, convert BGR to RGB, detect faces and update faceLoc QRect.</p>
<pre class="brush: cpp; title: ; notranslate">

void FaceRecognizer::queryFrame() {
IplImage* frame = cvQueryFrame( capture );

if( frame-&gt;origin == IPL_ORIGIN_TL )
cvCopy( frame, m_opencvimg, 0 );
else
cvFlip( frame, m_opencvimg, 0 );
cvCvtColor(m_opencvimg,m_opencvimg,CV_BGR2RGB);

CvRect r = detect_and_draw(m_opencvimg,storage,cascade);
faceLoc = QRect(QPoint(r.x,r.y),QSize(r.width,r.height));

this-&gt;update();
}

Finally - painting, which is easy:

void FaceRecognizer::paintEvent(QPaintEvent* e) {
QPainter painter(this);

painter.drawImage(QPoint(ui.frame-&gt;x(),ui.frame-&gt;y()),m_i);

if(faceLoc.x() &gt; 0 &amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp; faceLoc.y() &gt; 0) {
painter.setBrush(Qt::NoBrush);
painter.setPen(QColor(255,0,0));
painter.drawRect(QRect(faceLoc.x()+ui.frame-&gt;x(),faceLoc.y()+ui.frame-&gt;y(),faceLoc.width(),faceLoc.height()));
}
}
</pre>
<p>Looks like it&#8217;s all done&#8230; Here&#8217;s a video:<br />
<object width="425" height="344" data="http://www.youtube.com/v/3eyh-jmAQR0&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/3eyh-jmAQR0&amp;hl=en&amp;fs=1" /><param name="allowfullscreen" value="true" /></object></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2009%2F03%2F05%2Fqt-opencv-combined-for-face-detecting-qwidgets%2F&amp;title=Qt%20%26%23038%3B%20OpenCV%20combined%20for%20face%20detecting%20QWidgets" id="wpa2a_10"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2009/03/05/qt-opencv-combined-for-face-detecting-qwidgets/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Showing video with Qt toolbox and ffmpeg libraries</title>
		<link>http://www.morethantechnical.com/2008/11/02/showing-video-with-qt-toolbox-and-ffmpeg-libraries/</link>
		<comments>http://www.morethantechnical.com/2008/11/02/showing-video-with-qt-toolbox-and-ffmpeg-libraries/#comments</comments>
		<pubDate>Sun, 02 Nov 2008 08:12:00 +0000</pubDate>
		<dc:creator>Roy</dc:creator>
				<category><![CDATA[ffmpeg]]></category>
		<category><![CDATA[graphics]]></category>
		<category><![CDATA[gui]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[qt]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[sdl]]></category>

		<guid isPermaLink="false">http://www.morethantechnical.com/?p=78</guid>
		<description><![CDATA[I recently had to build a demo client that shows short video messages for Ubuntu environment. After checking out GTK+ I decided to go with the more natively OOP Qt toolbox (GTKmm didn&#8217;t look right to me), and I think i made the right choice. So anyway, I have my video files encoded in some [...]]]></description>
			<content:encoded><![CDATA[<p>I recently had to build a demo client that shows short video messages for Ubuntu environment.<br />
After checking out GTK+ I decided to go with the more natively OOP Qt toolbox (GTKmm didn&#8217;t look right to me), and I think i made the right choice.</p>
<p>So anyway, I have my video files encoded in some unknown format and I need my program to show them in a some widget. I went around looking for an exiting example, but i couldn&#8217;t find anything concrete, except for a good tip <a href="http://lists.trolltech.com/qt-interest/2007-09/thread00806-0.html">here</a> that led me <a href="http://www.inb.uni-luebeck.de/%7Eboehme/libavcodec_update.html">here</a> for an example of using ffmpeg&#8217;s libavformat and libavcodec, but no end-to-end example including the Qt code.</p>
<p>The ffmpeg example was simple enough to just copy-paste into my project, but the whole painting over the widget&#8217;s canvas was not covered. Turns out painting video is not as simple as overriding paintEvent()&#8230;</p>
<p>Firstly, you need a separate thread for grabbing frames from the video file, because you won&#8217;t let the GUI event thread do that.<br />
That makes sense, but when the frame-grabbing thread (I called VideoThread) actually grabbed a frame and inserted it somewhere in the memory, I needed to tell the GUI thread to take that buffered pixels and paint them over the widget&#8217;s canvas.</p>
<p>This is the moment where I praise Qt&#8217;s excellent Signals/Slots mechanism. So I&#8217;ll have my VideoThread emit a signal notifying some external entity that a new frame is in the buffer.<br />
Here&#8217;s a little code:</p>
<p><span id="more-78"></span></p>
<pre class="brush: plain; title: ; notranslate">
void VideoThread::run() {
/*
... Initialize libavformat &amp;amp;amp; libavcodec data structures.
You can see it in the example i referred to before
*/
// Open video file
if(av_open_input_file(&amp;amp;amp;pFormatCtx,
&amp;quot;lala.avi&amp;quot;,
NULL, 0, NULL)!=0)
return -1; // Couldn't open file

// Retrieve stream information
if(av_find_stream_info(pFormatCtx)&amp;amp;lt;0)
return -1; // Couldn't find stream information

// Find the first video stream ...

// Get a pointer to the codec context for the video
// stream...

// Find the decoder for the video stream...

// Open codec...

// Allocate video frame
pFrame=avcodec_alloc_frame();

// Allocate an AVFrame structure
pFrameRGB=avcodec_alloc_frame();
if(pFrameRGB==NULL)
return -1;

int dst_fmt = PIX_FMT_RGB24;
int dst_w = 160;
int dst_h = 120;

// Determine required buffer size and allocate buffer
numBytes = avpicture_get_size(dst_fmt, dst_w, dst_h);
buffer = new uint8_t[numBytes + 64];

//put a PPM header on the buffer
int headerlen = sprintf((char *) buffer,
&amp;quot;P6n%d %dn255n&amp;quot;,
dst_w, dst_h);

_v-&amp;amp;gt;buf = (uchar*)buffer;
_v-&amp;amp;gt;len = avpicture_get_size(dst_fmt,dst_w,dst_h) +
headerlen;

// Assign appropriate parts of buffer to image planes
// in pFrameRGB...

// I use libswscale to scale the frames to the required
// size.
// Setup the scaling context:
SwsContext *img_convert_ctx;
img_convert_ctx = sws_getContext(
pCodecCtx-&amp;amp;gt;width, pCodecCtx-&amp;amp;gt;height,
pCodecCtx-&amp;amp;gt;pix_fmt,
dst_w, dst_h, dst_fmt,
SWS_BICUBIC, NULL, NULL, NULL);

// Read frames and notify
i=0;
while(av_read_frame(pFormatCtx, &amp;amp;amp;packet)&amp;amp;gt;=0)
{
// Is this a packet from the video stream?
if(packet.stream_index==videoStream)
{
// Decode video frame
avcodec_decode_video(pCodecCtx,
pFrame,
&amp;amp;amp;frameFinished,
packet.data,
packet.size);

// Did we get a video frame?
if(frameFinished)
{
// Convert the image to RGB
sws_scale(img_convert_ctx,
pFrame-&amp;amp;gt;data,
pFrame-&amp;amp;gt;linesize,
0,
pCodecCtx-&amp;amp;gt;height,
pFrameRGB-&amp;amp;gt;data,
pFrameRGB-&amp;amp;gt;linesize);

emit frameReady();

//My video is 5FPS so sleep for 200ms.
this-&amp;amp;gt;msleep(200);
}
}

// Free the packet that was allocated by
// av_read_frame
av_free_packet(&amp;amp;amp;packet);
}

// Free the RGB image
delete [] buffer;
av_free(pFrameRGB);

// Free the YUV frame
av_free(pFrame);

// Close the codec...

// Close the video file...
} //end VideoThread::run
</pre>
<p>Ok so I have a frame-grabber that emits a frameReady signal everytime the buffer is full and ready for painting.</p>
<p>A couple of things to notice:</p>
<ul style="text-align: left;">
<li>I convert the image format to PIX_FMT_RGB24 (avcodec.h), which is required by Qt&#8217;s QImage::fromData() method.</li>
<li>I scale the image using ffmpeg&#8217;s libswscale. All conversion/scaling methods inside libavcodev are deprecated now.<br />
But it&#8217;s fairly simple, <a href="http://www.dranger.com/ffmpeg/tutorial08.html">here</a>&#8216;s a good example. Just remember you need a sws_getContext and then sws_scale.</li>
<li>I totally disregard actual frame rate here, I just sleep for 200ms because i know my file is 5FPS. For a (far-) more sophisticated way to get the FPS, very important if this is not a constant frame-rate video, you can find <a href="http://www.dranger.com/ffmpeg/tutorial05.html">here</a>.</li>
<li>I don&#8217;t cover audio in this example, although the mechanism to extract it from the file exists&#8230; you just need to grabe the audio stream&#8217;s frame. For playing audio you also need some Qt-external library. In a different project I used SDL very easily, <a href="http://www.dranger.com/ffmpeg/tutorial03.html">here</a>&#8216;s an example online.</li>
</ul>
<p>Now, for painting over the widget.<br />
This is fairly easy:</p>
<pre class="brush: plain; title: ; notranslate">
void VideoWidget::paintEvent(QPaintEvent * e) {
QPainter painter(this);
if(buf) {
QImage i = QImage::fromData(buf,len,&amp;quot;PPM&amp;quot;);
painter.drawImage(QPoint(0,0),i);
}
}
</pre>
<p>Two things to note:</p>
<ul style="text-align: left;">
<li>The widget needs to be given the pointer to the video frame buffer (buf).</li>
<li>The frame buffer needs to be in a PPM format. That means it needs to get a PPM header, which looks something like this: &#8220;P6n320 240n255n&#8221;, and then all the pixels in 3-byte per-pixel format (RGB24). You can see that i take care of that in the previous code block.</li>
</ul>
<p>Finally we need to orchestrate this whole mess.<br />
So in my GUI-screen class I do:</p>
<pre class="brush: plain; title: ; notranslate">
....
vt = new VideoThread();
connect(vt,SIGNAL(frameReady()),this,SLOT(updateVideoWidget()));
vt-&amp;amp;gt;start();
....
</pre>
<p>And:</p>
<pre class="brush: plain; title: ; notranslate">
void playMessage::updateVideoWidget() {
videoWidget-&amp;amp;gt;repaint(); //or update().
}
</pre>
<p>This will make the widget repaint on each frame ready.</p>
<p>Note:</p>
<ul style="text-align: left;">
<li>In this example I don&#8217;t take care of multi-threading issues. Since the GUI and the ffmpeg decoder threads share a memory buffer, I should probably have a mutex to protect it. It&#8217;s a classic producer-consumer problem.</li>
<li>Performance wise, Qt&#8217;s paint mechanism is by far the worst way to go when displaying video&#8230; but it&#8217;s great for a quick-and-dirty solution (I only needed 5fps). A more performance favorable solution will probably be using an overlay block and frame-serving with SDL.</li>
</ul>
<p>Enjoy!<br />
Roy.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.morethantechnical.com%2F2008%2F11%2F02%2Fshowing-video-with-qt-toolbox-and-ffmpeg-libraries%2F&amp;title=Showing%20video%20with%20Qt%20toolbox%20and%20ffmpeg%20libraries" id="wpa2a_12"><img src="http://www.morethantechnical.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.morethantechnical.com/2008/11/02/showing-video-with-qt-toolbox-and-ffmpeg-libraries/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

