mhs-rvideo 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +43 -0
- data/License.txt +20 -0
- data/README.txt +91 -0
- data/RULES +11 -0
- data/Rakefile +178 -0
- data/lib/rvideo/errors.rb +24 -0
- data/lib/rvideo/float.rb +7 -0
- data/lib/rvideo/inspector.rb +557 -0
- data/lib/rvideo/tools/abstract_tool.rb +156 -0
- data/lib/rvideo/tools/ffmpeg.rb +154 -0
- data/lib/rvideo/tools/flvtool2.rb +49 -0
- data/lib/rvideo/tools/mencoder.rb +65 -0
- data/lib/rvideo/tools/mp4box.rb +21 -0
- data/lib/rvideo/tools/mp4creator.rb +36 -0
- data/lib/rvideo/tools/mplayer.rb +31 -0
- data/lib/rvideo/transcoder.rb +138 -0
- data/lib/rvideo/version.rb +9 -0
- data/lib/rvideo.rb +20 -0
- metadata +75 -0
@@ -0,0 +1,154 @@
|
|
1
|
+
module RVideo
|
2
|
+
module Tools
|
3
|
+
class Ffmpeg
|
4
|
+
include AbstractTool::InstanceMethods
|
5
|
+
|
6
|
+
attr_reader :frame, :q, :size, :time, :output_bitrate, :video_size, :audio_size, :header_size, :overhead, :psnr, :output_fps
|
7
|
+
|
8
|
+
# Not sure if this is needed anymore...
|
9
|
+
def tool_command
|
10
|
+
'ffmpeg'
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Return -r and the frame rate of the original file. E.g.:
|
15
|
+
#
|
16
|
+
# -r 29.97
|
17
|
+
#
|
18
|
+
# If the original frame rate can't be determined, return an empty
|
19
|
+
# string.
|
20
|
+
def original_fps
|
21
|
+
inspect_original if @original.nil?
|
22
|
+
if @original.fps
|
23
|
+
"-r #{@original.fps}"
|
24
|
+
else
|
25
|
+
""
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def parse_result(result)
|
32
|
+
|
33
|
+
if m = /Unable for find a suitable output format for.*$/.match(result)
|
34
|
+
raise TranscoderError::InvalidCommand, m[0]
|
35
|
+
end
|
36
|
+
|
37
|
+
if m = /Unknown codec \'(.*)\'/.match(result)
|
38
|
+
raise TranscoderError::InvalidFile, "Codec #{m[1]} not supported by this build of ffmpeg"
|
39
|
+
end
|
40
|
+
|
41
|
+
if m = /could not find codec parameters/.match(result)
|
42
|
+
raise TranscoderError::InvalidFile, "Codec not supported by this build of ffmpeg"
|
43
|
+
end
|
44
|
+
|
45
|
+
if m = /I\/O error occured\n(.*)$/.match(result)
|
46
|
+
raise TranscoderError::InvalidFile, "I/O error: #{m[1].strip}"
|
47
|
+
end
|
48
|
+
|
49
|
+
if m = /\n(.*)Unknown Format$/.match(result)
|
50
|
+
raise TranscoderError::InvalidFile, "unknown format (#{m[1]})"
|
51
|
+
end
|
52
|
+
|
53
|
+
if m = /\nERROR.*/m.match(result)
|
54
|
+
raise TranscoderError::InvalidFile, m[0]
|
55
|
+
end
|
56
|
+
|
57
|
+
if result =~ /usage: ffmpeg/
|
58
|
+
raise TranscoderError::InvalidCommand, "must pass a command to ffmpeg"
|
59
|
+
end
|
60
|
+
|
61
|
+
if result =~ /Output file does not contain.*stream/
|
62
|
+
raise TranscoderError, "Output file does not contain any video or audio streams."
|
63
|
+
end
|
64
|
+
|
65
|
+
if m = /Unsupported codec.*id=(.*)\).*for input stream\s*(.*)\s*/.match(result)
|
66
|
+
inspect_original if @original.nil?
|
67
|
+
case m[2]
|
68
|
+
when @original.audio_stream_id
|
69
|
+
codec_type = "audio"
|
70
|
+
codec = @original.audio_codec
|
71
|
+
when @original.video_stream_id
|
72
|
+
codec_type = "video"
|
73
|
+
codec = @original.video_codec
|
74
|
+
else
|
75
|
+
codec_type = "video or audio"
|
76
|
+
codec = "unknown"
|
77
|
+
end
|
78
|
+
|
79
|
+
raise TranscoderError::InvalidFile, "Unsupported #{codec_type} codec: #{codec} (id=#{m[1]}, stream=#{m[2]})"
|
80
|
+
#raise TranscoderError, "Codec #{m[1]} not supported (in stream #{m[2]})"
|
81
|
+
end
|
82
|
+
|
83
|
+
# Could not open './spec/../config/../tmp/processed/1/kites-1.avi'
|
84
|
+
if result =~ /Could not open .#{@output_file}.\Z/
|
85
|
+
raise TranscoderError, "Could not write output file to #{@output_file}"
|
86
|
+
end
|
87
|
+
|
88
|
+
full_details = /Press .* to stop encoding\n(.*)/m.match(result)
|
89
|
+
raise TranscoderError, "Unexpected result details (#{result})" if full_details.nil?
|
90
|
+
details = full_details[1].strip.gsub(/\s*\n\s*/," - ")
|
91
|
+
|
92
|
+
if details =~ /Could not write header/
|
93
|
+
raise TranscoderError, details
|
94
|
+
end
|
95
|
+
|
96
|
+
#frame= 584 q=6.0 Lsize= 708kB time=19.5 bitrate= 297.8kbits/s
|
97
|
+
#video:49kB audio:153kB global headers:0kB muxing overhead 250.444444%
|
98
|
+
|
99
|
+
#frame= 4126 q=31.0 Lsize= 5917kB time=69.1 bitrate= 702.0kbits/s
|
100
|
+
#video:2417kB audio:540kB global headers:0kB muxing overhead 100.140277%
|
101
|
+
|
102
|
+
#frame= 273 fps= 31 q=10.0 Lsize= 398kB time=5.9 bitrate= 551.8kbits/s
|
103
|
+
#video:284kB audio:92kB global headers:0kB muxing overhead 5.723981%
|
104
|
+
|
105
|
+
#mdb:94, lastbuf:0 skipping granule 0
|
106
|
+
#size= 1080kB time=69.1 bitrate= 128.0kbits /s
|
107
|
+
#video:0kB audio:1080kB global headers:0kB muxing overhead 0.002893%
|
108
|
+
|
109
|
+
#size= 80kB time=5.1 bitrate= 128.0kbits/s ^Msize= 162kB time=10.3 bitrate= 128.0kbits/s ^Msize= 241kB time=15.4 bitrate= 128.0kbits/s ^Msize= 329kB time=21.1 bitrate= 128.0kbits/s ^Msize= 413kB time=26.4 bitrate= 128.0kbits/s ^Msize= 506kB time=32.4 bitrate= 128.0kbits/s ^Msize= 591kB time=37.8 bitrate= 128.0kbits/s ^Msize= 674kB time=43.2 bitrate= 128.0kbits/s ^Msize= 771kB time=49.4 bitrate= 128.0kbits/s ^Msize= 851kB time=54.5 bitrate= 128.0kbits/s ^Msize= 932kB time=59.6 bitrate= 128.0kbits/s ^Msize= 1015kB time=64.9 bitrate= 128.0kbits/s ^Msize= 1094kB time=70.0 bitrate= 128.0kbits/s ^Msize= 1175kB time=75.2 bitrate= 128.0kbits/s ^Msize= 1244kB time=79.6 bitrate= 128.0kbits/s ^Msize= 1335kB time=85.4 bitrate= 128.0kbits/s ^Msize= 1417kB time=90.7 bitrate= 128.0kbits/s ^Msize= 1508kB time=96.5 bitrate= 128.0kbits/s ^Msize= 1589kB time=101.7 bitrate= 128.0kbits/s ^Msize= 1671kB time=106.9 bitrate= 128.0kbits/s ^Msize= 1711kB time=109.5 bitrate= 128.0kbits/s - video:0kB audio:1711kB global headers:0kB muxing overhead 0.001826%
|
110
|
+
|
111
|
+
#mdb:14, lastbuf:0 skipping granule 0 - overread, skip -5 enddists: -2 -2 - overread, skip -5 enddists: -2 -2 - size= 90kB time=5.7 bitrate= 128.0kbits/s \nsize= 189kB time=12.1 bitrate= 128.0kbits/s
|
112
|
+
|
113
|
+
#size= 59kB time=20.2 bitrate= 24.0kbits/s \nsize= 139kB time=47.4 bitrate= 24.0kbits/s \nsize= 224kB time=76.5 bitrate= 24.0kbits/s \nsize= 304kB time=103.7 bitrate= 24.0kbits/s \nsi
|
114
|
+
|
115
|
+
#mdb:14, lastbuf:0 skipping granule 0 - overread, skip -5 enddists: -2 -2 - overread, skip -5 enddists: -2 -2 - size= 81kB time=10.3 bitrate= 64.0kbits/s \nsize= 153kB time=19.6 bitrate= 64.0kbits/s
|
116
|
+
|
117
|
+
#size= 65kB time=4.1 bitrate= 128.1kbits/s \nsize= 119kB time=7.6 bitrate= 128.0kbits/s \nsize= 188kB time=12.0 bitrate= 128.0kbits/s \nsize= 268kB time=17.1 bitrate= 128.0kbits/s \nsize=
|
118
|
+
|
119
|
+
#Error while decoding stream #0.1 [mpeg4aac @ 0xb7d089f0]faac: frame decoding failed: Gain control not yet implementedError while decoding stream #0.1frame= 2143 fps= 83 q=4.0 size= 4476kB time=71.3 bitrate= 514.5kbits/s ^M[mpeg4aac @ 0xb7d089f0]faac: frame decoding failed: Gain control not yet implementedError while decoding stream #0.1
|
120
|
+
|
121
|
+
# NOTE: had to remove "\s" from "\s.*L.*size=" from this regexp below.
|
122
|
+
# Not sure why. Unit tests were succeeding, but hand tests weren't.
|
123
|
+
if details =~ /video:/
|
124
|
+
#success = /^frame=\s*(\S*)\s*q=(\S*).*L.*size=\s*(\S*)\s*time=\s*(\S*)\s*bitrate=\s*(\S*)\s*/m.match(details)
|
125
|
+
@frame = sanitary_match(/frame=\s*(\S*)/, details)
|
126
|
+
@output_fps = sanitary_match(/fps=\s*(\S*)/, details)
|
127
|
+
@q = sanitary_match(/\s+q=\s*(\S*)/, details)
|
128
|
+
@size = sanitary_match(/size=\s*(\S*)/, details)
|
129
|
+
@time = sanitary_match(/time=\s*(\S*)/, details)
|
130
|
+
@output_bitrate = sanitary_match(/bitrate=\s*(\S*)/, details)
|
131
|
+
|
132
|
+
@video_size = /video:\s*(\S*)/.match(details)[1]
|
133
|
+
@audio_size = /audio:\s*(\S*)/.match(details)[1]
|
134
|
+
@header_size = /headers:\s*(\S*)/.match(details)[1]
|
135
|
+
@overhead = /overhead[:]*\s*(\S*)/.match(details)[1]
|
136
|
+
psnr_match = /PSNR=(.*)\s*size=/.match(details)
|
137
|
+
@psnr = psnr_match[1].strip if psnr_match
|
138
|
+
return true
|
139
|
+
end
|
140
|
+
|
141
|
+
#[mp3 @ 0x54340c]flv doesnt support that sample rate, choose from (44100, 22050, 11025)
|
142
|
+
#Could not write header for output file #0 (incorrect codec parameters ?)
|
143
|
+
|
144
|
+
raise TranscoderError::UnexpectedResult, details
|
145
|
+
end
|
146
|
+
|
147
|
+
def sanitary_match(regexp, string)
|
148
|
+
match = regexp.match(string)
|
149
|
+
return match[1] if match
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module RVideo
|
2
|
+
module Tools
|
3
|
+
class Flvtool2
|
4
|
+
include AbstractTool::InstanceMethods
|
5
|
+
|
6
|
+
attr_reader :raw_metadata
|
7
|
+
|
8
|
+
#attr_reader :has_key_frames, :cue_points, :audiodatarate, :has_video, :stereo, :can_seek_to_end, :framerate, :audiosamplerate, :videocodecid, :datasize, :lasttimestamp,
|
9
|
+
# :audiosamplesize, :audiosize, :has_audio, :audiodelay, :videosize, :metadatadate, :metadatacreator, :lastkeyframetimestamp, :height, :filesize, :has_metadata, :audiocodecid,
|
10
|
+
# :duration, :videodatarate, :has_cue_points, :width
|
11
|
+
|
12
|
+
def tool_command
|
13
|
+
'flvtool2'
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def parse_result(result)
|
19
|
+
if result.empty?
|
20
|
+
return true
|
21
|
+
end
|
22
|
+
|
23
|
+
if m = /ERROR: No such file or directory(.*)\n/.match(result)
|
24
|
+
raise TranscoderError::InputFileNotFound, m[0]
|
25
|
+
end
|
26
|
+
|
27
|
+
if m = /ERROR: IO is not a FLV stream/.match(result)
|
28
|
+
raise TranscoderError::InvalidFile, "input must be a valid FLV file"
|
29
|
+
end
|
30
|
+
|
31
|
+
if m = /Copyright.*Norman Timmler/i.match(result)
|
32
|
+
raise TranscoderError::InvalidCommand, "command printed flvtool2 help text (and presumably didn't execute)"
|
33
|
+
end
|
34
|
+
|
35
|
+
if m = /ERROR: undefined method .?timestamp.? for nil/.match(result)
|
36
|
+
raise TranscoderError::InvalidFile, "Output file was empty (presumably)"
|
37
|
+
end
|
38
|
+
|
39
|
+
if m = /\A---(.*)...\Z/m.match(result)
|
40
|
+
@raw_metadata = m[0]
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
|
44
|
+
raise TranscoderError::UnexpectedResult, result
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module RVideo
|
2
|
+
module Tools
|
3
|
+
class Mencoder
|
4
|
+
include AbstractTool::InstanceMethods
|
5
|
+
|
6
|
+
attr_reader :frame, :size, :time, :bitrate, :video_size, :audio_size, :fps
|
7
|
+
|
8
|
+
def tool_command
|
9
|
+
'mencoder'
|
10
|
+
end
|
11
|
+
|
12
|
+
def original_fps
|
13
|
+
inspect_original if @original.nil?
|
14
|
+
if @original.fps
|
15
|
+
"-ofps #{@original.fps}"
|
16
|
+
else
|
17
|
+
""
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse_result(result)
|
22
|
+
if m = /Exiting.*No output file specified/.match(result)
|
23
|
+
raise TranscoderError::InvalidCommand, "no command passed to mencoder, or no output file specified"
|
24
|
+
end
|
25
|
+
|
26
|
+
if m = /Sorry, this file format is not recognized\/supported/.match(result)
|
27
|
+
raise TranscoderError::InvalidFile, "unknown format"
|
28
|
+
end
|
29
|
+
|
30
|
+
if m = /Cannot open file\/device./.match(result)
|
31
|
+
raise TranscoderError::InvalidFile, "I/O error"
|
32
|
+
end
|
33
|
+
|
34
|
+
if m = /File not found:$/.match(result)
|
35
|
+
raise TranscoderError::InvalidFile, "I/O error"
|
36
|
+
end
|
37
|
+
|
38
|
+
video_details = result.match /Video stream:(.*)$/
|
39
|
+
if video_details
|
40
|
+
@bitrate = sanitary_match(/Video stream:\s*([0-9.]*)/, video_details[0])
|
41
|
+
@video_size = sanitary_match(/size:\s*(\d*)\s*(\S*)/, video_details[0])
|
42
|
+
@time = sanitary_match(/bytes\s*([0-9.]*)/, video_details[0])
|
43
|
+
@frame = sanitary_match(/secs\s*(\d*)/, video_details[0])
|
44
|
+
@fps = (@frame.to_f / @time.to_f).round_to(3)
|
45
|
+
elsif result =~ /Video stream is mandatory/
|
46
|
+
raise TranscoderError::InvalidFile, "Video stream required, and no video stream found"
|
47
|
+
end
|
48
|
+
|
49
|
+
audio_details = result.match /Audio stream:(.*)$/
|
50
|
+
if audio_details
|
51
|
+
@audio_size = sanitary_match(/size:\s*(\d*)\s*(\S*)/, audio_details[0])
|
52
|
+
else
|
53
|
+
@audio_size = 0
|
54
|
+
end
|
55
|
+
@size = (@video_size.to_i + @audio_size.to_i).to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
def sanitary_match(regexp, string)
|
59
|
+
match = regexp.match(string)
|
60
|
+
return match[1] if match
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RVideo
|
2
|
+
module Tools
|
3
|
+
class Mp4box
|
4
|
+
include AbstractTool::InstanceMethods
|
5
|
+
attr_reader :raw_metadata
|
6
|
+
|
7
|
+
def tool_command
|
8
|
+
'MP4Box'
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def parse_result(result)
|
14
|
+
#currently, no useful info returned in result to determine if successful or not
|
15
|
+
@raw_metadata = result.empty? ? "No Results" : result
|
16
|
+
return true
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RVideo
|
2
|
+
module Tools
|
3
|
+
class Mp4creator
|
4
|
+
include AbstractTool::InstanceMethods
|
5
|
+
|
6
|
+
attr_reader :raw_metadata
|
7
|
+
|
8
|
+
def tool_command
|
9
|
+
'mp4creator'
|
10
|
+
end
|
11
|
+
|
12
|
+
def original_fps
|
13
|
+
inspect_original if @original.nil?
|
14
|
+
if @original.fps
|
15
|
+
"-rate=#{@original.fps}"
|
16
|
+
else
|
17
|
+
""
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse_result(result)
|
22
|
+
if m = /can't open file/.match(result)
|
23
|
+
raise TranscoderError::InvalidFile, "I/O error"
|
24
|
+
end
|
25
|
+
|
26
|
+
if m = /unknown file type/.match(result)
|
27
|
+
raise TranscoderError::InvalidFile, "I/O error"
|
28
|
+
end
|
29
|
+
|
30
|
+
@raw_metadata = result.empty? ? "No Results" : result
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RVideo
|
2
|
+
module Tools
|
3
|
+
class Mplayer
|
4
|
+
include AbstractTool::InstanceMethods
|
5
|
+
|
6
|
+
attr_reader :raw_metadata
|
7
|
+
|
8
|
+
def tool_command
|
9
|
+
'mplayer'
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse_result(result)
|
13
|
+
if m = /This will likely crash/.match(result)
|
14
|
+
raise TranscoderError::InvalidFile, "unknown format"
|
15
|
+
end
|
16
|
+
|
17
|
+
if m = /Failed to open/.match(result)
|
18
|
+
raise TranscoderError::InvalidFile, "I/O error"
|
19
|
+
end
|
20
|
+
|
21
|
+
if m = /File not found/.match(result)
|
22
|
+
raise TranscoderError::InvalidFile, "I/O error"
|
23
|
+
end
|
24
|
+
|
25
|
+
@raw_metadata = result.empty? ? "No Results" : result
|
26
|
+
return true
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module RVideo # :nodoc:
|
2
|
+
class Transcoder
|
3
|
+
|
4
|
+
attr_reader :executed_commands, :processed, :errors, :warnings, :total_time
|
5
|
+
|
6
|
+
#
|
7
|
+
# To transcode a video, initialize a Transcoder object:
|
8
|
+
#
|
9
|
+
# transcoder = RVideo::Transcoder.new("/path/to/input.mov")
|
10
|
+
#
|
11
|
+
# Then pass a recipe and valid options to the execute method
|
12
|
+
#
|
13
|
+
# recipe = "ffmpeg -i $input_file$ -ar 22050 -ab 64 -f flv -r 29.97 -s"
|
14
|
+
# recipe += " $resolution$ -y $output_file$"
|
15
|
+
# recipe += "\nflvtool2 -U $output_file$"
|
16
|
+
# begin
|
17
|
+
# transcoder.execute(recipe, {:output_file => "/path/to/output.flv",
|
18
|
+
# :resolution => "640x360"})
|
19
|
+
# rescue TranscoderError => e
|
20
|
+
# puts "Unable to transcode file: #{e.class} - #{e.message}"
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# If the job succeeds, you can access the metadata of the input and output
|
24
|
+
# files with:
|
25
|
+
#
|
26
|
+
# transcoder.original # RVideo::Inspector object
|
27
|
+
# transcoder.processed # RVideo::Inspector object
|
28
|
+
#
|
29
|
+
# If the transcoding succeeds, the file may still have problems. RVideo
|
30
|
+
# will populate an errors array if the duration of the processed video
|
31
|
+
# differs from the duration of the original video, or if the processed
|
32
|
+
# file is unreadable.
|
33
|
+
#
|
34
|
+
|
35
|
+
def initialize(input_file = nil)
|
36
|
+
# Allow a nil input_file for backwards compatibility. (Change at 1.0?)
|
37
|
+
check_input_file(input_file)
|
38
|
+
|
39
|
+
@input_file = input_file
|
40
|
+
@executed_commands = []
|
41
|
+
@errors = []
|
42
|
+
@warnings = []
|
43
|
+
end
|
44
|
+
|
45
|
+
def original
|
46
|
+
@original ||= Inspector.new(:file => @input_file)
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Configure logging. Pass a valid Ruby logger object.
|
51
|
+
#
|
52
|
+
# logger = Logger.new(STDOUT)
|
53
|
+
# RVideo::Transcoder.logger = logger
|
54
|
+
#
|
55
|
+
|
56
|
+
def self.logger=(l)
|
57
|
+
@logger = l
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.logger
|
61
|
+
if @logger.nil?
|
62
|
+
@logger = Logger.new('/dev/null')
|
63
|
+
end
|
64
|
+
|
65
|
+
@logger
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Requires a command and a hash of various interpolated options. The
|
70
|
+
# command should be one or more lines of transcoder tool commands (e.g.
|
71
|
+
# ffmpeg, flvtool2). Interpolate options by adding $option_key$ to the
|
72
|
+
# recipe, and passing :option_key => "value" in the options hash.
|
73
|
+
#
|
74
|
+
# recipe = "ffmpeg -i $input_file$ -ar 22050 -ab 64 -f flv -r 29.97
|
75
|
+
# recipe += "-s $resolution$ -y $output_file$"
|
76
|
+
# recipe += "\nflvtool2 -U $output_file$"
|
77
|
+
#
|
78
|
+
# transcoder = RVideo::Transcoder.new("/path/to/input.mov")
|
79
|
+
# begin
|
80
|
+
# transcoder.execute(recipe, {:output_file => "/path/to/output.flv", :resolution => "320x240"})
|
81
|
+
# rescue TranscoderError => e
|
82
|
+
# puts "Unable to transcode file: #{e.class} - #{e.message}"
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
|
86
|
+
def execute(task, options = {})
|
87
|
+
t1 = Time.now
|
88
|
+
|
89
|
+
if @input_file.nil?
|
90
|
+
@input_file = options[:input_file]
|
91
|
+
end
|
92
|
+
|
93
|
+
Transcoder.logger.info("\nNew transcoder job\n================\nTask: #{task}\nOptions: #{options.inspect}")
|
94
|
+
parse_and_execute(task, options)
|
95
|
+
@processed = Inspector.new(:file => options[:output_file])
|
96
|
+
result = check_integrity
|
97
|
+
Transcoder.logger.info("\nFinished task. Total errors: #{@errors.size}\n")
|
98
|
+
@total_time = Time.now - t1
|
99
|
+
result
|
100
|
+
rescue TranscoderError => e
|
101
|
+
raise e
|
102
|
+
rescue Exception => e
|
103
|
+
Transcoder.logger.error("[ERROR] Unhandled RVideo exception: #{e.class} - #{e.message}\n#{e.backtrace}")
|
104
|
+
raise TranscoderError::UnknownError, "Unexpected RVideo error: #{e.message} (#{e.class})"
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def check_input_file(input_file)
|
110
|
+
if input_file and !FileTest.exist?(input_file.gsub("\"",""))
|
111
|
+
raise TranscoderError::InputFileNotFound, "File not found (#{input_file})"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def check_integrity
|
116
|
+
precision = 1.1
|
117
|
+
if @processed.invalid?
|
118
|
+
@errors << "Output file invalid"
|
119
|
+
elsif (@processed.duration >= (original.duration * precision) or @processed.duration <= (original.duration / precision))
|
120
|
+
@errors << "Original file has a duration of #{original.duration}, but processed file has a duration of #{@processed.duration}"
|
121
|
+
end
|
122
|
+
return @errors.size == 0
|
123
|
+
end
|
124
|
+
|
125
|
+
def parse_and_execute(task, options = {})
|
126
|
+
raise TranscoderError::ParameterError, "Expected a recipe class (as a string), but got a #{task.class.to_s} (#{task})" unless task.is_a? String
|
127
|
+
options = options.merge(:input_file => @input_file)
|
128
|
+
|
129
|
+
commands = task.split("\n").compact
|
130
|
+
commands.each do |c|
|
131
|
+
tool = Tools::AbstractTool.assign(c, options)
|
132
|
+
tool.original = @original
|
133
|
+
tool.execute
|
134
|
+
executed_commands << tool
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/lib/rvideo.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/rvideo'
|
2
|
+
|
3
|
+
require 'inspector'
|
4
|
+
require 'float'
|
5
|
+
require 'tools/abstract_tool'
|
6
|
+
require 'tools/ffmpeg'
|
7
|
+
require 'tools/mencoder'
|
8
|
+
require 'tools/flvtool2'
|
9
|
+
require 'tools/mp4box'
|
10
|
+
require 'tools/mplayer'
|
11
|
+
require 'tools/mp4creator'
|
12
|
+
require 'errors'
|
13
|
+
require 'transcoder'
|
14
|
+
require 'active_support'
|
15
|
+
|
16
|
+
TEMP_PATH = File.expand_path(File.dirname(__FILE__) + '/../tmp')
|
17
|
+
FIXTURE_PATH = File.expand_path(File.dirname(__FILE__) + '/../spec/fixtures')
|
18
|
+
TEST_FILE_PATH = File.expand_path(File.dirname(__FILE__) + '/../spec/files')
|
19
|
+
REPORT_PATH = File.expand_path(File.dirname(__FILE__) + '/../report')
|
20
|
+
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mhs-rvideo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jonathan Dahl (Slantwise Design)
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-27 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Inspect and process video or audio files.
|
17
|
+
email: jon@slantwisedesign.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- History.txt
|
24
|
+
- License.txt
|
25
|
+
- README.txt
|
26
|
+
files:
|
27
|
+
- History.txt
|
28
|
+
- License.txt
|
29
|
+
- README.txt
|
30
|
+
- RULES
|
31
|
+
- Rakefile
|
32
|
+
- lib/rvideo.rb
|
33
|
+
- lib/rvideo/errors.rb
|
34
|
+
- lib/rvideo/float.rb
|
35
|
+
- lib/rvideo/inspector.rb
|
36
|
+
- lib/rvideo/tools/abstract_tool.rb
|
37
|
+
- lib/rvideo/tools/ffmpeg.rb
|
38
|
+
- lib/rvideo/tools/flvtool2.rb
|
39
|
+
- lib/rvideo/tools/mencoder.rb
|
40
|
+
- lib/rvideo/tools/mp4box.rb
|
41
|
+
- lib/rvideo/tools/mp4creator.rb
|
42
|
+
- lib/rvideo/tools/mplayer.rb
|
43
|
+
- lib/rvideo/transcoder.rb
|
44
|
+
- lib/rvideo/version.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/mhs/rvideo
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options:
|
51
|
+
- --main
|
52
|
+
- README.txt
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project: rvideo
|
70
|
+
rubygems_version: 1.3.5
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Inspect and process video or audio files.
|
74
|
+
test_files: []
|
75
|
+
|