flv 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d87000942102a6037bcfed2bb5b54fb960726886
4
- data.tar.gz: dd3ff0b1bfda221527d70aa69c8728eeb4656f60
3
+ metadata.gz: f8a4f49876669363f9f2eb9b90cffb221efca11a
4
+ data.tar.gz: 72a72c4ad20f4ba477940c00d972426aff0528d2
5
5
  SHA512:
6
- metadata.gz: 830e93c9afb9d438396fad2dca39273f66608c96203c345f610454d8b12d066cd93cfdcde7a3c6ff9822ccfed2cb18e6f2e3f5a413e6a0b0bb6a73a043c69876
7
- data.tar.gz: fcb6abcce91188839c6d3835c096d8ea5f87b55e834b6cdbadb37adc2604f492c96d82496178365b1674c5643f967faf584f14a239331805e01e56a1976ccf98
6
+ metadata.gz: 01515ede28f3178c9898c63f254f99606f3bd382e89714e7eabcdfed1df47f17fad591764a690f4801a9644e93ae658688385b5c930091c47bce12d0cca84a75
7
+ data.tar.gz: 4415125baeb5ba78bafb233ff87f3947f40290be3f34f3ecb476873835d2e73e00585985516c33ce53520af895529544b3f5d67c22097ff50311f34c915dbc0f
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Charlie Somerville & Envato
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,53 @@
1
+ # FLV
2
+
3
+ A Ruby library for parsing FLV files and metadata sections.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem "flv"
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```shell
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```shell
22
+ $ gem install flv
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```ruby
28
+ flv = FLV.read("path/to/your/video.flv")
29
+ flv.audio? # => true
30
+ flv.video? # => true
31
+
32
+ data_tag = flv.tags.find { |tag| tag.is_a?(FLV::Tag::Data) }
33
+ data_tag.duration # => 60.0
34
+ data_tag.frame_rate # => 30.0
35
+ ```
36
+
37
+ The FLV gem also supports streaming parsing, so you can handle tags as they arrive from an I/O stream.
38
+
39
+ This is useful for pulling metadata out of FLV videos without having to download the whole lot:
40
+
41
+ ```ruby
42
+ flv = FLV.new(io)
43
+ data_tag = flv.each_tag.first
44
+ io.close
45
+ ```
46
+
47
+ ## Contributing
48
+
49
+ 1. Fork it
50
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
51
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
52
+ 4. Push to the branch (`git push origin my-new-feature`)
53
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "flv/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "flv"
8
+ spec.version = FLV::VERSION
9
+ spec.authors = ["Charlie Somerville"]
10
+ spec.email = ["charlie@charliesomerville.com"]
11
+ spec.description = %q{A library for handling FLV files}
12
+ spec.summary = %q{Ruby library for parsing and handling FLV files}
13
+ spec.homepage = "https://github.com/envato/flv"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec", "~> 2.13.0"
24
+ end
@@ -0,0 +1,54 @@
1
+ require "flv/version"
2
+ require "flv/stream_reader"
3
+ require "flv/format_error"
4
+ require "flv/tag"
5
+
6
+ class FLV
7
+ def self.read(path)
8
+ new(File.open(path, "rb"))
9
+ end
10
+
11
+ AUDIO_FLAG = 0x04
12
+ VIDEO_FLAG = 0x01
13
+
14
+ attr_reader :flags
15
+
16
+ def initialize(io)
17
+ @io = io
18
+ @reader = StreamReader.new(io)
19
+ read_header
20
+ read_useless_footer
21
+ end
22
+
23
+ def audio?
24
+ (flags & AUDIO_FLAG).nonzero?
25
+ end
26
+
27
+ def video?
28
+ (flags & VIDEO_FLAG).nonzero?
29
+ end
30
+
31
+ def tags
32
+ @tags ||= each_tag.to_a
33
+ end
34
+
35
+ def each_tag
36
+ return enum_for(:each_tag) unless block_given?
37
+
38
+ until @io.eof?
39
+ yield Tag.read(@io)
40
+ end
41
+ end
42
+
43
+ private
44
+ def read_header
45
+ raise FormatError, "bad header" unless @reader.read_bytes(3) == "FLV"
46
+ raise FormatError, "bad version" unless @reader.read_byte == 1
47
+ @flags = @reader.read_byte
48
+ raise FormatError, "bad header size" unless @reader.read_uint32_be == 9
49
+ end
50
+
51
+ def read_useless_footer
52
+ raise FormatError, "expected useless footer to be zero" unless @reader.read_uint32_be == 0
53
+ end
54
+ end
@@ -0,0 +1,4 @@
1
+ class FLV
2
+ class FormatError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,107 @@
1
+ # coding: BINARY
2
+ require "flv/stream_reader"
3
+ require "flv/format_error"
4
+
5
+ class FLV
6
+ class ScriptDataParser
7
+ def initialize(str)
8
+ @data_reader = StreamReader.for_string(str.dup.force_encoding("BINARY"))
9
+ end
10
+
11
+ def parse
12
+ Hash[until_terminator(TERMINATOR).map {
13
+ [expect_script_data_string, read_script_data_value]
14
+ }]
15
+ end
16
+
17
+ def parse_single_value
18
+ read_script_data_value
19
+ end
20
+
21
+ private
22
+ def read_script_data_value
23
+ case type = @data_reader.read_byte
24
+ when 0 then read_script_data_number
25
+ when 1 then read_script_data_boolean
26
+ when 2 then read_script_data_string
27
+ when 3 then read_script_data_object
28
+ when 4 then read_script_data_movie_clip
29
+ when 5 then read_script_data_null
30
+ when 6 then read_script_data_undefined
31
+ when 7 then read_script_data_reference
32
+ when 8 then read_script_data_array
33
+ when 10 then read_script_data_strict_array
34
+ when 11 then read_script_data_date
35
+ when 12 then read_script_data_long_string
36
+ else
37
+ raise FormatError, "unknown type #{type}"
38
+ end
39
+ end
40
+
41
+ def read_script_data_number
42
+ @data_reader.read_double_be
43
+ end
44
+
45
+ def read_script_data_string
46
+ length = @data_reader.read_uint16_be
47
+ @data_reader.read_bytes(length)
48
+ end
49
+
50
+ def read_script_data_boolean
51
+ !@data_reader.read_byte.zero?
52
+ end
53
+
54
+ TERMINATOR = "\x00\x00\x09".force_encoding("BINARY").freeze
55
+
56
+ def read_script_data_object
57
+ Hash[until_terminator(TERMINATOR).map {
58
+ [read_script_data_string, read_script_data_value]
59
+ }]
60
+ end
61
+
62
+ def read_script_data_array
63
+ # this value is ignored on purpose
64
+ approx_array_length = @data_reader.read_uint32_be
65
+
66
+ Hash[until_terminator(TERMINATOR).map {
67
+ read_script_data_variable
68
+ }]
69
+ end
70
+
71
+ def read_script_data_variable
72
+ [read_script_data_string, read_script_data_value]
73
+ end
74
+
75
+ def read_script_data_strict_array
76
+ count = @data_reader.read_uint32_be
77
+ count.times.map { read_script_data_value }
78
+ end
79
+
80
+ def read_script_data_date
81
+ time = @data_reader.read_double_be
82
+ utc_offset_minutes = @data_reader.read_sint16_be
83
+ Time.new(1970, 1, 1, 0, 0, 0, utc_offset_minutes * 60) + time
84
+ rescue ArgumentError
85
+ nil
86
+ end
87
+
88
+ def expect_script_data_string
89
+ read_script_data_value.tap do |value|
90
+ unless value.is_a?(String)
91
+ raise FormatError, "expected string, have #{value.inspect}"
92
+ end
93
+ end
94
+ end
95
+
96
+ def until_terminator(term)
97
+ return enum_for(:until_terminator, term) unless block_given?
98
+ sz = term.bytesize
99
+ loop do
100
+ bytes = @data_reader.read_bytes(sz)
101
+ return if bytes == term or bytes.nil?
102
+ @data_reader.seek(-sz)
103
+ yield
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,57 @@
1
+ # coding: BINARY
2
+
3
+ require "stringio"
4
+
5
+ class FLV
6
+ class StreamReader
7
+ def initialize(io)
8
+ @io = io
9
+ end
10
+
11
+ def self.for_string(str)
12
+ new(StringIO.new(str))
13
+ end
14
+
15
+ def eof?
16
+ @io.eof?
17
+ end
18
+
19
+ def seek(offset)
20
+ @io.seek(offset, IO::SEEK_CUR)
21
+ end
22
+
23
+ def read_bytes(n)
24
+ @io.read(n)
25
+ end
26
+
27
+ def read_byte
28
+ @io.readbyte
29
+ end
30
+
31
+ def read_uint32_be
32
+ read_bytes(4).unpack("L>").first
33
+ end
34
+
35
+ def read_uint24_be
36
+ "\x00#{read_bytes(3)}".unpack("L>").first
37
+ end
38
+
39
+ def read_uint16_be
40
+ read_bytes(2).unpack("S>").first
41
+ end
42
+
43
+ def read_sint16_be
44
+ read_bytes(2).unpack("s>").first
45
+ end
46
+
47
+ def read_uint32_weird_endian
48
+ lower = read_uint24_be
49
+ higher = read_byte
50
+ lower | (higher << 24)
51
+ end
52
+
53
+ def read_double_be
54
+ read_bytes(8).unpack("G").first
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,58 @@
1
+ require "flv/stream_reader"
2
+ require "flv/format_error"
3
+ require "flv/tag/data"
4
+ require "flv/tag/audio"
5
+ require "flv/tag/video"
6
+
7
+ class FLV
8
+ class Tag
9
+ METADATA_TYPE = 0x12
10
+ AUDIO_TYPE = 0x08
11
+ VIDEO_TYPE = 0x09
12
+
13
+ attr_reader :length, :timestamp, :raw_data, :footer
14
+
15
+ def self.read(io)
16
+ case io.readbyte
17
+ when METADATA_TYPE then Data.new(io)
18
+ when AUDIO_TYPE then Audio.new(io)
19
+ when VIDEO_TYPE then Video.new(io)
20
+ end
21
+ end
22
+
23
+ def initialize(io)
24
+ @reader = StreamReader.new(io)
25
+ read
26
+ end
27
+
28
+ def inspect
29
+ "#<#{self.class}>"
30
+ end
31
+
32
+ private
33
+ def decode_raw_data
34
+ # implemented in subclasses
35
+ end
36
+
37
+ def read
38
+ read_header
39
+ read_raw_data
40
+ read_footer
41
+ decode_raw_data
42
+ end
43
+
44
+ def read_header
45
+ @length = @reader.read_uint24_be
46
+ @timestamp = @reader.read_uint32_weird_endian
47
+ raise FormatError, "bad stream id" unless @reader.read_uint24_be == 0
48
+ end
49
+
50
+ def read_raw_data
51
+ @raw_data = @reader.read_bytes(length)
52
+ end
53
+
54
+ def read_footer
55
+ @footer = @reader.read_uint32_be
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,6 @@
1
+ class FLV
2
+ class Tag
3
+ class Audio < Tag
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,63 @@
1
+ require "flv/tag"
2
+ require "flv/stream_reader"
3
+ require "flv/format_error"
4
+ require "flv/script_data_parser"
5
+
6
+ class FLV
7
+ class Tag
8
+ class Data < Tag
9
+ def data
10
+ @data ||= ScriptDataParser.new(raw_data).parse
11
+ end
12
+
13
+ def inspect
14
+ "#<#{self.class} #{data.inspect}>"
15
+ end
16
+
17
+ def duration
18
+ meta_data["duration"]
19
+ end
20
+
21
+ def width
22
+ meta_data["width"]
23
+ end
24
+
25
+ def height
26
+ meta_data["height"]
27
+ end
28
+
29
+ def video_data_rate
30
+ meta_data["videodatarate"]
31
+ end
32
+
33
+ def frame_rate
34
+ meta_data["framerate"]
35
+ end
36
+
37
+ def video_codec_id
38
+ meta_data["videocodecid"]
39
+ end
40
+
41
+ def audio_data_rate
42
+ meta_data["audiodatarate"]
43
+ end
44
+
45
+ def audio_delay
46
+ meta_data["audiodelay"]
47
+ end
48
+
49
+ def audio_codec_id
50
+ meta_data["audiocodecid"]
51
+ end
52
+
53
+ def seek_to_end?
54
+ meta_data["canSeekToEnd"]
55
+ end
56
+
57
+ private
58
+ def meta_data
59
+ data["onMetaData"] || {}
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,6 @@
1
+ class FLV
2
+ class Tag
3
+ class Video < Tag
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ class FLV
2
+ VERSION = "0.1.0"
3
+ end
Binary file
@@ -0,0 +1,105 @@
1
+ require "flv/script_data_parser"
2
+
3
+ describe FLV::ScriptDataParser do
4
+ let(:parser) { FLV::ScriptDataParser.new(@str) }
5
+ let(:value) { parser.parse_single_value }
6
+
7
+ context "numbers" do
8
+ it "parses the number as a big endian double precision float" do
9
+ @str = "\x00@^\xDD/\x1A\x9F\xBEw"
10
+ value.should == 123.456
11
+ end
12
+ end
13
+
14
+ context "booleans" do
15
+ it "parses a 0 byte as false" do
16
+ @str = "\x01\x00"
17
+ value.should == false
18
+ end
19
+
20
+ it "parses a 1 byte as true" do
21
+ @str = "\x01\x01"
22
+ value.should == true
23
+ end
24
+ end
25
+
26
+ context "strings" do
27
+ it "parses empty strings" do
28
+ @str = "\x02\x00\x00"
29
+ value.should == ""
30
+ end
31
+
32
+ it "parses strings < 255 chars" do
33
+ @str = "\x02\x00\x0bhello world"
34
+ value.should == "hello world"
35
+ end
36
+
37
+ it "parses strings > 255 chars (where endianness matters)" do
38
+ @str = "\x02\x02\x00#{"x"*512}"
39
+ value.should == "x" * 512
40
+ end
41
+ end
42
+
43
+ context "objects" do
44
+ it "parses empty objects" do
45
+ @str = "\x03\x00\x00\x09"
46
+ value.should == {}
47
+ end
48
+
49
+ it "parses objects as pairs of a non-value strings and a value" do
50
+ @str = "\x03\x00\x04name\x02\x00\x05value\x00\x00\x09"
51
+ value.should == { "name" => "value" }
52
+ end
53
+ end
54
+
55
+ context "arrays" do
56
+ it "parses empty 'arrays' as empty hashes" do
57
+ @str = "\x08\x00\x00\x00\x00\x00\x00\x09"
58
+ value.should == {}
59
+ end
60
+
61
+ it "ignores the length hint" do
62
+ @str = "\x08\x11\x22\x33\x44\x00\x00\x09"
63
+ value.should == {}
64
+ end
65
+
66
+ it "parses arrays as pairs of a non-value string and a value" do
67
+ @str = "\x08\x00\x00\x00\x00\x00\x04name\x02\x00\x05value\x00\x00\x09"
68
+ value.should == { "name" => "value" }
69
+ end
70
+ end
71
+
72
+ context "strict arrays" do
73
+ it "parses empty strict arrays" do
74
+ @str = "\x0a\x00\x00\x00\x00"
75
+ value.should == []
76
+ end
77
+
78
+ it "parses strict arrays with values" do
79
+ @str = "\x0a\x00\x00\x00\x03\x02\x00\x03foo\x02\x00\x03bar\x02\x00\x03baz"
80
+ value.should == ["foo", "bar", "baz"]
81
+ end
82
+ end
83
+
84
+ context "dates" do
85
+ it "can parse an empty date" do
86
+ @str = "\x0b\0\0\0\0\0\0\0\0\0\0"
87
+ value.should == Time.utc(1970, 1, 1, 0, 0, 0)
88
+ end
89
+
90
+ it "can parse an empty date in UTC+10" do
91
+ @str = "\x0b\0\0\0\0\0\0\0\0\x02X"
92
+ value.should == Time.new(1970, 1, 1, 0, 0, 0, 10 * 3600)
93
+ end
94
+
95
+ it "can parse today in UTC+10" do
96
+ @str = "\x0bA\xD4bB\xDE\x80\0\0\x02X"
97
+ value.should == Time.new(2013, 5, 7, 14, 11, 6, 10 * 3600)
98
+ end
99
+
100
+ it "can parse today in UTC-10" do
101
+ @str = "\x0bA\xD4bB\xDE\x80\0\0\xfd\xa8"
102
+ value.should == Time.new(2013, 5, 7, 14, 11, 6, -10 * 3600)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,65 @@
1
+ # coding: BINARY
2
+
3
+ require "flv/stream_reader"
4
+ require "stringio"
5
+
6
+ describe FLV::StreamReader do
7
+ let(:string) { "\xde\xad\xbe\xef\x00\xfa\xca\xde" }
8
+ let(:io) { StringIO.new(string) }
9
+ subject { FLV::StreamReader.new(io) }
10
+
11
+ describe "#eof?" do
12
+ let(:val) { mock }
13
+
14
+ it "should delegate to the io" do
15
+ io.should_receive(:eof?).and_return(val)
16
+ subject.eof?.should == val
17
+ end
18
+ end
19
+
20
+ describe "#read_bytes" do
21
+ it "reads the specified number of bytes" do
22
+ subject.read_bytes(8).should == string
23
+ end
24
+
25
+ it "saves its spot in the stream" do
26
+ subject.read_bytes(4).should == "\xde\xad\xbe\xef"
27
+ subject.read_bytes(4).should == "\x00\xfa\xca\xde"
28
+ end
29
+ end
30
+
31
+ describe "#read_byte" do
32
+ it "returns fixnums" do
33
+ subject.read_byte.should == 0xde
34
+ subject.read_byte.should == 0xad
35
+ end
36
+ end
37
+
38
+ describe "#read_uint32_be" do
39
+ it "reads big endian unsigned 32 bit integers" do
40
+ subject.read_uint32_be.should == 0xdeadbeef
41
+ subject.read_uint32_be.should == 0x00facade
42
+ end
43
+ end
44
+
45
+ describe "#read_uint24_be" do
46
+ it "reads big endian unsigned 24 bit integers" do
47
+ subject.read_uint24_be.should == 0xdeadbe
48
+ subject.read_uint24_be.should == 0xef00fa
49
+ end
50
+ end
51
+
52
+ describe "#read_uint16_be" do
53
+ it "reads big endian unsigned 16 bit integers" do
54
+ subject.read_uint16_be.should == 0xdead
55
+ subject.read_uint16_be.should == 0xbeef
56
+ end
57
+ end
58
+
59
+ describe "#read_uint32_weird_endian" do
60
+ it "reads FLV's super weird mixed endian properly" do
61
+ subject.read_uint32_weird_endian.should == 0xefdeadbe
62
+ subject.read_uint32_weird_endian.should == 0xde00faca
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,19 @@
1
+ require "flv/tag/data"
2
+
3
+ describe FLV::Tag::Data do
4
+ context "integration test" do
5
+ let(:preview_flv) { File.open(File.expand_path("../../../files/preview.flv", __FILE__), "rb") }
6
+ subject { FLV.new(preview_flv).each_tag.first }
7
+
8
+ its(:duration) { should == 6.0 }
9
+ its(:width) { should == 640 }
10
+ its(:height) { should == 360 }
11
+ its(:video_data_rate) { should == 700 }
12
+ its(:frame_rate) { should == 30 }
13
+ its(:video_codec_id) { should == 4 }
14
+ its(:audio_data_rate) { should == 128 }
15
+ its(:audio_delay) { should == 0.038 }
16
+ its(:audio_codec_id) { should == 2 }
17
+ its(:seek_to_end?) { should == true }
18
+ end
19
+ end
@@ -0,0 +1,47 @@
1
+ # coding: BINARY
2
+
3
+ require "flv/tag"
4
+ require "stringio"
5
+
6
+ describe FLV::Tag do
7
+ describe ".read" do
8
+ let(:io) { StringIO.new(string) }
9
+
10
+ context "reading a metadata tag" do
11
+ let(:string) { "\x12" }
12
+
13
+ it "creates a FLV::Tag::Data" do
14
+ FLV::Tag::Data.should_receive(:new).with(io)
15
+ FLV::Tag.read(io)
16
+ end
17
+ end
18
+
19
+ context "reading an audio tag" do
20
+ let(:string) { "\x08" }
21
+
22
+ it "creates a FLV::Tag::Data" do
23
+ FLV::Tag::Audio.should_receive(:new).with(io)
24
+ FLV::Tag.read(io)
25
+ end
26
+ end
27
+
28
+ context "reading a video tag" do
29
+ let(:string) { "\x09" }
30
+
31
+ it "creates a FLV::Tag::Data" do
32
+ FLV::Tag::Video.should_receive(:new).with(io)
33
+ FLV::Tag.read(io)
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "tag parsing" do
39
+ let(:string) { "\x00\x00\x0b\xad\xbe\xef\xde\x00\x00\x00hello world\x00\x00\x00\x15" }
40
+ subject { FLV::Tag.new(StringIO.new(string)) }
41
+
42
+ its(:length) { should == 11 }
43
+ its(:timestamp) { should == 0xdeadbeef }
44
+ its(:raw_data) { should == "hello world" }
45
+ its(:footer) { should == 21 }
46
+ end
47
+ end
@@ -0,0 +1,42 @@
1
+ require "flv"
2
+
3
+ describe FLV do
4
+ context "integration test" do
5
+ let(:preview_flv) { File.open(File.expand_path("../files/preview.flv", __FILE__), "rb") }
6
+ subject { FLV.new(preview_flv) }
7
+
8
+ its(:audio?) { should be_true }
9
+ its(:video?) { should be_true }
10
+ end
11
+
12
+ describe "#audio? and #video?" do
13
+ let(:flags) { 0 }
14
+ subject { FLV.allocate.tap do |flv| flv.stub(:flags => flags) end }
15
+
16
+ context "doesn't have any flags set" do
17
+ its(:audio?) { should be_false }
18
+ its(:video?) { should be_false }
19
+ end
20
+
21
+ context "has the audio flag set" do
22
+ let(:flags) { FLV::AUDIO_FLAG }
23
+
24
+ its(:audio?) { should be_true }
25
+ its(:video?) { should be_false }
26
+ end
27
+
28
+ context "has the video flag set" do
29
+ let(:flags) { FLV::VIDEO_FLAG }
30
+
31
+ its(:audio?) { should be_false }
32
+ its(:video?) { should be_true }
33
+ end
34
+
35
+ context "has the audio and video flags set" do
36
+ let(:flags) { FLV::AUDIO_FLAG | FLV::VIDEO_FLAG }
37
+
38
+ its(:audio?) { should be_true }
39
+ its(:video?) { should be_true }
40
+ end
41
+ end
42
+ end
metadata CHANGED
@@ -1,23 +1,88 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charlie Somerville
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-06 00:00:00.000000000 Z
12
- dependencies: []
13
- description:
14
- email: charlie@charliesomerville.com
11
+ date: 2013-05-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 2.13.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.13.0
55
+ description: A library for handling FLV files
56
+ email:
57
+ - charlie@charliesomerville.com
15
58
  executables: []
