marcandre-flvedit 0.6.1
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.
- data/CHANGELOG.rdoc +5 -0
- data/LICENSE +24 -0
- data/README.rdoc +90 -0
- data/Rakefile +131 -0
- data/VERSION.yml +4 -0
- data/bin/flvedit +14 -0
- data/lib/flv.rb +24 -0
- data/lib/flv/audio.rb +66 -0
- data/lib/flv/base.rb +38 -0
- data/lib/flv/body.rb +57 -0
- data/lib/flv/edit.rb +20 -0
- data/lib/flv/edit/options.rb +162 -0
- data/lib/flv/edit/processor.rb +3 -0
- data/lib/flv/edit/processor/add.rb +67 -0
- data/lib/flv/edit/processor/base.rb +209 -0
- data/lib/flv/edit/processor/command_line.rb +23 -0
- data/lib/flv/edit/processor/cut.rb +27 -0
- data/lib/flv/edit/processor/debug.rb +30 -0
- data/lib/flv/edit/processor/head.rb +16 -0
- data/lib/flv/edit/processor/join.rb +52 -0
- data/lib/flv/edit/processor/meta_data_maker.rb +127 -0
- data/lib/flv/edit/processor/print.rb +13 -0
- data/lib/flv/edit/processor/printer.rb +27 -0
- data/lib/flv/edit/processor/reader.rb +30 -0
- data/lib/flv/edit/processor/save.rb +28 -0
- data/lib/flv/edit/processor/update.rb +27 -0
- data/lib/flv/edit/runner.rb +23 -0
- data/lib/flv/edit/version.rb +15 -0
- data/lib/flv/event.rb +40 -0
- data/lib/flv/file.rb +41 -0
- data/lib/flv/header.rb +37 -0
- data/lib/flv/packing.rb +140 -0
- data/lib/flv/tag.rb +62 -0
- data/lib/flv/timestamp.rb +124 -0
- data/lib/flv/util/double_check.rb +22 -0
- data/lib/flv/video.rb +73 -0
- data/test/fixtures/corrupted.flv +0 -0
- data/test/fixtures/short.flv +0 -0
- data/test/fixtures/tags.xml +39 -0
- data/test/test_flv.rb +145 -0
- data/test/test_flv_edit.rb +32 -0
- data/test/test_flv_edit_results.rb +27 -0
- data/test/test_helper.rb +9 -0
- data/test/text_flv_edit_results/add_tags.txt +132 -0
- data/test/text_flv_edit_results/cut_from.txt +114 -0
- data/test/text_flv_edit_results/cut_key.txt +20 -0
- data/test/text_flv_edit_results/debug.txt +132 -0
- data/test/text_flv_edit_results/debug_limited.txt +18 -0
- data/test/text_flv_edit_results/debug_range.txt +32 -0
- data/test/text_flv_edit_results/join.txt +237 -0
- data/test/text_flv_edit_results/print.txt +16 -0
- data/test/text_flv_edit_results/stop.txt +38 -0
- data/test/text_flv_edit_results/update.txt +33 -0
- metadata +134 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module FLV
|
2
|
+
class IOError < ::IOError # :nodoc:
|
3
|
+
end
|
4
|
+
|
5
|
+
module Util # :nodoc:
|
6
|
+
def self.double_check(event, expected, actual)
|
7
|
+
Checking.fail_check(event, expected, actual) unless [*expected].include? actual
|
8
|
+
end
|
9
|
+
|
10
|
+
class Checking # :nodoc:
|
11
|
+
class << self
|
12
|
+
attr_accessor :strict
|
13
|
+
def fail_check(event, expected, actual)
|
14
|
+
err = "Mismatch on #{event}: expected #{expected} vs #{actual}"
|
15
|
+
raise IOError, err if strict
|
16
|
+
#STDERR << "Caution: "+ err
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/lib/flv/video.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
module FLV
|
2
|
+
# The body of a video tag.
|
3
|
+
# The data is quite complex stuff. We make no attempt to understand it all
|
4
|
+
# or to be able to modify any of it. We simply consider it a complex string
|
5
|
+
# and read the interesting bits to give more info.
|
6
|
+
class Video < String
|
7
|
+
include Body
|
8
|
+
CODECS = Hash.new(:unknown).merge!(
|
9
|
+
1 => :JPEG,
|
10
|
+
2 => :h263,
|
11
|
+
3 => :screen,
|
12
|
+
4 => :on2_vp6,
|
13
|
+
5 => :on2_vp6_alpha,
|
14
|
+
6 => :screen_v2,
|
15
|
+
7 => :AVC
|
16
|
+
).freeze
|
17
|
+
|
18
|
+
FRAMES = Hash.new(:unknown).merge!(
|
19
|
+
1 => :keyframe ,
|
20
|
+
2 => :interframe,
|
21
|
+
3 => :disposable_interframe
|
22
|
+
).freeze
|
23
|
+
|
24
|
+
def frame_type
|
25
|
+
FRAMES[read_bits(0...4)]
|
26
|
+
end
|
27
|
+
|
28
|
+
def codec_id
|
29
|
+
read_bits(4...8)
|
30
|
+
end
|
31
|
+
|
32
|
+
def codec
|
33
|
+
CODECS[codec_id]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Dimensions for h263 encoding; either as a bit range or the final value
|
37
|
+
H263_DIMENSIONS = {
|
38
|
+
0 => [41...49, 49...57],
|
39
|
+
1 => [41...57, 57...73],
|
40
|
+
2 => [352, 288],
|
41
|
+
3 => [176, 144],
|
42
|
+
4 => [128, 96] ,
|
43
|
+
5 => [320, 240],
|
44
|
+
6 => [160, 120]
|
45
|
+
}.freeze
|
46
|
+
|
47
|
+
# Returns dimensions as {:width => w, :height => h}, for Sorensen H.263 and screen video codecs only (otherwise returns nil)
|
48
|
+
def dimensions
|
49
|
+
w, h = case codec
|
50
|
+
when :h263
|
51
|
+
H263_DIMENSIONS[read_bits(38...41)]
|
52
|
+
when :screen
|
53
|
+
[12...24, 24...32]
|
54
|
+
end
|
55
|
+
return nil unless w
|
56
|
+
w, h = [w, h].map{ |r| read_bits(r) } if w.is_a?(Range)
|
57
|
+
{:width => w, :height => h}
|
58
|
+
end
|
59
|
+
|
60
|
+
def is?(what)
|
61
|
+
frame_type.to_s.downcase == what.to_s.downcase || super
|
62
|
+
end
|
63
|
+
|
64
|
+
def getters
|
65
|
+
super - [:frame_type, :frame_type.to_s] # Let's exclude the frame_type from the normal attributes... (string vs symbol: ruby 1.8 vs 1.9)
|
66
|
+
end
|
67
|
+
|
68
|
+
def title
|
69
|
+
super + " (#{frame_type})" # ...and include it in the title instead.
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<tags>
|
3
|
+
<!-- an event cue point -->
|
4
|
+
<metatag event="onCuePoint">
|
5
|
+
<name>TestEvent1</name>
|
6
|
+
<timestamp>333</timestamp>
|
7
|
+
<parameters>
|
8
|
+
<speaker>Peter</speaker>
|
9
|
+
<says>Hello my Name is Peter.</says>
|
10
|
+
</parameters>
|
11
|
+
<type>event</type>
|
12
|
+
</metatag>
|
13
|
+
|
14
|
+
<!-- a navigation cue point -->
|
15
|
+
<metatag event="onCuePoint">
|
16
|
+
<name>TestEvent2</name>
|
17
|
+
<timestamp>1000</timestamp>
|
18
|
+
<parameters>
|
19
|
+
<index>1</index>
|
20
|
+
<title>Chapter 1</title>
|
21
|
+
</parameters>
|
22
|
+
<type>navigation</type>
|
23
|
+
</metatag>
|
24
|
+
|
25
|
+
<!-- this cuepoint overwrites the previous cue point, because of it's
|
26
|
+
identical timestamps and the overwrite parameter was set -->
|
27
|
+
|
28
|
+
<metatag event="onCuePoint" overwrite="true">
|
29
|
+
<name>TestEvent3</name>
|
30
|
+
<timestamp>1000</timestamp>
|
31
|
+
<parameters>
|
32
|
+
<index>1</index>
|
33
|
+
<title>Chapter 2</title>
|
34
|
+
</parameters>
|
35
|
+
<type>navigation</type>
|
36
|
+
</metatag>
|
37
|
+
</tags>
|
38
|
+
|
39
|
+
|
data/test/test_flv.rb
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class TestFlv < Test::Unit::TestCase
|
4
|
+
context "Timestamp" do
|
5
|
+
context "conversion" do
|
6
|
+
{ 0 => "0.000" ,
|
7
|
+
1 => "0.001" ,
|
8
|
+
1000 => "1.000" ,
|
9
|
+
12_345 => "12.345" ,
|
10
|
+
61_000 => "1:01.000" ,
|
11
|
+
601_000 => "10:01.000" ,
|
12
|
+
3600_000 => "1:00:00.000"
|
13
|
+
}.each do |n, s|
|
14
|
+
should "convert between #{s} and #{n} ms" do
|
15
|
+
assert_equal s, FLV::Timestamp.in_milliseconds(n).to_s
|
16
|
+
assert_equal n, FLV::Timestamp.try_convert(s).in_milliseconds
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
{ "0" => 0 ,
|
21
|
+
"1" => 1000,
|
22
|
+
"1.0" => 1000,
|
23
|
+
"1m" => 60_000,
|
24
|
+
"1h" => 60 * 60_000,
|
25
|
+
"1::" => 60 * 60_000,
|
26
|
+
"1h23m45.6789" => 60 * 60_000 + 23*60_000 + 45678
|
27
|
+
}.each do |s, n|
|
28
|
+
should "convert #{s} to #{n} ms" do
|
29
|
+
assert_equal n, FLV::Timestamp.try_convert(s).in_milliseconds
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "TimestampRange" do
|
36
|
+
context "conversion" do
|
37
|
+
{ "1:02-" => 62..(1/0.0),
|
38
|
+
"-1.23" => 0..1.23,
|
39
|
+
"12345-1:02:03.456" => 12345..3723.456,
|
40
|
+
"2m.345-1h" => 120.345..3600
|
41
|
+
}.each do |s, r|
|
42
|
+
should "convert #{s} to #{r} ms" do
|
43
|
+
assert_equal r, FLV::TimestampRange.try_convert(s).in_seconds
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
BIT_TEST = "\x01\x02\xff"
|
51
|
+
context "Bit reading from #{BIT_TEST.inspect}" do
|
52
|
+
setup do
|
53
|
+
@body = BIT_TEST.clone
|
54
|
+
class <<@body
|
55
|
+
include FLV::Body
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
[ [0..0, 0],
|
60
|
+
[0...7, 0],
|
61
|
+
[0..7, 1],
|
62
|
+
[6..7, 1],
|
63
|
+
[7..7, 1],
|
64
|
+
[14, 1],
|
65
|
+
[3..9, 0b100],
|
66
|
+
[3...15,0b1_0000_001],
|
67
|
+
[3..15, 0b1_0000_0010],
|
68
|
+
[3..16, 0b1_0000_0010_1]
|
69
|
+
].each do |bits, val|
|
70
|
+
should "return #{val} for bits #{bits}" do
|
71
|
+
assert_equal val, @body.read_bits(bits)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "Packing" do
|
77
|
+
context "a header" do
|
78
|
+
setup do
|
79
|
+
@header = FLV::Header.new
|
80
|
+
@header.extra = "hello"
|
81
|
+
@header.has_audio = true
|
82
|
+
end
|
83
|
+
|
84
|
+
should "work" do
|
85
|
+
assert_equal "FLV\001\004\000\000\000\016hello\000\000\000\000",
|
86
|
+
@header.pack
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "an audio tag" do
|
91
|
+
setup do
|
92
|
+
@tag = FLV::Tag.new(FLV::Timestamp.in_milliseconds(0x1234), FLV::Audio.new("bogus audio data!"))
|
93
|
+
end
|
94
|
+
|
95
|
+
should "work" do
|
96
|
+
assert_equal "\b\000\000\021\000\x12\x34\000\000\000\000bogus audio data!\000\000\000\034",
|
97
|
+
@tag.pack
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "Unpacking" do
|
103
|
+
setup do
|
104
|
+
@io = StringIO.new("FLV\001\004\000\000\000\016hello\000\000\000\000!!")
|
105
|
+
@header = @io.packed.read(FLV::Header)
|
106
|
+
end
|
107
|
+
|
108
|
+
should "read the header correctly" do
|
109
|
+
assert_equal "hello", @header.extra
|
110
|
+
assert_equal true, @header.has_audio
|
111
|
+
assert_equal false, @header.has_video
|
112
|
+
end
|
113
|
+
|
114
|
+
should "read just what's required" do
|
115
|
+
assert_equal "!!", @io.read
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "Typematch" do
|
120
|
+
setup do
|
121
|
+
@chunks = FLV::File.open(SHORT_FLV).each.first(4)
|
122
|
+
end
|
123
|
+
|
124
|
+
should "work" do
|
125
|
+
assert_equal false, @chunks[2].is?(:audio)
|
126
|
+
end
|
127
|
+
|
128
|
+
{
|
129
|
+
:header => [true , false, false, false],
|
130
|
+
:tag => [false, true , true , true ],
|
131
|
+
:audio => [false, false, false, false],
|
132
|
+
:audio_tag => [false, false, true , false],
|
133
|
+
:nellymoser => [false, false, false, false],
|
134
|
+
:mP3 => [false, false, true , false],
|
135
|
+
:event_tag => [false, true , false, false],
|
136
|
+
:onMetaData => [false, true , false, false],
|
137
|
+
:onCuePoint => [false, false, false, false],
|
138
|
+
}.each do |check, answers|
|
139
|
+
should "work for #{check}" do
|
140
|
+
assert_equal answers, @chunks.map{|t| t.is?(check) }, check
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class TestFlvEdit < Test::Unit::TestCase
|
4
|
+
context "Options parsing" do
|
5
|
+
setup do
|
6
|
+
@options = FLV::Edit::Options.new([SHORT_FLV, "--Debug"])
|
7
|
+
end
|
8
|
+
|
9
|
+
should "detect files" do
|
10
|
+
assert_equal [SHORT_FLV], @options.options[:files]
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
context "Command line tool" do
|
16
|
+
setup do
|
17
|
+
File.delete(TEMP_FLV) if File.exist?(TEMP_FLV)
|
18
|
+
end
|
19
|
+
|
20
|
+
should "save" do
|
21
|
+
assert !File.exist?(TEMP_FLV)
|
22
|
+
runner = FLV::Edit::Runner.new([SHORT_FLV, "--Update", "--Save", TEMP_FLV])
|
23
|
+
runner.options[:dont_catch_errors] = true
|
24
|
+
runner.run
|
25
|
+
assert File.exist?(TEMP_FLV)
|
26
|
+
end
|
27
|
+
|
28
|
+
teardown do
|
29
|
+
File.delete(TEMP_FLV) if File.exist?(TEMP_FLV)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class TestFlvEdit < Test::Unit::TestCase
|
4
|
+
context "Command line results" do
|
5
|
+
Dir.glob(File.dirname(__FILE__)+"/text_flv_edit_results/*.txt").each do |fn|
|
6
|
+
sep, args, sep, *expect = File.readlines(fn).map!(&:chomp)
|
7
|
+
args = args.split(' ')
|
8
|
+
args.unshift SHORT_FLV unless args.first.start_with?(".")
|
9
|
+
|
10
|
+
context "for 'flvedit #{args.join(' ')}'" do
|
11
|
+
setup do
|
12
|
+
Time.stubs(:now).returns(Time.utc(2008,"dec",20))
|
13
|
+
@result = ""
|
14
|
+
runner = FLV::Edit::Runner.new(args)
|
15
|
+
runner.options[:dont_catch_errors] = true
|
16
|
+
runner.options[:out] = StringIO.new(@result)
|
17
|
+
runner.run
|
18
|
+
end
|
19
|
+
should "match #{fn}" do
|
20
|
+
@result = @result.split("\n")
|
21
|
+
same = @result & expect
|
22
|
+
assert_equal expect-same, @result-same
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'backports'
|
4
|
+
require_relative '../lib/flv/edit'
|
5
|
+
require 'shoulda'
|
6
|
+
require 'mocha'
|
7
|
+
|
8
|
+
SHORT_FLV = File.dirname(__FILE__) + "/fixtures/short.flv"
|
9
|
+
TEMP_FLV = File.dirname(__FILE__) + "/fixtures/short_temp.flv"
|
@@ -0,0 +1,132 @@
|
|
1
|
+
*** command:
|
2
|
+
--Add ./test/fixtures/tags.xml --Debug
|
3
|
+
*** result:
|
4
|
+
Header| ./test/fixtures/short.flv
|
5
|
+
| extra :
|
6
|
+
| has_audio : true
|
7
|
+
| has_video : true
|
8
|
+
| version : 1
|
9
|
+
0.000 | FLV::Event tag
|
10
|
+
| event : onMetaData
|
11
|
+
| audiocodecid : 2
|
12
|
+
| audiodatarate : 16
|
13
|
+
| audiodelay : 0
|
14
|
+
| canSeekToEnd : 1
|
15
|
+
| creationdate : Fri Feb 03 122553 2006\n
|
16
|
+
| duration : 16.9
|
17
|
+
| framerate : 10
|
18
|
+
| height : 154
|
19
|
+
| videocodecid : 4
|
20
|
+
| videodatarate : 40
|
21
|
+
| width : 192
|
22
|
+
0.000 | FLV::Audio tag
|
23
|
+
| channel : mono
|
24
|
+
| codec_id : 2
|
25
|
+
| format : MP3
|
26
|
+
| rate : 11000
|
27
|
+
| sample_size : 16
|
28
|
+
0.000 | FLV::Video tag (keyframe)
|
29
|
+
| codec : on2_vp6
|
30
|
+
| codec_id : 4
|
31
|
+
| dimensions : nil
|
32
|
+
0.052 | FLV::Audio tag
|
33
|
+
0.100 | FLV::Video tag (interframe)
|
34
|
+
0.104 | FLV::Audio tag
|
35
|
+
0.156 | FLV::Audio tag
|
36
|
+
0.200 | FLV::Video tag (keyframe)
|
37
|
+
0.208 | FLV::Audio tag
|
38
|
+
0.261 | FLV::Audio tag
|
39
|
+
0.300 | FLV::Video tag (interframe)
|
40
|
+
0.313 | FLV::Audio tag
|
41
|
+
0.365 | FLV::Audio tag
|
42
|
+
0.400 | FLV::Video tag (interframe)
|
43
|
+
0.417 | FLV::Audio tag
|
44
|
+
0.470 | FLV::Audio tag
|
45
|
+
0.500 | FLV::Video tag (interframe)
|
46
|
+
0.522 | FLV::Audio tag
|
47
|
+
0.574 | FLV::Audio tag
|
48
|
+
0.600 | FLV::Video tag (interframe)
|
49
|
+
0.626 | FLV::Audio tag
|
50
|
+
0.679 | FLV::Audio tag
|
51
|
+
0.700 | FLV::Video tag (interframe)
|
52
|
+
0.731 | FLV::Audio tag
|
53
|
+
0.783 | FLV::Audio tag
|
54
|
+
0.800 | FLV::Video tag (interframe)
|
55
|
+
0.835 | FLV::Audio tag
|
56
|
+
0.888 | FLV::Audio tag
|
57
|
+
0.900 | FLV::Video tag (interframe)
|
58
|
+
0.940 | FLV::Audio tag
|
59
|
+
0.992 | FLV::Audio tag
|
60
|
+
1.000 | FLV::Video tag (interframe)
|
61
|
+
1.044 | FLV::Audio tag
|
62
|
+
1.097 | FLV::Audio tag
|
63
|
+
1.100 | FLV::Video tag (interframe)
|
64
|
+
1.149 | FLV::Audio tag
|
65
|
+
1.200 | FLV::Video tag (interframe)
|
66
|
+
1.201 | FLV::Audio tag
|
67
|
+
1.253 | FLV::Audio tag
|
68
|
+
1.300 | FLV::Video tag (interframe)
|
69
|
+
1.306 | FLV::Audio tag
|
70
|
+
1.358 | FLV::Audio tag
|
71
|
+
1.400 | FLV::Video tag (interframe)
|
72
|
+
1.410 | FLV::Audio tag
|
73
|
+
1.462 | FLV::Audio tag
|
74
|
+
1.500 | FLV::Video tag (interframe)
|
75
|
+
1.515 | FLV::Audio tag
|
76
|
+
1.567 | FLV::Audio tag
|
77
|
+
1.600 | FLV::Video tag (interframe)
|
78
|
+
1.619 | FLV::Audio tag
|
79
|
+
1.671 | FLV::Audio tag
|
80
|
+
1.700 | FLV::Video tag (interframe)
|
81
|
+
1.724 | FLV::Audio tag
|
82
|
+
1.776 | FLV::Audio tag
|
83
|
+
1.800 | FLV::Video tag (interframe)
|
84
|
+
1.828 | FLV::Audio tag
|
85
|
+
1.880 | FLV::Audio tag
|
86
|
+
1.900 | FLV::Video tag (interframe)
|
87
|
+
1.933 | FLV::Audio tag
|
88
|
+
1.985 | FLV::Audio tag
|
89
|
+
2.000 | FLV::Video tag (interframe)
|
90
|
+
2.037 | FLV::Audio tag
|
91
|
+
2.089 | FLV::Audio tag
|
92
|
+
2.100 | FLV::Video tag (interframe)
|
93
|
+
2.142 | FLV::Audio tag
|
94
|
+
2.194 | FLV::Audio tag
|
95
|
+
2.200 | FLV::Video tag (interframe)
|
96
|
+
2.246 | FLV::Audio tag
|
97
|
+
2.298 | FLV::Audio tag
|
98
|
+
2.300 | FLV::Video tag (interframe)
|
99
|
+
2.351 | FLV::Audio tag
|
100
|
+
2.400 | FLV::Video tag (interframe)
|
101
|
+
2.403 | FLV::Audio tag
|
102
|
+
2.455 | FLV::Audio tag
|
103
|
+
2.500 | FLV::Video tag (interframe)
|
104
|
+
2.507 | FLV::Audio tag
|
105
|
+
2.559 | FLV::Audio tag
|
106
|
+
2.600 | FLV::Video tag (interframe)
|
107
|
+
2.612 | FLV::Audio tag
|
108
|
+
2.664 | FLV::Audio tag
|
109
|
+
2.700 | FLV::Video tag (interframe)
|
110
|
+
2.716 | FLV::Audio tag
|
111
|
+
2.768 | FLV::Audio tag
|
112
|
+
2.800 | FLV::Video tag (interframe)
|
113
|
+
2.821 | FLV::Audio tag
|
114
|
+
2.873 | FLV::Audio tag
|
115
|
+
2.900 | FLV::Video tag (interframe)
|
116
|
+
2.925 | FLV::Audio tag
|
117
|
+
2.977 | FLV::Audio tag
|
118
|
+
3.000 | FLV::Video tag (interframe)
|
119
|
+
3.030 | FLV::Audio tag
|
120
|
+
3.082 | FLV::Audio tag
|
121
|
+
3.100 | FLV::Video tag (interframe)
|
122
|
+
3.134 | FLV::Audio tag
|
123
|
+
3.186 | FLV::Audio tag
|
124
|
+
3.200 | FLV::Video tag (interframe)
|
125
|
+
3.239 | FLV::Audio tag
|
126
|
+
3.291 | FLV::Audio tag
|
127
|
+
3.300 | FLV::Video tag (interframe)
|
128
|
+
3.343 | FLV::Audio tag
|
129
|
+
3.395 | FLV::Audio tag
|
130
|
+
3.400 | FLV::Video tag (interframe)
|
131
|
+
3.448 | FLV::Audio tag
|
132
|
+
3.500 | FLV::Video tag (interframe)
|