handbrake 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/handbrake.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "handbrake/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "handbrake"
7
+ s.version = HandBrake::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Rhett Sutphin"]
10
+ s.email = ["rhett@detailedbalance.net"]
11
+ s.homepage = "https://github.com/rsutphin/handbrake-ruby"
12
+ s.summary = %q{A ruby wrapper for HandBrakeCLI}
13
+ s.description = %q{A lightweight literate ruby wrapper for HandBrakeCLI, the command-line interface for the HandBrake video transcoder.}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency 'rubytree', '~> 0.8.1'
21
+
22
+ s.add_development_dependency 'rspec', '~> 2.5'
23
+ s.add_development_dependency 'rake', '~> 0.9.0'
24
+ s.add_development_dependency 'yard', '~> 0.7.0'
25
+ end
data/hrirb ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ######
4
+ # Run irb for interactive fiddling with this library from the source
5
+
6
+ require 'irb'
7
+
8
+ $LOAD_PATH << File.expand_path('../lib', __FILE__)
9
+ require 'handbrake'
10
+
11
+ $cli = HandBrake::CLI.new(:trace => true)
12
+
13
+ puts "`$cli` is a HandBrake::CLI instance with tracing on"
14
+
15
+ IRB.start(__FILE__)
@@ -0,0 +1,206 @@
1
+ require 'handbrake'
2
+
3
+ module HandBrake
4
+ ##
5
+ # The main entry point for this API. See {file:README.md} for usage
6
+ # examples.
7
+ class CLI
8
+ ##
9
+ # The full path (including filename) to the HandBrakeCLI
10
+ # executable to use.
11
+ #
12
+ # @return [String]
13
+ attr_accessor :bin_path
14
+
15
+ ##
16
+ # Set whether trace is enabled.
17
+ #
18
+ # @return [Boolean]
19
+ attr_writer :trace
20
+
21
+ ##
22
+ # @param [Hash] options
23
+ # @option options [String] :bin_path ('HandBrakeCLI') the full
24
+ # path to the executable to use
25
+ # @option options [Boolean] :trace (false) whether {#trace?} is
26
+ # enabled
27
+ # @option options [#run] :runner (a PopenRunner instance) the class
28
+ # encapsulating the execution method for HandBrakeCLI. You
29
+ # shouldn't usually need to replace this.
30
+ def initialize(options={})
31
+ @bin_path = options[:bin_path] || 'HandBrakeCLI'
32
+ @trace = options[:trace].nil? ? false : options[:trace]
33
+ @runner = options[:runner] || PopenRunner.new(self)
34
+
35
+ @args = []
36
+ end
37
+
38
+ ##
39
+ # Ensures that `#dup` produces a separate copy.
40
+ #
41
+ # @return [void]
42
+ def initialize_copy(original)
43
+ @args = original.instance_eval { @args }.collect { |bit| bit.dup }
44
+ end
45
+
46
+ ##
47
+ # Is trace enabled?
48
+ #
49
+ # If it is enabled, all output from HandBrakeCLI will be streamed
50
+ # to standard error. If not, the output from HandBrakeCLI will
51
+ # only be printed if there is a detectable error.
52
+ #
53
+ # @return [Boolean]
54
+ def trace?
55
+ @trace
56
+ end
57
+
58
+ ##
59
+ # Performs a conversion. This method immediately begins the
60
+ # transcoding process; set all other options first.
61
+ #
62
+ # @return [void]
63
+ def output(filename)
64
+ run('--output', filename)
65
+ end
66
+
67
+ ##
68
+ # Performs a title scan. Unlike HandBrakeCLI, if you do not
69
+ # specify a title, this method will return information for all
70
+ # titles. (HandBrakeCLI defaults to only returning information for
71
+ # title 1.)
72
+ #
73
+ # @return [Titles]
74
+ def scan
75
+ if arguments.include?('--title')
76
+ result = run('--scan')
77
+ Titles.from_output(result.output)
78
+ else
79
+ title(0).scan
80
+ end
81
+ end
82
+
83
+ ##
84
+ # Checks to see if the `HandBrakeCLI` instance designated by
85
+ # {#bin_path} is the current version.
86
+ #
87
+ # Note that `HandBrakeCLI` will always report that it is up to
88
+ # date if it can't connect to the update server, so this is not
89
+ # terribly reliable.
90
+ #
91
+ # @return [Boolean]
92
+ def update
93
+ result = run('--update')
94
+ result.output =~ /Your version of HandBrake is up to date./i
95
+ end
96
+
97
+ ##
98
+ # Returns a structure describing the presets that the current
99
+ # HandBrake install knows about. The structure is a two-level
100
+ # hash. The keys in the first level are the preset categories. The
101
+ # keys in the second level are the preset names and the values are
102
+ # string representations of the arguments for that preset.
103
+ #
104
+ # (This method is included for completeness only. This library does
105
+ # not provide a mechanism to translate the argument lists returned
106
+ # here into the configuration for a {HandBrake::CLI} instance.)
107
+ #
108
+ # @return [Hash]
109
+ def preset_list
110
+ result = run('--preset-list')
111
+ result.output.scan(%r{\< (.*?)\n(.*?)\>}m).inject({}) { |h1, (cat, block)|
112
+ h1[cat.strip] = block.scan(/\+(.*?):(.*?)\n/).inject({}) { |h2, (name, args)|
113
+ h2[name.strip] = args.strip
114
+ h2
115
+ }
116
+ h1
117
+ }
118
+ end
119
+
120
+ ##
121
+ # @private
122
+ def arguments
123
+ @args.collect { |req, *rest| ["--#{req.to_s.gsub('_', '-')}", *rest] }.flatten
124
+ end
125
+
126
+ private
127
+
128
+ def run(*more_args)
129
+ @runner.run(arguments.push(*more_args)).tap do |result|
130
+ unless result.status == 0
131
+ unless trace?
132
+ $stderr.puts result.output
133
+ end
134
+ raise "HandBrakeCLI execution failed (#{result.status.inspect})"
135
+ end
136
+ end
137
+ end
138
+
139
+ ##
140
+ # Copies this CLI instance and appends another command line switch
141
+ # plus optional arguments.
142
+ #
143
+ # This method does not do any validation of the switch name; if
144
+ # you use an invalid one, HandBrakeCLI will fail when it is
145
+ # ultimately invoked.
146
+ #
147
+ # @return [CLI]
148
+ def method_missing(name, *args)
149
+ copy = self.dup
150
+ copy.instance_eval { @args << [name, *(args.collect { |a| a.to_s })] }
151
+ copy
152
+ end
153
+
154
+ ##
155
+ # @private
156
+ # The default runner. Uses `IO.popen` to spawn
157
+ # HandBrakeCLI. General use of this library does not require
158
+ # monkeying with this class.
159
+ class PopenRunner
160
+ ##
161
+ # @param [CLI] cli_instance the {CLI} instance whose configuration to share
162
+ def initialize(cli_instance)
163
+ @cli = cli_instance
164
+ end
165
+
166
+ # Some notes on popen options
167
+ # - IO.popen on 1.9.2 is much more elegant than on 1.8.7
168
+ # (it lets you pass spawn args directly instead of using a
169
+ # subshell, so you can more cleanly pass args to the
170
+ # executable and redirect streams)
171
+ # - Open3.popen3 does not let you get the status
172
+ # - Open4.popen4 does not seem to stream the output and error
173
+ # and hangs when the child process fills some buffer
174
+ # Hence, this implementation:
175
+
176
+ ##
177
+ # @param [Array<String>] arguments the arguments to pass to HandBrakeCLI
178
+ # @return [RunnerResult]
179
+ def run(arguments)
180
+ output = ''
181
+
182
+ cmd = "'" + arguments.unshift(@cli.bin_path).join("' '") + "' 2>&1"
183
+
184
+ $stderr.puts "Spawning HandBrakeCLI using #{cmd.inspect}" if @cli.trace?
185
+ IO.popen(cmd) do |io|
186
+ while line = io.gets
187
+ output << line
188
+ $stderr.puts(line.chomp) if @cli.trace?
189
+ end
190
+ end
191
+ RunnerResult.new(output, $?)
192
+ end
193
+ end
194
+
195
+ ##
196
+ # @private
197
+ # The raw result of one execution of HandBrakeCLI.
198
+ #
199
+ # General use of the library will not require use of this class.
200
+ #
201
+ # @attr [String] output a string containing the combined output
202
+ # and error streams from the run
203
+ # @attr [#to_i] status the process exit status for the run
204
+ RunnerResult = Struct.new(:output, :status)
205
+ end
206
+ end
@@ -0,0 +1,181 @@
1
+ require 'tree'
2
+
3
+ require 'handbrake'
4
+
5
+ module HandBrake
6
+ ##
7
+ # And enhanced `Hash` which can self-parse the output from
8
+ # HandBrakeCLI's `--scan` mode. The keys of this hash will be title
9
+ # numbers and the values will be {Title} instances.
10
+ #
11
+ # @see Title
12
+ # @see Chapter
13
+ class Titles < Hash
14
+ ##
15
+ # The HandBrakeCLI scan output from which this instance was
16
+ # parsed, if available.
17
+ #
18
+ # @return [String,nil]
19
+ attr_reader :raw_output
20
+
21
+ ##
22
+ # A tree representing the indented output at the end of the
23
+ # HandBrakeCLI scan output, if available.
24
+ #
25
+ # @return [String,nil]
26
+ attr_reader :raw_tree
27
+
28
+ ##
29
+ # Builds a new {Titles} instance from the output of `HandBrakeCLI
30
+ # --scan`.
31
+ #
32
+ # @param [String] output the raw contents from the scan
33
+ # @return [Titles] a new, completely initialized title catalog
34
+ def self.from_output(output)
35
+ self.new.tap do |titles|
36
+ titles.raw_output = output
37
+ titles.raw_tree.children.
38
+ collect { |title_node| Title.from_tree(title_node) }.
39
+ each { |title| titles[title.number] = title }
40
+ end
41
+ end
42
+
43
+ ##
44
+ # Initializes the {#raw_output} and {#raw_tree} attributes from
45
+ # the given HandBrakeCLI output. Does not modify the contents of
46
+ # the hash.
47
+ #
48
+ # @param [String] output raw contents from a HandBrakeCLI title
49
+ # scan
50
+ # @return [void]
51
+ def raw_output=(output)
52
+ @raw_output = output
53
+ @raw_tree = extract_tree
54
+ end
55
+
56
+ private
57
+
58
+ def extract_tree
59
+ split_blocks(
60
+ raw_output.split("\n").grep(/^\s*\+/), ''
61
+ ).inject(Tree::TreeNode.new('__root__')) do |root, block|
62
+ root << read_node(block, '')
63
+ root
64
+ end
65
+ end
66
+
67
+ def split_blocks(lines, indent_level)
68
+ lines.inject([]) do |blocks, line|
69
+ blocks << [] if line =~ /^#{indent_level}\+/
70
+
71
+ blocks.last << line
72
+ blocks
73
+ end
74
+ end
75
+
76
+ def read_node(node_lines, indent_level)
77
+ next_indent = indent_level + ' '
78
+ split_blocks(
79
+ node_lines[1..-1], next_indent
80
+ ).inject(Tree::TreeNode.new(node_lines.first[(2 + indent_level.size)..-1])) do |node, block|
81
+ node << read_node(block, next_indent)
82
+ node
83
+ end
84
+ end
85
+ end
86
+
87
+ ##
88
+ # Provides a {#seconds} method for an object which has a `duration`
89
+ # property whose value is a string of the format "hh:mm:ss"
90
+ module DurationAsSeconds
91
+ ##
92
+ # The number of seconds described by the duration. E.g., if the
93
+ # duration were `"1:02:42"`, this method would return `3762`.
94
+ #
95
+ # @return [Fixnum]
96
+ def seconds
97
+ @seconds ||= duration.split(':').collect(&:to_i).reverse.
98
+ inject([1, 0]) { |(m, sum), i| [m * 60, sum + i * m] }.last
99
+ end
100
+ end
101
+
102
+ ##
103
+ # Metadata about a single DVD title.
104
+ class Title
105
+ include DurationAsSeconds
106
+
107
+ ##
108
+ # @return [Fixnum] The title number of this title (a positive integer).
109
+ attr_accessor :number
110
+
111
+ ##
112
+ # @return [String] The duration of the title in the format
113
+ # "hh:mm:ss"
114
+ attr_accessor :duration
115
+
116
+ ##
117
+ # @return [Array<Chapter>] The chapters into which the title is
118
+ # divided.
119
+ attr_writer :chapters
120
+
121
+ ##
122
+ # @return [Boolean] Whether HandBrake considers this title the
123
+ # "main feature".
124
+ attr_writer :main_feature
125
+
126
+ ##
127
+ # Creates a new instance from the given scan subtree.
128
+ #
129
+ # @see Titles.from_output
130
+ # @param [Tree::TreeNode] title_node
131
+ # @return [Title] a new, fully initialized instance
132
+ def self.from_tree(title_node)
133
+ self.new.tap do |title|
134
+ title.number = title_node.name.scan(/title (\d+)/).first.first.to_i
135
+ title.duration = title_node.children.
136
+ detect { |c| c.name =~ /duration/ }.name.
137
+ scan(/duration: (\d\d:\d\d:\d\d)/).first.first
138
+ title.chapters = title_node['chapters:'].children.
139
+ collect { |ch_node| Chapter.from_tree(ch_node) }
140
+ title.main_feature = title_node.children.detect { |c| c.name =~ /Main Feature/ }
141
+ end
142
+ end
143
+
144
+ ##
145
+ # @return [Boolean] Whether HandBrake considers this title the
146
+ # "main feature".
147
+ def main_feature?
148
+ @main_feature
149
+ end
150
+
151
+ ##
152
+ # @return [Array<Chapter>] The chapters into which the title is
153
+ # divided.
154
+ def chapters
155
+ @chapters ||= []
156
+ end
157
+ end
158
+
159
+ ##
160
+ # The metadata about a single chapter in a title of a DVD.
161
+ class Chapter
162
+ include DurationAsSeconds
163
+
164
+ ##
165
+ # @return [String] The duration of the title in the format
166
+ # "hh:mm:ss"
167
+ attr_accessor :duration
168
+
169
+ ##
170
+ # Creates a new instance from the given title subtree.
171
+ #
172
+ # @see Title.from_tree
173
+ # @param [Tree::TreeNode] chapter_node
174
+ # @return [Chapter] a new, fully initialized instance
175
+ def self.from_tree(chapter_node)
176
+ self.new.tap do |ch|
177
+ ch.duration = chapter_node.name.scan(/duration (\d\d:\d\d:\d\d)/).first.first
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,5 @@
1
+ module HandBrake
2
+ ##
3
+ # The current version
4
+ VERSION = "0.0.1"
5
+ end
data/lib/handbrake.rb ADDED
@@ -0,0 +1,11 @@
1
+ ##
2
+ # @see file:README.md
3
+ # @see CLI The main class
4
+ module HandBrake
5
+ autoload :VERSION, 'handbrake/version'
6
+
7
+ autoload :CLI, 'handbrake/cli'
8
+ autoload :Titles, 'handbrake/titles'
9
+ autoload :Title, 'handbrake/titles'
10
+ autoload :Chapter, 'handbrake/titles'
11
+ end
@@ -0,0 +1,162 @@
1
+ require File.expand_path('../../spec_helper.rb', __FILE__)
2
+
3
+ module HandBrake
4
+ describe CLI do
5
+ describe "#bin_path" do
6
+ it "looks on the path by default" do
7
+ HandBrake::CLI.new.bin_path.should == "HandBrakeCLI"
8
+ end
9
+
10
+ it "is the specified value when specified" do
11
+ HandBrake::CLI.new(:bin_path => '/Applications/HandBrakeCLI').bin_path.
12
+ should == '/Applications/HandBrakeCLI'
13
+ end
14
+ end
15
+
16
+ describe "#trace?" do
17
+ it "is false by default" do
18
+ HandBrake::CLI.new.trace?.should == false
19
+ end
20
+
21
+ it "can be set" do
22
+ HandBrake::CLI.new(:trace => true).trace?.should == true
23
+ end
24
+ end
25
+
26
+ describe "building a command" do
27
+ let(:cli) { HandBrake::CLI.new }
28
+
29
+ it "works for a parameter without an argument" do
30
+ cli.markers.arguments.should == %w(--markers)
31
+ end
32
+
33
+ it "works for a parameter with an argument" do
34
+ cli.quality('0.8').arguments.should == %w(--quality 0.8)
35
+ end
36
+
37
+ it "works with a parameter with a dashed name" do
38
+ cli.native_language('eng').arguments.should == %w(--native-language eng)
39
+ end
40
+
41
+ it "can chain parameters" do
42
+ cli.previews('15').format('avi').large_file.title('3').arguments.should ==
43
+ %w(--previews 15 --format avi --large-file --title 3)
44
+ end
45
+
46
+ it "stringifies arguments" do
47
+ cli.previews(18).arguments.should == %w(--previews 18)
48
+ end
49
+
50
+ it "can produce separate forks of the command" do
51
+ base = cli.input('/foo/bar')
52
+ base.quality('0.53').format('avi').arguments.should ==
53
+ %w(--input /foo/bar --quality 0.53 --format avi)
54
+ base.title('6').ipod_atom.arguments.should ==
55
+ %w(--input /foo/bar --title 6 --ipod-atom)
56
+ end
57
+ end
58
+
59
+ describe 'execution' do
60
+ let(:cli) { HandBrake::CLI.new(:runner => runner) }
61
+ let(:runner) { HandBrake::Spec::StaticRunner.new }
62
+
63
+ describe 'default runner' do
64
+ let(:cli) { HandBrake::CLI.new }
65
+
66
+ before do
67
+ `which HandBrakeCLI`
68
+ unless $? == 0
69
+ pending 'HandBrakeCLI is not on the path'
70
+ end
71
+ end
72
+
73
+ it 'works' do
74
+ lambda { cli.update }.should_not raise_error
75
+ end
76
+ end
77
+
78
+ describe '#output' do
79
+ it 'uses the --output argument' do
80
+ cli.output('/foo/bar.m4v')
81
+ runner.actual_arguments.should == %w(--output /foo/bar.m4v)
82
+ end
83
+ end
84
+
85
+ describe '#scan' do
86
+ let(:sample_scan) { File.read(File.expand_path('../sample-titles-scan.err', __FILE__)) }
87
+
88
+ before do
89
+ runner.output = sample_scan
90
+ end
91
+
92
+ it 'uses the --scan argument' do
93
+ cli.scan
94
+ runner.actual_arguments.last.should == '--scan'
95
+ end
96
+
97
+ it 'defaults to scanning all titles' do
98
+ cli.scan
99
+ runner.actual_arguments.should == %w(--title 0 --scan)
100
+ end
101
+
102
+ it 'only scans the specified title if one is specified' do
103
+ cli.title(3).scan
104
+ runner.actual_arguments.should == %w(--title 3 --scan)
105
+ end
106
+
107
+ it 'does not permanently modify the argument list when using the default title setting' do
108
+ cli.scan
109
+ cli.arguments.should_not include('--title')
110
+ end
111
+
112
+ it 'returns titles from the output' do
113
+ # The details for this are tested in titles_spec
114
+ cli.scan.size.should == 5
115
+ end
116
+ end
117
+
118
+ describe '#update' do
119
+ it 'uses the --update argument' do
120
+ cli.update
121
+ runner.actual_arguments.should == %w(--update)
122
+ end
123
+
124
+ it 'returns true if the thing is up to date' do
125
+ runner.output = 'Your version of HandBrake is up to date.'
126
+ cli.update.should be_true
127
+ end
128
+
129
+ it 'returns false if the executable is out of date' do
130
+ runner.output = 'You are using an old version of HandBrake.'
131
+ cli.update.should be_false
132
+ end
133
+ end
134
+
135
+ describe '#preset_list' do
136
+ let(:sample_presets) { File.read(File.expand_path('../sample-preset-list.out', __FILE__)) }
137
+
138
+ before do
139
+ runner.output = sample_presets
140
+ end
141
+
142
+ it 'uses the --preset-list argument' do
143
+ cli.preset_list
144
+ runner.actual_arguments.should == %w(--preset-list)
145
+ end
146
+
147
+ it 'returns a hash containing all the categories' do
148
+ cli.preset_list.keys.sort.should == %w(Apple Legacy Regular)
149
+ end
150
+
151
+ it 'returns a hash containing the presets in each category' do
152
+ cli.preset_list['Regular'].keys.sort.should == ['High Profile', 'Normal']
153
+ end
154
+
155
+ it 'returns a hash containing the actual args for a particular preset' do
156
+ cli.preset_list['Regular']['Normal'].should ==
157
+ '-e x264 -q 20.0 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 --strict-anamorphic -m -x ref=2:bframes=2:subme=6:mixed-refs=0:weightb=0:8x8dct=0:trellis=0'
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,38 @@
1
+
2
+ < Apple
3
+
4
+ + Universal: -e x264 -q 20.0 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -X 720 --loose-anamorphic -m -x cabac=0:ref=2:me=umh:bframes=0:weightp=0:8x8dct=0:trellis=0:subme=6
5
+
6
+ + iPod: -e x264 -b 700 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -I -X 320 -m -x level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=768:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:subme=6:8x8dct=0:trellis=0
7
+
8
+ + iPhone & iPod Touch: -e x264 -q 20.0 -a 1 -E faac -B 128 -6 dpl2 -R Auto -D 0.0 -f mp4 -X 480 -m -x cabac=0:ref=2:me=umh:bframes=0:weightp=0:subme=6:8x8dct=0:trellis=0
9
+
10
+ + iPhone 4: -e x264 -q 20.0 -r 29.97 --pfr -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -4 -X 960 --loose-anamorphic -m
11
+
12
+ + iPad: -e x264 -q 20.0 -r 29.97 --pfr -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -4 -X 1024 --loose-anamorphic -m
13
+
14
+ + AppleTV: -e x264 -q 20.0 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -4 -X 960 --loose-anamorphic -m -x cabac=0:ref=2:me=umh:b-pyramid=none:b-adapt=2:weightb=0:trellis=0:weightp=0:vbv-maxrate=9500:vbv-bufsize=9500
15
+
16
+ + AppleTV 2: -e x264 -q 20.0 -r 29.97 --pfr -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -4 -X 1280 --loose-anamorphic -m
17
+
18
+ >
19
+
20
+ < Regular
21
+
22
+ + Normal: -e x264 -q 20.0 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 --strict-anamorphic -m -x ref=2:bframes=2:subme=6:mixed-refs=0:weightb=0:8x8dct=0:trellis=0
23
+
24
+ + High Profile: -e x264 -q 20.0 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 --detelecine --decomb --loose-anamorphic -m -x b-adapt=2:rc-lookahead=50
25
+
26
+ >
27
+
28
+ < Legacy
29
+
30
+ + Classic: -b 1000 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4
31
+
32
+ + AppleTV Legacy: -e x264 -b 2500 -a 1,1 -E faac,copy:ac3 -B 160,160 -6 dpl2,auto -R Auto,Auto -D 0.0,0.0 -f mp4 -4 --strict-anamorphic -m -x ref=1:b-pyramid=none:weightp=0:subme=5:me=umh:no-fast-pskip=1:cabac=0:weightb=0:8x8dct=0:trellis=0
33
+
34
+ + iPhone Legacy: -e x264 -b 960 -a 1 -E faac -B 128 -6 dpl2 -R Auto -D 0.0 -f mp4 -I -X 480 -m -x level=30:cabac=0:ref=1:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:bframes=0:weightp=0:subme=6:8x8dct=0:trellis=0
35
+
36
+ + iPod Legacy: -e x264 -b 1500 -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0.0 -f mp4 -I -X 640 -m -x level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=1500:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:psy-rd=0,0:subme=6:8x8dct=0:trellis=0
37
+
38
+ >