mkv2m4v 0.0.1 → 0.1.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/.gitignore CHANGED
@@ -7,7 +7,6 @@ Gemfile.lock
7
7
  InstalledFiles
8
8
  _yardoc
9
9
  coverage
10
- doc/
11
10
  lib/bundler/man
12
11
  pkg
13
12
  rdoc
data/README.md CHANGED
@@ -1,6 +1,3 @@
1
- **This gem is a work in progress.** Do not expect any supported functionality
2
- until v0.1.0.
3
-
4
1
  # mkv2m4v
5
2
 
6
3
  Converts audio and video tracks from a MKV (Matroska Media) container into a
@@ -15,12 +12,44 @@ It attempts to pass through as many codecs as possible.
15
12
 
16
13
  ## Installation
17
14
 
18
- $ brew install mediainfo
19
- $ gem install mkv2m4v
15
+ mkv2m4v is dependent upon `mediainfo`, `mkvextract`, `ffmpeg`, and `MP4Box`.
16
+
17
+ ```bash
18
+ $ brew install mediainfo
19
+ $ brew install gpac
20
+ $ brew install mkvtoolnix
21
+ $ gem install mkv2m4v
22
+ ```
23
+
24
+ _Note: `gpac` includes `MP4Box` and is dependent on `ffmpeg`, so `ffmpeg`
25
+ should install automatically. If not, you should manually install `ffmpeg`:_
26
+
27
+ ```bash
28
+ # ffmpeg should already be installed, but just in case:
29
+ $ brew install ffmpeg --with-tools
30
+ ```
20
31
 
21
32
  ## Usage
22
33
 