16
59
  extensions: []
17
60
  extra_rdoc_files: []
18
- files: []
19
- homepage:
20
- licenses: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - flv.gemspec
68
+ - lib/flv.rb
69
+ - lib/flv/format_error.rb
70
+ - lib/flv/script_data_parser.rb
71
+ - lib/flv/stream_reader.rb
72
+ - lib/flv/tag.rb
73
+ - lib/flv/tag/audio.rb
74
+ - lib/flv/tag/data.rb
75
+ - lib/flv/tag/video.rb
76
+ - lib/flv/version.rb
77
+ - spec/files/preview.flv
78
+ - spec/flv/script_data_parser_spec.rb
79
+ - spec/flv/stream_reader_spec.rb
80
+ - spec/flv/tag/data_spec.rb
81
+ - spec/flv/tag_spec.rb
82
+ - spec/flv_spec.rb
83
+ homepage: https://github.com/envato/flv
84
+ licenses:
85
+ - MIT
21
86
  metadata: {}
22
87
  post_install_message:
23
88
  rdoc_options: []
@@ -35,9 +100,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
35
100
  version: '0'
36
101
  requirements: []
37
102
  rubyforge_project:
38
- rubygems_version: 2.0.3
103
+ rubygems_version: 2.0.0
39
104
  signing_key:
40
105
  specification_version: 4
41
- summary: coming soon!
42
- test_files: []
106
+ summary: Ruby library for parsing and handling FLV files
107
+ test_files:
108
+ - spec/files/preview.flv
109
+ - spec/flv/script_data_parser_spec.rb
110
+ - spec/flv/stream_reader_spec.rb
111
+ - spec/flv/tag/data_spec.rb
112
+ - spec/flv/tag_spec.rb
113
+ - spec/flv_spec.rb
43
114
  has_rdoc: