flv 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: