vcs_ruby 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/vcs.rb +4 -4
- data/lib/FFmpeg/ffmpeg.rb +141 -0
- data/lib/FFmpeg/ffmpeg_audio_stream.rb +38 -0
- data/lib/FFmpeg/ffmpeg_meta_info.rb +37 -0
- data/lib/FFmpeg/ffmpeg_video_stream.rb +52 -0
- data/lib/{mplayer.rb → MPlayer/mplayer.rb} +48 -63
- data/lib/MPlayer/mplayer_audio_stream.rb +35 -0
- data/lib/MPlayer/mplayer_meta_info.rb +40 -0
- data/lib/MPlayer/mplayer_video_stream.rb +44 -0
- data/lib/capturer.rb +17 -21
- data/lib/command.rb +4 -2
- data/lib/configuration.rb +18 -7
- data/lib/contact_sheet.rb +106 -127
- data/lib/defaults.yml +4 -4
- data/lib/font.rb +12 -12
- data/lib/{thumbnail.rb → frame.rb} +45 -24
- data/lib/libAV/libav.rb +143 -0
- data/lib/libAV/libav_audio_stream.rb +38 -0
- data/lib/libAV/libav_meta_info.rb +37 -0
- data/lib/libAV/libav_video_stream.rb +52 -0
- data/lib/stream.rb +24 -0
- data/lib/tools.rb +13 -20
- data/lib/vcs.rb +16 -4
- data/lib/version.info +1 -1
- data/lib/version.rb +2 -2
- data/lib/video.rb +89 -0
- metadata +37 -8
- data/lib/ffmpeg.rb +0 -183
- data/lib/libav.rb +0 -181
data/bin/vcs.rb
CHANGED
@@ -74,12 +74,12 @@ optparse = OptionParser.new do|opts|
|
|
74
74
|
opts.on('-C [CAPTURER]', '--capture [CAPTURER]', arguments['--capturer'], 'Capturer: ' + Tools::list_arguments(arguments["--capturer"])) do |capturer|
|
75
75
|
options[:capturer] = capturer
|
76
76
|
end
|
77
|
-
opts.on( '-T [TITLE]', '--title [TITLE]', 'Set
|
77
|
+
opts.on( '-T [TITLE]', '--title [TITLE]', 'Set Title') do |title|
|
78
78
|
options[:title] = title
|
79
79
|
end
|
80
80
|
opts.on( '-o [FILE]', '--output [FILE]', 'File name of output. When ommited will be derived from the input filename. Can be repeated for multiple files.') do |file|
|
81
81
|
options[:output] << file
|
82
|
-
end
|
82
|
+
end
|
83
83
|
opts.on( '-s [SIGNATURE]', '--signature [SIGNATURE]', 'Change the image signature to your preference.') do |signature|
|
84
84
|
options[:signature] = signature
|
85
85
|
end
|
@@ -141,8 +141,8 @@ optparse.parse!
|
|
141
141
|
|
142
142
|
Tools::print_help optparse if options[:help] || ARGV.empty?
|
143
143
|
|
144
|
-
|
145
|
-
|
144
|
+
Configuration.instance.verbose = options[:verbose]
|
145
|
+
Configuration.instance.quiet = options[:quiet]
|
146
146
|
|
147
147
|
# Invoke ContactSheet
|
148
148
|
|
@@ -0,0 +1,141 @@
|
|
1
|
+
#
|
2
|
+
# FFmpeg Abstraction
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'capturer'
|
6
|
+
require 'command'
|
7
|
+
|
8
|
+
module VCSRuby
|
9
|
+
class FFmpeg < Capturer
|
10
|
+
|
11
|
+
HEADER = 10
|
12
|
+
ENCODING_SUPPORT = 2
|
13
|
+
VIDEO_CODEC = 3
|
14
|
+
NAME = 8
|
15
|
+
|
16
|
+
attr_reader :info, :video_streams, :audio_streams
|
17
|
+
|
18
|
+
def initialize video
|
19
|
+
@video = video
|
20
|
+
@ffmpeg = Command.new :ffmpeg, 'ffmpeg'
|
21
|
+
@ffprobe = Command.new :ffmpeg, 'ffprobe'
|
22
|
+
|
23
|
+
detect_version if available?
|
24
|
+
end
|
25
|
+
|
26
|
+
def file_valid?
|
27
|
+
return probe_meta_information
|
28
|
+
end
|
29
|
+
|
30
|
+
def name
|
31
|
+
:ffmpeg
|
32
|
+
end
|
33
|
+
|
34
|
+
def available?
|
35
|
+
@ffmpeg.available? && !libav?
|
36
|
+
end
|
37
|
+
|
38
|
+
def libav?
|
39
|
+
@libav
|
40
|
+
end
|
41
|
+
|
42
|
+
def detect_version
|
43
|
+
info = @ffmpeg.execute('-version')
|
44
|
+
match = /avconv ([\d|.|-|:]*)/.match(info)
|
45
|
+
@libav = !!match
|
46
|
+
match = /ffmpeg version ([\d|.]*)/.match(info)
|
47
|
+
if match
|
48
|
+
@version = match[1]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def grab time, image_path
|
53
|
+
@ffmpeg.execute "-y -ss #{time.total_seconds} -i \"#{@video.full_path}\" -an -dframes 1 -vframes 1 -vcodec #{format} -f rawvideo \"#{image_path}\""
|
54
|
+
end
|
55
|
+
|
56
|
+
def available_formats
|
57
|
+
# Ordered by priority
|
58
|
+
image_formats = ['png', 'tiff', 'bmp', 'mjpeg']
|
59
|
+
formats = []
|
60
|
+
|
61
|
+
list = @ffprobe.execute "-codecs"
|
62
|
+
list.lines.drop(HEADER).each do |codec|
|
63
|
+
name, e, v = format_split(codec)
|
64
|
+
formats << name if image_formats.include?(name) && e && v
|
65
|
+
end
|
66
|
+
|
67
|
+
image_formats.select{ |format| formats.include?(format) }.map(&:to_sym)
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
"FFmpeg #{@version}"
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def format_split line
|
76
|
+
e = line[ENCODING_SUPPORT] == 'E'
|
77
|
+
v = line[VIDEO_CODEC] == 'V'
|
78
|
+
|
79
|
+
name = line[NAME..-1].split(' ', 2).first
|
80
|
+
return name, e, v
|
81
|
+
rescue
|
82
|
+
return nil, false, false
|
83
|
+
end
|
84
|
+
|
85
|
+
def probe_meta_information
|
86
|
+
check_cache
|
87
|
+
parse_meta_info
|
88
|
+
return true
|
89
|
+
rescue Exception => e
|
90
|
+
puts e
|
91
|
+
return false
|
92
|
+
end
|
93
|
+
|
94
|
+
def check_cache
|
95
|
+
unless @cache
|
96
|
+
@cache = @ffprobe.execute("\"#{@video.full_path}\" -show_format -show_streams", "2>&1")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_hash defines
|
101
|
+
result = {}
|
102
|
+
defines.lines.each do |line|
|
103
|
+
kv = line.split("=")
|
104
|
+
result[kv[0].strip] = kv[1].strip if kv.count == 2
|
105
|
+
end
|
106
|
+
result
|
107
|
+
end
|
108
|
+
|
109
|
+
def parse_meta_info
|
110
|
+
parse_format
|
111
|
+
parse_audio_streams
|
112
|
+
parse_video_streams
|
113
|
+
end
|
114
|
+
|
115
|
+
def parse_format
|
116
|
+
@cache.scan(/\[FORMAT\](.*?)\[\/FORMAT\]/m) do |format|
|
117
|
+
@info = FFmpegMetaInfo.new(get_hash(format[0]))
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def parse_audio_streams
|
122
|
+
@audio_streams = []
|
123
|
+
@cache.scan(/\[STREAM\](.*?)\[\/STREAM\]/m) do |stream|
|
124
|
+
info = get_hash(stream[0])
|
125
|
+
if info['codec_type'] == 'audio'
|
126
|
+
@audio_streams << FFmpegAudioStream.new(info)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def parse_video_streams
|
132
|
+
@video_streams = []
|
133
|
+
@cache.scan(/\[STREAM\](.*?)\[\/STREAM\]/m) do |stream|
|
134
|
+
info = get_hash(stream[0])
|
135
|
+
if info['codec_type'] == 'video'
|
136
|
+
@video_streams << FFmpegVideoStream.new(info)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#
|
2
|
+
# Implementes AudioStream Interface for FFmpeg
|
3
|
+
#
|
4
|
+
|
5
|
+
# AudioStream = Struct.new(:codec, :channels, :channel_layout, :sample_rate, :bit_rate, :raw)
|
6
|
+
module VCSRuby
|
7
|
+
class FFmpegAudioStream
|
8
|
+
attr_reader :raw
|
9
|
+
|
10
|
+
def initialize audio_stream
|
11
|
+
@raw = audio_stream
|
12
|
+
end
|
13
|
+
|
14
|
+
def codec short = false
|
15
|
+
if short
|
16
|
+
@raw['codec_name']
|
17
|
+
else
|
18
|
+
@raw['codec_long_name']
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def channels
|
23
|
+
@raw['channels'].to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
def channel_layout
|
27
|
+
@raw['channel_layout']
|
28
|
+
end
|
29
|
+
|
30
|
+
def sample_rate
|
31
|
+
@raw['sample_rate'].to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
def bit_rate
|
35
|
+
@raw['bit_rate'].to_i
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#
|
2
|
+
# Implementes MetaInfo Interface for FFmpeg
|
3
|
+
#
|
4
|
+
|
5
|
+
# MetaInformation = Struct.new(:duration, :bit_rate, :size, :format, :extension, :raw)
|
6
|
+
|
7
|
+
require_relative '../time_index'
|
8
|
+
|
9
|
+
module VCSRuby
|
10
|
+
class FFmpegMetaInfo
|
11
|
+
attr_reader :raw
|
12
|
+
|
13
|
+
def initialize meta_info
|
14
|
+
@raw = meta_info
|
15
|
+
end
|
16
|
+
|
17
|
+
def duration
|
18
|
+
TimeIndex.new(@raw['duration'].to_f)
|
19
|
+
end
|
20
|
+
|
21
|
+
def bit_rate
|
22
|
+
@raw['bit_rate'].to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
def size
|
26
|
+
@raw['size'].to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def format
|
30
|
+
@raw['format_long_name']
|
31
|
+
end
|
32
|
+
|
33
|
+
def extension
|
34
|
+
@raw['format_name']
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#
|
2
|
+
# Implementes VideoStream Interface for FFmpeg
|
3
|
+
#
|
4
|
+
|
5
|
+
# VideoStream = Struct.new(:width, :height, :codec, :color_space, :bit_rate, :frame_rate, :aspect_ratio, :raw)
|
6
|
+
|
7
|
+
module VCSRuby
|
8
|
+
class FFmpegVideoStream
|
9
|
+
attr_reader :raw
|
10
|
+
|
11
|
+
def initialize video_stream
|
12
|
+
@raw = video_stream
|
13
|
+
end
|
14
|
+
|
15
|
+
def width
|
16
|
+
@raw['width'].to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
def height
|
20
|
+
@raw['height'].to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
def codec short = false
|
24
|
+
if short
|
25
|
+
@raw['codec_name']
|
26
|
+
else
|
27
|
+
@raw['codec_long_name']
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def color_space
|
32
|
+
if ["unknown", "", nil].include? @raw['color_space']
|
33
|
+
@raw['pix_fmt']
|
34
|
+
else
|
35
|
+
@raw['color_space']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def bit_rate
|
40
|
+
@raw['bit_rate'].to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def frame_rate
|
45
|
+
Rational(@raw['r_frame_rate'])
|
46
|
+
end
|
47
|
+
|
48
|
+
def aspect_ratio
|
49
|
+
@raw['display_aspect_ratio']
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -2,15 +2,15 @@
|
|
2
2
|
# MPlayer Abstraction
|
3
3
|
#
|
4
4
|
|
5
|
-
require 'command'
|
6
5
|
require 'capturer'
|
7
|
-
require '
|
6
|
+
require 'command'
|
8
7
|
|
9
8
|
module VCSRuby
|
10
9
|
class MPlayer < Capturer
|
11
10
|
|
12
11
|
HEADER = 2
|
13
12
|
|
13
|
+
attr_reader :info, :video_streams, :audio_streams
|
14
14
|
def initialize video
|
15
15
|
@video = video
|
16
16
|
@mplayer = Command.new :mplayer, 'mplayer'
|
@@ -18,6 +18,10 @@ module VCSRuby
|
|
18
18
|
detect_version if available?
|
19
19
|
end
|
20
20
|
|
21
|
+
def file_valid?
|
22
|
+
return probe_meta_information
|
23
|
+
end
|
24
|
+
|
21
25
|
def name
|
22
26
|
:mplayer
|
23
27
|
end
|
@@ -25,55 +29,16 @@ module VCSRuby
|
|
25
29
|
def available?
|
26
30
|
@mplayer.available?
|
27
31
|
end
|
28
|
-
|
32
|
+
|
29
33
|
def detect_version
|
30
34
|
info = @mplayer.execute('')
|
31
35
|
match = /MPlayer (.*),/.match(info)
|
32
36
|
@version = match[1] if match
|
33
37
|
end
|
34
38
|
|
35
|
-
def length
|
36
|
-
load_probe
|
37
|
-
@length
|
38
|
-
end
|
39
|
-
|
40
|
-
def width
|
41
|
-
load_probe
|
42
|
-
@width
|
43
|
-
end
|
44
|
-
|
45
|
-
def height
|
46
|
-
load_probe
|
47
|
-
@height
|
48
|
-
end
|
49
|
-
|
50
|
-
def video_codec
|
51
|
-
load_probe
|
52
|
-
@video_codec
|
53
|
-
end
|
54
|
-
|
55
|
-
def audio_codec
|
56
|
-
load_probe
|
57
|
-
@audio_codec
|
58
|
-
end
|
59
|
-
|
60
|
-
def fps
|
61
|
-
load_probe
|
62
|
-
@fps
|
63
|
-
end
|
64
|
-
|
65
|
-
def file_pattern n
|
66
|
-
if format == :jpeg
|
67
|
-
"#{"%08d" % n}.jpg"
|
68
|
-
else
|
69
|
-
"#{"%08d" % n}.#{format.to_s}"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
39
|
def grab time, image_path
|
74
|
-
@mplayer.execute "-
|
75
|
-
|
76
|
-
FileUtils.mv(file_pattern(5), image_path)
|
40
|
+
@mplayer.execute "-vo png -ss #{time.total_seconds} -endpos 0 \"#{@video.full_path}\""
|
41
|
+
FileUtils.mv(file_pattern(1), image_path)
|
77
42
|
end
|
78
43
|
|
79
44
|
def available_formats
|
@@ -90,35 +55,55 @@ module VCSRuby
|
|
90
55
|
image_formats.select{ |format| formats.include?(format) }.map(&:to_sym)
|
91
56
|
end
|
92
57
|
|
93
|
-
def format_split line
|
94
|
-
name = line.strip.split(' ', 2).first
|
95
|
-
end
|
96
|
-
|
97
58
|
def to_s
|
98
59
|
"MPlayer #{@version}"
|
99
60
|
end
|
61
|
+
|
100
62
|
private
|
101
|
-
def
|
102
|
-
|
63
|
+
def format_split line
|
64
|
+
name = line.strip.split(' ', 2).first
|
65
|
+
end
|
66
|
+
def probe_meta_information
|
67
|
+
check_cache
|
68
|
+
parse_meta_info
|
69
|
+
return true
|
70
|
+
rescue Exception => e
|
71
|
+
puts e
|
72
|
+
return false
|
103
73
|
end
|
104
74
|
|
105
|
-
def
|
106
|
-
unless
|
107
|
-
|
75
|
+
def check_cache
|
76
|
+
unless @cache
|
77
|
+
@cache = @mplayer.execute("-ao null -vo null -identify -frames 0 -really-quiet \"#{@video.full_path}\"")
|
108
78
|
end
|
109
79
|
end
|
110
80
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
81
|
+
def get_hash defines
|
82
|
+
result = {}
|
83
|
+
defines.lines.each do |line|
|
84
|
+
kv = line.split("=")
|
85
|
+
result[kv[0].strip] = kv[1].strip if kv.count == 2
|
86
|
+
end
|
87
|
+
result
|
88
|
+
end
|
89
|
+
|
90
|
+
def parse_meta_info
|
91
|
+
mplayer_hash = get_hash(@cache)
|
92
|
+
@info = MPlayerMetaInfo.new(mplayer_hash, File.size(@video.full_path))
|
93
|
+
|
94
|
+
# Todo: Handling of multiple streams
|
95
|
+
@video_streams = []
|
96
|
+
@video_streams << MPlayerVideoStream.new(mplayer_hash)
|
97
|
+
@audio_streams = []
|
98
|
+
@audio_streams << MPlayerAudioStream.new(mplayer_hash)
|
99
|
+
end
|
100
|
+
|
101
|
+
def file_pattern n
|
102
|
+
if format == :jpeg
|
103
|
+
"#{"%08d" % n}.jpg"
|
104
|
+
else
|
105
|
+
"#{"%08d" % n}.#{format.to_s}"
|
120
106
|
end
|
121
|
-
@parsed = true
|
122
107
|
end
|
123
108
|
end
|
124
109
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#
|
2
|
+
# Implementes AudioStream Interface for MPlayer
|
3
|
+
#
|
4
|
+
|
5
|
+
# AudioStream = Struct.new(:codec, :channels, :channel_layout, :sample_rate, :bit_rate, :raw)
|
6
|
+
module VCSRuby
|
7
|
+
class MPlayerAudioStream
|
8
|
+
attr_reader :raw
|
9
|
+
|
10
|
+
def initialize audio_stream
|
11
|
+
@raw = audio_stream
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def codec short = false
|
16
|
+
@raw['ID_AUDIO_CODEC']
|
17
|
+
end
|
18
|
+
|
19
|
+
def channels
|
20
|
+
@raw['ID_AUDIO_NCH'].to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
def channel_layout
|
24
|
+
''
|
25
|
+
end
|
26
|
+
|
27
|
+
def sample_rate
|
28
|
+
@raw['ID_AUDIO_RATE'].to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
def bit_rate
|
32
|
+
@raw['ID_AUDIO_BITRATE'].to_i
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#
|
2
|
+
# Implementes MetaInfo Interface for MPlayer
|
3
|
+
#
|
4
|
+
|
5
|
+
# MetaInformation = Struct.new(:duration, :bit_rate, :size, :format, :extension, :raw)
|
6
|
+
|
7
|
+
require_relative '../time_index'
|
8
|
+
|
9
|
+
module VCSRuby
|
10
|
+
class MPlayerMetaInfo
|
11
|
+
attr_reader :raw
|
12
|
+
|
13
|
+
def initialize meta_info, filesize
|
14
|
+
@raw = meta_info
|
15
|
+
@filesize = filesize
|
16
|
+
end
|
17
|
+
|
18
|
+
def duration
|
19
|
+
TimeIndex.new(@raw['ID_LENGTH'].to_f)
|
20
|
+
end
|
21
|
+
|
22
|
+
def bit_rate
|
23
|
+
@raw['ID_AUDIO_BITRATE'].to_i + @raw['ID_VIDEO_BITRATE'].to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
def size
|
27
|
+
@filesize
|
28
|
+
end
|
29
|
+
|
30
|
+
def format
|
31
|
+
extension
|
32
|
+
end
|
33
|
+
|
34
|
+
def extension
|
35
|
+
ext = File.extname(@raw['ID_FILENAME'])
|
36
|
+
ext[0] = ''
|
37
|
+
ext
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#
|
2
|
+
# Implementes VideoStream Interface for MPlayer
|
3
|
+
#
|
4
|
+
|
5
|
+
# VideoStream = Struct.new(:width, :height, :codec, :color_space, :bit_rate, :frame_rate, :aspect_ratio, :raw)
|
6
|
+
|
7
|
+
module VCSRuby
|
8
|
+
class MPlayerVideoStream
|
9
|
+
attr_reader :raw
|
10
|
+
|
11
|
+
def initialize video_stream
|
12
|
+
@raw = video_stream
|
13
|
+
end
|
14
|
+
|
15
|
+
def width
|
16
|
+
@raw['ID_VIDEO_WIDTH'].to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
def height
|
20
|
+
@raw['ID_VIDEO_HEIGHT'].to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
def codec short = false
|
24
|
+
@raw['ID_VIDEO_FORMAT']
|
25
|
+
end
|
26
|
+
|
27
|
+
def color_space
|
28
|
+
''
|
29
|
+
end
|
30
|
+
|
31
|
+
def bit_rate
|
32
|
+
@raw['ID_VIDEO_BITRATE'].to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def frame_rate
|
37
|
+
@raw['ID_VIDEO_FPS'].to_f
|
38
|
+
end
|
39
|
+
|
40
|
+
def aspect_ratio
|
41
|
+
''
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/capturer.rb
CHANGED
@@ -2,42 +2,38 @@
|
|
2
2
|
# Capturer Baseclass
|
3
3
|
#
|
4
4
|
|
5
|
+
require 'vcs'
|
6
|
+
|
5
7
|
module VCSRuby
|
6
8
|
class Capturer
|
9
|
+
$formats = { :png => 'png', :bmp => 'bmp', :tiff => 'tif', :mjpeg => 'jpg', :jpeg => 'jpg', :jpg => 'jpg' }
|
10
|
+
|
7
11
|
def available?
|
8
12
|
false
|
9
13
|
end
|
10
14
|
|
11
|
-
def
|
12
|
-
|
13
|
-
end
|
15
|
+
def self.initialize_capturers video
|
16
|
+
capturers = []
|
14
17
|
|
15
|
-
|
16
|
-
raise "NotImplementedException"
|
18
|
+
puts "Available capturers: #{available_capturers.map{ |c| c.to_s }.join(', ')}" if Tools.verbose?
|
17
19
|
end
|
18
20
|
|
19
|
-
def
|
20
|
-
|
21
|
-
end
|
21
|
+
def self.create
|
22
|
+
capturers = []
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
capturers << LibAV.new(video)
|
25
|
+
capturers << MPlayer.new(video)
|
26
|
+
capturers << FFmpeg.new(video)
|
26
27
|
|
27
|
-
|
28
|
-
raise "NotImplementedException"
|
28
|
+
return capturers.first
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def available_formats
|
36
|
-
raise "NotImplementedException"
|
31
|
+
def format
|
32
|
+
@format || available_formats.first
|
37
33
|
end
|
38
34
|
|
39
|
-
def
|
40
|
-
|
35
|
+
def format_extension
|
36
|
+
$formats[format]
|
41
37
|
end
|
42
38
|
|
43
39
|
def format= format
|
data/lib/command.rb
CHANGED
@@ -17,7 +17,7 @@ module VCSRuby
|
|
17
17
|
|
18
18
|
def execute parameter, streams = 0, no_error = false
|
19
19
|
raise "Command '#{name}' not available" unless available?
|
20
|
-
puts "#{@command} #{parameter}
|
20
|
+
puts "#{@command} #{parameter}" if Configuration.instance.verbose?
|
21
21
|
result = nil
|
22
22
|
if Tools::windows?
|
23
23
|
streams = '2> nul' if streams === 0
|
@@ -40,7 +40,9 @@ private
|
|
40
40
|
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
41
41
|
exts.each do |ext|
|
42
42
|
exe = File.join(path, "#{cmd}#{ext}")
|
43
|
-
|
43
|
+
if File.executable?(exe) && !File.directory?(exe)
|
44
|
+
return exe
|
45
|
+
end
|
44
46
|
end
|
45
47
|
end
|
46
48
|
return nil
|