tag:blogger.com,1999:blog-83580446092016178622024-03-05T16:48:33.286-06:00Thoughts From The Fat, Slow KidRandom thoughts from the 'Fat, Slow Kid'.
I am a software engineer by profession, the majority of my thoughts will concern technology and my profession.FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.comBlogger181125tag:blogger.com,1999:blog-8358044609201617862.post-82226789218772263792015-10-11T14:41:00.000-06:002020-06-23T11:07:15.985-06:00FFMpeg is Digital Meth -- Part 1<br />
<h3>
FFMpeg Options</h3>
Global Options<br />
<br />
<br />
<pre><code><div>
</div>
</code></pre>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />
<h4>
AVOptions</h4>
<div>
These options are specific to the given container, device or codec. The '-profile' option above is an example of such an option. These options are provided directly to the <i>libavformat</i>, <i>libavdevice</i>, and <i>libavcodec</i> libraries.</div>
<div>
<br /></div>
<div>
<h4>
Main Options</h4>
</div>
<h4>
'-fmt (input/output)'</h4>
<div>
FFMpeg normally auto detects the file format for input or output files, guessed from the file extension so often it is not required to specify the format. The format can be explicitly specified by using '-fmt', for input or output files.</div>
<div>
<br /></div>
<div>
<h4>
'-y (global)'</h4>
</div>
<div>
If the output file(s) already exist, FFMpeg will halt and present the user with the option to overwrite the file. Specifying '-y' overwrites output files without user intervention.</div>
<div>
<br /></div>
<div>
<h4>
'-t duration (input/output)'</h4>
</div>
<div>
This argument applies both to input and output files. If specifying a duration as an input option (before -i), the result is limiting the duration of the data read from the input file. When specified as an output option (before the output filename) the FFMpeg will stop writing after its reached the specified duration.</div>
<div>
<br /></div>
<div>
Specifying '-t 20' as an input file, with two output files will result in decoding and re-encoding the 1st 20 seconds of video creating two equivalent output files:</div>
<div>
<pre><code>
$ ffmpeg -y -t 20 -i big_buck_bunny_1080p_h264.mov -an /tmp/foo1.mov -an /tmp/foo2.mov</code></pre>
</div>
<div>
<br /></div>
<div>
Repeating the command while specifying '-t 10' as an output argument to one of the files will result in one input file being 20 sec duration, the other a 10 second duration.</div>
<div>
<pre><code>
$ ffmpeg -y -t 20 -i big_buck_bunny_1080p_h264.mov -an /tmp/foo1.mov -an -t 10 /tmp/foo2.mov</code></pre>
</div>
<div>
<br /></div>
<div>
<div>
<h4>
'-fs fileSize (input/output)'</h4>
</div>
<div>
</div>
Another useful output option allows setting the file size limit. The input file is read, writing the output file until the file size limit specified has been reached. The result in the following case will be a video consisting of the first ~22 seconds of the input video.<br />
<br />
<pre><code>
$ ffmpeg -y -i big_buck_bunny_1080p_h264.mov -an -fs 10M /tmp/foo-10M.mov
$ ls -lh /tmp/foo-10M.mov
-rw-rw-r-- 1 user user 9.8M Sep 5 17:45 /tmp/foo-10M.mov</code></pre>
</div>
<br />
But what if you want to fast forward to 30 seconds into the input file followed by encoding the following 10 seconds? The '-ss' fits the bill when specified as an input file option. When specified as an output file option, the end result is similar, accomplished by decoding but discarding the input until the timestamps position is reached.<br />
<br />
<pre><code>
$ ffmpeg -y -ss 30 -i big_buck_bunny_1080p_h264.mov -t 10 -an /tmp/foo-30-40.mov
</code></pre>
<br />
Setting the timestamp
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-31514175280396274782015-10-11T12:31:00.000-06:002015-10-11T12:31:52.346-06:00Python Progress BarWas recently writing some python to process some test cases. One long'ish testcase would benefit from a progress bar, slapped one together below.<br />
<br />
One thing to note, progress doesn't allow going backwards, but indicates in ASCII text the current progress by writing characters and a series of backspaces.<br />
<br />
<br />
<pre><code>
#!/usr/bin/python
import time
import sys
class ProgressBar():
barLen_=0;
progress_=0;
def __init__(self,N=10):
self.barLen_=N;
print '['+' '*self.barLen_+']',
print '\b'*(self.barLen_+2),
def setProgress(self,x):
sys.stdout.flush();
k=int(x/100.0*self.barLen_);
if (k > self.progress_):
update='\b'+'.'*(k-self.progress_);
print update,
self.progress_=k;
N=50
p=ProgressBar(N);
for i in range(0,101):
p.setProgress(i);
time.sleep(.05);
</code></pre>
The result is of the form:
<br />
<pre><code>
user@river:~$ ./pBar
[.............. ]
</code></pre>
Enjoy.
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com2tag:blogger.com,1999:blog-8358044609201617862.post-39476131235792085012015-09-19T21:32:00.000-06:002015-09-19T21:32:00.066-06:00Limiting Network BandwidthOccasionally it's necessary to determine the affects of reduced network bandwidth. Authoring software that works for a networked system backed by Gigabit Ethernet as well as DSL requires testing on both forms of systems. The alternative is to test on the most capable networking system and then test lower-bandwidth systems on the same network by artificially limiting the bandwidth.<br />
<br />
Consulting the all-knowing Google provided a couple general options: trickle and wondershaper. While there are other utilities, I mainly focused on these two.<br />
<br />
Trickle is a 'lightweight user bandwidth shaper', it's particular value is the ability to limit processes independently and it doesn't require superuser privileges. <br />
<br />
<pre><code>
$ sudo apt-get install trickle
</code></pre>
<br />
<br />
You can limit uploads and downloads to 100 KB/s for a command such as;<br />
<pre><code>
$ trickle -u 100 -d 100 wget http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_1080p_stereo.ogg
</code></pre>
<br />
<br />
Independently, you could specify alternative limits for another command. Trickle is limited to TCP sockets so if you need to limit bandwidth for UDP sockets you'll need to look for an alternative. Applying system-wide bandwidth, TCP in this case, supposedly is supported via trickled daemon utility but after numerous hours I gave up on getting it to work. Regardless, I abandoned it's use not only because I couldn't get it to work but also it's limitation to TCP and applying the daemon and client command required prepending 'trickle' to the command line. This would disqualify applying the network bandwidth constraints to network services like sshd and such without modifying each service starting the process.<br />
<br />
Seeking a system-wide bandwidth traffic shaper brought me back to Wondershaper once again. My first experience with wondershaper I found it didn't always work, this round I tested the usage 1-10 Mbps and I quickly found that it limited the bandwidth like expected until reaching 10 Mbps where it jumped to realized bandwidth of 40 Mbps. Head-scratcher; working fine for bandwidths under 10Mbps but broke at >= 10Mbps. Consulting Google again brought me to a fix proposed by 'buzzy'; <a href="https://github.com/magnific0/wondershaper/issues/2">https://github.com/magnific0/wondershaper/issues/2</a>. Modifying the wondershaper script as 'buzzy' indicated resolved the issue and I could consistently specify bandwidths 1-40 Mbps and observe realized bandwidths accordingly.<br />
<br />
<pre><code>
$ cat go
#!/bin/bash
for i in `seq 1 50`; do
echo "$i Mbps"
K=`expr $i \* 1024`
sudo wondershaper wlan0 $K $K
iperf -t 10 -c 192.168.1.132 2> /dev/null | grep "Mbits/sec"
sleep 2
done
sudo wondershaper wlan0 clear
</code></pre>
<div>
<br /></div>
<div>
<div>
<pre><code>
lipeltgm@river:~$ ./go </code></pre>
</div>
<div>
1 Mbps</div>
<div>
[ 3] 0.0-11.2 sec 1.38 MBytes 1.03 Mbits/sec</div>
<div>
2 Mbps</div>
<div>
[ 3] 0.0-10.7 sec 2.62 MBytes 2.06 Mbits/sec</div>
<div>
3 Mbps</div>
<div>
[ 3] 0.0-10.4 sec 3.75 MBytes 3.02 Mbits/sec</div>
<div>
4 Mbps</div>
<div>
[ 3] 0.0-10.4 sec 5.00 MBytes 4.04 Mbits/sec</div>
<div>
5 Mbps</div>
<div>
[ 3] 0.0-10.5 sec 5.12 MBytes 4.11 Mbits/sec</div>
<div>
6 Mbps</div>
<div>
[ 3] 0.0-10.3 sec 7.38 MBytes 6.00 Mbits/sec</div>
<div>
7 Mbps</div>
<div>
[ 3] 0.0-10.3 sec 8.50 MBytes 6.95 Mbits/sec</div>
<div>
8 Mbps</div>
<div>
[ 3] 0.0-10.3 sec 9.75 MBytes 7.97 Mbits/sec</div>
<div>
9 Mbps</div>
<div>
[ 3] 0.0-10.2 sec 10.6 MBytes 8.76 Mbits/sec</div>
<div>
10 Mbps</div>
<div>
[ 3] 0.0-10.1 sec 12.0 MBytes 9.94 Mbits/sec</div>
<div>
11 Mbps</div>
<div>
[ 3] 0.0-10.1 sec 13.2 MBytes 11.0 Mbits/sec</div>
<div>
12 Mbps</div>
<div>
[ 3] 0.0-10.2 sec 14.5 MBytes 12.0 Mbits/sec</div>
<div>
13 Mbps</div>
<div>
[ 3] 0.0-10.2 sec 15.5 MBytes 12.8 Mbits/sec</div>
<div>
14 Mbps</div>
<div>
[ 3] 0.0-10.3 sec 16.1 MBytes 13.2 Mbits/sec</div>
<div>
15 Mbps</div>
<div>
[ 3] 0.0-10.1 sec 16.4 MBytes 13.6 Mbits/sec</div>
<div>
16 Mbps</div>
<div>
[ 3] 0.0-10.1 sec 19.0 MBytes 15.8 Mbits/sec</div>
<div>
17 Mbps</div>
<div>
[ 3] 0.0-10.1 sec 19.8 MBytes 16.4 Mbits/sec</div>
<div>
18 Mbps</div>
<div>
[ 3] 0.0-10.1 sec 21.1 MBytes 17.6 Mbits/sec</div>
<div>
19 Mbps</div>
<div>
[ 3] 0.0-10.1 sec 22.1 MBytes 18.3 Mbits/sec</div>
<div>
20 Mbps</div>
<div>
[ 3] 0.0-10.1 sec 23.1 MBytes 19.3 Mbits/sec</div>
...</div>
<div>
<br />
<br />
While the use of WonderShaper requires superuser privileges, it limits the system network bandwidth in it's entirety.
Enjoy.</div>
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-60526171946698754712015-09-12T20:29:00.000-06:002016-07-17T22:30:24.867-06:00Makefile MystiqueOriginating in the work by Stuart Feldman at Bell Labs in 1976, the <i>make</i> utility has existed in a number of fashions since and is one of the most common build utilities for *nix based systems. Despite that however, in my 16+ years of professional software development, authoring or maintaining makefiles takes on a classic game of 'not it!!' seemingly everywhere I work. <br />
<div>
<br /></div>
<div>
Few would argue that the utility lacks flexibility or power, the general complaint is the syntax/semantics are confusing and unmaintainable, one of the primary reasons that popular IDEs synthesize their own makefiles in an attempt to isolate the user from the pain and misery of doing it themselves. The goal of this post isn't to complain about the utility, but instead to work through a few examples in an attempt to better understand it myself. While authoring and maintaining a makefile may feel like a prostate exam, it's also likely as necessary as one. In preparing for this post I referred the documentation <a href="http://www.gnu.org/s/make/manual/make.pdf" target="_blank">here</a> and I invite you to do the same.</div>
<div>
<br /></div>
<div>
Part of <i>make's </i>popularity and power is because of it's implicit rules. Making use of these rules you'll find that like good liquor, a little goes a long way. This is evident for example when your project utilizes C/C++.</div>
<div>
<br /></div>
<div>
With a simple source file and relying on implicit make rules the necessary makefile is simplistic;</div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ cat main.c </span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">#include <stdio.h></span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">int main()</span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">{</span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"> printf("(%s:%d) main process initializing\n",__FILE__,__LINE__);</span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"> printf("(%s:%d) main process terminating\n",__FILE__,__LINE__);</span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span><br />
<div>
<br /></div>
A single rule comprises the makefile and provides a simplistic, minimalistic build system.</div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ cat Makefile </span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">main: main.o</span><br />
<div>
<br /></div>
Each makefile consists of 'rules' taking the form;</div>
</div>
<div>
<i> target ... : prerequisites ...</i></div>
<div>
<i> <tab> recipe</i></div>
<div>
<i> <tab> ...</i></div>
<div>
<br /></div>
<div>
Examining the rule we find the target is defined as 'main' with a prerequisite of 'main.o'. This simply means that in order to create 'main' the 'main.o' file must exist. The absence of a recipe relies on the implicit rules. This can be observed by looking at the output when running <i>make</i> as below;<br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ make</span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">cc -c -o main.o main.c</span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">cc main.o -o main</span><br />
<div>
<br /></div>
The existence of implicit rules comes with some disadvantages, namely it's easy to not understand what is being done for you. Conceptually, the implicit rule that generates the object files takes the form of the prefix rule below;<br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ cat Makefile </span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">main: main.o</span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>.c.o:</b></span><br />
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b><span class="Apple-tab-span" style="white-space: pre;"> </span>${CC} ${CPPFLAGS} ${CFLAGS} -c $^ </b></span><br />
<div>
<br /></div>
<div>
Understanding what is going on allows tailoring the behavior without explicitly defining a rule. Note the usage of the CPPFLAGS and CFLAGS variables. Tweaking the original makefile will allow us to add debugging info and specifying an optimization level 3 as below;</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ cat Makefile </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>CFLAGS += -g -o3</b></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">main: main.o</span></div>
</div>
<div>
<br /></div>
<div>
This results in a slight difference when we run make;</div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ make</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">cc <b>-g -o3</b> -c -o main.o main.c</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">cc main.o -o main</span></div>
</div>
<div>
<br /></div>
<div>
The foundation of make is detecting changes to the prerequisites and determining when the targets need to be remade. This can be observed by re-running make immediately after running make, the result is a notification that "'main' is up to date". Affecting the <i>main.c</i> file timestamp by modifying the file or simply touching it will result in the need for the rule to be applied once again.</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ make</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">cc -g -o3 -c -o main.o main.c</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">cc main.o -o main</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">user@kaylee:~/make.blog/C$ make</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>make: `main' is up to date.</b></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">user@kaylee:~/make.blog/C$ touch main.c </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">user@kaylee:~/make.blog/C$ make</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">cc -g -o3 -c -o main.o main.c</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">cc main.o -o main</span></div>
</div>
<div>
<br /></div>
<div>
Likely, you've seen this all before, but stay with me I assure you there's more interesting things to come.</div>
<div>
<br /></div>
<div>
Often, it's preferred to have a target that cleans up the directory and allows building from scratch. The convention is to name such a target <i>clean</i>. Below is a modified makefile that defines a <i>clean</i> target that simply deletes the executable and the object files.</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">CFLAGS += -g -o3</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">main: main.o</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>clean:</b></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b> ${RM} main main.o</b></span></div>
</div>
<div>
<br /></div>
<div>
Executing 'make clean' will result in deleting <i>main</i> and <i>main.o</i> files. Adding a file to your project can be accomplished by adding the object file to the prerequisites for main and recipe for the clean target or we can make use of pattern. We'll do this by explicitly defining each of the C source files in a variable, then perform a list replacement substituting the *.c with *.o extensions to get our object file list. The object file list can then be used in the target prerequisites and in the clean target recipe. Adding a file to the SRCS variable rather than duplication in multiple locations.</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ cat Makefile </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">CFLAGS += -g -o3</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>SRCS=main.c </b></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>OBJS=$(subst .c,.o,${SRCS})</b></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">main: <b>${OBJS}</b></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">clean:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${RM} main <b>${OBJS}</b></span></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Still however there is duplication, namely the multiple references of <i>main, </i>that can be addressed by a new variable definition.</div>
<div>
<div>
<br /></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ cat Makefile </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">CFLAGS += -g -o3</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>PROGS=main</b></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">SRCS=main.c </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">OBJS=$(subst .c,.o,${SRCS})</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>${PROGS}</b>: ${OBJS}</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">clean:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${RM} <b>${PROGS}</b> ${OBJS}</span></div>
</div>
<div>
<br /></div>
<div>
Definitely on the right path, but the addition of a file requires modification to the makefile. The wildcard expansion demonstrated in the following makefile. The addition or removal of a file with the .c extension in the current directory will take effect in the wildcard expansion.</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ cat Makefile </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">CFLAGS += -g -o3</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">PROGS=main</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><b>SRCS=${wildcard *.c}</b></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">OBJS=$(subst .c,.o,${SRCS})</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">${PROGS}: ${OBJS}</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">clean:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${RM} ${PROGS} ${OBJS}</span></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Let's look at some less typical usages of make which gives us a bit more insight into the creation of targets, prerequisites, and recipes. Imagemagick is a common utility that we'll be making use in the following examples.</div>
<div>
<br /></div>
<div>
We'll build up the makefile as we go, incorporating what we've learned above. We'll be satisfying the same objectives using two forms of makefiles; one that makes use of suffix rules, one that makes use of pattern rules.</div>
<div>
<br /></div>
<div>
Let's begin by defining our objectives. Suppose our project requires taking in a list of JPG files and converting each into a series of other image file formats, namely PNG, GIF, JP2 and XWD files.</div>
<div>
<br /></div>
<div>
Using the suffix rule syntax, the makefile can begin taking the following form;</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ cat Makefile.suffix </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">.SUFFIXES:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">.SUFFIXES: .jpg .png .gif .jp2 .xwd </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">all: image.xwd </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">.jpg.png:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">.png.gif:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">.gif.jp2:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">.jp2.xwd:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">clean:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${RM} *.gif *.jp2 *.xwd</span></div>
</div>
<div>
<br /></div>
<div>
The <i>all</i> target consists of the default target, the prerequisite of <i>image.xwd</i>. In other words, make is complete when an up-to-date image.xwd file exists. How it arrives at it is make magic, more precisely a series of suffix rules. A series of prefix rules chaining is required to get to the final XWD file, each target we can kick off by explicitly specifying on the command line. Specifying 'make -f Makefile.suffix image.png' results in firing of the <b><i>.jpg.png</i></b> suffix rule. The suffix rules are <i>chained</i> as each must fire to arrive at the final XWD file. Running 'make' performs this by stepping through a series of recipes; JPG => PNG => GIF => JP2 => XWD.</div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ make -f Makefile.suffix</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">convert image.jpg image.png</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">convert image.png image.gif</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">convert image.gif image.jp2</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">convert image.jp2 image.xwd</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">rm image.jp2 image.gif image.png</span></div>
</div>
<div>
<br /></div>
<div>
Notice the final step removes intermediate files which can be preserved which can be prevented by adding <i>".PRECIOUS: %.jpg %.png %.gif %.jp2 %.xwd"</i> line which tells make not to remove the intermediate files with the specified extensions. The example is a bit fictional but done to demonstrate suffix rules and chaining. Modifying the source file <i>image.jpg</i> followed by rerunning make will result in converting the new file to each of the alternative file formats.</div>
<div>
<br /></div>
<div>
As is, each prerequisite is generated via suffix rule chaining to completion before moving on to the next prerequisite. In other words, if you specified image.xwd and image01.xwd the image.xwd would be generated to completion (ie. JPG => PNG => GIF => JP2 => XWD) before moving on to image01.xwd.</div>
<div>
<br /></div>
<div>
Meeting the same goals, let's utilize pattern rules rather than suffix rules which are somewhat dated in use.</div>
<div>
<br /></div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ cat Makefile.pattern </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">.PRECIOUS: %.jpg %.png %.gif %.jp2 %.xwd</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">all: image.xwd</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">%.png:%.jpg</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">%.gif:%.png</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">%.jp2:%.gif</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">%.xwd:%.jp2</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">clean:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${RM} *.gif *.jp2 *.xwd</span></div>
</div>
<div>
<br /></div>
<div>
The most noteworthy difference between the target/prerequisites. The prefix rules define a target, the pattern rule defines a target and prerequisite making the illusion of the rules being reversed.</div>
<div>
<br /></div>
<div>
What if you want to convert each input images to Jpgs before moving on to Gifs before moving on to Jp2s before the Xwds. This can be done by specifying a wildcard expansion for the source files and using the substitution expression for each of the formats <u>then</u> specifying each of the formats in as prerequisites for the all target, as follows;</div>
<div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ cat Makefile.pattern </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">.PRECIOUS: %.jpg %.png %.gif %.jp2 %.xwd</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">SRCS=${wildcard *.jpg}</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">PNGS=$(subst .jpg,.png,${SRCS})</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">GIFS=$(subst .jpg,.gif,${SRCS})</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">JP2S=$(subst .jpg,.jp2,${SRCS})</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">XWDS=$(subst .jpg,.xwd,${SRCS})</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">all: ${PNGS} ${GIFS} ${JP2S} ${XWDS}</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">%.png:%.jpg</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">%.gif:%.png</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">%.jp2:%.gif</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">%.xwd:%.jp2</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} convert $< $@</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;">clean:</span></div>
<div>
<span style="color: #666666; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span class="Apple-tab-span" style="white-space: pre;"> </span>${RM} ${PNGS} ${GIFS} ${JP2S} ${XWDS}</span></div>
<div>
<br /></div>
</div>
<div>
This way, each format is fully satisfied before moving on to the next. Perhaps less necessary for image files, more applicable for generating source files. For example, the Protobuf message compiler allows generation of header/c++ files which also allows interdependencies between message files. This requires <b>all</b> the message files to be converted to C/H files before firing the compilation, otherwise a source file may reference a header file that hasn't been created yet.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Hope you find this useful. Good luck with your make projects!</div>
<div>
<br /></div>
<br />
<br /></div>
</div>
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-36633700109919385382015-02-01T22:46:00.000-06:002020-06-23T11:07:15.843-06:00Setting Up Android For the Nth TimeSince I've been authoring Android apps, I've gone through numerous occasions of installing/re-installing/re-re-installing of the SDK and more recently AndroidStudio. I've been a bit out of the loop, a bit of a hiatus from development but recently reacquainting with the SDK.<br />
<br />
Start by downloading and extracting the SDK;<br />
<pre><code>
$ wget http://dl.google.com/android/android-sdk_r24.0.2-linux.tgz
$ tar -zxvf android-sdk_r24.0.2-linux.tgz
</code></pre>
<div>
<br /></div>
<div>
Append the locations of the new utilities to your Bash profile;</div>
<div>
<br /></div>
<div>
<div>
<pre><code>
$ echo "export PATH=\$PATH:~/android-sdk-linux/tools" >> ~/.bashrc
$ echo "export PATH=\$PATH:~/android-sdk-linux/platform-tools" >> ~/.bashrc</code></pre>
</div>
</div>
<div>
<br /></div>
<div>
</div>
The default install generally installs the latest APIs, but you can install additional ones;
<br />
<div>
<div>
<pre><code>
$ android</code></pre>
</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmK2X1UKkJ7JUdBaxuLUNKq3F0Ct8SrpfYitqJhvqLr2cJRvCBsxj7CKN6ko30G3XcReZ131N-xB32puiIPfvqfcQubIqoZH-DKRoA-Or14Srhwz69W5wGn1CAM_XPrXPEFRblN7oh1fc/s1600/screen01.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmK2X1UKkJ7JUdBaxuLUNKq3F0Ct8SrpfYitqJhvqLr2cJRvCBsxj7CKN6ko30G3XcReZ131N-xB32puiIPfvqfcQubIqoZH-DKRoA-Or14Srhwz69W5wGn1CAM_XPrXPEFRblN7oh1fc/s1600/screen01.png" height="320" width="243" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Likely, if you've recently updated or reinstalled the Android SDK, you'll have to update the project XML files. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The 'update project' command takes a numeric target id, listing the targets and </div>
<div class="separator" style="clear: both; text-align: left;">
find the appropriate id.</div>
<pre><code>
<div class="separator" style="clear: both;">
$ android list targets | grep id:</div>
<div class="separator" style="clear: both;">
id: 1 or "android-7"</div>
<div class="separator" style="clear: both;">
id: 2 or "android-8"</div>
<div class="separator" style="clear: both;">
id: 3 or "android-21"</div>
<div class="separator" style="clear: both;">
id: 4 or "Google Inc.:Google APIs:7"</div>
<div class="separator" style="clear: both;">
id: 5 or "Google Inc.:Google APIs:8"</div>
<div class="separator" style="clear: both;">
id: 6 or "Google Inc.:Google APIs:21"</div>
<div class="separator" style="clear: both;">
</div>
</code></pre>
<div class="separator" style="clear: both;">
The current API version is stored in the project.properties file within the project directory.</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
</div>
<pre><code>
$ cat project.properties
<div class="separator" style="clear: both;">
.</div>
<div class="separator" style="clear: both;">
.</div>
<div class="separator" style="clear: both;">
target=Google Inc.:Google APIs:8</div>
<div class="separator" style="clear: both;">
.</div>
<div class="separator" style="clear: both;">
.</div>
</code></pre>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Updating the project to continue to use API 8 would therefore be done by;</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
</div>
<pre><code>
$ android update project -p . -t 5</code></pre>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Get the list of devices available by issuing the following command;</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
</div>
<pre><code>
$ adb devices</code></pre>
List of devices attached
<br />
<div class="separator" style="clear: both;">
</div>
<div class="separator" style="clear: both;">
01aa7bcb8c8c07be<span class="Apple-tab-span" style="white-space: pre;"> </span>device</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
$ adb -s 01aa7bcb8c8c07be install -r ./bin/Test01-debug-unaligned.apk</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
Whole buncha interesting stuff is available by examining the APK;</div>
<div class="separator" style="clear: both;">
</div>
<pre><code>
$ aapt dump badging ./bin/Test01-debug-unaligned.apk
<div class="separator" style="clear: both;">
package: name='com.abc.test01' versionCode='3' versionName='1.2' platformBuildVersionName=''</div>
<div class="separator" style="clear: both;">
application-label:'Test01'</div>
<div class="separator" style="clear: both;">
application-icon-160:'res/drawable/icon.png'</div>
<div class="separator" style="clear: both;">
application: label='Test01' icon='res/drawable/icon.png'</div>
<div class="separator" style="clear: both;">
application-debuggable</div>
<div class="separator" style="clear: both;">
launchable-activity: name='com.abc.test01.Test01' label='Test01' icon=''</div>
<div class="separator" style="clear: both;">
uses-permission: name='android.permission.INTERNET'</div>
<div class="separator" style="clear: both;">
uses-permission: name='android.permission.READ_PHONE_STATE'</div>
<div class="separator" style="clear: both;">
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'</div>
<div class="separator" style="clear: both;">
sdkVersion:'7'</div>
<div class="separator" style="clear: both;">
targetSdkVersion:'7'</div>
<div class="separator" style="clear: both;">
feature-group: label=''</div>
<div class="separator" style="clear: both;">
uses-feature: name='android.hardware.screen.portrait'</div>
<div class="separator" style="clear: both;">
uses-implied-feature: name='android.hardware.screen.portrait' reason='one or more activities have specified a portrait orientation'</div>
<div class="separator" style="clear: both;">
uses-feature: name='android.hardware.touchscreen'</div>
<div class="separator" style="clear: both;">
uses-implied-feature: name='android.hardware.touchscreen' reason='default feature for all apps'</div>
<div class="separator" style="clear: both;">
main</div>
<div class="separator" style="clear: both;">
other-activities</div>
<div class="separator" style="clear: both;">
supports-screens: 'small' 'normal' 'large'</div>
<div class="separator" style="clear: both;">
supports-any-density: 'true'</div>
<div class="separator" style="clear: both;">
locales: '--_--'</div>
<div class="separator" style="clear: both;">
densities: '160'</div>
<div class="separator" style="clear: both;">
</div>
</code></pre>
<div class="separator" style="clear: both; text-align: left;">
That's all for now. Cheers.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-22240054063696110572015-01-31T17:26:00.000-06:002020-06-23T11:07:15.760-06:00Android -- Introduction to Fragments (Part 2)Building off our last example, we'll spend some time demonstrating how to introduce multiple fragments into a single activity. Along the way, we'll pick up a little more knowledge on how the activities and fragment interaction with one another.<br />
<br />
Let's start by extending the res/layout/main.xml to have two layouts as follows;<br />
<br />
<pre><code>
$ cat res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<span style="color: blue;"> android:id="@+id/container"
</span> android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World, FragTest01"
/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<span style="color: blue;"> android:id="@+id/container2"
</span> android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World, FragTest02"
/>
</LinearLayout>
</LinearLayout>
</code></pre>
<div class="P1">
<br /></div>
<div class="P1">
Notice we've duplicated the original linear layout (id=container) and identified the copy as container2. In addition, both of these layouts have been contained within a parent layout, the layout_height attributes were modified to keep the first layout from using the full screen.<br />
<br />
As you may recall, the activity FragTest01.java specifies adding an object of the MyFragment class into the desired container;<br />
<pre><code>
<span style="color: blue;">
.
.
getFragmentManager().beginTransaction()
.add(R.id.container, MyFragment.newInstance())
.commit();
.
.
</span>
</code></pre>
</div>
<br />
If we extend on this call as follows we're left with creating two copies of the MyFragment fragment and placing into two independent containers.<br />
<pre><code>
<span style="color: blue;">
.
.
</span> getFragmentManager().beginTransaction()
.add(R.id.container, MyFragment.newInstance())
<span style="color: blue;"> .add(R.id.container2, MyFragment.newInstance())
</span> .commit();
<span style="color: blue;">.
.
</span>
</code></pre>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2SV8wX7S1lBoX-p7j6ViNQgsSWz8MULLBdnR-_f_zSOM1_hE8rYakf_ugpmyNj9Je1GxACy55TBEVQ8FueicctyZ45qtpjJGmBDOhkehrL76kYvbVRusjEjHTaAMOdRH8lQEH6iPwegI/s1600/Screenshot_2015-01-31-16-41-26.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2SV8wX7S1lBoX-p7j6ViNQgsSWz8MULLBdnR-_f_zSOM1_hE8rYakf_ugpmyNj9Je1GxACy55TBEVQ8FueicctyZ45qtpjJGmBDOhkehrL76kYvbVRusjEjHTaAMOdRH8lQEH6iPwegI/s1600/Screenshot_2015-01-31-16-41-26.png" height="320" width="192" /></a></div>
<br />
<br />
Ehh, not terribly interesting, two copies of the same fragment with the same layout. <br />
<br />
We can now create specialized fragments, one for each layout. We'll leave MyFragment.java/myfrag.xml in the top layout and create new elements MyFragment02.java/myfrag2.xml for the lower frame.<br />
<br />
Duplicating res/layout/myfrag.xml, we simply change the text to demonstrate the difference from the original.<br />
<br />
<pre><code>$ cat res/layout/myfrag2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#666666">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
<span style="color: blue;"> android:text="My Fragment Example 02"
</span> android:textColor="#000000"
android:textSize="20px" />
</LinearLayout>
</code></pre>
<br />
Similarly, we'll duplicate MyFragment.java for a new class, inflating from the new layout file.<br />
<br />
<pre><code>
$ cat src/com/fsk/example/FragTest01/MyFragment02.java
package com.fsk.example.FragTest01;
import android.os.Bundle;
import android.app.Fragment;
import android.view.ViewGroup;
import android.view.View;
import android.view.LayoutInflater;
public class MyFragment02 extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(<span style="color: blue;">R.layout.myfrag2</span>, container, false);
}
public static Fragment newInstance() {
MyFragment02 fragment = new MyFragment02();
fragment.setRetainInstance(true);
return fragment;
}
}
</code></pre>
<div>
<br /></div>
Finally, return to the activity and add unique fragments rather than adding two copies of the original.<br />
<pre><code>
.
.
getFragmentManager().beginTransaction()
.add(R.id.container, MyFragment.newInstance())
<span style="color: blue;">.add(R.id.container2, MyFragment02.newInstance())</span>
.commit();
.
.
</code></pre>
We end with two specialized fragments within the same activity;<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXl6mowGwDSWc_tqwd62E6qrRE3MbK0qVPm9ESfjMivar0ydTx3L0BqA8dgvwYFqfi6nfFRjoSIkf8Bey-98p7Mw35VUP-eM5tngpiawlMst7WAvUjk9u8qZtrsP-8eQNlGO37C-_mKLo/s1600/Screenshot_2015-01-31-16-54-13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXl6mowGwDSWc_tqwd62E6qrRE3MbK0qVPm9ESfjMivar0ydTx3L0BqA8dgvwYFqfi6nfFRjoSIkf8Bey-98p7Mw35VUP-eM5tngpiawlMst7WAvUjk9u8qZtrsP-8eQNlGO37C-_mKLo/s1600/Screenshot_2015-01-31-16-54-13.png" height="320" width="192" /></a></div>
<br />
Nothing sexy, but a toy example that demonstrates tying and linking activities and fragments.<br />
<br />
Cheers.FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-18769330020543925952015-01-31T16:14:00.000-06:002020-06-23T11:07:15.737-06:00Android -- Introduction to Fragments (Part 1)<div style="line-height: 100%; margin-bottom: 0in;">
Life gets busy. As
a result, I took a hiatus from Android development for a period of
several months. What I returned to; the concept of fragments,
support libraries, Android Studio and with it a new file structure,
new IDE and numerous new technologies for Android development.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Surrounded by new
concepts and tools, one must focus on ramping back up one area at a
time. With the objective of increased productivity, tools such as
Android Studio do much for the developer hiding subtleties from the
developer by automating a good deal of the heavy lifting. While I
fully recommend use of such tools, the course of this post will be
working with the SDK, no IDE, to better understand the subtleties and
reduce the complexity of the files and structures.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
</div>
<div style="line-height: 100%; margin-bottom: 0in;">
</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Let's start by
creating a project;</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<pre><code>
$ android list
targets | grep id:
id: 1 or "android-7"
id: 2 or "android-8"
id: 3 or "android-21"
id: 4 or "Google Inc.:Google APIs:7"
id: 5 or "Google Inc.:Google APIs:8"
id: 6 or "Google Inc.:Google APIs:21"</code></pre>
</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Targeting Google API v21, we specify target 6.</div>
<pre><code>
$ android create project --name FragTest01 --path ./ws/FragTest01 --target 6 --package com.fsk.example.FragTest01 --activity FragTest01
</code></pre>
Build it by executing the build via Ant;
<br />
<pre><code>
$ cd ws/FragTest01
$ ant debug
$ adb devices
List of devices attached
01aa7bcb8c8c07be device
</code></pre>
<br />
With a connected device, start the logcat service, followed by installing and running the app;<br />
<pre><code>
$ xterm -e adb logcat &amp;
$ adb -s 01aa7bcb8c8c07be install -r ./bin/FragTest01-debug-unaligned.apk
$ adb -s 01aa7bcb8c8c07be shell am start -a android.intent.action.MAIN -n com.fsk.example.FragTest01/.FragTest01
</code></pre>
<br />
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
We now have an
initial project set up, we can continue to play.</div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJLWm6nntz9uCa8WBe55MDu_CCQ3GKZV-2k8MpcW_bjyeUMEgvqrpsPqmM_3OA9XiosygrL-2NQcQYQRNLTlCXA2nOgqc7F3356wXEdkSAERTDScdyV7RgH5y3g5LZnvICEof4Hrcrc34/s1600/Screenshot_2015-01-31-13-24-47.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJLWm6nntz9uCa8WBe55MDu_CCQ3GKZV-2k8MpcW_bjyeUMEgvqrpsPqmM_3OA9XiosygrL-2NQcQYQRNLTlCXA2nOgqc7F3356wXEdkSAERTDScdyV7RgH5y3g5LZnvICEof4Hrcrc34/s1600/Screenshot_2015-01-31-13-24-47.png" height="320" width="192" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div style="line-height: 100%; margin-bottom: 0in;">
First modification
we'll make is to the res/layout/main.xml file that was generated as
part of the project creation. We'll simply be adding an id to the
layout, the usage will become apparent later.<br />
<br /></div>
<br />
<pre><code>$ cat res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<span style="color: blue;"> <span class="T3">android:id="@+id/container"</span>
</span> android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World, FragTest01"
/>
</LinearLayout>
</code></pre>
<br />
<br />
<div style="line-height: 100%; margin-bottom: 0in;">
We'll move along
next by creating our first fragment. Before we do so though, let's
spend a bit of time discussing the concept of fragments.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
The Android
developers website does solid job describing the concept of
fragments, I'd recommend spending some candle-lit quality time with
it, but for now the Cliff Notes for fragments are:</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br />
<ul>
<li><span style="line-height: 100%;">Fragments
represent behavior, or portion of user interface in an activity.
Think of fragments as a new container to stuff behaviors previously
localized in activities with the overall goal of better supporting
evolving screen sizes and resolutions.</span></li>
<li><span style="line-height: 100%;">A fragments
meaning of life is to be contained within an activity, the activity
gives the fragment(s) a purpose in life.</span></li>
</ul>
</div>
<br />
<div style="line-height: 100%; margin-bottom: 0in;">
Since a fragment represents a portion of the UI, let's create a layout file for it;</div>
<div class="P3">
<code></code><br />
<pre><code>$ cat res/layout/myfrag.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#666666">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="My Fragment Example"
android:textColor="#000000"
android:textSize="20px" />
</LinearLayout>
</code></pre>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Linear layout, text
view with some static text.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
Next, we'll create a
fragment that uses this layout.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<pre><code>
$ cat src/com/fsk/example/FragTest01/MyFragment.java
package com.fsk.example.FragTest01;
import android.os.Bundle;
import android.app.Fragment;
import android.view.ViewGroup;
import android.view.View;
import android.view.LayoutInflater;
public class MyFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.myfrag, container, false);
}
public static Fragment newInstance() {
MyFragment fragment = new MyFragment();
fragment.setRetainInstance(true);
return fragment;
}
}
</code></pre>
The two key methods
of interest; onCreateView() and newInstance(). </div>
<div style="line-height: 100%; margin-bottom: 0in;">
The onCreateView()
method is part of the Fragment Lifecycle, it's purpose is to return a
View that is the root of the fragment layout. This is done in this
case by inflating the myfrag.xml layout file.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<br />
<div style="line-height: 100%; margin-bottom: 0in;">
The newInstance()
method returns a new instance of the fragment, used by the activity
which is shown below;</div>
<div style="margin-bottom: 0in;">
<div style="line-height: 100%;">
<br /></div>
<pre><code><span style="line-height: 16px;">$ cat src/com/fsk/example/FragTest01/FragTest01.java </span>
<span style="line-height: 16px;">package com.fsk.example.FragTest01;</span>
<span style="line-height: 16px;">import android.app.Activity;</span>
<span style="line-height: 16px;">import android.os.Bundle;</span>
<span style="line-height: 16px;">import java.util.Timer;</span>
<span style="line-height: 16px;">import java.util.TimerTask;</span>
<span style="line-height: 16px;">public class FragTest01 extends Activity</span>
<span style="line-height: 16px;">{</span>
<span style="line-height: 16px;"> /** Called when the activity is first created. */</span>
<span style="line-height: 16px;"> @Override</span>
<span style="line-height: 16px;"> public void onCreate(Bundle savedInstanceState)</span>
<span style="line-height: 16px;"> {</span>
<span style="line-height: 16px;"> super.onCreate(savedInstanceState);</span>
<span style="line-height: 16px;"> setContentView(R.layout.main);</span>
<span style="line-height: 16px;"> init();</span>
<span style="line-height: 16px;"> }</span>
<span style="line-height: 16px;"> private void init()</span>
<span style="line-height: 16px;"> {</span>
<span style="line-height: 16px;"> Timer t=new Timer();</span>
<span style="line-height: 16px;"> t.schedule(new TimerTask() </span>
<span style="line-height: 16px;"> {</span>
<span style="line-height: 16px;"> public void run()</span>
<span style="line-height: 16px;"> {</span>
<span style="line-height: 16px;"> getFragmentManager().beginTransaction()</span>
<span style="line-height: 16px;"> .add(R.id.container, MyFragment.newInstance())</span>
<span style="line-height: 16px;"> .commit();</span>
<span style="line-height: 16px;"> }</span>
<span style="line-height: 16px;"> },5000);</span>
<span style="line-height: 16px;"> }</span>
<span style="line-height: 16px;">}</span>
</code></pre>
</div>
</div>
<span style="line-height: 100%;"><br /></span>
<span style="line-height: 100%;">The activity simply
sets the content view, represented by main.xml, then schedules a
timer to add (read that as create) the fragment after 5 seconds.
Adding/removing/replacing of fragments is done in the form of
'transactions' which are executed on the UI thread some time after
being committed.</span><br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGisZPbyVUd8VU8wQtNe_d0jfDUJWTbqRLlVJVSMb5mziwOM5UOU58Hx-sP1YIGVtcgR-ug4KHxuB_T1NxL0pjh_EYpdc7BOE7z6ic_F0kg0cgpctESDdnQ0sUpaz2rKg-Mc0HO9Vd4sY/s1600/Screenshot_2015-01-31-14-51-01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGisZPbyVUd8VU8wQtNe_d0jfDUJWTbqRLlVJVSMb5mziwOM5UOU58Hx-sP1YIGVtcgR-ug4KHxuB_T1NxL0pjh_EYpdc7BOE7z6ic_F0kg0cgpctESDdnQ0sUpaz2rKg-Mc0HO9Vd4sY/s1600/Screenshot_2015-01-31-14-51-01.png" height="320" width="192" /></a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
About as simple of
an example as there is. We'll expand on it in later posts.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
Full source for this
example can be retrieved <a href="https://code.google.com/p/fatslowkid/source/browse/#svn%2Ftrunk%2FAndroid%2Ffragment%2FFragTest01" target="_blank">here.</a></div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0in;">
</div>
<div style="line-height: 100%; margin-bottom: 0in;">
Cheers.</div>
<div style="line-height: 100%; margin-bottom: 0in;">
<br /></div>
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-83466139205385733452014-05-26T20:45:00.000-06:002014-05-26T20:45:47.576-06:00DVD Backup on LinuxIt's been years now, all my primary computers have Linux as the host operating system. Few things can't be done in Linux, but one in particular is backing up dvd's which required the installation of VirtualBox and Windows VM. I've been using that setup for some time to backup dvd's, with applications such as DVDFab, DvdShrink or the like. With WinXp at EOL and Nero failing to work with Win7 VMs I finally gave it up after finding an alternative application for native Linux.<br />
<br />
K9copy seems to scratch the itch. Using Ubuntu 12.04, I found setting it up takes the form:<br />
<br />
<pre><copy>
$ sudo apt-get install libdvdcss libdvdcss2
$ sudo apt-get update
$ sudo apt-get install libdvdread4
$ sudo /usr/share/doc/libdvdread4/install-css.sh
$ sudo apt-get install k9copy</copy></pre>
<br />
<br />
<a href="http://k9copy.sourceforge.net/web/index.php/en/" target="_blank">http://k9copy.sourceforge.net/web/index.php/en/</a>
<br />
<br />
Happy viewing.FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-80152665544632258302014-05-03T19:18:00.000-06:002014-05-03T19:18:24.110-06:00Google ArchiveDid you know that you can export all your Google artifacts?<br />
<br />
<div style="background-color: white; color: #747474; font-family: 'Fjord One', Arial, Helvetica, sans-serif; font-size: 15px; line-height: 20px; margin-bottom: 20px;">
<strong>https://www.google.com/takeout</strong></div>
<div style="background-color: white; color: #747474; font-family: 'Fjord One', Arial, Helvetica, sans-serif; font-size: 15px; line-height: 20px; margin-bottom: 20px;">
<span style="color: black; font-family: 'Times New Roman'; font-size: small; line-height: normal;">Check the items you want to export and kick out a Zip file.</span></div>
<div style="background-color: white; color: #747474; font-family: 'Fjord One', Arial, Helvetica, sans-serif; font-size: 15px; line-height: 20px; margin-bottom: 20px;">
<span style="color: black; font-family: 'Times New Roman'; font-size: small; line-height: normal;"><br /></span></div>
<div style="background-color: white; color: #747474; font-family: 'Fjord One', Arial, Helvetica, sans-serif; font-size: 15px; line-height: 20px; margin-bottom: 20px;">
<span style="color: black; font-family: 'Times New Roman'; font-size: small; line-height: normal;">Cheers.</span></div>
<div style="background-color: white; color: #747474; font-family: 'Fjord One', Arial, Helvetica, sans-serif; font-size: 15px; line-height: 20px; margin-bottom: 20px;">
<span style="color: black; font-family: 'Times New Roman'; font-size: small; line-height: normal;"><br /></span></div>
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-5347866554432619412014-04-11T21:00:00.000-06:002014-04-11T21:00:00.035-06:00Generating Multi-Plot Real-Time Plots with PythonIn my last post the real-time plotting capabilities were demonstrated, we're extending on this by showing how to generate multiple plots simultaneously. A couple noteworthy observations, in the past post the X and Y scaling was automatically scaled after each element addition. While you can still do this, typically for multiplots we would prefer maintaining a shared X range. While somewhat unnecessary, I've elected to maintain a uniform Y range.<br />
<br />
<br />
<pre><code>
#!/usr/bin/python
from pylab import *;
import time;
def log(M):
print "__(log) " + M;
def test02():
plt.ion();
fig=plt.figure(1);
ax1=fig.add_subplot(311);
ax2=fig.add_subplot(312);
ax3=fig.add_subplot(313);
l1,=ax1.plot(100,100,'r-');
l2,=ax2.plot(100,100,'r-');
l3,=ax3.plot(100,100,'r-');
time.sleep(3);
D=[];
i=0.0;
while (i < 50.0):
D.append((i,sin(i),cos(i),cos(i*2)));
T1=[x[0] for x in D];
L1=[x[1] for x in D];
L2=[x[2] for x in D];
L3=[x[3] for x in D];
l1.set_xdata(T1);
l1.set_ydata(L1);
l2.set_xdata(T1);
l2.set_ydata(L2);
l3.set_xdata(T1);
l3.set_ydata(L3);
ax1.set_xlim([0,50]);
ax2.set_xlim([0,50]);
ax3.set_xlim([0,50]);
ax1.set_ylim([-1.5,1.5]);
ax2.set_ylim([-1.5,1.5]);
ax3.set_ylim([-1.5,1.5]);
plt.draw();
i+=0.10;
show(block=True);
#---main---
log("main process initializing");
test02();
log("main process terminating");
</code></pre>
Easy Peasy;
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-77587664168446300882014-04-04T20:49:00.000-06:002014-04-04T20:49:00.282-06:00Generating Real-Time Plots with PythonIn my previous post we described plotting data using MatplotLib utilities and Python. While this may be valuable, it becomes notably more valuable when you can generate 'live' plots during run-time. In a past employment I worked with a series of controls engineers that utilized real-time data plots to debug and develop a highly complex multi-axis weapons system and it was the first time I understood how a real-time plot of sequence of steps simplified the development effort.<br />
<br />
Let's get started.<br />
Unlike the previous post, let's create the data and plot it as it is generated.<br />
<br />
<pre><code>
#!/usr/bin/python
from pylab import *;
import time;
def log(M):
print "__(log) " + M;
def test01():
plt.ion();
fig=plt.figure(1);
ax1=fig.add_subplot(111);
l1,=ax1.plot(100,100,'r-');
D=[];
i=0.0;
while (i < 50.0):
D.append((i,sin(i)));
T=[x[0] for x in D];
L=[x[1] for x in D];
l1.set_xdata(T);
l1.set_ydata(L);
ax1.relim();
ax1.autoscale_view();
plt.draw();
i+=0.10;
time.sleep(1/10.0);
show(block=True);
#---main---
log("main process initializing");
test01();
log("main process terminating");
</code></pre>
<pre><code>
</code></pre>
The result is a dynamically generated plot that resembles the following;<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dyuD9bb-D2vV1b7XyBZbjiYnnJ6QQBXNA0-mAEFOtwQKydhIFNlvTHcV5uHp8j6R7JFJf7HVVoYjS56FWwYig' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
Tie this plotting routine to a system providing run-time information via a socket, or perhaps monitoring network traffic via pcapture libraries and you've got yourself the foundation of a real-time data monitoring system.<br />
<br />
Cheers.FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-33121566927010501142014-04-01T20:12:00.000-06:002014-04-02T18:59:23.760-06:00Plotting with PythonScripting languages are incredibly powerful, but more powerful when you can visualize the data you are processing. In this post, we will demonstrate how to quickly plot data sets via Python.<br />
<br />
Start with installing Python and a plotting utility known as MatplotLib;<br />
<br />
<pre><code>
$ sudo apt-get install python python-matplotlib
</code></pre>
Then, let's start with a classic plot, sin(x);<br />
<br />
<br />
<pre><code>
#!/usr/bin/python
from pylab import *;
import time;
def log(M):
print "__(log) " + M;
def test00():
D=[];
i=0.0;
while (i < 50.0):
D.append((i,sin(i)));
i+=0.10;
plt.ion();
xlabel('radians');
ylabel('sin(x)');
grid(True);
plt.figure(1);
show();
T=[x[0] for x in D];
L=[x[1] for x in D];
plt.plot(T,L,'b-');
show(block=True);
#---main---
log("main process initializing");
test00();
log("main process terminating");
</code></pre>
The result is calculating a data set followed by plotting the data and allowing the user to manipulate the plots (e.g. zooming, panning, ...).
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsfTdpBJkvYoGYE34rl6hWBupSHUWbIoCTifVs89d7uZ1NrRg9xIO6JblqB0ReeXiRoD0xT4NlEOm09rySPjcNevk5kD4-u1_9zu1ZFomziDwcObWMNFPoQOspA-TyDpBAZdaD_dU4J2Q/s1600/plot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsfTdpBJkvYoGYE34rl6hWBupSHUWbIoCTifVs89d7uZ1NrRg9xIO6JblqB0ReeXiRoD0xT4NlEOm09rySPjcNevk5kD4-u1_9zu1ZFomziDwcObWMNFPoQOspA-TyDpBAZdaD_dU4J2Q/s1600/plot.png" height="257" width="320" /></a></div>
<br />
<br />
For more detailed features, refer to the MatlabLib site: <a href="http://matplotlib.org/contents.html">http://matplotlib.org/contents.html</a><br />
<br />
Cheers.<br />
<br />FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-90768188567687456172014-03-27T22:26:00.000-06:002014-04-02T18:58:07.744-06:00Tcpdump ExamplesAs much as I like using Wireshark, I'm a sucker for a command interface. The trouble is properly defining a filter has been difficult to say the least, boring simple post, but below is a list of brief examples and descriptions.<br />
<br />
#!/bin/bash<br />
<br />
#--grab the first 10 packets and write to file<br />
tcpdump -c 10 -i wlan0 -w /tmp/data.pcap<br />
<br />
#--grab the first 10 packets to/from host and write to file<br />
tcpdump -c 10 -i wlan0 host 192.168.1.125 -w /tmp/data.pcap<br />
<br />
#--grab the first 10 packets from host and write to file<br />
tcpdump -c 10 -i wlan0 src host 192.168.1.125 -w /tmp/data.pcap<br />
<br />
#--grab the first 10 packets to host and write to file<br />
tcpdump -c 10 -i wlan0 dst host 192.168.1.125 -w /tmp/data.pcap<br />
<br />
#--grab the first 10 packets to/from port and write to file<br />
tcpdump -c 10 -i wlan0 port 80 -w /tmp/data.pcap<br />
<br />
#--grab the first 10 packets to/from net and write to file<br />
tcpdump -c 10 -i wlan0 net 192.168.1 -w /tmp/data.pcap<br />
<br />
#--grab the first 10 packets from network and write to file<br />
tcpdump -c 10 -i wlan0 src net 192.168.1 -w /tmp/data.pcap<br />
<br />
#--grab the first 10 packets from network and write to file<br />
tcpdump -c 10 -i wlan0 dst net 192.168.1 -w /tmp/data.pcap<br />
<br />
#--grab the first 10 packets from network and write to file<br />
tcpdump -c 10 -i wlan0 '(dst host 192.168.1.125) and (port 443)' -w /tmp/data.pcap<br />
<div>
<br /></div>
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-47263714407089790452013-12-08T22:00:00.000-06:002014-04-02T18:57:45.462-06:00Useful FFMpeg Filter <div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />
<br />
FFMpeg offers more than standard encoding/decoding. It also allows for running a series of filters, both audio and video, that may prove useful in many a situation.<br />
<br />
Let's start with an good quality input video;<br />
<br />
<br />
$ ffmpeg -y -i video.avi -ss 10 -t 40 -qscale 0 -s 360x240 clip01.mpg<br />
<div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dw24YJKWBR-K1-Ca8glly8s4mM-xWWI5E170fEOAU3H4v4XWDO2a9YNV12ULIjEM-OoOnHWMPpGKy_ZmV2h2A' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Ok, now that we have a video let's look at a few things we may choose to do with it using our newly discovered filters.<br />
<br />
<h3>
Adjusting Video Speed</h3>
Suppose you wish to speed the video up, perhaps to expedite review of a surveillance video or perhaps minimizing the exposure to the latest Sandra Bullock film.<br />
<br />
We can double the playback speed by specifying a 0.5 playback coefficient;<br />
<br />
$ ffmpeg -y -i clip01.mpg -filter:v "setpts=0.5*PTS" clip02.mpg<br />
<br />
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzreeB20D1_KJQTTMEXTrD9tyBqJoSW8uhDSFrkn_dIZZvmIEbjcaqCCA5NZBVzc8WKMcvyo6eKpoqtQPPVBQ' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
You'll notice however from the previous video that while the video element is playing at double speed, the audio hasn't changed. We can speed up the audio similarly by adding an appropriate audio filter.<br />
<br />
<br />
<br />
$ ffmpeg -y -i clip01.mpg -filter:v "setpts=0.5*PTS" -filter:a "atempo=2.0" clip03.mpg<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxn0q2nvOA0nhTP3SBjasLcR_XpTrQRLFIclbgaE7JykoDYWxZEVBQfnEpGKL48Dp7AOI-CQgvA44Due-BQUw' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Attempting to speed up faster than 2x will present a hurdle with speeding up the audio filter, which specifies a coefficient range of [0.5, 2.0]. You can get around that by chaining filters;<br />
<br />
$ ffmpeg -i clip01.mpg -filter:v "setpts=0.25*PTS" -filter:a "atempo=2.0,atempo=2.0" clip04.mpg<br />
<br />
<br />
<br />
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwPoEvQtmJzNHUfNgFO3YTh8lOHt4vshln0zPcLdhRwNKg_1nZ3briEVd0PDaNVuFc9U-uE6SmJYOsQT0coTQ' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br />
<br />
<br />
<h3>
Cropping Video</h3>
Suppose we wish to crop the inner middle of the video. Given the video is 360x240, we need to grab 180x120 inset by 90,60.<br />
<br />
$ ffmpeg -y -i clip01.mpg -filter:v "crop=180:120:90:60" clip05.mpg<br />
<br />
<br />
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dw18T4VqUWkS_fqq26N1iGi3fSNiRj-W1hWJUaBKEInPjfTdTPxNTNgMyYjY6TCThKna9XCbKeA0kPIx52xvw' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br />
<br />
<br />
<br />
<h3>
Processing Edge Detection</h3>
<div>
Perhaps less useful, but certainly interesting, you can perform edge detection via a Canny Edge Detection algorithm;</div>
<div>
$ ffmpeg -y -i clip01.mpg -filter:v "edgedetect=low=0.1:high=0.4" clip06.mpg</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzfFsGzM8WjoYTBY2d9QeqZqUHkCMKphLMr8CJLHUCsGyY9uABO8y06D7tKq3RQHM8xW10UONbcA5gZL49Liw' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<div>
<br /></div>
<br />
<br />
<br />
<br />
<h3>
<span class="Apple-style-span" style="font-size: small; font-weight: normal;"><span class="Apple-style-span" style="font-size: x-large;"><span class="Apple-style-span" style="font-size: 19px;"><b>Flipping the Video</b></span></span></span></h3>
</div>
<div>
You can flip the video left-right or top-down;<br />
$ ffmpeg -y -i clip01.mpg -filter:v "hflip" clip07.mpg<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxgmFc1baShfnNlSx92Vom90aA92b_WGRVgwg8-0Q7tXZdTgGMlSKPFSTs-CRt-FX4YAawrGNYVPt_lGLEnsQ' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
$ ffmpeg -y -i clip01.mpg -filter:v "vflip" clip08.mpg<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxUNmxp09bBQnZgqzwcvJk_Z9YSFxeInVBfh9Px_lU5ZTHmgDh-N5QHlG8nyHAnOm3tHqFMOuF0cGy5ChF6SA' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
<br /></div>
<div>
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;">
</div>
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;">
<h3 style="font-weight: normal;">
<span class="Apple-style-span" style="font-size: small; font-weight: normal;"><span class="Apple-style-span" style="font-size: x-large;"><span class="Apple-style-span" style="font-size: 19px;"><b><br /></b></span></span></span></h3>
<h3 style="font-weight: normal;">
<span class="Apple-style-span" style="font-size: small; font-weight: normal;"><span class="Apple-style-span" style="font-size: x-large;"><span class="Apple-style-span" style="font-size: 19px;"><b><br /></b></span></span></span></h3>
<h3 style="font-weight: normal;">
<span class="Apple-style-span" style="font-size: small; font-weight: normal;"><span class="Apple-style-span" style="font-size: x-large;"><span class="Apple-style-span" style="font-size: 19px;"><b><br /></b></span></span></span></h3>
<h3 style="font-weight: normal;">
<span class="Apple-style-span" style="font-size: small; font-weight: normal;"><span class="Apple-style-span" style="font-size: x-large;"><span class="Apple-style-span" style="font-size: 19px;"><b><br /></b></span></span></span></h3>
<h3 style="font-weight: normal;">
<span class="Apple-style-span" style="font-size: small; font-weight: normal;"><span class="Apple-style-span" style="font-size: x-large;"><span class="Apple-style-span" style="font-size: 19px;"><b><br /></b></span></span></span></h3>
<h3 style="font-weight: normal;">
<span class="Apple-style-span" style="font-size: small; font-weight: normal;"><span class="Apple-style-span" style="font-size: x-large;"><span class="Apple-style-span" style="font-size: 19px;"><b><br /></b></span></span></span></h3>
<h3 style="font-weight: normal;">
<span class="Apple-style-span" style="font-size: small; font-weight: normal;"><span class="Apple-style-span" style="font-size: x-large;"><span class="Apple-style-span" style="font-size: 19px;"><b>Creating Video Using Source Filter</b></span></span></span></h3>
<div>
Occasionally, you want to generate a video using a test source; in other words, without an input video to start with.<br />
$ ffmpeg -f lavfi -i rgbtestsrc -t 30 -pix_fmt yuv420p clip09.mpg<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzRXVwuSr49jdh06wJjCbC0IIZPAg2AOIR9s-_ADYzki1pxDAc3WNIUK2DeIw9eINNTX_1i0YYDtNKB4rgV5g' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
$ ffmpeg -f lavfi -i testsrc=duration=20:size=1280x720:rate=30 -vcodec mpeg2video clip10.mpg</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwv9pR-SB-RePymMqhzPqxahcWfwxwMXehS6-uCLe-xASDpKGBck56i7wmfewD9mr_1y4cRXUel-zfgIZSCXA' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<div>
<br /></div>
</div>
</div>
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-82133586311031483632013-11-29T16:52:00.000-06:002014-04-02T18:56:33.003-06:00Extracting Video from DVDsTime and again I find a need to snag video from a DVD and perform some routine video processing.<br />
<br />
FFMpeg works nicely with standard video files, less nicely with DVD structures. While you can certainly extract video directly from the DVD VOB files (ref: <a href="http://en.wikibooks.org/wiki/Inside_DVD-Video/Directory_Structure">http://en.wikibooks.org/wiki/Inside_DVD-Video/Directory_Structure</a>) it's less than desirable since the locating the specific VOB file that contains the segment of video your interested in can be a bit of a setback.<br />
<br />
Enter Mplayer;<br />
Mplayer can readily play DVD contents in a user friendly way. It can also dump the file to a more usable file if you can persuade it to do so.<br />
<br />
You can extract the full main title into a single VOB file can be done by playing the DVD somewhat normally, but adding a few arguments;<br />
<br />
<pre><code>
$ mplayer dvd:// -dumpstream -dumpfile /tmp/video.vob
user@River:~$
</code></pre>
The above will extract the main title into a single VOB file. Examining with FFMpeg and you'll find that the output file has a video stream and a single audio stream;<br />
<br />
<br />
<pre><code>
$ ffprobe -i /tmp/video.vob
ffprobe version 1.1.2 Copyright (c) 2007-2013 the FFmpeg developers
built on Feb 10 2013 17:42:38 with gcc 4.4.5 (Debian 4.4.5-8)
configuration: --enable-filter=split
libavutil 52. 13.100 / 52. 13.100
libavcodec 54. 86.100 / 54. 86.100
libavformat 54. 59.106 / 54. 59.106
libavdevice 54. 3.102 / 54. 3.102
libavfilter 3. 32.100 / 3. 32.100
libswscale 2. 1.103 / 2. 1.103
libswresample 0. 17.102 / 0. 17.102
[mpeg @ 0x2cd4c60] max_analyze_duration 5000000 reached at 5004678
Input #0, mpeg, from '/tmp/video.vob':
Duration: 01:37:58.02, start: 0.280633, bitrate: 5012 kb/s
<b>Stream #0:0[0x1e0]: Video: mpeg2video</b> (Main), yuv420p, 720x480 [SAR 32:27 DAR 16:9], 26.50 fps, 59.94 tbr, 90k tbn, 59.94 tbc
<b>Stream #0:1[0x80]: Audio: ac3</b>, 48000 Hz, 5.1(side), fltp, 448 kb/s
</code></pre>
<br />
You may choose an alternative container rather than a VOB by specifying an alternative extension, such as an AVI container by specifying output file video.avi.<br />
<br />
Now, we have something we can readily work with.<br />
<br />
Let's snag a 30 sec clip starting at 90 seconds in:<br />
<code></code><br />
<code></code><br />
<code></code><br />
<code></code><br />
<pre><code>$ ffmpeg -i /tmp/video.vob -qscale 0 -ss 90 -t 30 /tmp/clip.mpg
</code></pre>
<code>
</code>
<br />
<br />
If you're only interested in the video, you can extract only the video by specifying;<br />
<br />
<pre><code>
$ mplayer dvd:// -dumpvideo -dumpfile /tmp/video01.avi
</code></pre>
<br />
Or, if you're only interested in listening to the Big Bang Theory like an audio tape, extract only the audio;<br />
<br />
<code></code><br />
<code></code><br />
<code></code><br />
<pre><code>$ mplayer dvd:// -dumpaudio -dumpfile /tmp/video01.aac
</code></pre>
<code>
</code><br />
<div>
<br /></div>
<div>
<br /></div>
Cheers.
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-53166758552446610372013-10-24T20:39:00.000-06:002014-04-02T18:55:15.964-06:00Create Counting Video<br />
On a couple of occasions, I've had the need to create a source video for video processing and testing video processing commands. A common need is to create a counting video by generating a series of frames and stitching them together at a pre-defined frame rate.<br />
<br />
Below is a mechanism for doing so;<br />
<br />
<pre><code>
$ cat createVideo
#!/bin/bash
ws=/var/tmp/cache
rm -rf $ws
mkdir -p $ws
for i in `seq 300`; do
N=$(printf %03d $i)
convert -size 640x480 -background white -fill black -pointsize 120 -gravity center label:$i $ws/frame-$N.jpg
done
ffmpeg -y -r 2/1 -i $ws/frame-%03d.jpg -r 30/1 $ws/video.avi
mplayer $ws/video.avi
</code></pre>
<br />
Cheers.FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-17954729819387718262013-10-18T19:07:00.000-06:002014-04-02T18:54:36.493-06:00Formatting Numerics With BashA repeated need I've encountered is a need to format a numeric with leading zeros, similar to the common form used in C. Typically, I take a over-complicated approach of comparing the number to >100 or >10 and pre-pending leading zeros.<br />
<br />
After investigating alternative approaches with good 'ole Google, the better approach is shown below;<br />
<br />
<pre><code>
$ cat /tmp/go
#!/bin/bash
for i in `seq 100`; do
N=$(printf %03d $i)
echo $N
done
</code></pre>
Cheers.<br />
<br />FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-37421009707984418692013-10-11T18:01:00.000-06:002014-04-02T18:53:53.702-06:00FFMpeg Cropping VideosRecently had a need to crop videos using FFMpeg, thought it worth sharing.
Starting with the initial video:
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwAd1yDZVnFCRJ-1wTEvgC4WJbaY0j_vAQTNONLJignPCJev-BBmHMPc894Spf5oWhfWNrNToTHupznILL9GA' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<pre><code>
$ ffmpeg -i ExSlyoVTX3I.flv -vf crop=160:120:10:10 -sameq /tmp/out.mp4
</code></pre>
<br />
The result is a cropped video 160x120 with an offset of 10,10 from the upper left-hand corner.<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dz_JdblB03eyCDlwtDF-G1HV5N9RRPAOwTqWbQX_3kRWUgoHLSS_j9l3vrFrZciYirO0wkQypN7JASgSO1zOA' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
<br />
Cheers.<br />
<br />FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-60381641250081385212013-10-05T21:37:00.000-06:002013-10-05T21:37:00.241-06:00Google ProtoBuff + ZeroMq -- PythonIn our last post, we combined ZeroMq & Google Protobuf, a combination that enables heterogeneous distributed computing systems. The last post integrated the two using C++, this post will focus on integrating the two using Python. In the end, we'll have an example that can communicate with the previous C++ example seamlessly.<br />
<br />
Below is a Makefile, used to create and clean up Google Protobuf message files.<br />
<br />
<pre><code>
$ cat Makefile
msgs:
<span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} protoc -I=. --python_out=. Messages.proto
clean:
<span class="Apple-tab-span" style="white-space: pre;"> </span>${RM} Messages_pb2.py
<div>
</div>
</code></pre>
<div>
<br /></div>
<div>
Our sender script is below, notice the change is that of the content exchanged, specifically the serialized protobuff message.</div>
<div>
<br /></div>
<div>
<pre><code>
<div>
<div>
$ cat sender</div>
<div>
#!/usr/bin/python</div>
<div>
</div>
<div>
import zmq;</div>
<div>
import time;</div>
<div>
import Messages_pb2</div>
<div>
</div>
<div>
context = zmq.Context();</div>
<div>
pub=context.socket(zmq.PUB);</div>
<div>
pub.bind("tcp://127.0.0.1:8000");</div>
<div>
</div>
<div>
for i in range(0,10):</div>
<div>
</div>
<div>
p=Messages_pb2.Person();</div>
<div>
p.id=i;</div>
<div>
p.name="fatslowkid";</div>
<div>
</div>
<div>
print "iteration",i</div>
<div>
pub.send(p.SerializeToString());</div>
<div>
time.sleep(1);</div>
</div>
<div>
</div>
</code></pre>
<div>
<br /></div>
<div>
The receiver;</div>
<div>
<pre><code>
<div>
<div>
$ cat receiver</div>
<div>
#!/usr/bin/python</div>
<div>
</div>
<div>
import zmq;</div>
<div>
import time;</div>
<div>
import Messages_pb2</div>
<div>
</div>
<div>
context = zmq.Context();</div>
<div>
sub=context.socket(zmq.SUB);</div>
<div>
sub.connect("tcp://127.0.0.1:8000");</div>
<div>
filter=""</div>
<div>
sub.setsockopt(zmq.SUBSCRIBE, filter);</div>
<div>
</div>
<div>
</div>
<div>
for i in range(0,20):</div>
<div>
print "waiting on msg"</div>
<div>
M=sub.recv();</div>
<div>
p=Messages_pb2.Person();</div>
<div>
p.ParseFromString(M);</div>
<div>
print "received",p</div>
<div>
print "> " + p.name;</div>
<div>
print p.id;</div>
</div>
<div>
</div>
<div>
</div>
</code></pre>
<div>
<br /></div>
<div>
The sender/receiver can be used together, or used with the previous C++ example.</div>
<div>
<br /></div>
<div>
Cheers.</div>
</div>
</div>
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-72613796289726286622013-09-28T21:41:00.000-06:002013-09-28T21:41:00.354-06:00Google ProtoBuff + ZeroMq -- C++In the last series of posts we demonstrated ZeroMq as a technology that supports 'sockets on steroids', supporting multiple platforms as well as multiple languages. The examples to-date have been transmitting strings between senders and receivers. While interesting, to effectively create a distributed heterogeneous system we need to be capable of transmitting meaningful messages, preferably complex data structures rather than just strings. That's where Google's Protobuff comes into play: <a href="http://code.google.com/p/protobuf/" target="_blank">http://code.google.com/p/protobuf/</a><br />
<div>
<br /></div>
<div>
Building off our previously created Ubuntu 12.04 32-bit VM, let's start by installing the additional necessary packages;</div>
<div>
<br /></div>
<div>
<pre><code>
<div>
$ sudo apt-get install libprotoc-dev</div>
<div>
</div>
</code></pre>
</div>
<div>
<br /></div>
<div>
With the developer libraries installed, we can now extend our previous C++ example to transmit a ProtoBuff message.</div>
<div>
<br /></div>
<div>
We'll extend our Makefile to add the necessary libraries and a target (e.g. msgs) to generate the C++ files for the message.</div>
<div>
<br /></div>
<div>
<pre><code>
<div>
<div>
$ cat Makefile </div>
<div>
CC=g++</div>
<div>
</div>
<div>
SRCS=main.cpp Messages.pb.cc</div>
<div>
OBJS=$(subst .cpp,.o,$(SRCS))</div>
<div>
INCLUDES += -I.</div>
<div>
LIBS += -lpthread -lrt -lzmq -lprotobuf</div>
<div>
</div>
<div>
.cpp.o:</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(CC) -c $<</div>
<div>
</div>
<div>
main: msgs ${OBJS} </div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>${CC} ${CFLAGS} -o $@ ${OBJS} ${LIBS}</div>
<div>
</div>
<div>
msgs:</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>${SH} protoc -I. --cpp_out=. Messages.proto</div>
<div>
</div>
<div>
clean:</div>
<div>
<span class="Apple-tab-span" style="white-space: pre;"> </span>${RM} ${OBJS} main *.pb.*</div>
</div>
<div>
</div>
</code></pre>
</div>
<div>
<br /></div>
<div>
Oh, we should take a look at our simple Protobuff message file:</div>
<div>
<pre><code>
<div>
<div>
$ cat Messages.proto </div>
<div>
message Person {</div>
<div>
required int32 id=1;</div>
<div>
required string name=2;</div>
<div>
}</div>
</div>
<div>
</div>
</code></pre>
</div>
<div>
<br /></div>
<div>
Finally, our extended main file:</div>
<div>
<pre><code>
<div>
<div>
$ cat main.cpp </div>
<div>
#include <stdio .h=""></stdio></div>
<div>
#include <zmq .h=""></zmq></div>
<div>
#include <pthread .h=""></pthread></div>
<div>
#include <assert .h=""></assert></div>
<div>
#include <string .h=""></string></div>
<div>
#include <unistd .h=""></unistd></div>
<div>
#include "Messages.pb.h"</div>
<div>
</div>
<div>
void* ctx=zmq_init(1);</div>
<div>
char* EndPoint="tcp://127.0.0.1:8000";</div>
<div>
static const int N=100;</div>
<div>
static const int BufferSize=128;</div>
<div>
</div>
<div>
void* sender(void*)</div>
<div>
{</div>
<div>
printf("(%s:%d) running\n",__FILE__,__LINE__);</div>
<div>
void* pub=zmq_socket(ctx, ZMQ_PUB);</div>
<div>
assert(pub);</div>
<div>
int rc=zmq_bind(pub,EndPoint);</div>
<div>
assert(rc==0);</div>
<div>
Person p;</div>
<div>
p.set_name("fatslowkid");</div>
<div>
p.set_id(01);</div>
<div>
for(int i=0; i<n div="" i=""></n><br />
<div>
{</div>
<div>
zmq_msg_t msg;</div>
<div>
std::string S=p.SerializeAsString();</div>
<div>
char* content=(char*)S.c_str();</div>
<div>
int rc=zmq_msg_init_size(&msg, BufferSize);</div>
<div>
assert(rc==0);</div>
<div>
rc=zmq_msg_init_data(&msg, content, strlen(content), 0,0);</div>
<div>
assert(rc==0);</div>
<div>
rc=zmq_send(pub, &msg, 0);</div>
<div>
assert(rc==0);</div>
<div>
::usleep(100000);</div>
<div>
}</div>
<div>
}</div>
<div>
</div>
<div>
void* receiver(void*)</div>
<div>
{</div>
<div>
printf("(%s:%d) running\n",__FILE__,__LINE__);</div>
<div>
void* sub=zmq_socket(ctx, ZMQ_SUB);</div>
<div>
assert(sub);</div>
<div>
int rc=zmq_connect(sub,EndPoint);</div>
<div>
assert(rc==0);</div>
<div>
char* filter="";</div>
<div>
rc=zmq_setsockopt(sub, ZMQ_SUBSCRIBE, filter, strlen(filter));</div>
<div>
assert(rc==0);</div>
<div>
for(int i=0; i<n-1 div="" i=""></n-1><br />
<div>
{</div>
<div>
zmq_msg_t msg;</div>
<div>
zmq_msg_init_size(&msg, BufferSize);</div>
<div>
const int rc=zmq_recv (sub, &msg, 0);</div>
<div>
char* content=(char*)zmq_msg_data(&msg);</div>
<div>
Person p;</div>
<div>
p.ParseFromString(content);</div>
<div>
printf("(%s:%d) received: '%s'\n",__FILE__,__LINE__,p.name().c_str());</div>
<div>
zmq_msg_close(&msg);</div>
<div>
}</div>
<div>
}</div>
<div>
</div>
<div>
int main(int argc, char* argv[])</div>
<div>
{</div>
<div>
printf("(%s:%d) main process initializing\n",__FILE__,__LINE__);</div>
<div>
int major, minor, patch;</div>
<div>
zmq_version (&major, &minor, &patch);</div>
<div>
printf("(%s:%d) zmq version: %d.%d.%d\n",__FILE__,__LINE__,major,minor,patch);</div>
<div>
</div>
<div>
pthread_t rId;</div>
<div>
pthread_create(&rId, 0, receiver, 0);</div>
<div>
</div>
<div>
pthread_t sId;</div>
<div>
pthread_create(&sId, 0, sender, 0);</div>
<div>
</div>
<div>
pthread_join(rId,0);</div>
<div>
pthread_join(sId,0);</div>
<div>
</div>
<div>
printf("(%s:%d) main process terminating\n",__FILE__,__LINE__);</div>
<div>
}</div>
</div>
<div>
</div>
</div>
</div>
</code></pre>
</div>
<div>
<br /></div>
<div>
Notice that we now transmit and receive Protobuf messages, serialized as strings. The value of this is that the serialization mechanism is multi-platform & multi-language support.</div>
<div>
<br /></div>
<div>
Cheers.</div>
FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-66956461342922236912013-09-21T22:19:00.000-06:002013-09-21T22:19:00.099-06:00ZeroMq Installation -- PythonIn a previous post I documented the procedure for installing ZeroMq libraries for C/C++ applications. This post will focus on installing ZeroMq for Python development.<br />
<br />
<br />
Let's get started;<br />
<br />
Our target installation machine is Ubuntu 12.04 64-bit Desktop edition; <a href="http://www.ubuntu.com/download/desktop" target="_blank">http://www.ubuntu.com/download/desktop</a>. Your mileage may vary with alternative distributions. I'm starting with a new default installation and will work through the installation process from here on.<br />
<br />
<pre><code>
$ sudo apt-get install python-zmq
</code></pre>
<br />
After the APT package handling utility is done humping package installations you should have a function, albeit dated, version to begin working with.<br />
<br />
Let's take a look at what version we're dealing with here.<br />
<br />
<br />
<pre><code>
$ cat go
#!/usr/bin/python
import zmq;
print zmq.pyzmq_version()
</code></pre>
Running this beauty will show us the version of Zmq we've got installed.
<br />
<pre><code>
$ ./go
2.1.11
</code></pre>
Let's continue our sandbox by creating a sender and receiver Python script as follows;
<br />
<pre><code>
$ more sender receiver
::::::::::::::
sender
::::::::::::::
#!/usr/bin/python
import zmq;
import time;
context = zmq.Context();
pub=context.socket(zmq.PUB);
pub.bind("tcp://127.0.0.1:8000");
for i in range(0,20):
print "iteration",i
pub.send("some message");
time.sleep(1);
::::::::::::::
receiver
::::::::::::::
#!/usr/bin/python
import zmq;
import time;
context = zmq.Context();
sub=context.socket(zmq.SUB);
sub.connect("tcp://127.0.0.1:8000");
filter=""
sub.setsockopt(zmq.SUBSCRIBE, filter);
for i in range(0,20):
print "waiting on msg"
M=sub.recv();
print "received",M
</code></pre>
Running these two concurrently demonstrates the message delivery from the sender to the receiver;
<br />
<pre><code>
::::::::::::::
sender.log
::::::::::::::
iteration 0
iteration 1
iteration 2
iteration 3
iteration 4
iteration 5
iteration 6
iteration 7
iteration 8
iteration 9
iteration 10
iteration 11
iteration 12
iteration 13
iteration 14
iteration 15
iteration 16
iteration 17
iteration 18
iteration 19
::::::::::::::
receiver.log
::::::::::::::
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
received some message
waiting on msg
</code></pre>
What may be of interest you as well is that since the 'endpoint' is defined identically to the one used in the C++ example you can send messages from the Python sender script to the C++ main application.
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9MjqIQLKUaxXER4DGYtufEOqlpJniU07DHQWe-rbtSMmyCP5QApznPeo8iPqHMyzClNzCE9xFenAojZwU71Xt9vl-hugtnzOIuKBFEdT-bARb7N85i-Mp5hNC8M8c4MjyqPTLhWpcChk/s1600/foo.png" imageanchor="1"><img border="0" height="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9MjqIQLKUaxXER4DGYtufEOqlpJniU07DHQWe-rbtSMmyCP5QApznPeo8iPqHMyzClNzCE9xFenAojZwU71Xt9vl-hugtnzOIuKBFEdT-bARb7N85i-Mp5hNC8M8c4MjyqPTLhWpcChk/s400/foo.png" width="400" /></a>
<br />
<br />
Enjoy.<br />
<br />FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-30689348635055784322013-09-14T21:30:00.000-06:002013-09-14T21:30:01.050-06:00ZeroMq Installation -- C++ZeroMq, or 0Mq if you prefer, is considered 'sockets on steroids'. The framework is aimed at simplifying distributed communications, serves as a concurrency framework, and supports more languages than any normal mortal would ever require.<br />
<a href="http://zeromq.org/" target="_blank">http://zeromq.org</a><br />
<br />
The topic of this post will be guiding through the installation on Ubuntu 12.04 and writing enough example code to verify all is happy. Future posts will focus on installation of alternative, and interesting, languages with the overall intent of demonstrating interoperability between the languages.<br />
<br />
Let's get started;<br />
<br />
Our target installation machine is Ubuntu 12.04 64-bit Desktop edition; <a href="http://www.ubuntu.com/download/desktop" target="_blank">http://www.ubuntu.com/download/desktop</a>. Your mileage may vary with alternative distributions. I'm starting with a new default installation and will work through the installation process from here on.<br />
<br />
<pre><code>
$ sudo apt-get install libzmq-dev
</code></pre>
<br />
After the APT package handling utility is done humping package installations you should have a function, albeit dated, version to begin working with.<br />
<br />
While ZeroMq supports a plethora of languages, the focus of this post is on C++. That said, we'll need to install GCC C++ compiler.<br />
<br />
<pre><code>
$ sudo apt-get install g++
</code></pre>
<br />
As I said earlier, the Ubuntu repository has a fairly old version. At time of this writing, v3.2.3 was the latest stable release but for the purposes of this post we'll continue to use this version.<br />
<br />
Let's confirm what version we have by authoring our first C++ application and ensure we can successfully compile/link with the installed libraries.<br />
<br />
Start with a simple Makefile;<br />
<br />
<pre><code>
$ cat Makefile
CC=g++
SRCS=main.cpp
OBJS=$(subst .cpp,.o,$(SRCS))
INCLUDES += -I.
LIBS += -lpthread -lrt -lzmq
.cpp.o:
<span class="Apple-tab-span" style="white-space: pre;"> </span>$(CC) -c $<
main: ${OBJS}
<span class="Apple-tab-span" style="white-space: pre;"> </span>${CC} ${CFLAGS} -o $@ ${OBJS} ${LIBS}
clean:
<span class="Apple-tab-span" style="white-space: pre;"> </span>${RM} ${OBJS} main
</code></pre>
<div>
<br /></div>
<div>
And now let's look as a trival main program that confirms we can compile/link with Zmq libraries;</div>
<div>
<br /></div>
<br />
<pre><code>
$ cat main.cpp
#include <stdio .h=""></stdio>
#include <zmq .h=""></zmq>
int main(int argc, char* argv[])
{
printf("(%s:%d) main process initializing\n",__FILE__,__LINE__);
int major, minor, patch;
zmq_version (&major, &minor, &patch);
printf("(%s:%d) zmq version: %d.%d.%d\n",__FILE__,__LINE__,major,minor,patch);
printf("(%s:%d) main process terminating\n",__FILE__,__LINE__);
}
</code></pre>
<div>
<br /></div>
<br />
Running it confirms the installed Zmq libraries are near ancient, but again ok for our short-term purposes.<br />
<br />
<pre><code>
$ ./main
(main.cpp:6) main process initializing
<div>
(main.cpp:6) zmq version: 2.1.11</div>
<div>
(main.cpp:6) main process terminating</div>
</code></pre>
<br />
Let's extend this to make it a bit more interesting, classic sender/receiver communication model using the PUB/SUB comm model provided by ZeroMq.<br />
<br />
<pre><code>
$ cat main.cpp
#include <stdio .h=""></stdio>
#include <zmq .h=""></zmq>
#include <pthread .h=""></pthread>
#include <assert .h=""></assert>
#include <string .h=""></string>
#include <unistd .h=""></unistd>
void* ctx=zmq_init(1);
char* EndPoint="tcp://127.0.0.1:8000";
static const int N=100;
static const int BufferSize=128;
void* sender(void*)
{
printf("(%s:%d) running\n",__FILE__,__LINE__);
void* pub=zmq_socket(ctx, ZMQ_PUB);
assert(pub);
int rc=zmq_bind(pub,EndPoint);
assert(rc==0);
for(int i=0; i<n i="" p=""> {
char content[BufferSize];
sprintf(content, "message %03d",i);
zmq_msg_t msg;
int rc=zmq_msg_init_size(&msg, BufferSize);
assert(rc==0);
rc=zmq_msg_init_data(&msg, content, strlen(content), 0,0);
assert(rc==0);
printf("(%s:%d) sending '%s'\n",__FILE__,__LINE__,content);
rc=zmq_send(pub, &msg, 0);
assert(rc==0);
::usleep(100000);
}
}
void* receiver(void*)
{
printf("(%s:%d) running\n",__FILE__,__LINE__);
void* sub=zmq_socket(ctx, ZMQ_SUB);
assert(sub);
int rc=zmq_connect(sub,EndPoint);
assert(rc==0);
char* filter="";
rc=zmq_setsockopt(sub, ZMQ_SUBSCRIBE, filter, strlen(filter));
assert(rc==0);
for(int i=0; i<n-1 i="" p=""> {
zmq_msg_t msg;
zmq_msg_init_size(&msg, BufferSize);
const int rc=zmq_recv (sub, &msg, 0);
char* content=(char*)zmq_msg_data(&msg);
printf("(%s:%d) received: '%s'\n",__FILE__,__LINE__,content);
zmq_msg_close(&msg);
}
}
int main(int argc, char* argv[])
{
printf("(%s:%d) main process initializing\n",__FILE__,__LINE__);
int major, minor, patch;
zmq_version (&major, &minor, &patch);
printf("(%s:%d) zmq version: %d.%d.%d\n",__FILE__,__LINE__,major,minor,patch);
pthread_t rId;
pthread_create(&rId, 0, receiver, 0);
pthread_t sId;
pthread_create(&sId, 0, sender, 0);
pthread_join(rId,0);
pthread_join(sId,0);
printf("(%s:%d) main process terminating\n",__FILE__,__LINE__);
}
</n-1></n></code></pre>
<div>
<br /></div>
<div>
Running this beauty will result in the following;</div>
<pre><code>
$ cat /var/tmp/ZmqMb/main.log
(main.cpp:59) main process initializing
(main.cpp:62) zmq version: 2.1.11
(main.cpp:15) running
(main.cpp:29) sending 'message 000'
(main.cpp:38) running
(main.cpp:29) sending 'message 001'
(main.cpp:52) received: 'message 001'
(main.cpp:29) sending 'message 002'
(main.cpp:52) received: 'message 002'
(main.cpp:29) sending 'message 003'
(main.cpp:52) received: 'message 003'
(main.cpp:29) sending 'message 004'
(main.cpp:52) received: 'message 004'
(main.cpp:29) sending 'message 005'
(main.cpp:52) received: 'message 005'
(main.cpp:29) sending 'message 006'
(main.cpp:52) received: 'message 006'
(main.cpp:29) sending 'message 007'
(main.cpp:52) received: 'message 007'
(main.cpp:29) sending 'message 008'
(main.cpp:52) received: 'message 008'
(main.cpp:29) sending 'message 009'
(main.cpp:52) received: 'message 009'
(main.cpp:29) sending 'message 010'
(main.cpp:52) received: 'message 010'
(main.cpp:29) sending 'message 011'
(main.cpp:52) received: 'message 011'
</code></pre>
<pre></pre>
<div>
</div>
You'll notice that the first message was lost. I've never had a sufficient understanding of why this happens, but typically the first message can be lost, primarily due to the pub/sub sockets not necessarily being fully established. Issuing a 'sleep' between socket creation and between the receiver and sender socket usage doesn't solve the problem, it's more involved than that and I have little to offer as an explanation.
<br />
<div>
<br /></div>
<div>
So, there you go; a simple usage of ZeroMq.</div>
<div>
<br /></div>
<div>
Cheers.</div>
<div>
<br /></div>
<br />
<br />
<br />
<br />FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-53349166522336784762013-09-07T19:52:00.000-06:002013-09-07T19:52:00.487-06:00Youtube Downloader from the Linux Command LineGod Bless YouTube!<br />
<br />
Where else can you find entertainment, education and countless kitty/puppy videos? <br />
<br />
But what if you wish to preserve the video, downloading for archive purposes or access it from Internet-incapable devices?<br />
<br />
Start by installing youtube-dl:<br />
<code></code><br />
<pre><code># apt-get install youtube-dl
</code></pre>
<br />
Next, navigate to your desired video and copy the URL; e.g.<br />
<br />
<a href="http://www.youtube.com/watch?v=Wtfo43yV8rA">http://www.youtube.com/watch?v=Wtfo43yV8rA</a><br />
<br />
Lastly, execute youtube-dl with specified URL:<br />
<br />
<code></code><br />
<pre><code>$ youtube-dl http://www.youtube.com/watch?v=Wtfo43yV8rA
</code></pre>
<br />
The result will be a Macromedia Flash Video file. Convert to your preferred file format using Ffmeg and Bob's Your Uncle.<br />
<br />FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-51710626495410780862013-08-31T20:24:00.000-06:002013-08-31T20:24:00.630-06:00Android Rtsp Usage<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3g3aCvJGQ5qUyDr7GPfJExQPZ5ySsW-oQK3eUprEtutuzdtejaSeq3jRU0gJUAZpMsAetp7SXirYy2_7He0NrZXe2hRfnCnXCRN6VTpMMQO0jF9vJAz5HHa-Dj9nQT6NRkBalSrLsiUw/s1600/foo.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><br /></a>Loved my Samsung Galaxy but recently replaced it. Result is that I have a relatively decent smart phone with little, to no, purpose in life. Repurposing as a RTSP server device seemed like a reasonable task.<br />
<br />
Reviewed a series of video server apps in the Google Play Store, but only one that worked well for me with Linux RTSP clients was:<br />
<a href="https://play.google.com/store/apps/details?id=com.pas.webcam">https://play.google.com/store/apps/details?id=com.pas.webcam</a><br />
<br />
After installing the app and short configuration, you start the server by clicking the 'Start server' button in the video preference activity.<br />
<br />
Once the phone streaming is running, it displays a live view of the scene and the connection URL.<br />
<br />
Open it with VLC and you're cookin' with bacon:<br />
<br />
<code></code><br />
<pre><code>$ cvlc http://192.168.0.157:8080/video
</code></pre>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIUcBX_hazhWwCHpbft2mZaUV_mxm6-r9rtTG8D50mh-IoSO_26E1Gbyr8eT1LQuBfuxNCGqH6uQ3WUiNqjRa62I6JdmmIHAh0GCQdn5UknklKBD1M5hsrQ5B9lGoFwQwlhDzXxd1j9yo/s1600/foo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIUcBX_hazhWwCHpbft2mZaUV_mxm6-r9rtTG8D50mh-IoSO_26E1Gbyr8eT1LQuBfuxNCGqH6uQ3WUiNqjRa62I6JdmmIHAh0GCQdn5UknklKBD1M5hsrQ5B9lGoFwQwlhDzXxd1j9yo/s640/foo.jpg" width="640" /></a></div>
<br />
<br />
<br />
VoilĂ .FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0tag:blogger.com,1999:blog-8358044609201617862.post-64580119115732916702013-08-24T19:37:00.000-06:002013-08-24T19:37:00.187-06:00Soupin' Up Your Linux Harddrive PerformanceI came across a little utility that I was until now unaware of. I discovered it when I was doing a search for increasing hard drive performance on our Linux workstations, the utility 'hdparm'.<br />
<br />
The remainder of this posting should be performed in single-user mode to avoid interrupting remote users and get proper performance measurements for your system.<br />
<br />
First, let's baseline our system hard drive performance, do so performing the following command as root.<br />
<pre><code>
# /sbin/hdparm -Tt /dev/hda
</code></pre>
<br />
The first parameter '-T' measures the performance of the cache system, how the memory, CPU and buffer cache perform together.<br />
<br />
The second parameter '-t' measures the performance of the disk, reading data not in cache. According to my drives specs which advertises XXX MB/sec this is pathetic in comparison.<br />
<pre><code>
# /sbin/hdparm /dev/hda
</code></pre>
<br />
It shouldn't surprise you to see a good number of the drive features are turned off. These default settings are nice, safe but by no means optimal. These settings are pretty much guaranteed to work for near any system you throw at it, from a x386 to bleeding edge hardware.<br />
<br />
The first option, 'multicount' is short for multiple sector count. This controls how many sectors are fetched from the disk for a single I/O interrupt. The man page suggests that enabling this feature may reduce disk overhead by 30-50% and provide 5-50% data throughput improvements.<br />
The second option, 'I/O support' controls how data passes from the PCI bus to the controller. Near all modern controller chipsets support mode 3, 32-bit mode w/sync. Turning this on will likely near double your throughput.<br />
The third option, 'unmaskirq' allows Linut to unmask other interrups, allowint it to attend to other interrupt driven tasks whil waiting for the disk to return the requested data. While not all hardware configurations will be able to handle this, if your hardware supports it you should note better response time.<br />
The fourth option, 'use_dma' should be used with a bit more caution, we'll be ignoring this feature as it's documented as risky.<br />
<br />
So, let's get our hands dirty.<br />
Let's first set 32-bit w/sync on and multicount on.<br />
<br />
<pre><code>
# /sbin/hdparm -c3 -m16 /dev/hda
# /sbin/hdparm -Tt /dev/hda</code></pre>
<br />
<br />
'K, let's take another step.<br />
<pre><code>
# /sbin/hdparm -X66 -d1 -u1 -m16 -c3 /dev/hda
# /sbin/hdparm -Tt /dev/hda</code></pre>
<br />
<br />
It's worth noting that these settings don't persist, rebooting your box will default back to your original settings. This allows you to play around with it 'til you find a suite of settings you're happy with. When you're happy, edit your /etc/rc.d/* scripts, adding the assignments after the fsck check.<br />
<br />
<br />
<br />
<br />FatSlowKidhttp://www.blogger.com/profile/17639329641892507863noreply@blogger.com0