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

<channel>
	<title>AlferSoft Blog &#187; video</title>
	<atom:link href="http://www.alfersoft.com.ar/blog/tag/video/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.alfersoft.com.ar/blog</link>
	<description>Explaining this blog in a few words since 1999</description>
	<lastBuildDate>Wed, 01 Feb 2012 22:36:48 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Revenge of the Tiny Pong VGA, now controlled with a single button</title>
		<link>http://www.alfersoft.com.ar/blog/2012/01/22/revenge-of-the-tiny-pong-vga-now-controlled-with-a-single-button/</link>
		<comments>http://www.alfersoft.com.ar/blog/2012/01/22/revenge-of-the-tiny-pong-vga-now-controlled-with-a-single-button/#comments</comments>
		<pubDate>Sun, 22 Jan 2012 04:09:16 +0000</pubDate>
		<dc:creator>fvicente</dc:creator>
				<category><![CDATA[Electronic Projects]]></category>
		<category><![CDATA[assembler]]></category>
		<category><![CDATA[attiny]]></category>
		<category><![CDATA[attiny45]]></category>
		<category><![CDATA[avr]]></category>
		<category><![CDATA[pong]]></category>
		<category><![CDATA[tiny]]></category>
		<category><![CDATA[VGA]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://www.alfersoft.com.ar/blog/?p=345</guid>
		<description><![CDATA[As it was suggested by Hackaday&#8217;s guys, I&#8217;ve added a simple push button in the only available pin of my ATtiny45 in order to control the Tiny Pong VGA. The switch toggles the paddle direction up and down, every time you release it. I&#8217;ve made some little changes in the code, so check it out, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.alfersoft.com.ar/blog/wp-content/uploads/2012/01/push_button_dn.png"><img src="http://www.alfersoft.com.ar/blog/wp-content/uploads/2012/01/push_button_dn-150x150.png" alt="Tiny Pong VGA push button" title="Tiny Pong VGA push button" width="150" height="150" class="alignleft size-thumbnail wp-image-363" /></a>As it was suggested by <a href="http://hackaday.com/2011/10/07/8-pin-micro-plays-pong-on-you-widescreen/" title="Hackaday Tiny Pong VGA" target="_blank">Hackaday&#8217;s guys</a>, I&#8217;ve added a simple push button in the only available pin of my ATtiny45 in order to control the Tiny Pong VGA. The switch toggles the paddle direction up and down, every time you release it.<br/><br />
I&#8217;ve made some little changes in the code, so check it out, you might find something interesting or useful. As always, source code, schematics, etc. freely available for download.<br/><br />
<span id="more-345"></span><br />
<strong>Hardware</strong><br/><br />
Compared to <a href="http://www.alfersoft.com.ar/blog/2011/09/19/tiny-pong-more-fun-with-attiny45-and-vga/" title="Tiny Pong: More fun with ATtiny45 and VGA" target="_blank">Tiny Pong 1.0</a>, I just added a push button on PB5 with a 10K ohms resistor as pull-down.<br />
Here is a picture of the circuit on the breadboard.<br />
<div id="attachment_364" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.alfersoft.com.ar/blog/wp-content/uploads/2012/01/IMG_2702.jpg"><img src="http://www.alfersoft.com.ar/blog/wp-content/uploads/2012/01/IMG_2702-300x200.jpg" alt="Tiny Pong VGA on the protoboard" title="Tiny Pong VGA on the protoboard" width="300" height="200" class="size-medium wp-image-364" /></a><p class="wp-caption-text">Tiny Pong VGA on the protoboard</p></div><br />
And a prototype I made with <a href="http://fritzing.org/" title="Fritzing" target="_blank">Fritzing</a><br/><br />
<div id="attachment_365" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.alfersoft.com.ar/blog/wp-content/uploads/2012/01/Tiny-Pong-VGA-Fritzing.png"><img src="http://www.alfersoft.com.ar/blog/wp-content/uploads/2012/01/Tiny-Pong-VGA-Fritzing-300x121.png" alt="Tiny Pong VGA - Fritzing" title="Tiny Pong VGA - Fritzing" width="300" height="121" class="size-medium wp-image-365" /></a><p class="wp-caption-text">Tiny Pong VGA - Fritzing</p></div><br />
<div id="attachment_369" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.alfersoft.com.ar/blog/wp-content/uploads/2012/01/vga_pinout.jpg"><img src="http://www.alfersoft.com.ar/blog/wp-content/uploads/2012/01/vga_pinout-300x300.jpg" alt="VGA pinout" title="VGA pinout" width="300" height="300" class="size-medium wp-image-369" /></a><p class="wp-caption-text">VGA pinout</p></div><br />
<strong>ATtiny firmware</strong><br/><br />
To use PB5 as an I/O port we need to reprogram the ATtiny fuses with some specific flags. Once you do this, you won&#8217;t be able to reprogram it anymore using a regular ISP programmer. If you need to flash another firmware, you will need to reset the fuses using a High Voltage programmer; <a href="http://www.rickety.us/2010/03/arduino-avr-high-voltage-serial-programmer/" title="AVR High Voltage programmer" target="_blank">this one</a> worked fine for me.<br />
AVR GNU toolchain is used for this project, so the code is written in GNU assembler.<br />
In order to build the firmware, I use the following script:</p>
<pre>
#!/bin/sh
avr-gcc -mmcu=attiny45 -mmcu=attiny45 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT pong.o -MF pong.o.d  -x assembler-with-cpp -Wa,-gdwarf2 -c pong.S tables.S
avr-gcc -mmcu=attiny45 -Wl,-Map=pong.map pong.o tables.o -o pong.elf
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature pong.elf pong.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex pong.elf pong.eep || exit 0
avr-size -C --mcu=attiny45 pong.elf
rm *.o
rm *.o.d
rm pong.eep
rm pong.elf
rm pong.map
</pre>
<p>And to upload it to the chip (note that I&#8217;m using the Arduino with mega-isp) I use the following script</p>
<pre>
#!/bin/sh
[ -e "/dev/tty.usbserial-A8008VmU" ] &#038;&#038; PORT=/dev/tty.usbserial-A8008VmU || PORT=/dev/ttyUSB0
avrdude -F -P $PORT -p attiny45 -c avrisp -b 19200 -U flash:w:pong.hex
# fuses
# WARNING: fuses with PB5 as I/O port
#avrdude -F -P $PORT -p attiny45 -c avrisp -b 19200 -U flash:w:pong.hex -Ulfuse:w:0xce:m -Uhfuse:w:0x5f:m -Uefuse:w:0xff:m
</pre>
<p>Uncomment the last line to program the fuses.<br/><br />
<strong>Code</strong><br/><br />
The source code is almost the same as the first version, but I fixed a few bugs. First, the Bresenham&#8217;s algorithm was wrongly implemented, and since I needed it only to calculate the next position of the ball when the angle is 22.5 or 67.5, I realized that was easier to simply increment the X (or Y) coordinate when the ball is at an even position.<br />
Regarding the button reading, it is done during the vertical blanking zone, 60 times per second which gives a pretty good responsiveness &#8211; see the <code>chkinput</code> label in the code for more details.<br />
<br/><br />
<iframe width="560" height="315" src="http://www.youtube.com/embed/VMZvNSRKmWE" frameborder="0" allowfullscreen></iframe><br />
<br/><br />
Download the <a href='http://www.alfersoft.com.ar/blog/wp-content/uploads/2012/01/tinypong_2.0.zip'>Tiny Pong 2.0</a> source code<br />
Enjoy!<br />
<br/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.alfersoft.com.ar/blog/2012/01/22/revenge-of-the-tiny-pong-vga-now-controlled-with-a-single-button/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tiny Pong: More fun with ATtiny45 and VGA</title>
		<link>http://www.alfersoft.com.ar/blog/2011/09/19/tiny-pong-more-fun-with-attiny45-and-vga/</link>
		<comments>http://www.alfersoft.com.ar/blog/2011/09/19/tiny-pong-more-fun-with-attiny45-and-vga/#comments</comments>
		<pubDate>Tue, 20 Sep 2011 02:54:13 +0000</pubDate>
		<dc:creator>fvicente</dc:creator>
				<category><![CDATA[Electronic Projects]]></category>
		<category><![CDATA[assembler]]></category>
		<category><![CDATA[atmel]]></category>
		<category><![CDATA[attiny]]></category>
		<category><![CDATA[attiny45]]></category>
		<category><![CDATA[avr]]></category>
		<category><![CDATA[fun]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[pong]]></category>
		<category><![CDATA[VGA]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://www.alfersoft.com.ar/blog/?p=284</guid>
		<description><![CDATA[I&#8217;m still waiting for my cheap Bluetooth module from China which will serve as an input interface for my scoreboard project. In the meantime, I&#8217;ll show you how to convert your ATtiny microcontroller into a Pong game (with no input so far). So, I&#8217;ve used the scoreboard source as a base and changed a little [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m still waiting for my cheap <a href="http://www.dealextreme.com/p/wireless-bluetooth-rs232-ttl-transceiver-module-80711" title="Bluetooth Module">Bluetooth module from China</a> which will serve as an input interface for my <a href="http://www.alfersoft.com.ar/blog/2011/08/30/scoreboard-part-1-vga-signal-from-an-attiny45/" title="Scoreboard (Part 1: VGA signal from an ATtiny45)">scoreboard project</a>. In the meantime, I&#8217;ll show you how to convert your ATtiny microcontroller into a Pong game (with no input so far).</p>
<p><a href="http://www.alfersoft.com.ar/blog/wp-content/uploads/2011/09/IMG_2019.jpg"><img src="http://www.alfersoft.com.ar/blog/wp-content/uploads/2011/09/IMG_2019-300x200.jpg" alt="" title="Tiny Pong" width="300" height="200" class="alignnone size-medium wp-image-285" /></a><br />
<span id="more-284"></span><br />
<a href="http://www.alfersoft.com.ar/blog/wp-content/uploads/2011/09/IMG_2018.jpg"><img src="http://www.alfersoft.com.ar/blog/wp-content/uploads/2011/09/IMG_2018-300x200.jpg" alt="" title="Tiny Pong in the  protoboard" width="300" height="200" class="alignnone size-medium wp-image-288" /></a><br />
So, I&#8217;ve used the scoreboard source as a base and changed a little bit the pinout.</p>
<pre>

                       ATtiny45
                  +-----------------+
                  |                 |
           IN ----| 1 (PB5) (VCC) 8 |---- +5V
    22pf          |                 |
  +--||----+------| 2 (PB3) (PB2) 7 |---- HSYNC
  |       [ ] XTAL|                 |
  +--||----+------| 3 (PB4) (PB1) 6 |---- VSYNC
  | 22pf          |                 |
  +---------------| 4 (GND) (PB0) 5 |---- RGB
  |               |                 |
 GND              +-----------------+
</pre>
<p>Now the RGB is connected to PB0, and there is a good reason for this. I&#8217;m still using the same technique of storing what I want to render in registers but instead of 4, this time I&#8217;m using 15 so I can achieve an horizontal resolution of 120 by 96 to make the pixels somehow squared. Now, to be able to walk trough the 120 bits and turn the RGB pin on/off accordingly (and evenly) I needed to crop the code, removing the loops (so you will see a lot of similar code in the part that renders the line) and the conditional skip now replaced by an &#8220;add with carry&#8221; after the shift into a temporary register that will be used with &#8220;out&#8221; which is less expensive than &#8220;sbi&#8221; and &#8220;cbi&#8221;.</p>
<p>So, in terms of code optimization, this:</p>
<pre>
	; r1 bit 0
	cbr r16, 1
	lsl r1
	adc r16, r22
	out PORT, r16
	... repeated 120 time (8 times per bit and 15 times per register)
</pre>
<p>Is better than:</p>
<pre>
	ldi r16, 0x08
line44:
	rol r8
	brcc rgboff44
	nop
	; RGB on
	sbi PORT, RGB		; sbi = 2 clocks
	rjmp cont44
rgboff44:
	; RGB off
	cbi PORT, RGB		; cbi = 2 clocks
	nop
	nop
cont44:
	dec r16
	nop
	nop
	nop
	nop
	nop
	brne line44
</pre>
<p>There are also other parts of the code that might be of interest. For example, I&#8217;ve use <a href="http://en.wikipedia.org/wiki/Linear_feedback_shift_register" title="Linear feedback shift register">LFSR</a> to add some pseudo-random variables to the ball direction and the paddle &#8220;computer&#8221; movements. Also, I&#8217;ve used the <a href="http://en.wikipedia.org/wiki/Bresenham's_line_algorithm" title="Bresenham's line algorithm">Bresenham&#8217;s line algorithm</a> to determine the ball position.<br />
The missing part, is still the input. I&#8217;m not sure how this will work with only one pin available, but I guess I&#8217;ll work out something with the Bluetooth module and one of the synch signals (if even possible).<br />
I&#8217;ve tried to add some intro screen or &#8220;splash&#8221;, but the program memory is so small that I&#8217;ve quickly exceeded the 4096 available bytes.</p>
<p><iframe width="560" height="315" src="http://www.youtube.com/embed/8KlHqu1tnMg" frameborder="0" allowfullscreen></iframe></p>
<p>Download the <a href='http://www.alfersoft.com.ar/blog/wp-content/uploads/2011/09/tinypong_1.0.zip'>Tiny Pong 1.0 source code</a> and enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.alfersoft.com.ar/blog/2011/09/19/tiny-pong-more-fun-with-attiny45-and-vga/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Extracting FLV meta tags with Python</title>
		<link>http://www.alfersoft.com.ar/blog/2010/02/05/extracting-flv-meta-tags-with-python/</link>
		<comments>http://www.alfersoft.com.ar/blog/2010/02/05/extracting-flv-meta-tags-with-python/#comments</comments>
		<pubDate>Sat, 06 Feb 2010 00:07:36 +0000</pubDate>
		<dc:creator>fvicente</dc:creator>
				<category><![CDATA[Programming FAQ]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[flv]]></category>
		<category><![CDATA[metadata]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://www.alfersoft.com.ar/blog/?p=112</guid>
		<description><![CDATA[I&#8217;ve stolen this code from http://code.activestate.com/recipes/457406/ which in turn was stolen / ported from http://inlet-media.de/flvtool2 , made some small fixes in bugs related to the date conversion function, object and array unmarshaling, file name hardcoded, etc&#8230; If you want to learn more about the FLV format and metatags read Acrobat&#8217;s Video File Format Specification Version [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve stolen this code from <a href="http://code.activestate.com/recipes/457406/" target="_blank">http://code.activestate.com/recipes/457406/</a> which in turn was stolen / ported from <a rel="nofollow" href="http://inlet-media.de/flvtool2">http://inlet-media.de/flvtool2 </a>, made some small fixes in bugs related to the date conversion function, object and array unmarshaling, file name hardcoded, etc&#8230; If you want to learn more about the FLV format and metatags read Acrobat&#8217;s <a title="Video File Format Specification Version 10" href="http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf" target="_blank">Video File Format Specification Version 10</a><br />
<span id="more-112"></span></p>
<pre class="brush: python; title: ; notranslate">
from struct import unpack
from datetime import datetime

class FLVReader(dict):
    &quot;&quot;&quot;
    Reads metadata from FLV files
    &quot;&quot;&quot;

    # Tag types
    AUDIO = 8
    VIDEO = 9
    META = 18
    UNDEFINED = 0

    def __init__(self, filename):
        &quot;&quot;&quot;
        Pass the filename of an flv file and it will return a dictionary of meta
        data.
        &quot;&quot;&quot;
        # Lock on to the file
        self.file = open(filename, 'rb')
        self.signature = self.file.read(3)
        assert self.signature == 'FLV', 'Not an flv file'
        self.version = self.readbyte()
        self.typeFlags = self.readbyte()
        self.dataOffset = self.readint()
        extraDataLen = self.dataOffset - self.file.tell()
        self.extraData = self.file.read(extraDataLen)
        self.readtag()

    def readtag(self):
        unknown = self.readint()
        tagType = self.readbyte()
        dataSize = self.read24bit()
        timeStamp = self.read24bit()
        unknown = self.readint()
        if tagType == self.AUDIO:
            print &quot;Can't handle audio tags yet&quot;
        elif tagType == self.VIDEO:
            print &quot;Can't handle video tags yet&quot;
        elif tagType == self.META:
            endpos = self.file.tell() + dataSize
            self.event = self.readAMFData()
            metaData = self.readAMFData()
            # We got the meta data.
            # Our job is done.
            # We are complete
            self.update(metaData)
        elif tagType == self.UNDEFINED:
            print &quot;Can't handle undefined tags yet&quot;

    def readint(self):
      data = self.file.read(4)
      return unpack('&gt;I', data)[0]

    def readshort(self):
      data = self.file.read(2)
      return unpack('&gt;H', data)[0]

    def readbyte(self):
      data = self.file.read(1)
      return unpack('B', data)[0]

    def read24bit(self):
      b1, b2, b3 = unpack('3B', self.file.read(3))
      return (b1 &lt;&lt; 16) + (b2 &lt;&lt; 8 ) + b3

    def readAMFData(self, dataType=None):
        if dataType is None:
            dataType = self.readbyte()
        funcs = {
            0: self.readAMFDouble,
            1: self.readAMFBoolean,
            2: self.readAMFString,
            3: self.readAMFObject,
            8: self.readAMFMixedArray,
           10: self.readAMFArray,
           11: self.readAMFDate
        }
        func = funcs[dataType]
        if callable(func):
            return func()

    def readAMFDouble(self):
        return unpack('&gt;d', self.file.read(8))[0]

    def readAMFBoolean(self):
        return self.readbyte() == 1

    def readAMFString(self):
        size = self.readshort()
        return self.file.read(size)

    def readAMFObject(self):
        result = {}
        data = True
        while data:
            size = self.readshort()
            key = self.file.read(size)
            dataType = self.readbyte()
            if not key and dataType == 9:
                break
            data = self.readAMFData(dataType)
            result[key] = data
        return result

    def readAMFMixedArray(self):
        size = self.readint()
        result = {}
        i = 0
        while i &lt; size:
            key = self.readAMFString()
            dataType = self.readbyte()
            if not key and dataType == 9:
                break
            result[key] = self.readAMFData(dataType)
            i += 1
        return result

    def readAMFArray(self):
        size = self.readint()
        result = []
        i = 0
        while i &lt; size:
            result.append(self.readAMFData())
            i += 1
        return result

    def readAMFDate(self):
        date = self.readAMFDouble()/1000
        localoffset = self.readshort()
        return datetime.fromtimestamp(date)

if __name__ == '__main__':
    import sys
    from pprint import pprint
    if len(sys.argv) == 1:
        print 'Usage: %s filename [filename]...' % sys.argv[0]
        print 'Where filename is a .flv file'
        print 'eg. %s myfile.flv' % sys.argv[0]
    for fn in sys.argv[1:]:
        x = FLVReader(fn)
        pprint(x)
</pre>
<p>Download this code snippet from <a title="flv.py" href="http://www.alfersoft.com.ar/files/flv.py" target="_blank">here</a></p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 55px; width: 1px; height: 1px;">from&amp;nbsp;struct&amp;nbsp;import&amp;nbsp;unpack<br />
from&amp;nbsp;datetime&amp;nbsp;import&amp;nbsp;datetime</p>
<p>class&amp;nbsp;FLVReader(dict):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&#8221;"&#8221;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Reads&amp;nbsp;metadata&amp;nbsp;from&amp;nbsp;FLV&amp;nbsp;files<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&#8221;"&#8221;</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Tag&amp;nbsp;types<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AUDIO&amp;nbsp;=&amp;nbsp;8<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VIDEO&amp;nbsp;=&amp;nbsp;9<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;META&amp;nbsp;=&amp;nbsp;18<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UNDEFINED&amp;nbsp;=&amp;nbsp;0</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;__init__(self,&amp;nbsp;filename):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&#8221;"&#8221;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Pass&amp;nbsp;the&amp;nbsp;filename&amp;nbsp;of&amp;nbsp;an&amp;nbsp;flv&amp;nbsp;file&amp;nbsp;and&amp;nbsp;it&amp;nbsp;will&amp;nbsp;return&amp;nbsp;a&amp;nbsp;dictionary&amp;nbsp;of&amp;nbsp;meta<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data.<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&#8221;"&#8221;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Lock&amp;nbsp;on&amp;nbsp;to&amp;nbsp;the&amp;nbsp;file<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.file&amp;nbsp;=&amp;nbsp;open(filename,&amp;nbsp;&#8217;rb&#8217;)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.signature&amp;nbsp;=&amp;nbsp;self.file.read(3)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assert&amp;nbsp;self.signature&amp;nbsp;==&amp;nbsp;&#8217;FLV&#8217;,&amp;nbsp;&#8217;Not&amp;nbsp;an&amp;nbsp;flv&amp;nbsp;file&#8217;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.version&amp;nbsp;=&amp;nbsp;self.readbyte()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.typeFlags&amp;nbsp;=&amp;nbsp;self.readbyte()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.dataOffset&amp;nbsp;=&amp;nbsp;self.readint()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;extraDataLen&amp;nbsp;=&amp;nbsp;self.dataOffset&amp;nbsp;-&amp;nbsp;self.file.tell()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.extraData&amp;nbsp;=&amp;nbsp;self.file.read(extraDataLen)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.readtag()</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readtag(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;unknown&amp;nbsp;=&amp;nbsp;self.readint()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tagType&amp;nbsp;=&amp;nbsp;self.readbyte()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dataSize&amp;nbsp;=&amp;nbsp;self.read24bit()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;timeStamp&amp;nbsp;=&amp;nbsp;self.read24bit()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;unknown&amp;nbsp;=&amp;nbsp;self.readint()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;tagType&amp;nbsp;==&amp;nbsp;self.AUDIO:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&#8221;Can&#8217;t&amp;nbsp;handle&amp;nbsp;audio&amp;nbsp;tags&amp;nbsp;yet&#8221;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;tagType&amp;nbsp;==&amp;nbsp;self.VIDEO:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&#8221;Can&#8217;t&amp;nbsp;handle&amp;nbsp;video&amp;nbsp;tags&amp;nbsp;yet&#8221;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;tagType&amp;nbsp;==&amp;nbsp;self.META:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;endpos&amp;nbsp;=&amp;nbsp;self.file.tell()&amp;nbsp;+&amp;nbsp;dataSize<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.event&amp;nbsp;=&amp;nbsp;self.readAMFData()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metaData&amp;nbsp;=&amp;nbsp;self.readAMFData()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;We&amp;nbsp;got&amp;nbsp;the&amp;nbsp;meta&amp;nbsp;data.<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;Our&amp;nbsp;job&amp;nbsp;is&amp;nbsp;done.<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;#&amp;nbsp;We&amp;nbsp;are&amp;nbsp;complete<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.update(metaData)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;elif&amp;nbsp;tagType&amp;nbsp;==&amp;nbsp;self.UNDEFINED:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&#8221;Can&#8217;t&amp;nbsp;handle&amp;nbsp;undefined&amp;nbsp;tags&amp;nbsp;yet&#8221;</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readint(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;self.file.read(4)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;unpack(&#8216;&gt;I&#8217;,&amp;nbsp;data)[0]</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readshort(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;self.file.read(2)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;unpack(&#8216;&gt;H&#8217;,&amp;nbsp;data)[0]</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readbyte(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;self.file.read(1)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;unpack(&#8216;B&#8217;,&amp;nbsp;data)[0]</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;read24bit(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;b1,&amp;nbsp;b2,&amp;nbsp;b3&amp;nbsp;=&amp;nbsp;unpack(&#8217;3B&#8217;,&amp;nbsp;self.file.read(3))<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;(b1&amp;nbsp;&lt;&lt;&amp;nbsp;16)&amp;nbsp;+&amp;nbsp;(b2&amp;nbsp;&lt;&lt;&amp;nbsp;8)&amp;nbsp;+&amp;nbsp;b3</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readAMFData(self,&amp;nbsp;dataType=None):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;dataType&amp;nbsp;is&amp;nbsp;None:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dataType&amp;nbsp;=&amp;nbsp;self.readbyte()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;funcs&amp;nbsp;=&amp;nbsp;{<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0:&amp;nbsp;self.readAMFDouble,<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1:&amp;nbsp;self.readAMFBoolean,<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2:&amp;nbsp;self.readAMFString,<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3:&amp;nbsp;self.readAMFObject,<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8:&amp;nbsp;self.readAMFMixedArray,<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;10:&amp;nbsp;self.readAMFArray,<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;11:&amp;nbsp;self.readAMFDate<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func&amp;nbsp;=&amp;nbsp;funcs[dataType]<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;callable(func):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;func()</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readAMFDouble(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;unpack(&#8216;&gt;d&#8217;,&amp;nbsp;self.file.read(8))[0]</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readAMFBoolean(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.readbyte()&amp;nbsp;==&amp;nbsp;1</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readAMFString(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;size&amp;nbsp;=&amp;nbsp;self.readshort()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;self.file.read(size)</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readAMFObject(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;{}<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;True<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;data:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;size&amp;nbsp;=&amp;nbsp;self.readshort()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key&amp;nbsp;=&amp;nbsp;self.file.read(size)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dataType&amp;nbsp;=&amp;nbsp;self.readbyte()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;key&amp;nbsp;and&amp;nbsp;dataType&amp;nbsp;==&amp;nbsp;9:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;data&amp;nbsp;=&amp;nbsp;self.readAMFData(dataType)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result[key]&amp;nbsp;=&amp;nbsp;data<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readAMFMixedArray(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;size&amp;nbsp;=&amp;nbsp;self.readint()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;{}<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;i&amp;nbsp;&lt;&amp;nbsp;size:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;key&amp;nbsp;=&amp;nbsp;self.readAMFString()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;dataType&amp;nbsp;=&amp;nbsp;self.readbyte()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;key&amp;nbsp;and&amp;nbsp;dataType&amp;nbsp;==&amp;nbsp;9:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;break<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result[key]&amp;nbsp;=&amp;nbsp;self.readAMFData(dataType)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i&amp;nbsp;+=&amp;nbsp;1<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readAMFArray(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;size&amp;nbsp;=&amp;nbsp;self.readint()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result&amp;nbsp;=&amp;nbsp;[]<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;i&amp;nbsp;&lt;&amp;nbsp;size:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result.append(self.readAMFData())<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i&amp;nbsp;+=&amp;nbsp;1<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;result</p>
<p>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def&amp;nbsp;readAMFDate(self):<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;date&amp;nbsp;=&amp;nbsp;self.readAMFDouble()/1000<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;localoffset&amp;nbsp;=&amp;nbsp;self.readshort()<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;datetime.fromtimestamp(date)</p>
<p>if&amp;nbsp;__name__&amp;nbsp;==&amp;nbsp;&#8217;__main__&#8217;:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;import&amp;nbsp;sys<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;from&amp;nbsp;pprint&amp;nbsp;import&amp;nbsp;pprint<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;len(sys.argv)&amp;nbsp;==&amp;nbsp;1:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&#8217;Usage:&amp;nbsp;%s&amp;nbsp;filename&amp;nbsp;[filename]&#8230;&#8217;&amp;nbsp;%&amp;nbsp;sys.argv[0]<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&#8217;Where&amp;nbsp;filename&amp;nbsp;is&amp;nbsp;a&amp;nbsp;.flv&amp;nbsp;file&#8217;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;print&amp;nbsp;&#8217;eg.&amp;nbsp;%s&amp;nbsp;myfile.flv&#8217;&amp;nbsp;%&amp;nbsp;sys.argv[0]<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;fn&amp;nbsp;in&amp;nbsp;sys.argv[1:]:<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x&amp;nbsp;=&amp;nbsp;FLVReader(fn)<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pprint(x)</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.alfersoft.com.ar/blog/2010/02/05/extracting-flv-meta-tags-with-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

