vcs_ruby 1.0.1 → 1.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.
- 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
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vcs_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,13 +9,16 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-10-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mini_magick
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '4.0'
|
19
22
|
- - ! '>='
|
20
23
|
- !ruby/object:Gem::Version
|
21
24
|
version: 4.0.0
|
@@ -24,6 +27,9 @@ dependencies:
|
|
24
27
|
version_requirements: !ruby/object:Gem::Requirement
|
25
28
|
none: false
|
26
29
|
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '4.0'
|
27
33
|
- - ! '>='
|
28
34
|
- !ruby/object:Gem::Version
|
29
35
|
version: 4.0.0
|
@@ -32,6 +38,9 @@ dependencies:
|
|
32
38
|
requirement: !ruby/object:Gem::Requirement
|
33
39
|
none: false
|
34
40
|
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.5'
|
35
44
|
- - ! '>='
|
36
45
|
- !ruby/object:Gem::Version
|
37
46
|
version: 1.5.0
|
@@ -40,6 +49,9 @@ dependencies:
|
|
40
49
|
version_requirements: !ruby/object:Gem::Requirement
|
41
50
|
none: false
|
42
51
|
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.5'
|
43
55
|
- - ! '>='
|
44
56
|
- !ruby/object:Gem::Version
|
45
57
|
version: 1.5.0
|
@@ -48,17 +60,23 @@ dependencies:
|
|
48
60
|
requirement: !ruby/object:Gem::Requirement
|
49
61
|
none: false
|
50
62
|
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '11.0'
|
51
66
|
- - ! '>='
|
52
67
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
68
|
+
version: 11.0.0
|
54
69
|
type: :development
|
55
70
|
prerelease: false
|
56
71
|
version_requirements: !ruby/object:Gem::Requirement
|
57
72
|
none: false
|
58
73
|
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '11.0'
|
59
77
|
- - ! '>='
|
60
78
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
79
|
+
version: 11.0.0
|
62
80
|
description: Creates a contact sheet, a preview, of a video, usable as library or
|
63
81
|
as a script. Based on VCS *NIX. Creating Thumbnails with libav, ffmpeg or mplayer
|
64
82
|
and compose it with ImageMagick into nice looking sheets.
|
@@ -68,17 +86,28 @@ executables:
|
|
68
86
|
extensions: []
|
69
87
|
extra_rdoc_files: []
|
70
88
|
files:
|
89
|
+
- lib/frame.rb
|
90
|
+
- lib/video.rb
|
91
|
+
- lib/MPlayer/mplayer_video_stream.rb
|
92
|
+
- lib/MPlayer/mplayer.rb
|
93
|
+
- lib/MPlayer/mplayer_audio_stream.rb
|
94
|
+
- lib/MPlayer/mplayer_meta_info.rb
|
95
|
+
- lib/libAV/libav_audio_stream.rb
|
96
|
+
- lib/libAV/libav_meta_info.rb
|
97
|
+
- lib/libAV/libav_video_stream.rb
|
98
|
+
- lib/libAV/libav.rb
|
71
99
|
- lib/time_index.rb
|
72
100
|
- lib/font.rb
|
101
|
+
- lib/stream.rb
|
73
102
|
- lib/tools.rb
|
74
|
-
- lib/mplayer.rb
|
75
|
-
- lib/thumbnail.rb
|
76
103
|
- lib/contact_sheet.rb
|
77
|
-
- lib/ffmpeg.rb
|
78
104
|
- lib/version.rb
|
79
|
-
- lib/libav.rb
|
80
105
|
- lib/white.yml
|
81
106
|
- lib/capturer.rb
|
107
|
+
- lib/FFmpeg/ffmpeg_meta_info.rb
|
108
|
+
- lib/FFmpeg/ffmpeg_video_stream.rb
|
109
|
+
- lib/FFmpeg/ffmpeg.rb
|
110
|
+
- lib/FFmpeg/ffmpeg_audio_stream.rb
|
82
111
|
- lib/version.info
|
83
112
|
- lib/vcs.rb
|
84
113
|
- lib/command.rb
|
data/lib/ffmpeg.rb
DELETED
@@ -1,183 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# FFmpeg Abstraction
|
3
|
-
#
|
4
|
-
|
5
|
-
require 'capturer'
|
6
|
-
require 'command'
|
7
|
-
require 'time_index'
|
8
|
-
|
9
|
-
module VCSRuby
|
10
|
-
class FFmpeg < Capturer
|
11
|
-
|
12
|
-
CODEC = 3
|
13
|
-
DIMENSION = 5
|
14
|
-
FPS = 7
|
15
|
-
|
16
|
-
HEADER = 10
|
17
|
-
|
18
|
-
ENCODING_SUPPORT = 2
|
19
|
-
VIDEO_CODEC = 3
|
20
|
-
NAME = 8
|
21
|
-
|
22
|
-
def initialize video
|
23
|
-
@video = video
|
24
|
-
@ffmpeg = Command.new :ffmpeg, 'ffmpeg'
|
25
|
-
@ffprobe = Command.new :ffmpeg, 'ffprobe'
|
26
|
-
|
27
|
-
detect_version if available?
|
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 = true if match
|
46
|
-
match = /ffmpeg version ([\d|.]*)/.match(info)
|
47
|
-
if match
|
48
|
-
@version = match[1]
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def length
|
53
|
-
load_probe
|
54
|
-
match = /Duration: ([\d|:|.]*)/.match(@cache)
|
55
|
-
return TimeIndex.new match[1]
|
56
|
-
end
|
57
|
-
|
58
|
-
def width
|
59
|
-
load_probe
|
60
|
-
@width
|
61
|
-
end
|
62
|
-
|
63
|
-
def height
|
64
|
-
load_probe
|
65
|
-
@height
|
66
|
-
end
|
67
|
-
|
68
|
-
def par
|
69
|
-
load_probe
|
70
|
-
@par
|
71
|
-
end
|
72
|
-
|
73
|
-
def dar
|
74
|
-
load_probe
|
75
|
-
@dar
|
76
|
-
end
|
77
|
-
|
78
|
-
def fps
|
79
|
-
load_probe
|
80
|
-
@fps
|
81
|
-
end
|
82
|
-
|
83
|
-
def video_codec
|
84
|
-
load_probe
|
85
|
-
|
86
|
-
@video_codec
|
87
|
-
end
|
88
|
-
|
89
|
-
def audio_codec
|
90
|
-
load_probe
|
91
|
-
|
92
|
-
@audio_codec
|
93
|
-
end
|
94
|
-
|
95
|
-
def grab time, image_path
|
96
|
-
@ffmpeg.execute "-y -ss #{time.total_seconds} -i \"#{@video}\" -an -dframes 1 -vframes 1 -vcodec png -f rawvideo \"#{image_path}\""
|
97
|
-
end
|
98
|
-
|
99
|
-
def available_formats
|
100
|
-
# Ordered by priority
|
101
|
-
image_formats = ['png', 'tiff', 'bmp', 'mjpeg']
|
102
|
-
formats = []
|
103
|
-
|
104
|
-
list = @ffprobe.execute "-codecs"
|
105
|
-
list.lines.drop(HEADER).each do |codec|
|
106
|
-
name, e, v = format_split(codec)
|
107
|
-
formats << name if image_formats.include?(name) && e && v
|
108
|
-
end
|
109
|
-
|
110
|
-
image_formats.select{ |format| formats.include?(format) }.map(&:to_sym)
|
111
|
-
end
|
112
|
-
|
113
|
-
def format_split line
|
114
|
-
e = line[ENCODING_SUPPORT] == 'E'
|
115
|
-
v = line[VIDEO_CODEC] == 'V'
|
116
|
-
|
117
|
-
name = line[NAME..-1].split(' ', 2).first
|
118
|
-
return name, e, v
|
119
|
-
rescue
|
120
|
-
return nil, false, false
|
121
|
-
end
|
122
|
-
|
123
|
-
def to_s
|
124
|
-
"FFmpeg #{@version}"
|
125
|
-
end
|
126
|
-
|
127
|
-
private
|
128
|
-
def load_probe
|
129
|
-
return if @cache
|
130
|
-
|
131
|
-
@cache = @ffprobe.execute("\"#{@video}\"", "2>&1")
|
132
|
-
puts @cache if Tools.verbose?
|
133
|
-
|
134
|
-
parse_video_streams
|
135
|
-
parse_audio_streams
|
136
|
-
end
|
137
|
-
|
138
|
-
def parse_video_streams
|
139
|
-
video_stream = split_stream_line(is_stream?(@cache, /Video/).first)
|
140
|
-
|
141
|
-
dimensions = /(\d*)x(\d*) \[PAR (\d*:\d*) DAR (\d*:\d*)\]/.match(video_stream[DIMENSION])
|
142
|
-
|
143
|
-
if dimensions
|
144
|
-
@par = dimensions[3]
|
145
|
-
@dar = dimensions[4]
|
146
|
-
else
|
147
|
-
dimensions = /(\d*)x(\d*)/.match(video_stream[DIMENSION])
|
148
|
-
end
|
149
|
-
|
150
|
-
if dimensions
|
151
|
-
@width = dimensions[1].to_i
|
152
|
-
@height = dimensions[2].to_i
|
153
|
-
end
|
154
|
-
|
155
|
-
fps = /([\d|.]+) fps/.match(video_stream[FPS])
|
156
|
-
@fps = fps ? fps[1].to_f : 0.0
|
157
|
-
|
158
|
-
@video_codec = video_stream[CODEC]
|
159
|
-
end
|
160
|
-
|
161
|
-
def parse_audio_streams
|
162
|
-
audio_stream = split_stream_line(is_stream?(@cache, /Audio/).first)
|
163
|
-
|
164
|
-
@audio_codec = audio_stream[CODEC]
|
165
|
-
end
|
166
|
-
|
167
|
-
def is_stream? probe, regex
|
168
|
-
streams(probe).select{ |s| s =~ regex }
|
169
|
-
end
|
170
|
-
|
171
|
-
def streams probe
|
172
|
-
@cache.split(/\r?\n/).map(&:strip).select{|l| l.start_with? 'Stream' }
|
173
|
-
end
|
174
|
-
|
175
|
-
def split_stream_line line
|
176
|
-
parts = line.split(',')
|
177
|
-
stream = parts.shift
|
178
|
-
result = stream.split(':')
|
179
|
-
result += parts
|
180
|
-
return result.map(&:strip)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
data/lib/libav.rb
DELETED
@@ -1,181 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# FFmpeg Abstraction
|
3
|
-
#
|
4
|
-
|
5
|
-
require 'capturer'
|
6
|
-
require 'command'
|
7
|
-
require 'time_index'
|
8
|
-
|
9
|
-
module VCSRuby
|
10
|
-
class LibAV < Capturer
|
11
|
-
|
12
|
-
CODEC = 2
|
13
|
-
DIMENSION = 4
|
14
|
-
FPS = 6
|
15
|
-
|
16
|
-
HEADER = 10
|
17
|
-
|
18
|
-
ENCODING_SUPPORT = 2
|
19
|
-
VIDEO_CODEC = 3
|
20
|
-
NAME = 8
|
21
|
-
|
22
|
-
def initialize video
|
23
|
-
@video = video
|
24
|
-
@avconv = Command.new :libav, 'avconv'
|
25
|
-
@avprobe = Command.new :libav, 'avprobe'
|
26
|
-
|
27
|
-
detect_version if available?
|
28
|
-
end
|
29
|
-
|
30
|
-
def name
|
31
|
-
:libav
|
32
|
-
end
|
33
|
-
|
34
|
-
def available?
|
35
|
-
@avconv.available? && @avprobe.available?
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
|
-
def detect_version
|
40
|
-
info = @avconv.execute('-version')
|
41
|
-
match = /avconv ([\d|.|-|:]*)/.match(info)
|
42
|
-
@version = match[1] if match
|
43
|
-
end
|
44
|
-
|
45
|
-
def length
|
46
|
-
load_probe
|
47
|
-
match = /Duration: ([\d|:|.]*)/.match(@cache)
|
48
|
-
return TimeIndex.new match[1]
|
49
|
-
end
|
50
|
-
|
51
|
-
def width
|
52
|
-
load_probe
|
53
|
-
@width
|
54
|
-
end
|
55
|
-
|
56
|
-
def height
|
57
|
-
load_probe
|
58
|
-
@height
|
59
|
-
end
|
60
|
-
|
61
|
-
def par
|
62
|
-
load_probe
|
63
|
-
@par
|
64
|
-
end
|
65
|
-
|
66
|
-
def dar
|
67
|
-
load_probe
|
68
|
-
@dar
|
69
|
-
end
|
70
|
-
|
71
|
-
def fps
|
72
|
-
load_probe
|
73
|
-
@fps
|
74
|
-
end
|
75
|
-
|
76
|
-
def video_codec
|
77
|
-
load_probe
|
78
|
-
|
79
|
-
@video_codec
|
80
|
-
end
|
81
|
-
|
82
|
-
def audio_codec
|
83
|
-
load_probe
|
84
|
-
|
85
|
-
@audio_codec
|
86
|
-
end
|
87
|
-
|
88
|
-
def grab time, image_path
|
89
|
-
@avconv.execute "-y -ss #{time.total_seconds} -i \"#{@video}\" -an -dframes 1 -vframes 1 -vcodec #{format} -f rawvideo \"#{image_path}\""
|
90
|
-
end
|
91
|
-
|
92
|
-
def available_formats
|
93
|
-
# Ordered by priority
|
94
|
-
image_formats = ['png', 'tiff', 'bmp', 'mjpeg']
|
95
|
-
formats = []
|
96
|
-
|
97
|
-
list = @avprobe.execute "-codecs"
|
98
|
-
list.lines.drop(HEADER).each do |codec|
|
99
|
-
name, e, v = format_split(codec)
|
100
|
-
formats << name if image_formats.include?(name) && e && v
|
101
|
-
end
|
102
|
-
|
103
|
-
image_formats.select{ |format| formats.include?(format) }.map(&:to_sym)
|
104
|
-
end
|
105
|
-
|
106
|
-
def format_split line
|
107
|
-
correction = 0
|
108
|
-
unless line[0] == ' '
|
109
|
-
correction = 1
|
110
|
-
end
|
111
|
-
e = line[ENCODING_SUPPORT - correction] == 'E'
|
112
|
-
v = line[VIDEO_CODEC - correction] == 'V'
|
113
|
-
|
114
|
-
name = line[NAME-correction..-1].split(' ', 2).first
|
115
|
-
return name, e, v
|
116
|
-
rescue
|
117
|
-
return nil, false, false
|
118
|
-
end
|
119
|
-
|
120
|
-
def to_s
|
121
|
-
"LibAV #{@version}"
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
def load_probe
|
126
|
-
return if @cache
|
127
|
-
|
128
|
-
@cache = @avprobe.execute("\"#{@video}\"", "2>&1")
|
129
|
-
puts @cache if Tools.verbose?
|
130
|
-
|
131
|
-
parse_video_streams
|
132
|
-
parse_audio_streams
|
133
|
-
end
|
134
|
-
|
135
|
-
def parse_video_streams
|
136
|
-
video_stream = split_stream_line(is_stream?(@cache, /Video/).first)
|
137
|
-
|
138
|
-
dimensions = /(\d*)x(\d*) \[PAR (\d*:\d*) DAR (\d*:\d*)\]/.match(video_stream[DIMENSION])
|
139
|
-
|
140
|
-
if dimensions
|
141
|
-
@par = dimensions[3]
|
142
|
-
@dar = dimensions[4]
|
143
|
-
else
|
144
|
-
dimensions = /(\d*)x(\d*)/.match(video_stream[DIMENSION])
|
145
|
-
end
|
146
|
-
|
147
|
-
if dimensions
|
148
|
-
@width = dimensions[1].to_i
|
149
|
-
@height = dimensions[2].to_i
|
150
|
-
end
|
151
|
-
|
152
|
-
fps = /([\d|.]+) fps/.match(video_stream[FPS])
|
153
|
-
@fps = fps ? fps[1].to_f : 0.0
|
154
|
-
|
155
|
-
@video_codec = video_stream[CODEC]
|
156
|
-
end
|
157
|
-
|
158
|
-
def parse_audio_streams
|
159
|
-
audio_stream = split_stream_line(is_stream?(@cache, /Audio/).first)
|
160
|
-
|
161
|
-
@audio_codec = audio_stream[CODEC]
|
162
|
-
end
|
163
|
-
|
164
|
-
def is_stream? probe, regex
|
165
|
-
streams(probe).select{ |s| s =~ regex }
|
166
|
-
end
|
167
|
-
|
168
|
-
def streams probe
|
169
|
-
@cache.split(/\r?\n/).map(&:strip).select{|l| l.start_with? 'Stream' }
|
170
|
-
end
|
171
|
-
|
172
|
-
def split_stream_line line
|
173
|
-
return [nil, nil, 'none'] unless line
|
174
|
-
parts = line.split(',')
|
175
|
-
stream = parts.shift
|
176
|
-
result = stream.split(':')
|
177
|
-
result += parts
|
178
|
-
return result.map(&:strip)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|