23
- $ mkv2m4v some-video.mkv
34
+ ```bash
35
+ $ mkv2m4v some-video.mkv
36
+ ```
37
+
38
+ ## Background
39
+
40
+ I got fed up with the reliability of the conversion tools out there for
41
+ converting MKV video containers to Apple TV compatible videos. Many of the
42
+ existing tools appear to have potential on the surface, but they fail under
43
+ certain scenarios.
44
+
45
+ [Handbrake](http://handbrake.fr/) is still the most realiable existing tool
46
+ out there, but it re-encodes h.264 video tracks, which is not ideal and very
47
+ slow.
48
+
49
+ The goal is to get a better, more automated tool to accomplish the task of
50
+ generating Apple TV compatible videos. Nothing more. It should generate an M4V
51
+ media file with the best possible quality given the original source and the
52
+ defaults should require no additional human interaction.
24
53
 
25
54
  ## Contributing
26
55
 
data/Rakefile CHANGED
@@ -1 +1,10 @@
1
+ require "rake/testtask"
1
2
  require "bundler/gem_tasks"
3
+
4
+ desc "Default: run unit tests."
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << "lib" << "test"
9
+ t.pattern = "test/**/*_test.rb"
10
+ end
data/doc/notes.md ADDED
@@ -0,0 +1,26 @@
1
+ Extracting tracks from an mkv (assuming correct track numbers):
2
+
3
+ $ mediainfo example.mkv # Inspect track IDs
4
+ $ mkvextract tracks example.mkv 1:example.h264 2:example.dts
5
+
6
+ Converting dts to ac3:
7
+
8
+ $ ffmpeg -i example.dts -acodec ac3 -ac 6 -ab 640k example-6ch.ac3
9
+
10
+ Converting dts to aac:
11
+
12
+ $ ffmpeg -i example.dts -acodec libfaac -ac 2 -ab 160k example-2ch.aac
13
+
14
+ Converting ac3 to aac:
15
+
16
+ $ ffmpeg -i example.ac3 -acodec libfaac -ac 2 -ab 160k example-2ch.aac
17
+
18
+ Remux the tracks into an M4V container. For Apple TV surround sound support,
19
+ the audio tracks must be in the same group with all but the first AAC track
20
+ disabled. [[source](http://forum.doom9.org/archive/index.php/t-160302.html)]
21
+
22
+ $ MP4Box \
23
+ -add example.h264:lang=en:name="AVC Video" \
24
+ -add example-2ch.aac:lang=en:group=1:delay=84:name="Stereo" \
25
+ -add example-6ch.ac3:lang=en:group=1:delay=84:disable:name="AC3" \
26
+ -new example_testing.m4v
@@ -0,0 +1,80 @@
1
+ require "mkv2m4v/track"
2
+ require "mkv2m4v/track_ranker"
3
+ require "mkv2m4v/transcoder"
4
+ require "mediainfo"
5
+ require "forwardable"
6
+ require "iso639"
7
+ require "colorize"
8
+
9
+ module Mkv2m4v
10
+ class File
11
+ extend Forwardable
12
+
13
+ attr_reader :info, :video_tracks, :audio_tracks, :text_tracks
14
+ attr_reader :ideal_video_track, :ideal_audio_track
15
+ def_delegator :info, :filename, :name
16
+ def_delegator :info, :full_filename, :filename
17
+
18
+ def initialize(filename, options = {})
19
+ @info = Mediainfo.new(filename)
20
+ @options = options
21
+ @languages = @options[:languages]
22
+ init_tracks
23
+ end
24
+
25
+ def format
26
+ info.general.format
27
+ end
28
+
29
+ def print
30
+ puts "#{format}: #{name}".black.on_yellow
31
+ video_tracks.filter.each(&:print) if @options[:verbose]
32
+ audio_tracks.filter.each(&:print) if @options[:verbose]
33
+ text_tracks.filter.each(&:print) if @options[:verbose]
34
+ print_ideal_tracks
35
+ puts
36
+ end
37
+
38
+ def transcode
39
+ puts "#{format}: #{name}".black.on_yellow
40
+ Transcoder.new(self, @options).run
41
+ puts
42
+ end
43
+
44
+ def self.each(filenames, options = {})
45
+ filenames.each do |filename|
46
+ if ::File.exists?(filename)
47
+ yield new(filename, options)
48
+ else
49
+ $stderr.puts "#{filename} does not exist."
50
+ end
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def print_ideal_tracks
57
+ puts "==> Ideal video track"
58
+ @ideal_video_track.print
59
+ puts "==> Ideal audio track"
60
+ @ideal_audio_track.print
61
+ end
62
+
63
+ def init_tracks
64
+ @video_tracks = tracks_by_type(:video)
65
+ @audio_tracks = tracks_by_type(:audio)
66
+ @text_tracks = tracks_by_type(:text)
67
+
68
+ @ideal_video_track = video_tracks.filter.rank.first
69
+ @ideal_audio_track = audio_tracks.filter.rank.first
70
+ end
71
+
72
+ def tracks_by_type(type)
73
+ info_tracks = info.send(type)
74
+ tracks = info_tracks.count.times.map do |i|
75
+ Mkv2m4v.const_get("#{type.capitalize}Track").new(info_tracks[i])
76
+ end
77
+ Mkv2m4v.const_get("#{type.capitalize}Ranker").new(tracks, @options)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,86 @@
1
+ require "forwardable"
2
+
3
+ module Mkv2m4v
4
+ class Track
5
+ extend Forwardable
6
+
7
+ attr_reader :info
8
+ def_delegator :info, :stream_id, :id
9
+ def_delegators :info, :format
10
+
11
+ def initialize(track_info)
12
+ @info = track_info
13
+ end
14
+
15
+ def language
16
+ Iso639[info["language"]]
17
+ end
18
+
19
+ def title
20
+ info["title"]
21
+ end
22
+
23
+ def format_description
24
+ "#{format} (#{info.format_info}, #{info.codec_id})"
25
+ end
26
+ end
27
+
28
+ class VideoTrack < Track
29
+ def_delegators :info, :frame_size, :interlaced?, :fps, :width, :height
30
+
31
+ def resolution
32
+ "#{frame_size}#{interlaced? ? "i" : "p"}"
33
+ end
34
+
35
+ def print
36
+ puts "Track #{id}: (video)"
37
+ puts " Format: #{format_description}"
38
+ puts " Resolution: #{resolution}"
39
+ puts " FPS: #{fps}"
40
+ puts " Language: #{language}"
41
+ puts " Title: #{title}"
42
+ end
43
+ end
44
+
45
+ class AudioTrack < Track
46
+ def_delegators :info, :bit_rate
47
+
48
+ def channel_count
49
+ info.channels.to_s.chars.first.to_i
50
+ end
51
+
52
+ def bit_rate_kbps
53
+ info.bit_rate.gsub(/\D/, "").to_i if info.bit_rate
54
+ end
55
+
56
+ def channel_description
57
+ "#{channel_count} (#{info.channel_positions})"
58
+ end
59
+
60
+ def bit_rate_description
61
+ "#{bit_rate_kbps}k (#{info.bit_rate_mode})"
62
+ end
63
+
64
+ def print
65
+ puts "Track #{id}: (audio)"
66
+ puts " Format: #{format_description}"
67
+ puts " Channels: #{channel_description}"
68
+ puts " Bit rate: #{bit_rate_description}"
69
+ puts " Language: #{language}"
70
+ puts " Title: #{title}"
71
+ end
72
+ end
73
+
74
+ class TextTrack < Track
75
+ def format_description
76
+ "#{format} (#{info.codec_id})"
77
+ end
78
+
79
+ def print
80
+ puts "Track #{id}: (text)"
81
+ puts " Format: #{format_description}"
82
+ puts " Language: #{language}"
83
+ puts " Title: #{title}"
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,64 @@
1
+ require "forwardable"
2
+
3
+ module Mkv2m4v
4
+ class TrackRanker
5
+ extend Forwardable
6
+
7
+ def_delegators :@tracks, :each, :first
8
+
9
+ def initialize(tracks, options = {})
10
+ @tracks = tracks
11
+ @options = options
12
+ end
13
+
14
+ def filter
15
+ filtered_tracks = @tracks.select { |t| language_okay?(t) }
16
+ self.class.new(filtered_tracks, @options)
17
+ end
18
+
19
+ def rank
20
+ ranked_tracks = @tracks.sort_by { |t| score(t) }.reverse
21
+ self.class.new(ranked_tracks, @options)
22
+ end
23
+
24
+ protected
25
+
26
+ def language_match?(track)
27
+ @options.languages.include?(track.language)
28
+ end
29
+
30
+ def language_okay?(track)
31
+ track.language.nil? ||
32
+ @options.languages.empty? ||
33
+ language_match?(track)
34
+ end
35
+ end
36
+
37
+ class VideoRanker < TrackRanker
38
+ def score(track)
39
+ score = 0
40
+ score += 8 if track.format == "AVC"
41
+ score += (track.height || 0)/ 1080.0 * 4.0
42
+ score += 2 if language_match?(track)
43
+ score
44
+ end
45
+ end
46
+
47
+ class AudioRanker < TrackRanker
48
+ def score(track)
49
+ score = 0
50
+ score += 4 if ["DTS", "AC-3"].include?(track.format)
51
+ score += 2 if track.format == "AAC"
52
+ score += (track.channel_count || 0) / 8.0 * 2.0
53
+ score += (track.bit_rate_kbps || 0) / 1500.0 * 2.0
54
+ score += 4 if language_match?(track)
55
+ score
56
+ end
57
+ end
58
+
59
+ class TextRanker < TrackRanker
60
+ # scoring not implemented yet
61
+ # def score(track)
62
+ # end
63
+ end
64
+ end
@@ -0,0 +1,141 @@
1
+ require "fileutils"
2
+ require "colorize"
3
+
4
+ module Mkv2m4v
5
+ class Transcoder
6
+ def initialize(file, options = {})
7
+ @file = file
8
+ @options = options
9
+ end
10
+
11
+ def run
12
+ setup
13
+ extract
14
+ transcode_avc
15
+ transcode_aac
16
+ transcode_ac3
17
+ remux
18
+ cleanup
19
+ end
20
+
21
+ private
22
+
23
+ def setup
24
+ FileUtils.mkdir_p tmp_dir
25
+ end
26
+
27
+ def extract
28
+ puts "==> Extracting #{video_id}:video.#{video_ext} #{audio_id}:audio.#{audio_ext} ".magenta
29
+ system "mkvextract tracks #{@file.filename.inspect} #{video_id}:#{video_file} #{audio_id}:#{audio_file}"
30
+ end
31
+
32
+ def transcode_avc
33
+ if video_format == "AVC"
34
+ puts "==> Assuming pass through for h.264 video track".yellow.on_black
35
+ else
36
+ puts "==> ERROR: Wrong Video format".white.on_red
37
+ end
38
+ end
39
+
40
+ def transcode_aac
41
+ if audio_format == "AAC"
42
+ puts "==> Assuming pass through for AAC audio track".yellow.on_black
43
+ else
44
+ puts "==> Transcoding #{audio_format} to Stereo AAC audio track".magenta
45
+ system "ffmpeg -i #{audio_file.inspect} -acodec libfaac -ac 2 -ab 160k #{audio_basename}.aac"
46
+ end
47
+ end
48
+
49
+ def transcode_ac3
50
+ if audio_format == "AC-3"
51
+ puts "==> Assuming pass through for AC-3 audio track".yellow.on_black
52
+ elsif audio_format == "AAC"
53
+ puts "==> Skipping AC-3 surround audio track".yellow.on_black
54
+ @skip_ac3 = true
55
+ else
56
+ puts "==> Transcoding #{audio_format} to Surround AC-3 audio track".magenta
57
+ system "ffmpeg -i #{audio_file.inspect} -acodec ac3 -ac #{max_audio_channels} -ab #{max_audio_bit_rate}k #{audio_basename}.ac3"
58
+ end
59
+ end
60
+
61
+ def remux
62
+ puts "==> Remuxing everything into an M4V container".magenta
63
+ command = "MP4Box"
64
+ command << " -add #{video_basename.inspect}.h264:lang=en:name=\"AVC Video\" "
65
+ command << " -add #{audio_basename.inspect}.aac:lang=en:group=1:delay=84:name=\"Stereo\" "
66
+ unless @skip_ac3
67
+ command << " -add #{audio_basename.inspect}.ac3:lang=en:group=1:delay=84:disable:name=\"AC3\" "
68
+ end
69
+ command << " -new #{m4v_file.inspect}"
70
+ system command
71
+ end
72
+
73
+ def cleanup
74
+ FileUtils.rm_rf tmp_dir
75
+ end
76
+
77
+ def video_basename
78
+ ::File.join(tmp_dir, "video")
79
+ end
80
+
81
+ def video_file
82
+ [video_basename, video_ext].join(".")
83
+ end
84
+
85
+ def video_id
86
+ @file.ideal_video_track.id
87
+ end
88
+
89
+ def video_format
90
+ @file.ideal_video_track.format
91
+ end
92
+
93
+ def video_ext
94
+ if video_format == "AVC"
95
+ "h264"
96
+ else
97
+ video_format.gsub(/\W/, "").downcase
98
+ end
99
+ end
100
+
101
+ def audio_basename
102
+ ::File.join(tmp_dir, "audio")
103
+ end
104
+
105
+ def audio_file
106
+ [audio_basename, audio_ext].join(".")
107
+ end
108
+
109
+ def audio_id
110
+ @file.ideal_audio_track.id
111
+ end
112
+
113
+ def audio_format
114
+ @file.ideal_audio_track.format
115
+ end
116
+
117
+ def audio_ext
118
+ audio_format.gsub(/\W/, "").downcase
119
+ end
120
+
121
+ def max_audio_channels
122
+ [@file.ideal_audio_track.channel_count, 6].min
123
+ end
124
+
125
+ def max_audio_bit_rate
126
+ [@file.ideal_audio_track.bit_rate_kbps, 640].min
127
+ end
128
+
129
+ def dir
130
+ @options[:dir] || ::File.dirname(@file.filename)
131
+ end
132
+
133
+ def tmp_dir
134
+ ::File.join(dir, ::File.basename(@file.name, ".*") + "-tracks")
135
+ end
136
+
137
+ def m4v_file
138
+ ::File.join(dir, ::File.basename(@file.name, ".*") + ".m4v")
139
+ end
140
+ end
141
+ end
@@ -1,5 +1,5 @@
1
1
  module Mkv2m4v
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.1"
3
3
 
4
4
  VersionDescription = "mkv2m4v #{VERSION} (c) 2012 Ryan McGeary"
5
5
  Description = <<EOS
data/lib/mkv2m4v.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require "mkv2m4v/version"
2
- require "mkv2m4v/mediainfo"
2
+ require "mkv2m4v/file"
3
3
  require "trollop"
4
4
 
5
5
  module Mkv2m4v
@@ -10,56 +10,17 @@ module Mkv2m4v
10
10
 
11
11
  def run
12
12
  if @options[:info]
13
- print_info
13
+ each_file(&:print)
14
14
  else
15
- convert_files
15
+ each_file(&:transcode)
16
16
  end
17
17
  end
18
18
 
19
19
  private
20
20
 
21
- def convert_files
22
- $stderr.puts "Converting files is not yet supported. For now, try the --info option."
23
- # each_file do |file|
24
- # end
25
- end
26
-
27
- def print_info
28
- each_file do |file|
29
- info = Mediainfo.new file
30
- puts "#{info.general.format}: #{file}"
31
- info.video.count.times do |i|
32
- print_video_track(info.video[i])
33
- end
34
- info.audio.count.times do |i|
35
- print_audio_track(info.audio[i])
36
- end
37
- puts
38
- end
39
- end
40
-
41
- def print_video_track(video)
42
- puts "Video Track #{video.stream_id}:"
43
- puts " Format: #{video.format} (#{video.format_info}, #{video.codec_id})"
44
- puts " Resolution: #{video.frame_size}#{video.interlaced? ? "i" : "p"}"
45
- puts " FPS: #{video.fps}"
46
- puts " Language: #{video.language}"
47
- end
48
-
49
- def print_audio_track(audio)
50
- puts "Audio Track #{audio.stream_id}:"
51
- puts " Format: #{audio.format} (#{audio.format_info}, #{audio.codec_id})"
52
- puts " Channels: #{audio.channel_count} (#{audio.channel_positions})"
53
- puts " Language: #{audio.language}"
54
- end
55
-
56
21
  def each_file
57
- ARGV.each do |file|
58
- if File.exists?(file)
59
- yield file
60
- else
61
- $stderr.puts "#{file} does not exist."
62
- end
22
+ Mkv2m4v::File.each(@filenames, @options) do |file|
23
+ yield file
63
24
  end
64
25
  end
65
26
 
@@ -69,7 +30,12 @@ module Mkv2m4v
69
30
  version Mkv2m4v::VersionDescription
70
31
  banner [Mkv2m4v::Description, Mkv2m4v::Usage].join("\n")
71
32
  opt :info, "Print media info only"
33
+ opt :lang, "Preferred languages", :type => :strings, :default => ["English"]
34
+ opt :dir, "Destination directory", :type => :string
35
+ opt :verbose, "More output", :type => :boolean
72
36
  end
37
+ @options[:languages] = @options[:lang].map { |lang| Iso639[lang] }.compact
38
+ @filenames = ARGV
73
39
  end
74
40
  end
75
41
  end
data/mkv2m4v.gemspec CHANGED
@@ -17,6 +17,11 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
 
20
- gem.add_dependency("trollop", "~> 2.0")
21
- gem.add_dependency("mediainfo", "~> 0.7")
20
+ gem.add_dependency "trollop", "~> 2.0"
21
+ gem.add_dependency "mediainfo", "~> 0.7"
22
+ gem.add_dependency "iso639", "~> 1.0", ">= 1.0.5"
23
+ gem.add_dependency "colorize", "~> 0.5"
24
+
25
+ gem.add_development_dependency "minitest", "~> 4.3"
26
+ gem.add_development_dependency "rake", "~> 10.0"
22
27
  end
@@ -0,0 +1,2 @@
1
+ require "minitest/autorun"
2
+ require "minitest/pride"
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: mkv2m4v
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.1.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ryan McGeary
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-23 00:00:00.000000000 Z
12
+ date: 2012-12-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  version_requirements: !ruby/object:Gem::Requirement
@@ -43,6 +43,76 @@ dependencies:
43
43
  - !ruby/object:Gem::Version
44
44
  version: '0.7'
45
45
  none: false
46
+ - !ruby/object:Gem::Dependency
47
+ version_requirements: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ~>
50
+ - !ruby/object:Gem::Version
51
+ version: '1.0'
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.5
55
+ none: false
56
+ name: iso639
57
+ type: :runtime
58
+ prerelease: false
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ~>
62
+ - !ruby/object:Gem::Version
63
+ version: '1.0'
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: 1.0.5
67
+ none: false
68
+ - !ruby/object:Gem::Dependency
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ version: '0.5'
74
+ none: false
75
+ name: colorize
76
+ type: :runtime
77
+ prerelease: false
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '0.5'
83
+ none: false
84
+ - !ruby/object:Gem::Dependency
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '4.3'
90
+ none: false
91
+ name: minitest
92
+ type: :development
93
+ prerelease: false
94
+ requirement: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ~>
97
+ - !ruby/object:Gem::Version
98
+ version: '4.3'
99
+ none: false
100
+ - !ruby/object:Gem::Dependency
101
+ version_requirements: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ~>
104
+ - !ruby/object:Gem::Version
105
+ version: '10.0'
106
+ none: false
107
+ name: rake
108
+ type: :development
109
+ prerelease: false
110
+ requirement: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ~>
113
+ - !ruby/object:Gem::Version
114
+ version: '10.0'
115
+ none: false
46
116
  description: ! 'mkv2m4v is a command line utility that converts audio and video tracks
47
117
  from a
48
118
 
@@ -62,10 +132,15 @@ files:
62
132
  - README.md
63
133
  - Rakefile
64
134
  - bin/mkv2m4v
135
+ - doc/notes.md
65
136
  - lib/mkv2m4v.rb
66
- - lib/mkv2m4v/mediainfo.rb
137
+ - lib/mkv2m4v/file.rb
138
+ - lib/mkv2m4v/track.rb
139
+ - lib/mkv2m4v/track_ranker.rb
140
+ - lib/mkv2m4v/transcoder.rb
67
141
  - lib/mkv2m4v/version.rb
68
142
  - mkv2m4v.gemspec
143
+ - test/test_helper.rb
69
144
  homepage: https://github.com/rmm5t/mkv2m4v
70
145
  licenses: []
71
146
  post_install_message:
@@ -90,4 +165,5 @@ rubygems_version: 1.8.23
90
165
  signing_key:
91
166
  specification_version: 3
92
167
  summary: Makes Apple TV compatible videos
93
- test_files: []
168
+ test_files:
169
+ - test/test_helper.rb
@@ -1,13 +0,0 @@
1
- require "mediainfo"
2
-
3
- class Mediainfo::Stream
4
- def language
5
- self["language"]
6
- end
7
- end
8
-
9
- class Mediainfo::AudioStream
10
- def channel_count
11
- channels.to_s.chars.first.to_i
12
- end
13
- end