vcs_ruby 1.1.9 → 1.1.10

Sign up to get free protection for your applications and to get access to all the features.
data/bin/vcs.rb CHANGED
@@ -1,171 +1,171 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Video Contact Sheet Ruby:
4
- # ----------------------
5
- #
6
- # Generates contact sheets of videos
7
- #
8
- # Prerequisites: Ruby, ImageMagick, ffmpeg/libav or mplayer
9
- #
10
-
11
- # Load library path for development
12
- $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "../lib")
13
-
14
- require 'optparse'
15
- require 'vcs'
16
- require 'yaml'
17
-
18
- include VCSRuby
19
-
20
-
21
- # Configuration can Override options
22
- options =
23
- {
24
- quiet: false,
25
- verbose: false,
26
- capturer: :any,
27
- format: nil,
28
- output: []
29
- }
30
-
31
- # Command Line Parameter arguments
32
-
33
- arguments =
34
- {
35
- '--capturer' => [:ffmpeg, :libav, :mplayer, :any],
36
- '--format' => [:png, :jpg, :jpeg, :tiff],
37
- '--funky' => [:polaroid, :photos, :overlap, :rotate, :photoframe, :polaroidframe, :film, :random]
38
- }
39
-
40
- # Command Line Parameters
41
- optparse = OptionParser.new do|opts|
42
- opts.separator $vcs_ruby_name + ' ' + $vcs_ruby_version.to_s
43
- opts.separator ''
44
- opts.on( '-i [INTERVAL]', '--interval [INTERVAL]', 'Set the interval [INTERVAL]') do |interval|
45
- options[:interval] = TimeIndex.new interval
46
- end
47
- opts.on( '-c [COLMNS]', '--columns [COLUMNS]', 'Arrange the output in <COLUMNS> columns.') do |columns|
48
- options[:columns] = columns.to_i
49
- end
50
- opts.on( '-r [ROWS]', '--rows [ROWS]', 'Arrange the output in <ROWS> rows.') do |rows|
51
- options[:rows] = rows.to_i
52
- end
53
- opts.on( '-H [HEIGHT]', '--height [HEIGHT]', 'Set the output (individual thumbnail) height.') do |height|
54
- options[:height] = height.to_i
55
- end
56
- opts.on( '-W [WIDTH]', '--width [WIDTH]', 'Set the output (individual thumbnail) width.') do |width|
57
- options[:width] = width.to_i
58
- end
59
- opts.on( '-A [ASPECT]', '--aspect [ASPECT]', 'Aspect ratio. Accepts a floating point number or a fraction. (i.e. 16/19)') do |aspect|
60
- options[:aspect_ratio] = aspect.to_r
61
- end
62
- opts.on( '-f [FROM]', '--from [FROM]', 'Set starting time. No caps before this.') do |from|
63
- options[:from] = TimeIndex.new from
64
- end
65
- opts.on( '-t [TO]', '--to [TO]', 'Set ending time. No caps beyond this.') do |to|
66
- options[:to] = TimeIndex.new to
67
- end
68
- opts.on( '-T [TITLE]', '--title [TITLE]', 'Set ending time. No caps beyond this.') do |title|
69
- options[:title] = title
70
- end
71
- opts.on( '-f [format]', '--format [FORMAT]', arguments['--format'], 'Formats: ' + Tools::list_arguments(arguments["--format"])) do |format|
72
- options[:format] = format
73
- end
74
- opts.on('-C [CAPTURER]', '--capture [CAPTURER]', arguments['--capturer'], 'Capturer: ' + Tools::list_arguments(arguments["--capturer"])) do |capturer|
75
- options[:capturer] = capturer
76
- end
77
- opts.on( '-T [TITLE]', '--title [TITLE]', 'Set Title') do |title|
78
- options[:title] = title
79
- end
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
- options[:output] << file
82
- end
83
- opts.on( '-s [SIGNATURE]', '--signature [SIGNATURE]', 'Change the image signature to your preference.') do |signature|
84
- options[:signature] = signature
85
- end
86
- opts.on( '--no-signature', 'Remove footer with signature') do
87
- options[:no_signature] = true
88
- end
89
- opts.on( '-l [HIGHLIGHT]', '--highlight [HIGHLIGHT]', 'Add the frame found at timestamp [HIGHLIGHT] as a highlight.') do |highlight|
90
- options[:highlight] = TimeIndex.new highlight
91
- end
92
- opts.on("--[no-]timestamp", "Add timestamp to thumbnails. Default: true") do |timestamp|
93
- options[:timestamp] = timestamp
94
- end
95
- opts.on("--[no-]shadow", "Add shadow to thumbnails. Default: true") do |shadow|
96
- options[:shadow] = shadow
97
- end
98
- opts.on("--[no-]polaroid", "Add polaroid frame to thumbnail. Default: false") do |polaroid|
99
- options[:polaroid] = polaroid
100
- end
101
- opts.on( '-p [PROFILE]', '--profile [PROFILE]', 'Loads additional setting from profile.yml.') do |profile|
102
- options[:profile] = profile
103
- end
104
- opts.on( '-q', '--quiet', 'Don\'t print progress messages just errors.') do |file|
105
- options[:quiet] = true
106
- end
107
- opts.on('--continue', 'Prints Error message and continues with next file (if any left)') do |file|
108
- options[:continue] = true
109
- end
110
- opts.on("-V", "--verbose", "More verbose Output.") do
111
- options[:verbose] = true
112
- end
113
- opts.on( '-v', '--version', 'Current Version' ) do
114
- puts $vcs_ruby_name + ' ' + $vcs_ruby_version.to_s
115
- exit 0
116
- end
117
-
118
- opts.on( '-h', '--help', 'Prints help' ) do
119
- options[:help] = true
120
- end
121
-
122
- opts.separator ''
123
- opts.separator 'Examples:'
124
- opts.separator ' Create a contact sheet with default values (4 x 4 matrix):'
125
- opts.separator ' $ vcs video.avi'
126
- opts.separator ''
127
- opts.separator ' Create a sheet with vidcaps at intervals of 3 and a half minutes, save to'
128
- opts.separator ' "output.jpg":'
129
- opts.separator ' $ vcs -i 3m30 input.wmv -o output.jpg'
130
- opts.separator ''
131
- opts.separator ' Create a sheet with vidcaps starting at 3 mins and ending at 18 mins in 2m intervals'
132
- opts.separator ' $ vcs --from 3m --to 18m -i 2m input.avi'
133
- opts.separator ''
134
- opts.separator ' See more examples at vcs-ruby homepage <https://github.com/FreeApophis/vcs.rb>.'
135
- opts.separator ''
136
- end
137
-
138
- Tools::print_help optparse if ARGV.empty?
139
-
140
- optparse.parse!
141
-
142
- Tools::print_help optparse if options[:help] || ARGV.empty?
143
-
144
- Configuration.instance.verbose = options[:verbose]
145
- Configuration.instance.quiet = options[:quiet]
146
-
147
- # Invoke ContactSheet
148
-
149
- errors = {}
150
- ARGV.each_with_index do |video, index|
151
- begin
152
- sheet = Tools::contact_sheet_with_options video, options
153
- if sheet
154
- sheet.initialize_filename(options[:output][index]) if options[:output][index]
155
- sheet.build
156
- end
157
- rescue Exception => e
158
- errors[video] = e
159
- STDERR.puts "ERROR: #{e.message}"
160
- STDERR.puts "#{e.backtrace.join("\n")}" if options[:verbose]
161
- break unless options[:continue]
162
- end
163
- end
164
-
165
- if options[:continue] && errors.length > 0
166
- errors.each do |video, e|
167
- STDERR.puts "File: #{video}"
168
- STDERR.puts "ERROR: #{e.message}"
169
- end
170
- STDERR.puts "Total: #{errors.length} Errors"
171
- end
1
+ #!/usr/bin/env ruby
2
+
3
+ # Video Contact Sheet Ruby:
4
+ # ----------------------
5
+ #
6
+ # Generates contact sheets of videos
7
+ #
8
+ # Prerequisites: Ruby, ImageMagick, ffmpeg/libav or mplayer
9
+ #
10
+
11
+ # Load library path for development
12
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "../lib")
13
+
14
+ require 'optparse'
15
+ require 'vcs'
16
+ require 'yaml'
17
+
18
+ include VCSRuby
19
+
20
+
21
+ # Configuration can Override options
22
+ options =
23
+ {
24
+ quiet: false,
25
+ verbose: false,
26
+ capturer: :any,
27
+ format: nil,
28
+ output: []
29
+ }
30
+
31
+ # Command Line Parameter arguments
32
+
33
+ arguments =
34
+ {
35
+ '--capturer' => [:ffmpeg, :libav, :mplayer, :any],
36
+ '--format' => [:png, :jpg, :jpeg, :tiff],
37
+ '--funky' => [:polaroid, :photos, :overlap, :rotate, :photoframe, :polaroidframe, :film, :random]
38
+ }
39
+
40
+ # Command Line Parameters
41
+ optparse = OptionParser.new do|opts|
42
+ opts.separator $vcs_ruby_name + ' ' + $vcs_ruby_version.to_s
43
+ opts.separator ''
44
+ opts.on( '-i [INTERVAL]', '--interval [INTERVAL]', 'Set the interval [INTERVAL]') do |interval|
45
+ options[:interval] = TimeIndex.new interval
46
+ end
47
+ opts.on( '-c [COLMNS]', '--columns [COLUMNS]', 'Arrange the output in <COLUMNS> columns.') do |columns|
48
+ options[:columns] = columns.to_i
49
+ end
50
+ opts.on( '-r [ROWS]', '--rows [ROWS]', 'Arrange the output in <ROWS> rows.') do |rows|
51
+ options[:rows] = rows.to_i
52
+ end
53
+ opts.on( '-H [HEIGHT]', '--height [HEIGHT]', 'Set the output (individual thumbnail) height.') do |height|
54
+ options[:height] = height.to_i
55
+ end
56
+ opts.on( '-W [WIDTH]', '--width [WIDTH]', 'Set the output (individual thumbnail) width.') do |width|
57
+ options[:width] = width.to_i
58
+ end
59
+ opts.on( '-A [ASPECT]', '--aspect [ASPECT]', 'Aspect ratio. Accepts a floating point number or a fraction. (i.e. 16/19)') do |aspect|
60
+ options[:aspect_ratio] = aspect.to_r
61
+ end
62
+ opts.on( '-f [FROM]', '--from [FROM]', 'Set starting time. No caps before this.') do |from|
63
+ options[:from] = TimeIndex.new from
64
+ end
65
+ opts.on( '-t [TO]', '--to [TO]', 'Set ending time. No caps beyond this.') do |to|
66
+ options[:to] = TimeIndex.new to
67
+ end
68
+ opts.on( '-T [TITLE]', '--title [TITLE]', 'Set ending time. No caps beyond this.') do |title|
69
+ options[:title] = title
70
+ end
71
+ opts.on( '-f [format]', '--format [FORMAT]', arguments['--format'], 'Formats: ' + Tools::list_arguments(arguments["--format"])) do |format|
72
+ options[:format] = format
73
+ end
74
+ opts.on('-C [CAPTURER]', '--capture [CAPTURER]', arguments['--capturer'], 'Capturer: ' + Tools::list_arguments(arguments["--capturer"])) do |capturer|
75
+ options[:capturer] = capturer
76
+ end
77
+ opts.on( '-T [TITLE]', '--title [TITLE]', 'Set Title') do |title|
78
+ options[:title] = title
79
+ end
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
+ options[:output] << file
82
+ end
83
+ opts.on( '-s [SIGNATURE]', '--signature [SIGNATURE]', 'Change the image signature to your preference.') do |signature|
84
+ options[:signature] = signature
85
+ end
86
+ opts.on( '--no-signature', 'Remove footer with signature') do
87
+ options[:no_signature] = true
88
+ end
89
+ opts.on( '-l [HIGHLIGHT]', '--highlight [HIGHLIGHT]', 'Add the frame found at timestamp [HIGHLIGHT] as a highlight.') do |highlight|
90
+ options[:highlight] = TimeIndex.new highlight
91
+ end
92
+ opts.on("--[no-]timestamp", "Add timestamp to thumbnails. Default: true") do |timestamp|
93
+ options[:timestamp] = timestamp
94
+ end
95
+ opts.on("--[no-]shadow", "Add shadow to thumbnails. Default: true") do |shadow|
96
+ options[:shadow] = shadow
97
+ end
98
+ opts.on("--[no-]polaroid", "Add polaroid frame to thumbnail. Default: false") do |polaroid|
99
+ options[:polaroid] = polaroid
100
+ end
101
+ opts.on( '-p [PROFILE]', '--profile [PROFILE]', 'Loads additional setting from profile.yml.') do |profile|
102
+ options[:profile] = profile
103
+ end
104
+ opts.on( '-q', '--quiet', 'Don\'t print progress messages just errors.') do |file|
105
+ options[:quiet] = true
106
+ end
107
+ opts.on('--continue', 'Prints Error message and continues with next file (if any left)') do |file|
108
+ options[:continue] = true
109
+ end
110
+ opts.on("-V", "--verbose", "More verbose Output.") do
111
+ options[:verbose] = true
112
+ end
113
+ opts.on( '-v', '--version', 'Current Version' ) do
114
+ puts $vcs_ruby_name + ' ' + $vcs_ruby_version.to_s
115
+ exit 0
116
+ end
117
+
118
+ opts.on( '-h', '--help', 'Prints help' ) do
119
+ options[:help] = true
120
+ end
121
+
122
+ opts.separator ''
123
+ opts.separator 'Examples:'
124
+ opts.separator ' Create a contact sheet with default values (4 x 4 matrix):'
125
+ opts.separator ' $ vcs video.avi'
126
+ opts.separator ''
127
+ opts.separator ' Create a sheet with vidcaps at intervals of 3 and a half minutes, save to'
128
+ opts.separator ' "output.jpg":'
129
+ opts.separator ' $ vcs -i 3m30 input.wmv -o output.jpg'
130
+ opts.separator ''
131
+ opts.separator ' Create a sheet with vidcaps starting at 3 mins and ending at 18 mins in 2m intervals'
132
+ opts.separator ' $ vcs --from 3m --to 18m -i 2m input.avi'
133
+ opts.separator ''
134
+ opts.separator ' See more examples at vcs-ruby homepage <https://github.com/FreeApophis/vcs.rb>.'
135
+ opts.separator ''
136
+ end
137
+
138
+ Tools::print_help optparse if ARGV.empty?
139
+
140
+ optparse.parse!
141
+
142
+ Tools::print_help optparse if options[:help] || ARGV.empty?
143
+
144
+ Configuration.instance.verbose = options[:verbose]
145
+ Configuration.instance.quiet = options[:quiet]
146
+
147
+ # Invoke ContactSheet
148
+
149
+ errors = {}
150
+ ARGV.each_with_index do |video, index|
151
+ begin
152
+ sheet = Tools::contact_sheet_with_options video, options
153
+ if sheet
154
+ sheet.initialize_filename(options[:output][index]) if options[:output][index]
155
+ sheet.build
156
+ end
157
+ rescue Exception => e
158
+ errors[video] = e
159
+ STDERR.puts "ERROR: #{e.message}"
160
+ STDERR.puts "#{e.backtrace.join("\n")}" if options[:verbose]
161
+ break unless options[:continue]
162
+ end
163
+ end
164
+
165
+ if options[:continue] && errors.length > 0
166
+ errors.each do |video, e|
167
+ STDERR.puts "File: #{video}"
168
+ STDERR.puts "ERROR: #{e.message}"
169
+ end
170
+ STDERR.puts "Total: #{errors.length} Errors"
171
+ end
data/lib/FFmpeg/ffmpeg.rb CHANGED
@@ -1,121 +1,121 @@
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? && @ffprobe.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 check_cache
86
- unless @cache
87
- @cache = @ffprobe.execute("\"#{@video.full_path}\" -show_format -show_streams", "2>&1")
88
- end
89
- end
90
-
91
- def parse_format
92
- @cache.scan(/\[FORMAT\](.*?)\[\/FORMAT\]/m) do |format|
93
- @info = FFmpegMetaInfo.new(get_hash(format[0]))
94
- return true
95
- end
96
- false
97
- end
98
-
99
- def parse_audio_streams
100
- @audio_streams = []
101
- @cache.scan(/\[STREAM\](.*?)\[\/STREAM\]/m) do |stream|
102
- info = get_hash(stream[0])
103
- if info['codec_type'] == 'audio'
104
- @audio_streams << FFmpegAudioStream.new(info)
105
- end
106
- end
107
- true
108
- end
109
-
110
- def parse_video_streams
111
- @video_streams = []
112
- @cache.scan(/\[STREAM\](.*?)\[\/STREAM\]/m) do |stream|
113
- info = get_hash(stream[0])
114
- if info['codec_type'] == 'video'
115
- @video_streams << FFmpegVideoStream.new(info)
116
- end
117
- end
118
- true
119
- end
120
- end
121
- end
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? && @ffprobe.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 check_cache
86
+ unless @cache
87
+ @cache = @ffprobe.execute("\"#{@video.full_path}\" -show_format -show_streams", "2>&1")
88
+ end
89
+ end
90
+
91
+ def parse_format
92
+ @cache.scan(/\[FORMAT\](.*?)\[\/FORMAT\]/m) do |format|
93
+ @info = FFmpegMetaInfo.new(get_hash(format[0]))
94
+ return true
95
+ end
96
+ false
97
+ end
98
+
99
+ def parse_audio_streams
100
+ @audio_streams = []
101
+ @cache.scan(/\[STREAM\](.*?)\[\/STREAM\]/m) do |stream|
102
+ info = get_hash(stream[0])
103
+ if info['codec_type'] == 'audio'
104
+ @audio_streams << FFmpegAudioStream.new(info)
105
+ end
106
+ end
107
+ true
108
+ end
109
+
110
+ def parse_video_streams
111
+ @video_streams = []
112
+ @cache.scan(/\[STREAM\](.*?)\[\/STREAM\]/m) do |stream|
113
+ info = get_hash(stream[0])
114
+ if info['codec_type'] == 'video'
115
+ @video_streams << FFmpegVideoStream.new(info)
116
+ end
117
+ end
118
+ true
119
+ end
120
+ end
121
+ end
@@ -1,38 +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
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
38
  end